/ Check-in [9c8d6856]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Fix a problem with the shell tool EXPLAIN indentation code and VDBE sub-programs.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 9c8d6856253f8da06b2cb5dc6bd89b6952fa03ed
User & Date: dan 2013-11-18 08:41:06
Context
2013-11-18
11:20
Fix harmless compiler warnings from clang scan-build. check-in: 8d002740 user: drh tags: trunk
08:41
Fix a problem with the shell tool EXPLAIN indentation code and VDBE sub-programs. check-in: 9c8d6856 user: dan tags: trunk
03:11
Enable the ONEPASS optimization for DELETE, for both rowid and WITHOUT ROWID tables. check-in: 44a07afd user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/shell.c.

   462    462     const char *zDbFilename;    /* name of the database file */
   463    463     char *zFreeOnClose;         /* Filename to free when closing */
   464    464     const char *zVfs;           /* Name of VFS to use */
   465    465     sqlite3_stmt *pStmt;   /* Current statement if any. */
   466    466     FILE *pLog;            /* Write log output here */
   467    467     int *aiIndent;         /* Array of indents used in MODE_Explain */
   468    468     int nIndent;           /* Size of array aiIndent[] */
          469  +  int iIndent;           /* Index of current op in aiIndent[] */
   469    470   };
   470    471   
   471    472   /*
   472    473   ** These are the allowed modes.
   473    474   */
   474    475   #define MODE_Line     0  /* One column per line.  Blank line between records */
   475    476   #define MODE_Column   1  /* One record per line in neat columns */
................................................................................
   767    768           }else{
   768    769              w = 10;
   769    770           }
   770    771           if( p->mode==MODE_Explain && azArg[i] && strlen30(azArg[i])>w ){
   771    772             w = strlen30(azArg[i]);
   772    773           }
   773    774           if( i==1 && p->aiIndent && p->pStmt ){
   774         -          int iOp = sqlite3_column_int(p->pStmt, 0);
   775         -          if( iOp<p->nIndent ){
   776         -            fprintf(p->out, "%*.s", p->aiIndent[iOp], "");
          775  +          if( p->iIndent<p->nIndent ){
          776  +            fprintf(p->out, "%*.s", p->aiIndent[p->iIndent], "");
   777    777             }
          778  +          p->iIndent++;
   778    779           }
   779    780           if( w<0 ){
   780    781             fprintf(p->out,"%*.*s%s",-w,-w,
   781    782                 azArg[i] ? azArg[i] : p->nullvalue, i==nArg-1 ? "\n": "  ");
   782    783           }else{
   783    784             fprintf(p->out,"%-*.*s%s",w,w,
   784    785                 azArg[i] ? azArg[i] : p->nullvalue, i==nArg-1 ? "\n": "  ");
................................................................................
  1180   1181   **       and "Goto" by 2 spaces.
  1181   1182   */
  1182   1183   static void explain_data_prepare(struct callback_data *p, sqlite3_stmt *pSql){
  1183   1184     const char *zSql;               /* The text of the SQL statement */
  1184   1185     const char *z;                  /* Used to check if this is an EXPLAIN */
  1185   1186     int *abYield = 0;               /* True if op is an OP_Yield */
  1186   1187     int nAlloc = 0;                 /* Allocated size of p->aiIndent[], abYield */
  1187         -  int iOp;
         1188  +  int iOp;                        /* Index of operation in p->aiIndent[] */
  1188   1189   
  1189   1190     const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext", 0 };
  1190   1191     const char *azYield[] = { "Yield", "SeekLt", "SeekGt", "RowSetRead", 0 };
  1191   1192     const char *azGoto[] = { "Goto", 0 };
  1192   1193   
  1193   1194     /* Try to figure out if this is really an EXPLAIN statement. If this
  1194   1195     ** cannot be verified, return early.  */
................................................................................
  1195   1196     zSql = sqlite3_sql(pSql);
  1196   1197     if( zSql==0 ) return;
  1197   1198     for(z=zSql; *z==' ' || *z=='\t' || *z=='\n' || *z=='\f' || *z=='\r'; z++);
  1198   1199     if( sqlite3_strnicmp(z, "explain", 7) ) return;
  1199   1200   
  1200   1201     for(iOp=0; SQLITE_ROW==sqlite3_step(pSql); iOp++){
  1201   1202       int i;
         1203  +    int iAddr = sqlite3_column_int(pSql, 0);
  1202   1204       const char *zOp = (const char*)sqlite3_column_text(pSql, 1);
         1205  +
         1206  +    /* Set p2 to the P2 field of the current opcode. Then, assuming that
         1207  +    ** p2 is an instruction address, set variable p2op to the index of that
         1208  +    ** instruction in the aiIndent[] array. p2 and p2op may be different if
         1209  +    ** the current instruction is part of a sub-program generated by an
         1210  +    ** SQL trigger or foreign key.  */
  1203   1211       int p2 = sqlite3_column_int(pSql, 3);
         1212  +    int p2op = (p2 + (iOp-iAddr));
  1204   1213   
  1205   1214       /* Grow the p->aiIndent array as required */
  1206   1215       if( iOp>=nAlloc ){
  1207   1216         nAlloc += 100;
  1208   1217         p->aiIndent = (int*)sqlite3_realloc(p->aiIndent, nAlloc*sizeof(int));
  1209   1218         abYield = (int*)sqlite3_realloc(abYield, nAlloc*sizeof(int));
  1210   1219       }
  1211   1220       abYield[iOp] = str_in_array(zOp, azYield);
  1212   1221       p->aiIndent[iOp] = 0;
  1213   1222       p->nIndent = iOp+1;
  1214   1223   
  1215   1224       if( str_in_array(zOp, azNext) ){
  1216         -      for(i=p2; i<iOp; i++) p->aiIndent[i] += 2;
         1225  +      for(i=p2op; i<iOp; i++) p->aiIndent[i] += 2;
  1217   1226       }
  1218         -    if( str_in_array(zOp, azGoto) && p2<p->nIndent && abYield[p2] ){
  1219         -      for(i=p2+1; i<iOp; i++) p->aiIndent[i] += 2;
         1227  +    if( str_in_array(zOp, azGoto) && p2op<p->nIndent && abYield[p2op] ){
         1228  +      for(i=p2op; i<iOp; i++) p->aiIndent[i] += 2;
  1220   1229       }
  1221   1230     }
  1222   1231   
         1232  +  p->iIndent = 0;
  1223   1233     sqlite3_free(abYield);
  1224   1234     sqlite3_reset(pSql);
  1225   1235   }
  1226   1236   
  1227   1237   /*
  1228   1238   ** Free the array allocated by explain_data_prepare().
  1229   1239   */
  1230   1240   static void explain_data_delete(struct callback_data *p){
  1231   1241     sqlite3_free(p->aiIndent);
  1232   1242     p->aiIndent = 0;
  1233   1243     p->nIndent = 0;
         1244  +  p->iIndent = 0;
  1234   1245   }
  1235   1246   
  1236   1247   /*
  1237   1248   ** Execute a statement or set of statements.  Print 
  1238   1249   ** any result rows/columns depending on the current mode 
  1239   1250   ** set via the supplied callback.
  1240   1251   **