]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
The LIKE optimization must be applied twice, once for strings and a second
authordrh <drh@noemail.net>
Fri, 6 Mar 2015 16:45:16 +0000 (16:45 +0000)
committerdrh <drh@noemail.net>
Fri, 6 Mar 2015 16:45:16 +0000 (16:45 +0000)
time for BLOBs.  Ticket [05f43be8fdda9f].  This check-in is a proof-of-concept
of how that might be done.

FossilOrigin-Name: 5757e803cb5759b476bbc6453c58340089611420

manifest
manifest.uuid
src/vdbe.c
src/where.c
src/whereInt.h

index d6db801e6a8a6e1f9ad6bdad7343edf163006a8b..759c643d7116870057ee6785db5d57da82574b69 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Clearification\sof\ssome\sdocumentation\stext.\s\sAdded\srequirements\smarks.
-D 2015-03-06T04:37:26.939
+C The\sLIKE\soptimization\smust\sbe\sapplied\stwice,\sonce\sfor\sstrings\sand\sa\ssecond\ntime\sfor\sBLOBs.\s\sTicket\s[05f43be8fdda9f].\s\sThis\scheck-in\sis\sa\sproof-of-concept\nof\show\sthat\smight\sbe\sdone.
+D 2015-03-06T16:45:16.543
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 2f643d6968dfc0b82d2e546a0525a39079f9e928
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -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 991e9b2c38cdc987ed214249b3c72ea73a06fb2e
+F src/vdbe.c 6bee3b85a2f013a8fdc496996089d3b6bedfb525
 F src/vdbe.h 6fc69d9c5e146302c56e163cb4b31d1ee64a18c3
 F src/vdbeInt.h bb56fd199d8af1a2c1b9639ee2f70724b4338e3a
 F src/vdbeapi.c dac0d0d8009a8aa549cd77d9c29da44c0344f0c4
@@ -307,8 +307,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 c1b3706929fe918966227f3b91ff433a825037fd
-F src/whereInt.h d3633e9b592103241b74b0ec76185f3e5b8b62e0
+F src/where.c b7e82341d2570ac8a051e133cfc44c7eec79a30e
+F src/whereInt.h 0ba6257f2a44acd6262f259d5147cd01c52cc45b
 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
 F test/aggnested.test b35b4cd69fc913f90d39a575e171e1116c3a4bb7
@@ -1240,7 +1240,10 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P 31d5e9b42e5c96207187dcde1cbbb1e79f26fca2
-R e3bd9c89d1416be2fa13657fae649477
+P 8c1e85aab9e0d90726057e25e2ea0663341c070f
+R db06eec232964b57030b876196612d14
+T *branch * like-opt-fix
+T *sym-like-opt-fix *
+T -sym-trunk *
 U drh
