Skip to content

Commit

Permalink
chore(sql_parse): Provide more meaningful SQLGlot errors (#27858)
Browse files Browse the repository at this point in the history
(cherry picked from commit c385297)
  • Loading branch information
john-bodley authored and michael-s-molina committed Apr 3, 2024
1 parent 58a53b4 commit d8cffb0
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 7 deletions.
16 changes: 13 additions & 3 deletions superset/sql_parse.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
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
Expand Down Expand Up @@ -297,11 +297,21 @@ def _extract_tables_from_sql(self) -> set[Table]:
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
Expand Down
12 changes: 8 additions & 4 deletions tests/unit_tests/sql_parse_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -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") == {
Expand Down

0 comments on commit d8cffb0

Please sign in to comment.