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:
74
src/expr.c
74
src/expr.c
@@ -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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user