2021SC@SDUSC SQLite源码分析(七)————VDBE结构分析
2021SC@SDUSC SQLite源码分析(七)————VDBE结构分析一、vdbeInt.h1.结构概览2.虚拟机框架对象二、解释引擎VDBE是SQLite的核心。用户程序发出的SQL语句请求,由前端编译器处理,生成字节代码程序,然后由VM解释执行。VM执行时,又会调用B-tree模块的相关的接口,并输出执行的结果。一、vdbeInt.h是vdbe.c的私有头文件,定义了VDBE的常用数据结
2021SC@SDUSC SQLite源码分析(七)————VDBE结构分析
VDBE是SQLite的核心。用户程序发出的SQL语句请求,由前端编译器处理,生成字节代码程序,然后由VM解释执行。VM执行时,又会调用B-tree模块的相关的接口,并输出执行的结果。
一、vdbeInt.h
是vdbe.c的私有头文件,定义了VDBE的常用数据结构。
主要包含一些结构体和方法的声明或者预定义
1.结构概览
struct VdbeCursor(vdbe游标)
struct VdbeFrame(vdbe框架)
struct Mem(仅对vdbe可见的数据结构)
struct VdbeFunc(辅助数据)
struct sqlite3_context(上下文和返回值等信息)
struct Explain(vdbe的信息)
struct Vdbe(vdbe整体结构)
定义了一个虚拟机的实体。这个结构体包含了虚拟机完整的状态。 sqlite3_stmt这个结构的指针由sqlite3_prepare()方法返回,它是这个结构实体的一个真实指针。
struct VdbeCursor
{
…
int iDb (检索数据库)
Bool isTable; (查看表是否存在)
Bool rowidIsValid(某一行的数据是否有效)
i64 lastRowid
int seekResult(查询结构)
…
}(树形结构,数据库页为子节点)
游标,是一个数据库文件中单一BTree的指示器。
游标能够找到拥有特定值的一个BTree的入口,或者遍历BTree的所有入口。你能够从新的BTree入口或者从这个指针通常指向的的入口检索值或者数据。每一个虚拟机已经开启的指针都代表着一个一下结构的常量。
2.虚拟机框架对象
typedef struct VdbeFrame VdbeFrame;
struct VdbeFrame {
Vdbe *v; /* VM this frame belongs to */
VdbeFrame *pParent; /* Parent of this frame, or NULL if parent is main */
Op *aOp; /* Program instructions for parent frame */
i64 *anExec; /* Event counters from parent frame */
Mem *aMem; /* Array of memory cells for parent frame */
VdbeCursor **apCsr; /* Array of Vdbe cursors for parent frame */
u8 *aOnce; /* Bitmask used by OP_Once */
void *token; /* Copy of SubProgram.token */
i64 lastRowid; /* Last insert rowid (sqlite3.lastRowid) */
AuxData *pAuxData; /* Linked list of auxdata allocations */
#if SQLITE_DEBUG
u32 iFrameMagic; /* magic number for sanity checking */
#endif
int nCursor; /* Number of entries in apCsr */
int pc; /* Program Counter in parent (calling) frame */
int nOp; /* Size of aOp array */
int nMem; /* Number of entries in aMem */
int nChildMem; /* Number of memory cells for child frame */
int nChildCsr; /* Number of cursors for child frame */
int nChange; /* Statement changes (Vdbe.nChange) */
int nDbChange; /* Value of db->nChange */
};
一个虚拟机框架对象的内存由父框架的一个存储单元中被分配和管理。当内存单元被删除或者重写,虚拟机框架对象不会被立即释放。
当虚拟机在中重启后,Vdbe.pDelFrame的目录清单被删除。这么做而不是立刻删除虚拟机框架对象是为了避免当属于子框架的存储单元被释放时循环调用sqlite3VdbeMemRelease()方法。
二、解释引擎
经过编译器生成的vdbe最终都是由 解释引擎 解释执行的,SQLite的解释引擎实现的原理非常简单,本质上就是一个包含大量case语句的for循环
删减后代码如下 (位于vdbe.c中):
/*
Execute as much of a VDBE program as we can.
This is the core of sqlite3_step().
执行VDBE程序.当从数据库中取出一行数据时,该函数会调用回调函数(如果有的话),或者返回SQLITE_ROW.
*/
int sqlite3VdbeExec(
Vdbe *p /* The VDBE */
){
//指令计数器
int pc; /* The program counter */
//当前指令
Op *pOp; /* Current operation */
int rc = SQLITE_OK; /* Value to return */
//数据库
sqlite3 *db = p->db; /* The database */
u8 encoding = ENC(db); /* The database encoding */
//栈顶
Mem *pTos; /* Top entry in the operand stack */
if( p->magic!=VDBE_MAGIC_RUN ) return SQLITE_MISUSE;
//当前栈顶指针
pTos = p->pTos;
if( p->rc==SQLITE_NOMEM ){
/* This happens if a malloc() inside a call to sqlite3_column_text() or
** sqlite3_column_text16() failed. */
goto no_mem;
}
p->rc = SQLITE_OK;
//如果需要进行出栈操作,则进行出栈操作
if( p->popStack ){
popStack(&pTos, p->popStack);
p->popStack = 0;
}
//表明栈中没有结果
p->resOnStack = 0;
db->busyHandler.nBusy = 0;
//执行指令
for(pc=p->pc; rc==SQLITE_OK; pc++){
//取出操作码
pOp = &p->aOp[pc];
switch( pOp->opcode ){
//跳到操作数P2指向的指令
case OP_Goto: { /* no-push */
CHECK_FOR_INTERRUPT;
//设置pc
pc = pOp->p2 - 1;
break;
}
//P1入栈
case OP_Integer: {
//当前栈顶指针上移
pTos++;
//设为整型
pTos->flags = MEM_Int;
//取操作数P1,并赋值
pTos->i = pOp->p1;
break;
}
//其它指令的实现
}//end switch
}//end for
}
参考资料:《inside SQLite》
更多推荐
所有评论(0)