Add simple tests (and a fix) for the change on this branch.

FossilOrigin-Name: 897f3f40267dc922f0fda287484435e1fd8709bade3e87c3829e2f945bb5e4aa
This commit is contained in:
dan 2021-01-15 11:39:46 +00:00
parent 6bfc167a67
commit 76cac6ef06
4 changed files with 107 additions and 25 deletions

View File

@ -1,5 +1,5 @@
C Allow\sthe\splanner\sto\sconvert\san\sEXISTS(SELECT...)\sexpression\sin\sa\sWHERE\sclause\sto\sthe\sequivalent\sIN(...)\sexpression\sin\ssituations\swhere\sthis\sis\spossible\sand\sadvantageous.
D 2021-01-14T20:50:40.571
C Add\ssimple\stests\s(and\sa\sfix)\sfor\sthe\schange\son\sthis\sbranch.
D 2021-01-15T11:39:46.131
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@ -630,7 +630,7 @@ F src/walker.c d9c4e454ebb9499e908aa62d55b8994c375cf5355ac78f60d45af17f7890701c
F src/where.c 3d31871d03906312d7d71a9c0b28c97bcbaead7606dfc15f9b3d080b18702385
F src/whereInt.h 9a3f577619f07700d16d89eeb2f3d94d6b7ed7f109c2dacf0ce8844921549506
F src/wherecode.c a3a1aff30fe99a818d8e7c607980f033f40c68d890e03ed25838b9dbb7908bee
F src/whereexpr.c e48e3edea45b4afabbf6f6ece9647734c828a20c49a8cc780ff4d69b42f55fa4
F src/whereexpr.c 1f4fac8ea8eac6facb9e80107c659094a56a8ad0b35108717ac99ea57bbc71bc
F src/window.c edd6f5e25a1e8f2b6f5305b7f5f7da7bb35f07f0d432b255b1d4c2fcab4205aa
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867de90627
@ -874,6 +874,7 @@ F test/exclusive.test 7ff63be7503990921838d5c9f77f6e33e68e48ed1a9d48cd28745bf650
F test/exclusive2.test 984090e8e9d1b331d2e8111daf6e5d61dda0bef7
F test/exec.test e949714dc127eaa5ecc7d723efec1ec27118fdd7
F test/exists.test 79a75323c78f02bbe9c251ea502a092f9ef63dac
F test/exists2.test 44e18a6aaadefa8e1c68a8453fb22a57a0270a673d9b256790d142ea257459e3
F test/expr.test 26cd01e8485bc48c8aa6a1add598e9ce1e706b4eb4f3f554e0b0223022e8c2cf
F test/expr2.test c27327ae9c017a7ff6280123f67aff496f912da74d78c888926d68b46ec75fd8
F test/extension01.test 00d13cec817f331a687a243e0e5a2d87b0e358c9
@ -1895,10 +1896,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 11e4eb095746602961a178044809a68a77ba7b367596997bef726e54062423d9
R 1a9ea60bc9bb7dab69ccea9e0b8c40d8
T *branch * exists-to-in
T *sym-exists-to-in *
T -sym-trunk *
P 9f90a88221d0694951c353e58efce342eb0b868b8ca6a4469c8205e5c7855b24
R 9984162db1d3035db01dde79c4fce484
U dan
Z d4d95c9878f460cd53a2ce8ada6afd2a
Z 278fef5940bb689562d7ebf0ab17cbb2

View File

@ -1 +1 @@
9f90a88221d0694951c353e58efce342eb0b868b8ca6a4469c8205e5c7855b24
897f3f40267dc922f0fda287484435e1fd8709bade3e87c3829e2f945bb5e4aa

View File

