概述
SQLite 可以配置为在异常发生时调用包含错误代码和简洁错误消息的回调函数。这种机制对于跟踪很少发生和在现场发生的模糊问题非常有帮助。鼓励应用程序开发人员在其产品中利用 SQLite 的错误记录功能,因为它的 CPU 和内存成本非常低,但可以为调试提供巨大帮助。
1.设置错误记录回调
每个进程只能有一个错误记录回调。错误记录回调是在启动时使用类似于以下的 C 代码注册的:
sqlite3_config(SQLITE_CONFIG_LOG, errorLogCallback, pData);
错误记录器回调函数可能看起来像这样:
void errorLogCallback(void *pArg, int iErrCode, const char *zMsg){ fprintf(stderr, "(%d) %s\n", iErrCode, zMsg); }
上面的示例说明了错误记录器回调的签名。但是,在嵌入式应用程序中,通常不会在 stderr 上打印消息。相反,可以将消息存储在预先分配的循环缓冲区中,在调试期间需要诊断信息时可以访问它们。或者也许可以将消息发送到Syslog。不知何故,消息需要存储在开发人员可以访问的地方,而不是显示给最终用户。
不要误解:向最终用户显示错误记录器消息在技术上没有任何错误。这些消息不包含必须防止未经授权查看的敏感或私人信息。相反,这些消息本质上是技术性的,对典型的最终用户没有用处或意义。来自错误记录器的消息是为数据库极客准备的。相应地显示它们。
2.接口细节
sqlite3_config ( SQLITE_CONFIG_LOG ,...) 接口的第三个参数(上例中的“pData”参数)是指向任意数据的指针。SQLite 将此指针传递给错误记录器回调的第一个参数。如果需要,指针可用于传递特定于应用程序的设置或状态信息。或者它可以只是一个被回调忽略的 NULL 指针。
错误记录器回调的第二个参数是一个整数 扩展错误代码。错误记录器的第三个参数是错误消息的文本。错误消息文本存储在调用函数的固定长度堆栈缓冲区中,因此仅在错误记录器回调函数期间有效。如果需要保留消息,错误记录器应该将此消息复制到持久存储中。
错误记录器回调应该像信号处理程序一样对待。应用程序应保存或以其他方式处理错误,然后尽快返回。不应从错误记录器直接或间接调用其他 SQLite API。SQLite不能通过错误记录器回调重入。特别是,当内存分配失败时会调用错误记录器回调,因此尝试在错误记录器内部分配内存通常不是一个好主意。甚至不要考虑尝试将错误消息存储在另一个 SQLite 数据库中。
如果需要,应用程序可以使用sqlite3_log(E,F,..) API 将新消息发送到日志,但不鼓励这样做。sqlite3_log() 接口仅供扩展使用,不适用于应用程序。
3.各种错误信息
可能发送到错误记录器的错误消息及其确切格式会随着版本的变化而变化。因此,应用程序不应依赖于任何特定的错误消息文本格式或错误代码。事物不会反复无常地变化,但它们有时会发生变化。
以下是可能出现在错误记录器回调中的消息种类的部分列表。
任何时候编译 SQL 语句(使用sqlite3_prepare_v2()或其兄弟)或运行 SQL 语句(使用sqlite3_step())时都会记录该错误。
当发生需要重新分析和重新准备准备好的语句的模式更改时,该事件将被记录为错误代码 SQLITE_SCHEMA。重新分析和重新准备通常是自动的(假设 sqlite3_prepare_v2()最初已用于准备语句,这是推荐的)因此这些日志记录事件通常是了解重新准备正在进行的唯一方法。
每当必须恢复数据库时,都会记录 SQLITE_NOTICE 消息,因为先前的编写器在未完成其事务的情况下崩溃。恢复回滚日志时错误代码为 SQLITE_NOTICE_RECOVER_ROLLBACK ,恢复 预 写日志时错误代码为 SQLITE_NOTICE_RECOVER_WAL 。
当数据库文件以可能导致数据库损坏的方式重命名或别名时,将记录 SQLITE_WARNING 消息。(有关其他信息,请参阅1和2。)
内存不足 (OOM) 错误情况会生成带有 SQLITE_NOMEM 错误代码的错误日志记录事件和一条消息,说明失败的分配请求了多少字节的内存。
操作系统接口中的 I/O 错误会生成错误记录事件。这些事件的消息给出了源代码中错误产生的行号,以及在存在相应文件时与事件关联的文件名。
当检测到数据库损坏时,将调用 SQLITE_CORRUPT 错误记录器回调。对于 I/O 错误,错误消息文本包含原始源代码中首次检测到错误的行号。
SQLITE_MISUSE 错误调用错误记录器回调。当在应用程序代码中未一致地检查返回代码时,这对于检测应用程序设计问题很有用。
SQLite 努力保持错误记录器流量低,并且只在确实有问题时才向错误记录器发送消息。应用程序可能会通过故意忽略它们不关心的某些类别的错误消息来进一步剔除错误消息流量。例如,频繁更改数据库架构的应用程序可能希望忽略所有 SQLITE_SCHEMA 错误。
4.总结
强烈建议使用错误记录器回调。事实证明,错误记录器提供的调试信息对于跟踪应用程序进入现场后出现的模糊问题非常有用。事实证明,错误记录器回调在捕获应用程序由于 API 返回代码检查不一致而遗漏的偶然错误方面也很有用。鼓励开发人员在开发周期的早期实施错误记录器回调,以便快速发现意外行为,并在部署过程中保持错误记录器回调处于打开状态。如果错误记录器从未发现问题,则不会造成任何伤害。但是未能设置适当的错误记录器可能会影响以后的诊断能力。