首页 > 解决方案 > SQLite - 浮动粒度打破了独特的约束?

问题描述

我在 Windows 上使用 SQLite 3.25.2,从官方页面https://sqlite.org/download.html下载了最新的预编译二进制文件

执行以下代码

DROP TABLE IF EXISTS TestReal;
CREATE TABLE TestReal(A REAL UNIQUE);
INSERT INTO TestReal values (9223372036854775807.0);
INSERT INTO TestReal values (9223372036854775807.0 - 1);
INSERT INTO TestReal values (9223372036854775807.0 - 2);
INSERT INTO TestReal values (9223372036854775807.0 - 3);

正如预期的那样失败,因为 9223372036854775807.0 是 2^63,这些数字超出了所有整数都可以精确表示为双精度数的范围。我是说

sqlite> select 9223372036854775807.0 = 9223372036854775807.0 - 1;
1
sqlite> select 9223372036854775807.0 = 9223372036854775807.0 - 512;
1

A 列是唯一的,因此打印“UNIQUE 约束失败:TestReal.A”消息非常有意义。但似乎有一个意想不到的解决方法

DROP TABLE IF EXISTS TestReal;
CREATE TABLE TestReal(A REAL UNIQUE);
INSERT INTO TestReal values (9223372036854775807);
INSERT INTO TestReal values (9223372036854775807 - 1);
INSERT INTO TestReal values (9223372036854775807 - 2);
INSERT INTO TestReal values (9223372036854775807 - 3);

运行没有任何问题。以下查询确认该表现在恰好插入了 4 个值,但只有一个不同的值,尽管具有唯一约束

sqlite> SELECT * FROM TestReal;
9.22337203685478e+18
9.22337203685478e+18
9.22337203685478e+18
9.22337203685478e+18
sqlite> SELECT DISTINCT(A) FROM TestReal;
9.22337203685478e+18
sqlite> .schema
CREATE TABLE TestReal(A REAL UNIQUE);

所以我的问题是:这是 SQLite 中的错误吗?还是我没有正确理解“独特”的实际含义?

标签: sqlitefloating-point

解决方案


随着 SQLite 3.29.0 的发布,它解决了,这从来都不是预期的行为,而是一个错误。该错误仍然存​​在于 3.28.0 中,但不在 3.29.0 中,在最新版本中,我的两个代码片段都按预期失败。

这是包含修复的提交: https ://www.sqlite.org/src/info/9b0915272f4d4052

我通过在 3.28.0 源代码上手动应用此提交并替换MEM_IntReal(MEM_Int | MEM_Real).

在官方 SQLite 邮件列表中报告可能的错误后打开错误票证: https ://www.mail-archive.com/sqlite-users@mailinglists.sqlite.org/msg115214.html

我也报告了它,实际上早一点,但我的报告并没有引起太多关注: https ://www.mail-archive.com/sqlite-users@mailinglists.sqlite.org/msg112655.html


推荐阅读