From: drh Date: Tue, 6 May 2014 15:28:56 +0000 (+0000) Subject: Experimental changes that reduce the size of Expr objects from 72 to 64 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=refs%2Fheads%2Fsmaller-expr;p=thirdparty%2Fsqlite.git Experimental changes that reduce the size of Expr objects from 72 to 64 bytes each on x64 and from 48 to 44 bytes each on x32. FossilOrigin-Name: 8ad0a123a2046e4bf95b4f9c28f26221afb3fc43 --- diff --git a/manifest b/manifest index 089fba14e7..29b28c7a0b 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C When\sbuilding\sfor\sWindows\s8.0\susing\sVisual\sStudio\s2013,\smake\ssure\sthe\scross-compilation\snative\slibrary\spath\sis\sset\scorrectly. -D 2014-05-05T22:43:17.621 +C Experimental\schanges\sthat\sreduce\sthe\ssize\sof\sExpr\sobjects\sfrom\s72\sto\s64\nbytes\seach\son\sx64\sand\sfrom\s48\sto\s44\sbytes\seach\son\sx32. +D 2014-05-06T15:28:56.475 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in dd2b1aba364ff9b05de41086f74407f285c57670 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -160,7 +160,7 @@ F sqlite3.1 3d8b83c91651f53472ca17599dae3457b8b89494 F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a F src/alter.c b00900877f766f116f9e16116f1ccacdc21d82f1 F src/analyze.c 3596f863bb80126fe56ba217df5932749271efc8 -F src/attach.c 3801129015ef59d76bf23c95ef9b0069d18a0c52 +F src/attach.c a1ada8e4177827c5873aa356b933f2d4d1293a9a F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34 F src/backup.c a729e63cf5cd1829507cb7b8e89f99b95141bb53 F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb @@ -174,10 +174,10 @@ F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac F src/ctime.c 0231df905e2c4abba4483ee18ffc05adc321df2a F src/date.c 593c744b2623971e45affd0bde347631bdfa4625 F src/delete.c bcf8f72126cea80fc3d5bc5494cf19b3f8935aaf -F src/expr.c 4f9e497c66e2f25a4d139357a778c84d5713207c +F src/expr.c 78326e5d1fa27a88a6c037fabc6c63359695e937 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c 5269ef07b100763134f71b889327c333bd0989cf -F src/func.c 2945bb2c4cdc0ac43733046285a4434310be1811 +F src/func.c 863735228a1ff6e225a8904169644a4fd40df43c F src/global.c 1d7bb7ea8254ae6a68ed9bfaf65fcb3d1690b486 F src/hash.c d139319967164f139c8d1bb8a11b14db9c4ba3cd F src/hash.h 8890a25af81fb85a9ad7790d32eedab4b994da22 @@ -210,7 +210,7 @@ F src/os_win.c 485d06a93965f306c7281fca0937829292367234 F src/os_win.h 057344a6720b4c8405d9bd98f58cb37a6ee46c25 F src/pager.c ab62a24218d87dda1be641f6c5ad291bff78fd94 F src/pager.h ffd5607f7b3e4590b415b007a4382f693334d428 -F src/parse.y 22d6a074e5f5a7258947a1dc55a9bf946b765dd0 +F src/parse.y b9adfa13ce569c12aa157c8ebc5fdc670f1a0acb F src/pcache.c d8eafac28290d4bb80332005435db44991d07fc2 F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222 F src/pcache1.c 102e6f5a2fbc646154463eb856d1fd716867b64c @@ -218,14 +218,14 @@ F src/pragma.c 810ef31ccfaa233201dcf100637a9777cc24e897 F src/prepare.c 677521ab7132615a8a26107a1d1c3132f44ae337 F src/printf.c e5a0005f8b3de21f85da6a709d2fbee76775bf4b F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece -F src/resolve.c 273d5f47c4e2c05b2d3d2bffeda939551ab59e66 +F src/resolve.c 06b706383c66ba05f515014fb7f37e84a22fdf96 F src/rowset.c a9c9aae3234b44a6d7c6f5a3cadf90dce1e627be -F src/select.c 089c4d46f067a5cccae93524c6377f981ba99bd9 +F src/select.c 109d659ed3f949e11de6bc74afe6a56b68ff3b80 F src/shell.c 2afe7a7154e97be0c74c5feacf09626bda8493be F src/sqlite.h.in bde98816e1ba0c9ffef50afe7b32f4e5a8f54fe0 F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc -F src/sqliteInt.h b2947801eccefd7ba3e5f14e1353289351a83cf3 +F src/sqliteInt.h 23b03ab00dac71f2402eb9fd977aaed735d42c0c F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e @@ -293,8 +293,8 @@ F src/vdbetrace.c 6f52bc0c51e144b7efdcfb2a8f771167a8816767 F src/vtab.c 21b932841e51ebd7d075e2d0ad1415dce8d2d5fd F src/wal.c 76e7fc6de229bea8b30bb2539110f03a494dc3a8 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 -F src/walker.c 11edb74d587bc87b33ca96a5173e3ec1b8389e45 -F src/where.c 91dfd382273c3f67fcdc0ac4728f9140f91c6ab3 +F src/walker.c 4a73ee39c361017532530ef18066d7e87e0d9bd0 +F src/where.c b8df0204d0e7bfe735f7892d8e96493652d607ac F src/whereInt.h 6804c2e5010378568c2bb1350477537755296a46 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 @@ -1168,7 +1168,10 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01 F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff -P 9a06773acc181e981f61f476a8e56417b98beba9 -R e91b1cf1dddb5793408fd6de2be74034 -U mistachkin -Z b713eaa9517cf3b104e3dc82bdd65124 +P c1ab9092e29bc9d172c1f1a3becbcc83b79f2080 +R 4b8f36fa136ae7cf835aa3d588ac1c25 +T *branch * smaller-expr +T *sym-smaller-expr * +T -sym-trunk * +U drh +Z 8672a4e9e0a77fa3f766205961da49e1 diff --git a/manifest.uuid b/manifest.uuid index af81c8bc82..c76d32477c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c1ab9092e29bc9d172c1f1a3becbcc83b79f2080 \ No newline at end of file +8ad0a123a2046e4bf95b4f9c28f26221afb3fc43 \ No newline at end of file diff --git a/src/attach.c b/src/attach.c index 89050fd9dc..e51c20ee1e 100644 --- a/src/attach.c +++ b/src/attach.c @@ -524,14 +524,14 @@ int sqlite3FixExpr( } } if( ExprHasProperty(pExpr, EP_TokenOnly) ) break; - if( ExprHasProperty(pExpr, EP_xIsSelect) ){ + if( ExprUsesRight(pExpr) ){ + if( sqlite3FixExpr(pFix, pExpr->x.pRight) ) return 1; + }else if( ExprHasProperty(pExpr, EP_xIsSelect) ){ if( sqlite3FixSelect(pFix, pExpr->x.pSelect) ) return 1; }else{ + assert( ExprHasProperty(pExpr, EP_xIsList) ); if( sqlite3FixExprList(pFix, pExpr->x.pList) ) return 1; } - if( sqlite3FixExpr(pFix, pExpr->pRight) ){ - return 1; - } pExpr = pExpr->pLeft; } return 0; diff --git a/src/expr.c b/src/expr.c index 08c121e386..c1e30cfd01 100644 --- a/src/expr.c +++ b/src/expr.c @@ -36,7 +36,7 @@ char sqlite3ExprAffinity(Expr *pExpr){ if( pExpr->flags & EP_Generic ) return SQLITE_AFF_NONE; op = pExpr->op; if( op==TK_SELECT ){ - assert( pExpr->flags&EP_xIsSelect ); + assert( ExprHasProperty(pExpr, EP_xIsSelect) ); return sqlite3ExprAffinity(pExpr->x.pSelect->pEList->a[0].pExpr); } #ifndef SQLITE_OMIT_CAST @@ -96,7 +96,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( ExprHasProperty(pExpr, EP_xIsList) ); assert( pExpr->x.pList->nExpr>0 ); assert( pExpr->op==TK_FUNCTION ); pExpr = pExpr->x.pList->a[0].pExpr; @@ -148,8 +148,8 @@ CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){ if( p->flags & EP_Collate ){ if( ALWAYS(p->pLeft) && (p->pLeft->flags & EP_Collate)!=0 ){ p = p->pLeft; - }else{ - p = p->pRight; + }else if( ExprUsesRight(p) ){ + p = p->x.pRight; } }else{ break; @@ -200,8 +200,8 @@ static char comparisonAffinity(Expr *pExpr){ pExpr->op==TK_NE || pExpr->op==TK_IS || pExpr->op==TK_ISNOT ); assert( pExpr->pLeft ); aff = sqlite3ExprAffinity(pExpr->pLeft); - if( pExpr->pRight ){ - aff = sqlite3CompareAffinity(pExpr->pRight, aff); + if( ExprUsesRight(pExpr) ){ + aff = sqlite3CompareAffinity(pExpr->x.pRight, aff); }else if( ExprHasProperty(pExpr, EP_xIsSelect) ){ aff = sqlite3CompareAffinity(pExpr->x.pSelect->pEList->a[0].pExpr, aff); }else if( !aff ){ @@ -359,10 +359,12 @@ static void heightOfSelect(Select *p, int *pnHeight){ static void exprSetHeight(Expr *p){ int nHeight = 0; heightOfExpr(p->pLeft, &nHeight); - heightOfExpr(p->pRight, &nHeight); - if( ExprHasProperty(p, EP_xIsSelect) ){ + if( ExprUsesRight(p) ){ + heightOfExpr(p->x.pRight, &nHeight); + }else if( ExprHasProperty(p, EP_xIsSelect) ){ heightOfSelect(p->x.pSelect, &nHeight); }else{ + assert( ExprHasProperty(p, EP_xIsList) ); heightOfExprList(p->x.pList, &nHeight); } p->nHeight = nHeight + 1; @@ -489,8 +491,8 @@ void sqlite3ExprAttachSubtrees( sqlite3ExprDelete(db, pRight); }else{ if( pRight ){ - pRoot->pRight = pRight; - pRoot->flags |= EP_Collate & pRight->flags; + pRoot->x.pRight = pRight; + pRoot->flags |= (EP_Collate & pRight->flags); } if( pLeft ){ pRoot->pLeft = pLeft; @@ -593,7 +595,7 @@ Expr *sqlite3ExprFunction(Parse *pParse, ExprList *pList, Token *pToken){ return 0; } pNew->x.pList = pList; - assert( !ExprHasProperty(pNew, EP_xIsSelect) ); + ExprSetProperty(pNew, EP_xIsList); sqlite3ExprSetHeight(pParse, pNew); return pNew; } @@ -690,14 +692,16 @@ void sqlite3ExprDelete(sqlite3 *db, Expr *p){ /* Sanity check: Assert that the IntValue is non-negative if it exists */ assert( !ExprHasProperty(p, EP_IntValue) || p->u.iValue>=0 ); if( !ExprHasProperty(p, EP_TokenOnly) ){ - /* The Expr.x union is never used at the same time as Expr.pRight */ - assert( p->x.pList==0 || p->pRight==0 ); sqlite3ExprDelete(db, p->pLeft); - sqlite3ExprDelete(db, p->pRight); - if( ExprHasProperty(p, EP_MemToken) ) sqlite3DbFree(db, p->u.zToken); - if( ExprHasProperty(p, EP_xIsSelect) ){ + if( ExprHasProperty(p, EP_MemToken) ){ + sqlite3DbFree(db, p->u.zToken); + } + if( ExprUsesRight(p) ){ + sqlite3ExprDelete(db, p->x.pRight); + }else if( ExprHasProperty(p, EP_xIsSelect) ){ sqlite3SelectDelete(db, p->x.pSelect); }else{ + assert( ExprHasProperty(p, EP_xIsList) ); sqlite3ExprListDelete(db, p->x.pList); } } @@ -766,7 +770,6 @@ static int dupedExprStructSize(Expr *p, int flags){ if( p->pLeft || p->x.pList ){ nSize = EXPR_REDUCEDSIZE | EP_Reduced; }else{ - assert( p->pRight==0 ); nSize = EXPR_TOKENONLYSIZE | EP_TokenOnly; } } @@ -804,7 +807,10 @@ static int dupedExprSize(Expr *p, int flags){ if( p ){ nByte = dupedExprNodeSize(p, flags); if( flags&EXPRDUP_REDUCE ){ - nByte += dupedExprSize(p->pLeft, flags) + dupedExprSize(p->pRight, flags); + nByte += dupedExprSize(p->pLeft, flags); + if( ExprUsesRight(p) ){ + nByte += dupedExprSize(p->x.pRight, flags); + } } } return nByte; @@ -814,7 +820,7 @@ static int dupedExprSize(Expr *p, int flags){ ** This function is similar to sqlite3ExprDup(), except that if pzBuffer ** is not NULL then *pzBuffer is assumed to point to a buffer large enough ** to store the copy of expression p, the copies of p->u.zToken -** (if applicable), and the copies of the p->pLeft and p->pRight expressions, +** (if applicable), and the copies of the p->pLeft and p->x.pRight expressions, ** if any. Before returning, *pzBuffer is set to the first byte passed the ** portion of the buffer copied into by this function. */ @@ -874,17 +880,20 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int flags, u8 **pzBuffer){ /* Fill in the pNew->x.pSelect or pNew->x.pList member. */ if( ExprHasProperty(p, EP_xIsSelect) ){ pNew->x.pSelect = sqlite3SelectDup(db, p->x.pSelect, isReduced); - }else{ + }else if( ExprHasProperty(p, EP_xIsList) ){ pNew->x.pList = sqlite3ExprListDup(db, p->x.pList, isReduced); } } - /* Fill in pNew->pLeft and pNew->pRight. */ + /* Fill in pNew->pLeft and pNew->x.pRight. */ if( ExprHasProperty(pNew, EP_Reduced|EP_TokenOnly) ){ zAlloc += dupedExprNodeSize(p, flags); if( ExprHasProperty(pNew, EP_Reduced) ){ pNew->pLeft = exprDup(db, p->pLeft, EXPRDUP_REDUCE, &zAlloc); - pNew->pRight = exprDup(db, p->pRight, EXPRDUP_REDUCE, &zAlloc); + if( ExprUsesRight(p) ){ + assert( ExprUsesRight(p) ); + pNew->x.pRight = exprDup(db, p->x.pRight, EXPRDUP_REDUCE, &zAlloc); + } } if( pzBuffer ){ *pzBuffer = zAlloc; @@ -892,7 +901,10 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int flags, u8 **pzBuffer){ }else{ if( !ExprHasProperty(p, EP_TokenOnly) ){ pNew->pLeft = sqlite3ExprDup(db, p->pLeft, 0); - pNew->pRight = sqlite3ExprDup(db, p->pRight, 0); + if( ExprUsesRight(p) ){ + assert( ExprUsesRight(pNew) ); + pNew->x.pRight = sqlite3ExprDup(db, p->x.pRight, 0); + } } } @@ -2530,8 +2542,9 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ case TK_NE: case TK_EQ: { r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); - r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); - codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, + assert( ExprUsesRight(pExpr) ); + r2 = sqlite3ExprCodeTemp(pParse, pExpr->x.pRight, ®Free2); + codeCompare(pParse, pExpr->pLeft, pExpr->x.pRight, op, r1, r2, inReg, SQLITE_STOREP2); assert(TK_LT==OP_Lt); testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt); assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le); @@ -2548,9 +2561,10 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ testcase( op==TK_IS ); testcase( op==TK_ISNOT ); r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); - r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); + assert( ExprUsesRight(pExpr) ); + r2 = sqlite3ExprCodeTemp(pParse, pExpr->x.pRight, ®Free2); op = (op==TK_IS) ? TK_EQ : TK_NE; - codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, + codeCompare(pParse, pExpr->pLeft, pExpr->x.pRight, op, r1, r2, inReg, SQLITE_STOREP2 | SQLITE_NULLEQ); VdbeCoverageIf(v, op==TK_EQ); VdbeCoverageIf(v, op==TK_NE); @@ -2582,7 +2596,8 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ assert( TK_RSHIFT==OP_ShiftRight ); testcase( op==TK_RSHIFT ); assert( TK_CONCAT==OP_Concat ); testcase( op==TK_CONCAT ); r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); - r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); + assert( ExprUsesRight(pExpr) ); + r2 = sqlite3ExprCodeTemp(pParse, pExpr->x.pRight, ®Free2); sqlite3VdbeAddOp3(v, op, r2, r1, target); testcase( regFree1==0 ); testcase( regFree2==0 ); @@ -2656,10 +2671,10 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ u8 enc = ENC(db); /* The text encoding used by this database */ CollSeq *pColl = 0; /* A collating sequence */ - assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); if( ExprHasProperty(pExpr, EP_TokenOnly) ){ pFarg = 0; }else{ + assert( ExprHasProperty(pExpr, EP_xIsList) ); pFarg = pExpr->x.pList; } nFarg = pFarg ? pFarg->nExpr : 0; @@ -2926,7 +2941,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ Expr *pTest = 0; /* X==Ei (form A) or just Ei (form B) */ VVA_ONLY( int iCacheLevel = pParse->iCacheLevel; ) - assert( !ExprHasProperty(pExpr, EP_xIsSelect) && pExpr->x.pList ); + assert( ExprHasProperty(pExpr, EP_xIsList) && pExpr->x.pList ); assert(pExpr->x.pList->nExpr > 0); pEList = pExpr->x.pList; aListelem = pEList->a; @@ -2938,6 +2953,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ exprToRegister(&tempX, sqlite3ExprCodeTemp(pParse, pX, ®Free1)); testcase( regFree1==0 ); opCompare.op = TK_EQ; + opCompare.flags = 0; opCompare.pLeft = &tempX; pTest = &opCompare; /* Ticket b351d95f9cd5ef17e9d9dbae18f5ca8611190001: @@ -2950,7 +2966,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ sqlite3ExprCachePush(pParse); if( pX ){ assert( pTest!=0 ); - opCompare.pRight = aListelem[i].pExpr; + opCompare.x.pRight = aListelem[i].pExpr; }else{ pTest = aListelem[i].pExpr; } @@ -3364,7 +3380,8 @@ void sqlite3ExplainExpr(Vdbe *pOut, Expr *pExpr){ sqlite3ExplainPrintf(pOut,"%s(", zBinOp); sqlite3ExplainExpr(pOut, pExpr->pLeft); sqlite3ExplainPrintf(pOut,","); - sqlite3ExplainExpr(pOut, pExpr->pRight); + assert( ExprUsesRight(pExpr) ); + sqlite3ExplainExpr(pOut, pExpr->x.pRight); sqlite3ExplainPrintf(pOut,")"); }else if( zUniOp ){ sqlite3ExplainPrintf(pOut,"%s(", zUniOp); @@ -3482,17 +3499,20 @@ static void exprCodeBetween( Expr exprX; /* The x subexpression */ int regFree1 = 0; /* Temporary use register */ - assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); + assert( ExprHasProperty(pExpr, EP_xIsList) ); exprX = *pExpr->pLeft; exprAnd.op = TK_AND; + exprAnd.flags = 0; exprAnd.pLeft = &compLeft; - exprAnd.pRight = &compRight; + exprAnd.x.pRight = &compRight; compLeft.op = TK_GE; + compLeft.flags = 0; compLeft.pLeft = &exprX; - compLeft.pRight = pExpr->x.pList->a[0].pExpr; + compLeft.x.pRight = pExpr->x.pList->a[0].pExpr; compRight.op = TK_LE; + compRight.flags = 0; compRight.pLeft = &exprX; - compRight.pRight = pExpr->x.pList->a[1].pExpr; + compRight.x.pRight = pExpr->x.pList->a[1].pExpr; exprToRegister(&exprX, sqlite3ExprCodeTemp(pParse, &exprX, ®Free1)); if( jumpIfTrue ){ sqlite3ExprIfTrue(pParse, &exprAnd, dest, jumpIfNull); @@ -3543,7 +3563,8 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ testcase( jumpIfNull==0 ); sqlite3ExprIfFalse(pParse, pExpr->pLeft, d2,jumpIfNull^SQLITE_JUMPIFNULL); sqlite3ExprCachePush(pParse); - sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull); + assert( ExprUsesRight(pExpr) ); + sqlite3ExprIfTrue(pParse, pExpr->x.pRight, dest, jumpIfNull); sqlite3VdbeResolveLabel(v, d2); sqlite3ExprCachePop(pParse); break; @@ -3552,7 +3573,8 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ testcase( jumpIfNull==0 ); sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull); sqlite3ExprCachePush(pParse); - sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull); + assert( ExprUsesRight(pExpr) ); + sqlite3ExprIfTrue(pParse, pExpr->x.pRight, dest, jumpIfNull); sqlite3ExprCachePop(pParse); break; } @@ -3569,8 +3591,9 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ case TK_EQ: { testcase( jumpIfNull==0 ); r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); - r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); - codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, + assert( ExprUsesRight(pExpr) ); + r2 = sqlite3ExprCodeTemp(pParse, pExpr->x.pRight, ®Free2); + codeCompare(pParse, pExpr->pLeft, pExpr->x.pRight, op, r1, r2, dest, jumpIfNull); assert(TK_LT==OP_Lt); testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt); assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le); @@ -3587,9 +3610,10 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ testcase( op==TK_IS ); testcase( op==TK_ISNOT ); r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); - r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); + assert( ExprUsesRight(pExpr) ); + r2 = sqlite3ExprCodeTemp(pParse, pExpr->x.pRight, ®Free2); op = (op==TK_IS) ? TK_EQ : TK_NE; - codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, + codeCompare(pParse, pExpr->pLeft, pExpr->x.pRight, op, r1, r2, dest, SQLITE_NULLEQ); VdbeCoverageIf(v, op==TK_EQ); VdbeCoverageIf(v, op==TK_NE); @@ -3698,7 +3722,8 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ testcase( jumpIfNull==0 ); sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull); sqlite3ExprCachePush(pParse); - sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull); + assert( ExprUsesRight(pExpr) ); + sqlite3ExprIfFalse(pParse, pExpr->x.pRight, dest, jumpIfNull); sqlite3ExprCachePop(pParse); break; } @@ -3707,7 +3732,8 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ testcase( jumpIfNull==0 ); sqlite3ExprIfTrue(pParse, pExpr->pLeft, d2, jumpIfNull^SQLITE_JUMPIFNULL); sqlite3ExprCachePush(pParse); - sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull); + assert( ExprUsesRight(pExpr) ); + sqlite3ExprIfFalse(pParse, pExpr->x.pRight, dest, jumpIfNull); sqlite3VdbeResolveLabel(v, d2); sqlite3ExprCachePop(pParse); break; @@ -3725,8 +3751,9 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ case TK_EQ: { testcase( jumpIfNull==0 ); r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); - r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); - codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, + assert( ExprUsesRight(pExpr) ); + r2 = sqlite3ExprCodeTemp(pParse, pExpr->x.pRight, ®Free2); + codeCompare(pParse, pExpr->pLeft, pExpr->x.pRight, op, r1, r2, dest, jumpIfNull); assert(TK_LT==OP_Lt); testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt); assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le); @@ -3743,9 +3770,10 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ testcase( pExpr->op==TK_IS ); testcase( pExpr->op==TK_ISNOT ); r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); - r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); + assert( ExprUsesRight(pExpr) ); + r2 = sqlite3ExprCodeTemp(pParse, pExpr->x.pRight, ®Free2); op = (pExpr->op==TK_IS) ? TK_NE : TK_EQ; - codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, + codeCompare(pParse, pExpr->pLeft, pExpr->x.pRight, op, r1, r2, dest, SQLITE_NULLEQ); VdbeCoverageIf(v, op==TK_EQ); VdbeCoverageIf(v, op==TK_NE); @@ -3848,10 +3876,16 @@ int sqlite3ExprCompare(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( sqlite3ExprCompare(pA->pLeft, pB->pLeft, iTab) ) return 2; - if( sqlite3ExprCompare(pA->pRight, pB->pRight, iTab) ) return 2; - if( sqlite3ExprListCompare(pA->x.pList, pB->x.pList, iTab) ) return 2; + if( (pA->flags&EP_xMask)!=(pB->flags&EP_xMask) ) return 2; + if( ExprUsesRight(pA) ){ + if( sqlite3ExprCompare(pA->x.pRight, pB->x.pRight, iTab) ) return 2; + }else if( ExprHasProperty(pA, EP_xIsSelect) ){ + return 2; + }else{ + assert( ExprHasProperty(pA, EP_xIsList) ); + if( sqlite3ExprListCompare(pA->x.pList, pB->x.pList, iTab) ) return 2; + } if( ALWAYS((combinedFlags & EP_Reduced)==0) ){ if( pA->iColumn!=pB->iColumn ) return 2; if( pA->iTable!=pB->iTable @@ -3916,7 +3950,7 @@ int sqlite3ExprImpliesExpr(Expr *pE1, Expr *pE2, int iTab){ } if( pE2->op==TK_OR && (sqlite3ExprImpliesExpr(pE1, pE2->pLeft, iTab) - || sqlite3ExprImpliesExpr(pE1, pE2->pRight, iTab) ) + || sqlite3ExprImpliesExpr(pE1, pE2->x.pRight, iTab) ) ){ return 1; } @@ -4119,7 +4153,7 @@ 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( ExprHasProperty(pExpr, EP_xIsList) ); pItem = &pAggInfo->aFunc[i]; pItem->pExpr = pExpr; pItem->iMem = ++pParse->nMem; diff --git a/src/func.c b/src/func.c index 6be963580c..cc8cb45cb8 100644 --- a/src/func.c +++ b/src/func.c @@ -1606,7 +1606,7 @@ void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive){ } /* -** pExpr points to an expression which implements a function. If +** pExpr might point to an expression which implements a function. If ** it is appropriate to apply the LIKE optimization to that function ** then set aWc[0] through aWc[2] to the wildcard characters and ** return TRUE. If the function is not a LIKE-style function then @@ -1614,13 +1614,11 @@ void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive){ */ int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){ FuncDef *pDef; - if( pExpr->op!=TK_FUNCTION - || !pExpr->x.pList - || pExpr->x.pList->nExpr!=2 - ){ + if( pExpr->op!=TK_FUNCTION ) return 0; + assert( ExprHasProperty(pExpr, EP_xIsList) || pExpr->x.pList==0 ); + if( !pExpr->x.pList || pExpr->x.pList->nExpr!=2 ){ return 0; } - assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); pDef = sqlite3FindFunction(db, pExpr->u.zToken, sqlite3Strlen30(pExpr->u.zToken), 2, SQLITE_UTF8, 0); diff --git a/src/parse.y b/src/parse.y index dbc129ce63..16b3a826c1 100644 --- a/src/parse.y +++ b/src/parse.y @@ -942,8 +942,9 @@ expr(A) ::= expr(X) NOT NULL(E). {spanUnaryPostfix(&A,pParse,TK_NOTNULL,&X,&E);} sqlite3 *db = pParse->db; if( db->mallocFailed==0 && pY->op==TK_NULL ){ pA->op = (u8)op; - sqlite3ExprDelete(db, pA->pRight); - pA->pRight = 0; + assert( ExprUsesRight(pA) ); + sqlite3ExprDelete(db, pA->x.pRight); + pA->x.pRight = 0; } } } @@ -997,6 +998,7 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] { A.pExpr = sqlite3PExpr(pParse, TK_BETWEEN, W.pExpr, 0, 0); if( A.pExpr ){ A.pExpr->x.pList = pList; + ExprSetProperty(A.pExpr, EP_xIsList); }else{ sqlite3ExprListDelete(pParse->db, pList); } @@ -1051,6 +1053,7 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] { A.pExpr = sqlite3PExpr(pParse, TK_IN, X.pExpr, 0, 0); if( A.pExpr ){ A.pExpr->x.pList = Y; + ExprSetProperty(A.pExpr, EP_xIsList); sqlite3ExprSetHeight(pParse, A.pExpr); }else{ sqlite3ExprListDelete(pParse->db, Y); @@ -1118,6 +1121,7 @@ expr(A) ::= CASE(C) case_operand(X) case_exprlist(Y) case_else(Z) END(E). { A.pExpr = sqlite3PExpr(pParse, TK_CASE, X, 0, 0); if( A.pExpr ){ A.pExpr->x.pList = Z ? sqlite3ExprListAppend(pParse,Y,Z) : Y; + ExprSetProperty(A.pExpr, EP_xIsList); sqlite3ExprSetHeight(pParse, A.pExpr); }else{ sqlite3ExprListDelete(pParse->db, Y); diff --git a/src/resolve.c b/src/resolve.c index 86169c51c1..dd4f3eb728 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -197,7 +197,7 @@ int sqlite3MatchSpanName( ** pExpr->iColumn Set to the column number within the table. ** pExpr->op Set to TK_COLUMN. ** pExpr->pLeft Any expression this points to is deleted -** pExpr->pRight Any expression this points to is deleted. +** pExpr->x.pRight Any expression this points to is deleted. ** ** The zDb variable is the name of the database (the "X"). This value may be ** NULL meaning that name is of the form Y.Z or Z. Any available database @@ -415,7 +415,7 @@ static int lookupName( char *zAs = pEList->a[j].zName; if( zAs!=0 && sqlite3StrICmp(zAs, zCol)==0 ){ Expr *pOrig; - assert( pExpr->pLeft==0 && pExpr->pRight==0 ); + assert( pExpr->pLeft==0 && pExpr->x.pRight==0 ); assert( pExpr->x.pList==0 ); assert( pExpr->x.pSelect==0 ); pOrig = pEList->a[j].pExpr; @@ -495,8 +495,10 @@ static int lookupName( */ sqlite3ExprDelete(db, pExpr->pLeft); pExpr->pLeft = 0; - sqlite3ExprDelete(db, pExpr->pRight); - pExpr->pRight = 0; + if( ExprUsesRight(pExpr) ){ + sqlite3ExprDelete(db, pExpr->x.pRight); + pExpr->x.pRight = 0; + } pExpr->op = (isTrigger ? TK_TRIGGER : TK_COLUMN); lookupname_end: if( cnt==1 ){ @@ -655,16 +657,18 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ Expr *pRight; /* if( pSrcList==0 ) break; */ - pRight = pExpr->pRight; + assert( ExprUsesRight(pExpr) ); + pRight = pExpr->x.pRight; if( pRight->op==TK_ID ){ zDb = 0; zTable = pExpr->pLeft->u.zToken; zColumn = pRight->u.zToken; }else{ assert( pRight->op==TK_DOT ); + assert( ExprUsesRight(pRight) ); zDb = pExpr->pLeft->u.zToken; zTable = pRight->pLeft->u.zToken; - zColumn = pRight->pRight->u.zToken; + zColumn = pRight->x.pRight->u.zToken; } return lookupName(pParse, zDb, zTable, zColumn, pNC, pExpr); } @@ -683,7 +687,7 @@ 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( ExprHasProperty(pExpr, EP_xIsList) || pList==0 ); notValidPartIdxWhere(pParse, pNC, "functions"); zId = pExpr->u.zToken; nId = sqlite3Strlen30(zId); diff --git a/src/select.c b/src/select.c index 5fff010f34..33c3cf07d6 100644 --- a/src/select.c +++ b/src/select.c @@ -340,7 +340,7 @@ static void setJoinExpr(Expr *p, int iTable){ ExprSetVVAProperty(p, EP_NoReduce); p->iRightJoinTable = (i16)iTable; setJoinExpr(p->pLeft, iTable); - p = p->pRight; + p = ExprUsesRight(p) ? p->x.pRight : 0; } } @@ -1562,7 +1562,8 @@ static int selectColumnsFromExprList( Expr *pColExpr = p; /* The expression that is the result column name */ Table *pTab; /* Table associated with this expression */ while( pColExpr->op==TK_DOT ){ - pColExpr = pColExpr->pRight; + assert( ExprUsesRight(pColExpr) ); + pColExpr = pColExpr->x.pRight; assert( pColExpr!=0 ); } if( pColExpr->op==TK_COLUMN && ALWAYS(pColExpr->pTab!=0) ){ @@ -2994,17 +2995,19 @@ static Expr *substExpr( }else{ Expr *pNew; assert( pEList!=0 && pExpr->iColumnnExpr ); - assert( pExpr->pLeft==0 && pExpr->pRight==0 ); + assert( pExpr->pLeft==0 && pExpr->x.pRight==0 ); pNew = sqlite3ExprDup(db, pEList->a[pExpr->iColumn].pExpr, 0); sqlite3ExprDelete(db, pExpr); pExpr = pNew; } }else{ pExpr->pLeft = substExpr(db, pExpr->pLeft, iTable, pEList); - pExpr->pRight = substExpr(db, pExpr->pRight, iTable, pEList); - if( ExprHasProperty(pExpr, EP_xIsSelect) ){ + if( ExprUsesRight(pExpr) ){ + pExpr->x.pRight = substExpr(db, pExpr->x.pRight, iTable, pEList); + }else if( ExprHasProperty(pExpr, EP_xIsSelect) ){ substSelect(db, pExpr->x.pSelect, iTable, pEList); }else{ + assert( ExprHasProperty(pExpr, EP_xIsList) ); substExprList(db, pExpr->x.pList, iTable, pEList); } } @@ -4054,9 +4057,9 @@ static int selectExpander(Walker *pWalker, Select *p){ for(k=0; knExpr; k++){ pE = pEList->a[k].pExpr; if( pE->op==TK_ALL ) break; - assert( pE->op!=TK_DOT || pE->pRight!=0 ); + assert( pE->op!=TK_DOT || !ExprUsesRight(pE) || pE->x.pRight!=0 ); assert( pE->op!=TK_DOT || (pE->pLeft!=0 && pE->pLeft->op==TK_ID) ); - if( pE->op==TK_DOT && pE->pRight->op==TK_ALL ) break; + if( pE->op==TK_DOT && pE->x.pRight->op==TK_ALL ) break; } if( knExpr ){ /* @@ -4079,7 +4082,7 @@ static int selectExpander(Walker *pWalker, Select *p){ for(k=0; knExpr; k++){ pE = a[k].pExpr; - pRight = pE->pRight; + pRight = ExprUsesRight(pE) ? pE->x.pRight : 0; assert( pE->op!=TK_DOT || pRight!=0 ); if( pE->op!=TK_ALL && (pE->op!=TK_DOT || pRight->op!=TK_ALL) ){ /* This particular expression does not need to be expanded. @@ -4376,7 +4379,7 @@ 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) ); + assert( ExprHasProperty(pE, EP_xIsList) || pE->x.pList==0 ); if( pE->x.pList==0 || pE->x.pList->nExpr!=1 ){ sqlite3ErrorMsg(pParse, "DISTINCT aggregates must have exactly one " "argument"); @@ -4400,7 +4403,7 @@ 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( ExprHasProperty(pF->pExpr, EP_xIsList) || pList==0 ); sqlite3VdbeAddOp4(v, OP_AggFinal, pF->iMem, pList ? pList->nExpr : 0, 0, (void*)pF->pFunc, P4_FUNCDEF); } @@ -4424,7 +4427,7 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){ int addrNext = 0; int regAgg; ExprList *pList = pF->pExpr->x.pList; - assert( !ExprHasProperty(pF->pExpr, EP_xIsSelect) ); + assert( ExprHasProperty(pF->pExpr, EP_xIsList) || pList==0 ); if( pList ){ nArg = pList->nExpr; regAgg = sqlite3GetTempRange(pParse, nArg); @@ -4899,7 +4902,8 @@ int sqlite3Select( } sAggInfo.nAccumulator = sAggInfo.nColumn; for(i=0; ix.pList==0 ); sNC.ncFlags |= NC_InAggFunc; sqlite3ExprAnalyzeAggList(&sNC, sAggInfo.aFunc[i].pExpr->x.pList); sNC.ncFlags &= ~NC_InAggFunc; diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 4bd65a690f..4a0f8ad4e5 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1871,8 +1871,8 @@ struct Expr { *********************************************************************/ Expr *pLeft; /* Left subnode */ - Expr *pRight; /* Right subnode */ union { + Expr *pRight; /* Right subnode */ ExprList *pList; /* op = IN, EXISTS, SELECT, CASE, FUNCTION, BETWEEN */ Select *pSelect; /* EP_xIsSelect and op = IN, EXISTS, SELECT */ } x; @@ -1882,13 +1882,13 @@ struct Expr { ** access them will result in a segfault or malfunction. *********************************************************************/ -#if SQLITE_MAX_EXPR_DEPTH>0 - int nHeight; /* Height of the tree headed by this node */ -#endif int iTable; /* TK_COLUMN: cursor number of table holding column ** TK_REGISTER: register number ** TK_TRIGGER: 1 -> new, 0 -> old ** EP_Unlikely: 1000 times likelihood */ +#if SQLITE_MAX_EXPR_DEPTH>0 + int nHeight; /* Height of the tree headed by this node */ +#endif ynVar iColumn; /* TK_COLUMN: column index. -1 for rowid. ** TK_VARIABLE: variable number (always >= 1). */ i16 iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */ @@ -1914,7 +1914,6 @@ 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) */ #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 */ @@ -1923,6 +1922,9 @@ struct Expr { #define EP_NoReduce 0x020000 /* Cannot EXPRDUP_REDUCE this Expr */ #define EP_Unlikely 0x040000 /* unlikely() or likelihood() function */ #define EP_Constant 0x080000 /* Node is a constant */ +#define EP_xIsSelect 0x100000 /* Use x.pSelect, not x.pList or x.pRight */ +#define EP_xIsList 0x200000 /* Use x.pList, not x.pSelect or x.pRight */ +#define EP_xMask 0x300000 /* Combination of xIsSelect and xIsList */ /* ** These macros can be used to test, set, or clear bits in the @@ -1933,6 +1935,10 @@ struct Expr { #define ExprSetProperty(E,P) (E)->flags|=(P) #define ExprClearProperty(E,P) (E)->flags&=~(P) +/* True if the x.pRight field of Expr E is valid */ +#define ExprUsesRight(E) (((E)->flags&EP_xMask)==0) + + /* The ExprSetVVAProperty() macro is used for Verification, Validation, ** and Accreditation only. It works like ExprSetProperty() during VVA ** processes but is a no-op for delivery. diff --git a/src/walker.c b/src/walker.c index 016ae77a92..d6916e69e7 100644 --- a/src/walker.c +++ b/src/walker.c @@ -45,10 +45,12 @@ int sqlite3WalkExpr(Walker *pWalker, Expr *pExpr){ if( rc==WRC_Continue && !ExprHasProperty(pExpr,EP_TokenOnly) ){ if( sqlite3WalkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort; - if( sqlite3WalkExpr(pWalker, pExpr->pRight) ) return WRC_Abort; - if( ExprHasProperty(pExpr, EP_xIsSelect) ){ + if( ExprUsesRight(pExpr) ){ + if( sqlite3WalkExpr(pWalker, pExpr->x.pRight) ) return WRC_Abort; + }else if( ExprHasProperty(pExpr, EP_xIsSelect) ){ if( sqlite3WalkSelect(pWalker, pExpr->x.pSelect) ) return WRC_Abort; }else{ + assert( ExprHasProperty(pExpr, EP_xIsList) ); if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort; } } diff --git a/src/where.c b/src/where.c index c5892590bc..31a4c41823 100644 --- a/src/where.c +++ b/src/where.c @@ -260,7 +260,8 @@ static void whereSplit(WhereClause *pWC, Expr *pExpr, u8 op){ whereClauseInsert(pWC, pExpr, 0); }else{ whereSplit(pWC, pExpr->pLeft, op); - whereSplit(pWC, pExpr->pRight, op); + assert( ExprUsesRight(pExpr) ); + whereSplit(pWC, pExpr->x.pRight, op); } } @@ -311,11 +312,13 @@ static Bitmask exprTableUsage(WhereMaskSet *pMaskSet, Expr *p){ mask = getMask(pMaskSet, p->iTable); return mask; } - mask = exprTableUsage(pMaskSet, p->pRight); - mask |= exprTableUsage(pMaskSet, p->pLeft); - if( ExprHasProperty(p, EP_xIsSelect) ){ + mask = exprTableUsage(pMaskSet, p->pLeft); + if( ExprUsesRight(p) ){ + mask |= exprTableUsage(pMaskSet, p->x.pRight); + }else if( ExprHasProperty(p, EP_xIsSelect) ){ mask |= exprSelectTableUsage(pMaskSet, p->x.pSelect); }else{ + assert( ExprHasProperty(p, EP_xIsList) ); mask |= exprListTableUsage(pMaskSet, p->x.pList); } return mask; @@ -382,15 +385,16 @@ static int allowedOp(int op){ ** is not commuted. */ static void exprCommute(Parse *pParse, Expr *pExpr){ - u16 expRight = (pExpr->pRight->flags & EP_Collate); + u16 expRight = (pExpr->x.pRight->flags & EP_Collate); u16 expLeft = (pExpr->pLeft->flags & EP_Collate); + assert( ExprUsesRight(pExpr) ); assert( allowedOp(pExpr->op) && pExpr->op!=TK_IN ); if( expRight==expLeft ){ /* Either X and Y both have COLLATE operator or neither do */ if( expRight ){ /* Both X and Y have COLLATE operators. Make sure X is always ** used by clearing the EP_Collate flag from Y. */ - pExpr->pRight->flags &= ~EP_Collate; + pExpr->x.pRight->flags &= ~EP_Collate; }else if( sqlite3ExprCollSeq(pParse, pExpr->pLeft)!=0 ){ /* Neither X nor Y have COLLATE operators, but X has a non-default ** collating sequence. So add the EP_Collate marker on X to cause @@ -398,7 +402,7 @@ static void exprCommute(Parse *pParse, Expr *pExpr){ pExpr->pLeft->flags |= EP_Collate; } } - SWAP(Expr*,pExpr->pRight,pExpr->pLeft); + SWAP(Expr*,pExpr->x.pRight,pExpr->pLeft); if( pExpr->op>=TK_GT ){ assert( TK_LT==TK_GT+2 ); assert( TK_GE==TK_LE+2 ); @@ -459,7 +463,8 @@ static WhereTerm *whereScanNext(WhereScan *pScan){ && pScan->nEquivaEquiv) ){ int j; - pX = sqlite3ExprSkipCollate(pTerm->pExpr->pRight); + assert( ExprUsesRight(pTerm->pExpr) ); + pX = sqlite3ExprSkipCollate(pTerm->pExpr->x.pRight); assert( pX->op==TK_COLUMN ); for(j=0; jnEquiv; j+=2){ if( pScan->aEquiv[j]==pX->iTable @@ -482,16 +487,16 @@ static WhereTerm *whereScanNext(WhereScan *pScan){ if( !sqlite3IndexAffinityOk(pX, pScan->idxaff) ){ continue; } - assert(pX->pLeft); - pColl = sqlite3BinaryCompareCollSeq(pParse, - pX->pLeft, pX->pRight); + assert( pX->pLeft!=0 ); + pColl = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, + ExprUsesRight(pX) ? pX->x.pRight : 0); if( pColl==0 ) pColl = pParse->db->pDfltColl; if( sqlite3StrICmp(pColl->zName, pScan->zCollName) ){ continue; } } if( (pTerm->eOperator & WO_EQ)!=0 - && (pX = pTerm->pExpr->pRight)->op==TK_COLUMN + && (pX = pTerm->pExpr->x.pRight)->op==TK_COLUMN && pX->iTable==pScan->aEquiv[0] && pX->iColumn==pScan->aEquiv[1] ){ @@ -1016,7 +1021,8 @@ static void exprAnalyzeOrTerm( ** of both right and left sides must be such that no type ** conversions are required on the right. (Ticket #2249) */ - affRight = sqlite3ExprAffinity(pOrTerm->pExpr->pRight); + assert( ExprUsesRight(pOrTerm->pExpr) ); + affRight = sqlite3ExprAffinity(pOrTerm->pExpr->x.pRight); affLeft = sqlite3ExprAffinity(pOrTerm->pExpr->pLeft); if( affRight!=0 && affRight!=affLeft ){ okToChngToIN = 0; @@ -1042,7 +1048,8 @@ static void exprAnalyzeOrTerm( assert( pOrTerm->eOperator & WO_EQ ); assert( pOrTerm->leftCursor==iCursor ); assert( pOrTerm->u.leftColumn==iColumn ); - pDup = sqlite3ExprDup(db, pOrTerm->pExpr->pRight, 0); + assert( ExprUsesRight(pOrTerm->pExpr) ); + pDup = sqlite3ExprDup(db, pOrTerm->pExpr->x.pRight, 0); pList = sqlite3ExprListAppend(pWInfo->pParse, pList, pDup); pLeft = pOrTerm->pExpr->pLeft; } @@ -1052,7 +1059,7 @@ static void exprAnalyzeOrTerm( if( pNew ){ int idxNew; transferJoinMarkings(pNew, pExpr); - assert( !ExprHasProperty(pNew, EP_xIsSelect) ); + ExprSetProperty(pNew, EP_xIsList); pNew->x.pList = pList; idxNew = whereClauseInsert(pWC, pNew, TERM_VIRTUAL|TERM_DYNAMIC); testcase( idxNew==0 ); @@ -1116,16 +1123,16 @@ static void exprAnalyze( prereqLeft = exprTableUsage(pMaskSet, pExpr->pLeft); op = pExpr->op; if( op==TK_IN ){ - assert( pExpr->pRight==0 ); if( ExprHasProperty(pExpr, EP_xIsSelect) ){ pTerm->prereqRight = exprSelectTableUsage(pMaskSet, pExpr->x.pSelect); }else{ + assert( ExprHasProperty(pExpr, EP_xIsList) || pExpr->x.pList==0 ); pTerm->prereqRight = exprListTableUsage(pMaskSet, pExpr->x.pList); } }else if( op==TK_ISNULL ){ pTerm->prereqRight = 0; - }else{ - pTerm->prereqRight = exprTableUsage(pMaskSet, pExpr->pRight); + }else if( ExprUsesRight(pExpr) ){ + pTerm->prereqRight = exprTableUsage(pMaskSet, pExpr->x.pRight); } prereqAll = exprTableUsage(pMaskSet, pExpr); if( ExprHasProperty(pExpr, EP_FromJoin) ){ @@ -1140,14 +1147,17 @@ static void exprAnalyze( pTerm->eOperator = 0; if( allowedOp(op) ){ Expr *pLeft = sqlite3ExprSkipCollate(pExpr->pLeft); - Expr *pRight = sqlite3ExprSkipCollate(pExpr->pRight); + Expr *pRight; u16 opMask = (pTerm->prereqRight & prereqLeft)==0 ? WO_ALL : WO_EQUIV; if( pLeft->op==TK_COLUMN ){ pTerm->leftCursor = pLeft->iTable; pTerm->u.leftColumn = pLeft->iColumn; pTerm->eOperator = operatorMask(op) & opMask; } - if( pRight && pRight->op==TK_COLUMN ){ + if( ExprUsesRight(pExpr) + && (pRight = sqlite3ExprSkipCollate(pExpr->x.pRight))!=0 + && pRight->op==TK_COLUMN + ){ WhereTerm *pNew; Expr *pDup; u16 eExtraOp = 0; /* Extra bits for pNew->eOperator */ @@ -1673,7 +1683,8 @@ static void constructAutomaticIndex( Expr *pX = pTerm->pExpr; idxCols |= cMask; pIdx->aiColumn[n] = pTerm->u.leftColumn; - pColl = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pX->pRight); + assert( ExprUsesRight(pX) ); + pColl = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pX->x.pRight); pIdx->azColl[n] = ALWAYS(pColl) ? pColl->zName : "BINARY"; n++; } @@ -2103,7 +2114,8 @@ static int whereRangeScanEst( /* If possible, improve on the iLower estimate using ($P:$L). */ if( pLower ){ int bOk; /* True if value is extracted from pExpr */ - Expr *pExpr = pLower->pExpr->pRight; + Expr *pExpr = pLower->pExpr->x.pRight; + assert( ExprUsesRight(pLower->pExpr) ); assert( (pLower->eOperator & (WO_GT|WO_GE))!=0 ); rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk); if( rc==SQLITE_OK && bOk ){ @@ -2118,7 +2130,8 @@ static int whereRangeScanEst( /* If possible, improve on the iUpper estimate using ($P:$U). */ if( pUpper ){ int bOk; /* True if value is extracted from pExpr */ - Expr *pExpr = pUpper->pExpr->pRight; + Expr *pExpr = pUpper->pExpr->x.pRight; + assert( ExprUsesRight(pUpper->pExpr) ); assert( (pUpper->eOperator & (WO_LT|WO_LE))!=0 ); rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk); if( rc==SQLITE_OK && bOk ){ @@ -2388,7 +2401,8 @@ static int codeEqualityTerm( assert( iTarget>0 ); if( pX->op==TK_EQ ){ - iReg = sqlite3ExprCodeTarget(pParse, pX->pRight, iTarget); + assert( ExprUsesRight(pX) ); + iReg = sqlite3ExprCodeTarget(pParse, pX->x.pRight, iTarget); }else if( pX->op==TK_ISNULL ){ iReg = iTarget; sqlite3VdbeAddOp2(v, OP_Null, 0, iReg); @@ -2571,7 +2585,8 @@ static int codeAllEqualityTerms( testcase( pTerm->eOperator & WO_ISNULL ); testcase( pTerm->eOperator & WO_IN ); if( (pTerm->eOperator & (WO_ISNULL|WO_IN))==0 ){ - Expr *pRight = pTerm->pExpr->pRight; + Expr *pRight = pTerm->pExpr->x.pRight; + assert( ExprUsesRight(pTerm->pExpr) ); if( sqlite3ExprCanBeNull(pRight) ){ sqlite3VdbeAddOp2(v, OP_IsNull, regBase+j, pLevel->addrBrk); VdbeCoverage(v); @@ -2848,7 +2863,8 @@ static Bitmask codeOneLoopStart( codeEqualityTerm(pParse, pTerm, pLevel, j, bRev, iTarget); addrNotFound = pLevel->addrNxt; }else{ - sqlite3ExprCode(pParse, pTerm->pExpr->pRight, iTarget); + assert( ExprUsesRight(pTerm->pExpr) ); + sqlite3ExprCode(pParse, pTerm->pExpr->x.pRight, iTarget); } } sqlite3VdbeAddOp2(v, OP_Integer, pLoop->u.vtab.idxNum, iReg); @@ -2939,7 +2955,8 @@ static Bitmask codeOneLoopStart( pX = pStart->pExpr; assert( pX!=0 ); testcase( pStart->leftCursor!=iCur ); /* transitive constraints */ - r1 = sqlite3ExprCodeTemp(pParse, pX->pRight, &rTemp); + assert( ExprUsesRight(pX) ); + r1 = sqlite3ExprCodeTemp(pParse, pX->x.pRight, &rTemp); sqlite3VdbeAddOp3(v, aMoveOp[pX->op-TK_GT], iCur, addrBrk, r1); VdbeComment((v, "pk")); VdbeCoverageIf(v, pX->op==TK_GT); @@ -2962,7 +2979,8 @@ static Bitmask codeOneLoopStart( testcase( pEnd->leftCursor!=iCur ); /* Transitive constraints */ testcase( pEnd->wtFlags & TERM_VIRTUAL ); memEndValue = ++pParse->nMem; - sqlite3ExprCode(pParse, pX->pRight, memEndValue); + assert( ExprUsesRight(pX) ); + sqlite3ExprCode(pParse, pX->x.pRight, memEndValue); if( pX->op==TK_LT || pX->op==TK_GT ){ testOp = bRev ? OP_Le : OP_Ge; }else{ @@ -3126,7 +3144,8 @@ static Bitmask codeOneLoopStart( /* Seek the index cursor to the start of the range. */ nConstraint = nEq; if( pRangeStart ){ - Expr *pRight = pRangeStart->pExpr->pRight; + Expr *pRight = pRangeStart->pExpr->x.pRight; + assert( ExprUsesRight(pRangeStart->pExpr) ); sqlite3ExprCode(pParse, pRight, regBase+nEq); if( (pRangeStart->wtFlags & TERM_VNULL)==0 && sqlite3ExprCanBeNull(pRight) @@ -3170,7 +3189,8 @@ static Bitmask codeOneLoopStart( */ nConstraint = nEq; if( pRangeEnd ){ - Expr *pRight = pRangeEnd->pExpr->pRight; + Expr *pRight = pRangeEnd->pExpr->x.pRight; + assert( ExprUsesRight(pRangeEnd->pExpr) ); sqlite3ExprCacheRemove(pParse, regBase+nEq, 1); sqlite3ExprCode(pParse, pRight, regBase+nEq); if( (pRangeEnd->wtFlags & TERM_VNULL)==0 @@ -4229,7 +4249,8 @@ static int whereLoopAddBtreeIndex( if( (eOp & (WO_EQ|WO_ISNULL))!=0 ){ testcase( eOp & WO_EQ ); testcase( eOp & WO_ISNULL ); - rc = whereEqualScanEst(pParse, pBuilder, pExpr->pRight, &nOut); + assert( ExprUsesRight(pExpr) ); + rc = whereEqualScanEst(pParse, pBuilder, pExpr->x.pRight, &nOut); }else{ rc = whereInScanEst(pParse, pBuilder, pExpr->x.pList, &nOut); }