srielau commented on code in PR #58530:
URL: https://github.com/apache/spark/pull/58530#discussion_r3962546204
##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/parser/SqlStatementSplitter.scala:
##########
@@ -285,8 +370,67 @@ object SqlStatementSplitter {
val unclosed = lexer.has_unclosed_bracketed_comment
val partial =
- if (bufferHasContent || unclosed) buffer.toString.trim else ""
- SqlStatementSplitResult(completeStatements.toSeq, partial, unclosed &&
partial.nonEmpty)
+ if (bufferHasContent || unclosed) positionedStatement("") else None
+ PositionedSqlStatementSplitResult(
+ completeStatements.toSeq,
+ partial,
+ unclosed && partial.nonEmpty)
+ }
+
+ /**
+ * Returns the delimiter-array index and ending token index of a real outer
END for a malformed
+ * compound statement. Error recovery may repair the body, but a missing END
is synthetic and
+ * has token index -1.
+ */
+ private def findMalformedCompoundEnd(
+ sqlText: String,
+ toUtf16: Array[Int],
+ stream: CommonTokenStream,
+ startIdx: Int,
+ delimiterPositions: Array[Int],
+ fromDelimiter: Int,
+ validationPreprocess: String => String,
+ conf: SqlApiConf): Option[(Int, Int)] = {
+ if (stream.get(startIdx).getType != SqlBaseLexer.BEGIN) {
+ return None
+ }
+
+ var delimiter = fromDelimiter
+ while (delimiter <= delimiterPositions.length) {
+ val endIdx = if (delimiter < delimiterPositions.length) {
+ delimiterPositions(delimiter)
+ } else {
+ stream.size() - 1
+ }
+ val firstTok = stream.get(startIdx)
+ val lastTok = stream.get(endIdx)
+ val regionStart = toUtf16(firstTok.getStartIndex)
+ val regionEnd = if (lastTok.getType == Token.EOF) {
+ sqlText.length
+ } else {
+ toUtf16(lastTok.getStopIndex + 1)
+ }
+ val candidate = validationPreprocess(sqlText.substring(regionStart,
regionEnd))
+ val lexer = new SqlBaseLexer(
+ new UpperCaseCharStream(CharStreams.fromString(candidate)))
+ lexer.removeErrorListeners()
+ val tokens = new CommonTokenStream(lexer)
+ tokens.fill()
+ val parser = new SqlBaseParser(tokens)
+ configureSplitterParser(parser, conf, bailOnError = false)
+ parser.getInterpreter.setPredictionMode(PredictionMode.LL)
+ try {
+ val context = parser.singleCompoundStatement()
+ val end = context.END()
+ if (end != null && end.getSymbol.getTokenIndex >= 0 && tokens.LA(1) ==
Token.EOF) {
Review Comment:
Fixed in afbd833ef61. Recovery now requires a real recovered END and
independently verifies the recovered candidate default-channel suffix as a real
outer END followed only by the optional semicolon and EOF. This prevents an
inner `END IF` from terminating the outer block. Added focused
SqlStatementSplitterSuite and ParseSqlResultSuite regressions for `BEGIN IFF
TRUE THEN SELECT 1; END IF; SELECT 2; END; SELECT 3`; they verify exactly one
failed outer block plus one successful SELECT with correct spans. The full
splitter, ParseSqlResult, and parse_sql suites and Catalyst/SQL Scalastyle
checks pass.
##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/parser/SqlStatementSplitter.scala:
##########
@@ -399,7 +548,48 @@ object SqlStatementSplitter {
parser.single_character_pipe_operator_enabled =
conf.singleCharacterPipeOperatorEnabled
parser.removeErrorListeners()
- parser.setErrorHandler(new BailErrorStrategy)
+ if (bailOnError) {
Review Comment:
Fixed in afbd833ef61. The Scaladoc now qualifies bail-strategy installation
with `bailOnError` and explains that malformed-compound recovery intentionally
retains DefaultErrorStrategy so it can inspect the recovered outer END boundary.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]