This is an automated email from the ASF dual-hosted git repository. michaelsmolina pushed a commit to branch pulse in repository https://gitbox.apache.org/repos/asf/superset.git
commit d8b01c668fdd3e6d12de52e8df104f70b46b96b0 Author: Beto Dealmeida <[email protected]> AuthorDate: Thu Jul 31 08:33:34 2025 -0400 fix: prevent anonymous code in Postgres (#34412) (cherry picked from commit 6fc734da5154524b2e235c4df0d75977a7d5211f) --- superset/sql/parse.py | 10 ++++++++++ tests/unit_tests/sql/parse_tests.py | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/superset/sql/parse.py b/superset/sql/parse.py index 792d0e9e6f..9286bca65a 100644 --- a/superset/sql/parse.py +++ b/superset/sql/parse.py @@ -382,6 +382,16 @@ class SQLStatement(BaseSQLStatement[exp.Expression]): if isinstance(node, exp.Command) and node.name == "ALTER": return True + if ( + self._dialect == Dialects.POSTGRES + and isinstance(self._parsed, exp.Command) + and self._parsed.name == "DO" + ): + # anonymous blocks can be written in many different languages (the default + # is PL/pgSQL), so parsing them it out of scope of this class; we just + # assume the anonymous block is mutating + return True + # Postgres runs DMLs prefixed by `EXPLAIN ANALYZE`, see # https://www.postgresql.org/docs/current/sql-explain.html if ( diff --git a/tests/unit_tests/sql/parse_tests.py b/tests/unit_tests/sql/parse_tests.py index 8dc06aeea3..dd93ad230c 100644 --- a/tests/unit_tests/sql/parse_tests.py +++ b/tests/unit_tests/sql/parse_tests.py @@ -1072,6 +1072,43 @@ def test_is_mutating(engine: str) -> None: ).is_mutating() [email protected]( + "sql, expected", + [ + ( + """ +DO $$ +BEGIN + INSERT INTO public.users (name, real_name) + VALUES ('SQLLab bypass DML', 'SQLLab bypass DML'); +END; +$$; + """, + True, + ), + ( + """ +DO $$ +BEGIN + IF (SELECT COUNT(*) FROM orders WHERE status = 'pending') > 100 THEN + RAISE NOTICE 'High pending order volume detected'; + END IF; +END; +$$; + """, + True, + ), + ], +) +def test_is_mutating_anonymous_block(sql: str, expected: bool) -> None: + """ + Test for `is_mutating` with a Postgres anonymous block. + + Since we can't parse the PL/pgSQL inside the block we always assume it is mutating. + """ + assert SQLStatement(sql, "postgresql").is_mutating() == expected + + def test_optimize() -> None: """ Test that the `optimize` method works as expected.
