]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Enhance the DBSTAT virtual table with a new hidden table "schema" that if
authordrh <drh@noemail.net>
Tue, 8 Sep 2015 21:12:53 +0000 (21:12 +0000)
committerdrh <drh@noemail.net>
Tue, 8 Sep 2015 21:12:53 +0000 (21:12 +0000)
set will cause the table to report on the specified schema rather than on
"main".  Also:  Fix a faulty assert in sqlite3_context_db_handle().

FossilOrigin-Name: 6beb512c7a3c3649b56f0df1ca77855535a87ba7

manifest
manifest.uuid
src/dbstat.c
src/vdbeapi.c

index a8b91dc3758b353961204a497703730e8351c9ac..0203e740f96c30c305d64b992336c9cb6c89cf30 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Eponymous\svirtual\stables\sexist\sin\sthe\s"main"\sschema\sonly.\s\sEnforce\sthis\srule.
-D 2015-09-08T20:26:09.245
+C Enhance\sthe\sDBSTAT\svirtual\stable\swith\sa\snew\shidden\stable\s"schema"\sthat\sif\nset\swill\scause\sthe\stable\sto\sreport\son\sthe\sspecified\sschema\srather\sthan\son\n"main".\s\sAlso:\s\sFix\sa\sfaulty\sassert\sin\ssqlite3_context_db_handle().
+D 2015-09-08T21:12:53.186
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in f85066ce844a28b671aaeeff320921cd0ce36239
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -289,7 +289,7 @@ F src/callback.c 7b44ce59674338ad48b0e84e7b72f935ea4f68b0
 F src/complete.c addcd8160b081131005d5bc2d34adf20c1c5c92f
 F src/ctime.c 5a0b735dc95604766f5dac73973658eef782ee8b
 F src/date.c fb1c99172017dcc8e237339132c91a21a0788584
-F src/dbstat.c f402e77e25089c6003d0c60b3233b9b3947d599a
+F src/dbstat.c e637e7a7ff40ef32132a418c6fdf1cfb63aa27c7
 F src/delete.c 6792c80d7fb54c4df9f7680413952600e7439492
 F src/expr.c 3a76afcdac925294c39903b7002ddb9e5fd29863
 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
@@ -405,7 +405,7 @@ F src/vacuum.c 2ddd5cad2a7b9cef7f9e431b8c7771634c6b1701
 F src/vdbe.c 6d85be995bd2308a5aa2a68c7b564c5d4cc1a6fb
 F src/vdbe.h 4bc88bd0e06f8046ee6ab7487c0015e85ad949ad
 F src/vdbeInt.h 8b54e01ad0463590e7cffabce0bc36da9ee4f816
-F src/vdbeapi.c bda74ef4b5103d7b4a4be36f936d3cf2b56a7d6f
+F src/vdbeapi.c b821d530bcb2900b4604cf5206f2177f3f881d15
 F src/vdbeaux.c fd00b489ab3f44f2dca1e4344faf289b7bfcf649
 F src/vdbeblob.c 1d7b97115e7bbac4c318db416d2ca83fc779544a
 F src/vdbemem.c 19b3036aa4d676e7103b0fb5efd6327da455f915
@@ -1383,7 +1383,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P 33a14e7be1004abca7a30f675459138d7f8d72b1
-R 1f56442884ee3ab877d3d3fe559d09f2
+P 06f90bb274c4bb0c30585024c8d365d43c4162f2
+R 0484df860261efad073810ad511e031a
 U drh
-Z b9e298f3b9bca3ea8a0b0e129438890a
+Z 217b27586d12b1e6acf8f38c50e52968
index b04d06e2a5f33a01db030fb61859b87c964f500e..bf85a4aab9e2f014eef118bb808048cf685f7e29 100644 (file)
@@ -1 +1 @@
-06f90bb274c4bb0c30585024c8d365d43c4162f2
\ No newline at end of file
+6beb512c7a3c3649b56f0df1ca77855535a87ba7
\ No newline at end of file
index c36be020af371643c6bc0120f0a602902276e397..f43b14881f5f04f3fb88a407835789f770c2c58f 100644 (file)
@@ -16,6 +16,9 @@
 ** information from an SQLite database in order to implement the
 ** "sqlite3_analyzer" utility.  See the ../tool/spaceanal.tcl script
 ** for an example implementation.
+**
+** Additional information is available on the "dbstat.html" page of the
+** official SQLite documentation.
 */
 
 #include "sqliteInt.h"   /* Requires access to internal data structures */
@@ -64,7 +67,8 @@
   "  unused     INTEGER,          /* Bytes of unused space on this page */" \
   "  mx_payload INTEGER,          /* Largest payload size of all cells */"  \
   "  pgoffset   INTEGER,          /* Offset of page in file */"             \
-  "  pgsize     INTEGER           /* Size of the page */"                   \
+  "  pgsize     INTEGER,          /* Size of the page */"                   \
+  "  schema     TEXT HIDDEN       /* Database schema being analyzed */"     \
   ");"
 
 
@@ -102,6 +106,7 @@ struct StatCursor {
   sqlite3_vtab_cursor base;
   sqlite3_stmt *pStmt;            /* Iterates through set of root pages */
   int isEof;                      /* After pStmt has returned SQLITE_DONE */
+  int iDb;                        /* Schema used for this query */
 
   StatPage aPage[32];
   int iPage;                      /* Current entry in aPage[] */
@@ -179,9 +184,32 @@ static int statDisconnect(sqlite3_vtab *pVtab){
 
 /*
 ** There is no "best-index". This virtual table always does a linear
-** scan of the binary VFS log file.
+** scan.  However, a schema=? constraint should cause this table to
+** operate on a different database schema, so check for it.
+**
+** idxNum is normally 0, but will be 1 if a schema=? constraint exists.
 */
 static int statBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
+  int i;
+
+  pIdxInfo->estimatedCost = 1.0e6;  /* Initial cost estimate */
+
+  /* Look for a valid schema=? constraint.  If found, change the idxNum to
+  ** 1 and request the value of that constraint be sent to xFilter.  And
+  ** lower the cost estimate to encourage the constrained version to be
+  ** used.
+  */
+  for(i=0; i<pIdxInfo->nConstraint; i++){
+    if( pIdxInfo->aConstraint[i].usable==0 ) continue;
+    if( pIdxInfo->aConstraint[i].op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
+    if( pIdxInfo->aConstraint[i].iColumn!=10 ) continue;
+    pIdxInfo->idxNum = 1;
+    pIdxInfo->estimatedCost = 1.0;
+    pIdxInfo->aConstraintUsage[i].argvIndex = 1;
+    pIdxInfo->aConstraintUsage[i].omit = 1;
+    break;
+  }
+
 
   /* Records are always returned in ascending order of (name, path). 
   ** If this will satisfy the client, set the orderByConsumed flag so that 
@@ -201,7 +229,6 @@ static int statBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
     pIdxInfo->orderByConsumed = 1;
   }
 
-  pIdxInfo->estimatedCost = 10.0;
   return SQLITE_OK;
 }
 
@@ -211,36 +238,18 @@ static int statBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
 static int statOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
   StatTable *pTab = (StatTable *)pVTab;
   StatCursor *pCsr;
-  int rc;
 
   pCsr = (StatCursor *)sqlite3_malloc64(sizeof(StatCursor));
   if( pCsr==0 ){
-    rc = SQLITE_NOMEM;
+    return SQLITE_NOMEM;
   }else{
-    char *zSql;
     memset(pCsr, 0, sizeof(StatCursor));
     pCsr->base.pVtab = pVTab;
-
-    zSql = sqlite3_mprintf(
-        "SELECT 'sqlite_master' AS name, 1 AS rootpage, 'table' AS type"
-        "  UNION ALL  "
-        "SELECT name, rootpage, type"
-        "  FROM \"%w\".sqlite_master WHERE rootpage!=0"
-        "  ORDER BY name", pTab->db->aDb[pTab->iDb].zName);
-    if( zSql==0 ){
-      rc = SQLITE_NOMEM;
-    }else{
-      rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pCsr->pStmt, 0);
-      sqlite3_free(zSql);
-    }
-    if( rc!=SQLITE_OK ){
-      sqlite3_free(pCsr);
-      pCsr = 0;
-    }
+    pCsr->iDb = pTab->iDb;
   }
 
   *ppCursor = (sqlite3_vtab_cursor *)pCsr;
-  return rc;
+  return SQLITE_OK;
 }
 
 static void statClearPage(StatPage *p){
@@ -265,6 +274,7 @@ static void statResetCsr(StatCursor *pCsr){
   pCsr->iPage = 0;
   sqlite3_free(pCsr->zPath);
   pCsr->zPath = 0;
+  pCsr->isEof = 0;
 }
 
 /*
@@ -427,7 +437,7 @@ static int statNext(sqlite3_vtab_cursor *pCursor){
   char *z;
   StatCursor *pCsr = (StatCursor *)pCursor;
   StatTable *pTab = (StatTable *)pCursor->pVtab;
-  Btree *pBt = pTab->db->aDb[pTab->iDb].pBt;
+  Btree *pBt = pTab->db->aDb[pCsr->iDb].pBt;
   Pager *pPager = sqlite3BtreePager(pBt);
 
   sqlite3_free(pCsr->zPath);
@@ -565,9 +575,43 @@ static int statFilter(
   int argc, sqlite3_value **argv
 ){
   StatCursor *pCsr = (StatCursor *)pCursor;
-
+  StatTable *pTab = (StatTable*)(pCursor->pVtab);
+  char *zSql;
+  int rc = SQLITE_OK;
+  char *zMaster;
+
+  if( idxNum==1 ){
+    const char *zDbase = (const char*)sqlite3_value_text(argv[0]);
+    pCsr->iDb = sqlite3FindDbName(pTab->db, zDbase);
+    if( pCsr->iDb<0 ){
+      sqlite3_free(pCursor->pVtab->zErrMsg);
+      pCursor->pVtab->zErrMsg = sqlite3_mprintf("no such schema: %s", zDbase);
+      return pCursor->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM;
+    }
+  }else{
+    pCsr->iDb = pTab->iDb;
+  }
   statResetCsr(pCsr);
-  return statNext(pCursor);
+  sqlite3_finalize(pCsr->pStmt);
+  pCsr->pStmt = 0;
+  zMaster = pCsr->iDb==1 ? "sqlite_temp_master" : "sqlite_master";
+  zSql = sqlite3_mprintf(
+      "SELECT 'sqlite_master' AS name, 1 AS rootpage, 'table' AS type"
+      "  UNION ALL  "
+      "SELECT name, rootpage, type"
+      "  FROM \"%w\".%s WHERE rootpage!=0"
+      "  ORDER BY name", pTab->db->aDb[pCsr->iDb].zName, zMaster);
+  if( zSql==0 ){
+    return SQLITE_NOMEM;
+  }else{
+    rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pCsr->pStmt, 0);
+    sqlite3_free(zSql);
+  }
+
+  if( rc==SQLITE_OK ){
+    rc = statNext(pCursor);
+  }
+  return rc;
 }
 
 static int statColumn(
@@ -604,10 +648,15 @@ static int statColumn(
     case 8:            /* pgoffset */
       sqlite3_result_int64(ctx, pCsr->iOffset);
       break;
-    default:           /* pgsize */
-      assert( i==9 );
+    case 9:            /* pgsize */
       sqlite3_result_int(ctx, pCsr->szPage);
       break;
+    default: {          /* schema */
+      sqlite3 *db = sqlite3_context_db_handle(ctx);
+      int iDb = pCsr->iDb;
+      sqlite3_result_text(ctx, db->aDb[iDb].zName, -1, SQLITE_STATIC);
+      break;
+    }
   }
   return SQLITE_OK;
 }
index 15a8bba0d4ea75a89d262c917f9fde44a32dc09d..faf97634c8eefb5bcef7efa2beb677d40f50e49f 100644 (file)
@@ -696,7 +696,7 @@ void *sqlite3_user_data(sqlite3_context *p){
 ** application defined function.
 */
 sqlite3 *sqlite3_context_db_handle(sqlite3_context *p){
-  assert( p && p->pFunc );
+  assert( p && p->pOut );
   return p->pOut->db;
 }