Skip to content

Commit 276ccfb

Browse files
committed
chore: get rid of sqlparse
1 parent 74f953d commit 276ccfb

9 files changed

Lines changed: 239 additions & 132 deletions

File tree

superset-frontend/src/SqlLab/actions/sqlLab.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -912,6 +912,7 @@ export function formatQuery(queryEditor) {
912912
const { sql } = getUpToDateQuery(getState(), queryEditor);
913913
return SupersetClient.post({
914914
endpoint: `/api/v1/sqllab/format_sql/`,
915+
// TODO (betodealmeida): pass engine as a parameter for better formatting
915916
body: JSON.stringify({ sql }),
916917
headers: { 'Content-Type': 'application/json' },
917918
}).then(({ json }) => {

superset/connectors/sqla/models.py

Lines changed: 3 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
import numpy as np
3434
import pandas as pd
3535
import sqlalchemy as sa
36-
import sqlparse
3736
from flask import escape, Markup
3837
from flask_appbuilder import Model
3938
from flask_appbuilder.security.sqla.models import User
@@ -1100,7 +1099,9 @@ def _process_sql_expression(
11001099

11011100

11021101
class SqlaTable(
1103-
Model, BaseDatasource, ExploreMixin
1102+
Model,
1103+
BaseDatasource,
1104+
ExploreMixin,
11041105
): # pylint: disable=too-many-public-methods
11051106
"""An ORM object for SqlAlchemy table references"""
11061107

@@ -1414,26 +1415,6 @@ def mutate_query_from_config(self, sql: str) -> str:
14141415
def get_template_processor(self, **kwargs: Any) -> BaseTemplateProcessor:
14151416
return get_template_processor(table=self, database=self.database, **kwargs)
14161417

1417-
def get_query_str_extended(
1418-
self,
1419-
query_obj: QueryObjectDict,
1420-
mutate: bool = True,
1421-
) -> QueryStringExtended:
1422-
sqlaq = self.get_sqla_query(**query_obj)
1423-
sql = self.database.compile_sqla_query(sqlaq.sqla_query)
1424-
sql = self._apply_cte(sql, sqlaq.cte)
1425-
sql = sqlparse.format(sql, reindent=True)
1426-
if mutate:
1427-
sql = self.mutate_query_from_config(sql)
1428-
return QueryStringExtended(
1429-
applied_template_filters=sqlaq.applied_template_filters,
1430-
applied_filter_columns=sqlaq.applied_filter_columns,
1431-
rejected_filter_columns=sqlaq.rejected_filter_columns,
1432-
labels_expected=sqlaq.labels_expected,
1433-
prequeries=sqlaq.prequeries,
1434-
sql=sql,
1435-
)
1436-
14371418
def get_query_str(self, query_obj: QueryObjectDict) -> str:
14381419
query_str_ext = self.get_query_str_extended(query_obj)
14391420
all_queries = query_str_ext.prequeries + [query_str_ext.sql]
@@ -1475,33 +1456,6 @@ def get_from_clause(
14751456

14761457
return from_clause, cte
14771458

1478-
def get_rendered_sql(
1479-
self, template_processor: BaseTemplateProcessor | None = None
1480-
) -> str:
1481-
"""
1482-
Render sql with template engine (Jinja).
1483-
"""
1484-
1485-
sql = self.sql
1486-
if template_processor:
1487-
try:
1488-
sql = template_processor.process_template(sql)
1489-
except TemplateError as ex:
1490-
raise QueryObjectValidationError(
1491-
_(
1492-
"Error while rendering virtual dataset query: %(msg)s",
1493-
msg=ex.message,
1494-
)
1495-
) from ex
1496-
sql = sqlparse.format(sql.strip("\t\r\n; "), strip_comments=True)
1497-
if not sql:
1498-
raise QueryObjectValidationError(_("Virtual dataset query cannot be empty"))
1499-
if len(sqlparse.split(sql)) > 1:
1500-
raise QueryObjectValidationError(
1501-
_("Virtual dataset query cannot consist of multiple statements")
1502-
)
1503-
return sql
1504-
15051459
def adhoc_metric_to_sqla(
15061460
self,
15071461
metric: AdhocMetric,

superset/db_engine_specs/base.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@
5959
from superset.constants import TimeGrain as TimeGrainConstants
6060
from superset.databases.utils import make_url_safe
6161
from superset.errors import ErrorLevel, SupersetError, SupersetErrorType
62-
from superset.sql_parse import ParsedQuery, Table
62+
from superset.sql_parse import ParsedQuery, SQLQuery, Table
6363
from superset.superset_typing import ResultSetColumnType, SQLAColumnType
6464
from superset.utils import core as utils
6565
from superset.utils.core import ColumnSpec, GenericDataType
@@ -1448,7 +1448,7 @@ def select_star( # pylint: disable=too-many-arguments,too-many-locals
14481448
qry = partition_query
14491449
sql = database.compile_sqla_query(qry)
14501450
if indent:
1451-
sql = sqlparse.format(sql, reindent=True)
1451+
sql = SQLQuery(sql).format()
14521452
return sql
14531453

14541454
@classmethod

superset/db_engine_specs/postgres.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
from re import Pattern
2525
from typing import Any, TYPE_CHECKING
2626

27-
import sqlparse
2827
from flask_babel import gettext as __
2928
from sqlalchemy.dialects.postgresql import DOUBLE_PRECISION, ENUM, JSON
3029
from sqlalchemy.dialects.postgresql.base import PGInspector
@@ -37,6 +36,7 @@
3736
from superset.errors import ErrorLevel, SupersetError, SupersetErrorType
3837
from superset.exceptions import SupersetException, SupersetSecurityException
3938
from superset.models.sql_lab import Query
39+
from superset.sql_parse import SQLQuery
4040
from superset.utils import core as utils
4141
from superset.utils.core import GenericDataType
4242

@@ -281,8 +281,9 @@ def get_default_schema_for_query(
281281
This method simply uses the parent method after checking that there are no
282282
malicious path setting in the query.
283283
"""
284-
sql = sqlparse.format(query.sql, strip_comments=True)
285-
if re.search(r"set\s+search_path\s*=", sql, re.IGNORECASE):
284+
statement = SQLQuery(query.sql)
285+
settings = statement.get_settings()
286+
if "search_path" in settings:
286287
raise SupersetSecurityException(
287288
SupersetError(
288289
error_type=SupersetErrorType.QUERY_SECURITY_ACCESS_ERROR,

superset/models/helpers.py

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@
7373
insert_rls_in_predicate,
7474
ParsedQuery,
7575
sanitize_clause,
76+
SQLQuery,
77+
SQLStatement,
7678
)
7779
from superset.superset_typing import (
7880
AdhocMetric,
@@ -901,12 +903,14 @@ def _apply_cte(sql: str, cte: Optional[str]) -> str:
901903
return sql
902904

903905
def get_query_str_extended(
904-
self, query_obj: QueryObjectDict, mutate: bool = True
906+
self,
907+
query_obj: QueryObjectDict,
908+
mutate: bool = True,
905909
) -> QueryStringExtended:
906910
sqlaq = self.get_sqla_query(**query_obj)
907911
sql = self.database.compile_sqla_query(sqlaq.sqla_query)
908912
sql = self._apply_cte(sql, sqlaq.cte)
909-
sql = sqlparse.format(sql, reindent=True)
913+
sql = SQLStatement(sql).format()
910914
if mutate:
911915
sql = self.mutate_query_from_config(sql)
912916
return QueryStringExtended(
@@ -1054,7 +1058,8 @@ def assign_column_label(df: pd.DataFrame) -> Optional[pd.DataFrame]:
10541058
)
10551059

10561060
def get_rendered_sql(
1057-
self, template_processor: Optional[BaseTemplateProcessor] = None
1061+
self,
1062+
template_processor: Optional[BaseTemplateProcessor] = None,
10581063
) -> str:
10591064
"""
10601065
Render sql with template engine (Jinja).
@@ -1071,13 +1076,16 @@ def get_rendered_sql(
10711076
msg=ex.message,
10721077
)
10731078
) from ex
1074-
sql = sqlparse.format(sql.strip("\t\r\n; "), strip_comments=True)
1075-
if not sql:
1076-
raise QueryObjectValidationError(_("Virtual dataset query cannot be empty"))
1077-
if len(sqlparse.split(sql)) > 1:
1079+
1080+
query = SQLQuery(sql.strip("\t\r\n; "))
1081+
if len(query.statements) > 1:
10781082
raise QueryObjectValidationError(
10791083
_("Virtual dataset query cannot consist of multiple statements")
10801084
)
1085+
1086+
sql = query.statements[0].format(comments=False)
1087+
if not sql:
1088+
raise QueryObjectValidationError(_("Virtual dataset query cannot be empty"))
10811089
return sql
10821090

10831091
def text(self, clause: str) -> TextClause:

0 commit comments

Comments
 (0)