From: drh <> Date: Mon, 26 Aug 2024 12:26:26 +0000 (+0000) Subject: Reduce rules added to the grammar. Kinda works, but there are still bugs. X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=7267c510acda87d3d8b449180f0367a2de0adc7f;p=thirdparty%2Fsqlite.git Reduce rules added to the grammar. Kinda works, but there are still bugs. FossilOrigin-Name: 3c7a5cc6d0d186e68a5885299f7474ad2e31b839af404a649dbc8f5b8f1d0a62 --- diff --git a/manifest b/manifest index f8c8ea58e0..2794be4a10 100644 --- 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. diff --git a/manifest.uuid b/manifest.uuid index b765932608..823da58ae3 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -8781d7352b926129027f73d1fe21df78fcb6d21ab3caeefe0f829437c7c1250b +3c7a5cc6d0d186e68a5885299f7474ad2e31b839af404a649dbc8f5b8f1d0a62 diff --git a/src/parse.y b/src/parse.y index 0106f5fc17..ae3422539f 100644 --- a/src/parse.y +++ b/src/parse.y @@ -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 " 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 diff --git a/src/tokenize.c b/src/tokenize.c index 65d1fbf350..661a68a59c 100644 --- a/src/tokenize.c +++ b/src/tokenize.c @@ -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: {