mirror of https://github.com/sqlite/sqlite
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
This commit is contained in:
parent
b4d472f609
commit
a46a4a63de
14
manifest
14
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
|
||||
|
|
|
@ -1 +1 @@
|
|||
06f90bb274c4bb0c30585024c8d365d43c4162f2
|
||||
6beb512c7a3c3649b56f0df1ca77855535a87ba7
|
105
src/dbstat.c
105
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; 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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue