Skip to content

[CALCITE-7731] Bound plain-notation expansion of DECIMAL literals to prevent parse-time OutOfMemoryError - #5204

Merged
rubenada merged 1 commit into
apache:mainfrom
rubenada:CALCITE-7731
Aug 22, 2026
Merged

[CALCITE-7731] Bound plain-notation expansion of DECIMAL literals to prevent parse-time OutOfMemoryError#5204
rubenada merged 1 commit into
apache:mainfrom
rubenada:CALCITE-7731

Conversation

@rubenada

Copy link
Copy Markdown
Contributor

Jira Link

CALCITE-7731

Changes Proposed

BigDecimal accepts any int exponent, so a DECIMAL literal such as DECIMAL '1E2147483647' (~12 characters) parses to a BigDecimal whose plain-notation form would be one character per digit: a multi-gigabyte allocation (potentially an OOM error).

Three places call BigDecimal.toPlainString() on a value derived from user-supplied input and would attempt that allocation:

SqlParserUtil.parseDecimalLiteral
SqlNumericLiteral.toValue
RexBuilder.makeLiteral

It is required to add a check in there to prevent an OOM error.

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

Not easy to tell by eye whether all the places where the conversion happens have been instrumented.

I wonder whether the exception message size is a concern. Is the problem only when the original literal is small but the internal representation is large?

@Override public String toValue() {
final BigDecimal bd = getValueNonNull();
if (exact) {
if (!SqlUtil.isBoundedDecimal(bd)) {

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.

could this error message be very large too?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, well spotted. I have changed it into bd.toString() , which should be the less OOM-risky alternative.

@rubenada

Copy link
Copy Markdown
Contributor Author

Not easy to tell by eye whether all the places where the conversion happens have been instrumented.

I wonder whether the exception message size is a concern. Is the problem only when the original literal is small but the internal representation is large?

The problem is mostly when toPlainString method is used, whose OOM risk can be quite high.
I have searched manually the callers of this method, and I think the PR covers all places susceptible to have a potential OOM risky input value from the user. There was another occurrence in SqlImplementor, I've just included the check in there just in case.

@rubenada rubenada added the LGTM-will-merge-soon Overall PR looks OK. Only minor things left. label Aug 22, 2026
@sonarqubecloud

Copy link
Copy Markdown

@rubenada
rubenada merged commit 5eb36fb into apache:main Aug 22, 2026
19 checks passed
@skrcode

skrcode commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

@rubenada — I ran JAIPilot Cloud against an earlier exact head of this now-merged PR. It produced an AI-generated test-only draft covering the three DECIMAL plain-notation bound guards that lacked direct tests: skrcode#4

The cloud run passed the focused tests and 16,649-test core build. Since the original PR is merged, this would need to be rebased as a follow-up if the coverage is still useful. Nothing is auto-merged.

@rubenada

Copy link
Copy Markdown
Contributor Author

@skrcode you're right, initially I planned to apply this patch at SqlParser level only (which seems the more likely scenario for a risky user-defined input leading to this potential OOM situation), but finally I decided to include the check also in other (potentially risky) places calling BigDecimal#toPlainString (but did not add tests for them).
You can open a separate, follow-up PR to add the extra tests to improve our test coverage. We'd appreciate it.

@skrcode

skrcode commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Thanks @rubenada — I opened #5212 with the three follow-up regression tests: #5212

It is rebased on current main and contains test changes only. The focused tests, full core build (16,658 tests with zero failures), and repository-wide build all pass locally; Apache Jenkins is also running its independent check.

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

Labels

LGTM-will-merge-soon Overall PR looks OK. Only minor things left.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants