AryaWu/sqlite
0
1/*2** 2020-03-233**4** The author disclaims copyright to this source code. In place of5** 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 content14** 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 bytecode30*/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 **pzErr56){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 "nexec INT,"73 "ncycle INT,"74 "stmt HIDDEN"75 ");",76 77 /* Tables_used() schema */78 "CREATE TABLE x("79 "type TEXT,"80 "schema TEXT,"81 "name TEXT,"82 "wr INT,"83 "subprog TEXT," 84 "stmt HIDDEN"85 ");"86 };87 88 (void)argc;89 (void)argv;90 (void)pzErr;91 rc = sqlite3_declare_vtab(db, azSchema[isTabUsed]);92 if( rc==SQLITE_OK ){93 pNew = sqlite3_malloc( sizeof(*pNew) );94 *ppVtab = (sqlite3_vtab*)pNew;95 if( pNew==0 ) return SQLITE_NOMEM;96 memset(pNew, 0, sizeof(*pNew));97 pNew->db = db;98 pNew->bTablesUsed = isTabUsed*2;99 }100 return rc;101}102 103/*104** This method is the destructor for bytecodevtab objects.105*/106static int bytecodevtabDisconnect(sqlite3_vtab *pVtab){107 bytecodevtab *p = (bytecodevtab*)pVtab;108 sqlite3_free(p);109 return SQLITE_OK;110}111 112/*113** Constructor for a new bytecodevtab_cursor object.114*/115static int bytecodevtabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){116 bytecodevtab *pVTab = (bytecodevtab*)p;117 bytecodevtab_cursor *pCur;118 pCur = sqlite3_malloc( sizeof(*pCur) );119 if( pCur==0 ) return SQLITE_NOMEM;120 memset(pCur, 0, sizeof(*pCur));121 sqlite3VdbeMemInit(&pCur->sub, pVTab->db, 1);122 *ppCursor = &pCur->base;123 return SQLITE_OK;124}125 126/*127** Clear all internal content from a bytecodevtab cursor.128*/129static void bytecodevtabCursorClear(bytecodevtab_cursor *pCur){130 sqlite3_free(pCur->zP4);131 pCur->zP4 = 0;132 sqlite3VdbeMemRelease(&pCur->sub);133 sqlite3VdbeMemSetNull(&pCur->sub);134 if( pCur->needFinalize ){135 sqlite3_finalize(pCur->pStmt);136 }137 pCur->pStmt = 0;138 pCur->needFinalize = 0;139 pCur->zType = 0;140 pCur->zSchema = 0;141 pCur->zName = 0;142}143 144/*145** Destructor for a bytecodevtab_cursor.146*/147static int bytecodevtabClose(sqlite3_vtab_cursor *cur){148 bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur;149 bytecodevtabCursorClear(pCur);150 sqlite3_free(pCur);151 return SQLITE_OK;152}153 154 155/*156** Advance a bytecodevtab_cursor to its next row of output.157*/158static int bytecodevtabNext(sqlite3_vtab_cursor *cur){159 bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur;160 bytecodevtab *pTab = (bytecodevtab*)cur->pVtab;161 int rc;162 if( pCur->zP4 ){163 sqlite3_free(pCur->zP4);164 pCur->zP4 = 0;165 }166 if( pCur->zName ){167 pCur->zName = 0;168 pCur->zType = 0;169 pCur->zSchema = 0;170 }171 rc = sqlite3VdbeNextOpcode(172 (Vdbe*)pCur->pStmt, 173 pCur->showSubprograms ? &pCur->sub : 0,174 pTab->bTablesUsed,175 &pCur->iRowid,176 &pCur->iAddr,177 &pCur->aOp);178 if( rc!=SQLITE_OK ){179 sqlite3VdbeMemSetNull(&pCur->sub);180 pCur->aOp = 0;181 }182 return SQLITE_OK;183}184 185/*186** Return TRUE if the cursor has been moved off of the last187** row of output.188*/189static int bytecodevtabEof(sqlite3_vtab_cursor *cur){190 bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur;191 return pCur->aOp==0;192}193 194/*195** Return values of columns for the row at which the bytecodevtab_cursor196** is currently pointing.197*/198static int bytecodevtabColumn(199 sqlite3_vtab_cursor *cur, /* The cursor */200 sqlite3_context *ctx, /* First argument to sqlite3_result_...() */201 int i /* Which column to return */202){203 bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur;204 bytecodevtab *pVTab = (bytecodevtab*)cur->pVtab;205 Op *pOp = pCur->aOp + pCur->iAddr;206 if( pVTab->bTablesUsed ){207 if( i==4 ){208 i = 8;209 }else{210 if( i<=2 && pCur->zType==0 ){211 Schema *pSchema;212 HashElem *k;213 int iDb = pOp->p3;214 Pgno iRoot = (Pgno)pOp->p2;215 sqlite3 *db = pVTab->db;216 pSchema = db->aDb[iDb].pSchema;217 pCur->zSchema = db->aDb[iDb].zDbSName;218 for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){219 Table *pTab = (Table*)sqliteHashData(k);220 if( !IsVirtual(pTab) && pTab->tnum==iRoot ){221 pCur->zName = pTab->zName;222 pCur->zType = "table";223 break;224 }225 }226 if( pCur->zName==0 ){227 for(k=sqliteHashFirst(&pSchema->idxHash); k; k=sqliteHashNext(k)){228 Index *pIdx = (Index*)sqliteHashData(k);229 if( pIdx->tnum==iRoot ){230 pCur->zName = pIdx->zName;231 pCur->zType = "index";232 }233 }234 }235 }236 i += 20;237 }238 }239 switch( i ){240 case 0: /* addr */241 sqlite3_result_int(ctx, pCur->iAddr);242 break;243 case 1: /* opcode */244 sqlite3_result_text(ctx, (char*)sqlite3OpcodeName(pOp->opcode),245 -1, SQLITE_STATIC);246 break;247 case 2: /* p1 */248 sqlite3_result_int(ctx, pOp->p1);249 break;250 case 3: /* p2 */251 sqlite3_result_int(ctx, pOp->p2);252 break;253 case 4: /* p3 */254 sqlite3_result_int(ctx, pOp->p3);255 break;256 case 5: /* p4 */257 case 7: /* comment */258 if( pCur->zP4==0 ){259 pCur->zP4 = sqlite3VdbeDisplayP4(pVTab->db, pOp);260 }261 if( i==5 ){262 sqlite3_result_text(ctx, pCur->zP4, -1, SQLITE_STATIC);263 }else{264#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS265 char *zCom = sqlite3VdbeDisplayComment(pVTab->db, pOp, pCur->zP4);266 sqlite3_result_text(ctx, zCom, -1, sqlite3_free);267#endif268 }269 break;270 case 6: /* p5 */271 sqlite3_result_int(ctx, pOp->p5);272 break;273 case 8: { /* subprog */274 Op *aOp = pCur->aOp;275 assert( aOp[0].opcode==OP_Init );276 assert( aOp[0].p4.z==0 || strncmp(aOp[0].p4.z,"-" "- ",3)==0 );277 if( pCur->iRowid==pCur->iAddr+1 ){278 break; /* Result is NULL for the main program */279 }else if( aOp[0].p4.z!=0 ){280 sqlite3_result_text(ctx, aOp[0].p4.z+3, -1, SQLITE_STATIC);281 }else{282 sqlite3_result_text(ctx, "(FK)", 4, SQLITE_STATIC);283 }284 break;285 }286 287#ifdef SQLITE_ENABLE_STMT_SCANSTATUS288 case 9: /* nexec */289 sqlite3_result_int64(ctx, pOp->nExec);290 break;291 case 10: /* ncycle */292 sqlite3_result_int64(ctx, pOp->nCycle);293 break;294#else295 case 9: /* nexec */296 case 10: /* ncycle */297 sqlite3_result_int(ctx, 0);298 break;299#endif300 301 case 20: /* tables_used.type */302 sqlite3_result_text(ctx, pCur->zType, -1, SQLITE_STATIC);303 break;304 case 21: /* tables_used.schema */305 sqlite3_result_text(ctx, pCur->zSchema, -1, SQLITE_STATIC);306 break;307 case 22: /* tables_used.name */308 sqlite3_result_text(ctx, pCur->zName, -1, SQLITE_STATIC);309 break;310 case 23: /* tables_used.wr */311 sqlite3_result_int(ctx, pOp->opcode==OP_OpenWrite);312 break;313 }314 return SQLITE_OK;315}316 317/*318** Return the rowid for the current row. In this implementation, the319** rowid is the same as the output value.320*/321static int bytecodevtabRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){322 bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur;323 *pRowid = pCur->iRowid;324 return SQLITE_OK;325}326 327/*328** Initialize a cursor.329**330** idxNum==0 means show all subprograms331** idxNum==1 means show only the main bytecode and omit subprograms.332*/333static int bytecodevtabFilter(334 sqlite3_vtab_cursor *pVtabCursor, 335 int idxNum, const char *idxStr,336 int argc, sqlite3_value **argv337){338 bytecodevtab_cursor *pCur = (bytecodevtab_cursor *)pVtabCursor;339 bytecodevtab *pVTab = (bytecodevtab *)pVtabCursor->pVtab;340 int rc = SQLITE_OK;341 (void)idxStr;342 343 bytecodevtabCursorClear(pCur);344 pCur->iRowid = 0;345 pCur->iAddr = 0;346 pCur->showSubprograms = idxNum==0;347 assert( argc==1 );348 if( sqlite3_value_type(argv[0])==SQLITE_TEXT ){349 const char *zSql = (const char*)sqlite3_value_text(argv[0]);350 if( zSql==0 ){351 rc = SQLITE_NOMEM;352 }else{353 rc = sqlite3_prepare_v2(pVTab->db, zSql, -1, &pCur->pStmt, 0);354 pCur->needFinalize = 1;355 }356 }else{357 pCur->pStmt = (sqlite3_stmt*)sqlite3_value_pointer(argv[0],"stmt-pointer");358 }359 if( pCur->pStmt==0 ){360 pVTab->base.zErrMsg = sqlite3_mprintf(361 "argument to %s() is not a valid SQL statement",362 pVTab->bTablesUsed ? "tables_used" : "bytecode"363 );364 rc = SQLITE_ERROR;365 }else{366 bytecodevtabNext(pVtabCursor);367 }368 return rc;369}370 371/*372** We must have a single stmt=? constraint that will be passed through373** into the xFilter method. If there is no valid stmt=? constraint,374** then return an SQLITE_CONSTRAINT error.375*/376static int bytecodevtabBestIndex(377 sqlite3_vtab *tab,378 sqlite3_index_info *pIdxInfo379){380 int i;381 int rc = SQLITE_CONSTRAINT;382 struct sqlite3_index_constraint *p;383 bytecodevtab *pVTab = (bytecodevtab*)tab;384 int iBaseCol = pVTab->bTablesUsed ? 4 : 10;385 pIdxInfo->estimatedCost = (double)100;386 pIdxInfo->estimatedRows = 100;387 pIdxInfo->idxNum = 0;388 for(i=0, p=pIdxInfo->aConstraint; i<pIdxInfo->nConstraint; i++, p++){389 if( p->usable==0 ) continue;390 if( p->op==SQLITE_INDEX_CONSTRAINT_EQ && p->iColumn==iBaseCol+1 ){391 rc = SQLITE_OK;392 pIdxInfo->aConstraintUsage[i].omit = 1;393 pIdxInfo->aConstraintUsage[i].argvIndex = 1;394 }395 if( p->op==SQLITE_INDEX_CONSTRAINT_ISNULL && p->iColumn==iBaseCol ){396 pIdxInfo->aConstraintUsage[i].omit = 1;397 pIdxInfo->idxNum = 1;398 }399 }400 return rc;401}402 403/*404** This following structure defines all the methods for the 405** virtual table.406*/407static sqlite3_module bytecodevtabModule = {408 /* iVersion */ 0,409 /* xCreate */ 0,410 /* xConnect */ bytecodevtabConnect,411 /* xBestIndex */ bytecodevtabBestIndex,412 /* xDisconnect */ bytecodevtabDisconnect,413 /* xDestroy */ 0,414 /* xOpen */ bytecodevtabOpen,415 /* xClose */ bytecodevtabClose,416 /* xFilter */ bytecodevtabFilter,417 /* xNext */ bytecodevtabNext,418 /* xEof */ bytecodevtabEof,419 /* xColumn */ bytecodevtabColumn,420 /* xRowid */ bytecodevtabRowid,421 /* xUpdate */ 0,422 /* xBegin */ 0,423 /* xSync */ 0,424 /* xCommit */ 0,425 /* xRollback */ 0,426 /* xFindMethod */ 0,427 /* xRename */ 0,428 /* xSavepoint */ 0,429 /* xRelease */ 0,430 /* xRollbackTo */ 0,431 /* xShadowName */ 0,432 /* xIntegrity */ 0433};434 435 436int sqlite3VdbeBytecodeVtabInit(sqlite3 *db){437 int rc;438 rc = sqlite3_create_module(db, "bytecode", &bytecodevtabModule, 0);439 if( rc==SQLITE_OK ){440 rc = sqlite3_create_module(db, "tables_used", &bytecodevtabModule, &db);441 }442 return rc;443}444#elif defined(SQLITE_ENABLE_BYTECODE_VTAB)445int sqlite3VdbeBytecodeVtabInit(sqlite3 *db){ return SQLITE_OK; }446#endif /* SQLITE_ENABLE_BYTECODE_VTAB */447 