diff options
author | drh <> | 2024-10-08 10:10:42 +0000 |
---|---|---|
committer | drh <> | 2024-10-08 10:10:42 +0000 |
commit | eaefd9ccc8cc73ecb17bdfceabcaff4d5285e837 (patch) | |
tree | 9301f1ec78df6f944ca0b424b8f12233cfdb5b4f /src/expr.c | |
parent | 2813eb3c9e64a706fdec47b3075ab33f1013d2af (diff) | |
parent | 7998b889e884b5752ac3c11da443022343ba1b8a (diff) | |
download | sqlite-eaefd9ccc8cc73ecb17bdfceabcaff4d5285e837.tar.gz sqlite-eaefd9ccc8cc73ecb17bdfceabcaff4d5285e837.zip |
Allow expressions with subtypes to be read from indexes unless they are
being used as direct or indirect parameters to SQLITE_SUBTYPE functions.
FossilOrigin-Name: 39a56a23fec24dd713905457b6d4ed7c148f88e325a26c376f1e6daf147c69c8
Diffstat (limited to 'src/expr.c')
-rw-r--r-- | src/expr.c | 64 |
1 files changed, 64 insertions, 0 deletions
diff --git a/src/expr.c b/src/expr.c index 1b18828dd..cc915987d 100644 --- a/src/expr.c +++ b/src/expr.c @@ -4555,6 +4555,59 @@ static int exprCodeInlineFunction( } /* +** 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 = ALWAYS(pExpr->x.pList) ? pExpr->x.pList->nExpr : 0; + pDef = sqlite3FindFunction(db, pExpr->u.zToken, n, ENC(db), 0); + if( NEVER(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 ** return the register into which the value has been read. If pExpr is @@ -4586,6 +4639,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_SubtArg) + && sqlite3ExprCanReturnSubtype(pParse, pExpr) + ){ + continue; + } + v = pParse->pVdbe; assert( v!=0 ); if( p->bMaybeNullRow ){ |