From: drh Date: Mon, 23 Mar 2020 20:58:55 +0000 (+0000) Subject: The bytecode() function now runs and sometimes works, but it untested and X-Git-Tag: version-3.32.0~50^2~15 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=8c5163a697789879f46d6b5db9a99d08d6ccb343;p=thirdparty%2Fsqlite.git The bytecode() function now runs and sometimes works, but it untested and there are known problems. FossilOrigin-Name: 6819b86eb2de516c445655a83f9b2ba5ae0bff660cffaf84f1345d9be79b051e --- diff --git a/manifest b/manifest index 6e2287c698..1dc7d4ebec 100644 --- 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 diff --git a/manifest.uuid b/manifest.uuid index 1432c3fd8f..6544abac45 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -aee1c12f4227cea9e8c6295cee3ec11797422c31b48c9468f176eb52f8261fe8 \ No newline at end of file +6819b86eb2de516c445655a83f9b2ba5ae0bff660cffaf84f1345d9be79b051e \ No newline at end of file diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 9aa10d89bf..a9465cc0ac 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -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); diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 37ec1aabbd..6c6eb8ec5f 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -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 diff --git a/src/vdbevtab.c b/src/vdbevtab.c index b2994cb256..a886d56787 100644 --- a/src/vdbevtab.c +++ b/src/vdbevtab.c @@ -19,10 +19,10 @@ /* 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; inConstraint; 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 */