Refactor some jump opcodes in the VDBE. Add JumpZeroIncr and DecrJumpZero.

Fix the LIKE optimization to work with DESC sort order.

FossilOrigin-Name: 26cb5145bf52f8c3fffa8c69b6c24aee4d974883
This commit is contained in:
drh 2015-03-07 00:57:37 +00:00
parent a9c18a9067
commit 16897072b5
7 changed files with 100 additions and 38 deletions

View File

@ -1,5 +1,5 @@
C Test\scases\sadded.\s\sComments\sfixed.\s\sProposed\ssolution\sfor\nticket\s[05f43be8fdda9fbd9].
D 2015-03-06T20:49:52.770
C Refactor\ssome\sjump\sopcodes\sin\sthe\sVDBE.\s\sAdd\sJumpZeroIncr\sand\sDecrJumpZero.\nFix\sthe\sLIKE\soptimization\sto\swork\swith\sDESC\ssort\sorder.
D 2015-03-07T00:57:37.923
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 2f643d6968dfc0b82d2e546a0525a39079f9e928
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@ -185,7 +185,7 @@ F src/delete.c 37964e6c1d73ff49cbea9ff690c9605fb15f600e
F src/expr.c 3ef111b88ae2941b84b6b6ea4be8d501ba1af0cb
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
F src/fkey.c e0444b61bed271a76840cbe6182df93a9baa3f12
F src/func.c f7f0f44b0a2cb568a9c42b1b07e613380ee0b9c6
F src/func.c 44512c557d6d4a40e51f3980c5854ae3e92862d6
F src/global.c 4f77cadbc5427d00139ba43d0f3979804cbb700e
F src/hash.c 4263fbc955f26c2e8cdc0cf214bc42435aa4e4f5
F src/hash.h c8f3c31722cf3277d03713909761e152a5b81094
@ -230,7 +230,7 @@ F src/printf.c 8da9a2687a396daa19860f4dc90975d319304744
F src/random.c ba2679f80ec82c4190062d756f22d0c358180696
F src/resolve.c f4d79e31ffa5820c2e3d1740baa5e9b190425f2b
F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e
F src/select.c e46cef4c224549b439384c88fc7f57ba064dad54
F src/select.c 94e016b6733b1d39a2f4c8d431155b4c2897d907
F src/shell.c cce82ca26392578a4a1ee927dfe55ea3411c7c92
F src/sqlite.h.in 356e69db9500b3fd11705c21ca247e19b95884a3
F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad
@ -293,7 +293,7 @@ F src/update.c 3c4ecc282accf12d39edb8d524cf089645e55a13
F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c
F src/util.c 98a7627ca48ad3265b6940915a1d08355eb3fc7e
F src/vacuum.c 9460b9de7b2d4e34b0d374894aa6c8a0632be8ec
F src/vdbe.c c9f4ad2c62bccebed38b1fd253064ed2a2c659ae
F src/vdbe.c 94cbc2115075b1a562a2a702c29ba48e74f85d34
F src/vdbe.h 6fc69d9c5e146302c56e163cb4b31d1ee64a18c3
F src/vdbeInt.h bb56fd199d8af1a2c1b9639ee2f70724b4338e3a
F src/vdbeapi.c dac0d0d8009a8aa549cd77d9c29da44c0344f0c4
@ -307,7 +307,7 @@ F src/vxworks.h c18586c8edc1bddbc15c004fa16aeb1e1342b4fb
F src/wal.c 39303f2c9db02a4e422cd8eb2c8760420c6a51fe
F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804
F src/where.c 8cd4fc29addda0945b28b1f849a7998e3749d8b9
F src/where.c 7c646a15d0d17850e10319aa31662d5ab61c69af
F src/whereInt.h cbe4aa57326998d89e7698ca65bb7c28541d483c
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
@ -691,7 +691,7 @@ F test/lastinsert.test 42e948fd6442f07d60acbd15d33fb86473e0ef63
F test/laststmtchanges.test ae613f53819206b3222771828d024154d51db200
F test/like.test 4f2a71d36a536233727f71995fef900756705e56
F test/like2.test 3b2ee13149ba4a8a60b59756f4e5d345573852da
F test/like3.test 9c85587224f739c81b51d8cdd2727c11ec678526
F test/like3.test f6fa86d6a81d95bd796c46b0e2ba7444669bdd7e
F test/limit.test 0c99a27a87b14c646a9d583c7c89fd06c352663e
F test/loadext.test 648cb95f324d1775c54a55c12271b2d1156b633b
F test/loadext2.test 0408380b57adca04004247179837a18e866a74f7
@ -1241,7 +1241,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 a58aafdb4e1422b6a8ffc07a67984928bbedf919
R d75eaf03976986bf457292a7b369e1ff
P 6b993bd54035b67f4d84941e3f444ca79b7feee1
R f90848042fe53f442912e9f9b75887d2
U drh
Z 9b58e75e5227e2cbfcfb68532871937f
Z ceb5f3bff4db8044ae0448ec360f04b2

View File

@ -1 +1 @@
6b993bd54035b67f4d84941e3f444ca79b7feee1
26cb5145bf52f8c3fffa8c69b6c24aee4d974883

View File

@ -1650,6 +1650,11 @@ void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive){
** then set aWc[0] through aWc[2] to the wildcard characters and
** return TRUE. If the function is not a LIKE-style function then
** return FALSE.
**
** *pIsNocase is set to true if uppercase and lowercase are equivalent for
** the function (default for LIKE). If the function makes the distinction
** between uppercase and lowercase (as does GLOB) then *pIsNocase is set to
** false.
*/
int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){
FuncDef *pDef;

View File

@ -563,20 +563,17 @@ static void pushOntoSorter(
}
sqlite3VdbeAddOp2(v, op, pSort->iECursor, regRecord);
if( pSelect->iLimit ){
int addr1, addr2;
int addr;
int iLimit;
if( pSelect->iOffset ){
iLimit = pSelect->iOffset+1;
}else{
iLimit = pSelect->iLimit;
}
addr1 = sqlite3VdbeAddOp1(v, OP_IfZero, iLimit); VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_AddImm, iLimit, -1);
addr2 = sqlite3VdbeAddOp0(v, OP_Goto);
sqlite3VdbeJumpHere(v, addr1);
addr = sqlite3VdbeAddOp3(v, OP_IfNotZero, iLimit, 0, -1); VdbeCoverage(v);
sqlite3VdbeAddOp1(v, OP_Last, pSort->iECursor);
sqlite3VdbeAddOp1(v, OP_Delete, pSort->iECursor);
sqlite3VdbeJumpHere(v, addr2);
sqlite3VdbeJumpHere(v, addr);
}
}
@ -973,7 +970,7 @@ static void selectInnerLoop(
** the output for us.
*/
if( pSort==0 && p->iLimit ){
sqlite3VdbeAddOp3(v, OP_IfZero, p->iLimit, iBreak, -1); VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_DecrJumpZero, p->iLimit, iBreak); VdbeCoverage(v);
}
}
@ -1826,7 +1823,7 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){
sqlite3ExprCode(pParse, p->pLimit, iLimit);
sqlite3VdbeAddOp1(v, OP_MustBeInt, iLimit); VdbeCoverage(v);
VdbeComment((v, "LIMIT counter"));
sqlite3VdbeAddOp2(v, OP_IfZero, iLimit, iBreak); VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_IfNot, iLimit, iBreak); VdbeCoverage(v);
}
if( p->pOffset ){
p->iOffset = iOffset = ++pParse->nMem;
@ -2045,7 +2042,7 @@ static void generateWithRecursiveQuery(
selectInnerLoop(pParse, p, p->pEList, iCurrent,
0, 0, pDest, addrCont, addrBreak);
if( regLimit ){
sqlite3VdbeAddOp3(v, OP_IfZero, regLimit, addrBreak, -1);
sqlite3VdbeAddOp2(v, OP_DecrJumpZero, regLimit, addrBreak);
VdbeCoverage(v);
}
sqlite3VdbeResolveLabel(v, addrCont);
@ -2270,7 +2267,7 @@ static int multiSelect(
p->iLimit = pPrior->iLimit;
p->iOffset = pPrior->iOffset;
if( p->iLimit ){
addr = sqlite3VdbeAddOp1(v, OP_IfZero, p->iLimit); VdbeCoverage(v);
addr = sqlite3VdbeAddOp1(v, OP_IfNot, p->iLimit); VdbeCoverage(v);
VdbeComment((v, "Jump ahead if LIMIT reached"));
}
explainSetInteger(iSub2, pParse->iNextSelectId);
@ -2671,7 +2668,7 @@ static int generateOutputSubroutine(
/* Jump to the end of the loop if the LIMIT is reached.
*/
if( p->iLimit ){
sqlite3VdbeAddOp3(v, OP_IfZero, p->iLimit, iBreak, -1); VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_DecrJumpZero, p->iLimit, iBreak); VdbeCoverage(v);
}
/* Generate the subroutine return

View File

@ -5585,10 +5585,12 @@ case OP_MemMax: { /* in2 */
/* Opcode: IfPos P1 P2 * * *
** Synopsis: if r[P1]>0 goto P2
**
** If the value of register P1 is 1 or greater, jump to P2.
** Register P1 must contain an integer.
** If the value of register P1 is 1 or greater, jump to P2 and
** add the literal value P3 to register P1.
**
** It is illegal to use this instruction on a register that does
** not contain an integer. An assertion fault will result if you try.
** If the initial value of register P1 is less than 1, then the
** value is unchanged and control passes through to the next instruction.
*/
case OP_IfPos: { /* jump, in1 */
pIn1 = &aMem[pOp->p1];
@ -5617,16 +5619,34 @@ case OP_IfNeg: { /* jump, in1 */
break;
}
/* Opcode: IfZero P1 P2 P3 * *
** Synopsis: r[P1]+=P3, if r[P1]==0 goto P2
/* Opcode: IfNotZero P1 P2 P3 * *
** Synopsis: if r[P1]!=0 then r[P1]+=P3, goto P2
**
** The register P1 must contain an integer. Add literal P3 to the
** value in register P1. If the result is exactly 0, jump to P2.
** Register P1 must contain an integer. If the content of register P1 is
** initially nonzero, then add P3 to P1 and jump to P2. If register P1 is
** initially zero, leave it unchanged and fall through.
*/
case OP_IfZero: { /* jump, in1 */
case OP_IfNotZero: { /* jump, in1 */
pIn1 = &aMem[pOp->p1];
assert( pIn1->flags&MEM_Int );
pIn1->u.i += pOp->p3;
VdbeBranchTaken(pIn1->u.i<0, 2);
if( pIn1->u.i ){
pIn1->u.i += pOp->p3;
pc = pOp->p2 - 1;
}
break;
}
/* Opcode: DecrJumpZero P1 P2 * * *
** Synopsis: if (--r[P1])==0 goto P2
**
** Register P1 must hold an integer. Decrement the value in register P1
** then jump to P2 if the new value is exactly zero.
*/
case OP_DecrJumpZero: { /* jump, in1 */
pIn1 = &aMem[pOp->p1];
assert( pIn1->flags&MEM_Int );
pIn1->u.i--;
VdbeBranchTaken(pIn1->u.i==0, 2);
if( pIn1->u.i==0 ){
pc = pOp->p2 - 1;
@ -5634,6 +5654,24 @@ case OP_IfZero: { /* jump, in1 */
break;
}
/* Opcode: JumpZeroIncr P1 P2 * * *
** Synopsis: if (r[P1]++)==0 ) goto P2
**
** The register P1 must contain an integer. If register P1 is initially
** zero, then jump to P2. Increment register P1 regardless of whether or
** not the jump is taken.
*/
case OP_JumpZeroIncr: { /* jump, in1 */
pIn1 = &aMem[pOp->p1];
assert( pIn1->flags&MEM_Int );
VdbeBranchTaken(pIn1->u.i==0, 2);
if( (pIn1->u.i++)==0 ){
pc = pOp->p2 - 1;
}
break;
}
/* Opcode: AggStep * P2 P3 P4 P5
** Synopsis: accum=r[P3] step(r[P2@P5])
**

View File

@ -3017,12 +3017,17 @@ static void addScanStatus(
** and if pLoop->iLikeRepCntr is non-zero, then change the P3 to be
** pLoop->iLikeRepCntr and set P5.
**
** This is part of the LIKE optimization. FIXME: Explain in more detail
** The LIKE optimization trys to evaluate "x LIKE 'abc%'" as a range
** expression: "x>='ABC' AND x<'abd'". But this requires that the range
** scan loop run twice, once for strings and a second time for BLOBs.
** The OP_String opcodes on the second pass convert the upper and lower
** bound string contants to blobs. This routine makes the necessary changes
** to the OP_String opcodes for that to happen.
*/
static void whereLikeOptimizationStringFixup(Vdbe *v, WhereLevel *pLevel){
VdbeOp *pOp;
pOp = sqlite3VdbeGetOp(v, -1);
if( pLevel->iLikeRepCntr && ALWAYS(pOp->opcode==OP_String8) ){
if( pLevel->iLikeRepCntr && pOp->opcode==OP_String8 ){
pOp->p3 = pLevel->iLikeRepCntr;
pOp->p5 = 1;
}
@ -3366,6 +3371,7 @@ static Bitmask codeOneLoopStart(
){
pLevel->iLikeRepCntr = ++pParse->nMem;
sqlite3VdbeAddOp2(v, OP_Integer, 0, pLevel->iLikeRepCntr);
VdbeComment((v, "LIKE loop counter"));
pLevel->addrLikeRep = sqlite3VdbeCurrentAddr(v);
}
if( pRangeStart==0
@ -3395,6 +3401,9 @@ static Bitmask codeOneLoopStart(
){
SWAP(WhereTerm *, pRangeEnd, pRangeStart);
SWAP(u8, bSeekPastNull, bStopAtNull);
if( pLevel->addrLikeRep ){
sqlite3VdbeChangeP1(v, pLevel->addrLikeRep-1, 1);
}
}
testcase( pRangeStart && (pRangeStart->eOperator & WO_LE)!=0 );
@ -3864,7 +3873,7 @@ static Bitmask codeOneLoopStart(
}
if( pTerm->wtFlags & TERM_LIKECOND ){
assert( pLevel->iLikeRepCntr>0 );
skipLikeAddr = sqlite3VdbeAddOp1(v, OP_IfZero, pLevel->iLikeRepCntr);
skipLikeAddr = sqlite3VdbeAddOp1(v, OP_IfNot, pLevel->iLikeRepCntr);
VdbeCoverage(v);
}
sqlite3ExprIfFalse(pParse, pE, addrCont, SQLITE_JUMPIFNULL);
@ -6673,11 +6682,10 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
sqlite3VdbeJumpHere(v, pLevel->addrSkip-2);
}
if( pLevel->addrLikeRep ){
addr = sqlite3VdbeAddOp1(v, OP_IfPos, pLevel->iLikeRepCntr);
sqlite3VdbeAddOp2(v,
pLevel->op==OP_Prev ? OP_DecrJumpZero : OP_JumpZeroIncr,
pLevel->iLikeRepCntr, pLevel->addrLikeRep);
VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_AddImm, pLevel->iLikeRepCntr, 1);
sqlite3VdbeAddOp2(v, OP_Goto, 0, pLevel->addrLikeRep);
sqlite3VdbeJumpHere(v, addr);
}
if( pLevel->iLeftJoin ){
addr = sqlite3VdbeAddOp1(v, OP_IfPos, pLevel->iLeftJoin); VdbeCoverage(v);

View File

@ -57,4 +57,18 @@ do_execsql_test like3-1.4 {
SELECT a, b FROM t2 WHERE +b GLOB 'ab*' ORDER BY +a;
} {1 abc 4 abc}
do_execsql_test like3-3.0 {
CREATE TABLE t3(x TEXT PRIMARY KEY COLLATE nocase);
INSERT INTO t3(x) VALUES('aaa'),('abc'),('abd'),('abe'),('acz');
INSERT INTO t3(x) SELECT CAST(x AS blob) FROM t3;
SELECT quote(x) FROM t3 WHERE x LIKE 'ab%' ORDER BY x;
} {'abc' 'abd' 'abe' X'616263' X'616264' X'616265'}
do_execsql_test like3-3.1 {
SELECT quote(x) FROM t3 WHERE x LIKE 'ab%' ORDER BY x DESC;
} {X'616265' X'616264' X'616263' 'abe' 'abd' 'abc'}
do_execsql_test like3-3.1ck {
SELECT quote(x) FROM t3 WHERE x LIKE 'ab%' ORDER BY +x DESC;
} {X'616265' X'616264' X'616263' 'abe' 'abd' 'abc'}
finish_test