]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Reduce rules added to the grammar. Kinda works, but there are still bugs.
authordrh <>
Mon, 26 Aug 2024 12:26:26 +0000 (12:26 +0000)
committerdrh <>
Mon, 26 Aug 2024 12:26:26 +0000 (12:26 +0000)
FossilOrigin-Name: 3c7a5cc6d0d186e68a5885299f7474ad2e31b839af404a649dbc8f5b8f1d0a62

manifest
manifest.uuid
src/parse.y
src/tokenize.c

index f8c8ea58e096ed521400af4fb1111d10f46a7b08..2794be4a10eba938926b1d2afe50b105dee80e15 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Another\sversion\sof\sthe\sparser\swith\sa\sslightly\sricher\ssyntax.\s\sThe\sghastly\npipe\soperator\sis\snow\soptional,\sbut\sis\snever\srequired.\s\sPipelines\scannot\nbe\sinitiated\sfrom\san\sarbitrary\sSELECT\sunless\sthe\sarbitrary\sSELECT\sis\sa\ssubquery\non\sthe\sinitial\sFROM.
-D 2024-08-26T02:53:31.582
+C Reduce\srules\sadded\sto\sthe\sgrammar.\s\sKinda\sworks,\sbut\sthere\sare\sstill\sbugs.
+D 2024-08-26T12:26:26.963
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -753,7 +753,7 @@ F src/os_win.c 6ff43bac175bd9ed79e7c0f96840b139f2f51d01689a638fd05128becf94908a
 F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
 F src/pager.c b08600ebf0db90b6d1e9b8b6577c6fa3877cbe1a100bd0b2899e4c6e9adad4b3
 F src/pager.h 4b1140d691860de0be1347474c51fee07d5420bd7f802d38cbab8ea4ab9f538a
-F src/parse.y 58718094002997d3ecde5b08840282e5d623429831d459154668b72097897df1
+F src/parse.y ed7a01c2619df3fb9da2db0c2e8d89bf5583574b291e57bac201caeac2c0fdea
 F src/pcache.c 588cc3c5ccaaadde689ed35ce5c5c891a1f7b1f4d1f56f6cf0143b74d8ee6484
 F src/pcache.h 1497ce1b823cf00094bb0cf3bac37b345937e6f910890c626b16512316d3abf5
 F src/pcache1.c 49516ad7718a3626f28f710fa7448ef1fce3c07fd169acbb4817341950264319
@@ -827,7 +827,7 @@ F src/test_windirent.h da2e5b73c32d09905fbdd00f27cd802212a32a58ead882736fe4f5eb7
 F src/test_window.c 6d80e11fba89a1796525e6f0048ff0c7789aa2c6b0b11c80827dc1437bd8ea72
 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
 F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
-F src/tokenize.c 3f703cacdab728d7741e5a6ac242006d74fe1c2754d4f03ed889d7253259bd68
+F src/tokenize.c 6fac7f14dd021fecfdd8be93c27937804c4b665d2da9e667a10e4b5f04c6e085
 F src/treeview.c 88aa39b754f5ef7214385c1bbbdd2f3dc20efafeed0cf590e8d1199b9c6e44aa
 F src/trigger.c 0bb986a5b96047fd597c6aac28588853df56064e576e6b81ba777ef2ccaac461
 F src/update.c 0e01aa6a3edf9ec112b33eb714b9016a81241497b1fb7c3e74332f4f71756508
@@ -2210,8 +2210,8 @@ F vsixtest/vsixtest.tcl 6195aba1f12a5e10efc2b8c0009532167be5e301abe5b31385638080
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 2c4bae3e68eea14a5edbc753a7a2d764924c95060aff95fa1d2141c11fa77fed
-R 1bcb173040dc70215ec3b6d0e2905929
+P 8781d7352b926129027f73d1fe21df78fcb6d21ab3caeefe0f829437c7c1250b
+R 33ad2ae364e02d05b491ddd0f2515c8c
 U drh
-Z 4734eb8c3c37dd8c83c589b63b01a613
+Z 0b901b3f54346f44cbd361c66879d520
 # Remove this line to create a well-formed Fossil manifest.
index b765932608d9edf5922cc405d0a4d423e28fd5a5..823da58ae3302b7c25c52a17e348544ea2d661d2 100644 (file)
@@ -1 +1 @@
-8781d7352b926129027f73d1fe21df78fcb6d21ab3caeefe0f829437c7c1250b
+3c7a5cc6d0d186e68a5885299f7474ad2e31b839af404a649dbc8f5b8f1d0a62
index 0106f5fc173052504793d2db1661db6e3953bd13..ae3422539fd2be655101956c5aa62cc907ac8809 100644 (file)
@@ -625,23 +625,196 @@ oneselect(A) ::= SELECT distinct(D) selcollist(W) from(X) where_opt(Y)
 }
 %endif
 
-//%type pipeline {Select*}
-//%destructor pipeline {sqlite3SelectDelete(pParse->db,$$);}
-
-oneselect(A) ::= pipeline.  {A = 0;}
-pipeline ::= FROM seltablist.
-pipeline ::= pipeline pipe pipejoinop nm dbnm as on_using.
-pipeline ::= pipeline pipe pipejoinop nm dbnm LP exprlist RP as on_using.
-pipeline ::= pipeline pipe pipejoinop LP select RP as on_using.
-pipeline ::= pipeline pipe pipejoinop LP seltablist RP as on_using.
-pipeline ::= pipeline pipe WHERE expr.
-pipeline ::= pipeline pipe AGGREGATE selcollist groupby_opt.
-pipeline ::= pipeline pipe SELECT selcollist.
-pipeline ::= pipeline pipe ORDER BY nexprlist.
-pipeline ::= pipeline pipe LIMIT expr.
-pipeline ::= pipeline pipe LIMIT expr OFFSET expr.
-pipeline ::= pipeline pipe AS nm.
-pipeline ::= pipeline pipe DISTINCT ON nexprlist.
+%ifndef SQLITE_OMIT_SUBQUERY
+%include {
+  SQLITE_NOINLINE SrcList *sqlite3SrcListAppendSubFrom(
+    Parse *pParse,           /* Parsing context */
+    SrcList *pFrom,          /* LHS of the FROM clause */
+    SrcList *pSubFrom,       /* New parenthesized sub-FROM to append */
+    Token *pAs,              /* AS-Name of the sub-FROM */
+    OnOrUsing *pOnUsing      /* ON or USING clause associated with the join */
+  ){
+    if( pFrom==0 && pAs->n==0 && pOnUsing->pOn==0 && pOnUsing->pUsing==0 ){
+      pFrom = pSubFrom;
+    }else if( ALWAYS(pSubFrom!=0) && pSubFrom->nSrc==1 ){
+      pFrom = sqlite3SrcListAppendFromTerm(pParse,pFrom,0,0,pAs,0,pOnUsing);
+      if( pFrom ){
+        SrcItem *pNew = &pFrom->a[pFrom->nSrc-1];
+        SrcItem *pOld = pSubFrom->a;
+        assert( pOld->fg.fixedSchema==0 );
+        pNew->zName = pOld->zName;
+        assert( pOld->fg.fixedSchema==0 );
+        if( pOld->fg.isSubquery ){
+          pNew->fg.isSubquery = 1;
+          pNew->u4.pSubq = pOld->u4.pSubq;
+          pOld->u4.pSubq = 0;
+          pOld->fg.isSubquery = 0;
+          assert( pNew->u4.pSubq!=0 && pNew->u4.pSubq->pSelect!=0 );
+          if( (pNew->u4.pSubq->pSelect->selFlags & SF_NestedFrom)!=0 ){
+            pNew->fg.isNestedFrom = 1;
+          }
+        }else{
+          pNew->u4.zDatabase = pOld->u4.zDatabase;
+          pOld->u4.zDatabase = 0;
+        }
+        if( pOld->fg.isTabFunc ){
+          pNew->u1.pFuncArg = pOld->u1.pFuncArg;
+          pOld->u1.pFuncArg = 0;
+          pOld->fg.isTabFunc = 0;
+          pNew->fg.isTabFunc = 1;
+        }
+        pOld->zName = 0;
+      }
+      sqlite3SrcListDelete(pParse->db, pSubFrom);
+    }else{
+      Select *pSubquery;
+      sqlite3SrcListShiftJoinType(pParse,pSubFrom);
+      pSubquery = sqlite3SelectNew(pParse,0,pSubFrom,0,0,0,0,SF_NestedFrom,0);
+      pFrom = sqlite3SrcListAppendFromTerm(pParse,pFrom,0,0,pAs,pSubquery,pOnUsing);
+    }
+    return pFrom;
+  }
+}
+%endif SQLITE_OMIT_SUBQUERY
+
+%ifndef SQLITE_OMIT_FROM_FIRST
+%include {
+  /* The Pipe object represents a pipe under construction.  It is a transient
+  ** object found only on the LALR(1) parser stack. */
+  typedef struct Pipe Pipe;
+  struct Pipe {
+    SrcList *pFrom;          /* The FROM clause */
+    ExprList *pProj;         /* The projection - list of columns to return */
+    ExprList *pOrderBy;      /* The ORDER BY clause */
+    ExprList *pGroupBy;      /* The GROUP BY clause */
+    Expr *pLimit;            /* The LIMIT or LIMIT/OFFSET clause */
+    Expr *pWhere;            /* The WHERE clause */
+    Expr *pHaving;           /* The HAVING clause */
+    int selFlags;            /* SF_DISTINCT or SF_ALL or 0 */
+    u8 bSeenAgg;             /* True if AGGREGATE has been seen */
+    Token sAs;               /* Value of a pending AS clause */
+  };
+
+  /* Delete a pipe object */
+  void sqlite3PipeDelete(sqlite3 *db, Pipe *p){
+    sqlite3SrcListDelete(db, p->pFrom);
+    sqlite3ExprListDelete(db, p->pProj);
+    sqlite3ExprListDelete(db, p->pOrderBy);
+    sqlite3ExprListDelete(db, p->pGroupBy);
+    sqlite3ExprDelete(db, p->pLimit);
+    sqlite3ExprDelete(db, p->pWhere);
+    sqlite3ExprDelete(db, p->pHaving);
+    sqlite3DbFree(db, p);
+  }
+
+  /* Generate a Select from the current content of a Pipe.  Reset the Pipe
+  ** to be empty, except do not remove the AS token if there is one and do
+  ** not delete the Pipe.
+  */
+  Select *sqlite3SelectFromPipe(Parse *pParse, Pipe *p){
+    Token sAs = p->sAs;
+    Select *pSel = sqlite3SelectNew(pParse, p->pProj, p->pFrom, p->pWhere,
+                                    p->pGroupBy, p->pHaving, p->pOrderBy,
+                                    p->selFlags, p->pLimit);
+    memset(p, 0, sizeof(*p));
+    p->sAs = sAs;
+    return pSel;
+  }
+
+  /* Take the current content of the pipe and make it "FROM <subquery>" pipe.
+  */
+  void sqlite3PipePush(Parse *pParse, Pipe *pPipe, int jointype){
+    Select *pSel = sqlite3SelectFromPipe(pParse, pPipe);
+    Token *pAs = pPipe->sAs.z!=0 ? &pPipe->sAs : 0;
+    SrcList *pFrom = pPipe->pFrom;
+    if( pFrom ) pFrom->a[pFrom->nSrc-1].fg.jointype = jointype;
+    pPipe->pFrom = sqlite3SrcListAppendFromTerm(pParse,0,0,0,pAs,pSel,0);
+    pPipe->sAs.z = 0;
+  }
+  
+}
+%type pipeline {Pipe*}
+%destructor pipeline {sqlite3PipeDelete(pParse->db,$$);}
+
+oneselect(A) ::= pipeline(X).  {
+  Pipe *pPipe = X;
+  Select *pSel = sqlite3SelectFromPipe(pParse,pPipe);
+  sqlite3DbFree(pParse->db, pPipe);
+  A = pSel; /*A-overwrites-X */
+}
+pipeline(A) ::= FROM seltablist(X). {
+  Pipe *pPipe = sqlite3DbMallocZero(pParse->db, sizeof(*pPipe));
+  A = pPipe;
+  if( pPipe ){
+    pPipe->pFrom = X;
+  }else{
+    sqlite3SrcListDelete(pParse->db, X);
+  }
+}
+pipeline(A) ::= pipeline(A) pipe pipejoinop(J) nm(Y) dbnm(D) as(Z) on_using(N). {
+  Pipe *p = A;
+  sqlite3PipePush(pParse, p, J);
+  p->pFrom = sqlite3SrcListAppendFromTerm(pParse, p->pFrom, &Y, &D, &Z, 0, &N);
+}
+pipeline(A) ::= pipeline(A) pipe 
+                pipejoinop(J) nm(Y) dbnm(D) LP exprlist(E) RP as(Z) on_using(N). {
+  Pipe *p = A;
+  sqlite3PipePush(pParse, p, J);
+  p->pFrom = sqlite3SrcListAppendFromTerm(pParse, p->pFrom, &Y, &D, &Z, 0, &N);
+  sqlite3SrcListFuncArgs(pParse, p->pFrom, E);
+}
+pipeline(A) ::= pipeline(A) pipe pipejoinop(J) LP select(S) RP as(Z) on_using(N). {
+  Pipe *p = A;
+  sqlite3PipePush(pParse, p, J);
+  p->pFrom = sqlite3SrcListAppendFromTerm(pParse,p->pFrom,0,0,&Z,S,&N);
+}  
+pipeline(A) ::= pipeline(A) pipe pipejoinop(J) LP seltablist(F) RP as(Z) on_using(N).{
+  Pipe *p = A;
+  sqlite3PipePush(pParse, p, J);
+  p->pFrom = sqlite3SrcListAppendSubFrom(pParse,p->pFrom,F,&Z,&N);
+}
+pipeline(A) ::= pipeline(A) pipe WHERE expr(W). {
+  Pipe *p = A;
+  if( p->bSeenAgg ){
+    p->pHaving = sqlite3ExprAnd(pParse, A->pHaving, W);
+  }else{
+    p->pWhere = sqlite3ExprAnd(pParse, A->pWhere, W);
+  }
+}
+pipeline(A) ::= pipeline(A) pipe HAVING expr(W). {
+  Pipe *p = A;
+  p->pHaving = sqlite3ExprAnd(pParse, A->pHaving, W);
+}
+//pipeline ::= pipeline pipe AGGREGATE selcollist groupby_opt.
+pipeline(A) ::= pipeline(A) pipe SELECT distinct(D) selcollist(W). {
+  Pipe *p = A;
+  if( p->pProj ) sqlite3PipePush(pParse, p, 0);
+  p->pProj = W;
+  p->selFlags = D;
+}
+pipeline(A) ::= pipeline(A) pipe ORDER BY sortlist(X). {
+  Pipe *p = A;
+  if( p->pOrderBy || p->pLimit ) sqlite3PipePush(pParse, p, 0);
+  p->pOrderBy = X;
+}
+pipeline(A) ::= pipeline(A) pipe LIMIT expr(X). {
+  Pipe *p = A;
+  Expr *pLimit = sqlite3PExpr(pParse,TK_LIMIT,X,0);
+  if( pLimit ){
+    sqlite3ExprDelete(pParse->db, p->pLimit);
+    p->pLimit = pLimit;
+  }
+}
+pipeline(A) ::= pipeline(A) pipe LIMIT expr(X) OFFSET expr(Y). {
+  Pipe *p = A;
+  Expr *pLimit = sqlite3PExpr(pParse,TK_LIMIT,X,Y);
+  if( pLimit ){
+    sqlite3ExprDelete(pParse->db, p->pLimit);
+    p->pLimit = pLimit;
+  }
+}
+pipeline(A) ::= pipeline(A) pipe AS nm(X).  {A->sAs = X;}
+//pipeline ::= pipeline pipe DISTINCT ON nexprlist.
 
 pipe ::= .
 pipe ::= PIPE.
@@ -655,7 +828,7 @@ pipejoinop(X) ::= JOIN_KW(A) nm(B) JOIN.
 pipejoinop(X) ::= JOIN_KW(A) nm(B) nm(C) JOIN.
                   {X = sqlite3JoinType(pParse,&A,&B,&C);/*X-overwrites-A*/}
 
-
+%endif FROM_first
 
 // Single row VALUES clause.
 //
@@ -765,44 +938,7 @@ seltablist(A) ::= stl_prefix(A) nm(Y) dbnm(D) LP exprlist(E) RP as(Z) on_using(N
     A = sqlite3SrcListAppendFromTerm(pParse,A,0,0,&Z,S,&N);
   }
   seltablist(A) ::= stl_prefix(A) LP seltablist(F) RP as(Z) on_using(N). {
-    if( A==0 && Z.n==0 && N.pOn==0 && N.pUsing==0 ){
-      A = F;
-    }else if( ALWAYS(F!=0) && F->nSrc==1 ){
-      A = sqlite3SrcListAppendFromTerm(pParse,A,0,0,&Z,0,&N);
-      if( A ){
-        SrcItem *pNew = &A->a[A->nSrc-1];
-        SrcItem *pOld = F->a;
-        assert( pOld->fg.fixedSchema==0 );
-        pNew->zName = pOld->zName;
-        assert( pOld->fg.fixedSchema==0 );
-        if( pOld->fg.isSubquery ){
-          pNew->fg.isSubquery = 1;
-          pNew->u4.pSubq = pOld->u4.pSubq;
-          pOld->u4.pSubq = 0;
-          pOld->fg.isSubquery = 0;
-          assert( pNew->u4.pSubq!=0 && pNew->u4.pSubq->pSelect!=0 );
-          if( (pNew->u4.pSubq->pSelect->selFlags & SF_NestedFrom)!=0 ){
-            pNew->fg.isNestedFrom = 1;
-          }
-        }else{
-          pNew->u4.zDatabase = pOld->u4.zDatabase;
-          pOld->u4.zDatabase = 0;
-        }
-        if( pOld->fg.isTabFunc ){
-          pNew->u1.pFuncArg = pOld->u1.pFuncArg;
-          pOld->u1.pFuncArg = 0;
-          pOld->fg.isTabFunc = 0;
-          pNew->fg.isTabFunc = 1;
-        }
-        pOld->zName = 0;
-      }
-      sqlite3SrcListDelete(pParse->db, F);
-    }else{
-      Select *pSubquery;
-      sqlite3SrcListShiftJoinType(pParse,F);
-      pSubquery = sqlite3SelectNew(pParse,0,F,0,0,0,0,SF_NestedFrom,0);
-      A = sqlite3SrcListAppendFromTerm(pParse,A,0,0,&Z,pSubquery,&N);
-    }
+    A = sqlite3SrcListAppendSubFrom(pParse,A,F,&Z,&N);
   }
 %endif  SQLITE_OMIT_SUBQUERY
 
index 65d1fbf350bc234de4d62b77b12ee86027ad71b3..661a68a59ce4ec2f8ddfa6b9142a7fd7d2db2376 100644 (file)
@@ -372,12 +372,17 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){
       }
     }
     case CC_PIPE: {
-      if( z[1]!='|' ){
-        *tokenType = TK_BITOR;
-        return 1;
-      }else{
+      if( z[1]=='|' ){
         *tokenType = TK_CONCAT;
         return 2;
+#ifdef TK_PIPE
+      }else if( z[1]=='>' ){
+        *tokenType = TK_PIPE;
+        return 2;
+#endif
+      }else{
+        *tokenType = TK_BITOR;
+        return 1;
       }
     }
     case CC_COMMA: {