From: drh <> Date: Thu, 23 Jul 2026 16:00:10 +0000 (+0000) Subject: Add the ability for Bloom filters to work on text values, as long as X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=83f39c17881b3ea079bb749374335ed07a4add71;p=thirdparty%2Fsqlite.git Add the ability for Bloom filters to work on text values, as long as the collating sequence is BINARY. FossilOrigin-Name: 2577edc796505a0a6dabccbcc1bb6a828457092caa4d074561da5e58a6f065a2 --- diff --git a/manifest b/manifest index aa9388367d..3376e09fc3 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C CLI\simprovement:\s\sNew\scommand-line\soption\s"--cmdline-edit\sBOOLEAN"\sto\nenable/disable\scommand-line\sediting.\s\sCommand-line\sediting\sis\sdisabled\nby\sdefault\sif\seither\sstdin\sor\sstdout\sis\snot\sa\stty. -D 2026-07-23T12:12:37.978 +C Add\sthe\sability\sfor\sBloom\sfilters\sto\swork\son\stext\svalues,\sas\slong\sas\nthe\scollating\ssequence\sis\sBINARY. +D 2026-07-23T16:00:10.290 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -685,7 +685,7 @@ F src/btmutex.c 30dada73a819a1ef5b7583786370dce1842e12e1ad941e4d05ac29695528daea F src/btree.c 462c140d0c1af68d75fd13a082f3c08883cc90496c2f02054ec6ca3592ee4b1c F src/btree.h 2ee0ddfdf4f8530ad1d46afffd7da21a0e243bfab10973011ac6f6b7fb4109a1 F src/btreeInt.h 1e4a7d04e809e98abc39654b6089c60d749a724598041ff553b392a3277e9b98 -F src/build.c dda58ec56d7bfa6193c21e2ccb66547412169cd488d9f7f2d462c30cfd90ea64 +F src/build.c 6d55fcda11273ae382e1bcf9695468ca0c05547a2e2f6f09d64f30cb64f4400e F src/callback.c 3605bbf02bd7ed46c79cd48346db4a32fc51d67624400539c0532f4eead804ad F src/carray.c 3efe3982d5fb323334c29328a4e189ccaef6b95612a6084ad5fa124fd5db1179 F src/complete.c f216b970ce99c5a657556cf1f17e7ddd494515d3beb63df426bf59ff43bd3d9a @@ -693,7 +693,7 @@ F src/date.c e1a002a4199bfa85e8778c0f72182c679580b131147d8e46d9221cfceffb8500 F src/dbpage.c c6a9de13b0a01f0bc94a41e16213ab1ecd15ccfe86df7255ced40fda9446257d F src/dbstat.c 73362c0df0f40ad5523a6f5501224959d0976757b511299bf892313e79d14f5c F src/delete.c 59eeca3fb88c29329afc41bb803ee568b120d9dd7470b5f38ab55cc38390b451 -F src/expr.c 15033331b4a3d90c9dedd97706e70224fbf8f6f6f9150265362e82ceb4dc84be +F src/expr.c b63b6d46f4531df5d35307cec69b0bda3b1c50dfcde6f0c14915291e02012ca3 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c 931f74cec1dc8038a0217ef340c91ce147dd1bbed08dc40c47ee0ec6edfffb08 F src/func.c 208b4d073a1e823df8d0e19d0529093c09a9984851dcfda9808445541cefe6d0 @@ -747,7 +747,7 @@ F src/shell.c.in 0df571dd1eae1a15577361902eb5487a072d3290ea94e1e72e757050b641f87 F src/sqlite.h.in 2101a2b494cbc282d0dc1c3f631c4fb83060c52876cc9d7615b091ad66d932b1 F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479 F src/sqlite3ext.h 0efd4723bad9124ea1f581d9f1ea0254ac1c6f3e5fb29e4f3dcf36c72485a456 -F src/sqliteInt.h 2637dcfb389e48068388146940e541da7c90cb799d42effe9f4f3215fa73618c +F src/sqliteInt.h b793a8b93acafdc0e9f0865f78f3ad4041b91565ee7f114b339136ff7059ecae F src/sqliteLimit.h 7617f2ee673dab382046beba4552283f442cf1a181bb169ac38eb908135dd8da F src/status.c 7565d63a79aa2f326339a24a0461a60096d0bd2bce711fefb50b5c89335f3592 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 @@ -809,7 +809,7 @@ F src/upsert.c dd9f0fcccbfb4f20e1026a21a7254ba3f2c08e9cfa92affaff5b5ec3b00ea549 F src/utf.c 7267c3fb9e2467020507601af3354c2446c61f444387e094c779dccd5ca62165 F src/util.c fcab5d997364c657e973e2bd3b9d2181aeb0926be0c028f20dfd4445894af3b4 F src/vacuum.c d3d35d8ae893d419ade5fa196d761a83bddcbb62137a1a157ae751ef38b26e82 -F src/vdbe.c 30a41b3b7452eba63ad6451d74b8363096b82eecb27c4c9ab1cb9c2aa6cf4ffb +F src/vdbe.c 5ddbf3be0d2a32ee32da6beb17eba46de0d46b4010e8c3aa231e7a7fbf8baa1c F src/vdbe.h 70e862ac8a11b590f8c1eaac17a0078429d42bc4ea3f757a9af0f451dd966a71 F src/vdbeInt.h c31ba4dc8d280c2b1dc89c6fcee68f2555e3813ab34279552c20b964c0e338b1 F src/vdbeapi.c 6ad0c841b6cb87de068f71787f385149d794e8830176bf72d09a36b9f655ac5b @@ -824,10 +824,10 @@ F src/vxworks.h 9d18819c5235b49c2340a8a4d48195ec5d5afb637b152406de95a9436beeaeab F src/wal.c abfd99239725a258af4f733681b24dd7a9ee298babe389a36d29c197e2443ebf F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452 F src/walker.c d5006d6b005e4ea7302ad390957a8d41ed83faa177e412f89bc5600a7462a014 -F src/where.c 18943748b107b94f35c9170a68b583d0fdea3a2107ce5300f502ae9b954fab31 -F src/whereInt.h 8d94cb116c9e06205c3d5ac87af065fc044f8cf08bfdccd94b6ea1c1308e65da -F src/wherecode.c bc39ccbe3648f01157038b16cc55bdbff128590972b7185521b5526dc2815765 -F src/whereexpr.c b48dd990a15d36173e12acbcf961b81b2ea9917adeda01b2fdb9821e2cea08f8 +F src/where.c 2f5b4091f37bfac7658ea3d52b2c192d8fb2ec062f232815e0eb5152a46267db +F src/whereInt.h f039ad303bc2913de673e431821ef8db3b619d249e6e5548d90072a684e72285 +F src/wherecode.c dd500ffc8682ec57d3ac7edee3699b675338c4e885c6d1fdb86c791103ebe1dd +F src/whereexpr.c 40264a22a796358bd56440daa0355a6513651115fd79bb39ef9cd934a184fdeb F src/window.c 0d7dacdf2e84c6ee8ff498d5cc881dd245fcb2f14f6c5976e97e112ce96e90dc F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/affinity2.test 4d7a34d328e58ca2a2d78fd76c27614a41ca7ddf4312ded9c68c04f430b3b47d @@ -891,7 +891,7 @@ F test/auth2.test fb34df35ceca8d24e01219e993a3c1d9cb646e83b434627e158343bda1f6e0 F test/auth3.test 76d20a7fa136d63bcfcf8bcb65c0b1455ed71078d81f22bcd0550d3eb18594ab F test/autoanalyze1.test b9cc3f32a990fa56669b668d237c6d53e983554ae80c0604992e18869a0b2dec F test/autoinc.test 9df9930966dbe92c55ef37a4d89112cfd537be0d0596d397177c12db9e581be0 -F test/autoindex1.test 2523a76f30734742c3f4d948d0cbf3b6627f775e7833814f425a2e289ba58b22 +F test/autoindex1.test adb42c4967aba3b7f14f60a70d0a0c83b02d3ac540c6919dd2e2617fafbeace9 F test/autoindex2.test 12ef578928102baaa0dc23ad397601a2f4ecb0df F test/autoindex3.test ca502c8050166ac6107a7b4fe4e951f4d3270a23a958af02b14f1b962b83c4b6 F test/autoindex4.test 3c2105e9172920e26f950ba3c5823e4972190e022c1e6f260ba476b0af24c593 @@ -939,7 +939,7 @@ F test/bind2.test 918bc35135f4141809ead7585909cde57d44db90a7a62aef540127148f91aa F test/bindxfer.test efecd12c580c14df5f4ad3b3e83c667744a4f7e0 F test/bitvec.test 75894a880520164d73b1305c1c3f96882615e142 F test/blob.test e7ac6c7d3a985cc4678c64f325292529a69ae252 -F test/bloom1.test 3b6277a647ac503b5d5df331037b0c01c40e88cc9537b94eaf2d8aa334ed4c8f +F test/bloom1.test dd9847746e1a52db2f19bc5c8cb751990b2eb04692aee6e8c9972b84cd4069bf F test/boundary1.tcl 6421b2d920d8b09539503a8673339d32f7609eb1 F test/boundary1.test 66d7f4706ccdb42d58eafdb081de07b0eb42d77b F test/boundary2.tcl e34ef4e930cf1083150d4d2c603e146bd3b76bcb @@ -1702,7 +1702,7 @@ F test/stmtvtab1.test 6873dfb24f8e79cbb5b799b95c2e4349060eb7a3b811982749a84b3594 F test/strict1.test a7f9091603fe71cdc62baab0766684cba12a97ec69bfbb70be965532669cd77a F test/strict2.test b22c7a98b5000aef937f1990776497f0e979b1a23bc4f63e2d53b00e59b20070 F test/subjournal.test 8d4e2572c0ee9a15549f0d8e40863161295107e52f07a3e8012a2e1fdd093c49 -F test/subquery.test 23087f9b1c15ab9cc5231d04946bdebc51db527c95eb9d7434a2222127e17a84 +F test/subquery.test 0a8fc4fc4eb04b9ee40b17f2cc5416aacfbf756b583fa8880b801e395d5abb36 F test/subquery2.test ab96ff3fa9c4e3dce0d699f74e61c50250ed4335bc8f400e127707d552a8999e F test/subselect.test 0966aa8e720224dbd6a5e769a3ec2a723e332303 F test/substr.test a673e3763e247e9b5e497a6cacbaf3da2bd8ec8921c0677145c109f2e633f36b @@ -2217,8 +2217,11 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh a554d13f6e5cf3760f041b87939e3d616ec6961859c3245e8ef701d1eafc2ca2 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P f8c408f66257881937ed18b77e274f71dba2d97dd44546372fa0b0a9629efbd2 -R bad555b624f4fd2230e93ef522552de4 +P 675ed9a486fecc734a6aad2e80fd800183c33f72dce1435a193f0e4cf4ede944 +R 00ac7f20a2b69e84c5ddcc65062ebf36 +T *branch * bloom-filter-on-text +T *sym-bloom-filter-on-text * +T -sym-trunk * U drh -Z 924a5276b6b3c8953d98d053fbac0712 +Z 541ba4b4a08222b7d4ea7f9be1e7e44a # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.tags b/manifest.tags index bec971799f..6cbfcc2e69 100644 --- a/manifest.tags +++ b/manifest.tags @@ -1,2 +1,2 @@ -branch trunk -tag trunk +branch bloom-filter-on-text +tag bloom-filter-on-text diff --git a/manifest.uuid b/manifest.uuid index 6a72c5b573..4cf658e5e9 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -675ed9a486fecc734a6aad2e80fd800183c33f72dce1435a193f0e4cf4ede944 +2577edc796505a0a6dabccbcc1bb6a828457092caa4d074561da5e58a6f065a2 diff --git a/src/build.c b/src/build.c index 7c5c095af5..6801afc14d 100644 --- a/src/build.c +++ b/src/build.c @@ -2235,6 +2235,23 @@ static int resizeIndexObject(Parse *pParse, Index *pIdx, int N){ return SQLITE_OK; } +/* +** Return true if the index pIdx can support a Bloom filter on its +** first N columns. Specifically, return true if all of the first N +** columns have the BINARY collating sequence or no collating sequence +** at all, and return false if there are any non-BINARY collating +** seqeuences on any of the first N columns. tag-202607231411 +*/ +int sqlite3IndexBloomable(const Index *pIdx, int N){ + int i; + assert( pIdx!=0 ); + assert( N <= pIdx->nColumn ); + for(i=0; iazColl[i],"BINARY")!=0 ) return 0; + } + return 1; +} + /* ** Estimate the total row width for a table. */ diff --git a/src/expr.c b/src/expr.c index c9402081c4..790b761163 100644 --- a/src/expr.c +++ b/src/expr.c @@ -3693,6 +3693,8 @@ void sqlite3CodeRhsOfIN( } #endif pKeyInfo = sqlite3KeyInfoAlloc(pParse->db, nVal, 1); + assert( pKeyInfo!=0 || pParse->nErr ); + if( pKeyInfo==0 ) return; if( ExprUseXSelect(pExpr) ){ /* Case 1: expr IN (SELECT ...) @@ -3717,6 +3719,19 @@ void sqlite3CodeRhsOfIN( sqlite3SelectDestInit(&dest, SRT_Set, iTab); dest.zAffSdst = exprINAffinity(pParse, pExpr); pSelect->iLimit = 0; + assert( pEList!=0 ); + assert( pEList->nExpr>0 ); + assert( sqlite3KeyInfoIsWriteable(pKeyInfo) ); + for(i=0; iaColl[i] = pColl = sqlite3BinaryCompareCollSeq( + pParse, p, pEList->a[i].pExpr + ); + if( !sqlite3IsBinary(pColl) ){ + allowBloom = 0; /* tag-202607231411 */ + } + } if( addrOnce && allowBloom && OptimizationEnabled(pParse->db, SQLITE_BloomFilter) @@ -3727,7 +3742,6 @@ void sqlite3CodeRhsOfIN( dest.iSDParm2 = regBloom; } testcase( pSelect->selFlags & SF_Distinct ); - testcase( pKeyInfo==0 ); /* Caused by OOM in sqlite3KeyInfoAlloc() */ pCopy = sqlite3SelectDup(pParse->db, pSelect, 0); rc = pParse->db->mallocFailed ? 1 :sqlite3Select(pParse, pCopy, &dest); sqlite3SelectDelete(pParse->db, pCopy); @@ -3745,16 +3759,6 @@ void sqlite3CodeRhsOfIN( sqlite3KeyInfoUnref(pKeyInfo); return; } - assert( pKeyInfo!=0 ); /* OOM will cause exit after sqlite3Select() */ - assert( pEList!=0 ); - assert( pEList->nExpr>0 ); - assert( sqlite3KeyInfoIsWriteable(pKeyInfo) ); - for(i=0; iaColl[i] = sqlite3BinaryCompareCollSeq( - pParse, p, pEList->a[i].pExpr - ); - } } }else if( ALWAYS(pExpr->x.pList!=0) ){ /* Case 2: expr IN (exprlist) diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 40c9ea3608..eeb0d7204d 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -5144,6 +5144,7 @@ void sqlite3IdListDelete(sqlite3*, IdList*); void sqlite3ClearOnOrUsing(sqlite3*, OnOrUsing*); void sqlite3SrcListDelete(sqlite3*, SrcList*); Index *sqlite3AllocateIndexObject(sqlite3*,int,int,char**); +int sqlite3IndexBloomable(const Index*,int); void sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*, Expr*, int, int, u8); void sqlite3DropIndex(Parse*, SrcList*, int); diff --git a/src/vdbe.c b/src/vdbe.c index e6a01e7276..252714216a 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -688,6 +688,10 @@ static Mem *out2Prerelease(Vdbe *p, VdbeOp *pOp){ /* ** Compute a bloom filter hash using pOp->p4.i registers from aMem[] beginning ** with pOp->p3. Return the hash. +** +** IMPORTANT RESTRICTION (tag-202607231411): This hash is only valid if the +** collating sequence for TEXT is BINARY. Hence, Bloom filters that use this +** hash will not work for look-ups that use any other collating sequence. */ static u64 filterHash(const Mem *aMem, const Op *pOp){ int i, mx; @@ -701,10 +705,18 @@ static u64 filterHash(const Mem *aMem, const Op *pOp){ }else if( p->flags & MEM_Real ){ h += sqlite3VdbeIntValue(p); }else if( p->flags & (MEM_Str|MEM_Blob) ){ - /* All strings have the same hash and all blobs have the same hash, - ** though, at least, those hashes are different from each other and - ** from NULL. */ - h += 4093 + (p->flags & (MEM_Str|MEM_Blob)); + u64 x; + h += p->n; + if( p->n >= sizeof(x) ){ + memcpy(&x, p->z, sizeof(x)); + h += x; + memcpy(&x, p->z + p->n - sizeof(x), sizeof(x)); + h += x; + }else{ + x = 0; + memcpy(&x, p->z, p->n); + h += x; + } } } return h; diff --git a/src/where.c b/src/where.c index d1c63ff8c0..9a8c6b6d6d 100644 --- a/src/where.c +++ b/src/where.c @@ -1007,7 +1007,7 @@ static SQLITE_NOINLINE void constructAutomaticIndex( Bitmask idxCols; /* Bitmap of columns used for indexing */ Bitmask extraCols; /* Bitmap of additional columns */ u8 sentWarning = 0; /* True if a warning has been issued */ - u8 useBloomFilter = 0; /* True to also add a Bloom filter */ + u8 useBloomFilter = 1; /* True to also add a Bloom filter */ Expr *pPartial = 0; /* Partial Index Expression */ int iContinue = 0; /* Jump here to skip excluded rows */ SrcList *pTabList; /* The complete FROM clause */ @@ -1134,18 +1134,13 @@ static SQLITE_NOINLINE void constructAutomaticIndex( pIdx->aiColumn[n] = pTerm->u.x.leftColumn; pColl = sqlite3ExprCompareCollSeq(pParse, pX); assert( pColl!=0 || pParse->nErr>0 ); /* TH3 collate01.800 */ + if( !sqlite3IsBinary(pColl) ){ + /* Disallow the use of a Bloom filter if any non-BINARY collating + ** sequence is involved. tag-202607231411 */ + useBloomFilter = 0; + } pIdx->azColl[n] = pColl ? pColl->zName : sqlite3StrBINARY; n++; - if( ALWAYS(pX->pLeft!=0) - && sqlite3ExprAffinity(pX->pLeft)!=SQLITE_AFF_TEXT - ){ - /* TUNING: only use a Bloom filter on an automatic index - ** if one or more key columns has the ability to hold numeric - ** values, since strings all have the same hash in the Bloom - ** filter implementation and hence a Bloom filter on a text column - ** is not usually helpful. */ - useBloomFilter = 1; - } } } } @@ -1215,6 +1210,7 @@ static SQLITE_NOINLINE void constructAutomaticIndex( pParse, pIdx, pLevel->iTabCur, regRecord, 0, 0, 0, 0 ); if( pLevel->regFilter ){ + assert( sqlite3WhereLoopBloomable(pLoop) ); sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pLevel->regFilter, 0, regBase, pLoop->u.btree.nEq); } @@ -1330,6 +1326,7 @@ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter( }else if( sz>10000000 ){ sz = 10000000; } + assert( sqlite3WhereLoopBloomable(pLoop) ); sqlite3VdbeAddOp2(v, OP_Blob, (int)sz, pLevel->regFilter); addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, iCur); VdbeCoverage(v); @@ -1352,6 +1349,7 @@ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter( int n = pLoop->u.btree.nEq; int r1 = sqlite3GetTempRange(pParse, n); int jj; + assert( pIdx!=0 ); for(jj=0; jjpTable==pItem->pSTab ); sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iCur, jj, r1+jj); @@ -6638,19 +6636,17 @@ static SQLITE_NOINLINE void whereCheckIfBloomFilterIsUseful( pTab->tabFlags |= TF_MaybeReanalyze; if( i>=1 && (pLoop->wsFlags & reqFlags)==reqFlags - /* vvvvvv--- Always the case if WHERE_COLUMN_EQ is defined */ - && ALWAYS((pLoop->wsFlags & (WHERE_IPK|WHERE_INDEXED))!=0) + && sqlite3WhereLoopBloomable(pLoop) + && nSearch > pTab->nRowLogEst ){ - if( nSearch > pTab->nRowLogEst ){ - testcase( pItem->fg.jointype & JT_LEFT ); - pLoop->wsFlags |= WHERE_BLOOMFILTER; - pLoop->wsFlags &= ~WHERE_IDX_ONLY; - WHERETRACE(0xffffffff, ( - "-> use Bloom-filter on loop %c because there are ~%.1e " - "lookups into %s which has only ~%.1e rows\n", - pLoop->cId, (double)sqlite3LogEstToInt(nSearch), pTab->zName, - (double)sqlite3LogEstToInt(pTab->nRowLogEst))); - } + testcase( pItem->fg.jointype & JT_LEFT ); + pLoop->wsFlags |= WHERE_BLOOMFILTER; + pLoop->wsFlags &= ~WHERE_IDX_ONLY; + WHERETRACE(0xffffffff, ( + "-> use Bloom-filter on loop %c because there are ~%.1e " + "lookups into %s which has only ~%.1e rows\n", + pLoop->cId, (double)sqlite3LogEstToInt(nSearch), pTab->zName, + (double)sqlite3LogEstToInt(pTab->nRowLogEst))); } nSearch += pLoop->nOut; } @@ -7400,15 +7396,15 @@ WhereInfo *sqlite3WhereBegin( && (pLevel->pRJ = sqlite3WhereMalloc(pWInfo, sizeof(WhereRightJoin)))!=0 ){ WhereRightJoin *pRJ = pLevel->pRJ; + int bBloomable = 0; pRJ->iMatch = pParse->nTab++; - pRJ->regBloom = ++pParse->nMem; - sqlite3VdbeAddOp2(v, OP_Blob, 65536, pRJ->regBloom); pRJ->regReturn = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Null, 0, pRJ->regReturn); assert( pTab==pTabItem->pSTab ); if( HasRowid(pTab) ){ KeyInfo *pInfo; sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRJ->iMatch, 1); + bBloomable = 1; pInfo = sqlite3KeyInfoAlloc(pParse->db, 1, 0); if( pInfo ){ pInfo->aColl[0] = 0; @@ -7419,6 +7415,13 @@ WhereInfo *sqlite3WhereBegin( Index *pPk = sqlite3PrimaryKeyIndex(pTab); sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRJ->iMatch, pPk->nKeyCol); sqlite3VdbeSetP4KeyInfo(pParse, pPk); + bBloomable = sqlite3IndexBloomable(pPk,pPk->nKeyCol); + } + if( bBloomable ){ + pRJ->regBloom = ++pParse->nMem; + sqlite3VdbeAddOp2(v, OP_Blob, 65536, pRJ->regBloom); + }else{ + pRJ->regBloom = 0; } pLoop->wsFlags &= ~WHERE_IDX_ONLY; /* The nature of RIGHT JOIN processing is such that it messes up diff --git a/src/whereInt.h b/src/whereInt.h index 09e02c8c73..2199a8438a 100644 --- a/src/whereInt.h +++ b/src/whereInt.h @@ -594,10 +594,7 @@ Bitmask sqlite3WhereExprUsageNN(WhereMaskSet*, Expr*); Bitmask sqlite3WhereExprListUsage(WhereMaskSet*, ExprList*); void sqlite3WhereExprAnalyze(SrcList*, WhereClause*); void sqlite3WhereTabFuncArgs(Parse*, SrcItem*, WhereClause*); - - - - +int sqlite3WhereLoopBloomable(const WhereLoop*); /* ** Bitmasks for the operators on WhereTerm objects. These are all diff --git a/src/wherecode.c b/src/wherecode.c index 8a1a593c70..294313d1e8 100644 --- a/src/wherecode.c +++ b/src/wherecode.c @@ -1416,6 +1416,7 @@ static SQLITE_NOINLINE void filterPullDown( regRowid = codeEqualityTerm(pParse, pTerm, pLevel, 0, 0, regRowid); sqlite3VdbeAddOp2(pParse->pVdbe, OP_MustBeInt, regRowid, addrNxt); VdbeCoverage(pParse->pVdbe); + assert( sqlite3WhereLoopBloomable(pLoop) ); sqlite3VdbeAddOp4Int(pParse->pVdbe, OP_Filter, pLevel->regFilter, addrNxt, regRowid, 1); VdbeCoverage(pParse->pVdbe); @@ -1429,6 +1430,7 @@ static SQLITE_NOINLINE void filterPullDown( r1 = codeAllEqualityTerms(pParse,pLevel,0,0,&zStartAff); codeApplyAffinity(pParse, r1, nEq, zStartAff); sqlite3DbFree(pParse->db, zStartAff); + assert( sqlite3WhereLoopBloomable(pLoop) ); sqlite3VdbeAddOp4Int(pParse->pVdbe, OP_Filter, pLevel->regFilter, addrNxt, r1, nEq); VdbeCoverage(pParse->pVdbe); @@ -2032,6 +2034,7 @@ Bitmask sqlite3WhereCodeOneLoopStart( VdbeComment((v, "NULL-scan pass ctr")); } if( pLevel->regFilter ){ + assert( sqlite3WhereLoopBloomable(pLoop) ); sqlite3VdbeAddOp4Int(v, OP_Filter, pLevel->regFilter, addrNxt, regBase, nEq); VdbeCoverage(v); @@ -2769,8 +2772,10 @@ Bitmask sqlite3WhereCodeOneLoopStart( VdbeComment((v, "match against %s", pTab->zName)); sqlite3VdbeAddOp3(v, OP_MakeRecord, r+1, nPk, r); sqlite3VdbeAddOp4Int(v, OP_IdxInsert, pRJ->iMatch, r, r+1, nPk); - sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pRJ->regBloom, 0, r+1, nPk); - sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); + if( pRJ->regBloom ){ + sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pRJ->regBloom, 0, r+1, nPk); + sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); + } sqlite3VdbeJumpHere(v, jmp1); sqlite3ReleaseTempRange(pParse, r, nPk+1); } @@ -2922,7 +2927,7 @@ SQLITE_NOINLINE void sqlite3WhereRightJoinLoop( int iCur = pLevel->iTabCur; int r = ++pParse->nMem; int nPk; - int jmp; + int jmp = 0; int addrCont = sqlite3WhereContinueLabel(pSubWInfo); Table *pTab = pTabItem->pSTab; if( HasRowid(pTab) ){ @@ -2938,11 +2943,13 @@ SQLITE_NOINLINE void sqlite3WhereRightJoinLoop( sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, iCol,r+iPk); } } - jmp = sqlite3VdbeAddOp4Int(v, OP_Filter, pRJ->regBloom, 0, r, nPk); - VdbeCoverage(v); + if( pRJ->regBloom ){ + jmp = sqlite3VdbeAddOp4Int(v, OP_Filter, pRJ->regBloom, 0, r, nPk); + VdbeCoverage(v); + } sqlite3VdbeAddOp4Int(v, OP_Found, pRJ->iMatch, addrCont, r, nPk); VdbeCoverage(v); - sqlite3VdbeJumpHere(v, jmp); + if( jmp ) sqlite3VdbeJumpHere(v, jmp); sqlite3VdbeAddOp2(v, OP_Gosub, pRJ->regReturn, pRJ->addrSubrtn); sqlite3WhereEnd(pSubWInfo); } diff --git a/src/whereexpr.c b/src/whereexpr.c index c51667083c..4c77e3b753 100644 --- a/src/whereexpr.c +++ b/src/whereexpr.c @@ -1978,3 +1978,15 @@ void sqlite3WhereTabFuncArgs( whereClauseInsert(pWC, pTerm, TERM_DYNAMIC); } } + +/* +** Return true if the WhereLoop pLoop can be use a Bloom filter. +** tag-202607231411 +*/ +int sqlite3WhereLoopBloomable(const WhereLoop *pLoop){ + if( pLoop->wsFlags & WHERE_IPK ) return 1; + if( (pLoop->wsFlags & WHERE_INDEXED)!=0 ){ + return sqlite3IndexBloomable(pLoop->u.btree.pIndex, pLoop->u.btree.nEq); + } + return 0; +} diff --git a/test/autoindex1.test b/test/autoindex1.test index be41d702ca..4efa556ed8 100644 --- a/test/autoindex1.test +++ b/test/autoindex1.test @@ -284,6 +284,7 @@ do_eqp_test autoindex1-600a { | `--CORRELATED SCALAR SUBQUERY xxxxxx | `--SEARCH later USING COVERING INDEX sqlite_autoindex_flock_owner_1 (flock_no=? AND owner_change_date>? AND owner_change_date