玩转SQLite-11:C语言高效API之sqlite3_prepare系列函数

SQLite是一个跨平台的轻量级数据库,支持C/C++开发,可用于嵌入式中,关于C/C++使用SQLite的简单实例,之前这篇文章,已经介绍过一种简单的使用方式。本篇来介绍另一种更加高效的调用方式。

1.1 普通方式

之前的文章介绍过sqlite3的C语言API函数基础操作,通过sqlite3_exec函数即可执行sql语句函数,该函数指定一个 sql语句字符串和对应的回调函数。

当执行sqlite3_exec时,其内部的执行可分为3步:

  • 解析sql语句字符串
  • 编译sql语句
  • 执行sql语句

可以看到,sqlite3_exec一个函数就实现了这么多功能,这是它的优点——使用方便,但同时也是它的缺点——效率低,因为解析和编译都是比较耗时的。

关于sqlite3_exec的使用示例可参考之前的文章:玩转SQLite6:使用C语言来读写数据库

1.2 高效方式

为此解决sqlite3_exec函数执行效率低的问题,就出现了其它更加高效的解决方式:将sqlite3_exec的功能进行分解,由多个函数共同完成。这就是本篇要介绍的:

  • **sqlite3_prepare_v2()**函数:实现对sql语句(模板)的解析和编译,生成了可以被执行的 sql语句实例
  • **sqlite3_stmt()**数据结构:可以理解为一种“准备语句对象”,它可以结合变量使用,进而实现相同操作的循环
  • **sqlite3_bind_*() **函数:用于绑定赋值变量
  • **sqlite3_step() **函数:用于执行sql语句

相比较使用sqlite3_exec函数,现在这种方式,sql语句的解析和编译只执行了一次,而sqlite3_step执行多次,整体的效率势必大大提升。

2 函数介绍

2.1 sqlite3错误码

在介绍各个函数之前,先来看一个这些函的错误码有哪些

#define SQLITE_OK           0   /* 成功 */
/* 错误码 */
#define SQLITE_ERROR        1   /* sql错误或丢失的数据库,SQL error or missing database */
#define SQLITE_INTERNAL     2   /* sqlite内部逻辑错误,Internal logic error in SQLite */
#define SQLITE_PERM         3   /* 拒绝访问,Access permission denied */
#define SQLITE_ABORT        4   /* 回调函数请求取消操作,Callback routine requested an abort */
#define SQLITE_BUSY         5   /* 数据库文件被锁定,The database file is locked */
#define SQLITE_LOCKED       6   /* 数据库的一个表被锁定,A table in the database is locked */
#define SQLITE_NOMEM        7   /* 某次malloc函数调用失败,A malloc() failed */
#define SQLITE_READONLY     8   /* 尝试写入一个只读数据库,Attempt to write a readonly database */
#define SQLITE_INTERRUPT    9   /* 操作sqlite3_interrupt函数被中断,Operation terminated by sqlite3_interrupt()*/
#define SQLITE_IOERR       10   /* 发生磁盘I/O错误,Some kind of disk I/O error occurred */
#define SQLITE_CORRUPT     11   /* 数据库磁盘映像不正确,The database disk image is malformed */
#define SQLITE_NOTFOUND    12   /* 找不到表或记录,NOT USED. Table or record not found */
#define SQLITE_FULL        13   /* 数据库满而插入失败,Insertion failed because database is full */
#define SQLITE_CANTOPEN    14   /* 无法打开数据库,Unable to open the database file */
#define SQLITE_PROTOCOL    15   /* 数据库锁定协议错误,NOT USED. Database lock protocol error */
#define SQLITE_EMPTY       16   /* 数据库为空,Database is empty */
#define SQLITE_SCHEMA      17   /* 数据库结构发生改变,The database schema changed */
#define SQLITE_TOOBIG      18   /* 数据大小超限,String or BLOB exceeds size limit */
#define SQLITE_CONSTRAINT  19   /* 约束违反,Abort due to constraint violation */
#define SQLITE_MISMATCH    20   /* 数据类型不匹配,Data type mismatch */
#define SQLITE_MISUSE      21   /* 库使用不正确,Library used incorrectly */
#define SQLITE_NOLFS       22   /* 使用了操作系统不支持的功能,Uses OS features not supported on host */
#define SQLITE_AUTH        23   /* 授权失败,Authorization denied */
#define SQLITE_FORMAT      24   /* 附加数据库格式错误,Auxiliary database format error */
#define SQLITE_RANGE       25   /* sqlite3_bind的第2给参数超出范围,2nd parameter to sqlite3_bind out of range */
#define SQLITE_NOTADB      26   /* 不是数据库文件,File opened that is not a database file */
#define SQLITE_NOTICE      27   /* Notifications from sqlite3_log() */
#define SQLITE_WARNING     28   /* Warnings from sqlite3_log() */
#define SQLITE_ROW         100  /* sqlite3_step产生一个就绪行,sqlite3_step() has another row ready */
#define SQLITE_DONE        101  /* sqlite3_step执行完成,sqlite3_step() has finished executing */

2.2 sqlite3_prepare_v2

该函数实现对sql语句(模板)的解析和编译,生成了可以被执行的sql语句实例

int sqlite3_prepare_v2(
    sqlite3 *db,            /* Database handle */
    const char *zSql,       /* SQL statement, UTF-8 encoded */
    int nByte,              /* Maximum length of zSql in bytes. */
    sqlite3_stmt **ppStmt,  /* OUT: Statement handle */
    const char **pzTail     /* OUT: Pointer to unused portion of zSql */
);

