4 ** The author disclaims copyright to this source code. In place of
5 ** a legal notice, here is a blessing:
7 ** May you do good and not evil.
8 ** May you find forgiveness for yourself and forgive others.
9 ** May you share freely, never taking more than you give.
11 *************************************************************************
13 ** This file demonstrates an eponymous virtual table that returns information
14 ** from sqlite3_status64() and sqlite3_db_status().
21 ** SELECT * FROM memstat;
23 #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_MEMSTATVTAB)
24 #if !defined(SQLITEINT_H)
25 #include "sqlite3ext.h"
27 SQLITE_EXTENSION_INIT1
31 #ifndef SQLITE_OMIT_VIRTUALTABLE
33 /* memstat_vtab is a subclass of sqlite3_vtab which will
34 ** serve as the underlying representation of a memstat virtual table
36 typedef struct memstat_vtab memstat_vtab
;
38 sqlite3_vtab base
; /* Base class - must be first */
39 sqlite3
*db
; /* Database connection for this memstat vtab */
42 /* memstat_cursor is a subclass of sqlite3_vtab_cursor which will
43 ** serve as the underlying representation of a cursor that scans
44 ** over rows of the result
46 typedef struct memstat_cursor memstat_cursor
;
47 struct memstat_cursor
{
48 sqlite3_vtab_cursor base
; /* Base class - must be first */
49 sqlite3
*db
; /* Database connection for this cursor */
50 int iRowid
; /* Current row in aMemstatColumn[] */
51 int iDb
; /* Which schema we are looking at */
52 int nDb
; /* Number of schemas */
53 char **azDb
; /* Names of all schemas */
54 sqlite3_int64 aVal
[2]; /* Result values */
58 ** The memstatConnect() method is invoked to create a new
59 ** memstat_vtab that describes the memstat virtual table.
61 ** Think of this routine as the constructor for memstat_vtab objects.
63 ** All this routine needs to do is:
65 ** (1) Allocate the memstat_vtab object and initialize all fields.
67 ** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the
68 ** result set of queries against memstat will look like.
70 static int memstatConnect(
73 int argc
, const char *const*argv
,
74 sqlite3_vtab
**ppVtab
,
81 #define MSV_COLUMN_NAME 0 /* Name of quantity being measured */
82 #define MSV_COLUMN_SCHEMA 1 /* schema name */
83 #define MSV_COLUMN_VALUE 2 /* Current value */
84 #define MSV_COLUMN_HIWTR 3 /* Highwater mark */
86 rc
= sqlite3_declare_vtab(db
,"CREATE TABLE x(name,schema,value,hiwtr)");
88 pNew
= sqlite3_malloc( sizeof(*pNew
) );
89 *ppVtab
= (sqlite3_vtab
*)pNew
;
90 if( pNew
==0 ) return SQLITE_NOMEM
;
91 memset(pNew
, 0, sizeof(*pNew
));
98 ** This method is the destructor for memstat_cursor objects.
100 static int memstatDisconnect(sqlite3_vtab
*pVtab
){
106 ** Constructor for a new memstat_cursor object.
108 static int memstatOpen(sqlite3_vtab
*p
, sqlite3_vtab_cursor
**ppCursor
){
109 memstat_cursor
*pCur
;
110 pCur
= sqlite3_malloc( sizeof(*pCur
) );
111 if( pCur
==0 ) return SQLITE_NOMEM
;
112 memset(pCur
, 0, sizeof(*pCur
));
113 pCur
->db
= ((memstat_vtab
*)p
)->db
;
114 *ppCursor
= &pCur
->base
;
119 ** Clear all the schema names from a cursor
121 static void memstatClearSchema(memstat_cursor
*pCur
){
123 if( pCur
->azDb
==0 ) return;
124 for(i
=0; i
<pCur
->nDb
; i
++){
125 sqlite3_free(pCur
->azDb
[i
]);
127 sqlite3_free(pCur
->azDb
);
133 ** Fill in the azDb[] array for the cursor.
135 static int memstatFindSchemas(memstat_cursor
*pCur
){
136 sqlite3_stmt
*pStmt
= 0;
138 if( pCur
->nDb
) return SQLITE_OK
;
139 rc
= sqlite3_prepare_v2(pCur
->db
, "PRAGMA database_list", -1, &pStmt
, 0);
141 sqlite3_finalize(pStmt
);
144 while( sqlite3_step(pStmt
)==SQLITE_ROW
){
146 az
= sqlite3_realloc64(pCur
->azDb
, sizeof(char*)*(pCur
->nDb
+1));
148 memstatClearSchema(pCur
);
152 z
= sqlite3_mprintf("%s", sqlite3_column_text(pStmt
, 1));
154 memstatClearSchema(pCur
);
157 pCur
->azDb
[pCur
->nDb
] = z
;
160 sqlite3_finalize(pStmt
);
166 ** Destructor for a memstat_cursor.
168 static int memstatClose(sqlite3_vtab_cursor
*cur
){
169 memstat_cursor
*pCur
= (memstat_cursor
*)cur
;
170 memstatClearSchema(pCur
);
177 ** Allowed values for aMemstatColumn[].eType
179 #define MSV_GSTAT 0 /* sqlite3_status64() information */
180 #define MSV_DB 1 /* sqlite3_db_status() information */
181 #define MSV_ZIPVFS 2 /* ZIPVFS file-control with 64-bit return */
184 ** An array of quantities that can be measured and reported by
185 ** this virtual table
187 static const struct MemstatColumns
{
188 const char *zName
; /* Symbolic name */
189 unsigned char eType
; /* Type of interface */
190 unsigned char mNull
; /* Bitmask of which columns are NULL */
191 /* 2: dbname, 4: current, 8: hiwtr */
192 int eOp
; /* Opcode */
193 } aMemstatColumn
[] = {
194 {"MEMORY_USED", MSV_GSTAT
, 2, SQLITE_STATUS_MEMORY_USED
},
195 {"MALLOC_SIZE", MSV_GSTAT
, 6, SQLITE_STATUS_MALLOC_SIZE
},
196 {"MALLOC_COUNT", MSV_GSTAT
, 2, SQLITE_STATUS_MALLOC_COUNT
},
197 {"PAGECACHE_USED", MSV_GSTAT
, 2, SQLITE_STATUS_PAGECACHE_USED
},
198 {"PAGECACHE_OVERFLOW", MSV_GSTAT
, 2, SQLITE_STATUS_PAGECACHE_OVERFLOW
},
199 {"PAGECACHE_SIZE", MSV_GSTAT
, 6, SQLITE_STATUS_PAGECACHE_SIZE
},
200 {"PARSER_STACK", MSV_GSTAT
, 6, SQLITE_STATUS_PARSER_STACK
},
201 {"DB_LOOKASIDE_USED", MSV_DB
, 2, SQLITE_DBSTATUS_LOOKASIDE_USED
},
202 {"DB_LOOKASIDE_HIT", MSV_DB
, 6, SQLITE_DBSTATUS_LOOKASIDE_HIT
},
203 {"DB_LOOKASIDE_MISS_SIZE", MSV_DB
, 6, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE
},
204 {"DB_LOOKASIDE_MISS_FULL", MSV_DB
, 6, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL
},
205 {"DB_CACHE_USED", MSV_DB
, 10, SQLITE_DBSTATUS_CACHE_USED
},
206 #if SQLITE_VERSION_NUMBER >= 3140000
207 {"DB_CACHE_USED_SHARED", MSV_DB
, 10, SQLITE_DBSTATUS_CACHE_USED_SHARED
},
209 {"DB_SCHEMA_USED", MSV_DB
, 10, SQLITE_DBSTATUS_SCHEMA_USED
},
210 {"DB_STMT_USED", MSV_DB
, 10, SQLITE_DBSTATUS_STMT_USED
},
211 {"DB_CACHE_HIT", MSV_DB
, 10, SQLITE_DBSTATUS_CACHE_HIT
},
212 {"DB_CACHE_MISS", MSV_DB
, 10, SQLITE_DBSTATUS_CACHE_MISS
},
213 {"DB_CACHE_WRITE", MSV_DB
, 10, SQLITE_DBSTATUS_CACHE_WRITE
},
214 #if SQLITE_VERSION_NUMBER >= 3230000
215 {"DB_CACHE_SPILL", MSV_DB
, 10, SQLITE_DBSTATUS_CACHE_SPILL
},
217 {"DB_DEFERRED_FKS", MSV_DB
, 10, SQLITE_DBSTATUS_DEFERRED_FKS
},
218 #ifdef SQLITE_ENABLE_ZIPVFS
219 {"ZIPVFS_CACHE_USED", MSV_ZIPVFS
, 8, 231454 },
220 {"ZIPVFS_CACHE_HIT", MSV_ZIPVFS
, 8, 231455 },
221 {"ZIPVFS_CACHE_MISS", MSV_ZIPVFS
, 8, 231456 },
222 {"ZIPVFS_CACHE_WRITE", MSV_ZIPVFS
, 8, 231457 },
223 {"ZIPVFS_DIRECT_READ", MSV_ZIPVFS
, 8, 231458 },
224 {"ZIPVFS_DIRECT_BYTES", MSV_ZIPVFS
, 8, 231459 },
225 #endif /* SQLITE_ENABLE_ZIPVFS */
227 #define MSV_NROW (sizeof(aMemstatColumn)/sizeof(aMemstatColumn[0]))
230 ** Advance a memstat_cursor to its next row of output.
232 static int memstatNext(sqlite3_vtab_cursor
*cur
){
233 memstat_cursor
*pCur
= (memstat_cursor
*)cur
;
235 assert( pCur
->iRowid
<=MSV_NROW
);
237 i
= (int)pCur
->iRowid
- 1;
238 if( i
<0 || (aMemstatColumn
[i
].mNull
& 2)!=0 || (++pCur
->iDb
)>=pCur
->nDb
){
240 if( pCur
->iRowid
>MSV_NROW
) return SQLITE_OK
; /* End of the table */
246 switch( aMemstatColumn
[i
].eType
){
248 if( sqlite3_libversion_number()>=3010000 ){
249 sqlite3_status64(aMemstatColumn
[i
].eOp
,
250 &pCur
->aVal
[0], &pCur
->aVal
[1],0);
253 sqlite3_status(aMemstatColumn
[i
].eOp
, &xCur
, &xHiwtr
, 0);
254 pCur
->aVal
[0] = xCur
;
255 pCur
->aVal
[1] = xHiwtr
;
261 sqlite3_db_status(pCur
->db
, aMemstatColumn
[i
].eOp
, &xCur
, &xHiwtr
, 0);
262 pCur
->aVal
[0] = xCur
;
263 pCur
->aVal
[1] = xHiwtr
;
268 rc
= sqlite3_file_control(pCur
->db
, pCur
->azDb
[pCur
->iDb
],
269 aMemstatColumn
[i
].eOp
, (void*)&pCur
->aVal
[0]);
270 if( rc
!=SQLITE_OK
) continue;
281 ** Return values of columns for the row at which the memstat_cursor
282 ** is currently pointing.
284 static int memstatColumn(
285 sqlite3_vtab_cursor
*cur
, /* The cursor */
286 sqlite3_context
*ctx
, /* First argument to sqlite3_result_...() */
287 int iCol
/* Which column to return */
289 memstat_cursor
*pCur
= (memstat_cursor
*)cur
;
291 assert( pCur
->iRowid
>0 && pCur
->iRowid
<=MSV_NROW
);
292 i
= (int)pCur
->iRowid
- 1;
293 if( (aMemstatColumn
[i
].mNull
& (1<<iCol
))!=0 ){
297 case MSV_COLUMN_NAME
: {
298 sqlite3_result_text(ctx
, aMemstatColumn
[i
].zName
, -1, SQLITE_STATIC
);
301 case MSV_COLUMN_SCHEMA
: {
302 sqlite3_result_text(ctx
, pCur
->azDb
[pCur
->iDb
], -1, 0);
305 case MSV_COLUMN_VALUE
: {
306 sqlite3_result_int64(ctx
, pCur
->aVal
[0]);
309 case MSV_COLUMN_HIWTR
: {
310 sqlite3_result_int64(ctx
, pCur
->aVal
[1]);
318 ** Return the rowid for the current row. In this implementation, the
319 ** rowid is the same as the output value.
321 static int memstatRowid(sqlite3_vtab_cursor
*cur
, sqlite_int64
*pRowid
){
322 memstat_cursor
*pCur
= (memstat_cursor
*)cur
;
323 *pRowid
= pCur
->iRowid
*1000 + pCur
->iDb
;
328 ** Return TRUE if the cursor has been moved off of the last
331 static int memstatEof(sqlite3_vtab_cursor
*cur
){
332 memstat_cursor
*pCur
= (memstat_cursor
*)cur
;
333 return pCur
->iRowid
>MSV_NROW
;
337 ** This method is called to "rewind" the memstat_cursor object back
338 ** to the first row of output. This method is always called at least
339 ** once prior to any call to memstatColumn() or memstatRowid() or
342 static int memstatFilter(
343 sqlite3_vtab_cursor
*pVtabCursor
,
344 int idxNum
, const char *idxStr
,
345 int argc
, sqlite3_value
**argv
347 memstat_cursor
*pCur
= (memstat_cursor
*)pVtabCursor
;
348 int rc
= memstatFindSchemas(pCur
);
352 return memstatNext(pVtabCursor
);
356 ** SQLite will invoke this method one or more times while planning a query
357 ** that uses the memstat virtual table. This routine needs to create
358 ** a query plan for each invocation and compute an estimated cost for that
361 static int memstatBestIndex(
363 sqlite3_index_info
*pIdxInfo
365 pIdxInfo
->estimatedCost
= (double)500;
366 pIdxInfo
->estimatedRows
= 500;
371 ** This following structure defines all the methods for the
372 ** memstat virtual table.
374 static sqlite3_module memstatModule
= {
377 memstatConnect
, /* xConnect */
378 memstatBestIndex
, /* xBestIndex */
379 memstatDisconnect
, /* xDisconnect */
381 memstatOpen
, /* xOpen - open a cursor */
382 memstatClose
, /* xClose - close a cursor */
383 memstatFilter
, /* xFilter - configure scan constraints */
384 memstatNext
, /* xNext - advance a cursor */
385 memstatEof
, /* xEof - check for end of scan */
386 memstatColumn
, /* xColumn - read data */
387 memstatRowid
, /* xRowid - read data */
402 #endif /* SQLITE_OMIT_VIRTUALTABLE */
404 int sqlite3MemstatVtabInit(sqlite3
*db
){
406 #ifndef SQLITE_OMIT_VIRTUALTABLE
407 rc
= sqlite3_create_module(db
, "sqlite_memstat", &memstatModule
, 0);
414 __declspec(dllexport
)
416 int sqlite3_memstat_init(
419 const sqlite3_api_routines
*pApi
422 SQLITE_EXTENSION_INIT2(pApi
);
423 #ifndef SQLITE_OMIT_VIRTUALTABLE
424 rc
= sqlite3MemstatVtabInit(db
);
428 #endif /* SQLITE_CORE */
429 #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_MEMSTATVTAB) */