以下是 SQLite 开发人员用来跟踪、检查和理解 SQLite 核心库行为的一些随机技巧。
这些技巧旨在帮助理解 SQLite 核心库本身,而不是仅仅使用 SQLite 的应用程序。
在 命令行 shell 中使用 ".eqp full" 选项
当您有一个正在调试或试图理解的 SQL 脚本时,通常很有用的是在 命令行 shell 中使用 ".eqp full" 设置运行它。当 ".eqp" 设置为 FULL 时,shell 会在实际运行每个命令之前自动显示该命令的 EXPLAIN 和 EXPLAIN QUERY PLAN 输出。
为了提高可读性,还可以设置 ".echo on",以便输出包含原始 SQL 文本。
较新的 ".eqp trace" 命令执行 ".eqp full" 执行的所有操作,并且还开启 VDBE 追踪。
使用编译时选项启用调试功能。
建议的编译时选项包括
SQLITE_ENABLE_TREETRACE 和 SQLITE_ENABLE_WHERETRACE 选项在 编译时选项 文档中没有记录,因为它们不受官方支持。它们的作用是在命令行 shell 中激活 ".treetrace" 和 ".wheretrace" 点命令,分别为生成 SELECT 和 DML 语句以及 WHERE 子句代码的逻辑提供低级跟踪输出。
从调试器调用 sqlite3ShowExpr() 及类似函数。
当使用 SQLITE_DEBUG 编译时,SQLite 包含一些例程,这些例程会将各种内部抽象语法树结构打印为 ASCII 艺术图。这在调试中非常有用,以便理解 SQLite 正在处理的变量。以下例程可用
这些例程不是 API,可能会发生变化。它们仅用于交互式调试。
在 test_addoptrace 上设置断点
调试 字节码 生成器时,通常需要知道某个特定操作码是在哪里生成的。要轻松找到它,请在调试器中运行脚本。在 "test_addoptrace" 例程上设置断点。然后运行 "PRAGMA vdbe_addoptrace=ON;",然后运行有问题的 SQL 语句。每个操作码在附加到 VDBE 程序时都会显示,并且断点随后会立即触发。单步执行直到到达操作码,然后在堆栈中向后查看以了解它是如何以及在哪里生成的。
这仅在使用 SQLITE_DEBUG 编译时有效。
使用 ".treetrace" 和 ".wheretrace" shell 命令
当命令行 shell 和 SQLite 核心库都使用 SQLITE_DEBUG 和 SQLITE_ENABLE_TREETRACE 以及 SQLITE_ENABLE_WHERETRACE 进行编译时,shell 就会有两个命令用于打开代码生成器最复杂部分的调试功能 - 分别处理 SELECT 语句和 WHERE 子句的逻辑。".treetrace" 和 ".wheretrace" 命令都接受一个可以用十六进制表示的数字参数。每一位都打开调试的不同部分。通常使用 "0xfff" 和 "0xff" 的值。使用 "0" 作为参数可关闭所有跟踪输出。
使用 ".breakpoint" shell 命令
CLI 中的 ".breakpoint" 命令什么也不做,只是调用名为 "test_breakpoint()" 的过程,该过程是一个空操作。
如果您有一个脚本,并且想要从该脚本中间的某个点开始调试,只需在 gdb(或您使用的任何调试器)中在 test_breakpoint() 函数上设置断点,并在您想要停止的地方添加 ".breakpoint" 命令。当您到达第一个断点时,设置您需要的任何其他断点或变量跟踪。
禁用 备用内存分配器
在查找内存分配问题(内存泄漏、释放后使用错误、缓冲区溢出等)时,有时禁用 备用内存分配器 然后在 valgrind 或 MSAN 或其他一些堆内存调试工具下运行测试会很有用。可以使用 SQLITE_CONFIG_LOOKASIDE 接口在启动时禁用备用内存分配器。如果 命令行 shell 使用 "--lookaside 0 0" 命令行选项启动,它将使用该接口禁用备用内存分配器。