第六章 核心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)

posted on 2018-07-31 14:38  mofei004  阅读(291)  评论(0编辑  收藏  举报

导航