From: drh Date: Thu, 19 Mar 2020 21:17:11 +0000 (+0000) Subject: Initial code for a proposed new sqlite3_stmt_mode() API. X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=8e8c2f149885f8ca64f5b35c68a27bf1fd57934d;p=thirdparty%2Fsqlite.git Initial code for a proposed new sqlite3_stmt_mode() API. This is an incomplete snapshot of a work-in-progress. FossilOrigin-Name: 3cf7537b5e14e218218b18b3c0c668c950a71fcddc68a5faf0f197519718a6c2 --- diff --git a/manifest b/manifest index 145549d62a..67aab6cc0c 100644 --- a/manifest +++ b/manifest @@ -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 Initial\scode\sfor\sa\sproposed\snew\ssqlite3_stmt_mode()\sAPI.\nThis\sis\san\sincomplete\ssnapshot\sof\sa\swork-in-progress. +D 2020-03-19T21:17:11.830 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 a6d7151326370346817560153c44dc73860c43e775fe43789981336910914dd2 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 ca986d3f9961045256c1b077a6986cd2e9cfa86909adfd0acafb761e6656b5bb F src/vdbe.h 51282fbe819ee0e8eeeaab176240860d334c20a12b14f3b363e7f1a4e05d60b9 -F src/vdbeInt.h a17146053a1aa438474012998fe07e314f3df274a61491ad838ad85d848ac051 -F src/vdbeapi.c 1252d80c548711e47a6d84dae88ed4e95d3fbb4e7bd0eaa1347299af7efddf02 -F src/vdbeaux.c e8baf66528e36474f4071e3171b660a454606eb5b54459a729982c939ad7a5bb +F src/vdbeInt.h a341e6994ffd865531089f0c94d3910acc66d25d312259c4a45f422693deab9b +F src/vdbeapi.c e8351c4f351e492e260fb8b0f9f57575772f583fbbe97dca4c31dcadd06760d6 +F src/vdbeaux.c ce2521d1979d6e081c21766523244891149df247092202db3a0e097f4eae40f2 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 @@ -1860,7 +1860,10 @@ 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 11e0844f71e8f2d27ce9363fb505e02fd7795c61dae0b3886cf0d8df4484dd97 +R bfd344317fdbc4dd2c74ef078364da12 +T *branch * sqlite3_stmt_mode +T *sym-sqlite3_stmt_mode * +T -sym-trunk * U drh -Z 2c8ae1f04515bf2ea893e9cb3af9713c +Z 4fdf6d3f28007c100776cbe88029096e diff --git a/manifest.uuid b/manifest.uuid index 6dd6aeb2a7..05aae7265e 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -11e0844f71e8f2d27ce9363fb505e02fd7795c61dae0b3886cf0d8df4484dd97 \ No newline at end of file +3cf7537b5e14e218218b18b3c0c668c950a71fcddc68a5faf0f197519718a6c2 \ No newline at end of file diff --git a/src/parse.y b/src/parse.y index c321daf195..0b6cf95bd4 100644 --- a/src/parse.y +++ b/src/parse.y @@ -121,8 +121,8 @@ 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; } +explain ::= EXPLAIN. { pParse->explain = SQLITE_STMTMODE_EXPLAIN; } +explain ::= EXPLAIN QUERY PLAN. { pParse->explain = SQLITE_STMTMODE_EQP; } %endif SQLITE_OMIT_EXPLAIN cmdx ::= cmd. { sqlite3FinishCoding(pParse); } diff --git a/src/resolve.c b/src/resolve.c index 05ef0c06eb..e69405db24 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -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); diff --git a/src/select.c b/src/select.c index 3128d482a9..eed610a048 100644 --- a/src/select.c +++ b/src/select.c @@ -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, diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 7b2049ae0a..f97d4f65d0 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -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()]. +** +** +*/ +#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 diff --git a/src/test1.c b/src/test1.c index 29207d51ac..78d4f897b1 100644 --- a/src/test1.c +++ b/src/test1.c @@ -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 }, diff --git a/src/vdbe.c b/src/vdbe.c index 7f05328660..1eae9c6294 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -704,7 +704,7 @@ 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 ); + assert( p->explain==SQLITE_STMTMODE_RUN ); p->pResultSet = 0; db->busyHandler.nBusy = 0; if( db->u1.isInterrupted ) goto abort_due_to_interrupt; diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 8102831624..1717d64a6f 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -420,6 +420,7 @@ struct Vdbe { 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 origExplain:2; /* The original value of explain */ 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 */ @@ -429,6 +430,7 @@ struct Vdbe { 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 */ diff --git a/src/vdbeapi.c b/src/vdbeapi.c index 074d458815..c007a77121 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -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 */ + 6 /* 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]; } /* @@ -1211,6 +1220,7 @@ static const void *columnName( N += useType*n; sqlite3_mutex_enter(db->mutex); assert( db->mallocFailed==0 ); + assert( N>=0 && NnColName ); #ifndef SQLITE_OMIT_UTF16 if( useUtf16 ){ ret = sqlite3_value_text16((sqlite3_value*)&p->aColName[N]); @@ -1683,6 +1693,22 @@ 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 + ){ + v->explain = iNewMode; + } + return v->explain; +} + /* ** Return true if the prepared statement is in need of being reset. */ diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 6afbf9a5a5..41b7e7bcc6 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -2388,6 +2388,7 @@ void sqlite3VdbeMakeReady( sqlite3VdbeSetColName(p, i-iFirst, COLNAME_NAME, azColName[i], SQLITE_STATIC); } + p->explain = p->origExplain = pParse->explain; } p->expired = 0; @@ -2425,7 +2426,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 +2563,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); } @@ -3412,7 +3415,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); diff --git a/src/wherecode.c b/src/wherecode.c index 4e8b211700..7bc3ceece0 100644 --- a/src/wherecode.c +++ b/src/wherecode.c @@ -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];