blob: 95ea0ad228a7a4d0417a52d6357981340b1cd8be [file] [log] [blame]
drh691b5c52020-03-23 15:49:22 +00001/*
2** 2020-03-23
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 implements virtual-tables for examining the bytecode content
14** of a prepared statement.
15*/
16#ifdef SQLITE_ENABLE_BYTECODE_VTAB
17#include "sqliteInt.h"
18#include "vdbeInt.h"
19
20/* An instance of the bytecode() table-valued function.
21*/
drh8c5163a2020-03-23 20:58:55 +000022typedef struct bytecodevtab bytecodevtab;
23struct bytecodevtab {
drh691b5c52020-03-23 15:49:22 +000024 sqlite3_vtab base; /* Base class - must be first */
drh8c5163a2020-03-23 20:58:55 +000025 sqlite3 *db; /* Database connection */
drh8f78a522020-03-26 16:48:18 +000026 int bTablesUsed; /* 2 for tables_used(). 0 for bytecode(). */
drh691b5c52020-03-23 15:49:22 +000027};
28
29/* A cursor for scanning through the bytecode
30*/
31typedef struct bytecodevtab_cursor bytecodevtab_cursor;
32struct bytecodevtab_cursor {
33 sqlite3_vtab_cursor base; /* Base class - must be first */
drh8c5163a2020-03-23 20:58:55 +000034 sqlite3_stmt *pStmt; /* The statement whose bytecode is displayed */
35 int iRowid; /* The rowid of the output table */
36 int iAddr; /* Address */
37 int needFinalize; /* Cursors owns pStmt and must finalize it */
drh77972072020-03-24 18:41:58 +000038 int showSubprograms; /* Provide a listing of subprograms */
drh8c5163a2020-03-23 20:58:55 +000039 Op *aOp; /* Operand array */
40 char *zP4; /* Rendered P4 value */
drh8f78a522020-03-26 16:48:18 +000041 const char *zType; /* tables_used.type */
42 const char *zSchema; /* tables_used.schema */
43 const char *zName; /* tables_used.name */
drh8c5163a2020-03-23 20:58:55 +000044 Mem sub; /* Subprograms */
drh691b5c52020-03-23 15:49:22 +000045};
46
47/*
48** Create a new bytecode() table-valued function.
49*/
50static int bytecodevtabConnect(
51 sqlite3 *db,
52 void *pAux,
53 int argc, const char *const*argv,
54 sqlite3_vtab **ppVtab,
55 char **pzErr
56){
drh8c5163a2020-03-23 20:58:55 +000057 bytecodevtab *pNew;
drh691b5c52020-03-23 15:49:22 +000058 int rc;
drh8f78a522020-03-26 16:48:18 +000059 int isTabUsed = pAux!=0;
60 const char *azSchema[2] = {
61 /* bytecode() schema */
62 "CREATE TABLE x("
63 "addr INT,"
64 "opcode TEXT,"
65 "p1 INT,"
66 "p2 INT,"
67 "p3 INT,"
68 "p4 TEXT,"
69 "p5 INT,"
70 "comment TEXT,"
71 "subprog TEXT,"
72 "stmt HIDDEN"
73 ");",
drh691b5c52020-03-23 15:49:22 +000074
drh8f78a522020-03-26 16:48:18 +000075 /* Tables_used() schema */
76 "CREATE TABLE x("
77 "type TEXT,"
78 "schema TEXT,"
79 "name TEXT,"
80 "wr INT,"
81 "subprog TEXT,"
82 "stmt HIDDEN"
83 ");"
84 };
85
86 rc = sqlite3_declare_vtab(db, azSchema[isTabUsed]);
drh691b5c52020-03-23 15:49:22 +000087 if( rc==SQLITE_OK ){
88 pNew = sqlite3_malloc( sizeof(*pNew) );
89 *ppVtab = (sqlite3_vtab*)pNew;
90 if( pNew==0 ) return SQLITE_NOMEM;
91 memset(pNew, 0, sizeof(*pNew));
drh8c5163a2020-03-23 20:58:55 +000092 pNew->db = db;
drh8f78a522020-03-26 16:48:18 +000093 pNew->bTablesUsed = isTabUsed*2;
drh691b5c52020-03-23 15:49:22 +000094 }
95 return rc;
96}
97
98/*
drh8c5163a2020-03-23 20:58:55 +000099** This method is the destructor for bytecodevtab objects.
drh691b5c52020-03-23 15:49:22 +0000100*/
101static int bytecodevtabDisconnect(sqlite3_vtab *pVtab){
drh8c5163a2020-03-23 20:58:55 +0000102 bytecodevtab *p = (bytecodevtab*)pVtab;
drh691b5c52020-03-23 15:49:22 +0000103 sqlite3_free(p);
104 return SQLITE_OK;
105}
106
107/*
108** Constructor for a new bytecodevtab_cursor object.
109*/
110static int bytecodevtabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
drh8c5163a2020-03-23 20:58:55 +0000111 bytecodevtab *pVTab = (bytecodevtab*)p;
drh691b5c52020-03-23 15:49:22 +0000112 bytecodevtab_cursor *pCur;
113 pCur = sqlite3_malloc( sizeof(*pCur) );
114 if( pCur==0 ) return SQLITE_NOMEM;
115 memset(pCur, 0, sizeof(*pCur));
drh8c5163a2020-03-23 20:58:55 +0000116 sqlite3VdbeMemInit(&pCur->sub, pVTab->db, 1);
drh691b5c52020-03-23 15:49:22 +0000117 *ppCursor = &pCur->base;
118 return SQLITE_OK;
119}
120
121/*
drh8c5163a2020-03-23 20:58:55 +0000122** Clear all internal content from a bytecodevtab cursor.
123*/
124static void bytecodevtabCursorClear(bytecodevtab_cursor *pCur){
125 sqlite3_free(pCur->zP4);
126 pCur->zP4 = 0;
drhcf08f082020-03-24 17:52:31 +0000127 sqlite3VdbeMemRelease(&pCur->sub);
drh8c5163a2020-03-23 20:58:55 +0000128 sqlite3VdbeMemSetNull(&pCur->sub);
129 if( pCur->needFinalize ){
130 sqlite3_finalize(pCur->pStmt);
131 }
132 pCur->pStmt = 0;
133 pCur->needFinalize = 0;
drh8f78a522020-03-26 16:48:18 +0000134 pCur->zType = 0;
135 pCur->zSchema = 0;
136 pCur->zName = 0;
drh8c5163a2020-03-23 20:58:55 +0000137}
138
139/*
drh691b5c52020-03-23 15:49:22 +0000140** Destructor for a bytecodevtab_cursor.
141*/
142static int bytecodevtabClose(sqlite3_vtab_cursor *cur){
143 bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur;
drh8c5163a2020-03-23 20:58:55 +0000144 bytecodevtabCursorClear(pCur);
drh691b5c52020-03-23 15:49:22 +0000145 sqlite3_free(pCur);
146 return SQLITE_OK;
147}
148
149
150/*
151** Advance a bytecodevtab_cursor to its next row of output.
152*/
153static int bytecodevtabNext(sqlite3_vtab_cursor *cur){
154 bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur;
drh8f78a522020-03-26 16:48:18 +0000155 bytecodevtab *pTab = (bytecodevtab*)cur->pVtab;
drh8c5163a2020-03-23 20:58:55 +0000156 int rc;
157 if( pCur->zP4 ){
158 sqlite3_free(pCur->zP4);
159 pCur->zP4 = 0;
160 }
drh8f78a522020-03-26 16:48:18 +0000161 if( pCur->zName ){
162 pCur->zName = 0;
163 pCur->zType = 0;
164 pCur->zSchema = 0;
165 }
drh77972072020-03-24 18:41:58 +0000166 rc = sqlite3VdbeNextOpcode(
167 (Vdbe*)pCur->pStmt,
168 pCur->showSubprograms ? &pCur->sub : 0,
drh8f78a522020-03-26 16:48:18 +0000169 pTab->bTablesUsed,
drh77972072020-03-24 18:41:58 +0000170 &pCur->iRowid,
171 &pCur->iAddr,
172 &pCur->aOp);
drh8c5163a2020-03-23 20:58:55 +0000173 if( rc!=SQLITE_OK ){
174 sqlite3VdbeMemSetNull(&pCur->sub);
175 pCur->aOp = 0;
176 }
drh691b5c52020-03-23 15:49:22 +0000177 return SQLITE_OK;
178}
179
180/*
drh8c5163a2020-03-23 20:58:55 +0000181** Return TRUE if the cursor has been moved off of the last
182** row of output.
183*/
184static int bytecodevtabEof(sqlite3_vtab_cursor *cur){
185 bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur;
186 return pCur->aOp==0;
187}
188
189/*
drh691b5c52020-03-23 15:49:22 +0000190** Return values of columns for the row at which the bytecodevtab_cursor
191** is currently pointing.
192*/
193static int bytecodevtabColumn(
194 sqlite3_vtab_cursor *cur, /* The cursor */
195 sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
196 int i /* Which column to return */
197){
198 bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur;
drh8f78a522020-03-26 16:48:18 +0000199 bytecodevtab *pVTab = (bytecodevtab*)cur->pVtab;
drh8c5163a2020-03-23 20:58:55 +0000200 Op *pOp = pCur->aOp + pCur->iAddr;
drh8f78a522020-03-26 16:48:18 +0000201 if( pVTab->bTablesUsed ){
202 if( i==4 ){
203 i = 8;
204 }else{
205 if( i<=2 && pCur->zType==0 ){
206 Schema *pSchema;
207 HashElem *k;
208 int iDb = pOp->p3;
209 int iRoot = pOp->p2;
210 sqlite3 *db = pVTab->db;
211 pSchema = db->aDb[iDb].pSchema;
212 pCur->zSchema = db->aDb[iDb].zDbSName;
213 for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){
214 Table *pTab = (Table*)sqliteHashData(k);
215 if( !IsVirtual(pTab) && pTab->tnum==iRoot ){
216 pCur->zName = pTab->zName;
217 pCur->zType = "table";
218 break;
219 }
220 }
221 if( pCur->zName==0 ){
222 for(k=sqliteHashFirst(&pSchema->idxHash); k; k=sqliteHashNext(k)){
223 Index *pIdx = (Index*)sqliteHashData(k);
224 if( pIdx->tnum==iRoot ){
225 pCur->zName = pIdx->zName;
226 pCur->zType = "index";
drh8f78a522020-03-26 16:48:18 +0000227 }
228 }
229 }
230 }
231 i += 10;
232 }
233 }
drh691b5c52020-03-23 15:49:22 +0000234 switch( i ){
drh0518d062020-03-24 13:27:53 +0000235 case 0: /* addr */
drh8c5163a2020-03-23 20:58:55 +0000236 sqlite3_result_int(ctx, pCur->iAddr);
drh691b5c52020-03-23 15:49:22 +0000237 break;
drh0518d062020-03-24 13:27:53 +0000238 case 1: /* opcode */
drh8c5163a2020-03-23 20:58:55 +0000239 sqlite3_result_text(ctx, (char*)sqlite3OpcodeName(pOp->opcode),
240 -1, SQLITE_STATIC);
241 break;
drh0518d062020-03-24 13:27:53 +0000242 case 2: /* p1 */
drh8c5163a2020-03-23 20:58:55 +0000243 sqlite3_result_int(ctx, pOp->p1);
244 break;
drh0518d062020-03-24 13:27:53 +0000245 case 3: /* p2 */
drh8c5163a2020-03-23 20:58:55 +0000246 sqlite3_result_int(ctx, pOp->p2);
247 break;
drh0518d062020-03-24 13:27:53 +0000248 case 4: /* p3 */
drh8c5163a2020-03-23 20:58:55 +0000249 sqlite3_result_int(ctx, pOp->p3);
250 break;
drh0518d062020-03-24 13:27:53 +0000251 case 5: /* p4 */
252 case 7: /* comment */
drh8c5163a2020-03-23 20:58:55 +0000253 if( pCur->zP4==0 ){
254 pCur->zP4 = sqlite3VdbeDisplayP4(pVTab->db, pOp);
255 }
256 if( i==5 ){
257 sqlite3_result_text(ctx, pCur->zP4, -1, SQLITE_STATIC);
258 }else{
drheeb55d82020-03-23 23:17:38 +0000259#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
drh8c5163a2020-03-23 20:58:55 +0000260 char *zCom = sqlite3VdbeDisplayComment(pVTab->db, pOp, pCur->zP4);
261 sqlite3_result_text(ctx, zCom, -1, sqlite3_free);
drheeb55d82020-03-23 23:17:38 +0000262#endif
drh8c5163a2020-03-23 20:58:55 +0000263 }
264 break;
drh0518d062020-03-24 13:27:53 +0000265 case 6: /* p5 */
drh8c5163a2020-03-23 20:58:55 +0000266 sqlite3_result_int(ctx, pOp->p5);
drh691b5c52020-03-23 15:49:22 +0000267 break;
drh0518d062020-03-24 13:27:53 +0000268 case 8: { /* subprog */
269 Op *aOp = pCur->aOp;
drh7e088a62020-05-02 00:01:39 +0000270 assert( aOp[0].opcode==OP_Init );
271 assert( aOp[0].p4.z==0 || strncmp(aOp[0].p4.z,"-" "- ",3)==0 );
drh0518d062020-03-24 13:27:53 +0000272 if( pCur->iRowid==pCur->iAddr+1 ){
273 break; /* Result is NULL for the main program */
drh7e088a62020-05-02 00:01:39 +0000274 }else if( aOp[0].p4.z!=0 ){
drh0518d062020-03-24 13:27:53 +0000275 sqlite3_result_text(ctx, aOp[0].p4.z+3, -1, SQLITE_STATIC);
276 }else{
277 sqlite3_result_text(ctx, "(FK)", 4, SQLITE_STATIC);
278 }
279 break;
280 }
drh8f78a522020-03-26 16:48:18 +0000281 case 10: /* tables_used.type */
282 sqlite3_result_text(ctx, pCur->zType, -1, SQLITE_STATIC);
283 break;
284 case 11: /* tables_used.schema */
285 sqlite3_result_text(ctx, pCur->zSchema, -1, SQLITE_STATIC);
286 break;
287 case 12: /* tables_used.name */
288 sqlite3_result_text(ctx, pCur->zName, -1, SQLITE_STATIC);
289 break;
290 case 13: /* tables_used.wr */
291 sqlite3_result_int(ctx, pOp->opcode==OP_OpenWrite);
292 break;
drh691b5c52020-03-23 15:49:22 +0000293 }
drh691b5c52020-03-23 15:49:22 +0000294 return SQLITE_OK;
295}
296
297/*
298** Return the rowid for the current row. In this implementation, the
299** rowid is the same as the output value.
300*/
301static int bytecodevtabRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
302 bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur;
303 *pRowid = pCur->iRowid;
304 return SQLITE_OK;
305}
306
307/*
drh77972072020-03-24 18:41:58 +0000308** Initialize a cursor.
309**
310** idxNum==0 means show all subprograms
311** idxNum==1 means show only the main bytecode and omit subprograms.
drh691b5c52020-03-23 15:49:22 +0000312*/
313static int bytecodevtabFilter(
314 sqlite3_vtab_cursor *pVtabCursor,
315 int idxNum, const char *idxStr,
316 int argc, sqlite3_value **argv
317){
318 bytecodevtab_cursor *pCur = (bytecodevtab_cursor *)pVtabCursor;
drh8c5163a2020-03-23 20:58:55 +0000319 bytecodevtab *pVTab = (bytecodevtab *)pVtabCursor->pVtab;
320 int rc = SQLITE_OK;
321
322 bytecodevtabCursorClear(pCur);
323 pCur->iRowid = 0;
324 pCur->iAddr = 0;
drh77972072020-03-24 18:41:58 +0000325 pCur->showSubprograms = idxNum==0;
drh8c5163a2020-03-23 20:58:55 +0000326 assert( argc==1 );
327 if( sqlite3_value_type(argv[0])==SQLITE_TEXT ){
328 const char *zSql = (const char*)sqlite3_value_text(argv[0]);
329 if( zSql==0 ){
330 rc = SQLITE_NOMEM;
331 }else{
332 rc = sqlite3_prepare_v2(pVTab->db, zSql, -1, &pCur->pStmt, 0);
333 pCur->needFinalize = 1;
334 }
335 }else{
336 pCur->pStmt = (sqlite3_stmt*)sqlite3_value_pointer(argv[0],"stmt-pointer");
337 }
338 if( pCur->pStmt==0 ){
339 pVTab->base.zErrMsg = sqlite3_mprintf(
drh8f78a522020-03-26 16:48:18 +0000340 "argument to %s() is not a valid SQL statement",
341 pVTab->bTablesUsed ? "tables_used" : "bytecode"
drh8c5163a2020-03-23 20:58:55 +0000342 );
343 rc = SQLITE_ERROR;
344 }else{
345 bytecodevtabNext(pVtabCursor);
346 }
347 return rc;
drh691b5c52020-03-23 15:49:22 +0000348}
349
350/*
drh8c5163a2020-03-23 20:58:55 +0000351** We must have a single stmt=? constraint that will be passed through
352** into the xFilter method. If there is no valid stmt=? constraint,
353** then return an SQLITE_CONSTRAINT error.
drh691b5c52020-03-23 15:49:22 +0000354*/
355static int bytecodevtabBestIndex(
356 sqlite3_vtab *tab,
357 sqlite3_index_info *pIdxInfo
358){
drh8c5163a2020-03-23 20:58:55 +0000359 int i;
360 int rc = SQLITE_CONSTRAINT;
drh77972072020-03-24 18:41:58 +0000361 struct sqlite3_index_constraint *p;
drh8f78a522020-03-26 16:48:18 +0000362 bytecodevtab *pVTab = (bytecodevtab*)tab;
363 int iBaseCol = pVTab->bTablesUsed ? 4 : 8;
drh8c5163a2020-03-23 20:58:55 +0000364 pIdxInfo->estimatedCost = (double)100;
365 pIdxInfo->estimatedRows = 100;
drh77972072020-03-24 18:41:58 +0000366 pIdxInfo->idxNum = 0;
367 for(i=0, p=pIdxInfo->aConstraint; i<pIdxInfo->nConstraint; i++, p++){
368 if( p->usable==0 ) continue;
drh8f78a522020-03-26 16:48:18 +0000369 if( p->op==SQLITE_INDEX_CONSTRAINT_EQ && p->iColumn==iBaseCol+1 ){
drh77972072020-03-24 18:41:58 +0000370 rc = SQLITE_OK;
371 pIdxInfo->aConstraintUsage[i].omit = 1;
372 pIdxInfo->aConstraintUsage[i].argvIndex = 1;
373 }
drh8f78a522020-03-26 16:48:18 +0000374 if( p->op==SQLITE_INDEX_CONSTRAINT_ISNULL && p->iColumn==iBaseCol ){
drh77972072020-03-24 18:41:58 +0000375 pIdxInfo->aConstraintUsage[i].omit = 1;
376 pIdxInfo->idxNum = 1;
377 }
drh8c5163a2020-03-23 20:58:55 +0000378 }
379 return rc;
drh691b5c52020-03-23 15:49:22 +0000380}
381
382/*
383** This following structure defines all the methods for the
384** virtual table.
385*/
386static sqlite3_module bytecodevtabModule = {
387 /* iVersion */ 0,
388 /* xCreate */ 0,
389 /* xConnect */ bytecodevtabConnect,
390 /* xBestIndex */ bytecodevtabBestIndex,
391 /* xDisconnect */ bytecodevtabDisconnect,
392 /* xDestroy */ 0,
393 /* xOpen */ bytecodevtabOpen,
394 /* xClose */ bytecodevtabClose,
395 /* xFilter */ bytecodevtabFilter,
396 /* xNext */ bytecodevtabNext,
397 /* xEof */ bytecodevtabEof,
398 /* xColumn */ bytecodevtabColumn,
399 /* xRowid */ bytecodevtabRowid,
400 /* xUpdate */ 0,
401 /* xBegin */ 0,
402 /* xSync */ 0,
403 /* xCommit */ 0,
404 /* xRollback */ 0,
405 /* xFindMethod */ 0,
406 /* xRename */ 0,
407 /* xSavepoint */ 0,
408 /* xRelease */ 0,
409 /* xRollbackTo */ 0,
410 /* xShadowName */ 0
411};
412
413
414int sqlite3VdbeBytecodeVtabInit(sqlite3 *db){
415 int rc;
drh8c5163a2020-03-23 20:58:55 +0000416 rc = sqlite3_create_module(db, "bytecode", &bytecodevtabModule, 0);
drh8f78a522020-03-26 16:48:18 +0000417 if( rc==SQLITE_OK ){
418 rc = sqlite3_create_module(db, "tables_used", &bytecodevtabModule, &db);
419 }
drh691b5c52020-03-23 15:49:22 +0000420 return rc;
421}
422#endif /* SQLITE_ENABLE_BYTECODE_VTAB */