matrixorigin / matrixorigin/matrixone

[Bug]: signed integer division uses DOUBLE and corrupts exact relational results

Open
#28,580 3 comments 0 reactions 1 assignee Claimed by @Ariznawlll View on GitHub
kind/bug severity/s0
Dominant language
Go
Stars
1.9k
Forks
311
Avg merge
1d 3h
Merged PRs (30d)
768

Description

## 现象

MatrixOne `main`(`fc621e3616d229c7a29d0c80e73ed8eb1997459c`)将两个有符号整数的 `/` 运算推导为 `DOUBLE`。当值超过 `2^53` 后,不同的 `BIGINT` 会折叠为同一个浮点值,不仅 SELECT 数值不准确,还会改变过滤、分组、排序、Join 和 CTAS 的结果。

```sql
CREATE TABLE src(id INT PRIMARY KEY, s BIGINT, KEY k_s(s));
INSERT INTO src VALUES
(1,9007199254740991),
(2,9007199254740992),
(3,9007199254740993),
(4,9223372036854775807);

SELECT id,s/1,s/3 FROM src ORDER BY id;
```

MatrixOne 中,id=2 和 id=3 的 `s/1` 都是 `9007199254740992.0`,`s/3` 都是 `3002399751580330.5`。MySQL 8.0.46 使用 DECIMAL 精确运算,保留四个不同整数,并且 id=3 的 `s/3` 为 `3002399751580331.0000`。

该类型推导会进一步造成关系结果错误:

```sql
-- MatrixOne 错误命中 id=2 和 id=3;MySQL 只命中 id=3
SELECT id FROM src WHERE s/1=9007199254740993;

-- MatrixOne 合并为一个 count=2 的 group;MySQL 是两个 count=1 的 group
SELECT s/1 AS q,COUNT(*)
FROM src WHERE id IN (2,3) GROUP BY q;

CREATE TABLE rhs AS SELECT id,s FROM src WHERE id IN (2,3);
-- MatrixOne 产生 4 个匹配;MySQL 只有 (2,2)、(3,3)
SELECT a.id,b.id
FROM src a JOIN rhs b ON a.s/1=b.s/1
WHERE a.id IN (2,3);

CREATE TABLE dst AS
SELECT id,s/1 AS q FROM src WHERE id IN (2,3);
```

MatrixOne 的 `dst.q` 是 `DOUBLE`,两行均被持久化成 `9007199254740992.0`;MySQL 的 `dst.q` 是 `DECIMAL(23,4)`,两行仍可区分。VIEW 元数据也分别为 `DOUBLE` 与 `DECIMAL(23,4)`。

覆盖结果还表明:

- `TINYINT/SMALLINT/INT/BIGINT` 的 signed/signed `/` 均被推导为 `DOUBLE`;
- `BIGINT UNSIGNED / 整数` 与 `DECIMAL / 整数` 在 MatrixOne 中走 DECIMAL 路径,能够保持精度;
- 显式 `DOUBLE` 的控制组与 MatrixOne 当前 signed/signed 结果相同;
- `SUM(BIGINT)/整数` 因 `SUM` 已返回 DECIMAL,能够保持精度;
- 字面量与 PreparedStatement 都受 signed/signed 浮点化影响,因此并非只发生在协议参数路径。

## 期望

精确数值类型之间的 `/` 应使用能够表示输入整数域的 DECIMAL 结果,不能在没有显式近似数值操作数时转为 DOUBLE。过滤、分组、排序、Join、VIEW 和 CTAS 必须基于未丢失的精确商。

## 代码定位

- `pkg/sql/plan/function/type_check.go` 的 `fixedBinaryCastRule2` 将 signed integer / signed integer 组合映射到 `FLOAT64`。
- `pkg/sql/plan/function/arithmetic.go` 的 `divFn` 因此进入 `T_float64` 分支并执行近似除法。
- 同一张 coercion 表对 `UINT64`/`DECIMAL` 组合选择 `DECIMAL128`,解释了相邻控制组精确而 signed/signed 路径丢失精度的差异。

## 复现信息

- MatrixOne main:`fc621e3616d229c7a29d0c80e73ed8eb1997459c`
- MySQL:8.0.46
- 整数宽度、`2^53±1`、`INT64_MAX`、signed/unsigned/decimal/double、PreparedStatement、WHERE、GROUP BY、ORDER BY、JOIN、VIEW、CTAS 和聚合控制组重复执行 3 次,结果一致

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.