** If compiled statement pSql appears to be an EXPLAIN statement, allocate ** and populate the ShellState.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 ** i
| 12954 | ** and "Goto" by 2 spaces. |
| 12955 | */ |
| 12956 | static void explain_data_prepare(ShellState *p, sqlite3_stmt *pSql){ |
| 12957 | const char *zSql; /* The text of the SQL statement */ |
| 12958 | const char *z; /* Used to check if this is an EXPLAIN */ |
| 12959 | int *abYield = 0; /* True if op is an OP_Yield */ |
| 12960 | int nAlloc = 0; /* Allocated size of p->aiIndent[], abYield */ |
| 12961 | int iOp; /* Index of operation in p->aiIndent[] */ |
| 12962 | |
| 12963 | const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext", 0 }; |
| 12964 | const char *azYield[] = { "Yield", "SeekLT", "SeekGT", "RowSetRead", |
| 12965 | "Rewind", 0 }; |
| 12966 | const char *azGoto[] = { "Goto", 0 }; |
| 12967 | |
| 12968 | /* Try to figure out if this is really an EXPLAIN statement. If this |
| 12969 | ** cannot be verified, return early. */ |
| 12970 | if( sqlite3_column_count(pSql)!=8 ){ |
| 12971 | p->cMode = p->mode; |
| 12972 | return; |
| 12973 | } |
| 12974 | zSql = sqlite3_sql(pSql); |
| 12975 | if( zSql==0 ) return; |
| 12976 | for(z=zSql; *z==' ' || *z=='\t' || *z=='\n' || *z=='\f' || *z=='\r'; z++); |
| 12977 | if( sqlite3_strnicmp(z, "explain", 7) ){ |
| 12978 | p->cMode = p->mode; |
| 12979 | return; |
| 12980 | } |
| 12981 | |
| 12982 | for(iOp=0; SQLITE_ROW==sqlite3_step(pSql); iOp++){ |
| 12983 | int i; |
| 12984 | int iAddr = sqlite3_column_int(pSql, 0); |
| 12985 | const char *zOp = (const char*)sqlite3_column_text(pSql, 1); |
| 12986 | |
| 12987 | /* Set p2 to the P2 field of the current opcode. Then, assuming that |
| 12988 | ** p2 is an instruction address, set variable p2op to the index of that |
| 12989 | ** instruction in the aiIndent[] array. p2 and p2op may be different if |
| 12990 | ** the current instruction is part of a sub-program generated by an |
| 12991 | ** SQL trigger or foreign key. */ |
| 12992 | int p2 = sqlite3_column_int(pSql, 3); |
| 12993 | int p2op = (p2 + (iOp-iAddr)); |
| 12994 | |
| 12995 | /* Grow the p->aiIndent array as required */ |
| 12996 | if( iOp>=nAlloc ){ |
| 12997 | if( iOp==0 ){ |
| 12998 | /* Do further verfication that this is explain output. Abort if |
| 12999 | ** it is not */ |
| 13000 | static const char *explainCols[] = { |
| 13001 | "addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment" }; |
| 13002 | int jj; |
| 13003 | for(jj=0; jj<ArraySize(explainCols); jj++){ |
| 13004 | if( strcmp(sqlite3_column_name(pSql,jj),explainCols[jj])!=0 ){ |
| 13005 | p->cMode = p->mode; |
| 13006 | sqlite3_reset(pSql); |
| 13007 | return; |
| 13008 | } |
| 13009 | } |
| 13010 | } |
| 13011 | nAlloc += 100; |
| 13012 | p->aiIndent = (int*)sqlite3_realloc64(p->aiIndent, nAlloc*sizeof(int)); |
| 13013 | if( p->aiIndent==0 ) shell_out_of_memory(); |
no test coverage detected