SQLiteC/C++接口详细介绍之sqlite3类(三)

上一篇:SQLiteC/C++接口详细介绍之sqlite3类(二)
下一篇:暂未发表

6.sqlite3_create_module与sqlite3_create_module_v2函数

用于创建自定义SQLite模块。创建自定义模块可以让SQLite具有更高的灵活性并满足不同的需求,开发者可以使用该函数创建自己的模块创建自定义的SQL函数、聚合函数和虚拟表等功能。

要使用sqlite3_create_module_v2函数创建自定义模块,需要先定义一个sqlite3_module结构体,该结构体包含了自定义模块需要实现的一组回调函数。这些回调函数通过sqlite3_create_module_v2函数注册到SQLite数据库中。

如下2中格式

cpp 复制代码
int sqlite3_create_module(
  sqlite3 *db,               /*SQLite数据库的句柄,用于指定该模块所属的数据库*/
  const char *zName,         /* 模块的名字,在SQLite数据库中必须唯一,用于描述该模块的作用和功能 */
  const sqlite3_module *p,   /* 自定义模块的结构体,包含了自定义模块需要实现的回调函数 */
  void *pClientData          /* 自定义的客户端数据指针,用于在回调函数中传递数据*/
);
int sqlite3_create_module_v2(
  sqlite3 *db,               /* SQLite数据库的句柄,用于指定该模块所属的数据库 */
  const char *zName,         /* 模块的名字,在SQLite数据库中必须唯一,用于描述该模块的作用和功能 */
  const sqlite3_module *p,   /*自定义模块的结构体,包含了自定义模块需要实现的回调函数*/
  void *pClientData,         /*自定义的客户端数据指针,用于在回调函数中传递数据 */
  void(*xDestroy)(void*)     /*模块销毁时候执行的自定义函数指针 */
);

两个函数返回值为整型,如果注册成功,返回 SQLITE_OK 表示成功,否则返回其他错误码,表示注册失败。一旦注册成功,该自定义模块就可以在SQLite数据库中使用了。

注意:

sqlite3_create_module_v2函数最后一个参数xDestroy是可选的,用于指定自定义模块销毁时执行的函数指针。当该可选参数不为空时,SQLite数据库在销毁该模块时将调用该函数。在该函数中,开发者可以释放模块中使用的不再需要的内存、关闭打开的文件和句柄等清理工作。如果不需要执行销毁函数的操作,可以将 xDestroy 参数设置为NULL,在这种情况下,SQLite不会调用任何函数。在绝大多数情况下,xDestroy参数都被设置为NULL。

下面是一个简单的例子来说明如何使用sqlite3_create_module_v2来创建一个自定义SQLite模块以实现自定义的SQlite函数:

cpp 复制代码
#include <sqlite3.h>
#include <stdio.h>
#include <stdlib.h>
// 自定义函数:计算两个整数之和
static void sumFunc(sqlite3_context *context, int argc, sqlite3_value **argv)
{
    if (argc == 2 && sqlite3_value_type(argv[0]) == SQLITE_INTEGER && sqlite3_value_type(argv[1]) == SQLITE_INTEGER) {
        sqlite3_int64 a = sqlite3_value_int64(argv[0]);
        sqlite3_int64 b = sqlite3_value_int64(argv[1]);
        sqlite3_int64 sum = a + b;
        sqlite3_result_int64(context, sum);
    } else {
        sqlite3_result_error(context, "Invalid arguments for sum function", -1);
    }
}
// 定义module结构体,注册自定义函数
static sqlite3_module myModule = {0, 0, 0, 0, 0, 0, 0,0,0,sumFunc};
int main(void)
{
    sqlite3 *db;
    char *errMsg;
    // 打开数据库
    if (sqlite3_open(":memory:", &db) != SQLITE_OK) {
        fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
        sqlite3_close(db);
        exit(1);
    }
    // 注册自定义模块
    if (sqlite3_create_module_v2(db, "myfunc", &myModule, NULL, NULL) != SQLITE_OK) {
        fprintf(stderr, "Can't create module: %s\n", sqlite3_errmsg(db));
        sqlite3_close(db);
        exit(1);
    }
    // 测试自定义模块
    char *sql = "SELECT myfunc(1, 2)";
    if (sqlite3_exec(db, sql, NULL, NULL, &errMsg) != SQLITE_OK) {
        fprintf(stderr, "SQL error: %s\n", errMsg);
        sqlite3_free(errMsg);
        sqlite3_close(db);
        exit(1);
    }
    sqlite3_close(db);
    return 0;
}

