]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Refactor some jump opcodes in the VDBE. Add JumpZeroIncr and DecrJumpZero.
authordrh <drh@noemail.net>
Sat, 7 Mar 2015 00:57:37 +0000 (00:57 +0000)
committerdrh <drh@noemail.net>
Sat, 7 Mar 2015 00:57:37 +0000 (00:57 +0000)
Fix the LIKE optimization to work with DESC sort order.

FossilOrigin-Name: 26cb5145bf52f8c3fffa8c69b6c24aee4d974883

manifest
manifest.uuid
src/func.c
src/select.c
src/vdbe.c
src/where.c
test/like3.test

index 254c6a0b57539d025a57eac2d08ba1bed7f8e196..5043d98fbb52cfe9d6d936a320439926303b7d13 100644 (file)
--- a/manifest
+++ b/manifest
@@ -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
index 7643f850793cb8c4efe4ea3b519a314a4b2bb758..35dc95ffeed7da8813a4ea68699175a546795302 100644 (file)
@@ -1 +1 @@
-6b993bd54035b67f4d84941e3f444ca79b7feee1
\ No newline at end of file
+26cb5145bf52f8c3fffa8c69b6c24aee4d974883
\ No newline at end of file
index 30990a30f3f0b5bd3988838c2c97a59825327257..d917bdbec3bb4b169d86f26fe75483f61d31c115 100644 (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;
index 91b3d4345f234ad9123784858734d9f78fdf308d..a9cecaa390c9d87602c026976958f272952a60c6 100644 (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
index 6adea67960040ba885c678bd77b968bdea61d46c..f81bfa8a79fd85d5c5195971ceb43deb3e992291 100644 (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])
 **
index e79e7d33bcce4f2e4d7a31805127129aab626eb2..ece403dfaa70ec667fd7cdca5bf19d2684071ebf 100644 (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);
index b3af2cda910e189b8c0c7ffac1a4529c807f194d..7ca45f88c2adc1495f54d59f82f269d763bf8666 100644 (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