Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ class SqlScriptingExecution(

context.frames.remove(context.frames.size - 1)

// If the last frame is a handler, set leave statement to be the next one in the
// If the last frame is an EXIT handler, set leave statement to be the next one in the
// innermost scope that should be exited.
if (lastFrame.frameType == SqlScriptingFrameType.EXIT_HANDLER
&& context.frames.nonEmpty) {
Expand All @@ -136,6 +136,8 @@ class SqlScriptingExecution(
injectLeaveStatement(context.frames.last.executionPlan, lastFrame.scopeLabel.get)
}

// If the last frame is a CONTINUE handler, leave the handler without injecting anything, but
// skip the conditional statement if the exception originated from its conditional expression.
if (lastFrame.frameType == SqlScriptingFrameType.CONTINUE_HANDLER
&& context.frames.nonEmpty) {
// Remove the scope if handler is executed.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,8 @@ object SqlScriptingFrameType extends Enumeration {
* @param executionPlan CompoundBody which need to be executed.
* @param frameType Type of the frame.
* @param scopeLabel Label of the scope where handler is defined.
* Available only for frameType = HANDLER.
* Available only for frameType = EXIT_HANDLER, frameType = CONTINUE_HANDLER
* and frameType = SQL_STORED_PROCEDURE.
*/
class SqlScriptingExecutionFrame(
val executionPlan: CompoundBodyExec,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,11 @@ trait NonLeafStatementExec extends CompoundStatementExec {
* Conditional node in the execution tree. It is a conditional non-leaf node.
*/
trait ConditionalStatementExec extends NonLeafStatementExec {
/**
* Used by CONTINUE HANDLER for all ConditionalStatementExec and by EXIT HANDLER for
* ForStatementExec to flag the statement as interrupted and subsequently force the
* hasNext method to return false (used for skipping the conditional statement).
*/
protected[scripting] var interrupted: Boolean = false
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,11 @@ case class SqlScriptingInterpreter(session: SparkSession) {
args,
context)

// Scope label should be Some(compoundBody.label.get) for both handler types
val handlerExec = new ExceptionHandlerExec(
handlerBodyExec,
handler.handlerType,
Some(compoundBody.label.get))
body = handlerBodyExec,
handlerType = handler.handlerType,
// Used as a parent label of where the handler is declared (label of compoundBody used).
scopeLabel = Some(compoundBody.label.get))

// For each condition handler is defined for, add corresponding key value pair
// to the conditionHandlerMap.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -402,68 +402,6 @@ class SqlScriptingExecutionSuite extends QueryTest with SharedSparkSession {
verifySqlScriptResult(sqlScript, expected = expected)
}

test("handler - exit resolve in the same block when if condition fails") {
val sqlScript =
"""
|BEGIN
| DECLARE VARIABLE flag INT = -1;
| scope_to_exit: BEGIN
| DECLARE EXIT HANDLER FOR SQLSTATE '22012'
| BEGIN
| SELECT flag;
| SET flag = 1;
| END;
| SELECT 2;
| SELECT 3;
| IF 1 > 1/0 THEN
| SELECT 10;
| END IF;
| SELECT 4;
| SELECT 5;
| END;
| SELECT flag;
|END
|""".stripMargin
val expected = Seq(
Seq(Row(2)), // select
Seq(Row(3)), // select
Seq(Row(-1)), // select flag
Seq(Row(1)) // select flag from the outer body
)
verifySqlScriptResult(sqlScript, expected = expected)
}

test("continue handler - continue after the if statement when if condition fails") {
val sqlScript =
"""
|BEGIN
| DECLARE VARIABLE flag INT = -1;
| DECLARE CONTINUE HANDLER FOR DIVIDE_BY_ZERO
| BEGIN
| SELECT flag;
| SET flag = 1;
| END;
| SELECT 2;
| SELECT 3;
| IF (1 > 1/0) THEN
| SELECT 4;
| END IF;
| SELECT 5;
| SELECT 6;
| SELECT flag;
|END
|""".stripMargin
val expected = Seq(
Seq(Row(2)), // select
Seq(Row(3)), // select
Seq(Row(-1)), // select flag
Seq(Row(5)), // select
Seq(Row(6)), // select
Seq(Row(1)) // select flag from the outer body
)
verifySqlScriptResult(sqlScript, expected = expected)
}

test("handler - exit resolve in outer block") {
val sqlScript =
"""
Expand Down Expand Up @@ -956,6 +894,10 @@ class SqlScriptingExecutionSuite extends QueryTest with SharedSparkSession {
| END;
| IF 1 > 1/0 THEN
| SELECT 10;
| ELSEIF (1 = 1) THEN
| SELECT 11;
| ELSE
| SELECT 12;
| END IF;
| SELECT 4;
| SELECT 5;
Expand Down Expand Up @@ -1012,6 +954,8 @@ class SqlScriptingExecutionSuite extends QueryTest with SharedSparkSession {
| END;
| CASE 1/0
| WHEN flag THEN SELECT 10;
| WHEN 1 THEN SELECT 11;
| ELSE SELECT 12;
| END CASE;
| SELECT 4;
| SELECT 5;
Expand Down Expand Up @@ -1068,6 +1012,9 @@ class SqlScriptingExecutionSuite extends QueryTest with SharedSparkSession {
| END;
| CASE flag
| WHEN 1/0 THEN SELECT 10;
| WHEN -1 THEN SELECT 11;
| WHEN 1 THEN SELECT 12;
| ELSE SELECT 13;
| END CASE;
| SELECT 4;
| SELECT 5;
Expand Down Expand Up @@ -1124,6 +1071,9 @@ class SqlScriptingExecutionSuite extends QueryTest with SharedSparkSession {
| END;
| CASE flag
| WHEN 'teststr' THEN SELECT 10;
| WHEN -1 THEN SELECT 11;
| WHEN 1 THEN SELECT 12;
| ELSE SELECT 13;
| END CASE;
| SELECT 4;
| SELECT 5;
Expand Down Expand Up @@ -1180,6 +1130,8 @@ class SqlScriptingExecutionSuite extends QueryTest with SharedSparkSession {
| END;
| CASE
| WHEN flag = 1/0 THEN SELECT 10;
| WHEN 1 = 1 THEN SELECT 11;
| ELSE SELECT 12;
| END CASE;
| SELECT 4;
| SELECT 5;
Expand Down