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()函数关闭数据库。

相关推荐
Karoku06629 分钟前
【企业级分布式系统】ELK优化
运维·服务器·数据库·elk·elasticsearch
小技与小术2 小时前
数据库表设计范式
数据库·mysql
安迁岚2 小时前
【SQL Server】华中农业大学空间数据库实验报告 实验三 数据操作
运维·服务器·数据库·sql·mysql
安迁岚2 小时前
【SQL Server】华中农业大学空间数据库实验报告 实验九 触发器
数据库·sql·mysql·oracle·实验报告
Loganer2 小时前
MongoDB分片集群搭建
数据库·mongodb
LKID体2 小时前
Python操作neo4j库py2neo使用之创建和查询(二)
数据库·python·neo4j
刘大浪2 小时前
后端数据增删改查基于Springboot+mybatis mysql 时间根据当时时间自动填充,数据库连接查询不一致,mysql数据库连接不好用
数据库·spring boot·mybatis
一只爱撸猫的程序猿2 小时前
简单实现一个系统升级过程中的数据平滑迁移的场景实例
数据库·spring boot·程序员
无敌岩雀2 小时前
MySQL中的索引
数据库·mysql
a_安徒生3 小时前
linux安装TDengine
linux·数据库·tdengine