mirror of
https://github.com/apache/superset.git
synced 2026-04-18 23:55:00 +00:00
feat: error messages for Presto connections (#14172)
* chore: rename connection errors * feat: error messages for Presto connections * Add unit tests * Update docs/src/pages/docs/Miscellaneous/issue_codes.mdx Co-authored-by: AAfghahi <48933336+AAfghahi@users.noreply.github.com> Co-authored-by: AAfghahi <48933336+AAfghahi@users.noreply.github.com>
This commit is contained in:
@@ -166,3 +166,12 @@ Either the database is spelled incorrectly or does not exist.
|
||||
```
|
||||
|
||||
Either the database was written incorrectly or it does not exist. Check that it was typed correctly.
|
||||
|
||||
|
||||
## Issue 1016
|
||||
|
||||
```
|
||||
The schema was deleted or renamed in the database.
|
||||
```
|
||||
|
||||
The schema was either removed or renamed. Check that the schema is typed correctly and exists.
|
||||
|
||||
@@ -28,6 +28,7 @@ export const ErrorTypeEnum = {
|
||||
GENERIC_DB_ENGINE_ERROR: 'GENERIC_DB_ENGINE_ERROR',
|
||||
COLUMN_DOES_NOT_EXIST_ERROR: 'COLUMN_DOES_NOT_EXIST_ERROR',
|
||||
TABLE_DOES_NOT_EXIST_ERROR: 'TABLE_DOES_NOT_EXIST_ERROR',
|
||||
SCHEMA_DOES_NOT_EXIST_ERROR: 'SCHEMA_DOES_NOT_EXIST_ERROR',
|
||||
CONNECTION_INVALID_USERNAME_ERROR: 'CONNECTION_INVALID_USERNAME_ERROR',
|
||||
CONNECTION_INVALID_PASSWORD_ERROR: 'CONNECTION_INVALID_PASSWORD_ERROR',
|
||||
CONNECTION_INVALID_HOSTNAME_ERROR: 'CONNECTION_INVALID_HOSTNAME_ERROR',
|
||||
|
||||
@@ -79,5 +79,9 @@ export default function setupErrorMessages() {
|
||||
ErrorTypeEnum.CONNECTION_UNKNOWN_DATABASE_ERROR,
|
||||
DatabaseErrorMessage,
|
||||
);
|
||||
errorMessageComponentRegistry.registerValue(
|
||||
ErrorTypeEnum.SCHEMA_DOES_NOT_EXIST_ERROR,
|
||||
DatabaseErrorMessage,
|
||||
);
|
||||
setupErrorMessagesExtra();
|
||||
}
|
||||
|
||||
@@ -130,7 +130,8 @@ class DatabaseTestConnectionDriverError(CommandInvalidError):
|
||||
message = _("Could not load database driver")
|
||||
|
||||
|
||||
class DatabaseTestConnectionUnexpectedError(CommandInvalidError):
|
||||
class DatabaseTestConnectionUnexpectedError(SupersetErrorsException):
|
||||
status = 422
|
||||
message = _("Unexpected error occurred, please check your logs for details")
|
||||
|
||||
|
||||
|
||||
@@ -49,6 +49,17 @@ class TestConnectionDatabaseCommand(BaseCommand):
|
||||
uri = self._properties.get("sqlalchemy_uri", "")
|
||||
if self._model and uri == self._model.safe_sqlalchemy_uri():
|
||||
uri = self._model.sqlalchemy_uri_decrypted
|
||||
|
||||
# context for error messages
|
||||
url = make_url(uri)
|
||||
context = {
|
||||
"hostname": url.host,
|
||||
"password": url.password,
|
||||
"port": url.port,
|
||||
"username": url.username,
|
||||
"database": url.database,
|
||||
}
|
||||
|
||||
try:
|
||||
database = DatabaseDAO.build_db_for_connection_test(
|
||||
server_cert=self._properties.get("server_cert", ""),
|
||||
@@ -87,14 +98,6 @@ class TestConnectionDatabaseCommand(BaseCommand):
|
||||
engine=database.db_engine_spec.__name__,
|
||||
)
|
||||
# check for custom errors (wrong username, wrong password, etc)
|
||||
url = make_url(uri)
|
||||
context = {
|
||||
"hostname": url.host,
|
||||
"password": url.password,
|
||||
"port": url.port,
|
||||
"username": url.username,
|
||||
"database": url.database,
|
||||
}
|
||||
errors = database.db_engine_spec.extract_errors(ex, context)
|
||||
raise DatabaseTestConnectionFailedError(errors)
|
||||
except SupersetSecurityException as ex:
|
||||
@@ -108,7 +111,8 @@ class TestConnectionDatabaseCommand(BaseCommand):
|
||||
action=f"test_connection_error.{ex.__class__.__name__}",
|
||||
engine=database.db_engine_spec.__name__,
|
||||
)
|
||||
raise DatabaseTestConnectionUnexpectedError(str(ex))
|
||||
errors = database.db_engine_spec.extract_errors(ex, context)
|
||||
raise DatabaseTestConnectionUnexpectedError(errors)
|
||||
|
||||
def validate(self) -> None:
|
||||
database_name = self._properties.get("database_name")
|
||||
|
||||
@@ -121,10 +121,7 @@ class MySQLEngineSpec(BaseEngineSpec):
|
||||
SupersetErrorType.CONNECTION_HOST_DOWN_ERROR,
|
||||
),
|
||||
CONNECTION_UNKNOWN_DATABASE_REGEX: (
|
||||
__(
|
||||
'We were unable to connect to your database named "%(database)s". '
|
||||
"Please verify your database name and try again."
|
||||
),
|
||||
__('Unable to connect to database "%(database)s".'),
|
||||
SupersetErrorType.CONNECTION_UNKNOWN_DATABASE_ERROR,
|
||||
),
|
||||
}
|
||||
|
||||
@@ -124,10 +124,7 @@ class PostgresBaseEngineSpec(BaseEngineSpec):
|
||||
SupersetErrorType.CONNECTION_HOST_DOWN_ERROR,
|
||||
),
|
||||
CONNECTION_UNKNOWN_DATABASE_REGEX: (
|
||||
__(
|
||||
'We were unable to connect to your database named "%(database)s".'
|
||||
" Please verify your database name and try again."
|
||||
),
|
||||
__('Unable to connect to database "%(database)s".'),
|
||||
SupersetErrorType.CONNECTION_UNKNOWN_DATABASE_ERROR,
|
||||
),
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ from sqlalchemy.types import TypeEngine
|
||||
|
||||
from superset import app, cache_manager, is_feature_enabled
|
||||
from superset.db_engine_specs.base import BaseEngineSpec
|
||||
from superset.errors import ErrorLevel, SupersetError, SupersetErrorType
|
||||
from superset.errors import SupersetErrorType
|
||||
from superset.exceptions import SupersetTemplateException
|
||||
from superset.models.sql_lab import Query
|
||||
from superset.models.sql_types.presto_sql_types import (
|
||||
@@ -70,8 +70,28 @@ if TYPE_CHECKING:
|
||||
# prevent circular imports
|
||||
from superset.models.core import Database
|
||||
|
||||
COLUMN_NOT_RESOLVED_ERROR_REGEX = "line (.+?): .*Column '(.+?)' cannot be resolved"
|
||||
TABLE_DOES_NOT_EXIST_ERROR_REGEX = ".*Table (.+?) does not exist"
|
||||
COLUMN_DOES_NOT_EXIST_REGEX = re.compile(
|
||||
"line (?P<location>.+?): .*Column '(?P<column_name>.+?)' cannot be resolved"
|
||||
)
|
||||
TABLE_DOES_NOT_EXIST_REGEX = re.compile(".*Table (?P<table_name>.+?) does not exist")
|
||||
SCHEMA_DOES_NOT_EXIST_REGEX = re.compile(
|
||||
"line (?P<location>.+?): .*Schema '(?P<schema_name>.+?)' does not exist"
|
||||
)
|
||||
CONNECTION_ACCESS_DENIED_REGEX = re.compile("Access Denied: Invalid credentials")
|
||||
CONNECTION_INVALID_HOSTNAME_REGEX = re.compile(
|
||||
r"Failed to establish a new connection: \[Errno 8\] nodename nor servname "
|
||||
"provided, or not known"
|
||||
)
|
||||
CONNECTION_HOST_DOWN_REGEX = re.compile(
|
||||
r"Failed to establish a new connection: \[Errno 60\] Operation timed out"
|
||||
)
|
||||
CONNECTION_PORT_CLOSED_REGEX = re.compile(
|
||||
r"Failed to establish a new connection: \[Errno 61\] Connection refused"
|
||||
)
|
||||
CONNECTION_UNKNOWN_DATABASE_ERROR = re.compile(
|
||||
r"line (?P<location>.+?): Catalog '(?P<catalog_name>.+?)' does not exist"
|
||||
)
|
||||
|
||||
|
||||
QueryStatus = utils.QueryStatus
|
||||
config = app.config
|
||||
@@ -145,6 +165,53 @@ class PrestoEngineSpec(BaseEngineSpec): # pylint: disable=too-many-public-metho
|
||||
"date_add('day', 1, CAST({col} AS TIMESTAMP))))",
|
||||
}
|
||||
|
||||
custom_errors = {
|
||||
COLUMN_DOES_NOT_EXIST_REGEX: (
|
||||
__(
|
||||
'We can\'t seem to resolve the column "%(column_name)s" at '
|
||||
"line %(location)s.",
|
||||
),
|
||||
SupersetErrorType.COLUMN_DOES_NOT_EXIST_ERROR,
|
||||
),
|
||||
TABLE_DOES_NOT_EXIST_REGEX: (
|
||||
__(
|
||||
'The table "%(table_name)s" does not exist. '
|
||||
"A valid table must be used to run this query.",
|
||||
),
|
||||
SupersetErrorType.TABLE_DOES_NOT_EXIST_ERROR,
|
||||
),
|
||||
SCHEMA_DOES_NOT_EXIST_REGEX: (
|
||||
__(
|
||||
'The schema "%(schema_name)s" does not exist. '
|
||||
"A valid schema must be used to run this query.",
|
||||
),
|
||||
SupersetErrorType.SCHEMA_DOES_NOT_EXIST_ERROR,
|
||||
),
|
||||
CONNECTION_ACCESS_DENIED_REGEX: (
|
||||
__('Either the username "%(username)s" or the password is incorrect.'),
|
||||
SupersetErrorType.CONNECTION_ACCESS_DENIED_ERROR,
|
||||
),
|
||||
CONNECTION_INVALID_HOSTNAME_REGEX: (
|
||||
__('The hostname "%(hostname)s" cannot be resolved.'),
|
||||
SupersetErrorType.CONNECTION_INVALID_HOSTNAME_ERROR,
|
||||
),
|
||||
CONNECTION_HOST_DOWN_REGEX: (
|
||||
__(
|
||||
'The host "%(hostname)s" might be down, and can\'t be '
|
||||
"reached on port %(port)s."
|
||||
),
|
||||
SupersetErrorType.CONNECTION_HOST_DOWN_ERROR,
|
||||
),
|
||||
CONNECTION_PORT_CLOSED_REGEX: (
|
||||
__('Port %(port)s on hostname "%(hostname)s" refused the connection.'),
|
||||
SupersetErrorType.CONNECTION_PORT_CLOSED_ERROR,
|
||||
),
|
||||
CONNECTION_UNKNOWN_DATABASE_ERROR: (
|
||||
__('Unable to connect to catalog named "%(catalog_name)s".'),
|
||||
SupersetErrorType.CONNECTION_UNKNOWN_DATABASE_ERROR,
|
||||
),
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def get_allow_cost_estimate(cls, extra: Dict[str, Any]) -> bool:
|
||||
version = extra.get("version")
|
||||
@@ -1131,45 +1198,6 @@ class PrestoEngineSpec(BaseEngineSpec): # pylint: disable=too-many-public-metho
|
||||
"""
|
||||
return database.get_df("SHOW FUNCTIONS")["Function"].tolist()
|
||||
|
||||
@classmethod
|
||||
def extract_errors(
|
||||
cls, ex: Exception, context: Optional[Dict[str, Any]] = None
|
||||
) -> List[SupersetError]:
|
||||
raw_message = cls._extract_error_message(ex)
|
||||
|
||||
column_match = re.search(COLUMN_NOT_RESOLVED_ERROR_REGEX, raw_message)
|
||||
if column_match:
|
||||
return [
|
||||
SupersetError(
|
||||
error_type=SupersetErrorType.COLUMN_DOES_NOT_EXIST_ERROR,
|
||||
message=__(
|
||||
'We can\'t seem to resolve the column "%(column_name)s" at '
|
||||
"line %(location)s.",
|
||||
column_name=column_match.group(2),
|
||||
location=column_match.group(1),
|
||||
),
|
||||
level=ErrorLevel.ERROR,
|
||||
extra={"engine_name": cls.engine_name},
|
||||
)
|
||||
]
|
||||
|
||||
table_match = re.search(TABLE_DOES_NOT_EXIST_ERROR_REGEX, raw_message)
|
||||
if table_match:
|
||||
return [
|
||||
SupersetError(
|
||||
error_type=SupersetErrorType.TABLE_DOES_NOT_EXIST_ERROR,
|
||||
message=__(
|
||||
'The table "%(table_name)s" does not exist. '
|
||||
"A valid table must be used to run this query.",
|
||||
table_name=table_match.group(1),
|
||||
),
|
||||
level=ErrorLevel.ERROR,
|
||||
extra={"engine_name": cls.engine_name},
|
||||
)
|
||||
]
|
||||
|
||||
return super().extract_errors(ex, context)
|
||||
|
||||
@classmethod
|
||||
def is_readonly_query(cls, parsed_query: ParsedQuery) -> bool:
|
||||
"""Pessimistic readonly, 100% sure statement won't mutate anything"""
|
||||
|
||||
@@ -39,6 +39,7 @@ class SupersetErrorType(str, Enum):
|
||||
GENERIC_DB_ENGINE_ERROR = "GENERIC_DB_ENGINE_ERROR"
|
||||
COLUMN_DOES_NOT_EXIST_ERROR = "COLUMN_DOES_NOT_EXIST_ERROR"
|
||||
TABLE_DOES_NOT_EXIST_ERROR = "TABLE_DOES_NOT_EXIST_ERROR"
|
||||
SCHEMA_DOES_NOT_EXIST_ERROR = "SCHEMA_DOES_NOT_EXIST_ERROR"
|
||||
CONNECTION_INVALID_USERNAME_ERROR = "CONNECTION_INVALID_USERNAME_ERROR"
|
||||
CONNECTION_INVALID_PASSWORD_ERROR = "CONNECTION_INVALID_PASSWORD_ERROR"
|
||||
CONNECTION_INVALID_HOSTNAME_ERROR = "CONNECTION_INVALID_HOSTNAME_ERROR"
|
||||
@@ -116,6 +117,21 @@ ERROR_TYPES_TO_ISSUE_CODES_MAPPING = {
|
||||
),
|
||||
},
|
||||
],
|
||||
SupersetErrorType.SCHEMA_DOES_NOT_EXIST_ERROR: [
|
||||
{
|
||||
"code": 1003,
|
||||
"message": _(
|
||||
"Issue 1003 - There is a syntax error in the SQL query. "
|
||||
"Perhaps there was a misspelling or a typo."
|
||||
),
|
||||
},
|
||||
{
|
||||
"code": 1016,
|
||||
"message": _(
|
||||
"Issue 1005 - The schema was deleted or renamed in the database."
|
||||
),
|
||||
},
|
||||
],
|
||||
SupersetErrorType.MISSING_TEMPLATE_PARAMS_ERROR: [
|
||||
{
|
||||
"code": 1006,
|
||||
@@ -132,7 +148,7 @@ ERROR_TYPES_TO_ISSUE_CODES_MAPPING = {
|
||||
},
|
||||
],
|
||||
SupersetErrorType.CONNECTION_PORT_CLOSED_ERROR: [
|
||||
{"code": 1008, "message": _("Issue 1008 - The port is closed."),},
|
||||
{"code": 1008, "message": _("Issue 1008 - The port is closed.")},
|
||||
],
|
||||
SupersetErrorType.CONNECTION_HOST_DOWN_ERROR: [
|
||||
{
|
||||
|
||||
@@ -200,17 +200,15 @@ class TestMySQLEngineSpecsDbEngineSpec(TestDbEngineSpec):
|
||||
result = MySQLEngineSpec.extract_errors(Exception(msg))
|
||||
assert result == [
|
||||
SupersetError(
|
||||
message='Unable to connect to database "badDB".',
|
||||
error_type=SupersetErrorType.CONNECTION_UNKNOWN_DATABASE_ERROR,
|
||||
message='We were unable to connect to your database named "badDB".'
|
||||
" Please verify your database name and try again.",
|
||||
level=ErrorLevel.ERROR,
|
||||
extra={
|
||||
"engine_name": "MySQL",
|
||||
"issue_codes": [
|
||||
{
|
||||
"code": 10015,
|
||||
"message": "Issue 1015 - Either the database is "
|
||||
"spelled incorrectly or does not exist.",
|
||||
"code": 1015,
|
||||
"message": "Issue 1015 - Either the database is spelled incorrectly or does not exist.",
|
||||
}
|
||||
],
|
||||
},
|
||||
|
||||
@@ -371,17 +371,18 @@ psql: error: could not connect to server: Operation timed out
|
||||
result = PostgresEngineSpec.extract_errors(Exception(msg))
|
||||
assert result == [
|
||||
SupersetError(
|
||||
message='Unable to connect to database "badDB".',
|
||||
error_type=SupersetErrorType.CONNECTION_UNKNOWN_DATABASE_ERROR,
|
||||
message='We were unable to connect to your database named "badDB".'
|
||||
" Please verify your database name and try again.",
|
||||
level=ErrorLevel.ERROR,
|
||||
extra={
|
||||
"engine_name": "PostgreSQL",
|
||||
"issue_codes": [
|
||||
{
|
||||
"code": 10015,
|
||||
"message": "Issue 1015 - Either the database is "
|
||||
"spelled incorrectly or does not exist.",
|
||||
"code": 1015,
|
||||
"message": (
|
||||
"Issue 1015 - Either the database is spelled "
|
||||
"incorrectly or does not exist.",
|
||||
),
|
||||
}
|
||||
],
|
||||
},
|
||||
|
||||
@@ -23,6 +23,7 @@ from sqlalchemy.engine.result import RowProxy
|
||||
from sqlalchemy.sql import select
|
||||
|
||||
from superset.db_engine_specs.presto import PrestoEngineSpec
|
||||
from superset.errors import ErrorLevel, SupersetError, SupersetErrorType
|
||||
from superset.sql_parse import ParsedQuery
|
||||
from superset.utils.core import DatasourceName, GenericDataType
|
||||
from tests.db_engine_specs.base_tests import TestDbEngineSpec
|
||||
@@ -829,6 +830,193 @@ class TestPrestoDbEngineSpec(TestDbEngineSpec):
|
||||
result = PrestoEngineSpec._extract_error_message(exception)
|
||||
assert result == "Err message"
|
||||
|
||||
def test_extract_errors(self):
|
||||
msg = "Generic Error"
|
||||
result = PrestoEngineSpec.extract_errors(Exception(msg))
|
||||
assert result == [
|
||||
SupersetError(
|
||||
message="Generic Error",
|
||||
error_type=SupersetErrorType.GENERIC_DB_ENGINE_ERROR,
|
||||
level=ErrorLevel.ERROR,
|
||||
extra={
|
||||
"engine_name": "Presto",
|
||||
"issue_codes": [
|
||||
{
|
||||
"code": 1002,
|
||||
"message": "Issue 1002 - The database returned an unexpected error.",
|
||||
}
|
||||
],
|
||||
},
|
||||
)
|
||||
]
|
||||
|
||||
msg = "line 1:8: Column 'bogus' cannot be resolved"
|
||||
result = PrestoEngineSpec.extract_errors(Exception(msg))
|
||||
assert result == [
|
||||
SupersetError(
|
||||
message='We can\'t seem to resolve the column "bogus" at line 1:8.',
|
||||
error_type=SupersetErrorType.COLUMN_DOES_NOT_EXIST_ERROR,
|
||||
level=ErrorLevel.ERROR,
|
||||
extra={
|
||||
"engine_name": "Presto",
|
||||
"issue_codes": [
|
||||
{
|
||||
"code": 1003,
|
||||
"message": "Issue 1003 - There is a syntax error in the SQL query. Perhaps there was a misspelling or a typo.",
|
||||
},
|
||||
{
|
||||
"code": 1004,
|
||||
"message": "Issue 1004 - The column was deleted or renamed in the database.",
|
||||
},
|
||||
],
|
||||
},
|
||||
)
|
||||
]
|
||||
|
||||
msg = "line 1:15: Table 'tpch.tiny.region2' does not exist"
|
||||
result = PrestoEngineSpec.extract_errors(Exception(msg))
|
||||
assert result == [
|
||||
SupersetError(
|
||||
message="The table \"'tpch.tiny.region2'\" does not exist. A valid table must be used to run this query.",
|
||||
error_type=SupersetErrorType.TABLE_DOES_NOT_EXIST_ERROR,
|
||||
level=ErrorLevel.ERROR,
|
||||
extra={
|
||||
"engine_name": "Presto",
|
||||
"issue_codes": [
|
||||
{
|
||||
"code": 1003,
|
||||
"message": "Issue 1003 - There is a syntax error in the SQL query. Perhaps there was a misspelling or a typo.",
|
||||
},
|
||||
{
|
||||
"code": 1005,
|
||||
"message": "Issue 1005 - The table was deleted or renamed in the database.",
|
||||
},
|
||||
],
|
||||
},
|
||||
)
|
||||
]
|
||||
|
||||
msg = "line 1:15: Schema 'tin' does not exist"
|
||||
result = PrestoEngineSpec.extract_errors(Exception(msg))
|
||||
assert result == [
|
||||
SupersetError(
|
||||
message='The schema "tin" does not exist. A valid schema must be used to run this query.',
|
||||
error_type=SupersetErrorType.SCHEMA_DOES_NOT_EXIST_ERROR,
|
||||
level=ErrorLevel.ERROR,
|
||||
extra={
|
||||
"engine_name": "Presto",
|
||||
"issue_codes": [
|
||||
{
|
||||
"code": 1003,
|
||||
"message": "Issue 1003 - There is a syntax error in the SQL query. Perhaps there was a misspelling or a typo.",
|
||||
},
|
||||
{
|
||||
"code": 1016,
|
||||
"message": "Issue 1005 - The schema was deleted or renamed in the database.",
|
||||
},
|
||||
],
|
||||
},
|
||||
)
|
||||
]
|
||||
|
||||
msg = b"Access Denied: Invalid credentials"
|
||||
result = PrestoEngineSpec.extract_errors(Exception(msg), {"username": "alice"})
|
||||
assert result == [
|
||||
SupersetError(
|
||||
message='Either the username "alice" or the password is incorrect.',
|
||||
error_type=SupersetErrorType.CONNECTION_ACCESS_DENIED_ERROR,
|
||||
level=ErrorLevel.ERROR,
|
||||
extra={
|
||||
"engine_name": "Presto",
|
||||
"issue_codes": [
|
||||
{
|
||||
"code": 1014,
|
||||
"message": "Issue 1014 - Either the username or the password is wrong.",
|
||||
}
|
||||
],
|
||||
},
|
||||
)
|
||||
]
|
||||
|
||||
msg = "Failed to establish a new connection: [Errno 8] nodename nor servname provided, or not known"
|
||||
result = PrestoEngineSpec.extract_errors(
|
||||
Exception(msg), {"hostname": "badhost"}
|
||||
)
|
||||
assert result == [
|
||||
SupersetError(
|
||||
message='The hostname "badhost" cannot be resolved.',
|
||||
error_type=SupersetErrorType.CONNECTION_INVALID_HOSTNAME_ERROR,
|
||||
level=ErrorLevel.ERROR,
|
||||
extra={
|
||||
"engine_name": "Presto",
|
||||
"issue_codes": [
|
||||
{
|
||||
"code": 1007,
|
||||
"message": "Issue 1007 - The hostname provided can't be resolved.",
|
||||
}
|
||||
],
|
||||
},
|
||||
)
|
||||
]
|
||||
|
||||
msg = "Failed to establish a new connection: [Errno 60] Operation timed out"
|
||||
result = PrestoEngineSpec.extract_errors(
|
||||
Exception(msg), {"hostname": "badhost", "port": 12345}
|
||||
)
|
||||
assert result == [
|
||||
SupersetError(
|
||||
message='The host "badhost" might be down, and can\'t be reached on port 12345.',
|
||||
error_type=SupersetErrorType.CONNECTION_HOST_DOWN_ERROR,
|
||||
level=ErrorLevel.ERROR,
|
||||
extra={
|
||||
"engine_name": "Presto",
|
||||
"issue_codes": [
|
||||
{
|
||||
"code": 1009,
|
||||
"message": "Issue 1009 - The host might be down, and can't be reached on the provided port.",
|
||||
}
|
||||
],
|
||||
},
|
||||
)
|
||||
]
|
||||
|
||||
msg = "Failed to establish a new connection: [Errno 61] Connection refused"
|
||||
result = PrestoEngineSpec.extract_errors(
|
||||
Exception(msg), {"hostname": "badhost", "port": 12345}
|
||||
)
|
||||
assert result == [
|
||||
SupersetError(
|
||||
message='Port 12345 on hostname "badhost" refused the connection.',
|
||||
error_type=SupersetErrorType.CONNECTION_PORT_CLOSED_ERROR,
|
||||
level=ErrorLevel.ERROR,
|
||||
extra={
|
||||
"engine_name": "Presto",
|
||||
"issue_codes": [
|
||||
{"code": 1008, "message": "Issue 1008 - The port is closed."}
|
||||
],
|
||||
},
|
||||
)
|
||||
]
|
||||
|
||||
msg = "line 1:15: Catalog 'wrong' does not exist"
|
||||
result = PrestoEngineSpec.extract_errors(Exception(msg))
|
||||
assert result == [
|
||||
SupersetError(
|
||||
message='Unable to connect to catalog named "wrong".',
|
||||
error_type=SupersetErrorType.CONNECTION_UNKNOWN_DATABASE_ERROR,
|
||||
level=ErrorLevel.ERROR,
|
||||
extra={
|
||||
"engine_name": "Presto",
|
||||
"issue_codes": [
|
||||
{
|
||||
"code": 1015,
|
||||
"message": "Issue 1015 - Either the database is spelled incorrectly or does not exist.",
|
||||
}
|
||||
],
|
||||
},
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
def test_is_readonly():
|
||||
def is_readonly(sql: str) -> bool:
|
||||
|
||||
Reference in New Issue
Block a user