-Z 0cf6c34744d872d2f1bdb9d1e644babc
+Z 9b71822fa0ca3d1b398ae4d623871060
index aa2a348ab8d7cb66c45b7de5ad08d7ae363e8935..58f48bf654c94f7eef3afa8abc1a8097f89c7732 100644 (file)
@@ -1 +1 @@
-8c1e85aab9e0d90726057e25e2ea0663341c070f
\ No newline at end of file
+5757e803cb5759b476bbc6453c58340089611420
\ No newline at end of file
index 39a334f29ff09e7ce117fa95ae5e66c5410b0b29..0c9a67e56b6f9075b4d9cfe1f98ce5535d572968 100644 (file)
@@ -1015,7 +1015,7 @@ case OP_Real: {            /* same as TK_FLOAT, out2-prerelease */
 ** Synopsis: r[P2]='P4'
 **
 ** P4 points to a nul terminated UTF-8 string. This opcode is transformed 
-** into a String before it is executed for the first time.  During
+** into a String opcode before it is executed for the first time.  During
 ** this transformation, the length of string P4 is computed and stored
 ** as the P1 parameter.
 */
@@ -1047,10 +1047,15 @@ case OP_String8: {         /* same as TK_STRING, out2-prerelease */
   /* Fall through to the next case, OP_String */
 }
   
-/* Opcode: String P1 P2 * P4 *
+/* Opcode: String P1 P2 P3 P4 P5
 ** Synopsis: r[P2]='P4' (len=P1)
 **
 ** The string value P4 of length P1 (bytes) is stored in register P2.
+**
+** If P5!=0 and the content of register P3 is greater than zero, then
+** the datatype of the register P2 is convert to BLOB.  The content is
+** the same string text, it is merely interpreted as a BLOB as if it
+** had been CAST.  
 */
 case OP_String: {          /* out2-prerelease */
   assert( pOp->p4.z!=0 );
@@ -1059,6 +1064,13 @@ case OP_String: {          /* out2-prerelease */
   pOut->n = pOp->p1;
   pOut->enc = encoding;
   UPDATE_MAX_BLOBSIZE(pOut);
+  if( pOp->p5 ){
+    assert( pOp->p3>0 );
+    assert( pOp->p3<=(p->nMem-p->nCursor) );
+    pIn3 = &aMem[pOp->p3];
+    assert( pIn3->flags & MEM_Int );
+    if( pIn3->u.i ) pOut->flags = MEM_Blob|MEM_Static|MEM_Term;
+  }
   break;
 }
 
index fedc67a79162f50c32dea9761ee7b4bf5a32607f..82c7e699f41e0ce28be0307bbe6e840b7ad40af4 100644 (file)
@@ -202,7 +202,7 @@ static void whereClauseClear(WhereClause *pWC){
 ** calling this routine.  Such pointers may be reinitialized by referencing
 ** the pWC->a[] array.
 */
-static int whereClauseInsert(WhereClause *pWC, Expr *p, u8 wtFlags){
+static int whereClauseInsert(WhereClause *pWC, Expr *p, u16 wtFlags){
   WhereTerm *pTerm;
   int idx;
   testcase( wtFlags & TERM_VIRTUAL );
@@ -627,7 +627,11 @@ static void exprAnalyzeAll(
 ** so and false if not.
 **
 ** In order for the operator to be optimizible, the RHS must be a string
-** literal that does not begin with a wildcard.  
+** literal that does not begin with a wildcard.  The LHS must be a column
+** that may only be NULL, a string, or a BLOB, never a number. (This means
+** that virtual tables cannot participate in the LIKE optimization.)  If the
+** collating sequence for the column on the LHS must be appropriate for
+** the operator.
 */
 static int isLikeOrGlob(
   Parse *pParse,    /* Parsing and code generating context */
@@ -656,7 +660,7 @@ static int isLikeOrGlob(
   pLeft = pList->a[1].pExpr;
   if( pLeft->op!=TK_COLUMN 
    || sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT 
-   || IsVirtual(pLeft->pTab)
+   || IsVirtual(pLeft->pTab)  /* Value might be numeric */
   ){
     /* IMP: R-02065-49465 The left-hand side of the LIKE or GLOB operator must
     ** be the name of an indexed column with TEXT affinity. */
@@ -1286,7 +1290,8 @@ static void exprAnalyze(
            sqlite3ExprAddCollateToken(pParse,pNewExpr1,&sCollSeqName),
            pStr1, 0);
     transferJoinMarkings(pNewExpr1, pExpr);
-    idxNew1 = whereClauseInsert(pWC, pNewExpr1, TERM_VIRTUAL|TERM_DYNAMIC);
+    idxNew1 = whereClauseInsert(pWC, pNewExpr1, 
+                                TERM_LIKEOPT|TERM_VIRTUAL|TERM_DYNAMIC);
     testcase( idxNew1==0 );
     exprAnalyze(pSrc, pWC, idxNew1);
     pNewExpr2 = sqlite3ExprDup(db, pLeft, 0);
@@ -1294,7 +1299,8 @@ static void exprAnalyze(
            sqlite3ExprAddCollateToken(pParse,pNewExpr2,&sCollSeqName),
            pStr2, 0);
     transferJoinMarkings(pNewExpr2, pExpr);
-    idxNew2 = whereClauseInsert(pWC, pNewExpr2, TERM_VIRTUAL|TERM_DYNAMIC);
+    idxNew2 = whereClauseInsert(pWC, pNewExpr2,
+                                TERM_LIKEOPT|TERM_VIRTUAL|TERM_DYNAMIC);
     testcase( idxNew2==0 );
     exprAnalyze(pSrc, pWC, idxNew2);
     pTerm = &pWC->a[idxTerm];
@@ -2966,7 +2972,21 @@ static void addScanStatus(
 # define addScanStatus(a, b, c, d) ((void)d)
 #endif
 
-
+/*
+** Look at the last instruction coded.  If that instruction is OP_String8
+** 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
+*/
+static void whereLikeOptimizationStringFixup(Vdbe *v, WhereLevel *pLevel){
+  VdbeOp *pOp;
+  pOp = sqlite3VdbeGetOp(v, -1);
+  if( pLevel->iLikeRepCntr && ALWAYS(pOp->opcode==OP_String8) ){
+    pOp->p3 = pLevel->iLikeRepCntr;
+    pOp->p5 = 1;
+  }
+}
 
 /*
 ** Generate code for the start of the iLevel-th loop in the WHERE clause
@@ -3300,6 +3320,14 @@ static Bitmask codeOneLoopStart(
     if( pLoop->wsFlags & WHERE_TOP_LIMIT ){
       pRangeEnd = pLoop->aLTerm[j++];
       nExtraReg = 1;
+      if( pRangeStart
+       && (pRangeStart->wtFlags & TERM_LIKEOPT)!=0
+       && (pRangeEnd->wtFlags & TERM_LIKEOPT)!=0
+      ){
+        pLevel->iLikeRepCntr = ++pParse->nMem;
+        sqlite3VdbeAddOp2(v, OP_Integer, 0, pLevel->iLikeRepCntr);
+        pLevel->addrLikeRep = sqlite3VdbeCurrentAddr(v);
+      }
       if( pRangeStart==0
        && (j = pIdx->aiColumn[nEq])>=0 
        && pIdx->pTable->aCol[j].notNull==0
@@ -3342,6 +3370,7 @@ static Bitmask codeOneLoopStart(
     if( pRangeStart ){
       Expr *pRight = pRangeStart->pExpr->pRight;
       sqlite3ExprCode(pParse, pRight, regBase+nEq);
+      whereLikeOptimizationStringFixup(v, pLevel);
       if( (pRangeStart->wtFlags & TERM_VNULL)==0
        && sqlite3ExprCanBeNull(pRight)
       ){
@@ -3387,6 +3416,7 @@ static Bitmask codeOneLoopStart(
       Expr *pRight = pRangeEnd->pExpr->pRight;
       sqlite3ExprCacheRemove(pParse, regBase+nEq, 1);
       sqlite3ExprCode(pParse, pRight, regBase+nEq);
+      whereLikeOptimizationStringFixup(v, pLevel);
       if( (pRangeEnd->wtFlags & TERM_VNULL)==0
        && sqlite3ExprCanBeNull(pRight)
       ){
@@ -6595,6 +6625,13 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
       sqlite3VdbeJumpHere(v, pLevel->addrSkip);
       sqlite3VdbeJumpHere(v, pLevel->addrSkip-2);
     }
+    if( pLevel->addrLikeRep ){
+      addr = sqlite3VdbeAddOp1(v, OP_IfPos, pLevel->iLikeRepCntr);
+      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);
       assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0
index 2ccc6ec0648e95afbbb851581ff700ed6a2c9098..6a42af47a868a02c1e3a80659fabc67c4d61f4c1 100644 (file)
@@ -69,6 +69,8 @@ struct WhereLevel {
   int addrCont;         /* Jump here to continue with the next loop cycle */
   int addrFirst;        /* First instruction of interior of the loop */
   int addrBody;         /* Beginning of the body of this loop */
+  int iLikeRepCntr;     /* LIKE range processing counter register */
+  int addrLikeRep;      /* LIKE range processing address */
   u8 iFrom;             /* Which entry in the FROM clause */
   u8 op, p3, p5;        /* Opcode, P3 & P5 of the opcode that ends the loop */
   int p1, p2;           /* Operands of the opcode used to ends the loop */
@@ -253,7 +255,7 @@ struct WhereTerm {
   } u;
   LogEst truthProb;       /* Probability of truth for this expression */
   u16 eOperator;          /* A WO_xx value describing <op> */
-  u8 wtFlags;             /* TERM_xxx bit flags.  See below */
+  u16 wtFlags;            /* TERM_xxx bit flags.  See below */
   u8 nChild;              /* Number of children that must disable us */
   WhereClause *pWC;       /* The clause this term is part of */
   Bitmask prereqRight;    /* Bitmask of tables used by pExpr->pRight */
@@ -275,6 +277,7 @@ struct WhereTerm {
 #else
 #  define TERM_VNULL    0x00   /* Disabled if not using stat3 */
 #endif
+#define TERM_LIKEOPT    0x100  /* Used by the LIKE optimization */
 
 /*
 ** An instance of the WhereScan object is used as an iterator for locating