Compare commits

...
Author SHA1 Message Date
Elizabeth Thompson 876b8641e2 fix(sql): catch sqlglot ParseError when parsing RLS predicates
SQLStatement.parse_predicate called sqlglot.parse_one unguarded, so a
syntactically invalid RLS predicate raised a raw sqlglot ParseError.
Reachable via apply_rls (e.g. POST /api/v1/sqllab/estimate with
RLS_IN_SQLLAB enabled), this surfaced as an opaque 500 instead of a
typed 422.

Wrap the call to convert ParseError/SqlglotError into SupersetParseError,
mirroring the existing idiom in SQLStatement._parse.
2026-08-28 16:49:17 +00:00
2 changed files with 33 additions and 1 deletions
+19 -1
View File
@@ -1539,7 +1539,25 @@ class SQLStatement(BaseSQLStatement[exp.Expression]):
:return: The parsed predicate.
"""
_check_script_length(predicate, self.engine)
return sqlglot.parse_one(predicate, dialect=self._dialect)
try:
return sqlglot.parse_one(predicate, dialect=self._dialect)
except sqlglot.errors.ParseError as ex:
kwargs = (
{
"highlight": ex.errors[0]["highlight"],
"line": ex.errors[0]["line"],
"column": ex.errors[0]["col"],
}
if ex.errors
else {}
)
raise SupersetParseError(predicate, self.engine, **kwargs) from ex
except sqlglot.errors.SqlglotError as ex:
raise SupersetParseError(
predicate,
self.engine,
message="Unable to parse predicate",
) from ex
def apply_rls(
self,
+14
View File
@@ -5578,6 +5578,20 @@ def test_parse_predicate_length_check() -> None:
stmt.parse_predicate("x" * 101)
def test_parse_predicate_invalid_sql_raises_superset_parse_error() -> None:
"""
A syntactically invalid RLS predicate raises ``SupersetParseError``.
``parse_predicate`` is reachable via ``apply_rls`` for any RLS clause
configured on a queried table; an invalid clause must surface as the
typed 422 parse error rather than leaking a raw ``sqlglot`` exception.
"""
stmt = SQLStatement("SELECT 1", "postgresql")
with pytest.raises(SupersetParseError) as excinfo:
stmt.parse_predicate("a >")
assert excinfo.value.status == 422
@pytest.mark.usefixtures("_small_parse_cap")
def test_transpile_to_dialect_length_check() -> None:
"""