Skip to content

fix(sqlengine): keep the exact FLOAT and DOUBLE bound in a forward filter - #818

Merged
egolearner merged 2 commits into
alibaba:mainfrom
jak-pan:fix/float-bound
Oct 20, 2026
Merged

egolearner merged 2 commits into
alibaba:mainfrom
jak-pan:fix/float-bound

Conversation

@jak-pan

@jak-pan jak-pan commented Oct 15, 2026

Copy link
Copy Markdown
Contributor

Keeps FLOAT and DOUBLE range bounds exact when the optimizer moves an inverted-index condition to a forward filter. An exclusive comparison then continues to exclude documents equal to its bound. Closes #817.

Problem on main

On d7b478df9843ddfda23a0021ec09f16c105835a5, price > 1.0000001 and weight > 1.0000000001 each return 1,001 documents in the reproduction instead of 951. The collection contains 50 documents at the bounds and 951 above them, split into a sealed segment of 1,000 and a writing segment of one.

The optimizer converts the binary bound back to text before the forward filter parses it again:

// 2. Revert numeric buf to numeric text
std::string numeric_text{""};
if (QueryInfoHelper::data_buf_2_text(right->text(), data_type,
&numeric_text)) {
right->set_text(numeric_text);
}

data_buf_2_text() uses StringHelper::ToString() for FLOAT and DOUBLE:

if (data_type == zvec::DataType::FLOAT) {
*text = ailego::StringHelper::ToString(*(float *)data_buf.data());
return true;
}
if (data_type == zvec::DataType::DOUBLE) {
*text = ailego::StringHelper::ToString(*(double *)data_buf.data());
return true;
}

Those overloads use std::to_string(), which prints both reproduction bounds as 1.000000 in this build:

//! Convert floating-point number string (double)
static std::string ToString(double val) {
return std::to_string(val);
}
//! Convert floating-point number string (float)
static std::string ToString(float val) {
return std::to_string(val);
}

Changes

  • Print FLOAT and DOUBLE bounds with %.*g and std::numeric_limits<T>::max_digits10 significant digits: 9 for float and 17 for double. For example, 1.0000001f prints as 1.00000012, which parses back to the same float.
  • Add FloatRangeFilter.ForwardScanKeepsExactBound, the collection-level reproduction from the issue. Both filters must return 951 documents.

Tests

Local Release verification on macOS 27.0.1 arm64, Apple clang 21.0.0, CMake 4.3.2. Base production sources matched d7b478df9843ddfda23a0021ec09f16c105835a5; fixed production sources included only this PR's helper change. The regression test was added to both builds.

Test Base This PR
ForwardScanKeepsExactBound 0 passed, 1 failed 1 passed, 0 failed
Seven existing suites 274 passed, 0 failed 274 passed, 0 failed

The regression fails on the base because each query returns 1,001. With the fix each returns 951.

Commands (binaries under build/bin):

cmake --build build --parallel 6 --target collection_float_range_filter_test optimizer_test simple_rewriter_test query_info_test sqlengine_test forward_recall_test invert_recall_test collection_test
build/bin/collection_float_range_filter_test --gtest_filter=FloatRangeFilter.ForwardScanKeepsExactBound
for suite in optimizer_test simple_rewriter_test query_info_test sqlengine_test forward_recall_test invert_recall_test collection_test; do
  build/bin/"$suite"
done

Both builds use the compiler cache and six jobs. Tests run serially. Changed-line formatting passes Apple clang-format 21.0.0 with the repository configuration; git diff --check passes.

Compatibility and cost

From code reading: the integer branches and public StringHelper::ToString() overloads keep their behavior. The conversion is shared by the optimizer and the constant-node conversion helper. A source search found no caller of that constant-node helper.

Each converted FLOAT or DOUBLE bound replaces one decimal conversion with snprintf into a 32-byte stack buffer. The optimizer's choice of scan and engine operations are unchanged. This adds no persistent state, on-disk format, dependency, or public API.

Not covered

  • Linux, other architectures, Python tests, and the full repository suite were not run. Verification covers the regression and the seven listed C++ suites.
  • The pre-commit formatter pins 18.1.8; only Apple clang-format 21.0.0 was available locally.
  • delete_by_filter("price > 1.0000001") on this data fails earlier, on both base and fixed sources, with ExecBatch::ToRecordBatch mismatching schema size. That is a separate defect; this PR does not change it.
  • No public CI result is available before posting.

…lter

When the optimizer moves a range on an indexed field to a forward
filter, data_buf_2_text() turns the bound back into text. For FLOAT and
DOUBLE it used std::to_string(), which keeps six decimals, so
"price > 1.0000001" became "price > 1.000000" on that segment and
returned the documents at 1.0000001. It now prints max_digits10
significant digits (9 for FLOAT, 17 for DOUBLE), which read back as the
same value.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-16T07:47:06.699468Z c66ff5c New commits
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@egolearner egolearner left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM

Thx for the fix.

@jak-pan

jak-pan commented Oct 20, 2026

Copy link
Copy Markdown
Contributor Author

The CI fail doesn't look like coming from me is it?

@egolearner
egolearner merged commit 8397071 into alibaba:main Oct 20, 2026
29 of 32 checks passed
@egolearner

Copy link
Copy Markdown
Collaborator

The CI fail doesn't look like coming from me is it?

Merged.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: FLOAT and DOUBLE range filters include documents at an excluded bound after conversion to a forward scan

4 participants