mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-03 16:53:36 +03:00
CLI enhancement: Add the ".eqp full" option, that shows both the EXPLAIN
QUERY PLAN and the EXPLAIN output for each command run. Also disable any ".wheretrace" and ".selecttrace" when showing EQP output. FossilOrigin-Name: 3e217d6265ecd16db783bed7ce1d9d0f9c4828bb
This commit is contained in:
14
manifest
14
manifest
@@ -1,5 +1,5 @@
|
||||
C In\sthe\sICU\sextension\stoupper()\sand\stolower()\sSQL\sfunctions,\savoid\scalling\su_strToUpper()\sor\su_strToLower()\sa\ssecond\stime\sif\sthe\sbuffer\spassed\sto\sthe\sfirst\sinvocation\sturns\sout\sto\sbe\slarge\senough.
|
||||
D 2016-04-14T17:29:13.982
|
||||
C CLI\senhancement:\s\sAdd\sthe\s".eqp\sfull"\soption,\sthat\sshows\sboth\sthe\sEXPLAIN\nQUERY\sPLAN\sand\sthe\sEXPLAIN\soutput\sfor\seach\scommand\srun.\s\sAlso\sdisable\nany\s".wheretrace"\sand\s".selecttrace"\swhen\sshowing\sEQP\soutput.
|
||||
D 2016-04-15T15:03:27.144
|
||||
F Makefile.in eba680121821b8a60940a81454316f47a341487a
|
||||
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
||||
F Makefile.msc 71b8b16cf9393f68e2e2035486ca104872558836
|
||||
@@ -376,7 +376,7 @@ F src/random.c ba2679f80ec82c4190062d756f22d0c358180696
|
||||
F src/resolve.c b8f7174e5f8c33c44ded3a25a973d0bb89228c20
|
||||
F src/rowset.c 9fe4b3ad7cc00944386bb600233d8f523de07a6e
|
||||
F src/select.c 30217121bdf6b587462150b8ee9e1467f7a6036b
|
||||
F src/shell.c ebcdf99f3e7c7409bd463eae443f1bd01e3e2d02
|
||||
F src/shell.c 14ff7f660530a52b117d110ba3390b7b2eb719b6
|
||||
F src/sqlite.h.in 64eb70a3b309751bebf73a5552a51244f68f0ea5
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h 98f72cbfe00169c39089115427d06ea05fe4b4a2
|
||||
@@ -1482,7 +1482,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 7b7a69d098f7581a43b818c251717c2450b797de
|
||||
R a8b6237f5057a202cac6f8ad76568fb8
|
||||
U dan
|
||||
Z 7154ea80cb4b14d420b76956f5072d2e
|
||||
P d23e581351fb8eea28e7b13b3dcadfc817c3a05f
|
||||
R e880e1f26ac9fef78137656188a6e0aa
|
||||
U drh
|
||||
Z dc2294cde78bca18f07e3e2fb59a4dd5
|
||||
|
||||
@@ -1 +1 @@
|
||||
d23e581351fb8eea28e7b13b3dcadfc817c3a05f
|
||||
3e217d6265ecd16db783bed7ce1d9d0f9c4828bb
|
||||
246
src/shell.c
246
src/shell.c
@@ -1733,7 +1733,7 @@ static void explain_data_prepare(ShellState *p, sqlite3_stmt *pSql){
|
||||
if( str_in_array(zOp, azGoto) && p2op<p->nIndent
|
||||
&& (abYield[p2op] || sqlite3_column_int(pSql, 2))
|
||||
){
|
||||
for(i=p2op+1; i<iOp; i++) p->aiIndent[i] += 2;
|
||||
for(i=p2op; i<iOp; i++) p->aiIndent[i] += 2;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1753,90 +1753,44 @@ static void explain_data_delete(ShellState *p){
|
||||
}
|
||||
|
||||
/*
|
||||
** Execute a statement or set of statements. Print
|
||||
** any result rows/columns depending on the current mode
|
||||
** set via the supplied callback.
|
||||
**
|
||||
** This is very similar to SQLite's built-in sqlite3_exec()
|
||||
** function except it takes a slightly different callback
|
||||
** and callback data argument.
|
||||
** Disable and restore .wheretrace and .selecttrace settings.
|
||||
*/
|
||||
static int shell_exec(
|
||||
sqlite3 *db, /* An open database */
|
||||
const char *zSql, /* SQL to be evaluated */
|
||||
int (*xCallback)(void*,int,char**,char**,int*), /* Callback function */
|
||||
/* (not the same as sqlite3_exec) */
|
||||
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
|
||||
extern int sqlite3SelectTrace;
|
||||
static int savedSelectTrace;
|
||||
#endif
|
||||
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
|
||||
extern int sqlite3WhereTrace;
|
||||
static int savedWhereTrace;
|
||||
#endif
|
||||
static void disable_debug_trace_modes(void){
|
||||
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
|
||||
savedSelectTrace = sqlite3SelectTrace;
|
||||
sqlite3SelectTrace = 0;
|
||||
#endif
|
||||
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
|
||||
savedWhereTrace = sqlite3WhereTrace;
|
||||
sqlite3WhereTrace = 0;
|
||||
#endif
|
||||
}
|
||||
static void restore_debug_trace_modes(void){
|
||||
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
|
||||
sqlite3SelectTrace = savedSelectTrace;
|
||||
#endif
|
||||
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
|
||||
sqlite3WhereTrace = savedWhereTrace;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** Run a prepared statement
|
||||
*/
|
||||
static void exec_prepared_stmt(
|
||||
ShellState *pArg, /* Pointer to ShellState */
|
||||
char **pzErrMsg /* Error msg written here */
|
||||
sqlite3_stmt *pStmt, /* Statment to run */
|
||||
int (*xCallback)(void*,int,char**,char**,int*) /* Callback function */
|
||||
){
|
||||
sqlite3_stmt *pStmt = NULL; /* Statement to execute. */
|
||||
int rc = SQLITE_OK; /* Return Code */
|
||||
int rc2;
|
||||
const char *zLeftover; /* Tail of unprocessed SQL */
|
||||
|
||||
if( pzErrMsg ){
|
||||
*pzErrMsg = NULL;
|
||||
}
|
||||
|
||||
while( zSql[0] && (SQLITE_OK == rc) ){
|
||||
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover);
|
||||
if( SQLITE_OK != rc ){
|
||||
if( pzErrMsg ){
|
||||
*pzErrMsg = save_err_msg(db);
|
||||
}
|
||||
}else{
|
||||
if( !pStmt ){
|
||||
/* this happens for a comment or white-space */
|
||||
zSql = zLeftover;
|
||||
while( IsSpace(zSql[0]) ) zSql++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* save off the prepared statment handle and reset row count */
|
||||
if( pArg ){
|
||||
pArg->pStmt = pStmt;
|
||||
pArg->cnt = 0;
|
||||
}
|
||||
|
||||
/* echo the sql statement if echo on */
|
||||
if( pArg && pArg->echoOn ){
|
||||
const char *zStmtSql = sqlite3_sql(pStmt);
|
||||
utf8_printf(pArg->out, "%s\n", zStmtSql ? zStmtSql : zSql);
|
||||
}
|
||||
|
||||
/* Show the EXPLAIN QUERY PLAN if .eqp is on */
|
||||
if( pArg && pArg->autoEQP ){
|
||||
sqlite3_stmt *pExplain;
|
||||
char *zEQP = sqlite3_mprintf("EXPLAIN QUERY PLAN %s",
|
||||
sqlite3_sql(pStmt));
|
||||
rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
while( sqlite3_step(pExplain)==SQLITE_ROW ){
|
||||
raw_printf(pArg->out,"--EQP-- %d,",sqlite3_column_int(pExplain, 0));
|
||||
raw_printf(pArg->out,"%d,", sqlite3_column_int(pExplain, 1));
|
||||
raw_printf(pArg->out,"%d,", sqlite3_column_int(pExplain, 2));
|
||||
utf8_printf(pArg->out,"%s\n", sqlite3_column_text(pExplain, 3));
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(pExplain);
|
||||
sqlite3_free(zEQP);
|
||||
}
|
||||
|
||||
if( pArg ){
|
||||
pArg->cMode = pArg->mode;
|
||||
if( pArg->autoExplain
|
||||
&& sqlite3_column_count(pStmt)==8
|
||||
&& sqlite3_strlike("%EXPLAIN%", sqlite3_sql(pStmt),0)==0
|
||||
){
|
||||
pArg->cMode = MODE_Explain;
|
||||
}
|
||||
|
||||
/* If the shell is currently in ".explain" mode, gather the extra
|
||||
** data required to add indents to the output.*/
|
||||
if( pArg->cMode==MODE_Explain ){
|
||||
explain_data_prepare(pArg, pStmt);
|
||||
}
|
||||
}
|
||||
int rc;
|
||||
|
||||
/* perform the first step. this will tell us if we
|
||||
** have a result set or not and how wide it is.
|
||||
@@ -1894,7 +1848,112 @@ static int shell_exec(
|
||||
} while( rc == SQLITE_ROW );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Execute a statement or set of statements. Print
|
||||
** any result rows/columns depending on the current mode
|
||||
** set via the supplied callback.
|
||||
**
|
||||
** This is very similar to SQLite's built-in sqlite3_exec()
|
||||
** function except it takes a slightly different callback
|
||||
** and callback data argument.
|
||||
*/
|
||||
static int shell_exec(
|
||||
sqlite3 *db, /* An open database */
|
||||
const char *zSql, /* SQL to be evaluated */
|
||||
int (*xCallback)(void*,int,char**,char**,int*), /* Callback function */
|
||||
/* (not the same as sqlite3_exec) */
|
||||
ShellState *pArg, /* Pointer to ShellState */
|
||||
char **pzErrMsg /* Error msg written here */
|
||||
){
|
||||
sqlite3_stmt *pStmt = NULL; /* Statement to execute. */
|
||||
int rc = SQLITE_OK; /* Return Code */
|
||||
int rc2;
|
||||
const char *zLeftover; /* Tail of unprocessed SQL */
|
||||
|
||||
if( pzErrMsg ){
|
||||
*pzErrMsg = NULL;
|
||||
}
|
||||
|
||||
while( zSql[0] && (SQLITE_OK == rc) ){
|
||||
static const char *zStmtSql;
|
||||
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover);
|
||||
if( SQLITE_OK != rc ){
|
||||
if( pzErrMsg ){
|
||||
*pzErrMsg = save_err_msg(db);
|
||||
}
|
||||
}else{
|
||||
if( !pStmt ){
|
||||
/* this happens for a comment or white-space */
|
||||
zSql = zLeftover;
|
||||
while( IsSpace(zSql[0]) ) zSql++;
|
||||
continue;
|
||||
}
|
||||
zStmtSql = sqlite3_sql(pStmt);
|
||||
while( IsSpace(zStmtSql[0]) ) zStmtSql++;
|
||||
|
||||
/* save off the prepared statment handle and reset row count */
|
||||
if( pArg ){
|
||||
pArg->pStmt = pStmt;
|
||||
pArg->cnt = 0;
|
||||
}
|
||||
|
||||
/* echo the sql statement if echo on */
|
||||
if( pArg && pArg->echoOn ){
|
||||
utf8_printf(pArg->out, "%s\n", zStmtSql ? zStmtSql : zSql);
|
||||
}
|
||||
|
||||
/* Show the EXPLAIN QUERY PLAN if .eqp is on */
|
||||
if( pArg && pArg->autoEQP && sqlite3_strlike("EXPLAIN%",zStmtSql,0)!=0 ){
|
||||
sqlite3_stmt *pExplain;
|
||||
char *zEQP;
|
||||
disable_debug_trace_modes();
|
||||
zEQP = sqlite3_mprintf("EXPLAIN QUERY PLAN %s", zStmtSql);
|
||||
rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
while( sqlite3_step(pExplain)==SQLITE_ROW ){
|
||||
raw_printf(pArg->out,"--EQP-- %d,",sqlite3_column_int(pExplain, 0));
|
||||
raw_printf(pArg->out,"%d,", sqlite3_column_int(pExplain, 1));
|
||||
raw_printf(pArg->out,"%d,", sqlite3_column_int(pExplain, 2));
|
||||
utf8_printf(pArg->out,"%s\n", sqlite3_column_text(pExplain, 3));
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(pExplain);
|
||||
sqlite3_free(zEQP);
|
||||
if( pArg->autoEQP>=2 ){
|
||||
/* Also do an EXPLAIN for ".eqp full" mode */
|
||||
zEQP = sqlite3_mprintf("EXPLAIN %s", zStmtSql);
|
||||
rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
pArg->cMode = MODE_Explain;
|
||||
explain_data_prepare(pArg, pExplain);
|
||||
exec_prepared_stmt(pArg, pExplain, xCallback);
|
||||
explain_data_delete(pArg);
|
||||
}
|
||||
sqlite3_finalize(pExplain);
|
||||
sqlite3_free(zEQP);
|
||||
}
|
||||
restore_debug_trace_modes();
|
||||
}
|
||||
|
||||
if( pArg ){
|
||||
pArg->cMode = pArg->mode;
|
||||
if( pArg->autoExplain
|
||||
&& sqlite3_column_count(pStmt)==8
|
||||
&& sqlite3_strlike("EXPLAIN%", zStmtSql,0)==0
|
||||
){
|
||||
pArg->cMode = MODE_Explain;
|
||||
}
|
||||
|
||||
/* If the shell is currently in ".explain" mode, gather the extra
|
||||
** data required to add indents to the output.*/
|
||||
if( pArg->cMode==MODE_Explain ){
|
||||
explain_data_prepare(pArg, pStmt);
|
||||
}
|
||||
}
|
||||
|
||||
exec_prepared_stmt(pArg, pStmt, xCallback);
|
||||
explain_data_delete(pArg);
|
||||
|
||||
/* print usage stats if stats on */
|
||||
@@ -2084,7 +2143,7 @@ static char zHelp[] =
|
||||
" If TABLE specified, only dump tables matching\n"
|
||||
" LIKE pattern TABLE.\n"
|
||||
".echo on|off Turn command echo on or off\n"
|
||||
".eqp on|off Enable or disable automatic EXPLAIN QUERY PLAN\n"
|
||||
".eqp on|off|full Enable or disable automatic EXPLAIN QUERY PLAN\n"
|
||||
".exit Exit this program\n"
|
||||
".explain ?on|off|auto? Turn EXPLAIN output mode on or off or to automatic\n"
|
||||
".fullschema ?--indent? Show schema and the content of sqlite_stat tables\n"
|
||||
@@ -3254,9 +3313,13 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
|
||||
if( c=='e' && strncmp(azArg[0], "eqp", n)==0 ){
|
||||
if( nArg==2 ){
|
||||
p->autoEQP = booleanValue(azArg[1]);
|
||||
if( strcmp(azArg[1],"full")==0 ){
|
||||
p->autoEQP = 2;
|
||||
}else{
|
||||
raw_printf(stderr, "Usage: .eqp on|off\n");
|
||||
p->autoEQP = booleanValue(azArg[1]);
|
||||
}
|
||||
}else{
|
||||
raw_printf(stderr, "Usage: .eqp on|off|full\n");
|
||||
rc = 1;
|
||||
}
|
||||
}else
|
||||
@@ -4017,7 +4080,6 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
|
||||
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
|
||||
if( c=='s' && n==11 && strncmp(azArg[0], "selecttrace", n)==0 ){
|
||||
extern int sqlite3SelectTrace;
|
||||
sqlite3SelectTrace = integerValue(azArg[1]);
|
||||
}else
|
||||
#endif
|
||||
@@ -4277,17 +4339,18 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
}else
|
||||
|
||||
if( c=='s' && strncmp(azArg[0], "show", n)==0 ){
|
||||
static const char *azBool[] = { "off", "on", "full", "unk" };
|
||||
int i;
|
||||
if( nArg!=1 ){
|
||||
raw_printf(stderr, "Usage: .show\n");
|
||||
rc = 1;
|
||||
goto meta_command_exit;
|
||||
}
|
||||
utf8_printf(p->out, "%12.12s: %s\n","echo", p->echoOn ? "on" : "off");
|
||||
utf8_printf(p->out, "%12.12s: %s\n","eqp", p->autoEQP ? "on" : "off");
|
||||
utf8_printf(p->out, "%12.12s: %s\n","echo", azBool[p->echoOn!=0]);
|
||||
utf8_printf(p->out, "%12.12s: %s\n","eqp", azBool[p->autoEQP&3]);
|
||||
utf8_printf(p->out, "%12.12s: %s\n","explain",
|
||||
p->mode==MODE_Explain ? "on" : p->autoExplain ? "auto" : "off");
|
||||
utf8_printf(p->out,"%12.12s: %s\n","headers", p->showHeader ? "on" : "off");
|
||||
utf8_printf(p->out,"%12.12s: %s\n","headers", azBool[p->showHeader!=0]);
|
||||
utf8_printf(p->out, "%12.12s: %s\n","mode", modeDescr[p->mode]);
|
||||
utf8_printf(p->out, "%12.12s: ", "nullvalue");
|
||||
output_c_string(p->out, p->nullValue);
|
||||
@@ -4300,7 +4363,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
utf8_printf(p->out,"%12.12s: ", "rowseparator");
|
||||
output_c_string(p->out, p->rowSeparator);
|
||||
raw_printf(p->out, "\n");
|
||||
utf8_printf(p->out, "%12.12s: %s\n","stats", p->statsOn ? "on" : "off");
|
||||
utf8_printf(p->out, "%12.12s: %s\n","stats", azBool[p->statsOn!=0]);
|
||||
utf8_printf(p->out, "%12.12s: ", "width");
|
||||
for (i=0;i<(int)ArraySize(p->colWidth) && p->colWidth[i] != 0;i++) {
|
||||
raw_printf(p->out, "%d ", p->colWidth[i]);
|
||||
@@ -4715,7 +4778,6 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
|
||||
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
|
||||
if( c=='w' && strncmp(azArg[0], "wheretrace", n)==0 ){
|
||||
extern int sqlite3WhereTrace;
|
||||
sqlite3WhereTrace = nArg>=2 ? booleanValue(azArg[1]) : 0xff;
|
||||
}else
|
||||
#endif
|
||||
@@ -5383,6 +5445,8 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
|
||||
data.echoOn = 1;
|
||||
}else if( strcmp(z,"-eqp")==0 ){
|
||||
data.autoEQP = 1;
|
||||
}else if( strcmp(z,"-eqpfull")==0 ){
|
||||
data.autoEQP = 2;
|
||||
}else if( strcmp(z,"-stats")==0 ){
|
||||
data.statsOn = 1;
|
||||
}else if( strcmp(z,"-scanstats")==0 ){
|
||||
|
||||
Reference in New Issue
Block a user