Enhance the WHERE-clause push-down optimization so that it is able to
push down WHERE clause terms that contain uncorrelated subqueries. FossilOrigin-Name: 69ec714b2d698acf9e37635256c01b233ce32f22e8323e226441d5ddd948a940
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
C Fix\sa\sharmless\scompiler\swarning\sin\sthe\sICU\sextension\sdue\sto\s[acddbc489d5231da].
|
||||
D 2024-04-08T11:45:15.171
|
||||
C Enhance\sthe\sWHERE-clause\spush-down\soptimization\sso\sthat\sit\sis\sable\sto\npush\sdown\sWHERE\sclause\sterms\sthat\scontain\suncorrelated\ssubqueries.
|
||||
D 2024-04-08T11:50:07.908
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||
@@ -700,7 +700,7 @@ F src/date.c 126ba2ab10aeb2e7ba6e089b5f07b747c0625b8287f78b60da346eda8d23c875
|
||||
F src/dbpage.c 80e46e1df623ec40486da7a5086cb723b0275a6e2a7b01d9f9b5da0f04ba2782
|
||||
F src/dbstat.c 3b677254d512fcafd4d0b341bf267b38b235ccfddbef24f9154e19360fa22e43
|
||||
F src/delete.c cb766727c78e715f9fb7ec8a7d03658ed2a3016343ca687acfcec9083cdca500
|
||||
F src/expr.c 98a1cabc44fbf64e4c87a639f4399d1afde640875c16dbc2e62a37c102cca9e8
|
||||
F src/expr.c 36071487e377356f1dd62e1e35870ed36a7212cb34ab1578b75d4a27ecdbfcb8
|
||||
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
||||
F src/fkey.c a47610f0a5c6cb0ad79f8fcef039c01833dec0c751bb695f28dc0ec6a4c3ba00
|
||||
F src/func.c 283d4f3b2751a1d9339fd93a8a013d1948fd5f4474a3cab0955eb4fafd445d0f
|
||||
@@ -748,14 +748,14 @@ F src/pragma.h e690a356c18e98414d2e870ea791c1be1545a714ba623719deb63f7f226d8bb7
|
||||
F src/prepare.c 371f6115cb69286ebc12c6f2d7511279c2e47d9f54f475d46a554d687a3b312c
|
||||
F src/printf.c 87b67bba3662a0523f39ae6b084a3907109702f717c654d6cecb838af5cd57f1
|
||||
F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
|
||||
F src/resolve.c 42d5d75a6ccfaf5b17d81fca64203ebce87f59702089142feed90df28dec1203
|
||||
F src/resolve.c 6310bdfed32184cd3a5d6ba203dfee1ea323051cb38a6c2e80a5b79c069f4e87
|
||||
F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
|
||||
F src/select.c 3c8e1b921edfb71904b01c1ef9fb378224cdba71543342b164c7718cc8e82a44
|
||||
F src/select.c 51893b3e34d38ad8d46b5010a6e380ca878b578be5001a640daa907336187424
|
||||
F src/shell.c.in 0354ca51eee5fbf6af394a7ef9f5ef6823ef45b743db65431f6777e4d5be2199
|
||||
F src/sqlite.h.in 32389e0d584551b300d0157881336162c14315a424cbf385c0d65eb7c2e31f7b
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h 3f046c04ea3595d6bfda99b781926b17e672fd6d27da2ba6d8d8fc39981dcb54
|
||||
F src/sqliteInt.h a275d95f5612f2640380532e484d1f6c46a48d84ae227e6c12e36712c22b7b8a
|
||||
F src/sqliteInt.h 4ca38e206befb3738d8cca97b6c6ee56c10f1c5bdb379ac5442d0f1a71b9fefa
|
||||
F src/sqliteLimit.h 6878ab64bdeb8c24a1d762d45635e34b96da21132179023338c93f820eee6728
|
||||
F src/status.c cb11f8589a6912af2da3bb1ec509a94dd8ef27df4d4c1a97e0bcf2309ece972b
|
||||
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
|
||||
@@ -835,7 +835,7 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
|
||||
F src/wal.c 887fc4ca3f020ebb2e376f222069570834ac63bf50111ef0cbf3ae417048ed89
|
||||
F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452
|
||||
F src/walker.c 7c7ea0115345851c3da4e04e2e239a29983b61fb5b038b94eede6aba462640e2
|
||||
F src/where.c 9982128f010a699560fb5be37633801c7641ac3540f49db43cec878025929a0e
|
||||
F src/where.c 09253e913dc1a93aa6e0e1a5d25a392b8fa39096cc30d230dd302264b3be0661
|
||||
F src/whereInt.h 82a13766f13d1a53b05387c2e60726289ef26404bc7b9b1f7770204d97357fb8
|
||||
F src/wherecode.c e033875570f5d65b99fdb5189e597d91c8bc34f4196089fd50e6086d174035e7
|
||||
F src/whereexpr.c 7b64295f1d82ad0928df435925dd7bbd5997b44a026153113eace0d9e71ff435
|
||||
@@ -1246,7 +1246,7 @@ F test/fuzz3.test 9c813e6613b837cb7a277b0383cd66bfa07042b4cf0317157c35852f30043c
|
||||
F test/fuzz4.test c229bcdb45518a89e1d208a21343e061503460ac69fae1539320a89f572eb634
|
||||
F test/fuzz_common.tcl b7197de6ed1ee8250a4f82d67876f4561b42ee8cbbfc6160dcb66331bad3f830
|
||||
F test/fuzz_malloc.test f348276e732e814802e39f042b1f6da6362a610af73a528d8f76898fde6b22f2
|
||||
F test/fuzzcheck.c e6a40f53ac5624aa5b7c4f31c385f09ba088d524cecc4512fd3057caeed8f530
|
||||
F test/fuzzcheck.c dc159967609d00b0cfe619e735cbbf8482570aca85711397034b0662b6c18fc7
|
||||
F test/fuzzdata1.db 3e86d9cf5aea68ddb8e27c02d7dfdaa226347426c7eb814918e4d95475bf8517
|
||||
F test/fuzzdata2.db 128b3feeb78918d075c9b14b48610145a0dd4c8d6f1ca7c2870c7e425f5bf31f
|
||||
F test/fuzzdata3.db c6586d3e3cef0fbc18108f9bb649aa77bfc38aba
|
||||
@@ -1258,7 +1258,7 @@ F test/fuzzdata8.db 4a53b6d077c6a5c23b609d8d3ac66996fa55ba3f8d02f9b6efdd0214a767
|
||||
F test/fuzzer1.test 3d4c4b7e547aba5e5511a2991e3e3d07166cfbb8
|
||||
F test/fuzzer2.test a85ef814ce071293bce1ad8dffa217cbbaad4c14
|
||||
F test/fuzzerfault.test f64c4aef4c9e9edf1d6dc0d3f1e65dcc81e67c996403c88d14f09b74807a42bc
|
||||
F test/fuzzinvariants.c d89b81c3bdad7b2837f8cce645d5b563ffa965f6d819ce33f0f6d82a71c6ca9a
|
||||
F test/fuzzinvariants.c 0729b9d8ed77ad0f8c5c7601168a707d5803087d2da030ede9057c51c809cc6c
|
||||
F test/gcfault.test 4ea410ac161e685f17b19e1f606f58514a2850e806c65b846d05f60d436c5b0d
|
||||
F test/gencol1.test e169bdfa11c7ed5e9f322a98a7db3afe9e66235750b68c923efee8e1876b46ec
|
||||
F test/genesis.tcl 1e2e2e8e5cc4058549a154ff1892fe5c9de19f98
|
||||
@@ -1510,7 +1510,7 @@ F test/printf.test 685fec5a0c5af2490ab0632775a301554361d674211d690f5bee0a97b0533
|
||||
F test/printf2.test 3f55c1871a5a65507416076f6eb97e738d5210aeda7595a74ee895f2224cce60
|
||||
F test/progress.test ebab27f670bd0d4eb9d20d49cef96e68141d92fb
|
||||
F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc
|
||||
F test/pushdown.test 45c6fa615f225041bbebac398d42aaaffdb6e0cdef8e542be9a8337a43d0ad95
|
||||
F test/pushdown.test 3330746a897ea271b1021bc1e7e57c6f8d49bcb8ca7d58a823d01aa64a303cc7
|
||||
F test/queryonly.test 5f653159e0f552f0552d43259890c1089391dcca
|
||||
F test/quick.test 1681febc928d686362d50057c642f77a02c62e57
|
||||
F test/quickcheck.test a4b7e878cd97e46108291c409b0bf8214f29e18fddd68a42bc5c1375ad1fb80a
|
||||
@@ -2184,8 +2184,9 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P 6431538f0bb3bb8606786f3c3e5c055c4bc387098dd3bdc8a94f6fda61c47f52
|
||||
R d4b41721554e465dd5d2ae1a7b49b70e
|
||||
P 3d8750e88558f8ea6a1523a5add4ccca3262e31f348b603e56ab193d81908995 67594481379824823105939fea2ce1fe280667f6db91735ac78b4b6164a78dab
|
||||
R 1ffe1af0415e1a4fed09276e65c27d2f
|
||||
T +closed 67594481379824823105939fea2ce1fe280667f6db91735ac78b4b6164a78dab
|
||||
U drh
|
||||
Z 2f169d04c81c297dd79cb34d0c3d4d69
|
||||
Z a907cc2f6ecf59760a4baca00ef3db65
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
3d8750e88558f8ea6a1523a5add4ccca3262e31f348b603e56ab193d81908995
|
||||
69ec714b2d698acf9e37635256c01b233ce32f22e8323e226441d5ddd948a940
|
||||
+47
-10
@@ -2500,7 +2500,7 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
|
||||
return WRC_Continue;
|
||||
}
|
||||
}
|
||||
static int exprIsConst(Parse *pParse, Expr *p, int initFlag, int iCur){
|
||||
static int exprIsConst(Parse *pParse, Expr *p, int initFlag){
|
||||
Walker w;
|
||||
w.eCode = initFlag;
|
||||
w.pParse = pParse;
|
||||
@@ -2509,7 +2509,6 @@ static int exprIsConst(Parse *pParse, Expr *p, int initFlag, int iCur){
|
||||
#ifdef SQLITE_DEBUG
|
||||
w.xSelectCallback2 = sqlite3SelectWalkAssert2;
|
||||
#endif
|
||||
w.u.iCur = iCur;
|
||||
sqlite3WalkExpr(&w, p);
|
||||
return w.eCode;
|
||||
}
|
||||
@@ -2529,7 +2528,7 @@ static int exprIsConst(Parse *pParse, Expr *p, int initFlag, int iCur){
|
||||
** function and on its parameters.
|
||||
*/
|
||||
int sqlite3ExprIsConstant(Parse *pParse, Expr *p){
|
||||
return exprIsConst(pParse, p, 1, 0);
|
||||
return exprIsConst(pParse, p, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2546,7 +2545,23 @@ int sqlite3ExprIsConstant(Parse *pParse, Expr *p){
|
||||
** the prepared statement starts up. See sqlite3ExprCodeRunJustOnce().
|
||||
*/
|
||||
static int sqlite3ExprIsConstantNotJoin(Parse *pParse, Expr *p){
|
||||
return exprIsConst(pParse, p, 2, 0);
|
||||
return exprIsConst(pParse, p, 2);
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine examines sub-SELECT statements as an expression is being
|
||||
** walked as part of sqlite3ExprIsTableConstant(). Sub-SELECTs are considered
|
||||
** constant as long as they are uncorrelated - meaning that they do not
|
||||
** contain any terms from outer contexts.
|
||||
*/
|
||||
static int exprSelectWalkTableConstant(Walker *pWalker, Select *pSelect){
|
||||
assert( pSelect!=0 );
|
||||
assert( pWalker->eCode==3 || pWalker->eCode==0 );
|
||||
if( (pSelect->selFlags & SF_Correlated)!=0 ){
|
||||
pWalker->eCode = 0;
|
||||
return WRC_Abort;
|
||||
}
|
||||
return WRC_Prune;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2554,9 +2569,26 @@ static int sqlite3ExprIsConstantNotJoin(Parse *pParse, Expr *p){
|
||||
** for any single row of the table with cursor iCur. In other words, the
|
||||
** expression must not refer to any non-deterministic function nor any
|
||||
** table other than iCur.
|
||||
**
|
||||
** Consider uncorrelated subqueries to be constants if the bAllowSubq
|
||||
** parameter is true.
|
||||
*/
|
||||
int sqlite3ExprIsTableConstant(Expr *p, int iCur){
|
||||
return exprIsConst(0, p, 3, iCur);
|
||||
static int sqlite3ExprIsTableConstant(Expr *p, int iCur, int bAllowSubq){
|
||||
Walker w;
|
||||
w.eCode = 3;
|
||||
w.pParse = 0;
|
||||
w.xExprCallback = exprNodeIsConstant;
|
||||
if( bAllowSubq ){
|
||||
w.xSelectCallback = exprSelectWalkTableConstant;
|
||||
}else{
|
||||
w.xSelectCallback = sqlite3SelectWalkFail;
|
||||
#ifdef SQLITE_DEBUG
|
||||
w.xSelectCallback2 = sqlite3SelectWalkAssert2;
|
||||
#endif
|
||||
}
|
||||
w.u.iCur = iCur;
|
||||
sqlite3WalkExpr(&w, p);
|
||||
return w.eCode;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2574,7 +2606,10 @@ int sqlite3ExprIsTableConstant(Expr *p, int iCur){
|
||||
**
|
||||
** (1) pExpr cannot refer to any table other than pSrc->iCursor.
|
||||
**
|
||||
** (2) pExpr cannot use subqueries or non-deterministic functions.
|
||||
** (2a) pExpr cannot use subqueries unless the bAllowSubq parameter is
|
||||
** true and the subquery is non-correlated
|
||||
**
|
||||
** (2b) pExpr cannot use non-deterministic functions.
|
||||
**
|
||||
** (3) pSrc cannot be part of the left operand for a RIGHT JOIN.
|
||||
** (Is there some way to relax this constraint?)
|
||||
@@ -2603,7 +2638,8 @@ int sqlite3ExprIsTableConstant(Expr *p, int iCur){
|
||||
int sqlite3ExprIsSingleTableConstraint(
|
||||
Expr *pExpr, /* The constraint */
|
||||
const SrcList *pSrcList, /* Complete FROM clause */
|
||||
int iSrc /* Which element of pSrcList to use */
|
||||
int iSrc, /* Which element of pSrcList to use */
|
||||
int bAllowSubq /* Allow non-correlated subqueries */
|
||||
){
|
||||
const SrcItem *pSrc = &pSrcList->a[iSrc];
|
||||
if( pSrc->fg.jointype & JT_LTORJ ){
|
||||
@@ -2628,7 +2664,8 @@ int sqlite3ExprIsSingleTableConstraint(
|
||||
}
|
||||
}
|
||||
}
|
||||
return sqlite3ExprIsTableConstant(pExpr, pSrc->iCursor); /* rules (1), (2) */
|
||||
/* Rules (1), (2a), and (2b) handled by the following: */
|
||||
return sqlite3ExprIsTableConstant(pExpr, pSrc->iCursor, bAllowSubq);
|
||||
}
|
||||
|
||||
|
||||
@@ -2713,7 +2750,7 @@ int sqlite3ExprIsConstantOrGroupBy(Parse *pParse, Expr *p, ExprList *pGroupBy){
|
||||
*/
|
||||
int sqlite3ExprIsConstantOrFunction(Expr *p, u8 isInit){
|
||||
assert( isInit==0 || isInit==1 );
|
||||
return exprIsConst(0, p, 4+isInit, 0);
|
||||
return exprIsConst(0, p, 4+isInit);
|
||||
}
|
||||
|
||||
#ifdef SQLITE_ENABLE_CURSOR_HINTS
|
||||
|
||||
@@ -1354,6 +1354,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
||||
testcase( pNC->ncFlags & NC_PartIdx );
|
||||
testcase( pNC->ncFlags & NC_IdxExpr );
|
||||
testcase( pNC->ncFlags & NC_GenCol );
|
||||
assert( pExpr->x.pSelect );
|
||||
if( pNC->ncFlags & NC_SelfRef ){
|
||||
notValidImpl(pParse, pNC, "subqueries", pExpr, pExpr);
|
||||
}else{
|
||||
@@ -1362,6 +1363,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
||||
assert( pNC->nRef>=nRef );
|
||||
if( nRef!=pNC->nRef ){
|
||||
ExprSetProperty(pExpr, EP_VarSelect);
|
||||
pExpr->x.pSelect->selFlags |= SF_Correlated;
|
||||
}
|
||||
pNC->ncFlags |= NC_Subquery;
|
||||
}
|
||||
|
||||
+1
-1
@@ -5272,7 +5272,7 @@ static int pushDownWhereTerms(
|
||||
}
|
||||
#endif
|
||||
|
||||
if( sqlite3ExprIsSingleTableConstraint(pWhere, pSrcList, iSrc) ){
|
||||
if( sqlite3ExprIsSingleTableConstraint(pWhere, pSrcList, iSrc, 1) ){
|
||||
nChng++;
|
||||
pSubq->selFlags |= SF_PushDown;
|
||||
while( pSubq ){
|
||||
|
||||
+2
-2
@@ -3585,6 +3585,7 @@ struct Select {
|
||||
#define SF_CopyCte 0x4000000 /* SELECT statement is a copy of a CTE */
|
||||
#define SF_OrderByReqd 0x8000000 /* The ORDER BY clause may not be omitted */
|
||||
#define SF_UpdateFrom 0x10000000 /* Query originates with UPDATE FROM */
|
||||
#define SF_Correlated 0x20000000 /* True if references the outer context */
|
||||
|
||||
/* True if S exists and has SF_NestedFrom */
|
||||
#define IsNestedFrom(S) ((S)!=0 && ((S)->selFlags&SF_NestedFrom)!=0)
|
||||
@@ -5081,8 +5082,7 @@ int sqlite3ExprTruthValue(const Expr*);
|
||||
int sqlite3ExprIsConstant(Parse*,Expr*);
|
||||
int sqlite3ExprIsConstantOrFunction(Expr*, u8);
|
||||
int sqlite3ExprIsConstantOrGroupBy(Parse*, Expr*, ExprList*);
|
||||
int sqlite3ExprIsTableConstant(Expr*,int);
|
||||
int sqlite3ExprIsSingleTableConstraint(Expr*,const SrcList*,int);
|
||||
int sqlite3ExprIsSingleTableConstraint(Expr*,const SrcList*,int,int);
|
||||
#ifdef SQLITE_ENABLE_CURSOR_HINTS
|
||||
int sqlite3ExprContainsSubquery(Expr*);
|
||||
#endif
|
||||
|
||||
+2
-2
@@ -942,7 +942,7 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
|
||||
** WHERE clause (or the ON clause of a LEFT join) that constrain which
|
||||
** rows of the target table (pSrc) that can be used. */
|
||||
if( (pTerm->wtFlags & TERM_VIRTUAL)==0
|
||||
&& sqlite3ExprIsSingleTableConstraint(pExpr, pTabList, pLevel->iFrom)
|
||||
&& sqlite3ExprIsSingleTableConstraint(pExpr, pTabList, pLevel->iFrom, 0)
|
||||
){
|
||||
pPartial = sqlite3ExprAnd(pParse, pPartial,
|
||||
sqlite3ExprDup(pParse->db, pExpr, 0));
|
||||
@@ -1211,7 +1211,7 @@ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter(
|
||||
for(pTerm=pWInfo->sWC.a; pTerm<pWCEnd; pTerm++){
|
||||
Expr *pExpr = pTerm->pExpr;
|
||||
if( (pTerm->wtFlags & TERM_VIRTUAL)==0
|
||||
&& sqlite3ExprIsSingleTableConstraint(pExpr, pTabList, iSrc)
|
||||
&& sqlite3ExprIsSingleTableConstraint(pExpr, pTabList, iSrc, 0)
|
||||
){
|
||||
sqlite3ExprIfFalse(pParse, pTerm->pExpr, addrCont, SQLITE_JUMPIFNULL);
|
||||
}
|
||||
|
||||
+11
-5
@@ -979,7 +979,8 @@ extern int fuzz_invariant(
|
||||
int iRow, /* The row number for pStmt */
|
||||
int nRow, /* Total number of output rows */
|
||||
int *pbCorrupt, /* IN/OUT: Flag indicating a corrupt database file */
|
||||
int eVerbosity /* How much debugging output */
|
||||
int eVerbosity, /* How much debugging output */
|
||||
unsigned int dbOpt /* Default optimization flags */
|
||||
);
|
||||
|
||||
/* Implementation of sqlite_dbdata and sqlite_dbptr */
|
||||
@@ -1031,7 +1032,12 @@ static int recoverDatabase(sqlite3 *db){
|
||||
/*
|
||||
** Run the SQL text
|
||||
*/
|
||||
static int runDbSql(sqlite3 *db, const char *zSql, unsigned int *pBtsFlags){
|
||||
static int runDbSql(
|
||||
sqlite3 *db, /* Run SQL on this database connection */
|
||||
const char *zSql, /* The SQL to be run */
|
||||
unsigned int *pBtsFlags,
|
||||
unsigned int dbOpt /* Default optimization flags */
|
||||
){
|
||||
int rc;
|
||||
sqlite3_stmt *pStmt;
|
||||
int bCorrupt = 0;
|
||||
@@ -1107,7 +1113,7 @@ static int runDbSql(sqlite3 *db, const char *zSql, unsigned int *pBtsFlags){
|
||||
iRow++;
|
||||
for(iCnt=0; iCnt<99999; iCnt++){
|
||||
rc = fuzz_invariant(db, pStmt, iCnt, iRow, nRow,
|
||||
&bCorrupt, eVerbosity);
|
||||
&bCorrupt, eVerbosity, dbOpt);
|
||||
if( rc==SQLITE_DONE ) break;
|
||||
if( rc!=SQLITE_ERROR ) g.nInvariant++;
|
||||
if( eVerbosity>0 ){
|
||||
@@ -1330,7 +1336,7 @@ int runCombinedDbSqlInput(
|
||||
char cSaved = zSql[i+1];
|
||||
zSql[i+1] = 0;
|
||||
if( sqlite3_complete(zSql+j) ){
|
||||
rc = runDbSql(cx.db, zSql+j, &btsFlags);
|
||||
rc = runDbSql(cx.db, zSql+j, &btsFlags, dbOpt);
|
||||
j = i+1;
|
||||
}
|
||||
zSql[i+1] = cSaved;
|
||||
@@ -1340,7 +1346,7 @@ int runCombinedDbSqlInput(
|
||||
}
|
||||
}
|
||||
if( j<i ){
|
||||
runDbSql(cx.db, zSql+j, &btsFlags);
|
||||
runDbSql(cx.db, zSql+j, &btsFlags, dbOpt);
|
||||
}
|
||||
}
|
||||
testrun_finished:
|
||||
|
||||
+24
-6
@@ -30,7 +30,13 @@
|
||||
/* Forward references */
|
||||
static char *fuzz_invariant_sql(sqlite3_stmt*, int);
|
||||
static int sameValue(sqlite3_stmt*,int,sqlite3_stmt*,int,sqlite3_stmt*);
|
||||
static void reportInvariantFailed(sqlite3_stmt*,sqlite3_stmt*,int);
|
||||
static void reportInvariantFailed(
|
||||
sqlite3_stmt *pOrig, /* The original query */
|
||||
sqlite3_stmt *pTest, /* The alternative test query with a missing row */
|
||||
int iRow, /* Row number in pOrig */
|
||||
unsigned int dbOpt, /* Optimization flags on pOrig */
|
||||
int noOpt /* True if opt flags inverted for pTest */
|
||||
);
|
||||
|
||||
/*
|
||||
** Do an invariant check on pStmt. iCnt determines which invariant check to
|
||||
@@ -68,7 +74,8 @@ int fuzz_invariant(
|
||||
int iRow, /* Current row number */
|
||||
int nRow, /* Number of output rows from pStmt */
|
||||
int *pbCorrupt, /* IN/OUT: Flag indicating a corrupt database file */
|
||||
int eVerbosity /* How much debugging output */
|
||||
int eVerbosity, /* How much debugging output */
|
||||
unsigned int dbOpt /* Default optimization flags */
|
||||
){
|
||||
char *zTest;
|
||||
sqlite3_stmt *pTestStmt = 0;
|
||||
@@ -76,13 +83,20 @@ int fuzz_invariant(
|
||||
int i;
|
||||
int nCol;
|
||||
int nParam;
|
||||
int noOpt = (iCnt%3)==0;
|
||||
|
||||
if( *pbCorrupt ) return SQLITE_DONE;
|
||||
nParam = sqlite3_bind_parameter_count(pStmt);
|
||||
if( nParam>100 ) return SQLITE_DONE;
|
||||
zTest = fuzz_invariant_sql(pStmt, iCnt);
|
||||
if( zTest==0 ) return SQLITE_DONE;
|
||||
if( noOpt ){
|
||||
sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS, db, ~dbOpt);
|
||||
}
|
||||
rc = sqlite3_prepare_v2(db, zTest, -1, &pTestStmt, 0);
|
||||
if( noOpt ){
|
||||
sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS, db, dbOpt);
|
||||
}
|
||||
if( rc ){
|
||||
if( eVerbosity ){
|
||||
printf("invariant compile failed: %s\n%s\n",
|
||||
@@ -212,7 +226,7 @@ int fuzz_invariant(
|
||||
}
|
||||
sqlite3_finalize(pCk);
|
||||
if( rc==SQLITE_DONE ){
|
||||
reportInvariantFailed(pStmt, pTestStmt, iRow);
|
||||
reportInvariantFailed(pStmt, pTestStmt, iRow, dbOpt, noOpt);
|
||||
return SQLITE_INTERNAL;
|
||||
}else if( eVerbosity>0 ){
|
||||
printf("invariant-error ignored due to the use of virtual tables\n");
|
||||
@@ -488,13 +502,17 @@ static void printRow(sqlite3_stmt *pStmt, int iRow){
|
||||
static void reportInvariantFailed(
|
||||
sqlite3_stmt *pOrig, /* The original query */
|
||||
sqlite3_stmt *pTest, /* The alternative test query with a missing row */
|
||||
int iRow /* Row number in pOrig */
|
||||
int iRow, /* Row number in pOrig */
|
||||
unsigned int dbOpt, /* Optimization flags on pOrig */
|
||||
int noOpt /* True if opt flags inverted for pTest */
|
||||
){
|
||||
int iTestRow = 0;
|
||||
printf("Invariant check failed on row %d.\n", iRow);
|
||||
printf("Original query --------------------------------------------------\n");
|
||||
printf("Original query (opt-flags: 0x%08x) --------------------------\n",
|
||||
dbOpt);
|
||||
printf("%s\n", sqlite3_expanded_sql(pOrig));
|
||||
printf("Alternative query -----------------------------------------------\n");
|
||||
printf("Alternative query (opt-flags: 0x%08x) -----------------------\n",
|
||||
noOpt ? ~dbOpt : dbOpt);
|
||||
printf("%s\n", sqlite3_expanded_sql(pTest));
|
||||
printf("Result row that is missing from the alternative -----------------\n");
|
||||
printRow(pOrig, iRow);
|
||||
|
||||
@@ -247,4 +247,89 @@ do_execsql_test 5.0 {
|
||||
WHERE e>0;
|
||||
} {- - 3 4 5}
|
||||
|
||||
|
||||
# 2024-04-05
|
||||
# Allow push-down of operators of the form "expr IN table".
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 6.0 {
|
||||
CREATE TABLE t01(w,x,y,z);
|
||||
CREATE TABLE t02(w,x,y,z);
|
||||
CREATE VIEW t0(w,x,y,z) AS
|
||||
SELECT w,x,y,z FROM t01 UNION ALL SELECT w,x,y,z FROM t02;
|
||||
CREATE INDEX t01x ON t01(w,x,y);
|
||||
CREATE INDEX t02x ON t02(w,x,y);
|
||||
CREATE VIEW v1(k) AS VALUES(77),(88),(99);
|
||||
CREATE TABLE k1(k);
|
||||
INSERT INTO k1 SELECT * FROM v1;
|
||||
}
|
||||
do_eqp_test 6.1 {
|
||||
WITH k(n) AS (VALUES(77),(88),(99))
|
||||
SELECT max(z) FROM t0 WHERE w=123 AND x IN k AND y BETWEEN 44 AND 55;
|
||||
} {
|
||||
QUERY PLAN
|
||||
|--CO-ROUTINE t0
|
||||
| `--COMPOUND QUERY
|
||||
| |--LEFT-MOST SUBQUERY
|
||||
| | |--SEARCH t01 USING INDEX t01x (w=? AND x=? AND y>? AND y<?)
|
||||
| | `--LIST SUBQUERY xxxxxx
|
||||
| | |--MATERIALIZE k
|
||||
| | | `--SCAN 3 CONSTANT ROWS
|
||||
| | `--SCAN k
|
||||
| `--UNION ALL
|
||||
| |--SEARCH t02 USING INDEX t02x (w=? AND x=? AND y>? AND y<?)
|
||||
| `--LIST SUBQUERY xxxxxx
|
||||
| `--SCAN k
|
||||
|--SEARCH t0
|
||||
`--LIST SUBQUERY xxxxxx
|
||||
`--SCAN k
|
||||
}
|
||||
# ^^^^--- The key feature above is that the SEARCH for each subquery
|
||||
# uses all three fields of the index w, x, and y. Prior to the push-down
|
||||
# of "expr IN table", only the w term of the index would be used. Similar
|
||||
# for the following tests:
|
||||
#
|
||||
do_eqp_test 6.2 {
|
||||
SELECT max(z) FROM t0 WHERE w=123 AND x IN v1 AND y BETWEEN 44 AND 55;
|
||||
} {
|
||||
QUERY PLAN
|
||||
|--CO-ROUTINE t0
|
||||
| `--COMPOUND QUERY
|
||||
| |--LEFT-MOST SUBQUERY
|
||||
| | |--SEARCH t01 USING INDEX t01x (w=? AND x=? AND y>? AND y<?)
|
||||
| | `--LIST SUBQUERY xxxxxx
|
||||
| | |--CO-ROUTINE v1
|
||||
| | | `--SCAN 3 CONSTANT ROWS
|
||||
| | `--SCAN v1
|
||||
| `--UNION ALL
|
||||
| |--SEARCH t02 USING INDEX t02x (w=? AND x=? AND y>? AND y<?)
|
||||
| `--LIST SUBQUERY xxxxxx
|
||||
| |--CO-ROUTINE v1
|
||||
| | `--SCAN 3 CONSTANT ROWS
|
||||
| `--SCAN v1
|
||||
|--SEARCH t0
|
||||
`--LIST SUBQUERY xxxxxx
|
||||
|--CO-ROUTINE v1
|
||||
| `--SCAN 3 CONSTANT ROWS
|
||||
`--SCAN v1
|
||||
}
|
||||
do_eqp_test 6.3 {
|
||||
SELECT max(z) FROM t0 WHERE w=123 AND x IN k1 AND y BETWEEN 44 AND 55;
|
||||
} {
|
||||
QUERY PLAN
|
||||
|--CO-ROUTINE t0
|
||||
| `--COMPOUND QUERY
|
||||
| |--LEFT-MOST SUBQUERY
|
||||
| | |--SEARCH t01 USING INDEX t01x (w=? AND x=? AND y>? AND y<?)
|
||||
| | `--LIST SUBQUERY xxxxxx
|
||||
| | `--SCAN k1
|
||||
| `--UNION ALL
|
||||
| |--SEARCH t02 USING INDEX t02x (w=? AND x=? AND y>? AND y<?)
|
||||
| `--LIST SUBQUERY xxxxxx
|
||||
| `--SCAN k1
|
||||
|--SEARCH t0
|
||||
`--LIST SUBQUERY xxxxxx
|
||||
`--SCAN k1
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
Reference in New Issue
Block a user