Skip to content

[Bug]: arithmetic predicate transposition changes floating results and hides integer overflow #29542

Closed

Description

@XuPeng-SH

Is there an existing issue for the same bug?

  • I checked existing issues (ConstantTranspose, transpose, floating arithmetic filter, floating point wrong result).

Branch Name

main

Commit ID

7b3d0c3

Other Environment Information

Linux amd64, CPU build, Go 1.26.4. Local isolated CN/TN/logservice with MinIO, GOMAXPROCS=2. Reproduced on actual SQL execution, not only plan inspection.

Actual Behavior

The planner algebraically transposes top-level arithmetic equality without proving preservation of floating rounding or integer overflow behavior. This produces incorrect rows and suppresses an arithmetic error. A logically equivalent OR wrapper uses the guarded Boolean normalization and gives different results.

Steps to Reproduce

CREATE DATABASE qa_transpose;
USE qa_transpose;
CREATE TABLE fp(v DOUBLE);
INSERT INTO fp VALUES (1e-17), (0), (NULL);
SELECT v, v + 1e0 = 1e0 FROM fp ORDER BY v;
-- NULL NULL; 0 true; 0.00000000000000001 true
SELECT v FROM fp WHERE v + 1e0 = 1e0 ORDER BY v;
-- Actual: only 0. Expected: 0 and 0.00000000000000001.
SELECT v FROM fp WHERE v + 1e0 = 1e0 OR v IS NULL ORDER BY v;
-- Actual: all three rows, including 1e-17.
EXPLAIN SELECT v FROM fp WHERE v + 1e0 = 1e0;
-- Filter Cond: (fp.v = 0)

CREATE TABLE ov(v BIGINT);
INSERT INTO ov VALUES (9223372036854775807);
SELECT v FROM ov WHERE v + 1 = 9223372036854775807;
-- Actual: empty result, no error.
SELECT v, v + 1 FROM ov;
-- ERROR 1690 (22003): int64 out of range (9223372036854775807 + 1).

Expected Behavior

Filter evaluation must preserve SQL arithmetic semantics. For binary64, 1e-17 + 1 rounds to 1, so transposing this equality to v=0 is invalid. Integer overflow must not disappear because a predicate is algebraically rearranged.

Additional Information

pkg/sql/plan/utils.go:ConstantTranspose still performs legacy equality algebra using canTranspose/getPath and inverse +/- operations. normalizeNativeRangeDirection protects Boolean subtrees, but top-level equality falls through to the old transformation. The existing planner normalization should own a consistent arithmetic safety policy across both paths; avoid a separate competing rewrite or merely patching this literal example.

Found during integrated QA of the latest ten author commits, including #29525. Attribution is not part of this report. The new Boolean guard does not close the shared top-level arithmetic domain invariant.

Suggested regression coverage: DOUBLE/FLOAT absorbed increments, cancellation and subtraction direction, prepared bindings, AND/OR nesting, integer overflow/underflow, safe exact controls, and indexed/composite-sortkey filters. Compare actual row sets and error behavior to independently evaluated expressions, not only expected generated plans.

Activity

  1. self-assigned this
    on Oct 1, 2026
  2. added a commit that references this issue on Oct 1, 2026
    e784c47
  3. Ariznawlll commented on Oct 2, 2026

    @Ariznawlll
    Collaborator

    测试版本

    • 分支:main
    • Commit:d50a2d475a406829f67127fef7b2ad4abc1c1d3d
    • 部署方式:本地全新单 CN mo-service,独立数据目录;MySQL 文本协议与 server-side PREPARE
    • 测试日期:2026-10-02

    原问题验证

    按 issue 原始语义在上述 commit 重新执行并重复 3 次。浮点谓词改写后同时保留 0 与 1e-17 两行;BIGINT 溢出仍返回 ERROR 1690。

    Happy Path 覆盖

    覆盖等式移项前后、正负极小量和常量侧交换。

    Unhappy Path 覆盖

    覆盖整数越界、NULL、NaN/Inf;未因优化改写改变错误或结果集合。

    白盒验证

    关联修复 #29544 已进入当前 main。同时将本 issue 的可公开观察契约固化为独立回归,避免只依赖实现细节或共享测试间接判断。

    回归测试

    测试证据

    • 精确测试版本:d50a2d475a406829f67127fef7b2ad4abc1c1d3d
    • 当前结果:浮点谓词改写后同时保留 0 与 1e-17 两行;BIGINT 溢出仍返回 ERROR 1690。
    • 回归代码与 golden result 已提交到 MOTR #209;本地全量 14_issue_regression 中观察到的旧 GOROOT/历史 golden/并发锁冲突属于既有无关失败,以上新增用例单独重跑均稳定通过。

    测试结论

    测试通过。

  4. Ariznawlll commented on Oct 8, 2026

    @Ariznawlll
    Collaborator

    在当前 main bab4b3286a0dd5683a9b291763817722233e586c 上补充了算术谓词的交换方向、prepared、索引和 DML 原子性覆盖。

    DOUBLE 表含 -1e-17 / 0 / 1e-17 / NULL / -1 / 1 / 2 / 1e16 并建立二级索引:

    • projection 的 (v+1=1) IS TRUE 与 WHERE v+1=1 均返回前三个微小值;
    • 1+v=1、v-1=-1、1-v=1 返回同一集合;
    • v+1e16=1e16 返回 -1e-17,0,1e-17,-1,1,保留 binary64 吸收/half-even 行为;
    • OR NULL 包装在上述三行基础上准确加入 NULL 行;
    • EXPLAIN 保留原表达式 ((v + 1) = 1),没有代数改写成 v=0;
    • 同一 prepared statement 在 1/1 → 1e16/1e16 → NULL/1 → 1/1 复用时,结果集合依次准确且能恢复。

    BIGINT 表含 MinInt64、-1、0、1、MaxInt64 并建立二级索引:

    • v+1、1+v、v-1、-1+v 的上下溢出路径都返回明确 1690,而不是被转置隐藏;
    • AND/OR 包装没有绕过溢出;
    • prepared 溢出后将参数改为 0/0,同一 handle 能恢复并只返回 v=0 行;
    • UPDATE ... WHERE v+1=MaxInt64 返回溢出后,五行 n 均保持 0,未发生部分更新;
    • 错误后连接继续可用。

    本轮浮点行集与逐行表达式一致,整数错误可见性及 DML 原子性也保持一致。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

kind/bugSomething isn't working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions