Skip to content

Commit

Permalink
Make odbc based dialects optional (#437)
Browse files Browse the repository at this point in the history
---------
Co-authored-by: Torsten Kilias <tkilias@users.noreply.github.com>
  • Loading branch information
Nicoretti authored Jan 26, 2024
1 parent 8a983b4 commit 2902482
Show file tree
Hide file tree
Showing 9 changed files with 89 additions and 130 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci-cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ jobs:
with:
python-version: ${{ matrix.python }}

- name: Install python project dependencies including trubodbc
run: poetry install --extras "turbodbc"
- name: Install python project dependencies including turbodbc
run: poetry install --all-extras
if: ${{ matrix.connector == 'turbodbc' }}

- name: Run Test for Python ${{ matrix.python }} using ${{ matrix.connector }}
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ jobs:
with:
python-version: ${{ matrix.python }}

- name: Install python project dependencies including trubodbc
run: poetry install --extras "turbodbc"
- name: Install python project dependencies including turbodbc
run: poetry install --all-extras
if: ${{ matrix.connector == 'turbodbc' }}

- name: Run Test for Python ${{ matrix.python }} using ${{ matrix.connector }}
Expand Down
5 changes: 5 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
Unreleased
==========

🔧 Changed
-----------
- Made websockets the default way to use sqlalchemy with exasol
- Made pydobc an optional dependency

🧰 Internal
-----------
- Relocked dependencies
Expand Down
162 changes: 59 additions & 103 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -43,60 +43,55 @@ SQLAlchemy Dialect for EXASOL DB
:alt: PyPI - Downloads


How to get started
------------------

Currently, sqlalchemy-exasol supports multiple dialects. The core difference
being if the dialect is :code:`odbc` or :code:`websocket` based.

Generally, we advise to use the websocket based Dialect, because odbc
based dialects require a good understanding of (unix)ODBC and the setup is
significant more complicated.
Getting Started with SQLAlchemy-Exasol
--------------------------------------
SQLAlchemy-Exasol supports multiple dialects, primarily differentiated by whether they are ODBC or Websocket based.

Choosing a Dialect
++++++++++++++++++

Turbodbc support
````````````````
We recommend using the Websocket-based dialect due to its simplicity. ODBC-based dialects demand a thorough understanding of (Unix)ODBC, and the setup is considerably more complex.

.. warning::

Maintenance of this feature is on hold. Also it is very likely that turbodbc support will be dropped in future versions.
The maintenance of Turbodbc support is currently paused, and it may be phased out in future versions.
We are also planning to phase out the pyodbc support in the future.

- You can use Turbodbc with sqlalchemy_exasol if you use a python version >= 3.8.
- Multi row update is not supported, see
`test/test_update.py <test/test_update.py>`_ for an example


Meet the system requirements
````````````````````````````
System Requirements
-------------------
- Python
- An Exasol DB (e.g. `docker-db <test_docker_image_>`_ or a `cloud instance <test_drive_>`_)

ODBC-based dialects additionally require the following to be available and set up:
.. note::

- The packages unixODBC and unixODBC-dev >= 2.2.14
- The Exasol `ODBC driver <odbc_driver_>`_
- The ODBC.ini and ODBCINST.ini configurations files setup
For ODBC-Based Dialects, additional libraries required for ODBC are necessary
(for further details, checkout the `developer guide`_).

Setting Up Your Python Project
------------------------------

Setup your python project and install sqlalchemy-exasol
```````````````````````````````````````````````````````
Install SQLAlchemy-Exasol:

.. code-block:: shell
$ pip install sqlalchemy-exasol
for turbodbc support:
.. note::

.. code-block:: shell
To use an ODBC-based dialect, you must specify it as an extra during installation.

$ pip install sqlalchemy-exasol[turbodbc]
.. code-block:: shell
Talk to the EXASOL DB using SQLAlchemy
``````````````````````````````````````
pip install "sqlalchemy-exasol[pydobc]"
pip install "sqlalchemy-exasol[turbodbc]"
**Websocket based Dialect:**
For more details regarding the websocket support checkout the section: "What is Websocket support?"
Using SQLAlchemy with EXASOL DB
-------------------------------

**Websocket based Dialect:**

.. code-block:: python
Expand All @@ -105,6 +100,31 @@ For more details regarding the websocket support checkout the section: "What is
e = create_engine(url)
r = e.execute("select 42 from dual").fetchall()
Examples:

.. code-block:: python
from sqlalchemy import create_engine
engine = create_engine("exa+websocket://sys:exasol@127.0.0.1:8888")
with engine.connect() as con:
...
.. code-block:: python
from sqlalchemy import create_engine
# ATTENTION:
# In terms of security it is NEVER a good idea to turn of certificate validation!!
# In rare cases it may be handy for non-security related reasons.
# That said, if you are not a 100% sure about your scenario, stick with the
# secure defaults.
# In most cases, having a valid certificate and/or configuring the truststore(s)
# appropriately is the best/correct solution.
engine = create_engine("exa+websocket://sys:exasol@127.0.0.1:8888?SSLCertificate=SSL_VERIFY_NONE")
with engine.connect() as con:
...
**Pyodbc (ODBC based Dialect):**

Expand All @@ -125,24 +145,13 @@ For more details regarding the websocket support checkout the section: "What is
r = e.execute("select 42 from dual").fetchall()
The dialect supports two types of connection urls creating an engine. A DSN (Data Source Name) mode and a host mode:

.. list-table::

* - Type
- Example
* - DSN URL
- 'exa+pyodbc://USER:PWD@exa_test'
* - HOST URL
- 'exa+pyodbc://USER:PWD@192.168.14.227..228:1234/my_schema?parameter'

Features
++++++++
--------

- SELECT, INSERT, UPDATE, DELETE statements

Notes
+++++
General Notes
-------------

- Schema name and parameters are optional for the host url
- At least on Linux/Unix systems it has proven valuable to pass 'CONNECTIONLCALL=en_US.UTF-8' as a url parameter. This will make sure that the client process (Python) and the EXASOL driver (UTF-8 internal) know how to interpret code pages correctly.
Expand All @@ -154,66 +163,13 @@ Notes
.. _test_drive: https://www.exasol.com/test-it-now/cloud/
.. _test_docker_image: https://github.com/exasol/docker-db

Known Issues
------------
* Insert
- Insert multiple empty rows via prepared statements does not work in all cases

Development & Testing
`````````````````````
---------------------
See `developer guide`_

What is Websocket support?
``````````````````````````
In the context of SQLA and Exasol, Websocket support means that an SQLA dialect
supporting the `Exasol Websocket Protocol <https://github.com/exasol/websocket-api>`_
is provided.

Using the websocket based protocol instead over ODBC will provide various advantages:

* Less System Dependencies
* Easier to use than ODBC based driver(s)
* Lock free metadata calls etc.

For further details `Why a Websockets API <https://github.com/exasol/websocket-api#why-a-websockets-api>`_.

Example Usage(s)
++++++++++++++++++

.. code-block:: python
from sqla import create_engine
engine = create_engine("exa+websocket://sys:exasol@127.0.0.1:8888")
with engine.connect() as con:
...
.. code-block:: python
from sqla import create_engine

# ATTENTION:
# In terms of security it is NEVER a good idea to turn of certificate validation!!
# In rare cases it may be handy for non-security related reasons.
# That said, if you are not a 100% sure about your scenario, stick with the
# secure defaults.
# In most cases, having a valid certificate and/or configuring the truststore(s)
# appropriately is the best/correct solution.
engine = create_engine("exa+websocket://sys:exasol@127.0.0.1:8888?SSLCertificate=SSL_VERIFY_NONE")
with engine.connect() as con:
...
Supported Connection Parameters
+++++++++++++++++++++++++++++++
.. list-table::

* - Parameter
- Values
- Comment
* - ENCRYPTION
- Y, Yes, N, No
- Y or Yes Enable Encryption (TLS) default, N or No disable Encryption
* - SSLCertificate
- SSL_VERIFY_NONE
- Disable certificate validation


Known Issues
++++++++++++
* Insert
- Insert multiple empty rows via prepared statements does not work in all cases
5 changes: 1 addition & 4 deletions doc/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,12 @@
# The full version, including alpha/beta/rc tags
release = VERSION


# -- General configuration ---------------------------------------------------

# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = ["sphinx_copybutton"]
extensions = ["sphinx_copybutton", "sphinx.ext.intersphinx"]

# Add any paths that contain templates here, relative to this directory.
templates_path = ["_templates"]
Expand All @@ -44,7 +43,6 @@
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]


