Skip to content

Commit

Permalink
added syntax errors to most used databases
Browse files Browse the repository at this point in the history
  • Loading branch information
AAfghahi committed Jun 29, 2021
1 parent ea82bdf commit 67988e7
Show file tree
Hide file tree
Showing 8 changed files with 166 additions and 3 deletions.
21 changes: 20 additions & 1 deletion superset/db_engine_specs/athena.py
Expand Up @@ -14,12 +14,20 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
import re
from datetime import datetime
from typing import Optional
from typing import Any, Dict, Optional, Pattern, Tuple

from flask_babel import gettext as __

from superset.db_engine_specs.base import BaseEngineSpec
from superset.errors import SupersetErrorType
from superset.utils import core as utils

SYNTAX_ERROR_REGEX = re.compile(
": mismatched input '(?P<syntax_error>.*?)'. Expecting: "
)


class AthenaEngineSpec(BaseEngineSpec):
engine = "awsathena"
Expand All @@ -41,6 +49,17 @@ class AthenaEngineSpec(BaseEngineSpec):
date_add('day', 1, CAST({col} AS TIMESTAMP))))",
}

custom_errors: Dict[Pattern[str], Tuple[str, SupersetErrorType, Dict[str, Any]]] = {
SYNTAX_ERROR_REGEX: (
__(
"Please check your query for syntax errors at or "
'near "%(syntax_error)s". Then, try running your query again.'
),
SupersetErrorType.SYNTAX_ERROR,
{},
),
}

@classmethod
def convert_dttm(cls, target_type: str, dttm: datetime) -> Optional[str]:
tt = target_type.upper()
Expand Down
18 changes: 17 additions & 1 deletion superset/db_engine_specs/gsheets.py
Expand Up @@ -14,12 +14,17 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
from typing import Optional
import re
from typing import Any, Dict, Optional, Pattern, Tuple

from flask_babel import gettext as __
from sqlalchemy.engine.url import URL

from superset import security_manager
from superset.db_engine_specs.sqlite import SqliteEngineSpec
from superset.errors import SupersetErrorType

SYNTAX_ERROR_REGEX = re.compile('SQLError: near "(?P<server_error>.*?)": syntax error')


class GSheetsEngineSpec(SqliteEngineSpec):
Expand All @@ -30,6 +35,17 @@ class GSheetsEngineSpec(SqliteEngineSpec):
allows_joins = False
allows_subqueries = True

custom_errors: Dict[Pattern[str], Tuple[str, SupersetErrorType, Dict[str, Any]]] = {
SYNTAX_ERROR_REGEX: (
__(
'Please check your query for syntax errors near "%(server_error)s". '
"Then, try running your query again."
),
SupersetErrorType.SYNTAX_ERROR,
{},
),
}

@classmethod
def modify_url_for_impersonation(
cls, url: URL, impersonate_user: bool, username: Optional[str]
Expand Down
13 changes: 13 additions & 0 deletions superset/db_engine_specs/mysql.py
Expand Up @@ -52,6 +52,11 @@
)
CONNECTION_UNKNOWN_DATABASE_REGEX = re.compile("Unknown database '(?P<database>.*?)'")

SYNTAX_ERROR_REGEX = re.compile(
"check the manual that corresponds to your MySQL server "
"version for the right syntax to use near '(?P<server_error>.*)"
)


class MySQLEngineSpec(BaseEngineSpec, BasicParametersMixin):
engine = "mysql"
Expand Down Expand Up @@ -134,6 +139,14 @@ class MySQLEngineSpec(BaseEngineSpec, BasicParametersMixin):
SupersetErrorType.CONNECTION_UNKNOWN_DATABASE_ERROR,
{"invalid": ["database"]},
),
SYNTAX_ERROR_REGEX: (
__(
'Please check your query for syntax errors near "%(server_error)s". '
"Then, try running your query again."
),
SupersetErrorType.SYNTAX_ERROR,
{},
),
}

@classmethod
Expand Down
10 changes: 10 additions & 0 deletions superset/db_engine_specs/postgres.py
Expand Up @@ -85,6 +85,8 @@ class FixedOffsetTimezone(_FixedOffset):
r"does not exist\s+LINE (?P<location>\d+?)"
)

SYNTAX_ERROR_REGEX = re.compile('syntax error at or near "(?P<syntax_error>.*?)"')


