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

Enhance the sqlite3ExprIsConstant() function so that it recognizes

constant functions.  So far the enhancement only applies to the multi-row
VALUES clause, but it could possibly be applied in many other places.

FossilOrigin-Name: c9e0488c6c0135932b6e76b0f3f3acd69ef65327e0a54daa59777f35da1aef26
This commit is contained in:
drh
2024-03-16 13:18:48 +00:00
parent 932b5f4575
commit f696591dd4
10 changed files with 108 additions and 40 deletions

View File

@@ -2346,6 +2346,52 @@ Expr *sqlite3ExprSimplifiedAndOr(Expr *pExpr){
return pExpr;
}
/*
** pExpr is a TK_FUNCTION node. Try to determine whether or not the
** function is a constant function. A function is constant if all of
** the following are true:
**
** (1) It is a scalar function (not an aggregate or window function)
** (2) It has either the SQLITE_FUNC_CONSTANT or SQLITE_FUNC_SLOCHNG
** property.
** (3) All of its arguments are constants
**
** This routine sets pWalker->eCode to 0 if pExpr is not a constant.
** It makes no changes to pWalker->eCode if pExpr is constant. In
** every case, it returns WRC_Abort.
**
** Called as a service subroutine from exprNodeIsConstant().
*/
static SQLITE_NOINLINE int exprNodeIsConstantFunction(
Walker *pWalker,
Expr *pExpr
){
int n; /* Number of arguments */
ExprList *pList; /* List of arguments */
FuncDef *pDef; /* The function */
sqlite3 *db; /* The database */
assert( pExpr->op==TK_FUNCTION );
if( pWalker->eCode==0 ) return WRC_Abort;
pList = pExpr->x.pList;
if( pList==0 ){
n = 0;
}else{
n = pList->nExpr;
sqlite3WalkExprList(pWalker, pList);
if( pWalker->eCode==0 ) return WRC_Abort;
}
db = pWalker->pParse->db;
pDef = sqlite3FindFunction(db, pExpr->u.zToken, n, ENC(db), 0);
if( pDef==0
|| pDef->xFinalize!=0
|| (pDef->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG))==0
){
pWalker->eCode = 0;
}
return WRC_Abort;
}
/*
** These routines are Walker callbacks used to check expressions to
@@ -2393,6 +2439,8 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
){
if( pWalker->eCode==5 ) ExprSetProperty(pExpr, EP_FromDDL);
return WRC_Continue;
}else if( pWalker->pParse ){
return exprNodeIsConstantFunction(pWalker, pExpr);
}else{
pWalker->eCode = 0;
return WRC_Abort;
@@ -2448,6 +2496,7 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
static int exprIsConst(Expr *p, int initFlag, int iCur){
Walker w;
w.eCode = initFlag;
w.pParse = 0;
w.xExprCallback = exprNodeIsConstant;
w.xSelectCallback = sqlite3SelectWalkFail;
#ifdef SQLITE_DEBUG
@@ -2465,9 +2514,24 @@ static int exprIsConst(Expr *p, int initFlag, int iCur){
** For the purposes of this function, a double-quoted string (ex: "abc")
** is considered a variable but a single-quoted string (ex: 'abc') is
** a constant.
**
** The pParse parameter may be NULL. But if it is NULL, there is no way
** to determine if function calls are constant or not, and hence all
** function calls will be considered to be non-constant. If pParse is
** not NULL, then a function call might be constant, depending on the
** function and on its parameters.
*/
int sqlite3ExprIsConstant(Expr *p){
return exprIsConst(p, 1, 0);
int sqlite3ExprIsConstant(Parse *pParse, Expr *p){
Walker w;
w.eCode = 1;
w.pParse = pParse;
w.xExprCallback = exprNodeIsConstant;
w.xSelectCallback = sqlite3SelectWalkFail;
#ifdef SQLITE_DEBUG
w.xSelectCallback2 = sqlite3SelectWalkAssert2;
#endif
sqlite3WalkExpr(&w, p);
return w.eCode;
}
/*
@@ -2902,7 +2966,7 @@ static int sqlite3InRhsIsConstant(Expr *pIn){
assert( !ExprHasProperty(pIn, EP_xIsSelect) );
pLHS = pIn->pLeft;
pIn->pLeft = 0;
res = sqlite3ExprIsConstant(pIn);
res = sqlite3ExprIsConstant(0, pIn);
pIn->pLeft = pLHS;
return res;
}
@@ -3454,7 +3518,7 @@ void sqlite3CodeRhsOfIN(
** this code only executes once. Because for a non-constant
** expression we need to rerun this code each time.
*/
if( addrOnce && !sqlite3ExprIsConstant(pE2) ){
if( addrOnce && !sqlite3ExprIsConstant(0, pE2) ){
sqlite3VdbeChangeToNoop(v, addrOnce-1);
sqlite3VdbeChangeToNoop(v, addrOnce);
ExprClearProperty(pExpr, EP_Subrtn);
@@ -4822,7 +4886,7 @@ expr_code_doover:
}
for(i=0; i<nFarg; i++){
if( i<32 && sqlite3ExprIsConstant(pFarg->a[i].pExpr) ){
if( i<32 && sqlite3ExprIsConstant(0, pFarg->a[i].pExpr) ){
testcase( i==31 );
constMask |= MASKBIT32(i);
}