/ Check-in [25ec09400b]
Login

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

Overview
Comment:Enhance the dbstat virtual table with the ability to analyze ATTACHed databases.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 25ec09400b753fcb10a2aae57eb43dbf0548b7ca
User & Date: drh 2015-05-07 14:41:56
Context
2015-05-07
18:29
Testing improvements and corner-case bug fixes for the dbstat virtual table. check-in: d51ce53932 user: drh tags: trunk
14:41
Enhance the dbstat virtual table with the ability to analyze ATTACHed databases. check-in: 25ec09400b user: drh tags: trunk
11:53
Version 3.8.10 check-in: cf975957b9 user: drh tags: trunk, release, version-3.8.10
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/dbstat.c.

   118    118     i64 iOffset;                    /* Value of 'pgOffset' column */
   119    119     int szPage;                     /* Value of 'pgSize' column */
   120    120   };
   121    121   
   122    122   struct StatTable {
   123    123     sqlite3_vtab base;
   124    124     sqlite3 *db;
          125  +  int iDb;                        /* Index of database to analyze */
   125    126   };
   126    127   
   127    128   #ifndef get2byte
   128    129   # define get2byte(x)   ((x)[0]<<8 | (x)[1])
   129    130   #endif
   130    131   
   131    132   /*
................................................................................
   136    137     void *pAux,
   137    138     int argc, const char *const*argv,
   138    139     sqlite3_vtab **ppVtab,
   139    140     char **pzErr
   140    141   ){
   141    142     StatTable *pTab = 0;
   142    143     int rc = SQLITE_OK;
          144  +  int iDb;
   143    145   
          146  +  if( argc>=4 ){
          147  +    iDb = sqlite3FindDbName(db, argv[3]);
          148  +    if( iDb<0 ){
          149  +      *pzErr = sqlite3_mprintf("no such database: %s", argv[3]);
          150  +      return SQLITE_ERROR;
          151  +    }
          152  +  }else{
          153  +    iDb = 0;
          154  +  }
   144    155     rc = sqlite3_declare_vtab(db, VTAB_SCHEMA);
   145    156     if( rc==SQLITE_OK ){
   146    157       pTab = (StatTable *)sqlite3_malloc64(sizeof(StatTable));
   147    158       if( pTab==0 ) rc = SQLITE_NOMEM;
   148    159     }
   149    160   
   150    161     assert( rc==SQLITE_OK || pTab==0 );
   151    162     if( rc==SQLITE_OK ){
   152    163       memset(pTab, 0, sizeof(StatTable));
   153    164       pTab->db = db;
          165  +    pTab->iDb = iDb;
   154    166     }
   155    167   
   156    168     *ppVtab = (sqlite3_vtab*)pTab;
   157    169     return rc;
   158    170   }
   159    171   
   160    172   /*
................................................................................
   201    213     StatCursor *pCsr;
   202    214     int rc;
   203    215   
   204    216     pCsr = (StatCursor *)sqlite3_malloc64(sizeof(StatCursor));
   205    217     if( pCsr==0 ){
   206    218       rc = SQLITE_NOMEM;
   207    219     }else{
          220  +    char *zSql;
   208    221       memset(pCsr, 0, sizeof(StatCursor));
   209    222       pCsr->base.pVtab = pVTab;
   210    223   
   211         -    rc = sqlite3_prepare_v2(pTab->db, 
          224  +    zSql = sqlite3_mprintf(
   212    225           "SELECT 'sqlite_master' AS name, 1 AS rootpage, 'table' AS type"
   213    226           "  UNION ALL  "
   214         -        "SELECT name, rootpage, type FROM sqlite_master WHERE rootpage!=0"
   215         -        "  ORDER BY name", -1,
   216         -        &pCsr->pStmt, 0
   217         -        );
          227  +        "SELECT name, rootpage, type"
          228  +        "  FROM \"%w\".sqlite_master WHERE rootpage!=0"
          229  +        "  ORDER BY name", pTab->db->aDb[pTab->iDb].zName);
          230  +    if( zSql==0 ){
          231  +      rc = SQLITE_NOMEM;
          232  +    }else{
          233  +      rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pCsr->pStmt, 0);
          234  +      sqlite3_free(zSql);
          235  +    }
   218    236       if( rc!=SQLITE_OK ){
   219    237         sqlite3_free(pCsr);
   220    238         pCsr = 0;
   221    239       }
   222    240     }
   223    241   
   224    242     *ppCursor = (sqlite3_vtab_cursor *)pCsr;
................................................................................
   376    394   
   377    395   /*
   378    396   ** Populate the pCsr->iOffset and pCsr->szPage member variables. Based on
   379    397   ** the current value of pCsr->iPageno.
   380    398   */
   381    399   static void statSizeAndOffset(StatCursor *pCsr){
   382    400     StatTable *pTab = (StatTable *)((sqlite3_vtab_cursor *)pCsr)->pVtab;
   383         -  Btree *pBt = pTab->db->aDb[0].pBt;
          401  +  Btree *pBt = pTab->db->aDb[pTab->iDb].pBt;
   384    402     Pager *pPager = sqlite3BtreePager(pBt);
   385    403     sqlite3_file *fd;
   386    404     sqlite3_int64 x[2];
   387    405   
   388    406     /* The default page size and offset */
   389    407     pCsr->szPage = sqlite3BtreeGetPageSize(pBt);
   390    408     pCsr->iOffset = (i64)pCsr->szPage * (pCsr->iPageno - 1);
   391    409   
   392    410     /* If connected to a ZIPVFS backend, override the page size and
   393    411     ** offset with actual values obtained from ZIPVFS.
   394    412     */
   395    413     fd = sqlite3PagerFile(pPager);
   396    414     x[0] = pCsr->iPageno;
   397         -  if( sqlite3OsFileControl(fd, 230440, &x)==SQLITE_OK ){
          415  +  if( fd->pMethods!=0 && sqlite3OsFileControl(fd, 230440, &x)==SQLITE_OK ){
   398    416       pCsr->iOffset = x[0];
   399    417       pCsr->szPage = (int)x[1];
   400    418     }
   401    419   }
   402    420   
   403    421   /*
   404    422   ** Move a statvfs cursor to the next entry in the file.
   405    423   */
   406    424   static int statNext(sqlite3_vtab_cursor *pCursor){
   407    425     int rc;
   408    426     int nPayload;
   409    427     StatCursor *pCsr = (StatCursor *)pCursor;
   410    428     StatTable *pTab = (StatTable *)pCursor->pVtab;
   411         -  Btree *pBt = pTab->db->aDb[0].pBt;
          429  +  Btree *pBt = pTab->db->aDb[pTab->iDb].pBt;
   412    430     Pager *pPager = sqlite3BtreePager(pBt);
   413    431   
   414    432     sqlite3_free(pCsr->zPath);
   415    433     pCsr->zPath = 0;
   416    434   
   417    435   statNextRestart:
   418    436     if( pCsr->aPage[0].pPg==0 ){

Changes to test/stat.test.

   162    162   
   163    163   db close
   164    164   forcedelete test.db
   165    165   sqlite3 db test.db
   166    166   register_dbstat_vtab db
   167    167   do_execsql_test stat-5.1 {
   168    168     PRAGMA auto_vacuum = OFF;
   169         -  CREATE VIRTUAL TABLE temp.stat USING dbstat;
   170         -  CREATE TABLE t1(x);
          169  +  CREATE TABLE tx(y);
          170  +  ATTACH ':memory:' AS aux1;
          171  +  CREATE VIRTUAL TABLE temp.stat USING dbstat(aux1);
          172  +  CREATE TABLE aux1.t1(x);
   171    173     INSERT INTO t1 VALUES(zeroblob(1513));
   172    174     INSERT INTO t1 VALUES(zeroblob(1514));
   173    175     SELECT name, path, pageno, pagetype, ncell, payload, unused, mx_payload
   174    176       FROM stat WHERE name = 't1';
   175    177   } [list \
   176    178     t1 / 2 leaf 2 993 5 1517                \
   177    179     t1 /000+000000 3 overflow 0 1020 0 0    \
   178    180     t1 /001+000000 4 overflow 0 1020 0 0    \
   179    181   ]
   180    182   
          183  +do_catchsql_test stat-6.1 {
          184  +  CREATE VIRTUAL TABLE temp.s2 USING dbstat(mainx);
          185  +} {1 {no such database: mainx}}
          186  +
   181    187   finish_test