Closed proddata closed 3 weeks ago
Interestingly, in this situation when collecting errors, antrl4 gives us an None e
def syntaxError(self, recognizer, offendingSymbol, line, column, msg, e):
error = ParsingException(
msg=msg,
offending_token=offendingSymbol,
e=e, # <--------------------
query=e.ctx.parser.getTokenStream().getText(e.ctx.start, e.offendingToken.tokenIndex)
)
raise error
column = {int} 4
e = {NoneType} None
line = {int} 5
msg = {str} "extraneous input ';' expecting {',', ')'}"
offendingSymbol = {CommonToken} [@41,117:117=';',<301>,5:4]
recognizer = {SqlBaseParser} <cratedb_sqlparse.generated_parser.SqlBaseParser.SqlBaseParser object at 0x7a927b0715b0>
self = {ExceptionErrorListener} <cratedb_sqlparse.parser.ExceptionErrorListener object at 0x7a927b1ed430>
We still have the error message and could just compose the exception ourselves, the only issue is that we currently use the e
object to get the query and later match the exception with the original query.
Potential fix:
def syntaxError(self, recognizer, offendingSymbol, line, column, msg, e):
if e:
query = recognizer.getTokenStream().getText(e.ctx.start, offendingSymbol.tokenIndex)
else:
# If antlr4 doesn't give us an error object, we heuristically create a query, or a piece of it
# so we increase the chances of it being correctly assigned.
# It means that theoretically if you input two wrong queries that antlr4 manages
# to distinguish as two different statements (which is hard already), and both are similar
# the errors could be matched wrongly. Still pretty rare, and it is very hard to come up with
# an actual query that does it.
# The newly generated query will be either the offendingToken + one token to the left
# or offendingToken + two tokens to the left, if the second is possible it takes precedence.
min_token_to_check = max(1, offendingSymbol.tokenIndex - 2)
tokens = recognizer.getTokenStream().tokens[
min_token_to_check: offendingSymbol.tokenIndex:offendingSymbol.tokenIndex + 1]
query = "".join(map(lambda x: x.text, tokens))
error = ParsingException(
msg=msg,
offending_token=offendingSymbol,
e=e if e else type('NotViableInput', (Exception,), {})(),
query=query
)
self.errors.append(error)
Example:
Leads to: