2021SC@SDUSC
这里写目录标题
VDBE核心
vdbe.c文件中存放着VDBE的执行方法(sqlite3VdbeExec),这是VDBE的核心,也是SQLite的核心,SQL解析器生成一个程序然后由VDBE执行SQL语句的工作。 下面是sqlite3VdbeExec函数的说明:
int sqlite3VdbeExec( Vdbe *p) {
/* The VDBE */
int pc=0; /* 程序计数器 */
Op *aOp = p->aOp; /* p->aOp的复本 */
Op *pOp; /* 当前操作码 */
int rc = SQLITE_OK; /* 函数返回值 */
sqlite3 *db = p->db; /* 数据库 */
Mem *aMem = p->aMem; /* p->aMem的复本 */
Mem *pIn1 = 0; /* 第一次输入的参数 */
Mem *pIn2 = 0; /* 第二次输入的参数 */
Mem *pIn3 = 0; /* 第三次输入的参数 */
Mem *pOut = 0; /* 输出的参数*/
int iCompare = 0; /*存放操作码OP_Compare的操作结果*/
int *aPermute = 0; /*操作码OP_Compare使用的数组。*/
sqlite3VdbeEnter(p); /*初始化虚拟机程序p的环境*/
p->rc = SQLITE_OK;
p->pResultSet = 0;
db->busyHandler.nBusy = 0;
CHECK_FOR_INTERRUPT;
sqlite3VdbeIOTraceSql(p);
for(pc=p->pc; rc==SQLITE_OK; pc++){
pOp = &aOp[pc];
if( pOp->opflags & OPFLG_OUT2_PRERELEASE ){
assert( pOp->p2>0 );
assert( pOp->p2<=p->nMem );
pOut = &aMem[pOp->p2];
memAboutToChange(p, pOut);
VdbeMemRelease(pOut);
pOut->flags = MEM_Int;
}
switch( pOp->opcode ){
//switch语句,每一个case都是在VDBE里执行一个单独的指令,一共155个。
……
}
}
VDBE程序在形式上类似于汇编语言。VDBC程序由一系列线性操作组成,每个操作都有1个操作码和5个操作数,操作数P1,P2,P3是整数,操作数P4是一个以null结尾的字符串,操作数P5是一个无符号字符。sqlite3VdbeExec函数用于解析VDBE程序指令,但 是要建立一个程序指令还需要其它文件里的函数的帮助和支撑。
main函数
int main()
{
sqlite3 *db = NULL;
int result;
result = sqlite3_open("test.db", &db);
if (SQLITE_OK != result)
{
printf("Create/Open test.db error! \n");
}
printf("Create/Open test.db success!! \n");
const char *sqlStr1 = "create table table2(sid integer primary key not null,age string);";
result = sqlite3_exec(db, sqlStr1, 0, 0, 0);
if (SQLITE_OK != result)
{
printf("create table table1 error! \n");
return 0;
}
printf("create table table1 success! \n");
const char* sqlStr2 = "insert into table1() values(1,'name1');";
result = sqlite3_exec(db, sqlStr2, 0, 0, 0);
if (SQLITE_OK != result)
{
printf("insert table table1 error! \n");
return 0;
}
printf("insert table table1 success! \n");
sqlite3_close(db);
return 0;
}
在代码中我们可以看到几个重要的API函数的调用(sqlite3_open、sqlite3_exec、sqlite3_close),sqlite3_exec函数执行我们输入的SQL语句,这些语句包括表的创建和表数据的增删查改。
OP_Init
case OP_Init: {
/* jump */
if( pOp->p2 ){
pc = pOp->p2 - 1;
}
}
OP_Init操作符是根据p2的值去确定下一个操作符,这里p2=32,所以pc=31,经过for循环后,pc=32。那么下一个要执行的操作符是aOp[32]及OP_Transaction。
OP_Transaction
case OP_Transaction: {
Btree* pBt = db->aDb[pOp->p1].pBt;
sqlite3BtreeBeginTrans(pBt, pOp->p2){
sqlite3BtreeEnter(p);
sqlite3PagerBegin();
newDatabase(pBt);
sqlite3PagerOpenSavepoint(pBt->pPager, p->db->nSavepoint);
}
}
OP_Transaction操作符的作用就是开始执行一个事务sqlite3BtreeBeginTrans根据p2的值确定是读或写,进入sqlite3BtreeBeginTrans函数后,先是通过sqlite3BtreeEnter函数在后端级别上(Btree和Pager)给当前操作加锁,然后通过sqlite3PagerBegin函数对内存进行操作,实现对内存中的数据库的操作。
OP_TableLock
case OP_TableLock: {
u8 isWriteLock = (u8)pOp->p3;
sqlite3BtreeLockTable(db->aDb[p1].pBt,pOp->p2,isWriteLock){
if( p->sharable ){
//db->aDb[p1].pBt->sharable为0
sqlite3BtreeEnter(p);
……
}
}
}
OP_TableLock操作符功能就是在共享缓存的前提下给我们要创建的表加写锁。