Skip to content

[BugFix] Exclude NULL rows for negated MATCH in OR inverted-index fallback#76350

Open
Beauuu-0826 wants to merge 2 commits into
StarRocks:mainfrom
Beauuu-0826:bugfix/gin-or-fallback-negated-null
Open

[BugFix] Exclude NULL rows for negated MATCH in OR inverted-index fallback#76350
Beauuu-0826 wants to merge 2 commits into
StarRocks:mainfrom
Beauuu-0826:bugfix/gin-or-fallback-negated-null

Conversation

@Beauuu-0826

@Beauuu-0826 Beauuu-0826 commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Why I'm doing:

The OR-MATCH inverted-index fallback returned NULL rows for negated MATCH
predicates nested inside an OR (e.g. col1 MATCH 'a' OR col2 NOT MATCH 'b').
Under SQL three-valued logic NOT (NULL MATCH x) is NULL, not TRUE, so those
NULL rows must not be returned. The canonical AND filtering path
(ColumnExprPredicate::seek_inverted_index) already handled this correctly by
subtracting the NULL posting list; the fallback path did not.

What I'm doing:

The fallback built its bitmap from the raw positive-match posting list and
flipped membership at evaluate() time for negated predicates. Because NULL
rows are never present in a posting list, the flip selected them, producing
extra rows.

This PR builds the fallback bitmap through
ColumnExprPredicate::seek_inverted_index instead — the same path the normal
AND filtering uses — so the bitmap already is the set of rows for which the
predicate is TRUE (matches intersected for a plain MATCH; matches and NULLs
subtracted for a negated MATCH). evaluate() then selects rows by plain
membership with no flip, and the rewriter treats an empty bitmap as
ALWAYS_FALSE unconditionally. The now-unused is_negated_expr() is removed
and read_inverted_index() is made private (it is only an implementation
detail of seek_inverted_index).

Tests: a C++ unit test for the no-flip evaluate() contract, plus SQL
regression cases under test/sql/test_inverted_index proving a negated MATCH
inside an OR excludes NULL rows while a sibling OR arm can still legitimately
select them.

What type of PR is this:

  • BugFix
  • Feature
  • Enhancement
  • Refactor
  • UT
  • Doc
  • Tool

Does this PR entail a change in behavior?

  • Yes, this PR will result in a change in behavior.
  • No, this PR will not result in a change in behavior.

If yes, please specify the type of change:

  • Interface/UI changes: syntax, type conversion, expression evaluation, display information
  • Parameter changes: default values, similar parameters but with different default values
  • Policy changes: use new policy to replace old one, functionality automatically enabled
  • Feature removed
  • Miscellaneous: upgrade & downgrade compatibility, etc.

Checklist:

  • I have added test cases for my bug fix or my new feature
  • This pr needs user documentation (for new or modified features or behaviors)
    • I have added documentation for my new feature or new function
    • This pr needs auto generate documentation
  • This is a backport pr

Bugfix cherry-pick branch check:

  • I have checked the version labels which the pr will be auto-backported to the target branch
    • 4.1
    • 4.0
    • 3.5

…lback

The OR-MATCH inverted-index fallback built its bitmap from the raw
positive-match posting list and flipped membership at evaluate() time for
negated predicates. Because NULL rows are never present in a posting list, a
negated predicate (NOT (col MATCH x)) selected them through the flip, which
violates SQL three-valued logic: NOT (NULL MATCH x) is NULL, not TRUE, so the
NULL rows must not be returned.

Build the fallback bitmap through ColumnExprPredicate::seek_inverted_index
instead, so it already is the set of rows for which the predicate is TRUE
(matches intersected for a plain MATCH; matches and NULLs subtracted for a
negated MATCH), consistent with the normal AND filtering path. evaluate() then
selects rows by plain membership with no flip, and the rewriter treats an empty
bitmap as ALWAYS_FALSE unconditionally. Drop the now-unused is_negated_expr()
and make read_inverted_index() private.

Signed-off-by: eason <1569163626@qq.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
@CelerData-Reviewer

Copy link
Copy Markdown

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 28067c6f55

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread be/src/storage/rowset/or_match_fallback_visitor.h
…ed-index seek

seek_inverted_index cleared the row bitmap whenever the match literal was empty
(read_inverted_index returned nullopt), regardless of negation. That dropped
every row for NOT (col MATCH ''), even though MATCH '' matches nothing and its
negation is TRUE for all non-null rows. This surfaced once the OR-MATCH fallback
started reusing seek_inverted_index.

Substitute an empty posting set for the nullopt case and reuse the shared
with_not / intersect path, so col MATCH '' keeps no rows while NOT (col MATCH '')
keeps every non-null row (only NULLs stay out). Fixes the same latent bug on the
AND filtering path. Add SQL regression for both the AND and OR-MATCH fallback
paths.

Signed-off-by: eason <1569163626@qq.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
@Beauuu-0826 Beauuu-0826 force-pushed the bugfix/gin-or-fallback-negated-null branch from c006d54 to 7ceb086 Compare July 14, 2026 10:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants