From: drh Date: Tue, 18 Sep 2018 21:35:31 +0000 (+0000) Subject: In the Expr object, the Expr.eX field determines what value is stored in the X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=3b3c86ade21f42d7c08bfee302fc3507db41268a;p=thirdparty%2Fsqlite.git In the Expr object, the Expr.eX field determines what value is stored in the Expr.x union. This mostly works, but there are issues identified by valgrind. FossilOrigin-Name: 8849a463d67d79ec60c74a08835c176c08da651a82731558a1dceac2781cd75d --- diff --git a/manifest b/manifest index 97749237ef..3e59128139 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Merge\sall\srecent\strunk\senhancements. -D 2018-09-18T18:08:01.839 +C In\sthe\sExpr\sobject,\sthe\sExpr.eX\sfield\sdetermines\swhat\svalue\sis\sstored\sin\sthe\nExpr.x\sunion.\s\sThis\smostly\sworks,\sbut\sthere\sare\sissues\sidentified\sby\svalgrind. +D 2018-09-18T21:35:31.300 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 01e95208a78b57d056131382c493c963518f36da4c42b12a97eb324401b3a334 @@ -438,7 +438,7 @@ F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786 F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a F src/alter.c 2269dd2f37ba963fde4c51e9e83542f126c86a8e10357c17f48137c6bee5299b F src/analyze.c 3dc6b98cf007b005af89df165c966baaa48e8124f38c87b4d2b276fe7f0b9eb9 -F src/attach.c 4bd5b92633671d3e8ce431153ebb1893b50335818423b5373f3f27969f79769a +F src/attach.c 8b8e52590fca04bed868461aadc5d38de7542f005310ced863e032c83e1b1b6a F src/auth.c 32a5bbe3b755169ab6c66311c5225a3cd4f75a46c041f7fb117e0cbb68055114 F src/backup.c 78d3cecfbe28230a3a9a1793e2ead609f469be43e8f486ca996006be551857ab F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33 @@ -453,11 +453,11 @@ F src/ctime.c b157b01081f92442f8b0218ddb93ddce8ebddad36dbddeecfdd771561dd4f387 F src/date.c ebe1dc7c8a347117bb02570f1a931c62dd78f4a2b1b516f4837d45b7d6426957 F src/dbpage.c 4aa7f26198934dbd002e69418220eae3dbc71b010bbac32bd78faf86b52ce6c3 F src/dbstat.c edabb82611143727511a45ca0859b8cd037851ebe756ae3db289859dd18b6f91 -F src/delete.c 107e28d3ef8bd72fd11953374ca9107cd74e8b09c3ded076a6048742d26ce7d2 -F src/expr.c 83c279eda8f3a888141e2432633051f644db68fdb7882c12e0ef00894d7f8ade +F src/delete.c 07a7ecf18a64478be7241cbb332bc26321586384c750e47fb566f678c5aee512 +F src/expr.c c7d6ce81a4363fc3be403ac05a86a6ea3ed63c5c6668d9c774fd4bb714f07911 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c f59253c0be4b1e9dfcb073b6d6d6ab83090ae50c08b5c113b76013c4b157cd6a -F src/func.c 7c288b4ce309b5a8b8473514b88e1f8e69a80134509a8c0db8e39c858e367e7f +F src/func.c 82aeef69505b67197a476836d44cc16c1a434ee53481f23cffb70a75a1bcbc7a F src/global.c 9bf034fd560bdd514715170ed8460bb7f823cec113f0569ef3f18a20c7ccd128 F src/hash.c a12580e143f10301ed5166ea4964ae2853d3905a511d4e0c44497245c7ce1f7a F src/hash.h ab34c5c54a9e9de2e790b24349ba5aab3dbb4fd4 @@ -491,7 +491,7 @@ F src/os_win.c 070cdbb400097c6cda54aa005356095afdc2f3ee691d17192c54724ef146a971 F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a F src/pager.c a0d8f686ef64549ad5b356fd30429bd9ee7a06dd42b4d6faa096352ff26b1c5b F src/pager.h ecc554a55bc55d1c4ba5e17137b72e238e00bd81e72ff2662d8b9c8c10ae3963 -F src/parse.y 4118dbf9c37c410e5c4775c033b1aaf67ac8ff7965df7a4bb429dd5db2dbe374 +F src/parse.y 15eeb0ead639555727ed81fc61bd8e28968e9379bc074ae9cb48b95c79b50f0d F src/pcache.c 135ef0bc6fb2e3b7178d49ab5c9176254c8a691832c1bceb1156b2fbdd0869bd F src/pcache.h 072f94d29281cffd99e46c1539849f248c4b56ae7684c1f36626797fee375170 F src/pcache1.c 716975564c15eb6679e97f734cec1bfd6c16ac3d4010f05f1f8e509fc7d19880 @@ -500,14 +500,14 @@ F src/pragma.h bb83728944b42f6d409c77f5838a8edbdb0fe83046c5496ffc9602b40340a324 F src/prepare.c f8e260d940a0e08494c0f30744521b2f832d7263eca9d02b050cea0ba144b097 F src/printf.c 0f1177cf1dd4d7827bf64d840768514ec76409abecaca9e8b577dbd065150381 F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384 -F src/resolve.c 352c6af1a99441206ff62a6f7429dbf537827f42c428639695220b9c8639e33b +F src/resolve.c 301eadb8bf5afcd0b673d4db3c85c179334e19970af276187932e5b0a97b90ec F src/rowset.c d977b011993aaea002cab3e0bb2ce50cf346000dff94e944d547b989f4b1fe93 -F src/select.c 8afcc2b56a6ef76717bb59b6109cd3de0f6fae2803894d6f806640c0aa24dfac +F src/select.c af9efbeea79c7eaa21f51c2640f9f8e21d1c9dbcea236d5af68bb8f0313d9b1e F src/shell.c.in 6e0aad854be738a5d0368940459399be211e9ac43aebe92bb9ed46cfe38d0e1f F src/sqlite.h.in 4b4c2f2daeeed4412ba9d81bc78092c69831fe6eda4f0ae5bf951da51a8dccec F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 305adca1b5da4a33ce2db5bd236935768e951d5651bfe5560ed55cfcdbce6a63 -F src/sqliteInt.h 83ee9b55db521b70294b2858872e69b96d0a4810d8221796def3e99cca5ee663 +F src/sqliteInt.h 0aed6451d241a43814ac54d93f7d2b8645826ffa9e35e7289240dd38e967b813 F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34 @@ -566,7 +566,7 @@ F src/test_window.c cdae419fdcea5bad6dcd9368c685abdad6deb59e9fc8b84b153de513d394 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c F src/tokenize.c 9f55961518f77793edd56eee860ecf035d4370ebbb0726ad2f6cada6637fd16b -F src/treeview.c e7a7f90552bb418533cdd0309b5eb71d4effa50165b880fc8c2001e613577e5f +F src/treeview.c b6f459831c544d697e4b38471b98b972d9dd3b4611d0e8c6338632c7ad926d12 F src/trigger.c d3d78568f37fb2e6cdcc2d1e7b60156f15b0b600adec55b83c5d42f6cad250bd F src/update.c 682f112c49247d2fe5950c9fe2226046c6bc497cf114f74d58766926914216ff F src/upsert.c 0dd81b40206841814d46942a7337786932475f085716042d0cb2fc7791bf8ca4 @@ -586,11 +586,11 @@ F src/vtab.c 8665561f244c137a2d17b5c3e5910d7303054fe841c5d510e53f23beb0089594 F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c 3f4f653daf234fe713edbcbca3fec2350417d159d28801feabc702a22c4e213f F src/wal.h 606292549f5a7be50b6227bd685fa76e3a4affad71bb8ac5ce4cb5c79f6a176a -F src/walker.c ba7225773931760cf60bf22f34d0cce2588df7ce5ce0f215a52eb88234b55ac4 -F src/where.c 2019126801437944c38cc62a99491e98591460b7cc07ab57eb66165f710a289b +F src/walker.c b2d62136868f1f939a7778bdce8b372bb4e314862cd2b33bd1ec9614eef0b44c +F src/where.c c90c392c7c8c8ea3e36592dba9800cee35eeadd36c512ab904da8245c334b148 F src/whereInt.h b90ef9b9707ef750eab2a7a080c48fb4900315033274689def32d0cf5a81ebe4 -F src/wherecode.c 4f88f5b39ad4aeb5bdd47a546d74149bb902ef49ca9f02a45b2a5bd2dd70b6bd -F src/whereexpr.c eb462ebe085f6cbb6bdda797a041fbd7e3724586203344043d1088a2117d8e44 +F src/wherecode.c 75a3b20d28a5c9f88e6c6dd9037ffeacdd786feaba8013245f7d8576a093dcf4 +F src/whereexpr.c c08b5afce2e7b9046c65f5edc3302888d79e8c541907a97df089c135895b25f0 F src/window.c 4b503da928dace3e845b891381a4d98eeb8c5744313ae3643df8d8d21fdcca65 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd @@ -1767,7 +1767,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 81f25d5c84e4d2d0cd3c6a7c105c7c93d310218feeea4e023dbc32e7e96b2a52 e461cb281959d8517296e3e4e934eba8206770b1a592cd7655b6567268da1634 -R da6eee78fa2fbbeca2d219d82da2f3c5 +P 655f065404e08083ad5eb9b22a036f410b46eb5eb2bcfb0fbc953b4e152c95e7 +R cc9722e20d1a4071193f4dca3fb58785 U drh -Z d193f19d8649854bc581fb0b4773613d +Z bb5fe9a1a876c7e1afc567f393930991 diff --git a/manifest.uuid b/manifest.uuid index 8575e39ee7..2102aadff2 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -655f065404e08083ad5eb9b22a036f410b46eb5eb2bcfb0fbc953b4e152c95e7 \ No newline at end of file +8849a463d67d79ec60c74a08835c176c08da651a82731558a1dceac2781cd75d \ No newline at end of file diff --git a/src/attach.c b/src/attach.c index 42ae536942..9d77d83c47 100644 --- a/src/attach.c +++ b/src/attach.c @@ -564,10 +564,15 @@ int sqlite3FixExpr( } } if( ExprHasProperty(pExpr, EP_TokenOnly|EP_Leaf) ) break; - if( ExprHasProperty(pExpr, EP_xIsSelect) ){ - if( sqlite3FixSelect(pFix, pExpr->x.pSelect) ) return 1; - }else{ - if( sqlite3FixExprList(pFix, pExpr->x.pList) ) return 1; + switch( pExpr->eX ){ + case EX_Select: { + if( sqlite3FixSelect(pFix, pExpr->x.pSelect) ) return 1; + break; + } + case EX_List: { + if( sqlite3FixExprList(pFix, pExpr->x.pList) ) return 1; + break; + } } if( sqlite3FixExpr(pFix, pExpr->pRight) ){ return 1; diff --git a/src/delete.c b/src/delete.c index 746f6725b9..cd6254aae8 100644 --- a/src/delete.c +++ b/src/delete.c @@ -185,9 +185,7 @@ Expr *sqlite3LimitWhere( pEList = sqlite3ExprListAppend(pParse, pEList, p); } pLhs = sqlite3PExpr(pParse, TK_VECTOR, 0, 0); - if( pLhs ){ - pLhs->x.pList = sqlite3ExprListDup(db, pEList, 0); - } + sqlite3PExprAddExprList(pParse, pLhs, pEList); } } diff --git a/src/expr.c b/src/expr.c index 063627505b..0053c9fbd6 100644 --- a/src/expr.c +++ b/src/expr.c @@ -48,7 +48,7 @@ char sqlite3ExprAffinity(Expr *pExpr){ if( pExpr->flags & EP_Generic ) return 0; op = pExpr->op; if( op==TK_SELECT ){ - assert( pExpr->flags&EP_xIsSelect ); + assert( pExpr->eX==EX_Select ); return sqlite3ExprAffinity(pExpr->x.pSelect->pEList->a[0].pExpr); } if( op==TK_REGISTER ) op = pExpr->op2; @@ -62,7 +62,7 @@ char sqlite3ExprAffinity(Expr *pExpr){ return sqlite3TableColumnAffinity(pExpr->pTab, pExpr->iColumn); } if( op==TK_SELECT_COLUMN ){ - assert( pExpr->pLeft->flags&EP_xIsSelect ); + assert( pExpr->pLeft->eX==EX_Select ); return sqlite3ExprAffinity( pExpr->pLeft->x.pSelect->pEList->a[pExpr->iColumn].pExpr ); @@ -108,7 +108,7 @@ Expr *sqlite3ExprAddCollateString(Parse *pParse, Expr *pExpr, const char *zC){ Expr *sqlite3ExprSkipCollate(Expr *pExpr){ while( pExpr && ExprHasProperty(pExpr, EP_Skip) ){ if( ExprHasProperty(pExpr, EP_Unlikely) ){ - assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); + assert( pExpr->eX==EX_List ); assert( pExpr->x.pList->nExpr>0 ); assert( pExpr->op==TK_FUNCTION ); pExpr = pExpr->x.pList->a[0].pExpr; @@ -167,12 +167,10 @@ CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){ p = p->pLeft; }else{ Expr *pNext = p->pRight; - /* The Expr.x union is never used at the same time as Expr.pRight */ - assert( p->x.pList==0 || p->pRight==0 ); /* p->flags holds EP_Collate and p->pLeft->flags does not. And ** p->x.pSelect cannot. So if p->x.pLeft exists, it must hold at ** least one EP_Collate. Thus the following two ALWAYS. */ - if( p->x.pList!=0 && ALWAYS(!ExprHasProperty(p, EP_xIsSelect)) ){ + if( p->eX==EX_List ){ int i; for(i=0; ALWAYS(ix.pList->nExpr); i++){ if( ExprHasProperty(p->x.pList->a[i].pExpr, EP_Collate) ){ @@ -260,7 +258,7 @@ static char comparisonAffinity(Expr *pExpr){ aff = sqlite3ExprAffinity(pExpr->pLeft); if( pExpr->pRight ){ aff = sqlite3CompareAffinity(pExpr->pRight, aff); - }else if( ExprHasProperty(pExpr, EP_xIsSelect) ){ + }else if( pExpr->eX==EX_Select ){ aff = sqlite3CompareAffinity(pExpr->x.pSelect->pEList->a[0].pExpr, aff); }else if( aff==0 ){ aff = SQLITE_AFF_BLOB; @@ -439,7 +437,7 @@ Expr *sqlite3ExprForVectorField( ){ Expr *pRet; if( pVector->op==TK_SELECT ){ - assert( pVector->flags & EP_xIsSelect ); + assert( pVector->eX==EX_Select ); /* The TK_SELECT_COLUMN Expr node: ** ** pLeft: pVector containing TK_SELECT. Not deleted. @@ -682,9 +680,9 @@ static void exprSetHeight(Expr *p){ int nHeight = 0; heightOfExpr(p->pLeft, &nHeight); heightOfExpr(p->pRight, &nHeight); - if( ExprHasProperty(p, EP_xIsSelect) ){ + if( p->eX==EX_Select ){ heightOfSelect(p->x.pSelect, &nHeight); - }else if( p->x.pList ){ + }else if( p->eX==EX_List ){ heightOfExprList(p->x.pList, &nHeight); p->flags |= EP_Propagate & sqlite3ExprListFlags(p->x.pList); } @@ -700,7 +698,7 @@ static void exprSetHeight(Expr *p){ ** Expr.flags. */ void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p){ - if( pParse->nErr ) return; + if( p==0 || pParse->nErr ) return; exprSetHeight(p); sqlite3ExprCheckHeight(pParse, p->nHeight); } @@ -720,7 +718,7 @@ int sqlite3SelectExprHeight(Select *p){ ** Expr.flags. */ void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p){ - if( p && p->x.pList && !ExprHasProperty(p, EP_xIsSelect) ){ + if( p && p->eX==EX_List ){ p->flags |= EP_Propagate & sqlite3ExprListFlags(p->x.pList); } } @@ -873,9 +871,11 @@ Expr *sqlite3PExpr( ** do a memory allocation failure) then delete the pSelect object. */ void sqlite3PExprAddSelect(Parse *pParse, Expr *pExpr, Select *pSelect){ - if( pExpr ){ + if( pExpr && pSelect ){ + assert( pExpr->eX==EX_None ); + pExpr->eX = EX_Select; pExpr->x.pSelect = pSelect; - ExprSetProperty(pExpr, EP_xIsSelect|EP_Subquery); + ExprSetProperty(pExpr, EP_Subquery); sqlite3ExprSetHeightAndFlags(pParse, pExpr); }else{ assert( pParse->db->mallocFailed ); @@ -883,6 +883,22 @@ void sqlite3PExprAddSelect(Parse *pParse, Expr *pExpr, Select *pSelect){ } } +/* +** Add ExprList to the Expr.x.pList field. Or, if pExpr is NULL (due +** do a memory allocation failure) then delete the pSelect object. +*/ +void sqlite3PExprAddExprList(Parse *pParse, Expr *pExpr, ExprList *pList){ + if( pExpr && pList ){ + assert( pExpr->eX==EX_None ); + pExpr->eX = EX_List; + pExpr->x.pList = pList; + /* sqlite3ExprSetHeightAndFlags(pParse, pExpr); // done by caller */ + }else{ + assert( pParse->db->mallocFailed ); + sqlite3ExprListDelete(pParse->db, pList); + } +} + /* ** If the expression is always either TRUE or FALSE (respectively), @@ -956,9 +972,12 @@ Expr *sqlite3ExprFunction( if( pList && pList->nExpr > pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG] ){ sqlite3ErrorMsg(pParse, "too many arguments on function %T", pToken); } - pNew->x.pList = pList; + assert( pNew->eX==EX_None ); + if( pList ){ + pNew->eX = EX_List; + pNew->x.pList = pList; + } ExprSetProperty(pNew, EP_HasFunc); - assert( !ExprHasProperty(pNew, EP_xIsSelect) ); sqlite3ExprSetHeightAndFlags(pParse, pNew); if( eDistinct==SF_Distinct ) ExprSetProperty(pNew, EP_Distinct); return pNew; @@ -1052,11 +1071,13 @@ static SQLITE_NOINLINE void sqlite3ExprDeleteNN(sqlite3 *db, Expr *p){ assert( p!=0 ); /* Sanity check: Assert that the IntValue is non-negative if it exists */ assert( !ExprHasProperty(p, EP_IntValue) || p->u.iValue>=0 ); + assert( p->eX!=EX_Select || p->x.pSelect!=0 ); + assert( p->eX!=EX_List || p->x.pList!=0 ); #ifdef SQLITE_DEBUG if( ExprHasProperty(p, EP_Leaf) && !ExprHasProperty(p, EP_TokenOnly) ){ assert( p->pLeft==0 ); assert( p->pRight==0 ); - assert( p->x.pSelect==0 ); + assert( p->eX==EX_None ); } if( !ExprHasProperty(p, EP_TokenOnly) ){ assert( p->op!=TK_FUNCTION || p->pLeft==0 ); @@ -1066,8 +1087,7 @@ static SQLITE_NOINLINE void sqlite3ExprDeleteNN(sqlite3 *db, Expr *p){ assert( p->pWin==0 || p->pLeft==0 ); assert( p->pWin==0 || p->pTab==0 ); assert( p->pWin==0 || p->op==TK_FUNCTION ); - assert( p->pWin==0 || !ExprHasProperty(p, EP_xIsSelect) ); - assert( p->pTab==0 || (p->pRight==0 && p->x.pSelect==0) ); + assert( p->pTab==0 || (p->pRight==0 && p->eX==EX_None) ); } #endif if( !ExprHasProperty(p, (EP_TokenOnly|EP_Leaf)) ){ @@ -1076,10 +1096,17 @@ static SQLITE_NOINLINE void sqlite3ExprDeleteNN(sqlite3 *db, Expr *p){ if( p->pLeft && p->op!=TK_SELECT_COLUMN ) sqlite3ExprDeleteNN(db, p->pLeft); if( p->pRight ){ sqlite3ExprDeleteNN(db, p->pRight); - }else if( ExprHasProperty(p, EP_xIsSelect) ){ - sqlite3SelectDelete(db, p->x.pSelect); }else{ - sqlite3ExprListDelete(db, p->x.pList); + switch( p->eX ){ + case EX_Select: { + sqlite3SelectDelete(db, p->x.pSelect); + break; + } + case EX_List: { + sqlite3ExprListDelete(db, p->x.pList); + break; + } + } } if( !ExprHasProperty(p, EP_Reduced) ){ sqlite3WindowDelete(db, p->pWin); @@ -1259,6 +1286,8 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){ pNew->flags &= ~(EP_Reduced|EP_TokenOnly|EP_Static|EP_MemToken); pNew->flags |= nStructSize & (EP_Reduced|EP_TokenOnly); pNew->flags |= staticFlag; + assert( pNew->eX==p->eX ); + assert( pNew->eV==p->eV ); /* Copy the p->u.zToken string, if any. */ if( nToken ){ @@ -1268,10 +1297,19 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){ if( 0==((p->flags|pNew->flags) & (EP_TokenOnly|EP_Leaf)) ){ /* Fill in the pNew->x.pSelect or pNew->x.pList member. */ - if( ExprHasProperty(p, EP_xIsSelect) ){ - pNew->x.pSelect = sqlite3SelectDup(db, p->x.pSelect, dupFlags); - }else{ - pNew->x.pList = sqlite3ExprListDup(db, p->x.pList, dupFlags); + switch( p->eX ){ + case EX_Select: { + assert( pNew->eX==EX_Select ); + pNew->x.pSelect = sqlite3SelectDup(db, p->x.pSelect, dupFlags); + if( pNew->x.pSelect==0 ) pNew->eX = EX_None; + break; + } + case EX_List: { + assert( pNew->eX==EX_List ); + pNew->x.pList = sqlite3ExprListDup(db, p->x.pList, dupFlags); + if( pNew->x.pList==0 ) pNew->eX = EX_None; + break; + } } } @@ -1965,7 +2003,7 @@ static int exprNodeIsConstantOrGroupBy(Walker *pWalker, Expr *pExpr){ } /* Check if pExpr is a sub-select. If so, consider it variable. */ - if( ExprHasProperty(pExpr, EP_xIsSelect) ){ + if( pExpr->eX==EX_Select ){ pWalker->eCode = 0; return WRC_Abort; } @@ -2171,8 +2209,10 @@ static Select *isCandidateForInOpt(Expr *pX){ ExprList *pEList; Table *pTab; int i; - if( !ExprHasProperty(pX, EP_xIsSelect) ) return 0; /* Not a subquery */ - if( ExprHasProperty(pX, EP_VarSelect) ) return 0; /* Correlated subq */ + if( pX->eX!=EX_Select ) return 0; /* Not a subquery */ + if( ExprHasProperty(pX, EP_VarSelect) ){ + return 0; /* Correlated subq */ + } p = pX->x.pSelect; if( p->pPrior ) return 0; /* Not a compound SELECT */ if( p->selFlags & (SF_Distinct|SF_Aggregate) ){ @@ -2230,7 +2270,7 @@ static void sqlite3SetHasNullFlag(Vdbe *v, int iCur, int regHasNull){ static int sqlite3InRhsIsConstant(Expr *pIn){ Expr *pLHS; int res; - assert( !ExprHasProperty(pIn, EP_xIsSelect) ); + assert( pIn->eX!=EX_Select ); pLHS = pIn->pLeft; pIn->pLeft = 0; res = sqlite3ExprIsConstant(pIn); @@ -2341,7 +2381,7 @@ int sqlite3FindInIndex( ** or not NULL is actually possible (it may not be, for example, due ** to NOT NULL constraints in the schema). If no NULL values are possible, ** set prRhsHasNull to 0 before continuing. */ - if( prRhsHasNull && (pX->flags & EP_xIsSelect) ){ + if( prRhsHasNull && pX->eX==EX_Select ){ int i; ExprList *pEList = pX->x.pSelect->pEList; for(i=0; inExpr; i++){ @@ -2494,8 +2534,8 @@ int sqlite3FindInIndex( ** the IN operator so return IN_INDEX_NOOP. */ if( eType==0 - && (inFlags & IN_INDEX_NOOP_OK) - && !ExprHasProperty(pX, EP_xIsSelect) + && (inFlags & IN_INDEX_NOOP_OK)!=0 + && pX->eX==EX_List && (!sqlite3InRhsIsConstant(pX) || pX->x.pList->nExpr<=2) ){ eType = IN_INDEX_NOOP; @@ -2510,7 +2550,7 @@ int sqlite3FindInIndex( eType = IN_INDEX_EPH; if( inFlags & IN_INDEX_LOOP ){ pParse->nQueryLoop = 0; - if( pX->pLeft->iColumn<0 && !ExprHasProperty(pX, EP_xIsSelect) ){ + if( pX->pLeft->iColumn<0 && pX->eX==EX_List ){ eType = IN_INDEX_ROWID; } }else if( prRhsHasNull ){ @@ -2543,7 +2583,7 @@ int sqlite3FindInIndex( static char *exprINAffinity(Parse *pParse, Expr *pExpr){ Expr *pLeft = pExpr->pLeft; int nVal = sqlite3ExprVectorSize(pLeft); - Select *pSelect = (pExpr->flags & EP_xIsSelect) ? pExpr->x.pSelect : 0; + Select *pSelect = (pExpr->eX==EX_Select) ? pExpr->x.pSelect : 0; char *zRet; assert( pExpr->op==TK_IN ); @@ -2591,7 +2631,7 @@ void sqlite3SubselectError(Parse *pParse, int nActual, int nExpect){ */ void sqlite3VectorErrorMsg(Parse *pParse, Expr *pExpr){ #ifndef SQLITE_OMIT_SUBQUERY - if( pExpr->flags & EP_xIsSelect ){ + if( pExpr->eX==EX_Select ){ sqlite3SubselectError(pParse, pExpr->x.pSelect->pEList->nExpr, 1); }else #endif @@ -2683,7 +2723,8 @@ int sqlite3CodeSubselect( pExpr->iTable, (isRowid?0:nVal)); pKeyInfo = isRowid ? 0 : sqlite3KeyInfoAlloc(pParse->db, nVal, 1); - if( ExprHasProperty(pExpr, EP_xIsSelect) ){ + assert( pExpr->eX==EX_Select || pExpr->eX==EX_List ); + if( pExpr->eX==EX_Select ){ /* Case 1: expr IN (SELECT ...) ** ** Generate code to write the results of the select into the temporary @@ -2812,7 +2853,7 @@ int sqlite3CodeSubselect( testcase( pExpr->op==TK_EXISTS ); testcase( pExpr->op==TK_SELECT ); assert( pExpr->op==TK_EXISTS || pExpr->op==TK_SELECT ); - assert( ExprHasProperty(pExpr, EP_xIsSelect) ); + assert( pExpr->eX==EX_Select ); pSel = pExpr->x.pSelect; ExplainQueryPlan((pParse, 1, "%sSCALAR SUBQUERY", @@ -2869,7 +2910,7 @@ int sqlite3CodeSubselect( */ int sqlite3ExprCheckIN(Parse *pParse, Expr *pIn){ int nVector = sqlite3ExprVectorSize(pIn->pLeft); - if( (pIn->flags & EP_xIsSelect) ){ + if( pIn->eX==EX_Select ){ if( nVector!=pIn->x.pSelect->pEList->nExpr ){ sqlite3SubselectError(pParse, pIn->x.pSelect->pEList->nExpr, nVector); return 1; @@ -2999,7 +3040,7 @@ static void sqlite3ExprCodeIN( int r2, regToFree; int regCkNull = 0; int ii; - assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); + assert( pExpr->eX==EX_List ); if( destIfNull!=destIfFalse ){ regCkNull = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp3(v, OP_BitAnd, rLhs, rLhs, regCkNull); @@ -3637,7 +3678,7 @@ expr_code_doover: ** out of the inner loop, even if that means an extra OP_Copy. */ return sqlite3ExprCodeAtInit(pParse, pExpr, -1); } - assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); + assert( pExpr->eX==EX_List || pExpr->eX==EX_None ); if( ExprHasProperty(pExpr, EP_TokenOnly) ){ pFarg = 0; }else{ @@ -3946,8 +3987,8 @@ expr_code_doover: Expr *pX; /* The X expression */ Expr *pTest = 0; /* X==Ei (form A) or just Ei (form B) */ - assert( !ExprHasProperty(pExpr, EP_xIsSelect) && pExpr->x.pList ); - assert(pExpr->x.pList->nExpr > 0); + assert( pExpr->eX==EX_List ); + assert( pExpr->x.pList->nExpr > 0); pEList = pExpr->x.pList; aListelem = pEList->a; nExpr = pEList->nExpr; @@ -4279,7 +4320,7 @@ static void exprCodeBetween( memset(&compRight, 0, sizeof(Expr)); memset(&exprAnd, 0, sizeof(Expr)); - assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); + assert( pExpr->eX==EX_List ); exprX = *pExpr->pLeft; exprAnd.op = TK_AND; exprAnd.pLeft = &compLeft; @@ -4741,11 +4782,13 @@ int sqlite3ExprCompare(Parse *pParse, Expr *pA, Expr *pB, int iTab){ } if( (pA->flags & EP_Distinct)!=(pB->flags & EP_Distinct) ) return 2; if( ALWAYS((combinedFlags & EP_TokenOnly)==0) ){ - if( combinedFlags & EP_xIsSelect ) return 2; + if( pA->eX==EX_Select || pA->eX!=pB->eX ) return 2; if( (combinedFlags & EP_FixedCol)==0 && sqlite3ExprCompare(pParse, pA->pLeft, pB->pLeft, iTab) ) return 2; if( sqlite3ExprCompare(pParse, pA->pRight, pB->pRight, iTab) ) return 2; - if( sqlite3ExprListCompare(pA->x.pList, pB->x.pList, iTab) ) return 2; + if( pA->eX==EX_List ){ + if( sqlite3ExprListCompare(pA->x.pList, pB->x.pList, iTab) ) return 2; + } assert( (combinedFlags & EP_Reduced)==0 ); if( pA->op!=TK_STRING && pA->op!=TK_TRUEFALSE ){ if( pA->iColumn!=pB->iColumn ) return 2; @@ -5200,14 +5243,14 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){ u8 enc = ENC(pParse->db); i = addAggInfoFunc(pParse->db, pAggInfo); if( i>=0 ){ - assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); + assert( pExpr->eX==EX_List || pExpr->eX==EX_None ); pItem = &pAggInfo->aFunc[i]; pItem->pExpr = pExpr; pItem->iMem = ++pParse->nMem; assert( !ExprHasProperty(pExpr, EP_IntValue) ); pItem->pFunc = sqlite3FindFunction(pParse->db, pExpr->u.zToken, - pExpr->x.pList ? pExpr->x.pList->nExpr : 0, enc, 0); + pExpr->eX==EX_List ? pExpr->x.pList->nExpr : 0, enc, 0); if( pExpr->flags & EP_Distinct ){ pItem->iDistinct = pParse->nTab++; }else{ diff --git a/src/func.c b/src/func.c index 0504a8f026..9cc744965a 100644 --- a/src/func.c +++ b/src/func.c @@ -1848,7 +1848,7 @@ int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){ if( pExpr->op!=TK_FUNCTION || !pExpr->x.pList ){ return 0; } - assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); + assert( pExpr->eX==EX_List ); nExpr = pExpr->x.pList->nExpr; pDef = sqlite3FindFunction(db, pExpr->u.zToken, nExpr, SQLITE_UTF8, 0); if( NEVER(pDef==0) || (pDef->funcFlags & SQLITE_FUNC_LIKE)==0 ){ diff --git a/src/parse.y b/src/parse.y index f2cb072948..aaa2f91787 100644 --- a/src/parse.y +++ b/src/parse.y @@ -936,10 +936,10 @@ idlist(A) ::= nm(Y). /* memset(p, 0, sizeof(Expr)); */ p->op = (u8)op; p->affinity = 0; + p->eX = EX_None; p->flags = EP_Leaf; p->iAgg = -1; p->pLeft = p->pRight = 0; - p->x.pList = 0; p->pAggInfo = 0; p->pTab = 0; p->op2 = 0; @@ -1052,11 +1052,7 @@ term(A) ::= CTIME_KW(OP). { expr(A) ::= LP nexprlist(X) COMMA expr(Y) RP. { ExprList *pList = sqlite3ExprListAppend(pParse, X, Y); A = sqlite3PExpr(pParse, TK_VECTOR, 0, 0); - if( A ){ - A->x.pList = pList; - }else{ - sqlite3ExprListDelete(pParse->db, pList); - } + sqlite3PExprAddExprList(pParse, A, pList); } expr(A) ::= expr(A) AND(OP) expr(Y). {A=sqlite3PExpr(pParse,@OP,A,Y);} @@ -1143,11 +1139,7 @@ expr(A) ::= expr(A) between_op(N) expr(X) AND expr(Y). [BETWEEN] { ExprList *pList = sqlite3ExprListAppend(pParse,0, X); pList = sqlite3ExprListAppend(pParse,pList, Y); A = sqlite3PExpr(pParse, TK_BETWEEN, A, 0); - if( A ){ - A->x.pList = pList; - }else{ - sqlite3ExprListDelete(pParse->db, pList); - } + sqlite3PExprAddExprList(pParse, A, pList); if( N ) A = sqlite3PExpr(pParse, TK_NOT, A, 0); } %ifndef SQLITE_OMIT_SUBQUERY @@ -1195,12 +1187,8 @@ expr(A) ::= expr(A) between_op(N) expr(X) AND expr(Y). [BETWEEN] { A = sqlite3PExpr(pParse, N ? TK_NE : TK_EQ, A, pRHS); }else{ A = sqlite3PExpr(pParse, TK_IN, A, 0); - if( A ){ - A->x.pList = Y; - sqlite3ExprSetHeightAndFlags(pParse, A); - }else{ - sqlite3ExprListDelete(pParse->db, Y); - } + sqlite3PExprAddExprList(pParse, A, Y); + sqlite3ExprSetHeightAndFlags(pParse, A); if( N ) A = sqlite3PExpr(pParse, TK_NOT, A, 0); } } @@ -1231,13 +1219,8 @@ expr(A) ::= expr(A) between_op(N) expr(X) AND expr(Y). [BETWEEN] { /* CASE expressions */ expr(A) ::= CASE case_operand(X) case_exprlist(Y) case_else(Z) END. { A = sqlite3PExpr(pParse, TK_CASE, X, 0); - if( A ){ - A->x.pList = Z ? sqlite3ExprListAppend(pParse,Y,Z) : Y; - sqlite3ExprSetHeightAndFlags(pParse, A); - }else{ - sqlite3ExprListDelete(pParse->db, Y); - sqlite3ExprDelete(pParse->db, Z); - } + sqlite3PExprAddExprList(pParse,A,Z ? sqlite3ExprListAppend(pParse,Y,Z) : Y); + sqlite3ExprSetHeightAndFlags(pParse, A); } %type case_exprlist {ExprList*} %destructor case_exprlist {sqlite3ExprListDelete(pParse->db, $$);} diff --git a/src/resolve.c b/src/resolve.c index 9fb4d4c63f..6b2111af29 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -430,8 +430,7 @@ static int lookupName( if( zAs!=0 && sqlite3StrICmp(zAs, zCol)==0 ){ Expr *pOrig; assert( pExpr->pLeft==0 && pExpr->pRight==0 ); - assert( pExpr->x.pList==0 ); - assert( pExpr->x.pSelect==0 ); + assert( pExpr->eX==EX_None ); pOrig = pEList->a[j].pExpr; if( (pNC->ncFlags&NC_AllowAgg)==0 && ExprHasProperty(pOrig, EP_Agg) ){ sqlite3ErrorMsg(pParse, "misuse of aliased aggregate %s", zAs); @@ -701,8 +700,8 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ /* Resolve function names */ case TK_FUNCTION: { - ExprList *pList = pExpr->x.pList; /* The argument list */ - int n = pList ? pList->nExpr : 0; /* Number of arguments */ + ExprList *pList; /* The argument list */ + int n; /* Number of arguments */ int no_such_func = 0; /* True if no such function exists */ int wrong_num_args = 0; /* True if wrong number of arguments */ int is_agg = 0; /* True if is an aggregate function */ @@ -711,7 +710,14 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ FuncDef *pDef; /* Information about the function */ u8 enc = ENC(pParse->db); /* The database encoding */ - assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); + assert( pExpr->eX==EX_List || pExpr->eX==EX_None ); + if( pExpr->eX==EX_List ){ + pList = pExpr->x.pList; + n = pList->nExpr; + }else{ + pList = 0; + n = 0; + } zId = pExpr->u.zToken; nId = sqlite3Strlen30(zId); pDef = sqlite3FindFunction(pParse->db, zId, n, enc, 0); @@ -876,7 +882,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ #endif case TK_IN: { testcase( pExpr->op==TK_IN ); - if( ExprHasProperty(pExpr, EP_xIsSelect) ){ + if( pExpr->eX==EX_Select ){ int nRef = pNC->nRef; notValid(pParse, pNC, "subqueries", NC_IsCheck|NC_PartIdx|NC_IdxExpr); sqlite3WalkSelect(pWalker, pExpr->x.pSelect); diff --git a/src/select.c b/src/select.c index bc5960fe49..17ba72c76d 100644 --- a/src/select.c +++ b/src/select.c @@ -1736,7 +1736,7 @@ static const char *columnTypeImpl( NameContext sNC; Select *pS = pExpr->x.pSelect; Expr *p = pS->pEList->a[0].pExpr; - assert( ExprHasProperty(pExpr, EP_xIsSelect) ); + assert( pExpr->eX==EX_Select ); sNC.pSrcList = pS->pSrc; sNC.pNext = pNC; sNC.pParse = pNC->pParse; @@ -3472,10 +3472,15 @@ static Expr *substExpr( } pExpr->pLeft = substExpr(pSubst, pExpr->pLeft); pExpr->pRight = substExpr(pSubst, pExpr->pRight); - if( ExprHasProperty(pExpr, EP_xIsSelect) ){ - substSelect(pSubst, pExpr->x.pSelect, 1); - }else{ - substExprList(pSubst, pExpr->x.pList); + switch( pExpr->eX ){ + case EX_Select: { + substSelect(pSubst, pExpr->x.pSelect, 1); + break; + } + case EX_List: { + substExprList(pSubst, pExpr->x.pList); + break; + } } } return pExpr; @@ -5242,8 +5247,8 @@ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){ for(pFunc=pAggInfo->aFunc, i=0; inFunc; i++, pFunc++){ if( pFunc->iDistinct>=0 ){ Expr *pE = pFunc->pExpr; - assert( !ExprHasProperty(pE, EP_xIsSelect) ); - if( pE->x.pList==0 || pE->x.pList->nExpr!=1 ){ + assert( pE->eX==EX_List || pE->eX==EX_None ); + if( pE->eX==EX_None || pE->x.pList->nExpr!=1 ){ sqlite3ErrorMsg(pParse, "DISTINCT aggregates must have exactly one " "argument"); pFunc->iDistinct = -1; @@ -5266,7 +5271,8 @@ static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){ struct AggInfo_func *pF; for(i=0, pF=pAggInfo->aFunc; inFunc; i++, pF++){ ExprList *pList = pF->pExpr->x.pList; - assert( !ExprHasProperty(pF->pExpr, EP_xIsSelect) ); + assert( pF->pExpr->eX==EX_List || pF->pExpr->eX==EX_None ); + assert( pF->pExpr->eX==EX_List || pList==0 ); sqlite3VdbeAddOp2(v, OP_AggFinal, pF->iMem, pList ? pList->nExpr : 0); sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF); } @@ -5296,7 +5302,7 @@ static void updateAccumulator(Parse *pParse, int regAcc, AggInfo *pAggInfo){ int addrNext = 0; int regAgg; ExprList *pList = pF->pExpr->x.pList; - assert( !ExprHasProperty(pF->pExpr, EP_xIsSelect) ); + assert( pF->pExpr->eX==EX_List || pF->pExpr->eX==EX_None ); if( pList ){ nArg = pList->nExpr; regAgg = sqlite3GetTempRange(pParse, nArg); @@ -6186,10 +6192,11 @@ int sqlite3Select( minMaxFlag = WHERE_ORDERBY_NORMAL; } for(i=0; ix.pList); - sNC.ncFlags &= ~NC_InAggFunc; + if( sAggInfo.aFunc[i].pExpr->eX==EX_List ){ + sNC.ncFlags |= NC_InAggFunc; + sqlite3ExprAnalyzeAggList(&sNC, sAggInfo.aFunc[i].pExpr->x.pList); + sNC.ncFlags &= ~NC_InAggFunc; + } } sAggInfo.mxReg = pParse->nMem; if( db->mallocFailed ) goto select_end; diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 74438b5abc..5779f4d3c3 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -2419,6 +2419,8 @@ typedef int ynVar; struct Expr { u8 op; /* Operation performed by this node */ char affinity; /* The affinity of the column or 0 if not a column */ + u8 eV; /* Which element of v-union is used */ + u8 eX; /* Which element of x-union is used */ u32 flags; /* Various flags. EP_* See below */ union { char *zToken; /* Token value. Zero terminated and dequoted */ @@ -2466,6 +2468,20 @@ struct Expr { #endif }; +/* +** Allowed values for the Expr.eV and Expr.eX fields: +*/ +#define EV_None 0 /* Expr.v is not used */ +#define EV_Left 1 /* Expr.v.pLeft */ +#define EV_Vector 2 /* Expr.v.pVector */ +#define EV_Win 3 /* Expr.v.pWin */ + +#define EX_None 0 /* Expr.x is not used */ +#define EX_Right 1 /* Expr.x.pRight */ +#define EX_List 2 /* Expr.x.pList */ +#define EX_Select 3 /* Expr.x.pSelect */ +#define EX_Tab 4 /* Expr.x.pTab */ + /* ** The following are the meanings of bits in the Expr.flags field. */ @@ -2480,7 +2496,7 @@ struct Expr { #define EP_Collate 0x000100 /* Tree contains a TK_COLLATE operator */ #define EP_Generic 0x000200 /* Ignore COLLATE or affinity on this tree */ #define EP_IntValue 0x000400 /* Integer value contained in u.iValue */ -#define EP_xIsSelect 0x000800 /* x.pSelect is valid (otherwise x.pList is) */ +/* 0x000800 -- Available for reuse */ #define EP_Skip 0x001000 /* COLLATE, AS, or UNLIKELY */ #define EP_Reduced 0x002000 /* Expr struct EXPR_REDUCEDSIZE bytes only */ #define EP_TokenOnly 0x004000 /* Expr struct EXPR_TOKENONLYSIZE bytes only */ @@ -3794,6 +3810,7 @@ Expr *sqlite3Expr(sqlite3*,int,const char*); void sqlite3ExprAttachSubtrees(sqlite3*,Expr*,Expr*,Expr*); Expr *sqlite3PExpr(Parse*, int, Expr*, Expr*); void sqlite3PExprAddSelect(Parse*, Expr*, Select*); +void sqlite3PExprAddExprList(Parse*, Expr*, ExprList*); Expr *sqlite3ExprAnd(sqlite3*,Expr*, Expr*); Expr *sqlite3ExprFunction(Parse*,ExprList*, Token*, int); void sqlite3ExprAssignVarNumber(Parse*, Expr*, u32); diff --git a/src/treeview.c b/src/treeview.c index cde776d0fa..713fc13b5b 100644 --- a/src/treeview.c +++ b/src/treeview.c @@ -532,10 +532,15 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){ case TK_IN: { sqlite3TreeViewLine(pView, "IN flags=0x%x", pExpr->flags); sqlite3TreeViewExpr(pView, pExpr->pLeft, 1); - if( ExprHasProperty(pExpr, EP_xIsSelect) ){ - sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0); - }else{ - sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, 0); + switch( pExpr->eX ){ + case EX_Select: { + sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0); + break; + } + case EX_List: { + sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, 0); + break; + } } break; } diff --git a/src/walker.c b/src/walker.c index b3d4cd805d..4c6701f1c7 100644 --- a/src/walker.c +++ b/src/walker.c @@ -49,10 +49,17 @@ static SQLITE_NOINLINE int walkExpr(Walker *pWalker, Expr *pExpr){ if( pExpr->pRight ){ pExpr = pExpr->pRight; continue; - }else if( ExprHasProperty(pExpr, EP_xIsSelect) ){ - if( sqlite3WalkSelect(pWalker, pExpr->x.pSelect) ) return WRC_Abort; - }else if( pExpr->x.pList ){ - if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort; + }else{ + switch( pExpr->eX ){ + case EX_Select: { + if( sqlite3WalkSelect(pWalker, pExpr->x.pSelect) ) return WRC_Abort; + break; + } + case EX_List: { + if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort; + break; + } + } } #ifndef SQLITE_OMIT_WINDOWFUNC if( !ExprHasProperty(pExpr, EP_Reduced) && pExpr->pWin ){ diff --git a/src/where.c b/src/where.c index d8d577d521..2a195f8aff 100644 --- a/src/where.c +++ b/src/where.c @@ -2330,7 +2330,8 @@ static int whereRangeVectorLen( CollSeq *pColl; /* Comparison collation sequence */ Expr *pLhs = pTerm->pExpr->pLeft->x.pList->a[i].pExpr; Expr *pRhs = pTerm->pExpr->pRight; - if( pRhs->flags & EP_xIsSelect ){ + assert( pRhs->eX==EX_Select || pRhs->eX==EX_List ); + if( pRhs->eX==EX_Select ){ pRhs = pRhs->x.pSelect->pEList->a[i].pExpr; }else{ pRhs = pRhs->x.pList->a[i].pExpr; @@ -2488,24 +2489,29 @@ static int whereLoopAddBtreeIndex( if( eOp & WO_IN ){ Expr *pExpr = pTerm->pExpr; - if( ExprHasProperty(pExpr, EP_xIsSelect) ){ - /* "x IN (SELECT ...)": TUNING: the SELECT returns 25 rows */ - int i; - nIn = 46; assert( 46==sqlite3LogEst(25) ); - - /* The expression may actually be of the form (x, y) IN (SELECT...). - ** In this case there is a separate term for each of (x) and (y). - ** However, the nIn multiplier should only be applied once, not once - ** for each such term. The following loop checks that pTerm is the - ** first such term in use, and sets nIn back to 0 if it is not. */ - for(i=0; inLTerm-1; i++){ - if( pNew->aLTerm[i] && pNew->aLTerm[i]->pExpr==pExpr ) nIn = 0; + switch( pExpr->eX ){ + case EX_Select: { + /* "x IN (SELECT ...)": TUNING: the SELECT returns 25 rows */ + int i; + nIn = 46; assert( 46==sqlite3LogEst(25) ); + + /* The expression may actually be of the form (x, y) IN (SELECT...). + ** In this case there is a separate term for each of (x) and (y). + ** However, the nIn multiplier should only be applied once, not once + ** for each such term. The following loop checks that pTerm is the + ** first such term in use, and sets nIn back to 0 if it is not. */ + for(i=0; inLTerm-1; i++){ + if( pNew->aLTerm[i] && pNew->aLTerm[i]->pExpr==pExpr ) nIn = 0; + } + break; + } + case EX_List: { + /* "x IN (value, value, ...)" */ + nIn = sqlite3LogEst(pExpr->x.pList->nExpr); + assert( nIn>0 ); /* RHS always has 2 or more terms... The parser + ** changes "x IN (?)" into "x=?". */ + break; } - }else if( ALWAYS(pExpr->x.pList && pExpr->x.pList->nExpr) ){ - /* "x IN (value, value, ...)" */ - nIn = sqlite3LogEst(pExpr->x.pList->nExpr); - assert( nIn>0 ); /* RHS always has 2 or more terms... The parser - ** changes "x IN (?)" into "x=?". */ } if( pProbe->hasStat1 ){ LogEst M, logK, safetyMargin; @@ -2620,7 +2626,7 @@ static int whereLoopAddBtreeIndex( if( nInMul==0 && pProbe->nSample && pNew->u.btree.nEq<=pProbe->nSampleCol - && ((eOp & WO_IN)==0 || !ExprHasProperty(pTerm->pExpr, EP_xIsSelect)) + && ((eOp & WO_IN)==0 || pTerm->pExpr->eX==EX_List) && OptimizationEnabled(db, SQLITE_Stat34) ){ Expr *pExpr = pTerm->pExpr; diff --git a/src/wherecode.c b/src/wherecode.c index 65cbc4ca2c..84174ea595 100644 --- a/src/wherecode.c +++ b/src/wherecode.c @@ -435,7 +435,9 @@ static Expr *removeUnindexableInClauseTerms( } sqlite3ExprListDelete(db, pOrigRhs); sqlite3ExprListDelete(db, pOrigLhs); + assert( pNew->pLeft->eX==EX_List ); pNew->pLeft->x.pList = pLhs; + if( pLhs==0 ) pNew->pLeft->eX = EX_None; pNew->x.pSelect->pEList = pRhs; if( pLhs && pLhs->nExpr==1 ){ /* Take care here not to generate a TK_VECTOR containing only a @@ -538,7 +540,7 @@ static int codeEqualityTerm( if( pLoop->aLTerm[i]->pExpr==pX ) nEq++; } - if( (pX->flags & EP_xIsSelect)==0 || pX->x.pSelect->pEList->nExpr==1 ){ + if( pX->eX!=EX_Select || pX->x.pSelect->pEList->nExpr==1 ){ eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, 0); }else{ sqlite3 *db = pParse->db; @@ -734,7 +736,7 @@ static int codeAllEqualityTerms( } } if( pTerm->eOperator & WO_IN ){ - if( pTerm->pExpr->flags & EP_xIsSelect ){ + if( pTerm->pExpr->eX==EX_Select ){ /* No affinity ever needs to be (or should be) applied to a value ** from the RHS of an "? IN (SELECT ...)" expression. The ** sqlite3FindInIndex() routine has already ensured that the @@ -1074,7 +1076,7 @@ static void codeExprOrVector(Parse *pParse, Expr *p, int iReg, int nReg){ assert( nReg>0 ); if( p && sqlite3ExprIsVector(p) ){ #ifndef SQLITE_OMIT_SUBQUERY - if( (p->flags & EP_xIsSelect) ){ + if( p->eX==EX_Select ){ Vdbe *v = pParse->pVdbe; int iSelect = sqlite3CodeSubselect(pParse, p, 0, 0); sqlite3VdbeAddOp3(v, OP_Copy, iSelect, iReg, nReg-1); @@ -2194,7 +2196,7 @@ Bitmask sqlite3WhereCodeOneLoopStart( if( pAlt==0 ) continue; if( pAlt->wtFlags & (TERM_CODED) ) continue; if( (pAlt->eOperator & WO_IN) - && (pAlt->pExpr->flags & EP_xIsSelect) + && (pAlt->pExpr->eX==EX_Select) && (pAlt->pExpr->x.pSelect->pEList->nExpr>1) ){ continue; diff --git a/src/whereexpr.c b/src/whereexpr.c index 808c0d21c7..16d441c52b 100644 --- a/src/whereexpr.c +++ b/src/whereexpr.c @@ -860,18 +860,20 @@ static void exprAnalyzeOrTerm( assert( pLeft!=0 ); pDup = sqlite3ExprDup(db, pLeft, 0); pNew = sqlite3PExpr(pParse, TK_IN, pDup, 0); - if( pNew ){ + if( pNew && pList ){ int idxNew; transferJoinMarkings(pNew, pExpr); - assert( !ExprHasProperty(pNew, EP_xIsSelect) ); + assert( pNew->eX==EX_None ); + pNew->eX = EX_List; pNew->x.pList = pList; idxNew = whereClauseInsert(pWC, pNew, TERM_VIRTUAL|TERM_DYNAMIC); testcase( idxNew==0 ); exprAnalyze(pSrc, pWC, idxNew); - /* pTerm = &pWC->a[idxTerm]; // would be needed if pTerm where used again */ + /* pTerm = &pWC->a[idxTerm]; // would be needed if pTerm used again */ markTermAsChild(pWC, idxNew, idxTerm); }else{ sqlite3ExprListDelete(db, pList); + sqlite3ExprDelete(db, pNew); } } } @@ -1055,10 +1057,15 @@ static void exprAnalyze( if( op==TK_IN ){ assert( pExpr->pRight==0 ); if( sqlite3ExprCheckIN(pParse, pExpr) ) return; - if( ExprHasProperty(pExpr, EP_xIsSelect) ){ - pTerm->prereqRight = exprSelectUsage(pMaskSet, pExpr->x.pSelect); - }else{ - pTerm->prereqRight = sqlite3WhereExprListUsage(pMaskSet, pExpr->x.pList); + switch( pExpr->eX ){ + case EX_Select: { + pTerm->prereqRight = exprSelectUsage(pMaskSet, pExpr->x.pSelect); + break; + } + case EX_List: { + pTerm->prereqRight = sqlite3WhereExprListUsage(pMaskSet,pExpr->x.pList); + break; + } } }else if( op==TK_ISNULL ){ pTerm->prereqRight = 0; @@ -1329,8 +1336,7 @@ static void exprAnalyze( && (pExpr->op==TK_EQ || pExpr->op==TK_IS) && (nLeft = sqlite3ExprVectorSize(pExpr->pLeft))>1 && sqlite3ExprVectorSize(pExpr->pRight)==nLeft - && ( (pExpr->pLeft->flags & EP_xIsSelect)==0 - || (pExpr->pRight->flags & EP_xIsSelect)==0) + && ( pExpr->pLeft->eX!=EX_Select || pExpr->pRight->eX!=EX_Select ) ){ int i; for(i=0; ipRight ){ mask |= sqlite3WhereExprUsageNN(pMaskSet, p->pRight); assert( p->x.pList==0 ); - }else if( ExprHasProperty(p, EP_xIsSelect) ){ - if( ExprHasProperty(p, EP_VarSelect) ) pMaskSet->bVarSelect = 1; - mask |= exprSelectUsage(pMaskSet, p->x.pSelect); - }else if( p->x.pList ){ - mask |= sqlite3WhereExprListUsage(pMaskSet, p->x.pList); + }else{ + switch( p->eX ){ + case EX_Select: { + if( ExprHasProperty(p, EP_VarSelect) ) pMaskSet->bVarSelect = 1; + mask |= exprSelectUsage(pMaskSet, p->x.pSelect); + break; + } + case EX_List: { + mask |= sqlite3WhereExprListUsage(pMaskSet, p->x.pList); + break; + } + } } return mask; }