mirror of
https://github.com/sqlite/sqlite.git
synced 2026-10-23 21:49:02 +03:00
Fix the fsdir() table-valued function to better cope with
unreasonable LEVEL constraints. [bugs:/info/2026-10-21T10:49:41Z|Bug 2026-10-21T10:49:41Z] FossilOrigin-Name: 3e8932ebf2cec334b4867e0192d22b6de8102eda48f9f6e168fe5d2d24a8db0c
This commit is contained in:
@@ -962,13 +962,38 @@ static int fsdirFilter(
|
||||
assert( argc>i );
|
||||
pCur->zBase = (const char*)sqlite3_value_text(argv[i++]);
|
||||
}
|
||||
pCur->mxLvl = 1000000000;
|
||||
if( (idxNum & 0x0c)!=0 ){
|
||||
/* The LEVEL constraint is only used to limit the depth of the
|
||||
** search. SQLite still checks the constraint against every row, so
|
||||
** mxLvl may admit rows that do not match, but must never exclude
|
||||
** a row that does. Only entries with level<mxLvl are visited. */
|
||||
sqlite3_value *pMx;
|
||||
assert( argc>i );
|
||||
pCur->mxLvl = sqlite3_value_int(argv[i++]);
|
||||
if( idxNum & 0x08 ) pCur->mxLvl++;
|
||||
if( pCur->mxLvl<=0 ) pCur->mxLvl = 1000000000;
|
||||
}else{
|
||||
pCur->mxLvl = 1000000000;
|
||||
pMx = argv[i++];
|
||||
switch( sqlite3_value_type(pMx) ){
|
||||
case SQLITE_NULL: {
|
||||
/* No row can match a NULL constraint */
|
||||
pCur->mxLvl = 1;
|
||||
break;
|
||||
}
|
||||
case SQLITE_INTEGER:
|
||||
case SQLITE_FLOAT: {
|
||||
double r = sqlite3_value_double(pMx);
|
||||
if( r<1.0 ){
|
||||
pCur->mxLvl = 1;
|
||||
}else if( r<1.0e9 ){
|
||||
int iMx = (int)r;
|
||||
if( (idxNum & 0x08)!=0 || (double)iMx<r ) iMx++;
|
||||
pCur->mxLvl = iMx;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
/* TEXT or BLOB. Do not limit the search. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( pCur->zBase ){
|
||||
pCur->nBase = (int)strlen(pCur->zBase)+1;
|
||||
@@ -1001,7 +1026,11 @@ static int fsdirFilter(
|
||||
**
|
||||
** 0x01 The path value is supplied by argv[0]
|
||||
** 0x02 dir is in argv[1]
|
||||
** 0x04 maxdepth is in argv[1] or [2]
|
||||
** 0x04 LEVEL< bound is in argv[1] or [2]
|
||||
** 0x08 LEVEL<= or LEVEL= bound is in argv[1] or [2]
|
||||
**
|
||||
** The LEVEL constraint is never omitted. It is used only to limit the
|
||||
** depth of the directory search, and SQLite rechecks it for each row.
|
||||
*/
|
||||
static int fsdirBestIndex(
|
||||
sqlite3_vtab *tab,
|
||||
@@ -1012,7 +1041,6 @@ static int fsdirBestIndex(
|
||||
int idxDir = -1; /* Index in pIdxInfo->aConstraint of DIR= */
|
||||
int idxLevel = -1; /* Index in pIdxInfo->aConstraint of LEVEL< or <= */
|
||||
int idxLevelEQ = 0; /* 0x08 for LEVEL<= or LEVEL=. 0x04 for LEVEL< */
|
||||
int omitLevel = 0; /* omit the LEVEL constraint */
|
||||
int seenPath = 0; /* True if an unusable PATH= constraint is seen */
|
||||
int seenDir = 0; /* True if an unusable DIR= constraint is seen */
|
||||
const struct sqlite3_index_constraint *pConstraint;
|
||||
@@ -1044,7 +1072,6 @@ static int fsdirBestIndex(
|
||||
if( pConstraint->usable && idxLevel<0 ){
|
||||
idxLevel = i;
|
||||
idxLevelEQ = 0x08;
|
||||
omitLevel = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1057,11 +1084,9 @@ static int fsdirBestIndex(
|
||||
if( pConstraint->op==SQLITE_INDEX_CONSTRAINT_LE ){
|
||||
idxLevel = i;
|
||||
idxLevelEQ = 0x08;
|
||||
omitLevel = 1;
|
||||
}else if( pConstraint->op==SQLITE_INDEX_CONSTRAINT_LT ){
|
||||
idxLevel = i;
|
||||
idxLevelEQ = 0x04;
|
||||
omitLevel = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1088,7 +1113,6 @@ static int fsdirBestIndex(
|
||||
pIdxInfo->estimatedCost /= 1.0e4;
|
||||
}
|
||||
if( idxLevel>=0 ){
|
||||
pIdxInfo->aConstraintUsage[idxLevel].omit = omitLevel;
|
||||
pIdxInfo->aConstraintUsage[idxLevel].argvIndex = i++;
|
||||
pIdxInfo->idxNum |= idxLevelEQ;
|
||||
pIdxInfo->estimatedCost /= 1.0e4;
|
||||
|
||||
16
manifest
16
manifest
@@ -1,5 +1,5 @@
|
||||
C Ensure\sthat\sall\s(parent_key\s=\schild_key)\scomparisons\sperformed\sas\spart\sof\sforeign\skey\sprocessing\sare\sdone\susing\sthe\saffinity\sof\sthe\sparent\skey.\sReport\s[bugs:/info/2026-10-20T02:56:10Z\s|\s2026-10-20T02:56:10Z].
|
||||
D 2026-10-21T11:52:56.928
|
||||
C Fix\sthe\sfsdir()\stable-valued\sfunction\sto\sbetter\scope\swith\nunreasonable\sLEVEL\sconstraints.\n[bugs:/info/2026-10-21T10:49:41Z|Bug\s2026-10-21T10:49:41Z]
|
||||
D 2026-10-21T14:28:22.100
|
||||
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
@@ -379,7 +379,7 @@ F ext/misc/decimal.c 68e987966e4772efdb8df03e2bf253d02bae3254af29fd4a99d34fc6e6f
|
||||
F ext/misc/diskused.c 444139c01398df6f73e8a021c91e24d97d7914f5c1b49f55dd503abbca347c6e
|
||||
F ext/misc/eval.c d4ea2d9898fbe4d30d38ff675ee51958d3bb0601a145bade56dee8b8f438cc5b
|
||||
F ext/misc/explain.c 04c9270fd8cf93a9bceb12d2f5f67e3f09a4e58b3e0efe14d24531444d2fffdf
|
||||
F ext/misc/fileio.c 6bf2543ae190401f5fda74661c20387a450071eb5d17bfc05d3b45416bbedcb7
|
||||
F ext/misc/fileio.c 04a2ba5c4a1dc985315c302d7123dda0209860a5bfe4a5541d0faeac137196e8
|
||||
F ext/misc/fossildelta.c 0af6a5ef3db6bba299271c29b604489e4a5d9e75395c6b83460405a9ccf05c2a
|
||||
F ext/misc/fuzzer.c 32cef9a29864a1bc1329ccb6dfa613f197bb83491a7612c2ca2c83ee26cd8f14
|
||||
F ext/misc/ieee754.c 2901d08a586d00a1d3c0fd89e03c57ee9e2b5f013b0daab9e49c7a48a9d5946b
|
||||
@@ -2198,7 +2198,7 @@ F test/zeroblob.test 7b74cefc7b281dfa2b07cd237987fbe94b4a2037a7771e9e83f2d5f608b
|
||||
F test/zeroblobfault.test 861d8191a0d944dfebb3cb4d2c5b4e46a5a119eaec5a63dd996c2389f8063441
|
||||
F test/zerodamage.test 9c41628db7e8d9e8a0181e59ea5f189df311a9f6ce99cc376dc461f66db6f8dc
|
||||
F test/zipfile.test 88b8b8babbe24dd3c1e58e8f96685429029c283fbf54b6df07b145b66032de9a
|
||||
F test/zipfile2.test b43ff7de2ae9453b3d441ad62e357c67927dad9a5cdbea014596f46ff14c066a
|
||||
F test/zipfile2.test e4aaa5d3eea4d48f54f168d8739f2b8dc222a935b73eb8882efc4f861ffe354e
|
||||
F test/zipfilefault.test 44d4d7a7f7cca7521d569d7f71026b241d65a6b1757aa409c1a168827edbbc2c
|
||||
F tool/GetFile.cs 47852aa0d806fe47ed1ac5138bdce7f000fe87aaa7f28107d0cb1e26682aeb44
|
||||
F tool/GetTclKit.bat d84033c6a93dfe735d247f48ba00292a1cc284dcf69963e5e672444e04534bbf
|
||||
@@ -2295,8 +2295,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee
|
||||
F tool/warnings.sh a554d13f6e5cf3760f041b87939e3d616ec6961859c3245e8ef701d1eafc2ca2
|
||||
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
||||
F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c
|
||||
P decd49e6565bd5105e3b5cbe1067c8992582076a7c4e12cb6f3d089f38aba524
|
||||
R a84e136060b7946f27e7ae696367e34b
|
||||
U dan
|
||||
Z 340908e2de6a8df53446363a056624d5
|
||||
P feb6d3a3016d890fb1a8ca2a1752949b8adc0c06debb6ca305cacafc6b6edd10
|
||||
R 854fb1ab222ea4ef60886c214072ce9e
|
||||
U drh
|
||||
Z 937fcd40605458ba83a093198ece3d68
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
||||
@@ -1 +1 @@
|
||||
feb6d3a3016d890fb1a8ca2a1752949b8adc0c06debb6ca305cacafc6b6edd10
|
||||
3e8932ebf2cec334b4867e0192d22b6de8102eda48f9f6e168fe5d2d24a8db0c
|
||||
|
||||
@@ -373,4 +373,81 @@ if {[catch { load_static_extension db fileio }]==0} {
|
||||
} {65535}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Bug 7faad02e21dced4d. The LEVEL constraint on fsdir() must give the
|
||||
# same results as if it were not passed to xBestIndex, even for values
|
||||
# that are out of range, negative, NULL or non-integer.
|
||||
#
|
||||
if {[catch { load_static_extension db fileio }]==0} {
|
||||
forcedelete test_fsdir
|
||||
file mkdir test_fsdir/a/b/c
|
||||
foreach f {test_fsdir/x test_fsdir/a/y test_fsdir/a/b/z test_fsdir/a/b/c/w} {
|
||||
close [open $f w]
|
||||
}
|
||||
|
||||
set i 0
|
||||
foreach {w res} {
|
||||
{level<=2147483647} 8
|
||||
{level<=4294967296} 8
|
||||
{level<=4294967297} 8
|
||||
{level<0} 0
|
||||
{level<=-1} 0
|
||||
{level<=0} 0
|
||||
{level<1} 0
|
||||
{level<=1} 1
|
||||
{level<2} 1
|
||||
{level<=2} 3
|
||||
{level<2.5} 3
|
||||
{level<=2.5} 3
|
||||
{level<=NULL} 0
|
||||
{level<NULL} 0
|
||||
{level=NULL} 0
|
||||
{level<'x'} 8
|
||||
{level<x'00'} 8
|
||||
{level=3} 2
|
||||
{level=3.0} 2
|
||||
{level=3.5} 0
|
||||
{level=4294967299} 0
|
||||
} {
|
||||
incr i
|
||||
do_execsql_test 10.$i.1 "
|
||||
SELECT count(*) FROM fsdir('test_fsdir') WHERE $w
|
||||
" $res
|
||||
do_execsql_test 10.$i.2 "
|
||||
SELECT count(*) FROM fsdir('test_fsdir') WHERE +$w
|
||||
" $res
|
||||
}
|
||||
|
||||
# Check that the LEVEL constraint still limits the depth of the
|
||||
# search. Make directory test_fsdir/a/b/c (itself at level 4) unreadable.
|
||||
# Then queries that need the entries within it (level 5) fail, and
|
||||
# those that do not succeed.
|
||||
#
|
||||
if {$::tcl_platform(platform)=="unix"} {
|
||||
file attributes test_fsdir/a/b/c -permissions 0000
|
||||
if {[catch {glob -nocomplain test_fsdir/a/b/c/*}]} {
|
||||
do_execsql_test 10.100 {
|
||||
SELECT count(*) FROM fsdir('test_fsdir') WHERE level<=4
|
||||
} {7}
|
||||
do_execsql_test 10.101 {
|
||||
SELECT count(*) FROM fsdir('test_fsdir') WHERE level<5
|
||||
} {7}
|
||||
do_execsql_test 10.102 {
|
||||
SELECT count(*) FROM fsdir('test_fsdir') WHERE level<4.5
|
||||
} {7}
|
||||
do_execsql_test 10.103 {
|
||||
SELECT count(*) FROM fsdir('test_fsdir') WHERE level=4
|
||||
} {2}
|
||||
do_catchsql_test 10.104 {
|
||||
SELECT count(*) FROM fsdir('test_fsdir') WHERE level<5.5
|
||||
} {1 {cannot read directory: test_fsdir/a/b/c}}
|
||||
do_catchsql_test 10.105 {
|
||||
SELECT count(*) FROM fsdir('test_fsdir') WHERE level<=5
|
||||
} {1 {cannot read directory: test_fsdir/a/b/c}}
|
||||
}
|
||||
file attributes test_fsdir/a/b/c -permissions 0755
|
||||
}
|
||||
forcedelete test_fsdir
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
Reference in New Issue
Block a user