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