Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consolidate docs in README file #110

Merged
merged 1 commit into from
Oct 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
220 changes: 203 additions & 17 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,17 @@ SQLAlchemy dialect for SAP HANA
:target: https://api.reuse.software/info/github.com/SAP/sqlalchemy-hana

This dialect allows you to use the SAP HANA database with SQLAlchemy.
It can use the supported SAP HANA Python Driver `hdbcli` (supported since SAP HANA SPS 2) or the
open-source pure Python client `PyHDB`. Please notice that sqlalchemy-hana isn't an official SAP
product and isn't covered by SAP support.
It uses ``hdbcli`` to connect to SAP HANA.
Please notice that sqlalchemy-hana isn't an official SAP product and isn't covered by SAP support.

Prerequisites
-------------

Python 2.7 or Python 3.X with installed SAP HANA DBAPI implementation.

SAP HANA Python Driver see `SAP HANA Client Interface Programming Reference <https://help.sap.com/viewer/0eec0d68141541d1b07893a39944924e/2.0.02/en-US/39eca89d94ca464ca52385ad50fc7dea.html>`_ or the install section of `PyHDB <https://github.com/SAP/PyHDB>`_.
* Python 3.8+
* SQLAlchemy 1.4 or 2.x
* `hdbcli <https://help.sap.com/viewer/f1b440ded6144a54ada97ff95dac7adf/latest/en-US/f3b8fabf34324302b123297cdbe710f0.html>`_

Install
-------

Install from Python Package Index:

.. code-block:: bash
Expand All @@ -36,8 +33,8 @@ You can also install the latest version direct from a cloned git repository.

Getting started
---------------

If you do not have access to a SAP HANA server, you can also use the `SAP HANA Express edition <https://www.sap.com/cmp/td/sap-hana-express-edition.html>`_.
If you do not have access to a SAP HANA server, you can also use the
`SAP HANA Express edition <https://www.sap.com/cmp/td/sap-hana-express-edition.html>`_.

After installation of sqlalchemy-hana, you can create a engine which connects to a SAP HANA
instance. This engine works like all other engines of SQLAlchemy.
Expand All @@ -47,7 +44,8 @@ instance. This engine works like all other engines of SQLAlchemy.
from sqlalchemy import create_engine
engine = create_engine('hana://username:[email protected]:30015')

Alternatively, you can use HDB User Store to avoid entering connection-related information manually each time you want to establish a connection to an SAP HANA database:
Alternatively, you can use HDB User Store to avoid entering connection-related information manually
each time you want to establish a connection to an SAP HANA database:

.. code-block:: python

Expand All @@ -67,12 +65,200 @@ In case of a tenant database, you may use:
from sqlalchemy import create_engine
engine = engine = create_engine('hana://user:pass@host/tenant_db_name')

Contribute
----------
Usage
-----

If you found bugs or have other issues, you are welcome to create a GitHub Issue. If you have questions about usage or something similar please create a `Stack Overflow <http://stackoverflow.com/>`_ Question with tag `sqlalchemy <http://stackoverflow.com/questions/tagged/sqlalchemy>`_ and `hana <http://stackoverflow.com/questions/tagged/hana>`_.
Special CREATE TABLE argument
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sqlalchemy-hana provides a special argument called “hana_table_type” which can be used to
specify the type of table one wants to create with SAP HANA (i.e. ROW/COLUMN).
The default table type depends on your SAP HANA configuration and version.

License
-------
.. code-block:: python

t = Table('my_table', metadata, Column('id', Integer), hana_table_type = 'COLUMN')
t.create(engine)

Case Sensitivity
~~~~~~~~~~~~~~~~
In SAP HANA, all case insensitive identifiers are represented using uppercase text.
In SQLAlchemy on the other hand all lower case identifier names are considered to be case insensitive.
The sqlalchemy-hana dialect converts all case insensitive and case sensitive identifiers to the
right casing during schema level communication.
In the sqlalchemy-hana dialect, using an uppercase name on the SQLAlchemy side indicates a case
sensitive identifier, and SQLAlchemy will quote the name,which may cause case mismatches between
data received from SAP HANA.
Unless identifier names have been truly created as case sensitive (i.e. using quoted names),
all lowercase names should be used on the SQLAlchemy side.

Auto Increment Behavior
~~~~~~~~~~~~~~~~~~~~~~~
SQLAlchemy Table objects which include integer primary keys are usually assumed to have
“auto incrementing” behavior, which means that primary key values can be automatically generated
upon INSERT.
Since SAP HANA has no auto-increment feature, SQLAlchemy relies upon sequences to automatically
generate primary key values.

Sequences
"""""""""
With the sqlalchemy-hana dialect, a sequence must be explicitly specified to enable
auto-incrementing behavior.
This is different than the majority of SQLAlchemy documentation examples which assume the usage of
an auto-increment-capable database.
To create sequences, use the sqlalchemy.schema.Sequence object which is passed to a ``Column`` construct.

.. code-block:: python

t = Table('my_table', metadata, Column('id', Integer, Sequence('id_seq'), primary key=True))
t.create(engine)

IDENTITY Feature
""""""""""""""""
SAP HANA also comes with an option to have an ``IDENTITY`` column which can also be used to create
new primary key values for integer-based primary key columns.
Built-in support for rendering of ``IDENTITY`` is not available yet, however the following compilation
hook may be used to make use of
the IDENTITY feature.

.. code-block:: python

