-
Notifications
You must be signed in to change notification settings - Fork 29.2k
[SPARK-50449][SQL] Fix SQL Scripting grammar allowing empty bodies for loops, IF and CASE #48989
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
50a8061
7a41e6b
729e735
2260faa
1cafcb5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -82,7 +82,7 @@ class SqlScriptingParserSuite extends SparkFunSuite with SQLHelper { | |
| } | ||
| } | ||
|
|
||
| test("empty BEGIN END block") { | ||
| test("empty singleCompoundStatement") { | ||
| val sqlScriptText = | ||
| """ | ||
| |BEGIN | ||
|
|
@@ -91,6 +91,20 @@ class SqlScriptingParserSuite extends SparkFunSuite with SQLHelper { | |
| assert(tree.collection.isEmpty) | ||
| } | ||
|
|
||
| test("empty beginEndCompoundBlock") { | ||
| val sqlScriptText = | ||
| """ | ||
| |BEGIN | ||
| | BEGIN | ||
| | END; | ||
| |END""".stripMargin | ||
| val tree = parsePlan(sqlScriptText).asInstanceOf[CompoundBody] | ||
| assert(tree.collection.length == 1) | ||
| assert(tree.collection.head.isInstanceOf[CompoundBody]) | ||
| val innerBody = tree.collection.head.asInstanceOf[CompoundBody] | ||
| assert(innerBody.collection.isEmpty) | ||
| } | ||
|
|
||
| test("multiple ; in row - should fail") { | ||
| val sqlScriptText = | ||
| """ | ||
|
|
@@ -439,6 +453,21 @@ class SqlScriptingParserSuite extends SparkFunSuite with SQLHelper { | |
| assert(ifStmt.conditions.head.getText == "1=1") | ||
| } | ||
|
|
||
| test("if with empty body") { | ||
| val sqlScriptText = | ||
| """BEGIN | ||
| | IF 1 = 1 THEN | ||
| | END IF; | ||
| |END | ||
| """.stripMargin | ||
| checkError( | ||
| exception = intercept[ParseException] { | ||
| parsePlan(sqlScriptText) | ||
| }, | ||
| condition = "PARSE_SYNTAX_ERROR", | ||
| parameters = Map("error" -> "'IF'", "hint" -> "")) | ||
| } | ||
|
|
||
| test("if else") { | ||
| val sqlScriptText = | ||
| """BEGIN | ||
|
|
@@ -623,6 +652,21 @@ class SqlScriptingParserSuite extends SparkFunSuite with SQLHelper { | |
| assert(whileStmt.label.contains("lbl")) | ||
| } | ||
|
|
||
| test("while with empty body") { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we also add test like the one in PR description:
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I will add that one in the follow up PR, as that case is still not fixed. |
||
| val sqlScriptText = | ||
| """BEGIN | ||
| | WHILE 1 = 1 DO | ||
| | END WHILE; | ||
| |END | ||
| """.stripMargin | ||
| checkError( | ||
| exception = intercept[ParseException] { | ||
| parsePlan(sqlScriptText) | ||
| }, | ||
| condition = "PARSE_SYNTAX_ERROR", | ||
| parameters = Map("error" -> "'WHILE'", "hint" -> "")) | ||
| } | ||
|
|
||
| test("while with complex condition") { | ||
| val sqlScriptText = | ||
| """ | ||
|
|
@@ -1067,6 +1111,21 @@ class SqlScriptingParserSuite extends SparkFunSuite with SQLHelper { | |
| assert(repeatStmt.label.contains("lbl")) | ||
| } | ||
|
|
||
| test("repeat with empty body") { | ||
| val sqlScriptText = | ||
| """BEGIN | ||
| | REPEAT UNTIL 1 = 1 | ||
| | END REPEAT; | ||
| |END | ||
| """.stripMargin | ||
| checkError( | ||
| exception = intercept[ParseException] { | ||
| parsePlan(sqlScriptText) | ||
| }, | ||
| condition = "PARSE_SYNTAX_ERROR", | ||
| parameters = Map("error" -> "'1'", "hint" -> "")) | ||
| } | ||
|
|
||
| test("repeat with complex condition") { | ||
| val sqlScriptText = | ||
| """ | ||
|
|
@@ -1197,6 +1256,22 @@ class SqlScriptingParserSuite extends SparkFunSuite with SQLHelper { | |
| assert(caseStmt.conditions.head.getText == "1 = 1") | ||
| } | ||
|
|
||
| test("searched case statement with empty body") { | ||
| val sqlScriptText = | ||
| """BEGIN | ||
| | CASE | ||
| | WHEN 1 = 1 THEN | ||
| | END CASE; | ||
| |END | ||
| """.stripMargin | ||
| checkError( | ||
| exception = intercept[ParseException] { | ||
| parsePlan(sqlScriptText) | ||
| }, | ||
| condition = "PARSE_SYNTAX_ERROR", | ||
| parameters = Map("error" -> "'CASE'", "hint" -> "")) | ||
| } | ||
|
|
||
| test("searched case statement - multi when") { | ||
| val sqlScriptText = | ||
| """ | ||
|
|
@@ -1335,6 +1410,21 @@ class SqlScriptingParserSuite extends SparkFunSuite with SQLHelper { | |
| checkSimpleCaseStatementCondition(caseStmt.conditions.head, _ == Literal(1), _ == Literal(1)) | ||
| } | ||
|
|
||
| test("simple case statement with empty body") { | ||
| val sqlScriptText = | ||
| """BEGIN | ||
| | CASE 1 | ||
| | WHEN 1 THEN | ||
| | END CASE; | ||
| |END | ||
| """.stripMargin | ||
| checkError( | ||
| exception = intercept[ParseException] { | ||
| parsePlan(sqlScriptText) | ||
| }, | ||
| condition = "PARSE_SYNTAX_ERROR", | ||
| parameters = Map("error" -> "'CASE'", "hint" -> "")) | ||
| } | ||
|
|
||
| test("simple case statement - multi when") { | ||
| val sqlScriptText = | ||
|
|
@@ -1482,6 +1572,21 @@ class SqlScriptingParserSuite extends SparkFunSuite with SQLHelper { | |
| assert(whileStmt.label.contains("lbl")) | ||
| } | ||
|
|
||
| test("loop with empty body") { | ||
| val sqlScriptText = | ||
| """BEGIN | ||
| | LOOP | ||
| | END LOOP; | ||
| |END | ||
| """.stripMargin | ||
| checkError( | ||
| exception = intercept[ParseException] { | ||
| parsePlan(sqlScriptText) | ||
| }, | ||
| condition = "PARSE_SYNTAX_ERROR", | ||
| parameters = Map("error" -> "'LOOP'", "hint" -> "")) | ||
| } | ||
|
|
||
| test("loop with if else block") { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does it also make sense to add test with for with empty body, in this PR or your other one, depending on which you merge first?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, I will add it to the one which gets merged last, or if they both get merged then I will create a separate PR.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added tests for FOR |
||
| val sqlScriptText = | ||
| """BEGIN | ||
|
|
@@ -1960,6 +2065,21 @@ class SqlScriptingParserSuite extends SparkFunSuite with SQLHelper { | |
| assert(forStmt.label.contains("lbl")) | ||
| } | ||
|
|
||
| test("for statement - empty body") { | ||
| val sqlScriptText = | ||
| """ | ||
| |BEGIN | ||
| | lbl: FOR x AS SELECT 5 DO | ||
| | END FOR; | ||
| |END""".stripMargin | ||
| checkError( | ||
| exception = intercept[ParseException] { | ||
| parsePlan(sqlScriptText) | ||
| }, | ||
| condition = "PARSE_SYNTAX_ERROR", | ||
| parameters = Map("error" -> "'FOR'", "hint" -> "")) | ||
| } | ||
|
|
||
| test("for statement - no label") { | ||
| val sqlScriptText = | ||
| """ | ||
|
|
@@ -2076,6 +2196,21 @@ class SqlScriptingParserSuite extends SparkFunSuite with SQLHelper { | |
| assert(forStmt.label.contains("lbl")) | ||
| } | ||
|
|
||
| test("for statement - no variable - empty body") { | ||
| val sqlScriptText = | ||
| """ | ||
| |BEGIN | ||
| | lbl: FOR SELECT 5 DO | ||
| | END FOR; | ||
| |END""".stripMargin | ||
| checkError( | ||
| exception = intercept[ParseException] { | ||
| parsePlan(sqlScriptText) | ||
| }, | ||
| condition = "PARSE_SYNTAX_ERROR", | ||
| parameters = Map("error" -> "'FOR'", "hint" -> "")) | ||
| } | ||
|
|
||
| test("for statement - no variable - no label") { | ||
| val sqlScriptText = | ||
| """ | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought we should throw exception in the
getOrElsebranch, how does this fix work?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If
ctx.compoundBody()is null, that means we haveThis is allowed, so in this case we simply return a
CompoundBodywith empty statements list.