]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
The bytecode() function now runs and sometimes works, but it untested and
authordrh <drh@noemail.net>
Mon, 23 Mar 2020 20:58:55 +0000 (20:58 +0000)
committerdrh <drh@noemail.net>
Mon, 23 Mar 2020 20:58:55 +0000 (20:58 +0000)
there are known problems.

FossilOrigin-Name: 6819b86eb2de516c445655a83f9b2ba5ae0bff660cffaf84f1345d9be79b051e

manifest
manifest.uuid
src/vdbeInt.h
src/vdbeaux.c
src/vdbevtab.c

index 6e2287c6980bc185ec549f3bdcd68e9a18ad56a9..1dc7d4ebecdfc52dd1e78ec0d67706f586b10f24 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Further\ssimplification\sand\smodularization\sof\sthe\sEXPLAIN\slogic.
-D 2020-03-23T19:14:11.433
+C The\sbytecode()\sfunction\snow\sruns\sand\ssometimes\sworks,\sbut\sit\suntested\sand\nthere\sare\sknown\sproblems.
+D 2020-03-23T20:58:55.887
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -605,14 +605,14 @@ F src/util.c a285c1e026907b69fa2592bd05047a565a1d8a1aef2b73c924b6a8ffe772871a
 F src/vacuum.c 813b510ba887fee6492bcb11f2bf77d7eb58b232b83649136372e0a2fc17f4b9
 F src/vdbe.c c1c123c6248fa88940b932a00bcc75056921b6d046d45a82566cb97415d2299c
 F src/vdbe.h 07b8c636a87df8b6e58f29d6badd7f10d5844353deff1d7c88ed1c2bfe3bbd35
-F src/vdbeInt.h 198e552a1a8945061c7576d3d7f8c8603300bbbb9ba0a337184bf13a7cdda65d
+F src/vdbeInt.h 5f36e2261731e6a39c66c6902634e474d4a98ed14ca10be6dea5c3776ece4342
 F src/vdbeapi.c 1252d80c548711e47a6d84dae88ed4e95d3fbb4e7bd0eaa1347299af7efddf02
-F src/vdbeaux.c a041e907fed078029e6d7608f62acf9d69ea262d515b00254f8736eff5f4d363
+F src/vdbeaux.c c99bdd953b93d74bfc22c11a47a9fb79e6e498017a4d2c7eb4a0320d54df60fd
 F src/vdbeblob.c 253ed82894924c362a7fa3079551d3554cd1cdace39aa833da77d3bc67e7c1b1
 F src/vdbemem.c 39b942ecca179f4f30a32b54579a85d74ccaefa5af2a0ad2700abe5ef0768b22
 F src/vdbesort.c 2be76d26998ce2b3324cdcc9f6443728e54b6c7677c553ad909c7d7cfab587df
 F src/vdbetrace.c fa3bf238002f0bbbdfb66cc8afb0cea284ff9f148d6439bc1f6f2b4c3b7143f0
-F src/vdbevtab.c dfe1e9b661e3de27f49fc160a04fc0275ab08bb46cdf20943bf2bf418db398a5
+F src/vdbevtab.c c2dad21236249e745f99e6c4c175ab3c8c1430d84483bea30d3388b8c82bf945
 F src/vtab.c 7b704a90515a239c6cdba6a66b1bb3a385e62326cceb5ecb05ec7a091d6b8515
 F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
 F src/wal.c 697424314e40d99f93f548c7bfa526c10e87f4bdf64d5a76a96b999dd7133ebc
@@ -1861,7 +1861,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 2c4dd79fbd4b9f72634a732abb9ed833cd8c9b05fe1e10af8f23e6d6ec023c7c
-R 4748d2ea6081821a30c83e5089756745
+P aee1c12f4227cea9e8c6295cee3ec11797422c31b48c9468f176eb52f8261fe8
+R 4e495b787689ae8a4210faab4d40d67a
 U drh
