#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_MEMSTATVTAB)
#if !defined(SQLITEINT_H)
#include "sqlite3ext.h"
#endif
SQLITE_EXTENSION_INIT1
#include <assert.h>
#include <string.h>
#ifndef SQLITE_OMIT_VIRTUALTABLE
typedef struct memstat_vtab memstat_vtab;
struct memstat_vtab {
sqlite3_vtab base;
sqlite3 *db;
};
typedef struct memstat_cursor memstat_cursor;
struct memstat_cursor {
sqlite3_vtab_cursor base;
sqlite3 *db;
int iRowid;
int iDb;
int nDb;
char **azDb;
sqlite3_int64 aVal[2];
};
static int memstatConnect(
sqlite3 *db,
void *pAux,
int argc, const char *const*argv,
sqlite3_vtab **ppVtab,
char **pzErr
){
memstat_vtab *pNew;
int rc;
#define MSV_COLUMN_NAME 0
#define MSV_COLUMN_SCHEMA 1
#define MSV_COLUMN_VALUE 2
#define MSV_COLUMN_HIWTR 3
rc = sqlite3_declare_vtab(db,"CREATE TABLE x(name,schema,value,hiwtr)");
if( rc==SQLITE_OK ){
pNew = sqlite3_malloc( sizeof(*pNew) );
*ppVtab = (sqlite3_vtab*)pNew;
if( pNew==0 ) return SQLITE_NOMEM;
memset(pNew, 0, sizeof(*pNew));
pNew->db = db;
}
return rc;
}
static int memstatDisconnect(sqlite3_vtab *pVtab){
sqlite3_free(pVtab);
return SQLITE_OK;
}
static int memstatOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
memstat_cursor *pCur;
pCur = sqlite3_malloc( sizeof(*pCur) );
if( pCur==0 ) return SQLITE_NOMEM;
memset(pCur, 0, sizeof(*pCur));
pCur->db = ((memstat_vtab*)p)->db;
*ppCursor = &pCur->base;
return SQLITE_OK;
}
static void memstatClearSchema(memstat_cursor *pCur){
int i;
if( pCur->azDb==0 ) return;
for(i=0; i<pCur->nDb; i++){
sqlite3_free(pCur->azDb[i]);
}
sqlite3_free(pCur->azDb);
pCur->azDb = 0;
pCur->nDb = 0;
}
static int memstatFindSchemas(memstat_cursor *pCur){
sqlite3_stmt *pStmt = 0;
int rc;
if( pCur->nDb ) return SQLITE_OK;
rc = sqlite3_prepare_v2(pCur->db, "PRAGMA database_list", -1, &pStmt, 0);
if( rc ){
sqlite3_finalize(pStmt);
return rc;
}
while( sqlite3_step(pStmt)==SQLITE_ROW ){
char **az, *z;
az = sqlite3_realloc64(pCur->azDb, sizeof(char*)*(pCur->nDb+1));
if( az==0 ){
memstatClearSchema(pCur);
return SQLITE_NOMEM;
}
pCur->azDb = az;
z = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 1));
if( z==0 ){
memstatClearSchema(pCur);
return SQLITE_NOMEM;
}
pCur->azDb[pCur->nDb] = z;
pCur->nDb++;
}
sqlite3_finalize(pStmt);
return SQLITE_OK;
}
static int memstatClose(sqlite3_vtab_cursor *cur){
memstat_cursor *pCur = (memstat_cursor*)cur;
memstatClearSchema(pCur);
sqlite3_free(cur);
return SQLITE_OK;
}
#define MSV_GSTAT 0
#define MSV_DB 1
#define MSV_ZIPVFS 2
static const struct MemstatColumns {
const char *zName;
unsigned char eType;
unsigned char mNull;
int eOp;
} aMemstatColumn[] = {
{"MEMORY_USED", MSV_GSTAT, 2, SQLITE_STATUS_MEMORY_USED },
{"MALLOC_SIZE", MSV_GSTAT, 6, SQLITE_STATUS_MALLOC_SIZE },
{"MALLOC_COUNT", MSV_GSTAT, 2, SQLITE_STATUS_MALLOC_COUNT },
{"PAGECACHE_USED", MSV_GSTAT, 2, SQLITE_STATUS_PAGECACHE_USED },
{"PAGECACHE_OVERFLOW", MSV_GSTAT, 2, SQLITE_STATUS_PAGECACHE_OVERFLOW },
{"PAGECACHE_SIZE", MSV_GSTAT, 6, SQLITE_STATUS_PAGECACHE_SIZE },
{"PARSER_STACK", MSV_GSTAT, 6, SQLITE_STATUS_PARSER_STACK },
{"DB_LOOKASIDE_USED", MSV_DB, 2, SQLITE_DBSTATUS_LOOKASIDE_USED },
{"DB_LOOKASIDE_HIT", MSV_DB, 6, SQLITE_DBSTATUS_LOOKASIDE_HIT },
{"DB_LOOKASIDE_MISS_SIZE", MSV_DB, 6, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE},
{"DB_LOOKASIDE_MISS_FULL", MSV_DB, 6, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL},
{"DB_CACHE_USED", MSV_DB, 10, SQLITE_DBSTATUS_CACHE_USED },
#if SQLITE_VERSION_NUMBER >= 3140000
{"DB_CACHE_USED_SHARED", MSV_DB, 10, SQLITE_DBSTATUS_CACHE_USED_SHARED },
#endif
{"DB_SCHEMA_USED", MSV_DB, 10, SQLITE_DBSTATUS_SCHEMA_USED },
{"DB_STMT_USED", MSV_DB, 10, SQLITE_DBSTATUS_STMT_USED },
{"DB_CACHE_HIT", MSV_DB, 10, SQLITE_DBSTATUS_CACHE_HIT },
{"DB_CACHE_MISS", MSV_DB, 10, SQLITE_DBSTATUS_CACHE_MISS },
{"DB_CACHE_WRITE", MSV_DB, 10, SQLITE_DBSTATUS_CACHE_WRITE },
#if SQLITE_VERSION_NUMBER >= 3230000
{"DB_CACHE_SPILL", MSV_DB, 10, SQLITE_DBSTATUS_CACHE_SPILL },
#endif
{"DB_DEFERRED_FKS", MSV_DB, 10, SQLITE_DBSTATUS_DEFERRED_FKS },
#ifdef SQLITE_ENABLE_ZIPVFS
{"ZIPVFS_CACHE_USED", MSV_ZIPVFS, 8, 231454 },
{"ZIPVFS_CACHE_HIT", MSV_ZIPVFS, 8, 231455 },
{"ZIPVFS_CACHE_MISS", MSV_ZIPVFS, 8, 231456 },
{"ZIPVFS_CACHE_WRITE", MSV_ZIPVFS, 8, 231457 },
{"ZIPVFS_DIRECT_READ", MSV_ZIPVFS, 8, 231458 },
{"ZIPVFS_DIRECT_BYTES", MSV_ZIPVFS, 8, 231459 },
#endif
};
#define MSV_NROW (sizeof(aMemstatColumn)/sizeof(aMemstatColumn[0]))
static int memstatNext(sqlite3_vtab_cursor *cur){
memstat_cursor *pCur = (memstat_cursor*)cur;
int i;
assert( pCur->iRowid<=MSV_NROW );
while(1){
i = (int)pCur->iRowid - 1;
if( i<0 || (aMemstatColumn[i].mNull & 2)!=0 || (++pCur->iDb)>=pCur->nDb ){
pCur->iRowid++;
if( pCur->iRowid>MSV_NROW ) return SQLITE_OK;
pCur->iDb = 0;
i++;
}
pCur->aVal[0] = 0;
pCur->aVal[1] = 0;
switch( aMemstatColumn[i].eType ){
case MSV_GSTAT: {
if( sqlite3_libversion_number()>=3010000 ){
sqlite3_status64(aMemstatColumn[i].eOp,
&pCur->aVal[0], &pCur->aVal[1],0);
}else{
int xCur, xHiwtr;
sqlite3_status(aMemstatColumn[i].eOp, &xCur, &xHiwtr, 0);
pCur->aVal[0] = xCur;
pCur->aVal[1] = xHiwtr;
}
break;
}
case MSV_DB: {
int xCur, xHiwtr;
sqlite3_db_status(pCur->db, aMemstatColumn[i].eOp, &xCur, &xHiwtr, 0);
pCur->aVal[0] = xCur;
pCur->aVal[1] = xHiwtr;
break;
}
case MSV_ZIPVFS: {
int rc;
rc = sqlite3_file_control(pCur->db, pCur->azDb[pCur->iDb],
aMemstatColumn[i].eOp, (void*)&pCur->aVal[0]);
if( rc!=SQLITE_OK ) continue;
break;
}
}
break;
}
return SQLITE_OK;
}
static int memstatColumn(
sqlite3_vtab_cursor *cur,
sqlite3_context *ctx,
int iCol
){
memstat_cursor *pCur = (memstat_cursor*)cur;
int i;
assert( pCur->iRowid>0 && pCur->iRowid<=MSV_NROW );
i = (int)pCur->iRowid - 1;
if( (aMemstatColumn[i].mNull & (1<<iCol))!=0 ){
return SQLITE_OK;
}
switch( iCol ){
case MSV_COLUMN_NAME: {
sqlite3_result_text(ctx, aMemstatColumn[i].zName, -1, SQLITE_STATIC);
break;
}
case MSV_COLUMN_SCHEMA: {
sqlite3_result_text(ctx, pCur->azDb[pCur->iDb], -1, 0);
break;
}
case MSV_COLUMN_VALUE: {
sqlite3_result_int64(ctx, pCur->aVal[0]);
break;
}
case MSV_COLUMN_HIWTR: {
sqlite3_result_int64(ctx, pCur->aVal[1]);
break;
}
}
return SQLITE_OK;
}
static int memstatRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
memstat_cursor *pCur = (memstat_cursor*)cur;
*pRowid = pCur->iRowid*1000 + pCur->iDb;
return SQLITE_OK;
}
static int memstatEof(sqlite3_vtab_cursor *cur){
memstat_cursor *pCur = (memstat_cursor*)cur;
return pCur->iRowid>MSV_NROW;
}
static int memstatFilter(
sqlite3_vtab_cursor *pVtabCursor,
int idxNum, const char *idxStr,
int argc, sqlite3_value **argv
){
memstat_cursor *pCur = (memstat_cursor *)pVtabCursor;
int rc = memstatFindSchemas(pCur);
if( rc ) return rc;
pCur->iRowid = 0;
pCur->iDb = 0;
return memstatNext(pVtabCursor);
}
static int memstatBestIndex(
sqlite3_vtab *tab,
sqlite3_index_info *pIdxInfo
){
pIdxInfo->estimatedCost = (double)500;
pIdxInfo->estimatedRows = 500;
return SQLITE_OK;
}
static sqlite3_module memstatModule = {
0,
0,
memstatConnect,
memstatBestIndex,
memstatDisconnect,
0,
memstatOpen,
memstatClose,
memstatFilter,
memstatNext,
memstatEof,
memstatColumn,
memstatRowid,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
};
#endif
int sqlite3MemstatVtabInit(sqlite3 *db){
int rc = SQLITE_OK;
#ifndef SQLITE_OMIT_VIRTUALTABLE
rc = sqlite3_create_module(db, "sqlite_memstat", &memstatModule, 0);
#endif
return rc;
}
#ifndef SQLITE_CORE
#ifdef _WIN32
__declspec(dllexport)
#endif
int sqlite3_memstat_init(
sqlite3 *db,
char **pzErrMsg,
const sqlite3_api_routines *pApi
){
int rc = SQLITE_OK;
SQLITE_EXTENSION_INIT2(pApi);
#ifndef SQLITE_OMIT_VIRTUALTABLE
rc = sqlite3MemstatVtabInit(db);
#endif
return rc;
}
#endif
#endif