As evidenced by [forum:/forumpost/f3f546025a|forum post f3f546025a], the
new RIGHT JOIN related restriction on the push-down optimization implemented by [da3fba18742b6e0b] also needs to apply to the automatic index (a.k.a. hash-join) optimization and to the Bloom filter optimization. Computation of the restriction is now moved into the sqlite3ExprIsSingleTableConstraint() routine. FossilOrigin-Name: 4902015dcf3869f08d9986e422faa231d9218a5e0fc59ba8df0f407e4eb3d605
This commit is contained in:
parent
fa746af4a3
commit
eb4455e4e4
20
manifest
20
manifest
@ -1,5 +1,5 @@
|
||||
C Simplify\sthe\sinterface\sto\sconstructAutomaticIndex().
|
||||
D 2023-05-15T01:02:50.881
|
||||
C As\sevidenced\sby\s[forum:/forumpost/f3f546025a|forum\spost\sf3f546025a],\sthe\nnew\sRIGHT\sJOIN\srelated\srestriction\son\sthe\spush-down\soptimization\simplemented\nby\s[da3fba18742b6e0b]\salso\sneeds\sto\sapply\sto\sthe\sautomatic\sindex\n(a.k.a.\shash-join)\soptimization\sand\sto\sthe\sBloom\sfilter\soptimization.\nComputation\sof\sthe\srestriction\sis\snow\nmoved\sinto\sthe\ssqlite3ExprIsSingleTableConstraint()\sroutine.
|
||||
D 2023-05-15T02:06:35.229
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||
@ -585,7 +585,7 @@ F src/date.c aca9e0c08b400b21238b609aea7c09585396cd770985cf8f475560f69222dad3
|
||||
F src/dbpage.c f3eea5f7ec47e09ee7da40f42b25092ecbe961fc59566b8e5f705f34335b2387
|
||||
F src/dbstat.c ec92074baa61d883de58c945162d9e666c13cd7cf3a23bc38b4d1c4d0b2c2bef
|
||||
F src/delete.c a9c6d3f51c0a31e9b831e0a0580a98d702904b42d216fee530940e40dec34873
|
||||
F src/expr.c b239be118a24f1520b44efb850cd1754854606bccb1a5f9dceeb0ff48f6bad79
|
||||
F src/expr.c 941fe758212c6cf0007c6d7daf5368e11c199376ace9b3018494296e18a27eac
|
||||
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
||||
F src/fkey.c 03c134cc8bffe54835f742ddea0b72ebfc8f6b32773d175c71b8afeea6cb5c83
|
||||
F src/func.c 03e6b501f3056d0ba398bda17df938b2b566aa0b3ca7e1942a3cd1925d04ec36
|
||||
@ -635,12 +635,12 @@ F src/printf.c b9320cdbeca0b336c3f139fd36dd121e4167dd62b35fbe9ccaa9bab44c0af38d
|
||||
F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
|
||||
F src/resolve.c 3e53e02ce87c9582bd7e7d22f13f4094a271678d9dc72820fa257a2abb5e4032
|
||||
F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
|
||||
F src/select.c 12aa3168be4ff175702fe0ebeaf544312be22d275d378a28e7b2fad32d552d36
|
||||
F src/select.c 738c3a3d6929f8be66c319bad17f6b297bd60a4eb14006075c48a28487dc7786
|
||||
F src/shell.c.in 52836b4002a2cad8095b451f0c39a6542c23a231eb0ed5e39387bc8b1f7aaa9e
|
||||
F src/sqlite.h.in c14a4471fcd897a03631ac7ad3d05505e895e7b6419ec5b96cae9bc4df7a9fc6
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h da473ce2b3d0ae407a6300c4a164589b9a6bfdbec9462688a8593ff16f3bb6e4
|
||||
F src/sqliteInt.h 6e08039aa944e874d3878c4f12bbd78cea797c988dad147adc9ffb1c2b179402
|
||||
F src/sqliteInt.h a3ced8b9ebc573189c87b69f24bf10d2b9cd3cefefaae52623a2fa79e6fdd408
|
||||
F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657
|
||||
F src/status.c 160c445d7d28c984a0eae38c144f6419311ed3eace59b44ac6dafc20db4af749
|
||||
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
|
||||
@ -720,7 +720,7 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
|
||||
F src/wal.c 7a65f64bfe4a783c5e2df73ffb0efc383dec934dee9e3ac706b2eeb3631d17ac
|
||||
F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a
|
||||
F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b
|
||||
F src/where.c 58a3ecca3d688030a9e61d66874e37f1c21a02ada78b4342feca384e7f149ab4
|
||||
F src/where.c b74a83b4c8f65b218c5c1c8d9122433f85ee1300fd9263ba1697d0e1040eeb36
|
||||
F src/whereInt.h e25203e5bfee149f5f1225ae0166cfb4f1e65490c998a024249e98bb0647377c
|
||||
F src/wherecode.c b300db0bcd84ad6c2642bf3f509f92fad7b7d697b9856b64dd66d692d184d054
|
||||
F src/whereexpr.c 22cf19b0ececeaf838daed1039c5231a8778784eba5ad67b991442a23473fd3f
|
||||
@ -1407,7 +1407,7 @@ F test/printf.test 512152dca7f2f578f045a5a732e7bee08e4f47a8a212f83ce46791b518eba
|
||||
F test/printf2.test 3f55c1871a5a65507416076f6eb97e738d5210aeda7595a74ee895f2224cce60
|
||||
F test/progress.test ebab27f670bd0d4eb9d20d49cef96e68141d92fb
|
||||
F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc
|
||||
F test/pushdown.test 043e69055d841f5c4be0ff264b2a9de32d2342c3d71b20a786b0e6656603c66a
|
||||
F test/pushdown.test 1495a09837a1cedfc0adf07ba42dc6b83be05a2c15de331b67c39a0e22078238
|
||||
F test/queryonly.test 5f653159e0f552f0552d43259890c1089391dcca
|
||||
F test/quick.test 1681febc928d686362d50057c642f77a02c62e57
|
||||
F test/quickcheck.test f86b25b33455af0189b4d3fe7bd6e553115e80b2d7ec9bbe9a6b37fce0881bfe
|
||||
@ -2069,8 +2069,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 e4989c111ddffe6818cbb88a72bd027b30124d1e8de0cce4109c72a214ffb5b8
|
||||
R b21c8261c54a385eacafd0ff3e6873f4
|
||||
P c5da16551619718bf649c517515261706843e11e131f0b99e1fd6927d0f7e238
|
||||
R 19526b8216d20a0f1da8af3749d5cbdb
|
||||
U drh
|
||||
Z 300738534ea13b0c642673e90b4b2e81
|
||||
Z 784c6c524217b70137b2b3907aa60981
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
@ -1 +1 @@
|
||||
c5da16551619718bf649c517515261706843e11e131f0b99e1fd6927d0f7e238
|
||||
4902015dcf3869f08d9986e422faa231d9218a5e0fc59ba8df0f407e4eb3d605
|
44
src/expr.c
44
src/expr.c
@ -2378,10 +2378,11 @@ int sqlite3ExprIsTableConstant(Expr *p, int iCur){
|
||||
}
|
||||
|
||||
/*
|
||||
** Check pExpr to see if it is an constraint on the single data source pSrc.
|
||||
** In other words, check to see if pExpr constrains pSrc but does not depend
|
||||
** on any other tables or data sources anywhere else in the query. Return
|
||||
** true (non-zero) if pExpr is a constraint on pSrc only.
|
||||
** Check pExpr to see if it is an constraint on the single data source
|
||||
** pSrc = &pSrcList->a[iSrc]. In other words, check to see if pExpr
|
||||
** constrains pSrc but does not depend on any other tables or data
|
||||
** sources anywhere else in the query. Return true (non-zero) if pExpr
|
||||
** is a constraint on pSrc only.
|
||||
**
|
||||
** This is an optimization. False negatives will perhaps cause slower
|
||||
** queries, but false positives will yield incorrect answers. So when in
|
||||
@ -2398,13 +2399,31 @@ int sqlite3ExprIsTableConstant(Expr *p, int iCur){
|
||||
**
|
||||
** (4) If pSrc is the right operand of a LEFT JOIN, then...
|
||||
** (4a) pExpr must come from an ON clause..
|
||||
(4b) and specifically the ON clause associated with the LEFT JOIN.
|
||||
** (4b) and specifically the ON clause associated with the LEFT JOIN.
|
||||
**
|
||||
** (5) If pSrc is not the right operand of a LEFT JOIN or the left
|
||||
** operand of a RIGHT JOIN, then pExpr must be from the WHERE
|
||||
** clause, not an ON clause.
|
||||
**
|
||||
** (6) Either:
|
||||
**
|
||||
** (6a) pExpr does not originate in an ON or USING clause, or
|
||||
**
|
||||
** (6b) The ON or USING clause from which pExpr is derived is
|
||||
** not to the left of a RIGHT JOIN (or FULL JOIN).
|
||||
**
|
||||
** Without this restriction, accepting pExpr as a single-table
|
||||
** constraint might move the the ON/USING filter expression
|
||||
** from the left side of a RIGHT JOIN over to the right side,
|
||||
** which leads to incorrect answers. See also restriction (9)
|
||||
** on push-down.
|
||||
*/
|
||||
int sqlite3ExprIsSingleTableConstraint(Expr *pExpr, const SrcItem *pSrc){
|
||||
int sqlite3ExprIsSingleTableConstraint(
|
||||
Expr *pExpr, /* The constraint */
|
||||
const SrcList *pSrcList, /* Complete FROM clause */
|
||||
int iSrc /* Which element of pSrcList to use */
|
||||
){
|
||||
const SrcItem *pSrc = &pSrcList->a[iSrc];
|
||||
if( pSrc->fg.jointype & JT_LTORJ ){
|
||||
return 0; /* rule (3) */
|
||||
}
|
||||
@ -2414,6 +2433,19 @@ int sqlite3ExprIsSingleTableConstraint(Expr *pExpr, const SrcItem *pSrc){
|
||||
}else{
|
||||
if( ExprHasProperty(pExpr, EP_OuterON) ) return 0; /* rule (5) */
|
||||
}
|
||||
if( ExprHasProperty(pExpr, EP_OuterON|EP_InnerON) /* (6a) */
|
||||
&& (pSrcList->a[0].fg.jointype & JT_LTORJ)!=0 /* Fast pre-test of (6b) */
|
||||
){
|
||||
int jj;
|
||||
for(jj=0; jj<iSrc; jj++){
|
||||
if( pExpr->w.iJoin==pSrcList->a[jj].iCursor ){
|
||||
if( (pSrcList->a[jj].fg.jointype & JT_LTORJ)!=0 ){
|
||||
return 0; /* restriction (6) */
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return sqlite3ExprIsTableConstant(pExpr, pSrc->iCursor); /* rules (1), (2) */
|
||||
}
|
||||
|
||||
|
@ -5119,7 +5119,8 @@ static int pushDownWindowCheck(Parse *pParse, Select *pSubq, Expr *pExpr){
|
||||
**
|
||||
** Without this restriction, the push-down optimization might move
|
||||
** the ON/USING filter expression from the left side of a RIGHT JOIN
|
||||
** over to the right side, which leads to incorrect answers.
|
||||
** over to the right side, which leads to incorrect answers. See
|
||||
** also restriction (6) in sqlite3ExprIsSingleTableConstraint().
|
||||
**
|
||||
** (10) The inner query is not the right-hand table of a RIGHT JOIN.
|
||||
**
|
||||
@ -5204,6 +5205,7 @@ static int pushDownWhereTerms(
|
||||
pWhere = pWhere->pLeft;
|
||||
}
|
||||
|
||||
#if 0 /* These checks now done by sqlite3ExprIsSingleTableConstraint() */
|
||||
if( ExprHasProperty(pWhere, EP_OuterON|EP_InnerON) /* (9a) */
|
||||
&& (pSrcList->a[0].fg.jointype & JT_LTORJ)!=0 /* Fast pre-test of (9c) */
|
||||
){
|
||||
@ -5221,8 +5223,6 @@ static int pushDownWhereTerms(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if 0 /* These checks now done by sqlite3ExprIsSingleTableConstraint() */
|
||||
if( isLeftJoin
|
||||
&& (ExprHasProperty(pWhere,EP_OuterON)==0
|
||||
|| pWhere->w.iJoin!=iCursor)
|
||||
@ -5236,7 +5236,7 @@ static int pushDownWhereTerms(
|
||||
}
|
||||
#endif
|
||||
|
||||
if( sqlite3ExprIsSingleTableConstraint(pWhere, pSrc) ){
|
||||
if( sqlite3ExprIsSingleTableConstraint(pWhere, pSrcList, iSrc) ){
|
||||
nChng++;
|
||||
pSubq->selFlags |= SF_PushDown;
|
||||
while( pSubq ){
|
||||
|
@ -4906,7 +4906,7 @@ int sqlite3ExprIsConstantNotJoin(Expr*);
|
||||
int sqlite3ExprIsConstantOrFunction(Expr*, u8);
|
||||
int sqlite3ExprIsConstantOrGroupBy(Parse*, Expr*, ExprList*);
|
||||
int sqlite3ExprIsTableConstant(Expr*,int);
|
||||
int sqlite3ExprIsSingleTableConstraint(Expr*,const SrcItem*);
|
||||
int sqlite3ExprIsSingleTableConstraint(Expr*,const SrcList*,int);
|
||||
#ifdef SQLITE_ENABLE_CURSOR_HINTS
|
||||
int sqlite3ExprContainsSubquery(Expr*);
|
||||
#endif
|
||||
|
14
src/where.c
14
src/where.c
@ -895,6 +895,7 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
|
||||
u8 useBloomFilter = 0; /* True to also add a Bloom filter */
|
||||
Expr *pPartial = 0; /* Partial Index Expression */
|
||||
int iContinue = 0; /* Jump here to skip excluded rows */
|
||||
SrcList *pTabList; /* The complete FROM clause */
|
||||
SrcItem *pSrc; /* The FROM clause term to get the next index */
|
||||
int addrCounter = 0; /* Address where integer counter is initialized */
|
||||
int regBase; /* Array of registers where record is assembled */
|
||||
@ -911,7 +912,8 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
|
||||
/* Count the number of columns that will be added to the index
|
||||
** and used to match WHERE clause constraints */
|
||||
nKeyCol = 0;
|
||||
pSrc = &pWC->pWInfo->pTabList->a[pLevel->iFrom];
|
||||
pTabList = pWC->pWInfo->pTabList;
|
||||
pSrc = &pTabList->a[pLevel->iFrom];
|
||||
pTable = pSrc->pTab;
|
||||
pWCEnd = &pWC->a[pWC->nTerm];
|
||||
pLoop = pLevel->pWLoop;
|
||||
@ -922,7 +924,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, pSrc)
|
||||
&& sqlite3ExprIsSingleTableConstraint(pExpr, pTabList, pLevel->iFrom)
|
||||
){
|
||||
pPartial = sqlite3ExprAnd(pParse, pPartial,
|
||||
sqlite3ExprDup(pParse->db, pExpr, 0));
|
||||
@ -1150,9 +1152,11 @@ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter(
|
||||
|
||||
addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
|
||||
do{
|
||||
const SrcList *pTabList;
|
||||
const SrcItem *pItem;
|
||||
const Table *pTab;
|
||||
u64 sz;
|
||||
int iSrc;
|
||||
sqlite3WhereExplainBloomFilter(pParse, pWInfo, pLevel);
|
||||
addrCont = sqlite3VdbeMakeLabel(pParse);
|
||||
iCur = pLevel->iTabCur;
|
||||
@ -1166,7 +1170,9 @@ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter(
|
||||
** testing complicated. By basing the blob size on the value in the
|
||||
** sqlite_stat1 table, testing is much easier.
|
||||
*/
|
||||
pItem = &pWInfo->pTabList->a[pLevel->iFrom];
|
||||
pTabList = pWInfo->pTabList;
|
||||
iSrc = pLevel->iFrom;
|
||||
pItem = &pTabList->a[iSrc];
|
||||
assert( pItem!=0 );
|
||||
pTab = pItem->pTab;
|
||||
assert( pTab!=0 );
|
||||
@ -1183,7 +1189,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, pItem)
|
||||
&& sqlite3ExprIsSingleTableConstraint(pExpr, pTabList, iSrc)
|
||||
){
|
||||
sqlite3ExprIfFalse(pParse, pTerm->pExpr, addrCont, SQLITE_JUMPIFNULL);
|
||||
}
|
||||
|
@ -207,4 +207,24 @@ do_execsql_test 4.3 {
|
||||
SELECT * FROM t1 JOIN t2 ON false JOIN v6 ON true RIGHT JOIN t3 ON true;
|
||||
} {- - - - 3}
|
||||
|
||||
# 2023-05-15 https://sqlite.org/forum/forumpost/f3f546025a
|
||||
# This is restriction (6) on sqlite3ExprIsSingleTableConstraint().
|
||||
# That restriction (now) used to implement restriction (9) on push-down.
|
||||
# It is used for other things too, so it is not purely a push-down
|
||||
# restriction. But it seems convenient to put it here.
|
||||
#
|
||||
reset_db
|
||||
db null -
|
||||
do_execsql_test 5.0 {
|
||||
CREATE TABLE t1(a INT); INSERT INTO t1 VALUES(1);
|
||||
CREATE TABLE t2(b INT); INSERT INTO t2 VALUES(2);
|
||||
CREATE TABLE t3(c INT); INSERT INTO t3 VALUES(3);
|
||||
CREATE TABLE t4(d INT); INSERT INTO t4 VALUES(4);
|
||||
CREATE TABLE t5(e INT); INSERT INTO t5 VALUES(5);
|
||||
SELECT *
|
||||
FROM t1 JOIN t2 ON null RIGHT JOIN t3 ON true
|
||||
LEFT JOIN (t4 JOIN t5 ON d+1=e) ON d=4
|
||||
WHERE e>0;
|
||||
} {- - 3 4 5}
|
||||
|
||||
finish_test
|
||||
|
Loading…
Reference in New Issue
Block a user