Skip to content

fix(plan): align coalesce decimal scale across branches - #24842

Merged
mergify[bot] merged 9 commits into
matrixorigin:mainfrom
ck89119:issue-24565-decimal256-main
Jun 10, 2026
Merged

fix(plan): align coalesce decimal scale across branches#24842
mergify[bot] merged 9 commits into
matrixorigin:mainfrom
ck89119:issue-24565-decimal256-main

Conversation

@ck89119

@ck89119 ck89119 commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

What type of PR is this?

  • API-change
  • BUG
  • Improvement
  • Documentation
  • Feature
  • Test and CI
  • Code Refactoring

Which issue(s) this PR fixes:

issue #24565

What this PR does / why we need it:

COALESCE over decimal branches with different scales returned the first
branch's scale while carrying another branch's raw value, magnifying the
result (e.g. by 10^5):

SELECT COALESCE(
  CAST(NULL AS DECIMAL(23,2)),
  7.01970 * CAST(-58140.00 AS DECIMAL(23,2))
);
-- before: magnified; after: -408125.3580000 (matches the direct multiplication)

coalesceCheck short-circuited on a direct match without aligning scale/width.
It now falls through to the alignment cast path unless every decimal branch
already shares the same scale and width (new decimalInputsAligned guard).

The companion decimal256-comparison scenario of issue #24565 (a decimal256
CASE result compared with a decimal128) is already handled on main, so this
PR only adds the missing COALESCE alignment. The 3.0-dev branch lacks the
decimal256 comparison support, so that part is delivered separately in #24841.

Added coverage:

  • Test_CoalesceCheck_DecimalScaleAlignment / Test_CoalesceCheck_DecimalAligned_NoCast

Validation:

  • go test ./pkg/sql/plan/function, go vet, gofmt
  • manual verification on a main build: the COALESCE result is no longer magnified
  • mo-tester case_when.sql (incl. the COALESCE repro) passed 101/101 locally

🤖 Generated with Claude Code

issue matrixorigin#24565

COALESCE over decimal branches with different scales returned the first
branch's scale while carrying another branch's raw value, magnifying the
result (e.g. by 10^5):

  SELECT COALESCE(
    CAST(NULL AS DECIMAL(23,2)),
    7.01970 * CAST(-58140.00 AS DECIMAL(23,2))
  );

coalesceCheck short-circuited on a direct match without aligning
scale/width. It now falls through to the alignment cast path unless every
decimal branch already shares the same scale and width (new
decimalInputsAligned guard).

The companion decimal256-comparison part of issue matrixorigin#24565 is already handled
on main; this PR only adds the missing COALESCE alignment.

Added coverage: coalesce scale-alignment / already-aligned unit tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@qodo-code-review

Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@matrix-meow matrix-meow added the size/S Denotes a PR that changes [10,99] lines label Jun 4, 2026
@mergify mergify Bot added the kind/bug Something isn't working label Jun 4, 2026
issue matrixorigin#24565

BVT reproduction for the COALESCE decimal scale alignment fix, plus
regression coverage for comparing a decimal256 CASE result with a
decimal128 value. Result rows are appended in the existing format.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@qodo-code-review

Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@XuPeng-SH XuPeng-SH left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not find a new hard correctness blocker in the implementation itself, but with a high bar I still think the regression coverage is too narrow for a user-visible type-inference fix.

Right now the added tests do prove the core bug is fixed for constant-expression cases, which is good. What is still missing are the more realistic/product-level cases where these decimal-type regressions usually hide:

  1. column-based COALESCE
    The new BVT coverage is still mostly constant-expression driven. I would want at least one table-backed case like COALESCE(dec23_2_col, dec38_7_col) with rows where the first branch is NULL and non-NULL, so we lock the real execution path rather than only planner/unit helpers.

  2. mixed integer + decimal branches
    This PR touches numeric branch unification, but I don’t see a meaningful BVT for cases like COALESCE(int_col, decimal_col) or COALESCE(NULL, 1, CAST(... AS DECIMAL(...))). That is a very common regression surface.

  3. 3+ branch COALESCE
    The current coverage is still mostly 2-branch oriented. A case like COALESCE(NULL, dec_a, dec_b) or COALESCE(NULL, NULL, dec_expr) would better prove the final chosen decimal metadata is stable when more than two branches participate.

  4. metadata/type visibility
    Since the bug is fundamentally about inferred decimal width/scale, I would also like one SQL-level metadata check (for example through CREATE VIEW + DESC) so we know the visible column type is correct, not just the runtime value.

So my conclusion is: the main bug is covered, but the user-visible regression surface is still thinner than I would like. I would be much more comfortable after a small set of realistic SQL/BVT cases is added.

issue matrixorigin#24565

Address review feedback on matrixorigin#24842: extend COALESCE decimal coverage beyond
constant-expression cases to product-level scenarios.

- column-based COALESCE over decimal branches with null/non-null rows
  (COALESCE(dec(23,2), dec(38,7)) -> DECIMAL(38,7))
