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;

  Cursor *pC = 0;
  char *zRec;

  BtCursor *pCrsr;
  u32 *aType;
  u32 *aOffset;

  u32 nField;
  int len;
  int i;
  char *zData;
  Mem sMem;

  sMem.flags = 0;
  assert( p1<p->nCursor );

  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{

      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( p2<nField );

  if( pC && pC->cacheStatus==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 ){

      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 );

    szHdrSz = GetVarint((u8*)zData, offset);

    if( !zRec && avail<offset ){
      rc = sqlite3VdbeMemFromBtree(pCrsr, 0, offset, pC->isIndex, &sMem);
      if( rc!=SQLITE_OK ){
        goto op_column_out;
      }
      zData = sMem.z;
    }

    zEndHdr = (u8 *)&zData[offset];

    zIdx = (u8 *)&zData[szHdrSz];

    for(i=0; i<nField; i++){
      if( zIdx<zEndHdr ){

        aOffset[i] = offset;

        zIdx += GetVarint(zIdx, aType[i]);

        offset += sqlite3VdbeSerialTypeLen(aType[i]);
      }else{

        aOffset[i] = 0;
      }
    }
    Release(&sMem);
    sMem.flags = MEM_Null;

    if( zIdx>zEndHdr || offset>payloadSize ){
      rc = SQLITE_CORRUPT_BKPT;
      goto op_column_out;
    }
  }

  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;
    }

    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->p1<p->nCursor );
  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 );

      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; pMem<pFirstColumn; pMem++){
    Deephemeralize(pMem);
  }

  p->cacheCtr = (p->cacheCtr + 2)|1;

  for(; pMempTos; pMem++ ){
    sqlite3VdbeMemNulTerminate(pMem);

    storeTypeInfo(pMem, encoding);
  }

  p->resOnStack = 1;
  p->nCallback++;

  p->popStack = pOp->p1;

  p->pc = pc + 1;

  p->pTos = pTos;
  return SQLITE_ROW;
}

Original: https://blog.csdn.net/qq_45936073/article/details/121543734
Author: 神明不自知
Title: 2021SC@SDUSC SQLite源码分析(八)————SQLite虚拟机指令集

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/817518/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球