mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-08 14:02:16 +03:00
The bytecode() function now runs and sometimes works, but it untested and
there are known problems. FossilOrigin-Name: 6819b86eb2de516c445655a83f9b2ba5ae0bff660cffaf84f1345d9be79b051e
This commit is contained in:
164
src/vdbevtab.c
164
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;
|
||||
default:
|
||||
assert( i==TEMPLATEVTAB_B );
|
||||
sqlite3_result_int(ctx, 2000 + pCur->iRowid);
|
||||
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;
|
||||
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 */
|
||||
|
Reference in New Issue
Block a user