mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-16 23:02:26 +03:00
Add the experimental sqlite3_reoptimize() API.
FossilOrigin-Name: 9bd6f3d8864d422fe42074688b191915b27ad8ea
This commit is contained in:
115
src/where.c
115
src/where.c
@@ -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