) {
- const [isModalOpen, setIsModalOpen] = useState(false);
- const [isMessageExpanded, setIsMessageExpanded] = useState(false);
- const { extra } = error;
+ const { extra, level } = error;
const isVisualization = (['dashboard', 'explore'] as (
| string
| undefined
)[]).includes(source);
- const isExpandable = (['explore', 'sqllab'] as (
- | string
- | undefined
- )[]).includes(source);
-
- const title = isVisualization
+ const subtitle = isVisualization
? tn(
'We’re having trouble loading this visualization. Queries are set to timeout after %s second.',
'We’re having trouble loading this visualization. Queries are set to timeout after %s seconds.',
@@ -125,7 +57,7 @@ function TimeoutErrorMessage({
extra.timeout,
);
- const message = (
+ const body = (
<>
{t('This may be triggered by:')}
@@ -157,91 +89,19 @@ function TimeoutErrorMessage({
>
);
- const copyText = `${title}
+ const copyText = `${subtitle}
${t('This may be triggered by:')}
${extra.issue_codes.map(issueCode => issueCode.message).join('\n')}`;
return (
-
-
- {isExpandable ? (
-
- ) : (
- setIsModalOpen(false)}>
-
-
-
- {t('Timeout Error')}
-
- setIsModalOpen(false)}
- >
-
-
-
-
- {title}
-
- {message}
-
-
- {t('Copy Message')}}
- />
- setIsModalOpen(false)}>
- {t('Close')}
-
-
-
- )}
-
+
);
}
diff --git a/superset-frontend/src/setup/setupErrorMessages.ts b/superset-frontend/src/setup/setupErrorMessages.ts
index 269e7c573..29f3940a1 100644
--- a/superset-frontend/src/setup/setupErrorMessages.ts
+++ b/superset-frontend/src/setup/setupErrorMessages.ts
@@ -19,6 +19,7 @@
import getErrorMessageComponentRegistry from 'src/components/ErrorMessage/getErrorMessageComponentRegistry';
import { ErrorTypeEnum } from 'src/components/ErrorMessage/types';
import TimeoutErrorMessage from 'src/components/ErrorMessage/TimeoutErrorMessage';
+import DatabaseErrorMessage from 'src/components/ErrorMessage/DatabaseErrorMessage';
import setupErrorMessagesExtra from './setupErrorMessagesExtra';
@@ -33,5 +34,9 @@ export default function setupErrorMessages() {
ErrorTypeEnum.BACKEND_TIMEOUT_ERROR,
TimeoutErrorMessage,
);
+ errorMessageComponentRegistry.registerValue(
+ ErrorTypeEnum.GENERIC_DB_ENGINE_ERROR,
+ DatabaseErrorMessage,
+ );
setupErrorMessagesExtra();
}
diff --git a/superset/db_engine_specs/athena.py b/superset/db_engine_specs/athena.py
index eaf76e858..91e1069ff 100644
--- a/superset/db_engine_specs/athena.py
+++ b/superset/db_engine_specs/athena.py
@@ -23,6 +23,7 @@ from superset.utils import core as utils
class AthenaEngineSpec(BaseEngineSpec):
engine = "awsathena"
+ engine_name = "Amazon Athena"
_time_grain_expressions = {
None: "{col}",
diff --git a/superset/db_engine_specs/base.py b/superset/db_engine_specs/base.py
index 120ea4ba9..cfd651b13 100644
--- a/superset/db_engine_specs/base.py
+++ b/superset/db_engine_specs/base.py
@@ -137,6 +137,9 @@ class BaseEngineSpec: # pylint: disable=too-many-public-methods
"""Abstract class for database engine specific configurations"""
engine = "base" # str as defined in sqlalchemy.engine.engine
+ engine_name: Optional[
+ str
+ ] = None # used for user messages, overridden in child classes
_date_trunc_functions: Dict[str, str] = {}
_time_grain_expressions: Dict[Optional[str], str] = {}
time_groupby_inline = False
@@ -569,7 +572,7 @@ class BaseEngineSpec: # pylint: disable=too-many-public-methods
return f"{cls.engine} error: {cls._extract_error_message(ex)}"
@classmethod
- def _extract_error_message(cls, ex: Exception) -> Optional[str]:
+ def _extract_error_message(cls, ex: Exception) -> str:
"""Extract error message for queries"""
return utils.error_msg_from_exception(ex)
@@ -579,9 +582,9 @@ class BaseEngineSpec: # pylint: disable=too-many-public-methods
dataclasses.asdict(
SupersetError(
error_type=SupersetErrorType.GENERIC_DB_ENGINE_ERROR,
- message=cls.extract_error_message(ex),
+ message=cls._extract_error_message(ex),
level=ErrorLevel.ERROR,
- extra={"engine": cls.engine},
+ extra={"engine_name": cls.engine_name},
)
)
]
diff --git a/superset/db_engine_specs/bigquery.py b/superset/db_engine_specs/bigquery.py
index f45145f3b..ea33531b4 100644
--- a/superset/db_engine_specs/bigquery.py
+++ b/superset/db_engine_specs/bigquery.py
@@ -37,6 +37,7 @@ class BigQueryEngineSpec(BaseEngineSpec):
As contributed by @mxmzdlv on issue #945"""
engine = "bigquery"
+ engine_name = "Google BigQuery"
max_column_name_length = 128
"""
diff --git a/superset/db_engine_specs/clickhouse.py b/superset/db_engine_specs/clickhouse.py
index f02ef51ab..658aef01f 100644
--- a/superset/db_engine_specs/clickhouse.py
+++ b/superset/db_engine_specs/clickhouse.py
@@ -25,6 +25,7 @@ class ClickHouseEngineSpec(BaseEngineSpec): # pylint: disable=abstract-method
"""Dialect for ClickHouse analytical DB."""
engine = "clickhouse"
+ engine_name = "ClickHouse"
time_secondary_columns = True
time_groupby_inline = True
diff --git a/superset/db_engine_specs/cockroachdb.py b/superset/db_engine_specs/cockroachdb.py
index 09fa98d58..f2f00c1a0 100644
--- a/superset/db_engine_specs/cockroachdb.py
+++ b/superset/db_engine_specs/cockroachdb.py
@@ -19,3 +19,4 @@ from superset.db_engine_specs.postgres import PostgresEngineSpec
class CockroachDbEngineSpec(PostgresEngineSpec):
engine = "cockroachdb"
+ engine_name = "CockroachDB"
diff --git a/superset/db_engine_specs/db2.py b/superset/db_engine_specs/db2.py
index 4087d2186..ba03366de 100644
--- a/superset/db_engine_specs/db2.py
+++ b/superset/db_engine_specs/db2.py
@@ -19,6 +19,7 @@ from superset.db_engine_specs.base import BaseEngineSpec, LimitMethod
class Db2EngineSpec(BaseEngineSpec):
engine = "ibm_db_sa"
+ engine_name = "IBM Db2"
limit_method = LimitMethod.WRAP_SQL
force_column_alias_quotes = True
max_column_name_length = 30
diff --git a/superset/db_engine_specs/dremio.py b/superset/db_engine_specs/dremio.py
index 33f027d3d..4a1142424 100644
--- a/superset/db_engine_specs/dremio.py
+++ b/superset/db_engine_specs/dremio.py
@@ -20,6 +20,7 @@ from superset.db_engine_specs.base import BaseEngineSpec
class DremioBaseEngineSpec(BaseEngineSpec):
engine = "dremio"
+ engine_name = "Dremio"
_time_grain_expressions = {
None: "{col}",
diff --git a/superset/db_engine_specs/drill.py b/superset/db_engine_specs/drill.py
index b1b0ceaf6..7406d654c 100644
--- a/superset/db_engine_specs/drill.py
+++ b/superset/db_engine_specs/drill.py
@@ -28,6 +28,7 @@ class DrillEngineSpec(BaseEngineSpec):
"""Engine spec for Apache Drill"""
engine = "drill"
+ engine_name = "Apache Drill"
_time_grain_expressions = {
None: "{col}",
diff --git a/superset/db_engine_specs/druid.py b/superset/db_engine_specs/druid.py
index 5a81ea9da..f941fd1ba 100644
--- a/superset/db_engine_specs/druid.py
+++ b/superset/db_engine_specs/druid.py
@@ -35,6 +35,7 @@ class DruidEngineSpec(BaseEngineSpec): # pylint: disable=abstract-method
"""Engine spec for Druid.io"""
engine = "druid"
+ engine_name = "Apache Druid"
allows_joins = False
allows_subqueries = True
diff --git a/superset/db_engine_specs/elasticsearch.py b/superset/db_engine_specs/elasticsearch.py
index f1cc561b0..4f6067710 100644
--- a/superset/db_engine_specs/elasticsearch.py
+++ b/superset/db_engine_specs/elasticsearch.py
@@ -23,6 +23,7 @@ from superset.utils import core as utils
class ElasticSearchEngineSpec(BaseEngineSpec): # pylint: disable=abstract-method
engine = "elasticsearch"
+ engine_name = "ElasticSearch"
time_groupby_inline = True
time_secondary_columns = True
allows_joins = False
diff --git a/superset/db_engine_specs/exasol.py b/superset/db_engine_specs/exasol.py
index 23449f0f8..a485be542 100644
--- a/superset/db_engine_specs/exasol.py
+++ b/superset/db_engine_specs/exasol.py
@@ -23,6 +23,7 @@ class ExasolEngineSpec(BaseEngineSpec): # pylint: disable=abstract-method
"""Engine spec for Exasol"""
engine = "exa"
+ engine_name = "Exasol"
max_column_name_length = 128
# Exasol's DATE_TRUNC function is PostgresSQL compatible
diff --git a/superset/db_engine_specs/gsheets.py b/superset/db_engine_specs/gsheets.py
index 698728e09..308bc560a 100644
--- a/superset/db_engine_specs/gsheets.py
+++ b/superset/db_engine_specs/gsheets.py
@@ -21,5 +21,6 @@ class GSheetsEngineSpec(SqliteEngineSpec):
"""Engine for Google spreadsheets"""
engine = "gsheets"
+ engine_name = "Google Sheets"
allows_joins = False
allows_subqueries = False
diff --git a/superset/db_engine_specs/hana.py b/superset/db_engine_specs/hana.py
index 2514194f4..c4b157a62 100644
--- a/superset/db_engine_specs/hana.py
+++ b/superset/db_engine_specs/hana.py
@@ -24,6 +24,7 @@ from superset.utils import core as utils
class HanaEngineSpec(PostgresBaseEngineSpec):
engine = "hana"
+ engine_name = "SAP HANA"
limit_method = LimitMethod.WRAP_SQL
force_column_alias_quotes = True
max_column_name_length = 30
diff --git a/superset/db_engine_specs/hive.py b/superset/db_engine_specs/hive.py
index 206e1c7d3..9cbcfb7e9 100644
--- a/superset/db_engine_specs/hive.py
+++ b/superset/db_engine_specs/hive.py
@@ -55,6 +55,7 @@ class HiveEngineSpec(PrestoEngineSpec):
"""Reuses PrestoEngineSpec functionality."""
engine = "hive"
+ engine_name = "Apache Hive"
max_column_name_length = 767
# pylint: disable=line-too-long
_time_grain_expressions = {
diff --git a/superset/db_engine_specs/impala.py b/superset/db_engine_specs/impala.py
index c0c4f0743..9d8dc9137 100644
--- a/superset/db_engine_specs/impala.py
+++ b/superset/db_engine_specs/impala.py
@@ -27,6 +27,7 @@ class ImpalaEngineSpec(BaseEngineSpec):
"""Engine spec for Cloudera's Impala"""
engine = "impala"
+ engine_name = "Apache Impala"
_time_grain_expressions = {
None: "{col}",
diff --git a/superset/db_engine_specs/kylin.py b/superset/db_engine_specs/kylin.py
index 9f828d11d..4a64091d1 100644
--- a/superset/db_engine_specs/kylin.py
+++ b/superset/db_engine_specs/kylin.py
@@ -25,6 +25,7 @@ class KylinEngineSpec(BaseEngineSpec): # pylint: disable=abstract-method
"""Dialect for Apache Kylin"""
engine = "kylin"
+ engine_name = "Apache Kylin"
_time_grain_expressions = {
None: "{col}",
diff --git a/superset/db_engine_specs/mssql.py b/superset/db_engine_specs/mssql.py
index a8a6b9a86..abe1f6c2a 100644
--- a/superset/db_engine_specs/mssql.py
+++ b/superset/db_engine_specs/mssql.py
@@ -32,6 +32,7 @@ logger = logging.getLogger(__name__)
class MssqlEngineSpec(BaseEngineSpec):
engine = "mssql"
+ engine_name = "Microsoft SQL"
limit_method = LimitMethod.WRAP_SQL
max_column_name_length = 128
diff --git a/superset/db_engine_specs/mysql.py b/superset/db_engine_specs/mysql.py
index 7d750d3aa..4d57c3807 100644
--- a/superset/db_engine_specs/mysql.py
+++ b/superset/db_engine_specs/mysql.py
@@ -26,6 +26,7 @@ from superset.utils import core as utils
class MySQLEngineSpec(BaseEngineSpec):
engine = "mysql"
+ engine_name = "MySQL"
max_column_name_length = 64
_time_grain_expressions = {
diff --git a/superset/db_engine_specs/oracle.py b/superset/db_engine_specs/oracle.py
index 813b1507a..24ebdb00d 100644
--- a/superset/db_engine_specs/oracle.py
+++ b/superset/db_engine_specs/oracle.py
@@ -23,6 +23,7 @@ from superset.utils import core as utils
class OracleEngineSpec(BaseEngineSpec):
engine = "oracle"
+ engine_name = "Oracle"
limit_method = LimitMethod.WRAP_SQL
force_column_alias_quotes = True
max_column_name_length = 30
diff --git a/superset/db_engine_specs/pinot.py b/superset/db_engine_specs/pinot.py
index 853d756e3..d79a6947a 100644
--- a/superset/db_engine_specs/pinot.py
+++ b/superset/db_engine_specs/pinot.py
@@ -24,6 +24,7 @@ from superset.db_engine_specs.base import BaseEngineSpec, TimestampExpression
class PinotEngineSpec(BaseEngineSpec): # pylint: disable=abstract-method
engine = "pinot"
+ engine_name = "Apache Pinot"
allows_subqueries = False
allows_joins = False
allows_column_aliases = False
diff --git a/superset/db_engine_specs/postgres.py b/superset/db_engine_specs/postgres.py
index dceac26b1..0ccf51dba 100644
--- a/superset/db_engine_specs/postgres.py
+++ b/superset/db_engine_specs/postgres.py
@@ -38,6 +38,7 @@ class PostgresBaseEngineSpec(BaseEngineSpec):
""" Abstract class for Postgres 'like' databases """
engine = ""
+ engine_name = "PostgreSQL"
_time_grain_expressions = {
None: "{col}",
diff --git a/superset/db_engine_specs/presto.py b/superset/db_engine_specs/presto.py
index fc74eb2cc..16e6a4c53 100644
--- a/superset/db_engine_specs/presto.py
+++ b/superset/db_engine_specs/presto.py
@@ -27,6 +27,7 @@ from urllib import parse
import pandas as pd
import simplejson as json
+from flask_babel import lazy_gettext as _
from sqlalchemy import Column, literal_column
from sqlalchemy.engine.base import Engine
from sqlalchemy.engine.reflection import Inspector
@@ -104,6 +105,7 @@ def get_children(column: Dict[str, str]) -> List[Dict[str, str]]:
class PrestoEngineSpec(BaseEngineSpec):
engine = "presto"
+ engine_name = "Presto"
_time_grain_expressions = {
None: "{col}",
@@ -780,7 +782,7 @@ class PrestoEngineSpec(BaseEngineSpec):
polled = cursor.poll()
@classmethod
- def _extract_error_message(cls, ex: Exception) -> Optional[str]:
+ def _extract_error_message(cls, ex: Exception) -> str:
if (
hasattr(ex, "orig")
and type(ex.orig).__name__ == "DatabaseError" # type: ignore
@@ -794,7 +796,7 @@ class PrestoEngineSpec(BaseEngineSpec):
)
if type(ex).__name__ == "DatabaseError" and hasattr(ex, "args") and ex.args:
error_dict = ex.args[0]
- return error_dict.get("message")
+ return error_dict.get("message", _("Unknown Presto Error"))
return utils.error_msg_from_exception(ex)
@classmethod
diff --git a/superset/db_engine_specs/redshift.py b/superset/db_engine_specs/redshift.py
index 5c9f4bc46..ef7b0e29a 100644
--- a/superset/db_engine_specs/redshift.py
+++ b/superset/db_engine_specs/redshift.py
@@ -19,6 +19,7 @@ from superset.db_engine_specs.postgres import PostgresBaseEngineSpec
class RedshiftEngineSpec(PostgresBaseEngineSpec):
engine = "redshift"
+ engine_name = "Amazon Redshift"
max_column_name_length = 127
@staticmethod
diff --git a/superset/db_engine_specs/snowflake.py b/superset/db_engine_specs/snowflake.py
index 8b78b5248..e7282b884 100644
--- a/superset/db_engine_specs/snowflake.py
+++ b/superset/db_engine_specs/snowflake.py
@@ -30,6 +30,7 @@ if TYPE_CHECKING:
class SnowflakeEngineSpec(PostgresBaseEngineSpec):
engine = "snowflake"
+ engine_name = "Snowflake"
force_column_alias_quotes = True
max_column_name_length = 256
diff --git a/superset/db_engine_specs/sqlite.py b/superset/db_engine_specs/sqlite.py
index 72f1f3187..c14b8b937 100644
--- a/superset/db_engine_specs/sqlite.py
+++ b/superset/db_engine_specs/sqlite.py
@@ -29,6 +29,7 @@ if TYPE_CHECKING:
class SqliteEngineSpec(BaseEngineSpec):
engine = "sqlite"
+ engine_name = "SQLite"
_time_grain_expressions = {
None: "{col}",
diff --git a/superset/db_engine_specs/teradata.py b/superset/db_engine_specs/teradata.py
index 0226baef6..88bffa5a0 100644
--- a/superset/db_engine_specs/teradata.py
+++ b/superset/db_engine_specs/teradata.py
@@ -21,6 +21,7 @@ class TeradataEngineSpec(BaseEngineSpec):
"""Dialect for Teradata DB."""
engine = "teradata"
+ engine_name = "Teradata"
limit_method = LimitMethod.WRAP_SQL
max_column_name_length = 30 # since 14.10 this is 128
diff --git a/superset/db_engine_specs/vertica.py b/superset/db_engine_specs/vertica.py
index e5f890122..5f3d99c6c 100644
--- a/superset/db_engine_specs/vertica.py
+++ b/superset/db_engine_specs/vertica.py
@@ -19,3 +19,4 @@ from superset.db_engine_specs.postgres import PostgresBaseEngineSpec
class VerticaEngineSpec(PostgresBaseEngineSpec):
engine = "vertica"
+ engine_name = "Vertica"
diff --git a/superset/errors.py b/superset/errors.py
index f2fda00bb..08a8cd80a 100644
--- a/superset/errors.py
+++ b/superset/errors.py
@@ -61,7 +61,13 @@ ERROR_TYPES_TO_ISSUE_CODES_MAPPING = {
"code": 1001,
"message": _("Issue 1001 - The database is under an unusual load."),
},
- ]
+ ],
+ SupersetErrorType.GENERIC_DB_ENGINE_ERROR: [
+ {
+ "code": 1002,
+ "message": _("Issue 1002 - The database returned an unexpected error."),
+ }
+ ],
}