# -- Options for HTML output -------------------------------------------------

# The theme to use for HTML and HTML Help pages. See the documentation for
Expand All @@ -57,7 +55,6 @@
"dark_logo": "dark-exasol-logo.svg",
}


# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
Expand Down
1 change: 1 addition & 0 deletions doc/developer_guide/developer_guide.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Tools
* integration-test-docker-environment_
* Prerequisites_


Libraries
+++++++++
* unixodbc
Expand Down
20 changes: 7 additions & 13 deletions doc/index.rst
Original file line number Diff line number Diff line change
@@ -1,26 +1,20 @@
SQLAlchemy-Exasol
=================
SQLAlchemy-Exasol is an SQLAlchemy dialect extension.

Overview
--------
The dialect is the system SQLAlchemy uses to communicate with various types of DBAPI implementations and databases.
The sections that follow contain reference documentation and notes specific to the usage of each backend,
as well as notes for the various DBAPIs.

For more details have a look into the `SQLAlchemy documentation <https://docs.sqlalchemy.org/en/13/dialects/>`_.
SQLAlchemy-Exasol is a dialect extension for SQLAlchemy, implementing support for Exasol databases.

Getting Started
---------------

#. `Install the Exasol-ODBC driver <https://docs.exasol.com/db/latest/connect_exasol/drivers/odbc.htm>`_

#. Add `sqlalchemy-exasol <https://pypi.org/project/sqlalchemy-exasol/>`_ as a dependency
#. Install the `SQLAlchemy-Exasol extension <https://pypi.org/project/sqlalchemy-exasol/>`_

.. code-block:: shell
$ pip install sqlalchemy-exasol
.. note::

SQLAlchemy will be installed due to the fact that it is an required dependency for SQLAlchemy-Exasol.

#. Execute queries

.. code-block:: python
Expand All @@ -38,5 +32,5 @@ For more details on SQLAlchemy consult it's `documenation <https://docs.sqlalche
:hidden:

readme
changelog
developer_guide/index
changelog
11 changes: 6 additions & 5 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 6 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ exclude = []

[tool.poetry.dependencies]
python = ">=3.8,<4.0"
pyodbc = ">=4.0.34,<6"
packaging = ">=21.3"
pyexasol = "^0.25.1"
sqlalchemy = ">=1.4,<2"
Expand All @@ -70,6 +69,10 @@ sqlalchemy = ">=1.4,<2"
version = "==4.5.4"
optional = true

[tool.poetry.dependencies.pyodbc]
version = ">=4.0.34,<6"
optional = true

[tool.poetry.group.dev.dependencies]
nox = ">=2022.1.7"
urlscan = ">=0.9.9"
Expand All @@ -90,8 +93,10 @@ pyupgrade = ">=3.0.0"
rich = "^13.3.1"
exasol-integration-test-docker-environment = "^1.5.0"
pytest-history = ">=0.2.0"
pyodbc = ">=4.0.34,<6"

[tool.poetry.extras]
pyodbc = ["pyodbc"]
turbodbc = ["turbodbc"]

[tool.poetry.plugins."sqlalchemy.dialects"]
Expand Down

0 comments on commit 2902482

Please sign in to comment.