]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
If SQLITE_ENABLE_STMT_SCANSTATUS is defined, record the number of times each VDBE...
authordan <dan@noemail.net>
Sat, 1 Nov 2014 20:38:06 +0000 (20:38 +0000)
committerdan <dan@noemail.net>
Sat, 1 Nov 2014 20:38:06 +0000 (20:38 +0000)
FossilOrigin-Name: 9ea37422a8cc2fce51bb10508e5e90f40fd4b511

manifest
manifest.uuid
src/vdbe.c
src/vdbe.h
src/vdbeInt.h
src/vdbeapi.c
src/vdbeaux.c
src/where.c
src/whereInt.h
test/scanstatus.test

index 8582d6b5e8bad8f8f4f3abbd8f7e0de3b511e2c1..c81e91139507f1f4e908f144a5fa4a63501d8f0d 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Minor\sfixes\sand\sdocumentation\simprovements\sfor\ssqlite3_stmt_scanstatus().
-D 2014-11-01T18:08:04.130
+C If\sSQLITE_ENABLE_STMT_SCANSTATUS\sis\sdefined,\srecord\sthe\snumber\sof\stimes\seach\sVDBE\sopcode\sis\sexecuted.\sDerive\sthe\svalues\sreturned\sby\ssqlite3_stmt_scanstatus()\sfrom\sthese\srecords\son\sdemand.
+D 2014-11-01T20:38:06.833
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -289,11 +289,11 @@ F src/update.c 3c4ecc282accf12d39edb8d524cf089645e55a13
 F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c
 F src/util.c 3b627daa45c7308c1e36e3dbaa3f9ce7e5c7fa73
 F src/vacuum.c 59f03f92bcff57faa6a8ca256eb29ccddfb0614a
-F src/vdbe.c 5240bad20ce0b707afee211f0c21a862b54b1e0b
-F src/vdbe.h f8e5388173dbf8408da4ae1dcbf75911caf2253d
-F src/vdbeInt.h 284b2294c188474daa9b5ce2bd0200560cb0940d
-F src/vdbeapi.c 2afa2e162f290879ca9c51e8795a377035f1662a
-F src/vdbeaux.c 1e2561eeb94749f6b8c0a1eb02b5fecb645ed48c
+F src/vdbe.c 69d025732d242d7c97282e6570a4e5eb768ebaff
+F src/vdbe.h 7d603b93d128e614ba2600f12a6c541435405522
+F src/vdbeInt.h ee8d44cba5998279039bcd91ebddb6d9a2d463b8
+F src/vdbeapi.c 19e433e69fe2b27bfc9337a207b6ebf499f41d03
+F src/vdbeaux.c bad342af7cadb8d3bf2990700a78787d602dcd69
 F src/vdbeblob.c 8b5442ff0954c44b45cbabbe2e94091a2e16fdef
 F src/vdbemem.c 31d8eabb0cd78bfeab4e5124c7363c3e9e54db9f
 F src/vdbesort.c 975aeffa99acb0991b2f288d30294756bff41438
@@ -302,8 +302,8 @@ F src/vtab.c 2a30791bbd7926b589401bd09c3abb33de563793
 F src/wal.c 10e7de7ce90865a68153f001a61f1d985cd17983
 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
 F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804
-F src/where.c 636ca646c8f2f53fd66f9ed5c773e84cb0c4b762
-F src/whereInt.h 99d324a8f921d7a40c605a8b197350c3cb18977d
+F src/where.c fb404e3db40db61c212ffb39022e885a91252498
+F src/whereInt.h a2bc22f4e3e70eeaa57272f354c288bc3b71b80b
 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
 F test/aggnested.test b35b4cd69fc913f90d39a575e171e1116c3a4bb7
@@ -801,7 +801,7 @@ F test/savepoint4.test c8f8159ade6d2acd9128be61e1230f1c1edc6cc0
 F test/savepoint5.test 0735db177e0ebbaedc39812c8d065075d563c4fd
 F test/savepoint6.test f41279c5e137139fa5c21485773332c7adb98cd7
 F test/savepoint7.test fbf319a7b2dda089ec5be30a424a0e95f121d423
-F test/scanstatus.test b4b1780bad243e1576329d05597b99f06886e4d2
+F test/scanstatus.test 40c7712c8bc0adc3fb88e0419356880679a3a5fb
 F test/schema.test 8f7999be894260f151adf15c2c7540f1c6d6a481
 F test/schema2.test 906408621ea881fdb496d878b1822572a34e32c5
 F test/schema3.test 1bc1008e1f8cb5654b248c55f27249366eb7ed38
