1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-08 14:02:16 +03:00

Improvements to the way the LIKE optimization is implemented, resulting in

slightly smaller and faster code that is easier to test.

FossilOrigin-Name: 54c63b329288729031f45b7778752552cd90e226
This commit is contained in:
drh
2016-05-02 10:25:42 +00:00
parent 40cf36ff17
commit 44aebff246
6 changed files with 43 additions and 52 deletions

View File

@@ -1,5 +1,5 @@
C Change\sthe\sway\stester.tcl\shandes\s$argv\sso\sthat\sin\s"permutations.test\s<permutation>\s<filename>"\s<filename>\smay\sbe\sthe\sname\sof\sany\sfile\sin\sthe\stest/\sdirectory. C Improvements\sto\sthe\sway\sthe\sLIKE\soptimization\sis\simplemented,\sresulting\sin\nslightly\ssmaller\sand\sfaster\scode\sthat\sis\seasier\sto\stest.
D 2016-04-30T19:23:10.056 D 2016-05-02T10:25:42.392
F Makefile.in 9e816d0323e418fbc0f8b2c05fc14e0b3763d9e8 F Makefile.in 9e816d0323e418fbc0f8b2c05fc14e0b3763d9e8
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434 F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
F Makefile.msc 71b8b16cf9393f68e2e2035486ca104872558836 F Makefile.msc 71b8b16cf9393f68e2e2035486ca104872558836
@@ -443,7 +443,7 @@ F src/update.c 3e67ab3c0814635f355fb1f8ab010a2b9e016e7d
F src/utf.c 699001c79f28e48e9bcdf8a463da029ea660540c F src/utf.c 699001c79f28e48e9bcdf8a463da029ea660540c
F src/util.c 810ec3f22e2d1b62e66c30fe3621ebdedd23584d F src/util.c 810ec3f22e2d1b62e66c30fe3621ebdedd23584d
F src/vacuum.c feb1eabb20987983d9350cad98299b21fa811f52 F src/vacuum.c feb1eabb20987983d9350cad98299b21fa811f52
F src/vdbe.c 465bb820f9760602959ba8d279cdae621206d696 F src/vdbe.c 4bad04212736526845fda9ca674afafb10078b2b
F src/vdbe.h 5591b5add447096e31288b5a0a78ec5d7b5c5170 F src/vdbe.h 5591b5add447096e31288b5a0a78ec5d7b5c5170
F src/vdbeInt.h ddb157974436d87652de7dc641f7191496d9a8cd F src/vdbeInt.h ddb157974436d87652de7dc641f7191496d9a8cd
F src/vdbeapi.c ba85b78fe08dc4a9ce747e62c89a2b4a4547e74c F src/vdbeapi.c ba85b78fe08dc4a9ce747e62c89a2b4a4547e74c
@@ -457,9 +457,9 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
F src/wal.c 4db22ed7e77bcf672b1a685d6ddeffba8d5be302 F src/wal.c 4db22ed7e77bcf672b1a685d6ddeffba8d5be302
F src/wal.h 2f7c831cf3b071fa548bf2d5cac640846a7ff19c F src/wal.h 2f7c831cf3b071fa548bf2d5cac640846a7ff19c
F src/walker.c 0f142b5bd3ed2041fc52d773880748b212e63354 F src/walker.c 0f142b5bd3ed2041fc52d773880748b212e63354
F src/where.c bae50f2f18f9e8584549a77363858623b07e4915 F src/where.c 019e5b10dedcf54ef077ce23dd8fce38d614dcf4
F src/whereInt.h 7de94b751f088fe3fdc8cc04a491376f0900a059 F src/whereInt.h 3b1fc240e322613ba4e9dc857ca9c7c3390acc74
F src/wherecode.c 8fdad9fbba723df1c1e8d07e7ea8507572040340 F src/wherecode.c 28951741be3974701186281ced0564e9586a0db3
F src/whereexpr.c eacc0e60d029a082b4fc0cc42ea98544add1319e F src/whereexpr.c eacc0e60d029a082b4fc0cc42ea98544add1319e
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
@@ -1486,7 +1486,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P 459a0b456da69112605b37adc9af27d79e35a4d7 P 820c57bb24ad3d8663ca512e4022268b940bb2ee
R 23212a22e435d3100aef78ab9c45b327 R c58e65d0f2e2d03ddd82d7f66bccab45
U dan U drh
Z 034fcb062ad20342a7b230d87b3ffc20 Z 38f3015d7db64980369a2f7c9273004f

View File

@@ -1 +1 @@
820c57bb24ad3d8663ca512e4022268b940bb2ee 54c63b329288729031f45b7778752552cd90e226

View File

@@ -1091,10 +1091,12 @@ case OP_String8: { /* same as TK_STRING, out2 */
** **
** The string value P4 of length P1 (bytes) is stored in register P2. ** 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 ** If P3 is not zero and the content of register P3 is equal to P5, then
** the datatype of the register P2 is converted to BLOB. The content is ** 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 ** the same sequence of bytes, it is merely interpreted as a BLOB instead
** of a string, as if it had been CAST. ** of a string, as if it had been CAST. In other words:
**
** if( P3!=0 and reg[P3]==P5 ) reg[P2] := CAST(reg[P2] as BLOB)
*/ */
case OP_String: { /* out2 */ case OP_String: { /* out2 */
assert( pOp->p4.z!=0 ); assert( pOp->p4.z!=0 );
@@ -1105,12 +1107,11 @@ case OP_String: { /* out2 */
pOut->enc = encoding; pOut->enc = encoding;
UPDATE_MAX_BLOBSIZE(pOut); UPDATE_MAX_BLOBSIZE(pOut);
#ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS #ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS
if( pOp->p5 ){ if( pOp->p3>0 ){
assert( pOp->p3>0 );
assert( pOp->p3<=(p->nMem+1 - p->nCursor) ); assert( pOp->p3<=(p->nMem+1 - p->nCursor) );
pIn3 = &aMem[pOp->p3]; pIn3 = &aMem[pOp->p3];
assert( pIn3->flags & MEM_Int ); assert( pIn3->flags & MEM_Int );
if( pIn3->u.i ) pOut->flags = MEM_Blob|MEM_Static|MEM_Term; if( pIn3->u.i==pOp->p5 ) pOut->flags = MEM_Blob|MEM_Static|MEM_Term;
} }
#endif #endif
break; break;
@@ -5966,21 +5967,6 @@ case OP_DecrJumpZero: { /* jump, in1 */
} }
/* 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 ) goto jump_to_p2;
break;
}
/* Opcode: AggStep0 * P2 P3 P4 P5 /* Opcode: AggStep0 * P2 P3 P4 P5
** Synopsis: accum=r[P3] step(r[P2@P5]) ** Synopsis: accum=r[P3] step(r[P2@P5])
** **

View File

@@ -4607,13 +4607,8 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
} }
#ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS #ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS
if( pLevel->addrLikeRep ){ if( pLevel->addrLikeRep ){
int op; sqlite3VdbeAddOp2(v, OP_DecrJumpZero, (int)(pLevel->iLikeRepCntr>>1),
if( sqlite3VdbeGetOp(v, pLevel->addrLikeRep-1)->p1 ){ pLevel->addrLikeRep);
op = OP_DecrJumpZero;
}else{
op = OP_JumpZeroIncr;
}
sqlite3VdbeAddOp2(v, op, pLevel->iLikeRepCntr, pLevel->addrLikeRep);
VdbeCoverage(v); VdbeCoverage(v);
} }
#endif #endif

View File

@@ -70,7 +70,7 @@ struct WhereLevel {
int addrFirst; /* First instruction of interior of the loop */ int addrFirst; /* First instruction of interior of the loop */
int addrBody; /* Beginning of the body of this loop */ int addrBody; /* Beginning of the body of this loop */
#ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS #ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS
int iLikeRepCntr; /* LIKE range processing counter register */ u32 iLikeRepCntr; /* LIKE range processing counter register (times 2) */
int addrLikeRep; /* LIKE range processing address */ int addrLikeRep; /* LIKE range processing address */
#endif #endif
u8 iFrom; /* Which entry in the FROM clause */ u8 iFrom; /* Which entry in the FROM clause */

View File

@@ -560,9 +560,10 @@ static int codeAllEqualityTerms(
#ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS #ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS
/* /*
** If the most recently coded instruction is a constant range contraint ** If the most recently coded instruction is a constant range constraint
** that originated from the LIKE optimization, then change the P3 to be ** (a string literal) that originated from the LIKE optimization, then
** pLoop->iLikeRepCntr and set P5. ** set P3 and P5 on the OP_String opcode so that the string will be cast
** to a BLOB at appropriate times.
** **
** The LIKE optimization trys to evaluate "x LIKE 'abc%'" as a range ** The LIKE optimization trys to evaluate "x LIKE 'abc%'" as a range
** expression: "x>='ABC' AND x<'abd'". But this requires that the range ** expression: "x>='ABC' AND x<'abd'". But this requires that the range
@@ -587,8 +588,8 @@ static void whereLikeOptimizationStringFixup(
assert( pOp!=0 ); assert( pOp!=0 );
assert( pOp->opcode==OP_String8 assert( pOp->opcode==OP_String8
|| pTerm->pWC->pWInfo->pParse->db->mallocFailed ); || pTerm->pWC->pWInfo->pParse->db->mallocFailed );
pOp->p3 = pLevel->iLikeRepCntr; pOp->p3 = (int)(pLevel->iLikeRepCntr>>1); /* Register holding counter */
pOp->p5 = 1; pOp->p5 = (u8)(pLevel->iLikeRepCntr&1); /* ASC or DESC */
} }
} }
#else #else
@@ -1175,14 +1176,17 @@ Bitmask sqlite3WhereCodeOneLoopStart(
if( (pRangeEnd->wtFlags & TERM_LIKEOPT)!=0 ){ if( (pRangeEnd->wtFlags & TERM_LIKEOPT)!=0 ){
assert( pRangeStart!=0 ); /* LIKE opt constraints */ assert( pRangeStart!=0 ); /* LIKE opt constraints */
assert( pRangeStart->wtFlags & TERM_LIKEOPT ); /* occur in pairs */ assert( pRangeStart->wtFlags & TERM_LIKEOPT ); /* occur in pairs */
pLevel->iLikeRepCntr = ++pParse->nMem; pLevel->iLikeRepCntr = (u32)++pParse->nMem;
testcase( bRev ); sqlite3VdbeAddOp2(v, OP_Integer, 1, (int)pLevel->iLikeRepCntr);
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")); VdbeComment((v, "LIKE loop counter"));
pLevel->addrLikeRep = sqlite3VdbeCurrentAddr(v); pLevel->addrLikeRep = sqlite3VdbeCurrentAddr(v);
/* iLikeRepCntr actually stores 2x the counter register number. The
** bottom bit indicates whether the search order is ASC or DESC. */
testcase( bRev );
testcase( pIdx->aSortOrder[nEq]==SQLITE_SO_DESC );
assert( (bRev & ~1)==0 );
pLevel->iLikeRepCntr <<=1;
pLevel->iLikeRepCntr |= bRev ^ (pIdx->aSortOrder[nEq]==SQLITE_SO_DESC);
} }
#endif #endif
if( pRangeStart==0 if( pRangeStart==0
@@ -1696,11 +1700,17 @@ Bitmask sqlite3WhereCodeOneLoopStart(
continue; continue;
} }
if( pTerm->wtFlags & TERM_LIKECOND ){ if( pTerm->wtFlags & TERM_LIKECOND ){
/* If the TERM_LIKECOND flag is set, that means that the range search
** is sufficient to guarantee that the LIKE operator is true, so we
** can skip the call to the like(A,B) function. But this only works
** for strings. So do not skip the call to the function on the pass
** that compares BLOBs. */
#ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS #ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS
continue; continue;
#else #else
assert( pLevel->iLikeRepCntr>0 ); u32 x = pLevel->iLikeRepCntr;
skipLikeAddr = sqlite3VdbeAddOp1(v, OP_IfNot, pLevel->iLikeRepCntr); assert( x>0 );
skipLikeAddr = sqlite3VdbeAddOp1(v, (x&1)? OP_IfNot : OP_If, (int)(x>>1));
VdbeCoverage(v); VdbeCoverage(v);
#endif #endif
} }