Merge the sqlite3_reoptimize() changes into the trunk.
FossilOrigin-Name: 50136840d54674c239613265ebbacaabf215f4e2
This commit is contained in:
+7
-6
@@ -571,12 +571,12 @@ void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){
|
||||
if( z[1]==0 ){
|
||||
/* Wildcard of the form "?". Assign the next variable number */
|
||||
assert( z[0]=='?' );
|
||||
pExpr->iTable = ++pParse->nVar;
|
||||
pExpr->iColumn = ++pParse->nVar;
|
||||
}else if( z[0]=='?' ){
|
||||
/* Wildcard of the form "?nnn". Convert "nnn" to an integer and
|
||||
** use it as the variable number */
|
||||
int i;
|
||||
pExpr->iTable = i = atoi((char*)&z[1]);
|
||||
pExpr->iColumn = i = atoi((char*)&z[1]);
|
||||
testcase( i==0 );
|
||||
testcase( i==1 );
|
||||
testcase( i==db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER]-1 );
|
||||
@@ -600,12 +600,12 @@ void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){
|
||||
Expr *pE = pParse->apVarExpr[i];
|
||||
assert( pE!=0 );
|
||||
if( memcmp(pE->u.zToken, z, n)==0 && pE->u.zToken[n]==0 ){
|
||||
pExpr->iTable = pE->iTable;
|
||||
pExpr->iColumn = pE->iColumn;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( i>=pParse->nVarExpr ){
|
||||
pExpr->iTable = ++pParse->nVar;
|
||||
pExpr->iColumn = ++pParse->nVar;
|
||||
if( pParse->nVarExpr>=pParse->nVarExprAlloc-1 ){
|
||||
pParse->nVarExprAlloc += pParse->nVarExprAlloc + 10;
|
||||
pParse->apVarExpr =
|
||||
@@ -2164,7 +2164,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
assert( pExpr->u.zToken[0]!=0 );
|
||||
if( pExpr->u.zToken[1]==0
|
||||
&& (pOp = sqlite3VdbeGetOp(v, -1))->opcode==OP_Variable
|
||||
&& pOp->p1+pOp->p3==pExpr->iTable
|
||||
&& pOp->p1+pOp->p3==pExpr->iColumn
|
||||
&& pOp->p2+pOp->p3==target
|
||||
&& pOp->p4.z==0
|
||||
){
|
||||
@@ -2175,7 +2175,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
*/
|
||||
pOp->p3++;
|
||||
}else{
|
||||
sqlite3VdbeAddOp3(v, OP_Variable, pExpr->iTable, target, 1);
|
||||
sqlite3VdbeAddOp3(v, OP_Variable, pExpr->iColumn, target, 1);
|
||||
if( pExpr->u.zToken[1]!=0 ){
|
||||
sqlite3VdbeChangeP4(v, -1, pExpr->u.zToken, 0);
|
||||
}
|
||||
@@ -2801,6 +2801,7 @@ int sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr, int target){
|
||||
iMem = ++pParse->nMem;
|
||||
sqlite3VdbeAddOp2(v, OP_Copy, inReg, iMem);
|
||||
pExpr->iTable = iMem;
|
||||
pExpr->op2 = pExpr->op;
|
||||
pExpr->op = TK_REGISTER;
|
||||
}
|
||||
return inReg;
|
||||
|
||||
+2
-2
@@ -1481,8 +1481,8 @@ static const int aHardLimit[] = {
|
||||
#if SQLITE_MAX_LIKE_PATTERN_LENGTH<1
|
||||
# error SQLITE_MAX_LIKE_PATTERN_LENGTH must be at least 1
|
||||
#endif
|
||||
#if SQLITE_MAX_VARIABLE_NUMBER<1
|
||||
# error SQLITE_MAX_VARIABLE_NUMBER must be at least 1
|
||||
#if SQLITE_MAX_VARIABLE_NUMBER<1 || SQLITE_MAX_VARIABLE_NUMBER>32767
|
||||
# error SQLITE_MAX_VARIABLE_NUMBER must be between 1 and 32767
|
||||
#endif
|
||||
#if SQLITE_MAX_COLUMN>32767
|
||||
# error SQLITE_MAX_COLUMN must not exceed 32767
|
||||
|
||||
+9
-6
@@ -525,6 +525,7 @@ static int sqlite3Prepare(
|
||||
const char *zSql, /* UTF-8 encoded SQL statement. */
|
||||
int nBytes, /* Length of zSql in bytes. */
|
||||
int saveSqlFlag, /* True to copy SQL text into the sqlite3_stmt */
|
||||
Vdbe *pReprepare, /* VM being reprepared */
|
||||
sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
|
||||
const char **pzTail /* OUT: End of parsed string */
|
||||
){
|
||||
@@ -539,6 +540,7 @@ static int sqlite3Prepare(
|
||||
rc = SQLITE_NOMEM;
|
||||
goto end_prepare;
|
||||
}
|
||||
pParse->pReprepare = pReprepare;
|
||||
|
||||
if( sqlite3SafetyOn(db) ){
|
||||
rc = SQLITE_MISUSE;
|
||||
@@ -696,6 +698,7 @@ static int sqlite3LockAndPrepare(
|
||||
const char *zSql, /* UTF-8 encoded SQL statement. */
|
||||
int nBytes, /* Length of zSql in bytes. */
|
||||
int saveSqlFlag, /* True to copy SQL text into the sqlite3_stmt */
|
||||
Vdbe *pOld, /* VM being reprepared */
|
||||
sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
|
||||
const char **pzTail /* OUT: End of parsed string */
|
||||
){
|
||||
@@ -707,10 +710,10 @@ static int sqlite3LockAndPrepare(
|
||||
}
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
sqlite3BtreeEnterAll(db);
|
||||
rc = sqlite3Prepare(db, zSql, nBytes, saveSqlFlag, ppStmt, pzTail);
|
||||
rc = sqlite3Prepare(db, zSql, nBytes, saveSqlFlag, pOld, ppStmt, pzTail);
|
||||
if( rc==SQLITE_SCHEMA ){
|
||||
sqlite3_finalize(*ppStmt);
|
||||
rc = sqlite3Prepare(db, zSql, nBytes, saveSqlFlag, ppStmt, pzTail);
|
||||
rc = sqlite3Prepare(db, zSql, nBytes, saveSqlFlag, pOld, ppStmt, pzTail);
|
||||
}
|
||||
sqlite3BtreeLeaveAll(db);
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
@@ -736,7 +739,7 @@ int sqlite3Reprepare(Vdbe *p){
|
||||
assert( zSql!=0 ); /* Reprepare only called for prepare_v2() statements */
|
||||
db = sqlite3VdbeDb(p);
|
||||
assert( sqlite3_mutex_held(db->mutex) );
|
||||
rc = sqlite3LockAndPrepare(db, zSql, -1, 0, &pNew, 0);
|
||||
rc = sqlite3LockAndPrepare(db, zSql, -1, 0, p, &pNew, 0);
|
||||
if( rc ){
|
||||
if( rc==SQLITE_NOMEM ){
|
||||
db->mallocFailed = 1;
|
||||
@@ -770,7 +773,7 @@ int sqlite3_prepare(
|
||||
const char **pzTail /* OUT: End of parsed string */
|
||||
){
|
||||
int rc;
|
||||
rc = sqlite3LockAndPrepare(db,zSql,nBytes,0,ppStmt,pzTail);
|
||||
rc = sqlite3LockAndPrepare(db,zSql,nBytes,0,0,ppStmt,pzTail);
|
||||
assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); /* VERIFY: F13021 */
|
||||
return rc;
|
||||
}
|
||||
@@ -782,7 +785,7 @@ int sqlite3_prepare_v2(
|
||||
const char **pzTail /* OUT: End of parsed string */
|
||||
){
|
||||
int rc;
|
||||
rc = sqlite3LockAndPrepare(db,zSql,nBytes,1,ppStmt,pzTail);
|
||||
rc = sqlite3LockAndPrepare(db,zSql,nBytes,1,0,ppStmt,pzTail);
|
||||
assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); /* VERIFY: F13021 */
|
||||
return rc;
|
||||
}
|
||||
@@ -816,7 +819,7 @@ static int sqlite3Prepare16(
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
zSql8 = sqlite3Utf16to8(db, zSql, nBytes);
|
||||
if( zSql8 ){
|
||||
rc = sqlite3LockAndPrepare(db, zSql8, -1, saveSqlFlag, ppStmt, &zTail8);
|
||||
rc = sqlite3LockAndPrepare(db, zSql8, -1, saveSqlFlag, 0, ppStmt, &zTail8);
|
||||
}
|
||||
|
||||
if( zTail8 && pzTail ){
|
||||
|
||||
@@ -5743,6 +5743,15 @@ int sqlite3_unlock_notify(
|
||||
*/
|
||||
int sqlite3_strnicmp(const char *, const char *, int);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Optimizing for Bound Parameters
|
||||
** EXPERIMENTAL
|
||||
**
|
||||
** If possible, optimize the SQL statement passed as the only argument
|
||||
** for the values currently bound to the statements SQL variables.
|
||||
*/
|
||||
int sqlite3_reoptimize(sqlite3_stmt *pStmt);
|
||||
|
||||
/*
|
||||
** Undo the hack that converts floating point types to integer for
|
||||
** builds on processors without floating point support.
|
||||
|
||||
+3
-1
@@ -1590,7 +1590,8 @@ struct Expr {
|
||||
int iTable; /* TK_COLUMN: cursor number of table holding column
|
||||
** TK_REGISTER: register number
|
||||
** TK_TRIGGER: 1 -> new, 0 -> old */
|
||||
i16 iColumn; /* TK_COLUMN: column index. -1 for rowid */
|
||||
i16 iColumn; /* TK_COLUMN: column index. -1 for rowid.
|
||||
** TK_VARIABLE: variable number (always >= 1). */
|
||||
i16 iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */
|
||||
i16 iRightJoinTable; /* If EP_FromJoin, the right table of the join */
|
||||
u8 flags2; /* Second set of flags. EP2_... */
|
||||
@@ -2132,6 +2133,7 @@ struct Parse {
|
||||
int nVarExpr; /* Number of used slots in apVarExpr[] */
|
||||
int nVarExprAlloc; /* Number of allocated slots in apVarExpr[] */
|
||||
Expr **apVarExpr; /* Pointers to :aaa and $aaaa wildcard expressions */
|
||||
Vdbe *pReprepare; /* VM being reprepared (sqlite3Reprepare()) */
|
||||
int nAlias; /* Number of aliased result set columns */
|
||||
int nAliasAlloc; /* Number of allocated slots for aAlias[] */
|
||||
int *aAlias; /* Register used to hold aliased result */
|
||||
|
||||
@@ -1128,6 +1128,16 @@ static int dbPrepareAndBind(
|
||||
}
|
||||
pPreStmt->nParm = iParm;
|
||||
*ppPreStmt = pPreStmt;
|
||||
|
||||
/* Call sqlite3_reoptimize() to optimize the statement according to
|
||||
** the values just bound to it. If SQLITE_ENABLE_STAT2 is not defined
|
||||
** or the statement will not benefit from re-optimization, this
|
||||
** call is a no-op. */
|
||||
if( SQLITE_OK!=sqlite3_reoptimize(pPreStmt->pStmt) ){
|
||||
Tcl_SetObjResult(interp, dbTextToObj(sqlite3_errmsg(pDb->db)));
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
|
||||
+31
@@ -2049,6 +2049,34 @@ static int test_stmt_status(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_reoptimize STMT
|
||||
**
|
||||
** Call sqlite3_reoptimize() on the statement handle passed as the
|
||||
** only parameter. Return a string representing the value returned by
|
||||
** sqlite3_reoptimize - "SQLITE_OK", "SQLITE_MISUSE" etc.
|
||||
*/
|
||||
static int test_reoptimize(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
sqlite3_stmt *pStmt;
|
||||
int rc;
|
||||
|
||||
if( objc!=2 ){
|
||||
Tcl_AppendResult(interp, "wrong # args: should be \"",
|
||||
Tcl_GetString(objv[0]), " STMT", 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
|
||||
rc = sqlite3_reoptimize(pStmt);
|
||||
Tcl_ResetResult(interp);
|
||||
Tcl_SetResult(interp, (char *)t1ErrorName(rc), 0);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_next_stmt DB STMT
|
||||
**
|
||||
@@ -3303,6 +3331,7 @@ static int test_prepare(
|
||||
if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR;
|
||||
|
||||
rc = sqlite3_prepare(db, zSql, bytes, &pStmt, objc>=5 ? &zTail : 0);
|
||||
Tcl_ResetResult(interp);
|
||||
if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
|
||||
if( zTail && objc>=5 ){
|
||||
if( bytes>=0 ){
|
||||
@@ -3360,6 +3389,7 @@ static int test_prepare_v2(
|
||||
|
||||
rc = sqlite3_prepare_v2(db, zSql, bytes, &pStmt, objc>=5 ? &zTail : 0);
|
||||
assert(rc==SQLITE_OK || pStmt==0);
|
||||
Tcl_ResetResult(interp);
|
||||
if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
|
||||
if( zTail && objc>=5 ){
|
||||
if( bytes>=0 ){
|
||||
@@ -5001,6 +5031,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
{ "sqlite3_step", test_step ,0 },
|
||||
{ "sqlite3_sql", test_sql ,0 },
|
||||
{ "sqlite3_next_stmt", test_next_stmt ,0 },
|
||||
{ "sqlite3_reoptimize", test_reoptimize ,0 },
|
||||
|
||||
{ "sqlite3_release_memory", test_release_memory, 0},
|
||||
{ "sqlite3_soft_heap_limit", test_soft_heap_limit, 0},
|
||||
|
||||
+10
-12
@@ -151,12 +151,10 @@ int sqlite3_found_count = 0;
|
||||
/*
|
||||
** Argument pMem points at a register that will be passed to a
|
||||
** user-defined function or returned to the user as the result of a query.
|
||||
** The second argument, 'db_enc' is the text encoding used by the vdbe for
|
||||
** register variables. This routine sets the pMem->enc and pMem->type
|
||||
** variables used by the sqlite3_value_*() routines.
|
||||
** This routine sets the pMem->type variable used by the sqlite3_value_*()
|
||||
** routines.
|
||||
*/
|
||||
#define storeTypeInfo(A,B) _storeTypeInfo(A)
|
||||
static void _storeTypeInfo(Mem *pMem){
|
||||
void sqlite3VdbeMemStoreType(Mem *pMem){
|
||||
int flags = pMem->flags;
|
||||
if( flags & MEM_Null ){
|
||||
pMem->type = SQLITE_NULL;
|
||||
@@ -327,7 +325,7 @@ static void applyAffinity(
|
||||
int sqlite3_value_numeric_type(sqlite3_value *pVal){
|
||||
Mem *pMem = (Mem*)pVal;
|
||||
applyNumericAffinity(pMem);
|
||||
storeTypeInfo(pMem, 0);
|
||||
sqlite3VdbeMemStoreType(pMem);
|
||||
return pMem->type;
|
||||
}
|
||||
|
||||
@@ -1021,7 +1019,7 @@ case OP_Variable: {
|
||||
n = pOp->p3;
|
||||
assert( p1>=0 && p1+n<=p->nVar );
|
||||
assert( p2>=1 && p2+n-1<=p->nMem );
|
||||
assert( pOp->p4.z==0 || pOp->p3==1 );
|
||||
assert( pOp->p4.z==0 || pOp->p3==1 || pOp->p3==0 );
|
||||
|
||||
while( n-- > 0 ){
|
||||
pVar = &p->aVar[p1++];
|
||||
@@ -1168,7 +1166,7 @@ case OP_ResultRow: {
|
||||
pMem = p->pResultSet = &p->aMem[pOp->p1];
|
||||
for(i=0; i<pOp->p2; i++){
|
||||
sqlite3VdbeMemNulTerminate(&pMem[i]);
|
||||
storeTypeInfo(&pMem[i], encoding);
|
||||
sqlite3VdbeMemStoreType(&pMem[i]);
|
||||
REGISTER_TRACE(pOp->p1+i, &pMem[i]);
|
||||
}
|
||||
if( db->mallocFailed ) goto no_mem;
|
||||
@@ -1387,7 +1385,7 @@ case OP_Function: {
|
||||
pArg = &p->aMem[pOp->p2];
|
||||
for(i=0; i<n; i++, pArg++){
|
||||
apVal[i] = pArg;
|
||||
storeTypeInfo(pArg, encoding);
|
||||
sqlite3VdbeMemStoreType(pArg);
|
||||
REGISTER_TRACE(pOp->p2, pArg);
|
||||
}
|
||||
|
||||
@@ -5057,7 +5055,7 @@ case OP_AggStep: {
|
||||
assert( apVal || n==0 );
|
||||
for(i=0; i<n; i++, pRec++){
|
||||
apVal[i] = pRec;
|
||||
storeTypeInfo(pRec, encoding);
|
||||
sqlite3VdbeMemStoreType(pRec);
|
||||
}
|
||||
ctx.pFunc = pOp->p4.pFunc;
|
||||
assert( pOp->p3>0 && pOp->p3<=p->nMem );
|
||||
@@ -5345,7 +5343,7 @@ case OP_VFilter: { /* jump */
|
||||
apArg = p->apArg;
|
||||
for(i = 0; i<nArg; i++){
|
||||
apArg[i] = &pArgc[i+1];
|
||||
storeTypeInfo(apArg[i], 0);
|
||||
sqlite3VdbeMemStoreType(apArg[i]);
|
||||
}
|
||||
|
||||
if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
|
||||
@@ -5549,7 +5547,7 @@ case OP_VUpdate: {
|
||||
apArg = p->apArg;
|
||||
pX = &p->aMem[pOp->p3];
|
||||
for(i=0; i<nArg; i++){
|
||||
storeTypeInfo(pX, 0);
|
||||
sqlite3VdbeMemStoreType(pX);
|
||||
apArg[i] = pX;
|
||||
pX++;
|
||||
}
|
||||
|
||||
@@ -202,6 +202,8 @@ void sqlite3VdbeSetSql(Vdbe*, const char *z, int n, int);
|
||||
void sqlite3VdbeSwap(Vdbe*,Vdbe*);
|
||||
VdbeOp *sqlite3VdbeTakeOpArray(Vdbe*, int*, int*);
|
||||
void sqlite3VdbeProgramDelete(sqlite3 *, SubProgram *, int);
|
||||
sqlite3_value *sqlite3VdbeGetValue(Vdbe*, int, u8);
|
||||
void sqlite3VdbeSetVarmask(Vdbe*,int,int);
|
||||
|
||||
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
|
||||
int sqlite3VdbeReleaseMemory(int);
|
||||
|
||||
@@ -323,6 +323,9 @@ struct Vdbe {
|
||||
#endif
|
||||
VdbeFrame *pFrame; /* Parent frame */
|
||||
int nFrame; /* Number of frames in pFrame list */
|
||||
u8 optimizable; /* True if VM may benefit from sqlite3_reoptimize() */
|
||||
u32 optmask; /* Bitmask of vars that may be used by reoptimize() */
|
||||
u32 expmask; /* Binding to these vars invalidates VM */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -388,6 +391,7 @@ int sqlite3VdbeFrameRestore(VdbeFrame *);
|
||||
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
|
||||
int sqlite3VdbeReleaseBuffers(Vdbe *p);
|
||||
#endif
|
||||
void sqlite3VdbeMemStoreType(Mem *pMem);
|
||||
|
||||
#ifndef SQLITE_OMIT_FOREIGN_KEY
|
||||
int sqlite3VdbeCheckFk(Vdbe *, int);
|
||||
|
||||
@@ -914,6 +914,21 @@ static int vdbeUnbind(Vdbe *p, int i){
|
||||
sqlite3VdbeMemRelease(pVar);
|
||||
pVar->flags = MEM_Null;
|
||||
sqlite3Error(p->db, SQLITE_OK, 0);
|
||||
|
||||
/* If the bit corresponding to this variable is set in Vdbe.opmask, set
|
||||
** the optimizable flag before returning. This tells the sqlite3_reoptimize()
|
||||
** function that the VM program may benefit from recompilation.
|
||||
**
|
||||
** If the bit in Vdbe.expmask is set, then binding a new value to this
|
||||
** variable invalidates the current query plan. This comes about when the
|
||||
** variable is the RHS of a LIKE or GLOB operator and the LIKE/GLOB is
|
||||
** able to use an index. */
|
||||
if( (i<32 && p->optmask & ((u32)1 << i)) || p->optmask==0xffffffff ){
|
||||
p->optimizable = 1;
|
||||
}
|
||||
if( (i<32 && p->expmask & ((u32)1 << i)) || p->expmask==0xffffffff ){
|
||||
p->expired = 1;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
@@ -1205,3 +1220,25 @@ int sqlite3_stmt_status(sqlite3_stmt *pStmt, int op, int resetFlag){
|
||||
if( resetFlag ) pVdbe->aCounter[op-1] = 0;
|
||||
return v;
|
||||
}
|
||||
|
||||
/*
|
||||
** If possible, optimize the statement for the current bindings.
|
||||
*/
|
||||
int sqlite3_reoptimize(sqlite3_stmt *pStmt){
|
||||
int rc = SQLITE_OK;
|
||||
Vdbe *v = (Vdbe *)pStmt;
|
||||
sqlite3 *db = v->db;
|
||||
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
if( v->isPrepareV2==0 || v->pc>0 ){
|
||||
rc = SQLITE_MISUSE;
|
||||
}else if( v->optimizable ){
|
||||
rc = sqlite3Reprepare(v);
|
||||
rc = sqlite3ApiExit(db, rc);
|
||||
}
|
||||
assert( rc!=SQLITE_OK || v->optimizable==0 );
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
@@ -3022,3 +3022,44 @@ void sqlite3ExpirePreparedStatements(sqlite3 *db){
|
||||
sqlite3 *sqlite3VdbeDb(Vdbe *v){
|
||||
return v->db;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return a pointer to an sqlite3_value structure containing the value bound
|
||||
** parameter iVar of VM v. Except, if the value is an SQL NULL, return
|
||||
** 0 instead. Unless it is NULL, apply affinity aff (one of the SQLITE_AFF_*
|
||||
** constants) to the value before returning it.
|
||||
**
|
||||
** The returned value must be freed by the caller using sqlite3ValueFree().
|
||||
*/
|
||||
sqlite3_value *sqlite3VdbeGetValue(Vdbe *v, int iVar, u8 aff){
|
||||
assert( iVar>0 );
|
||||
if( v ){
|
||||
Mem *pMem = &v->aVar[iVar-1];
|
||||
if( 0==(pMem->flags & MEM_Null) ){
|
||||
sqlite3_value *pRet = sqlite3ValueNew(v->db);
|
||||
if( pRet ){
|
||||
sqlite3VdbeMemCopy((Mem *)pRet, pMem);
|
||||
sqlite3ValueApplyAffinity(pRet, aff, SQLITE_UTF8);
|
||||
sqlite3VdbeMemStoreType((Mem *)pRet);
|
||||
}
|
||||
return pRet;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Configure SQL variable iVar so that binding a new value to it signals
|
||||
** to sqlite3_reoptimize() that re-preparing the statement may result
|
||||
** in a better query plan.
|
||||
*/
|
||||
void sqlite3VdbeSetVarmask(Vdbe *v, int iVar, int isExpire){
|
||||
u32 *mask = (isExpire ? &v->expmask : &v->optmask);
|
||||
assert( iVar>0 );
|
||||
if( iVar>32 ){
|
||||
*mask = 0xffffffff;
|
||||
}else{
|
||||
*mask |= ((u32)1 << (iVar-1));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1053,6 +1053,9 @@ int sqlite3ValueFromExpr(
|
||||
}
|
||||
#endif
|
||||
|
||||
if( pVal ){
|
||||
sqlite3VdbeMemStoreType(pVal);
|
||||
}
|
||||
*ppVal = pVal;
|
||||
return SQLITE_OK;
|
||||
|
||||
|
||||
+89
-26
@@ -625,11 +625,11 @@ static void exprAnalyzeAll(
|
||||
static int isLikeOrGlob(
|
||||
Parse *pParse, /* Parsing and code generating context */
|
||||
Expr *pExpr, /* Test this expression */
|
||||
int *pnPattern, /* Number of non-wildcard prefix characters */
|
||||
Expr **ppPrefix, /* Pointer to TK_STRING expression with pattern prefix */
|
||||
int *pisComplete, /* True if the only wildcard is % in the last character */
|
||||
int *pnoCase /* True if uppercase is equivalent to lowercase */
|
||||
){
|
||||
const char *z; /* String on RHS of LIKE operator */
|
||||
const char *z = 0; /* String on RHS of LIKE operator */
|
||||
Expr *pRight, *pLeft; /* Right and left size of LIKE operator */
|
||||
ExprList *pList; /* List of operands to the LIKE operator */
|
||||
int c; /* One character in z[] */
|
||||
@@ -637,6 +637,8 @@ static int isLikeOrGlob(
|
||||
char wc[3]; /* Wildcard characters */
|
||||
CollSeq *pColl; /* Collating sequence for LHS */
|
||||
sqlite3 *db = pParse->db; /* Database connection */
|
||||
sqlite3_value *pVal = 0;
|
||||
int op; /* Opcode of pRight */
|
||||
|
||||
if( !sqlite3IsLikeFunction(db, pExpr, pnoCase, wc) ){
|
||||
return 0;
|
||||
@@ -645,10 +647,6 @@ static int isLikeOrGlob(
|
||||
if( *pnoCase ) return 0;
|
||||
#endif
|
||||
pList = pExpr->x.pList;
|
||||
pRight = pList->a[0].pExpr;
|
||||
if( pRight->op!=TK_STRING ){
|
||||
return 0;
|
||||
}
|
||||
pLeft = pList->a[1].pExpr;
|
||||
if( pLeft->op!=TK_COLUMN ){
|
||||
return 0;
|
||||
@@ -661,19 +659,54 @@ static int isLikeOrGlob(
|
||||
return 0;
|
||||
}
|
||||
if( sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT ) return 0;
|
||||
z = pRight->u.zToken;
|
||||
if( ALWAYS(z) ){
|
||||
|
||||
pRight = pList->a[0].pExpr;
|
||||
op = pRight->op;
|
||||
if( op==TK_REGISTER ){
|
||||
op = pRight->op2;
|
||||
}
|
||||
if( op==TK_VARIABLE ){
|
||||
Vdbe *pReprepare = pParse->pReprepare;
|
||||
pVal = sqlite3VdbeGetValue(pReprepare, pRight->iColumn, SQLITE_AFF_NONE);
|
||||
if( pVal && sqlite3_value_type(pVal)==SQLITE_TEXT ){
|
||||
z = (char *)sqlite3_value_text(pVal);
|
||||
}
|
||||
sqlite3VdbeSetVarmask(pParse->pVdbe, pRight->iColumn, 0);
|
||||
assert( pRight->op==TK_VARIABLE || pRight->op==TK_REGISTER );
|
||||
}else if( op==TK_STRING ){
|
||||
z = pRight->u.zToken;
|
||||
}
|
||||
if( z ){
|
||||
cnt = 0;
|
||||
while( (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2] ){
|
||||
cnt++;
|
||||
}
|
||||
if( cnt!=0 && c!=0 && 255!=(u8)z[cnt-1] ){
|
||||
Expr *pPrefix;
|
||||
*pisComplete = z[cnt]==wc[0] && z[cnt+1]==0;
|
||||
*pnPattern = cnt;
|
||||
return 1;
|
||||
pPrefix = sqlite3Expr(db, TK_STRING, z);
|
||||
if( pPrefix ) pPrefix->u.zToken[cnt] = 0;
|
||||
*ppPrefix = pPrefix;
|
||||
if( op==TK_VARIABLE ){
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
sqlite3VdbeSetVarmask(v, pRight->iColumn, 1);
|
||||
if( *pisComplete && pRight->u.zToken[1] ){
|
||||
/* If the rhs of the LIKE expression is a variable, and the current
|
||||
** value of the variable means there is no need to invoke the LIKE
|
||||
** function, then no OP_Variable will be added to the program.
|
||||
** This causes problems for the sqlite3_bind_parameter_name()
|
||||
** API. To workaround them, add a dummy OP_Variable here. */
|
||||
sqlite3ExprCodeTarget(pParse, pRight, 1);
|
||||
sqlite3VdbeChangeP3(v, sqlite3VdbeCurrentAddr(v)-1, 0);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
z = 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
sqlite3ValueFree(pVal);
|
||||
return (z!=0);
|
||||
}
|
||||
#endif /* SQLITE_OMIT_LIKE_OPTIMIZATION */
|
||||
|
||||
@@ -1055,12 +1088,12 @@ static void exprAnalyze(
|
||||
Bitmask prereqLeft; /* Prerequesites of the pExpr->pLeft */
|
||||
Bitmask prereqAll; /* Prerequesites of pExpr */
|
||||
Bitmask extraRight = 0;
|
||||
int nPattern;
|
||||
int isComplete;
|
||||
int noCase;
|
||||
int op; /* Top-level operator. pExpr->op */
|
||||
Parse *pParse = pWC->pParse; /* Parsing context */
|
||||
sqlite3 *db = pParse->db; /* Database connection */
|
||||
Expr *pStr1;
|
||||
|
||||
if( db->mallocFailed ){
|
||||
return;
|
||||
@@ -1192,21 +1225,19 @@ static void exprAnalyze(
|
||||
** The last character of the prefix "abc" is incremented to form the
|
||||
** termination condition "abd".
|
||||
*/
|
||||
if( isLikeOrGlob(pParse, pExpr, &nPattern, &isComplete, &noCase)
|
||||
&& pWC->op==TK_AND ){
|
||||
Expr *pLeft, *pRight;
|
||||
Expr *pStr1, *pStr2;
|
||||
if( pWC->op==TK_AND
|
||||
&& isLikeOrGlob(pParse, pExpr, &pStr1, &isComplete, &noCase)
|
||||
){
|
||||
Expr *pLeft;
|
||||
Expr *pStr2;
|
||||
Expr *pNewExpr1, *pNewExpr2;
|
||||
int idxNew1, idxNew2;
|
||||
|
||||
pLeft = pExpr->x.pList->a[1].pExpr;
|
||||
pRight = pExpr->x.pList->a[0].pExpr;
|
||||
pStr1 = sqlite3Expr(db, TK_STRING, pRight->u.zToken);
|
||||
if( pStr1 ) pStr1->u.zToken[nPattern] = 0;
|
||||
pStr2 = sqlite3ExprDup(db, pStr1, 0);
|
||||
if( !db->mallocFailed ){
|
||||
u8 c, *pC; /* Last character before the first wildcard */
|
||||
pC = (u8*)&pStr2->u.zToken[nPattern-1];
|
||||
pC = (u8*)&pStr2->u.zToken[sqlite3Strlen30(pStr2->u.zToken)-1];
|
||||
c = *pC;
|
||||
if( noCase ){
|
||||
/* The point is to increment the last character before the first
|
||||
@@ -1984,6 +2015,39 @@ static int whereRangeRegion(
|
||||
}
|
||||
#endif /* #ifdef SQLITE_ENABLE_STAT2 */
|
||||
|
||||
/*
|
||||
** If expression pExpr represents a literal value, set *pp to point to
|
||||
** an sqlite3_value structure containing the same value, with affinity
|
||||
** aff applied to it, before returning. It is the responsibility of the
|
||||
** caller to eventually release this structure by passing it to
|
||||
** sqlite3ValueFree().
|
||||
**
|
||||
** If the current parse is a recompile (sqlite3Reprepare()) and pExpr
|
||||
** is an SQL variable that currently has a non-NULL value bound to it,
|
||||
** create an sqlite3_value structure containing this value, again with
|
||||
** affinity aff applied to it, instead.
|
||||
**
|
||||
** If neither of the above apply, set *pp to NULL.
|
||||
**
|
||||
** If an error occurs, return an error code. Otherwise, SQLITE_OK.
|
||||
*/
|
||||
static int valueFromExpr(
|
||||
Parse *pParse,
|
||||
Expr *pExpr,
|
||||
u8 aff,
|
||||
sqlite3_value **pp
|
||||
){
|
||||
if( (pExpr->op==TK_VARIABLE)
|
||||
|| (pExpr->op==TK_REGISTER && pExpr->op2==TK_VARIABLE)
|
||||
){
|
||||
int iVar = pExpr->iColumn;
|
||||
sqlite3VdbeSetVarmask(pParse->pVdbe, iVar, 0);
|
||||
*pp = sqlite3VdbeGetValue(pParse->pReprepare, iVar, aff);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
return sqlite3ValueFromExpr(pParse->db, pExpr, SQLITE_UTF8, aff, pp);
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is used to estimate the number of rows that will be visited
|
||||
** by scanning an index for a range of values. The range may have an upper
|
||||
@@ -2036,23 +2100,22 @@ static int whereRangeScanEst(
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
#ifdef SQLITE_ENABLE_STAT2
|
||||
sqlite3 *db = pParse->db;
|
||||
sqlite3_value *pLowerVal = 0;
|
||||
sqlite3_value *pUpperVal = 0;
|
||||
|
||||
if( nEq==0 && p->aSample ){
|
||||
sqlite3_value *pLowerVal = 0;
|
||||
sqlite3_value *pUpperVal = 0;
|
||||
int iEst;
|
||||
int iLower = 0;
|
||||
int iUpper = SQLITE_INDEX_SAMPLES;
|
||||
u8 aff = p->pTable->aCol[0].affinity;
|
||||
u8 aff = p->pTable->aCol[p->aiColumn[0]].affinity;
|
||||
|
||||
if( pLower ){
|
||||
Expr *pExpr = pLower->pExpr->pRight;
|
||||
rc = sqlite3ValueFromExpr(db, pExpr, SQLITE_UTF8, aff, &pLowerVal);
|
||||
rc = valueFromExpr(pParse, pExpr, aff, &pLowerVal);
|
||||
}
|
||||
if( rc==SQLITE_OK && pUpper ){
|
||||
Expr *pExpr = pUpper->pExpr->pRight;
|
||||
rc = sqlite3ValueFromExpr(db, pExpr, SQLITE_UTF8, aff, &pUpperVal);
|
||||
rc = valueFromExpr(pParse, pExpr, aff, &pUpperVal);
|
||||
}
|
||||
|
||||
if( rc!=SQLITE_OK || (pLowerVal==0 && pUpperVal==0) ){
|
||||
|
||||
Reference in New Issue
Block a user