1c6603af7Sdrh /*
2c6603af7Sdrh ** 2017-05-31
3c6603af7Sdrh **
4c6603af7Sdrh ** The author disclaims copyright to this source code. In place of
5c6603af7Sdrh ** a legal notice, here is a blessing:
6c6603af7Sdrh **
7c6603af7Sdrh ** May you do good and not evil.
8c6603af7Sdrh ** May you find forgiveness for yourself and forgive others.
9c6603af7Sdrh ** May you share freely, never taking more than you give.
10c6603af7Sdrh **
11c6603af7Sdrh *************************************************************************
12c6603af7Sdrh **
13c6603af7Sdrh ** This file demonstrates an eponymous virtual table that returns information
14c6603af7Sdrh ** about all prepared statements for the database connection.
15c6603af7Sdrh **
16c6603af7Sdrh ** Usage example:
17c6603af7Sdrh **
18c6603af7Sdrh ** .load ./stmt
19c6603af7Sdrh ** .mode line
20c6603af7Sdrh ** .header on
21c6603af7Sdrh ** SELECT * FROM stmt;
22c6603af7Sdrh */
23c6603af7Sdrh #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB)
24c6603af7Sdrh #if !defined(SQLITEINT_H)
25c6603af7Sdrh #include "sqlite3ext.h"
26c6603af7Sdrh #endif
27c6603af7Sdrh SQLITE_EXTENSION_INIT1
28c6603af7Sdrh #include <assert.h>
29c6603af7Sdrh #include <string.h>
30c6603af7Sdrh
31c6603af7Sdrh #ifndef SQLITE_OMIT_VIRTUALTABLE
32c6603af7Sdrh
33e26f592eSdan
34e26f592eSdan #define STMT_NUM_INTEGER_COLUMN 10
35e26f592eSdan typedef struct StmtRow StmtRow;
36e26f592eSdan struct StmtRow {
37e26f592eSdan sqlite3_int64 iRowid; /* Rowid value */
38e26f592eSdan char *zSql; /* column "sql" */
39e26f592eSdan int aCol[STMT_NUM_INTEGER_COLUMN+1]; /* all other column values */
40e26f592eSdan StmtRow *pNext; /* Next row to return */
41e26f592eSdan };
42e26f592eSdan
43c6603af7Sdrh /* stmt_vtab is a subclass of sqlite3_vtab which will
44c6603af7Sdrh ** serve as the underlying representation of a stmt virtual table
45c6603af7Sdrh */
46c6603af7Sdrh typedef struct stmt_vtab stmt_vtab;
47c6603af7Sdrh struct stmt_vtab {
48c6603af7Sdrh sqlite3_vtab base; /* Base class - must be first */
49c6603af7Sdrh sqlite3 *db; /* Database connection for this stmt vtab */
50c6603af7Sdrh };
51c6603af7Sdrh
52c6603af7Sdrh /* stmt_cursor is a subclass of sqlite3_vtab_cursor which will
53c6603af7Sdrh ** serve as the underlying representation of a cursor that scans
54c6603af7Sdrh ** over rows of the result
55c6603af7Sdrh */
56c6603af7Sdrh typedef struct stmt_cursor stmt_cursor;
57c6603af7Sdrh struct stmt_cursor {
58c6603af7Sdrh sqlite3_vtab_cursor base; /* Base class - must be first */
59c6603af7Sdrh sqlite3 *db; /* Database connection for this cursor */
60e26f592eSdan StmtRow *pRow; /* Current row */
61c6603af7Sdrh };
62c6603af7Sdrh
63c6603af7Sdrh /*
64c6603af7Sdrh ** The stmtConnect() method is invoked to create a new
654a9e1407Sdrh ** stmt_vtab that describes the stmt virtual table.
66c6603af7Sdrh **
67c6603af7Sdrh ** Think of this routine as the constructor for stmt_vtab objects.
68c6603af7Sdrh **
69c6603af7Sdrh ** All this routine needs to do is:
70c6603af7Sdrh **
71c6603af7Sdrh ** (1) Allocate the stmt_vtab object and initialize all fields.
72c6603af7Sdrh **
73c6603af7Sdrh ** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the
744a9e1407Sdrh ** result set of queries against stmt will look like.
75c6603af7Sdrh */
stmtConnect(sqlite3 * db,void * pAux,int argc,const char * const * argv,sqlite3_vtab ** ppVtab,char ** pzErr)76c6603af7Sdrh static int stmtConnect(
77c6603af7Sdrh sqlite3 *db,
78c6603af7Sdrh void *pAux,
79c6603af7Sdrh int argc, const char *const*argv,
80c6603af7Sdrh sqlite3_vtab **ppVtab,
81c6603af7Sdrh char **pzErr
82c6603af7Sdrh ){
83c6603af7Sdrh stmt_vtab *pNew;
84c6603af7Sdrh int rc;
85c6603af7Sdrh
86c6603af7Sdrh /* Column numbers */
87e83b847bSdrh #define STMT_COLUMN_SQL 0 /* SQL for the statement */
88e83b847bSdrh #define STMT_COLUMN_NCOL 1 /* Number of result columns */
89e83b847bSdrh #define STMT_COLUMN_RO 2 /* True if read-only */
90e83b847bSdrh #define STMT_COLUMN_BUSY 3 /* True if currently busy */
91e83b847bSdrh #define STMT_COLUMN_NSCAN 4 /* SQLITE_STMTSTATUS_FULLSCAN_STEP */
92e83b847bSdrh #define STMT_COLUMN_NSORT 5 /* SQLITE_STMTSTATUS_SORT */
93e83b847bSdrh #define STMT_COLUMN_NAIDX 6 /* SQLITE_STMTSTATUS_AUTOINDEX */
94e83b847bSdrh #define STMT_COLUMN_NSTEP 7 /* SQLITE_STMTSTATUS_VM_STEP */
95e83b847bSdrh #define STMT_COLUMN_REPREP 8 /* SQLITE_STMTSTATUS_REPREPARE */
96e83b847bSdrh #define STMT_COLUMN_RUN 9 /* SQLITE_STMTSTATUS_RUN */
97e83b847bSdrh #define STMT_COLUMN_MEM 10 /* SQLITE_STMTSTATUS_MEMUSED */
98c6603af7Sdrh
99c6603af7Sdrh
100c6603af7Sdrh rc = sqlite3_declare_vtab(db,
101e83b847bSdrh "CREATE TABLE x(sql,ncol,ro,busy,nscan,nsort,naidx,nstep,"
102c6603af7Sdrh "reprep,run,mem)");
103c6603af7Sdrh if( rc==SQLITE_OK ){
104*90120b9fSdrh pNew = sqlite3_malloc64( sizeof(*pNew) );
105c6603af7Sdrh *ppVtab = (sqlite3_vtab*)pNew;
106c6603af7Sdrh if( pNew==0 ) return SQLITE_NOMEM;
107c6603af7Sdrh memset(pNew, 0, sizeof(*pNew));
108c6603af7Sdrh pNew->db = db;
109c6603af7Sdrh }
110c6603af7Sdrh return rc;
111c6603af7Sdrh }
112c6603af7Sdrh
113c6603af7Sdrh /*
114c6603af7Sdrh ** This method is the destructor for stmt_cursor objects.
115c6603af7Sdrh */
stmtDisconnect(sqlite3_vtab * pVtab)116c6603af7Sdrh static int stmtDisconnect(sqlite3_vtab *pVtab){
117c6603af7Sdrh sqlite3_free(pVtab);
118c6603af7Sdrh return SQLITE_OK;
119c6603af7Sdrh }
120c6603af7Sdrh
121c6603af7Sdrh /*
122c6603af7Sdrh ** Constructor for a new stmt_cursor object.
123c6603af7Sdrh */
stmtOpen(sqlite3_vtab * p,sqlite3_vtab_cursor ** ppCursor)124c6603af7Sdrh static int stmtOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
125c6603af7Sdrh stmt_cursor *pCur;
126*90120b9fSdrh pCur = sqlite3_malloc64( sizeof(*pCur) );
127c6603af7Sdrh if( pCur==0 ) return SQLITE_NOMEM;
128c6603af7Sdrh memset(pCur, 0, sizeof(*pCur));
129c6603af7Sdrh pCur->db = ((stmt_vtab*)p)->db;
130c6603af7Sdrh *ppCursor = &pCur->base;
131c6603af7Sdrh return SQLITE_OK;
132c6603af7Sdrh }
133c6603af7Sdrh
stmtCsrReset(stmt_cursor * pCur)134e26f592eSdan static void stmtCsrReset(stmt_cursor *pCur){
135e26f592eSdan StmtRow *pRow = 0;
136e26f592eSdan StmtRow *pNext = 0;
137e26f592eSdan for(pRow=pCur->pRow; pRow; pRow=pNext){
138e26f592eSdan pNext = pRow->pNext;
139e26f592eSdan sqlite3_free(pRow);
140e26f592eSdan }
141e26f592eSdan pCur->pRow = 0;
142e26f592eSdan }
143e26f592eSdan
144c6603af7Sdrh /*
145c6603af7Sdrh ** Destructor for a stmt_cursor.
146c6603af7Sdrh */
stmtClose(sqlite3_vtab_cursor * cur)147c6603af7Sdrh static int stmtClose(sqlite3_vtab_cursor *cur){
148e26f592eSdan stmtCsrReset((stmt_cursor*)cur);
149c6603af7Sdrh sqlite3_free(cur);
150c6603af7Sdrh return SQLITE_OK;
151c6603af7Sdrh }
152c6603af7Sdrh
153c6603af7Sdrh
154c6603af7Sdrh /*
155c6603af7Sdrh ** Advance a stmt_cursor to its next row of output.
156c6603af7Sdrh */
stmtNext(sqlite3_vtab_cursor * cur)157c6603af7Sdrh static int stmtNext(sqlite3_vtab_cursor *cur){
158c6603af7Sdrh stmt_cursor *pCur = (stmt_cursor*)cur;
159e26f592eSdan StmtRow *pNext = pCur->pRow->pNext;
160e26f592eSdan sqlite3_free(pCur->pRow);
161e26f592eSdan pCur->pRow = pNext;
162c6603af7Sdrh return SQLITE_OK;
163c6603af7Sdrh }
164c6603af7Sdrh
165c6603af7Sdrh /*
166c6603af7Sdrh ** Return values of columns for the row at which the stmt_cursor
167c6603af7Sdrh ** is currently pointing.
168c6603af7Sdrh */
stmtColumn(sqlite3_vtab_cursor * cur,sqlite3_context * ctx,int i)169c6603af7Sdrh static int stmtColumn(
170c6603af7Sdrh sqlite3_vtab_cursor *cur, /* The cursor */
171c6603af7Sdrh sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
172c6603af7Sdrh int i /* Which column to return */
173c6603af7Sdrh ){
174c6603af7Sdrh stmt_cursor *pCur = (stmt_cursor*)cur;
175e26f592eSdan StmtRow *pRow = pCur->pRow;
176e26f592eSdan if( i==STMT_COLUMN_SQL ){
177e26f592eSdan sqlite3_result_text(ctx, pRow->zSql, -1, SQLITE_TRANSIENT);
178e26f592eSdan }else{
179e26f592eSdan sqlite3_result_int(ctx, pRow->aCol[i]);
180c6603af7Sdrh }
181c6603af7Sdrh return SQLITE_OK;
182c6603af7Sdrh }
183c6603af7Sdrh
184c6603af7Sdrh /*
185c6603af7Sdrh ** Return the rowid for the current row. In this implementation, the
186c6603af7Sdrh ** rowid is the same as the output value.
187c6603af7Sdrh */
stmtRowid(sqlite3_vtab_cursor * cur,sqlite_int64 * pRowid)188c6603af7Sdrh static int stmtRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
189c6603af7Sdrh stmt_cursor *pCur = (stmt_cursor*)cur;
190e26f592eSdan *pRowid = pCur->pRow->iRowid;
191c6603af7Sdrh return SQLITE_OK;
192c6603af7Sdrh }
193c6603af7Sdrh
194c6603af7Sdrh /*
195c6603af7Sdrh ** Return TRUE if the cursor has been moved off of the last
196c6603af7Sdrh ** row of output.
197c6603af7Sdrh */
stmtEof(sqlite3_vtab_cursor * cur)198c6603af7Sdrh static int stmtEof(sqlite3_vtab_cursor *cur){
199c6603af7Sdrh stmt_cursor *pCur = (stmt_cursor*)cur;
200e26f592eSdan return pCur->pRow==0;
201c6603af7Sdrh }
202c6603af7Sdrh
203c6603af7Sdrh /*
204c6603af7Sdrh ** This method is called to "rewind" the stmt_cursor object back
205c6603af7Sdrh ** to the first row of output. This method is always called at least
206c6603af7Sdrh ** once prior to any call to stmtColumn() or stmtRowid() or
207c6603af7Sdrh ** stmtEof().
208c6603af7Sdrh */
stmtFilter(sqlite3_vtab_cursor * pVtabCursor,int idxNum,const char * idxStr,int argc,sqlite3_value ** argv)209c6603af7Sdrh static int stmtFilter(
210c6603af7Sdrh sqlite3_vtab_cursor *pVtabCursor,
211c6603af7Sdrh int idxNum, const char *idxStr,
212c6603af7Sdrh int argc, sqlite3_value **argv
213c6603af7Sdrh ){
214c6603af7Sdrh stmt_cursor *pCur = (stmt_cursor *)pVtabCursor;
215e26f592eSdan sqlite3_stmt *p = 0;
216e26f592eSdan sqlite3_int64 iRowid = 1;
217e26f592eSdan StmtRow **ppRow = 0;
218e26f592eSdan
219e26f592eSdan stmtCsrReset(pCur);
220e26f592eSdan ppRow = &pCur->pRow;
221e26f592eSdan for(p=sqlite3_next_stmt(pCur->db, 0); p; p=sqlite3_next_stmt(pCur->db, p)){
222e26f592eSdan const char *zSql = sqlite3_sql(p);
223d5c2e084Sdrh sqlite3_int64 nSql = zSql ? strlen(zSql)+1 : 0;
224*90120b9fSdrh StmtRow *pNew = (StmtRow*)sqlite3_malloc64(sizeof(StmtRow) + nSql);
225e26f592eSdan
226e26f592eSdan if( pNew==0 ) return SQLITE_NOMEM;
227e26f592eSdan memset(pNew, 0, sizeof(StmtRow));
228e26f592eSdan if( zSql ){
229e26f592eSdan pNew->zSql = (char*)&pNew[1];
230e26f592eSdan memcpy(pNew->zSql, zSql, nSql);
231e26f592eSdan }
232e26f592eSdan pNew->aCol[STMT_COLUMN_NCOL] = sqlite3_column_count(p);
233e26f592eSdan pNew->aCol[STMT_COLUMN_RO] = sqlite3_stmt_readonly(p);
234e26f592eSdan pNew->aCol[STMT_COLUMN_BUSY] = sqlite3_stmt_busy(p);
235e26f592eSdan pNew->aCol[STMT_COLUMN_NSCAN] = sqlite3_stmt_status(
236e26f592eSdan p, SQLITE_STMTSTATUS_FULLSCAN_STEP, 0
237e26f592eSdan );
238e26f592eSdan pNew->aCol[STMT_COLUMN_NSORT] = sqlite3_stmt_status(
239e26f592eSdan p, SQLITE_STMTSTATUS_SORT, 0
240e26f592eSdan );
241e26f592eSdan pNew->aCol[STMT_COLUMN_NAIDX] = sqlite3_stmt_status(
242e26f592eSdan p, SQLITE_STMTSTATUS_AUTOINDEX, 0
243e26f592eSdan );
244e26f592eSdan pNew->aCol[STMT_COLUMN_NSTEP] = sqlite3_stmt_status(
245e26f592eSdan p, SQLITE_STMTSTATUS_VM_STEP, 0
246e26f592eSdan );
247e26f592eSdan pNew->aCol[STMT_COLUMN_REPREP] = sqlite3_stmt_status(
248e26f592eSdan p, SQLITE_STMTSTATUS_REPREPARE, 0
249e26f592eSdan );
250e26f592eSdan pNew->aCol[STMT_COLUMN_RUN] = sqlite3_stmt_status(
251e26f592eSdan p, SQLITE_STMTSTATUS_RUN, 0
252e26f592eSdan );
253e26f592eSdan pNew->aCol[STMT_COLUMN_MEM] = sqlite3_stmt_status(
254e26f592eSdan p, SQLITE_STMTSTATUS_MEMUSED, 0
255e26f592eSdan );
256e26f592eSdan pNew->iRowid = iRowid++;
257e26f592eSdan *ppRow = pNew;
258e26f592eSdan ppRow = &pNew->pNext;
259e26f592eSdan }
260e26f592eSdan
261e26f592eSdan return SQLITE_OK;
262c6603af7Sdrh }
263c6603af7Sdrh
264c6603af7Sdrh /*
265c6603af7Sdrh ** SQLite will invoke this method one or more times while planning a query
2664a9e1407Sdrh ** that uses the stmt virtual table. This routine needs to create
267c6603af7Sdrh ** a query plan for each invocation and compute an estimated cost for that
268c6603af7Sdrh ** plan.
269c6603af7Sdrh */
stmtBestIndex(sqlite3_vtab * tab,sqlite3_index_info * pIdxInfo)270c6603af7Sdrh static int stmtBestIndex(
271c6603af7Sdrh sqlite3_vtab *tab,
272c6603af7Sdrh sqlite3_index_info *pIdxInfo
273c6603af7Sdrh ){
274c6603af7Sdrh pIdxInfo->estimatedCost = (double)500;
275c6603af7Sdrh pIdxInfo->estimatedRows = 500;
276c6603af7Sdrh return SQLITE_OK;
277c6603af7Sdrh }
278c6603af7Sdrh
279c6603af7Sdrh /*
280c6603af7Sdrh ** This following structure defines all the methods for the
2814a9e1407Sdrh ** stmt virtual table.
282c6603af7Sdrh */
283c6603af7Sdrh static sqlite3_module stmtModule = {
284c6603af7Sdrh 0, /* iVersion */
285c6603af7Sdrh 0, /* xCreate */
286c6603af7Sdrh stmtConnect, /* xConnect */
287c6603af7Sdrh stmtBestIndex, /* xBestIndex */
288c6603af7Sdrh stmtDisconnect, /* xDisconnect */
289c6603af7Sdrh 0, /* xDestroy */
290c6603af7Sdrh stmtOpen, /* xOpen - open a cursor */
291c6603af7Sdrh stmtClose, /* xClose - close a cursor */
292c6603af7Sdrh stmtFilter, /* xFilter - configure scan constraints */
293c6603af7Sdrh stmtNext, /* xNext - advance a cursor */
294c6603af7Sdrh stmtEof, /* xEof - check for end of scan */
295c6603af7Sdrh stmtColumn, /* xColumn - read data */
296c6603af7Sdrh stmtRowid, /* xRowid - read data */
297c6603af7Sdrh 0, /* xUpdate */
298c6603af7Sdrh 0, /* xBegin */
299c6603af7Sdrh 0, /* xSync */
300c6603af7Sdrh 0, /* xCommit */
301c6603af7Sdrh 0, /* xRollback */
302c6603af7Sdrh 0, /* xFindMethod */
303c6603af7Sdrh 0, /* xRename */
3047ccf95dbSdrh 0, /* xSavepoint */
3057ccf95dbSdrh 0, /* xRelease */
3067ccf95dbSdrh 0, /* xRollbackTo */
30784c501baSdrh 0, /* xShadowName */
308c6603af7Sdrh };
309c6603af7Sdrh
310c6603af7Sdrh #endif /* SQLITE_OMIT_VIRTUALTABLE */
311c6603af7Sdrh
sqlite3StmtVtabInit(sqlite3 * db)312c6603af7Sdrh int sqlite3StmtVtabInit(sqlite3 *db){
313c6603af7Sdrh int rc = SQLITE_OK;
314c6603af7Sdrh #ifndef SQLITE_OMIT_VIRTUALTABLE
315e83b847bSdrh rc = sqlite3_create_module(db, "sqlite_stmt", &stmtModule, 0);
316c6603af7Sdrh #endif
317c6603af7Sdrh return rc;
318c6603af7Sdrh }
319c6603af7Sdrh
320c6603af7Sdrh #ifndef SQLITE_CORE
321c6603af7Sdrh #ifdef _WIN32
322c6603af7Sdrh __declspec(dllexport)
323c6603af7Sdrh #endif
sqlite3_stmt_init(sqlite3 * db,char ** pzErrMsg,const sqlite3_api_routines * pApi)324c6603af7Sdrh int sqlite3_stmt_init(
325c6603af7Sdrh sqlite3 *db,
326c6603af7Sdrh char **pzErrMsg,
327c6603af7Sdrh const sqlite3_api_routines *pApi
328c6603af7Sdrh ){
329c6603af7Sdrh int rc = SQLITE_OK;
330c6603af7Sdrh SQLITE_EXTENSION_INIT2(pApi);
331c6603af7Sdrh #ifndef SQLITE_OMIT_VIRTUALTABLE
332c6603af7Sdrh rc = sqlite3StmtVtabInit(db);
333c6603af7Sdrh #endif
334c6603af7Sdrh return rc;
335c6603af7Sdrh }
336c6603af7Sdrh #endif /* SQLITE_CORE */
337c6603af7Sdrh #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */
338