from sqlalchemy.schema import CreateColumn
from sqlalchemy.ext.compiler import compiles

@compiles(CreateColumn, 'hana')
def use_identity(element, compiler, **kw):
text = compiler.visit_create_column(element, **kw)
text = text.replace('NOT NULL', 'NOT NULL GENERATED BY DEFAULT AS IDENTITY')
return text

t = Table('t', meta, Column('id', Integer, primary_key=True), Column('data', String))

t.create(engine)

LIMIT/OFFSET Support
~~~~~~~~~~~~~~~~~~~~
SAP HANA supports both ``LIMIT`` and ``OFFSET``, but it only supports ``OFFSET`` in conjunction with ``LIMIT``
i.e. in the select statement the offset parameter cannot be set without the ``LIMIT`` clause,
hence in sqlalchemy-hana if the user tries to use offset without limit, a limit of 2147384648 would
be set, this has been done so that the users can smoothly use ``LIMIT`` or ``OFFSET`` as in other
databases that do not have this limitation.
2147384648 was chosen, because it is the maximum number of records per result set.

RETURNING Support
~~~~~~~~~~~~~~~~~
Sqlalchemy-hana does not support ``RETURNING`` in the ``INSERT``, ``UPDATE`` and ``DELETE``
statements to retrieve result sets of matched rows from ``INSERT``, ``UPDATE`` and ``DELETE``
statements because newly generated primary key values are neither fetched nor returned automatically
in SAP HANA and SAP HANA does not support the syntax ``INSERT... RETURNING...``.

Constraint Reflection
~~~~~~~~~~~~~~~~~~~~
The sqlalchemy-hana dialect can return information about foreign keys, unique constraints and
check constraints, as well as table indexes.

Raw information regarding these constraints can be acquired using:

* Inspector.get_foreign_keys()
* Inspector.get_unique_constraints()
* Inspector.get_check_constraints()
* Inspector.get_indexes()

Copyright (c) 2015-2021 SAP SE or an SAP affiliate company and sqlalchemy-hana contributors. Please see our `LICENSE file <https://github.com/SAP/sqlalchemy-hana/blob/master/LICENSE>`__ for copyright and license information. Detailed information including third-party components and their licensing/copyright information is available `via the REUSE tool <https://api.reuse.software/info/github.com/SAP/sqlalchemy-hana>`__.
When using refection at the table level, the table will also include these constraints.

Foreign key Options
"""""""""""""""""""
In SAP HANA the following ``UPDATE`` and ``DELETE`` foreign key referential actions are available:

* RESTRICT
* CASCADE
* SET NULL
* SET DEFAULT

The foreign key referential option ``NO ACTION`` does not exist in SAP HANA.
The default is ``RESTRICT``.

CHECK Constraints
"""""""""""""""""
Table level check constraints can be created as well as reflected in the sqlalchemy-hana dialect.
Column level check constraints are not available in SAP HANA.

.. code-block:: python

t = Table('my_table', metadata, Column('id', Integer), Column(...), ..., CheckConstraint('id >5', name='my_check_const'))

UNIQUE Constraints
""""""""""""""""""
For each unique constraint an index is created in SAP HANA, this may lead to unexpected behavior
in programs using reflection.

Special Reflection Option
~~~~~~~~~~~~~~~~~~~~~~~~
The Inspector used for the SAP HANA database is an instance of ``HANAInspector`` and offers an
additional method.

get_table_oid(table name, schema=None)
""""""""""""""""""""""""""""""""""""""
Return the OID (object id) for the given table name.

.. code-block:: python

from sqlalchemy import create_engine, inspect

engine = create_engine("hana://username:[email protected]:30015")
insp = inspect(engine)
# will be a HANAInspector
print(insp.get_table_oid('my_table'))

Data types
~~~~~~~~~~

As with all SQLAlchemy dialects, all UPPERCASE types that are known to be valid with SAP HANA are
importable from the top level dialect, whether they originate from sqlalchemy types or from the
local dialect.
The allowed data types for sqlalchemy-hana are as follows:

* BOOLEAN
* NUMERIC
* NVARCHAR
* CLOB
* BLOB
* DATE
* TIME
* TIMESTAMP
* CHAR
* VARCHAR
* VARBINARY
* BIGINT
* SMALLINT
* INTEGER
* FLOAT
* TEXT

DateTime Compatibility
""""""""""""""""""""""
SAP HANA has no data type known as ``DATETIME``, it instead has the datatype ``TIMESTAMP``, which can
actually store the date and time value.
For this reason, the sqlalchemy-hana dialect provides a ``TIMESTAMP`` type which is a ```datetime``.

NUMERIC Compatibility
"""""""""""""""""""""
SAP HANA does not have a data type known as ``NUMERIC``, hence if a user has a column with data type
numeric while using sqlalchemy-hana, it is stored as ``DECIMAL`` data type instead.

TEXT datatype
"""""""""""""
SAP HANA only supports the datatype ``TEXT`` for column tables.
It is not a valid data type for row tables. Hence, one must mention ``hana_table_type="COLUMN"``

Bound Parameter Styles
~~~~~~~~~~~~~~~~~~~~~~
The default parameter style for the sqlalchemy-hana dialect is ``qmark``, where SQL is rendered
using the following style:

.. code-block:: sql

WHERE my_column = ?

Contribute
----------
If you found bugs or have other issues, you are welcome to create a GitHub Issue
20 changes: 0 additions & 20 deletions docs/Makefile

This file was deleted.

Loading