SQLite学习笔记(14)-虚拟机

来源:互联网 发布:sybase数据网站 编辑:程序博客网 时间:2024/04/28 20:01

虚拟机(Virtual Machine)

VDBE是SQLite的核心,它的上层模块和下层模块都是本质上都是为它服务的。它的实现位于vbde.c, vdbe.h, vdbeapi.c, vdbeInt.h, 和vdbemem.c等几个文件中。它通过底层的基础设施B-Tree执行由编译器(Compiler)生成的字节代码,这种字节代码程序语言 (bytecode programming lauguage)是为了进行查询、读取和修改数据库而专门设计的。

字节代码在内存中被封装成sqlit_stmt对象(内部叫做Vdbe),Vdbe(或者说statement)包含执行程序所需要的一切:

a)    a bytecode program

b)    names and data types for all result columns

c)    values bound to input parameters

d)    a program counter

e)    an execution stack of operands

f)    an arbitrary amount of "numbered"memory cells

g)    other run-time state information (such asopen BTree objects, sorters, lists, sets)

其代码位于vdbeInt.h,如下所示:

struct Vdbe {  sqlite3 *db;            /* The database connection that owns this statement */  Op *aOp;                /* Space to hold the virtual machine's program */  Mem *aMem;              /* The memory locations */  Mem **apArg;            /* Arguments to currently executing user function */  Mem *aColName;          /* Column names to return */  Mem *pResultSet;        /* Pointer to an array of results */  Parse *pParse;          /* Parsing context used to create this Vdbe */  int nMem;               /* Number of memory locations currently allocated */  int nOp;                /* Number of instructions in the program */  int nCursor;            /* Number of slots in apCsr[] */  u32 magic;              /* Magic number for sanity checking */  char *zErrMsg;          /* Error message written here */  Vdbe *pPrev,*pNext;     /* Linked list of VDBEs with the same Vdbe.db */  VdbeCursor **apCsr;     /* One element of this array for each open cursor */  Mem *aVar;              /* Values for the OP_Variable opcode. */  char **azVar;           /* Name of variables */  ynVar nVar;             /* Number of entries in aVar[] */  ynVar nzVar;            /* Number of entries in azVar[] */  u32 cacheCtr;           /* VdbeCursor row cache generation counter */  int pc;                 /* The program counter */  int rc;                 /* Value to return */……};

字节代码和汇编程序十分类似,每一条指令由操作码和五个操作数构成:P1, P2 P3, P4, 和P5。Opcode为一定功能的操作码,为了理解,可以看成一个函数。P1、P2和P3都是32位有符号整数,P2通常是跳转指令的目标地址。P4是以联合体的形式进行定义,有时是32位有符号整数,有时是64有符号整数等等。P5是一个8位无符号整数,一般用来做标识。有的程序可以使用五个操作数,而有的程序一个都不用。和C API不同的是,VDBE操作码经常变化,所以不应该用字节码写程序。其代码如下所示:

struct VdbeOp {  u8 opcode;          /* What operation to perform */  signed char p4type; /* One of the P4_xxx constants for p4 */  u8 opflags;         /* Mask of the OPFLG_* flags in opcodes.h */  u8 p5;              /* Fifth parameter is an unsigned character */  int p1;             /* First operand */  int p2;             /* Second parameter (often the jump destination) */  int p3;             /* The third parameter */  union p4union {     /* fourth parameter */    int i;                 /* Integer value if p4type==P4_INT32 */    void *p;               /* Generic pointer */    char *z;               /* Pointer to data for string (char array) types */    i64 *pI64;             /* Used when p4type is P4_INT64 */    double *pReal;         /* Used when p4type is P4_REAL */    FuncDef *pFunc;        /* Used when p4type is P4_FUNCDEF */    sqlite3_context *pCtx; /* Used when p4type is P4_FUNCCTX */    CollSeq *pColl;        /* Used when p4type is P4_COLLSEQ */    Mem *pMem;             /* Used when p4type is P4_MEM */    VTable *pVtab;         /* Used when p4type is P4_VTAB */    KeyInfo *pKeyInfo;     /* Used when p4type is P4_KEYINFO */    int *ai;               /* Used when p4type is P4_INTARRAY */    SubProgram *pProgram;  /* Used when p4type is P4_SUBPROGRAM */    int (*xAdvance)(BtCursor *, int *);  } p4;#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS  char *zComment;          /* Comment to improve readability */#endif#ifdef VDBE_PROFILE  u32 cnt;                 /* Number of times this instruction was executed */  u64 cycles;              /* Total time spent executing this instruction */#endif#ifdef SQLITE_VDBE_COVERAGE  int iSrcLine;            /* Source-code line that generated this opcode */#endif};

下面看一个具体的字节码程序:

sqlite> CREATE TABLE examp(one text, two int);sqlite> .explainsqlite> EXPLAIN INSERT INTO examp VALUES('Hello, World!',99);addr  opcode         p1    p2    p3    p4             p5  comment----  -------------  ----  ----  ----  -------------  --  -------------0     Init           0     8     0                    001     OpenWrite      0     2     0     2              002     NewRowid       0     1     0                    003     String8        0     2     0     Hello, World!  004     Integer        99    3     0                    005     MakeRecord     2     2     4     BD             006     Insert         0     4     1     examp          1b7     Halt           0     0     0                    008     Transaction    0     1     5     0              019     TableLock      0     2     1     examp          0010    Goto           0     1     0                    00

表2.1列出了部分操作码及其操作内容.

表2.1 部分操作码及其含义



操作码名称

说明

Add

Add the value in register P1 to the value in register P2 and store the result in register P3. If either input is NULL, the result is NULL.

AddImm

Add the constant P2 to the value in register P1. The result is always an integer.

To force any register to be an integer, just add 0.

Affinity

Apply affinities to a range of P2 registers starting with P1.

P4 is a string that is P2 characters long. The nth character of the string indicates the column affinity that should be used for the nth memory cell in the range.

AggFinal

Execute the finalizer function for an aggregate. P1 is the memory location that is the accumulator for the aggregate.

P2 is the number of arguments that the step function takes and P4 is a pointer to the FuncDef for this function. The P2 argument is not used by this opcode. It is only there to disambiguate functions that can take varying numbers of arguments. The P4 argument is only needed for the degenerate case where the step function was not previously called.

And

Take the logical AND of the values in registers P1 and P2 and write the result into register P3.

If either P1 or P2 is 0 (false) then the result is 0 even if the other input is NULL. A NULL and true or two NULLs give a NULL output.




0 0
原创粉丝点击