Skip to content

fix: accept any numeric literal for OPTIMIZE options - #833

Open
jackylee-ch wants to merge 3 commits into
lance-format:mainfrom
jackylee-ch:fix/optimize-numeric-literals
Open

jackylee-ch wants to merge 3 commits into
lance-format:mainfrom
jackylee-ch:fix/optimize-numeric-literals

Conversation

@jackylee-ch

Copy link
Copy Markdown
Contributor

The extension grammar boxes a numeric literal as Long, Float or Double depending on how it was written (1, 0.5, 0.5d), but buildOptions cast each option to one fixed box. So OPTIMIZE t WITH (materialize_deletions_threshold = 1) — the natural way to ask for "always materialize" — threw java.lang.ClassCastException: class java.lang.Long cannot be cast to class java.lang.Float, and = 0.5d threw the same for Double. Only 0.5 and 0.5f parse as Float and worked; the one existing test happens to use 0.2f.

Routes every numeric option through a Number accessor that takes all three boxes, and names the option when the value is not numeric — the wording AddIndexExec.extractTrain already uses for train. Booleans get the same treatment, so a wrong literal no longer surfaces a raw cast error either.

Reverting just the threshold accessor reproduces the Long cannot be cast to Float failure and turns the non-numeric message back into class java.lang.String cannot be cast to class java.lang.Float. With the fix: 7 tests, 0 failures on both 4.1/2.13 and 3.5/2.12.

The extension grammar boxes a numeric literal as Long, Float or Double depending on
how it was written (`1`, `0.5`, `0.5d`), but buildOptions cast each option to one
fixed box. So `OPTIMIZE t WITH (materialize_deletions_threshold = 1)` — the natural
way to ask for "always materialize" — threw

  java.lang.ClassCastException: class java.lang.Long cannot be cast to class java.lang.Float

and `= 0.5d` threw the same for Double. Only `0.5` and `0.5f` parsed as Float and
worked; the one existing test happened to use `0.2f`.

Route every numeric option through a Number accessor that takes all three boxes, and
give the non-numeric case an error naming the option, matching the wording
AddIndexExec.extractTrain already uses for `train`. The boolean options get the same
treatment so a wrong literal no longer surfaces a raw cast error.
@github-actions github-actions Bot added the bug Something isn't working label Sep 15, 2026
lance-gatekeeper[bot]

This comment was marked as outdated.

@lance-gatekeeper lance-gatekeeper Bot added K-approved Latest Gatekeeper recommendation permits acceptance. K-risk Latest Gatekeeper recommendation includes a non-blocking risk. labels Sep 15, 2026
The shared Number accessor widened the Long options too, so `num_threads = 2.5`
would have run compaction with a silently truncated 2 where it previously failed.
Narrow the widening to the one option documented as a float, and reject a
non-integer literal for the Long options by name instead.
@lance-gatekeeper lance-gatekeeper Bot removed K-approved Latest Gatekeeper recommendation permits acceptance. K-risk Latest Gatekeeper recommendation includes a non-blocking risk. labels Sep 15, 2026
lance-gatekeeper[bot]

This comment was marked as outdated.

@lance-gatekeeper lance-gatekeeper Bot added the K-approved Latest Gatekeeper recommendation permits acceptance. label Sep 15, 2026

// The grammar boxes 1 as Long, 0.5 as Float and 0.5d as Double, so every spelling has to
// reach withMaterializeDeletionsThreshold instead of failing the cast. Only the first call
// has fragments left to compact, so assert acceptance rather than the compaction counts.

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.

nit: test is pretty selfdocumenting we can drop the comment

Comment on lines +54 to +59
/**
* The SQL extension grammar boxes a numeric literal as Long, Float or Double depending on how it
* was written (`1`, `0.5`, `0.5d`), so an option documented as a float cannot assume one of them.
* Options documented as Long stay Long-only on purpose: widening them would let `2.5` through as
* a silently truncated `2` instead of being rejected.
*/

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.

nit: we can drop the javadoc. floatArg is any Number. the Long-only rule belongs on longArg w/Number.longValue would turn 2.5 into 2.

@geruh

geruh commented Sep 18, 2026

Copy link
Copy Markdown
Collaborator

Thanks for working on this @jackylee-ch!!

@lance-gatekeeper lance-gatekeeper Bot removed the K-approved Latest Gatekeeper recommendation permits acceptance. label Sep 18, 2026

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

Gate recommendation: approve.

The current merge retains the byte-for-byte patch reviewed at e614328. The Long-option conversion remains corrected: integer-valued options reject fractional literals by name, while materialize_deletions_threshold continues to accept the supported numeric spellings. The original threshold-boxing failure remains covered, and no significant residual risk remains.

@lance-gatekeeper lance-gatekeeper Bot added the K-approved Latest Gatekeeper recommendation permits acceptance. label Sep 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working K-approved Latest Gatekeeper recommendation permits acceptance.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants