aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/expr.c74
-rw-r--r--src/insert.c19
-rw-r--r--src/parse.y2
-rw-r--r--src/select.c6
-rw-r--r--src/sqliteInt.h2
-rw-r--r--src/where.c10
-rw-r--r--src/whereexpr.c2
-rw-r--r--src/window.c2
8 files changed, 91 insertions, 26 deletions
diff --git a/src/expr.c b/src/expr.c
index e4bfa995d..6050058e4 100644
--- a/src/expr.c
+++ b/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);
}
diff --git a/src/insert.c b/src/insert.c
index 2bd846e83..915f368fb 100644
--- a/src/insert.c
+++ b/src/insert.c
@@ -594,10 +594,10 @@ void sqlite3MultiValuesEnd(Parse *pParse, Select *pVal){
** Return true if all expressions in the expression-list passed as the
** only argument are constant.
*/
-static int exprListIsConstant(ExprList *pRow){
+static int exprListIsConstant(Parse *pParse, ExprList *pRow){
int ii;
for(ii=0; ii<pRow->nExpr; ii++){
- if( 0==sqlite3ExprIsConstant(pRow->a[ii].pExpr) ) return 0;
+ if( 0==sqlite3ExprIsConstant(pParse, pRow->a[ii].pExpr) ) return 0;
}
return 1;
}
@@ -606,9 +606,9 @@ static int exprListIsConstant(ExprList *pRow){
** Return true if all expressions in the expression-list passed as the
** only argument are both constant and have no affinity.
*/
-static int exprListIsNoAffinity(ExprList *pRow){
+static int exprListIsNoAffinity(Parse *pParse, ExprList *pRow){
int ii;
- if( exprListIsConstant(pRow)==0 ) return 0;
+ if( exprListIsConstant(pParse,pRow)==0 ) return 0;
for(ii=0; ii<pRow->nExpr; ii++){
assert( pRow->a[ii].pExpr->affExpr==0 );
if( 0!=sqlite3ExprAffinity(pRow->a[ii].pExpr) ) return 0;
@@ -670,11 +670,12 @@ static int exprListIsNoAffinity(ExprList *pRow){
*/
Select *sqlite3MultiValues(Parse *pParse, Select *pLeft, ExprList *pRow){
- if( pLeft->pPrior /* co-routine precluded by prior row */
- || pParse->bHasWith /* condition (a) above */
- || pParse->db->init.busy /* condition (b) above */
- || exprListIsConstant(pRow)==0 /* condition (c) above */
- || (pLeft->pSrc->nSrc==0 && exprListIsNoAffinity(pLeft->pEList)==0) /* (d) */
+ if( pLeft->pPrior /* co-routine precluded by prior row */
+ || pParse->bHasWith /* condition (a) above */
+ || pParse->db->init.busy /* condition (b) above */
+ || exprListIsConstant(pParse,pRow)==0 /* condition (c) above */
+ || (pLeft->pSrc->nSrc==0 &&
+ exprListIsNoAffinity(pParse,pLeft->pEList)==0) /* condition (d) above */
|| IN_SPECIAL_PARSE
){
/* The co-routine method cannot be used. Fall back to UNION ALL. */
diff --git a/src/parse.y b/src/parse.y
index 36566d28a..78404ce67 100644
--- a/src/parse.y
+++ b/src/parse.y
@@ -1325,7 +1325,7 @@ expr(A) ::= expr(A) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
if( A ) sqlite3ExprIdToTrueFalse(A);
}else{
Expr *pRHS = Y->a[0].pExpr;
- if( Y->nExpr==1 && sqlite3ExprIsConstant(pRHS) && A->op!=TK_VECTOR ){
+ if( Y->nExpr==1 && sqlite3ExprIsConstant(0,pRHS) && A->op!=TK_VECTOR ){
Y->a[0].pExpr = 0;
sqlite3ExprListDelete(pParse->db, Y);
pRHS = sqlite3PExpr(pParse, TK_UPLUS, pRHS, 0);
diff --git a/src/select.c b/src/select.c
index 4158dd2fd..bffbaa980 100644
--- a/src/select.c
+++ b/src/select.c
@@ -4776,7 +4776,7 @@ static void constInsert(
){
int i;
assert( pColumn->op==TK_COLUMN );
- assert( sqlite3ExprIsConstant(pValue) );
+ assert( sqlite3ExprIsConstant(0, pValue) );
if( ExprHasProperty(pColumn, EP_FixedCol) ) return;
if( sqlite3ExprAffinity(pValue)!=0 ) return;
@@ -4834,10 +4834,10 @@ static void findConstInWhere(WhereConst *pConst, Expr *pExpr){
pLeft = pExpr->pLeft;
assert( pRight!=0 );
assert( pLeft!=0 );
- if( pRight->op==TK_COLUMN && sqlite3ExprIsConstant(pLeft) ){
+ if( pRight->op==TK_COLUMN && sqlite3ExprIsConstant(0, pLeft) ){
constInsert(pConst,pRight,pLeft,pExpr);
}
- if( pLeft->op==TK_COLUMN && sqlite3ExprIsConstant(pRight) ){
+ if( pLeft->op==TK_COLUMN && sqlite3ExprIsConstant(0, pRight) ){
constInsert(pConst,pLeft,pRight,pExpr);
}
}
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 391339271..205cb6afe 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -5058,7 +5058,7 @@ void sqlite3LeaveMutexAndCloseZombie(sqlite3*);
u32 sqlite3IsTrueOrFalse(const char*);
int sqlite3ExprIdToTrueFalse(Expr*);
int sqlite3ExprTruthValue(const Expr*);
-int sqlite3ExprIsConstant(Expr*);
+int sqlite3ExprIsConstant(Parse*,Expr*);
int sqlite3ExprIsConstantNotJoin(Expr*);
int sqlite3ExprIsConstantOrFunction(Expr*, u8);
int sqlite3ExprIsConstantOrGroupBy(Parse*, Expr*, ExprList*);
diff --git a/src/where.c b/src/where.c
index 9abc8e30f..2a99c7398 100644
--- a/src/where.c
+++ b/src/where.c
@@ -1329,7 +1329,7 @@ static sqlite3_index_info *allocateIndexInfo(
Expr *pE2;
/* Skip over constant terms in the ORDER BY clause */
- if( sqlite3ExprIsConstant(pExpr) ){
+ if( sqlite3ExprIsConstant(0, pExpr) ){
continue;
}
@@ -1441,7 +1441,7 @@ static sqlite3_index_info *allocateIndexInfo(
pIdxInfo->nConstraint = j;
for(i=j=0; i<nOrderBy; i++){
Expr *pExpr = pOrderBy->a[i].pExpr;
- if( sqlite3ExprIsConstant(pExpr) ) continue;
+ if( sqlite3ExprIsConstant(0, pExpr) ) continue;
assert( pExpr->op==TK_COLUMN
|| (pExpr->op==TK_COLLATE && pExpr->pLeft->op==TK_COLUMN
&& pExpr->iColumn==pExpr->pLeft->iColumn) );
@@ -3623,7 +3623,7 @@ static void wherePartIdxExpr(
u8 aff;
if( pLeft->op!=TK_COLUMN ) return;
- if( !sqlite3ExprIsConstant(pRight) ) return;
+ if( !sqlite3ExprIsConstant(0, pRight) ) return;
if( !sqlite3IsBinary(sqlite3ExprCompareCollSeq(pParse, pPart)) ) return;
if( pLeft->iColumn<0 ) return;
aff = pIdx->pTable->aCol[pLeft->iColumn].affinity;
@@ -4997,7 +4997,7 @@ static i8 wherePathSatisfiesOrderBy(
if( MASKBIT(i) & obSat ) continue;
p = pOrderBy->a[i].pExpr;
mTerm = sqlite3WhereExprUsage(&pWInfo->sMaskSet,p);
- if( mTerm==0 && !sqlite3ExprIsConstant(p) ) continue;
+ if( mTerm==0 && !sqlite3ExprIsConstant(0,p) ) continue;
if( (mTerm&~orderDistinctMask)==0 ){
obSat |= MASKBIT(i);
}
@@ -5866,7 +5866,7 @@ static SQLITE_NOINLINE void whereAddIndexedExpr(
}else{
continue;
}
- if( sqlite3ExprIsConstant(pExpr) ) continue;
+ if( sqlite3ExprIsConstant(0,pExpr) ) continue;
if( pExpr->op==TK_FUNCTION ){
/* Functions that might set a subtype should not be replaced by the
** value taken from an expression index since the index omits the
diff --git a/src/whereexpr.c b/src/whereexpr.c
index 25db8f396..9d1f947a0 100644
--- a/src/whereexpr.c
+++ b/src/whereexpr.c
@@ -989,7 +989,7 @@ static SQLITE_NOINLINE int exprMightBeIndexed2(
if( pIdx->aiColumn[i]!=XN_EXPR ) continue;
assert( pIdx->bHasExpr );
if( sqlite3ExprCompareSkip(pExpr,pIdx->aColExpr->a[i].pExpr,iCur)==0
- && !sqlite3ExprIsConstant(pIdx->aColExpr->a[i].pExpr)
+ && !sqlite3ExprIsConstant(0,pIdx->aColExpr->a[i].pExpr)
){
aiCurCol[0] = iCur;
aiCurCol[1] = XN_EXPR;
diff --git a/src/window.c b/src/window.c
index 62df349fb..bcee65d92 100644
--- a/src/window.c
+++ b/src/window.c
@@ -1164,7 +1164,7 @@ void sqlite3WindowListDelete(sqlite3 *db, Window *p){
** variable values in the expression tree.
*/
static Expr *sqlite3WindowOffsetExpr(Parse *pParse, Expr *pExpr){
- if( 0==sqlite3ExprIsConstant(pExpr) ){
+ if( 0==sqlite3ExprIsConstant(0,pExpr) ){
if( IN_RENAME_OBJECT ) sqlite3RenameExprUnmap(pParse, pExpr);
sqlite3ExprDelete(pParse->db, pExpr);
pExpr = sqlite3ExprAlloc(pParse->db, TK_NULL, 0, 0);