SQLiteC/C++接口详细介绍sqlite3_stmt类(二)

返回目录:SQLite---免费开源数据库系列文章目录

上一篇:SQLiteC/C++接口详细介绍sqlite3_stmt类简介

下一篇:SQLiteC/C++接口详细介绍sqlite3_stmt类(三)

sqlite3_reset()

功能:重置一个准备好执行的SQL语句的状态,使其可以重复执行或进行新的绑定。

在SQLite3准备执行一个SQL语句之前,需要进行一系列的准备工作,包括将SQL语句编译成字节码、执行查询计划等等,这些准备工作都会影响SQL语句的执行效率。如果希望对同一个SQL语句进行多次执行,每次都重新进行这些准备工作是非常浪费时间和资源的,因此我们可以使用sqlite3_reset()函数来重置一个准备好执行的SQL语句的状态,以实现多次执行同一个SQL语句的效果。

sqlite3_reset()函数的原型定义如下:

cpp 复制代码
int sqlite3_reset(sqlite3_stmt *pStmt);

函数的参数是一个sqlite3_stmt类型的指针,它是由sqlite3_prepare_v2()或sqlite3_prepare()等函数返回的sqlite3_stmt类型的准备好的语句。函数返回值为一个整型,表示函数的执行状态,成功则返回SQLITE_OK,否则返回错误代码。

下面是一个使用sqlite3_reset()的简单示例:

cpp 复制代码
#include <sqlite3.h>
#include <stdio.h>
int main() {
    sqlite3 *db;
    sqlite3_stmt *stmt;
    const char *tail;
    char *err_msg = 0;
    sqlite3_open(":memory:", &db);
    sqlite3_prepare_v2(db, "SELECT 1", -1, &stmt, &tail);
    printf("%d\n", sqlite3_step(stmt));  // 输出1
    printf("%d\n", sqlite3_step(stmt));  // 输出101,再次执行SQL语句
    sqlite3_reset(stmt);
    printf("%d\n", sqlite3_step(stmt));  // 再次输出1
    sqlite3_finalize(stmt);
    sqlite3_close(db);
    return 0;
}

以上示例首先使用sqlite3_prepare_v2()函数将SQL语句"SELECT 1"编译成字节码并准备好执行,接着使用sqlite3_step()函数执行SQL语句并输出结果。再次调用sqlite3_step()函数会导致返回101的错误代码,因为SQL语句已经执行完毕且无法再次执行。接下来,使用sqlite3_reset()函数重置SQL语句的状态,使其可以重新执行。最后使用sqlite3_finalize()函数清理sqlite3_stmt对象并关闭数据库连接。

注意:sqlite3_reset()仅重置SQL语句的状态,包括其绑定参数、计数器和游标位置等等,不会清除上一次查询的结果数据,需要使用sqlite3_clear_bindings()函数清除之前的参数绑定。

sqlite3_finalize

使用完sqlite3stmt之后清理预处理语句占用的资源。

sqlite3_finalize函数的声明如下:

cpp 复制代码
int sqlite3_finalize(sqlite3_stmt *pStmt);

sqlite3stmt是一个预处理语句的指针,在使用完sqlite3stmt之后,使用sqlite3finalize来释放占用的资源,返回值为SQLITEOK代表操作成功,SQLITEBUSY代表sqlite3stmt连接正在被其他线程使用,SQLITE_ERROR代表出现其他错误。

sqlite3finalize的作用是结束一个预处理语句的执行,调用该函数会释放sqlite3stmt结构体占用的内存。在使用完sqlite3stmt之后,使用sqlite3finalize进行清理是非常重要的,它可以释放sqlite3stmt连接占用的资源,并且可以检查语法错误等问题,比如程序是否忘记释放sqlite3stmt导致程序内存泄漏等情况。

以下是一个使用sqlite3_finalize的示例:

cpp 复制代码
#include <stdio.h>
#include <sqlite3.h>
int main(void) {
  sqlite3 *db;
  char *zErrMsg = 0;
  int rc;
  const char *sql;
  rc = sqlite3_open(":memory:", &db);
  sql = "CREATE TABLE PERSON(ID INT PRIMARY KEY NOT NULL, NAME TEXT NOT NULL, AGE INT NOT NULL);";
  rc = sqlite3_exec(db, sql, NULL, 0, &zErrMsg);
  if (rc != SQLITE_OK) {
    fprintf(stderr, "SQL error: %s", zErrMsg);
    sqlite3_free(zErrMsg);
  }
  sqlite3_stmt *stmt;

  sql = "INSERT INTO PERSON(ID, NAME, AGE) VALUES(1, 'John', 25);";
  rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
  if (rc != SQLITE_OK) {
    fprintf(stderr, "SQL error: %s", zErrMsg);
    sqlite3_free(zErrMsg);
  }
  rc = sqlite3_step(stmt);
  if (rc != SQLITE_DONE) {
    fprintf(stderr, "Execution Failed: %s\n", sqlite3_errmsg(db));
  }
  sqlite3_finalize(stmt);
  sqlite3_close(db);
  return 0;
}

以上示例程序首先通过sqlite3open()函数打开一个内存数据库,创建一个名为PERSON的表。接着使用sqlite3preparev2()函数在表中插入一条数据。在数据插入完毕后,使用sqlite3finalize()函数释放sqlite3stmt结构体占用的内存。然后,使用sqlite3close()函数关闭数据库。

可以看到,示例程序使用sqlite3finalize()函数结束sqlite3stmt结构体,以释放内存,并保证我们不会出现内存泄漏的情况。

sqlite3_prepare类

在SQLite3的C语言API中,有多个版本的sqlite3_prepare函数,包括sqlite3_prepare、sqlite3_prepare16、sqlite3_prepare16_v2、sqlite3_prepare16_v3、sqlite3_prepare_v2和sqlite3_prepare_v3函数。它们都被用于编译SQL语句为字节码,为后续的查询执行做准备,并返回准备好的语句的sqlite3_stmt对象的指针。

1、sqlite3_prepare函数
cpp 复制代码
int sqlite3_prepare(
  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 */
);

该函数用于对SQL语句进行编译,生成SQLite的字节码。其中,db是数据库句柄,zSql是要编译的SQL语句,nByte是SQL语句的长度,ppStmt是sqlite3_stmt的指针的指针,它在函数运行成功后将指向一个sqlite3_stmt对象,包含与此SQL语句执行相关的信息,如参数和结果集的列数。pzTail指向SQL语句中未编译的部分的第一个字符的指针。

2. sqlite3_prepare16和sqlite3_prepare16_v2函数
cpp 复制代码
int sqlite3_prepare16(
  sqlite3* db,                   /* Database handle */
  const void* zSql,              /* SQL statement, UTF-16 encoded */
  int nByte,                     /* Maximum length of zSql in bytes. */
  sqlite3_stmt** ppStmt,         /* OUT: Statement handle */
  const void** pzTail            /* OUT: Pointer to unused portion of zSql */
);
int sqlite3_prepare16_v2(
  sqlite3* db,                   /* Database handle */
  const void* zSql,              /* SQL statement, UTF-16 encoded */
  int nByte,                     /* Maximum length of zSql in bytes. */
  sqlite3_stmt** ppStmt,         /* OUT: Statement handle */
  const void** pzTail            /* OUT: Pointer to unused portion of zSql */
  int *pnReserved                /* Reserved for future use */
);

这两个函数与sqlite3_prepare函数类似,用于编译SQL语句,区别在于zSql是UTF-16编码的SQL语句。

3. sqlite3_prepare16_v3函数
cpp 复制代码
int sqlite3_prepare16_v3(
  sqlite3* db,                   /* Database handle */
  const void* zSql,              /* SQL statement, UTF-16 encoded */
  int nByte,                     /* Maximum length of zSql in bytes. */
  unsigned int prepFlags,        /* Zero or more SQLITE_PREPARE_* flags */
  sqlite3_stmt** ppStmt,         /* OUT: Statement handle */
  const void** pzTail            /* OUT: Pointer to unused portion of zSql */
  int *pnReserved                /* Reserved for future use */
);

该函数与sqlite3_prepare16_v2函数类似,不同之处在于多了一个prepFlags参数,这个参数是用于控制编译过程的属性,如 SQLITE_PREPARE_PERSISTENT、SQLITE_PREPARE_NO_VTAB、 SQLITE_PREPARE_DESERIALIZED 等。

