mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-08 14:02:16 +03:00
Minor fixes and documentation improvements for sqlite3_stmt_scanstatus().
FossilOrigin-Name: 8d8cc9608d30bb65fffcfe488e904411cbbc7f41
This commit is contained in:
23
manifest
23
manifest
@@ -1,5 +1,5 @@
|
||||
C Add\sthe\sexperimental\ssqlite3_stmt_scanstatus()\sAPI.
|
||||
D 2014-10-31T20:11:32.562
|
||||
C Minor\sfixes\sand\sdocumentation\simprovements\sfor\ssqlite3_stmt_scanstatus().
|
||||
D 2014-11-01T18:08:04.130
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
@@ -229,7 +229,7 @@ F src/resolve.c 4965007d6497b6a4d7a6d98751cc39712885f952
|
||||
F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e
|
||||
F src/select.c 428165951748151e87a15295b7357221433e311b
|
||||
F src/shell.c 282f8f5278e0c78eb442217531172ec9e1538796
|
||||
F src/sqlite.h.in 6e90cdb404e4fa8c0eb149ca79c11c6608a97ece
|
||||
F src/sqlite.h.in aeba29025ba5fc721a11c1b81ed8745f93029590
|
||||
F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad
|
||||
F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d
|
||||
F src/sqliteInt.h 4f86ac648ea398c1bb3db036062934cde257ea23
|
||||
@@ -289,7 +289,7 @@ F src/update.c 3c4ecc282accf12d39edb8d524cf089645e55a13
|
||||
F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c
|
||||
F src/util.c 3b627daa45c7308c1e36e3dbaa3f9ce7e5c7fa73
|
||||
F src/vacuum.c 59f03f92bcff57faa6a8ca256eb29ccddfb0614a
|
||||
F src/vdbe.c 80329be857cff3c2d6e8c1f594ac689166c44ae7
|
||||
F src/vdbe.c 5240bad20ce0b707afee211f0c21a862b54b1e0b
|
||||
F src/vdbe.h f8e5388173dbf8408da4ae1dcbf75911caf2253d
|
||||
F src/vdbeInt.h 284b2294c188474daa9b5ce2bd0200560cb0940d
|
||||
F src/vdbeapi.c 2afa2e162f290879ca9c51e8795a377035f1662a
|
||||
@@ -302,8 +302,8 @@ F src/vtab.c 2a30791bbd7926b589401bd09c3abb33de563793
|
||||
F src/wal.c 10e7de7ce90865a68153f001a61f1d985cd17983
|
||||
F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
|
||||
F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804
|
||||
F src/where.c 344beac082f8f4f69ec7c4a669d74294475e5abe
|
||||
F src/whereInt.h 19279cd0664ce1d90b9ad3ef0108cb494acfe455
|
||||
F src/where.c 636ca646c8f2f53fd66f9ed5c773e84cb0c4b762
|
||||
F src/whereInt.h 99d324a8f921d7a40c605a8b197350c3cb18977d
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||
F test/aggnested.test b35b4cd69fc913f90d39a575e171e1116c3a4bb7
|
||||
@@ -801,7 +801,7 @@ F test/savepoint4.test c8f8159ade6d2acd9128be61e1230f1c1edc6cc0
|
||||
F test/savepoint5.test 0735db177e0ebbaedc39812c8d065075d563c4fd
|
||||
F test/savepoint6.test f41279c5e137139fa5c21485773332c7adb98cd7
|
||||
F test/savepoint7.test fbf319a7b2dda089ec5be30a424a0e95f121d423
|
||||
F test/scanstatus.test a62dad3311fc51eab1d6977b082738bd2148fe07
|
||||
F test/scanstatus.test b4b1780bad243e1576329d05597b99f06886e4d2
|
||||
F test/schema.test 8f7999be894260f151adf15c2c7540f1c6d6a481
|
||||
F test/schema2.test 906408621ea881fdb496d878b1822572a34e32c5
|
||||
F test/schema3.test 1bc1008e1f8cb5654b248c55f27249366eb7ed38
|
||||
@@ -1211,10 +1211,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
|
||||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||
F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
|
||||
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
||||
P 67f0d469da28c023200239a1f3d0c6cef9ef0e45
|
||||
R 4c76f3e7b97f67c1dd65bda3a6e96149
|
||||
T *branch * scanstatus
|
||||
T *sym-scanstatus *
|
||||
T -sym-trunk *
|
||||
P 6a9bab34aeb6a01b612211a28c140de60a3e883c
|
||||
R d964f269915d57cf95d9198c6ba22665
|
||||
U dan
|
||||
Z 4994ca943ee260eeca8f493b4f59766a
|
||||
Z 082decdd6298ff1a2330407f8d406dfb
|
||||
|
@@ -1 +1 @@
|
||||
6a9bab34aeb6a01b612211a28c140de60a3e883c
|
||||
8d8cc9608d30bb65fffcfe488e904411cbbc7f41
|
@@ -7408,6 +7408,8 @@ int sqlite3_vtab_on_conflict(sqlite3 *);
|
||||
|
||||
|
||||
/*
|
||||
** CAPI3REF: Prepared Statement Scan Statuses
|
||||
**
|
||||
** Return status data for a single loop within query pStmt.
|
||||
**
|
||||
** Parameter "idx" identifies the specific loop to retrieve statistics for.
|
||||
@@ -7415,7 +7417,25 @@ int sqlite3_vtab_on_conflict(sqlite3 *);
|
||||
** zero or greater than or equal to the total number of loops used to implement
|
||||
** the statement - a non-zero value is returned. In this case the final value
|
||||
** of all five output parameters is undefined. Otherwise, if idx is in range,
|
||||
** the output parameters are populated and zero returned.
|
||||
** zero is returned and the output parameters set as follows:
|
||||
**
|
||||
** <ul>
|
||||
** <li> (*pnLoop) is set to the total number of times the loop has been run.
|
||||
** <li> (*pnVisit) is set to the total number of rows visited by the loop.
|
||||
** <li> (*pnEst) is set to the estimate of the number of rows visited
|
||||
** by each run of the loop used by the SQL optimizer. Ideally, this
|
||||
** value should be close to (*pnVisit)/(*pnLoop).
|
||||
** <li> (*pzName) is set to point to a nul-terminated string containing the
|
||||
** name of the index of table used by this loop.
|
||||
** <li> (*pzExplain) is set to point to a nul-terminated string containing
|
||||
** same text that would be returned for this loop by an EXPLAIN
|
||||
** QUERY PLAN command.
|
||||
** </ul>
|
||||
**
|
||||
** Output parameters *pzName and *pzExplain are set to point to buffers
|
||||
** managed by the statement object. Both of these pointers may be invalidated
|
||||
** by any API call on the same statement object, including an sqlite3_step()
|
||||
** sqlite3_bind_*() call.
|
||||
**
|
||||
** Statistics may not be available for all loops in all statements. In cases
|
||||
** where there exist loops with no available statistics, this function ignores
|
||||
@@ -7436,6 +7456,8 @@ SQLITE_EXPERIMENTAL int sqlite3_stmt_scanstatus(
|
||||
|
||||
|
||||
/*
|
||||
** CAPI3REF: Zero Scan-Status Counters
|
||||
**
|
||||
** Zero all sqlite3_stmt_scanstatus() related event counters.
|
||||
**
|
||||
** This API is only available if the library is built with pre-processor
|
||||
|
@@ -3889,6 +3889,7 @@ case OP_NotExists: { /* jump, in3 */
|
||||
res = 0;
|
||||
iKey = pIn3->u.i;
|
||||
rc = sqlite3BtreeMovetoUnpacked(pCrsr, 0, iKey, 0, &res);
|
||||
IncrementExplainCounter(pC, nLoop);
|
||||
pC->movetoTarget = iKey; /* Used by OP_Delete */
|
||||
pC->nullRow = 0;
|
||||
pC->cacheStatus = CACHE_STALE;
|
||||
@@ -3896,6 +3897,8 @@ case OP_NotExists: { /* jump, in3 */
|
||||
VdbeBranchTaken(res!=0,2);
|
||||
if( res!=0 ){
|
||||
pc = pOp->p2 - 1;
|
||||
}else{
|
||||
IncrementExplainCounter(pC, nVisit);
|
||||
}
|
||||
pC->seekResult = res;
|
||||
break;
|
||||
|
38
src/where.c
38
src/where.c
@@ -2739,7 +2739,7 @@ static int codeAllEqualityTerms(
|
||||
return regBase;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_EXPLAIN
|
||||
#if !defined(SQLITE_OMIT_EXPLAIN) || defined(SQLITE_ENABLE_STMT_SCANSTATUS)
|
||||
/*
|
||||
** This routine is a helper for explainIndexRange() below
|
||||
**
|
||||
@@ -2815,19 +2815,23 @@ static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop, Table *pTab){
|
||||
static void explainOneScan(
|
||||
Parse *pParse, /* Parse context */
|
||||
SrcList *pTabList, /* Table list this loop refers to */
|
||||
WhereLevel *pLevel, /* Scan to write OP_Explain opcode for */
|
||||
WhereInfo *pWInfo, /* WHERE clause this loop belongs to */
|
||||
int iLevel, /* Value for "level" column of output */
|
||||
int iFrom, /* Value for "from" column of output */
|
||||
u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */
|
||||
){
|
||||
#if !defined(SQLITE_DEBUG) && !defined(SQLITE_ENABLE_STMT_SCANSTATUS)
|
||||
if( pParse->explain==2 )
|
||||
#endif
|
||||
{
|
||||
WhereLevel *pLevel = &pWInfo->a[iLevel];
|
||||
struct SrcList_item *pItem = &pTabList->a[pLevel->iFrom];
|
||||
Vdbe *v = pParse->pVdbe; /* VM being constructed */
|
||||
sqlite3 *db = pParse->db; /* Database handle */
|
||||
#ifdef SQLITE_OMIT_EXPLAIN
|
||||
int iId = 0; /* Select id (left-most output column) */
|
||||
#else
|
||||
int iId = pParse->iSelectId; /* Select id (left-most output column) */
|
||||
#endif
|
||||
int isSearch; /* True for a SEARCH. False for SCAN. */
|
||||
WhereLoop *pLoop; /* The controlling WhereLoop object */
|
||||
u32 flags; /* Flags that describe this loop */
|
||||
@@ -2839,7 +2843,7 @@ static void explainOneScan(
|
||||
|
||||
pLoop = pLevel->pWLoop;
|
||||
flags = pLoop->wsFlags;
|
||||
if( (flags&WHERE_MULTI_OR) || (wctrlFlags&WHERE_ONETABLE_ONLY) ) return;
|
||||
if( (flags&WHERE_MULTI_OR) ) return;
|
||||
|
||||
sqlite3StrAccumInit(&str, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH);
|
||||
str.db = db;
|
||||
@@ -2865,7 +2869,11 @@ static void explainOneScan(
|
||||
|| (wctrlFlags&(WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX));
|
||||
sqlite3StrAccumAppendAll(&str, isSearch ? "SEARCH" : "SCAN");
|
||||
if( pItem->pSelect ){
|
||||
#ifdef SQLITE_OMIT_EXPLAIN
|
||||
sqlite3XPrintf(&str, 0, " SUBQUERY 0");
|
||||
#else
|
||||
sqlite3XPrintf(&str, 0, " SUBQUERY %d", pItem->iSelectId);
|
||||
#endif
|
||||
}else{
|
||||
sqlite3XPrintf(&str, 0, " TABLE %s", pItem->zName);
|
||||
}
|
||||
@@ -2937,15 +2945,15 @@ static void explainOneScan(
|
||||
pExplain->nEst = nEstRow;
|
||||
pExplain->zName = (const char*)&pExplain[1];
|
||||
pExplain->zExplain = &pExplain->zName[sqlite3Strlen30(pExplain->zName)+1];
|
||||
sqlite3VdbeAddOp4(v, OP_Explain,
|
||||
iId, iLevel, iFrom, (char*)pExplain,P4_EXPLAIN
|
||||
pWInfo->iExplain = sqlite3VdbeAddOp4(v, OP_Explain,
|
||||
iId, iLevel, pLevel->iFrom, (char*)pExplain,P4_EXPLAIN
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
# define explainOneScan(u,v,w,x,y,z)
|
||||
#endif /* SQLITE_OMIT_EXPLAIN */
|
||||
# define explainOneScan(v,w,x,y,z)
|
||||
#endif /* !SQLITE_OMIT_EXPLAIN || SQLITE_ENABLE_STMT_SCANSTATUS */
|
||||
|
||||
|
||||
/*
|
||||
@@ -3613,9 +3621,15 @@ static Bitmask codeOneLoopStart(
|
||||
assert( pSubWInfo || pParse->nErr || db->mallocFailed );
|
||||
if( pSubWInfo ){
|
||||
WhereLoop *pSubLoop;
|
||||
explainOneScan(
|
||||
pParse, pOrTab, &pSubWInfo->a[0], iLevel, pLevel->iFrom, 0
|
||||
);
|
||||
|
||||
/* If an OP_Explain was added for this sub-loop, fix the P2 and
|
||||
** P3 parameters to it so that they are relative to the current
|
||||
** context. */
|
||||
if( pSubWInfo->iExplain!=0 ){
|
||||
sqlite3VdbeChangeP2(v, pSubWInfo->iExplain, iLevel);
|
||||
sqlite3VdbeChangeP3(v, pSubWInfo->iExplain, pLevel->iFrom);
|
||||
}
|
||||
|
||||
/* This is the sub-WHERE clause body. First skip over
|
||||
** duplicate rows from prior sub-WHERE clauses, and record the
|
||||
** rowid (or PRIMARY KEY) for the current row so that the same
|
||||
@@ -6455,7 +6469,7 @@ WhereInfo *sqlite3WhereBegin(
|
||||
if( db->mallocFailed ) goto whereBeginError;
|
||||
}
|
||||
#endif
|
||||
explainOneScan(pParse, pTabList, pLevel, ii, pLevel->iFrom, wctrlFlags);
|
||||
explainOneScan(pParse, pTabList, pWInfo, ii, wctrlFlags);
|
||||
pLevel->addrBody = sqlite3VdbeCurrentAddr(v);
|
||||
notReady = codeOneLoopStart(pWInfo, ii, notReady);
|
||||
pWInfo->iContinue = pLevel->addrCont;
|
||||
|
@@ -407,6 +407,7 @@ struct WhereInfo {
|
||||
int iTop; /* The very beginning of the WHERE loop */
|
||||
int iContinue; /* Jump here to continue with next record */
|
||||
int iBreak; /* Jump here to break out of the loop */
|
||||
int iExplain; /* Address of OP_Explain (if WHERE_ONETABLE_ONLY) */
|
||||
int savedNQueryLoop; /* pParse->nQueryLoop outside the WHERE loop */
|
||||
int aiCurOnePass[2]; /* OP_OpenWrite cursors for the ONEPASS opt */
|
||||
WhereMaskSet sMaskSet; /* Map cursor numbers to bitmasks */
|
||||
|
@@ -53,16 +53,148 @@ do_scanstatus_test 1.4 {
|
||||
nLoop 2 nVisit 6 nEst 3 zName t2 zExplain {SCAN TABLE t2}
|
||||
}
|
||||
|
||||
do_execsql_test 1.5 {
|
||||
ANALYZE;
|
||||
do_execsql_test 1.5 { ANALYZE }
|
||||
do_execsql_test 1.6 {
|
||||
SELECT count(*) FROM t1, t2 WHERE t2.rowid>1;
|
||||
} 4
|
||||
do_scanstatus_test 1.6 {
|
||||
do_scanstatus_test 1.7 {
|
||||
nLoop 1 nVisit 2 nEst 2 zName t2 zExplain
|
||||
{SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid>?)}
|
||||
nLoop 2 nVisit 4 nEst 2 zName t1 zExplain {SCAN TABLE t1}
|
||||
}
|
||||
|
||||
do_execsql_test 1.8 {
|
||||
SELECT count(*) FROM t1, t2 WHERE t2.rowid>1;
|
||||
} 4
|
||||
|
||||
do_scanstatus_test 1.9 {
|
||||
nLoop 2 nVisit 4 nEst 2 zName t2 zExplain
|
||||
{SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid>?)}
|
||||
nLoop 4 nVisit 8 nEst 2 zName t1 zExplain {SCAN TABLE t1}
|
||||
}
|
||||
|
||||
do_test 1.9 {
|
||||
sqlite3_stmt_scanstatus_reset [db_last_stmt_ptr db]
|
||||
} {}
|
||||
|
||||
do_scanstatus_test 1.10 {
|
||||
nLoop 0 nVisit 0 nEst 2 zName t2 zExplain
|
||||
{SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid>?)}
|
||||
nLoop 0 nVisit 0 nEst 2 zName t1 zExplain {SCAN TABLE t1}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Try a few different types of scans.
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 2.1 {
|
||||
CREATE TABLE x1(i INTEGER PRIMARY KEY, j);
|
||||
INSERT INTO x1 VALUES(1, 'one');
|
||||
INSERT INTO x1 VALUES(2, 'two');
|
||||
INSERT INTO x1 VALUES(3, 'three');
|
||||
INSERT INTO x1 VALUES(4, 'four');
|
||||
CREATE INDEX x1j ON x1(j);
|
||||
|
||||
SELECT * FROM x1 WHERE i=2;
|
||||
} {2 two}
|
||||
|
||||
do_scanstatus_test 2.2 {
|
||||
nLoop 1 nVisit 1 nEst 1 zName x1
|
||||
zExplain {SEARCH TABLE x1 USING INTEGER PRIMARY KEY (rowid=?)}
|
||||
}
|
||||
|
||||
do_execsql_test 2.3.1 {
|
||||
SELECT * FROM x1 WHERE j='two'
|
||||
} {2 two}
|
||||
do_scanstatus_test 2.3.2 {
|
||||
nLoop 1 nVisit 1 nEst 10 zName x1j
|
||||
zExplain {SEARCH TABLE x1 USING COVERING INDEX x1j (j=?)}
|
||||
}
|
||||
|
||||
do_execsql_test 2.4.1 {
|
||||
SELECT * FROM x1 WHERE j<'two'
|
||||
} {4 four 1 one 3 three}
|
||||
do_scanstatus_test 2.4.2 {
|
||||
nLoop 1 nVisit 4 nEst 262144 zName x1j
|
||||
zExplain {SEARCH TABLE x1 USING COVERING INDEX x1j (j<?)}
|
||||
}
|
||||
|
||||
do_execsql_test 2.5.1 {
|
||||
SELECT * FROM x1 WHERE j>='two'
|
||||
} {2 two}
|
||||
do_scanstatus_test 2.5.2 {
|
||||
nLoop 1 nVisit 1 nEst 262144 zName x1j
|
||||
zExplain {SEARCH TABLE x1 USING COVERING INDEX x1j (j>?)}
|
||||
}
|
||||
|
||||
do_execsql_test 2.6.1 {
|
||||
SELECT * FROM x1 WHERE j BETWEEN 'three' AND 'two'
|
||||
} {3 three 2 two}
|
||||
do_scanstatus_test 2.6.2 {
|
||||
nLoop 1 nVisit 2 nEst 16384 zName x1j
|
||||
zExplain {SEARCH TABLE x1 USING COVERING INDEX x1j (j>? AND j<?)}
|
||||
}
|
||||
|
||||
do_execsql_test 2.7.1 {
|
||||
CREATE TABLE x2(i INTEGER, j, k);
|
||||
INSERT INTO x2 SELECT i, j, i || ' ' || j FROM x1;
|
||||
CREATE INDEX x2j ON x2(j);
|
||||
CREATE INDEX x2ij ON x2(i, j);
|
||||
SELECT * FROM x2 WHERE j BETWEEN 'three' AND 'two'
|
||||
} {3 three {3 three} 2 two {2 two}}
|
||||
|
||||
do_scanstatus_test 2.7.2 {
|
||||
nLoop 1 nVisit 2 nEst 16384 zName x2j
|
||||
zExplain {SEARCH TABLE x2 USING INDEX x2j (j>? AND j<?)}
|
||||
}
|
||||
|
||||
do_execsql_test 2.8.1 {
|
||||
SELECT * FROM x2 WHERE i=1 AND j='two'
|
||||
}
|
||||
do_scanstatus_test 2.8.2 {
|
||||
nLoop 1 nVisit 1 nEst 8 zName x2ij
|
||||
zExplain {SEARCH TABLE x2 USING INDEX x2ij (i=? AND j=?)}
|
||||
}
|
||||
|
||||
do_execsql_test 2.9.1 {
|
||||
SELECT * FROM x2 WHERE i=5 AND j='two'
|
||||
}
|
||||
do_scanstatus_test 2.9.2 {
|
||||
nLoop 1 nVisit 0 nEst 8 zName x2ij
|
||||
zExplain {SEARCH TABLE x2 USING INDEX x2ij (i=? AND j=?)}
|
||||
}
|
||||
|
||||
do_execsql_test 2.10.1 {
|
||||
SELECT * FROM x2 WHERE i=3 AND j='three'
|
||||
} {3 three {3 three}}
|
||||
do_scanstatus_test 2.10.2 {
|
||||
nLoop 1 nVisit 2 nEst 8 zName x2ij
|
||||
zExplain {SEARCH TABLE x2 USING INDEX x2ij (i=? AND j=?)}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Try with queries that use the OR optimization.
|
||||
#
|
||||
do_execsql_test 3.1 {
|
||||
CREATE TABLE a1(a, b, c, d);
|
||||
CREATE INDEX a1a ON a1(a);
|
||||
CREATE INDEX a1bc ON a1(b, c);
|
||||
|
||||
WITH d(x) AS (SELECT 1 UNION ALL SELECT x+1 AS n FROM d WHERE n<=100)
|
||||
INSERT INTO a1 SELECT x, x, x, x FROM d;
|
||||
}
|
||||
|
||||
do_execsql_test 3.2.1 {
|
||||
SELECT d FROM a1 WHERE (a=4 OR b=13)
|
||||
} {4 13}
|
||||
|
||||
do_scanstatus_test 2.4 {
|
||||
nLoop 1 nVisit 2 nEst 10 zName a1a
|
||||
zExplain {SEARCH TABLE a1 USING INDEX a1a (a=?)}
|
||||
|
||||
nLoop 1 nVisit 2 nEst 10 zName a1bc
|
||||
zExplain {SEARCH TABLE a1 USING INDEX a1bc (b=?)}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user