-Z 573498e339f1a839323caa9c87282f78
+Z 0475543e1eec2402a1a0d93a49295452
index 1432c3fd8f204ce79543c4dcdbb32dee27ca513b..6544abac453a7077784004e27952d2e3577244f1 100644 (file)
@@ -1 +1 @@
-aee1c12f4227cea9e8c6295cee3ec11797422c31b48c9468f176eb52f8261fe8
\ No newline at end of file
+6819b86eb2de516c445655a83f9b2ba5ae0bff660cffaf84f1345d9be79b051e
\ No newline at end of file
index 9aa10d89bf7d2b7cf2b6e3e3ee9151651f7db47e..a9465cc0ac7c8ebbd179073a383cdb5360617c39 100644 (file)
@@ -31,7 +31,8 @@
 ** "explain" P4 display logic is enabled.
 */
 #if !defined(SQLITE_OMIT_EXPLAIN) || !defined(NDEBUG) \
-     || defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
+     || defined(VDBE_PROFILE) || defined(SQLITE_DEBUG) \
+     || defined(SQLITE_ENABLE_BYTECODE_VTAB)
 # define VDBE_DISPLAY_P4 1
 #else
 # define VDBE_DISPLAY_P4 0
@@ -496,8 +497,12 @@ int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *);
 int sqlite3VdbeIdxKeyCompare(sqlite3*,VdbeCursor*,UnpackedRecord*,int*);
 int sqlite3VdbeIdxRowid(sqlite3*, BtCursor*, i64*);
 int sqlite3VdbeExec(Vdbe*);
-#ifndef SQLITE_OMIT_EXPLAIN
+#if !defined(SQLITE_OMIT_EXPLAIN) || defined(SQLITE_ENABLE_BYTECODE_VTAB)
 int sqlite3VdbeNextOpcode(Vdbe*,Mem*,int,int*,int*,Op**);
+char *sqlite3VdbeDisplayP4(sqlite3*,Op*);
+char *sqlite3VdbeDisplayComment(sqlite3*,const Op*,const char*);
+#endif
+#if !defined(SQLITE_OMIT_EXPLAIN)
 int sqlite3VdbeList(Vdbe*);
 #endif
 int sqlite3VdbeHalt(Vdbe*);
@@ -539,7 +544,7 @@ int sqlite3VdbeMemFinalize(Mem*, FuncDef*);
 #ifndef SQLITE_OMIT_WINDOWFUNC
 int sqlite3VdbeMemAggValue(Mem*, Mem*, FuncDef*);
 #endif
-#ifndef SQLITE_OMIT_EXPLAIN
+#if !defined(SQLITE_OMIT_EXPLAIN) || defined(SQLITE_ENABLE_BYTECODE_VTAB)
 const char *sqlite3OpcodeName(int);
 #endif
 int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve);
