From: drh Date: Tue, 8 Sep 2015 21:12:53 +0000 (+0000) Subject: Enhance the DBSTAT virtual table with a new hidden table "schema" that if X-Git-Tag: version-3.9.0~137 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=a46a4a63de1853cf4dac3ecfad4bbefa596d670d;p=thirdparty%2Fsqlite.git Enhance the DBSTAT virtual table with a new hidden table "schema" that if 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 --- diff --git a/manifest b/manifest index a8b91dc375..0203e740f9 100644 --- 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 diff --git a/manifest.uuid b/manifest.uuid index b04d06e2a5..bf85a4aab9 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -06f90bb274c4bb0c30585024c8d365d43c4162f2 \ No newline at end of file +6beb512c7a3c3649b56f0df1ca77855535a87ba7 \ No newline at end of file diff --git a/src/dbstat.c b/src/dbstat.c index c36be020af..f43b14881f 100644 --- a/src/dbstat.c +++ b/src/dbstat.c @@ -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; inConstraint; 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; } diff --git a/src/vdbeapi.c b/src/vdbeapi.c index 15a8bba0d4..faf97634c8 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -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; }