aboutsummaryrefslogtreecommitdiff
path: root/src/shell.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/shell.c')
-rw-r--r--src/shell.c38
1 files changed, 25 insertions, 13 deletions
diff --git a/src/shell.c b/src/shell.c
index 61df7d6d5..1db1e64e7 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -466,6 +466,7 @@ struct callback_data {
FILE *pLog; /* Write log output here */
int *aiIndent; /* Array of indents used in MODE_Explain */
int nIndent; /* Size of array aiIndent[] */
+ int iIndent; /* Index of current op in aiIndent[] */
};
/*
@@ -771,10 +772,10 @@ static int shell_callback(void *pArg, int nArg, char **azArg, char **azCol, int
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( p->iIndent<p->nIndent ){
+ fprintf(p->out, "%*.s", p->aiIndent[p->iIndent], "");
}
+ p->iIndent++;
}
if( w<0 ){
fprintf(p->out,"%*.*s%s",-w,-w,
@@ -1173,9 +1174,10 @@ static int str_in_array(const char *zStr, const char **azArray){
** 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", "SeekGt",
-** or "SeekLt" instruction that occurs earlier in the program than
-** the Goto itself, indent all opcodes between the earlier instruction
+** * For each "Goto", if the jump destination is earlier in the program
+** and ends on one of:
+** Yield SeekGt SeekLt RowSetRead
+** then indent all opcodes between the earlier instruction
** and "Goto" by 2 spaces.
*/
static void explain_data_prepare(struct callback_data *p, sqlite3_stmt *pSql){
@@ -1183,10 +1185,10 @@ static void explain_data_prepare(struct callback_data *p, sqlite3_stmt *pSql){
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;
+ int iOp; /* Index of operation in p->aiIndent[] */
- const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", 0 };
- const char *azYield[] = { "Yield", "SeekLt", "SeekGt", 0 };
+ const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext", 0 };
+ const char *azYield[] = { "Yield", "SeekLt", "SeekGt", "RowSetRead", 0 };
const char *azGoto[] = { "Goto", 0 };
/* Try to figure out if this is really an EXPLAIN statement. If this
@@ -1198,8 +1200,16 @@ static void explain_data_prepare(struct callback_data *p, sqlite3_stmt *pSql){
for(iOp=0; SQLITE_ROW==sqlite3_step(pSql); iOp++){
int i;
+ int iAddr = sqlite3_column_int(pSql, 0);
const char *zOp = (const char*)sqlite3_column_text(pSql, 1);
+
+ /* Set p2 to the P2 field of the current opcode. Then, assuming that
+ ** p2 is an instruction address, set variable p2op to the index of that
+ ** instruction in the aiIndent[] array. p2 and p2op may be different if
+ ** the current instruction is part of a sub-program generated by an
+ ** SQL trigger or foreign key. */
int p2 = sqlite3_column_int(pSql, 3);
+ int p2op = (p2 + (iOp-iAddr));
/* Grow the p->aiIndent array as required */
if( iOp>=nAlloc ){
@@ -1212,13 +1222,14 @@ static void explain_data_prepare(struct callback_data *p, sqlite3_stmt *pSql){
p->nIndent = iOp+1;
if( str_in_array(zOp, azNext) ){
- for(i=p2; i<iOp; i++) p->aiIndent[i] += 2;
+ for(i=p2op; 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;
+ if( str_in_array(zOp, azGoto) && p2op<p->nIndent && abYield[p2op] ){
+ for(i=p2op; i<iOp; i++) p->aiIndent[i] += 2;
}
}
+ p->iIndent = 0;
sqlite3_free(abYield);
sqlite3_reset(pSql);
}
@@ -1230,6 +1241,7 @@ static void explain_data_delete(struct callback_data *p){
sqlite3_free(p->aiIndent);
p->aiIndent = 0;
p->nIndent = 0;
+ p->iIndent = 0;
}
/*
@@ -1295,7 +1307,7 @@ 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 ){
+ if( pArg && pArg->mode==MODE_Explain ){
explain_data_prepare(pArg, pStmt);
}