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: 767597cc116079bedcf84c4d5d2e406de3182cc60f3a89da38bb82ab0c1e9444
This commit is contained in:
23
manifest
23
manifest
@@ -1,5 +1,5 @@
|
||||
C Handle\stemp\striggers\sattached\sto\sdatabases\sclobbered\sby\ssqlite3_deserialize()\sin\sthe\ssame\sway\sas\sthose\sattached\sto\sDETACHed\sdatabases.
|
||||
D 2026-10-05T18:11:38.016
|
||||
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:14:26.869
|
||||
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
@@ -692,7 +692,7 @@ F src/date.c 61e92f1f7e2e88e1cd91e91dc69eb2b2854e7877254470f9fabd776bfac922b8
|
||||
F src/dbpage.c 98c716bc5c0c70af4e7934bfcddd707f14e78b5d4cf1e0602a07b485e1af2e74
|
||||
F src/dbstat.c 73362c0df0f40ad5523a6f5501224959d0976757b511299bf892313e79d14f5c
|
||||
F src/delete.c 1f2268d6fe3c78fc1bf794ba65d7026498b78e2342ffaf85825dedae546e6fde
|
||||
F src/expr.c a7b8c6f9e8f63de44a46e76304ddbebf59c2a423ddc8c3ec31a691303e780078
|
||||
F src/expr.c 008844c5f099b2da02b0112dc00dc4c6dad670ea806e6c7bf54219f4702cb577
|
||||
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
||||
F src/fkey.c 931f74cec1dc8038a0217ef340c91ce147dd1bbed08dc40c47ee0ec6edfffb08
|
||||
F src/func.c 03d6ae4f1b5ccdf44b68691ce7cb6353cf3aa5984fb75d69dd41b5b21031e836
|
||||
@@ -746,7 +746,7 @@ F src/shell.c.in 6d65129dc4a24a38a22e044eeafffbd70cd74f95561ab05a8fb1d71ab3d31cf
|
||||
F src/sqlite.h.in 17f32e2b049e704f85a27a6571917c05e6f3c812ee867eb0ba5614ee9cb566cd
|
||||
F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479
|
||||
F src/sqlite3ext.h 1b7a0ee438bb5c2896d0609c537e917d8057b3340f6ad004d2de44f03e3d3cca
|
||||
F src/sqliteInt.h f71bc80528ec06ac877657f80f0171458fda685cd4a2bf1212627edcf88c8d3d
|
||||
F src/sqliteInt.h a1cdabe460b385841835487d10c08d533d644097eeedf29035ce0a644cd01785
|
||||
F src/sqliteLimit.h c70656b67ab5b96741a8f1c812bdd80c81f2b1c1e443d0cc3ea8c33bb1f1a092
|
||||
F src/status.c 7565d63a79aa2f326339a24a0461a60096d0bd2bce711fefb50b5c89335f3592
|
||||
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
|
||||
@@ -765,7 +765,7 @@ F src/test_backup.c a2bfd90d2ff2511b8635507bdb30fa9b605ade19c16b533066cae3077f5b
|
||||
F src/test_bestindex.c d75fad21369d80910238032bcf8d9ca1f2bffda13c1ceec63bfbb7f704448b15
|
||||
F src/test_blob.c 77b994e17f2c87055f44fd96c9a206c5a7155bae2cda2769af60c2f3582f962c
|
||||
F src/test_btree.c 28283787d32b8fa953eb77412ad0de2c9895260e4e5bd5a94b3c7411664f90d5
|
||||
F src/test_config.c e02566c2c4ee2916324ce17123a798b47663cead2de546cfbd71d8cddb46bb26
|
||||
F src/test_config.c 7a0c290cd51068c9eaa679192b8cbf93bd6cd26c57c3ad9ac0a6c5d27a6e4a57
|
||||
F src/test_delete.c d0e8f6dc55cfc98a7c27c057fb88d512260564bf0b611482656c68b8f7f401ed
|
||||
F src/test_demovfs.c 3efa2adf4f21e10d95521721687d5ca047aea91fa62dd8cc22ac9e5a9c942383
|
||||
F src/test_devsym.c 649434ed34d0b03fbd5a6b42df80f0f9a7e53f94dd1710aad5dd8831e91c4e86
|
||||
@@ -1578,6 +1578,7 @@ F test/rowvaluefault.test 963ae9cdaed30a85a29668dd514e639f3556cae903ee9f172ea972
|
||||
F test/rowvaluevtab.test cd9747bb3f308086944c07968f547ad6b05022e698d80b9ffbdfe09ce0b8da6f
|
||||
F test/rtree.test 0c8d9dd458d6824e59683c19ab2ffa9ef946f798
|
||||
F test/run-wordcount.sh 891e89c4c2d16e629cd45951d4ed899ad12afc09
|
||||
F test/sandbox1.sql 35ec3792bde234d03b446a0d5551dba210d4a7bdfb3ee64cd4b7d18cdbd2a613
|
||||
F test/savepoint.test 6e9804a17767f08432c7a5e738b9a8f4b891d243110b63d3a41d270d3d1378ec
|
||||
F test/savepoint2.test 9b8543940572a2f01a18298c3135ad0c9f4f67d7
|
||||
F test/savepoint4.test c8f8159ade6d2acd9128be61e1230f1c1edc6cc0
|
||||
@@ -2149,7 +2150,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 68f3ee9e2e6a06524b25d79b5b61a883053466080a39da59e0a0697f0c4d9a3b x
|
||||
F tool/mkctimec.tcl f75a9f8b4561af37a45f7c2ea8c232b8a0f04f4489e5c0762f4211365942f0d5 x
|
||||
F tool/mkfptab.c 24ea40113f96584caca3f6dd06b4ad5adffa0f39023910cb83fa7ef2ffa9b0ba
|
||||
F tool/mkkeywordhash.c 82d5af1d0e677900739fba59155cddac172d8c712c2d91ab73d6e6bcb30060f0
|
||||
F tool/mkmsvcmin.tcl d76c45efda1cce2d4005bcea7b8a22bb752e3256009f331120fb4fecb14ebb7a
|
||||
@@ -2207,9 +2208,9 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee
|
||||
F tool/warnings.sh a554d13f6e5cf3760f041b87939e3d616ec6961859c3245e8ef701d1eafc2ca2
|
||||
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
||||
F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c
|
||||
P 794e3e0fe386284327c3a58f7071087ab9d3580aae44efe835663597f74e39c2
|
||||
Q +84c773fcc2f785346fd12e8a17ac45f9068797d9629ddc367318994b6fed421b
|
||||
R 777a55f2c40fa66f94e2eb9c2dcce8af
|
||||
U dan
|
||||
Z 386fc9eedeb6167cb33d766410e272b8
|
||||
P 872587e1567020e32c6c833b40818ba88a0b02de97b9db7b16daae08762508a8
|
||||
Q +035fd52d54a6f8f9c8276a48f466d660832d46d05a02b3ee4a41959922a4bc22
|
||||
R 5a6d9e1f449ed3cd72c95e119869a5ff
|
||||
U drh
|
||||
Z 8bb1081a7b6f8a6403b0d627cac3ffd7
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
branch branch-3.53
|
||||
tag branch-3.53
|
||||
branch branch-3.53-sandbox-func
|
||||
tag branch-3.53-sandbox-func
|
||||
|
||||
@@ -1 +1 @@
|
||||
872587e1567020e32c6c833b40818ba88a0b02de97b9db7b16daae08762508a8
|
||||
767597cc116079bedcf84c4d5d2e406de3182cc60f3a89da38bb82ab0c1e9444
|
||||
|
||||
62
src/expr.c
62
src/expr.c
@@ -1162,6 +1162,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.
|
||||
@@ -1175,6 +1211,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 */
|
||||
@@ -1182,17 +1224,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;
|
||||
}
|
||||
|
||||
@@ -2847,7 +2892,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
|
||||
@@ -2868,7 +2913,8 @@ int sqlite3ExprIsConstantOrFunction(Expr *p, u8 isInit){
|
||||
return exprIsConst(0, p, 4+isInit);
|
||||
}
|
||||
|
||||
#ifdef SQLITE_ENABLE_CURSOR_HINTS
|
||||
#if defined(SQLITE_ENABLE_CURSOR_HINTS) \
|
||||
|| defined(SQLITE_ENABLE_SANDBOX_FUNCTION)
|
||||
/*
|
||||
** Walk an expression tree. Return 1 if the expression contains a
|
||||
** subquery of some kind. Return 0 if there are no subqueries.
|
||||
|
||||
@@ -5186,7 +5186,8 @@ int sqlite3ExprIsConstant(Parse*,Expr*);
|
||||
int sqlite3ExprIsConstantOrFunction(Expr*, u8);
|
||||
int sqlite3ExprIsConstantOrGroupBy(Parse*, Expr*, ExprList*);
|
||||
int sqlite3ExprIsSingleTableConstraint(Expr*,const SrcList*,int,int);
|
||||
#ifdef SQLITE_ENABLE_CURSOR_HINTS
|
||||
#if defined(SQLITE_ENABLE_CURSOR_HINTS) \
|
||||
|| defined(SQLITE_ENABLE_SANDBOX_FUNCTION)
|
||||
int sqlite3ExprContainsSubquery(Expr*);
|
||||
#endif
|
||||
int sqlite3ExprIsInteger(const Expr*, int*, Parse*);
|
||||
|
||||
@@ -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