diff options
author | drh <drh@noemail.net> | 2017-12-08 19:37:04 +0000 |
---|---|---|
committer | drh <drh@noemail.net> | 2017-12-08 19:37:04 +0000 |
commit | 7e8515d8bec405f8d17a91a94c9d0d690b0a9ff5 (patch) | |
tree | 6fb4068009e6287fcf4b12885188b67d301712ab /src | |
parent | 21540ae47984b44a70dbc653e2edca27c3ee4735 (diff) | |
download | sqlite-7e8515d8bec405f8d17a91a94c9d0d690b0a9ff5.tar.gz sqlite-7e8515d8bec405f8d17a91a94c9d0d690b0a9ff5.zip |
The query planner tries to avoids using indexes that use unknown collating
functions.
FossilOrigin-Name: 02013fc120bf71a8be3550c696a588af8c92f2209f8e5db530624878ddc8aa7e
Diffstat (limited to 'src')
-rw-r--r-- | src/build.c | 12 | ||||
-rw-r--r-- | src/callback.c | 1 | ||||
-rw-r--r-- | src/prepare.c | 18 | ||||
-rw-r--r-- | src/sqlite.h.in | 2 | ||||
-rw-r--r-- | src/sqliteInt.h | 3 | ||||
-rw-r--r-- | src/where.c | 10 |
6 files changed, 28 insertions, 18 deletions
diff --git a/src/build.c b/src/build.c index fc4dbcdba..9582f136c 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 e08924b2c..0396df7a0 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 9141cb8a7..65a4afcbb 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 443406442..29b0458d7 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 27b896d67..47d9fc695 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 e11194bdd..5b77b7662 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 |