-
Notifications
You must be signed in to change notification settings - Fork 14.4k
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
fix(sqlglot): Address regressions introduced in #26476 #27217
Changes from all commits
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 |
---|---|---|
|
@@ -28,7 +28,7 @@ | |
from sqlalchemy import and_ | ||
from sqlglot import exp, parse, parse_one | ||
from sqlglot.dialects import Dialects | ||
from sqlglot.errors import ParseError | ||
from sqlglot.errors import SqlglotError | ||
from sqlglot.optimizer.scope import Scope, ScopeType, traverse_scope | ||
from sqlparse import keywords | ||
from sqlparse.lexer import Lexer | ||
|
@@ -287,7 +287,7 @@ def _extract_tables_from_sql(self) -> set[Table]: | |
""" | ||
try: | ||
statements = parse(self.stripped(), dialect=self._dialect) | ||
except ParseError: | ||
except SqlglotError: | ||
logger.warning("Unable to parse SQL (%s): %s", self._dialect, self.sql) | ||
return set() | ||
|
||
|
@@ -319,12 +319,17 @@ def _extract_tables_from_statement(self, statement: exp.Expression) -> set[Table | |
elif isinstance(statement, exp.Command): | ||
# Commands, like `SHOW COLUMNS FROM foo`, have to be converted into a | ||
# `SELECT` statetement in order to extract tables. | ||
literal = statement.find(exp.Literal) | ||
if not literal: | ||
if not (literal := statement.find(exp.Literal)): | ||
return set() | ||
|
||
pseudo_query = parse_one(f"SELECT {literal.this}", dialect=self._dialect) | ||
sources = pseudo_query.find_all(exp.Table) | ||
try: | ||
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. This issue surfaced when trying to parse an 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 have no idea what your use case is, but if you want more lenient sql parsing, you can try error_level=IGNORE 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. Ha! I was wondering whether I should have raised this with you. 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. always free to chat. you can hit me up on slack (i'm in your slack or you can come to mine) 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. Aside, but I had a similar problem with the old |
||
pseudo_query = parse_one( | ||
f"SELECT {literal.this}", | ||
dialect=self._dialect, | ||
) | ||
sources = pseudo_query.find_all(exp.Table) | ||
except SqlglotError: | ||
return set() | ||
else: | ||
sources = [ | ||
source | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -271,6 +271,7 @@ def test_extract_tables_illdefined() -> None: | |
assert extract_tables("SELECT * FROM catalogname..tbname") == { | ||
Table(table="tbname", schema=None, catalog="catalogname") | ||
} | ||
assert extract_tables('SELECT * FROM "tbname') == set() | ||
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. The ill-formed SQL statement throws a 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. @tobymao ideally should illformed SQL throw a 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. it depends on if it's a token error or a parser error! when you have unbalanced quotes, it's basically impossible to finish tokenization, so that's why we throw a token error. most everything else is a parser error |
||
|
||
|
||
def test_extract_tables_show_tables_from() -> None: | ||
|
@@ -558,6 +559,10 @@ def test_extract_tables_multistatement() -> None: | |
Table("t1"), | ||
Table("t2"), | ||
} | ||
assert extract_tables( | ||
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. This example throws as |
||
"ADD JAR file:///hive.jar; SELECT * FROM t1;", | ||
engine="hive", | ||
) == {Table("t1")} | ||
|
||
|
||
def test_extract_tables_complex() -> None: | ||
|
@@ -1815,10 +1820,7 @@ def test_extract_table_references(mocker: MockerFixture) -> None: | |
# test falling back to sqlparse | ||
logger = mocker.patch("superset.sql_parse.logger") | ||
sql = "SELECT * FROM table UNION ALL SELECT * FROM other_table" | ||
assert extract_table_references( | ||
sql, | ||
"trino", | ||
) == { | ||
assert extract_table_references(sql, "trino") == { | ||
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. This was picked up by Black as part of the |
||
Table(table="table", schema=None, catalog=None), | ||
Table(table="other_table", schema=None, catalog=None), | ||
} | ||
|
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.
Parsing (for right or wrong) can throw either a
ParseError
orTokenError
. It seems like both a derived from the theSqlglotError
error type and thus it seemed prudent to include a more broader except.