From 7e8515d8bec405f8d17a91a94c9d0d690b0a9ff5 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 8 Dec 2017 19:37:04 +0000 Subject: [PATCH] The query planner tries to avoids using indexes that use unknown collating functions. FossilOrigin-Name: 02013fc120bf71a8be3550c696a588af8c92f2209f8e5db530624878ddc8aa7e --- manifest | 24 ++++++++++++------------ manifest.uuid | 2 +- src/build.c | 12 ++++++++++++ src/callback.c | 1 + src/prepare.c | 18 ++++++++++-------- src/sqlite.h.in | 2 ++ src/sqliteInt.h | 3 ++- src/where.c | 10 +--------- 8 files changed, 41 insertions(+), 31 deletions(-) diff --git a/manifest b/manifest index 7872cf0b11..d824fdaf09 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\scompile\stime\sswitch\sSQLITE_ENABLE_ICU_COLLATIONS.\sFor\senabling\sICU\ncollations\swithout\salso\senabling\sthe\stokenizer,\sthe\sLIKE\soperator,\sthe\nREGEXP\soperator,\sor\sthe\sunicode\saware\supper()/lower()\sscalar\sfunctions. -D 2017-12-08T16:23:38.347 +C The\squery\splanner\stries\sto\savoids\susing\sindexes\sthat\suse\sunknown\scollating\nfunctions. +D 2017-12-08T19:37:04.216 F Makefile.in 6a879cbf01e37f9eac131414955f71774b566502d9a57ded1b8585b507503cb8 F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434 F Makefile.msc e5d7606238f55816da99f719969598df5b091aa2e9a6935c9412fcae8f53fc44 @@ -416,8 +416,8 @@ F src/btmutex.c 0e9ce2d56159b89b9bc8e197e023ee11e39ff8ca F src/btree.c b83a6b03f160528020bb965f0c3a40af5286cd4923c3870fd218177f03a120a7 F src/btree.h 32ef5d3f25dc70ef1ee9cecf84a023c21378f06a57cd701d2e866e141b150f09 F src/btreeInt.h 55b702efce17e5d1941865464227d3802cfc9c7c832fac81d4c94dced47a71fc -F src/build.c 514db9d494ed29155e552f2ec2fa7c55c0241f847c683156b7c017f4b0bad9fa -F src/callback.c 28a8ede982fde4129b828350f78f2c01fe7d12c74d1a0a05d7108ab36f308688 +F src/build.c 87b68e3b45559ec404b12f095f0ba5f06f91a6dd2d21bd8443e41d8ac2e67196 +F src/callback.c fe677cb5f5abb02f7a772a62a98c2f516426081df68856e8f2d5f950929b966a F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/ctime.c ff1be3eed7bdd75aaca61ca8dc848f7c9f850ef2fb9cb56f2734e922a098f9c0 F src/date.c ebe1dc7c8a347117bb02570f1a931c62dd78f4a2b1b516f4837d45b7d6426957 @@ -466,17 +466,17 @@ F src/pcache.h 072f94d29281cffd99e46c1539849f248c4b56ae7684c1f36626797fee375170 F src/pcache1.c 716975564c15eb6679e97f734cec1bfd6c16ac3d4010f05f1f8e509fc7d19880 F src/pragma.c d04725ac25387d9638919e197fb009f378e13af7bf899516979e54b3164e3602 F src/pragma.h bb83728944b42f6d409c77f5838a8edbdb0fe83046c5496ffc9602b40340a324 -F src/prepare.c 7cf451f903ad92a14e22de415a13e7a7d30f1bd23b3d21eeb0dc7264723244c5 +F src/prepare.c 259f4e7960c47082c9653f3d5f0c294abd68bb9c3aab86de7630700cba1c20fb F src/printf.c 9506b4b96e59c0467047155f09015750cb2878aeda3d39e5610c1192ddc3c41c F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384 F src/resolve.c bbee7e31d369a18a2f4836644769882e9c5d40ef4a3af911db06410b65cb3730 F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac F src/select.c 17e220191860a64a18c084141e1a8b7309e166a6f2d42c02021af27ea080d157 F src/shell.c.in 6ffed0c589f5aff180789a8c8abf5b2d3e2eea7470c86b30e797887cb0c9d0e5 -F src/sqlite.h.in 8fd97993d48b50b9bade38c52f12d175942c9497c960905610c7b03a3e4b5818 +F src/sqlite.h.in 4622dbb3bb94119795fd926c2a10cacfb86d59900fa9b037e8678acd9830d147 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h c02d628cca67f3889c689d82d25c3eb45e2c155db08e4c6089b5840d64687d34 -F src/sqliteInt.h 4c910d9c0d88a90e8639a4f83ef05f701ccfe731cf593e757444074f01df4964 +F src/sqliteInt.h 55b8e7da85947eb61b13d4d2523ccdda7800a13e987c3fc4ca73d8518bbf02fa F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b F src/status.c 9737ed017279a9e0c5da748701c3c7bf1e8ae0dae459aad20dd64fcff97a7e35 F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34 @@ -554,7 +554,7 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c 5a3f464edd64596f601683ed321d12e6fd93c5fb9afdfb3653d6ffd0fee9c48f F src/wal.h 8de5d2d3de0956d6f6cb48c83a4012d5f227b8fe940f3a349a4b7e85ebcb492a F src/walker.c da987a20d40145c0a03c07d8fefcb2ed363becc7680d0500d9c79915591f5b1f -F src/where.c ea27cbc78ccc8c1f054adc2ebced57a883620b77605699ccf6e865ea871bf17b +F src/where.c ee9dd4a438a07cd364c8449e834db4c4d6163a2576a69e937d7a4c37685612a2 F src/whereInt.h 82c04c5075308abbac59180c8bad5ecb45b07453981f60a53f3c7dee21e1e971 F src/wherecode.c 611fcabd05592ed2febd7d182f9621425b0466c5232d70e0981c842d429356d5 F src/whereexpr.c 427ea8e96ec24f2a7814c67b8024ad664a9c7656264c4566c34743cb23186e46 @@ -1679,7 +1679,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 e526d0c40b971d970367a52a57d3920cb64e6a98920114bfac46ba009f0b1eb5 -R e5fd041d6b7727f71627ca57ebea4f83 -U dan -Z b6d953d578629eaa29d8e731d0cdeaa8 +P a079f914522d7bc4b3d27d70114eb09adedfac936a64883e6ed8d382c428dd0e +R 4ebf4200d512dd6155db0a93b95e863f +U drh +Z 0f53fc2b441082d70fbf7ea067c767d4 diff --git a/manifest.uuid b/manifest.uuid index 8ccd338cb9..16a4e71f56 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a079f914522d7bc4b3d27d70114eb09adedfac936a64883e6ed8d382c428dd0e \ No newline at end of file +02013fc120bf71a8be3550c696a588af8c92f2209f8e5db530624878ddc8aa7e \ No newline at end of file diff --git a/src/build.c b/src/build.c index fc4dbcdba8..9582f136c8 100644 --- a/src/build.c +++ b/src/build.c @@ -4364,6 +4364,18 @@ KeyInfo *sqlite3KeyInfoOfIndex(Parse *pParse, Index *pIdx){ pKey->aSortOrder[i] = pIdx->aSortOrder[i]; } if( pParse->nErr ){ + assert( pParse->rc==SQLITE_ERROR_MISSING_COLLSEQ ); + if( pIdx->bNoQuery==0 ){ + /* Deactivate the index because it contains an unknown collating + ** sequence. The only way to reactive the index is to reload the + ** schema. Adding the missing collating sequence later does not + ** reactive the index. The application had the chance to register + ** the missing index using the collation-needed callback. For + ** simplicity, SQLite will not give the application a second chance. + */ + pIdx->bNoQuery = 1; + pParse->rc = SQLITE_ERROR_RETRY; + } sqlite3KeyInfoUnref(pKey); pKey = 0; } diff --git a/src/callback.c b/src/callback.c index e08924b2c2..0396df7a02 100644 --- a/src/callback.c +++ b/src/callback.c @@ -105,6 +105,7 @@ CollSeq *sqlite3GetCollSeq( assert( !p || p->xCmp ); if( p==0 ){ sqlite3ErrorMsg(pParse, "no such collation sequence: %s", zName); + pParse->rc = SQLITE_ERROR_MISSING_COLLSEQ; } return p; } diff --git a/src/prepare.c b/src/prepare.c index 9141cb8a78..65a4afcbbd 100644 --- a/src/prepare.c +++ b/src/prepare.c @@ -655,8 +655,6 @@ static int sqlite3Prepare( end_prepare: sqlite3ParserReset(&sParse); - rc = sqlite3ApiExit(db, rc); - assert( (rc&db->errMask)==rc ); return rc; } static int sqlite3LockAndPrepare( @@ -669,6 +667,7 @@ static int sqlite3LockAndPrepare( const char **pzTail /* OUT: End of parsed string */ ){ int rc; + int cnt = 0; #ifdef SQLITE_ENABLE_API_ARMOR if( ppStmt==0 ) return SQLITE_MISUSE_BKPT; @@ -679,15 +678,18 @@ static int sqlite3LockAndPrepare( } sqlite3_mutex_enter(db->mutex); sqlite3BtreeEnterAll(db); - rc = sqlite3Prepare(db, zSql, nBytes, prepFlags, pOld, ppStmt, pzTail); - if( rc==SQLITE_SCHEMA ){ - sqlite3ResetOneSchema(db, -1); - sqlite3_finalize(*ppStmt); + do{ + /* Make multiple attempts to compile the SQL, until it either succeeds + ** or encounters a permanent error. A schema problem after one schema + ** reset is considered a permanent error. */ rc = sqlite3Prepare(db, zSql, nBytes, prepFlags, pOld, ppStmt, pzTail); - } + assert( rc==SQLITE_OK || *ppStmt==0 ); + }while( rc==SQLITE_ERROR_RETRY + || (rc==SQLITE_SCHEMA && (sqlite3ResetOneSchema(db,-1), cnt++)==0) ); sqlite3BtreeLeaveAll(db); + rc = sqlite3ApiExit(db, rc); + assert( (rc&db->errMask)==rc ); sqlite3_mutex_leave(db->mutex); - assert( rc==SQLITE_OK || *ppStmt==0 ); return rc; } diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 4434064421..29b0458d76 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -470,6 +470,8 @@ int sqlite3_exec( ** the most recent error can be obtained using ** [sqlite3_extended_errcode()]. */ +#define SQLITE_ERROR_MISSING_COLLSEQ (SQLITE_ERROR | (1<<8)) +#define SQLITE_ERROR_RETRY (SQLITE_ERROR | (2<<8)) #define SQLITE_IOERR_READ (SQLITE_IOERR | (1<<8)) #define SQLITE_IOERR_SHORT_READ (SQLITE_IOERR | (2<<8)) #define SQLITE_IOERR_WRITE (SQLITE_IOERR | (3<<8)) diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 27b896d67c..47d9fc6953 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -2172,6 +2172,7 @@ struct Index { unsigned isCovering:1; /* True if this is a covering index */ unsigned noSkipScan:1; /* Do not try to use skip-scan if true */ unsigned hasStat1:1; /* aiRowLogEst values come from sqlite_stat1 */ + unsigned bNoQuery:1; /* Do not use this index to optimize queries */ #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 int nSample; /* Number of elements in aSample[] */ int nSampleCol; /* Size of IndexSample.anEq[] and so on */ @@ -2984,7 +2985,7 @@ struct Parse { int nMem; /* Number of memory cells used so far */ int nOpAlloc; /* Number of slots allocated for Vdbe.aOp[] */ int szOpAlloc; /* Bytes of memory space allocated for Vdbe.aOp[] */ - int iSelfTab; /* Table for associated with an index on expr, or negative + int iSelfTab; /* Table associated with an index on expr, or negative ** of the base register during check-constraint eval */ int iCacheLevel; /* ColCache valid when aColCache[].iLevel<=iCacheLevel */ int iCacheCnt; /* Counter used to generate aColCache[].lru values */ diff --git a/src/where.c b/src/where.c index e11194bdd4..5b77b76625 100644 --- a/src/where.c +++ b/src/where.c @@ -2879,6 +2879,7 @@ static int whereLoopAddBtree( testcase( pNew->iTab!=pSrc->iCursor ); /* See ticket [98d973b8f5] */ continue; /* Partial index inappropriate for this query */ } + if( pProbe->bNoQuery ) continue; rSize = pProbe->aiRowLogEst[0]; pNew->u.btree.nEq = 0; pNew->u.btree.nBtm = 0; @@ -4870,16 +4871,7 @@ WhereInfo *sqlite3WhereBegin( assert( iIndexCur>=0 ); if( op ){ sqlite3VdbeAddOp3(v, op, iIndexCur, pIx->tnum, iDb); - - /* If the index is only being scanned - if there is no searching - - ** then no collating functions are required. Set db->init.busy in that - ** case, to prevent sqlite3VdbeSetP4KeyInfo() from raising needless - ** errors about the missing collating functions. */ - assert( db->init.busy==0 ); - db->init.busy = (pLoop->wsFlags & ~(WHERE_IDX_ONLY|WHERE_INDEXED))==0; sqlite3VdbeSetP4KeyInfo(pParse, pIx); - db->init.busy = 0; /* Restore db->init.busy */ - if( (pLoop->wsFlags & WHERE_CONSTRAINT)!=0 && (pLoop->wsFlags & (WHERE_COLUMN_RANGE|WHERE_SKIPSCAN))==0 && (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)==0