1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-11-11 01:42:22 +03:00

Improvements to the constant-propagation optimization in order to better

deal with unusual affinities.  See
[forum:/forumpost/6a06202608|forum post 6a06202608] for more detail.

FossilOrigin-Name: 9be208a6d70582c6808abe6e016ab9cd8d10f0deefb8c7a8c0543372cca15b12
This commit is contained in:
drh
2021-05-26 23:10:19 +00:00
4 changed files with 176 additions and 14 deletions

View File

@@ -4417,6 +4417,7 @@ struct WhereConst {
Parse *pParse; /* Parsing context */
int nConst; /* Number for COLUMN=CONSTANT terms */
int nChng; /* Number of times a constant is propagated */
int bHasAffBlob; /* At least one column in apExpr[] as affinity BLOB */
Expr **apExpr; /* [i*2] is COLUMN and [i*2+1] is VALUE */
};
@@ -4455,6 +4456,9 @@ static void constInsert(
return; /* Already present. Return without doing anything. */
}
}
if( sqlite3ExprAffinity(pColumn)==SQLITE_AFF_BLOB ){
pConst->bHasAffBlob = 1;
}
pConst->nConst++;
pConst->apExpr = sqlite3DbReallocOrFree(pConst->pParse->db, pConst->apExpr,
@@ -4496,26 +4500,34 @@ static void findConstInWhere(WhereConst *pConst, Expr *pExpr){
}
/*
** This is a Walker expression callback. pExpr is a candidate expression
** to be replaced by a value. If pExpr is equivalent to one of the
** columns named in pWalker->u.pConst, then overwrite it with its
** corresponding value.
** This is a helper function for Walker callback propagateConstantExprRewrite().
**
** Argument pExpr is a candidate expression to be replaced by a value. If
** pExpr is equivalent to one of the columns named in pWalker->u.pConst,
** then overwrite it with the corresponding value. Except, do not do so
** if argument bIgnoreAffBlob is non-zero and the affinity of pExpr
** is SQLITE_AFF_BLOB.
*/
static int propagateConstantExprRewrite(Walker *pWalker, Expr *pExpr){
static int propagateConstantExprRewriteOne(
WhereConst *pConst,
Expr *pExpr,
int bIgnoreAffBlob
){
int i;
WhereConst *pConst;
if( pExpr->op!=TK_COLUMN ) return WRC_Continue;
if( ExprHasProperty(pExpr, EP_FixedCol|EP_FromJoin) ){
testcase( ExprHasProperty(pExpr, EP_FixedCol) );
testcase( ExprHasProperty(pExpr, EP_FromJoin) );
return WRC_Continue;
}
pConst = pWalker->u.pConst;
for(i=0; i<pConst->nConst; i++){
Expr *pColumn = pConst->apExpr[i*2];
if( pColumn==pExpr ) continue;
if( pColumn->iTable!=pExpr->iTable ) continue;
if( pColumn->iColumn!=pExpr->iColumn ) continue;
if( bIgnoreAffBlob && sqlite3ExprAffinity(pColumn)==SQLITE_AFF_BLOB ){
break;
}
/* A match is found. Add the EP_FixedCol property */
pConst->nChng++;
ExprClearProperty(pExpr, EP_Leaf);
@@ -4527,6 +4539,41 @@ static int propagateConstantExprRewrite(Walker *pWalker, Expr *pExpr){
return WRC_Prune;
}
/*
** This is a Walker expression callback. pExpr is a node from the WHERE
** clause of a SELECT statement. This function examines pExpr to see if
** any substitutions based on the contents of pWalker->u.pConst should
** be made to pExpr or its immediate children.
**
** A substitution is made if:
**
** + pExpr is a column with an affinity other than BLOB that matches
** one of the columns in pWalker->u.pConst, or
**
** + pExpr is a binary comparison operator (=, <=, >=, <, >) that
** uses an affinity other than TEXT and one of its immediate
** children is a column that matches one of the columns in
** pWalker->u.pConst.
*/
static int propagateConstantExprRewrite(Walker *pWalker, Expr *pExpr){
WhereConst *pConst = pWalker->u.pConst;
assert( TK_GT==TK_EQ+1 );
assert( TK_LE==TK_EQ+2 );
assert( TK_LT==TK_EQ+3 );
assert( TK_GE==TK_EQ+4 );
if( pConst->bHasAffBlob ){
if( (pExpr->op>=TK_EQ && pExpr->op<=TK_GE)
|| pExpr->op==TK_IS
){
propagateConstantExprRewriteOne(pConst, pExpr->pLeft, 0);
if( sqlite3ExprAffinity(pExpr->pLeft)!=SQLITE_AFF_TEXT ){
propagateConstantExprRewriteOne(pConst, pExpr->pRight, 0);
}
}
}
return propagateConstantExprRewriteOne(pConst, pExpr, pConst->bHasAffBlob);
}
/*
** The WHERE-clause constant propagation optimization.
**
@@ -4575,6 +4622,7 @@ static int propagateConstants(
x.nConst = 0;
x.nChng = 0;
x.apExpr = 0;
x.bHasAffBlob = 0;
findConstInWhere(&x, p->pWhere);
if( x.nConst ){
memset(&w, 0, sizeof(w));