关于无效 UTF,SQLite 遵循垃圾进,垃圾出的策略 (GIGO)。如果您将无效 UTF 插入 SQLite 数据库,然后尝试查询该数据,您得到的结果可能与您输入的不完全相同。如果您输入了垃圾,那么您可能不会抱怨得到不同的垃圾。
在本讨论中,"无效 UTF" 可以指以下任何情况
UTF-16 中的无效代理对。
UTF-8 中的无效多字节序列。
使用超过表示单个码位的必要的 UTF-8 字节数。(示例:将 'A' 编码为 0xc1, 0x01 的两个字节序列,而不是单个 0x41 字节。)
字符串中嵌入的 NUL 字符 (U+0000)。
无效的组合字符序列。
UTF-8 或 UTF-16 字节序列,编码的数字不是定义的 Unicode 字符。
如果您将无效 UTF 插入 SQLite 数据库,SQLite 不会保证您能获得什么样的文本。但它承诺无效 UTF 永远不会导致内存错误 (数组越界、读取或写入未初始化的内存等),至少对于 SQLite 的内置处理而言是如此。换句话说,无效 UTF 不会导致 SQLite 崩溃。
当然,此承诺仅适用于 SQLite 的核心组件,而不适用于应用程序提供的扩展。如果应用程序添加了新的应用程序定义的 SQL 函数、虚拟表、排序规则或其他扩展,并且数据库包含无效 UTF,则无效 UTF 可能会传递到这些扩展中。如果无效 UTF 导致其中一个扩展崩溃,那么这是扩展的问题,而不是 SQLite 的问题。
SQLite 不会尝试强制执行 UTF 格式规则。您可以将无效 UTF 插入 TEXT 字段,SQLite 不会对此有任何抱怨。它尽力存储无效的 TEXT。SQLite 认为自己的角色是存储引擎,而不是文本格式验证引擎。
SQLite 不会承诺始终保留无效的 UTF,但它确实会尽力而为。一般来说,如果您将无效 UTF 插入 SQLite,您将得到完全相同的字节序列,只要您没有要求 SQLite 以任何方式转换文本即可。
例如,如果您将一些带有无效代理的 UTF-16LE 插入具有 PRAGMA encoding=UTF16LE 的数据库表的 TEXT 列中,然后使用 sqlite3_column_text16() 查询该列,您可能会获得完全相同的无效 UTF-16。但是,如果您将相同的无效 UTF-16LE 内容插入 PRAGMA encoding=UTF8 数据库中,则该内容在存储时必须转换为 UTF8,这可能会对该内容造成不可逆转的更改。或者,如果您将相同的无效 UTF-16LE 内容插入 PRAGMA encoding=UTF16LE 数据库,但使用 sqlite3_column_text() 读取它,则在读取时必须进行 UTF16 到 UTF8 的转换,该转换可能会引入不可逆转的更改。
或者,假设您使用的是 UTF-8 (最常见的情况)。无效 UTF-8 通常会通过数据库而不会改变其字节序列。但是,如果您尝试使用 substr() 或 replace() 等 SQL 函数转换无效 UTF-8,或者尝试使用 LIKE 运算符进行字符串匹配,那么您可能会得到意外的结果。
因此,换句话说,SQLite 不会主动尝试破坏您的无效文本。但是,当您要求 SQLite 对无效 UTF 进行转换时,不能保证这些转换是可逆的,甚至是有意义的。
如果数据库模式包含无效 UTF 的名称 (表名、列名、索引名等),SQLite 将继续正常运行。就 SQLite 而言,这些名称只是字节序列。SQLite 不关心它们是否是有效的 UTF。
在生成错误消息时 (例如,使用 sqlite3_errmsg()),SQLite 有时会将数据库模式的部分嵌入到错误消息中。如果这些嵌入的模式元素是无效的 UTF,则生成的错误消息也可能是无效的 UTF。同样,PRAGMA integrity_check 和类似语句的输出有时会嵌入模式元素的名称。如果这些模式元素名称是无效的 UTF,则命令的输出也将是无效的 UTF。
此页面上次修改于 2023-12-05 14:43:20 UTC