- mixed integer + decimal branches (column COALESCE(int, dec(20,5)) and
  constant COALESCE(NULL, 1, CAST(.. AS DECIMAL)))
- 3+ branch COALESCE (NULL + two decimals, and all-NULL leading branches)
- visible inferred decimal type via CREATE VIEW + DESC (Type = DECIMAL(38,7))

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@aunjgr aunjgr left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fix in func_binary.go is correct, but the BVT coverage is too thin — constants only. The 4.0-dev backport (#24899) already has the full BVT suite this needs: column-based COALESCE over mixed-scale decimals, mixed integer+decimal branches, 3-branch decimal cases, and a CREATE VIEW + DESC metadata check. Please port that BVT coverage here.

@aunjgr aunjgr left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The BVT coverage is actually complete — column-based, mixed int+decimal, 3-branch, and VIEW+DESC metadata check are all present. The fix in coalesceCheck is correct. No concerns.

@mergify

mergify Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Merge Queue Status

  • Entered queue2026-06-10 10:03 UTC · Rule: main
  • Checks passed · in-place
  • Merged2026-06-10 11:08 UTC · at 3e437f583a811b6232fe7ffb3ca270665803402b · squash

This pull request spent 1 hour 4 minutes 55 seconds in the queue, including 1 hour 4 minutes 23 seconds running CI.

Required conditions to merge
  • #approved-reviews-by >= 1 [🛡 GitHub branch protection]
  • #review-threads-unresolved = 0 [🛡 GitHub branch protection]
  • github-review-decision = APPROVED [🛡 GitHub branch protection]
  • any of [🛡 GitHub branch protection]:
    • check-success = Matrixone Compose CI / multi cn e2e bvt test docker compose(PESSIMISTIC)
    • check-neutral = Matrixone Compose CI / multi cn e2e bvt test docker compose(PESSIMISTIC)
    • check-skipped = Matrixone Compose CI / multi cn e2e bvt test docker compose(PESSIMISTIC)
  • any of [🛡 GitHub branch protection]:
    • check-success = Matrixone Standlone CI / Multi-CN e2e BVT Test on Linux/x64(LAUNCH, PROXY)
    • check-neutral = Matrixone Standlone CI / Multi-CN e2e BVT Test on Linux/x64(LAUNCH, PROXY)
    • check-skipped = Matrixone Standlone CI / Multi-CN e2e BVT Test on Linux/x64(LAUNCH, PROXY)
  • any of [🛡 GitHub branch protection]:
    • check-success = Matrixone Standlone CI / e2e BVT Test on Linux/x64(LAUNCH, PESSIMISTIC)
    • check-neutral = Matrixone Standlone CI / e2e BVT Test on Linux/x64(LAUNCH, PESSIMISTIC)
    • check-skipped = Matrixone Standlone CI / e2e BVT Test on Linux/x64(LAUNCH, PESSIMISTIC)
  • any of [🛡 GitHub branch protection]:
    • check-success = Matrixone CI / SCA Test on Ubuntu/x86
    • check-neutral = Matrixone CI / SCA Test on Ubuntu/x86
    • check-skipped = Matrixone CI / SCA Test on Ubuntu/x86
  • any of [🛡 GitHub branch protection]:
    • check-success = Matrixone CI / UT Test on Ubuntu/x86
    • check-neutral = Matrixone CI / UT Test on Ubuntu/x86
    • check-skipped = Matrixone CI / UT Test on Ubuntu/x86
  • any of [🛡 GitHub branch protection]:
    • check-success = Matrixone Compose CI / multi cn e2e bvt test docker compose(Optimistic/PUSH)
    • check-neutral = Matrixone Compose CI / multi cn e2e bvt test docker compose(Optimistic/PUSH)
    • check-skipped = Matrixone Compose CI / multi cn e2e bvt test docker compose(Optimistic/PUSH)
  • any of [🛡 GitHub branch protection]:
    • check-success = Matrixone Standlone CI / e2e BVT Test on Linux/x64(LAUNCH,Optimistic)
    • check-neutral = Matrixone Standlone CI / e2e BVT Test on Linux/x64(LAUNCH,Optimistic)
    • check-skipped = Matrixone Standlone CI / e2e BVT Test on Linux/x64(LAUNCH,Optimistic)
  • any of [🛡 GitHub branch protection]:
    • check-success = Matrixone Upgrade CI / Compatibility Test With Target on Linux/x64(LAUNCH)
    • check-neutral = Matrixone Upgrade CI / Compatibility Test With Target on Linux/x64(LAUNCH)
    • check-skipped = Matrixone Upgrade CI / Compatibility Test With Target on Linux/x64(LAUNCH)
  • any of [🛡 GitHub branch protection]:
    • check-success = Matrixone Utils CI / Coverage
    • check-neutral = Matrixone Utils CI / Coverage
    • check-skipped = Matrixone Utils CI / Coverage

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

Labels

kind/bug Something isn't working size/M Denotes a PR that changes [100,499] lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants