1
0
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:
dan
2009-10-15 18:35:38 +00:00
parent 9bd42e96ac
commit 937d0dea4f
17 changed files with 880 additions and 84 deletions

View File

@@ -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) ){