class PostgresBaseEngineSpec(BaseEngineSpec):
""" Abstract class for Postgres 'like' databases """
Expand Down Expand Up @@ -151,6 +153,14 @@ class PostgresBaseEngineSpec(BaseEngineSpec):
SupersetErrorType.COLUMN_DOES_NOT_EXIST_ERROR,
{},
),
SYNTAX_ERROR_REGEX: (
__(
"Please check your query for syntax errors at or "
'near "%(syntax_error)s". Then, try running your query again.'
),
SupersetErrorType.SYNTAX_ERROR,
{},
),
}

@classmethod
Expand Down
24 changes: 24 additions & 0 deletions tests/db_engine_specs/athena_tests.py
Expand Up @@ -15,6 +15,7 @@
# specific language governing permissions and limitations
# under the License.
from superset.db_engine_specs.athena import AthenaEngineSpec
from superset.errors import ErrorLevel, SupersetError, SupersetErrorType
from tests.db_engine_specs.base_tests import TestDbEngineSpec


Expand All @@ -31,3 +32,26 @@ def test_convert_dttm(self):
AthenaEngineSpec.convert_dttm("TIMESTAMP", dttm),
"from_iso8601_timestamp('2019-01-02T03:04:05.678900')",
)

def test_extract_errors(self):
"""
Test that custom error messages are extracted correctly.
"""
msg = ": mismatched input 'fromm'. Expecting: "
result = AthenaEngineSpec.extract_errors(Exception(msg))
assert result == [
SupersetError(
message='Please check your query for syntax errors at or near "fromm". Then, try running your query again.',
error_type=SupersetErrorType.SYNTAX_ERROR,
level=ErrorLevel.ERROR,
extra={
"engine_name": "Amazon Athena",
"issue_codes": [
{
"code": 1030,
"message": "Issue 1030 - The query has a syntax error.",
}
],
},
)
]
44 changes: 44 additions & 0 deletions tests/db_engine_specs/gsheets_tests.py
@@ -0,0 +1,44 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
from superset.db_engine_specs.gsheets import GSheetsEngineSpec
from superset.errors import ErrorLevel, SupersetError, SupersetErrorType
from tests.db_engine_specs.base_tests import TestDbEngineSpec


class TestGsheetsDbEngineSpec(TestDbEngineSpec):
def test_extract_errors(self):
"""
Test that custom error messages are extracted correctly.
"""
msg = 'SQLError: near "fromm": syntax error'
result = GSheetsEngineSpec.extract_errors(Exception(msg))
assert result == [
SupersetError(
message='Please check your query for syntax errors near "fromm". Then, try running your query again.',
error_type=SupersetErrorType.SYNTAX_ERROR,
level=ErrorLevel.ERROR,
extra={
"engine_name": "Google Sheets",
"issue_codes": [
{
"code": 1030,
"message": "Issue 1030 - The query has a syntax error.",
}
],
},
)
]
20 changes: 19 additions & 1 deletion tests/db_engine_specs/mysql_tests.py
Expand Up @@ -199,7 +199,6 @@ def test_extract_errors(self):

msg = "mysql: Unknown database 'badDB'"
result = MySQLEngineSpec.extract_errors(Exception(msg))
print(result)
assert result == [
SupersetError(
message='Unable to connect to database "badDB".',
Expand All @@ -217,3 +216,22 @@ def test_extract_errors(self):
},
)
]

msg = "check the manual that corresponds to your MySQL server version for the right syntax to use near 'fromm"
result = MySQLEngineSpec.extract_errors(Exception(msg))
assert result == [
SupersetError(
message='Please check your query for syntax errors near "fromm". Then, try running your query again.',
error_type=SupersetErrorType.SYNTAX_ERROR,
level=ErrorLevel.ERROR,
extra={
"engine_name": "MySQL",
"issue_codes": [
{
"code": 1030,
"message": "Issue 1030 - The query has a syntax error.",
}
],
},
)
]
19 changes: 19 additions & 0 deletions tests/db_engine_specs/postgres_tests.py
Expand Up @@ -421,6 +421,25 @@ def test_extract_errors(self):
)
]

msg = 'syntax error at or near "fromm"'
result = PostgresEngineSpec.extract_errors(Exception(msg))
assert result == [
SupersetError(
message='Please check your query for syntax errors at or near "fromm". Then, try running your query again.',
error_type=SupersetErrorType.SYNTAX_ERROR,
level=ErrorLevel.ERROR,
extra={
"engine_name": "PostgreSQL",
"issue_codes": [
{
"code": 1030,
"message": "Issue 1030 - The query has a syntax error.",
}
],
},
)
]


def test_base_parameters_mixin():
parameters = {
Expand Down

0 comments on commit 67988e7

Please sign in to comment.