Skip to content

fix(plan): handle NULL left operand in IN predicates - #25236

Merged
mergify[bot] merged 2 commits into
matrixorigin:mainfrom
jiangxinmeng1:fix-null-in-left-in-predicate
Jun 30, 2026
Merged

fix(plan): handle NULL left operand in IN predicates#25236
mergify[bot] merged 2 commits into
matrixorigin:mainfrom
jiangxinmeng1:fix-null-in-left-in-predicate

Conversation

@jiangxinmeng1

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 #25221

What this PR does / why we need it:

  • Return a typed boolean NULL when scalar IN / NOT IN has a constant NULL left operand.
  • Avoid generating invalid casts to ANY for expressions like NULL IN (1, NULL).
  • Add regression coverage for NULL IN (1, NULL) and NULL NOT IN (1, NULL).

@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 found two substantive blockers here.

  1. NULL IN (...) is now folded before volatility checks, so RHS side effects disappear.

The new early return replaces the whole predicate with a constant NULL before the RHS expressions are preserved in the plan. That bypasses the normal “do not fold volatile functions” safeguard. So a query like SELECT NULL IN (nextval('s')) would no longer advance the sequence, which is an observable behavior change and not compatible with the normal planner rule that volatile expressions must not be folded away.

Suggested fix: don’t replace the predicate with a constant at bind time. Keep the normal RHS/type-checking path and only fold when the RHS is provably side-effect-free.

  1. The early return skips RHS validation, so invalid scalar-vs-row IN lists can now be silently accepted.

Because the new return happens before the normal RHS comparison-building/validation path, malformed RHS items are never checked if the left operand is a literal NULL. A query like NULL IN ((1,2)) should still be rejected as an invalid scalar-vs-row comparison, not accepted as a constant NULL.

Suggested fix: keep the normal RHS shape/type validation, then handle the constant-NULL result after the list form is known to be valid.

The current SQL regression covers the original reported bug, but it does not protect either of these new semantic regressions.

@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.

All three concerns from the earlier review are resolved:

  1. Volatility: NULL IN (nextval('s')) correctly advances the sequence (regression proves currval = 1).
  2. RHS validation: NULL IN ((1,2)) now uses ErrOperandColumns (ER_OPERAND_COLUMNS, SQLSTATE 21000) — proper user-facing error, not internal error.
  3. No early folding: validation happens before the NULL special-case.

LGTM.

@mergify

mergify Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Queued — the merge queue status continues in this comment ↓.

@mergify mergify Bot added the queued label Jun 30, 2026
@mergify

mergify Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Merge Queue Status

  • Entered queue2026-06-30 08:24 UTC · Rule: main · triggered by rule Automatic queue on approval for main
  • Checks passed · in-place
  • Merged2026-06-30 09:35 UTC · at b9d96e6a808188d778effb14e9ea953075dad7ff · squash

This pull request spent 1 hour 11 minutes 33 seconds in the queue, including 1 hour 11 minutes 11 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 / 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
  • any of [🛡 GitHub branch protection]:
    • check-success = Matrixone CI / SCA Test on Linux/arm64
    • check-neutral = Matrixone CI / SCA Test on Linux/arm64
    • check-skipped = Matrixone CI / SCA Test on Linux/arm64

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/S Denotes a PR that changes [10,99] lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants