Skip to content

[CALCITE-5845] Select a very large predicate throw threw 'java.lang.StackOverflowError' exception in SqlNode to RelNode phase - #5384

Merged
xuzifu666 merged 1 commit into
apache:mainfrom
xuzifu666:calcite-5845
Nov 5, 2026
Merged

xuzifu666 merged 1 commit into
apache:mainfrom
xuzifu666:calcite-5845

Conversation

@xuzifu666

Copy link
Copy Markdown
Member

jira: https://issues.apache.org/jira/browse/CALCITE-5845

This pr is aimed to fix StackOverflowError, without this changes test such as testLargeAndPredicate would error out with 'java.lang.StackOverflowError'.

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

I see 6 changes and only 4 tests.
Does each change have coverage in the new tests?

@xuzifu666

Copy link
Copy Markdown
Member Author

I see 6 changes and only 4 tests. Does each change have coverage in the new tests?

Thank you for the point, these tests only covered the convertlet change; the rest got flat n-ary input (depth 1) and decomposeDisjunction wasn't reached at all.
I added more test case to cover it. Now each of the 6 changes has a dedicated unit test (20k-level binary tree on a 256KB-stack thread), all verified would failed on the main branch. @mihaibudiu

List<RexNode> rexList,
List<RexNode> notList) {
if (rexPredicate == null || rexPredicate.isAlwaysTrue()) {
// Use an explicit stack to avoid StackOverflowError on deeply nested ANDs

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.

only ANDs or deep expressions in general?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

General, not just ANDs, the loop handles nodes of any kind, and NOT delegates a deep OR operand to the also-iterative decomposeDisjunction. Comment updated to 'deeply nested expressions'.

continue;
}
final RexCall call = (RexCall) current;
if (!isFlat(call.getOperands(), call.getOperator())) {

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.

I haven't checked if this function may be recursive.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

It's non-recursive and it only loops over an explicit ArrayDeque, and the private list overload is the original non-recursive exists() check. testIsFlatDeeplyNested verifies it: overflows against the old code on a 256KB stack, passes in latest commit.

* <a href="https://issues.apache.org/jira/browse/CALCITE-5845">[CALCITE-5845]
* StackOverflowError when SQL has a very large predicate with many ANDs</a>.
*
* <p>Verifies that {@link RexUtil#flattenAnd} does not recurse when given a

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.

Strictly speaking it's not checking the lack of recursion, but the ability to compute with a small stack.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Make sense, the test checks "completes on a small stack", which is the observable contract. Reworded all six javadocs accordingly.

/** Runs {@code callable} on a thread with a small stack, so that a recursive
* implementation of the callee overflows quickly, while an iterative
* implementation completes. */
private static <T> T runInSmallStack(Callable<T> callable) {

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.

how does this differ from the other function with the same name?

@xuzifu666 xuzifu666 Nov 3, 2026 •

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

It doesn't differ, because they were identical copies. Extracted into a shared org.apache.calcite.test.SmallStack used by both classes In a recent commit.

@sonarqubecloud

sonarqubecloud Bot commented Nov 3, 2026

Copy link
Copy Markdown

…tackOverflowError' exception in SqlNode to RelNode phase
@xuzifu666

Copy link
Copy Markdown
Member Author

I had squashed the commits and would merge it if there no more comments in coming days.

@xuzifu666 xuzifu666 added the LGTM-will-merge-soon Overall PR looks OK. Only minor things left. label Nov 4, 2026
@xuzifu666
xuzifu666 merged commit 81ec38a into apache:main Nov 5, 2026
13 checks passed
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.

2 participants