1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-08 14:02:16 +03:00

Experimental change to allow expressions with subtypes to be read from indexes in situations where they are not used as function parameters.

FossilOrigin-Name: ac63f98ad85a4dd1e49cc64b41f0ca0044153972c15d71c669f4bc3ec590e268
This commit is contained in:
dan
2024-10-05 17:37:19 +00:00
parent 706fdeebb8
commit c857b9eb5d
6 changed files with 155 additions and 69 deletions

View File

@@ -1164,6 +1164,7 @@ Expr *sqlite3ExprFunction(
){
Expr *pNew;
sqlite3 *db = pParse->db;
int ii;
assert( pToken );
pNew = sqlite3ExprAlloc(db, TK_FUNCTION, pToken, 1);
if( pNew==0 ){
@@ -1178,6 +1179,11 @@ Expr *sqlite3ExprFunction(
){
sqlite3ErrorMsg(pParse, "too many arguments on function %T", pToken);
}
if( pList && pParse->nErr==0 ){
for(ii=0; ii<pList->nExpr; ii++){
ExprSetProperty(pList->a[ii].pExpr, EP_FuncArg);
}
}
pNew->x.pList = pList;
ExprSetProperty(pNew, EP_HasFunc);
assert( ExprUseXList(pNew) );
@@ -4554,6 +4560,59 @@ static int exprCodeInlineFunction(
return target;
}
/*
** Expression Node callback for sqlite3ExprCanReturnSubtype().
**
** Only a function call is able to return a subtype. So if the node
** is not a function call, return WRC_Prune immediately.
**
** A function call is able to return a subtype if it has the
** SQLITE_RESULT_SUBTYPE property.
**
** Assume that every function is able to pass-through a subtype from
** one of its argument (using sqlite3_result_value()). Most functions
** are not this way, but we don't have a mechanism to distinguish those
** that are from those that are not, so assume they all work this way.
** That means that if one of its arguments is another function and that
** other function is able to return a subtype, then this function is
** able to return a subtype.
*/
static int exprNodeCanReturnSubtype(Walker *pWalker, Expr *pExpr){
int n;
FuncDef *pDef;
sqlite3 *db;
if( pExpr->op!=TK_FUNCTION ){
return WRC_Prune;
}
assert( ExprUseXList(pExpr) );
db = pWalker->pParse->db;
n = pExpr->x.pList ? pExpr->x.pList->nExpr : 0;
pDef = sqlite3FindFunction(db, pExpr->u.zToken, n, ENC(db), 0);
if( pDef==0 || (pDef->funcFlags & SQLITE_RESULT_SUBTYPE)!=0 ){
pWalker->eCode = 1;
return WRC_Prune;
}
return WRC_Continue;
}
/*
** Return TRUE if expression pExpr is able to return a subtype.
**
** A TRUE return does not guarantee that a subtype will be returned.
** It only indicates that a subtype return is possible. False positives
** are acceptable as they only disable an optimization. False negatives,
** on the other hand, can lead to incorrect answers.
*/
static int sqlite3ExprCanReturnSubtype(Parse *pParse, Expr *pExpr){
Walker w;
memset(&w, 0, sizeof(w));
w.pParse = pParse;
w.xExprCallback = exprNodeCanReturnSubtype;
sqlite3WalkExpr(&w, pExpr);
return w.eCode;
}
/*
** Check to see if pExpr is one of the indexed expressions on pParse->pIdxEpr.
** If it is, then resolve the expression by reading from the index and
@@ -4586,6 +4645,17 @@ static SQLITE_NOINLINE int sqlite3IndexedExprLookup(
continue;
}
/* Functions that might set a subtype should not be replaced by the
** value taken from an expression index if they are themselves an
** argument to another scalar function or aggregate.
** https://sqlite.org/forum/forumpost/68d284c86b082c3e */
if( ExprHasProperty(pExpr, EP_FuncArg)
&& sqlite3ExprCanReturnSubtype(pParse, pExpr)
){
continue;
}
v = pParse->pVdbe;
assert( v!=0 );
if( p->bMaybeNullRow ){