diff options
author | drh <drh@noemail.net> | 2019-10-30 18:50:08 +0000 |
---|---|---|
committer | drh <drh@noemail.net> | 2019-10-30 18:50:08 +0000 |
commit | 20cee7d0bb8f627c3952f24a5c4772f8fbb4d720 (patch) | |
tree | 8fa04661f1fdf2da038495b7517dbfcc964a2984 /src | |
parent | 920cf596e67ecccecb497cfa60cc65945048f866 (diff) | |
download | sqlite-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.c | 4 | ||||
-rw-r--r-- | src/resolve.c | 21 | ||||
-rw-r--r-- | src/sqliteInt.h | 12 | ||||
-rw-r--r-- | src/vdbeaux.c | 27 |
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; |