Allow whereShortCut() to use the PRIMARY KEY index of a WITHOUT ROWID table to optimize a vector of "IS" operators in a WHERE clause.

FossilOrigin-Name: 52e73eeca063bb30092ce600068bf487641399a0
This commit is contained in:
dan 2015-03-18 20:03:27 +00:00
parent 9340de52e2
commit c3b328da6e
6 changed files with 109 additions and 14 deletions

View File

@ -580,6 +580,32 @@ foreach {tn3 create_vfs destroy_vfs} {
list [catch { run_ota test.db ota.db } msg] $msg
} {0 SQLITE_DONE}
# Test that OTA can update indexes containing NULL values.
#
reset_db
forcedelete ota.db
do_execsql_test $tn3.8.1 {
CREATE TABLE t1(a PRIMARY KEY, b, c);
CREATE INDEX i1 ON t1(b, c);
INSERT INTO t1 VALUES(1, 1, NULL);
INSERT INTO t1 VALUES(2, NULL, 2);
INSERT INTO t1 VALUES(3, NULL, NULL);
ATTACH 'ota.db' AS ota;
CREATE TABLE ota.data_t1(a, b, c, ota_control);
INSERT INTO data_t1 VALUES(1, NULL, NULL, 1);
INSERT INTO data_t1 VALUES(3, NULL, NULL, 1);
} {}
do_test $tn3.8.2 {
list [catch { run_ota test.db ota.db } msg] $msg
} {0 SQLITE_DONE}
do_execsql_test $tn3.8.3 {
SELECT * FROM t1
} {2 {} 2}
do_execsql_test $tn3.8.4 { PRAGMA integrity_check } {ok}
catch { db close }
eval $destroy_vfs
}

View File

@ -1,5 +1,5 @@
C Clarify\sthat\sOTA\sis\sunable\sto\supdate\sor\sdelete\srows\swith\sNULL\svalues\sin\sprimary\skey\sfields.
D 2015-03-18T19:04:40.018
C Allow\swhereShortCut()\sto\suse\sthe\sPRIMARY\sKEY\sindex\sof\sa\sWITHOUT\sROWID\stable\sto\soptimize\sa\svector\sof\s"IS"\soperators\sin\sa\sWHERE\sclause.
D 2015-03-18T20:03:27.026
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 2f643d6968dfc0b82d2e546a0525a39079f9e928
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@ -124,7 +124,7 @@ F ext/misc/vfslog.c fe40fab5c077a40477f7e5eba994309ecac6cc95
F ext/misc/vtshim.c babb0dc2bf116029e3e7c9a618b8a1377045303e
F ext/misc/wholenumber.c 784b12543d60702ebdd47da936e278aa03076212
F ext/ota/ota.c feb0a11f720a8f30d2bebb835bba3c131a725685
F ext/ota/ota1.test 1684d4a1c4137190368ee5fd31c91b223172ed89
F ext/ota/ota1.test 960418e4171a989426f8b1ad8ee31770e0f94fb8
F ext/ota/ota10.test 85e0f6e7964db5007590c1b299e75211ed4240d4
F ext/ota/ota11.test 2f606cd2b4af260a86b549e91b9f395450fc75cb
F ext/ota/ota12.test 0dff44474de448fb4b0b28c20da63273a4149abb
@ -325,8 +325,8 @@ F src/vxworks.h c18586c8edc1bddbc15c004fa16aeb1e1342b4fb
F src/wal.c 39303f2c9db02a4e422cd8eb2c8760420c6a51fe
F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804
F src/where.c eb141b075776e9864d38f279333e2472a8653202
F src/whereInt.h cbe4aa57326998d89e7698ca65bb7c28541d483c
F src/where.c 67c115096fac6c286ab517939d368cfb12ed0d2d
F src/whereInt.h c1fd5690f91d9551c0c42aa44205248bbd3f7650
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
F test/aggnested.test b35b4cd69fc913f90d39a575e171e1116c3a4bb7
@ -1191,6 +1191,7 @@ F test/whereG.test 69f5ec4b15760a8c860f80e2d55525669390aab3
F test/whereH.test e4b07f7a3c2f5d31195cd33710054c78667573b2
F test/whereI.test 1d89199697919d4930be05a71e7fe620f114e622
F test/whereJ.test 55a3221706a7ab706293f17cc8f96da563bf0767
F test/whereK.test 424caa7391ca5c41484a37cc4a13dc9ed6243bee
F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31
F test/wild001.test bca33f499866f04c24510d74baf1e578d4e44b1c
F test/win32heap.test ea19770974795cff26e11575e12d422dbd16893c
@ -1260,7 +1261,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
P 5489cb68921f62f10d832adbc4d19ea8c6c5da50
R ca30e53e82893df5e57d16fcd6b31c80
P 2e7c1e0a0d128d9bac119692b2505b5ed0abe87a
R fd8b7ec489c2b24931575fb551b9bcda
U dan
Z c06907a568937b6ba3fe4165dc01a3f0
Z 501dc9071dd532eb126e9e20f313175e

View File

@ -1 +1 @@
2e7c1e0a0d128d9bac119692b2505b5ed0abe87a
52e73eeca063bb30092ce600068bf487641399a0

View File

