aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2017-12-08 19:37:04 +0000
committerdrh <drh@noemail.net>2017-12-08 19:37:04 +0000
commit7e8515d8bec405f8d17a91a94c9d0d690b0a9ff5 (patch)
tree6fb4068009e6287fcf4b12885188b67d301712ab /src
parent21540ae47984b44a70dbc653e2edca27c3ee4735 (diff)
downloadsqlite-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.c12
-rw-r--r--src/callback.c1
-rw-r--r--src/prepare.c18
-rw-r--r--src/sqlite.h.in2
-rw-r--r--src/sqliteInt.h3
-rw-r--r--src/where.c10
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