In the shell tool, if an "EXPLAIN" command is executed in ".explain on" mode, attempt to automatically indent the bodies of loops in the output VDBE program.
FossilOrigin-Name: e7d34ec6814ed4606a6d5d7f68c218ae4d25e666
This commit is contained in:
parent
84e55a80db
commit
a98bf365fe
14
manifest
14
manifest
@ -1,5 +1,5 @@
|
||||
C Add\sthe\s"PRAGMA\svdbe_eqp"\scommand,\sonly\savailable\swith\sSQLITE_DEBUG.\s\sSimplify\nsome\sof\sthe\sother\sdebugging\slogic.
|
||||
D 2013-11-13T17:58:23.573
|
||||
C In\sthe\sshell\stool,\sif\san\s"EXPLAIN"\scommand\sis\sexecuted\sin\s".explain\son"\smode,\sattempt\sto\sautomatically\sindent\sthe\sbodies\sof\sloops\sin\sthe\soutput\sVDBE\sprogram.
|
||||
D 2013-11-13T18:35:01.894
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in 8a07bebafbfda0eb67728f4bd15a36201662d1a1
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
@ -220,7 +220,7 @@ F src/random.c 0b2dbc37fdfbfa6bd455b091dfcef5bdb32dba68
|
||||
F src/resolve.c fc4673cc49b116e51e7f12de074c0acf8f2388f9
|
||||
F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0
|
||||
F src/select.c 7317406831ecced390edba972818f3c5f82238c0
|
||||
F src/shell.c 03d8d9b4052430343ff30d646334621f980f1202
|
||||
F src/shell.c 3b23017da75118da0a7e3518c6ce78a7b747fb05
|
||||
F src/sqlite.h.in 4dedcab5b32358bf7a596badffe7363be1f1a82d
|
||||
F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e
|
||||
F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
|
||||
@ -1138,7 +1138,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381
|
||||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||
F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
|
||||
F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
|
||||
P 5196000930600d0cd931b87e864507791b9dab08
|
||||
R f5035ff28ea611640fd4871588416d7f
|
||||
U drh
|
||||
Z f0bce2e671cb5c826c0cf7f8a42a33dc
|
||||
P 8ce33f4c818e1c785a1c176f6f631b8184e1166b
|
||||
R 5d7c6b4eb6f0cadad72d4cdb7ed00f79
|
||||
U dan
|
||||
Z 87b1c90d92386c54cb5a5e86314bc13e
|
||||
|
@ -1 +1 @@
|
||||
8ce33f4c818e1c785a1c176f6f631b8184e1166b
|
||||
e7d34ec6814ed4606a6d5d7f68c218ae4d25e666
|
102
src/shell.c
102
src/shell.c
@ -464,6 +464,8 @@ struct callback_data {
|
||||
const char *zVfs; /* Name of VFS to use */
|
||||
sqlite3_stmt *pStmt; /* Current statement if any. */
|
||||
FILE *pLog; /* Write log output here */
|
||||
int *aiIndent; /* Array of indents used in MODE_Explain */
|
||||
int nIndent; /* Size of array aiIndent[] */
|
||||
};
|
||||
|
||||
/*
|
||||
@ -765,10 +767,15 @@ static int shell_callback(void *pArg, int nArg, char **azArg, char **azCol, int
|
||||
}else{
|
||||
w = 10;
|
||||
}
|
||||
if( p->mode==MODE_Explain && azArg[i] &&
|
||||
strlen30(azArg[i])>w ){
|
||||
if( p->mode==MODE_Explain && azArg[i] && strlen30(azArg[i])>w ){
|
||||
w = strlen30(azArg[i]);
|
||||
}
|
||||
if( i==1 && p->aiIndent && p->pStmt ){
|
||||
int iOp = sqlite3_column_int(p->pStmt, 0);
|
||||
if( iOp<p->nIndent ){
|
||||
fprintf(p->out, "%*.s", p->aiIndent[iOp], "");
|
||||
}
|
||||
}
|
||||
if( w<0 ){
|
||||
fprintf(p->out,"%*.*s%s",-w,-w,
|
||||
azArg[i] ? azArg[i] : p->nullvalue, i==nArg-1 ? "\n": " ");
|
||||
@ -1141,6 +1148,89 @@ static int display_stats(
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Parameter azArray points to a zero-terminated array of strings. zStr
|
||||
** points to a single nul-terminated string. Return non-zero if zStr
|
||||
** is equal, according to strcmp(), to any of the strings in the array.
|
||||
** Otherwise, return zero.
|
||||
*/
|
||||
static int str_in_array(const char *zStr, const char **azArray){
|
||||
int i;
|
||||
for(i=0; azArray[i]; i++){
|
||||
if( 0==strcmp(zStr, azArray[i]) ) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** If compiled statement pSql appears to be an EXPLAIN statement, allocate
|
||||
** and populate the callback_data.aiIndent[] array with the number of
|
||||
** spaces each opcode should be indented before it is output.
|
||||
**
|
||||
** The indenting rules are:
|
||||
**
|
||||
** * For each "Next", "Prev", "VNext" or "VPrev" instruction, indent
|
||||
** all opcodes that occur between the p2 jump destination and the opcode
|
||||
** itself by 2 spaces.
|
||||
**
|
||||
** * For each "Goto", if the jump destination is a "Yield" instruction
|
||||
** that occurs earlier in the program than the Goto itself, indent
|
||||
** all opcodes between the "Yield" and "Goto" by 2 spaces.
|
||||
*/
|
||||
static void explain_data_prepare(struct callback_data *p, sqlite3_stmt *pSql){
|
||||
const char *zSql; /* The text of the SQL statement */
|
||||
const char *z; /* Used to check if this is an EXPLAIN */
|
||||
int *abYield = 0; /* True if op is an OP_Yield */
|
||||
int nAlloc = 0; /* Allocated size of p->aiIndent[], abYield */
|
||||
int iOp;
|
||||
|
||||
const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", 0 };
|
||||
const char *azYield[] = { "Yield", 0 };
|
||||
const char *azGoto[] = { "Goto", 0 };
|
||||
|
||||
/* Try to figure out if this is really an EXPLAIN statement. If this
|
||||
** cannot be verified, return early. */
|
||||
zSql = sqlite3_sql(pSql);
|
||||
if( zSql==0 ) return;
|
||||
for(z=zSql; *z==' ' || *z=='\t' || *z=='\n' || *z=='\f' || *z=='\r'; z++);
|
||||
if( sqlite3_strnicmp(z, "explain", 7) ) return;
|
||||
|
||||
for(iOp=0; SQLITE_ROW==sqlite3_step(pSql); iOp++){
|
||||
int i;
|
||||
const char *zOp = (const char*)sqlite3_column_text(pSql, 1);
|
||||
int p2 = sqlite3_column_int(pSql, 3);
|
||||
|
||||
/* Grow the p->aiIndent array as required */
|
||||
if( iOp>=nAlloc ){
|
||||
nAlloc += 100;
|
||||
p->aiIndent = (int*)sqlite3_realloc(p->aiIndent, nAlloc*sizeof(int));
|
||||
abYield = (int*)sqlite3_realloc(abYield, nAlloc*sizeof(int));
|
||||
}
|
||||
abYield[iOp] = str_in_array(zOp, azYield);
|
||||
p->aiIndent[iOp] = 0;
|
||||
p->nIndent = iOp+1;
|
||||
|
||||
if( str_in_array(zOp, azNext) ){
|
||||
for(i=p2; i<iOp; i++) p->aiIndent[i] += 2;
|
||||
}
|
||||
if( str_in_array(zOp, azGoto) && p2<p->nIndent && abYield[p2] ){
|
||||
for(i=p2+1; i<iOp; i++) p->aiIndent[i] += 2;
|
||||
}
|
||||
}
|
||||
|
||||
sqlite3_free(abYield);
|
||||
sqlite3_reset(pSql);
|
||||
}
|
||||
|
||||
/*
|
||||
** Free the array allocated by explain_data_prepare().
|
||||
*/
|
||||
static void explain_data_delete(struct callback_data *p){
|
||||
sqlite3_free(p->aiIndent);
|
||||
p->aiIndent = 0;
|
||||
p->nIndent = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Execute a statement or set of statements. Print
|
||||
** any result rows/columns depending on the current mode
|
||||
@ -1202,6 +1292,12 @@ static int shell_exec(
|
||||
}
|
||||
}
|
||||
|
||||
/* If the shell is currently in ".explain" mode, gather the extra
|
||||
** data required to add indents to the output.*/
|
||||
if( pArg->mode==MODE_Explain ){
|
||||
explain_data_prepare(pArg, pStmt);
|
||||
}
|
||||
|
||||
/* perform the first step. this will tell us if we
|
||||
** have a result set or not and how wide it is.
|
||||
*/
|
||||
@ -1259,6 +1355,8 @@ static int shell_exec(
|
||||
}
|
||||
}
|
||||
|
||||
explain_data_delete(pArg);
|
||||
|
||||
/* print usage stats if stats on */
|
||||
if( pArg && pArg->statsOn ){
|
||||
display_stats(db, pArg, 0);
|
||||
|
Loading…
x
Reference in New Issue
Block a user