-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
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
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
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
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
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
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
-11e0844f71e8f2d27ce9363fb505e02fd7795c61dae0b3886cf0d8df4484dd97
\ No newline at end of file
+3cf7537b5e14e218218b18b3c0c668c950a71fcddc68a5faf0f197519718a6c2
\ No newline at end of file
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); }
#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);
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,
** 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
/*
** 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,
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;
}
{ "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 },
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;
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 */
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 */
** 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];
}
/*
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]);
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.
*/
sqlite3VdbeSetColName(p, i-iFirst, COLNAME_NAME,
azColName[i], SQLITE_STATIC);
}
+ p->explain = p->origExplain = pParse->explain;
}
p->expired = 0;
p->pVList = pParse->pVList;
pParse->pVList = 0;
- p->explain = pParse->explain;
if( db->mallocFailed ){
p->nVar = 0;
p->nCursor = 0;
** 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);
}
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);
){
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];