字符串中的 NUL 字符

、简介

SQLite 允许在数据库中存储的字符串值中间使用 NUL 字符(ASCII 0x00,Unicode \u0000)。但是,在字符串中使用 NUL 会导致令人惊讶的行为:

  1. length() SQL 函数只计算不超过第一个 NUL 的字符

  2. quote() SQL 函数仅显示不超过第一个 NUL 的字符

  3. CLI中 的.dump命令省略了它生成的 SQL 输出中的第一个 NUL 字符和所有后续文本。事实上, CLI在所有上下文中都会忽略第一个 NUL 字符之后的所有内容。

不建议在 SQL 文本字符串中使用 NUL 字符。

2.意外行为

考虑以下 SQL:

CREATE TABLE t1(
  a INTEGER PRIMARY KEY,
  b TEXT
);
INSERT INTO t1(a,b) VALUES(1, 'abc'||char(0)||'xyz');

SELECT a, b, length(b) FROM t1;

上面的 SELECT 语句显示输出:

1,'abc',3

(通过本文档,我们假设CLI设置了“ .mode quote ”。)但是如果您运行:

SELECT * FROM t1 WHERE b='abc';

然后没有行被返回。SQLite 知道 t1.b 列实际上包含一个 7 个字符的字符串,并且 7 个字符的字符串 'abc'||char(0)||'xyz' 不等于 3 个字符的字符串 'abc',并且所以没有行被返回。但是用户可能很容易对此感到困惑,因为CLI输出似乎显示该字符串只有 3 个字符。这似乎是一个错误。但这就是 SQLite 的工作方式。

3.如何判断字符串中是否有 NUL 字符

如果将字符串CAST为 BLOB,则会显示字符串的整个长度。例如:

SELECT a, CAST(b AS BLOB) FROM t1;

给出这个结果:

1,X'6162630078797a'

在 BLOB 输出中,您可以清楚地看到 NUL 字符是 7 个字符的字符串中的第 4 个字符。

另一种更自动化的判断字符串值 X 是否包含嵌入的 NUL 字符的方法是使用如下表达式:

instr(X,char(0))

如果此表达式返回非零值 N,则在第 N 个字符位置存在嵌入的 NUL。因此要计算包含嵌入 NUL 字符的行数:

SELECT count(*) FROM t1 WHERE instr(b,char(0))>0;

4.从文本字段中删除 NUL 字符

以下示例说明如何从表的列中删除 NUL 字符及其后的所有文本。因此,如果您有一个包含嵌入式 NUL 的数据库文件并且您想要删除它们,运行类似于以下的 UPDATE 语句可能会有所帮助:

UPDATE t1 SET b=substr(b,1,instr(b,char(0)))
 WHERE instr(b,char(0));