mirror of
https://github.com/sqlite/sqlite.git
synced 2026-10-23 21:49:02 +03:00
Initial implementation of the experimental sandbox(N1,E,N2) function.
The function resolves (by transforming the AST) to the expression E if N1 and N2 are the same constant expression. Requires the -DSQLITE_ENABLE_SANDBOX_FUNCTION compile-time option. FossilOrigin-Name: 035fd52d54a6f8f9c8276a48f466d660832d46d05a02b3ee4a41959922a4bc22
This commit is contained in:
20
manifest
20
manifest
@@ -1,5 +1,5 @@
|
||||
C Fix\sindexes\son\stypeless\sgenerated\scolumns\sthat\spull\sfrom\sREAL\scolumns\sso\nthat\sthey\scorrectly\sreturn\sREAL\svalues.\n[bugs:/info/2026-10-14T17:34:30Z|Bug\s2026-10-14T17:34:30Z].
|
||||
D 2026-10-14T18:39:44.984
|
||||
C Initial\simplementation\sof\sthe\sexperimental\ssandbox(N1,E,N2)\sfunction.\nThe\sfunction\sresolves\s(by\stransforming\sthe\sAST)\sto\sthe\sexpression\sE\sif\nN1\sand\sN2\sare\sthe\ssame\sconstant\sexpression.\s\sRequires\sthe\n-DSQLITE_ENABLE_SANDBOX_FUNCTION\scompile-time\soption.
|
||||
D 2026-10-14T20:06:21.237
|
||||
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
@@ -755,7 +755,7 @@ F src/date.c 080641f59097d14fc7341f8bc0458d273b3a62d8381916db8ccbc89c2aae07b3
|
||||
F src/dbpage.c ec8590c5e7a564cef28ca3c6156521316a4d26cb572a34841b0bcb26b67b3f97
|
||||
F src/dbstat.c 34d4e825fbf763640ce3dbc56910ab080495ef4a6efb48b2b1852a43d43763fc
|
||||
F src/delete.c f3f07c1fb6ac87fac2425d48fd40ecb2f24a4495a9966f5a939668d3576916c8
|
||||
F src/expr.c e4097826bbb853e233c1f4f27fd93f2ebc48104eb88d7ac9ba0541ddb631d5c7
|
||||
F src/expr.c 5ba49ab1ace9fff5a551b71c148945e22cffc4de008eef678f3acab688a31028
|
||||
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
||||
F src/fkey.c 26788ae6c785d70f9829c4176e9764447014fc73e6ba31e9f1881720a64ae7f1
|
||||
F src/func.c 9372b65d0e5e6fc9fff7c4fc20558c5e68babcc7f54f033bba67da39f47acc37
|
||||
@@ -828,7 +828,7 @@ F src/test_backup.c a2bfd90d2ff2511b8635507bdb30fa9b605ade19c16b533066cae3077f5b
|
||||
F src/test_bestindex.c d75fad21369d80910238032bcf8d9ca1f2bffda13c1ceec63bfbb7f704448b15
|
||||
F src/test_blob.c 3a946319c1b062a58d249c67be099c3bc1ec52f2e6ba23b1867699f0b8189ac2
|
||||
F src/test_btree.c 28283787d32b8fa953eb77412ad0de2c9895260e4e5bd5a94b3c7411664f90d5
|
||||
F src/test_config.c 45b83ce7981fd01c58e85b67955bc6a344da5abfb4db1c3f2ba6dcc7adc85d83
|
||||
F src/test_config.c ff851c26abc3e994b1a21b4b410e165538c2b5ee990cf4a171ef32d07e626c1f
|
||||
F src/test_delete.c 4abfe8cb9da1f7faf725b18ae93391485e8d8c7df0bad9dcb68f6066add5b8c3
|
||||
F src/test_demovfs.c 3efa2adf4f21e10d95521721687d5ca047aea91fa62dd8cc22ac9e5a9c942383
|
||||
F src/test_devsym.c 649434ed34d0b03fbd5a6b42df80f0f9a7e53f94dd1710aad5dd8831e91c4e86
|
||||
@@ -1654,6 +1654,7 @@ F test/rowvaluevtab.test cd9747bb3f308086944c07968f547ad6b05022e698d80b9ffbdfe09
|
||||
F test/rtree.test 0c8d9dd458d6824e59683c19ab2ffa9ef946f798
|
||||
F test/run-wordcount.sh 891e89c4c2d16e629cd45951d4ed899ad12afc09
|
||||
F test/safemode.sql 8373efb03c49a9ceae81fa6d9216c69d7e8573351b273b3f82ae2c5ad9305f99
|
||||
F test/sandbox1.sql 35ec3792bde234d03b446a0d5551dba210d4a7bdfb3ee64cd4b7d18cdbd2a613
|
||||
F test/savepoint.test 6e9804a17767f08432c7a5e738b9a8f4b891d243110b63d3a41d270d3d1378ec
|
||||
F test/savepoint2.test 9b8543940572a2f01a18298c3135ad0c9f4f67d7
|
||||
F test/savepoint4.test c8f8159ade6d2acd9128be61e1230f1c1edc6cc0
|
||||
@@ -2230,7 +2231,7 @@ F tool/mkamalzip.tcl 8aa5ebe7973c8b8774062d34e15fea9815c4cc2ceea3a9b184695f00591
|
||||
F tool/mkautoconfamal.sh 06fbe090b81c24e592c1f22b404334f805ba74d482a9260f2ac81e6f3d3386d8
|
||||
F tool/mkccode.tcl c42a8f8cf78f92e83795d5447460dbce7aaf78a3bbf9082f1507dc71a3665f3c x
|
||||
F tool/mkcombo.tcl 2a5189b219c4a495e1ff7fc980bd568d3cfb82ae9d50c84e77f7a161e96fc132
|
||||
F tool/mkctimec.tcl 85ce722e10f81368bc42fb194fe6af450f7f0ef9199b706cbc02b5b484ce3d4a x
|
||||
F tool/mkctimec.tcl 4116e0190e8fc1016a922d6dfd33dcf936d9ee57e0ed28fd788dc238c909729b x
|
||||
F tool/mkfptab.c 24ea40113f96584caca3f6dd06b4ad5adffa0f39023910cb83fa7ef2ffa9b0ba
|
||||
F tool/mkkeywordhash.c 82d5af1d0e677900739fba59155cddac172d8c712c2d91ab73d6e6bcb30060f0
|
||||
F tool/mkmsvcmin.tcl d76c45efda1cce2d4005bcea7b8a22bb752e3256009f331120fb4fecb14ebb7a
|
||||
@@ -2289,8 +2290,11 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee
|
||||
F tool/warnings.sh a554d13f6e5cf3760f041b87939e3d616ec6961859c3245e8ef701d1eafc2ca2
|
||||
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
||||
F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c
|
||||
P eaf646e376a5a3e10a874ed1c07ca1382f0ccb7cdf1cc963697638a54b98c779
|
||||
R cd5e05e09f37035495964650d20d3282
|
||||
P 7408f90ecc2dd26aceb52f92de78b8e1521cb5a294d3231fd32a903afe1db41d
|
||||
R 2f6a7a6115fad7c13aff2db60c940aac
|
||||
T *branch * sandbox-func
|
||||
T *sym-sandbox-func *
|
||||
T -sym-trunk *
|
||||
U drh
|
||||
Z 60c70d9c1707258a8e85a246e04bf473
|
||||
Z f504d7ec1dca2d8a14e6b845203e3501
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
branch trunk
|
||||
tag trunk
|
||||
branch sandbox-func
|
||||
tag sandbox-func
|
||||
|
||||
@@ -1 +1 @@
|
||||
7408f90ecc2dd26aceb52f92de78b8e1521cb5a294d3231fd32a903afe1db41d
|
||||
035fd52d54a6f8f9c8276a48f466d660832d46d05a02b3ee4a41959922a4bc22
|
||||
|
||||
59
src/expr.c
59
src/expr.c
@@ -1181,6 +1181,42 @@ Expr *sqlite3ExprAnd(Parse *pParse, Expr *pLeft, Expr *pRight){
|
||||
}
|
||||
}
|
||||
|
||||
#if SQLITE_ENABLE_SANDBOX_FUNCTION+0>0
|
||||
/*
|
||||
** Magical SQL function: sandbox(N1, E, N2)
|
||||
**
|
||||
** This function is magical in that it is evaluated at compile-time: No
|
||||
** bytecode is generated. Instead sandbox() transforms the AST.
|
||||
**
|
||||
** The AST for the sandbox() itself is replaced with the middle expression E
|
||||
** if and only if all of the following are true:
|
||||
**
|
||||
** * N1 and N2 must compare equal using sqlite3ExprCompare().
|
||||
**
|
||||
** * N1 (and hence N2 also, due to the prior constrant) must both be
|
||||
** a constant expression. It cannot use variables or table references.
|
||||
**
|
||||
** * E does not contain any subqueries - either scalar subqueries or
|
||||
** "EXISTS" expressions or IN operators where the RHS is a subquery.
|
||||
*/
|
||||
static SQLITE_NOINLINE Expr *exprSandbox(Parse *pParse, Expr *pOrig){
|
||||
struct ExprList_item *a = pOrig->x.pList->a;
|
||||
Expr *pMid = a[1].pExpr;
|
||||
if( sqlite3ExprCompare(pParse, a[0].pExpr, a[2].pExpr, 0)!=0
|
||||
|| sqlite3ExprIsConstant(pParse, a[0].pExpr)==0
|
||||
|| sqlite3ExprIsConstantOrFunction(a[0].pExpr, 0)==0
|
||||
|| sqlite3ExprContainsSubquery(pMid)
|
||||
){
|
||||
sqlite3ErrorMsg(pParse, "sandbox violation");
|
||||
return pOrig;
|
||||
}
|
||||
a[1] = a[2];
|
||||
pOrig->x.pList->nExpr = 2;
|
||||
sqlite3ExprDelete(pParse->db, pOrig);
|
||||
return pMid;
|
||||
}
|
||||
#endif /* SQLITE_ENABLE_SANDBOX_FUNCTION */
|
||||
|
||||
/*
|
||||
** Construct a new expression node for a function with multiple
|
||||
** arguments.
|
||||
@@ -1194,6 +1230,12 @@ Expr *sqlite3ExprFunction(
|
||||
Expr *pNew;
|
||||
sqlite3 *db = pParse->db;
|
||||
assert( pToken );
|
||||
if( pList
|
||||
&& pList->nExpr > pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG]
|
||||
&& !pParse->nested
|
||||
){
|
||||
sqlite3ErrorMsg(pParse, "too many arguments on function %T", pToken);
|
||||
}
|
||||
pNew = sqlite3ExprAlloc(db, TK_FUNCTION, pToken, 1);
|
||||
if( pNew==0 ){
|
||||
sqlite3ExprListDelete(db, pList); /* Avoid memory leak when malloc fails */
|
||||
@@ -1201,17 +1243,20 @@ Expr *sqlite3ExprFunction(
|
||||
}
|
||||
assert( !ExprHasProperty(pNew, EP_InnerON|EP_OuterON) );
|
||||
pNew->w.iOfst = (int)(pToken->z - pParse->zTail);
|
||||
if( pList
|
||||
&& pList->nExpr > pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG]
|
||||
&& !pParse->nested
|
||||
){
|
||||
sqlite3ErrorMsg(pParse, "too many arguments on function %T", pToken);
|
||||
}
|
||||
pNew->x.pList = pList;
|
||||
ExprSetProperty(pNew, EP_HasFunc);
|
||||
assert( ExprUseXList(pNew) );
|
||||
sqlite3ExprSetHeightAndFlags(pParse, pNew);
|
||||
if( eDistinct==SF_Distinct ) ExprSetProperty(pNew, EP_Distinct);
|
||||
#if SQLITE_ENABLE_SANDBOX_FUNCTION+0>0
|
||||
if( pToken->n==7
|
||||
&& pList!=0
|
||||
&& pList->nExpr==3
|
||||
&& sqlite3_strnicmp(pToken->z,"SANDBOX",7)==0
|
||||
){
|
||||
pNew = exprSandbox(pParse, pNew);
|
||||
}
|
||||
#endif /* SQLITE_ENABLE_SANDBOX_FUNCTION */
|
||||
return pNew;
|
||||
}
|
||||
|
||||
@@ -2901,7 +2946,7 @@ int sqlite3ExprIsConstantOrGroupBy(Parse *pParse, Expr *p, ExprList *pGroupBy){
|
||||
** in a CREATE TABLE statement. Return non-zero if the expression is
|
||||
** acceptable for use as a DEFAULT. That is to say, return non-zero if
|
||||
** the expression is constant or a function call with constant arguments.
|
||||
** Return and 0 if there are any variables.
|
||||
** Return 0 if there are any variables.
|
||||
**
|
||||
** isInit is true when parsing from sqlite_schema. isInit is false when
|
||||
** processing a new CREATE TABLE statement. When isInit is true, parameters
|
||||
|
||||
@@ -209,6 +209,12 @@ static void set_options(Tcl_Interp *interp){
|
||||
Tcl_SetVar2(interp, "sqlite_options", "preupdate", "0", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_ENABLE_SANDBOX_FUNCTION
|
||||
Tcl_SetVar2(interp, "sqlite_options", "sandbox", "1", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
Tcl_SetVar2(interp, "sqlite_options", "sandbox", "0", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_ENABLE_SNAPSHOT
|
||||
Tcl_SetVar2(interp, "sqlite_options", "snapshot", "1", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
|
||||
48
test/sandbox1.sql
Normal file
48
test/sandbox1.sql
Normal file
@@ -0,0 +1,48 @@
|
||||
# 2026-10-14
|
||||
#
|
||||
# Compile the CLI with -DSQLITE_ENABLE_SANDBOX_FUNCTION then run this
|
||||
# script to verify the sandbox() function.
|
||||
#
|
||||
CREATE TABLE t1(a,b,c,d);
|
||||
INSERT INTO t1 VALUES(1,2,3,4),('a','b','c','d'),(9,8,7,6);
|
||||
CREATE INDEX t1a ON t1(a);
|
||||
CREATE INDEX t1bc ON t1(b,c);
|
||||
CREATE TABLE t2(x,y,z);
|
||||
INSERT INTO t2 values(1,2,3),('x','y','z'),(1,0,-1);
|
||||
|
||||
.testcase 100
|
||||
SELECT * FROM t1, t2 WHERE sandbox(12345, a=x, 12346);
|
||||
.check --glob 'sandbox violation'
|
||||
.testcase 110
|
||||
SELECT * FROM t1, t2 WHERE sandbox(1, (SELECT 1)=x, 1);
|
||||
.check --glob 'sandbox violation'
|
||||
.testcase 120
|
||||
SELECT * FROM t1, t2 WHERE sandbox($abc, a=x, $abc);
|
||||
.check --glob 'sandbox violation'
|
||||
.testcase 130
|
||||
SELECT * FROM t1, t2 WHERE sandbox(2, a=x, 2, 4);
|
||||
.check --glob 'no such function: sandbox'
|
||||
.testcase 140
|
||||
SELECT * FROM t1, t2 WHERE sandbox(2, a=x) AND a=x;
|
||||
.check --glob 'no such function: sandbox'
|
||||
.testcase 150
|
||||
SELECT * FROM t1, t2 WHERE sandbox() AND a=x;
|
||||
.check --glob 'no such function: sandbox'
|
||||
|
||||
.testcase 200
|
||||
.eqp on
|
||||
.mode list --colsep , --rowsep ";"
|
||||
SELECT a, x FROM t1, t2 WHERE sandbox(3, b<>11 AND a=x AND y<>22, 3);
|
||||
.check <<END
|
||||
QUERY PLAN
|
||||
|--SCAN t2
|
||||
`--SEARCH t1 USING INDEX t1a (a=?)
|
||||
1,1;1,1;
|
||||
END
|
||||
|
||||
.testcase 210
|
||||
.eqp off
|
||||
.mode list --colsep ,
|
||||
SELECT count(*) FROM pragma_compile_options
|
||||
WHERE compile_options LIKE '%sandbox%';
|
||||
.check 1
|
||||
@@ -169,6 +169,7 @@ set boolean_defnil_options {
|
||||
SQLITE_ENABLE_QPSG
|
||||
SQLITE_ENABLE_RBU
|
||||
SQLITE_ENABLE_RTREE
|
||||
SQLITE_ENABLE_SANDBOX_FUNCTION
|
||||
SQLITE_ENABLE_SESSION
|
||||
SQLITE_ENABLE_SETLK_TIMEOUT
|
||||
SQLITE_ENABLE_SNAPSHOT
|
||||
|
||||
Reference in New Issue
Block a user