-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
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
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
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[] */
};
/*
}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": " ");
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
}
}
+ /* 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.
*/
}
}
+ explain_data_delete(pArg);
+
/* print usage stats if stats on */
if( pArg && pArg->statsOn ){
display_stats(db, pArg, 0);