blob: 6557d8cb019c733cbc0e3b11ca86e70d5ce25757 [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*/
drh691b5c52020-03-23 15:49:22 +000016#include "sqliteInt.h"
dand48eafb2020-05-15 16:19:35 +000017#if defined(SQLITE_ENABLE_BYTECODE_VTAB) && !defined(SQLITE_OMIT_VIRTUALTABLE)
drh691b5c52020-03-23 15:49:22 +000018#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
drh3547e492022-12-23 14:49:24 +000086 (void)argc;
87 (void)argv;
88 (void)pzErr;
drh8f78a522020-03-26 16:48:18 +000089 rc = sqlite3_declare_vtab(db, azSchema[isTabUsed]);
drh691b5c52020-03-23 15:49:22 +000090 if( rc==SQLITE_OK ){
91 pNew = sqlite3_malloc( sizeof(*pNew) );
92 *ppVtab = (sqlite3_vtab*)pNew;
93 if( pNew==0 ) return SQLITE_NOMEM;
94 memset(pNew, 0, sizeof(*pNew));
drh8c5163a2020-03-23 20:58:55 +000095 pNew->db = db;
drh8f78a522020-03-26 16:48:18 +000096 pNew->bTablesUsed = isTabUsed*2;
drh691b5c52020-03-23 15:49:22 +000097 }
98 return rc;
99}
100
101/*
drh8c5163a2020-03-23 20:58:55 +0000102** This method is the destructor for bytecodevtab objects.
drh691b5c52020-03-23 15:49:22 +0000103*/
104static int bytecodevtabDisconnect(sqlite3_vtab *pVtab){
drh8c5163a2020-03-23 20:58:55 +0000105 bytecodevtab *p = (bytecodevtab*)pVtab;
drh691b5c52020-03-23 15:49:22 +0000106 sqlite3_free(p);
107 return SQLITE_OK;
108}
109
110/*
111** Constructor for a new bytecodevtab_cursor object.
112*/
113static int bytecodevtabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
drh8c5163a2020-03-23 20:58:55 +0000114 bytecodevtab *pVTab = (bytecodevtab*)p;
drh691b5c52020-03-23 15:49:22 +0000115 bytecodevtab_cursor *pCur;
116 pCur = sqlite3_malloc( sizeof(*pCur) );
117 if( pCur==0 ) return SQLITE_NOMEM;
118 memset(pCur, 0, sizeof(*pCur));
drh8c5163a2020-03-23 20:58:55 +0000119 sqlite3VdbeMemInit(&pCur->sub, pVTab->db, 1);
drh691b5c52020-03-23 15:49:22 +0000120 *ppCursor = &pCur->base;
121 return SQLITE_OK;
122}
123
124/*
drh8c5163a2020-03-23 20:58:55 +0000125** Clear all internal content from a bytecodevtab cursor.
126*/
127static void bytecodevtabCursorClear(bytecodevtab_cursor *pCur){
128 sqlite3_free(pCur->zP4);
129 pCur->zP4 = 0;
drhcf08f082020-03-24 17:52:31 +0000130 sqlite3VdbeMemRelease(&pCur->sub);
drh8c5163a2020-03-23 20:58:55 +0000131 sqlite3VdbeMemSetNull(&pCur->sub);
132 if( pCur->needFinalize ){
133 sqlite3_finalize(pCur->pStmt);
134 }
135 pCur->pStmt = 0;
136 pCur->needFinalize = 0;
drh8f78a522020-03-26 16:48:18 +0000137 pCur->zType = 0;
138 pCur->zSchema = 0;
139 pCur->zName = 0;
drh8c5163a2020-03-23 20:58:55 +0000140}
141
142/*
drh691b5c52020-03-23 15:49:22 +0000143** Destructor for a bytecodevtab_cursor.
144*/
145static int bytecodevtabClose(sqlite3_vtab_cursor *cur){
146 bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur;
drh8c5163a2020-03-23 20:58:55 +0000147 bytecodevtabCursorClear(pCur);
drh691b5c52020-03-23 15:49:22 +0000148 sqlite3_free(pCur);
149 return SQLITE_OK;
150}
151
152
153/*
154** Advance a bytecodevtab_cursor to its next row of output.
155*/
156static int bytecodevtabNext(sqlite3_vtab_cursor *cur){
157 bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur;
drh8f78a522020-03-26 16:48:18 +0000158 bytecodevtab *pTab = (bytecodevtab*)cur->pVtab;
drh8c5163a2020-03-23 20:58:55 +0000159 int rc;
160 if( pCur->zP4 ){
161 sqlite3_free(pCur->zP4);
162 pCur->zP4 = 0;
163 }
drh8f78a522020-03-26 16:48:18 +0000164 if( pCur->zName ){
165 pCur->zName = 0;
166 pCur->zType = 0;
167 pCur->zSchema = 0;
168 }
drh77972072020-03-24 18:41:58 +0000169 rc = sqlite3VdbeNextOpcode(
170 (Vdbe*)pCur->pStmt,
171 pCur->showSubprograms ? &pCur->sub : 0,
drh8f78a522020-03-26 16:48:18 +0000172 pTab->bTablesUsed,
drh77972072020-03-24 18:41:58 +0000173 &pCur->iRowid,
174 &pCur->iAddr,
175 &pCur->aOp);
drh8c5163a2020-03-23 20:58:55 +0000176 if( rc!=SQLITE_OK ){
177 sqlite3VdbeMemSetNull(&pCur->sub);
178 pCur->aOp = 0;
179 }
drh691b5c52020-03-23 15:49:22 +0000180 return SQLITE_OK;
181}
182
183/*
drh8c5163a2020-03-23 20:58:55 +0000184** Return TRUE if the cursor has been moved off of the last
185** row of output.
186*/
187static int bytecodevtabEof(sqlite3_vtab_cursor *cur){
188 bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur;
189 return pCur->aOp==0;
190}
191
192/*
drh691b5c52020-03-23 15:49:22 +0000193** Return values of columns for the row at which the bytecodevtab_cursor
194** is currently pointing.
195*/
196static int bytecodevtabColumn(
197 sqlite3_vtab_cursor *cur, /* The cursor */
198 sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
199 int i /* Which column to return */
200){
201 bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur;
drh8f78a522020-03-26 16:48:18 +0000202 bytecodevtab *pVTab = (bytecodevtab*)cur->pVtab;
drh8c5163a2020-03-23 20:58:55 +0000203 Op *pOp = pCur->aOp + pCur->iAddr;
drh8f78a522020-03-26 16:48:18 +0000204 if( pVTab->bTablesUsed ){
205 if( i==4 ){
206 i = 8;
207 }else{
208 if( i<=2 && pCur->zType==0 ){
209 Schema *pSchema;
210 HashElem *k;
211 int iDb = pOp->p3;
drh013e7bb2020-07-30 17:37:49 +0000212 Pgno iRoot = (Pgno)pOp->p2;
drh8f78a522020-03-26 16:48:18 +0000213 sqlite3 *db = pVTab->db;
214 pSchema = db->aDb[iDb].pSchema;
215 pCur->zSchema = db->aDb[iDb].zDbSName;
216 for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){
217 Table *pTab = (Table*)sqliteHashData(k);
218 if( !IsVirtual(pTab) && pTab->tnum==iRoot ){
219 pCur->zName = pTab->zName;
220 pCur->zType = "table";
221 break;
222 }
223 }
224 if( pCur->zName==0 ){
225 for(k=sqliteHashFirst(&pSchema->idxHash); k; k=sqliteHashNext(k)){
226 Index *pIdx = (Index*)sqliteHashData(k);
227 if( pIdx->tnum==iRoot ){
228 pCur->zName = pIdx->zName;
229 pCur->zType = "index";
drh8f78a522020-03-26 16:48:18 +0000230 }
231 }
232 }
233 }
234 i += 10;
235 }
236 }
drh691b5c52020-03-23 15:49:22 +0000237 switch( i ){
drh0518d062020-03-24 13:27:53 +0000238 case 0: /* addr */
drh8c5163a2020-03-23 20:58:55 +0000239 sqlite3_result_int(ctx, pCur->iAddr);
drh691b5c52020-03-23 15:49:22 +0000240 break;
drh0518d062020-03-24 13:27:53 +0000241 case 1: /* opcode */
drh8c5163a2020-03-23 20:58:55 +0000242 sqlite3_result_text(ctx, (char*)sqlite3OpcodeName(pOp->opcode),
243 -1, SQLITE_STATIC);
244 break;
drh0518d062020-03-24 13:27:53 +0000245 case 2: /* p1 */
drh8c5163a2020-03-23 20:58:55 +0000246 sqlite3_result_int(ctx, pOp->p1);
247 break;
drh0518d062020-03-24 13:27:53 +0000248 case 3: /* p2 */
drh8c5163a2020-03-23 20:58:55 +0000249 sqlite3_result_int(ctx, pOp->p2);
250 break;
drh0518d062020-03-24 13:27:53 +0000251 case 4: /* p3 */
drh8c5163a2020-03-23 20:58:55 +0000252 sqlite3_result_int(ctx, pOp->p3);
253 break;
drh0518d062020-03-24 13:27:53 +0000254 case 5: /* p4 */
255 case 7: /* comment */
drh8c5163a2020-03-23 20:58:55 +0000256 if( pCur->zP4==0 ){
257 pCur->zP4 = sqlite3VdbeDisplayP4(pVTab->db, pOp);
258 }
259 if( i==5 ){
260 sqlite3_result_text(ctx, pCur->zP4, -1, SQLITE_STATIC);
261 }else{
drheeb55d82020-03-23 23:17:38 +0000262#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
drh8c5163a2020-03-23 20:58:55 +0000263 char *zCom = sqlite3VdbeDisplayComment(pVTab->db, pOp, pCur->zP4);
264 sqlite3_result_text(ctx, zCom, -1, sqlite3_free);
drheeb55d82020-03-23 23:17:38 +0000265#endif
drh8c5163a2020-03-23 20:58:55 +0000266 }
267 break;
drh0518d062020-03-24 13:27:53 +0000268 case 6: /* p5 */
drh8c5163a2020-03-23 20:58:55 +0000269 sqlite3_result_int(ctx, pOp->p5);
drh691b5c52020-03-23 15:49:22 +0000270 break;
drh0518d062020-03-24 13:27:53 +0000271 case 8: { /* subprog */
272 Op *aOp = pCur->aOp;
drh7e088a62020-05-02 00:01:39 +0000273 assert( aOp[0].opcode==OP_Init );
274 assert( aOp[0].p4.z==0 || strncmp(aOp[0].p4.z,"-" "- ",3)==0 );
drh0518d062020-03-24 13:27:53 +0000275 if( pCur->iRowid==pCur->iAddr+1 ){
276 break; /* Result is NULL for the main program */
drh7e088a62020-05-02 00:01:39 +0000277 }else if( aOp[0].p4.z!=0 ){
drh0518d062020-03-24 13:27:53 +0000278 sqlite3_result_text(ctx, aOp[0].p4.z+3, -1, SQLITE_STATIC);
279 }else{
280 sqlite3_result_text(ctx, "(FK)", 4, SQLITE_STATIC);
281 }
282 break;
283 }
drh8f78a522020-03-26 16:48:18 +0000284 case 10: /* tables_used.type */
285 sqlite3_result_text(ctx, pCur->zType, -1, SQLITE_STATIC);
286 break;
287 case 11: /* tables_used.schema */
288 sqlite3_result_text(ctx, pCur->zSchema, -1, SQLITE_STATIC);
289 break;
290 case 12: /* tables_used.name */
291 sqlite3_result_text(ctx, pCur->zName, -1, SQLITE_STATIC);
292 break;
293 case 13: /* tables_used.wr */
294 sqlite3_result_int(ctx, pOp->opcode==OP_OpenWrite);
295 break;
drh691b5c52020-03-23 15:49:22 +0000296 }
drh691b5c52020-03-23 15:49:22 +0000297 return SQLITE_OK;
298}
299
300/*
301** Return the rowid for the current row. In this implementation, the
302** rowid is the same as the output value.
303*/
304static int bytecodevtabRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
305 bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur;
306 *pRowid = pCur->iRowid;
307 return SQLITE_OK;
308}
309
310/*
drh77972072020-03-24 18:41:58 +0000311** Initialize a cursor.
312**
313** idxNum==0 means show all subprograms
314** idxNum==1 means show only the main bytecode and omit subprograms.
drh691b5c52020-03-23 15:49:22 +0000315*/
316static int bytecodevtabFilter(
317 sqlite3_vtab_cursor *pVtabCursor,
318 int idxNum, const char *idxStr,
319 int argc, sqlite3_value **argv
320){
321 bytecodevtab_cursor *pCur = (bytecodevtab_cursor *)pVtabCursor;
drh8c5163a2020-03-23 20:58:55 +0000322 bytecodevtab *pVTab = (bytecodevtab *)pVtabCursor->pVtab;
323 int rc = SQLITE_OK;
drh3547e492022-12-23 14:49:24 +0000324 (void)idxStr;
drh8c5163a2020-03-23 20:58:55 +0000325
326 bytecodevtabCursorClear(pCur);
327 pCur->iRowid = 0;
328 pCur->iAddr = 0;
drh77972072020-03-24 18:41:58 +0000329 pCur->showSubprograms = idxNum==0;
drh8c5163a2020-03-23 20:58:55 +0000330 assert( argc==1 );
331 if( sqlite3_value_type(argv[0])==SQLITE_TEXT ){
332 const char *zSql = (const char*)sqlite3_value_text(argv[0]);
333 if( zSql==0 ){
334 rc = SQLITE_NOMEM;
335 }else{
336 rc = sqlite3_prepare_v2(pVTab->db, zSql, -1, &pCur->pStmt, 0);
337 pCur->needFinalize = 1;
338 }
339 }else{
340 pCur->pStmt = (sqlite3_stmt*)sqlite3_value_pointer(argv[0],"stmt-pointer");
341 }
342 if( pCur->pStmt==0 ){
343 pVTab->base.zErrMsg = sqlite3_mprintf(
drh8f78a522020-03-26 16:48:18 +0000344 "argument to %s() is not a valid SQL statement",
345 pVTab->bTablesUsed ? "tables_used" : "bytecode"
drh8c5163a2020-03-23 20:58:55 +0000346 );
347 rc = SQLITE_ERROR;
348 }else{
349 bytecodevtabNext(pVtabCursor);
350 }
351 return rc;
drh691b5c52020-03-23 15:49:22 +0000352}
353
354/*
drh8c5163a2020-03-23 20:58:55 +0000355** We must have a single stmt=? constraint that will be passed through
356** into the xFilter method. If there is no valid stmt=? constraint,
357** then return an SQLITE_CONSTRAINT error.
drh691b5c52020-03-23 15:49:22 +0000358*/
359static int bytecodevtabBestIndex(
360 sqlite3_vtab *tab,
361 sqlite3_index_info *pIdxInfo
362){
drh8c5163a2020-03-23 20:58:55 +0000363 int i;
364 int rc = SQLITE_CONSTRAINT;
drh77972072020-03-24 18:41:58 +0000365 struct sqlite3_index_constraint *p;
drh8f78a522020-03-26 16:48:18 +0000366 bytecodevtab *pVTab = (bytecodevtab*)tab;
367 int iBaseCol = pVTab->bTablesUsed ? 4 : 8;
drh8c5163a2020-03-23 20:58:55 +0000368 pIdxInfo->estimatedCost = (double)100;
369 pIdxInfo->estimatedRows = 100;
drh77972072020-03-24 18:41:58 +0000370 pIdxInfo->idxNum = 0;
371 for(i=0, p=pIdxInfo->aConstraint; i<pIdxInfo->nConstraint; i++, p++){
372 if( p->usable==0 ) continue;
drh8f78a522020-03-26 16:48:18 +0000373 if( p->op==SQLITE_INDEX_CONSTRAINT_EQ && p->iColumn==iBaseCol+1 ){
drh77972072020-03-24 18:41:58 +0000374 rc = SQLITE_OK;
375 pIdxInfo->aConstraintUsage[i].omit = 1;
376 pIdxInfo->aConstraintUsage[i].argvIndex = 1;
377 }
drh8f78a522020-03-26 16:48:18 +0000378 if( p->op==SQLITE_INDEX_CONSTRAINT_ISNULL && p->iColumn==iBaseCol ){
drh77972072020-03-24 18:41:58 +0000379 pIdxInfo->aConstraintUsage[i].omit = 1;
380 pIdxInfo->idxNum = 1;
381 }
drh8c5163a2020-03-23 20:58:55 +0000382 }
383 return rc;
drh691b5c52020-03-23 15:49:22 +0000384}
385
386/*
387** This following structure defines all the methods for the
388** virtual table.
389*/
390static sqlite3_module bytecodevtabModule = {
391 /* iVersion */ 0,
392 /* xCreate */ 0,
393 /* xConnect */ bytecodevtabConnect,
394 /* xBestIndex */ bytecodevtabBestIndex,
395 /* xDisconnect */ bytecodevtabDisconnect,
396 /* xDestroy */ 0,
397 /* xOpen */ bytecodevtabOpen,
398 /* xClose */ bytecodevtabClose,
399 /* xFilter */ bytecodevtabFilter,
400 /* xNext */ bytecodevtabNext,
401 /* xEof */ bytecodevtabEof,
402 /* xColumn */ bytecodevtabColumn,
403 /* xRowid */ bytecodevtabRowid,
404 /* xUpdate */ 0,
405 /* xBegin */ 0,
406 /* xSync */ 0,
407 /* xCommit */ 0,
408 /* xRollback */ 0,
409 /* xFindMethod */ 0,
410 /* xRename */ 0,
411 /* xSavepoint */ 0,
412 /* xRelease */ 0,
413 /* xRollbackTo */ 0,
414 /* xShadowName */ 0
415};
416
417
418int sqlite3VdbeBytecodeVtabInit(sqlite3 *db){
419 int rc;
drh8c5163a2020-03-23 20:58:55 +0000420 rc = sqlite3_create_module(db, "bytecode", &bytecodevtabModule, 0);
drh8f78a522020-03-26 16:48:18 +0000421 if( rc==SQLITE_OK ){
422 rc = sqlite3_create_module(db, "tables_used", &bytecodevtabModule, &db);
423 }
drh691b5c52020-03-23 15:49:22 +0000424 return rc;
425}
dan34d15662020-05-15 11:36:16 +0000426#elif defined(SQLITE_ENABLE_BYTECODE_VTAB)
427int sqlite3VdbeBytecodeVtabInit(sqlite3 *db){ return SQLITE_OK; }
drh691b5c52020-03-23 15:49:22 +0000428#endif /* SQLITE_ENABLE_BYTECODE_VTAB */