matrixorigin / matrixorigin/matrixone
[Bug]: prepared numeric CAST truncates fractional parameters instead of rounding
- Dominant language
- Go
- Stars
- 1.9k
- Forks
- 311
- Avg merge
- 1d 3h
- Merged PRs (30d)
- 768
Description
## 现象
MatrixOne `main`(`fc621e3616d229c7a29d0c80e73ed8eb1997459c`)对 PreparedStatement 参数执行 `CAST(? AS SIGNED/UNSIGNED)` 时,把带小数的 numeric 参数按字符串整数前缀截断;同一值作为 DECIMAL/DOUBLE 字面量、列或 user variable 直接 CAST 时则按数值规则舍入。
```sql
PREPARE p FROM 'SELECT CAST(? AS SIGNED),CAST(? AS UNSIGNED)';
SET @a=1.5,@b=1.5;
EXECUTE p USING @a,@b;
SET @a=-1.5,@b=-1.5;
EXECUTE p USING @a,@b;
```
MatrixOne:
```text
1 1
-1 18446744073709551615
```
MySQL 8.0.46:
```text
2 2
-2 18446744073709551614
```
MatrixOne 自身的非 PreparedStatement 控制组也说明参数路径改变了值语义:
```sql
SELECT CAST(1.5 AS SIGNED),CAST(-1.5 AS SIGNED);
-- 2, -2
CREATE TABLE src(d DECIMAL(10,1),f DOUBLE,v VARCHAR(10));
INSERT INTO src VALUES (1.5,1.5,'1.5'),(-1.5,-1.5,'-1.5');
SELECT CAST(d AS SIGNED),CAST(f AS SIGNED),CAST(v AS SIGNED) FROM src;
-- DECIMAL/DOUBLE: ±2;VARCHAR: ±1
```
在 SQL-level `PREPARE/EXECUTE USING` 与真实 MySQL binary prepared protocol 中均可复现。使用 Go MySQL driver 发送 `float64(±1.5)` 时,MatrixOne 仍返回 ±1,MySQL 返回 ±2;整数和 NULL 参数控制组一致。
该问题会进入写路径:
```sql
CREATE TABLE dst(id INT PRIMARY KEY,d DECIMAL(10,1));
PREPARE pi FROM
'INSERT INTO dst VALUES (?,CAST(? AS SIGNED))';
SET @id=1,@d=1.5;
EXECUTE pi USING @id,@d;
```
MatrixOne 写入 `1.0`,MySQL 写入 `2.0`。正负 `1.5`、`1.6`、显式 DECIMAL、DOUBLE、字符串、整数、NULL 和重复执行均表现稳定。
## 期望
PreparedStatement 应保留参数的 numeric runtime kind。DECIMAL/DOUBLE 参数进入显式整数 CAST 时应使用与直接 numeric CAST 一致的舍入规则,不能因为参数传输使用文本载体而退化为字符串前缀截断。
## 代码定位
- frontend/process 已为参数维护 `PrepareParamInteger`、`PrepareParamFloat`、`PrepareParamDecimal` 等 runtime kind。
- `pkg/sql/plan/function/func_cast.go` 的 `NewExplicitCast` / `newCast` 主要根据参数 vector 的物理 `fromType` 分派;typed DECIMAL/DOUBLE 能进入 `decimalToInt64Explicit` / `floatToInt64Explicit` 并执行舍入。
- Prepared 参数的载体仍为 text/varlen 时,执行落入 `parseSignedExplicitCastString` / `parseUnsignedExplicitCastString`,`1.5` 被当作整数前缀 `1`,没有利用已有的 `PrepareParamKind` 恢复 numeric cast 路径。
## 复现信息
- MatrixOne main:`fc621e3616d229c7a29d0c80e73ed8eb1997459c`
- MySQL:8.0.46
- SQL PREPARE 与 Go MySQL driver binary prepare 均重复执行 3 次;正负 half、非 half、DECIMAL/DOUBLE/string/integer/NULL、direct variable、列和 INSERT 路径结果一致
Contributor guide
Assessment
This issue has not been assessed yet.