index 37ec1aabbd939aa69e4ad7d7f6ea77975a444404..6c6eb8ec5f358d6a609f9c0ad55067c4fa47202e 100644 (file)
@@ -1464,7 +1464,7 @@ static int translateP(char c, const Op *pOp){
 **       "PX@PY+1" ->  "r[X..X+Y]"    or "r[x]" if y is 0
 **       "PY..PY"  ->  "r[X..Y]"      or "r[x]" if y<=x
 */
-static char *displayComment(
+char *sqlite3VdbeDisplayComment(
   sqlite3 *db,       /* Optional - Oom error reporting only */
   const Op *pOp,     /* The opcode to be commented */
   const char *zP4    /* Previously obtained value for P4 */
@@ -1629,7 +1629,7 @@ static void displayP4Expr(StrAccum *p, Expr *pExpr){
 ** Compute a string that describes the P4 parameter for an opcode.
 ** Use zTemp for any required temporary buffer space.
 */
-static char *displayP4(sqlite3 *db, Op *pOp){
+char *sqlite3VdbeDisplayP4(sqlite3 *db, Op *pOp){
   char *zP4 = 0;
   StrAccum x;
 
@@ -1836,9 +1836,9 @@ void sqlite3VdbePrintOp(FILE *pOut, int pc, VdbeOp *pOp){
   char *zCom;
   static const char *zFormat1 = "%4d %-13s %4d %4d %4d %-13s %.2X %s\n";
   if( pOut==0 ) pOut = stdout;
-  zP4 = displayP4(0, pOp);
+  zP4 = sqlite3VdbeDisplayP4(0, pOp);
 #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
-  zCom = displayComment(0, pOp, zP4);
+  zCom = sqlite3VdbeDisplayComment(0, pOp, zP4);
 #else
   zCom = 0;
 #endif
@@ -1942,6 +1942,7 @@ void sqlite3VdbeFrameMemDel(void *pArg){
   pFrame->v->pDelFrame = pFrame;
 }
 
+#if defined(SQLITE_ENABLE_BYTECODE_VTAB) || !defined(SQLITE_OMIT_EXPLAIN)
 /*
 ** Locate the next opcode to be displayed in EXPLAIN or EXPLAIN
 ** QUERY PLAN output.
@@ -2043,6 +2044,7 @@ int sqlite3VdbeNextOpcode(
   *paOp = aOp;
   return rc;
 }
+#endif /* SQLITE_ENABLE_BYTECODE_VTAB || !SQLITE_OMIT_EXPLAIN */
 
 
 /*
@@ -2132,7 +2134,7 @@ int sqlite3VdbeList(
       rc = SQLITE_ERROR;
       sqlite3VdbeError(p, sqlite3ErrStr(p->rc));
     }else{
-      char *zP4 = displayP4(db, pOp);
+      char *zP4 = sqlite3VdbeDisplayP4(db, pOp);
       if( p->explain==2 ){
         sqlite3VdbeMemSetInt64(pMem, pOp->p1);
         sqlite3VdbeMemSetInt64(pMem+1, pOp->p2);
@@ -2150,7 +2152,7 @@ int sqlite3VdbeList(
         sqlite3VdbeMemSetInt64(pMem+6, pOp->p5);
 #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
         {
-          char *zCom = displayComment(db, pOp, zP4);
+          char *zCom = sqlite3VdbeDisplayComment(db, pOp, zP4);
           sqlite3VdbeMemSetStr(pMem+7, zCom, -1, SQLITE_UTF8, sqlite3_free);
         }
 #else
index b2994cb2566688853420156e121b7f7f0248fb44..a886d567879b60cfe7e89a4ad1ace0a9ac97e50b 100644 (file)
 
 /* An instance of the bytecode() table-valued function.
 */
-typedef struct bytecodevtab_vtab bytecodevtab_vtab;
-struct bytecodevtab_vtab {
+typedef struct bytecodevtab bytecodevtab;
+struct bytecodevtab {
   sqlite3_vtab base;     /* Base class - must be first */
-  sqlite3_stmt *pStmt;   /* The statement whose bytecode is to be displayed */
+  sqlite3 *db;           /* Database connection */
 };
 
 /* A cursor for scanning through the bytecode
@@ -30,7 +30,13 @@ struct bytecodevtab_vtab {
 typedef struct bytecodevtab_cursor bytecodevtab_cursor;
 struct bytecodevtab_cursor {
   sqlite3_vtab_cursor base;  /* Base class - must be first */
-  sqlite3_int64 iRowid;      /* The rowid */
+  sqlite3_stmt *pStmt;       /* The statement whose bytecode is displayed */
+  int iRowid;                /* The rowid of the output table */
+  int iAddr;                 /* Address */
+  int needFinalize;          /* Cursors owns pStmt and must finalize it */
+  Op *aOp;                   /* Operand array */
+  char *zP4;                 /* Rendered P4 value */
+  Mem sub;                   /* Subprograms */
 };
 
 /*
@@ -43,7 +49,7 @@ static int bytecodevtabConnect(
   sqlite3_vtab **ppVtab,
   char **pzErr
 ){
-  bytecodevtab_vtab *pNew;
+  bytecodevtab *pNew;
   int rc;
 
   rc = sqlite3_declare_vtab(db,
@@ -65,15 +71,16 @@ static int bytecodevtabConnect(
     *ppVtab = (sqlite3_vtab*)pNew;
     if( pNew==0 ) return SQLITE_NOMEM;
     memset(pNew, 0, sizeof(*pNew));
+    pNew->db = db;
   }
   return rc;
 }
 
 /*
-** This method is the destructor for bytecodevtab_vtab objects.
+** This method is the destructor for bytecodevtab objects.
 */
 static int bytecodevtabDisconnect(sqlite3_vtab *pVtab){
-  bytecodevtab_vtab *p = (bytecodevtab_vtab*)pVtab;
+  bytecodevtab *p = (bytecodevtab*)pVtab;
   sqlite3_free(p);
   return SQLITE_OK;
 }
@@ -82,19 +89,36 @@ static int bytecodevtabDisconnect(sqlite3_vtab *pVtab){
 ** Constructor for a new bytecodevtab_cursor object.
 */
 static int bytecodevtabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
+  bytecodevtab *pVTab = (bytecodevtab*)p;
   bytecodevtab_cursor *pCur;
   pCur = sqlite3_malloc( sizeof(*pCur) );
   if( pCur==0 ) return SQLITE_NOMEM;
   memset(pCur, 0, sizeof(*pCur));
+  sqlite3VdbeMemInit(&pCur->sub, pVTab->db, 1);
   *ppCursor = &pCur->base;
   return SQLITE_OK;
 }
 
+/*
+** Clear all internal content from a bytecodevtab cursor.
+*/
+static void bytecodevtabCursorClear(bytecodevtab_cursor *pCur){
+  sqlite3_free(pCur->zP4);
+  pCur->zP4 = 0;
+  sqlite3VdbeMemSetNull(&pCur->sub);
+  if( pCur->needFinalize ){
+    sqlite3_finalize(pCur->pStmt);
+  }
+  pCur->pStmt = 0;
+  pCur->needFinalize = 0;
+}
+
 /*
 ** Destructor for a bytecodevtab_cursor.
 */
 static int bytecodevtabClose(sqlite3_vtab_cursor *cur){
   bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur;
+  bytecodevtabCursorClear(pCur);
   sqlite3_free(pCur);
   return SQLITE_OK;
 }
@@ -105,10 +129,29 @@ static int bytecodevtabClose(sqlite3_vtab_cursor *cur){
 */
 static int bytecodevtabNext(sqlite3_vtab_cursor *cur){
   bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur;
-  pCur->iRowid++;
+  int rc;
+  if( pCur->zP4 ){
+    sqlite3_free(pCur->zP4);
+    pCur->zP4 = 0;
+  }
+  rc = sqlite3VdbeNextOpcode((Vdbe*)pCur->pStmt, &pCur->sub, 0,
+                             &pCur->iRowid, &pCur->iAddr, &pCur->aOp);
+  if( rc!=SQLITE_OK ){
+    sqlite3VdbeMemSetNull(&pCur->sub);
+    pCur->aOp = 0;
+  }
   return SQLITE_OK;
 }
 
+/*
+** Return TRUE if the cursor has been moved off of the last
+** row of output.
+*/
+static int bytecodevtabEof(sqlite3_vtab_cursor *cur){
+  bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur;
+  return pCur->aOp==0;
+}
+
 /*
 ** Return values of columns for the row at which the bytecodevtab_cursor
 ** is currently pointing.
@@ -119,17 +162,42 @@ static int bytecodevtabColumn(
   int i                       /* Which column to return */
 ){
   bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur;
-#if 0
+  bytecodevtab *pVTab;
+  Op *pOp = pCur->aOp + pCur->iAddr;
   switch( i ){
-    case TEMPLATEVTAB_A:
-      sqlite3_result_int(ctx, 1000 + pCur->iRowid);
+    case 0:
+      sqlite3_result_int(ctx, pCur->iAddr);
+      break;
+    case 1:
+      sqlite3_result_text(ctx, (char*)sqlite3OpcodeName(pOp->opcode),
+                          -1, SQLITE_STATIC);
+      break;
+    case 2:
+      sqlite3_result_int(ctx, pOp->p1);
+      break;
+    case 3:
+      sqlite3_result_int(ctx, pOp->p2);
       break;
-    default:
-      assert( i==TEMPLATEVTAB_B );
-      sqlite3_result_int(ctx, 2000 + pCur->iRowid);
+    case 4:
+      sqlite3_result_int(ctx, pOp->p3);
+      break;
+    case 5:
+    case 7:
+      pVTab = (bytecodevtab*)cur->pVtab;
+      if( pCur->zP4==0 ){
+        pCur->zP4 = sqlite3VdbeDisplayP4(pVTab->db, pOp);
+      }
+      if( i==5 ){
+        sqlite3_result_text(ctx, pCur->zP4, -1, SQLITE_STATIC);
+      }else{
+        char *zCom = sqlite3VdbeDisplayComment(pVTab->db, pOp, pCur->zP4);
+        sqlite3_result_text(ctx, zCom, -1, sqlite3_free);
+      }
+      break;
+    case 6:
+      sqlite3_result_int(ctx, pOp->p5);
       break;
   }
-#endif
   return SQLITE_OK;
 }
 
@@ -144,16 +212,7 @@ static int bytecodevtabRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
 }
 
 /*
-** Return TRUE if the cursor has been moved off of the last
-** row of output.
-*/
-static int bytecodevtabEof(sqlite3_vtab_cursor *cur){
-  bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur;
-  return pCur->iRowid>=10;
-}
-
-/*
-** This method is called to "rewind" the bytecodevtab_cursor object back
+** Initialize a cursor to use a new
 ** to the first row of output.  This method is always called at least
 ** once prior to any call to bytecodevtabColumn() or bytecodevtabRowid() or 
 ** bytecodevtabEof().
@@ -164,23 +223,58 @@ static int bytecodevtabFilter(
   int argc, sqlite3_value **argv
 ){
   bytecodevtab_cursor *pCur = (bytecodevtab_cursor *)pVtabCursor;
-  pCur->iRowid = 1;
-  return SQLITE_OK;
+  bytecodevtab *pVTab = (bytecodevtab *)pVtabCursor->pVtab;
+  int rc = SQLITE_OK;
+
+  bytecodevtabCursorClear(pCur);
+  pCur->iRowid = 0;
+  pCur->iAddr = 0;
+  assert( argc==1 );
+  if( sqlite3_value_type(argv[0])==SQLITE_TEXT ){
+    const char *zSql = (const char*)sqlite3_value_text(argv[0]);
+    if( zSql==0 ){
+      rc = SQLITE_NOMEM;
+    }else{
+      rc = sqlite3_prepare_v2(pVTab->db, zSql, -1, &pCur->pStmt, 0);
+      pCur->needFinalize = 1;
+    }
+  }else{
+    pCur->pStmt = (sqlite3_stmt*)sqlite3_value_pointer(argv[0],"stmt-pointer");
+  }
+  if( pCur->pStmt==0 ){
+    pVTab->base.zErrMsg = sqlite3_mprintf(
+       "argument to bytecode() is not a valid SQL statement"
+    );
+    rc = SQLITE_ERROR;
+  }else{
+    bytecodevtabNext(pVtabCursor);
+  }
+  return rc;
 }
 
 /*
-** SQLite will invoke this method one or more times while planning a query
-** that uses the virtual table.  This routine needs to create
-** a query plan for each invocation and compute an estimated cost for that
-** plan.
+** We must have a single stmt=? constraint that will be passed through
+** into the xFilter method.  If there is no valid stmt=? constraint,
+** then return an SQLITE_CONSTRAINT error.
 */
 static int bytecodevtabBestIndex(
   sqlite3_vtab *tab,
   sqlite3_index_info *pIdxInfo
 ){
-  pIdxInfo->estimatedCost = (double)10;
-  pIdxInfo->estimatedRows = 10;
-  return SQLITE_OK;
+  int i;
+  int rc = SQLITE_CONSTRAINT;
+  pIdxInfo->estimatedCost = (double)100;
+  pIdxInfo->estimatedRows = 100;
+  for(i=0; i<pIdxInfo->nConstraint; i++){
+    if( pIdxInfo->aConstraint[i].usable==0 ) continue;
+    if( pIdxInfo->aConstraint[i].op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
+    if( pIdxInfo->aConstraint[i].iColumn!=9 ) continue;
+    rc = SQLITE_OK;
+    pIdxInfo->aConstraintUsage[i].omit = 1;
+    pIdxInfo->aConstraintUsage[i].argvIndex = 1;
+    break;
+  }
+  return rc;
 }
 
 /*
@@ -217,7 +311,7 @@ static sqlite3_module bytecodevtabModule = {
 
 int sqlite3VdbeBytecodeVtabInit(sqlite3 *db){
   int rc;
-  rc = sqlite3_create_module(db, "bytecodevtab", &bytecodevtabModule, 0);
+  rc = sqlite3_create_module(db, "bytecode", &bytecodevtabModule, 0);
   return rc;
 }
 #endif /* SQLITE_ENABLE_BYTECODE_VTAB */