4. sqlite3_prepare_v2函数和sqlite3_prepare_v3函数
cpp 复制代码
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 */ 
); 
int sqlite3_prepare_v3(
 sqlite3 *db,             /* Database handle */ 
 const char *zSql,        /* SQL statement, UTF-8 encoded */ 
 int nByte,               /* Maximum length of zSql in bytes. */ 
 unsigned int prepFlags,  /* Zero or more SQLITE_PREPARE_* flags */ 
 sqlite3_stmt **ppStmt,   /* OUT: Statement handle */ 
 const char **pzTail      /* OUT: Pointer to unused portion of zSql */ 
);

这两个函数也是用于编译SQL语句,ppStmt参数返回一个sqlite3_stmt结构体指针,pzTail参数类似 sqlite3_prepare16_v3的 pzTail参数,它用于存放未被编译的 SQL 语句字符(UTF-8编码)位置。因为sqlite3_prepare_v2和sqlite3_prepare_v3函数使用UTF-8编码,而sqlite3_prepare、sqlite3_prepare16、sqlite3_prepare16_v2、sqlite3_prepare16_v3函数使用UTF-16编码。

以上是SQLite3 C语言API中的6种预处理函数,它们用于编译SQL语句,生成SQLite的字节码,为后续的查询执行做准备,并返回准备好的语句的sqlite3_stmt对象的指针。其中,选择哪一个预处理函数取决于需求的功能和SQL语句编码格式。

以下是一个使用SQLite3 C语言API中的sqlite3_prepare_v2函数编译SQL语句的示例:

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <sqlite3.h>
int main(void) {
  sqlite3 *db;
  char *err_msg = 0;
  int rc = sqlite3_open("example.db", &db);
  if (rc != SQLITE_OK) {
    fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db));
    sqlite3_close(db);
    return 1;
  }
  const char *sql = "SELECT * FROM person";
  sqlite3_stmt *stmt;
  rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
  if (rc != SQLITE_OK) {
    fprintf(stderr, "Failed to prepare statement: %s\n", sqlite3_errmsg(db));
    sqlite3_close(db);
    return 1;
  }
  while (sqlite3_step(stmt) == SQLITE_ROW) {
    int id = sqlite3_column_int(stmt, 0);
    char *name = (char *)sqlite3_column_text(stmt, 1);
    int age = sqlite3_column_int(stmt, 2);
    printf("ID = %d, NAME = %s, AGE = %d\n", id, name, age);
  }
  sqlite3_finalize(stmt);
  sqlite3_close(db);
  return 0;
}

该示例程序首先使用sqlite3_open()函数打开名为"example.db"的数据库。接着,使用sqlite3_prepare_v2()函数编译一个查询语句,并返回一个sqlite3_stmt对象的指针,包含与此SQL语句执行相关的信息。然后,使用sqlite3_step()函数遍历结果集,使用sqlite3_column_xxx()函数获取结果集中的每一行数据。最后,使用sqlite3_finalize()函数释放sqlite3_stmt结构体占用的内存,并使用sqlite3_close()函数关闭数据库。

相关推荐
YashanDB1 小时前
【YashanDB知识库】XMLAGG方法的兼容
数据库·yashandb·崖山数据库
独行soc1 小时前
#渗透测试#漏洞挖掘#红蓝攻防#护网#sql注入介绍11基于XML的SQL注入(XML-Based SQL Injection)
数据库·安全·web安全·漏洞挖掘·sql注入·hw·xml注入
风间琉璃""2 小时前
bugkctf 渗透测试1超详细版
数据库·web安全·网络安全·渗透测试·内网·安全工具
drebander2 小时前
SQL 实战-巧用 CASE WHEN 实现条件分组与统计
大数据·数据库·sql
IvorySQL2 小时前
IvorySQL 4.0 发布:全面支持 PostgreSQL 17
数据库·postgresql·开源数据库·国产数据库·ivorysql
18号房客3 小时前
高级sql技巧进阶教程
大数据·数据库·数据仓库·sql·mysql·时序数据库·数据库架构
Dawnㅤ3 小时前
使用sql实现将一张表的某些字段数据存到另一种表里
数据库·sql
张声录13 小时前
【ETCD】【实操篇(十二)】分布式系统中的“王者之争”:基于ETCD的Leader选举实战
数据库·etcd
运维&陈同学3 小时前
【模块一】kubernetes容器编排进阶实战之基于velero及minio实现etcd数据备份与恢复
数据库·后端·云原生·容器·kubernetes·etcd·minio·velero
有态度的马甲3 小时前
一种基于etcd实践节点自动故障转移的思路
数据库·etcd