]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Enhances the parser so that it accepts arbitrary expressions for the arguments
authordrh <drh@noemail.net>
Mon, 24 Aug 2015 20:21:20 +0000 (20:21 +0000)
committerdrh <drh@noemail.net>
Mon, 24 Aug 2015 20:21:20 +0000 (20:21 +0000)
of an index, though the code generator still rejects everything other than
simple column names.  The sqlite3RestrictColumnListSyntax() routine is removed
since that feature is now handled by the parser.

FossilOrigin-Name: bed42116addabcf3dfdc2e2d51ae183965704988

manifest
manifest.uuid
src/build.c
src/expr.c
src/parse.y
src/sqliteInt.h
test/parser1.test
test/with2.test

index ac41156aaeb3da94dcf5672cabcf8a182db82b86..bc354b2e9254d5225ee2ff3d7ffc61c1eb7e0dae 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-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
@@ -282,14 +282,14 @@ F src/btmutex.c 45a968cc85afed9b5e6cf55bf1f42f8d18107f79
 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
@@ -326,7 +326,7 @@ F src/os_win.c 40b3af7a47eb1107d0d69e592bec345a3b7b798a
 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
@@ -342,7 +342,7 @@ F src/shell.c b1f91e60918df3a68efad1e3a11696b9a7e23d23
 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
@@ -910,7 +910,7 @@ F test/pagerfault2.test caf4c7facb914fd3b03a17b31ae2b180c8d6ca1f
 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
@@ -1312,7 +1312,7 @@ F test/win32heap.test ea19770974795cff26e11575e12d422dbd16893c
 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
@@ -1379,7 +1379,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
 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
index 358a0a25909af085d6513cfa4f511c174e8ee4d7..defc8a532935d3475bae205f22ecbf468dae3a2d 100644 (file)
@@ -1 +1 @@
-d794b34da6f9c77dfe17773b0b17b22de72cce7f
\ No newline at end of file
+bed42116addabcf3dfdc2e2d51ae183965704988
\ No newline at end of file
index 815b17deb8487c4cbb73123915f3c20f65e7ead2..8a7dda89c176d40347460ab1c2c41bdb5c48c1f8 100644 (file)
@@ -1310,11 +1310,15 @@ void sqlite3AddPrimaryKey(
   }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;
+          }
         }
       }
     }
@@ -1696,10 +1700,12 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
   */
   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);
@@ -2076,7 +2082,6 @@ void sqlite3CreateView(
     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);
@@ -2607,8 +2612,6 @@ void sqlite3CreateForeignKey(
 
   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;
@@ -3043,12 +3046,16 @@ Index *sqlite3CreateIndex(
   ** 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
@@ -3056,8 +3063,7 @@ Index *sqlite3CreateIndex(
   */
   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));
     }
   }
@@ -3109,10 +3115,17 @@ Index *sqlite3CreateIndex(
   ** 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;
     }
@@ -3124,9 +3137,8 @@ Index *sqlite3CreateIndex(
     }
     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 );
@@ -4293,32 +4305,6 @@ KeyInfo *sqlite3KeyInfoOfIndex(Parse *pParse, Index *pIdx){
   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 
@@ -4335,8 +4321,6 @@ With *sqlite3WithAdd(
   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);
index 1c57ecc6fd6592c52b305b7704b732006f36c0ae..1aebef6b166ce2bdc0f445c5780180523e006148 100644 (file)
@@ -1172,7 +1172,6 @@ void sqlite3ExprListSetSortOrder(ExprList *p, int iSortOrder){
     return;
   }
   p->a[p->nExpr-1].sortOrder = (u8)iSortOrder;
-  p->a[p->nExpr-1].bDefinedSO = 1;
 }
 
 /*
index acd899449ef2a366e4af4c0f12462c244d0f870f..e99feeefc148d4a0a4ae58f13dbcffc64508fc90 100644 (file)
@@ -301,7 +301,7 @@ ccons ::= PRIMARY KEY sortorder(Z) onconf(R) autoinc(I).
                                  {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);}
@@ -345,14 +345,14 @@ conslist ::= tcons.
 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);
 }
@@ -386,7 +386,7 @@ ifexists(A) ::= .            {A = 0;}
 ///////////////////// 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);
 }
@@ -674,6 +674,11 @@ using_opt(U) ::= .                        {U = 0;}
 
 %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, $$);}
 
@@ -1208,7 +1213,7 @@ nexprlist(A) ::= expr(Y).
 ///////////////////////////// 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);
@@ -1218,31 +1223,64 @@ cmd ::= createkw(S) uniqueflag(U) INDEX ifnotexists(NE) nm(X) dbnm(D)
 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 /////////////////////////
@@ -1490,10 +1528,10 @@ with(A) ::= . {A = 0;}
 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
index 5f123505385d725b91827f860906c9df27c5a400..4c17904ff85fa32a578967d56148924671fcd326 100644 (file)
@@ -2189,7 +2189,6 @@ struct ExprList {
     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 */
@@ -3758,7 +3757,6 @@ const char *sqlite3JournalModename(int);
   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*);
index f4c3227f87c41a46d4f7a29409b504049c6a99c4..78c1a40c630e41ac29858536a4c8cfddfa0316a0 100644 (file)
@@ -21,7 +21,13 @@ do_catchsql_test parser1-1.1 {
     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,
@@ -42,7 +48,22 @@ do_test parser1-1.3 {
   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
index eb0614729bed31db388dc155da18910312370ba4..02d10b5112b1045fd40d4cae1afe06577f9df46d 100644 (file)
@@ -250,7 +250,8 @@ do_execsql_test  4.4 [genstmt 255] 1
 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 
@@ -415,4 +416,3 @@ do_execsql_test 8.3 {
 
 
 finish_test
-