diff --git a/docs/index.rst b/docs/index.rst
index 00b796d0116..465423a6efa 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -109,6 +109,7 @@ The following RDBMS are currently suppored:
- `Apache Spark SQL `_
- `BigQuery `_
- `ClickHouse `_
+- `Exasol `_
- `Google Sheets `_
- `Greenplum `_
- `IBM Db2 `_
diff --git a/docs/installation.rst b/docs/installation.rst
index fc8fc2b9bd4..cc6792a0d51 100644
--- a/docs/installation.rst
+++ b/docs/installation.rst
@@ -377,6 +377,8 @@ Here's a list of some of the recommended packages.
+------------------+---------------------------------------+-------------------------------------------------+
| ClickHouse | ``pip install sqlalchemy-clickhouse`` | |
+------------------+---------------------------------------+-------------------------------------------------+
+| Exasol | ``pip install sqlalchemy-exasol`` | ``exa+pyodbc://`` |
++------------------+---------------------------------------+-------------------------------------------------+
| Google Sheets | ``pip install gsheetsdb`` | ``gsheets://`` |
+------------------+---------------------------------------+-------------------------------------------------+
| IBM Db2 | ``pip install ibm_db_sa`` | ``db2+ibm_db://`` |
@@ -659,6 +661,25 @@ it in the ``extra`` parameter::
}
+Exasol
+---------
+
+The connection string for Exasol looks like this ::
+
+ exa+pyodbc://{user}:{password}@{host}
+
+*Note*: It's required to have Exasol ODBC drivers installed for the sqlalchemy dialect to work properly. Exasol ODBC Drivers available are here: https://www.exasol.com/portal/display/DOWNLOAD/Exasol+Download+Section
+
+Example config (odbcinst.ini can be left empty) ::
+
+ $ cat $/.../path/to/odbc.ini
+ [EXAODBC]
+ DRIVER = /.../path/to/driver/EXASOL_driver.so
+ EXAHOST = host:8563
+ EXASCHEMA = main
+
+See `SQLAlchemy for Exasol `_.
+
CORS
----
diff --git a/superset/db_engine_specs/exasol.py b/superset/db_engine_specs/exasol.py
new file mode 100644
index 00000000000..c6b38cba5d1
--- /dev/null
+++ b/superset/db_engine_specs/exasol.py
@@ -0,0 +1,48 @@
+# 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.
+# pylint: disable=C,R,W
+from typing import List, Tuple
+
+from superset.db_engine_specs.base import BaseEngineSpec
+
+
+class ExasolEngineSpec(BaseEngineSpec):
+ """Engine spec for Exasol"""
+
+ engine = "exa"
+ max_column_name_length = 128
+
+ # Exasol's DATE_TRUNC function is PostgresSQL compatible
+ _time_grain_functions = {
+ None: "{col}",
+ "PT1S": "DATE_TRUNC('second', {col})",
+ "PT1M": "DATE_TRUNC('minute', {col})",
+ "PT1H": "DATE_TRUNC('hour', {col})",
+ "P1D": "DATE_TRUNC('day', {col})",
+ "P1W": "DATE_TRUNC('week', {col})",
+ "P1M": "DATE_TRUNC('month', {col})",
+ "P0.25Y": "DATE_TRUNC('quarter', {col})",
+ "P1Y": "DATE_TRUNC('year', {col})",
+ }
+
+ @classmethod
+ def fetch_data(cls, cursor, limit: int) -> List[Tuple]:
+ data = super().fetch_data(cursor, limit)
+ # Lists of `pyodbc.Row` need to be unpacked further
+ if data and type(data[0]).__name__ == "Row":
+ data = [[value for value in row] for row in data]
+ return data