SQLite 中 C/C++ 接口介绍

jopen 10年前

这篇文章简要的介绍了 SQLite 的 C/C++ 接口。

早期版本的 SQLite 很好学是因为他们只提供了 5 个 C/C++ 的接口。但是随着 SQLite 功能的增加,新的 C/C++ 接口加入,现在已经有超过 200 个不同的 API 了。这对新人可能是一种阻碍。幸运的是,大部分的 C/C++ 接口都是有特殊用途的,不需要了解。尽管有这么多的入口点,核心的 API 还是相当的简单而且容易使用。这篇文章旨在提供所有能使读者容易理解 SQLite 如何工作的背景信息。

一个独立的接口文档提供了 SQLite 不同的 C/C++ 接口的详细说明。一旦读者理解了操作 SQLite 的基本概念,该文档就可以成为参考手册了。这篇文章只是一个介绍,不会是 SQLite 的完整、权威的参考手册。

1.0 核心对象和接口

SQL 数据库引擎的核心任务是计算 SQL 语句的值(evaluate statements of SQL)。为了完成这个目的,开发者需要了解两个对象:

数据库连接对象(The database connection object):sqlite3
预处理好的语句对象(The prepared statement object): sqlite3_stmt

严格来讲,对于一些封装好的便捷接口 prepared statement object不是必须的,比如sqlite3_exec 还有 sqlite3_get_table, 在内部求值时都会封装并隐藏这些 prepared statement object。然而,要想充分利用 SQLite, 理解 prepared statements 还是有必要的。

Database connection 和 prepared statement 对象由下面列出的一组 C/C++ 接口(interface routine)控制。

sqlite3_open()    sqlite3_prepare()    sqlite3_step()    sqlite3_column()    sqlite3_finalize()    sqlite3_close()

上面列出的 6 个 C/C++ 接口还有两个对象组成了 SQLite 的核心功能。理解了这些的开发者在使用 SQLite 时就会很容易了。

注意上面列出的这些接口只是一类接口而不是实际的接口。这些接口都有许多不同的版本。比如,上面列出的一个叫做 sqlite3_open() 的接口,事实上是由 3 个完全不同的接口组成的:sqlite3_open()sqlite3_open16() 还有 sqlite3_open_v2()。上面列表中提到的sqlite3_column() 实际上并不存在。列表中提到的 “sqlite3_column()” 实际上是由一簇为了获取不同列类型的接口组成。

下面是核心接口的简要介绍:

sqlite3_open()    这个接口打开一个到 SQLite 数据库文件的链接并返回一个数据库连接对象。这通常是应用程序调用的第一个 SQLite 的 API,并且也是其他大部分的 SQLite API 所需要的。大部分的 SQLite 接口需要一个指向 database connection object 的指针作为第一个参数,可以认为是数据库连接对象上的方法。这个接口是数据库连接对象的构造器。

sqlite3_prepare()    这个接口将 SQL 语句转换为一个 prepared statement 对象并返回指向这个对象的指针。这个接口需要之前使用 sqlite3_open() 返回的数据库连接对象,还有一个包含 SQL 语句的文本字符串作为参数。这个 API 实际上并不执行 SQL 语句。它仅仅只是准备用于执行的 SQL 语句。把每个 SQL 语句想象成一个小型的计算机程序。sqlite3_prepare() 是为了把那个程序编译成对象代码(object code)。Prepared statement 就是这个对象代码。之后 sqlite3_step() 运行这个对象代码获取结果。

注意对于新的程序已经不推荐使用 sqlite3_prepare()。新的应用推荐使用sqlite3_prepare_v2() 接口。

sqlite3_step()     这个接口用于执行之前用 sqlite3_prepare() 创建的 prepared statement。这个接口只返回结果集的第一条结果。为了获取第二条结果,再调用一次sqlite3_step()。继续调用 sqlite3_step() 直到语句结束。不返回结果的语句(比如:INSERT, UPDATE, 或者 DELETE 语句)调用一次 sqlite3_step() 就行了。

sqlite3_column()    这个接口返回使用 sqlite3_step() 查询的 prepared statement 的结果集中当前行的某一列。每次调用完 sqlite3_step() 都会产生一个新的 result set row。这个接口可以被调用多次用于获取一行中的不同列。正如上面所提到的,事实上在 SQLite 的 API 中并没有 “sqlite3_column()” 这个函数。相反的,我们这里调用的 “sqlite3_column()” 是为了获取某列中不同类型值的一簇的接口占位符(a place-holder for an entire family of functions)。这类接口中有返回结果大小(如果是字符串或者 BLOB,译注:Binary Large OBject)还有结果集中列数的接口。

sqlite3_column_blob()    sqlite3_column_bytes()    sqlite3_column_bytes16()    sqlite3_column_count()    sqlite3_column_double()    sqlite3_column_int()    sqlite3_column_int64()    sqlite3_column_text()    sqlite3_column_text16()    sqlite3_column_type()    sqlite3_column_value()

sqlite3_finalize()    这个接口销毁之前由 sqlite3_prepare() 创建的 prepared statement。为了避免内存泄露,必须这个接口销毁之前创建的 prepared statement。

sqlite3_close()    这个接口关闭之前由调用 sqlite3_open() 创建的数据库连接。在关闭数据库连接前所有与之关联的 prepared statements 都应该已经被销毁了。

1.1 核心接口和对象的使用方法

一个想要使用 SQLite 的应用程序通常在初始化时使用 sqlite3_open() 创建一个数据库连接。注意 sqlite3_open() 既可以用于打开一个现存的数据库,也可以创建并打开一个新的数据库。因为许多的应用程序只使用一个数据库连接,所以就没有理由让一个应用程序多次调用sqlite3_open() 创建多个数据库连接 – 同一个数据库或者不同的数据库。有时一个多线程的应用会为不同的线程创建独立的数据库连接。注意,为了访问两个或者多个数据库也没必要创建多个独立的连接。一个单一的数据库连接可以使用 ATTACH SQL 语句同时访问两个或者多个数据库(译注:http://sqlite.awardspace.info/syntax/sqlitepg12.htm)。

许多应用在关闭时调用 sqlite3_close() 销毁它们的数据库连接。比如,一个使用 SQLite 作为它的应用程序文件格式(application file format)会在点击 文件/打开(File/Open) 菜单时创建一个数据库连接,在点击 文件/关闭 (File/Close) 菜单时关闭这个连接。

要执行 SQL 语句,程序需要遵循以下几步:

使用 **sqlite3_prepare()** 创建一个 prepared statement。        通过一次或多次调用 **sqlite3_step()** 查询 prepared statement 的结果。      对于查询来说,在调用 **sqlite3_step()** 后通过调用 **sqlite3_column()** 获取结果。      使用 **sqlite3_finalize()** 销毁 prepared statement。

上述都是为了高效的使用 SQLite 读者所需要知道的。其余的都只是补充和细节。

2.0 核心 API 的便捷封装

sqlite3_exec() 是使用一次函数调用完成上述四种接口调用的便捷封装。 sqlite3_exec()在处理结果集的每行时调用传入的回调函数。sqlite3_get_table() 是另一个使用一次函数调用完成上述四种接口调用的便捷封装。sqlite3_get_table() 与 sqlite3_exec() 的不同之处是将结果集保存在堆中而不是每次都调用回调函数。

需要注意的是 sqlite3_exec() 和 sqlite3_get_table() 都不能实现核心接口不能完成的事。事实上,这些封装都是完全由核心接口实现的。

3.0 参数绑定与重用 Prepared Statements

在之前的讨论中,都假设每个 SQL 语句都只准备一次( prepared once),执行(evaluated),然后销毁。但是,SQLite 允许相同的 prepared statement 被执行多次。通过以下的方法实现:

sqlite3_reset()  sqlite3_bind()

sqlite3_step() 执行一次或多次 prepared statement 后,通过 sqlite3_reset() 可以重置并重新执行(evaluated)。对现存的 prepared statement 使用 sqlite3_reset() 可以避免调用 sqlite3_prepare() 创建一个新的 prepared statement。对于部分的 SQL 语句,调用sqlite3_prepare() 的时间和调用 sqlite3_step() 一样。所以避免调用sqlite3_prepare() 对性能提升有重大的影响。

通常不会对一个 SQL 语句执行(evaluate)多次。更常见的是,执行一个相似的语句。例如,你想通过执行多次 INSERT 语句插入不同的值。为了实现类似的灵活性,SQLite 允许对一条 SQL 语句每次“绑定”不同的值。这些值之后可以改变,并且同样的 prepared statement 使用新的值可以二次使用。(译注:说白了就是对一个表一次插入多条数据,每次插入的不同的值在 SQL 语句中用通配符占位)

在 SQLite 中,任何地方都允许插入字符串字面量(string literal),可以使用以下几种形式:

?  ?NNN  :AAA  $AAA  @AAA

在上面个的例子中,NNN 代表整型值( integer value ),AAA 是个标识符(identifier)(译注:字母数字组合)。参数的初始值为 NULL。在第一次调用 sqlite3_step() 之前或立即在调用 sqlite3_reset() 之后,应用程序可以调用某个 sqlite3_bind() 接口绑定值到参数上。每次调用 sqlite3_bind() 都会覆盖之前绑定到相同参数的值。

应用可以按需要提前准备多个 SQL prepared statements 并按需要执行(evaluate)。没有严格的限制 prepared statements 的数量。

4.0 配置 SQLite

默认的 SQLite 配置对于大部分的应用工作的都挺好的。但有时开发者想要优化设置项去尝试压榨出更多的性能,或者利用一些隐蔽的特性。

sqlite3_config() 可以设置 SQLite 全局的,进程级(process-wide)的配置项。sqlite3_config() 只能在数据库连接建立后被调用。sqlite3_config() 允许程序员做以下的事情:

调整 SQLite 如何分配内存,包括为安全敏感(safety-critical)的实时的嵌入式系统和应用程序定义的(application-defined)内存分配器设置为可选的(alternative)内存分配器(memory allocators)。  设置一个进程级的错误日志。  指定一个应用程序定义的页缓存(page cache)。  调整 mutex 的使用,这样就可以使用多种线程模型,或者替换一个程序定义的 mutex 系统。

在进程级的设置完成(configuration is complete)并且数据库连接已经创建后,不同的数据库连接可以通过调用 sqlite3_limit() 和 sqlite3_db_config() 配置。

5.0 扩展 SQLite

SQLite 包含可以扩展功能的接口。这些接口(routine)包括:

sqlite3_create_collation()    sqlite3_create_function()    sqlite3_create_module()    sqlite3_vfs_register()

sqlite3_create_collation() 接口用于创建排序文字用的新的校对队列(collating sequences)。sqlite3_create_module() 接口用于注册新的虚表实现。sqlite3_vfs_register() 创建一个新的 VFS(译注:Virtual File System,虚拟文件系统)。

sqlite3_create_function() 接口用于创建新的 SQL 函数(function)—— scalar 函数或者 aggregate 函数(译注:http://www.w3schools.com/sql/sql_functions.asp)。新的函数实现通常使用以下的额外接口:

sqlite3_aggregate_context()  sqlite3_result()  sqlite3_user_data()  sqlite3_value()

所有的 SQLite 内建 SQL 函数都使用的是这些接口创建的。可以参考 SQLite 的源文件,尤其是 date.c 和 func.c。

共享库或者 DLL 可以作为 SQLite 的可装卸扩展(loadable extensions)(译注:http://www.sqlite.org/cvstrac/wiki?p=LoadableExtensions)。

6.0 其他接口

这篇文章只提到了 SQLite 的一些基础接口。SQLite 库中还包含一些这里没有提到的有用的 API。可以在 SQLite 的 C/C++ 的接口说明中找到完整的函数列表(译注:http://sqlite.org/c3ref/intro.html)。参考此文档可以找到完整和权威的关于 SQLite 接口的信息。

来源:Cocoabit