mirror of
https://github.com/sqlite/sqlite.git
synced 2026-01-06 08:01:16 +03:00
Enhance the FSDIR virtual table with a new "level" column. The query planner
knows how to optimize to avoid search deeper than the maximum requested level. FossilOrigin-Name: 1ddc0f9e79c33957961bc1443ccb74d756a02cbd20850052079782e76aef2706
This commit is contained in:
@@ -67,6 +67,7 @@
|
||||
** data: For a regular file, a blob containing the file data. For a
|
||||
** symlink, a text value containing the text of the link. For a
|
||||
** directory, NULL.
|
||||
** level: Directory hierarchy level. Topmost is 1.
|
||||
**
|
||||
** If a non-NULL value is specified for the optional $dir parameter and
|
||||
** $path is a relative path, then $path is interpreted relative to $dir.
|
||||
@@ -116,14 +117,16 @@ SQLITE_EXTENSION_INIT1
|
||||
/*
|
||||
** Structure of the fsdir() table-valued function
|
||||
*/
|
||||
/* 0 1 2 3 4 5 */
|
||||
#define FSDIR_SCHEMA "(name,mode,mtime,data,path HIDDEN,dir HIDDEN)"
|
||||
/* 0 1 2 3 4 5 6 */
|
||||
#define FSDIR_SCHEMA "(name,mode,mtime,data,level,path HIDDEN,dir HIDDEN)"
|
||||
|
||||
#define FSDIR_COLUMN_NAME 0 /* Name of the file */
|
||||
#define FSDIR_COLUMN_MODE 1 /* Access mode */
|
||||
#define FSDIR_COLUMN_MTIME 2 /* Last modification time */
|
||||
#define FSDIR_COLUMN_DATA 3 /* File content */
|
||||
#define FSDIR_COLUMN_PATH 4 /* Path to top of search */
|
||||
#define FSDIR_COLUMN_DIR 5 /* Path is relative to this directory */
|
||||
#define FSDIR_COLUMN_LEVEL 4 /* Level. Topmost is 1 */
|
||||
#define FSDIR_COLUMN_PATH 5 /* Path to top of search */
|
||||
#define FSDIR_COLUMN_DIR 6 /* Path is relative to this directory */
|
||||
|
||||
/*
|
||||
** UTF8 chmod() function for Windows
|
||||
@@ -620,6 +623,7 @@ struct fsdir_cursor {
|
||||
sqlite3_vtab_cursor base; /* Base class - must be first */
|
||||
|
||||
int nLvl; /* Number of entries in aLvl[] array */
|
||||
int mxLvl; /* Maximum level */
|
||||
int iLvl; /* Index of current entry */
|
||||
FsdirLevel *aLvl; /* Hierarchy of directories being traversed */
|
||||
|
||||
@@ -738,7 +742,7 @@ static int fsdirNext(sqlite3_vtab_cursor *cur){
|
||||
mode_t m = pCur->sStat.st_mode;
|
||||
|
||||
pCur->iRowid++;
|
||||
if( S_ISDIR(m) ){
|
||||
if( S_ISDIR(m) && pCur->iLvl+3<pCur->mxLvl ){
|
||||
/* Descend into this directory */
|
||||
int iNew = pCur->iLvl + 1;
|
||||
FsdirLevel *pLvl;
|
||||
@@ -846,7 +850,11 @@ static int fsdirColumn(
|
||||
}else{
|
||||
readFileContents(ctx, pCur->zPath);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FSDIR_COLUMN_LEVEL:
|
||||
sqlite3_result_int(ctx, pCur->iLvl+2);
|
||||
break;
|
||||
case FSDIR_COLUMN_PATH:
|
||||
default: {
|
||||
/* The FSDIR_COLUMN_PATH and FSDIR_COLUMN_DIR are input parameters.
|
||||
@@ -880,8 +888,11 @@ static int fsdirEof(sqlite3_vtab_cursor *cur){
|
||||
/*
|
||||
** xFilter callback.
|
||||
**
|
||||
** idxNum==1 PATH parameter only
|
||||
** idxNum==2 Both PATH and DIR supplied
|
||||
** idxNum bit Meaning
|
||||
** 0x01 PATH=N
|
||||
** 0x02 DIR=N
|
||||
** 0x04 LEVEL<N
|
||||
** 0x08 LEVEL<=N
|
||||
*/
|
||||
static int fsdirFilter(
|
||||
sqlite3_vtab_cursor *cur,
|
||||
@@ -892,20 +903,31 @@ static int fsdirFilter(
|
||||
fsdir_cursor *pCur = (fsdir_cursor*)cur;
|
||||
(void)idxStr;
|
||||
fsdirResetCursor(pCur);
|
||||
int i;
|
||||
|
||||
if( idxNum==0 ){
|
||||
fsdirSetErrmsg(pCur, "table function fsdir requires an argument");
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
assert( argc==idxNum && (argc==1 || argc==2) );
|
||||
assert( (idxNum & 0x01)!=0 && argc>0 );
|
||||
zDir = (const char*)sqlite3_value_text(argv[0]);
|
||||
if( zDir==0 ){
|
||||
fsdirSetErrmsg(pCur, "table function fsdir requires a non-NULL argument");
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
if( argc==2 ){
|
||||
pCur->zBase = (const char*)sqlite3_value_text(argv[1]);
|
||||
i = 1;
|
||||
if( (idxNum & 0x02)!=0 ){
|
||||
assert( argc>i );
|
||||
pCur->zBase = (const char*)sqlite3_value_text(argv[i++]);
|
||||
}
|
||||
if( (idxNum & 0x0c)!=0 ){
|
||||
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;
|
||||
}
|
||||
if( pCur->zBase ){
|
||||
pCur->nBase = (int)strlen(pCur->zBase)+1;
|
||||
@@ -934,10 +956,11 @@ static int fsdirFilter(
|
||||
** In this implementation idxNum is used to represent the
|
||||
** query plan. idxStr is unused.
|
||||
**
|
||||
** The query plan is represented by values of idxNum:
|
||||
** The query plan is represented by bits in idxNum:
|
||||
**
|
||||
** (1) The path value is supplied by argv[0]
|
||||
** (2) Path is in argv[0] and dir is in argv[1]
|
||||
** 0x01 The path value is supplied by argv[0]
|
||||
** 0x02 dir is in argv[1]
|
||||
** 0x04 maxdepth is in argv[1] or [2]
|
||||
*/
|
||||
static int fsdirBestIndex(
|
||||
sqlite3_vtab *tab,
|
||||
@@ -946,6 +969,9 @@ static int fsdirBestIndex(
|
||||
int i; /* Loop over constraints */
|
||||
int idxPath = -1; /* Index in pIdxInfo->aConstraint of PATH= */
|
||||
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;
|
||||
@@ -953,25 +979,48 @@ static int fsdirBestIndex(
|
||||
(void)tab;
|
||||
pConstraint = pIdxInfo->aConstraint;
|
||||
for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
|
||||
if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
|
||||
switch( pConstraint->iColumn ){
|
||||
case FSDIR_COLUMN_PATH: {
|
||||
if( pConstraint->usable ){
|
||||
idxPath = i;
|
||||
seenPath = 0;
|
||||
}else if( idxPath<0 ){
|
||||
seenPath = 1;
|
||||
if( pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ ){
|
||||
switch( pConstraint->iColumn ){
|
||||
case FSDIR_COLUMN_PATH: {
|
||||
if( pConstraint->usable ){
|
||||
idxPath = i;
|
||||
seenPath = 0;
|
||||
}else if( idxPath<0 ){
|
||||
seenPath = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FSDIR_COLUMN_DIR: {
|
||||
if( pConstraint->usable ){
|
||||
idxDir = i;
|
||||
seenDir = 0;
|
||||
}else if( idxDir<0 ){
|
||||
seenDir = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FSDIR_COLUMN_LEVEL: {
|
||||
if( pConstraint->usable && idxLevel<0 ){
|
||||
idxLevel = i;
|
||||
idxLevelEQ = 0x08;
|
||||
omitLevel = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FSDIR_COLUMN_DIR: {
|
||||
if( pConstraint->usable ){
|
||||
idxDir = i;
|
||||
seenDir = 0;
|
||||
}else if( idxDir<0 ){
|
||||
seenDir = 1;
|
||||
}
|
||||
break;
|
||||
}else
|
||||
if( pConstraint->iColumn==FSDIR_COLUMN_LEVEL
|
||||
&& pConstraint->usable
|
||||
&& idxLevel<0
|
||||
){
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -988,14 +1037,20 @@ static int fsdirBestIndex(
|
||||
}else{
|
||||
pIdxInfo->aConstraintUsage[idxPath].omit = 1;
|
||||
pIdxInfo->aConstraintUsage[idxPath].argvIndex = 1;
|
||||
pIdxInfo->idxNum = 0x01;
|
||||
pIdxInfo->estimatedCost = 1.0e9;
|
||||
i = 2;
|
||||
if( idxDir>=0 ){
|
||||
pIdxInfo->aConstraintUsage[idxDir].omit = 1;
|
||||
pIdxInfo->aConstraintUsage[idxDir].argvIndex = 2;
|
||||
pIdxInfo->idxNum = 2;
|
||||
pIdxInfo->estimatedCost = 10.0;
|
||||
}else{
|
||||
pIdxInfo->idxNum = 1;
|
||||
pIdxInfo->estimatedCost = 100.0;
|
||||
pIdxInfo->aConstraintUsage[idxDir].argvIndex = i++;
|
||||
pIdxInfo->idxNum |= 0x02;
|
||||
pIdxInfo->estimatedCost /= 1.0e4;
|
||||
}
|
||||
if( idxLevel>=0 ){
|
||||
pIdxInfo->aConstraintUsage[idxLevel].omit = omitLevel;
|
||||
pIdxInfo->aConstraintUsage[idxLevel].argvIndex = i++;
|
||||
pIdxInfo->idxNum |= idxLevelEQ;
|
||||
pIdxInfo->estimatedCost /= 1.0e4;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
14
manifest
14
manifest
@@ -1,5 +1,5 @@
|
||||
C tea\sbuild:\sadd\san\sinfo-exists\scheck\safter\sa\s'scan'\scall,\sas\sscan\sdoes\snot\screate\sits\starget\svars\son\serror.\sProblem\sreported\sat\s[forum:fde857fb8101a4be\s|\sforum\spost\sfde857fb8101a4be]\sand\striggers\swhen\sthe\s'vsatisfies'\stest\sfor\sthe\shost's\sTcl\sversion\sfails\s(so\sthe\sbuild\swould\sfail\sanyway,\sbut\swill\sfail\smore\sinformatively\swith\sthis\sfix).
|
||||
D 2025-06-04T18:34:20.003
|
||||
C Enhance\sthe\sFSDIR\svirtual\stable\swith\sa\snew\s"level"\scolumn.\s\sThe\squery\splanner\nknows\show\sto\soptimize\sto\savoid\ssearch\sdeeper\sthan\sthe\smaximum\srequested\slevel.
|
||||
D 2025-06-05T18:28:54.497
|
||||
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
@@ -417,7 +417,7 @@ F ext/misc/dbdump.c b8592f6f2da292c62991a13864a60d6c573c47a9cc58362131b9e6a64f82
|
||||
F ext/misc/decimal.c 228d47e9ef4de60daf5851da19e3ac9ac1eda9e94432816914469501db6a1129
|
||||
F ext/misc/eval.c 04bc9aada78c888394204b4ed996ab834b99726fb59603b0ee3ed6e049755dc1
|
||||
F ext/misc/explain.c 606100185fb90d6a1eade1ed0414d53503c86820d8956a06e3b0a56291894f2b
|
||||
F ext/misc/fileio.c 34993b810514c58ff99d7b4254d4a388d844a4774ea77bec68a1dafe8de5ce41
|
||||
F ext/misc/fileio.c f01aca52627d0a4b212800a024de62c6bb2c09403a09e782592d59902d49675f
|
||||
F ext/misc/fossildelta.c 0aeb099e9627eea693cf21ae47826ecd1e0319b93143bed23090838b2ef0c162
|
||||
F ext/misc/fuzzer.c 6b231352815304ba60d8e9ec2ee73d4918e74d9b76bda8940ba2b64e8777515e
|
||||
F ext/misc/ieee754.c c9dd9d77c8e8e18e0a5706f8ffcccf4ccb6562073709f7453d4d73f5122f4362
|
||||
@@ -2209,8 +2209,8 @@ F tool/version-info.c 3b36468a90faf1bbd59c65fd0eb66522d9f941eedd364fabccd7227350
|
||||
F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
|
||||
F tool/warnings.sh 1ad0169b022b280bcaaf94a7fa231591be96b514230ab5c98fbf15cd7df842dd
|
||||
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
||||
P 2f8a1b79533879e4975b405c46fea496ba8bffbef065e7dd0ad29fd4aa8f8f92
|
||||
R 93ec2f0ba3ae7edbce8d608ede6c810e
|
||||
U stephan
|
||||
Z 0897533fcae3d269da2c3a6ccf2bfc1d
|
||||
P 4f21874d5d20aef2e2d67a59e4fa03d98aa6514b16e4d956acfc817142cfbdb6
|
||||
R 59f5d0a04d958d7cb4b261048dbd0b85
|
||||
U drh
|
||||
Z 276de0b7a4b37abe2f1a437bfc4df89c
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
||||
@@ -1 +1 @@
|
||||
4f21874d5d20aef2e2d67a59e4fa03d98aa6514b16e4d956acfc817142cfbdb6
|
||||
1ddc0f9e79c33957961bc1443ccb74d756a02cbd20850052079782e76aef2706
|
||||
|
||||
Reference in New Issue
Block a user