aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/build.c12
-rw-r--r--src/main.c5
-rw-r--r--src/pragma.c1
-rw-r--r--src/prepare.c2
-rw-r--r--src/sqlite.h.in27
-rw-r--r--src/sqliteInt.h4
-rw-r--r--src/tclsqlite.c2
-rw-r--r--src/trigger.c2
-rw-r--r--src/vdbe.c6
-rw-r--r--src/vdbeaux.c175
-rw-r--r--src/where.c41
11 files changed, 179 insertions, 98 deletions
diff --git a/src/build.c b/src/build.c
index e04406d85..47339e82b 100644
--- a/src/build.c
+++ b/src/build.c
@@ -479,7 +479,7 @@ void sqlite3UnlinkAndDeleteIndex(sqlite3 *db, int iDb, const char *zIdxName){
}
freeIndex(db, pIndex);
}
- db->flags |= SQLITE_InternChanges;
+ db->bInternChanges = 1;
}
/*
@@ -551,7 +551,7 @@ void sqlite3ResetAllSchemasOfConnection(sqlite3 *db){
sqlite3SchemaClear(pDb->pSchema);
}
}
- db->flags &= ~SQLITE_InternChanges;
+ db->bInternChanges = 0;
sqlite3VtabUnlockList(db);
sqlite3BtreeLeaveAll(db);
sqlite3CollapseDatabaseArray(db);
@@ -561,7 +561,7 @@ void sqlite3ResetAllSchemasOfConnection(sqlite3 *db){
** This routine is called when a commit occurs.
*/
void sqlite3CommitInternalChanges(sqlite3 *db){
- db->flags &= ~SQLITE_InternChanges;
+ db->bInternChanges = 0;
}
/*
@@ -665,7 +665,7 @@ void sqlite3UnlinkAndDeleteTable(sqlite3 *db, int iDb, const char *zTabName){
pDb = &db->aDb[iDb];
p = sqlite3HashInsert(&pDb->pSchema->tblHash, zTabName, 0);
sqlite3DeleteTable(db, p);
- db->flags |= SQLITE_InternChanges;
+ db->bInternChanges = 1;
}
/*
@@ -2051,7 +2051,7 @@ void sqlite3EndTable(
return;
}
pParse->pNewTable = 0;
- db->flags |= SQLITE_InternChanges;
+ db->bInternChanges = 1;
#ifndef SQLITE_OMIT_ALTERTABLE
if( !p->pSelect ){
@@ -3320,7 +3320,7 @@ void sqlite3CreateIndex(
sqlite3OomFault(db);
goto exit_create_index;
}
- db->flags |= SQLITE_InternChanges;
+ db->bInternChanges = 1;
if( pTblName!=0 ){
pIndex->tnum = db->init.newTnum;
}
diff --git a/src/main.c b/src/main.c
index 4ac5327e4..db508abc5 100644
--- a/src/main.c
+++ b/src/main.c
@@ -811,6 +811,7 @@ int sqlite3_db_config(sqlite3 *db, int op, ...){
{ SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, SQLITE_Fts3Tokenizer },
{ SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, SQLITE_LoadExtension },
{ SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE, SQLITE_NoCkptOnClose },
+ { SQLITE_DBCONFIG_FULL_EQP, SQLITE_FullEQP },
};
unsigned int i;
rc = SQLITE_ERROR; /* IMP: R-42790-23372 */
@@ -1252,7 +1253,7 @@ void sqlite3RollbackAll(sqlite3 *db, int tripCode){
** the database rollback and schema reset, which can cause false
** corruption reports in some cases. */
sqlite3BtreeEnterAll(db);
- schemaChange = (db->flags & SQLITE_InternChanges)!=0 && db->init.busy==0;
+ schemaChange = db->bInternChanges && db->init.busy==0;
for(i=0; i<db->nDb; i++){
Btree *p = db->aDb[i].pBt;
@@ -1266,7 +1267,7 @@ void sqlite3RollbackAll(sqlite3 *db, int tripCode){
sqlite3VtabRollback(db);
sqlite3EndBenignMalloc();
- if( (db->flags&SQLITE_InternChanges)!=0 && db->init.busy==0 ){
+ if( db->bInternChanges && db->init.busy==0 ){
sqlite3ExpirePreparedStatements(db);
sqlite3ResetAllSchemasOfConnection(db);
}
diff --git a/src/pragma.c b/src/pragma.c
index 945fd2d4a..fb7a40628 100644
--- a/src/pragma.c
+++ b/src/pragma.c
@@ -1076,6 +1076,7 @@ void sqlite3Pragma(
** type: Column declaration type.
** notnull: True if 'NOT NULL' is part of column declaration
** dflt_value: The default value for the column, if any.
+ ** pk: Non-zero for PK fields.
*/
case PragTyp_TABLE_INFO: if( zRight ){
Table *pTab;
diff --git a/src/prepare.c b/src/prepare.c
index 74127bc76..aa36cca16 100644
--- a/src/prepare.c
+++ b/src/prepare.c
@@ -354,7 +354,7 @@ error_out:
*/
int sqlite3Init(sqlite3 *db, char **pzErrMsg){
int i, rc;
- int commit_internal = !(db->flags&SQLITE_InternChanges);
+ int commit_internal = db->bInternChanges==0;
assert( sqlite3_mutex_held(db->mutex) );
assert( sqlite3BtreeHoldsMutex(db->aDb[0].pBt) );
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index 99d381d9d..6a5de5f5b 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -2007,6 +2007,16 @@ struct sqlite3_mem_methods {
** have been disabled - 0 if they are not disabled, 1 if they are.
** </dd>
**
+** <dt>SQLITE_DBCONFIG_FULL_EQP</dt>
+** <dd> By default, the output of EXPLAIN QUERY PLAN commands does not
+** include output for any operations performed by trigger programs. This
+** option is used to set or clear (the default) a flag that governs this
+** behavior. The first parameter passed to this operation is an integer -
+** non-zero to enable output for trigger programs, or zero to disable it.
+** The second parameter is a pointer to an integer into which is written
+** 0 or 1 to indicate whether output-for-triggers has been disabled - 0 if
+** it is not disabled, 1 if it is.
+** </dd>
** </dl>
*/
#define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */
@@ -2016,6 +2026,7 @@ struct sqlite3_mem_methods {
#define SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER 1004 /* int int* */
#define SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION 1005 /* int int* */
#define SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE 1006 /* int int* */
+#define SQLITE_DBCONFIG_FULL_EQP 1007 /* int int* */
/*
@@ -8038,6 +8049,22 @@ int sqlite3_vtab_config(sqlite3*, int op, ...);
int sqlite3_vtab_on_conflict(sqlite3 *);
/*
+** CAPI3REF: Determine The Collation For a Virtual Table Constraint
+**
+** This function may only be called from within a call to the [xBestIndex]
+** method of a [virtual table implementation].
+**
+** The first argument must be the database handle with which the virtual
+** table is associated (the one passed to the [xConnect] or [xCreate] method
+** to create the sqlite3_vtab object. The second argument must be an index
+** into the aConstraint[] array belonging to the sqlite3_index_info structure
+** passed to xBestIndex. This function returns a pointer to a buffer
+** containing the name of the collation sequence for the corresponding
+** constraint.
+*/
+SQLITE_EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3*, int);
+
+/*
** CAPI3REF: Conflict resolution modes
** KEYWORDS: {conflict resolution mode}
**
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 40660aed9..3ce77bf7d 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -1334,6 +1334,7 @@ struct sqlite3 {
u8 mTrace; /* zero or more SQLITE_TRACE flags */
u8 skipBtreeMutex; /* True if no shared-cache backends */
u8 nSqlExec; /* Number of pending OP_SqlExec opcodes */
+ u8 bInternChanges; /* There are uncommited schema changes */
int nextPagesize; /* Pagesize after VACUUM if >0 */
u32 magic; /* Magic number for detect library misuse */
int nChange; /* Value returned by sqlite3_changes() */
@@ -1399,6 +1400,7 @@ struct sqlite3 {
VtabCtx *pVtabCtx; /* Context for active vtab connect/create */
VTable **aVTrans; /* Virtual tables with open transactions */
VTable *pDisconnect; /* Disconnect these in next sqlite3_prepare() */
+ void *pBestIndexCtx; /* For sqlite3_vtab_collation() */
#endif
Hash aFunc; /* Hash table of connection functions */
Hash aCollSeq; /* All collating sequences */
@@ -1448,7 +1450,7 @@ struct sqlite3 {
** SQLITE_CacheSpill == PAGER_CACHE_SPILL
*/
#define SQLITE_VdbeTrace 0x00000001 /* True to trace VDBE execution */
-#define SQLITE_InternChanges 0x00000002 /* Uncommitted Hash table changes */
+#define SQLITE_FullEQP 0x00000002 /* Include triggers in EQP output */
#define SQLITE_FullColNames 0x00000004 /* Show full column names on SELECT */
#define SQLITE_FullFSync 0x00000008 /* Use full fsync on the backend */
#define SQLITE_CkptFullFSync 0x00000010 /* Use full fsync for checkpoint */
diff --git a/src/tclsqlite.c b/src/tclsqlite.c
index 9df023b45..a4a0ed3f3 100644
--- a/src/tclsqlite.c
+++ b/src/tclsqlite.c
@@ -4129,6 +4129,7 @@ static void init_all(Tcl_Interp *interp){
#if defined(SQLITE_ENABLE_SESSION) && defined(SQLITE_ENABLE_PREUPDATE_HOOK)
extern int TestSession_Init(Tcl_Interp*);
#endif
+ extern int TestExpert_Init(Tcl_Interp*);
extern int Fts5tcl_Init(Tcl_Interp *);
extern int SqliteRbu_Init(Tcl_Interp*);
extern int Sqlitetesttcl_Init(Tcl_Interp*);
@@ -4177,6 +4178,7 @@ static void init_all(Tcl_Interp *interp){
#if defined(SQLITE_ENABLE_SESSION) && defined(SQLITE_ENABLE_PREUPDATE_HOOK)
TestSession_Init(interp);
#endif
+ TestExpert_Init(interp);
Fts5tcl_Init(interp);
SqliteRbu_Init(interp);
Sqlitetesttcl_Init(interp);
diff --git a/src/trigger.c b/src/trigger.c
index bdf964084..197dcda6c 100644
--- a/src/trigger.c
+++ b/src/trigger.c
@@ -584,7 +584,7 @@ void sqlite3UnlinkAndDeleteTrigger(sqlite3 *db, int iDb, const char *zName){
*pp = (*pp)->pNext;
}
sqlite3DeleteTrigger(db, pTrigger);
- db->flags |= SQLITE_InternChanges;
+ db->bInternChanges = 1;
}
}
diff --git a/src/vdbe.c b/src/vdbe.c
index 5bed6f6f4..6f9d3e18b 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -3056,7 +3056,7 @@ case OP_Savepoint: {
int isSchemaChange;
iSavepoint = db->nSavepoint - iSavepoint - 1;
if( p1==SAVEPOINT_ROLLBACK ){
- isSchemaChange = (db->flags & SQLITE_InternChanges)!=0;
+ isSchemaChange = db->bInternChanges;
for(ii=0; ii<db->nDb; ii++){
rc = sqlite3BtreeTripAllCursors(db->aDb[ii].pBt,
SQLITE_ABORT_ROLLBACK,
@@ -3075,7 +3075,7 @@ case OP_Savepoint: {
if( isSchemaChange ){
sqlite3ExpirePreparedStatements(db);
sqlite3ResetAllSchemasOfConnection(db);
- db->flags = (db->flags | SQLITE_InternChanges);
+ db->bInternChanges = 1;
}
}
@@ -3355,7 +3355,7 @@ case OP_SetCookie: {
if( pOp->p2==BTREE_SCHEMA_VERSION ){
/* When the schema cookie changes, record the new cookie internally */
pDb->pSchema->schema_cookie = pOp->p3;
- db->flags |= SQLITE_InternChanges;
+ db->bInternChanges = 1;
}else if( pOp->p2==BTREE_FILE_FORMAT ){
/* Record changes in the file format */
pDb->pSchema->file_format = pOp->p3;
diff --git a/src/vdbeaux.c b/src/vdbeaux.c
index 00a5ec91a..5de43f42c 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -1611,6 +1611,8 @@ int sqlite3VdbeList(
int i; /* Loop counter */
int rc = SQLITE_OK; /* Return code */
Mem *pMem = &p->aMem[1]; /* First Mem of result set */
+ int bFull = (p->explain==1 || (db->flags & SQLITE_FullEQP));
+ Op *pOp;
assert( p->explain );
assert( p->magic==VDBE_MAGIC_RUN );
@@ -1638,7 +1640,7 @@ int sqlite3VdbeList(
** encountered, but p->pc will eventually catch up to nRow.
*/
nRow = p->nOp;
- if( p->explain==1 ){
+ if( bFull ){
/* The first 8 memory cells are used for the result set. So we will
** commandeer the 9th cell to use as storage for an array of pointers
** to trigger subprograms. The VDBE is guaranteed to have at least 9
@@ -1658,17 +1660,11 @@ int sqlite3VdbeList(
do{
i = p->pc++;
- }while( i<nRow && p->explain==2 && p->aOp[i].opcode!=OP_Explain );
- if( i>=nRow ){
- p->rc = SQLITE_OK;
- rc = SQLITE_DONE;
- }else if( db->u1.isInterrupted ){
- p->rc = SQLITE_INTERRUPT;
- rc = SQLITE_ERROR;
- sqlite3VdbeError(p, sqlite3ErrStr(p->rc));
- }else{
- char *zP4;
- Op *pOp;
+ if( i>=nRow ){
+ p->rc = SQLITE_OK;
+ rc = SQLITE_DONE;
+ break;
+ }
if( i<p->nOp ){
/* The output line number is small enough that we are still in the
** main program. */
@@ -1683,94 +1679,107 @@ int sqlite3VdbeList(
}
pOp = &apSub[j]->aOp[i];
}
- if( p->explain==1 ){
- pMem->flags = MEM_Int;
- pMem->u.i = i; /* Program counter */
- pMem++;
-
- pMem->flags = MEM_Static|MEM_Str|MEM_Term;
- pMem->z = (char*)sqlite3OpcodeName(pOp->opcode); /* Opcode */
- assert( pMem->z!=0 );
- pMem->n = sqlite3Strlen30(pMem->z);
- pMem->enc = SQLITE_UTF8;
- pMem++;
- /* When an OP_Program opcode is encounter (the only opcode that has
- ** a P4_SUBPROGRAM argument), expand the size of the array of subprograms
- ** kept in p->aMem[9].z to hold the new program - assuming this subprogram
- ** has not already been seen.
- */
- if( pOp->p4type==P4_SUBPROGRAM ){
- int nByte = (nSub+1)*sizeof(SubProgram*);
- int j;
- for(j=0; j<nSub; j++){
- if( apSub[j]==pOp->p4.pProgram ) break;
- }
- if( j==nSub && SQLITE_OK==sqlite3VdbeMemGrow(pSub, nByte, nSub!=0) ){
- apSub = (SubProgram **)pSub->z;
- apSub[nSub++] = pOp->p4.pProgram;
- pSub->flags |= MEM_Blob;
- pSub->n = nSub*sizeof(SubProgram*);
- }
+ /* When an OP_Program opcode is encounter (the only opcode that has
+ ** a P4_SUBPROGRAM argument), expand the size of the array of subprograms
+ ** kept in p->aMem[9].z to hold the new program - assuming this subprogram
+ ** has not already been seen.
+ */
+ if( bFull && pOp->p4type==P4_SUBPROGRAM ){
+ int nByte = (nSub+1)*sizeof(SubProgram*);
+ int j;
+ for(j=0; j<nSub; j++){
+ if( apSub[j]==pOp->p4.pProgram ) break;
+ }
+ if( j==nSub ){
+ rc = sqlite3VdbeMemGrow(pSub, nByte, nSub!=0);
+ if( rc!=SQLITE_OK ) break;
+ apSub = (SubProgram **)pSub->z;
+ apSub[nSub++] = pOp->p4.pProgram;
+ pSub->flags |= MEM_Blob;
+ pSub->n = nSub*sizeof(SubProgram*);
+ nRow += pOp->p4.pProgram->nOp;
}
}
+ }while( p->explain==2 && pOp->opcode!=OP_Explain );
- pMem->flags = MEM_Int;
- pMem->u.i = pOp->p1; /* P1 */
- pMem++;
+ if( rc==SQLITE_OK ){
+ if( db->u1.isInterrupted ){
+ p->rc = SQLITE_INTERRUPT;
+ rc = SQLITE_ERROR;
+ sqlite3VdbeError(p, sqlite3ErrStr(p->rc));
+ }else{
+ char *zP4;
+ if( p->explain==1 ){
+ pMem->flags = MEM_Int;
+ pMem->u.i = i; /* Program counter */
+ pMem++;
+
+ pMem->flags = MEM_Static|MEM_Str|MEM_Term;
+ pMem->z = (char*)sqlite3OpcodeName(pOp->opcode); /* Opcode */
+ assert( pMem->z!=0 );
+ pMem->n = sqlite3Strlen30(pMem->z);
+ pMem->enc = SQLITE_UTF8;
+ pMem++;
+ }
- pMem->flags = MEM_Int;
- pMem->u.i = pOp->p2; /* P2 */
- pMem++;
+ pMem->flags = MEM_Int;
+ pMem->u.i = pOp->p1; /* P1 */
+ pMem++;
- pMem->flags = MEM_Int;
- pMem->u.i = pOp->p3; /* P3 */
- pMem++;
+ pMem->flags = MEM_Int;
+ pMem->u.i = pOp->p2; /* P2 */
+ pMem++;
- if( sqlite3VdbeMemClearAndResize(pMem, 100) ){ /* P4 */
- assert( p->db->mallocFailed );
- return SQLITE_ERROR;
- }
- pMem->flags = MEM_Str|MEM_Term;
- zP4 = displayP4(pOp, pMem->z, pMem->szMalloc);
- if( zP4!=pMem->z ){
- pMem->n = 0;
- sqlite3VdbeMemSetStr(pMem, zP4, -1, SQLITE_UTF8, 0);
- }else{
- assert( pMem->z!=0 );
- pMem->n = sqlite3Strlen30(pMem->z);
- pMem->enc = SQLITE_UTF8;
- }
- pMem++;
+ pMem->flags = MEM_Int;
+ pMem->u.i = pOp->p3; /* P3 */
+ pMem++;
- if( p->explain==1 ){
- if( sqlite3VdbeMemClearAndResize(pMem, 4) ){
+ if( sqlite3VdbeMemClearAndResize(pMem, 100) ){ /* P4 */
assert( p->db->mallocFailed );
return SQLITE_ERROR;
}
pMem->flags = MEM_Str|MEM_Term;
- pMem->n = 2;
- sqlite3_snprintf(3, pMem->z, "%.2x", pOp->p5); /* P5 */
- pMem->enc = SQLITE_UTF8;
+ zP4 = displayP4(pOp, pMem->z, pMem->szMalloc);
+ if( zP4!=pMem->z ){
+ pMem->n = 0;
+ sqlite3VdbeMemSetStr(pMem, zP4, -1, SQLITE_UTF8, 0);
+ }else{
+ assert( pMem->z!=0 );
+ pMem->n = sqlite3Strlen30(pMem->z);
+ pMem->enc = SQLITE_UTF8;
+ }
pMem++;
-
+
+ if( p->explain==1 ){
+ if( sqlite3VdbeMemClearAndResize(pMem, 4) ){
+ assert( p->db->mallocFailed );
+ return SQLITE_ERROR;
+ }
+ pMem->flags = MEM_Str|MEM_Term;
+ pMem->n = 2;
+ sqlite3_snprintf(3, pMem->z, "%.2x", pOp->p5); /* P5 */
+ pMem->enc = SQLITE_UTF8;
+ pMem++;
+
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
- if( sqlite3VdbeMemClearAndResize(pMem, 500) ){
- assert( p->db->mallocFailed );
- return SQLITE_ERROR;
- }
- pMem->flags = MEM_Str|MEM_Term;
- pMem->n = displayComment(pOp, zP4, pMem->z, 500);
- pMem->enc = SQLITE_UTF8;
+ if( sqlite3VdbeMemClearAndResize(pMem, 500) ){
+ assert( p->db->mallocFailed );
+ return SQLITE_ERROR;
+ }
+ pMem->flags = MEM_Str|MEM_Term;
+ pMem->n = displayComment(pOp, zP4, pMem->z, 500);
+ pMem->enc = SQLITE_UTF8;
#else
- pMem->flags = MEM_Null; /* Comment */
+ pMem->flags = MEM_Null; /* Comment */
#endif
- }
+ }
- p->nResColumn = 8 - 4*(p->explain-1);
- p->pResultSet = &p->aMem[1];
- p->rc = SQLITE_OK;
- rc = SQLITE_ROW;
+ p->nResColumn = 8 - 4*(p->explain-1);
+ p->pResultSet = &p->aMem[1];
+ p->rc = SQLITE_OK;
+ rc = SQLITE_ROW;
+ }
}
return rc;
}
diff --git a/src/where.c b/src/where.c
index 479e38d01..91050de90 100644
--- a/src/where.c
+++ b/src/where.c
@@ -885,7 +885,8 @@ static sqlite3_index_info *allocateIndexInfo(
*/
pIdxInfo = sqlite3DbMallocZero(pParse->db, sizeof(*pIdxInfo)
+ (sizeof(*pIdxCons) + sizeof(*pUsage))*nTerm
- + sizeof(*pIdxOrderBy)*nOrderBy );
+ + sizeof(*pIdxOrderBy)*nOrderBy
+ );
if( pIdxInfo==0 ){
sqlite3ErrorMsg(pParse, "out of memory");
return 0;
@@ -3117,6 +3118,35 @@ static int whereLoopAddVirtualOne(
/*
+** Context object used to pass information from whereLoopAddVirtual()
+** to sqlite3_vtab_collation().
+*/
+struct BestIndexCtx {
+ WhereClause *pWC;
+ sqlite3_index_info *pIdxInfo;
+ Parse *pParse;
+};
+
+/*
+** If this function is invoked from within an xBestIndex() callback, it
+** returns a pointer to a buffer containing the name of the collation
+** sequence associated with element iCons of the sqlite3_index_info.aConstraint
+** array. Or, if iCons is out of range or there is no active xBestIndex
+** call, return NULL.
+*/
+const char *sqlite3_vtab_collation(sqlite3 *db, int iCons){
+ struct BestIndexCtx *p = (struct BestIndexCtx*)db->pBestIndexCtx;
+ const char *zRet = 0;
+ if( p && iCons>=0 && iCons<p->pIdxInfo->nConstraint ){
+ int iTerm = p->pIdxInfo->aConstraint[iCons].iTermOffset;
+ Expr *pX = p->pWC->a[iTerm].pExpr;
+ CollSeq *pC = sqlite3BinaryCompareCollSeq(p->pParse,pX->pLeft,pX->pRight);
+ zRet = (pC ? pC->zName : "BINARY");
+ }
+ return zRet;
+}
+
+/*
** Add all WhereLoop objects for a table of the join identified by
** pBuilder->pNew->iTab. That table is guaranteed to be a virtual table.
**
@@ -3157,6 +3187,8 @@ static int whereLoopAddVirtual(
WhereLoop *pNew;
Bitmask mBest; /* Tables used by best possible plan */
u16 mNoOmit;
+ struct BestIndexCtx bic;
+ void *pSaved;
assert( (mPrereq & mUnusable)==0 );
pWInfo = pBuilder->pWInfo;
@@ -3178,6 +3210,12 @@ static int whereLoopAddVirtual(
return SQLITE_NOMEM_BKPT;
}
+ bic.pWC = pWC;
+ bic.pIdxInfo = p;
+ bic.pParse = pParse;
+ pSaved = pParse->db->pBestIndexCtx;
+ pParse->db->pBestIndexCtx = (void*)&bic;
+
/* First call xBestIndex() with all constraints usable. */
WHERETRACE(0x40, (" VirtualOne: all usable\n"));
rc = whereLoopAddVirtualOne(pBuilder, mPrereq, ALLBITS, 0, p, mNoOmit, &bIn);
@@ -3254,6 +3292,7 @@ static int whereLoopAddVirtual(
if( p->needToFreeIdxStr ) sqlite3_free(p->idxStr);
sqlite3DbFreeNN(pParse->db, p);
+ pParse->db->pBestIndexCtx = pSaved;
return rc;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */