Compare commits

...

4 Commits

Author SHA1 Message Date
drh 27de99df79 Add the EXPLAIN TABLES syntax that uses SQLITE_STMTMODE_TABLELIST. Seems
to work, but not well-tested.

FossilOrigin-Name: e7343ce7514f61eb1aeba22ab83da5b05779080db394332e2e90b4d54cabe123
2020-03-20 20:00:10 +00:00
drh 3041bf593b Further simplification of the EXPLAIN logic. Fix the test errors from
the previous check-in.

FossilOrigin-Name: 5eaba9af1c35ea7b7c08cad7d0d9b5a4b63b11b3177bb84a570ce1cea44b9f57
2020-03-20 17:49:37 +00:00
drh cc6408ffa3 Revamp the EXPLAIN infrastructure to facilitate sqlite3_stmt_mode(). The
currently code mostly works, but there are test failures.  This is an
incremental check-in.

FossilOrigin-Name: e9e17e2125dbbafd5da4adb3bd2893735fa4d0aaa5f3daee75f866cb32231a8d
2020-03-20 16:13:41 +00:00
drh 8e8c2f1498 Initial code for a proposed new sqlite3_stmt_mode() API.
This is an incomplete snapshot of a work-in-progress.

FossilOrigin-Name: 3cf7537b5e14e218218b18b3c0c668c950a71fcddc68a5faf0f197519718a6c2
2020-03-19 21:17:11 +00:00
13 changed files with 331 additions and 139 deletions
+16 -16
View File
@@ -1,5 +1,5 @@
C Chagnes\sthe\sESCAPE\sclause\son\sthe\sLIKE\soperator\sto\soverwrite\swildcard\ncharacters,\sin\sorder\sot\smatch\sthe\sbehavior\sof\sPosgreSQL.
D 2020-03-19T18:13:29.000
C Add\sthe\sEXPLAIN\sTABLES\ssyntax\sthat\suses\sSQLITE_STMTMODE_TABLELIST.\s\sSeems\nto\swork,\sbut\snot\swell-tested.
D 2020-03-20T20:00:10.751
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -520,7 +520,7 @@ F src/os_win.c 035a813cbd17f355bdcad7ab894af214a9c13a1db8aeac902365350b98cd45a7
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
F src/pager.c a71ffd145f55e28cbdc1bdabb5e6bef063da428a6c0de3c3a36e9a0c41d4c8c0
F src/pager.h 3b33619a90180e0874c7eca31d6f6ceb464d9322c6fb4e9a7bbb318c8a17bdb3
F src/parse.y 8575183809cf30f8c9d1fbea65ca34d1de78b659792bc7c42681e01fc596b520
F src/parse.y dc4521689a9d91b9da0c74ec02ccc6529d4610eece436cdf21c53ca167fd2a93
F src/pcache.c 385ff064bca69789d199a98e2169445dc16e4291fa807babd61d4890c3b34177
F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586
F src/pcache1.c 6596e10baf3d8f84cc1585d226cf1ab26564a5f5caf85a15757a281ff977d51a
@@ -529,11 +529,11 @@ F src/pragma.h 9473160d220416456b40f27323bb4b316d4e4e08ffbf8bf88c5f7045d49c38e5
F src/prepare.c 8d4d6c8aa6afefc48027c54b41cdf134b4d6bc2fc4badbe483ad7fd9e1728a28
F src/printf.c 9be6945837c839ba57837b4bc3af349eba630920fa5532aa518816defe42a7d4
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
F src/resolve.c 38e3a5636f5bdc92e3683e4cafbba6418c0aa15e0d89ca5b28bd0b621dbb80bf
F src/resolve.c ad43b2ed4bea58abca3092993382aa2ac91b89144d2066faae4ac924b39396f9
F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
F src/select.c 49d46acea0e69311aa891e18253973d63e81da2a9c135924bc827856d33872ad
F src/select.c 128d9d6996eca5e0db686495559b6588f197ef1b6643fa8ec4914861226ff021
F src/shell.c.in f76590931c0cbbfef347f44f81ade6b335f80c46bc6e59b8b6114383a8df30e0
F src/sqlite.h.in 802957feeb249ede54f8dfe99b72aa19e70a0b7737969c46e625dc2f9f2d42b0
F src/sqlite.h.in 416ef92b6b08bfb9a31de8001eb5d44243ecda036224421623cc8e5fdfdf1528
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 9c5269260409eb3275324ccace6a13a96f4ad330c708415f70ca6097901ff4ee
F src/sqliteInt.h 5f74c1c52b152259ee07f241821620f11736e4f590936cfaf1cbbff9a2f563d3
@@ -541,7 +541,7 @@ F src/sqliteLimit.h 95cb8479ca459496d9c1c6a9f76b38aee12203a56ce1092fe13e50ae2454
F src/status.c 9ff2210207c6c3b4d9631a8241a7d45ab1b26a0e9c84cb07a9b5ce2de9a3b278
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
F src/tclsqlite.c d0aa320416efe88c4dbb0156ed6c494f2f9958871a940e46984ee57b3e7fcc50
F src/test1.c 5e8b8cc54e8c88906ea8a084387aa79bad245e539f4cee73149e5c0527e1db16
F src/test1.c 93cc6cb90fd708c1822ab74543fd586e4d3510236db24ddcc5ef046f74a4b19c
F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5
F src/test3.c 61798bb0d38b915067a8c8e03f5a534b431181f802659a6616f9b4ff7d872644
F src/test4.c 405834f6a93ec395cc4c9bb8ecebf7c3d8079e7ca16ae65e82d01afd229694bb
@@ -603,11 +603,11 @@ F src/upsert.c 2920de71b20f04fe25eb00b655d086f0ba60ea133c59d7fa3325c49838818e78
F src/utf.c 95fb6e03a5ca679045c5adccd05380f0addccabef5911abddcb06af069500ab7
F src/util.c a285c1e026907b69fa2592bd05047a565a1d8a1aef2b73c924b6a8ffe772871a
F src/vacuum.c 813b510ba887fee6492bcb11f2bf77d7eb58b232b83649136372e0a2fc17f4b9
F src/vdbe.c c1c123c6248fa88940b932a00bcc75056921b6d046d45a82566cb97415d2299c
F src/vdbe.c b7b9ec1d604a12f4cafedf796027a297bc306f0d3afb340948898256cb4473b9
F src/vdbe.h 51282fbe819ee0e8eeeaab176240860d334c20a12b14f3b363e7f1a4e05d60b9
F src/vdbeInt.h a17146053a1aa438474012998fe07e314f3df274a61491ad838ad85d848ac051
F src/vdbeapi.c 1252d80c548711e47a6d84dae88ed4e95d3fbb4e7bd0eaa1347299af7efddf02
F src/vdbeaux.c e8baf66528e36474f4071e3171b660a454606eb5b54459a729982c939ad7a5bb
F src/vdbeInt.h 1a8807b7dfac4142f5b9047767295327be41f02c17f7bb6bd8ffef6219dac588
F src/vdbeapi.c d840fb3b80bbbd25fd44e1bb2d4a209e297832f527d21ea718fa53502a2a2d97
F src/vdbeaux.c 66dcae8b09af6c2213da7cfb4ca9ad6e8c4be5d4c1b8dd3eb8c5a1ada9e36ec0
F src/vdbeblob.c 253ed82894924c362a7fa3079551d3554cd1cdace39aa833da77d3bc67e7c1b1
F src/vdbemem.c 39b942ecca179f4f30a32b54579a85d74ccaefa5af2a0ad2700abe5ef0768b22
F src/vdbesort.c 2be76d26998ce2b3324cdcc9f6443728e54b6c7677c553ad909c7d7cfab587df
@@ -619,7 +619,7 @@ F src/wal.h 606292549f5a7be50b6227bd685fa76e3a4affad71bb8ac5ce4cb5c79f6a176a
F src/walker.c a137468bf36c92e64d2275caa80c83902e3a0fc59273591b96c6416d3253d05d
F src/where.c 9546c82056e8cdb27291f98cf1adca5d271240b399bb97b32f77fc2bea6146c9
F src/whereInt.h 6b874aa15f94e43a2cec1080be64d955b04deeafeac90ffb5d6975c0d511be3c
F src/wherecode.c 7b939de85d65cc4b4bfa197513136b9e0ae03167e3b82842ca5a0ba1055ba65d
F src/wherecode.c 9e931b9d01c3c6ffa9b150f4535dacea0dd38360fa740b6f525cf27c17415ba0
F src/whereexpr.c 264d58971eaf8256eb5b0917bcd7fc7a1f1109fdda183a8382308a1b18a2dce7
F src/window.c ba1ffb78d73c5831433681aab7ee634230ee32f14ad508efa585044662141d5a
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
@@ -1788,7 +1788,7 @@ F tool/max-limits.c cbb635fbb37ae4d05f240bfb5b5270bb63c54439
F tool/mkautoconfamal.sh 422fc365358a2e92876ffc62971a0ff28ed472fc8bcf9de0df921c736fdeca5e
F tool/mkccode.tcl 86463e68ce9c15d3041610fedd285ce32a5cf7a58fc88b3202b8b76837650dbe x
F tool/mkctimec.tcl dd183b73ae1c28249669741c250525f0407e579a70482371668fd5f130d9feb3
F tool/mkkeywordhash.c 11a3f3af8e787d0c5ca459ed66fe80fd09e661876506e7b978ec08c19477bdc2
F tool/mkkeywordhash.c cb015b0376aea574f00b3b7f7b8e8a43cb52c8adffb2d292454d27aa2567a7b4
F tool/mkmsvcmin.tcl 6ecab9fe22c2c8de4d82d4c46797bda3d2deac8e763885f5a38d0c44a895ab33
F tool/mkopcodec.tcl d1b6362bd3aa80d5520d4d6f3765badf01f6c43c
F tool/mkopcodeh.tcl 352a4319c0ad869eb26442bf7c3b015aa15594c21f1cce5a6420dbe999367c21
@@ -1860,7 +1860,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P 1d64f4a8af81fe1235fffa54884d8f842a48ff6a33d6172f0cd65bf42fe8b2a1
R 199dfbc9c8ca72850da0099d6c1cde58
P 5eaba9af1c35ea7b7c08cad7d0d9b5a4b63b11b3177bb84a570ce1cea44b9f57
R b8dc18a0109dd1b6247089b6701d54e2
U drh
Z 2c8ae1f04515bf2ea893e9cb3af9713c
Z 13571b2afccf3e4212df912e00f6dcfa
+1 -1
View File
@@ -1 +1 @@
11e0844f71e8f2d27ce9363fb505e02fd7795c61dae0b3886cf0d8df4484dd97
e7343ce7514f61eb1aeba22ab83da5b05779080db394332e2e90b4d54cabe123
+4 -3
View File
@@ -120,9 +120,10 @@ cmdlist ::= ecmd.
ecmd ::= SEMI.
ecmd ::= cmdx SEMI.
%ifndef SQLITE_OMIT_EXPLAIN
ecmd ::= explain cmdx SEMI. {NEVER-REDUCE}
explain ::= EXPLAIN. { pParse->explain = 1; }
explain ::= EXPLAIN QUERY PLAN. { pParse->explain = 2; }
ecmd ::= explain cmdx SEMI. {NEVER-REDUCE}
explain ::= EXPLAIN. { pParse->explain = SQLITE_STMTMODE_EXPLAIN; }
explain ::= EXPLAIN QUERY PLAN. { pParse->explain = SQLITE_STMTMODE_EQP; }
explain ::= EXPLAIN TABLES. { pParse->explain = SQLITE_STMTMODE_TABLELIST; }
%endif SQLITE_OMIT_EXPLAIN
cmdx ::= cmd. { sqlite3FinishCoding(pParse); }
+1 -1
View File
@@ -934,7 +934,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
#endif
else if( no_such_func && pParse->db->init.busy==0
#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
&& pParse->explain==0
&& pParse->explain==SQLITE_STMTMODE_RUN
#endif
){
sqlite3ErrorMsg(pParse, "no such function: %.*s", nId, zId);
+1 -1
View File
@@ -5505,7 +5505,7 @@ static void explainSimpleCount(
Table *pTab, /* Table being queried */
Index *pIdx /* Index used to optimize scan, or NULL */
){
if( pParse->explain==2 ){
if( pParse->explain==SQLITE_STMTMODE_EQP ){
int bCover = (pIdx!=0 && (HasRowid(pTab) || !IsPrimaryKeyIndex(pIdx)));
sqlite3VdbeExplain(pParse, 0, "SCAN TABLE %s%s%s",
pTab->zName,
+79 -5
View File
@@ -4132,14 +4132,88 @@ int sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
** CAPI3REF: Query The EXPLAIN Setting For A Prepared Statement
** METHOD: sqlite3_stmt
**
** ^The sqlite3_stmt_isexplain(S) interface returns 1 if the
** prepared statement S is an EXPLAIN statement, or 2 if the
** statement S is an EXPLAIN QUERY PLAN.
** ^The sqlite3_stmt_isexplain(S) interface returns 0 if S is
** an ordinary statement or a NULL pointer.
** ^The sqlite3_stmt_isexplain(S) interface returns [SQLITE_STMTMODE_EXPLAIN]
** if the prepared statement S is an EXPLAIN statement, or
** [SQLITE_STMTMODE_EQP] if the* statement S is an [EXPLAIN QUERY PLAN].
** ^The sqlite3_stmt_isexplain(S) interface returns [SQLITE_STMTMODE_RUN]
** if S is an ordinary statement or a NULL pointer.
**
** The sqlite3_stmt_isexplain(S) call is the same thing as
** [sqlite3_stmt_mode](S, [SQLITE_STMTMODE_QUERY]).
*/
int sqlite3_stmt_isexplain(sqlite3_stmt *pStmt);
/*
** CAPI3REF: Set Or Query The Operating Mode For A Prepared Statement
** METHOD: sqlite3_stmt
**
** The sqlite3_stmt_mode(S,M) attempts to change the "mode" of
** statement S to value M, where M is one of the
** [SQLITE_STMTMODE_RUN|statement mode constants]. The value
** of the statement mode (after the change) is returned. The mode
** change might be disallowed, for example if the statement is currently
** in use or for other reasons listed below. If the mode change is
** disallowed, then the original mode is returned. The only way to
** determine if mode change was effective is to compare the return value
** against the second parameter to see if they are the same.
**
** The mode cannot be changed to SQLITE_STMTMODE_RUN unless the prepared
** statement was originally compiled without either the "EXPLAIN" or
** "EXPLAIN QUERY PLAN" prefix.
**
** The mode cannot be changed to SQLITE_STMTMODE_EQP unless the
** statement was originally compiled using the "EXPLAIN QUERY PLAN"
** prefix.
**
** If M is SQLITE_STMTMODE_QUERY, then the mode is not changed but the
** current mode is still returned. This can be used to query the mode
** of a statement without changing it.
*/
int sqlite3_stmt_mode(sqlite3_stmt*,int);
/* CAPI3REF: Prepared Statement Modes
**
** These integer constants are used as the second parameter and the
** return value from the [sqlite3_stmt_mode()] interface and as the
** return value from [sqlite3_stmt_isexplain()].
**
** <ul>
** <li>[[SQLITE_STMTMODE_RUN]]
** The [SQLITE_STMTMODE_RUN] value indicates that the statement will
** run the SQL statement as normal. This is the default and usual
** mode for a prepared statement.
**
** <li>[[SQLITE_STMTMODE_EXPLAIN]]
** The [SQLITE_STMTMODE_EXPLAIN] value indicates that the statement will
** output the [bytecode] used to implement the SQL statement. This is
** the mode that a prepared statement is initialized to if the input
** SQL begins with the "EXPLAIN" keyword.
**
** <li>[[SQLITE_STMTMODE_EQP]]
** The [SQLITE_STMTMODE_EQP] value indicates that the statement is an
** [EXPLAIN QUERY PLAN] statement. In order for this mode to operate
** correctly, it is necessary to prepare the statement using the
** "EXPLAIN QUERY PLAN" keywords. If a statement is converted into
** this mode after having been prepared without the "EXPLAIN QUERY PLAN"
** prefix, then it will probably not output the query plan.
**
** <li>[[SQLITE_STMTMODE_TABLELIST]]
** The [SQLITE_STMTMODE_TABLELIST] value indicates that the statement
** will output information about all (non-transient) tables and indexes that
** are used by the prepared statement.
**
** <li>[[SQLITE_STMTMODE_QUERY]]
** The [SQLITE_STMTMODE_QUERY] value is not an actual statement mode, but
** this value can be used as the second parameter to [sqlite3_stmt_mode()]
** in order to determine the statement mode without changing it.
** </ul>
*/
#define SQLITE_STMTMODE_RUN 0
#define SQLITE_STMTMODE_EXPLAIN 1
#define SQLITE_STMTMODE_EQP 2
#define SQLITE_STMTMODE_TABLELIST 3
#define SQLITE_STMTMODE_QUERY (-1)
/*
** CAPI3REF: Determine If A Prepared Statement Has Been Reset
** METHOD: sqlite3_stmt
+12 -5
View File
@@ -2697,9 +2697,10 @@ static int SQLITE_TCLAPI test_stmt_readonly(
/*
** Usage: sqlite3_stmt_isexplain STMT
** Usage: sqlite3_stmt_mode STMT NEWMODE
**
** Return 1, 2, or 0 respectively if STMT is an EXPLAIN statement, an
** EXPLAIN QUERY PLAN statement or an ordinary statement or NULL pointer.
** Return integers 0, 1, 2, or 3 depending on the mode of STMT. If the
** 2nd argument is provided, change the mode to the integer in that argument.
*/
static int SQLITE_TCLAPI test_stmt_isexplain(
void * clientData,
@@ -2710,14 +2711,19 @@ static int SQLITE_TCLAPI test_stmt_isexplain(
sqlite3_stmt *pStmt;
int rc;
if( objc!=2 ){
if( objc!=2 && objc!=3 ){
Tcl_AppendResult(interp, "wrong # args: should be \"",
Tcl_GetStringFromObj(objv[0], 0), " STMT", 0);
return TCL_ERROR;
}
if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
rc = sqlite3_stmt_isexplain(pStmt);
if( objc==3 ){
int iNewMode = SQLITE_STMTMODE_QUERY;
if( Tcl_GetIntFromObj(interp, objv[2], &iNewMode) ) return TCL_ERROR;
rc = sqlite3_stmt_mode(pStmt, iNewMode);
}else{
rc = sqlite3_stmt_isexplain(pStmt);
}
Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
return TCL_OK;
}
@@ -7976,6 +7982,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "sqlite3_next_stmt", test_next_stmt ,0 },
{ "sqlite3_stmt_readonly", test_stmt_readonly ,0 },
{ "sqlite3_stmt_isexplain", test_stmt_isexplain,0 },
{ "sqlite3_stmt_mode", test_stmt_isexplain,0 },
{ "sqlite3_stmt_busy", test_stmt_busy ,0 },
{ "uses_stmt_journal", uses_stmt_journal ,0 },
+17 -5
View File
@@ -539,9 +539,10 @@ void sqlite3VdbeMemPrettyPrint(Mem *pMem, StrAccum *pStr){
#ifdef SQLITE_DEBUG
/*
** Print the value of a register for tracing purposes:
** Print the value of a Mem object on standard output.
** Used for tracing and for interactive debugging only.
*/
static void memTracePrint(Mem *p){
static void memPrint(Mem *p){
if( p->flags & MEM_Undefined ){
printf(" undefined");
}else if( p->flags & MEM_Null ){
@@ -567,9 +568,19 @@ static void memTracePrint(Mem *p){
}
if( p->flags & MEM_Subtype ) printf(" subtype=0x%02x", p->eSubtype);
}
/* Print N Mem objects beginning with p. Used for interactive debugging */
void sqlite3MemPrint(Mem *p, int N){
int i;
for(i=0; i<N; i++){
if( N>1 ) printf("%3d:", i);
memPrint(p+i);
printf("\n");
}
fflush(stdout);
}
static void registerTrace(int iReg, Mem *p){
printf("R[%d] = ", iReg);
memTracePrint(p);
memPrint(p);
if( p->pScopyFrom ){
printf(" <== R[%d]", (int)(p->pScopyFrom - &p[-iReg]));
}
@@ -704,8 +715,8 @@ int sqlite3VdbeExec(
assert( p->rc==SQLITE_OK || (p->rc&0xff)==SQLITE_BUSY );
assert( p->bIsReader || p->readOnly!=0 );
p->iCurrentTime = 0;
assert( p->explain==0 );
p->pResultSet = 0;
assert( p->explain==SQLITE_STMTMODE_RUN );
p->nRes = 0;
db->busyHandler.nBusy = 0;
if( db->u1.isInterrupted ) goto abort_due_to_interrupt;
sqlite3VdbeIOTraceSql(p);
@@ -1493,6 +1504,7 @@ case OP_ResultRow: {
** a side effect.
*/
pMem = p->pResultSet = &aMem[pOp->p1];
p->nRes = pOp->p2;
for(i=0; i<pOp->p2; i++){
assert( memIsValid(&pMem[i]) );
Deephemeralize(&pMem[i]);
+18 -14
View File
@@ -26,6 +26,11 @@
# define SQLITE_MAX_SCHEMA_RETRY 50
#endif
/*
** Maximum number of columns in any "EXPLAIN" output
*/
#define VDBE_EXPLAIN_COLS 9
/*
** VDBE_DISPLAY_P4 is true or false depending on whether or not the
** "explain" P4 display logic is enabled.
@@ -337,11 +342,6 @@ struct sqlite3_context {
sqlite3_value *argv[1]; /* Argument set */
};
/* A bitfield type for use inside of structures. Always follow with :N where
** N is the number of bits.
*/
typedef unsigned bft; /* Bit Field Type */
/* The ScanStatus object holds a single value for the
** sqlite3_stmt_scanstatus() interface.
*/
@@ -414,21 +414,24 @@ struct Vdbe {
int rcApp; /* errcode set by sqlite3_result_error_code() */
u32 nWrite; /* Number of write operations that have occurred */
#endif
u16 nResColumn; /* Number of columns in one row of the result set */
u16 nResColumn; /* Columns in one row of a normal result set */
u16 nRes; /* Columns in the current actual result set */
u8 errorAction; /* Recovery action to do in case of an error */
u8 minWriteFileFormat; /* Minimum file format for writable database files */
u8 prepFlags; /* SQLITE_PREPARE_* flags */
bft expired:2; /* 1: recompile VM immediately 2: when convenient */
bft explain:2; /* True if EXPLAIN present on SQL command */
bft doingRerun:1; /* True if rerunning after an auto-reprepare */
bft changeCntOn:1; /* True to update the change-counter */
bft runOnlyOnce:1; /* Automatically expire on reset */
bft usesStmtJournal:1; /* True if uses a statement journal */
bft readOnly:1; /* True for statements that do not write */
bft bIsReader:1; /* True for statements that read */
u8 explain:2; /* True if EXPLAIN present on SQL command */
u8 origExplain:2; /* The original value of explain */
u8 expired:2; /* 1: recompile VM immediately 2: when convenient */
u8 doingRerun:1; /* True if rerunning after an auto-reprepare */
u8 changeCntOn:1; /* True to update the change-counter */
u8 runOnlyOnce:1; /* Automatically expire on reset */
u8 usesStmtJournal:1; /* True if uses a statement journal */
u8 readOnly:1; /* True for statements that do not write */
u8 bIsReader:1; /* True for statements that read */
yDbMask btreeMask; /* Bitmask of db->aDb[] entries referenced */
yDbMask lockMask; /* Subset of btreeMask that requires a lock */
u32 aCounter[7]; /* Counters used by sqlite3_stmt_status() */
u32 nColName; /* Number of slots allocated to aColName[] above */
char *zSql; /* Text of the SQL statement that generated this */
#ifdef SQLITE_ENABLE_NORMALIZE
char *zNormSql; /* Normalization of the associated SQL statement */
@@ -497,6 +500,7 @@ int sqlite3VdbeIdxKeyCompare(sqlite3*,VdbeCursor*,UnpackedRecord*,int*);
int sqlite3VdbeIdxRowid(sqlite3*, BtCursor*, i64*);
int sqlite3VdbeExec(Vdbe*);
#ifndef SQLITE_OMIT_EXPLAIN
Mem *sqlite3VdbeSetExplainColumnNames(Vdbe*);
int sqlite3VdbeList(Vdbe*);
#endif
int sqlite3VdbeHalt(Vdbe*);
+32 -4
View File
@@ -996,8 +996,17 @@ int sqlite3_aggregate_count(sqlite3_context *p){
** Return the number of columns in the result set for the statement pStmt.
*/
int sqlite3_column_count(sqlite3_stmt *pStmt){
static const u8 anColumn[] = {
0, /* SQLITE_STMTMODE_RUN (Use pVm->nResColumn instead) */
8, /* SQLITE_STMTMODE_EXPLAIN */
4, /* SQLITE_STMTMODE_EQP */
5 /* SQLITE_STMTMODE_TABLELIST */
};
Vdbe *pVm = (Vdbe *)pStmt;
return pVm ? pVm->nResColumn : 0;
if( pVm==0 ) return 0;
assert( pVm->explain>=0 && pVm->explain<=3 );
if( pVm->explain==0 ) return pVm->nResColumn;
return (int)anColumn[pVm->explain];
}
/*
@@ -1006,8 +1015,8 @@ int sqlite3_column_count(sqlite3_stmt *pStmt){
*/
int sqlite3_data_count(sqlite3_stmt *pStmt){
Vdbe *pVm = (Vdbe *)pStmt;
if( pVm==0 || pVm->pResultSet==0 ) return 0;
return pVm->nResColumn;
if( pVm==0 || pVm->nRes==0 ) return 0;
return sqlite3_column_count(pStmt);
}
/*
@@ -1061,7 +1070,7 @@ static Mem *columnMem(sqlite3_stmt *pStmt, int i){
if( pVm==0 ) return (Mem*)columnNullValue();
assert( pVm->db );
sqlite3_mutex_enter(pVm->db->mutex);
if( pVm->pResultSet!=0 && i<pVm->nResColumn && i>=0 ){
if( i<pVm->nRes && i>=0 ){
pOut = &pVm->pResultSet[i];
}else{
sqlite3Error(pVm->db, SQLITE_RANGE);
@@ -1211,6 +1220,7 @@ static const void *columnName(
N += useType*n;
sqlite3_mutex_enter(db->mutex);
assert( db->mallocFailed==0 );
assert( N>=0 && N<p->nColName );
#ifndef SQLITE_OMIT_UTF16
if( useUtf16 ){
ret = sqlite3_value_text16((sqlite3_value*)&p->aColName[N]);
@@ -1683,6 +1693,24 @@ int sqlite3_stmt_isexplain(sqlite3_stmt *pStmt){
return pStmt ? ((Vdbe*)pStmt)->explain : 0;
}
/*
** Query or set the mode for a prepared statement.
*/
int sqlite3_stmt_mode(sqlite3_stmt *pStmt, int iNewMode){
Vdbe *v;
if( pStmt==0 ) return SQLITE_STMTMODE_RUN;
v = (Vdbe*)pStmt;
if( iNewMode==SQLITE_STMTMODE_EXPLAIN
|| iNewMode==SQLITE_STMTMODE_TABLELIST
|| iNewMode==v->origExplain
){
if( v->magic==VDBE_MAGIC_RUN && v->pc<0 ){
v->explain = iNewMode;
}
}
return v->explain;
}
/*
** Return true if the prepared statement is in need of being reset.
*/
+148 -83
View File
@@ -1872,7 +1872,11 @@ static void initMemArray(Mem *p, int N, sqlite3 *db, u16 flags){
}
/*
** Release an array of N Mem elements
** Release all content from an array of N Mem elements. All elements
** are left in a state of "MEM_Undefined".
**
** This routine does not free the array itself. It just frees the
** content held by the Mem elements in the array.
*/
static void releaseMemArray(Mem *p, int N){
if( p && N ){
@@ -1961,24 +1965,66 @@ void sqlite3VdbeFrameDelete(VdbeFrame *p){
sqlite3DbFree(p->v->db, p);
}
#ifndef SQLITE_OMIT_EXPLAIN
/*
** There should are VDBE_EXPLAIN_COLS*2+1 extra registers on the end of the
** Vdbe.aColName array for statements that are in one of the
** "explain" modes.
**
** * VDBE_EXPLAIN_COLS registers for the column names
** * 1 register to keep track of subprograms
** * VDBE_EXPLAIN_COLS registers to hold row output
**
** This routine makes sure those extra register exist and returns
** a pointer to the first of them. If the extra registers do
** not exist, then the are allocated.
**
** NULL is returned if there is a memory allocation error.
*/
Mem *sqlite3VdbeSetExplainColumnNames(Vdbe *p){
int n = p->nResColumn*COLNAME_N;
if( p->nColName<=n ){
static const char * const azColName[] = {
"addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment",
"id", "parent", "notused", "detail",
"schema", "name", "type", "rw", "src"
};
int iFirst, cnt, i;
Mem *pNew = sqlite3DbRealloc(p->db, p->aColName,
(n+VDBE_EXPLAIN_COLS*2+1)*sizeof(Mem));
if( pNew==0 ){
return 0;
}
p->aColName = pNew;
p->nColName = n+VDBE_EXPLAIN_COLS*2+1;
initMemArray(p->aColName+n, VDBE_EXPLAIN_COLS*2+1, p->db, MEM_Null);
if( p->explain==SQLITE_STMTMODE_EXPLAIN ){
iFirst = 0;
cnt = 8;
}else if( p->explain==SQLITE_STMTMODE_EQP ){
iFirst = 8;
cnt = 4;
}else{
iFirst = 12;
cnt = 5;
}
assert( cnt<=VDBE_EXPLAIN_COLS );
for(i=0; i<cnt; i++){
sqlite3VdbeMemSetStr(pNew+n+i, azColName[i+iFirst], -1,
SQLITE_UTF8, SQLITE_STATIC);
}
}
return p->aColName + n;
}
#endif
#ifndef SQLITE_OMIT_EXPLAIN
/*
** Give a listing of the program in the virtual machine.
**
** The interface is the same as sqlite3VdbeExec(). But instead of
** running the code, it invokes the callback once for each instruction.
** This feature is used to implement "EXPLAIN".
**
** When p->explain==1, each instruction is listed. When
** p->explain==2, only OP_Explain instructions are listed and these
** are shown in a different format. p->explain==2 is used to implement
** EXPLAIN QUERY PLAN.
** 2018-04-24: In p->explain==2 mode, the OP_Init opcodes of triggers
** are also shown, so that the boundaries between the main program and
** each trigger are clear.
**
** When p->explain==1, first the main program is listed, then each of
** the trigger subprograms are listed one by one.
** running the code, it returns rows based on the bytecode content,
** rather than on actually running the bytecode.
*/
int sqlite3VdbeList(
Vdbe *p /* The VDBE */
@@ -1990,11 +2036,13 @@ int sqlite3VdbeList(
sqlite3 *db = p->db; /* The database connection */
int i; /* Loop counter */
int rc = SQLITE_OK; /* Return code */
Mem *pMem = &p->aMem[1]; /* First Mem of result set */
int bListSubprogs = (p->explain==1 || (db->flags & SQLITE_TriggerEQP)!=0);
Mem *pMem; /* First Mem of result set */
int bListSubprogs; /* Also show subprograms */
Op *pOp = 0;
assert( p->explain );
assert( p->explain==SQLITE_STMTMODE_EXPLAIN
|| p->explain==SQLITE_STMTMODE_EQP
|| p->explain==SQLITE_STMTMODE_TABLELIST );
assert( p->magic==VDBE_MAGIC_RUN );
assert( p->rc==SQLITE_OK || p->rc==SQLITE_BUSY || p->rc==SQLITE_NOMEM );
@@ -2002,8 +2050,13 @@ int sqlite3VdbeList(
** the result, result columns may become dynamic if the user calls
** sqlite3_column_text16(), causing a translation to UTF-16 encoding.
*/
releaseMemArray(pMem, 8);
p->pResultSet = 0;
pMem = sqlite3VdbeSetExplainColumnNames(p);
if( pMem==0 ){
p->rc = SQLITE_NOMEM;
return SQLITE_ERROR;
}
pMem += VDBE_EXPLAIN_COLS;
p->nRes = 0;
if( p->rc==SQLITE_NOMEM ){
/* This happens if a malloc() inside a call to sqlite3_column_text() or
@@ -2020,13 +2073,10 @@ int sqlite3VdbeList(
** encountered, but p->pc will eventually catch up to nRow.
*/
nRow = p->nOp;
bListSubprogs = p->explain!=SQLITE_STMTMODE_EQP
|| (db->flags & SQLITE_TriggerEQP)!=0;
if( bListSubprogs ){
/* The first 8 memory cells are used for the result set. So we will
** commandeer the 9th cell to use as storage for an array of pointers
** to trigger subprograms. The VDBE is guaranteed to have at least 9
** cells. */
assert( p->nMem>9 );
pSub = &p->aMem[9];
pSub = pMem++;
if( pSub->flags&MEM_Blob ){
/* On the first call to sqlite3_step(), pSub will hold a NULL. It is
** initialized to a BLOB by the P4_SUBPROGRAM processing logic below */
@@ -2037,6 +2087,7 @@ int sqlite3VdbeList(
nRow += apSub[i]->nOp;
}
}
p->pResultSet = pMem;
while(1){ /* Loop exits via break */
i = p->pc++;
@@ -2065,7 +2116,7 @@ int sqlite3VdbeList(
/* When an OP_Program opcode is encounter (the only opcode that has
** a P4_SUBPROGRAM argument), expand the size of the array of subprograms
** kept in p->aMem[9].z to hold the new program - assuming this subprogram
** to hold the new program - assuming this subprogram
** has not already been seen.
*/
if( bListSubprogs && pOp->p4type==P4_SUBPROGRAM ){
@@ -2082,14 +2133,23 @@ int sqlite3VdbeList(
}
apSub = (SubProgram **)pSub->z;
apSub[nSub++] = pOp->p4.pProgram;
pSub->flags |= MEM_Blob;
MemSetTypeFlag(pSub, MEM_Blob);
pSub->n = nSub*sizeof(SubProgram*);
nRow += pOp->p4.pProgram->nOp;
}
}
if( p->explain<2 ) break;
if( pOp->opcode==OP_Explain ) break;
if( pOp->opcode==OP_Init && p->pc>1 ) break;
if( p->explain==SQLITE_STMTMODE_EXPLAIN ){
break; /* Show every bytecode line for SQLITE_STMTMODE_EXPLAIN */
}else if( p->explain==SQLITE_STMTMODE_EQP ){
/* Only OP_Init and OP_Explain opcodes are significant for EQP */
if( pOp->opcode==OP_Explain ) break;
if( pOp->opcode==OP_Init && p->pc>1 ) break;
}else{
/* TABLELIST wants OP_Open opcodes only */
if( pOp->opcode==OP_OpenRead ) break;
if( pOp->opcode==OP_OpenWrite && (pOp->p5 & OPFLAG_P2ISREG)==0 ) break;
if( pOp->opcode==OP_ReopenIdx ) break;
}
}
if( rc==SQLITE_OK ){
@@ -2097,32 +2157,52 @@ int sqlite3VdbeList(
p->rc = SQLITE_INTERRUPT;
rc = SQLITE_ERROR;
sqlite3VdbeError(p, sqlite3ErrStr(p->rc));
}else if( p->explain==SQLITE_STMTMODE_TABLELIST ){
Schema *pSchema;
HashElem *k;
int iDb = pOp->p3;
int iRoot = pOp->p2;
const char *zName = 0;
const char *zType = 0;
assert( iDb>=0 && iDb<db->nDb );
sqlite3VdbeMemSetStr(pMem++, db->aDb[iDb].zDbSName, -1,
SQLITE_UTF8, SQLITE_STATIC);
pSchema = db->aDb[iDb].pSchema;
for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){
Table *pTab = (Table*)sqliteHashData(k);
if( !IsVirtual(pTab) && pTab->tnum==iRoot ){
zName = pTab->zName;
zType = "table";
break;
}
}
if( zName==0 ){
for(k=sqliteHashFirst(&pSchema->idxHash); k; k=sqliteHashNext(k)){
Index *pIdx = (Index*)sqliteHashData(k);
if( pIdx->tnum==iRoot ){
zName = pIdx->zName;
zType = "index";
break;
}
}
}
sqlite3VdbeMemSetStr(pMem++, zName, -1, SQLITE_UTF8, SQLITE_STATIC);
sqlite3VdbeMemSetStr(pMem++, zType, 5, SQLITE_UTF8, SQLITE_STATIC);
sqlite3VdbeMemSetInt64(pMem++, pOp->opcode==OP_OpenWrite);
sqlite3VdbeMemSetInt64(pMem++, i<p->pc-1);
p->nRes = 5;
p->rc = SQLITE_OK;
rc = SQLITE_ROW;
}else{
char *zP4;
if( p->explain==1 ){
pMem->flags = MEM_Int;
pMem->u.i = i; /* Program counter */
pMem++;
pMem->flags = MEM_Static|MEM_Str|MEM_Term;
pMem->z = (char*)sqlite3OpcodeName(pOp->opcode); /* Opcode */
assert( pMem->z!=0 );
pMem->n = sqlite3Strlen30(pMem->z);
pMem->enc = SQLITE_UTF8;
pMem++;
if( p->explain==SQLITE_STMTMODE_EXPLAIN ){
sqlite3VdbeMemSetInt64(pMem++, i); /* Program counter */
sqlite3VdbeMemSetStr(pMem++, (char*)sqlite3OpcodeName(pOp->opcode),
-1, SQLITE_UTF8, SQLITE_STATIC);
}
pMem->flags = MEM_Int;
pMem->u.i = pOp->p1; /* P1 */
pMem++;
pMem->flags = MEM_Int;
pMem->u.i = pOp->p2; /* P2 */
pMem++;
pMem->flags = MEM_Int;
pMem->u.i = pOp->p3; /* P3 */
pMem++;
sqlite3VdbeMemSetInt64(pMem++, pOp->p1); /* P1 */
sqlite3VdbeMemSetInt64(pMem++, pOp->p2); /* P2 */
sqlite3VdbeMemSetInt64(pMem++, pOp->p3); /* P3 */
if( sqlite3VdbeMemClearAndResize(pMem, 100) ){ /* P4 */
assert( p->db->mallocFailed );
@@ -2140,7 +2220,7 @@ int sqlite3VdbeList(
}
pMem++;
if( p->explain==1 ){
if( p->explain==SQLITE_STMTMODE_EXPLAIN ){
if( sqlite3VdbeMemClearAndResize(pMem, 4) ){
assert( p->db->mallocFailed );
return SQLITE_ERROR;
@@ -2162,10 +2242,11 @@ int sqlite3VdbeList(
#else
pMem->flags = MEM_Null; /* Comment */
#endif
pMem++;
}
p->nResColumn = 8 - 4*(p->explain-1);
p->pResultSet = &p->aMem[1];
p->nRes = (int)(pMem - p->pResultSet);
assert( p->nRes<=VDBE_EXPLAIN_COLS );
p->rc = SQLITE_OK;
rc = SQLITE_ROW;
}
@@ -2369,25 +2450,7 @@ void sqlite3VdbeMakeReady(
resolveP2Values(p, &nArg);
p->usesStmtJournal = (u8)(pParse->isMultiWrite && pParse->mayAbort);
if( pParse->explain ){
static const char * const azColName[] = {
"addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment",
"id", "parent", "notused", "detail"
};
int iFirst, mx, i;
if( nMem<10 ) nMem = 10;
if( pParse->explain==2 ){
sqlite3VdbeSetNumCols(p, 4);
iFirst = 8;
mx = 12;
}else{
sqlite3VdbeSetNumCols(p, 8);
iFirst = 0;
mx = 8;
}
for(i=iFirst; i<mx; i++){
sqlite3VdbeSetColName(p, i-iFirst, COLNAME_NAME,
azColName[i], SQLITE_STATIC);
}
p->explain = p->origExplain = pParse->explain;
}
p->expired = 0;
@@ -2425,7 +2488,6 @@ void sqlite3VdbeMakeReady(
p->pVList = pParse->pVList;
pParse->pVList = 0;
p->explain = pParse->explain;
if( db->mallocFailed ){
p->nVar = 0;
p->nCursor = 0;
@@ -2563,17 +2625,20 @@ static void closeAllCursors(Vdbe *p){
** be called on an SQL statement before sqlite3_step().
*/
void sqlite3VdbeSetNumCols(Vdbe *p, int nResColumn){
int n;
sqlite3 *db = p->db;
u32 n;
if( p->nResColumn ){
releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
if( p->nColName ){
releaseMemArray(p->aColName, p->nColName);
sqlite3DbFree(db, p->aColName);
}
n = nResColumn*COLNAME_N;
p->nResColumn = (u16)nResColumn;
n = p->nColName = (u32)nResColumn*COLNAME_N;
p->aColName = (Mem*)sqlite3DbMallocRawNN(db, sizeof(Mem)*n );
if( p->aColName==0 ) return;
if( p->aColName==0 ){
p->nColName = 0;
return;
}
initMemArray(p->aColName, n, db, MEM_Null);
}
@@ -3307,7 +3372,7 @@ int sqlite3VdbeReset(Vdbe *p){
#endif
sqlite3DbFree(db, p->zErrMsg);
p->zErrMsg = 0;
p->pResultSet = 0;
p->nRes = 0;
#ifdef SQLITE_DEBUG
p->nWrite = 0;
#endif
@@ -3412,7 +3477,7 @@ void sqlite3VdbeDeleteAuxData(sqlite3 *db, AuxData **pp, int iOp, int mask){
void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){
SubProgram *pSub, *pNext;
assert( p->db==0 || p->db==db );
releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
releaseMemArray(p->aColName, p->nColName);
for(pSub=p->pProgram; pSub; pSub=pNext){
pNext = pSub->pNext;
vdbeFreeOpArray(db, pSub->aOp, pSub->nOp);
+1 -1
View File
@@ -126,7 +126,7 @@ int sqlite3WhereExplainOneScan(
){
int ret = 0;
#if !defined(SQLITE_DEBUG) && !defined(SQLITE_ENABLE_STMT_SCANSTATUS)
if( sqlite3ParseToplevel(pParse)->explain==2 )
if( sqlite3ParseToplevel(pParse)->explain==SQLITE_STMTMODE_EQP )
#endif
{
struct SrcList_item *pItem = &pTabList->a[pLevel->iFrom];
+1
View File
@@ -288,6 +288,7 @@ static Keyword aKeywordTable[] = {
{ "SELECT", "TK_SELECT", ALWAYS, 10 },
{ "SET", "TK_SET", ALWAYS, 10 },
{ "TABLE", "TK_TABLE", ALWAYS, 1 },
{ "TABLES", "TK_TABLES", EXPLAIN, 10 },
{ "TEMP", "TK_TEMP", ALWAYS, 1 },
{ "TEMPORARY", "TK_TEMP", ALWAYS, 1 },
{ "THEN", "TK_THEN", ALWAYS, 3 },