SQLite源代码分析----------代码生成器②

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操作符功能就是在共享缓存的前提下给我们要创建的表加写锁。

附录:

vdbe.c

おすすめ

転載: blog.csdn.net/wy_csdn_sdu/article/details/121733301