Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
vdbevtab.c447 linesDownload Raw Back to src
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