Index: src/dbstat.c ================================================================== --- src/dbstat.c +++ src/dbstat.c @@ -120,10 +120,11 @@ }; struct StatTable { sqlite3_vtab base; sqlite3 *db; + int iDb; /* Index of database to analyze */ }; #ifndef get2byte # define get2byte(x) ((x)[0]<<8 | (x)[1]) #endif @@ -138,11 +139,21 @@ sqlite3_vtab **ppVtab, char **pzErr ){ StatTable *pTab = 0; int rc = SQLITE_OK; + int iDb; + if( argc>=4 ){ + iDb = sqlite3FindDbName(db, argv[3]); + if( iDb<0 ){ + *pzErr = sqlite3_mprintf("no such database: %s", argv[3]); + return SQLITE_ERROR; + } + }else{ + iDb = 0; + } rc = sqlite3_declare_vtab(db, VTAB_SCHEMA); if( rc==SQLITE_OK ){ pTab = (StatTable *)sqlite3_malloc64(sizeof(StatTable)); if( pTab==0 ) rc = SQLITE_NOMEM; } @@ -149,10 +160,11 @@ assert( rc==SQLITE_OK || pTab==0 ); if( rc==SQLITE_OK ){ memset(pTab, 0, sizeof(StatTable)); pTab->db = db; + pTab->iDb = iDb; } *ppVtab = (sqlite3_vtab*)pTab; return rc; } @@ -203,20 +215,26 @@ pCsr = (StatCursor *)sqlite3_malloc64(sizeof(StatCursor)); if( pCsr==0 ){ rc = SQLITE_NOMEM; }else{ + char *zSql; memset(pCsr, 0, sizeof(StatCursor)); pCsr->base.pVtab = pVTab; - rc = sqlite3_prepare_v2(pTab->db, + zSql = sqlite3_mprintf( "SELECT 'sqlite_master' AS name, 1 AS rootpage, 'table' AS type" " UNION ALL " - "SELECT name, rootpage, type FROM sqlite_master WHERE rootpage!=0" - " ORDER BY name", -1, - &pCsr->pStmt, 0 - ); + "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; } } @@ -378,11 +396,11 @@ ** Populate the pCsr->iOffset and pCsr->szPage member variables. Based on ** the current value of pCsr->iPageno. */ static void statSizeAndOffset(StatCursor *pCsr){ StatTable *pTab = (StatTable *)((sqlite3_vtab_cursor *)pCsr)->pVtab; - Btree *pBt = pTab->db->aDb[0].pBt; + Btree *pBt = pTab->db->aDb[pTab->iDb].pBt; Pager *pPager = sqlite3BtreePager(pBt); sqlite3_file *fd; sqlite3_int64 x[2]; /* The default page size and offset */ @@ -392,11 +410,11 @@ /* If connected to a ZIPVFS backend, override the page size and ** offset with actual values obtained from ZIPVFS. */ fd = sqlite3PagerFile(pPager); x[0] = pCsr->iPageno; - if( sqlite3OsFileControl(fd, 230440, &x)==SQLITE_OK ){ + if( fd->pMethods!=0 && sqlite3OsFileControl(fd, 230440, &x)==SQLITE_OK ){ pCsr->iOffset = x[0]; pCsr->szPage = (int)x[1]; } } @@ -406,11 +424,11 @@ static int statNext(sqlite3_vtab_cursor *pCursor){ int rc; int nPayload; StatCursor *pCsr = (StatCursor *)pCursor; StatTable *pTab = (StatTable *)pCursor->pVtab; - Btree *pBt = pTab->db->aDb[0].pBt; + Btree *pBt = pTab->db->aDb[pTab->iDb].pBt; Pager *pPager = sqlite3BtreePager(pBt); sqlite3_free(pCsr->zPath); pCsr->zPath = 0; Index: test/stat.test ================================================================== --- test/stat.test +++ test/stat.test @@ -164,12 +164,14 @@ forcedelete test.db sqlite3 db test.db register_dbstat_vtab db do_execsql_test stat-5.1 { PRAGMA auto_vacuum = OFF; - CREATE VIRTUAL TABLE temp.stat USING dbstat; - CREATE TABLE t1(x); + CREATE TABLE tx(y); + ATTACH ':memory:' AS aux1; + CREATE VIRTUAL TABLE temp.stat USING dbstat(aux1); + CREATE TABLE aux1.t1(x); INSERT INTO t1 VALUES(zeroblob(1513)); INSERT INTO t1 VALUES(zeroblob(1514)); SELECT name, path, pageno, pagetype, ncell, payload, unused, mx_payload FROM stat WHERE name = 't1'; } [list \ @@ -176,6 +178,10 @@ t1 / 2 leaf 2 993 5 1517 \ t1 /000+000000 3 overflow 0 1020 0 0 \ t1 /001+000000 4 overflow 0 1020 0 0 \ ] +do_catchsql_test stat-6.1 { + CREATE VIRTUAL TABLE temp.s2 USING dbstat(mainx); +} {1 {no such database: mainx}} + finish_test