@@ -1211,7 +1211,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P 6a9bab34aeb6a01b612211a28c140de60a3e883c
-R d964f269915d57cf95d9198c6ba22665
+P 8d8cc9608d30bb65fffcfe488e904411cbbc7f41
+R e1e809461d373caeeb0e83f126874426
 U dan
-Z 082decdd6298ff1a2330407f8d406dfb
+Z 5d5debb04affeaeb7378f6b538c8f641
index 7325586095a1a0b0261c545cf03db00e5ebaa83d..f70d7e8aef5c7f2e2d22162648b725f7ef1b0c3a 100644 (file)
@@ -1 +1 @@
-8d8cc9608d30bb65fffcfe488e904411cbbc7f41
\ No newline at end of file
+9ea37422a8cc2fce51bb10508e5e90f40fd4b511
\ No newline at end of file
index 1abccfeeab17d156a62b39f1985f14bc53535bf0..bc49505dd0cbcf327be0bd679efe862283dd908d 100644 (file)
@@ -167,18 +167,6 @@ int sqlite3_found_count = 0;
 /* Return true if the cursor was opened using the OP_OpenSorter opcode. */
 #define isSorter(x) ((x)->pSorter!=0)
 
-/*
-** The first argument passed to the IncrementExplainCounter() macro must
-** be a non-NULL pointer to an object of type VdbeCursor. The second 
-** argument must be either "nLoop" or "nVisit" (without the double-quotes).
-*/
-#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
-# define IncrementExplainCounter(pCsr, counter) \
-    if( (pCsr)->pExplain ) (pCsr)->pExplain->counter++
-#else
-# define IncrementExplainCounter(pCsr, counter)
-#endif
-
 /*
 ** Allocate VdbeCursor number iCur.  Return a pointer to it.  Return NULL
 ** if we run out of memory.
@@ -620,6 +608,9 @@ int sqlite3VdbeExec(
 #endif
     nVmStep++;
     pOp = &aOp[pc];
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+    if( p->pFrame==0 ) p->anExec[pc]++;
+#endif
 
     /* Only allow tracing if SQLITE_DEBUG is defined.
     */
@@ -3568,7 +3559,6 @@ case OP_SeekGT: {       /* jump, in3 */
 #ifdef SQLITE_DEBUG
   pC->seekOp = pOp->opcode;
 #endif
-  IncrementExplainCounter(pC, nLoop);
   if( pC->isTable ){
     /* The input value in P3 might be of any type: integer, real, string,
     ** blob, or NULL.  But it needs to be an integer before we can do
@@ -3677,8 +3667,6 @@ case OP_SeekGT: {       /* jump, in3 */
   VdbeBranchTaken(res!=0,2);
   if( res ){
     pc = pOp->p2 - 1;
-  }else{
-    IncrementExplainCounter(pC, nVisit);
   }
   break;
 }
@@ -3889,7 +3877,6 @@ case OP_NotExists: {        /* jump, in3 */
   res = 0;
   iKey = pIn3->u.i;
   rc = sqlite3BtreeMovetoUnpacked(pCrsr, 0, iKey, 0, &res);
-  IncrementExplainCounter(pC, nLoop);
   pC->movetoTarget = iKey;  /* Used by OP_Delete */
   pC->nullRow = 0;
   pC->cacheStatus = CACHE_STALE;
@@ -3897,8 +3884,6 @@ case OP_NotExists: {        /* jump, in3 */
   VdbeBranchTaken(res!=0,2);
   if( res!=0 ){
     pc = pOp->p2 - 1;
-  }else{
-    IncrementExplainCounter(pC, nVisit);
   }
   pC->seekResult = res;
   break;
@@ -4467,8 +4452,6 @@ case OP_Last: {        /* jump */
   res = 0;
   assert( pCrsr!=0 );
   rc = sqlite3BtreeLast(pCrsr, &res);
-  IncrementExplainCounter(pC, nLoop);
-  if( res==0 ) IncrementExplainCounter(pC, nVisit);
   pC->nullRow = (u8)res;
   pC->deferredMoveto = 0;
   pC->cacheStatus = CACHE_STALE;
@@ -4538,14 +4521,11 @@ case OP_Rewind: {        /* jump */
     pC->deferredMoveto = 0;
     pC->cacheStatus = CACHE_STALE;
   }
-  IncrementExplainCounter(pC, nLoop);
   pC->nullRow = (u8)res;
   assert( pOp->p2>0 && pOp->p2<p->nOp );
   VdbeBranchTaken(res!=0,2);
   if( res ){
     pc = pOp->p2 - 1;
-  }else{
-    IncrementExplainCounter(pC, nVisit);
   }
   break;
 }
@@ -4656,7 +4636,6 @@ next_tail:
   pC->cacheStatus = CACHE_STALE;
   VdbeBranchTaken(res==0,2);
   if( res==0 ){
-    IncrementExplainCounter(pC, nVisit);
     pC->nullRow = 0;
     pc = pOp->p2 - 1;
     p->aCounter[pOp->p5]++;
@@ -6079,10 +6058,7 @@ case OP_VFilter: {   /* jump */
     VdbeBranchTaken(res!=0,2);
     if( res ){
       pc = pOp->p2 - 1;
-    }else{
-      IncrementExplainCounter(pCur, nVisit);
     }
-    IncrementExplainCounter(pCur, nLoop);
   }
   pCur->nullRow = 0;
 
@@ -6175,7 +6151,6 @@ case OP_VNext: {   /* jump */
   if( !res ){
     /* If there is data, jump to P2 */
     pc = pOp->p2 - 1;
-    IncrementExplainCounter(pCur, nVisit);
   }
   goto check_for_interrupt;
 }
@@ -6375,19 +6350,6 @@ case OP_Init: {          /* jump */
   break;
 }
 
-#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
-case OP_Explain: {
-  ExplainArg *pArg;
-  VdbeCursor *pCur;
-  if( pOp->p4type==P4_EXPLAIN && (pArg = pOp->p4.pExplain)->iCsr>=0 ){
-    pArg = pOp->p4.pExplain;
-    pCur = p->apCsr[pArg->iCsr];
-    pCur->pExplain = pArg;
-  }
-  break;
-}
-#endif
-
 
 /* Opcode: Noop * * * * *
 **
index 1b470441bed1a15b77030d657843ab4b9a4b73a4..966fdb622ef1ca77271cd6338aabf6afcc6ca3bf 100644 (file)
@@ -25,7 +25,6 @@
 ** of this structure.
 */
 typedef struct Vdbe Vdbe;
-typedef struct ExplainArg ExplainArg;
 
 /*
 ** The names of the following types declared in vdbeInt.h are required
@@ -60,7 +59,6 @@ struct VdbeOp {
     KeyInfo *pKeyInfo;     /* Used when p4type is P4_KEYINFO */
     int *ai;               /* Used when p4type is P4_INTARRAY */
     SubProgram *pProgram;  /* Used when p4type is P4_SUBPROGRAM */
-    ExplainArg *pExplain;  /* Used when p4type is P4_EXPLAIN */
     int (*xAdvance)(BtCursor *, int *);
   } p4;
 #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
@@ -102,19 +100,6 @@ struct VdbeOpList {
 };
 typedef struct VdbeOpList VdbeOpList;
 
-/*
-** Structure used as the P4 parameter for OP_Explain opcodes.
-*/
-struct ExplainArg {
-  int iCsr;                       /* Cursor number this applies to */
-  i64 nLoop;                      /* Number of times loop has run */
-  i64 nVisit;                     /* Total number of rows visited */
-  i64 nEst;                       /* Estimated number of rows per scan */
-  const char *zName;              /* Name of table/index being scanned */
-  const char *zExplain;           /* EQP text for this loop */
-};
-
-
 /*
 ** Allowed values of VdbeOp.p4type
 */
@@ -134,7 +119,6 @@ struct ExplainArg {
 #define P4_INTARRAY (-15) /* P4 is a vector of 32-bit integers */
 #define P4_SUBPROGRAM  (-18) /* P4 is a pointer to a SubProgram structure */
 #define P4_ADVANCE  (-19) /* P4 is a pointer to BtreeNext() or BtreePrev() */
-#define P4_EXPLAIN  (-20) /* P4 is a pointer to an instance of ExplainArg */
 
 /* Error message codes for OP_Halt */
 #define P5_ConstraintNotNull 1
@@ -298,4 +282,10 @@ void sqlite3VdbeLinkSubProgram(Vdbe *, SubProgram *);
 # define VDBE_OFFSET_LINENO(x) 0
 #endif
 
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+void sqlite3VdbeScanCounter(Vdbe*, int, int, int, i64, const char*);
+#else
+# define sqlite3VdbeScanCounter(a,b,c,d,e)
+#endif
+
 #endif
index 839108f6bc721057889d55a1bef573f36630dc6d..9f21ac7ebf59190a31a15954779860ff9e3e5b8b 100644 (file)
@@ -83,7 +83,6 @@ struct VdbeCursor {
   i64 seqCount;         /* Sequence counter */
   i64 movetoTarget;     /* Argument to the deferred sqlite3BtreeMoveto() */
   VdbeSorter *pSorter;  /* Sorter object for OP_SorterOpen cursors */
-  ExplainArg *pExplain; /* Object to store seek/visit counts (may be NULL) */
 
   /* Cached information about the header for the data record that the
   ** cursor is currently pointing to.  Only valid if cacheStatus matches
@@ -292,12 +291,20 @@ struct Explain {
   char zBase[100];   /* Initial space */
 };
 
-
 /* A bitfield type for use inside of structures.  Always follow with :N where
 ** N is the number of bits.
 */
 typedef unsigned bft;  /* Bit Field Type */
 
+typedef struct ScanCounter ScanCounter;
+struct ScanCounter {
+  int addrExplain;                /* OP_Explain for loop */
+  int addrLoop;                   /* Address of "loops" counter */
+  int addrVisit;                  /* Address of "rows visited" counter */
+  i64 nEst;                       /* Estimated rows per loop */
+  char *zName;                    /* Name of table or index */
+};
+
 /*
 ** An instance of the virtual machine.  This structure contains the complete
 ** state of the virtual machine.
@@ -370,8 +377,11 @@ struct Vdbe {
   int nOnceFlag;          /* Size of array aOnceFlag[] */
   u8 *aOnceFlag;          /* Flags for OP_Once */
   AuxData *pAuxData;      /* Linked list of auxdata allocations */
-  ExplainArg **apExplain; /* Array of pointers to P4_EXPLAIN p4 values */
-  int nExplain;           /* Number of entries in array apExplain */
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+  i64 *anExec;            /* Number of times each op has been executed */
+  int nScan;              /* Entries in aScan[] */
+  ScanCounter *aScan;     /* Scan definitions for sqlite3_stmt_scanstatus() */
+#endif
 };
 
 /*
index b09faa1fa5b4568808f1dc45d6179af375d8d04f..f2e124dc51e07bdaa823db9028fd260c0b670002 100644 (file)
@@ -1476,6 +1476,7 @@ int sqlite3_stmt_status(sqlite3_stmt *pStmt, int op, int resetFlag){
   return (int)v;
 }
 
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
 /*
 ** Return status data for a single loop within query pStmt.
 */
@@ -1489,14 +1490,20 @@ int sqlite3_stmt_scanstatus(
   const char **pzExplain          /* OUT: EQP string */
 ){
   Vdbe *p = (Vdbe*)pStmt;
-  ExplainArg *pExplain;
-  if( idx<0 || idx>=p->nExplain ) return 1;
-  pExplain = p->apExplain[idx];
-  if( pnLoop ) *pnLoop = pExplain->nLoop;
-  if( pnVisit ) *pnVisit = pExplain->nVisit;
-  if( pnEst ) *pnEst = pExplain->nEst;
-  if( *pzName ) *pzName = pExplain->zName;
-  if( *pzExplain ) *pzExplain = pExplain->zExplain;
+  ScanCounter *pScan;
+  if( idx<0 || idx>=p->nScan ) return 1;
+  pScan = &p->aScan[idx];
+  if( pnLoop ) *pnLoop = p->anExec[pScan->addrLoop];
+  if( pnVisit ) *pnVisit = p->anExec[pScan->addrVisit];
+  if( pnEst ) *pnEst = pScan->nEst;
+  if( *pzName ) *pzName = pScan->zName;
+  if( *pzExplain ){
+    if( pScan->addrExplain ){
+      *pzExplain = p->aOp[ pScan->addrExplain ].p4.z;
+    }else{
+      *pzExplain = 0;
+    }
+  }
   return 0;
 }
 
@@ -1505,10 +1512,7 @@ int sqlite3_stmt_scanstatus(
 */
 void sqlite3_stmt_scanstatus_reset(sqlite3_stmt *pStmt){
   Vdbe *p = (Vdbe*)pStmt;
-  int i;
-  for(i=0; i<p->nExplain; i++){
-    p->apExplain[i]->nLoop = 0;
-    p->apExplain[i]->nVisit = 0;
-  }
+  memset(p->anExec, 0, p->nOp * sizeof(i64));
 }
+#endif /* SQLITE_ENABLE_STMT_SCANSTATUS */
 
index a8223890bd34836aa28613af9541c7f3efed790b..3f75cfee7a1d7cecb3cac578bb0398a015de874b 100644 (file)
@@ -597,6 +597,34 @@ int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp, int iLineno){
   return addr;
 }
 
+#if defined(SQLITE_ENABLE_STMT_SCANSTATUS)
+/*
+** Add an entry to the array of counters managed by sqlite3_stmt_scanstatus().
+*/
+void sqlite3VdbeScanCounter(
+  Vdbe *p,                        /* VM to add scanstatus() to */
+  int addrExplain,                /* Address of OP_Explain (or 0) */
+  int addrLoop,                   /* Address of loop counter */ 
+  int addrVisit,                  /* Address of rows visited counter */
+  i64 nEst,                       /* Estimated number of rows */
+  const char *zName               /* Name of table or index being scanned */
+){
+  int nByte = (p->nScan+1) * sizeof(ScanCounter);
+  ScanCounter *aNew;
+  aNew = (ScanCounter*)sqlite3DbRealloc(p->db, p->aScan, nByte);
+  if( aNew ){
+    ScanCounter *pNew = &aNew[p->nScan++];
+    pNew->addrExplain = addrExplain;
+    pNew->addrLoop = addrLoop;
+    pNew->addrVisit = addrVisit;
+    pNew->nEst = nEst;
+    pNew->zName = sqlite3DbStrDup(p->db, zName);
+    p->aScan = aNew;
+  }
+}
+#endif
+
+
 /*
 ** Change the value of the P1 operand for a specific instruction.
 ** This routine is useful when a large program is loaded from a
@@ -672,7 +700,6 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){
   if( p4 ){
     assert( db );
     switch( p4type ){
-      case P4_EXPLAIN:
       case P4_REAL:
       case P4_INT64:
       case P4_DYNAMIC:
@@ -821,13 +848,6 @@ void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int n){
     pOp->p4type = P4_VTAB;
     sqlite3VtabLock((VTable *)zP4);
     assert( ((VTable *)zP4)->db==p->db );
-  }else if( n==P4_EXPLAIN ){
-    pOp->p4.p = (void*)zP4;
-    pOp->p4type = P4_EXPLAIN;
-    p->apExplain = (ExplainArg**)sqlite3DbReallocOrFree(
-        p->db, p->apExplain, sizeof(ExplainArg*) * p->nExplain + 1
-    );
-    if( p->apExplain ) p->apExplain[p->nExplain++] = (ExplainArg*)zP4;
   }else if( n<0 ){
     pOp->p4.p = (void*)zP4;
     pOp->p4type = (signed char)n;
@@ -1111,10 +1131,6 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
       zTemp[0] = 0;
       break;
     }
-    case P4_EXPLAIN: {
-      zP4 = (char*)pOp->p4.pExplain->zExplain;
-      break;
-    }
     default: {
       zP4 = pOp->p4.z;
       if( zP4==0 ){
@@ -1714,6 +1730,10 @@ void sqlite3VdbeMakeReady(
     zEnd = &zCsr[nByte];
   }while( nByte && !db->mallocFailed );
 
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+    p->anExec = (i64*)sqlite3DbMallocZero(db, p->nOp*sizeof(i64));
+#endif
+
   p->nCursor = nCursor;
   p->nOnceFlag = nOnce;
   if( p->aVar ){
@@ -2697,7 +2717,13 @@ void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){
   sqlite3DbFree(db, p->aColName);
   sqlite3DbFree(db, p->zSql);
   sqlite3DbFree(db, p->pFree);
-  sqlite3DbFree(db, p->apExplain);
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+  sqlite3DbFree(db, p->anExec);
+  for(i=0; i<p->nScan; i++){
+    sqlite3DbFree(db, p->aScan[i].zName);
+  }
+  sqlite3DbFree(db, p->aScan);
+#endif
 }
 
 /*
index ae3c12725ee74f763ecbef6215b0c3fa59ee7c7b..8151a7057bbf84b0d220027abe9ef2ddbdd8c941 100644 (file)
@@ -2739,7 +2739,7 @@ static int codeAllEqualityTerms(
   return regBase;
 }
 
-#if !defined(SQLITE_OMIT_EXPLAIN) || defined(SQLITE_ENABLE_STMT_SCANSTATUS)
+#ifndef SQLITE_OMIT_EXPLAIN
 /*
 ** This routine is a helper for explainIndexRange() below
 **
@@ -2812,68 +2812,43 @@ static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop, Table *pTab){
 ** record is added to the output to describe the table scan strategy in 
 ** pLevel.
 */
-static void explainOneScan(
+static int explainOneScan(
   Parse *pParse,                  /* Parse context */
   SrcList *pTabList,              /* Table list this loop refers to */
-  WhereInfo *pWInfo,              /* WHERE clause this loop belongs to */
+  WhereLevel *pLevel,             /* Scan to write OP_Explain opcode for */
   int iLevel,                     /* Value for "level" column of output */
+  int iFrom,                      /* Value for "from" column of output */
   u16 wctrlFlags                  /* Flags passed to sqlite3WhereBegin() */
 ){
-#if !defined(SQLITE_DEBUG) && !defined(SQLITE_ENABLE_STMT_SCANSTATUS)
+  int ret = 0;
+#ifndef SQLITE_DEBUG
   if( pParse->explain==2 )
 #endif
   {
-    WhereLevel *pLevel = &pWInfo->a[iLevel];
     struct SrcList_item *pItem = &pTabList->a[pLevel->iFrom];
     Vdbe *v = pParse->pVdbe;      /* VM being constructed */
     sqlite3 *db = pParse->db;     /* Database handle */
-#ifdef SQLITE_OMIT_EXPLAIN
-    int iId = 0;                  /* Select id (left-most output column) */
-#else
-    int iId = pParse->iSelectId;   /* Select id (left-most output column) */
-#endif
+    int iId = pParse->iSelectId;  /* Select id (left-most output column) */
     int isSearch;                 /* True for a SEARCH. False for SCAN. */
     WhereLoop *pLoop;             /* The controlling WhereLoop object */
     u32 flags;                    /* Flags that describe this loop */
+    char *zMsg;                   /* Text to add to EQP output */
     StrAccum str;                 /* EQP output string */
     char zBuf[100];               /* Initial space for EQP output string */
-    const char *zObj;
-    ExplainArg *pExplain;
-    i64 nEstRow;                  /* Estimated rows per scan of pLevel */
 
     pLoop = pLevel->pWLoop;
     flags = pLoop->wsFlags;
-    if( (flags&WHERE_MULTI_OR) ) return;
-
-    sqlite3StrAccumInit(&str, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH);
-    str.db = db;
-
-    /* Reserve space at the start of the buffer managed by the StrAccum
-    ** object for *pExplain.  */
-    assert( sizeof(*pExplain)<=sizeof(zBuf) );
-    str.nChar = sizeof(*pExplain);
+    if( (flags&WHERE_MULTI_OR) || (wctrlFlags&WHERE_ONETABLE_ONLY) ) return 0;
 
-    /* Append the object (table or index) name to the buffer. */
-    if( pItem->pSelect ){
-      zObj = "";
-    }else if( (flags & (WHERE_IPK|WHERE_VIRTUALTABLE))==0 ){
-      zObj = pLoop->u.btree.pIndex->zName;
-    }else{
-      zObj = pItem->zName;
-    }
-    sqlite3StrAccumAppend(&str, zObj, sqlite3Strlen30(zObj)+1);
-
-    /* Append the EQP text to the buffer */
     isSearch = (flags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))!=0
             || ((flags&WHERE_VIRTUALTABLE)==0 && (pLoop->u.btree.nEq>0))
             || (wctrlFlags&(WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX));
+
+    sqlite3StrAccumInit(&str, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH);
+    str.db = db;
     sqlite3StrAccumAppendAll(&str, isSearch ? "SEARCH" : "SCAN");
     if( pItem->pSelect ){
-#ifdef SQLITE_OMIT_EXPLAIN
-      sqlite3XPrintf(&str, 0, " SUBQUERY 0");
-#else
       sqlite3XPrintf(&str, 0, " SUBQUERY %d", pItem->iSelectId);
-#endif
     }else{
       sqlite3XPrintf(&str, 0, " TABLE %s", pItem->zName);
     }
@@ -2927,33 +2902,48 @@ static void explainOneScan(
                   pLoop->u.vtab.idxNum, pLoop->u.vtab.idxStr);
     }
 #endif
-    nEstRow = pLoop->nOut>=10 ? sqlite3LogEstToInt(pLoop->nOut) : 1;
 #ifdef SQLITE_EXPLAIN_ESTIMATED_ROWS
-    sqlite3XPrintf(&str, 0, " (~%llu rows)", nEstRow);
-#endif
-    pExplain = (ExplainArg*)sqlite3StrAccumFinish(&str);
-    assert( pExplain || db->mallocFailed );
-    if( pExplain ){
-      memset(pExplain, 0, sizeof(*pExplain));
-      if( pLoop->wsFlags & WHERE_INDEXED ){
-        pExplain->iCsr = pLevel->iIdxCur;
-      }else if( pItem->pSelect==0 ){
-        pExplain->iCsr = pLevel->iTabCur;
-      }else{
-        pExplain->iCsr = -1;
-      }
-      pExplain->nEst = nEstRow;
-      pExplain->zName = (const char*)&pExplain[1];
-      pExplain->zExplain = &pExplain->zName[sqlite3Strlen30(pExplain->zName)+1];
-      pWInfo->iExplain = sqlite3VdbeAddOp4(v, OP_Explain, 
-          iId, iLevel, pLevel->iFrom, (char*)pExplain,P4_EXPLAIN
-      );
+    if( pLoop->nOut>=10 ){
+      sqlite3XPrintf(&str, 0, " (~%llu rows)", sqlite3LogEstToInt(pLoop->nOut));
+    }else{
+      sqlite3StrAccumAppend(&str, " (~1 row)", 9);
     }
+#endif
+    zMsg = sqlite3StrAccumFinish(&str);
+    ret = sqlite3VdbeAddOp4(v, OP_Explain, iId, iLevel, iFrom, zMsg,P4_DYNAMIC);
+  }
+  return ret;
+}
+#else
+# define explainOneScan(u,v,w,x,y,z) 0
+#endif /* SQLITE_OMIT_EXPLAIN */
+
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+static void addScanStatus(
+  Vdbe *v, 
+  SrcList *pSrclist,
+  WhereLevel *pLvl,
+  int addrExplain
+){
+  const char *zObj = 0;
+  i64 nEst = 1;
+  WhereLoop *pLoop = pLvl->pWLoop;
+  if( (pLoop->wsFlags & (WHERE_IPK|WHERE_VIRTUALTABLE))==0 ){
+    zObj = pLoop->u.btree.pIndex->zName;
+  }else{
+    zObj = pSrclist->a[pLvl->iFrom].zName;
   }
+  if( pLoop->nOut>=10 ){
+    nEst = sqlite3LogEstToInt(pLoop->nOut);
+  }
+  sqlite3VdbeScanCounter(
+      v, addrExplain, pLvl->addrBody, pLvl->addrVisit, nEst, zObj
+  );
 }
 #else
-# define explainOneScan(v,w,x,y,z)
-#endif /* !SQLITE_OMIT_EXPLAIN || SQLITE_ENABLE_STMT_SCANSTATUS */
+# define addScanStatus(a, b, c, d)
+#endif
+
 
 
 /*
@@ -3621,14 +3611,10 @@ static Bitmask codeOneLoopStart(
         assert( pSubWInfo || pParse->nErr || db->mallocFailed );
         if( pSubWInfo ){
           WhereLoop *pSubLoop;
-
-          /* If an OP_Explain was added for this sub-loop, fix the P2 and
-          ** P3 parameters to it so that they are relative to the current
-          ** context.  */
-          if( pSubWInfo->iExplain!=0 ){
-            sqlite3VdbeChangeP2(v, pSubWInfo->iExplain, iLevel);
-            sqlite3VdbeChangeP3(v, pSubWInfo->iExplain, pLevel->iFrom);
-          }
+          int addrExplain = explainOneScan(
+              pParse, pOrTab, &pSubWInfo->a[0], iLevel, pLevel->iFrom, 0
+          );
+          addScanStatus(v, pOrTab, &pSubWInfo->a[0], addrExplain);
 
           /* This is the sub-WHERE clause body.  First skip over
           ** duplicate rows from prior sub-WHERE clauses, and record the
@@ -3760,6 +3746,10 @@ static Bitmask codeOneLoopStart(
     }
   }
 
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+  pLevel->addrVisit = sqlite3VdbeCurrentAddr(v);
+#endif
+
   /* Insert code to test every subexpression that can be completely
   ** computed using the current set of tables.
   */
@@ -6461,7 +6451,10 @@ WhereInfo *sqlite3WhereBegin(
   */
   notReady = ~(Bitmask)0;
   for(ii=0; ii<nTabList; ii++){
+    int addrExplain;
+    int wsFlags;
     pLevel = &pWInfo->a[ii];
+    wsFlags = pLevel->pWLoop->wsFlags;
 #ifndef SQLITE_OMIT_AUTOMATIC_INDEX
     if( (pLevel->pWLoop->wsFlags & WHERE_AUTO_INDEX)!=0 ){
       constructAutomaticIndex(pParse, &pWInfo->sWC,
@@ -6469,10 +6462,15 @@ WhereInfo *sqlite3WhereBegin(
       if( db->mallocFailed ) goto whereBeginError;
     }
 #endif
-    explainOneScan(pParse, pTabList, pWInfo, ii, wctrlFlags);
+    addrExplain = explainOneScan(
+        pParse, pTabList, pLevel, ii, pLevel->iFrom, wctrlFlags
+    );
     pLevel->addrBody = sqlite3VdbeCurrentAddr(v);
     notReady = codeOneLoopStart(pWInfo, ii, notReady);
     pWInfo->iContinue = pLevel->addrCont;
+    if( (wsFlags&WHERE_MULTI_OR)==0 && (wctrlFlags&WHERE_ONETABLE_ONLY)==0 ){
+      addScanStatus(v, pTabList, pLevel, addrExplain);
+    }
   }
 
   /* Done. */
index dcf0e00604bff5a646edd16e467d0fff3e57c359..168e11f4c78cbe7833e489ff5f5600deff30dfcf 100644 (file)
@@ -85,6 +85,9 @@ struct WhereLevel {
   } u;
   struct WhereLoop *pWLoop;  /* The selected WhereLoop object */
   Bitmask notReady;          /* FROM entries not usable at this level */
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+  int addrVisit;        /* Address at which row is visited */
+#endif
 };
 
 /*
index 9df80f9ba8df9a998ac3dbed663a03d766e93226..e4e0bbd4a55c64ef780b15cbd118f68cd317ea21 100644 (file)
@@ -115,7 +115,7 @@ do_execsql_test 2.4.1 {
   SELECT * FROM x1 WHERE j<'two'
 } {4 four 1 one 3 three}
 do_scanstatus_test 2.4.2 {
-  nLoop 1 nVisit 4 nEst 262144 zName x1j 
+  nLoop 1 nVisit 3 nEst 262144 zName x1j 
   zExplain {SEARCH TABLE x1 USING COVERING INDEX x1j (j<?)}
 }
 
@@ -152,7 +152,7 @@ do_execsql_test 2.8.1 {
   SELECT * FROM x2 WHERE i=1 AND j='two'
 }
 do_scanstatus_test 2.8.2 {
-  nLoop 1 nVisit 1 nEst 8 zName x2ij 
+  nLoop 1 nVisit 0 nEst 8 zName x2ij 
   zExplain {SEARCH TABLE x2 USING INDEX x2ij (i=? AND j=?)}
 }
 
@@ -168,7 +168,7 @@ do_execsql_test 2.10.1 {
   SELECT * FROM x2 WHERE i=3 AND j='three'
 } {3 three {3 three}}
 do_scanstatus_test 2.10.2 {
-  nLoop 1 nVisit 2 nEst 8 zName x2ij 
+  nLoop 1 nVisit 1 nEst 8 zName x2ij 
   zExplain {SEARCH TABLE x2 USING INDEX x2ij (i=? AND j=?)}
 }
 
@@ -187,15 +187,48 @@ do_execsql_test 3.1 {
 do_execsql_test 3.2.1 {
   SELECT d FROM a1 WHERE (a=4 OR b=13)
 } {4 13}
-
-do_scanstatus_test 2.4 {
-  nLoop 1 nVisit 2 nEst 10 zName a1a 
+do_scanstatus_test 3.2.2 {
+  nLoop 1 nVisit 1 nEst 10 zName a1a 
   zExplain {SEARCH TABLE a1 USING INDEX a1a (a=?)}
-
-  nLoop 1 nVisit 2 nEst 10 zName a1bc 
+  nLoop 1 nVisit 1 nEst 10 zName a1bc 
   zExplain {SEARCH TABLE a1 USING INDEX a1bc (b=?)}
 }
 
-
+do_execsql_test 3.2.1 {
+  SELECT count(*) FROM a1 WHERE (a BETWEEN 4 AND 12) OR (b BETWEEN 40 AND 60)
+} {30}
+do_scanstatus_test 3.2.2 {
+  nLoop 1 nVisit 9 nEst 16384 zName a1a 
+  zExplain {SEARCH TABLE a1 USING INDEX a1a (a>? AND a<?)}
+  nLoop 1 nVisit 21 nEst 16384 zName a1bc
+  zExplain {SEARCH TABLE a1 USING INDEX a1bc (b>? AND b<?)}
+}
+
+do_execsql_test 3.3.1 {
+  SELECT count(*) FROM a1 AS x, a1 AS y 
+  WHERE (x.a BETWEEN 4 AND 12) AND (y.b BETWEEN 1 AND 10)
+} {90}
+do_scanstatus_test 3.2.2 {
+  nLoop 1 nVisit 10 nEst 16384 zName a1bc 
+  zExplain {SEARCH TABLE a1 AS y USING COVERING INDEX a1bc (b>? AND b<?)}
+  nLoop 10 nVisit 90 nEst 16384 zName a1a
+  zExplain {SEARCH TABLE a1 AS x USING COVERING INDEX a1a (a>? AND a<?)}
+}
+
+do_execsql_test 3.4.1 {
+  SELECT count(*) FROM a1 WHERE a IN (1, 5, 10, 15);
+} {4}
+do_scanstatus_test 3.4.2 {
+  nLoop 1 nVisit 4 nEst 40 zName a1a 
+  zExplain {SEARCH TABLE a1 USING COVERING INDEX a1a (a=?)}
+}
+
+do_execsql_test 3.4.1 {
+  SELECT count(*) FROM a1 WHERE rowid IN (1, 5, 10, 15);
+} {4}
+do_scanstatus_test 3.4.2 {
+  nLoop 1 nVisit 4 nEst 4 zName a1
+  zExplain {SEARCH TABLE a1 USING INTEGER PRIMARY KEY (rowid=?)}
+}
 
 finish_test