Index: src/shell.c ================================================================== --- src/shell.c +++ src/shell.c @@ -464,10 +464,11 @@ 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[] */ + int iIndent; /* Index of current op in aiIndent[] */ }; /* ** These are the allowed modes. */ @@ -769,14 +770,14 @@ } 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( iOpnIndent ){ - fprintf(p->out, "%*.s", p->aiIndent[iOp], ""); + if( p->iIndentnIndent ){ + fprintf(p->out, "%*.s", p->aiIndent[p->iIndent], ""); } + p->iIndent++; } if( w<0 ){ fprintf(p->out,"%*.*s%s",-w,-w, azArg[i] ? azArg[i] : p->nullvalue, i==nArg-1 ? "\n": " "); }else{ @@ -1182,11 +1183,11 @@ 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; + int iOp; /* Index of operation in p->aiIndent[] */ const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext", 0 }; const char *azYield[] = { "Yield", "SeekLt", "SeekGt", "RowSetRead", 0 }; const char *azGoto[] = { "Goto", 0 }; @@ -1197,12 +1198,20 @@ 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; + 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 ){ nAlloc += 100; p->aiIndent = (int*)sqlite3_realloc(p->aiIndent, nAlloc*sizeof(int)); @@ -1211,17 +1220,18 @@ abYield[iOp] = str_in_array(zOp, azYield); p->aiIndent[iOp] = 0; p->nIndent = iOp+1; if( str_in_array(zOp, azNext) ){ - for(i=p2; iaiIndent[i] += 2; + for(i=p2op; iaiIndent[i] += 2; } - if( str_in_array(zOp, azGoto) && p2nIndent && abYield[p2] ){ - for(i=p2+1; iaiIndent[i] += 2; + if( str_in_array(zOp, azGoto) && p2opnIndent && abYield[p2op] ){ + for(i=p2op; iaiIndent[i] += 2; } } + p->iIndent = 0; sqlite3_free(abYield); sqlite3_reset(pSql); } /* @@ -1229,10 +1239,11 @@ */ static void explain_data_delete(struct callback_data *p){ sqlite3_free(p->aiIndent); p->aiIndent = 0; p->nIndent = 0; + p->iIndent = 0; } /* ** Execute a statement or set of statements. Print ** any result rows/columns depending on the current mode