Skip to content

Comments

[SPARK-55005][SQL] Fix CONTINUE HANDLER to continue loop execution after handling exceptions in loop body#53759

Closed
miland-db wants to merge 2 commits intoapache:masterfrom
miland-db:milan-dankovic_data/continue-handler-fix-loops
Closed

[SPARK-55005][SQL] Fix CONTINUE HANDLER to continue loop execution after handling exceptions in loop body#53759
miland-db wants to merge 2 commits intoapache:masterfrom
miland-db:milan-dankovic_data/continue-handler-fix-loops

Conversation

@miland-db
Copy link
Contributor

What changes were proposed in this pull request?

This PR fixes a critical bug in CONTINUE HANDLER execution within loops. When a CONTINUE HANDLER handled an exception that occurred inside a loop body, the loop would exit completely instead of continuing to the next iteration.

Root cause

The interruptConditionalStatements method in SqlScriptingExecution.scala was designed to skip conditional statements when exceptions occurred in their condition evaluation (e.g., WHILE 1/0 > 0). However, it didn't distinguish between:

  • Exception in condition → loop should be skipped
  • Exception in body → loop should continue to next iteration

The method unconditionally set interrupted = true on all conditional statements, causing loops to exit even when the error occurred during body execution.

The fix

The fix was to add isInCondition: Boolean method to ConditionalStatementExec trait to track whether a conditional statement is currently evaluating its condition or executing its body. It was also needed to implement isInCondition for all 6 ConditionalStatementExec:

  • IfElseStatementExec
  • WhileStatementExec
  • RepeatStatementExec
  • ForStatementExec
  • SearchedCaseStatementExec
  • SimpleCaseStatementExec

Why are the changes needed?

This ensures CONTINUE HANDLER only interrupts conditional statements when exceptions occur during condition evaluation, allowing loops to continue normally when exceptions occur in their bodies.

Does this PR introduce any user-facing change?

No.

How was this patch tested?

Added comprehensive test coverage for CONTINUE HANDLER across all conditional statement types. These tests verify that when an exception occurs inside a loop body and is handled by a CONTINUE HANDLER, the loop continues to the next iteration rather than exiting.

Was this patch authored or co-authored using generative AI tooling?

@github-actions
Copy link

JIRA Issue Information

=== Sub-task SPARK-55005 ===
Summary: CONTINUE handler not working properly when exception occurs inside loops
Assignee: None
Status: Open
Affected: ["4.2.0"]


This comment was automatically generated by GitHub Actions

@github-actions github-actions bot added the SQL label Jan 10, 2026
@miland-db
Copy link
Contributor Author

Adding @cloud-fan and @srielau. Please review

Copy link
Contributor

@srielau srielau left a comment

Choose a reason for hiding this comment

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

LGTM

@cloud-fan
Copy link
Contributor

thanks, merging to master/4.1!

@cloud-fan cloud-fan changed the title [SPARK-55005] Fix CONTINUE HANDLER to continue loop execution after handling exceptions in loop body [SPARK-55005][SQL] Fix CONTINUE HANDLER to continue loop execution after handling exceptions in loop body Jan 12, 2026
@cloud-fan cloud-fan closed this in 7a40891 Jan 12, 2026
cloud-fan pushed a commit that referenced this pull request Jan 12, 2026
…ter handling exceptions in loop body

### What changes were proposed in this pull request?
This PR fixes a critical bug in `CONTINUE HANDLER` execution within loops. When a `CONTINUE HANDLER` handled an exception that occurred inside a loop body, the loop would exit completely instead of continuing to the next iteration.

#### Root cause
The `interruptConditionalStatements` method in `SqlScriptingExecution.scala` was designed to skip conditional statements when exceptions occurred in their condition evaluation (e.g., WHILE 1/0 > 0). However, it didn't distinguish between:
  - Exception in condition → loop should be skipped
  - Exception in body → loop should continue to next iteration

The method unconditionally set `interrupted = true` on all conditional statements, causing loops to exit even when the error occurred during body execution.

#### The fix
The fix was to add `isInCondition: Boolean` method to `ConditionalStatementExec` trait to track whether a conditional statement is currently evaluating its condition or executing its body. It was also needed to implement `isInCondition` for all 6 `ConditionalStatementExec`:
- IfElseStatementExec
- WhileStatementExec
- RepeatStatementExec
- ForStatementExec
- SearchedCaseStatementExec
- SimpleCaseStatementExec

### Why are the changes needed?
This ensures `CONTINUE HANDLER` only interrupts conditional statements when exceptions occur during condition evaluation, allowing loops to continue normally when exceptions occur in their bodies.

### Does this PR introduce _any_ user-facing change?
No.

### How was this patch tested?
Added comprehensive test coverage for `CONTINUE HANDLER` across all conditional statement types.  These tests verify that when an exception occurs inside a loop body and is handled by a `CONTINUE HANDLER`, the loop continues to the next iteration rather than exiting.

### Was this patch authored or co-authored using generative AI tooling?

Closes #53759 from miland-db/milan-dankovic_data/continue-handler-fix-loops.

Authored-by: Milan Dankovic <milan.dankovic@databricks.com>
Signed-off-by: Wenchen Fan <wenchen@databricks.com>
(cherry picked from commit 7a40891)
Signed-off-by: Wenchen Fan <wenchen@databricks.com>
srielau added a commit to srielau/spark that referenced this pull request Jan 14, 2026
Removed setReturnCurrentWithoutAdvancing() method and returnCurrentWithoutAdvancing
flag as they are no longer needed after PR apache#53759.

PR apache#53759 fixed CONTINUE HANDLER to properly handle exceptions in loop bodies by
introducing isInCondition to distinguish between:
- Exception in condition → loop should be interrupted
- Exception in body → loop should continue to next iteration

The returnCurrentWithoutAdvancing flag was an earlier workaround that attempted
to solve iterator advancement issues after CONTINUE handlers. With the proper
fix in place via isInCondition, this code is now redundant.

Tested: All continue handler and cursor tests pass without this code.
srielau added a commit to srielau/spark that referenced this pull request Jan 14, 2026
…PEAT+CONTINUE HANDLER

The code removed in commit 3b1dccf was NOT dead code - it was needed for
REPEAT loops with CONTINUE handlers.

Root Cause Analysis:
1. Before FETCH variable resolution fix: Tests had 58 UNRESOLVED_COLUMN errors,
   never reached the iterator logic
2. After FETCH variable resolution fix (dad9930): Variables resolved correctly,
   tests progressed into REPEAT loop execution
3. This exposed a pre-existing bug: 7 'No more elements' INTERNAL_ERROR in
   REPEAT+CONTINUE HANDLER tests
4. The UNRESOLVED_COLUMN errors were MASKING the iterator bug

The returnCurrentWithoutAdvancing flag handles a specific case:
- When a CONTINUE handler fires within a REPEAT loop body (e.g., from FETCH)
- After the handler completes, curr already points to the correct next statement
- Without the flag, the iterator incorrectly advances again, causing 'No more elements'

PR apache#53759's isInCondition fix handles exceptions in loop CONDITIONS vs BODIES,
but doesn't cover the case of handlers firing from statements (like FETCH) within
REPEAT loop bodies.

This restores the removed code with a whitespace fix.

Results:
- All 7 'No more elements' INTERNAL_ERROR fixed ✅
- All cursor tests now pass with proper REPEAT+CONTINUE HANDLER behavior
- 0 INTERNAL_ERROR in cursors.sql.out
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants