栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

2021SC@SDUSC SQLite源码分析(八)————SQLite虚拟机指令集

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

2021SC@SDUSC SQLite源码分析(八)————SQLite虚拟机指令集

2021SC@SDUSC SQLite源码分析(八)————SQLite虚拟机指令集

为了执行一个SQL语句,SQLite库首先解析SQL,分析该语句,然后生成简短的程序来执行该语句。产生的程序将由SQLite库实现的虚拟机来执行。虚拟机的源代码是vdbe.c文件。所有操作码的定义都包含在源文件注释中,下面是几个操作码指令实例分析

一、OP_Column

解析当前游标指定的记录的数据
p1为当前游标索引号,p2为列号

case OP_Column: {
  u32 payloadSize;   
  int p1 = pOp->p1;  
  //列号
  int p2 = pOp->p2;  
  //VDBE游标
  Cursor *pC = 0;    
  char *zRec;        
  //btree游标
  BtCursor *pCrsr;   
  u32 *aType;        
  u32 *aOffset;      
  //列数
  u32 nField;        
  int len;           
  int i;             
  char *zData;       
  Mem sMem;          

  sMem.flags = 0;
  assert( p1nCursor );
  //栈顶指针上移
  pTos++;
  pTos->flags = MEM_Null;

  
  //设置游标
  pC = p->apCsr[p1];
  
  assert( pC!=0 );
  if( pC->pCursor!=0 ){
    
    //移到当前游标
    rc = sqlite3VdbeCursorMoveto(pC);
    if( rc ) goto abort_due_to_error;
    zRec = 0;
    pCrsr = pC->pCursor;
    if( pC->nullRow ){
      payloadSize = 0;
    }else if( pC->cacheStatus==p->cacheCtr ){
      payloadSize = pC->payloadSize;
      zRec = (char*)pC->aRow;
    }else if( pC->isIndex ){
      i64 payloadSize64;
      sqlite3BtreeKeySize(pCrsr, &payloadSize64);
      payloadSize = payloadSize64;
    }else{
      //解析数据,payloadSize保存cell的数据字节数
      sqlite3BtreeDataSize(pCrsr, &payloadSize);
    }
    nField = pC->nField;
  }else if( pC->pseudoTable ){
    
    payloadSize = pC->nData;
    zRec = pC->pData;
    pC->cacheStatus = CACHE_STALE;
    assert( payloadSize==0 || zRec!=0 );
    nField = pC->nField;
    pCrsr = 0;
  }else{
    zRec = 0;
    payloadSize = 0;
    pCrsr = 0;
    nField = 0;
  }

  
  if( payloadSize==0 ){
    assert( pTos->flags==MEM_Null );
    break;
  }

  assert( p2cacheStatus==p->cacheCtr ){
    aType = pC->aType;
    aOffset = pC->aOffset;
  }else{
    u8 *zIdx;        
    u8 *zEndHdr;     
    u32 offset;      
    int szHdrSz;     
    int avail;       
    
    //数据类型数组
    aType = pC->aType;
    if( aType==0 ){
      //每个数据类型分配8字节---sizeof(aType)==4
      pC->aType = aType = sqliteMallocRaw( 2*nField*sizeof(aType) );
    }
    if( aType==0 ){
      goto no_mem;
    }
    //每列数据的偏移
    pC->aOffset = aOffset = &aType[nField];
    pC->payloadSize = payloadSize;
    pC->cacheStatus = p->cacheCtr;

    
    if( zRec ){
      zData = zRec;
    }else{
      if( pC->isIndex ){
        zData = (char*)sqlite3BtreeKeyFetch(pCrsr, &avail);
      }else{
        //获取数据
        zData = (char*)sqlite3BtreeDataFetch(pCrsr, &avail);
      }
      
      if( avail>=payloadSize ){
        zRec = zData;
        pC->aRow = (u8*)zData;
      }else{
        pC->aRow = 0;
      }
    }
    assert( zRec!=0 || avail>=payloadSize || avail>=9 );
    //获得header size
    szHdrSz = GetVarint((u8*)zData, offset);

    
    if( !zRec && availisIndex, &sMem);
      if( rc!=SQLITE_OK ){
        goto op_column_out;
      }
      zData = sMem.z;
    }

    //header之后的数据,对于上例为:63 61 74 01
    zEndHdr = (u8 *)&zData[offset];
    //header数据的索引号,对于上例为:00 13 01
    zIdx = (u8 *)&zData[szHdrSz];

    
    
    for(i=0; izEndHdr || offset>payloadSize ){
      rc = SQLITE_CORRUPT_BKPT;
      goto op_column_out;
    }
  }

  
  //获取P2指定的列的数据
  if( aOffset[p2] ){
    assert( rc==SQLITE_OK );
    if( zRec ){
      //取得该列的数据
      zData = &zRec[aOffset[p2]];
    }else{
      len = sqlite3VdbeSerialTypeLen(aType[p2]);
      rc = sqlite3VdbeMemFromBtree(pCrsr, aOffset[p2], len, pC->isIndex,&sMem);
      if( rc!=SQLITE_OK ){
        goto op_column_out;
      }
      zData = sMem.z;
    }
    //解析zData,并将结果保存在pTos中
    sqlite3VdbeSerialGet((u8*)zData, aType[p2], pTos);
    pTos->enc = encoding;
  }else{
    if( pOp->p3type==P3_MEM ){
      sqlite3VdbeMemShallowCopy(pTos, (Mem *)(pOp->p3), MEM_Static);
    }else{
      pTos->flags = MEM_Null;
    }
  }

  
  if( (sMem.flags & MEM_Dyn)!=0 ){
    assert( pTos->flags & MEM_Ephem );
    assert( pTos->flags & (MEM_Str|MEM_Blob) );
    assert( pTos->z==sMem.z );
    assert( sMem.flags & MEM_Term );
    pTos->flags &= ~MEM_Ephem;
    pTos->flags |= MEM_Dyn|MEM_Term;
  }

  
  rc = sqlite3VdbeMemMakeWriteable(pTos);

