This is an automated email from the ASF dual-hosted git repository.
beto pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/superset.git
The following commit(s) were added to refs/heads/master by this push:
new cc9fd88c0d chore: improve DML check (#30417)
cc9fd88c0d is described below
commit cc9fd88c0d2a2406f202da7dcea2f0d14f1d017e
Author: Beto Dealmeida <[email protected]>
AuthorDate: Fri Sep 27 15:26:36 2024 -0400
chore: improve DML check (#30417)
---
pyproject.toml | 2 +-
requirements/base.txt | 2 +-
superset/sql/parse.py | 2 +-
superset/sql_lab.py | 29 +++++++++++++++++++++--------
tests/integration_tests/sqllab_tests.py | 6 +++++-
tests/unit_tests/sql/parse_tests.py | 14 ++++++++++++++
6 files changed, 43 insertions(+), 12 deletions(-)
diff --git a/pyproject.toml b/pyproject.toml
index 2318f6fca1..e1f32afa78 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -89,7 +89,7 @@ dependencies = [
"slack_sdk>=3.19.0, <4",
"sqlalchemy>=1.4, <2",
"sqlalchemy-utils>=0.38.3, <0.39",
- "sqlglot>=23.0.2,<24",
+ "sqlglot>=25.24.0,<26",
"sqlparse>=0.5.0",
"tabulate>=0.8.9, <0.9",
"typing-extensions>=4, <5",
diff --git a/requirements/base.txt b/requirements/base.txt
index 22540e3d7a..904b1a18fc 100644
--- a/requirements/base.txt
+++ b/requirements/base.txt
@@ -350,7 +350,7 @@ sqlalchemy-utils==0.38.3
# via
# apache-superset
# flask-appbuilder
-sqlglot==23.6.3
+sqlglot==25.24.0
# via apache-superset
sqlparse==0.5.0
# via apache-superset
diff --git a/superset/sql/parse.py b/superset/sql/parse.py
index 3ec928fabd..377411b944 100644
--- a/superset/sql/parse.py
+++ b/superset/sql/parse.py
@@ -362,7 +362,7 @@ class SQLStatement(BaseSQLStatement[exp.Expression]):
"""
return {
- eq.this.sql(): eq.expression.sql()
+ eq.this.sql(comments=False): eq.expression.sql(comments=False)
for set_item in self._parsed.find_all(exp.SetItem)
for eq in set_item.find_all(exp.EQ)
}
diff --git a/superset/sql_lab.py b/superset/sql_lab.py
index 3d3b2898fa..65a093610d 100644
--- a/superset/sql_lab.py
+++ b/superset/sql_lab.py
@@ -46,6 +46,7 @@ from superset.exceptions import (
OAuth2RedirectError,
SupersetErrorException,
SupersetErrorsException,
+ SupersetParseError,
)
from superset.extensions import celery_app, event_logger
from superset.models.core import Database
@@ -236,15 +237,27 @@ def execute_sql_statement( # pylint:
disable=too-many-statements, too-many-loca
# We are testing to see if more rows exist than the limit.
increased_limit = None if query.limit is None else query.limit + 1
- parsed_statement = SQLStatement(sql_statement,
engine=db_engine_spec.engine)
- if parsed_statement.is_mutating() and not database.allow_dml:
- raise SupersetErrorException(
- SupersetError(
- message=__("Only SELECT statements are allowed against this
database."),
- error_type=SupersetErrorType.DML_NOT_ALLOWED_ERROR,
- level=ErrorLevel.ERROR,
+ if not database.allow_dml:
+ try:
+ parsed_statement = SQLStatement(sql_statement,
engine=db_engine_spec.engine)
+ disallowed = parsed_statement.is_mutating()
+ except SupersetParseError:
+ # if we fail to parse teh query, disallow by default
+ disallowed = True
+
+ if disallowed:
+ raise SupersetErrorException(
+ SupersetError(
+ message=__(
+ "This database does not allow for DDL/DML, and the
query "
+ "could not be parsed to confirm it is a read-only
query. Please "
+ "contact your administrator for more assistance."
+ ),
+ error_type=SupersetErrorType.DML_NOT_ALLOWED_ERROR,
+ level=ErrorLevel.ERROR,
+ )
)
- )
+
if apply_ctas:
if not query.tmp_table_name:
start_dttm = datetime.fromtimestamp(query.start_time)
diff --git a/tests/integration_tests/sqllab_tests.py
b/tests/integration_tests/sqllab_tests.py
index 829854d966..cc1a813c93 100644
--- a/tests/integration_tests/sqllab_tests.py
+++ b/tests/integration_tests/sqllab_tests.py
@@ -137,7 +137,11 @@ class TestSqlLab(SupersetTestCase):
assert data == {
"errors": [
{
- "message": "Only SELECT statements are allowed against
this database.",
+ "message": (
+ "This database does not allow for DDL/DML, and the
query "
+ "could not be parsed to confirm it is a read-only
query. Please "
+ "contact your administrator for more assistance."
+ ),
"error_type": SupersetErrorType.DML_NOT_ALLOWED_ERROR,
"level": ErrorLevel.ERROR,
"extra": {
diff --git a/tests/unit_tests/sql/parse_tests.py
b/tests/unit_tests/sql/parse_tests.py
index f5d55bc13b..6c1e579127 100644
--- a/tests/unit_tests/sql/parse_tests.py
+++ b/tests/unit_tests/sql/parse_tests.py
@@ -918,3 +918,17 @@ def test_has_mutation(engine: str, sql: str, expected:
bool) -> None:
Test the `has_mutation` method.
"""
assert SQLScript(sql, engine).has_mutation() == expected
+
+
+def test_get_settings() -> None:
+ """
+ Test `get_settings` in some edge cases.
+ """
+ sql = """
+set
+-- this is a tricky comment
+search_path -- another one
+= bar;
+SELECT * FROM some_table;
+ """
+ assert SQLScript(sql, "postgresql").get_settings() == {"search_path":
"bar"}