The WHERE-clause constant propagation optimization attempts to use
transitive laws to replace column values with constants in the WHERE clause in order to help to query planner make more aggressive optimizations. FossilOrigin-Name: f4229707ac08d66c5b0f53483ce17a63f5ac40a21922f66c3408e1b6fda3a7c2
This commit is contained in:
commit
2d475e80bd
29
manifest
29
manifest
@ -1,5 +1,5 @@
|
||||
C In\sthe\sunix\sVFS,\sgive\severy\sunixInodeInfo\sobject\sits\sown\smutex,\srather\nthan\susing\sthe\sglobal\sVFS\smutex,\sto\simprove\sconcurrency\sin\scases\swhere\sthere\nare\smany\sthreads\soperating\son\sseparate\sdatabase\sfiles.
|
||||
D 2018-07-26T21:48:05.458
|
||||
C The\sWHERE-clause\sconstant\spropagation\soptimization\sattempts\sto\suse\ntransitive\slaws\sto\sreplace\scolumn\svalues\swith\sconstants\sin\sthe\sWHERE\nclause\sin\sorder\sto\shelp\sto\squery\splanner\smake\smore\saggressive\soptimizations.
|
||||
D 2018-07-27T20:37:42.265
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F Makefile.in 0a3a6c81e6fcb969ff9106e882f0a08547014ba463cb6beca4c4efaecc924ee6
|
||||
@ -450,7 +450,7 @@ F src/date.c ebe1dc7c8a347117bb02570f1a931c62dd78f4a2b1b516f4837d45b7d6426957
|
||||
F src/dbpage.c 4aa7f26198934dbd002e69418220eae3dbc71b010bbac32bd78faf86b52ce6c3
|
||||
F src/dbstat.c edabb82611143727511a45ca0859b8cd037851ebe756ae3db289859dd18b6f91
|
||||
F src/delete.c 4c8c7604277a2041647f96b78f4b9a47858e9217e4fb333d35e7b5ab32c5b57f
|
||||
F src/expr.c bb148f4c45b6e53b5b58a912974253547e8862685cb001fbdfaef0ab24812e6f
|
||||
F src/expr.c 5b5e7b571f377ca76fc76eec0a684384483e0bf6525f6b561a09db09d81600eb
|
||||
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
||||
F src/fkey.c b1da9ef8dc834603bb0d28972378a7ce65897847f9a1e89ab800bbdf24c788ee
|
||||
F src/func.c 7c288b4ce309b5a8b8473514b88e1f8e69a80134509a8c0db8e39c858e367e7f
|
||||
@ -462,7 +462,7 @@ F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
||||
F src/insert.c 8613af9c5ba1503bc68f4e9432c6c024e0fdafdc791575c50f380f73ec91189f
|
||||
F src/legacy.c 134ab3e3fae00a0f67a5187981d6935b24b337bcf0f4b3e5c9fa5763da95bf4e
|
||||
F src/loadext.c 6aae5739198d96c51ae6eb97c4a5b1744c22ed7a5a565a5399a717780d48a36b
|
||||
F src/main.c 73a3db1c9788de97a826ac794bf98a8a811c7594e93bef4f0c085b3f9ddeb76d
|
||||
F src/main.c dc023f468eda20aed1fb7c300673cbb40617607b5771840e4229ec239dade250
|
||||
F src/malloc.c 07295435093ce354c6d9063ac05a2eeae28bd251d2e63c48b3d67c12c76f7e18
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de
|
||||
@ -498,12 +498,12 @@ F src/printf.c 7f6f3cba8e0c49c19e30a1ff4e9aeda6e06814dcbad4b664a69e1b6cb6e7e365
|
||||
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
|
||||
F src/resolve.c 797088662ed61102485e3070ba3b3f7828bd5ef6a588223ba6865d77d52f6cea
|
||||
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
|
||||
F src/select.c 2e9661d4424f43ccf595c4a7b4acdf32db523c0f6b31cbd62e6e5a2f43118981
|
||||
F src/select.c 2534927341d0a2e8d9a3222a87b69e353b22042a02c3d531291590af7f3acf19
|
||||
F src/shell.c.in f6ebd05c461805a7c708333cd645e74e0a93560d2118f5adb73a75d8c9cf6b01
|
||||
F src/sqlite.h.in c6451bb876adced3aba5b1682c6317d215c5eceaba21a6ce979e71a0b8d0bf95
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h 9887b27e69c01e79c2cbe74ef73bf01af5b5703d6a7f0a4371e386d7249cb1c7
|
||||
F src/sqliteInt.h 427471586351daefbc81155384a702b2173801051fe345bc25a09558b919db77
|
||||
F src/sqliteInt.h fafe020e6fa39964ffff8ff1b48e2a7f0b394e03c722a746629751d2d31721ae
|
||||
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
|
||||
F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e
|
||||
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
|
||||
@ -562,7 +562,7 @@ F src/test_window.c cdae419fdcea5bad6dcd9368c685abdad6deb59e9fc8b84b153de513d394
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
|
||||
F src/tokenize.c 01e96d1b639c3eb0b9ef90616e766d453935c554f1f7aa86b6db937b79554b97
|
||||
F src/treeview.c 26c5674083674377b0f41737647802e93ac31f1da89c9b9648501d8a34a44698
|
||||
F src/treeview.c e7a7f90552bb418533cdd0309b5eb71d4effa50165b880fc8c2001e613577e5f
|
||||
F src/trigger.c 4ace6d1d5ba9a89822deb287317f33c810440526eafe185c2d8a48c31df1e995
|
||||
F src/update.c 7b7c768dc415a8d2eb9fd2cea8b524cb29cf354f319700e22f94f262d3f507cb
|
||||
F src/upsert.c 47edd408cc73f8d3c00a140550d1ad180b407c146285947969dd09874802bf88
|
||||
@ -583,10 +583,10 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
|
||||
F src/wal.c d44a0811afd2155b1157c38b33141d4ac028fda6232485bed664015bb05819ca
|
||||
F src/wal.h 8de5d2d3de0956d6f6cb48c83a4012d5f227b8fe940f3a349a4b7e85ebcb492a
|
||||
F src/walker.c ba7225773931760cf60bf22f34d0cce2588df7ce5ce0f215a52eb88234b55ac4
|
||||
F src/where.c 2d313b446758317b60626763d0e1285e04b04c061ce94945dcfffad9525badc1
|
||||
F src/where.c fae13835da8cd457bbc50a8530b1f4bfe6eb173dec0687cf1572fc02a7aec415
|
||||
F src/whereInt.h b90ef9b9707ef750eab2a7a080c48fb4900315033274689def32d0cf5a81ebe4
|
||||
F src/wherecode.c fe23a55294b4c94bf658d2a6eb7996170dd563bf33af4c3e5d71aff3483e4b08
|
||||
F src/whereexpr.c 571618c67a3eb5ce0f1158c2792c1aee9b4a4a264392fc4fb1b35467f80abf9a
|
||||
F src/wherecode.c 2c552dfe50d06e0916dbd49a180e4bf0accfce6d17d46a2dfeea8f75d2b5861b
|
||||
F src/whereexpr.c dc34f0df69418dedb4619f7ad61b7d31f447971223540b957a1b836a62c0ce7b
|
||||
F src/window.c c61434ce7e35b7d76b3321dec39e10e79061c10eed1e3d7976c87dbdd77aefb5
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
|
||||
@ -1617,6 +1617,7 @@ F test/whereH.test e4b07f7a3c2f5d31195cd33710054c78667573b2
|
||||
F test/whereI.test b7769ee8dbefd987fb266715fee887f05f9ff180016b06fca7fa402df739193b
|
||||
F test/whereJ.test 88287550f6ee604422403b053455b1ad894eeaa5c35d348532dfa1439286cb9a
|
||||
F test/whereK.test f8e3cf26a8513ecc7f514f54df9f0572c046c42b
|
||||
F test/whereL.test 786ae3e0b6d8f7c9b83a98bffcd9d458b0de47c6a9f9dcf872043f54a4752c68
|
||||
F test/wherefault.test 1374c3aa198388925246475f84ad4cd5f9528864
|
||||
F test/wherelfault.test 9012e4ef5259058b771606616bd007af5d154e64cc25fa9fd4170f6411db44e3
|
||||
F test/wherelimit.test 592081800806d297dd7449b1030c863d2883d6d42901837ccd2e5a9bd962edb0
|
||||
@ -1752,8 +1753,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P 0e3de8abbb0c7ae64e637776cb055ce79736f99a103e00e44d17a6b091b98c81 1c94834879be0601ac40ef3c4fb1b140f7737e89af7808f2f1db4ceb3daae19f
|
||||
R da25b06b381bb54c2132bc2143418cfd
|
||||
T +closed 1c94834879be0601ac40ef3c4fb1b140f7737e89af7808f2f1db4ceb3daae19f
|
||||
P 22f47cf430827c50634794a5a33987511bb71492c0dd1f6466a0c5b779d0521b 865249de683e6971984a645a30d96f9fcc6f6d9d7af7e269ff68cc3e42e5fe71
|
||||
R 689982bf0de4818ecef4897183e8c441
|
||||
T +closed 865249de683e6971984a645a30d96f9fcc6f6d9d7af7e269ff68cc3e42e5fe71
|
||||
U drh
|
||||
Z 66336f4799fa18d98782ce7463d9d357
|
||||
Z ad17e846b7bdfa92b5025758f4a66673
|
||||
|
@ -1 +1 @@
|
||||
22f47cf430827c50634794a5a33987511bb71492c0dd1f6466a0c5b779d0521b
|
||||
f4229707ac08d66c5b0f53483ce17a63f5ac40a21922f66c3408e1b6fda3a7c2
|
27
src/expr.c
27
src/expr.c
@ -141,14 +141,6 @@ CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
|
||||
while( p ){
|
||||
int op = p->op;
|
||||
if( p->flags & EP_Generic ) break;
|
||||
if( op==TK_CAST || op==TK_UPLUS ){
|
||||
p = p->pLeft;
|
||||
continue;
|
||||
}
|
||||
if( op==TK_COLLATE || (op==TK_REGISTER && p->op2==TK_COLLATE) ){
|
||||
pColl = sqlite3GetCollSeq(pParse, ENC(db), 0, p->u.zToken);
|
||||
break;
|
||||
}
|
||||
if( (op==TK_AGG_COLUMN || op==TK_COLUMN
|
||||
|| op==TK_REGISTER || op==TK_TRIGGER)
|
||||
&& p->pTab!=0
|
||||
@ -162,6 +154,14 @@ CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
|
||||
}
|
||||
break;
|
||||
}
|
||||
if( op==TK_CAST || op==TK_UPLUS ){
|
||||
p = p->pLeft;
|
||||
continue;
|
||||
}
|
||||
if( op==TK_COLLATE || (op==TK_REGISTER && p->op2==TK_COLLATE) ){
|
||||
pColl = sqlite3GetCollSeq(pParse, ENC(db), 0, p->u.zToken);
|
||||
break;
|
||||
}
|
||||
if( p->flags & EP_Collate ){
|
||||
if( p->pLeft && (p->pLeft->flags & EP_Collate)!=0 ){
|
||||
p = p->pLeft;
|
||||
@ -1839,6 +1839,9 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
|
||||
testcase( pExpr->op==TK_COLUMN );
|
||||
testcase( pExpr->op==TK_AGG_FUNCTION );
|
||||
testcase( pExpr->op==TK_AGG_COLUMN );
|
||||
if( ExprHasProperty(pExpr, EP_FixedCol) ){
|
||||
return WRC_Continue;
|
||||
}
|
||||
if( pWalker->eCode==3 && pExpr->iTable==pWalker->u.iCur ){
|
||||
return WRC_Continue;
|
||||
}
|
||||
@ -1927,7 +1930,7 @@ static int exprNodeIsConstantOrGroupBy(Walker *pWalker, Expr *pExpr){
|
||||
Expr *p = pGroupBy->a[i].pExpr;
|
||||
if( sqlite3ExprCompare(0, pExpr, p, -1)<2 ){
|
||||
CollSeq *pColl = sqlite3ExprNNCollSeq(pWalker->pParse, p);
|
||||
if( sqlite3_stricmp("BINARY", pColl->zName)==0 ){
|
||||
if( sqlite3IsBinary(pColl) ){
|
||||
return WRC_Prune;
|
||||
}
|
||||
}
|
||||
@ -3581,6 +3584,9 @@ expr_code_doover:
|
||||
}
|
||||
case TK_COLUMN: {
|
||||
int iTab = pExpr->iTable;
|
||||
if( ExprHasProperty(pExpr, EP_FixedCol) ){
|
||||
return sqlite3ExprCodeTarget(pParse, pExpr->pLeft,target);
|
||||
}
|
||||
if( iTab<0 ){
|
||||
if( pParse->iSelfTab<0 ){
|
||||
/* Generating CHECK constraints or inserting into partial index */
|
||||
@ -4942,7 +4948,8 @@ 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( sqlite3ExprCompare(pParse, pA->pLeft, pB->pLeft, iTab) ) 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;
|
||||
assert( (combinedFlags & EP_Reduced)==0 );
|
||||
|
@ -910,6 +910,15 @@ static int binCollFunc(
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return true if CollSeq is the default built-in BINARY.
|
||||
*/
|
||||
int sqlite3IsBinary(const CollSeq *p){
|
||||
assert( p==0 || p->xCmp!=binCollFunc || p->pUser!=0
|
||||
|| strcmp(p->zName,"BINARY")==0 );
|
||||
return p==0 || (p->xCmp==binCollFunc && p->pUser==0);
|
||||
}
|
||||
|
||||
/*
|
||||
** Another built-in collating sequence: NOCASE.
|
||||
**
|
||||
|
180
src/select.c
180
src/select.c
@ -4074,7 +4074,168 @@ static int flattenSubquery(
|
||||
}
|
||||
#endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */
|
||||
|
||||
/*
|
||||
** A structure to keep track of all of the column values that fixed to
|
||||
** a known value due to WHERE clause constraints of the form COLUMN=VALUE.
|
||||
*/
|
||||
typedef struct WhereConst WhereConst;
|
||||
struct WhereConst {
|
||||
Parse *pParse; /* Parsing context */
|
||||
int nConst; /* Number for COLUMN=CONSTANT terms */
|
||||
int nChng; /* Number of times a constant is propagated */
|
||||
Expr **apExpr; /* [i*2] is COLUMN and [i*2+1] is VALUE */
|
||||
};
|
||||
|
||||
/*
|
||||
** Add a new entry to the pConst object
|
||||
*/
|
||||
static void constInsert(
|
||||
WhereConst *pConst,
|
||||
Expr *pColumn,
|
||||
Expr *pValue
|
||||
){
|
||||
|
||||
pConst->nConst++;
|
||||
pConst->apExpr = sqlite3DbReallocOrFree(pConst->pParse->db, pConst->apExpr,
|
||||
pConst->nConst*2*sizeof(Expr*));
|
||||
if( pConst->apExpr==0 ){
|
||||
pConst->nConst = 0;
|
||||
}else{
|
||||
if( ExprHasProperty(pValue, EP_FixedCol) ) pValue = pValue->pLeft;
|
||||
pConst->apExpr[pConst->nConst*2-2] = pColumn;
|
||||
pConst->apExpr[pConst->nConst*2-1] = pValue;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Find all terms of COLUMN=VALUE or VALUE=COLUMN in pExpr where VALUE
|
||||
** is a constant expression and where the term must be true because it
|
||||
** is part of the AND-connected terms of the expression. For each term
|
||||
** found, add it to the pConst structure.
|
||||
*/
|
||||
static void findConstInWhere(WhereConst *pConst, Expr *pExpr){
|
||||
Expr *pRight, *pLeft;
|
||||
if( pExpr==0 ) return;
|
||||
if( ExprHasProperty(pExpr, EP_FromJoin) ) return;
|
||||
if( pExpr->op==TK_AND ){
|
||||
findConstInWhere(pConst, pExpr->pRight);
|
||||
findConstInWhere(pConst, pExpr->pLeft);
|
||||
return;
|
||||
}
|
||||
if( pExpr->op!=TK_EQ ) return;
|
||||
pRight = pExpr->pRight;
|
||||
pLeft = pExpr->pLeft;
|
||||
assert( pRight!=0 );
|
||||
assert( pLeft!=0 );
|
||||
if( pRight->op==TK_COLUMN
|
||||
&& !ExprHasProperty(pRight, EP_FixedCol)
|
||||
&& sqlite3ExprIsConstant(pLeft)
|
||||
&& sqlite3IsBinary(sqlite3BinaryCompareCollSeq(pConst->pParse,pLeft,pRight))
|
||||
){
|
||||
constInsert(pConst, pRight, pLeft);
|
||||
}else
|
||||
if( pLeft->op==TK_COLUMN
|
||||
&& !ExprHasProperty(pLeft, EP_FixedCol)
|
||||
&& sqlite3ExprIsConstant(pRight)
|
||||
&& sqlite3IsBinary(sqlite3BinaryCompareCollSeq(pConst->pParse,pLeft,pRight))
|
||||
){
|
||||
constInsert(pConst, pLeft, pRight);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** This is a Walker expression callback. pExpr is a candidate expression
|
||||
** to be replaced by a value. If pExpr is equivalent to one of the
|
||||
** columns named in pWalker->u.pConst, then overwrite it with its
|
||||
** corresponding value.
|
||||
*/
|
||||
static int propagateConstantExprRewrite(Walker *pWalker, Expr *pExpr){
|
||||
int i;
|
||||
WhereConst *pConst;
|
||||
if( pExpr->op!=TK_COLUMN ) return WRC_Continue;
|
||||
if( ExprHasProperty(pExpr, EP_FixedCol) ) return WRC_Continue;
|
||||
pConst = pWalker->u.pConst;
|
||||
for(i=0; i<pConst->nConst; i++){
|
||||
Expr *pColumn = pConst->apExpr[i*2];
|
||||
if( pColumn==pExpr ) continue;
|
||||
if( pColumn->iTable!=pExpr->iTable ) continue;
|
||||
if( pColumn->iColumn!=pExpr->iColumn ) continue;
|
||||
/* A match is found. Add the EP_FixedCol property */
|
||||
pConst->nChng++;
|
||||
ExprClearProperty(pExpr, EP_Leaf);
|
||||
ExprSetProperty(pExpr, EP_FixedCol);
|
||||
assert( pExpr->pLeft==0 );
|
||||
pExpr->pLeft = sqlite3ExprDup(pConst->pParse->db, pConst->apExpr[i*2+1], 0);
|
||||
break;
|
||||
}
|
||||
return WRC_Prune;
|
||||
}
|
||||
|
||||
/*
|
||||
** The WHERE-clause constant propagation optimization.
|
||||
**
|
||||
** If the WHERE clause contains terms of the form COLUMN=CONSTANT or
|
||||
** CONSTANT=COLUMN that must be tree (in other words, if the terms top-level
|
||||
** AND-connected terms that are not part of a ON clause from a LEFT JOIN)
|
||||
** then throughout the query replace all other occurrences of COLUMN
|
||||
** with CONSTANT within the WHERE clause.
|
||||
**
|
||||
** For example, the query:
|
||||
**
|
||||
** SELECT * FROM t1, t2, t3 WHERE t1.a=39 AND t2.b=t1.a AND t3.c=t2.b
|
||||
**
|
||||
** Is transformed into
|
||||
**
|
||||
** SELECT * FROM t1, t2, t3 WHERE t1.a=39 AND t2.b=39 AND t3.c=39
|
||||
**
|
||||
** Return true if any transformations where made and false if not.
|
||||
**
|
||||
** Implementation note: Constant propagation is tricky due to affinity
|
||||
** and collating sequence interactions. Consider this example:
|
||||
**
|
||||
** CREATE TABLE t1(a INT,b TEXT);
|
||||
** INSERT INTO t1 VALUES(123,'0123');
|
||||
** SELECT * FROM t1 WHERE a=123 AND b=a;
|
||||
** SELECT * FROM t1 WHERE a=123 AND b=123;
|
||||
**
|
||||
** The two SELECT statements above should return different answers. b=a
|
||||
** is alway true because the comparison uses numeric affinity, but b=123
|
||||
** is false because it uses text affinity and '0123' is not the same as '123'.
|
||||
** To work around this, the expression tree is not actually changed from
|
||||
** "b=a" to "b=123" but rather the "a" in "b=a" is tagged with EP_FixedCol
|
||||
** and the "123" value is hung off of the pLeft pointer. Code generator
|
||||
** routines know to generate the constant "123" instead of looking up the
|
||||
** column value. Also, to avoid collation problems, this optimization is
|
||||
** only attempted if the "a=123" term uses the default BINARY collation.
|
||||
*/
|
||||
static int propagateConstants(
|
||||
Parse *pParse, /* The parsing context */
|
||||
Select *p /* The query in which to propagate constants */
|
||||
){
|
||||
WhereConst x;
|
||||
Walker w;
|
||||
int nChng = 0;
|
||||
x.pParse = pParse;
|
||||
do{
|
||||
x.nConst = 0;
|
||||
x.nChng = 0;
|
||||
x.apExpr = 0;
|
||||
findConstInWhere(&x, p->pWhere);
|
||||
if( x.nConst ){
|
||||
memset(&w, 0, sizeof(w));
|
||||
w.pParse = pParse;
|
||||
w.xExprCallback = propagateConstantExprRewrite;
|
||||
w.xSelectCallback = sqlite3SelectWalkNoop;
|
||||
w.xSelectCallback2 = 0;
|
||||
w.walkerDepth = 0;
|
||||
w.u.pConst = &x;
|
||||
sqlite3WalkExpr(&w, p->pWhere);
|
||||
sqlite3DbFree(x.pParse->db, x.apExpr);
|
||||
nChng += x.nChng;
|
||||
}
|
||||
}while( x.nChng );
|
||||
return nChng;
|
||||
}
|
||||
|
||||
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
|
||||
/*
|
||||
@ -5599,6 +5760,25 @@ int sqlite3Select(
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Do the WHERE-clause constant propagation optimization if this is
|
||||
** a join. No need to speed time on this operation for non-join queries
|
||||
** as the equivalent optimization will be handled by query planner in
|
||||
** sqlite3WhereBegin().
|
||||
*/
|
||||
if( pTabList->nSrc>1
|
||||
&& OptimizationEnabled(db, SQLITE_PropagateConst)
|
||||
&& propagateConstants(pParse, p)
|
||||
){
|
||||
#if SELECTTRACE_ENABLED
|
||||
if( sqlite3SelectTrace & 0x100 ){
|
||||
SELECTTRACE(0x100,pParse,p,("After constant propagation:\n"));
|
||||
sqlite3TreeViewSelect(0, p, 0);
|
||||
}
|
||||
#endif
|
||||
}else{
|
||||
SELECTTRACE(0x100,pParse,p,("Constant propagation not helpful\n"));
|
||||
}
|
||||
|
||||
/* For each term in the FROM clause, do two things:
|
||||
** (1) Authorized unreferenced tables
|
||||
** (2) Generate code for all sub-queries
|
||||
|
@ -1584,6 +1584,7 @@ struct sqlite3 {
|
||||
#define SQLITE_PushDown 0x1000 /* The push-down optimization */
|
||||
#define SQLITE_SimplifyJoin 0x2000 /* Convert LEFT JOIN to JOIN */
|
||||
#define SQLITE_SkipScan 0x4000 /* Skip-scans */
|
||||
#define SQLITE_PropagateConst 0x8000 /* The constant propagation opt */
|
||||
#define SQLITE_AllOpts 0xffff /* All optimizations */
|
||||
|
||||
/*
|
||||
@ -2478,7 +2479,7 @@ struct Expr {
|
||||
#define EP_FromJoin 0x000001 /* Originates in ON/USING clause of outer join */
|
||||
#define EP_Agg 0x000002 /* Contains one or more aggregate functions */
|
||||
#define EP_HasFunc 0x000004 /* Contains one or more functions of any kind */
|
||||
/* 0x000008 // available for use */
|
||||
#define EP_FixedCol 0x000008 /* TK_Column with a known fixed value */
|
||||
#define EP_Distinct 0x000010 /* Aggregate function with DISTINCT keyword */
|
||||
#define EP_VarSelect 0x000020 /* pSelect is correlated, not constant */
|
||||
#define EP_DblQuoted 0x000040 /* token.z was originally in "..." */
|
||||
@ -3436,6 +3437,7 @@ struct Walker {
|
||||
ExprList *pGroupBy; /* GROUP BY clause */
|
||||
Select *pSelect; /* HAVING to WHERE clause ctx */
|
||||
struct WindowRewrite *pRewrite; /* Window rewrite context */
|
||||
struct WhereConst *pConst; /* WHERE clause constants */
|
||||
} u;
|
||||
};
|
||||
|
||||
@ -4169,6 +4171,7 @@ int sqlite3MemdbInit(void);
|
||||
const char *sqlite3ErrStr(int);
|
||||
int sqlite3ReadSchema(Parse *pParse);
|
||||
CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int);
|
||||
int sqlite3IsBinary(const CollSeq*);
|
||||
CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName);
|
||||
CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr);
|
||||
CollSeq *sqlite3ExprNNCollSeq(Parse *pParse, Expr *pExpr);
|
||||
|
@ -374,6 +374,9 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
|
||||
sqlite3TreeViewLine(pView, "{%d:%d}%s",
|
||||
pExpr->iTable, pExpr->iColumn, zFlgs);
|
||||
}
|
||||
if( ExprHasProperty(pExpr, EP_FixedCol) ){
|
||||
sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TK_INTEGER: {
|
||||
|
@ -3205,7 +3205,7 @@ const char *sqlite3_vtab_collation(sqlite3_index_info *pIdxInfo, int iCons){
|
||||
if( pX->pLeft ){
|
||||
pC = sqlite3BinaryCompareCollSeq(pHidden->pParse, pX->pLeft, pX->pRight);
|
||||
}
|
||||
zRet = (pC ? pC->zName : "BINARY");
|
||||
zRet = (pC ? pC->zName : sqlite3StrBINARY);
|
||||
}
|
||||
return zRet;
|
||||
}
|
||||
|
@ -883,7 +883,7 @@ static int codeCursorHintIsOrFunction(Walker *pWalker, Expr *pExpr){
|
||||
static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){
|
||||
int rc = WRC_Continue;
|
||||
struct CCurHint *pHint = pWalker->u.pCCurHint;
|
||||
if( pExpr->op==TK_COLUMN ){
|
||||
if( pExpr->op==TK_COLUMN && !ExprHasProperty(pExpr, EP_FixedCol) ){
|
||||
if( pExpr->iTable!=pHint->iTabCur ){
|
||||
Vdbe *v = pWalker->pParse->pVdbe;
|
||||
int reg = ++pWalker->pParse->nMem; /* Register for column value */
|
||||
|
@ -859,7 +859,7 @@ static int termIsEquivalence(Parse *pParse, Expr *pExpr){
|
||||
return 0;
|
||||
}
|
||||
pColl = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft, pExpr->pRight);
|
||||
if( pColl==0 || sqlite3StrICmp(pColl->zName, "BINARY")==0 ) return 1;
|
||||
if( sqlite3IsBinary(pColl) ) return 1;
|
||||
return sqlite3ExprCollSeqMatch(pParse, pExpr->pLeft, pExpr->pRight);
|
||||
}
|
||||
|
||||
@ -1200,7 +1200,7 @@ static void exprAnalyze(
|
||||
}
|
||||
*pC = c + 1;
|
||||
}
|
||||
zCollSeqName = noCase ? "NOCASE" : "BINARY";
|
||||
zCollSeqName = noCase ? "NOCASE" : sqlite3StrBINARY;
|
||||
pNewExpr1 = sqlite3ExprDup(db, pLeft, 0);
|
||||
pNewExpr1 = sqlite3PExpr(pParse, TK_GE,
|
||||
sqlite3ExprAddCollateString(pParse,pNewExpr1,zCollSeqName),
|
||||
@ -1450,7 +1450,7 @@ void sqlite3WhereClauseClear(WhereClause *pWC){
|
||||
*/
|
||||
Bitmask sqlite3WhereExprUsageNN(WhereMaskSet *pMaskSet, Expr *p){
|
||||
Bitmask mask;
|
||||
if( p->op==TK_COLUMN ){
|
||||
if( p->op==TK_COLUMN && !ExprHasProperty(p, EP_FixedCol) ){
|
||||
return sqlite3WhereGetMask(pMaskSet, p->iTable);
|
||||
}else if( ExprHasProperty(p, EP_TokenOnly|EP_Leaf) ){
|
||||
assert( p->op!=TK_IF_NULL_ROW );
|
||||
|
70
test/whereL.test
Normal file
70
test/whereL.test
Normal file
@ -0,0 +1,70 @@
|
||||
# 2018-07-26
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this file is testing the WHERE-clause constant propagation
|
||||
# optimization.
|
||||
#
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set ::testprefix whereL
|
||||
|
||||
do_execsql_test 100 {
|
||||
CREATE TABLE t1(a INT PRIMARY KEY, b, c, d, e);
|
||||
CREATE TABLE t2(a INT PRIMARY KEY, f, g, h, i);
|
||||
CREATE TABLE t3(a INT PRIMARY KEY, j, k, l, m);
|
||||
CREATE VIEW v4 AS SELECT * FROM t2 UNION ALL SELECT * FROM t3;
|
||||
}
|
||||
do_eqp_test 110 {
|
||||
SELECT * FROM t1, v4 WHERE t1.a=?1 AND v4.a=t1.a;
|
||||
} {
|
||||
QUERY PLAN
|
||||
|--MATERIALIZE xxxxxx
|
||||
| `--COMPOUND QUERY
|
||||
| |--LEFT-MOST SUBQUERY
|
||||
| | `--SEARCH TABLE t2 USING INDEX sqlite_autoindex_t2_1 (a=?)
|
||||
| `--UNION ALL
|
||||
| `--SEARCH TABLE t3 USING INDEX sqlite_autoindex_t3_1 (a=?)
|
||||
|--SCAN SUBQUERY xxxxxx
|
||||
`--SEARCH TABLE t1 USING INDEX sqlite_autoindex_t1_1 (a=?)
|
||||
}
|
||||
|
||||
# The scan of the t1 table goes first since that enables the ORDER BY
|
||||
# sort to be omitted. This would not be possible without constant
|
||||
# propagation because without it the t1 table would depend on t3.
|
||||
#
|
||||
do_eqp_test 120 {
|
||||
SELECT * FROM t1, t2, t3
|
||||
WHERE t1.a=t2.a AND t2.a=t3.j AND t3.j=5
|
||||
ORDER BY t1.a;
|
||||
} {
|
||||
QUERY PLAN
|
||||
|--SEARCH TABLE t1 USING INDEX sqlite_autoindex_t1_1 (a=?)
|
||||
|--SEARCH TABLE t2 USING INDEX sqlite_autoindex_t2_1 (a=?)
|
||||
`--SCAN TABLE t3
|
||||
}
|
||||
|
||||
# Constant propagation in the face of collating sequences:
|
||||
#
|
||||
do_execsql_test 200 {
|
||||
CREATE TABLE c3(x COLLATE binary, y COLLATE nocase, z COLLATE binary);
|
||||
CREATE INDEX c3x ON c3(x);
|
||||
INSERT INTO c3 VALUES('ABC', 'ABC', 'abc');
|
||||
SELECT * FROM c3 WHERE x=y AND y=z AND z='abc';
|
||||
} {ABC ABC abc}
|
||||
|
||||
# If the constants are blindly propagated, as shown in the following
|
||||
# query, the wrong answer results:
|
||||
#
|
||||
do_execsql_test 201 {
|
||||
SELECT * FROM c3 WHERE x='abc' AND y='abc' AND z='abc';
|
||||
} {}
|
||||
|
||||
finish_test
|
Loading…
Reference in New Issue
Block a user