@ -362,7 +362,7 @@ static int allowedOp(int op){
assert( TK_LT>TK_EQ && TK_LT<TK_GE );
assert( TK_LE>TK_EQ && TK_LE<TK_GE );
assert( TK_GE==TK_EQ+4 );
return op==TK_IN || (op>=TK_EQ && op<=TK_GE) || op==TK_ISNULL;
return op==TK_IN || (op>=TK_EQ && op<=TK_GE) || op==TK_ISNULL || op==TK_IS;
}
/*
@ -415,6 +415,8 @@ static u16 operatorMask(int op){
c = WO_IN;
}else if( op==TK_ISNULL ){
c = WO_ISNULL;
}else if( op==TK_IS ){
c = WO_IS;
}else{
assert( (WO_EQ<<(op-TK_EQ)) < 0x7fff );
c = (u16)(WO_EQ<<(op-TK_EQ));
@ -2596,7 +2598,7 @@ static int codeEqualityTerm(
int iReg; /* Register holding results */
assert( iTarget>0 );
if( pX->op==TK_EQ ){
if( pX->op==TK_EQ || pX->op==TK_IS ){
iReg = sqlite3ExprCodeTarget(pParse, pX->pRight, iTarget);
}else if( pX->op==TK_ISNULL ){
iReg = iTarget;
@ -2781,7 +2783,7 @@ static int codeAllEqualityTerms(
testcase( pTerm->eOperator & WO_IN );
if( (pTerm->eOperator & (WO_ISNULL|WO_IN))==0 ){
Expr *pRight = pTerm->pExpr->pRight;
if( sqlite3ExprCanBeNull(pRight) ){
if( sqlite3ExprCanBeNull(pRight) && pTerm->eOperator!=WO_IS ){
sqlite3VdbeAddOp2(v, OP_IsNull, regBase+j, pLevel->addrBrk);
VdbeCoverage(v);
}
@ -6112,13 +6114,15 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
pLoop->rRun = 33; /* 33==sqlite3LogEst(10) */
}else{
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
u32 mask = WO_EQ;
assert( pLoop->aLTermSpace==pLoop->aLTerm );
if( !IsUniqueIndex(pIdx)
|| pIdx->pPartIdxWhere!=0
|| pIdx->nKeyCol>ArraySize(pLoop->aLTermSpace)
) continue;
if( HasRowid(pTab)==0 && IsPrimaryKeyIndex(pIdx) ) mask |= WO_IS;
for(j=0; j<pIdx->nKeyCol; j++){
pTerm = findTerm(pWC, iCur, pIdx->aiColumn[j], 0, WO_EQ, pIdx);
pTerm = findTerm(pWC, iCur, pIdx->aiColumn[j], 0, mask, pIdx);
if( pTerm==0 ) break;
pLoop->aLTerm[j] = pTerm;
}

View File

@ -440,8 +440,9 @@ struct WhereInfo {
#define WO_AND 0x200 /* Two or more AND-connected terms */
#define WO_EQUIV 0x400 /* Of the form A==B, both columns */
#define WO_NOOP 0x800 /* This term does not restrict search space */
#define WO_IS 0x1000 /* The IS operator */
#define WO_ALL 0xfff /* Mask of all possible WO_* values */
#define WO_ALL 0x1fff /* Mask of all possible WO_* values */
#define WO_SINGLE 0x0ff /* Mask of all non-compound WO_* values */
/*

63
test/whereK.test Normal file
View File

@ -0,0 +1,63 @@
# 2015-03-19
#
# 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.
#
#***********************************************************************
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set ::testprefix whereK
do_execsql_test 1.0 {
CREATE TABLE t1(v, w TEXT, x, PRIMARY KEY(w, x)) WITHOUT ROWID;
INSERT INTO t1 VALUES('a', 1, 1);
INSERT INTO t1 VALUES('B', 2, 2);
INSERT INTO t1 VALUES('C', 3, 3);
INSERT INTO t1 VALUES('d', 4, 4);
CREATE TABLE t2(v, w TEXT, x, PRIMARY KEY(w, x));
CREATE TABLE t3(a, b, c);
CREATE UNIQUE INDEX t3a ON t3(a);
}
do_eqp_test 1.1.1 {
SELECT v FROM t1 WHERE w IS ? AND x IS ?
} {/SEARCH TABLE t1.*(w=. AND x=.)/}
do_eqp_test 1.1.2 {
SELECT v FROM t2 WHERE w IS ? AND x IS ?
} {/SCAN TABLE t2/}
do_execsql_test 1.2.1 { SELECT v FROM t1 WHERE w IS 1 AND x IS 1 } {a}
do_execsql_test 1.2.2 { SELECT v FROM t1 WHERE w IS '2' AND x IS 2 } {B}
do_execsql_test 1.2.3 { SELECT v FROM t1 WHERE w IS 3 AND x IS '3' } {}
do_execsql_test 1.2.4 { SELECT v FROM t1 WHERE w IS '4' AND x IS '4' } {}
# IS constraints may only be used if all fields of the index are
# constrained by either "IS" or "=".
#
do_eqp_test 1.3.1 {
SELECT v FROM t1 WHERE w IS ?
} {/SCAN TABLE t1/}
do_eqp_test 1.3.2 {
SELECT v FROM t1 WHERE w IS ? AND x > ?
} {/SCAN TABLE t1/}
do_execsql_test 1.4.1 { SELECT v FROM t1 WHERE w IS 3 AND x = 3 } {C}
do_execsql_test 1.4.2 { SELECT v FROM t1 WHERE w = '4' AND x IS 4 } {d}
do_eqp_test 1.5.1 { SELECT b FROM t3 WHERE a IS ? } {/SCAN TABLE/}
do_eqp_test 1.5.2 { SELECT b FROM t3 WHERE a = ? } {/SEARCH TABLE/}
finish_test