From 660ee55663fb8aa26a7ebd764ec5c94440bcd62f Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 26 Jul 2018 21:16:53 +0000 Subject: [PATCH 1/8] Initial implementation of the WHERE-clause constant propagation optimization. FossilOrigin-Name: 2fb82ad8ebb6434438c0d235b1239444fb08c8711cea2c5a9ed955fedd0acdec --- manifest | 20 ++++--- manifest.uuid | 2 +- src/select.c | 141 +++++++++++++++++++++++++++++++++++++++++++++++ src/sqliteInt.h | 2 + test/whereL.test | 39 +++++++++++++ 5 files changed, 195 insertions(+), 9 deletions(-) create mode 100644 test/whereL.test diff --git a/manifest b/manifest index a03887e107..7fe18e364a 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\sbuffer\soverread\sin\sfts5. -D 2018-07-25T15:25:55.074 +C Initial\simplementation\sof\sthe\sWHERE-clause\sconstant\spropagation\soptimization. +D 2018-07-26T21:16:53.742 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 0a3a6c81e6fcb969ff9106e882f0a08547014ba463cb6beca4c4efaecc924ee6 @@ -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 cd3993844ab1186e80069f9de2304e730732cfea1f718e603293792d4401d037 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 0da0d929642cacf99963e406d34e2e3be891a30168f99aefc1cb81c2c545a09b F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34 @@ -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 46492cf4b3b2bfa5bb8adb8d6565f31c010bf8f23baf66bcba4e38cec89117a2 F test/wherefault.test 1374c3aa198388925246475f84ad4cd5f9528864 F test/wherelfault.test 9012e4ef5259058b771606616bd007af5d154e64cc25fa9fd4170f6411db44e3 F test/wherelimit.test 592081800806d297dd7449b1030c863d2883d6d42901837ccd2e5a9bd962edb0 @@ -1752,7 +1753,10 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 6ee2950b272ede475e485bfaa7d413eaa81482fe9dd6452aeeaf95ff7938f7da -R b452b7474ada2f7df230e94f47eaea02 -U dan -Z 3eecc6d8fc02fe02d8a834ac76aa6a16 +P 0e3de8abbb0c7ae64e637776cb055ce79736f99a103e00e44d17a6b091b98c81 +R 83557e363f35588e2f481ff35d0d8054 +T *branch * propagate-const-opt +T *sym-propagate-const-opt * +T -sym-trunk * +U drh +Z 8488ca3ac81dbe859bc19508bb265e68 diff --git a/manifest.uuid b/manifest.uuid index e67b600db4..8c60a8812f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -0e3de8abbb0c7ae64e637776cb055ce79736f99a103e00e44d17a6b091b98c81 \ No newline at end of file +2fb82ad8ebb6434438c0d235b1239444fb08c8711cea2c5a9ed955fedd0acdec \ No newline at end of file diff --git a/src/select.c b/src/select.c index dd8c89cbce..a0f140ef92 100644 --- a/src/select.c +++ b/src/select.c @@ -4074,7 +4074,134 @@ static int flattenSubquery( } #endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */ +/* +** A structure to keep track of all of the column values that must be +** constant in a WHERE clause. +*/ +typedef struct WhereConst WhereConst; +struct WhereConst { + sqlite3 *db; /* Database pointer, used by sqlite3DbRealloc() */ + 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 CONSTANT */ +}; +/* +** Add a new entry to the pConst object +*/ +static void constInsert( + WhereConst *pConst, + Expr *pColumn, + Expr *pValue +){ + pConst->nConst++; + pConst->apExpr = sqlite3DbReallocOrFree(pConst->db, pConst->apExpr, + pConst->nConst*2*sizeof(Expr*)); + if( pConst->apExpr==0 ){ + pConst->nConst = 0; + }else{ + pConst->apExpr[pConst->nConst*2-2] = pColumn; + pConst->apExpr[pConst->nConst*2-1] = pValue; + } +} + +/* +** Find all instances of COLUMN=CONSTANT or CONSTANT=COLUMN in pExpr that +** must be true (that are part of the AND-connected terms) and add each +** to pConst. +*/ +static void findConstInWhere(WhereConst *pConst, Expr *pExpr){ + 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; + assert( pExpr->pRight!=0 ); + assert( pExpr->pLeft!=0 ); + if( pExpr->pRight->op==TK_COLUMN && sqlite3ExprIsConstant(pExpr->pLeft) ){ + constInsert(pConst, pExpr->pRight, pExpr->pLeft); + }else + if( pExpr->pLeft->op==TK_COLUMN && sqlite3ExprIsConstant(pExpr->pRight) ){ + constInsert(pConst, pExpr->pLeft, pExpr->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; + pConst = pWalker->u.pConst; + for(i=0; inConst; 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. Transform the COLUMN into a CONSTANT */ + pConst->nChng++; + ExprClearProperty(pExpr, EP_Leaf); + pExpr->op = TK_UPLUS; + pExpr->pLeft = sqlite3ExprDup(pConst->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. +** +** 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. +*/ +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.db = pParse->db; + 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; + sqlite3WalkSelect(&w, p); + sqlite3DbFree(x.db, x.apExpr); + nChng += x.nChng; + } + }while( x.nChng ); + return nChng; +} #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) /* @@ -5663,6 +5790,20 @@ int sqlite3Select( */ pParse->nHeight += sqlite3SelectExprHeight(p); + /* Do the constant propagation optimization */ + if( 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 possible\n")); + } + /* Make copies of constant WHERE-clause terms in the outer query down ** inside the subquery. This can help the subquery to run more efficiently. */ diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 2c52dfec5c..9dbe683398 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -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 */ /* @@ -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; }; diff --git a/test/whereL.test b/test/whereL.test new file mode 100644 index 0000000000..04c8f066cc --- /dev/null +++ b/test/whereL.test @@ -0,0 +1,39 @@ +# 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=?) +} + +finish_test From 24e1116e0f0d1e0a6db4dbac8a1d58e4a2eff164 Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 26 Jul 2018 23:47:11 +0000 Subject: [PATCH 2/8] Generalize the constant propagation optimization so that it applies on every WHERE close, not just those that contain a subquery. This then demonstrates that the current implementation is inadequate since it does not take into account collating sequences. FossilOrigin-Name: 57eb2abd5b270d65be5e0f138f0d46899fa6091df3ba20b0ea7ef04244a15d48 --- manifest | 19 ++++++++----------- manifest.uuid | 2 +- src/expr.c | 2 +- src/select.c | 29 +++++++++++++++-------------- test/whereL.test | 15 +++++++++++++++ 5 files changed, 40 insertions(+), 27 deletions(-) diff --git a/manifest b/manifest index 7fe18e364a..4a1a680ce5 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Initial\simplementation\sof\sthe\sWHERE-clause\sconstant\spropagation\soptimization. -D 2018-07-26T21:16:53.742 +C Generalize\sthe\sconstant\spropagation\soptimization\sso\sthat\sit\sapplies\son\severy\nWHERE\sclose,\snot\sjust\sthose\sthat\scontain\sa\ssubquery.\s\sThis\sthen\sdemonstrates\nthat\sthe\scurrent\simplementation\sis\sinadequate\ssince\sit\sdoes\snot\stake\sinto\naccount\scollating\ssequences. +D 2018-07-26T23:47:11.108 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 8187c1be1003230f027bfc5f5a9830aa43d55beb67d87f4a2589d125749fbcfd F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c b1da9ef8dc834603bb0d28972378a7ce65897847f9a1e89ab800bbdf24c788ee F src/func.c 7c288b4ce309b5a8b8473514b88e1f8e69a80134509a8c0db8e39c858e367e7f @@ -498,7 +498,7 @@ F src/printf.c 7f6f3cba8e0c49c19e30a1ff4e9aeda6e06814dcbad4b664a69e1b6cb6e7e365 F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384 F src/resolve.c 797088662ed61102485e3070ba3b3f7828bd5ef6a588223ba6865d77d52f6cea F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac -F src/select.c cd3993844ab1186e80069f9de2304e730732cfea1f718e603293792d4401d037 +F src/select.c 81c6517a8d7b6aae805aaa4171187390f72988d1ceec343ad2f51be09513b289 F src/shell.c.in f6ebd05c461805a7c708333cd645e74e0a93560d2118f5adb73a75d8c9cf6b01 F src/sqlite.h.in c6451bb876adced3aba5b1682c6317d215c5eceaba21a6ce979e71a0b8d0bf95 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 @@ -1617,7 +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 46492cf4b3b2bfa5bb8adb8d6565f31c010bf8f23baf66bcba4e38cec89117a2 +F test/whereL.test eca38f3f9e056bec962c3cf9abb8825a1701311a3fdc281471460cc127618714 F test/wherefault.test 1374c3aa198388925246475f84ad4cd5f9528864 F test/wherelfault.test 9012e4ef5259058b771606616bd007af5d154e64cc25fa9fd4170f6411db44e3 F test/wherelimit.test 592081800806d297dd7449b1030c863d2883d6d42901837ccd2e5a9bd962edb0 @@ -1753,10 +1753,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 0e3de8abbb0c7ae64e637776cb055ce79736f99a103e00e44d17a6b091b98c81 -R 83557e363f35588e2f481ff35d0d8054 -T *branch * propagate-const-opt -T *sym-propagate-const-opt * -T -sym-trunk * +P 2fb82ad8ebb6434438c0d235b1239444fb08c8711cea2c5a9ed955fedd0acdec +R aac189787e29efcfb7af237e9604f0a0 U drh -Z 8488ca3ac81dbe859bc19508bb265e68 +Z b571d91896795a40b7aa465c4c8e4005 diff --git a/manifest.uuid b/manifest.uuid index 8c60a8812f..db9ef1c737 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -2fb82ad8ebb6434438c0d235b1239444fb08c8711cea2c5a9ed955fedd0acdec \ No newline at end of file +57eb2abd5b270d65be5e0f138f0d46899fa6091df3ba20b0ea7ef04244a15d48 \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 019bf17b99..6e5100a224 100644 --- a/src/expr.c +++ b/src/expr.c @@ -4935,7 +4935,7 @@ int sqlite3ExprCompare(Parse *pParse, Expr *pA, Expr *pB, int iTab){ if( sqlite3StrICmp(pA->u.zToken,pB->u.zToken)!=0 ) return 2; }else if( pA->op==TK_COLLATE ){ if( sqlite3_stricmp(pA->u.zToken,pB->u.zToken)!=0 ) return 2; - }else if( strcmp(pA->u.zToken,pB->u.zToken)!=0 ){ + }else if( pA->op!=TK_UPLUS && strcmp(pA->u.zToken,pB->u.zToken)!=0 ){ return 2; } } diff --git a/src/select.c b/src/select.c index a0f140ef92..2060524c49 100644 --- a/src/select.c +++ b/src/select.c @@ -4100,6 +4100,7 @@ static void constInsert( if( pConst->apExpr==0 ){ pConst->nConst = 0; }else{ + while( pValue->op==TK_UPLUS ) pValue = pValue->pLeft; pConst->apExpr[pConst->nConst*2-2] = pColumn; pConst->apExpr[pConst->nConst*2-1] = pValue; } @@ -5726,6 +5727,20 @@ int sqlite3Select( } #endif + /* Do the constant propagation optimization */ + if( 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 possible\n")); + } + /* For each term in the FROM clause, do two things: ** (1) Authorized unreferenced tables ** (2) Generate code for all sub-queries @@ -5790,20 +5805,6 @@ int sqlite3Select( */ pParse->nHeight += sqlite3SelectExprHeight(p); - /* Do the constant propagation optimization */ - if( 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 possible\n")); - } - /* Make copies of constant WHERE-clause terms in the outer query down ** inside the subquery. This can help the subquery to run more efficiently. */ diff --git a/test/whereL.test b/test/whereL.test index 04c8f066cc..33e612b855 100644 --- a/test/whereL.test +++ b/test/whereL.test @@ -36,4 +36,19 @@ do_eqp_test 110 { `--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 +} + finish_test From 7de7602eb7deac00e4bb5c2f44f82f5389cbcb83 Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 26 Jul 2018 23:54:19 +0000 Subject: [PATCH 3/8] Add a test case demonstrating the collation problem with constant propagation. FossilOrigin-Name: 50add839fd95665bd67a6ae5de8346fd09e83904bbcbad26fad280dff86d9e93 --- manifest | 12 ++++++------ manifest.uuid | 2 +- test/whereL.test | 16 ++++++++++++++++ 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/manifest b/manifest index 4a1a680ce5..73c3e5b372 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Generalize\sthe\sconstant\spropagation\soptimization\sso\sthat\sit\sapplies\son\severy\nWHERE\sclose,\snot\sjust\sthose\sthat\scontain\sa\ssubquery.\s\sThis\sthen\sdemonstrates\nthat\sthe\scurrent\simplementation\sis\sinadequate\ssince\sit\sdoes\snot\stake\sinto\naccount\scollating\ssequences. -D 2018-07-26T23:47:11.108 +C Add\sa\stest\scase\sdemonstrating\sthe\scollation\sproblem\swith\sconstant\spropagation. +D 2018-07-26T23:54:19.662 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 0a3a6c81e6fcb969ff9106e882f0a08547014ba463cb6beca4c4efaecc924ee6 @@ -1617,7 +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 eca38f3f9e056bec962c3cf9abb8825a1701311a3fdc281471460cc127618714 +F test/whereL.test 786ae3e0b6d8f7c9b83a98bffcd9d458b0de47c6a9f9dcf872043f54a4752c68 F test/wherefault.test 1374c3aa198388925246475f84ad4cd5f9528864 F test/wherelfault.test 9012e4ef5259058b771606616bd007af5d154e64cc25fa9fd4170f6411db44e3 F test/wherelimit.test 592081800806d297dd7449b1030c863d2883d6d42901837ccd2e5a9bd962edb0 @@ -1753,7 +1753,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 2fb82ad8ebb6434438c0d235b1239444fb08c8711cea2c5a9ed955fedd0acdec -R aac189787e29efcfb7af237e9604f0a0 +P 57eb2abd5b270d65be5e0f138f0d46899fa6091df3ba20b0ea7ef04244a15d48 +R 4901cf7d6c93780d74bf2f77c4b5611e U drh -Z b571d91896795a40b7aa465c4c8e4005 +Z e93689647fb1d0f73e5b2a94dfb414a1 diff --git a/manifest.uuid b/manifest.uuid index db9ef1c737..bcb4361963 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -57eb2abd5b270d65be5e0f138f0d46899fa6091df3ba20b0ea7ef04244a15d48 \ No newline at end of file +50add839fd95665bd67a6ae5de8346fd09e83904bbcbad26fad280dff86d9e93 \ No newline at end of file diff --git a/test/whereL.test b/test/whereL.test index 33e612b855..177efa1ddf 100644 --- a/test/whereL.test +++ b/test/whereL.test @@ -51,4 +51,20 @@ do_eqp_test 120 { `--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 From efad2e23668ea5cbd744b6abde43058de45fb53a Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 27 Jul 2018 16:57:11 +0000 Subject: [PATCH 4/8] Constant propagation is now restricted to just the WHERE clause. The mechanism is changed to take affinity and collation into account. This seems to give correct answers. But the search for constant propagation costs 4 million cycles in the speed test. FossilOrigin-Name: 82c67efb723dba387964f690cd459b420e59e3367d9589016597a76531596391 --- manifest | 22 +++++++------- manifest.uuid | 2 +- src/expr.c | 23 +++++++++++++-- src/select.c | 76 +++++++++++++++++++++++++++++++++++-------------- src/sqliteInt.h | 3 +- src/treeview.c | 3 ++ src/wherecode.c | 2 +- src/whereexpr.c | 4 +-- 8 files changed, 94 insertions(+), 41 deletions(-) diff --git a/manifest b/manifest index 73c3e5b372..79cc142c4a 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sa\stest\scase\sdemonstrating\sthe\scollation\sproblem\swith\sconstant\spropagation. -D 2018-07-26T23:54:19.662 +C Constant\spropagation\sis\snow\srestricted\sto\sjust\sthe\sWHERE\sclause.\sThe\nmechanism\sis\schanged\sto\stake\saffinity\sand\scollation\sinto\saccount.\s\sThis\nseems\sto\sgive\scorrect\sanswers.\s\sBut\sthe\ssearch\sfor\sconstant\spropagation\ncosts\s4\smillion\scycles\sin\sthe\sspeed\stest. +D 2018-07-27T16:57:11.322 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 8187c1be1003230f027bfc5f5a9830aa43d55beb67d87f4a2589d125749fbcfd +F src/expr.c af489eb4dac501d06c1f05b9f27f7fc37a05582b9f9b7724e0e1ccc78ae8a530 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c b1da9ef8dc834603bb0d28972378a7ce65897847f9a1e89ab800bbdf24c788ee F src/func.c 7c288b4ce309b5a8b8473514b88e1f8e69a80134509a8c0db8e39c858e367e7f @@ -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 81c6517a8d7b6aae805aaa4171187390f72988d1ceec343ad2f51be09513b289 +F src/select.c 7d2a980be754def09d3458c9eba5ac781ec2962c3415e6ce6d3e00ca100468f8 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 0da0d929642cacf99963e406d34e2e3be891a30168f99aefc1cb81c2c545a09b +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 @@ -585,8 +585,8 @@ F src/wal.h 8de5d2d3de0956d6f6cb48c83a4012d5f227b8fe940f3a349a4b7e85ebcb492a F src/walker.c ba7225773931760cf60bf22f34d0cce2588df7ce5ce0f215a52eb88234b55ac4 F src/where.c 2d313b446758317b60626763d0e1285e04b04c061ce94945dcfffad9525badc1 F src/whereInt.h b90ef9b9707ef750eab2a7a080c48fb4900315033274689def32d0cf5a81ebe4 -F src/wherecode.c fe23a55294b4c94bf658d2a6eb7996170dd563bf33af4c3e5d71aff3483e4b08 -F src/whereexpr.c 571618c67a3eb5ce0f1158c2792c1aee9b4a4a264392fc4fb1b35467f80abf9a +F src/wherecode.c 2c552dfe50d06e0916dbd49a180e4bf0accfce6d17d46a2dfeea8f75d2b5861b +F src/whereexpr.c 7d30c744f37e8bd53811f88fd1d949f6145d24ce77a6f51b252e2b903dc4434e F src/window.c c61434ce7e35b7d76b3321dec39e10e79061c10eed1e3d7976c87dbdd77aefb5 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd @@ -1753,7 +1753,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 57eb2abd5b270d65be5e0f138f0d46899fa6091df3ba20b0ea7ef04244a15d48 -R 4901cf7d6c93780d74bf2f77c4b5611e +P 50add839fd95665bd67a6ae5de8346fd09e83904bbcbad26fad280dff86d9e93 +R 50f5324ffb4955a3d4663001ed61326d U drh -Z e93689647fb1d0f73e5b2a94dfb414a1 +Z f7259f5866467f9069a6566db546a485 diff --git a/manifest.uuid b/manifest.uuid index bcb4361963..f10ad29d73 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -50add839fd95665bd67a6ae5de8346fd09e83904bbcbad26fad280dff86d9e93 \ No newline at end of file +82c67efb723dba387964f690cd459b420e59e3367d9589016597a76531596391 \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 6e5100a224..69270959fb 100644 --- a/src/expr.c +++ b/src/expr.c @@ -328,6 +328,15 @@ CollSeq *sqlite3BinaryCompareCollSeq( return pColl; } +/* +** Return true if CollSeq is the default built-in BINARY. +*/ +int sqlite3IsBinary(const CollSeq *p){ + if( p==0 ) return 1; + if( sqlite3_stricmp(p->zName,"BINARY")==0 ) return 1; + return 0; +} + /* ** Generate code for a comparison operator. */ @@ -1839,6 +1848,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 +1939,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 +3593,10 @@ expr_code_doover: } case TK_COLUMN: { int iTab = pExpr->iTable; + if( ExprHasProperty(pExpr, EP_FixedCol) ){ + pExpr = pExpr->pLeft; + goto expr_code_doover; + } if( iTab<0 ){ if( pParse->iSelfTab<0 ){ /* Generating CHECK constraints or inserting into partial index */ @@ -4935,14 +4951,15 @@ int sqlite3ExprCompare(Parse *pParse, Expr *pA, Expr *pB, int iTab){ if( sqlite3StrICmp(pA->u.zToken,pB->u.zToken)!=0 ) return 2; }else if( pA->op==TK_COLLATE ){ if( sqlite3_stricmp(pA->u.zToken,pB->u.zToken)!=0 ) return 2; - }else if( pA->op!=TK_UPLUS && strcmp(pA->u.zToken,pB->u.zToken)!=0 ){ + }else if( strcmp(pA->u.zToken,pB->u.zToken)!=0 ){ return 2; } } 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 ); diff --git a/src/select.c b/src/select.c index 2060524c49..d74af40989 100644 --- a/src/select.c +++ b/src/select.c @@ -4075,15 +4075,15 @@ static int flattenSubquery( #endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */ /* -** A structure to keep track of all of the column values that must be -** constant in a WHERE clause. +** 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 { - sqlite3 *db; /* Database pointer, used by sqlite3DbRealloc() */ + 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 CONSTANT */ + Expr **apExpr; /* [i*2] is COLUMN and [i*2+1] is VALUE */ }; /* @@ -4095,23 +4095,26 @@ static void constInsert( Expr *pValue ){ pConst->nConst++; - pConst->apExpr = sqlite3DbReallocOrFree(pConst->db, pConst->apExpr, + pConst->apExpr = sqlite3DbReallocOrFree(pConst->pParse->db, pConst->apExpr, pConst->nConst*2*sizeof(Expr*)); if( pConst->apExpr==0 ){ pConst->nConst = 0; }else{ - while( pValue->op==TK_UPLUS ) pValue = pValue->pLeft; + if( ExprHasProperty(pValue, EP_FixedCol) ) pValue = pValue->pLeft; pConst->apExpr[pConst->nConst*2-2] = pColumn; pConst->apExpr[pConst->nConst*2-1] = pValue; } } /* -** Find all instances of COLUMN=CONSTANT or CONSTANT=COLUMN in pExpr that -** must be true (that are part of the AND-connected terms) and add each -** to pConst. +** 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; + CollSeq *pColl; if( pExpr==0 ) return; if( ExprHasProperty(pExpr, EP_FromJoin) ) return; if( pExpr->op==TK_AND ){ @@ -4120,13 +4123,22 @@ static void findConstInWhere(WhereConst *pConst, Expr *pExpr){ return; } if( pExpr->op!=TK_EQ ) return; - assert( pExpr->pRight!=0 ); - assert( pExpr->pLeft!=0 ); - if( pExpr->pRight->op==TK_COLUMN && sqlite3ExprIsConstant(pExpr->pLeft) ){ - constInsert(pConst, pExpr->pRight, pExpr->pLeft); + pRight = pExpr->pRight; + pLeft = pExpr->pLeft; + assert( pRight!=0 ); + assert( pLeft!=0 ); + pColl = sqlite3BinaryCompareCollSeq(pConst->pParse, pLeft, pRight); + if( !sqlite3IsBinary(pColl) ) return; + if( pRight->op==TK_COLUMN + && !ExprHasProperty(pRight, EP_FixedCol) + && sqlite3ExprIsConstant(pLeft) + ){ + constInsert(pConst, pRight, pLeft); }else - if( pExpr->pLeft->op==TK_COLUMN && sqlite3ExprIsConstant(pExpr->pRight) ){ - constInsert(pConst, pExpr->pLeft, pExpr->pRight); + if( pLeft->op==TK_COLUMN + && !ExprHasProperty(pLeft, EP_FixedCol) + && sqlite3ExprIsConstant(pRight) ){ + constInsert(pConst, pLeft, pRight); } } @@ -4140,17 +4152,19 @@ 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; inConst; 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. Transform the COLUMN into a CONSTANT */ + /* A match is found. Add the EP_FixedCol property */ pConst->nChng++; ExprClearProperty(pExpr, EP_Leaf); - pExpr->op = TK_UPLUS; - pExpr->pLeft = sqlite3ExprDup(pConst->db, pConst->apExpr[i*2+1], 0); + ExprSetProperty(pExpr, EP_FixedCol); + assert( pExpr->pLeft==0 ); + pExpr->pLeft = sqlite3ExprDup(pConst->pParse->db, pConst->apExpr[i*2+1], 0); break; } return WRC_Prune; @@ -4163,7 +4177,7 @@ static int propagateConstantExprRewrite(Walker *pWalker, Expr *pExpr){ ** 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. +** with CONSTANT within the WHERE clause. ** ** For example, the query: ** @@ -4174,6 +4188,24 @@ static int propagateConstantExprRewrite(Walker *pWalker, Expr *pExpr){ ** 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 */ @@ -4182,7 +4214,7 @@ static int propagateConstants( WhereConst x; Walker w; int nChng = 0; - x.db = pParse->db; + x.pParse = pParse; do{ x.nConst = 0; x.nChng = 0; @@ -4196,8 +4228,8 @@ static int propagateConstants( w.xSelectCallback2 = 0; w.walkerDepth = 0; w.u.pConst = &x; - sqlite3WalkSelect(&w, p); - sqlite3DbFree(x.db, x.apExpr); + sqlite3WalkExpr(&w, p->pWhere); + sqlite3DbFree(x.pParse->db, x.apExpr); nChng += x.nChng; } }while( x.nChng ); diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 9dbe683398..7c4d46a40a 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -2479,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 "..." */ @@ -4171,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); diff --git a/src/treeview.c b/src/treeview.c index 7605fa2cb3..cde776d0fa 100644 --- a/src/treeview.c +++ b/src/treeview.c @@ -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: { diff --git a/src/wherecode.c b/src/wherecode.c index 3bb220d2ed..1f24c578b3 100644 --- a/src/wherecode.c +++ b/src/wherecode.c @@ -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 */ diff --git a/src/whereexpr.c b/src/whereexpr.c index 6f6e660ad2..4abadb1878 100644 --- a/src/whereexpr.c +++ b/src/whereexpr.c @@ -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); } @@ -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 ); From 7810ab646453c143966dad28f51e1a1950c89f88 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 27 Jul 2018 17:51:20 +0000 Subject: [PATCH 5/8] Only run the constant propagation optimization on joins since that is the only scenario where it is useful. This saves prepare time for the common case of a simple query. FossilOrigin-Name: 598d608359005b13fa1151c6c69f2fd12ef3ab7f563a035fc4a6f3c569dc6c67 --- manifest | 18 +++++++++--------- manifest.uuid | 2 +- src/expr.c | 4 +--- src/select.c | 11 ++++++++--- src/where.c | 2 +- src/whereexpr.c | 2 +- 6 files changed, 21 insertions(+), 18 deletions(-) diff --git a/manifest b/manifest index 79cc142c4a..8733168556 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Constant\spropagation\sis\snow\srestricted\sto\sjust\sthe\sWHERE\sclause.\sThe\nmechanism\sis\schanged\sto\stake\saffinity\sand\scollation\sinto\saccount.\s\sThis\nseems\sto\sgive\scorrect\sanswers.\s\sBut\sthe\ssearch\sfor\sconstant\spropagation\ncosts\s4\smillion\scycles\sin\sthe\sspeed\stest. -D 2018-07-27T16:57:11.322 +C Only\srun\sthe\sconstant\spropagation\soptimization\son\sjoins\ssince\sthat\sis\sthe\nonly\sscenario\swhere\sit\sis\suseful.\s\sThis\ssaves\sprepare\stime\sfor\sthe\scommon\ncase\sof\sa\ssimple\squery. +D 2018-07-27T17:51:20.481 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 af489eb4dac501d06c1f05b9f27f7fc37a05582b9f9b7724e0e1ccc78ae8a530 +F src/expr.c eaf12eb8eb1dcf6358ee32bb21fd31225783a28ca42b27b1cdc497cc6c356493 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c b1da9ef8dc834603bb0d28972378a7ce65897847f9a1e89ab800bbdf24c788ee F src/func.c 7c288b4ce309b5a8b8473514b88e1f8e69a80134509a8c0db8e39c858e367e7f @@ -498,7 +498,7 @@ F src/printf.c 7f6f3cba8e0c49c19e30a1ff4e9aeda6e06814dcbad4b664a69e1b6cb6e7e365 F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384 F src/resolve.c 797088662ed61102485e3070ba3b3f7828bd5ef6a588223ba6865d77d52f6cea F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac -F src/select.c 7d2a980be754def09d3458c9eba5ac781ec2962c3415e6ce6d3e00ca100468f8 +F src/select.c a86a20bd89ea4298267b1d2f44a8b14a53cb6ad1e75a555af5d57de5cf7abd3b F src/shell.c.in f6ebd05c461805a7c708333cd645e74e0a93560d2118f5adb73a75d8c9cf6b01 F src/sqlite.h.in c6451bb876adced3aba5b1682c6317d215c5eceaba21a6ce979e71a0b8d0bf95 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 @@ -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 2c552dfe50d06e0916dbd49a180e4bf0accfce6d17d46a2dfeea8f75d2b5861b -F src/whereexpr.c 7d30c744f37e8bd53811f88fd1d949f6145d24ce77a6f51b252e2b903dc4434e +F src/whereexpr.c dc34f0df69418dedb4619f7ad61b7d31f447971223540b957a1b836a62c0ce7b F src/window.c c61434ce7e35b7d76b3321dec39e10e79061c10eed1e3d7976c87dbdd77aefb5 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd @@ -1753,7 +1753,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 50add839fd95665bd67a6ae5de8346fd09e83904bbcbad26fad280dff86d9e93 -R 50f5324ffb4955a3d4663001ed61326d +P 82c67efb723dba387964f690cd459b420e59e3367d9589016597a76531596391 +R 25b438a30597294879dd2d1bc42efd58 U drh -Z f7259f5866467f9069a6566db546a485 +Z bbd08ff7c79abf3a0e619aafbe2d2c13 diff --git a/manifest.uuid b/manifest.uuid index f10ad29d73..5a7c8b3472 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -82c67efb723dba387964f690cd459b420e59e3367d9589016597a76531596391 \ No newline at end of file +598d608359005b13fa1151c6c69f2fd12ef3ab7f563a035fc4a6f3c569dc6c67 \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 69270959fb..98d93333bf 100644 --- a/src/expr.c +++ b/src/expr.c @@ -332,9 +332,7 @@ CollSeq *sqlite3BinaryCompareCollSeq( ** Return true if CollSeq is the default built-in BINARY. */ int sqlite3IsBinary(const CollSeq *p){ - if( p==0 ) return 1; - if( sqlite3_stricmp(p->zName,"BINARY")==0 ) return 1; - return 0; + return p==0 || sqlite3StrICmp(p->zName,sqlite3StrBINARY)==0; } /* diff --git a/src/select.c b/src/select.c index d74af40989..87bf5fa6e8 100644 --- a/src/select.c +++ b/src/select.c @@ -5759,8 +5759,13 @@ int sqlite3Select( } #endif - /* Do the constant propagation optimization */ - if( OptimizationEnabled(db, SQLITE_PropagateConst) + /* 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 @@ -5770,7 +5775,7 @@ int sqlite3Select( } #endif }else{ - SELECTTRACE(0x100,pParse,p,("Constant propagation not possible\n")); + SELECTTRACE(0x100,pParse,p,("Constant propagation not helpful\n")); } /* For each term in the FROM clause, do two things: diff --git a/src/where.c b/src/where.c index d4f88a27af..b7e51f3d94 100644 --- a/src/where.c +++ b/src/where.c @@ -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; } diff --git a/src/whereexpr.c b/src/whereexpr.c index 4abadb1878..752a0842c0 100644 --- a/src/whereexpr.c +++ b/src/whereexpr.c @@ -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), From bcd15938ae67554be43ba93c076bd2430cb62479 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 27 Jul 2018 18:12:40 +0000 Subject: [PATCH 6/8] Faster implementation of sqlite3IsBinary(). FossilOrigin-Name: be05d0db09f43cc3362c28273463d1d236af737a4f8a494cf1050da07ed0df47 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/expr.c | 10 +--------- src/main.c | 9 +++++++++ 4 files changed, 18 insertions(+), 17 deletions(-) diff --git a/manifest b/manifest index 8733168556..a1c63d4fe7 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Only\srun\sthe\sconstant\spropagation\soptimization\son\sjoins\ssince\sthat\sis\sthe\nonly\sscenario\swhere\sit\sis\suseful.\s\sThis\ssaves\sprepare\stime\sfor\sthe\scommon\ncase\sof\sa\ssimple\squery. -D 2018-07-27T17:51:20.481 +C Faster\simplementation\sof\ssqlite3IsBinary(). +D 2018-07-27T18:12:40.840 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 eaf12eb8eb1dcf6358ee32bb21fd31225783a28ca42b27b1cdc497cc6c356493 +F src/expr.c fe08e0dbf1c561491f879cf4bbf9d3be5ff8ccb9555f60093d3c56c0c37a37b3 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 @@ -1753,7 +1753,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 82c67efb723dba387964f690cd459b420e59e3367d9589016597a76531596391 -R 25b438a30597294879dd2d1bc42efd58 +P 598d608359005b13fa1151c6c69f2fd12ef3ab7f563a035fc4a6f3c569dc6c67 +R 1d79df50e5dd49c24c2c0d46db1dcbfe U drh -Z bbd08ff7c79abf3a0e619aafbe2d2c13 +Z d36b5ae00dc0d8f1b3add00c50463640 diff --git a/manifest.uuid b/manifest.uuid index 5a7c8b3472..16820a46c5 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -598d608359005b13fa1151c6c69f2fd12ef3ab7f563a035fc4a6f3c569dc6c67 \ No newline at end of file +be05d0db09f43cc3362c28273463d1d236af737a4f8a494cf1050da07ed0df47 \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 98d93333bf..5c9a29f63e 100644 --- a/src/expr.c +++ b/src/expr.c @@ -328,13 +328,6 @@ CollSeq *sqlite3BinaryCompareCollSeq( return pColl; } -/* -** Return true if CollSeq is the default built-in BINARY. -*/ -int sqlite3IsBinary(const CollSeq *p){ - return p==0 || sqlite3StrICmp(p->zName,sqlite3StrBINARY)==0; -} - /* ** Generate code for a comparison operator. */ @@ -3592,8 +3585,7 @@ expr_code_doover: case TK_COLUMN: { int iTab = pExpr->iTable; if( ExprHasProperty(pExpr, EP_FixedCol) ){ - pExpr = pExpr->pLeft; - goto expr_code_doover; + return sqlite3ExprCodeTarget(pParse, pExpr->pLeft,target); } if( iTab<0 ){ if( pParse->iSelfTab<0 ){ diff --git a/src/main.c b/src/main.c index 07f6688810..4ae5c7ecdd 100644 --- a/src/main.c +++ b/src/main.c @@ -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. ** From e081d73c464e8e6040b536b5140a6515929a41d0 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 27 Jul 2018 18:19:12 +0000 Subject: [PATCH 7/8] Performance improvement to sqlite3ExprCollSeq(). With this change, the performance of speed-check.sh is within 400,000 cycles of trunk. FossilOrigin-Name: a5f86f49b7d9e52546f234f7c3bcbac6b0f78aa55a71c44ca69e21bc31139f3e --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/expr.c | 16 ++++++++-------- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/manifest b/manifest index a1c63d4fe7..f2357567e3 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Faster\simplementation\sof\ssqlite3IsBinary(). -D 2018-07-27T18:12:40.840 +C Performance\simprovement\sto\ssqlite3ExprCollSeq().\s\sWith\sthis\schange,\sthe\nperformance\sof\sspeed-check.sh\sis\swithin\s400,000\scycles\sof\strunk. +D 2018-07-27T18:19:12.560 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 fe08e0dbf1c561491f879cf4bbf9d3be5ff8ccb9555f60093d3c56c0c37a37b3 +F src/expr.c 5b5e7b571f377ca76fc76eec0a684384483e0bf6525f6b561a09db09d81600eb F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c b1da9ef8dc834603bb0d28972378a7ce65897847f9a1e89ab800bbdf24c788ee F src/func.c 7c288b4ce309b5a8b8473514b88e1f8e69a80134509a8c0db8e39c858e367e7f @@ -1753,7 +1753,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 598d608359005b13fa1151c6c69f2fd12ef3ab7f563a035fc4a6f3c569dc6c67 -R 1d79df50e5dd49c24c2c0d46db1dcbfe +P be05d0db09f43cc3362c28273463d1d236af737a4f8a494cf1050da07ed0df47 +R 1753b15b3d22c91de99ab8b77a1df21b U drh -Z d36b5ae00dc0d8f1b3add00c50463640 +Z 1c821d2ad72826ccbc3322222c2b360d diff --git a/manifest.uuid b/manifest.uuid index 16820a46c5..63b99ad1fa 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -be05d0db09f43cc3362c28273463d1d236af737a4f8a494cf1050da07ed0df47 \ No newline at end of file +a5f86f49b7d9e52546f234f7c3bcbac6b0f78aa55a71c44ca69e21bc31139f3e \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 5c9a29f63e..7767061050 100644 --- a/src/expr.c +++ b/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; From 9cbf4f3550cd536dc6532892c32749e721505103 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 27 Jul 2018 20:01:00 +0000 Subject: [PATCH 8/8] Reduce the performance cost of the constant propagation optimization to less than 200,000 cycles. FossilOrigin-Name: 865249de683e6971984a645a30d96f9fcc6f6d9d7af7e269ff68cc3e42e5fe71 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/select.c | 9 +++++---- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/manifest b/manifest index f2357567e3..402e0c2279 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Performance\simprovement\sto\ssqlite3ExprCollSeq().\s\sWith\sthis\schange,\sthe\nperformance\sof\sspeed-check.sh\sis\swithin\s400,000\scycles\sof\strunk. -D 2018-07-27T18:19:12.560 +C Reduce\sthe\sperformance\scost\sof\sthe\sconstant\spropagation\soptimization\sto\nless\sthan\s200,000\scycles. +D 2018-07-27T20:01:00.824 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 0a3a6c81e6fcb969ff9106e882f0a08547014ba463cb6beca4c4efaecc924ee6 @@ -498,7 +498,7 @@ F src/printf.c 7f6f3cba8e0c49c19e30a1ff4e9aeda6e06814dcbad4b664a69e1b6cb6e7e365 F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384 F src/resolve.c 797088662ed61102485e3070ba3b3f7828bd5ef6a588223ba6865d77d52f6cea F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac -F src/select.c a86a20bd89ea4298267b1d2f44a8b14a53cb6ad1e75a555af5d57de5cf7abd3b +F src/select.c 2534927341d0a2e8d9a3222a87b69e353b22042a02c3d531291590af7f3acf19 F src/shell.c.in f6ebd05c461805a7c708333cd645e74e0a93560d2118f5adb73a75d8c9cf6b01 F src/sqlite.h.in c6451bb876adced3aba5b1682c6317d215c5eceaba21a6ce979e71a0b8d0bf95 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 @@ -1753,7 +1753,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 be05d0db09f43cc3362c28273463d1d236af737a4f8a494cf1050da07ed0df47 -R 1753b15b3d22c91de99ab8b77a1df21b +P a5f86f49b7d9e52546f234f7c3bcbac6b0f78aa55a71c44ca69e21bc31139f3e +R 4b45ff0184fcc33e2981efc28067c07f U drh -Z 1c821d2ad72826ccbc3322222c2b360d +Z 6933d6a2066e2d71a489bc51f2ac806c diff --git a/manifest.uuid b/manifest.uuid index 63b99ad1fa..6bfa54e908 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a5f86f49b7d9e52546f234f7c3bcbac6b0f78aa55a71c44ca69e21bc31139f3e \ No newline at end of file +865249de683e6971984a645a30d96f9fcc6f6d9d7af7e269ff68cc3e42e5fe71 \ No newline at end of file diff --git a/src/select.c b/src/select.c index 87bf5fa6e8..4ab658d01d 100644 --- a/src/select.c +++ b/src/select.c @@ -4094,6 +4094,7 @@ static void constInsert( Expr *pColumn, Expr *pValue ){ + pConst->nConst++; pConst->apExpr = sqlite3DbReallocOrFree(pConst->pParse->db, pConst->apExpr, pConst->nConst*2*sizeof(Expr*)); @@ -4114,7 +4115,6 @@ static void constInsert( */ static void findConstInWhere(WhereConst *pConst, Expr *pExpr){ Expr *pRight, *pLeft; - CollSeq *pColl; if( pExpr==0 ) return; if( ExprHasProperty(pExpr, EP_FromJoin) ) return; if( pExpr->op==TK_AND ){ @@ -4127,17 +4127,18 @@ static void findConstInWhere(WhereConst *pConst, Expr *pExpr){ pLeft = pExpr->pLeft; assert( pRight!=0 ); assert( pLeft!=0 ); - pColl = sqlite3BinaryCompareCollSeq(pConst->pParse, pLeft, pRight); - if( !sqlite3IsBinary(pColl) ) return; 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) ){ + && sqlite3ExprIsConstant(pRight) + && sqlite3IsBinary(sqlite3BinaryCompareCollSeq(pConst->pParse,pLeft,pRight)) + ){ constInsert(pConst, pLeft, pRight); } }