1/*
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#include "sqliteInt.h"
17#if defined(SQLITE_ENABLE_BYTECODE_VTAB) && !defined(SQLITE_OMIT_VIRTUALTABLE)
18#include "vdbeInt.h"
19
20/* An instance of the bytecode() table-valued function.
21*/
22typedef struct bytecodevtab bytecodevtab;
23struct bytecodevtab {
24 sqlite3_vtab base; /* Base class - must be first */
25 sqlite3 *db; /* Database connection */
26 int bTablesUsed; /* 2 for tables_used(). 0 for bytecode(). */
27};
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 */
34 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 */
38 int showSubprograms; /* Provide a listing of subprograms */
39 Op *aOp; /* Operand array */
40 char *zP4; /* Rendered P4 value */
41 const char *zType; /* tables_used.type */
42 const char *zSchema; /* tables_used.schema */
43 const char *zName; /* tables_used.name */
44 Mem sub; /* Subprograms */
45};
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){
57 bytecodevtab *pNew;
58 int rc;
59 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 ");",
74
75 /* 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]);
87 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));
92 pNew->db = db;
93 pNew->bTablesUsed = isTabUsed*2;
94 }
95 return rc;
96}
97
98/*
99** This method is the destructor for bytecodevtab objects.
100*/
101static int bytecodevtabDisconnect(sqlite3_vtab *pVtab){
102 bytecodevtab *p = (bytecodevtab*)pVtab;
103 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){
111 bytecodevtab *pVTab = (bytecodevtab*)p;
112 bytecodevtab_cursor *pCur;
113 pCur = sqlite3_malloc( sizeof(*pCur) );
114 if( pCur==0 ) return SQLITE_NOMEM;
115 memset(pCur, 0, sizeof(*pCur));
116 sqlite3VdbeMemInit(&pCur->sub, pVTab->db, 1);
117 *ppCursor = &pCur->base;
118 return SQLITE_OK;
119}
120
121/*
122** Clear all internal content from a bytecodevtab cursor.
123*/
124static void bytecodevtabCursorClear(bytecodevtab_cursor *pCur){
125 sqlite3_free(pCur->zP4);
126 pCur->zP4 = 0;
127 sqlite3VdbeMemRelease(&pCur->sub);
128 sqlite3VdbeMemSetNull(&pCur->sub);
129 if( pCur->needFinalize ){
130 sqlite3_finalize(pCur->pStmt);
131 }
132 pCur->pStmt = 0;
133 pCur->needFinalize = 0;
134 pCur->zType = 0;
135 pCur->zSchema = 0;
136 pCur->zName = 0;
137}
138
139/*
140** Destructor for a bytecodevtab_cursor.
141*/
142static int bytecodevtabClose(sqlite3_vtab_cursor *cur){
143 bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur;
144 bytecodevtabCursorClear(pCur);
145 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;
155 bytecodevtab *pTab = (bytecodevtab*)cur->pVtab;
156 int rc;
157 if( pCur->zP4 ){
158 sqlite3_free(pCur->zP4);
159 pCur->zP4 = 0;
160 }
161 if( pCur->zName ){
162 pCur->zName = 0;
163 pCur->zType = 0;
164 pCur->zSchema = 0;
165 }
166 rc = sqlite3VdbeNextOpcode(
167 (Vdbe*)pCur->pStmt,
168 pCur->showSubprograms ? &pCur->sub : 0,
169 pTab->bTablesUsed,
170 &pCur->iRowid,
171 &pCur->iAddr,
172 &pCur->aOp);
173 if( rc!=SQLITE_OK ){
174 sqlite3VdbeMemSetNull(&pCur->sub);
175 pCur->aOp = 0;
176 }
177 return SQLITE_OK;
178}
179
180/*
181** 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/*
190** 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;
199 bytecodevtab *pVTab = (bytecodevtab*)cur->pVtab;
200 Op *pOp = pCur->aOp + pCur->iAddr;
201 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 Pgno iRoot = (Pgno)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";
227 }
228 }
229 }
230 }
231 i += 10;
232 }
233 }
234 switch( i ){
235 case 0: /* addr */
236 sqlite3_result_int(ctx, pCur->iAddr);
237 break;
238 case 1: /* opcode */
239 sqlite3_result_text(ctx, (char*)sqlite3OpcodeName(pOp->opcode),
240 -1, SQLITE_STATIC);
241 break;
242 case 2: /* p1 */
243 sqlite3_result_int(ctx, pOp->p1);
244 break;
245 case 3: /* p2 */
246 sqlite3_result_int(ctx, pOp->p2);
247 break;
248 case 4: /* p3 */
249 sqlite3_result_int(ctx, pOp->p3);
250 break;
251 case 5: /* p4 */
252 case 7: /* comment */
253 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{
259#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
260 char *zCom = sqlite3VdbeDisplayComment(pVTab->db, pOp, pCur->zP4);
261 sqlite3_result_text(ctx, zCom, -1, sqlite3_free);
262#endif
263 }
264 break;
265 case 6: /* p5 */
266 sqlite3_result_int(ctx, pOp->p5);
267 break;
268 case 8: { /* subprog */
269 Op *aOp = pCur->aOp;
270 assert( aOp[0].opcode==OP_Init );
271 assert( aOp[0].p4.z==0 || strncmp(aOp[0].p4.z,"-" "- ",3)==0 );
272 if( pCur->iRowid==pCur->iAddr+1 ){
273 break; /* Result is NULL for the main program */
274 }else if( aOp[0].p4.z!=0 ){
275 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 }
281 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;
293 }
294 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/*
308** Initialize a cursor.
309**
310** idxNum==0 means show all subprograms
311** idxNum==1 means show only the main bytecode and omit subprograms.
312*/
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;
319 bytecodevtab *pVTab = (bytecodevtab *)pVtabCursor->pVtab;
320 int rc = SQLITE_OK;
321
322 bytecodevtabCursorClear(pCur);
323 pCur->iRowid = 0;
324 pCur->iAddr = 0;
325 pCur->showSubprograms = idxNum==0;
326 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(
340 "argument to %s() is not a valid SQL statement",
341 pVTab->bTablesUsed ? "tables_used" : "bytecode"
342 );
343 rc = SQLITE_ERROR;
344 }else{
345 bytecodevtabNext(pVtabCursor);
346 }
347 return rc;
348}
349
350/*
351** 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.
354*/
355static int bytecodevtabBestIndex(
356 sqlite3_vtab *tab,
357 sqlite3_index_info *pIdxInfo
358){
359 int i;
360 int rc = SQLITE_CONSTRAINT;
361 struct sqlite3_index_constraint *p;
362 bytecodevtab *pVTab = (bytecodevtab*)tab;
363 int iBaseCol = pVTab->bTablesUsed ? 4 : 8;
364 pIdxInfo->estimatedCost = (double)100;
365 pIdxInfo->estimatedRows = 100;
366 pIdxInfo->idxNum = 0;
367 for(i=0, p=pIdxInfo->aConstraint; i<pIdxInfo->nConstraint; i++, p++){
368 if( p->usable==0 ) continue;
369 if( p->op==SQLITE_INDEX_CONSTRAINT_EQ && p->iColumn==iBaseCol+1 ){
370 rc = SQLITE_OK;
371 pIdxInfo->aConstraintUsage[i].omit = 1;
372 pIdxInfo->aConstraintUsage[i].argvIndex = 1;
373 }
374 if( p->op==SQLITE_INDEX_CONSTRAINT_ISNULL && p->iColumn==iBaseCol ){
375 pIdxInfo->aConstraintUsage[i].omit = 1;
376 pIdxInfo->idxNum = 1;
377 }
378 }
379 return rc;
380}
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;
416 rc = sqlite3_create_module(db, "bytecode", &bytecodevtabModule, 0);
417 if( rc==SQLITE_OK ){
418 rc = sqlite3_create_module(db, "tables_used", &bytecodevtabModule, &db);
419 }
420 return rc;
421}
422#elif defined(SQLITE_ENABLE_BYTECODE_VTAB)
423int sqlite3VdbeBytecodeVtabInit(sqlite3 *db){ return SQLITE_OK; }
424#endif /* SQLITE_ENABLE_BYTECODE_VTAB */
425