From f07cf6e2a54866d913ca8a9b4eaae3d3aecb2601 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 6 Mar 2015 16:45:16 +0000 Subject: [PATCH 1/7] The LIKE optimization must be applied twice, once for strings and a second time for BLOBs. Ticket [05f43be8fdda9f]. This check-in is a proof-of-concept of how that might be done. FossilOrigin-Name: 5757e803cb5759b476bbc6453c58340089611420 --- manifest | 19 +++++++++++-------- manifest.uuid | 2 +- src/vdbe.c | 16 ++++++++++++++-- src/where.c | 49 +++++++++++++++++++++++++++++++++++++++++++------ src/whereInt.h | 5 ++++- 5 files changed, 73 insertions(+), 18 deletions(-) diff --git a/manifest b/manifest index d6db801e6a..759c643d71 100644 --- 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 diff --git a/manifest.uuid b/manifest.uuid index aa2a348ab8..58f48bf654 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -8c1e85aab9e0d90726057e25e2ea0663341c070f \ No newline at end of file +5757e803cb5759b476bbc6453c58340089611420 \ No newline at end of file diff --git a/src/vdbe.c b/src/vdbe.c index 39a334f29f..0c9a67e56b 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -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; } diff --git a/src/where.c b/src/where.c index fedc67a791..82c7e699f4 100644 --- a/src/where.c +++ b/src/where.c @@ -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 diff --git a/src/whereInt.h b/src/whereInt.h index 2ccc6ec064..6a42af47a8 100644 --- a/src/whereInt.h +++ b/src/whereInt.h @@ -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 */ - 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 From 8f1a7ed33f89a56ed58aa99516014dbf0295df64 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 6 Mar 2015 19:47:38 +0000 Subject: [PATCH 2/7] Fix the LIKE optimization even when comparing mixed-case BLOBs. FossilOrigin-Name: a58aafdb4e1422b6a8ffc07a67984928bbedf919 --- manifest | 17 ++++++-------- manifest.uuid | 2 +- src/where.c | 62 ++++++++++++++++++++++++++++++++++++++++---------- src/whereInt.h | 4 +++- 4 files changed, 61 insertions(+), 24 deletions(-) diff --git a/manifest b/manifest index 759c643d71..4af39ccdfb 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -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 +C Fix\sthe\sLIKE\soptimization\seven\swhen\scomparing\smixed-case\sBLOBs. +D 2015-03-06T19:47:38.505 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 2f643d6968dfc0b82d2e546a0525a39079f9e928 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -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 b7e82341d2570ac8a051e133cfc44c7eec79a30e -F src/whereInt.h 0ba6257f2a44acd6262f259d5147cd01c52cc45b +F src/where.c cace7eef1838ea22f549e824236eaaa4195b83e6 +F src/whereInt.h cbe4aa57326998d89e7698ca65bb7c28541d483c F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test b35b4cd69fc913f90d39a575e171e1116c3a4bb7 @@ -1240,10 +1240,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 8c1e85aab9e0d90726057e25e2ea0663341c070f -R db06eec232964b57030b876196612d14 -T *branch * like-opt-fix -T *sym-like-opt-fix * -T -sym-trunk * +P 5757e803cb5759b476bbc6453c58340089611420 +R 1a18426c5e280ce5513288eef4bf379e U drh -Z 9b71822fa0ca3d1b398ae4d623871060 +Z 4902bd060fa099614e1fc5278ee9e5b6 diff --git a/manifest.uuid b/manifest.uuid index 58f48bf654..95ba3aa550 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5757e803cb5759b476bbc6453c58340089611420 \ No newline at end of file +a58aafdb4e1422b6a8ffc07a67984928bbedf919 \ No newline at end of file diff --git a/src/where.c b/src/where.c index 82c7e699f4..24c3843472 100644 --- a/src/where.c +++ b/src/where.c @@ -1264,9 +1264,25 @@ static void exprAnalyze( int idxNew1; int idxNew2; Token sCollSeqName; /* Name of collating sequence */ + const u16 wtFlags = TERM_LIKEOPT | TERM_VIRTUAL | TERM_DYNAMIC; + pTerm->wtFlags |= TERM_LIKE; pLeft = pExpr->x.pList->a[1].pExpr; pStr2 = sqlite3ExprDup(db, pStr1, 0); + + /* Convert the lower bound to upper-case and the upper bound to + ** lower-case (upper-case is less than lower-case in ASCII) so that + ** the range constraints also work for BLOBs + */ + if( noCase && !pParse->db->mallocFailed ){ + int i; + char c; + for(i=0; (c = pStr1->u.zToken[i])!=0; i++){ + pStr1->u.zToken[i] = sqlite3Toupper(c); + pStr2->u.zToken[i] = sqlite3Tolower(c); + } + } + if( !db->mallocFailed ){ u8 c, *pC; /* Last character before the first wildcard */ pC = (u8*)&pStr2->u.zToken[sqlite3Strlen30(pStr2->u.zToken)-1]; @@ -1286,12 +1302,11 @@ static void exprAnalyze( sCollSeqName.z = noCase ? "NOCASE" : "BINARY"; sCollSeqName.n = 6; pNewExpr1 = sqlite3ExprDup(db, pLeft, 0); - pNewExpr1 = sqlite3PExpr(pParse, TK_GE, + pNewExpr1 = sqlite3PExpr(pParse, TK_GE, sqlite3ExprAddCollateToken(pParse,pNewExpr1,&sCollSeqName), pStr1, 0); transferJoinMarkings(pNewExpr1, pExpr); - idxNew1 = whereClauseInsert(pWC, pNewExpr1, - TERM_LIKEOPT|TERM_VIRTUAL|TERM_DYNAMIC); + idxNew1 = whereClauseInsert(pWC, pNewExpr1, wtFlags); testcase( idxNew1==0 ); exprAnalyze(pSrc, pWC, idxNew1); pNewExpr2 = sqlite3ExprDup(db, pLeft, 0); @@ -1299,8 +1314,7 @@ static void exprAnalyze( sqlite3ExprAddCollateToken(pParse,pNewExpr2,&sCollSeqName), pStr2, 0); transferJoinMarkings(pNewExpr2, pExpr); - idxNew2 = whereClauseInsert(pWC, pNewExpr2, - TERM_LIKEOPT|TERM_VIRTUAL|TERM_DYNAMIC); + idxNew2 = whereClauseInsert(pWC, pNewExpr2, wtFlags); testcase( idxNew2==0 ); exprAnalyze(pSrc, pWC, idxNew2); pTerm = &pWC->a[idxTerm]; @@ -2475,20 +2489,37 @@ static int whereInScanEst( ** but joins might run a little slower. The trick is to disable as much ** as we can without disabling too much. If we disabled in (1), we'd get ** the wrong answer. See ticket #813. +** +** If all the children of a term are disabled, then that term is also +** automatically disabled. In this way, terms get disabled if derived +** virtual terms are tested first. For example: +** +** x GLOB 'abc*' AND x>='abc' AND x<'acd' +** \___________/ \______/ \_____/ +** parent child1 child2 +** +** Only the parent term was in the original WHERE clause. The child1 +** and child2 terms were added by the LIKE optimization. If both of +** the virtual child terms are valid, then testing of the parent can be +** skipped. */ static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){ - if( pTerm + int nLoop = 0; + while( pTerm && (pTerm->wtFlags & TERM_CODED)==0 && (pLevel->iLeftJoin==0 || ExprHasProperty(pTerm->pExpr, EP_FromJoin)) && (pLevel->notReady & pTerm->prereqAll)==0 ){ - pTerm->wtFlags |= TERM_CODED; - if( pTerm->iParent>=0 ){ - WhereTerm *pOther = &pTerm->pWC->a[pTerm->iParent]; - if( (--pOther->nChild)==0 ){ - disableTerm(pLevel, pOther); - } + if( nLoop && (pTerm->wtFlags & TERM_LIKE)!=0 ){ + pTerm->wtFlags |= TERM_LIKECOND; + }else{ + pTerm->wtFlags |= TERM_CODED; } + if( pTerm->iParent<0 ) break; + pTerm = &pTerm->pWC->a[pTerm->iParent]; + pTerm->nChild--; + if( pTerm->nChild!=0 ) break; + nLoop++; } } @@ -3807,6 +3838,7 @@ static Bitmask codeOneLoopStart( */ for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){ Expr *pE; + int skipLikeAddr = 0; testcase( pTerm->wtFlags & TERM_VIRTUAL ); testcase( pTerm->wtFlags & TERM_CODED ); if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; @@ -3821,7 +3853,13 @@ static Bitmask codeOneLoopStart( if( pLevel->iLeftJoin && !ExprHasProperty(pE, EP_FromJoin) ){ continue; } + if( pTerm->wtFlags & TERM_LIKECOND ){ + assert( pLevel->iLikeRepCntr>0 ); + skipLikeAddr = sqlite3VdbeAddOp1(v, OP_IfZero, pLevel->iLikeRepCntr); + VdbeCoverage(v); + } sqlite3ExprIfFalse(pParse, pE, addrCont, SQLITE_JUMPIFNULL); + if( skipLikeAddr ) sqlite3VdbeJumpHere(v, skipLikeAddr); pTerm->wtFlags |= TERM_CODED; } diff --git a/src/whereInt.h b/src/whereInt.h index 6a42af47a8..04cc2029d8 100644 --- a/src/whereInt.h +++ b/src/whereInt.h @@ -277,7 +277,9 @@ struct WhereTerm { #else # define TERM_VNULL 0x00 /* Disabled if not using stat3 */ #endif -#define TERM_LIKEOPT 0x100 /* Used by the LIKE optimization */ +#define TERM_LIKEOPT 0x100 /* Virtual terms from the LIKE optimization */ +#define TERM_LIKECOND 0x200 /* Conditionally this LIKE operator term */ +#define TERM_LIKE 0x400 /* The original LIKE operator */ /* ** An instance of the WhereScan object is used as an iterator for locating From a9c18a90673169aa9f39dbfff515dded87654691 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 6 Mar 2015 20:49:52 +0000 Subject: [PATCH 3/7] Test cases added. Comments fixed. Proposed solution for ticket [05f43be8fdda9fbd9]. FossilOrigin-Name: 6b993bd54035b67f4d84941e3f444ca79b7feee1 --- manifest | 21 ++++++++-------- manifest.uuid | 2 +- src/vdbe.c | 6 ++--- src/where.c | 19 +++++++++++---- test/analyze3.test | 24 +++++++++---------- test/like.test | 4 ++-- test/like3.test | 60 ++++++++++++++++++++++++++++++++++++++++++++++ test/where8.test | 4 ++-- 8 files changed, 105 insertions(+), 35 deletions(-) create mode 100644 test/like3.test diff --git a/manifest b/manifest index 4af39ccdfb..254c6a0b57 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sthe\sLIKE\soptimization\seven\swhen\scomparing\smixed-case\sBLOBs. -D 2015-03-06T19:47:38.505 +C Test\scases\sadded.\s\sComments\sfixed.\s\sProposed\ssolution\sfor\nticket\s[05f43be8fdda9fbd9]. +D 2015-03-06T20:49:52.770 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 6bee3b85a2f013a8fdc496996089d3b6bedfb525 +F src/vdbe.c c9f4ad2c62bccebed38b1fd253064ed2a2c659ae 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 cace7eef1838ea22f549e824236eaaa4195b83e6 +F src/where.c 8cd4fc29addda0945b28b1f849a7998e3749d8b9 F src/whereInt.h cbe4aa57326998d89e7698ca65bb7c28541d483c F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 @@ -321,7 +321,7 @@ F test/alter4.test c461150723ac957f3b2214aa0b11552cd72023ec F test/altermalloc.test e81ac9657ed25c6c5bb09bebfa5a047cd8e4acfc F test/amatch1.test b5ae7065f042b7f4c1c922933f4700add50cdb9f F test/analyze.test 1772936d66471c65221e437b6d1999c3a03166c4 -F test/analyze3.test bf41f0f680dd1e0d44eed5e769531e93a5320275 +F test/analyze3.test 75b9e42ea1e4edc919250450dc5762186965d4e6 F test/analyze4.test eff2df19b8dd84529966420f29ea52edc6b56213 F test/analyze5.test 765c4e284aa69ca172772aa940946f55629bc8c4 F test/analyze6.test f1c552ce39cca4ec922a7e4e0e5d0203d6b3281f @@ -689,8 +689,9 @@ F test/jrnlmode3.test 556b447a05be0e0963f4311e95ab1632b11c9eaa F test/keyword1.test 37ef6bba5d2ed5b07ecdd6810571de2956599dff F test/lastinsert.test 42e948fd6442f07d60acbd15d33fb86473e0ef63 F test/laststmtchanges.test ae613f53819206b3222771828d024154d51db200 -F test/like.test e191e536d0fcd722a6b965e7cd1ee0bfd12a5991 +F test/like.test 4f2a71d36a536233727f71995fef900756705e56 F test/like2.test 3b2ee13149ba4a8a60b59756f4e5d345573852da +F test/like3.test 9c85587224f739c81b51d8cdd2727c11ec678526 F test/limit.test 0c99a27a87b14c646a9d583c7c89fd06c352663e F test/loadext.test 648cb95f324d1775c54a55c12271b2d1156b633b F test/loadext2.test 0408380b57adca04004247179837a18e866a74f7 @@ -1158,7 +1159,7 @@ F test/where4.test d8420ceeb8323a41ceff1f1841fc528e824e1ecf F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2 F test/where6.test 5da5a98cec820d488e82708301b96cb8c18a258b F test/where7.test 5a4b0abc207d71da4deecd734ad8579e8dd40aa8 -F test/where8.test 806f1dcec4088be2b826b33f757fe6e17c3236a1 +F test/where8.test 2eafe74e01cc10355985874e1ff868ac03dbae5e F test/where8m.test da346596e19d54f0aba35ebade032a7c47d79739 F test/where9.test 729c3ba9b47e8f9f1aab96bae7dad2a524f1d1a2 F test/whereA.test 4d253178d135ec46d1671e440cd8f2b916aa6e6b @@ -1240,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 5757e803cb5759b476bbc6453c58340089611420 -R 1a18426c5e280ce5513288eef4bf379e +P a58aafdb4e1422b6a8ffc07a67984928bbedf919 +R d75eaf03976986bf457292a7b369e1ff U drh -Z 4902bd060fa099614e1fc5278ee9e5b6 +Z 9b58e75e5227e2cbfcfb68532871937f diff --git a/manifest.uuid b/manifest.uuid index 95ba3aa550..7643f85079 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a58aafdb4e1422b6a8ffc07a67984928bbedf919 \ No newline at end of file +6b993bd54035b67f4d84941e3f444ca79b7feee1 \ No newline at end of file diff --git a/src/vdbe.c b/src/vdbe.c index 0c9a67e56b..6adea67960 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -1053,9 +1053,9 @@ case OP_String8: { /* same as TK_STRING, out2-prerelease */ ** 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. +** the datatype of the register P2 is converted to BLOB. The content is +** the same sequence of bytes, it is merely interpreted as a BLOB instead +** of a string, as if it had been CAST. */ case OP_String: { /* out2-prerelease */ assert( pOp->p4.z!=0 ); diff --git a/src/where.c b/src/where.c index 24c3843472..e79e7d33bc 100644 --- a/src/where.c +++ b/src/where.c @@ -1109,7 +1109,7 @@ static void exprAnalyze( Bitmask extraRight = 0; /* Extra dependencies on LEFT JOIN */ Expr *pStr1 = 0; /* RHS of LIKE/GLOB operator */ int isComplete = 0; /* RHS of LIKE/GLOB ends with wildcard */ - int noCase = 0; /* LIKE/GLOB distinguishes case */ + int noCase = 0; /* uppercase equivalent to lowercase */ int op; /* Top-level operator. pExpr->op */ Parse *pParse = pWInfo->pParse; /* Parsing context */ sqlite3 *db = pParse->db; /* Database connection */ @@ -1247,12 +1247,15 @@ static void exprAnalyze( /* Add constraints to reduce the search space on a LIKE or GLOB ** operator. ** - ** A like pattern of the form "x LIKE 'abc%'" is changed into constraints + ** A like pattern of the form "x LIKE 'aBc%'" is changed into constraints ** - ** x>='abc' AND x<'abd' AND x LIKE 'abc%' + ** x>='ABC' AND x<'abd' AND x LIKE 'aBc%' ** ** The last character of the prefix "abc" is incremented to form the - ** termination condition "abd". + ** termination condition "abd". If case is not significant (the default + ** for LIKE) then the lower-bound is made all uppercase and the upper- + ** bound is made all lowercase so that the bounds also work when comparing + ** BLOBs. */ if( pWC->op==TK_AND && isLikeOrGlob(pParse, pExpr, &pStr1, &isComplete, &noCase) @@ -1266,7 +1269,6 @@ static void exprAnalyze( Token sCollSeqName; /* Name of collating sequence */ const u16 wtFlags = TERM_LIKEOPT | TERM_VIRTUAL | TERM_DYNAMIC; - pTerm->wtFlags |= TERM_LIKE; pLeft = pExpr->x.pList->a[1].pExpr; pStr2 = sqlite3ExprDup(db, pStr1, 0); @@ -1277,6 +1279,7 @@ static void exprAnalyze( if( noCase && !pParse->db->mallocFailed ){ int i; char c; + pTerm->wtFlags |= TERM_LIKE; for(i=0; (c = pStr1->u.zToken[i])!=0; i++){ pStr1->u.zToken[i] = sqlite3Toupper(c); pStr2->u.zToken[i] = sqlite3Tolower(c); @@ -2502,6 +2505,12 @@ static int whereInScanEst( ** and child2 terms were added by the LIKE optimization. If both of ** the virtual child terms are valid, then testing of the parent can be ** skipped. +** +** Usually the parent term is marked as TERM_CODED. But if the parent +** term was originally TERM_LIKE, then the parent gets TERM_LIKECOND instead. +** The TERM_LIKECOND marking indicates that the term should be coded inside +** a conditional such that is only evaluated on the second pass of a +** LIKE-optimization loop, when scanning BLOBs instead of strings. */ static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){ int nLoop = 0; diff --git a/test/analyze3.test b/test/analyze3.test index e7416d5730..d22387dcc3 100644 --- a/test/analyze3.test +++ b/test/analyze3.test @@ -281,35 +281,35 @@ do_eqp_test analyze3-2.3 { do_test analyze3-2.4 { sf_execsql { SELECT count(*) FROM t1 WHERE b LIKE 'a%' } -} {101 0 100} +} {102 0 100} do_test analyze3-2.5 { sf_execsql { SELECT count(*) FROM t1 WHERE b LIKE '%a' } } {999 999 100} -do_test analyze3-2.4 { +do_test analyze3-2.6 { set like "a%" sf_execsql { SELECT count(*) FROM t1 WHERE b LIKE $like } -} {101 0 100} -do_test analyze3-2.5 { +} {102 0 100} +do_test analyze3-2.7 { set like "%a" sf_execsql { SELECT count(*) FROM t1 WHERE b LIKE $like } } {999 999 100} -do_test analyze3-2.6 { +do_test analyze3-2.8 { set like "a" sf_execsql { SELECT count(*) FROM t1 WHERE b LIKE $like } -} {101 0 0} -do_test analyze3-2.7 { +} {102 0 0} +do_test analyze3-2.9 { set like "ab" sf_execsql { SELECT count(*) FROM t1 WHERE b LIKE $like } -} {11 0 0} -do_test analyze3-2.8 { +} {12 0 0} +do_test analyze3-2.10 { set like "abc" sf_execsql { SELECT count(*) FROM t1 WHERE b LIKE $like } -} {2 0 1} -do_test analyze3-2.9 { +} {3 0 1} +do_test analyze3-2.11 { set like "a_c" sf_execsql { SELECT count(*) FROM t1 WHERE b LIKE $like } -} {101 0 10} +} {102 0 10} #------------------------------------------------------------------------- diff --git a/test/like.test b/test/like.test index 923272cfb2..18a01dc996 100644 --- a/test/like.test +++ b/test/like.test @@ -749,7 +749,7 @@ ifcapable like_opt&&!icu { count { SELECT a FROM t10 WHERE f LIKE '12%' ORDER BY +a; } - } {12 123 scan 3 like 0} + } {12 123 scan 4 like 0} do_test like-10.6 { count { SELECT a FROM t10 WHERE a LIKE '12%' ORDER BY +a; @@ -790,7 +790,7 @@ ifcapable like_opt&&!icu { count { SELECT a FROM t10b WHERE f GLOB '12*' ORDER BY +a; } - } {12 123 scan 3 like 0} + } {12 123 scan 4 like 0} do_test like-10.15 { count { SELECT a FROM t10b WHERE a GLOB '12*' ORDER BY +a; diff --git a/test/like3.test b/test/like3.test new file mode 100644 index 0000000000..b3af2cda91 --- /dev/null +++ b/test/like3.test @@ -0,0 +1,60 @@ +# 2015-03-06 +# +# 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 the LIKE and GLOB operators and +# in particular the optimizations that occur to help those operators +# run faster and that those optimizations work correctly when there +# are both strings and blobs being tested. +# +# Ticket 05f43be8fdda9fbd948d374319b99b054140bc36 shows that the following +# SQL was not working correctly: +# +# CREATE TABLE t1(x TEXT UNIQUE COLLATE nocase); +# INSERT INTO t1(x) VALUES(x'616263'); +# SELECT 'query-1', x FROM t1 WHERE x LIKE 'a%'; +# SELECT 'query-2', x FROM t1 WHERE +x LIKE 'a%'; +# +# This script verifies that it works right now. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +do_execsql_test like3-1.1 { + PRAGMA encoding=UTF8; + CREATE TABLE t1(a,b TEXT COLLATE nocase); + INSERT INTO t1(a,b) + VALUES(1,'abc'), + (2,'ABX'), + (3,'BCD'), + (4,x'616263'), + (5,x'414258'), + (6,x'424344'); + CREATE INDEX t1ba ON t1(b,a); + + SELECT a, b FROM t1 WHERE b LIKE 'aB%' ORDER BY +a; +} {1 abc 2 ABX 4 abc 5 ABX} +do_execsql_test like3-1.2 { + SELECT a, b FROM t1 WHERE +b LIKE 'aB%' ORDER BY +a; +} {1 abc 2 ABX 4 abc 5 ABX} + +do_execsql_test like3-1.3 { + CREATE TABLE t2(a, b TEXT); + INSERT INTO t2 SELECT a, b FROM t1; + CREATE INDEX t2ba ON t2(b,a); + SELECT a, b FROM t2 WHERE b GLOB 'ab*' ORDER BY +a; +} {1 abc 4 abc} +do_execsql_test like3-1.4 { + SELECT a, b FROM t2 WHERE +b GLOB 'ab*' ORDER BY +a; +} {1 abc 4 abc} + +finish_test diff --git a/test/where8.test b/test/where8.test index 139251aa07..a155a95ab2 100644 --- a/test/where8.test +++ b/test/where8.test @@ -66,11 +66,11 @@ do_test where8-1.3 { do_test where8-1.4 { execsql_status2 { SELECT c FROM t1 WHERE a > 8 OR b GLOB 't*' } -} {IX X III II 0 0 9} +} {IX X III II 0 0 10} do_test where8-1.5 { execsql_status2 { SELECT c FROM t1 WHERE a > 8 OR b GLOB 'f*' } -} {IX X V IV 0 0 9} +} {IX X V IV 0 0 10} do_test where8-1.6 { execsql_status { SELECT c FROM t1 WHERE a = 1 OR b = 'three' ORDER BY rowid } From 16897072b5bd1dc5970cc7d3259f538424f502ad Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 7 Mar 2015 00:57:37 +0000 Subject: [PATCH 4/7] Refactor some jump opcodes in the VDBE. Add JumpZeroIncr and DecrJumpZero. Fix the LIKE optimization to work with DESC sort order. FossilOrigin-Name: 26cb5145bf52f8c3fffa8c69b6c24aee4d974883 --- manifest | 20 +++++++++--------- manifest.uuid | 2 +- src/func.c | 5 +++++ src/select.c | 19 +++++++---------- src/vdbe.c | 56 +++++++++++++++++++++++++++++++++++++++++-------- src/where.c | 22 ++++++++++++------- test/like3.test | 14 +++++++++++++ 7 files changed, 100 insertions(+), 38 deletions(-) diff --git a/manifest b/manifest index 254c6a0b57..5043d98fbb 100644 --- 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 diff --git a/manifest.uuid b/manifest.uuid index 7643f85079..35dc95ffee 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -6b993bd54035b67f4d84941e3f444ca79b7feee1 \ No newline at end of file +26cb5145bf52f8c3fffa8c69b6c24aee4d974883 \ No newline at end of file diff --git a/src/func.c b/src/func.c index 30990a30f3..d917bdbec3 100644 --- a/src/func.c +++ b/src/func.c @@ -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; diff --git a/src/select.c b/src/select.c index 91b3d4345f..a9cecaa390 100644 --- a/src/select.c +++ b/src/select.c @@ -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 diff --git a/src/vdbe.c b/src/vdbe.c index 6adea67960..f81bfa8a79 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -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]) ** diff --git a/src/where.c b/src/where.c index e79e7d33bc..ece403dfaa 100644 --- a/src/where.c +++ b/src/where.c @@ -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); diff --git a/test/like3.test b/test/like3.test index b3af2cda91..7ca45f88c2 100644 --- a/test/like3.test +++ b/test/like3.test @@ -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 From b7c60ba668a6abd18fb30877a003cb3ff336156d Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 7 Mar 2015 02:51:59 +0000 Subject: [PATCH 5/7] Fix problems with reverse order sorting and indexes in the LIKE optimization. FossilOrigin-Name: 564b8fe79475d7584a21078e6098840b8ce6a6e1 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/where.c | 18 ++++++++++++++---- test/like3.test | 26 ++++++++++++++++++++++++++ 4 files changed, 48 insertions(+), 12 deletions(-) diff --git a/manifest b/manifest index 5043d98fbb..5835e728b1 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -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 +C Fix\sproblems\swith\sreverse\sorder\ssorting\sand\sindexes\sin\sthe\sLIKE\soptimization. +D 2015-03-07T02:51:59.332 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 2f643d6968dfc0b82d2e546a0525a39079f9e928 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -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 7c646a15d0d17850e10319aa31662d5ab61c69af +F src/where.c efa0cef9fdf1c7f15e1f22d8e0a26d989c5fd947 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 f6fa86d6a81d95bd796c46b0e2ba7444669bdd7e +F test/like3.test 2fd1fd45cf7169093206e0d1d848e616df98ed46 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 6b993bd54035b67f4d84941e3f444ca79b7feee1 -R f90848042fe53f442912e9f9b75887d2 +P 26cb5145bf52f8c3fffa8c69b6c24aee4d974883 +R 26c030dedce138311a8813ea74e14352 U drh -Z ceb5f3bff4db8044ae0448ec360f04b2 +Z 2f44b5f1b4f68b861174549cabd12bcf diff --git a/manifest.uuid b/manifest.uuid index 35dc95ffee..bc078d5c07 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -26cb5145bf52f8c3fffa8c69b6c24aee4d974883 \ No newline at end of file +564b8fe79475d7584a21078e6098840b8ce6a6e1 \ No newline at end of file diff --git a/src/where.c b/src/where.c index ece403dfaa..ed7febf3cb 100644 --- a/src/where.c +++ b/src/where.c @@ -3370,7 +3370,11 @@ static Bitmask codeOneLoopStart( && (pRangeEnd->wtFlags & TERM_LIKEOPT)!=0 ){ pLevel->iLikeRepCntr = ++pParse->nMem; - sqlite3VdbeAddOp2(v, OP_Integer, 0, pLevel->iLikeRepCntr); + testcase( bRev ); + testcase( pIdx->aSortOrder[nEq]==SQLITE_SO_DESC ); + sqlite3VdbeAddOp2(v, OP_Integer, + bRev ^ (pIdx->aSortOrder[nEq]==SQLITE_SO_DESC), + pLevel->iLikeRepCntr); VdbeComment((v, "LIKE loop counter")); pLevel->addrLikeRep = sqlite3VdbeCurrentAddr(v); } @@ -3401,9 +3405,11 @@ static Bitmask codeOneLoopStart( ){ SWAP(WhereTerm *, pRangeEnd, pRangeStart); SWAP(u8, bSeekPastNull, bStopAtNull); +#if 0 if( pLevel->addrLikeRep ){ sqlite3VdbeChangeP1(v, pLevel->addrLikeRep-1, 1); } +#endif } testcase( pRangeStart && (pRangeStart->eOperator & WO_LE)!=0 ); @@ -6682,9 +6688,13 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ sqlite3VdbeJumpHere(v, pLevel->addrSkip-2); } if( pLevel->addrLikeRep ){ - sqlite3VdbeAddOp2(v, - pLevel->op==OP_Prev ? OP_DecrJumpZero : OP_JumpZeroIncr, - pLevel->iLikeRepCntr, pLevel->addrLikeRep); + int op; + if( sqlite3VdbeGetOp(v, pLevel->addrLikeRep-1)->p1 ){ + op = OP_DecrJumpZero; + }else{ + op = OP_JumpZeroIncr; + } + sqlite3VdbeAddOp2(v, op, pLevel->iLikeRepCntr, pLevel->addrLikeRep); VdbeCoverage(v); } if( pLevel->iLeftJoin ){ diff --git a/test/like3.test b/test/like3.test index 7ca45f88c2..d360363747 100644 --- a/test/like3.test +++ b/test/like3.test @@ -69,6 +69,32 @@ do_execsql_test like3-3.1 { 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'} +do_execsql_test like3-3.2 { + SELECT quote(x) FROM t3 WHERE x LIKE 'ab%' ORDER BY x ASC; +} {'abc' 'abd' 'abe' X'616263' X'616264' X'616265'} +do_execsql_test like3-3.2ck { + SELECT quote(x) FROM t3 WHERE x LIKE 'ab%' ORDER BY +x ASC; +} {'abc' 'abd' 'abe' X'616263' X'616264' X'616265'} + +do_execsql_test like3-4.0 { + CREATE TABLE t4(x TEXT COLLATE nocase); + CREATE INDEX t4x ON t4(x DESC); + INSERT INTO t4(x) SELECT x FROM t3; + SELECT quote(x) FROM t4 WHERE x LIKE 'ab%' ORDER BY x; +} {'abc' 'abd' 'abe' X'616263' X'616264' X'616265'} +do_execsql_test like3-4.1 { + SELECT quote(x) FROM t4 WHERE x LIKE 'ab%' ORDER BY x DESC; +} {X'616265' X'616264' X'616263' 'abe' 'abd' 'abc'} +do_execsql_test like3-4.1ck { + SELECT quote(x) FROM t4 WHERE x LIKE 'ab%' ORDER BY +x DESC; +} {X'616265' X'616264' X'616263' 'abe' 'abd' 'abc'} +do_execsql_test like3-4.2 { + SELECT quote(x) FROM t4 WHERE x LIKE 'ab%' ORDER BY x ASC; +} {'abc' 'abd' 'abe' X'616263' X'616264' X'616265'} +do_execsql_test like3-4.2ck { + SELECT quote(x) FROM t4 WHERE x LIKE 'ab%' ORDER BY +x ASC; +} {'abc' 'abd' 'abe' X'616263' X'616264' X'616265'} + finish_test From ab87a5e5b887b0818f777de45fb630b00e98e1a3 Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 7 Mar 2015 03:02:38 +0000 Subject: [PATCH 6/7] Remove some code that is commented out. FossilOrigin-Name: 55ff429177acfdab056a16a67361a5381115c6c7 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 5 ----- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/manifest b/manifest index 5835e728b1..80dc152241 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sproblems\swith\sreverse\sorder\ssorting\sand\sindexes\sin\sthe\sLIKE\soptimization. -D 2015-03-07T02:51:59.332 +C Remove\ssome\scode\sthat\sis\scommented\sout. +D 2015-03-07T03:02:38.737 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 2f643d6968dfc0b82d2e546a0525a39079f9e928 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -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 efa0cef9fdf1c7f15e1f22d8e0a26d989c5fd947 +F src/where.c 84104123394d38aa530f4e3e12b4ac7efcd7fe19 F src/whereInt.h cbe4aa57326998d89e7698ca65bb7c28541d483c F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 @@ -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 26cb5145bf52f8c3fffa8c69b6c24aee4d974883 -R 26c030dedce138311a8813ea74e14352 +P 564b8fe79475d7584a21078e6098840b8ce6a6e1 +R fde0ab8284854a8bdb2fb2edfcc14f2f U drh -Z 2f44b5f1b4f68b861174549cabd12bcf +Z 7743073cc3ebbf2511c96fb7b06cce37 diff --git a/manifest.uuid b/manifest.uuid index bc078d5c07..7c3e1a5b9b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -564b8fe79475d7584a21078e6098840b8ce6a6e1 \ No newline at end of file +55ff429177acfdab056a16a67361a5381115c6c7 \ No newline at end of file diff --git a/src/where.c b/src/where.c index ed7febf3cb..64c9652b0b 100644 --- a/src/where.c +++ b/src/where.c @@ -3405,11 +3405,6 @@ static Bitmask codeOneLoopStart( ){ SWAP(WhereTerm *, pRangeEnd, pRangeStart); SWAP(u8, bSeekPastNull, bStopAtNull); -#if 0 - if( pLevel->addrLikeRep ){ - sqlite3VdbeChangeP1(v, pLevel->addrLikeRep-1, 1); - } -#endif } testcase( pRangeStart && (pRangeStart->eOperator & WO_LE)!=0 ); From 560b7c72beb1a5bfddf79fdb64ae3e0078c232bc Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 7 Mar 2015 12:58:52 +0000 Subject: [PATCH 7/7] New test cases for LIKE and GLOB with BLOB left-hand side values. FossilOrigin-Name: 50fa3c5fae90bd3b2f4121e99ab52d79963a6fda --- manifest | 12 ++++++------ manifest.uuid | 2 +- test/like3.test | 16 ++++++++++++++-- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 80dc152241..9eb096b756 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\ssome\scode\sthat\sis\scommented\sout. -D 2015-03-07T03:02:38.737 +C New\stest\scases\sfor\sLIKE\sand\sGLOB\swith\sBLOB\sleft-hand\sside\svalues. +D 2015-03-07T12:58:52.057 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 2f643d6968dfc0b82d2e546a0525a39079f9e928 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -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 2fd1fd45cf7169093206e0d1d848e616df98ed46 +F test/like3.test 7b0525a39e4f25c4fd113de7e2e28eb712dcdedf 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 564b8fe79475d7584a21078e6098840b8ce6a6e1 -R fde0ab8284854a8bdb2fb2edfcc14f2f +P 55ff429177acfdab056a16a67361a5381115c6c7 +R 2fc7830b1fa14938513120a1368ba854 U drh -Z 7743073cc3ebbf2511c96fb7b06cce37 +Z b3a1ad10fdcf5eac37975294f3354efc diff --git a/manifest.uuid b/manifest.uuid index 7c3e1a5b9b..da4c850322 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -55ff429177acfdab056a16a67361a5381115c6c7 \ No newline at end of file +50fa3c5fae90bd3b2f4121e99ab52d79963a6fda \ No newline at end of file diff --git a/test/like3.test b/test/like3.test index d360363747..a1faf76915 100644 --- a/test/like3.test +++ b/test/like3.test @@ -47,15 +47,27 @@ do_execsql_test like3-1.2 { SELECT a, b FROM t1 WHERE +b LIKE 'aB%' ORDER BY +a; } {1 abc 2 ABX 4 abc 5 ABX} -do_execsql_test like3-1.3 { +do_execsql_test like3-2.0 { CREATE TABLE t2(a, b TEXT); INSERT INTO t2 SELECT a, b FROM t1; CREATE INDEX t2ba ON t2(b,a); SELECT a, b FROM t2 WHERE b GLOB 'ab*' ORDER BY +a; } {1 abc 4 abc} -do_execsql_test like3-1.4 { +do_execsql_test like3-2.1 { SELECT a, b FROM t2 WHERE +b GLOB 'ab*' ORDER BY +a; } {1 abc 4 abc} +do_execsql_test like3-2.2 { + SELECT a, b FROM t2 WHERE b>=x'6162' AND b GLOB 'ab*' +} {4 abc} +do_execsql_test like3-2.3 { + SELECT a, b FROM t2 WHERE +b>=x'6162' AND +b GLOB 'ab*' +} {4 abc} +do_execsql_test like3-2.4 { + SELECT a, b FROM t2 WHERE b GLOB 'ab*' AND b>=x'6162' +} {4 abc} +do_execsql_test like3-2.5 { + SELECT a, b FROM t2 WHERE +b GLOB 'ab*' AND +b>=x'6162' +} {4 abc} do_execsql_test like3-3.0 { CREATE TABLE t3(x TEXT PRIMARY KEY COLLATE nocase);