diff options
Diffstat (limited to 'src/shell.c')
-rw-r--r-- | src/shell.c | 38 |
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); } |