aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2019-10-30 18:50:08 +0000
committerdrh <drh@noemail.net>2019-10-30 18:50:08 +0000
commit20cee7d0bb8f627c3952f24a5c4772f8fbb4d720 (patch)
tree8fa04661f1fdf2da038495b7517dbfcc964a2984 /src
parent920cf596e67ecccecb497cfa60cc65945048f866 (diff)
downloadsqlite-20cee7d0bb8f627c3952f24a5c4772f8fbb4d720.tar.gz
sqlite-20cee7d0bb8f627c3952f24a5c4772f8fbb4d720.zip
Always disallow the use of non-deterministic functions in CHECK constraints,
even date/time functions that use the 'now' or similar keywords. Provide improved error messages when this requirement is not met. Ticket [830277d9db6c3ba1] FossilOrigin-Name: 2978b65ebe25eeabe543b67cb266308cceb20082a4ae71565d6d083d7c08bc9f
Diffstat (limited to 'src')
-rw-r--r--src/expr.c4
-rw-r--r--src/resolve.c21
-rw-r--r--src/sqliteInt.h12
-rw-r--r--src/vdbeaux.c27
4 files changed, 38 insertions, 26 deletions
diff --git a/src/expr.c b/src/expr.c
index 36ab7c795..b0c61f00f 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -4033,7 +4033,7 @@ expr_code_doover:
#endif
{
sqlite3VdbeAddFunctionCall(pParse, constMask, r1, target, nFarg,
- pDef, pParse->iSelfTab);
+ pDef, pExpr->op2);
}
if( nFarg && constMask==0 ){
sqlite3ReleaseTempRange(pParse, r1, nFarg);
@@ -5028,7 +5028,7 @@ int sqlite3ExprCompare(Parse *pParse, Expr *pA, Expr *pB, int iTab){
&& (combinedFlags & EP_Reduced)==0
){
if( pA->iColumn!=pB->iColumn ) return 2;
- if( pA->op2!=pB->op2 ) return 2;
+ if( pA->op2!=pB->op2 && (pA->op!=TK_FUNCTION || iTab<0) ) return 2;
if( pA->op!=TK_IN && pA->iTable!=pB->iTable && pA->iTable!=iTab ){
return 2;
}
diff --git a/src/resolve.c b/src/resolve.c
index a9c20b101..9be62c090 100644
--- a/src/resolve.c
+++ b/src/resolve.c
@@ -815,15 +815,18 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
if( pDef->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG) ){
/* For the purposes of the EP_ConstFunc flag, date and time
** functions and other functions that change slowly are considered
- ** constant because they are constant for the duration of one query */
+ ** constant because they are constant for the duration of one query.
+ ** This allows them to be factored out of inner loops. */
ExprSetProperty(pExpr,EP_ConstFunc);
}
if( (pDef->funcFlags & SQLITE_FUNC_CONSTANT)==0 ){
/* Date/time functions that use 'now', and other functions like
** sqlite_version() that might change over time cannot be used
** in an index. */
- notValid(pParse, pNC, "non-deterministic functions",
- NC_IdxExpr|NC_PartIdx|NC_GenCol);
+ notValid(pParse, pNC, "non-deterministic functions", NC_SelfRef);
+ }else{
+ assert( (NC_SelfRef & 0xff)==NC_SelfRef ); /* Must fit in 8 bits */
+ pExpr->op2 = pNC->ncFlags & NC_SelfRef;
}
if( (pDef->funcFlags & SQLITE_FUNC_INTERNAL)!=0
&& pParse->nested==0
@@ -1789,11 +1792,13 @@ void sqlite3ResolveSelectNames(
** Resolve names in expressions that can only reference a single table
** or which cannot reference any tables at all. Examples:
**
-** (1) CHECK constraints
-** (2) WHERE clauses on partial indices
-** (3) Expressions in indexes on expressions
-** (4) Expression arguments to VACUUM INTO.
-** (5) GENERATED ALWAYS as expressions
+** "type" flag
+** ------------
+** (1) CHECK constraints NC_IsCheck
+** (2) WHERE clauses on partial indices NC_PartIdx
+** (3) Expressions in indexes on expressions NC_IdxExpr
+** (4) Expression arguments to VACUUM INTO. 0
+** (5) GENERATED ALWAYS as expressions NC_GenCol
**
** In all cases except (4), the Expr.iTable value for Expr.op==TK_COLUMN
** nodes of the expression is set to -1 and the Expr.iColumn value is
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index d8668a278..cf7abfe66 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -2487,6 +2487,10 @@ typedef int ynVar;
struct Expr {
u8 op; /* Operation performed by this node */
char affExpr; /* affinity, or RAISE type */
+ u8 op2; /* TK_REGISTER/TK_TRUTH: original value of Expr.op
+ ** TK_COLUMN: the value of p5 for OP_Column
+ ** TK_AGG_FUNCTION: nesting depth
+ ** TK_FUNCTION: NC_SelfRef flag if needs OP_PureFunc */
u32 flags; /* Various flags. EP_* See below */
union {
char *zToken; /* Token value. Zero terminated and dequoted */
@@ -2525,9 +2529,6 @@ struct Expr {
** TK_SELECT_COLUMN: column of the result vector */
i16 iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */
i16 iRightJoinTable; /* If EP_FromJoin, the right table of the join */
- u8 op2; /* TK_REGISTER/TK_TRUTH: original value of Expr.op
- ** TK_COLUMN: the value of p5 for OP_Column
- ** TK_AGG_FUNCTION: nesting depth */
AggInfo *pAggInfo; /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */
union {
Table *pTab; /* TK_COLUMN: Table containing column. Can be NULL
@@ -2840,9 +2841,10 @@ struct NameContext {
#define NC_AllowAgg 0x00001 /* Aggregate functions are allowed here */
#define NC_PartIdx 0x00002 /* True if resolving a partial index WHERE */
#define NC_IsCheck 0x00004 /* True if resolving a CHECK constraint */
-#define NC_InAggFunc 0x00008 /* True if analyzing arguments to an agg func */
+#define NC_GenCol 0x00008 /* True for a GENERATED ALWAYS AS clause */
#define NC_HasAgg 0x00010 /* One or more aggregate functions seen */
#define NC_IdxExpr 0x00020 /* True if resolving columns of CREATE INDEX */
+#define NC_SelfRef 0x0002e /* Combo: PartIdx, isCheck, GenCol, and IdxExpr */
#define NC_VarSelect 0x00040 /* A correlated subquery has been seen */
#define NC_UEList 0x00080 /* True if uNC.pEList is used */
#define NC_UAggInfo 0x00100 /* True if uNC.pAggInfo is used */
@@ -2852,7 +2854,7 @@ struct NameContext {
#define NC_AllowWin 0x04000 /* Window functions are allowed here */
#define NC_HasWin 0x08000 /* One or more window functions seen */
#define NC_IsDDL 0x10000 /* Resolving names in a CREATE statement */
-#define NC_GenCol 0x20000 /* True for a GENERATED ALWAYS AS clause */
+#define NC_InAggFunc 0x20000 /* True if analyzing arguments to an agg func */
/*
** An instance of the following object describes a single ON CONFLICT
diff --git a/src/vdbeaux.c b/src/vdbeaux.c
index de6575cd5..9596e163b 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -365,11 +365,12 @@ int sqlite3VdbeAddFunctionCall(
}
pCtx->pOut = 0;
pCtx->pFunc = (FuncDef*)pFunc;
- pCtx->pVdbe = v;
+ pCtx->pVdbe = 0;
pCtx->isError = 0;
pCtx->argc = nArg;
addr = sqlite3VdbeAddOp4(v, eCallCtx ? OP_PureFunc : OP_Function,
p1, p2, p3, (char*)pCtx, P4_FUNCCTX);
+ sqlite3VdbeChangeP5(v, eCallCtx & NC_SelfRef);
pCtx->iOp = addr;
return addr;
}
@@ -4999,21 +5000,25 @@ void sqlite3VdbeSetVarmask(Vdbe *v, int iVar){
** features such as 'now'.
*/
int sqlite3NotPureFunc(sqlite3_context *pCtx){
+ const VdbeOp *pOp;
#ifdef SQLITE_ENABLE_STAT4
if( pCtx->pVdbe==0 ) return 1;
#endif
- if( pCtx->pVdbe->aOp[pCtx->iOp].opcode==OP_PureFunc ){
-#if 0
- char *zMsg = sqlite3_mprintf(
- "non-deterministic use of %s() in an index, CHECK constraint, "
- "or generated column", pCtx->pFunc->zName);
+ pOp = pCtx->pVdbe->aOp + pCtx->iOp;
+ if( pOp->opcode==OP_PureFunc ){
+ const char *zContext;
+ char *zMsg;
+ if( pOp->p5 & NC_IsCheck ){
+ zContext = "a CHECK constraint";
+ }else if( pOp->p5 & NC_GenCol ){
+ zContext = "a generated column";
+ }else{
+ zContext = "an index";
+ }
+ zMsg = sqlite3_mprintf("non-deterministic use of %s() in %s",
+ pCtx->pFunc->zName, zContext);
sqlite3_result_error(pCtx, zMsg, -1);
sqlite3_free(zMsg);
-#else
- sqlite3_result_error(pCtx,
- "non-deterministic function in index expression or CHECK constraint",
- -1);
-#endif
return 0;
}
return 1;