aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2019-08-17 00:53:29 +0000
committerdrh <drh@noemail.net>2019-08-17 00:53:29 +0000
commit217ca657d82f2324d6c5a97598bf4f77ebbb1fe7 (patch)
tree2d6db295d13828d0624f70b99e6d476e93569f1b /src
parentcc5979dbd384049c1efef847e5cc22082191024b (diff)
parent42d2fce7f5b5e5776f3e881b4685deae2e0266ff (diff)
downloadsqlite-217ca657d82f2324d6c5a97598bf4f77ebbb1fe7.tar.gz
sqlite-217ca657d82f2324d6c5a97598bf4f77ebbb1fe7.zip
The SQLITE_DIRECTONLY flag, when added to sqlite3_create_function() prevents
the function from being used inside a trigger or view. FossilOrigin-Name: de767376987f7668b0770c4920f1532e341b5a27f797d69c0f5e92b87d036170
Diffstat (limited to 'src')
-rw-r--r--src/attach.c1
-rw-r--r--src/main.c4
-rw-r--r--src/resolve.c9
-rw-r--r--src/sqlite.h.in13
-rw-r--r--src/sqliteInt.h63
-rw-r--r--src/tclsqlite.c14
-rw-r--r--src/treeview.c6
7 files changed, 73 insertions, 37 deletions
diff --git a/src/attach.c b/src/attach.c
index 55e0eb536..61f169ed7 100644
--- a/src/attach.c
+++ b/src/attach.c
@@ -560,6 +560,7 @@ int sqlite3FixExpr(
Expr *pExpr /* The expression to be fixed to one database */
){
while( pExpr ){
+ ExprSetProperty(pExpr, EP_Indirect);
if( pExpr->op==TK_VARIABLE ){
if( pFix->pParse->db->init.busy ){
pExpr->op = TK_NULL;
diff --git a/src/main.c b/src/main.c
index 79a17e5a5..a8c1d4dc6 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1718,7 +1718,8 @@ int sqlite3CreateFunc(
}
assert( SQLITE_FUNC_CONSTANT==SQLITE_DETERMINISTIC );
- extraFlags = enc & SQLITE_DETERMINISTIC;
+ assert( SQLITE_FUNC_DIRECT==SQLITE_DIRECTONLY );
+ extraFlags = enc & (SQLITE_DETERMINISTIC|SQLITE_DIRECTONLY);
enc &= (SQLITE_FUNC_ENCMASK|SQLITE_ANY);
#ifndef SQLITE_OMIT_UTF16
@@ -1781,6 +1782,7 @@ int sqlite3CreateFunc(
p->u.pDestructor = pDestructor;
p->funcFlags = (p->funcFlags & SQLITE_FUNC_ENCMASK) | extraFlags;
testcase( p->funcFlags & SQLITE_DETERMINISTIC );
+ testcase( p->funcFlags & SQLITE_DIRECTONLY );
p->xSFunc = xSFunc ? xSFunc : xStep;
p->xFinalize = xFinal;
p->xValue = xValue;
diff --git a/src/resolve.c b/src/resolve.c
index 31600382f..ab2266409 100644
--- a/src/resolve.c
+++ b/src/resolve.c
@@ -823,6 +823,15 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
** SQL is being compiled using sqlite3NestedParse() */
no_such_func = 1;
pDef = 0;
+ }else
+ if( (pDef->funcFlags & SQLITE_FUNC_DIRECT)!=0
+ && ExprHasProperty(pExpr, EP_Indirect)
+ && !IN_RENAME_OBJECT
+ ){
+ /* Functions tagged with SQLITE_DIRECTONLY may not be used
+ ** inside of triggers and views */
+ sqlite3ErrorMsg(pParse, "%s() prohibited in triggers and views",
+ pDef->zName);
}
}
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index e0d02b272..ed5e2922c 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -4860,6 +4860,9 @@ int sqlite3_reset(sqlite3_stmt *pStmt);
** function that is not deterministic. The SQLite query planner is able to
** perform additional optimizations on deterministic functions, so use
** of the [SQLITE_DETERMINISTIC] flag is recommended where possible.
+** ^The fourth parameter may also optionally include the [SQLITE_DIRECTONLY]
+** flag, which if present prevents the function from being invoked from
+** within VIEWs or TRIGGERs.
**
** ^(The fifth parameter is an arbitrary pointer. The implementation of the
** function can gain access to this pointer using [sqlite3_user_data()].)^
@@ -4977,8 +4980,16 @@ int sqlite3_create_window_function(
** [SQLITE_UTF8 | preferred text encoding] as the fourth argument
** to [sqlite3_create_function()], [sqlite3_create_function16()], or
** [sqlite3_create_function_v2()].
+**
+** The SQLITE_DETERMINISTIC flag means that the new function will always
+** maps the same inputs into the same output. The abs() function is
+** deterministic, for example, but randomblob() is not.
+**
+** The SQLITE_DIRECTONLY flag means that the function may only be invoked
+** from top-level SQL, and cannot be used in VIEWs or TRIGGERs.
*/
-#define SQLITE_DETERMINISTIC 0x800
+#define SQLITE_DETERMINISTIC 0x000000800
+#define SQLITE_DIRECTONLY 0x000080000
/*
** CAPI3REF: Deprecated Functions
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 07e241a1c..552a435c9 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -1664,6 +1664,7 @@ struct FuncDestructor {
** SQLITE_FUNC_LENGTH == OPFLAG_LENGTHARG
** SQLITE_FUNC_TYPEOF == OPFLAG_TYPEOFARG
** SQLITE_FUNC_CONSTANT == SQLITE_DETERMINISTIC from the API
+** SQLITE_FUNC_DIRECT == SQLITE_DIRECTONLY from the API
** SQLITE_FUNC_ENCMASK depends on SQLITE_UTF* macros in the API
*/
#define SQLITE_FUNC_ENCMASK 0x0003 /* SQLITE_UTF8, SQLITE_UTF16BE or UTF16LE */
@@ -1684,6 +1685,7 @@ struct FuncDestructor {
#define SQLITE_FUNC_OFFSET 0x8000 /* Built-in sqlite_offset() function */
#define SQLITE_FUNC_WINDOW 0x00010000 /* Built-in window-only function */
#define SQLITE_FUNC_INTERNAL 0x00040000 /* For use by NestedParse() only */
+#define SQLITE_FUNC_DIRECT 0x00080000 /* Not for use in TRIGGERs or VIEWs */
/*
** The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are
@@ -2496,36 +2498,37 @@ struct Expr {
** EP_Agg == NC_HasAgg == SF_HasAgg
** EP_Win == NC_HasWin
*/
-#define EP_FromJoin 0x000001 /* Originates in ON/USING clause of outer join */
-#define EP_Distinct 0x000002 /* Aggregate function with DISTINCT keyword */
-#define EP_HasFunc 0x000004 /* Contains one or more functions of any kind */
-#define EP_FixedCol 0x000008 /* TK_Column with a known fixed value */
-#define EP_Agg 0x000010 /* Contains one or more aggregate functions */
-#define EP_VarSelect 0x000020 /* pSelect is correlated, not constant */
-#define EP_DblQuoted 0x000040 /* token.z was originally in "..." */
-#define EP_InfixFunc 0x000080 /* True for an infix function: LIKE, GLOB, etc */
-#define EP_Collate 0x000100 /* Tree contains a TK_COLLATE operator */
-#define EP_Generic 0x000200 /* Ignore COLLATE or affinity on this tree */
-#define EP_IntValue 0x000400 /* Integer value contained in u.iValue */
-#define EP_xIsSelect 0x000800 /* x.pSelect is valid (otherwise x.pList is) */
-#define EP_Skip 0x001000 /* Operator does not contribute to affinity */
-#define EP_Reduced 0x002000 /* Expr struct EXPR_REDUCEDSIZE bytes only */
-#define EP_TokenOnly 0x004000 /* Expr struct EXPR_TOKENONLYSIZE bytes only */
-#define EP_Win 0x008000 /* Contains window functions */
-#define EP_MemToken 0x010000 /* Need to sqlite3DbFree() Expr.zToken */
-#define EP_NoReduce 0x020000 /* Cannot EXPRDUP_REDUCE this Expr */
-#define EP_Unlikely 0x040000 /* unlikely() or likelihood() function */
-#define EP_ConstFunc 0x080000 /* A SQLITE_FUNC_CONSTANT or _SLOCHNG function */
-#define EP_CanBeNull 0x100000 /* Can be null despite NOT NULL constraint */
-#define EP_Subquery 0x200000 /* Tree contains a TK_SELECT operator */
-#define EP_Alias 0x400000 /* Is an alias for a result set column */
-#define EP_Leaf 0x800000 /* Expr.pLeft, .pRight, .u.pSelect all NULL */
-#define EP_WinFunc 0x1000000 /* TK_FUNCTION with Expr.y.pWin set */
-#define EP_Subrtn 0x2000000 /* Uses Expr.y.sub. TK_IN, _SELECT, or _EXISTS */
-#define EP_Quoted 0x4000000 /* TK_ID was originally quoted */
-#define EP_Static 0x8000000 /* Held in memory not obtained from malloc() */
-#define EP_IsTrue 0x10000000 /* Always has boolean value of TRUE */
-#define EP_IsFalse 0x20000000 /* Always has boolean value of FALSE */
+#define EP_FromJoin 0x000001 /* Originates in ON/USING clause of outer join */
+#define EP_Distinct 0x000002 /* Aggregate function with DISTINCT keyword */
+#define EP_HasFunc 0x000004 /* Contains one or more functions of any kind */
+#define EP_FixedCol 0x000008 /* TK_Column with a known fixed value */
+#define EP_Agg 0x000010 /* Contains one or more aggregate functions */
+#define EP_VarSelect 0x000020 /* pSelect is correlated, not constant */
+#define EP_DblQuoted 0x000040 /* token.z was originally in "..." */
+#define EP_InfixFunc 0x000080 /* True for an infix function: LIKE, GLOB, etc */
+#define EP_Collate 0x000100 /* Tree contains a TK_COLLATE operator */
+#define EP_Generic 0x000200 /* Ignore COLLATE or affinity on this tree */
+#define EP_IntValue 0x000400 /* Integer value contained in u.iValue */
+#define EP_xIsSelect 0x000800 /* x.pSelect is valid (otherwise x.pList is) */
+#define EP_Skip 0x001000 /* Operator does not contribute to affinity */
+#define EP_Reduced 0x002000 /* Expr struct EXPR_REDUCEDSIZE bytes only */
+#define EP_TokenOnly 0x004000 /* Expr struct EXPR_TOKENONLYSIZE bytes only */
+#define EP_Win 0x008000 /* Contains window functions */
+#define EP_MemToken 0x010000 /* Need to sqlite3DbFree() Expr.zToken */
+#define EP_NoReduce 0x020000 /* Cannot EXPRDUP_REDUCE this Expr */
+#define EP_Unlikely 0x040000 /* unlikely() or likelihood() function */
+#define EP_ConstFunc 0x080000 /* A SQLITE_FUNC_CONSTANT or _SLOCHNG function */
+#define EP_CanBeNull 0x100000 /* Can be null despite NOT NULL constraint */
+#define EP_Subquery 0x200000 /* Tree contains a TK_SELECT operator */
+#define EP_Alias 0x400000 /* Is an alias for a result set column */
+#define EP_Leaf 0x800000 /* Expr.pLeft, .pRight, .u.pSelect all NULL */
+#define EP_WinFunc 0x1000000 /* TK_FUNCTION with Expr.y.pWin set */
+#define EP_Subrtn 0x2000000 /* Uses Expr.y.sub. TK_IN, _SELECT, or _EXISTS */
+#define EP_Quoted 0x4000000 /* TK_ID was originally quoted */
+#define EP_Static 0x8000000 /* Held in memory not obtained from malloc() */
+#define EP_IsTrue 0x10000000 /* Always has boolean value of TRUE */
+#define EP_IsFalse 0x20000000 /* Always has boolean value of FALSE */
+#define EP_Indirect 0x40000000 /* Contained within a TRIGGER or a VIEW */
/*
** The EP_Propagate mask is a set of properties that automatically propagate
diff --git a/src/tclsqlite.c b/src/tclsqlite.c
index 8b32bf82d..80a057262 100644
--- a/src/tclsqlite.c
+++ b/src/tclsqlite.c
@@ -2809,10 +2809,16 @@ deserialize_error:
}
/*
- ** $db function NAME [-argcount N] [-deterministic] SCRIPT
+ ** $db function NAME [OPTIONS] SCRIPT
**
** Create a new SQL function called NAME. Whenever that function is
** called, invoke SCRIPT to evaluate the function.
+ **
+ ** Options:
+ ** --argcount N Function has exactly N arguments
+ ** --deterministic The function is pure
+ ** --directonly Prohibit use inside triggers and views
+ ** --returntype TYPE Specify the return type of the function
*/
case DB_FUNCTION: {
int flags = SQLITE_UTF8;
@@ -2845,6 +2851,9 @@ deserialize_error:
if( n>1 && strncmp(z, "-deterministic",n)==0 ){
flags |= SQLITE_DETERMINISTIC;
}else
+ if( n>1 && strncmp(z, "-directonly",n)==0 ){
+ flags |= SQLITE_DIRECTONLY;
+ }else
if( n>1 && strncmp(z, "-returntype", n)==0 ){
const char *azType[] = {"integer", "real", "text", "blob", "any", 0};
assert( SQLITE_INTEGER==1 && SQLITE_FLOAT==2 && SQLITE_TEXT==3 );
@@ -2860,7 +2869,8 @@ deserialize_error:
eType++;
}else{
Tcl_AppendResult(interp, "bad option \"", z,
- "\": must be -argcount, -deterministic or -returntype", (char*)0
+ "\": must be -argcount, -deterministic, -directonly,"
+ " or -returntype", (char*)0
);
return TCL_ERROR;
}
diff --git a/src/treeview.c b/src/treeview.c
index 753f21489..6dfdccd7e 100644
--- a/src/treeview.c
+++ b/src/treeview.c
@@ -557,10 +557,10 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
#endif
}
if( pExpr->op==TK_AGG_FUNCTION ){
- sqlite3TreeViewLine(pView, "AGG_FUNCTION%d %Q",
- pExpr->op2, pExpr->u.zToken);
+ sqlite3TreeViewLine(pView, "AGG_FUNCTION%d %Q%s",
+ pExpr->op2, pExpr->u.zToken, zFlgs);
}else{
- sqlite3TreeViewLine(pView, "FUNCTION %Q", pExpr->u.zToken);
+ sqlite3TreeViewLine(pView, "FUNCTION %Q%s", pExpr->u.zToken, zFlgs);
}
if( pFarg ){
sqlite3TreeViewExprList(pView, pFarg, pWin!=0, 0);