Sqlite China  
首页 | 各种语言的sqlite编程 | sqlite研究 |sqlite应用实例与杂谈 | sqlite相关下载 | SQlite论坛
当前位置 : 主页>sqlite研究>列表
SQLite数据库的VDBE虚拟机(翻译自sqlite.org)
来源:工友 作者:工友 时间:2007-12-20

本文描述了SQLite 2.8所使用的虚拟机。SQLite 3.0和3.1使用的虚拟机概念上

与此相似,但是许多操作码已变化,算法也有些不同。本文可用作SQLite 3.0所

使用的虚拟机背后思想的大致描述,但不能作为虚拟机如何工作的详细参考。
为了解SQLite库的内部工作原理,需要深入理解虚拟数据库引擎,简称为VDBE。

VDBE在处理流程的中部,涉及到库的各个部分。VDBE是SQLite的核心。
本文简要地介绍了VDBE的工作原理,特别讲述了各种VDBE指令如何组合起来做一

些有用的事情。文章使用教程的风格,从简单到复杂,顺着这种方法,我们将分

析SQLite库的大部分模块。阅读完此教程后,你应该对SQLite是如何工作的有一

个很到的理解,从而可以开始研究实际的源代码了。

$1  预备工作
VDBE实现了一个虚拟的计算机,这个计算机上运行虚拟机的语言。每个程序的目

标是查询或者改变数据库。为了这个目标,VDBE的机器语言特别设计成搜索,读

取和修改数据库。
VDBE语言的每条指令包含一个操作码和三个操作数:P1,P2,P3。操作数P1是任

意整数。P2是一个非负整数。P3是一个指向一数据结构的指针或者一个以null结

尾的字符串或者为空。只有几条VDBE指令用到所有的三个操作数。许多指令仅仅

用一两个操作数。大量的指令没有操作数,而是使用执行栈来获取数据和存储结

果。每条指令的细节描述在另一个文档中。
一个VDBE程序从指令0开始执行,继续执行后继的指令直到:
1. 碰到严重错误
2. 执行Halt指令
3. 升高计数器到程序的最后一条指令。
当一个VDBE程序执行完了后,所有打开的数据库指针都被关闭,所有分配的内存

都会被释放,栈中的每个东西都被弹出。因此不需要担心内存泄漏或未回收的资

源问题。
如果你以前搞过汇编编程或任何种类的抽象机器,你应该很熟悉这些细节,下面

让我们开始看些代码。

$2  Insert操作
 我们从一个能用少数几条VDBE指令解决的问题开始。假定我们有一个按

下列方法创建的表:
CREATE TABLE examp(one text, two int);
 换句话说,我们已有一个名为examp的数据库表,这个表有两列数据,

名字分别为one和two。现在我们插入一条记录到这个表中:
INSERT INTO examp VALUES('Hello, World!',99);
我们可以使用sqlite命令行工具看到VDBE程序,首先使用sqlite在一个空的数据

库中创建表。然后改变sqlite的输出格式:使用.explain命令倒出VDBE程序。最

后,输入上面的INSERT语句,并且前面加上EXPLAIN。EXPLAIN关键字使得sqlite

打印出VDBE程序,但并不执行。如下所示:
$ sqlite test_database_1
sqlite> CREATE TABLE examp(one text, two int);
sqlite> .explain
sqlite> EXPLAIN INSERT INTO examp VALUES('Hello, World!',99);
addr  opcode        p1     p2     p3                                  

  
----  ------------  -----  -----  -----------------------------------
0     Transaction   0      0                                        
1     VerifyCookie  0      81                                       
2     Transaction   1      0                                        
3     Integer       0      0                                        
4     OpenWrite     0      3      examp                             
5     NewRecno      0      0                                        
6     String        0      0      Hello, World!                     
7     Integer       99     0      99                                
8     MakeRecord    2      0                                        
9     PutIntKey     0      1                                        
10    Close         0      0                                        
11    Commit        0      0                                        
12    Halt          0      0
从上面的程序可以看出我们简单的插入语句使用了12条指令来实现。最前面的3

条指令和最后的2条指令总是这个样子不会变化,因此实际的工作是使用七条指

令来完成的。这儿没有跳转,因此程序从上往下执行。下面我们详细分析每条指

令:
0     Transaction   0      0                                        
1     VerifyCookie  0      81                                       
2     Transaction   1      0
 Transaction指令开始一个事务,Commit或Rollback结束一个事务。P1

是事务在其上开始的数据库文件索引。索引0表示主数据库文件。当一个事务开

始时需要获得写锁,这时其它进程既不能读也不能写这个数据库文件了。一个事

务开始时也创建了一个回滚日志。必须在数据库要改变之前开始一个事务。
 VerifyCookie检验数据库模式的版本,使之等于P2,P2是数据库模式最

后一次读中获取的。P1是数据库数字。该指令保证数据库模式没有被另一个线程

所改变,这种情况下就得从新读取数据库模式。
 第二条Transaction指令在数据库1上开始了一个事务和一个回滚日志,

数据库1用于临时表。
3     Integer       0      0                                   
4     OpenWrite     0      3      examp
 Integer指令把P1的值压入堆栈,这里0表示用来读写的数据库号数。如

果P3不是NULL那么,P3所表示的字符串代表同样的整数值。这条指令执行完后,

栈如下所示:
(integer) 0
 OpenWrite指令在P1(这儿为0)上即examp表上打开一个读写指针,

examp表的根页面是P2(这儿为3)。读写指针可以是任何一个非负整数。但是

VDBE使用一个数组来保存指针。为节省内存,最好从0开始,然后向上增长。这

里P3是要打开表的名字,其时这个是没有用的,仅仅是为了增加易读性。该指令

弹出栈中的数据库号数来作为参数,这里是0号数据库,它表示主数据库,因此

指令执行后栈为空。
5     NewRecno      0      0
 NewRecno指令为表指针P1创建一个整数记录号。记录号不是表中的键。

新纪录号被压入堆栈。指令执行后栈中如下所示:
(integer) new record key
6     String        0      0      Hello, World!

 String指令把它的P3操作数压入栈顶。其后栈如下所示:
(string) "Hello, World!"
(integer) new record key
7     Integer       99     0      99
 Integer指令把其P1操作数压入栈顶,其后栈如下所示:
(integer) 99
(string) "Hello, World!"
(integer) new record key
8     MakeRecord    2      0
 MakeRecord指令弹出栈顶的P1个元素,这里是2个,然后把他们转化为

数据库文件用来存储记录的二进制格式,MakeRecord新产生的记录压入栈顶。执

行后栈如下所示:
(record) "Hello, World!", 99
(integer) new record key
9     PutIntKey     0      1
PutIntKey指令用栈顶的两项组成一个数据行,写入P1所指向的表。若其不存在

则创建一个新的数据行,若存在则覆盖它。记录数据是栈顶数据,键是下面的一

项。这条指令使得栈被弹出两次。P2是行改变计数,这个技术不断增加,使用

sqlite_last_insert_rowid()函数可以返回行id。如果P2是0的话行改变计数将

不变,插入操作在这条指令中实际体现。
10    Close         0      0
Close指令以前打开的P1指针,如果P1没有打开则什么也不做。
11    Commit        0      0
 Commit指令使得自从最后的一个Transaction到这儿所有对数据库的修

改生效。知道另一个事务开始,没有别的修改出现。Commit指令删除日志文件,

释放写锁。如果指针还是打开的话,读锁继续保持。
12    Halt          0      0
 Halt指令使得VDBE引擎立即退出。所有打开的指针,列表,排序等等都

统统关闭。P1是sqlite_exec()返回的结果代码。对一个正常的退出,这个结果

码应该是SQLITE_OK (0)。若有错误出现,它将是其它值。当有错误出现是回用

到操作数P2。Halt 0 0 0出现在VDBE运行的每一个程序的结尾。

(阅读次数:
上一篇:基于SQLite的Object Persistent 下一篇:关于SQLite数据库的远程维护
[收藏] [推荐] [评论(0条)] [返回顶部] [打印本页] [关闭窗口]
用户名: 新注册) 密码: 匿名评论
评论内容:(不能超过250字,需审核后才会公布,请自觉遵守互联网相关政策法规。
§最新评论
热点文章
·SQLite数据库的体系结构
·SQLite与其他数据库的速度
·SQL 语言参考资料
·SQLite语法备忘录
·sqlite 的相关调查1
·嵌入式数据库SQLite的一份
·SQLite在嵌入式Web服务器
·点评主流开源数据库的技术
·基于ARM-Linux的SQLite嵌
·SQLite与其他数据库的速度
·SQLite数据库编程--创建数
·SQL 语法手册
·SQLite Mode 数据库交互的
·SQLITE3 使用总结(3)
·XXTEA加密算法为SQLite 3.
·SQLite 第三版总览(简介)
·SQLite 第三版中的数据类
·用sqlite 执行标准 sql 语
·System.Data.Sqlite 上手
·SQLite编译安装步骤
相关文章
·SQLite Mode 数据库交互的
·SQL 语言参考资料
·SQLite在嵌入式Web服务器
·SQL 语法手册
·System.Data.Sqlite 上手
·SQLite数据库编程--创建数
·SQLite数据库编程--数据库
·SQLite在TorqueScript中的
·关于sqlite_exec回调函数
·用sqlite 执行标准 sql 语

版权Power by DedeCms   后台登陆
Copyright @ 2007