• 第六章 核心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
    ", 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
    ", 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, "
    ");
    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
    ",
    24                          sqlite3_column_name(stmt, i),
    25                          sqlite3_column_type(stmt, i),
    26                          sqlite3_column_decltype(stmt, i));
    27     }
    28     fprintf(stdout, "
    ");
    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'
    ", id,cid,name);
    36         } else {
    37             /* Field is NULL */
    38             fprintf(stderr, "Row:  id=%i, cid=%i, name=NULL
    ", 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)
  • 相关阅读:
    无题
    生活真像小说
    草样年华
    Intentional Programming
    厌倦说话
    解释 Intentional Programming
    开始折腾iphone cdma 恢复,降级,刷机,越狱,手编,写号
    新手如何成为更好的图形设计师
    Grunt.js 初使用
    有抱负的程序员应看的10个TED演讲
  • 原文地址:https://www.cnblogs.com/mofei004/p/9392010.html
Copyright © 2020-2023  润新知