1691b5c54Sdrh /*
2691b5c54Sdrh ** 2020-03-23
3691b5c54Sdrh **
4691b5c54Sdrh ** The author disclaims copyright to this source code. In place of
5691b5c54Sdrh ** a legal notice, here is a blessing:
6691b5c54Sdrh **
7691b5c54Sdrh ** May you do good and not evil.
8691b5c54Sdrh ** May you find forgiveness for yourself and forgive others.
9691b5c54Sdrh ** May you share freely, never taking more than you give.
10691b5c54Sdrh **
11691b5c54Sdrh *************************************************************************
12691b5c54Sdrh **
13691b5c54Sdrh ** This file implements virtual-tables for examining the bytecode content
14691b5c54Sdrh ** of a prepared statement.
15691b5c54Sdrh */
16691b5c54Sdrh #include "sqliteInt.h"
17d48eafb9Sdan #if defined(SQLITE_ENABLE_BYTECODE_VTAB) && !defined(SQLITE_OMIT_VIRTUALTABLE)
18691b5c54Sdrh #include "vdbeInt.h"
19691b5c54Sdrh
20691b5c54Sdrh /* An instance of the bytecode() table-valued function.
21691b5c54Sdrh */
228c5163a6Sdrh typedef struct bytecodevtab bytecodevtab;
238c5163a6Sdrh struct bytecodevtab {
24691b5c54Sdrh sqlite3_vtab base; /* Base class - must be first */
258c5163a6Sdrh sqlite3 *db; /* Database connection */
268f78a528Sdrh int bTablesUsed; /* 2 for tables_used(). 0 for bytecode(). */
27691b5c54Sdrh };
28691b5c54Sdrh
29691b5c54Sdrh /* A cursor for scanning through the bytecode
30691b5c54Sdrh */
31691b5c54Sdrh typedef struct bytecodevtab_cursor bytecodevtab_cursor;
32691b5c54Sdrh struct bytecodevtab_cursor {
33691b5c54Sdrh sqlite3_vtab_cursor base; /* Base class - must be first */
348c5163a6Sdrh sqlite3_stmt *pStmt; /* The statement whose bytecode is displayed */
358c5163a6Sdrh int iRowid; /* The rowid of the output table */
368c5163a6Sdrh int iAddr; /* Address */
378c5163a6Sdrh int needFinalize; /* Cursors owns pStmt and must finalize it */
3877972075Sdrh int showSubprograms; /* Provide a listing of subprograms */
398c5163a6Sdrh Op *aOp; /* Operand array */
408c5163a6Sdrh char *zP4; /* Rendered P4 value */
418f78a528Sdrh const char *zType; /* tables_used.type */
428f78a528Sdrh const char *zSchema; /* tables_used.schema */
438f78a528Sdrh const char *zName; /* tables_used.name */
448c5163a6Sdrh Mem sub; /* Subprograms */
45691b5c54Sdrh };
46691b5c54Sdrh
47691b5c54Sdrh /*
48691b5c54Sdrh ** Create a new bytecode() table-valued function.
49691b5c54Sdrh */
bytecodevtabConnect(sqlite3 * db,void * pAux,int argc,const char * const * argv,sqlite3_vtab ** ppVtab,char ** pzErr)50691b5c54Sdrh static int bytecodevtabConnect(
51691b5c54Sdrh sqlite3 *db,
52691b5c54Sdrh void *pAux,
53691b5c54Sdrh int argc, const char *const*argv,
54691b5c54Sdrh sqlite3_vtab **ppVtab,
55691b5c54Sdrh char **pzErr
56691b5c54Sdrh ){
578c5163a6Sdrh bytecodevtab *pNew;
58691b5c54Sdrh int rc;
598f78a528Sdrh int isTabUsed = pAux!=0;
608f78a528Sdrh const char *azSchema[2] = {
618f78a528Sdrh /* bytecode() schema */
62691b5c54Sdrh "CREATE TABLE x("
63691b5c54Sdrh "addr INT,"
64691b5c54Sdrh "opcode TEXT,"
65691b5c54Sdrh "p1 INT,"
66691b5c54Sdrh "p2 INT,"
67691b5c54Sdrh "p3 INT,"
68691b5c54Sdrh "p4 TEXT,"
69691b5c54Sdrh "p5 INT,"
70691b5c54Sdrh "comment TEXT,"
71691b5c54Sdrh "subprog TEXT,"
72691b5c54Sdrh "stmt HIDDEN"
738f78a528Sdrh ");",
748f78a528Sdrh
758f78a528Sdrh /* Tables_used() schema */
768f78a528Sdrh "CREATE TABLE x("
778f78a528Sdrh "type TEXT,"
788f78a528Sdrh "schema TEXT,"
798f78a528Sdrh "name TEXT,"
808f78a528Sdrh "wr INT,"
818f78a528Sdrh "subprog TEXT,"
828f78a528Sdrh "stmt HIDDEN"
83691b5c54Sdrh ");"
848f78a528Sdrh };
858f78a528Sdrh
868f78a528Sdrh rc = sqlite3_declare_vtab(db, azSchema[isTabUsed]);
87691b5c54Sdrh if( rc==SQLITE_OK ){
88691b5c54Sdrh pNew = sqlite3_malloc( sizeof(*pNew) );
89691b5c54Sdrh *ppVtab = (sqlite3_vtab*)pNew;
90691b5c54Sdrh if( pNew==0 ) return SQLITE_NOMEM;
91691b5c54Sdrh memset(pNew, 0, sizeof(*pNew));
928c5163a6Sdrh pNew->db = db;
938f78a528Sdrh pNew->bTablesUsed = isTabUsed*2;
94691b5c54Sdrh }
95691b5c54Sdrh return rc;
96691b5c54Sdrh }
97691b5c54Sdrh
98691b5c54Sdrh /*
998c5163a6Sdrh ** This method is the destructor for bytecodevtab objects.
100691b5c54Sdrh */
bytecodevtabDisconnect(sqlite3_vtab * pVtab)101691b5c54Sdrh static int bytecodevtabDisconnect(sqlite3_vtab *pVtab){
1028c5163a6Sdrh bytecodevtab *p = (bytecodevtab*)pVtab;
103691b5c54Sdrh sqlite3_free(p);
104691b5c54Sdrh return SQLITE_OK;
105691b5c54Sdrh }
106691b5c54Sdrh
107691b5c54Sdrh /*
108691b5c54Sdrh ** Constructor for a new bytecodevtab_cursor object.
109691b5c54Sdrh */
bytecodevtabOpen(sqlite3_vtab * p,sqlite3_vtab_cursor ** ppCursor)110691b5c54Sdrh static int bytecodevtabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
1118c5163a6Sdrh bytecodevtab *pVTab = (bytecodevtab*)p;
112691b5c54Sdrh bytecodevtab_cursor *pCur;
113691b5c54Sdrh pCur = sqlite3_malloc( sizeof(*pCur) );
114691b5c54Sdrh if( pCur==0 ) return SQLITE_NOMEM;
115691b5c54Sdrh memset(pCur, 0, sizeof(*pCur));
1168c5163a6Sdrh sqlite3VdbeMemInit(&pCur->sub, pVTab->db, 1);
117691b5c54Sdrh *ppCursor = &pCur->base;
118691b5c54Sdrh return SQLITE_OK;
119691b5c54Sdrh }
120691b5c54Sdrh
121691b5c54Sdrh /*
1228c5163a6Sdrh ** Clear all internal content from a bytecodevtab cursor.
1238c5163a6Sdrh */
bytecodevtabCursorClear(bytecodevtab_cursor * pCur)1248c5163a6Sdrh static void bytecodevtabCursorClear(bytecodevtab_cursor *pCur){
1258c5163a6Sdrh sqlite3_free(pCur->zP4);
1268c5163a6Sdrh pCur->zP4 = 0;
127cf08f08dSdrh sqlite3VdbeMemRelease(&pCur->sub);
1288c5163a6Sdrh sqlite3VdbeMemSetNull(&pCur->sub);
1298c5163a6Sdrh if( pCur->needFinalize ){
1308c5163a6Sdrh sqlite3_finalize(pCur->pStmt);
1318c5163a6Sdrh }
1328c5163a6Sdrh pCur->pStmt = 0;
1338c5163a6Sdrh pCur->needFinalize = 0;
1348f78a528Sdrh pCur->zType = 0;
1358f78a528Sdrh pCur->zSchema = 0;
1368f78a528Sdrh pCur->zName = 0;
1378c5163a6Sdrh }
1388c5163a6Sdrh
1398c5163a6Sdrh /*
140691b5c54Sdrh ** Destructor for a bytecodevtab_cursor.
141691b5c54Sdrh */
bytecodevtabClose(sqlite3_vtab_cursor * cur)142691b5c54Sdrh static int bytecodevtabClose(sqlite3_vtab_cursor *cur){
143691b5c54Sdrh bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur;
1448c5163a6Sdrh bytecodevtabCursorClear(pCur);
145691b5c54Sdrh sqlite3_free(pCur);
146691b5c54Sdrh return SQLITE_OK;
147691b5c54Sdrh }
148691b5c54Sdrh
149691b5c54Sdrh
150691b5c54Sdrh /*
151691b5c54Sdrh ** Advance a bytecodevtab_cursor to its next row of output.
152691b5c54Sdrh */
bytecodevtabNext(sqlite3_vtab_cursor * cur)153691b5c54Sdrh static int bytecodevtabNext(sqlite3_vtab_cursor *cur){
154691b5c54Sdrh bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur;
1558f78a528Sdrh bytecodevtab *pTab = (bytecodevtab*)cur->pVtab;
1568c5163a6Sdrh int rc;
1578c5163a6Sdrh if( pCur->zP4 ){
1588c5163a6Sdrh sqlite3_free(pCur->zP4);
1598c5163a6Sdrh pCur->zP4 = 0;
1608c5163a6Sdrh }
1618f78a528Sdrh if( pCur->zName ){
1628f78a528Sdrh pCur->zName = 0;
1638f78a528Sdrh pCur->zType = 0;
1648f78a528Sdrh pCur->zSchema = 0;
1658f78a528Sdrh }
16677972075Sdrh rc = sqlite3VdbeNextOpcode(
16777972075Sdrh (Vdbe*)pCur->pStmt,
16877972075Sdrh pCur->showSubprograms ? &pCur->sub : 0,
1698f78a528Sdrh pTab->bTablesUsed,
17077972075Sdrh &pCur->iRowid,
17177972075Sdrh &pCur->iAddr,
17277972075Sdrh &pCur->aOp);
1738c5163a6Sdrh if( rc!=SQLITE_OK ){
1748c5163a6Sdrh sqlite3VdbeMemSetNull(&pCur->sub);
1758c5163a6Sdrh pCur->aOp = 0;
1768c5163a6Sdrh }
177691b5c54Sdrh return SQLITE_OK;
178691b5c54Sdrh }
179691b5c54Sdrh
180691b5c54Sdrh /*
1818c5163a6Sdrh ** Return TRUE if the cursor has been moved off of the last
1828c5163a6Sdrh ** row of output.
1838c5163a6Sdrh */
bytecodevtabEof(sqlite3_vtab_cursor * cur)1848c5163a6Sdrh static int bytecodevtabEof(sqlite3_vtab_cursor *cur){
1858c5163a6Sdrh bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur;
1868c5163a6Sdrh return pCur->aOp==0;
1878c5163a6Sdrh }
1888c5163a6Sdrh
1898c5163a6Sdrh /*
190691b5c54Sdrh ** Return values of columns for the row at which the bytecodevtab_cursor
191691b5c54Sdrh ** is currently pointing.
192691b5c54Sdrh */
bytecodevtabColumn(sqlite3_vtab_cursor * cur,sqlite3_context * ctx,int i)193691b5c54Sdrh static int bytecodevtabColumn(
194691b5c54Sdrh sqlite3_vtab_cursor *cur, /* The cursor */
195691b5c54Sdrh sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
196691b5c54Sdrh int i /* Which column to return */
197691b5c54Sdrh ){
198691b5c54Sdrh bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur;
1998f78a528Sdrh bytecodevtab *pVTab = (bytecodevtab*)cur->pVtab;
2008c5163a6Sdrh Op *pOp = pCur->aOp + pCur->iAddr;
2018f78a528Sdrh if( pVTab->bTablesUsed ){
2028f78a528Sdrh if( i==4 ){
2038f78a528Sdrh i = 8;
2048f78a528Sdrh }else{
2058f78a528Sdrh if( i<=2 && pCur->zType==0 ){
2068f78a528Sdrh Schema *pSchema;
2078f78a528Sdrh HashElem *k;
2088f78a528Sdrh int iDb = pOp->p3;
209*013e7bb7Sdrh Pgno iRoot = (Pgno)pOp->p2;
2108f78a528Sdrh sqlite3 *db = pVTab->db;
2118f78a528Sdrh pSchema = db->aDb[iDb].pSchema;
2128f78a528Sdrh pCur->zSchema = db->aDb[iDb].zDbSName;
2138f78a528Sdrh for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){
2148f78a528Sdrh Table *pTab = (Table*)sqliteHashData(k);
2158f78a528Sdrh if( !IsVirtual(pTab) && pTab->tnum==iRoot ){
2168f78a528Sdrh pCur->zName = pTab->zName;
2178f78a528Sdrh pCur->zType = "table";
2188f78a528Sdrh break;
2198f78a528Sdrh }
2208f78a528Sdrh }
2218f78a528Sdrh if( pCur->zName==0 ){
2228f78a528Sdrh for(k=sqliteHashFirst(&pSchema->idxHash); k; k=sqliteHashNext(k)){
2238f78a528Sdrh Index *pIdx = (Index*)sqliteHashData(k);
2248f78a528Sdrh if( pIdx->tnum==iRoot ){
2258f78a528Sdrh pCur->zName = pIdx->zName;
2268f78a528Sdrh pCur->zType = "index";
2278f78a528Sdrh }
2288f78a528Sdrh }
2298f78a528Sdrh }
2308f78a528Sdrh }
2318f78a528Sdrh i += 10;
2328f78a528Sdrh }
2338f78a528Sdrh }
234691b5c54Sdrh switch( i ){
2350518d061Sdrh case 0: /* addr */
2368c5163a6Sdrh sqlite3_result_int(ctx, pCur->iAddr);
237691b5c54Sdrh break;
2380518d061Sdrh case 1: /* opcode */
2398c5163a6Sdrh sqlite3_result_text(ctx, (char*)sqlite3OpcodeName(pOp->opcode),
2408c5163a6Sdrh -1, SQLITE_STATIC);
2418c5163a6Sdrh break;
2420518d061Sdrh case 2: /* p1 */
2438c5163a6Sdrh sqlite3_result_int(ctx, pOp->p1);
2448c5163a6Sdrh break;
2450518d061Sdrh case 3: /* p2 */
2468c5163a6Sdrh sqlite3_result_int(ctx, pOp->p2);
2478c5163a6Sdrh break;
2480518d061Sdrh case 4: /* p3 */
2498c5163a6Sdrh sqlite3_result_int(ctx, pOp->p3);
2508c5163a6Sdrh break;
2510518d061Sdrh case 5: /* p4 */
2520518d061Sdrh case 7: /* comment */
2538c5163a6Sdrh if( pCur->zP4==0 ){
2548c5163a6Sdrh pCur->zP4 = sqlite3VdbeDisplayP4(pVTab->db, pOp);
2558c5163a6Sdrh }
2568c5163a6Sdrh if( i==5 ){
2578c5163a6Sdrh sqlite3_result_text(ctx, pCur->zP4, -1, SQLITE_STATIC);
2588c5163a6Sdrh }else{
259eeb55d86Sdrh #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
2608c5163a6Sdrh char *zCom = sqlite3VdbeDisplayComment(pVTab->db, pOp, pCur->zP4);
2618c5163a6Sdrh sqlite3_result_text(ctx, zCom, -1, sqlite3_free);
262eeb55d86Sdrh #endif
2638c5163a6Sdrh }
2648c5163a6Sdrh break;
2650518d061Sdrh case 6: /* p5 */
2668c5163a6Sdrh sqlite3_result_int(ctx, pOp->p5);
267691b5c54Sdrh break;
2680518d061Sdrh case 8: { /* subprog */
2690518d061Sdrh Op *aOp = pCur->aOp;
2707e088a6cSdrh assert( aOp[0].opcode==OP_Init );
2717e088a6cSdrh assert( aOp[0].p4.z==0 || strncmp(aOp[0].p4.z,"-" "- ",3)==0 );
2720518d061Sdrh if( pCur->iRowid==pCur->iAddr+1 ){
2730518d061Sdrh break; /* Result is NULL for the main program */
2747e088a6cSdrh }else if( aOp[0].p4.z!=0 ){
2750518d061Sdrh sqlite3_result_text(ctx, aOp[0].p4.z+3, -1, SQLITE_STATIC);
2760518d061Sdrh }else{
2770518d061Sdrh sqlite3_result_text(ctx, "(FK)", 4, SQLITE_STATIC);
2780518d061Sdrh }
2790518d061Sdrh break;
2800518d061Sdrh }
2818f78a528Sdrh case 10: /* tables_used.type */
2828f78a528Sdrh sqlite3_result_text(ctx, pCur->zType, -1, SQLITE_STATIC);
2838f78a528Sdrh break;
2848f78a528Sdrh case 11: /* tables_used.schema */
2858f78a528Sdrh sqlite3_result_text(ctx, pCur->zSchema, -1, SQLITE_STATIC);
2868f78a528Sdrh break;
2878f78a528Sdrh case 12: /* tables_used.name */
2888f78a528Sdrh sqlite3_result_text(ctx, pCur->zName, -1, SQLITE_STATIC);
2898f78a528Sdrh break;
2908f78a528Sdrh case 13: /* tables_used.wr */
2918f78a528Sdrh sqlite3_result_int(ctx, pOp->opcode==OP_OpenWrite);
2928f78a528Sdrh break;
293691b5c54Sdrh }
294691b5c54Sdrh return SQLITE_OK;
295691b5c54Sdrh }
296691b5c54Sdrh
297691b5c54Sdrh /*
298691b5c54Sdrh ** Return the rowid for the current row. In this implementation, the
299691b5c54Sdrh ** rowid is the same as the output value.
300691b5c54Sdrh */
bytecodevtabRowid(sqlite3_vtab_cursor * cur,sqlite_int64 * pRowid)301691b5c54Sdrh static int bytecodevtabRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
302691b5c54Sdrh bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur;
303691b5c54Sdrh *pRowid = pCur->iRowid;
304691b5c54Sdrh return SQLITE_OK;
305691b5c54Sdrh }
306691b5c54Sdrh
307691b5c54Sdrh /*
30877972075Sdrh ** Initialize a cursor.
30977972075Sdrh **
31077972075Sdrh ** idxNum==0 means show all subprograms
31177972075Sdrh ** idxNum==1 means show only the main bytecode and omit subprograms.
312691b5c54Sdrh */
bytecodevtabFilter(sqlite3_vtab_cursor * pVtabCursor,int idxNum,const char * idxStr,int argc,sqlite3_value ** argv)313691b5c54Sdrh static int bytecodevtabFilter(
314691b5c54Sdrh sqlite3_vtab_cursor *pVtabCursor,
315691b5c54Sdrh int idxNum, const char *idxStr,
316691b5c54Sdrh int argc, sqlite3_value **argv
317691b5c54Sdrh ){
318691b5c54Sdrh bytecodevtab_cursor *pCur = (bytecodevtab_cursor *)pVtabCursor;
3198c5163a6Sdrh bytecodevtab *pVTab = (bytecodevtab *)pVtabCursor->pVtab;
3208c5163a6Sdrh int rc = SQLITE_OK;
3218c5163a6Sdrh
3228c5163a6Sdrh bytecodevtabCursorClear(pCur);
3238c5163a6Sdrh pCur->iRowid = 0;
3248c5163a6Sdrh pCur->iAddr = 0;
32577972075Sdrh pCur->showSubprograms = idxNum==0;
3268c5163a6Sdrh assert( argc==1 );
3278c5163a6Sdrh if( sqlite3_value_type(argv[0])==SQLITE_TEXT ){
3288c5163a6Sdrh const char *zSql = (const char*)sqlite3_value_text(argv[0]);
3298c5163a6Sdrh if( zSql==0 ){
3308c5163a6Sdrh rc = SQLITE_NOMEM;
3318c5163a6Sdrh }else{
3328c5163a6Sdrh rc = sqlite3_prepare_v2(pVTab->db, zSql, -1, &pCur->pStmt, 0);
3338c5163a6Sdrh pCur->needFinalize = 1;
3348c5163a6Sdrh }
3358c5163a6Sdrh }else{
3368c5163a6Sdrh pCur->pStmt = (sqlite3_stmt*)sqlite3_value_pointer(argv[0],"stmt-pointer");
3378c5163a6Sdrh }
3388c5163a6Sdrh if( pCur->pStmt==0 ){
3398c5163a6Sdrh pVTab->base.zErrMsg = sqlite3_mprintf(
3408f78a528Sdrh "argument to %s() is not a valid SQL statement",
3418f78a528Sdrh pVTab->bTablesUsed ? "tables_used" : "bytecode"
3428c5163a6Sdrh );
3438c5163a6Sdrh rc = SQLITE_ERROR;
3448c5163a6Sdrh }else{
3458c5163a6Sdrh bytecodevtabNext(pVtabCursor);
3468c5163a6Sdrh }
3478c5163a6Sdrh return rc;
348691b5c54Sdrh }
349691b5c54Sdrh
350691b5c54Sdrh /*
3518c5163a6Sdrh ** We must have a single stmt=? constraint that will be passed through
3528c5163a6Sdrh ** into the xFilter method. If there is no valid stmt=? constraint,
3538c5163a6Sdrh ** then return an SQLITE_CONSTRAINT error.
354691b5c54Sdrh */
bytecodevtabBestIndex(sqlite3_vtab * tab,sqlite3_index_info * pIdxInfo)355691b5c54Sdrh static int bytecodevtabBestIndex(
356691b5c54Sdrh sqlite3_vtab *tab,
357691b5c54Sdrh sqlite3_index_info *pIdxInfo
358691b5c54Sdrh ){
3598c5163a6Sdrh int i;
3608c5163a6Sdrh int rc = SQLITE_CONSTRAINT;
36177972075Sdrh struct sqlite3_index_constraint *p;
3628f78a528Sdrh bytecodevtab *pVTab = (bytecodevtab*)tab;
3638f78a528Sdrh int iBaseCol = pVTab->bTablesUsed ? 4 : 8;
3648c5163a6Sdrh pIdxInfo->estimatedCost = (double)100;
3658c5163a6Sdrh pIdxInfo->estimatedRows = 100;
36677972075Sdrh pIdxInfo->idxNum = 0;
36777972075Sdrh for(i=0, p=pIdxInfo->aConstraint; i<pIdxInfo->nConstraint; i++, p++){
36877972075Sdrh if( p->usable==0 ) continue;
3698f78a528Sdrh if( p->op==SQLITE_INDEX_CONSTRAINT_EQ && p->iColumn==iBaseCol+1 ){
3708c5163a6Sdrh rc = SQLITE_OK;
3718c5163a6Sdrh pIdxInfo->aConstraintUsage[i].omit = 1;
3728c5163a6Sdrh pIdxInfo->aConstraintUsage[i].argvIndex = 1;
37377972075Sdrh }
3748f78a528Sdrh if( p->op==SQLITE_INDEX_CONSTRAINT_ISNULL && p->iColumn==iBaseCol ){
37577972075Sdrh pIdxInfo->aConstraintUsage[i].omit = 1;
37677972075Sdrh pIdxInfo->idxNum = 1;
37777972075Sdrh }
3788c5163a6Sdrh }
3798c5163a6Sdrh return rc;
380691b5c54Sdrh }
381691b5c54Sdrh
382691b5c54Sdrh /*
383691b5c54Sdrh ** This following structure defines all the methods for the
384691b5c54Sdrh ** virtual table.
385691b5c54Sdrh */
386691b5c54Sdrh static sqlite3_module bytecodevtabModule = {
387691b5c54Sdrh /* iVersion */ 0,
388691b5c54Sdrh /* xCreate */ 0,
389691b5c54Sdrh /* xConnect */ bytecodevtabConnect,
390691b5c54Sdrh /* xBestIndex */ bytecodevtabBestIndex,
391691b5c54Sdrh /* xDisconnect */ bytecodevtabDisconnect,
392691b5c54Sdrh /* xDestroy */ 0,
393691b5c54Sdrh /* xOpen */ bytecodevtabOpen,
394691b5c54Sdrh /* xClose */ bytecodevtabClose,
395691b5c54Sdrh /* xFilter */ bytecodevtabFilter,
396691b5c54Sdrh /* xNext */ bytecodevtabNext,
397691b5c54Sdrh /* xEof */ bytecodevtabEof,
398691b5c54Sdrh /* xColumn */ bytecodevtabColumn,
399691b5c54Sdrh /* xRowid */ bytecodevtabRowid,
400691b5c54Sdrh /* xUpdate */ 0,
401691b5c54Sdrh /* xBegin */ 0,
402691b5c54Sdrh /* xSync */ 0,
403691b5c54Sdrh /* xCommit */ 0,
404691b5c54Sdrh /* xRollback */ 0,
405691b5c54Sdrh /* xFindMethod */ 0,
406691b5c54Sdrh /* xRename */ 0,
407691b5c54Sdrh /* xSavepoint */ 0,
408691b5c54Sdrh /* xRelease */ 0,
409691b5c54Sdrh /* xRollbackTo */ 0,
410691b5c54Sdrh /* xShadowName */ 0
411691b5c54Sdrh };
412691b5c54Sdrh
413691b5c54Sdrh
sqlite3VdbeBytecodeVtabInit(sqlite3 * db)414691b5c54Sdrh int sqlite3VdbeBytecodeVtabInit(sqlite3 *db){
415691b5c54Sdrh int rc;
4168c5163a6Sdrh rc = sqlite3_create_module(db, "bytecode", &bytecodevtabModule, 0);
4178f78a528Sdrh if( rc==SQLITE_OK ){
4188f78a528Sdrh rc = sqlite3_create_module(db, "tables_used", &bytecodevtabModule, &db);
4198f78a528Sdrh }
420691b5c54Sdrh return rc;
421691b5c54Sdrh }
42234d15667Sdan #elif defined(SQLITE_ENABLE_BYTECODE_VTAB)
sqlite3VdbeBytecodeVtabInit(sqlite3 * db)42334d15667Sdan int sqlite3VdbeBytecodeVtabInit(sqlite3 *db){ return SQLITE_OK; }
424691b5c54Sdrh #endif /* SQLITE_ENABLE_BYTECODE_VTAB */
425