/ Check-in [f5313e0c]
Login

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

Overview
Comment:Remove unused variable from struct WhereInfo. Add some explanatory comments to new code.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | scanstatus
Files: files | file ages | folders
SHA1: f5313e0c680d9baebefb1cf50ddadedd4418a334
User & Date: dan 2014-11-03 11:25:32
Context
2014-11-03
15:33
Add further tests. Fixes so that compilation without ENABLE_STMT_SCANSTATUS works. check-in: a2303c71 user: dan tags: scanstatus
11:25
Remove unused variable from struct WhereInfo. Add some explanatory comments to new code. check-in: f5313e0c user: dan tags: scanstatus
2014-11-01
21:00
Minor performance enhancements to SQLITE_ENABLE_STMT_SCANSTATUS code. check-in: f13d6ba8 user: dan tags: scanstatus
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/vdbe.h.

279
280
281
282
283
284
285
286
287
288
289
290
291
# define VdbeCoverageIf(v,x)
# define VdbeCoverageAlwaysTaken(v)
# define VdbeCoverageNeverTaken(v)
# 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







|

|



279
280
281
282
283
284
285
286
287
288
289
290
291
# define VdbeCoverageIf(v,x)
# define VdbeCoverageAlwaysTaken(v)
# define VdbeCoverageNeverTaken(v)
# define VDBE_OFFSET_LINENO(x) 0
#endif

#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
void sqlite3VdbeScanStatus(Vdbe*, int, int, int, i64, const char*);
#else
# define sqlite3VdbeScanStatus(a,b,c,d,e)
#endif

#endif

Changes to src/vdbeInt.h.

293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
...
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
};

/* 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 */
};

................................................................................
  SubProgram *pProgram;   /* Linked list of all sub-programs used by VM */
  int nOnceFlag;          /* Size of array aOnceFlag[] */
  u8 *aOnceFlag;          /* Flags for OP_Once */
  AuxData *pAuxData;      /* Linked list of auxdata allocations */
#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
};

/*
** The following are allowed values for Vdbe.magic
*/
#define VDBE_MAGIC_INIT     0x26bceaa5    /* Building a VDBE program */







|
|







 







|







293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
...
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
};

/* 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 ScanStatus ScanStatus;
struct ScanStatus {
  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 */
};

................................................................................
  SubProgram *pProgram;   /* Linked list of all sub-programs used by VM */
  int nOnceFlag;          /* Size of array aOnceFlag[] */
  u8 *aOnceFlag;          /* Flags for OP_Once */
  AuxData *pAuxData;      /* Linked list of auxdata allocations */
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
  i64 *anExec;            /* Number of times each op has been executed */
  int nScan;              /* Entries in aScan[] */
  ScanStatus *aScan;      /* Scan definitions for sqlite3_stmt_scanstatus() */
#endif
};

/*
** The following are allowed values for Vdbe.magic
*/
#define VDBE_MAGIC_INIT     0x26bceaa5    /* Building a VDBE program */

Changes to src/vdbeapi.c.

1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
  sqlite3_int64 *pnLoop,          /* OUT: Number of times loop was run */
  sqlite3_int64 *pnVisit,         /* OUT: Number of rows visited (all loops) */
  sqlite3_int64 *pnEst,           /* OUT: Number of rows estimated (per loop) */
  const char **pzName,            /* OUT: Object name (table or index) */
  const char **pzExplain          /* OUT: EQP string */
){
  Vdbe *p = (Vdbe*)pStmt;
  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 ){







|







1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
  sqlite3_int64 *pnLoop,          /* OUT: Number of times loop was run */
  sqlite3_int64 *pnVisit,         /* OUT: Number of rows visited (all loops) */
  sqlite3_int64 *pnEst,           /* OUT: Number of rows estimated (per loop) */
  const char **pzName,            /* OUT: Object name (table or index) */
  const char **pzExplain          /* OUT: EQP string */
){
  Vdbe *p = (Vdbe*)pStmt;
  ScanStatus *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 ){

Changes to src/vdbeaux.c.

597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
  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;
  }







|







|
|
|

|







597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
  return addr;
}

#if defined(SQLITE_ENABLE_STMT_SCANSTATUS)
/*
** Add an entry to the array of counters managed by sqlite3_stmt_scanstatus().
*/
void sqlite3VdbeScanStatus(
  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(ScanStatus);
  ScanStatus *aNew;
  aNew = (ScanStatus*)sqlite3DbRealloc(p->db, p->aScan, nByte);
  if( aNew ){
    ScanStatus *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;
  }

Changes to src/where.c.

2804
2805
2806
2807
2808
2809
2810
2811

2812
2813



2814
2815
2816
2817
2818
2819
2820
....
2915
2916
2917
2918
2919
2920
2921









2922
2923

2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
    explainAppendTerm(pStr, i, z, "<");
  }
  sqlite3StrAccumAppend(pStr, ")", 1);
}

/*
** This function is a no-op unless currently processing an EXPLAIN QUERY PLAN
** command. If the query being compiled is an EXPLAIN QUERY PLAN, a single

** record is added to the output to describe the table scan strategy in 
** pLevel.



*/
static int explainOneScan(
  Parse *pParse,                  /* Parse context */
  SrcList *pTabList,              /* Table list this loop refers 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 */
................................................................................
  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 addScanStatus(a, b, c, d)
#endif








|
>
|
<
>
>
>







 







>
>
>
>
>
>
>
>
>

<
>
|
|
|












|







2804
2805
2806
2807
2808
2809
2810
2811
2812
2813

2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
....
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934

2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
    explainAppendTerm(pStr, i, z, "<");
  }
  sqlite3StrAccumAppend(pStr, ")", 1);
}

/*
** This function is a no-op unless currently processing an EXPLAIN QUERY PLAN
** command, or if either SQLITE_DEBUG or SQLITE_ENABLE_STMT_SCANSTATUS was
** defined at compile-time. If it is not a no-op, a single OP_Explain opcode 
** is added to the output to describe the table scan strategy in pLevel.

**
** If an OP_Explain opcode is added to the VM, its address is returned.
** Otherwise, if no OP_Explain is coded, zero is returned.
*/
static int explainOneScan(
  Parse *pParse,                  /* Parse context */
  SrcList *pTabList,              /* Table list this loop refers 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 */
................................................................................
  return ret;
}
#else
# define explainOneScan(u,v,w,x,y,z) 0
#endif /* SQLITE_OMIT_EXPLAIN */

#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
/*
** Configure the VM passed as the first argument with an
** sqlite3_stmt_scanstatus() entry corresponding to the scan used to 
** implement level pLvl. Argument pSrclist is a pointer to the FROM 
** clause that the scan reads data from.
**
** If argument addrExplain is not 0, it must be the address of an 
** OP_Explain instruction that describes the same loop.
*/
static void addScanStatus(

  Vdbe *v,                        /* Vdbe to add scanstatus entry to */
  SrcList *pSrclist,              /* FROM clause pLvl reads data from */
  WhereLevel *pLvl,               /* Level to add scanstatus() entry for */
  int addrExplain                 /* Address of OP_Explain (or 0) */
){
  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);
  }
  sqlite3VdbeScanStatus(
      v, addrExplain, pLvl->addrBody, pLvl->addrVisit, nEst, zObj
  );
}
#else
# define addScanStatus(a, b, c, d)
#endif

Changes to src/whereInt.h.

406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
  u8 okOnePass;             /* Ok to use one-pass algorithm for UPDATE/DELETE */
  u8 untestedTerms;         /* Not all WHERE terms resolved by outer loop */
  u8 eDistinct;             /* One of the WHERE_DISTINCT_* values below */
  u8 nLevel;                /* Number of nested loop */
  int iTop;                 /* The very beginning of the WHERE loop */
  int iContinue;            /* Jump here to continue with next record */
  int iBreak;               /* Jump here to break out of the loop */
  int iExplain;             /* Address of OP_Explain (if WHERE_ONETABLE_ONLY) */
  int savedNQueryLoop;      /* pParse->nQueryLoop outside the WHERE loop */
  int aiCurOnePass[2];      /* OP_OpenWrite cursors for the ONEPASS opt */
  WhereMaskSet sMaskSet;    /* Map cursor numbers to bitmasks */
  WhereClause sWC;          /* Decomposition of the WHERE clause */
  WhereLevel a[1];          /* Information about each nest loop in WHERE */
};








<







406
407
408
409
410
411
412

413
414
415
416
417
418
419
  u8 okOnePass;             /* Ok to use one-pass algorithm for UPDATE/DELETE */
  u8 untestedTerms;         /* Not all WHERE terms resolved by outer loop */
  u8 eDistinct;             /* One of the WHERE_DISTINCT_* values below */
  u8 nLevel;                /* Number of nested loop */
  int iTop;                 /* The very beginning of the WHERE loop */
  int iContinue;            /* Jump here to continue with next record */
  int iBreak;               /* Jump here to break out of the loop */

  int savedNQueryLoop;      /* pParse->nQueryLoop outside the WHERE loop */
  int aiCurOnePass[2];      /* OP_OpenWrite cursors for the ONEPASS opt */
  WhereMaskSet sMaskSet;    /* Map cursor numbers to bitmasks */
  WhereClause sWC;          /* Decomposition of the WHERE clause */
  WhereLevel a[1];          /* Information about each nest loop in WHERE */
};

Changes to test/scanstatus.test.

226
227
228
229
230
231
232
233



































234
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








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
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=?)}
}

#-------------------------------------------------------------------------
# Test that scanstatus() data is not available for searches performed
# by triggers.
#
# It is available for searches performed as part of FK processing, but 
# not FK action processing.
#
do_execsql_test 4.0 {
  CREATE TABLE t1(a, b, c);
  CREATE TABLE t2(x PRIMARY KEY, y, z);
  CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN
    SELECT * FROM t2 WHERE x BETWEEN 20 AND 40;
  END;
  WITH d(x) AS (SELECT 1 UNION ALL SELECT x+1 AS n FROM d WHERE n<=100)
  INSERT INTO t2 SELECT x, x*2, x*3 FROM d;
}

do_execsql_test    4.1.1 { INSERT INTO t1 VALUES(1, 2, 3); }
do_scanstatus_test 4.1.2 { }

do_execsql_test 4.2 {
  CREATE TABLE p1(x PRIMARY KEY);
  INSERT INTO p1 VALUES(1), (2), (3), (4);
  CREATE TABLE c1(y REFERENCES p1);
  INSERT INTO c1 VALUES(1), (2), (3);
  PRAGMA foreign_keys=on;
}
do_execsql_test    4.2.1 { DELETE FROM p1 WHERE x=4 }
do_scanstatus_test 4.2.2 { 
  nLoop 1 nVisit 1 nEst 1 zName sqlite_autoindex_p1_1 
  zExplain {SEARCH TABLE p1 USING INDEX sqlite_autoindex_p1_1 (x=?)}

  nLoop 1 nVisit 3 nEst 524288 zName c1 zExplain {SCAN TABLE c1}
}

finish_test