-C Enhance\sthe\sCREATE\sVIEW\ssyntax\sso\sthat\sthe\snames\sof\scolumns\sof\sthe\sview\scan\nbe\sspecified\safter\sthe\sview\sname.
-D 2015-08-24T17:42:49.622
+C Enhances\sthe\sparser\sso\sthat\sit\saccepts\sarbitrary\sexpressions\sfor\sthe\sarguments\nof\san\sindex,\sthough\sthe\scode\sgenerator\sstill\srejects\severything\sother\sthan\nsimple\scolumn\snames.\s\sThe\ssqlite3RestrictColumnListSyntax()\sroutine\sis\sremoved\nsince\sthat\sfeature\sis\snow\shandled\sby\sthe\sparser.
+D 2015-08-24T20:21:20.985
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in e2218eb228374422969de7b1680eda6864affcef
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
F src/btree.c f48b3ef91676c06a90a8832987ecef6b94c931ee
F src/btree.h 969adc948e89e449220ff0ff724c94bb2a52e9f1
F src/btreeInt.h 8177c9ab90d772d6d2c6c517e05bed774b7c92c0
-F src/build.c a4e2669bc59729589b7e3867c58eae5a4f2419ff
+F src/build.c 789e75f3478ac63c0f398a131c49a0802c356c2b
F src/callback.c 7b44ce59674338ad48b0e84e7b72f935ea4f68b0
F src/complete.c addcd8160b081131005d5bc2d34adf20c1c5c92f
F src/ctime.c 5a0b735dc95604766f5dac73973658eef782ee8b
F src/date.c 8ec787fed4929d8ccdf6b1bc360fccc3e1d2ca58
F src/dbstat.c f402e77e25089c6003d0c60b3233b9b3947d599a
F src/delete.c 8857a6f27560718f65d43bdbec86c967ae1f8dfa
-F src/expr.c c05d67f1a03c097d5c29839d5a538cfde9c472ce
+F src/expr.c 650ac7c4f659980a3315e2aaa02a0d71e87f14a5
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
F src/fkey.c c9b63a217d86582c22121699a47f22f524608869
F src/func.c 824bea430d3a2b7dbc62806ad54da8fdb8ed9e3f
F src/os_win.h eb7a47aa17b26b77eb97e4823f20a00b8bda12ca
F src/pager.c aa916ca28606ccf4b6877dfc2b643ccbca86589f
F src/pager.h 6d435f563b3f7fcae4b84433b76a6ac2730036e2
-F src/parse.y 07f2084f9ec157b108f1bf12466277d6f17b59d1
+F src/parse.y f599aa5e871a493330d567ced93de696f61f48f7
F src/pcache.c cde06aa50962595e412d497e22fd2e07878ba1f0
F src/pcache.h 9968603796240cdf83da7e7bef76edf90619cea9
F src/pcache1.c a3fe31b17e841ec70beee72a2c960e9c787a8857
F src/sqlite.h.in 378bebc8fe6a88bade25e5f23b7e6123fdc64b00
F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad
F src/sqlite3ext.h f700e6a9dd1fdcccc9951ab022b366fb66b9e413
-F src/sqliteInt.h 79a8e76bcbe67170d371ae2a08c85cc2d7cd0caf
+F src/sqliteInt.h edbcd0c0787541a636a25ab1d1eaf847dbd043f1
F src/sqliteLimit.h 216557999cb45f2e3578ed53ebefe228d779cb46
F src/status.c f266ad8a2892d659b74f0f50cb6a88b6e7c12179
F src/table.c 51b46b2a62d1b3a959633d593b89bab5e2c9155e
F test/pagerfault3.test 1003fcda009bf48a8e22a516e193b6ef0dd1bbd8
F test/pageropt.test 6b8f6a123a5572c195ad4ae40f2987007923bbd6
F test/pagesize.test 5769fc62d8c890a83a503f67d47508dfdc543305
-F test/parser1.test 23867b6f2c4758c7774108826d9f17e9cd17bcde
+F test/parser1.test 222b5cbf3e2e659fec1bf7d723488c8b9c94f1d0
F test/pcache.test c8acbedd3b6fd0f9a7ca887a83b11d24a007972b
F test/pcache2.test af7f3deb1a819f77a6d0d81534e97d1cf62cd442
F test/percentile.test 4243af26b8f3f4555abe166f723715a1f74c77ff
F test/win32lock.test fbf107c91d8f5512be5a5b87c4c42ab9fdd54972
F test/win32longpath.test 169c75a3b2e43481f4a62122510210c67b08f26d
F test/with1.test a1e8660be88e2eb4648f8860f831d1e38b5b5443
-F test/with2.test ee227a663586aa09771cafd4fa269c5217eaf775
+F test/with2.test 2b40da883658eb74ad8ad06afabe11a408e7fb87
F test/withM.test e97f2a8c506ab3ea9eab94e6f6072f6cc924c991
F test/without_rowid1.test 1a7b9bd51b899928d327052df9741d2fe8dbe701
F test/without_rowid2.test af260339f79d13cb220288b67cd287fbcf81ad99
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P a1ae20cd97456a1126cfa1a9bedce0bac0940ad6
-R 7c6b5f2ebead0dd2f6f395aca9a96d64
+P d794b34da6f9c77dfe17773b0b17b22de72cce7f
+R 551ba7ed9667cd3021493a6e99ba80fb
U drh
-Z 9176898b8b319f8964514d527c2d8cd5
+Z 12005a1b68dc81ba8d64d2d3b63a147c
-d794b34da6f9c77dfe17773b0b17b22de72cce7f
\ No newline at end of file
+bed42116addabcf3dfdc2e2d51ae183965704988
\ No newline at end of file
}else{
nTerm = pList->nExpr;
for(i=0; i<nTerm; i++){
- for(iCol=0; iCol<pTab->nCol; iCol++){
- if( sqlite3StrICmp(pList->a[i].zName, pTab->aCol[iCol].zName)==0 ){
- pTab->aCol[iCol].colFlags |= COLFLAG_PRIMKEY;
- zType = pTab->aCol[iCol].zType;
- break;
+ Expr *pCExpr = sqlite3ExprSkipCollate(pList->a[i].pExpr);
+ if( pCExpr && pCExpr->op==TK_ID ){
+ const char *zCName = pCExpr->u.zToken;
+ for(iCol=0; iCol<pTab->nCol; iCol++){
+ if( sqlite3StrICmp(zCName, pTab->aCol[iCol].zName)==0 ){
+ pTab->aCol[iCol].colFlags |= COLFLAG_PRIMKEY;
+ zType = pTab->aCol[iCol].zType;
+ break;
+ }
}
}
}
*/
if( pTab->iPKey>=0 ){
ExprList *pList;
- pList = sqlite3ExprListAppend(pParse, 0, 0);
+ Token ipkToken;
+ ipkToken.z = pTab->aCol[pTab->iPKey].zName;
+ ipkToken.n = sqlite3Strlen30(ipkToken.z);
+ pList = sqlite3ExprListAppend(pParse, 0,
+ sqlite3ExprAlloc(db, TK_ID, &ipkToken, 0));
if( pList==0 ) return;
- pList->a[0].zName = sqlite3DbStrDup(pParse->db,
- pTab->aCol[pTab->iPKey].zName);
pList->a[0].sortOrder = pParse->iPkSortOrder;
assert( pParse->pNewTable==pTab );
pPk = sqlite3CreateIndex(pParse, 0, 0, 0, pList, pTab->keyConf, 0, 0, 0, 0);
return;
}
sqlite3StartTable(pParse, pName1, pName2, isTemp, 1, 0, noErr);
- sqlite3RestrictColumnListSyntax(pParse, pCNames);
p = pParse->pNewTable;
if( p==0 || pParse->nErr ) goto create_view_fail;
sqlite3TwoPartName(pParse, pName1, pName2, &pName);
assert( pTo!=0 );
if( p==0 || IN_DECLARE_VTAB ) goto fk_end;
- sqlite3RestrictColumnListSyntax(pParse, pFromCol);
- sqlite3RestrictColumnListSyntax(pParse, pToCol);
if( pFromCol==0 ){
int iCol = p->nCol-1;
if( NEVER(iCol<0) ) goto fk_end;
** So create a fake list to simulate this.
*/
if( pList==0 ){
- pList = sqlite3ExprListAppend(pParse, 0, 0);
+ Token prevCol;
+ prevCol.z = pTab->aCol[pTab->nCol-1].zName;
+ prevCol.n = sqlite3Strlen30(prevCol.z);
+ pList = sqlite3ExprListAppend(pParse, 0,
+ sqlite3ExprAlloc(db, TK_ID, &prevCol, 0));
if( pList==0 ) goto exit_create_index;
- pList->a[0].zName = sqlite3DbStrDup(pParse->db,
- pTab->aCol[pTab->nCol-1].zName);
assert( pList->nExpr==1 );
sqlite3ExprListSetSortOrder(pList, sortOrder);
+ }else{
+ sqlite3ExprListCheckLength(pParse, pList, "index");
}
/* Figure out how many bytes of space are required to store explicitly
*/
for(i=0; i<pList->nExpr; i++){
Expr *pExpr = pList->a[i].pExpr;
- if( pExpr ){
- assert( pExpr->op==TK_COLLATE );
+ if( pExpr && pExpr->op==TK_COLLATE ){
nExtra += (1 + sqlite3Strlen30(pExpr->u.zToken));
}
}
** break backwards compatibility - it needs to be a warning.
*/
for(i=0, pListItem=pList->a; i<pList->nExpr; i++, pListItem++){
- const char *zColName = pListItem->zName;
+ const char *zColName;
+ Expr *pCExpr;
int requestedSortOrder;
char *zColl; /* Collation sequence name */
+ pCExpr = sqlite3ExprSkipCollate(pListItem->pExpr);
+ if( pCExpr->op!=TK_ID ){
+ sqlite3ErrorMsg(pParse, "indexes on expressions not yet supported");
+ continue;
+ }
+ zColName = pCExpr->u.zToken;
for(j=0, pTabCol=pTab->aCol; j<pTab->nCol; j++, pTabCol++){
if( sqlite3StrICmp(zColName, pTabCol->zName)==0 ) break;
}
}
assert( j<=0x7fff );
pIndex->aiColumn[i] = (i16)j;
- if( pListItem->pExpr ){
+ if( pListItem->pExpr->op==TK_COLLATE ){
int nColl;
- assert( pListItem->pExpr->op==TK_COLLATE );
zColl = pListItem->pExpr->u.zToken;
nColl = sqlite3Strlen30(zColl) + 1;
assert( nExtra>=nColl );
return pKey;
}
-/*
-** Generate a syntax error if the expression list provided contains
-** any COLLATE or ASC or DESC keywords.
-**
-** Some legacy versions of SQLite allowed constructs like:
-**
-** CREATE TABLE x(..., FOREIGN KEY(x COLLATE binary DESC) REFERENCES...);
-** ^^^^^^^^^^^^^^^^^^^
-**
-** The COLLATE and sort order terms were ignored. To prevent compatibility
-** problems in case something like this appears in a legacy sqlite_master
-** table, only enforce the restriction on new SQL statements, not when
-** parsing the schema out of the sqlite_master table.
-*/
-void sqlite3RestrictColumnListSyntax(Parse *pParse, ExprList *p){
- int i;
- if( p==0 || pParse->db->init.busy ) return;
- for(i=0; i<p->nExpr; i++){
- if( p->a[i].pExpr!=0 || p->a[i].bDefinedSO ){
- sqlite3ErrorMsg(pParse, "syntax error after column name \"%w\"",
- p->a[i].zName);
- return;
- }
- }
-}
-
#ifndef SQLITE_OMIT_CTE
/*
** This routine is invoked once per CTE by the parser while parsing a
With *pNew;
char *zName;
- sqlite3RestrictColumnListSyntax(pParse, pArglist);
-
/* Check that the CTE name is unique within this WITH clause. If
** not, store an error in the Parse structure. */
zName = sqlite3NameFromToken(pParse->db, pName);
return;
}
p->a[p->nExpr-1].sortOrder = (u8)iSortOrder;
- p->a[p->nExpr-1].bDefinedSO = 1;
}
/*
{sqlite3AddPrimaryKey(pParse,0,R,I,Z);}
ccons ::= UNIQUE onconf(R). {sqlite3CreateIndex(pParse,0,0,0,0,R,0,0,0,0);}
ccons ::= CHECK LP expr(X) RP. {sqlite3AddCheckConstraint(pParse,X.pExpr);}
-ccons ::= REFERENCES nm(T) idxlist_opt(TA) refargs(R).
+ccons ::= REFERENCES nm(T) eidlist_opt(TA) refargs(R).
{sqlite3CreateForeignKey(pParse,0,&T,TA,R);}
ccons ::= defer_subclause(D). {sqlite3DeferForeignKey(pParse,D);}
ccons ::= COLLATE ids(C). {sqlite3AddCollateType(pParse, &C);}
tconscomma ::= COMMA. {pParse->constraintName.n = 0;}
tconscomma ::= .
tcons ::= CONSTRAINT nm(X). {pParse->constraintName = X;}
-tcons ::= PRIMARY KEY LP idxlist(X) autoinc(I) RP onconf(R).
+tcons ::= PRIMARY KEY LP sortlist(X) autoinc(I) RP onconf(R).
{sqlite3AddPrimaryKey(pParse,X,R,I,0);}
-tcons ::= UNIQUE LP idxlist(X) RP onconf(R).
+tcons ::= UNIQUE LP sortlist(X) RP onconf(R).
{sqlite3CreateIndex(pParse,0,0,0,X,R,0,0,0,0);}
tcons ::= CHECK LP expr(E) RP onconf.
{sqlite3AddCheckConstraint(pParse,E.pExpr);}
-tcons ::= FOREIGN KEY LP idxlist(FA) RP
- REFERENCES nm(T) idxlist_opt(TA) refargs(R) defer_subclause_opt(D). {
+tcons ::= FOREIGN KEY LP eidlist(FA) RP
+ REFERENCES nm(T) eidlist_opt(TA) refargs(R) defer_subclause_opt(D). {
sqlite3CreateForeignKey(pParse, FA, &T, TA, R);
sqlite3DeferForeignKey(pParse, D);
}
///////////////////// The CREATE VIEW statement /////////////////////////////
//
%ifndef SQLITE_OMIT_VIEW
-cmd ::= createkw(X) temp(T) VIEW ifnotexists(E) nm(Y) dbnm(Z) idxlist_opt(C)
+cmd ::= createkw(X) temp(T) VIEW ifnotexists(E) nm(Y) dbnm(Z) eidlist_opt(C)
AS select(S). {
sqlite3CreateView(pParse, &X, &Y, &Z, C, S, T, E);
}
%type orderby_opt {ExprList*}
%destructor orderby_opt {sqlite3ExprListDelete(pParse->db, $$);}
+
+// the sortlist non-terminal stores a list of expression where each
+// expression is optionally followed by ASC or DESC to indicate the
+// sort order.
+//
%type sortlist {ExprList*}
%destructor sortlist {sqlite3ExprListDelete(pParse->db, $$);}
///////////////////////////// The CREATE INDEX command ///////////////////////
//
cmd ::= createkw(S) uniqueflag(U) INDEX ifnotexists(NE) nm(X) dbnm(D)
- ON nm(Y) LP idxlist(Z) RP where_opt(W). {
+ ON nm(Y) LP sortlist(Z) RP where_opt(W). {
sqlite3CreateIndex(pParse, &X, &D,
sqlite3SrcListAppend(pParse->db,0,&Y,0), Z, U,
&S, W, SQLITE_SO_ASC, NE);
uniqueflag(A) ::= UNIQUE. {A = OE_Abort;}
uniqueflag(A) ::= . {A = OE_None;}
-%type idxlist {ExprList*}
-%destructor idxlist {sqlite3ExprListDelete(pParse->db, $$);}
-%type idxlist_opt {ExprList*}
-%destructor idxlist_opt {sqlite3ExprListDelete(pParse->db, $$);}
-
-idxlist_opt(A) ::= . {A = 0;}
-idxlist_opt(A) ::= LP idxlist(X) RP. {A = X;}
-idxlist(A) ::= idxlist(X) COMMA nm(Y) collate(C) sortorder(Z). {
- Expr *p = sqlite3ExprAddCollateToken(pParse, 0, &C, 1);
- A = sqlite3ExprListAppend(pParse,X, p);
- sqlite3ExprListSetName(pParse,A,&Y,1);
- sqlite3ExprListCheckLength(pParse, A, "index");
- sqlite3ExprListSetSortOrder(A,Z);
+
+// The eidlist non-terminal (Expression Id List) generates an ExprList
+// from a list of identifiers. The identifier names are in ExprList.a[].zName.
+// This list is stored in an ExprList rather than an IdList so that it
+// can be easily sent to sqlite3ColumnsExprList().
+//
+// eidlist is grouped with CREATE INDEX because it used to be the non-terminal
+// used for the arguments to an index. That is just an historical accident.
+//
+// IMPORTANT COMPATIBILITY NOTE: Some prior versions of SQLite accepted
+// COLLATE clauses and ASC or DESC keywords on ID lists in inappropriate
+// places - places that might have been stored in the sqlite_master schema.
+// Those extra features were ignored. But because they might be in some
+// (busted) old databases, we need to continue parsing them when loading
+// historical schemas.
+//
+%type eidlist {ExprList*}
+%destructor eidlist {sqlite3ExprListDelete(pParse->db, $$);}
+%type eidlist_opt {ExprList*}
+%destructor eidlist_opt {sqlite3ExprListDelete(pParse->db, $$);}
+
+%include {
+ /* Add a single new term to an ExprList that is used to store a
+ ** list of identifiers. Report an error if the ID list contains
+ ** a COLLATE clause or an ASC or DESC keyword, except ignore the
+ ** error while parsing a legacy schema.
+ */
+ static ExprList *parserAddExprIdListTerm(
+ Parse *pParse,
+ ExprList *pPrior,
+ Token *pIdToken,
+ int hasCollate,
+ int sortOrder
+ ){
+ ExprList *p = sqlite3ExprListAppend(pParse, pPrior, 0);
+ if( (hasCollate || sortOrder!=SQLITE_SO_UNDEFINED)
+ && pParse->db->init.busy==0
+ ){
+ sqlite3ErrorMsg(pParse, "syntax error after column name \"%.*s\"",
+ pIdToken->n, pIdToken->z);
+ }
+ sqlite3ExprListSetName(pParse, p, pIdToken, 1);
+ return p;
+ }
+} // end %include
+
+eidlist_opt(A) ::= . {A = 0;}
+eidlist_opt(A) ::= LP eidlist(X) RP. {A = X;}
+eidlist(A) ::= eidlist(X) COMMA nm(Y) collate(C) sortorder(Z). {
+ A = parserAddExprIdListTerm(pParse, X, &Y, C, Z);
}
-idxlist(A) ::= nm(Y) collate(C) sortorder(Z). {
- Expr *p = sqlite3ExprAddCollateToken(pParse, 0, &C, 1);
- A = sqlite3ExprListAppend(pParse,0, p);
- sqlite3ExprListSetName(pParse, A, &Y, 1);
- sqlite3ExprListCheckLength(pParse, A, "index");
- sqlite3ExprListSetSortOrder(A,Z);
+eidlist(A) ::= nm(Y) collate(C) sortorder(Z). {
+ A = parserAddExprIdListTerm(pParse, 0, &Y, C, Z);
}
-%type collate {Token}
-collate(C) ::= . {C.z = 0; C.n = 0;}
-collate(C) ::= COLLATE ids(X). {C = X;}
+%type collate {int}
+collate(C) ::= . {C = 0;}
+collate(C) ::= COLLATE ids. {C = 1;}
///////////////////////////// The DROP INDEX command /////////////////////////
with(A) ::= WITH wqlist(W). { A = W; }
with(A) ::= WITH RECURSIVE wqlist(W). { A = W; }
-wqlist(A) ::= nm(X) idxlist_opt(Y) AS LP select(Z) RP. {
+wqlist(A) ::= nm(X) eidlist_opt(Y) AS LP select(Z) RP. {
A = sqlite3WithAdd(pParse, 0, &X, Y, Z);
}
-wqlist(A) ::= wqlist(W) COMMA nm(X) idxlist_opt(Y) AS LP select(Z) RP. {
+wqlist(A) ::= wqlist(W) COMMA nm(X) eidlist_opt(Y) AS LP select(Z) RP. {
A = sqlite3WithAdd(pParse, W, &X, Y, Z);
}
%endif SQLITE_OMIT_CTE
unsigned done :1; /* A flag to indicate when processing is finished */
unsigned bSpanIsTab :1; /* zSpan holds DB.TABLE.COLUMN */
unsigned reusable :1; /* Constant expression is reusable */
- unsigned bDefinedSO :1; /* True if either DESC or ASC keywords present */
union {
struct {
u16 iOrderByCol; /* For ORDER BY, column number in result set */
int sqlite3Checkpoint(sqlite3*, int, int, int*, int*);
int sqlite3WalDefaultHook(void*,sqlite3*,const char*,int);
#endif
-void sqlite3RestrictColumnListSyntax(Parse*,ExprList*);
#ifndef SQLITE_OMIT_CTE
With *sqlite3WithAdd(Parse*,With*,Token*,ExprList*,Select*);
void sqlite3WithDelete(sqlite3*,With*);
b TEXT,
FOREIGN KEY(b COLLATE nocase DESC) REFERENCES t1(a COLLATE binary ASC)
);
-} {1 {syntax error after column name "a"}}
+} {1 {syntax error after column name "b"}}
+
+
+# Verify that a legacy schema in the sqlite_master file is allowed to have
+# COLLATE, ASC, and DESC keywords on the id list of a FK constraint, and that
+# those keywords are silently ignored.
+#
do_execsql_test parser1-1.2 {
CREATE TABLE t1(
a TEXT PRIMARY KEY,
sqlite3 db2 test.db
db2 eval {SELECT * FROM t1 ORDER BY 1}
} {abc {} xyz abc}
+db2 close
+do_execsql_test parser1-1.4 {
+ UPDATE sqlite_master SET sql='CREATE TABLE t1(
+ a TEXT PRIMARY KEY,
+ b TEXT,
+ FOREIGN KEY(b ASC) REFERENCES t1(a)
+ )' WHERE name='t1';
+ SELECT name FROM sqlite_master WHERE sql LIKE '%ASC%';
+} {t1}
+sqlite3 db2 test.db
+do_test parser1-1.5 {
+ sqlite3 db2 test.db
+ db2 eval {SELECT * FROM t1 ORDER BY 1}
+} {abc {} xyz abc}
+db2 close
do_catchsql_test parser1-2.1 {
WITH RECURSIVE
set nLimit [sqlite3_limit db SQLITE_LIMIT_COLUMN -1]
do_execsql_test 4.5 [genstmt [expr $nLimit-1]] 1
do_execsql_test 4.6 [genstmt $nLimit] 1
-do_catchsql_test 4.7 [genstmt [expr $nLimit+1]] {1 {too many columns in index}}
+do_catchsql_test 4.7 [genstmt [expr $nLimit+1]] \
+ {1 {too many columns in result set}}
#---------------------------------------------------------------------------
# Check that adding a WITH clause to an INSERT disables the xfer
finish_test
-