From: drh Date: Mon, 2 May 2016 10:25:42 +0000 (+0000) Subject: Improvements to the way the LIKE optimization is implemented, resulting in X-Git-Tag: version-3.13.0~47 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=44aebff24623d6adc3e2977d1e95ad1a2353ea6d;p=thirdparty%2Fsqlite.git Improvements to the way the LIKE optimization is implemented, resulting in slightly smaller and faster code that is easier to test. FossilOrigin-Name: 54c63b329288729031f45b7778752552cd90e226 --- diff --git a/manifest b/manifest index ec489b353d..4b7ff45c68 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Change\sthe\sway\stester.tcl\shandes\s$argv\sso\sthat\sin\s"permutations.test\s\s"\s\smay\sbe\sthe\sname\sof\sany\sfile\sin\sthe\stest/\sdirectory. -D 2016-04-30T19:23:10.056 +C Improvements\sto\sthe\sway\sthe\sLIKE\soptimization\sis\simplemented,\sresulting\sin\nslightly\ssmaller\sand\sfaster\scode\sthat\sis\seasier\sto\stest. +D 2016-05-02T10:25:42.392 F Makefile.in 9e816d0323e418fbc0f8b2c05fc14e0b3763d9e8 F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434 F Makefile.msc 71b8b16cf9393f68e2e2035486ca104872558836 @@ -443,7 +443,7 @@ F src/update.c 3e67ab3c0814635f355fb1f8ab010a2b9e016e7d F src/utf.c 699001c79f28e48e9bcdf8a463da029ea660540c F src/util.c 810ec3f22e2d1b62e66c30fe3621ebdedd23584d F src/vacuum.c feb1eabb20987983d9350cad98299b21fa811f52 -F src/vdbe.c 465bb820f9760602959ba8d279cdae621206d696 +F src/vdbe.c 4bad04212736526845fda9ca674afafb10078b2b F src/vdbe.h 5591b5add447096e31288b5a0a78ec5d7b5c5170 F src/vdbeInt.h ddb157974436d87652de7dc641f7191496d9a8cd F src/vdbeapi.c ba85b78fe08dc4a9ce747e62c89a2b4a4547e74c @@ -457,9 +457,9 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c 4db22ed7e77bcf672b1a685d6ddeffba8d5be302 F src/wal.h 2f7c831cf3b071fa548bf2d5cac640846a7ff19c F src/walker.c 0f142b5bd3ed2041fc52d773880748b212e63354 -F src/where.c bae50f2f18f9e8584549a77363858623b07e4915 -F src/whereInt.h 7de94b751f088fe3fdc8cc04a491376f0900a059 -F src/wherecode.c 8fdad9fbba723df1c1e8d07e7ea8507572040340 +F src/where.c 019e5b10dedcf54ef077ce23dd8fce38d614dcf4 +F src/whereInt.h 3b1fc240e322613ba4e9dc857ca9c7c3390acc74 +F src/wherecode.c 28951741be3974701186281ced0564e9586a0db3 F src/whereexpr.c eacc0e60d029a082b4fc0cc42ea98544add1319e F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd @@ -1486,7 +1486,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 459a0b456da69112605b37adc9af27d79e35a4d7 -R 23212a22e435d3100aef78ab9c45b327 -U dan -Z 034fcb062ad20342a7b230d87b3ffc20 +P 820c57bb24ad3d8663ca512e4022268b940bb2ee +R c58e65d0f2e2d03ddd82d7f66bccab45 +U drh +Z 38f3015d7db64980369a2f7c9273004f diff --git a/manifest.uuid b/manifest.uuid index 6ff03c7829..d98c57c9ad 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -820c57bb24ad3d8663ca512e4022268b940bb2ee \ No newline at end of file +54c63b329288729031f45b7778752552cd90e226 \ No newline at end of file diff --git a/src/vdbe.c b/src/vdbe.c index 469ab86e42..dc8201595b 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -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. ** -** 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 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 */ assert( pOp->p4.z!=0 ); @@ -1105,12 +1107,11 @@ case OP_String: { /* out2 */ pOut->enc = encoding; UPDATE_MAX_BLOBSIZE(pOut); #ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS - if( pOp->p5 ){ - assert( pOp->p3>0 ); + if( pOp->p3>0 ){ assert( pOp->p3<=(p->nMem+1 - p->nCursor) ); pIn3 = &aMem[pOp->p3]; 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 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 ** Synopsis: accum=r[P3] step(r[P2@P5]) ** diff --git a/src/where.c b/src/where.c index ca810a3b16..d45a872c85 100644 --- a/src/where.c +++ b/src/where.c @@ -4607,13 +4607,8 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ } #ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS if( 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); + sqlite3VdbeAddOp2(v, OP_DecrJumpZero, (int)(pLevel->iLikeRepCntr>>1), + pLevel->addrLikeRep); VdbeCoverage(v); } #endif diff --git a/src/whereInt.h b/src/whereInt.h index 252905aa5a..d33d995af1 100644 --- a/src/whereInt.h +++ b/src/whereInt.h @@ -70,7 +70,7 @@ struct WhereLevel { int addrFirst; /* First instruction of interior of the loop */ int addrBody; /* Beginning of the body of this loop */ #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 */ #endif u8 iFrom; /* Which entry in the FROM clause */ diff --git a/src/wherecode.c b/src/wherecode.c index 8105e99dde..77543a9388 100644 --- a/src/wherecode.c +++ b/src/wherecode.c @@ -560,9 +560,10 @@ static int codeAllEqualityTerms( #ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS /* -** If the most recently coded instruction is a constant range contraint -** that originated from the LIKE optimization, then change the P3 to be -** pLoop->iLikeRepCntr and set P5. +** If the most recently coded instruction is a constant range constraint +** (a string literal) that originated from the LIKE optimization, then +** 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 ** expression: "x>='ABC' AND x<'abd'". But this requires that the range @@ -587,8 +588,8 @@ static void whereLikeOptimizationStringFixup( assert( pOp!=0 ); assert( pOp->opcode==OP_String8 || pTerm->pWC->pWInfo->pParse->db->mallocFailed ); - pOp->p3 = pLevel->iLikeRepCntr; - pOp->p5 = 1; + pOp->p3 = (int)(pLevel->iLikeRepCntr>>1); /* Register holding counter */ + pOp->p5 = (u8)(pLevel->iLikeRepCntr&1); /* ASC or DESC */ } } #else @@ -1175,14 +1176,17 @@ Bitmask sqlite3WhereCodeOneLoopStart( if( (pRangeEnd->wtFlags & TERM_LIKEOPT)!=0 ){ assert( pRangeStart!=0 ); /* LIKE opt constraints */ assert( pRangeStart->wtFlags & TERM_LIKEOPT ); /* occur in pairs */ - pLevel->iLikeRepCntr = ++pParse->nMem; - testcase( bRev ); - testcase( pIdx->aSortOrder[nEq]==SQLITE_SO_DESC ); - sqlite3VdbeAddOp2(v, OP_Integer, - bRev ^ (pIdx->aSortOrder[nEq]==SQLITE_SO_DESC), - pLevel->iLikeRepCntr); + pLevel->iLikeRepCntr = (u32)++pParse->nMem; + sqlite3VdbeAddOp2(v, OP_Integer, 1, (int)pLevel->iLikeRepCntr); VdbeComment((v, "LIKE loop counter")); 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 if( pRangeStart==0 @@ -1696,11 +1700,17 @@ Bitmask sqlite3WhereCodeOneLoopStart( continue; } 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 continue; #else - assert( pLevel->iLikeRepCntr>0 ); - skipLikeAddr = sqlite3VdbeAddOp1(v, OP_IfNot, pLevel->iLikeRepCntr); + u32 x = pLevel->iLikeRepCntr; + assert( x>0 ); + skipLikeAddr = sqlite3VdbeAddOp1(v, (x&1)? OP_IfNot : OP_If, (int)(x>>1)); VdbeCoverage(v); #endif }