Skip to content

fix(filter): handle constant vectors in CBloomFilter/CRoaring/Cbitmap#25720

Open
cpegeric wants to merge 3 commits into
matrixorigin:mainfrom
cpegeric:issue_25621
Open

fix(filter): handle constant vectors in CBloomFilter/CRoaring/Cbitmap#25720
cpegeric wants to merge 3 commits into
matrixorigin:mainfrom
cpegeric:issue_25621

Conversation

@cpegeric

@cpegeric cpegeric commented Jul 14, 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 #25621 #25618

What this PR does / why we need it:

The three cgo membership filters confused a vector's logical row count with its physical element count for CONSTANT vectors. A constant stores a single physical value (none for const-null) but reports Length() = row count, so passing the logical length to C over the 1-element (or empty) physical buffer read past the buffer — false negatives ([1,0,0] instead of [1,1,1]) — or panicked on the empty const-null buffer (&data[0]). This affects PK/partition filtering and IVF_FLAT bloom ops, where a single-value predicate folds to a constant vector.

Process only the PHYSICAL element(s) and broadcast the result to all logical rows:

  • bloomfilter/cbloomfilter.go: vecPhysCount (1 for non-null const, 0 for const-null, Length() otherwise), emitConstNull (all-zero result, every row NULL), broadcastResults (expand the single result across rows). All six fixed/varlena test/add/testAndAdd helpers short-circuit const-null, guard nitem==0 (also fixes a latent panic on regular length-0 fixed vectors), call C with the physical count, then broadcast.
  • docfilter/croaring.go: vecFixedArgs computes the physical nitem; new finalizeVecResults broadcasts for constants. cbitmap.go shares both (its TestVector rewired). Build-from-constant now contains the value.

Non-const vectors take a byte-identical path. Tests: TestCBloomFilterConstVector (const int64/varchar, non-null + null, across Test/Add/TestAndAdd), TestCRoaringConstVector + TestCbitmapConstVector (present/absent/null probes, build-from-const). All fail on the original code (verified via git-revert) and pass under -race.

…matrixorigin#25621)

The three cgo membership filters confused a vector's logical row count with its
physical element count for CONSTANT vectors. A constant stores a single physical
value (none for const-null) but reports Length() = row count, so passing the
logical length to C over the 1-element (or empty) physical buffer read past the
buffer — false negatives ([1,0,0] instead of [1,1,1]) — or panicked on the empty
const-null buffer (&data[0]). This affects PK/partition filtering and IVF_FLAT
bloom ops, where a single-value predicate folds to a constant vector.

Process only the PHYSICAL element(s) and broadcast the result to all logical rows:
  - bloomfilter/cbloomfilter.go: vecPhysCount (1 for non-null const, 0 for
    const-null, Length() otherwise), emitConstNull (all-zero result, every row
    NULL), broadcastResults (expand the single result across rows). All six
    fixed/varlena test/add/testAndAdd helpers short-circuit const-null, guard
    nitem==0 (also fixes a latent panic on regular length-0 fixed vectors), call
    C with the physical count, then broadcast.
  - docfilter/croaring.go: vecFixedArgs computes the physical nitem; new
    finalizeVecResults broadcasts for constants. cbitmap.go shares both (its
    TestVector rewired). Build-from-constant now contains the value.

Non-const vectors take a byte-identical path. Tests: TestCBloomFilterConstVector
(const int64/varchar, non-null + null, across Test/Add/TestAndAdd),
TestCRoaringConstVector + TestCbitmapConstVector (present/absent/null probes,
build-from-const). All fail on the original code (verified via git-revert) and
pass under -race.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@cpegeric cpegeric requested a review from XuPeng-SH as a code owner July 14, 2026 10:46
@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 →

…rigin#25618)

matrixorigin#25618 (fixed-width vector APIs panic with "index out of range [0] with length
0" on a zero-length vector) is already resolved by the constant-vector fix
(matrixorigin#25621): an empty vector has physical count 0, so the nitem==0 guards short-
circuit before indexing &fixedData[0]/&results[0]. Add the regression test to
lock it in — TestVector returns empty, AddVector/TestAndAddVector are no-ops that
never invoke the callback, for both fixed-width and variable-length types.

Verified: the test panics on the pre-fix code and passes with the matrixorigin#25621 guards.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

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

The stateless TestVector/AddVector fixes look correct, but TestAndAddVector does not preserve the logical per-row semantics for a constant vector.

Reproduced on head 1a3664c with both INT64 and VARCHAR. On a fresh filter, a regular vector containing [99, 99, 99] reports callback states [false, true, true]: the first logical row inserts the value, so subsequent duplicate rows observe it. The equivalent constant vector (value 99, logical length 3) reports [false, false, false].

The C test-and-add implementation is intentionally stateful and processes elements sequentially. This PR calls it once for the single physical constant value, then uses broadcastResults to copy the pre-insert result to every logical row. Broadcasting is valid for TestVector, but not for TestAndAddVector because the filter state changes after the first logical row. This can let repeated logical values all appear new to a deduplication callback and also makes constant and flat representations of the same rows observably different.

Please give TestAndAddVector state-aware constant handling and add fixed-width plus varlena equivalence tests against a flat repeated-value vector. The current test only asserts [false, false, false], which bakes in the incorrect behavior.

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.

3 participants