第六章 核心API
一、查询封装
1、连接与断开连接
打开数据库API如下:
1 int sqlite3_open( 2 const char *zFilename, /* Database filename (UTF-8) */ 3 sqlite3 **ppDb /* OUT: SQLite db handle */ 4 ) 5 6 int sqlite3_open_v2( 7 const char *filename, /* Database filename (UTF-8) */ 8 sqlite3 **ppDb, /* OUT: SQLite db handle */ 9 int flags, /* Flags */ 10 const char *zVfs /* Name of VFS module to use */ 11 ) 12 13 int sqlite3_open16( 14 const void *zFilename, /* Database filename (UTF-16) */ 15 sqlite3 **ppDb /* OUT: SQLite db handle */ 16 )
1)zFilename
- 使用”:memory",sqlite3_open_v2()将在内存中创建数据库,只存在于连接生存期间。
- null:sqlite3_open_v2()将打开临时磁盘文件,并在连接关闭时自动删除该文件。
- 其他:sqlite3_open_v2()将通过该名字打开一个新的数据库文件,如果不包含SQLITE_OPEN_CREATE,将返回错误。
2)flags
以下均为比特向量:
- SQLITE_OPEN_CREATE
- SQLITE_OPEN_READONLY
- SQLITE_OPEN_READWRITE
可结合以下标志使用
- SQLITE_OPEN_NOMUTEX: 设置数据库连接运行在多线程模式(没有指定单线程模式的情况下)
- SQLITE_OPEN_FULLMUTE:设置数据库连接运行在串行模式。
- SQLITE_OPEN_SHAREDCACHE:设置运行在共享缓存模式。
- SQLITE_OPEN_PRIVATECACHE:设置运行在非共享缓存模式。
3)ppDb
可视为一个不透明句柄,代表到数据库的一个连接。可能将多个数据库附加到单个连接上。无论多少个数据库附加到带连接上,它依然代表事务上下文环境。
4)zVfs
允许调用去重写默认的操作系统接口sqlite3_vfs方法。
关闭数据库API如下:
1 int sqlite3_close(sqlite3 *db) 2 int sqlite3_close_v2(sqlite3 *db)
调用sqlite3_close()时,如果有查询仍未完成,会返回SQLITE_BUSY,并显示错误消息“由于有位完成的语句,所以无法关闭连接”
调用sqlite3_close_v2()时,若关闭时连接有未提交的事务,该事务会自动回滚。
2、执行查询
sqlite3_exec()提供了一种快速、方便执行SQL命令的方法。
int sqlite3_exec( sqlite3 *db, /* The database on which the SQL executes */ const char *zSql, /* The SQL to be executed */ sqlite3_callback xCallback, /* Invoke this callback routine */ void *pArg, /* First argument to xCallback() */ char **pzErrMsg /* Write error messages here */ )
1)zsql
可包含多个SQL命令。插入一条记录时,如果数据库尚未存在,创建表命令从物理上创建数据库文件。
2)xCallback、 pArg
通过上述两个参数实现回调函数。
xCallback:提供指向回调函数的指针
pArg:void指针,执行要提供给回调函数的应用程序特定的数据,回调函数的第一个参数。
下面是回调函数的类型声明:
1 typedef int (*sqlite3_callback)(void*,int,char**, char**);
参数:
- 第一个参数:sqlite3_exec()函数的第四个参数提供的数据
- 第二个参数:行中字段的数目
- 第三个参数:代表行中字段名称的字符串数据
- 第四个参数:代表字段名称的字符串数组
3)pzErrMsg
指向错误消息字符串的执政,可将处理中发生的错误消息写入该字符串。
errmsg指向的错误信息在堆上分配的,故如果errmsg不为NULL,则需要调用sqlite3_free()释放errmsg所占用的内存。
注意:如果回调函数的返回值不为0,将会影响sqlite3_exec()的执行。将会终止当前命令和sql字符串后续命令的所有处理。
3、获取表查询
sqlite3_get_table()封装了sqlite3_exec()。不必处理回调函数,更容易获取记录。但最新的文档,不建议用此接口。
1 int sqlite3_get_table( 2 sqlite3 *db, /* The database on which the SQL executes */ 3 const char *zSql, /* The SQL to be executed */ 4 char ***pazResult, /* Write the result table here */ 5 int *pnRow, /* Write the number of rows in the result here */ 6 int *pnColumn, /* Write the number of columns of result here */ 7 char **pzErrMsg /* Write error messages here */ 8 )
1)pazResult
查询结果存储位置指针。必须调用sqlite3_free_table()释放内存。pazResult中第一个记录是列的名称,即先打印出查询内容的各个字段名称。
打印结果的每一行和每一列:
1 rc = sqlite3_get_table(db, sql, &result, &nrows, &ncols, &zErr); 2 3 for(i=0; i < nrows; i++) { 4 for(j=0; j < ncols; j++) { 5 /* the i+1 term skips over the first record, 6 which is the column headers */ 7 fprintf(stdout, "%s", result[(i+1)*ncols + j]); 8 } 9 }
二、查询准备
列值可通过sqlite3_column_xxx()获得。其中xxx表示返回值的声明类型(如int、double、blob)。
查询准备有三个步骤:编译、执行和完成。
使用sqlite3_prepare_v2()编译查询,使用函数sqlite3_step()分步执行查询,使用函数sqlite_finalize()关闭查询,或使用sqlit3_reset()重用编译。
1、编译
编译或准备接收SQL语句,并将其编译为虚拟数据库殷勤(VDBE)可读字节码。
sqlite3_prepare_v2()可直接通过编译器工作,为执行准备查询。语句句柄高度依赖它所被编译的数据库模式。如果另一个连接在准备语句和实际执行语句期间更改了数据库模式,那么准备语句就会失效。有可能的话,函数会自动试图重新编译(重准备)语句。如果重新编译无法实现,sqlite3_step()调用会导致SQLITE_SCHEMA错误。
1 int sqlite3_prepare_v2( 2 sqlite3 *db, /* Database handle. */ 3 const char *zSql, /* UTF-8 encoded SQL statement. */ 4 int nBytes, /* Length of zSql in bytes. */ 5 sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ 6 const char **pzTail /* OUT: End of parsed string */ 7 )
1)ppStmt
sqlite3_stmt类型结构体。这种数据结构包含了命令的字节码、绑定的参数、B-tree游标、执行上下文以及sqlite3_step()在执行过程中管理查询状态所需的其他数据。
能够使用sqlite3_setp()执行编译好的准备语句的指针,如果发生错误,它被置位NULL,如输入的文本不包括sql语句。调用过程必须负责在编译好的sql语句完成使用后使用sqlit3_finalize()删除它。
2)pzTail
zSql在遇见终止符或者是达到设定的nByte之后结束,假如zSql还有剩余的内容,那么这些剩余的内容被存放到pZTail中,不包括终止符。如果pszTail不为NULL, 则*pszTail指向sql中第一个被传入的SQL语句的结尾。该函数只编译sql的第一个语句, 所以*pszTail指向的内容则是未被编译的。
说明:
如果函数执行成功,则返回SQLITE_OK,否者返回一个错误码。
备注:
<1>准备语句(prepareed statement)对象
1 typedef struct sqlite3_stmt sqlite3_stmt;
一个准备语句(prepared statement)对象代表一个简单SQL语句对象的实例,这个对象通常被称为“准备语句”或者“编译好的SQL语句”或者就直接称为“语句”。
语句对象的生命周期经历这样的过程:
- 使用sqlite3_prepare_v2或相关的函数创建这个对象
- 使用sqlite3_bind_*()给宿主参数(host parameters)绑定值
- 通过调用sqlite3_step一次或多次来执行这个sql
- 使用sqlite3——reset()重置这个语句,然后回到第2步,这个过程做0次或多次
- 使用sqlite3_finalize()销毁这个对象
在sqlite中并没有定义sqlite3_stmt这个结构的具体内容,它只是一个抽象类型,在使用过程中一般以它的指针进行操作,而sqlite3_stmt类型的指针在实际上是一个指向Vdbe(虚拟机实例)的结构体得指针。
<2>宿主参数(host parameters)
在传给sqlite3_prepare_v2()的sql的语句文本或者它的变量中,满足如下模板的文字将被替换成一个参数:
| ?
| ?NNN //NNN代表数字
| :VVV //VVV代表字符
| @VVV
| $VVV
在上面这些模板中,NNN代表一个数字,VVV代表一个字母数字标记符(例如:222表示名称为222的标记符),sql语句中的参数(变量)通过上面的几个模板来指定,如“select ? from ? “这个语句中指定了两个参数,sqlite语句中的第一个参数的索引值是1,这就知道这个语句中的两个参数的索引分别为1和2,使用”?”的话会被自动给予索引值,而使用”?NNN”则可以自己指定参数的索引值,它表示这个参数的索引值为NNN。”:VVV”表示一个名为”VVV”的参数,它也有一个索引值,被自动指定。
例如:
INSERT INTO people (id, name) VALUES ( ?, ? ); INSERT INTO people (id, id2,name) VALUES ( ?1, ?1.?2 ); //作用:可以用同一个值绑定几个变量 INSERT INTO people (id, name) VALUES ( :id, :name ); INSERT INTO people (id, name) VALUES ( @id, @name ); INSERT INTO people (id, name) VALUES ( $id, $name ); //用来支持Tcl变量的扩展语法,除非使用Tcl编程,否则推荐使用“:<name>”版本
可以使用sqlite3_bind_*()来给这些参数绑定值。
2、执行
int sqlite3_step(sqlite3_stmt *pStmt)
sqlite3_step()接收句柄并直接与VDBE通信,生成执行SQL语句的字节码指令。第一次调用时,VDBE获得执行该命令所需的必要的数据库锁。如果不能获取锁,并没有指派繁忙处理程序,sqlite3_step()将返回SQLITE_BUSY。如果指定了繁忙处理程序,将调用该处理程序。
对于返回数据的SQL语句,sqlite3_step()第一次调用将语句定位在第一个记录的B-tree光标上。后续调用将定位在结果集内的后续记录。到达末尾值前,sqlite3_step()为结果集中的每个记录返回SQLITE_ROW,返回SQLITE_DONE,表示已到达结果集末尾。
3、完成与重置
1 int sqlite3_finalize(sqlite3_stmt *pStmt); 2 int sqlite3_reset(sqlite3_stmt *pStmt);
- sqlite3_finalize()将关闭语句。释放资源并提交或回滚任何隐式事务(如果该链接是自动自动提交模式),清除日志文件并释放相关联的锁。
- sqlite3_reset()将保持已编译的SQL语句(和任何绑定的参数),但会将语句相关联的变化提交到数据库。如果启动了自动提交,它还释放锁定并清除日志文件。此函数保留与语句关联的资源。避免了再次调用sqlite3_prepare()。
示例(未处理错误、繁忙条件等):
1 #include <stdio.h> 2 #include <sqlite3.h> 3 4 int main(int argc, char **argv) 5 { 6 int rc, i, ncols; 7 sqlite3 *db; 8 sqlite3_stmt *stmt; 9 char *sql; 10 const char *tail; 11 12 rc = sqlite3_open("foods.db", &db); 13 14 if(rc) { 15 fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db)); 16 sqlite3_close(db); 17 exit(1); 18 } 19 20 sql = "select * from episodes;"; 21 22 rc = sqlite3_prepare_v2(db, sql, strlen(sql), &stmt, &tail); 23 24 if(rc != SQLITE_OK) { 25 fprintf(stderr, "SQL error: %s\n", sqlite3_errmsg(db)); 26 } 27 28 rc = sqlite3_step(stmt); 29 ncols = sqlite3_column_count(stmt); 30 31 while(rc == SQLITE_ROW) { 32 33 for(i=0; i < ncols; i++) { 34 fprintf(stderr, "'%s' ", sqlite3_column_text(stmt, i)); 35 } 36 37 fprintf(stderr, "\n"); 38 39 rc = sqlite3_step(stmt); 40 } 41 42 sqlite3_finalize(stmt); 43 sqlite3_close(db); 44 45 return 0; 46 }
sqlite3_prepare_v2()支持多条SQL语句的处理方法。
1 while(sqlite3_complete(sql)) 2 { 3 rc = sqlite3_prepare(db,sql, -1, &stmt, &tail); 4 5 /*处理查询结果*/ 6 7 /*跳到字符串的下一条命令*/ 8 sql = tail; 9 }
三、获取记录
1 /* 2 ** Return the number of columns in the result set for the statement pStmt. 3 */ 4 int sqlite3_column_count(sqlite3_stmt *pStmt) 5 6 /* 7 ** Return the number of values available from the current row of the 8 ** currently executing statement pStmt. 9 */ 10 int sqlite3_data_count(sqlite3_stmt *pStmt)
- sqlite3_column_count():返回与语句句柄相关联的字段数,如果请求不是select语句,则sqlite3_column_count()返回0;
- sqlite3_data_count():sqlite3_step()返回SQLITE_ROW后,返回会当前记录的列数。只有语句句柄存在活动游标是,该函数才能工作。
1、获取字段信息
1 /* 2 ** Return the name of the Nth column of the result set returned by SQL 3 ** statement pStmt. 4 */ 5 const char *sqlite3_column_name(sqlite3_stmt *pStmt, int N)
获取当前记录中的所有列的名字。
1 int sqlite3_column_type(sqlite3_stmt *pStmt, /*语句句柄*/ 2 int i /*字段的次序*/); 3 4 #define SQLITE_INTEGER 1 5 #define SQLITE_FLOAT 2 6 #define SQLITE_BLOB 4 7 #define SQLITE_NULL 5
获取每个字段相关联的存储类。
/* ** Return the column declaration type (if applicable) of the 'i'th column ** of the result set of SQL statement pStmt. */ const char *sqlite3_column_decltype(sqlite3_stmt *pStmt, int N)
获取字段在表模式定义中声明的数据类型。
如果结果集中的列与实际表中的列不对应,该函数将返回NULL。
1 /* 2 ** Return the name of the database from which a result column derives. 3 ** NULL is returned if the result column is an expression or constant or 4 ** anything else which is not an unambiguous reference to a database column. 5 */ 6 const char *sqlite3_column_database_name(sqlite3_stmt *pStmt, int N) 7 8 /* 9 ** Return the name of the table from which a result column derives. 10 ** NULL is returned if the result column is an expression or constant or 11 ** anything else which is not an unambiguous reference to a database column. 12 */ 13 const char *sqlite3_column_table_name(sqlite3_stmt *pStmt, int N) 14 15 /* 16 ** Return the name of the table column from which a result column derives. 17 ** NULL is returned if the result column is an expression or constant or 18 ** anything else which is not an unambiguous reference to a database column. 19 */ 20 const char *sqlite3_column_origin_name(sqlite3_stmt *pStmt, int N)
上面三个函数的功能:
- 返回列相关联的数据库
- 返回它所在的表
- 返回列在模式中的定义名称
上述函数只有在编译SQLite时启用了SQLITE_ENABLE_COLUMN_METADATA预处理指令时,才可用。
2、获取字段值
通过以下API获取字段值。
1 /**************************** sqlite3_column_ ******************************* 2 ** The following routines are used to access elements of the current row 3 ** in the result set. 4 */ 5 const void *sqlite3_column_blob(sqlite3_stmt *pStmt, int i){ 6 const void *val; 7 val = sqlite3_value_blob( columnMem(pStmt,i) ); 8 /* Even though there is no encoding conversion, value_blob() might 9 ** need to call malloc() to expand the result of a zeroblob() 10 ** expression. 11 */ 12 columnMallocFailure(pStmt); 13 return val; 14 } 15 int sqlite3_column_bytes(sqlite3_stmt *pStmt, int i){ 16 int val = sqlite3_value_bytes( columnMem(pStmt,i) ); 17 columnMallocFailure(pStmt); 18 return val; 19 } 20 int sqlite3_column_bytes16(sqlite3_stmt *pStmt, int i){ 21 int val = sqlite3_value_bytes16( columnMem(pStmt,i) ); 22 columnMallocFailure(pStmt); 23 return val; 24 } 25 double sqlite3_column_double(sqlite3_stmt *pStmt, int i){ 26 double val = sqlite3_value_double( columnMem(pStmt,i) ); 27 columnMallocFailure(pStmt); 28 return val; 29 } 30 int sqlite3_column_int(sqlite3_stmt *pStmt, int i){ 31 int val = sqlite3_value_int( columnMem(pStmt,i) ); 32 columnMallocFailure(pStmt); 33 return val; 34 } 35 sqlite_int64 sqlite3_column_int64(sqlite3_stmt *pStmt, int i){ 36 sqlite_int64 val = sqlite3_value_int64( columnMem(pStmt,i) ); 37 columnMallocFailure(pStmt); 38 return val; 39 } 40 const unsigned char *sqlite3_column_text(sqlite3_stmt *pStmt, int i){ 41 const unsigned char *val = sqlite3_value_text( columnMem(pStmt,i) ); 42 columnMallocFailure(pStmt); 43 return val; 44 } 45 sqlite3_value *sqlite3_column_value(sqlite3_stmt *pStmt, int i){ 46 Mem *pOut = columnMem(pStmt, i); 47 if( pOut->flags&MEM_Static ){ 48 pOut->flags &= ~MEM_Static; 49 pOut->flags |= MEM_Ephem; 50 } 51 columnMallocFailure(pStmt); 52 return (sqlite3_value *)pOut; 53 } 54 #ifndef SQLITE_OMIT_UTF16 55 const void *sqlite3_column_text16(sqlite3_stmt *pStmt, int i){ 56 const void *val = sqlite3_value_text16( columnMem(pStmt,i) ); 57 columnMallocFailure(pStmt); 58 return val; 59 } 60 #endif /* SQLITE_OMIT_UTF16 */
数据类型转换:
对于BLOB列,通过sqlite3_column_bytes()获取实际数据的长度。示例如下:
1 int len = sqlite3_column_bytes(stmt, 0); 2 void* data = malloc(len); 3 memcpy(data, len, sqlite3_column_blob(stmt,0));
实例代码:
1 #include <stdio.h> 2 #include <sqlite3.h> 3 4 int main(int argc, char **argv) 5 { 6 int rc, i, ncols, id, cid; 7 char *name, *sql; 8 sqlite3 *db; 9 sqlite3_stmt *stmt; 10 11 sql = "select id, name from episodes"; 12 sqlite3_open("test.db", &db); 13 14 setup(db); 15 16 sqlite3_prepare_v2(db, sql, strlen(sql), &stmt, NULL); 17 18 ncols = sqlite3_column_count(stmt); 19 rc = sqlite3_step(stmt); 20 21 /* Print column information */ 22 for(i=0; i < ncols; i++) { 23 fprintf(stdout, "Column: name=%s, storage class=%i, declared=%s\n", 24 sqlite3_column_name(stmt, i), 25 sqlite3_column_type(stmt, i), 26 sqlite3_column_decltype(stmt, i)); 27 } 28 fprintf(stdout, "\n"); 29 30 while(rc == SQLITE_ROW) { 31 id = sqlite3_column_int(stmt, 0); 32 cid = sqlite3_column_int(stmt, 1); 33 name = sqlite3_column_text(stmt, 2); 34 if(name != NULL){ 35 fprintf(stderr, "Row: id=%i, cid=%i, name='%s'\n", id,cid,name); 36 } else { 37 /* Field is NULL */ 38 fprintf(stderr, "Row: id=%i, cid=%i, name=NULL\n", id,cid); 39 } 40 rc = sqlite3_step(stmt); 41 } 42 43 sqlite3_finalize(stmt); 44 sqlite3_close(db); 45 return 0; 46 }
另,可通过一个给定的语句句柄,获取关联连接句柄。这个函数免除了到处传递关联连接句柄的麻烦。
1 /* 2 ** Return the sqlite3* database handle to which the prepared statement given 3 ** in the argument belongs. This is the same database handle that was 4 ** the first argument to the sqlite3_prepare() that was used to create 5 ** the statement in the first place. 6 */ 7 sqlite3 *sqlite3_db_handle(sqlite3_stmt *pStmt)