@ -1062,18 +1062,14 @@ struct ExistsToInCtx {
Expr **ppParent;
};
static int exprExistsToInIter(
struct ExistsToInCtx *p,
Expr *pExpr,
Expr **ppExpr
){
assert( ppExpr==0 || *ppExpr==pExpr );
static int exprExistsToInIter(struct ExistsToInCtx *p, Expr **ppExpr){
Expr *pExpr = *ppExpr;
switch( pExpr->op ){
case TK_AND:
p->ppParent = ppExpr;
if( exprExistsToInIter(p, pExpr->pLeft, &pExpr->pLeft) ) return 1;
if( exprExistsToInIter(p, &pExpr->pLeft) ) return 1;
p->ppParent = ppExpr;
if( exprExistsToInIter(p, pExpr->pRight, &pExpr->pRight) ) return 1;
if( exprExistsToInIter(p, &pExpr->pRight) ) return 1;
break;
case TK_EQ: {
int bLeft = exprUsesSrclist(p->pSrc, pExpr->pLeft, 0);
@ -1081,9 +1077,9 @@ static int exprExistsToInIter(
if( bLeft || bRight ){
if( (bLeft && bRight) || p->pInLhs ) return 1;
p->pInLhs = bLeft ? pExpr->pLeft : pExpr->pRight;
if( exprUsesSrclist(p->pSrc, p->pInLhs, 1) ) return 1;
p->pEq = pExpr;
p->ppAnd = p->ppParent;
if( exprUsesSrclist(p->pSrc, p->pInLhs, 1) ) return 1;
}
break;
}
@ -1098,15 +1094,14 @@ static int exprExistsToInIter(
}
static Expr *exprAnalyzeExistsFindEq(
SrcList *pSrc,
Expr *pWhere, /* WHERE clause to traverse */
Select *pSel,
Expr **ppEq, /* OUT: == node from WHERE clause */
Expr ***pppAnd /* OUT: Pointer to parent of ==, if any */
){
struct ExistsToInCtx ctx;
memset(&ctx, 0, sizeof(ctx));
ctx.pSrc = pSrc;
if( exprExistsToInIter(&ctx, pWhere, 0) ){
ctx.pSrc = pSel->pSrc;
if( exprExistsToInIter(&ctx, &pSel->pWhere) ){
return 0;
}
if( ppEq ) *ppEq = ctx.pEq;
@ -1165,7 +1160,7 @@ static void exprAnalyzeExists(
if( (pSel->selFlags & SF_Aggregate) || pSel->pWin ) return;
if( pSel->pPrior ) return;
if( pSel->pWhere==0 ) return;
if( 0==exprAnalyzeExistsFindEq(pSel->pSrc, pSel->pWhere, 0, 0) ) return;
if( 0==exprAnalyzeExistsFindEq(pSel, 0, 0) ) return;
pDup = sqlite3ExprDup(pParse->db, pExpr, 0);
if( pDup==0 ) return;
@ -1173,7 +1168,9 @@ static void exprAnalyzeExists(
sqlite3ExprListDelete(pParse->db, pSel->pEList);
pSel->pEList = 0;
pInLhs = exprAnalyzeExistsFindEq(pSel->pSrc, pSel->pWhere, &pEq, &ppAnd);
pInLhs = exprAnalyzeExistsFindEq(pSel, &pEq, &ppAnd);
assert( pInLhs && pEq );
assert( pEq==pSel->pWhere || ppAnd );
assert( pDup->pLeft==0 );
pDup->op = TK_IN;

87
test/exists2.test Normal file
View File

@ -0,0 +1,87 @@
# 2021 January 15
#
# 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 cases where EXISTS expressions are
# transformed to IN() expressions by where.c
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix exists2
do_execsql_test 1.0 {
CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
INSERT INTO t1 VALUES(1, 'one');
INSERT INTO t1 VALUES(2, 'two');
INSERT INTO t1 VALUES(3, 'three');
INSERT INTO t1 VALUES(4, 'four');
INSERT INTO t1 VALUES(5, 'five');
INSERT INTO t1 VALUES(6, 'six');
INSERT INTO t1 VALUES(7, 'seven');
CREATE TABLE t2(c INTEGER, d INTEGER);
INSERT INTO t2 VALUES(1, 1);
INSERT INTO t2 VALUES(3, 2);
INSERT INTO t2 VALUES(5, 3);
INSERT INTO t2 VALUES(7, 4);
}
proc do_execsql_eqp_test {tn sql eqp res} {
uplevel [list do_eqp_test $tn.1 $sql [string trim $eqp]]
uplevel [list do_execsql_test $tn.2 $sql $res]
}
do_execsql_eqp_test 1.1 {
SELECT t1.* FROM t1 WHERE EXISTS(SELECT * FROM t2 WHERE t1.a=t2.c);
} {
USING INTEGER PRIMARY KEY
} {
1 one 3 three 5 five 7 seven
}
do_execsql_eqp_test 1.2 {
SELECT t1.* FROM t1 WHERE EXISTS(SELECT * FROM t2 WHERE t2.c=t1.a);
} {
SEARCH TABLE t1 USING INTEGER PRIMARY KEY
} {
1 one 3 three 5 five 7 seven
}
do_execsql_eqp_test 1.3 {
SELECT t1.* FROM t1 WHERE EXISTS(SELECT * FROM t2 WHERE t2.c+1=t1.a);
} {
SEARCH TABLE t1 USING INTEGER PRIMARY KEY
} {
2 two 4 four 6 six
}
do_execsql_eqp_test 1.4 {
SELECT t1.* FROM t1 WHERE EXISTS(SELECT * FROM t2 WHERE t2.c+1=t1.a+1);
} {
SCAN TABLE t1
} {
1 one 3 three 5 five 7 seven
}
breakpoint
do_execsql_eqp_test 1.5 {
SELECT t1.* FROM t1 WHERE EXISTS(
SELECT * FROM t2 WHERE t1.a=t2.c AND d IN (1, 2, 3)
);
} {
SEARCH TABLE t1 USING INTEGER PRIMARY KEY
} {
1 one 3 three 5 five
}
finish_test