op_column_out:
  break;
}

二、OP_Next

移动游标使它指向表的下一个记录

case OP_Next: {        
  Cursor *pC;
  BtCursor *pCrsr;

  CHECK_FOR_INTERRUPT;
  assert( pOp->p1>=0 && pOp->p1nCursor );
  pC = p->apCsr[pOp->p1];
  assert( pC!=0 );
  if( (pCrsr = pC->pCursor)!=0 ){
    int res;
    if( pC->nullRow ){
      res = 1;
    }else{
      assert( pC->deferredMoveto==0 );
      //调用B-tree模块,移动游标指向下一条记录
      rc = pOp->opcode==OP_Next ? sqlite3BtreeNext(pCrsr, &res) :
                                  sqlite3BtreePrevious(pCrsr, &res);
      pC->nullRow = res;
      pC->cacheStatus = CACHE_STALE;
    }
    if( res==0 ){
      pc = pOp->p2 - 1;
      sqlite3_search_count++;
    }
  }else{
    pC->nullRow = 1;
  }
  pC->rowidIsValid = 0;
  break;
}
三、OP_Callback

该指令执行后,PC将指向下一条指令.
栈中栈顶的P1个值为查询的结果.该指令会导致sqlite3_step()函数将以SQLITE_ROW为返回码
而结束运行.此时用户程序就可以通过sqlite3_column_XXX读取位于栈中的数据了.
当sqlite3_step()再一次运行时,栈顶的P1个值会在执行Next指令前自动出栈.

case OP_Callback: {            
  Mem *pMem;
  Mem *pFirstColumn;
  assert( p->nResColumn==pOp->p1 );

  
  pFirstColumn = &pTos[0-pOp->p1];
  for(pMem = p->aStack; pMemcacheCtr = (p->cacheCtr + 2)|1;

  
  for(; pMem<=pTos; pMem++ ){
    sqlite3VdbeMemNulTerminate(pMem);
    //设置结果集中的数据类型
    storeTypeInfo(pMem, encoding);
  }

  
  p->resonStack = 1; //栈上有结果
  p->nCallback++;  //回调次数加1
  //出栈的数据个数,在下次执行VDBE时,会先进行出栈操作
  p->popStack = pOp->p1;
  //程序计数器加1
  p->pc = pc + 1;
  
  //设置vdbe的栈顶指针,此时,栈中保存有结果
  p->pTos = pTos;
  return SQLITE_ROW;
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/603678.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号