Skip to content

feat: implement null-safe equal operator (<=>)#23599

Merged
mergify[bot] merged 10 commits intomatrixorigin:mainfrom
gouhongshen:feat/null_safe_equal
Mar 9, 2026
Merged

feat: implement null-safe equal operator (<=>)#23599
mergify[bot] merged 10 commits intomatrixorigin:mainfrom
gouhongshen:feat/null_safe_equal

Conversation

@gouhongshen
Copy link
Contributor

@gouhongshen gouhongshen commented Jan 26, 2026

What type of PR is this?

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

Which issue(s) this PR fixes:

issue ##23009

What this PR does / why we need it:

Summary
This PR implements the NULL-safe equal operator (<=>), providing full compatibility with MySQL semantics. It ensures that NULL <=> NULL returns 1 (TRUE) and Value <=> NULL returns 0 (FALSE), never returning NULL.

Changes

  • Function Registration: Added NULL_SAFE_EQUAL to function_id.go and initialized metadata in init.go and list_operator.go.
  • Execution Logic: Implemented vectorized nullSafeEqualFn in func_compare.go with support for all major data types (Numeric, String, JSON, Decimal, Date/Time, etc.).
  • Plan & Binding:
    • Updated base_binder.go to bind tree.NULL_SAFE_EQUAL to the <=> function.
    • Implemented Tuple expansion logic: (a, b) <=> (c, d) is automatically expanded to (a <=> c) AND (b <=> d).
  • Optimizer Integration: Marked the operator as PRODUCE_NO_NULL, allowing the optimizer to deduce NotNullable properties and perform optimizations like IS NULL constant folding.
  • Safety & Correctness:
    • Join: Explicitly excluded from equi-join identification (IsEqualFunc) to avoid incorrect result dropping in the current Hash
      Join implementation regarding NULL keys.
    • Zonemap: Disabled ZONEMAPPABLE flag to prevent incorrect block pruning, as the generic evaluator currently lacks specialized logic for NULL-safe comparisons.

Testing

  • Added comprehensive BVT cases in test/distributed/cases/function/func_null_safe_equal.sql.
  • Coverage:
    • Basic scalar comparisons with all NULL combinations.
    • Table-based filtering and Join correctness (NULL matching NULL).
    • Complex types: JSON, Decimal (with scale alignment), and Date/Time.
    • Tuple comparisons and nested logic.
    • Optimizer attribute verification (verifying results are never NULL).
  • All tests verified against a live MatrixOne instance.

@matrix-meow matrix-meow added the size/L Denotes a PR that changes [500,999] lines label Jan 26, 2026
@mergify mergify bot added the kind/feature label Jan 26, 2026
@mergify
Copy link
Contributor

mergify bot commented Mar 9, 2026

Merge Queue Status

Rule: main


  • Entered queue2026-03-09 03:11 UTC
  • Checks passed · in-place
  • Merged2026-03-09 05:26 UTC · at d3fe69e2c66ce9a7319750e75b40fc7cc7c0ea6b

This pull request spent 2 hours 15 minutes 43 seconds in the queue, including 53 minutes 25 seconds running CI.

Required conditions to merge
  • #approved-reviews-by >= 1 [🛡 GitHub branch protection]
  • #changes-requested-reviews-by = 0 [🛡 GitHub branch protection]
  • #review-threads-unresolved = 0 [🛡 GitHub branch protection]
  • branch-protection-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/feature size/XL Denotes a PR that changes [1000, 1999] lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants