This is an automated email from the ASF dual-hosted git repository. michaelsmolina pushed a commit to branch 3.1 in repository https://gitbox.apache.org/repos/asf/superset.git
commit d8cffb0a3f87a4f944a67fcc322d537f1845043c Author: John Bodley <[email protected]> AuthorDate: Wed Apr 3 07:10:52 2024 -0700 chore(sql_parse): Provide more meaningful SQLGlot errors (#27858) (cherry picked from commit c38529741e68f7e98bbcdfa0e543dc2ef4acf7f9) --- superset/sql_parse.py | 16 +++++++++++++--- tests/unit_tests/sql_parse_tests.py | 12 ++++++++---- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/superset/sql_parse.py b/superset/sql_parse.py index 3f4daf171a..d2e20f9cba 100644 --- a/superset/sql_parse.py +++ b/superset/sql_parse.py @@ -31,7 +31,7 @@ from jinja2 import nodes from sqlalchemy import and_ from sqlglot import exp, parse, parse_one from sqlglot.dialects import Dialects -from sqlglot.errors import SqlglotError +from sqlglot.errors import ParseError, SqlglotError from sqlglot.optimizer.scope import Scope, ScopeType, traverse_scope from sqlparse import keywords from sqlparse.lexer import Lexer @@ -297,11 +297,21 @@ class ParsedQuery: statements = parse(self.stripped(), dialect=self._dialect) except SqlglotError as ex: logger.warning("Unable to parse SQL (%s): %s", self._dialect, self.sql) - dialect = self._dialect or "generic" + + message = ( + "Error parsing near '{highlight}' at line {line}:{col}".format( # pylint: disable=consider-using-f-string + **ex.errors[0] + ) + if isinstance(ex, ParseError) + else str(ex) + ) + raise SupersetSecurityException( SupersetError( error_type=SupersetErrorType.QUERY_SECURITY_ACCESS_ERROR, - message=__(f"Unable to parse SQL ({dialect}): {self.sql}"), + message=__( + f"You may have an error in your SQL statement. {message}" + ), level=ErrorLevel.ERROR, ) ) from ex diff --git a/tests/unit_tests/sql_parse_tests.py b/tests/unit_tests/sql_parse_tests.py index 20f1823218..d3d432bb98 100644 --- a/tests/unit_tests/sql_parse_tests.py +++ b/tests/unit_tests/sql_parse_tests.py @@ -273,26 +273,30 @@ def test_extract_tables_illdefined() -> None: with pytest.raises(SupersetSecurityException) as excinfo: extract_tables("SELECT * FROM schemaname.") assert ( - str(excinfo.value) == "Unable to parse SQL (generic): SELECT * FROM schemaname." + str(excinfo.value) + == "You may have an error in your SQL statement. Error parsing near '.' at line 1:25" ) with pytest.raises(SupersetSecurityException) as excinfo: extract_tables("SELECT * FROM catalogname.schemaname.") assert ( str(excinfo.value) - == "Unable to parse SQL (generic): SELECT * FROM catalogname.schemaname." + == "You may have an error in your SQL statement. Error parsing near '.' at line 1:37" ) with pytest.raises(SupersetSecurityException) as excinfo: extract_tables("SELECT * FROM catalogname..") assert ( str(excinfo.value) - == "Unable to parse SQL (generic): SELECT * FROM catalogname.." + == "You may have an error in your SQL statement. Error parsing near '.' at line 1:27" ) with pytest.raises(SupersetSecurityException) as excinfo: extract_tables('SELECT * FROM "tbname') - assert str(excinfo.value) == 'Unable to parse SQL (generic): SELECT * FROM "tbname' + assert ( + str(excinfo.value) + == "You may have an error in your SQL statement. Error tokenizing 'SELECT * FROM \"tbnam'" + ) # odd edge case that works assert extract_tables("SELECT * FROM catalogname..tbname") == {
