From 783667168bcdf8ca0a8d08e0a579a1b252b9c509 Mon Sep 17 00:00:00 2001 From: kevang Date: Sun, 6 Oct 2019 12:43:45 +0100 Subject: [PATCH] Add support for Exasol (#8343) * Add support for Exasol * add time grain functions for Exasol * remove duplicate of * override ExasolEngineSpec's fetch_data method * remove duplicate https * simplify super call --- docs/index.rst | 1 + docs/installation.rst | 21 +++++++++++++ superset/db_engine_specs/exasol.py | 48 ++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+) create mode 100644 superset/db_engine_specs/exasol.py diff --git a/docs/index.rst b/docs/index.rst index 00b796d011..465423a6ef 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 fc8fc2b9bd..cc6792a0d5 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 0000000000..c6b38cba5d --- /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