在上面的例子中,我们首先实现了一个自定义函数 sumFunc,该函数可以计算两个整数的和。然后,我们定义了一个 myModule sqlite3_module 结构体,将自定义函数通过模块结构体注册到 SQLite 数据库中。

接下来,我们在程序中通过 sqlite3_open() 函数打开了一个内存数据库,并通过 sqlite3_create_module_v2() 函数将自定义模块注册到 SQLite 中。最后,我们使用sqlite3_exec()函数测试了自定义函数的功能,完成测试后关闭了 SQLite 数据库。

7.sqlite3_errstr类函数

可以使用它来将 SQLite 中的错误码转换为相应的文本信息。当执行 SQLite 数据库的 C API 函数时,可能会出现各种错误,例如:SQL 语法错误、数据库不存在或文件打开失败等。此时,SQLite 数据库会返回一个错误码,用户可以使用 sqlite3_errstr() 函数将这个错误码转换为一个描述错误的对应信息。这种对 SQLite 错误码的转换可以帮助程序员快速了解错误所在,更方便地进行问题排查和处理。sqlite3_errstr() 此函数包含一个整形参数错误码,当传递到该函数的错误码是SQLite数据库中存在的错误码之一时,sqlite3_errstr() 返回该错误码的文本表示。否则,该函数返回 "unknown error" 的字符串。相关函数如下:

cpp 复制代码
int sqlite3_errcode(sqlite3 *db);
int sqlite3_extended_errcode(sqlite3 *db);
const char *sqlite3_errmsg(sqlite3*);
const void *sqlite3_errmsg16(sqlite3*);
const char *sqlite3_errstr(int);
int sqlite3_error_offset(sqlite3 *db);

如果与数据库连接D关联的最新sqlite3_*API调用失败,则sqlite3_errcode(D)接口返回该数字结果代码或扩展结果代码API调用。sqlite3_extended_errcode()interface是相同的,只是它始终返回扩展结果代码,即使扩展结果代码是禁用。

sqlite3_errcode()和/或sqlite3_extended_errcode()可能会随着每次API调用而更改。除了,有些接口保证永远不会更改错误代码的值。保留错误代码接口包括:

sqlite3_errcode()

sqlite3_extended_errcode()

sqlite3_errmsg()

sqlite3_errmsg16()

sqlite3_error_offset()

sqlite3_errmsg()和sqlite3_errmsg16()返回英语描述错误的文本,分别为UTF-8或UTF-16,如果没有可用的错误消息,则为NULL。(请参阅SQLite如何处理无效的UTF,了解此规则的例外情况。用于保存错误消息字符串的内存在内部进行管理。应用程序无需担心释放结果。但是,错误字符串可能会被覆盖或解除分配对其他SQLite接口函数的后续调用。

sqlite3_errstr(E)接口返回英文文本将结果代码E描述为UTF-8,如果E不是文本错误消息可用的结果代码。用于保存错误消息字符串的内存在内部进行管理并且不得由应用程序释放。

如果最近的错误引用了输入中的特定标记SQL,sqlite3_error_offset()接口返回字节偏移量该令牌的开头。返回的字节偏移量sqlite3_error_offset()假定输入SQL为UTF8。如果最近的错误未引用输入中的特定标记SQL,则sqlite3_error_offset()函数返回-1。

当使用序列化线程模式时,它可能是如果在两者之间的单独线程上发生第二个错误第一个错误的时间和对这些接口的调用。发生这种情况时,将报告第二个错误,因为这些接口始终报告最新结果。避免这样一来,每个线程都可以获得数据库连接D的独占使用通过在开始之前调用sqlite3_mutex_enter(sqlite3_db_mutex(D))使用D并在之后调用sqlite3_mutex_leave(sqlite3_db_mutex(D))对此处列出的接口的所有调用均已完成。

如果接口出现故障并SQLITE_MISUSE,则表示接口被应用程序错误地调用。在这种情况下,可以设置错误代码和消息,也可以不设置错误代码和消息。

8.sqlite3_prepare类函数

是SQLite C API中用于编译和准备SQL语句的函数之一。使用sqlite3prepare函数可以将一个SQL字符串编译成SQLite内部认识的字节码,该字节码包含了该SQL语句执行的计划。如果该SQL语句后面有参数,那么sqlite3prepare函数会使用占位符代替它们,并返回一个sqlite3stmt类型的指针,该指针可以用于为SQL语句绑定参数、执行SQL语句和获取语句执行的结果。

相关函数:

cpp 复制代码
int sqlite3_prepare(
  sqlite3 *db,            /* 数据库句柄 */
  const char *zSql,       /* SQL语句,UTF-8编码 */
  int nByte,              /* zSql的最大长度,以字节为单位 */
  sqlite3_stmt **ppStmt,  /* 输出:语句句柄 */
  const char **pzTail     /* 输出:zSql未使用的部分的指针 */
);
int sqlite3_prepare_v2(
  sqlite3 *db,            /* 数据库句柄 */
  const char *zSql,       /* SQL语句,UTF-8编码 */
  int nByte,              /* zSql的最大长度,以字节为单位 */
  sqlite3_stmt **ppStmt,  /* 输出:语句句柄 */
  const char **pzTail     /* 输出:zSql未使用的部分的指针 */
);
int sqlite3_prepare_v3(
  sqlite3 *db,            /* 数据库句柄 */
  const char *zSql,       /* SQL语句,UTF-8编码 */
  int nByte,              /* zSql的最大长度,以字节为单位 */
  unsigned int prepFlags, /* 零个或多个SQLITE_PREPARE_标志 */
  sqlite3_stmt **ppStmt,  /* 输出:语句句柄 */
  const char **pzTail     /* 输出:zSql未使用的部分的指针 */
);
int sqlite3_prepare16(
  sqlite3 *db,            /* 数据库句柄 */
  const void *zSql,       /* SQL语句,UTF-16编码 */
  int nByte,              /* zSql的最大长度,以字节为单位 */
  sqlite3_stmt **ppStmt,  /* 输出:语句句柄 */
  const void **pzTail     /* 输出:zSql未使用的部分的指针 */
);
int sqlite3_prepare16_v2(
  sqlite3 *db,            /* 数据库句柄 */
  const void *zSql,       /* SQL语句,UTF-16编码 */
  int nByte,              /* zSql的最大长度,以字节为单位 */
  sqlite3_stmt **ppStmt,  /* 输出:语句句柄 */
  const void **pzTail     /* 输出:zSql未使用的部分的指针 */
);
int sqlite3_prepare16_v3(
  sqlite3 *db,            /* 数据库句柄 */
  const void *zSql,       /* SQL语句,UTF-16编码 */
  int nByte,              /* zSql的最大长度,以字节为单位 */
  unsigned int prepFlags, /* 零个或多个SQLITE_PREPARE_标志 */
  sqlite3_stmt **ppStmt,  /* 输出:语句句柄 */
  const void **pzTail     /* 输出:zSql未使用的部分的指针 */
);

上述函数均用于准备 SQL 语句并将其编译成可执行的字节码。其中:

  • 参数 db 是数据库连接句柄。

  • 参数 zSql 是要编译的 SQL 语句,可以是 UTF-8 或 UTF-16 编码。

  • 参数 nByte 是 SQL 语句的最大长度,以字节为单位。

  • 参数 ppStmt 是输出参数,该函数将编译后的语句句柄存储在该指针中。

  • 参数 pzTail 是输出参数,该函数将指向未使用的 SQL 语句部分的指针存储在该指针中。

sqlite3_prepare_v3和sqlite3_prepare16_v3函数带有一个额外的参数,即零个或多个SQLITE_PREPARE_标志,可以控制语句如何被准备和编译。

函数返回 SQLITE_OK 表示成功,否则返回其他错误码。

说明:

要执行SQL语句,必须首先将其编译为字节码使用这些例程之一进行编程。或者,换句话说,这些例程是预准备语句对象的构造函数。

首选例程是sqlite3_prepare_v2()。sqlite3_prepare()接口是遗留的,应避免使用。sqlite3_prepare_v3()有一个额外的"prepFlags"选项,用于用于特殊目的。

首选使用UTF-8接口,因为目前是SQLite使用UTF-8进行所有解析。提供UTF-16接口为了方便起见。UTF-16接口的工作原理是将将文本输入到UTF-8中,然后调用相应的UTF-8接口。

第一个参数"db"是从之前成功调用sqlite3_open()、sqlite3_open_v2()或sqlite3_open16()。数据库连接不得已关闭。

第二个参数"zSql"是要编译、编码的语句作为UTF-8或UTF-16。sqlite3_prepare()、sqlite3_prepare_v2()、和sqlite3_prepare_v3()接口使用UTF-8和sqlite3_prepare16()、sqlite3_prepare16_v2()、和sqlite3_prepare16_v3()使用UTF-16。

如果nByte参数为负数,则zSql将读取到第一个零终结者。如果nByte为正数,则它是从zSql读取的字节数。如果nByte为零,则没有准备语句生成。如果调用方知道提供的字符串是nul终止的,则传递一个nByte参数有一个很小的性能优势,即是输入字符串中的字节数,包括NUL终止符。

如果pzTail不为NULL,则*pzTail指向第一个字节过了zSql中第一个SQL语句的末尾。仅限这些例程编译zSql中的第一个语句,因此*pzTail指向什么仍未编译。

*ppStmt指向已编译的预准备语句,该语句可以是使用sqlite3_step()执行。如果出现错误,则设置*ppStmt设置为NULL。如果输入文本不包含SQL(如果输入为空string或注释),则*ppStmt设置为NULL。调用过程负责删除已编译的SQL语句在完成后使用sqlite3_finalize()。ppStmt不能为NULL。

成功后,sqlite3_prepare()系列例程返回SQLITE_OK;否则返回错误代码。

sqlite3_prepare_v2()、sqlite3_prepare_v3()、sqlite3_prepare16_v2()、和sqlite3_prepare16_v3()接口建议用于所有新程序。较旧的接口(sqlite3_prepare()和sqlite3_prepare16())为了向后兼容而保留,但不建议使用它们。在"vX"接口中,预准备语句返回的(sqlite3_stmt对象)包含原始SQL文本。这会导致sqlite3_step()接口在三种方式上表现不同:

如果数据库架构发生更改,而不是按原样返回SQLITE_SCHEMA总是用来做,sqlite3_step()会自动重新编译SQL语句,然后尝试再次运行它。在sqlite3_step()放弃并返回错误之前,将发生多达SQLITE_MAX_SCHEMA_RETRY次重试。

发生错误时,sqlite3_step()将返回详细的错误代码或扩展错误代码之一。遗留行为是sqlite3_step()只会返回泛型SQLITE_ERROR结果代码应用程序必须再次调用sqlite3_reset()才能找到问题的根本原因。使用"v2"准备接口,则会立即返回错误的根本原因。

如果特定值绑定到host参数WHERE子句可能会影响语句的查询计划选择,然后语句将自动重新编译,就好像曾经有过一样架构更改,在进行任何更改后的第一个sqlite3_step()调用时添加到该参数的绑定中。WHERE子句参数的特定值可能会影响如果参数是LIKE或GLOB运算符的左侧,或者将参数与索引列进行比较,则选择查询计划并启用SQLITE_ENABLE_STAT4编译时选项。

sqlite3_prepare_v3()与sqlite3_prepare_v2()的不同之处仅在于具有额外的prepFlags参数,它是一个由零或更多SQLITE_PREPARE_*标志。这sqlite3_prepare_v2()接口的工作原理与sqlite3_prepare_v3()的prepFlags参数为零。

上述函数均用于准备SQL语句并将其编译成可执行的字节码。其中:

-参数db是数据库连接句柄。

-参数zSql是要编译的SQL语句,可以是UTF-8或UTF-16编码。

-参数nByte是SQL语句的最大长度,以字节为单位。

-参数ppStmt是输出参数,该函数将编译后的语句句柄存储在该指针中。

-参数pzTail是输出参数,该函数将指向未使用的SQL语句部分的指针存储在该指针中。

sqlite3_prepare_v3和sqlite3_prepare16_v3函数带有一个额外的参数,即零个或多个SQLITE_PREPARE_标志,可以控制语句如何被准备和编译。

函数返回SQLITE_OK表示成功,否则返回其他错误码。

相关推荐
计算机学姐4 分钟前
基于SSM的宠物领养平台
java·vue.js·spring·maven·intellij-idea·mybatis·宠物
K.L.Zous5 分钟前
Arduino键盘
c++
泰山小张只吃荷园14 分钟前
期末Python复习-输入输出
java·前端·spring boot·python·spring cloud·docker·容器
Mr_Xuhhh17 分钟前
程序地址空间
android·java·开发语言·数据库
fpcc17 分钟前
c++应用网络编程之十五Nagle算法
网络·c++
YSRM22 分钟前
异或-java-leetcode
java·算法·leetcode
大明湖的狗凯.26 分钟前
MySQL 中的乐观锁与悲观锁
java·数据库·mysql
z2023050831 分钟前
linux之调度管理(13)- wake affine 唤醒特性
java·开发语言
AI人H哥会Java32 分钟前
【JAVA】Java高级:Java网络编程——TCP/IP与UDP协议基础
java·开发语言
萧萧玉树1 小时前
分布式在线评测系统
前端·c++·后端·负载均衡