参数

  • db:sqlite数据库
  • zSql:要执行的sql语句(可以包含未赋值的变量)
  • nByte:sql语句的(字符串的)长度
  • ppStmt:解析编译出的sql语句实例
  • pzTail:

返回值:见前面的sqlite3错误码

2.3 sqlite3_bind

该函数组用于绑定变量值到prepare语句中,也就是给 sqlite3_stmt变量赋值。前面的文章讲过,我们一定是先通过sqlite3_prepare_v2函数创建并初始化一个 sqlite3_stmt 变量语句,然后使用sqlite3_bind_xxx函数对 这个 sql语句变量进行绑定参数。

int sqlite3_bind_int(sqlite3_stmt*, int, int);
int sqlite3_bind_doubule(sqlite3_stmt*, int, double);
int sqlite3_bind_text(sqlite3_stmt*, int, const char*, int, void(*)(void*));

参数

  • 形参1:sqlite3_stmt: prepare语句编译出的sql语句实例
  • 形参2: sqlite3_stmt变量参数的序号索引值,规定最左侧的SQL参数的索引值为 1,也就是说参数索引值从1开始。
  • 形参3: 是要绑定给第2个形参指向的 变量参数的 实际值。第2个形参可以指向不同的索引值。
  • 形参4: 对于有4个形参的函数,第4个形参一般是第3个形参的长度。
  • 形参5: 是用于BLOB和字符串绑定后的 析构函数,用于在sqlite处理完blob或字符串之后处理它,一般可以设置为NULL。

返回值:见前面的sqlite3错误码

代码示例:
假设表的字段结构为:person(name,age,sex),数据库指针为 pdb。

    sqlite3_stmt *pstmt;
	const char *sql = "INSERT INTO person(name, age, sex) VALUES(?,?,?);";
	nRet = sqlite3_prepare_v2(pdb, sql, strlen(sql), &pstmt, &pzTail);
	int i;
 
	for(i = 0; i < 10; i++){
    
    
		nCol = 1;
		sqlite3_bind_text(pstmt, nCol++, a[i].name, strlen(a[i].name), NULL);
		sqlite3_bind_int(pstmt, nCol++, a[i].age);
		sqlite3_bind_text(pstmt, nCol++, a[i].sex, strlen(a[i].name), NULL);
 
		sqlite3_step(pstmt);
		sqlite3_reset(pstmt);
	}
 
	sqlite3_finalize(pstmt);

2.4 sqlite3_step

int sqlite3_step(sqlite3_stmt *pStmt);

参数

  • pStmt:prepare语句编译出的sql语句实例

返回值:

这里再对几个常见的返回值进一步说明:

  • SQLITE_DONE:意味着sql语句执行完成且成功。一旦执行成功后,sqlite3_step()就不应该被再次调用执行,除非我们使用sqlite3_reset()重置 sqlite3_stmt 数据。

  • SQLITE_ROW:这个比较常用,当我们的sql语句是 读命令,比如"SELECT FROM…",返回的数据一般很多,并且数据是按行返回的,且每次只返回一行*,其返回值为 SQLITE_ROW,所以需要重复调用sqlite3_step函数,直到sqlite3_step返回 SQLITE_DONE.

  • SQLITE_MISUSE: 表示该函数实例被滥用,不合适,比如sqlite_stmt结构已经被销毁了。

2.5 sqlite3_reset

int sqlite3_reset(sqlite3_stmt *pStmt);

用于重置一个准备语句对象到它的初始状态,然后准备被重新执行。所有sql语句变量使用sqlite3_bind*绑定值,使用sqlite3_clear_bindings重设这些绑定。Sqlite3_reset接口重置准备语句到它代码开始的时候。sqlite3_reset并不改变在准备语句上的任何绑定值,那么这里猜测,可能是语句在被执行的过程中发生了其他的改变,然后这个语句将它重置到绑定值的时候的那个状态。

2.6 sqlite3_column

该函数实例用于 查询(query)结果的筛选,返回当前结果的某1列。

int sqlite3_column_int(sqlite3_stmt*, int iCol);
double sqlite3_column_double(sqlite3_stmt*, int iCol);
const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);

参数

  • sqlite3_stmt*:prepare语句编译出的sql语句实例

  • iCol: 要查询的"列"索引值。sqlite3规定最左侧的“列”索引值是 0,也就是“列”索引号从 0 开始。

返回

  • 根据函数类型,返回相应的数据,比如int型,double型(浮点数也是),text(字符串型)等。

3 总结

本篇主要介绍了sqlite的C语言操作的高效API函数,用于取代功能强大但效率较低的sqlite3_exec函数。本篇介绍到的几个API函数总结如下:

  • sqlite3_prepare_v2() 创建sqlite3_stmt对象
  • sqlite3_bind_*() 绑定参数值到sqlite3_stmt
  • sqlite3_step() 运行sql语句,可以是一次,也可以是循环执行
  • sqlite3_reset() 重置sqlite3_stmt对象
  • sqlite3_finalize() 销毁sqlite3_stmt对象

下篇,将通过一个实际的例子,来体会这些函数的具体使用效果。

猜你喜欢

转载自blog.csdn.net/hbsyaaa/article/details/127858034