aboutsummaryrefslogtreecommitdiff
path: root/src/vdbeaux.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/vdbeaux.c')
-rw-r--r--src/vdbeaux.c60
1 files changed, 55 insertions, 5 deletions
diff --git a/src/vdbeaux.c b/src/vdbeaux.c
index c83292fa4..de6575cd5 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -15,6 +15,10 @@
#include "sqliteInt.h"
#include "vdbeInt.h"
+/* Forward references */
+static void freeEphemeralFunction(sqlite3 *db, FuncDef *pDef);
+static void vdbeFreeOpArray(sqlite3 *, Op *, int);
+
/*
** Create a new virtual database engine.
*/
@@ -329,6 +333,48 @@ int sqlite3VdbeAddOp4(
}
/*
+** Add an OP_Function or OP_PureFunc opcode.
+**
+** The eCallCtx argument is information (typically taken from Expr.op2)
+** that describes the calling context of the function. 0 means a general
+** function call. NC_IsCheck means called by a check constraint,
+** NC_IdxExpr means called as part of an index expression. NC_PartIdx
+** means in the WHERE clause of a partial index. NC_GenCol means called
+** while computing a generated column value. 0 is the usual case.
+*/
+int sqlite3VdbeAddFunctionCall(
+ Parse *pParse, /* Parsing context */
+ int p1, /* Constant argument mask */
+ int p2, /* First argument register */
+ int p3, /* Register into which results are written */
+ int nArg, /* Number of argument */
+ const FuncDef *pFunc, /* The function to be invoked */
+ int eCallCtx /* Calling context */
+){
+ Vdbe *v = pParse->pVdbe;
+ int nByte;
+ int addr;
+ sqlite3_context *pCtx;
+ assert( v );
+ nByte = sizeof(*pCtx) + (nArg-1)*sizeof(sqlite3_value*);
+ pCtx = sqlite3DbMallocRawNN(pParse->db, nByte);
+ if( pCtx==0 ){
+ assert( pParse->db->mallocFailed );
+ freeEphemeralFunction(pParse->db, (FuncDef*)pFunc);
+ return 0;
+ }
+ pCtx->pOut = 0;
+ pCtx->pFunc = (FuncDef*)pFunc;
+ pCtx->pVdbe = v;
+ pCtx->isError = 0;
+ pCtx->argc = nArg;
+ addr = sqlite3VdbeAddOp4(v, eCallCtx ? OP_PureFunc : OP_Function,
+ p1, p2, p3, (char*)pCtx, P4_FUNCCTX);
+ pCtx->iOp = addr;
+ return addr;
+}
+
+/*
** Add an opcode that includes the p4 value with a P4_INT64 or
** P4_REAL type.
*/
@@ -1020,8 +1066,6 @@ static void freeEphemeralFunction(sqlite3 *db, FuncDef *pDef){
}
}
-static void vdbeFreeOpArray(sqlite3 *, Op *, int);
-
/*
** Delete a P4 value if necessary.
*/
@@ -1031,7 +1075,7 @@ static SQLITE_NOINLINE void freeP4Mem(sqlite3 *db, Mem *p){
}
static SQLITE_NOINLINE void freeP4FuncCtx(sqlite3 *db, sqlite3_context *p){
freeEphemeralFunction(db, p->pFunc);
- sqlite3DbFreeNN(db, p);
+ sqlite3DbFreeNN(db, p);
}
static void freeP4(sqlite3 *db, int p4type, void *p4){
assert( db );
@@ -1537,13 +1581,11 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
sqlite3_str_appendf(&x, "%s(%d)", pDef->zName, pDef->nArg);
break;
}
-#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
case P4_FUNCCTX: {
FuncDef *pDef = pOp->p4.pCtx->pFunc;
sqlite3_str_appendf(&x, "%s(%d)", pDef->zName, pDef->nArg);
break;
}
-#endif
case P4_INT64: {
sqlite3_str_appendf(&x, "%lld", *pOp->p4.pI64);
break;
@@ -4961,9 +5003,17 @@ int sqlite3NotPureFunc(sqlite3_context *pCtx){
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);
+ 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;