:ref:`SQL Server Transaction Isolation <mssql_isolation_level>`
- :ref:`Oracle Transaction Isolation <oracle_isolation_level>`
+ :ref:`Oracle Database Transaction Isolation <oracle_isolation_level>`
:ref:`session_transaction_isolation` - for the ORM
Using Server Side Cursors (a.k.a. stream results)
-------------------------------------------------
-Some backends feature explicit support for the concept of "server
-side cursors" versus "client side cursors". A client side cursor here
-means that the database driver fully fetches all rows from a result set
-into memory before returning from a statement execution. Drivers such as
-those of PostgreSQL and MySQL/MariaDB generally use client side cursors
-by default. A server side cursor, by contrast, indicates that result rows
-remain pending within the database server's state as result rows are consumed
-by the client. The drivers for Oracle generally use a "server side" model,
-for example, and the SQLite dialect, while not using a real "client / server"
-architecture, still uses an unbuffered result fetching approach that will
-leave result rows outside of process memory before they are consumed.
+Some backends feature explicit support for the concept of "server side cursors"
+versus "client side cursors". A client side cursor here means that the
+database driver fully fetches all rows from a result set into memory before
+returning from a statement execution. Drivers such as those of PostgreSQL and
+MySQL/MariaDB generally use client side cursors by default. A server side
+cursor, by contrast, indicates that result rows remain pending within the
+database server's state as result rows are consumed by the client. The drivers
+for Oracle Database generally use a "server side" model, for example, and the
+SQLite dialect, while not using a real "client / server" architecture, still
+uses an unbuffered result fetching approach that will leave result rows outside
+of process memory before they are consumed.
.. topic:: What we really mean is "buffered" vs. "unbuffered" results
~~~~~~~~~~~~~~~
The feature is enabled for all backend included in SQLAlchemy that support
-RETURNING, with the exception of Oracle for which both the cx_Oracle and
-OracleDB drivers offer their own equivalent feature. The feature normally takes
-place when making use of the :meth:`_dml.Insert.returning` method of an
-:class:`_dml.Insert` construct in conjunction with :term:`executemany`
-execution, which occurs when passing a list of dictionaries to the
-:paramref:`_engine.Connection.execute.parameters` parameter of the
-:meth:`_engine.Connection.execute` or :meth:`_orm.Session.execute` methods (as
-well as equivalent methods under :ref:`asyncio <asyncio_toplevel>` and
-shorthand methods like :meth:`_orm.Session.scalars`). It also takes place
-within the ORM :term:`unit of work` process when using methods such as
-:meth:`_orm.Session.add` and :meth:`_orm.Session.add_all` to add rows.
+RETURNING, with the exception of Oracle Database for which both the
+python-oracledb and cx_Oracle drivers offer their own equivalent feature. The
+feature normally takes place when making use of the
+:meth:`_dml.Insert.returning` method of an :class:`_dml.Insert` construct in
+conjunction with :term:`executemany` execution, which occurs when passing a
+list of dictionaries to the :paramref:`_engine.Connection.execute.parameters`
+parameter of the :meth:`_engine.Connection.execute` or
+:meth:`_orm.Session.execute` methods (as well as equivalent methods under
+:ref:`asyncio <asyncio_toplevel>` and shorthand methods like
+:meth:`_orm.Session.scalars`). It also takes place within the ORM :term:`unit
+of work` process when using methods such as :meth:`_orm.Session.add` and
+:meth:`_orm.Session.add_all` to add rows.
For SQLAlchemy's included dialects, support or equivalent support is currently
as follows:
* SQL Server - all supported SQL Server versions [#]_
* MariaDB - supported for MariaDB versions 10.5 and above
* MySQL - no support, no RETURNING feature is present
-* Oracle - supports RETURNING with executemany using native cx_Oracle / OracleDB
- APIs, for all supported Oracle versions 9 and above, using multi-row OUT
+* Oracle Database - supports RETURNING with executemany using native python-oracledb / cx_Oracle
+ APIs, for all supported Oracle Database versions 9 and above, using multi-row OUT
parameters. This is not the same implementation as "executemanyvalues", however has
the same usage patterns and equivalent performance benefits.
:class:`~sqlalchemy.schema.Sequence` object, which is considered to be a
special case of "column default". It only has an effect on databases which have
explicit support for sequences, which among SQLAlchemy's included dialects
-includes PostgreSQL, Oracle, MS SQL Server, and MariaDB. The
+includes PostgreSQL, Oracle Database, MS SQL Server, and MariaDB. The
:class:`~sqlalchemy.schema.Sequence` object is otherwise ignored.
.. tip::
In the above example, ``CREATE TABLE`` for PostgreSQL will make use of the
``SERIAL`` datatype for the ``cart_id`` column, and the ``cart_id_seq``
-sequence will be ignored. However on Oracle, the ``cart_id_seq`` sequence
-will be created explicitly.
+sequence will be ignored. However on Oracle Database, the ``cart_id_seq``
+sequence will be created explicitly.
.. tip::
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. note:: The following technique is known to work only with the PostgreSQL
- database. It does not work with Oracle.
+ database. It does not work with Oracle Database.
The preceding sections illustrate how to associate a :class:`.Sequence` with a
:class:`_schema.Column` as the **Python side default generator**::
:ref:`postgresql_sequences` - in the PostgreSQL dialect documentation
- :ref:`oracle_returning` - in the Oracle dialect documentation
+ :ref:`oracle_returning` - in the Oracle Database dialect documentation
.. _computed_ddl:
* PostgreSQL as of version 12
-* Oracle - with the caveat that RETURNING does not work correctly with UPDATE
- (a warning will be emitted to this effect when the UPDATE..RETURNING that
- includes a computed column is rendered)
+* Oracle Database - with the caveat that RETURNING does not work correctly with
+ UPDATE (a warning will be emitted to this effect when the UPDATE..RETURNING
+ that includes a computed column is rendered)
* Microsoft SQL Server
* PostgreSQL as of version 10.
-* Oracle as of version 12. It also supports passing ``always=None`` to
+* Oracle Database as of version 12. It also supports passing ``always=None`` to
enable the default generated mode and the parameter ``on_null=True`` to
specify "ON NULL" in conjunction with a "BY DEFAULT" identity column.
Oracle
^^^^^^^^^^
-The Oracle dialect uses cx_oracle as the default DBAPI::
+The preferred Oracle Database dialect uses the python-oracledb driver as the
+DBAPI::
- engine = create_engine("oracle://scott:tiger@127.0.0.1:1521/sidname")
+ engine = create_engine(
+ "oracle+oracledb://scott:tiger@127.0.0.1:1521/?service_name=freepdb1"
+ )
- engine = create_engine("oracle+cx_oracle://scott:tiger@tnsname")
+ engine = create_engine("oracle+oracledb://scott:tiger@tnsalias")
-More notes on connecting to Oracle at :ref:`oracle_toplevel`.
+For historical reasons, the Oracle dialect uses the obsolete cx_Oracle driver
+as the default DBAPI::
+
+ engine = create_engine("oracle://scott:tiger@127.0.0.1:1521/?service_name=freepdb1")
+
+ engine = create_engine("oracle+cx_oracle://scott:tiger@tnsalias")
+
+More notes on connecting to Oracle Database at :ref:`oracle_toplevel`.
Microsoft SQL Server
^^^^^^^^^^^^^^^^^^^^
... conn.execute(text("select :some_private_name"), {"some_private_name": "pii"})
2020-10-24 12:48:32,808 INFO sqlalchemy.engine.Engine select ?
2020-10-24 12:48:32,808 INFO sqlalchemy.engine.Engine [SQL parameters hidden due to hide_parameters=True]
-
geometry of a "schema" takes many forms, including names of "schemas" under the
scope of a particular database (e.g. PostgreSQL schemas), named sibling
databases (e.g. MySQL / MariaDB access to other databases on the same server),
-as well as other concepts like tables owned by other usernames (Oracle, SQL
-Server) or even names that refer to alternate database files (SQLite ATTACH) or
-remote servers (Oracle DBLINK with synonyms).
+as well as other concepts like tables owned by other usernames (Oracle
+Database, SQL Server) or even names that refer to alternate database files
+(SQLite ATTACH) or remote servers (Oracle Database DBLINK with synonyms).
What all of the above approaches have (mostly) in common is that there's a way
of referencing this alternate set of tables using a string name. SQLAlchemy
"database" that typically has a single "owner". Within this database there
can be any number of "schemas" which then contain the actual table objects.
- A table within a specific schema is referenced explicitly using the
- syntax "<schemaname>.<tablename>". Contrast this to an architecture such
- as that of MySQL, where there are only "databases", however SQL statements
- can refer to multiple databases at once, using the same syntax except it
- is "<database>.<tablename>". On Oracle, this syntax refers to yet another
- concept, the "owner" of a table. Regardless of which kind of database is
- in use, SQLAlchemy uses the phrase "schema" to refer to the qualifying
- identifier within the general syntax of "<qualifier>.<tablename>".
+ A table within a specific schema is referenced explicitly using the syntax
+ "<schemaname>.<tablename>". Contrast this to an architecture such as that
+ of MySQL, where there are only "databases", however SQL statements can
+ refer to multiple databases at once, using the same syntax except it is
+ "<database>.<tablename>". On Oracle Database, this syntax refers to yet
+ another concept, the "owner" of a table. Regardless of which kind of
+ database is in use, SQLAlchemy uses the phrase "schema" to refer to the
+ qualifying identifier within the general syntax of
+ "<qualifier>.<tablename>".
.. seealso::
to a PostgreSQL database, the default "schema" is called "public".
There are often cases where the default "schema" cannot be set via the login
-itself and instead would usefully be configured each time a connection
-is made, using a statement such as "SET SEARCH_PATH" on PostgreSQL or
-"ALTER SESSION" on Oracle. These approaches may be achieved by using
-the :meth:`_pool.PoolEvents.connect` event, which allows access to the
-DBAPI connection when it is first created. For example, to set the
-Oracle CURRENT_SCHEMA variable to an alternate name::
+itself and instead would usefully be configured each time a connection is made,
+using a statement such as "SET SEARCH_PATH" on PostgreSQL or "ALTER SESSION" on
+Oracle Database. These approaches may be achieved by using the
+:meth:`_pool.PoolEvents.connect` event, which allows access to the DBAPI
+connection when it is first created. For example, to set the Oracle Database
+CURRENT_SCHEMA variable to an alternate name::
from sqlalchemy import event
from sqlalchemy import create_engine
- engine = create_engine("oracle+cx_oracle://scott:tiger@tsn_name")
+ engine = create_engine(
+ "oracle+oracledb://scott:tiger@localhost:1521?service_name=freepdb1"
+ )
@event.listens_for(engine, "connect", insert=True)
as if this disconnect should cause the entire connection pool to be invalidated
or not.
-For example, to add support to consider the Oracle error codes
-``DPY-1001`` and ``DPY-4011`` to be handled as disconnect codes, apply an
-event handler to the engine after creation::
+For example, to add support to consider the Oracle Database driver error codes
+``DPY-1001`` and ``DPY-4011`` to be handled as disconnect codes, apply an event
+handler to the engine after creation::
import re
from sqlalchemy import create_engine
- engine = create_engine("oracle://scott:tiger@dnsname")
+ engine = create_engine(
+ "oracle+oracledb://scott:tiger@localhost:1521?service_name=freepdb1"
+ )
@event.listens_for(engine, "handle_error")
def handle_exception(context: ExceptionContext) -> None:
if not context.is_disconnect and re.match(
- r"^(?:DPI-1001|DPI-4011)", str(context.original_exception)
+ r"^(?:DPY-1001|DPY-4011)", str(context.original_exception)
):
context.is_disconnect = True
return None
-The above error processing function will be invoked for all Oracle errors
-raised, including those caught when using the
-:ref:`pool pre ping <pool_disconnects_pessimistic>` feature for those backends
-that rely upon disconnect error handling (new in 2.0).
+The above error processing function will be invoked for all Oracle Database
+errors raised, including those caught when using the :ref:`pool pre ping
+<pool_disconnects_pessimistic>` feature for those backends that rely upon
+disconnect error handling (new in 2.0).
.. seealso::
.. autoclass:: _ConnectionFairy
.. autoclass:: _ConnectionRecord
-
or BIT values 0 and 1, some have boolean literal constants ``true`` and
``false`` while others dont. For this datatype, :class:`_types.Boolean`
may render ``BOOLEAN`` on a backend such as PostgreSQL, ``BIT`` on the
-MySQL backend and ``SMALLINT`` on Oracle. As data is sent and received
-from the database using this type, based on the dialect in use it may be
-interpreting Python numeric or boolean values.
+MySQL backend and ``SMALLINT`` on Oracle Database. As data is sent and
+received from the database using this type, based on the dialect in use it
+may be interpreting Python numeric or boolean values.
The typical SQLAlchemy application will likely wish to use primarily
"CamelCase" types in the general case, as they will generally provide the best
.. autoclass:: VARCHAR
-
-
.. automodule:: sqlalchemy.dialects.oracle.base
-Oracle Data Types
------------------
+Oracle Database Data Types
+--------------------------
-As with all SQLAlchemy dialects, all UPPERCASE types that are known to be
-valid with Oracle are importable from the top level dialect, whether
-they originate from :mod:`sqlalchemy.types` or from the local dialect::
+As with all SQLAlchemy dialects, all UPPERCASE types that are known to be valid
+with Oracle Database are importable from the top level dialect, whether they
+originate from :mod:`sqlalchemy.types` or from the local dialect::
from sqlalchemy.dialects.oracle import (
BFILE,
.. versionadded:: 1.2.19 Added :class:`_types.NCHAR` to the list of datatypes
exported by the Oracle dialect.
-Types which are specific to Oracle, or have Oracle-specific
+Types which are specific to Oracle Database, or have Oracle-specific
construction arguments, are as follows:
.. currentmodule:: sqlalchemy.dialects.oracle
.. autoclass:: TIMESTAMP
:members: __init__
-.. _cx_oracle:
-
-cx_Oracle
----------
-
-.. automodule:: sqlalchemy.dialects.oracle.cx_oracle
-
.. _oracledb:
python-oracledb
.. automodule:: sqlalchemy.dialects.oracle.oracledb
+.. _cx_oracle:
+
+cx_Oracle
+---------
+
+.. automodule:: sqlalchemy.dialects.oracle.cx_oracle
A key limitation of the ``cursor.executemany()`` method as used with
all known DBAPIs is that the ``cursor`` is not configured to return
rows when this method is used. For **most** backends (a notable
- exception being the cx_Oracle, / OracleDB DBAPIs), this means that
+ exception being the python-oracledb / cx_Oracle DBAPIs), this means that
statements like ``INSERT..RETURNING`` typically cannot be used with
``cursor.executemany()`` directly, since DBAPIs typically do not
aggregate the single row from each INSERT execution together.
values as they are not included otherwise (but note any series of columns
or SQL expressions can be placed into RETURNING, not just default-value columns).
- The backends that currently support
- RETURNING or a similar construct are PostgreSQL, SQL Server, Oracle,
- and Firebird. The PostgreSQL and Firebird implementations are generally
- full featured, whereas the implementations of SQL Server and Oracle
- have caveats. On SQL Server, the clause is known as "OUTPUT INSERTED"
- for INSERT and UPDATE statements and "OUTPUT DELETED" for DELETE statements;
- the key caveat is that triggers are not supported in conjunction with this
- keyword. On Oracle, it is known as "RETURNING...INTO", and requires that the
- value be placed into an OUT parameter, meaning not only is the syntax awkward,
- but it can also only be used for one row at a time.
+ The backends that currently support RETURNING or a similar construct
+ are PostgreSQL, SQL Server, Oracle Database, and Firebird. The
+ PostgreSQL and Firebird implementations are generally full featured,
+ whereas the implementations of SQL Server and Oracle Database have
+ caveats. On SQL Server, the clause is known as "OUTPUT INSERTED" for
+ INSERT and UPDATE statements and "OUTPUT DELETED" for DELETE
+ statements; the key caveat is that triggers are not supported in
+ conjunction with this keyword. In Oracle Database, it is known as
+ "RETURNING...INTO", and requires that the value be placed into an OUT
+ parameter, meaning not only is the syntax awkward, but it can also only
+ be used for one row at a time.
SQLAlchemy's :meth:`.UpdateBase.returning` system provides a layer of abstraction
on top of the RETURNING systems of these backends to provide a consistent
.. seealso::
:ref:`session_object_states`
-
:doc:`PostgreSQL <dialects/postgresql>` |
:doc:`MySQL and MariaDB <dialects/mysql>` |
:doc:`SQLite <dialects/sqlite>` |
- :doc:`Oracle <dialects/oracle>` |
+ :doc:`Oracle Database <dialects/oracle>` |
:doc:`Microsoft SQL Server <dialects/mssql>`
:doc:`More Dialects ... <dialects/index>`
* :doc:`Error Message Guide <errors>` - Explanations of many SQLAlchemy Errors
* :doc:`Complete table of of contents <contents>`
* :ref:`Index <genindex>`
-
The feature also has conditional support to work in conjunction with
primary key columns. For backends that have RETURNING support
-(including Oracle, SQL Server, MariaDB 10.5, SQLite 3.35) a
+(including Oracle Database, SQL Server, MariaDB 10.5, SQLite 3.35) a
SQL expression may be assigned to a primary key column as well. This allows
both the SQL expression to be evaluated, as well as allows any server side
triggers that modify the primary key value on INSERT, to be successfully
database support RETURNING or an equivalent, such as "OUTPUT inserted"; these
are SQL phrases which return a server-generated value at the same time as the
INSERT or UPDATE statement is invoked. RETURNING is currently supported
-by PostgreSQL, Oracle, MariaDB 10.5, SQLite 3.35, and SQL Server.
+by PostgreSQL, Oracle Database, MariaDB 10.5, SQLite 3.35, and SQL Server.
Case 1: non primary key, RETURNING or equivalent is supported
-------------------------------------------------------------
include functions for fetching the "last inserted id" where RETURNING
is not supported, and where RETURNING is supported SQLAlchemy will use that.
-For example, using Oracle with a column marked as :class:`.Identity`,
+For example, using Oracle Database with a column marked as :class:`.Identity`,
RETURNING is used automatically to fetch the new primary key value::
class MyOracleModel(Base):
id: Mapped[int] = mapped_column(Identity(), primary_key=True)
data: Mapped[str] = mapped_column(String(50))
-The INSERT for a model as above on Oracle looks like:
+The INSERT for a model as above on Oracle Database looks like:
.. sourcecode:: sql
For non-integer values generated by server side functions or triggers, as well
as for integer values that come from constructs outside the table itself,
including explicit sequences and triggers, the server default generation must
-be marked in the table metadata. Using Oracle as the example again, we can
+be marked in the table metadata. Using Oracle Database as the example again, we can
illustrate a similar table as above naming an explicit sequence using the
:class:`.Sequence` construct::
id: Mapped[int] = mapped_column(Sequence("my_oracle_seq"), primary_key=True)
data: Mapped[str] = mapped_column(String(50))
-An INSERT for this version of the model on Oracle would look like:
+An INSERT for this version of the model on Oracle Database would look like:
.. sourcecode:: sql
Things to know about this kind of loading include:
* The strategy emits a SELECT for up to 500 parent primary key values at a
- time, as the primary keys are rendered into a large IN expression in the
- SQL statement. Some databases like Oracle have a hard limit on how large
- an IN expression can be, and overall the size of the SQL string shouldn't
- be arbitrarily large.
+ time, as the primary keys are rendered into a large IN expression in the SQL
+ statement. Some databases like Oracle Database have a hard limit on how
+ large an IN expression can be, and overall the size of the SQL string
+ shouldn't be arbitrarily large.
* As "selectin" loading relies upon IN, for a mapping with composite primary
keys, it must use the "tuple" form of IN, which looks like ``WHERE
1 'somewidget' 5 5 'someentry' 1
In the first case, a row points to itself. Technically, a database that uses
-sequences such as PostgreSQL or Oracle can INSERT the row at once using a
-previously generated value, but databases which rely upon autoincrement-style
-primary key identifiers cannot. The :func:`~sqlalchemy.orm.relationship`
-always assumes a "parent/child" model of row population during flush, so
-unless you are populating the primary key/foreign key columns directly,
-:func:`~sqlalchemy.orm.relationship` needs to use two statements.
+sequences such as PostgreSQL or Oracle Database can INSERT the row at once
+using a previously generated value, but databases which rely upon
+autoincrement-style primary key identifiers cannot. The
+:func:`~sqlalchemy.orm.relationship` always assumes a "parent/child" model of
+row population during flush, so unless you are populating the primary
+key/foreign key columns directly, :func:`~sqlalchemy.orm.relationship` needs to
+use two statements.
In the second case, the "widget" row must be inserted before any referring
"entry" rows, but then the "favorite_entry_id" column of that "widget" row
reference a primary key column whose value has changed.
The primary platforms without referential integrity features are
MySQL when the ``MyISAM`` storage engine is used, and SQLite when the
-``PRAGMA foreign_keys=ON`` pragma is not used. The Oracle database also
+``PRAGMA foreign_keys=ON`` pragma is not used. Oracle Database also
has no support for ``ON UPDATE CASCADE``, but because it still enforces
referential integrity, needs constraints to be marked as deferrable
so that SQLAlchemy can emit UPDATE statements.
map for objects that may be referencing the one with a
mutating primary key, not throughout the database.
-As virtually all databases other than Oracle now support ``ON UPDATE CASCADE``,
-it is highly recommended that traditional ``ON UPDATE CASCADE`` support be used
-in the case that natural and mutable primary key values are in use.
-
+As virtually all databases other than Oracle Database now support ``ON UPDATE
+CASCADE``, it is highly recommended that traditional ``ON UPDATE CASCADE``
+support be used in the case that natural and mutable primary key values are in
+use.
It is *strongly recommended* that server side version counters only be used
when absolutely necessary and only on backends that support :term:`RETURNING`,
-currently PostgreSQL, Oracle, MariaDB 10.5, SQLite 3.35, and SQL Server.
+currently PostgreSQL, Oracle Database, MariaDB 10.5, SQLite 3.35, and SQL
+Server.
Programmatic or Conditional Version Counters
as :class:`_functions.count`, :class:`_functions.now`, :class:`_functions.max`,
:class:`_functions.concat` include pre-packaged versions of themselves which
provide for proper typing information as well as backend-specific SQL
-generation in some cases. The example below contrasts the SQL generation
-that occurs for the PostgreSQL dialect compared to the Oracle dialect for
+generation in some cases. The example below contrasts the SQL generation that
+occurs for the PostgreSQL dialect compared to the Oracle Database dialect for
the :class:`_functions.now` function::
>>> from sqlalchemy.dialects import postgresql
Table-valued SQL functions support a scalar representation that contains named
sub-elements. Often used for JSON and ARRAY-oriented functions as well as
functions like ``generate_series()``, the table-valued function is specified in
-the FROM clause, and is then referenced as a table, or sometimes even as
-a column. Functions of this form are prominent within the PostgreSQL database,
+the FROM clause, and is then referenced as a table, or sometimes even as a
+column. Functions of this form are prominent within the PostgreSQL database,
however some forms of table valued functions are also supported by SQLite,
-Oracle, and SQL Server.
+Oracle Database, and SQL Server.
.. seealso::
Column Valued Functions - Table Valued Function as a Scalar Column
##################################################################
-A special syntax supported by PostgreSQL and Oracle is that of referring
-towards a function in the FROM clause, which then delivers itself as a
-single column in the columns clause of a SELECT statement or other column
+A special syntax supported by PostgreSQL and Oracle Database is that of
+referring towards a function in the FROM clause, which then delivers itself as
+a single column in the columns clause of a SELECT statement or other column
expression context. PostgreSQL makes great use of this syntax for such
functions as ``json_array_elements()``, ``json_object_keys()``,
``json_each_text()``, ``json_each()``, etc.
{printsql}SELECT x
FROM json_array_elements(:json_array_elements_1) AS x
-The "column valued" form is also supported by the Oracle dialect, where
-it is usable for custom SQL functions::
+The "column valued" form is also supported by the Oracle Database dialects,
+where it is usable for custom SQL functions::
>>> from sqlalchemy.dialects import oracle
>>> stmt = select(func.scalar_strings(5).column_valued("s"))
r"""
.. dialect:: oracle
- :name: Oracle
+ :name: Oracle Database
:normal_support: 11+
:best_effort: 9+
Auto Increment Behavior
-----------------------
-SQLAlchemy Table objects which include integer primary keys are usually
-assumed to have "autoincrementing" behavior, meaning they can generate their
-own primary key values upon INSERT. For use within Oracle, two options are
-available, which are the use of IDENTITY columns (Oracle 12 and above only)
-or the association of a SEQUENCE with the column.
+SQLAlchemy Table objects which include integer primary keys are usually assumed
+to have "autoincrementing" behavior, meaning they can generate their own
+primary key values upon INSERT. For use within Oracle Database, two options are
+available, which are the use of IDENTITY columns (Oracle Database 12 and above
+only) or the association of a SEQUENCE with the column.
-Specifying GENERATED AS IDENTITY (Oracle 12 and above)
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Specifying GENERATED AS IDENTITY (Oracle Database 12 and above)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Starting from version 12 Oracle can make use of identity columns using
-the :class:`_sql.Identity` to specify the autoincrementing behavior::
+Starting from version 12, Oracle Database can make use of identity columns
+using the :class:`_sql.Identity` to specify the autoincrementing behavior::
t = Table('mytable', metadata,
Column('id', Integer, Identity(start=3), primary_key=True),
The :class:`_schema.Identity` object support many options to control the
"autoincrementing" behavior of the column, like the starting value, the
-incrementing value, etc.
-In addition to the standard options, Oracle supports setting
-:paramref:`_schema.Identity.always` to ``None`` to use the default
-generated mode, rendering GENERATED AS IDENTITY in the DDL.
-Oracle also supports two custom options specified using dialect kwargs:
+incrementing value, etc. In addition to the standard options, Oracle Database
+supports setting :paramref:`_schema.Identity.always` to ``None`` to use the
+default generated mode, rendering GENERATED AS IDENTITY in the DDL. Oracle
+Database also supports two custom options specified using dialect kwargs:
* ``oracle_on_null``: when set to ``True`` renders ``ON NULL`` in conjunction
with a 'BY DEFAULT' identity column.
* ``oracle_order``: when ``True``, renders the ORDER keyword, indicating the
identity is definitively ordered. May be necessary to provide deterministic
- ordering using Oracle RAC.
+ ordering using Oracle Real Application Clusters (RAC).
-Using a SEQUENCE (all Oracle versions)
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Using a SEQUENCE (all Oracle Database versions)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Older version of Oracle had no "autoincrement"
-feature, SQLAlchemy relies upon sequences to produce these values. With the
-older Oracle versions, *a sequence must always be explicitly specified to
-enable autoincrement*. This is divergent with the majority of documentation
-examples which assume the usage of an autoincrement-capable database. To
-specify sequences, use the sqlalchemy.schema.Sequence object which is passed
-to a Column construct::
+Older version of Oracle Database had no "autoincrement" feature: SQLAlchemy
+relies upon sequences to produce these values. With the older Oracle Database
+versions, *a sequence must always be explicitly specified to enable
+autoincrement*. This is divergent with the majority of documentation examples
+which assume the usage of an autoincrement-capable database. To specify
+sequences, use the sqlalchemy.schema.Sequence object which is passed to a
+Column construct::
t = Table('mytable', metadata,
Column('id', Integer, Sequence('id_seq', start=1), primary_key=True),
autoload_with=engine
)
-In addition to the standard options, Oracle supports the following custom
-option specified using dialect kwargs:
+In addition to the standard options, Oracle Database supports the following
+custom option specified using dialect kwargs:
* ``oracle_order``: when ``True``, renders the ORDER keyword, indicating the
sequence is definitively ordered. May be necessary to provide deterministic
Transaction Isolation Level / Autocommit
----------------------------------------
-The Oracle database supports "READ COMMITTED" and "SERIALIZABLE" modes of
-isolation. The AUTOCOMMIT isolation level is also supported by the cx_Oracle
-dialect.
+Oracle Database supports "READ COMMITTED" and "SERIALIZABLE" modes of
+isolation. The AUTOCOMMIT isolation level is also supported by the
+python-oracledb and cx_Oracle dialects.
To set using per-connection execution options::
isolation_level="AUTOCOMMIT"
)
-For ``READ COMMITTED`` and ``SERIALIZABLE``, the Oracle dialect sets the
-level at the session level using ``ALTER SESSION``, which is reverted back
-to its default setting when the connection is returned to the connection
-pool.
+For ``READ COMMITTED`` and ``SERIALIZABLE``, the Oracle Database dialects sets
+the level at the session level using ``ALTER SESSION``, which is reverted back
+to its default setting when the connection is returned to the connection pool.
Valid values for ``isolation_level`` include:
.. note:: The implementation for the
:meth:`_engine.Connection.get_isolation_level` method as implemented by the
- Oracle dialect necessarily forces the start of a transaction using the
- Oracle LOCAL_TRANSACTION_ID function; otherwise no level is normally
- readable.
+ Oracle Database dialects necessarily force the start of a transaction using the
+ Oracle Database DBMS_TRANSACTION.LOCAL_TRANSACTION_ID function; otherwise no
+ level is normally readable.
Additionally, the :meth:`_engine.Connection.get_isolation_level` method will
raise an exception if the ``v$transaction`` view is not available due to
- permissions or other reasons, which is a common occurrence in Oracle
+ permissions or other reasons, which is a common occurrence in Oracle Database
installations.
- The cx_Oracle dialect attempts to call the
+ The python-oracledb and cx_Oracle dialects attempt to call the
:meth:`_engine.Connection.get_isolation_level` method when the dialect makes
its first connection to the database in order to acquire the
"default"isolation level. This default level is necessary so that the level
can be reset on a connection after it has been temporarily modified using
- :meth:`_engine.Connection.execution_options` method. In the common event
+ :meth:`_engine.Connection.execution_options` method. In the common event
that the :meth:`_engine.Connection.get_isolation_level` method raises an
exception due to ``v$transaction`` not being readable as well as any other
database-related failure, the level is assumed to be "READ COMMITTED". No
warning is emitted for this initial first-connect condition as it is
expected to be a common restriction on Oracle databases.
-.. versionadded:: 1.3.16 added support for AUTOCOMMIT to the cx_oracle dialect
+.. versionadded:: 1.3.16 added support for AUTOCOMMIT to the cx_Oracle dialect
as well as the notion of a default isolation level
.. versionadded:: 1.3.21 Added support for SERIALIZABLE as well as live
Identifier Casing
-----------------
-In Oracle, the data dictionary represents all case insensitive identifier
-names using UPPERCASE text. SQLAlchemy on the other hand considers an
-all-lower case identifier name to be case insensitive. The Oracle dialect
-converts all case insensitive identifiers to and from those two formats during
-schema level communication, such as reflection of tables and indexes. Using
-an UPPERCASE name on the SQLAlchemy side indicates a case sensitive
+In Oracle Database, the data dictionary represents all case insensitive
+identifier names using UPPERCASE text. SQLAlchemy on the other hand considers
+an all-lower case identifier name to be case insensitive. The Oracle Database
+dialects convert all case insensitive identifiers to and from those two formats
+during schema level communication, such as reflection of tables and indexes.
+Using an UPPERCASE name on the SQLAlchemy side indicates a case sensitive
identifier, and SQLAlchemy will quote the name - this will cause mismatches
-against data dictionary data received from Oracle, so 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.
+against data dictionary data received from Oracle Database, so 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.
.. _oracle_max_identifier_lengths:
-Max Identifier Lengths
-----------------------
+Maximum Identifier Lengths
+--------------------------
-Oracle has changed the default max identifier length as of Oracle Server
-version 12.2. Prior to this version, the length was 30, and for 12.2 and
-greater it is now 128. This change impacts SQLAlchemy in the area of
-generated SQL label names as well as the generation of constraint names,
-particularly in the case where the constraint naming convention feature
-described at :ref:`constraint_naming_conventions` is being used.
-
-To assist with this change and others, Oracle includes the concept of a
-"compatibility" version, which is a version number that is independent of the
-actual server version in order to assist with migration of Oracle databases,
-and may be configured within the Oracle server itself. This compatibility
-version is retrieved using the query ``SELECT value FROM v$parameter WHERE
-name = 'compatible';``.
-The SQLAlchemy Oracle dialect, when tasked with determining the default max
-identifier length, will use the ``max_identifier_length`` attribute available
-in the connection of the oracledb driver since version 2.5. When using an older
-version or cx_oracle SQLAlchemy will instead attempted to use the query
-mentioned above upon first connect in order to determine the effective
-compatibility version of the server, which determines what the maximum allowed
-identifier length is for the server. If the table is not available, the server
-version information is used instead.
-
-As of SQLAlchemy 1.4, the default max identifier length for the Oracle dialect
-is 128 characters. Upon first connect, the compatibility version is detected
-and if it is less than Oracle version 12.2, the max identifier length is
-changed to be 30 characters. In all cases, setting the
+SQLAlchemy is sensitive to the maximum identifier length supported by Oracle
+Database. This affects generated SQL label names as well as the generation of
+constraint names, particularly in the case where the constraint naming
+convention feature described at :ref:`constraint_naming_conventions` is being
+used.
+
+Oracle Database 12.2 increased the default maximum identifier length from 30 to
+128. As of SQLAlchemy 1.4, the default maximum identifier length for the Oracle
+dialects is 128 characters. Upon first connection, the maximum length actually
+supported by the database is obtained. In all cases, setting the
:paramref:`_sa.create_engine.max_identifier_length` parameter will bypass this
change and the value given will be used as is::
engine = create_engine(
- "oracle+cx_oracle://scott:tiger@oracle122",
+ "oracle+oracledb://scott:tiger@localhost:1521?service_name=freepdb1",
max_identifier_length=30)
+If :paramref:`_sa.create_engine.max_identifier_length` is not set, the oracledb
+dialect internally uses the ``max_identifier_length`` attribute available on
+driver connections since python-oracledb version 2.5. When using an older
+driver version, or using the cx_Oracle dialect, SQLAlchemy will instead attempt
+to use the query ``SELECT value FROM v$parameter WHERE name = 'compatible'``
+upon first connect in order to determine the effective compatibility version of
+the database. The "compatibility" version is a version number that is
+independent of the actual database version. It is used to assist database
+migration. It is configured by an Oracle Database initialization parameter. The
+compatibility version then determines the maximum allowed identifier length for
+the database. If the V$ view is not available, the database version information
+is used instead.
+
The maximum identifier length comes into play both when generating anonymized
SQL labels in SELECT statements, but more crucially when generating constraint
names from a naming convention. It is this area that has created the need for
-SQLAlchemy to change this default conservatively. For example, the following
+SQLAlchemy to change this default conservatively. For example, the following
naming convention produces two very different constraint names based on the
identifier length::
CREATE INDEX ix_some_column_name_1s_70cd ON t
(some_column_name_1, some_column_name_2, some_column_name_3)
-However with length=128, it becomes::
+However with length of 128, it becomes::
CREATE INDEX ix_some_column_name_1some_column_name_2some_column_name_3 ON t
(some_column_name_1, some_column_name_2, some_column_name_3)
-Applications which have run versions of SQLAlchemy prior to 1.4 on an Oracle
-server version 12.2 or greater are therefore subject to the scenario of a
+Applications which have run versions of SQLAlchemy prior to 1.4 on Oracle
+Database version 12.2 or greater are therefore subject to the scenario of a
database migration that wishes to "DROP CONSTRAINT" on a name that was
previously generated with the shorter length. This migration will fail when
the identifier length is changed without the name of the index or constraint
first being adjusted. Such applications are strongly advised to make use of
-:paramref:`_sa.create_engine.max_identifier_length`
-in order to maintain control
-of the generation of truncated names, and to fully review and test all database
-migrations in a staging environment when changing this value to ensure that the
-impact of this change has been mitigated.
+:paramref:`_sa.create_engine.max_identifier_length` in order to maintain
+control of the generation of truncated names, and to fully review and test all
+database migrations in a staging environment when changing this value to ensure
+that the impact of this change has been mitigated.
-.. versionchanged:: 1.4 the default max_identifier_length for Oracle is 128
- characters, which is adjusted down to 30 upon first connect if an older
- version of Oracle server (compatibility version < 12.2) is detected.
+.. versionchanged:: 1.4 the default max_identifier_length for Oracle Database
+ is 128 characters, which is adjusted down to 30 upon first connect if the
+ Oracle Database, or its compatibility setting, are lower than version 12.2.
LIMIT/OFFSET/FETCH Support
--------------------------
-Methods like :meth:`_sql.Select.limit` and :meth:`_sql.Select.offset` make
-use of ``FETCH FIRST N ROW / OFFSET N ROWS`` syntax assuming
-Oracle 12c or above, and assuming the SELECT statement is not embedded within
-a compound statement like UNION. This syntax is also available directly by using
-the :meth:`_sql.Select.fetch` method.
-
-.. versionchanged:: 2.0 the Oracle dialect now uses
- ``FETCH FIRST N ROW / OFFSET N ROWS`` for all
- :meth:`_sql.Select.limit` and :meth:`_sql.Select.offset` usage including
- within the ORM and legacy :class:`_orm.Query`. To force the legacy
- behavior using window functions, specify the ``enable_offset_fetch=False``
- dialect parameter to :func:`_sa.create_engine`.
-
-The use of ``FETCH FIRST / OFFSET`` may be disabled on any Oracle version
-by passing ``enable_offset_fetch=False`` to :func:`_sa.create_engine`, which
-will force the use of "legacy" mode that makes use of window functions.
+Methods like :meth:`_sql.Select.limit` and :meth:`_sql.Select.offset` make use
+of ``FETCH FIRST N ROW / OFFSET N ROWS`` syntax assuming Oracle Database 12c or
+above, and assuming the SELECT statement is not embedded within a compound
+statement like UNION. This syntax is also available directly by using the
+:meth:`_sql.Select.fetch` method.
+
+.. versionchanged:: 2.0 the Oracle Database dialects now use ``FETCH FIRST N
+ ROW / OFFSET N ROWS`` for all :meth:`_sql.Select.limit` and
+ :meth:`_sql.Select.offset` usage including within the ORM and legacy
+ :class:`_orm.Query`. To force the legacy behavior using window functions,
+ specify the ``enable_offset_fetch=False`` dialect parameter to
+ :func:`_sa.create_engine`.
+
+The use of ``FETCH FIRST / OFFSET`` may be disabled on any Oracle Database
+version by passing ``enable_offset_fetch=False`` to :func:`_sa.create_engine`,
+which will force the use of "legacy" mode that makes use of window functions.
This mode is also selected automatically when using a version of Oracle
-prior to 12c.
+Database prior to 12c.
-When using legacy mode, or when a :class:`.Select` statement
-with limit/offset is embedded in a compound statement, an emulated approach for
-LIMIT / OFFSET based on window functions is used, which involves creation of a
-subquery using ``ROW_NUMBER`` that is prone to performance issues as well as
-SQL construction issues for complex statements. However, this approach is
-supported by all Oracle versions. See notes below.
+When using legacy mode, or when a :class:`.Select` statement with limit/offset
+is embedded in a compound statement, an emulated approach for LIMIT / OFFSET
+based on window functions is used, which involves creation of a subquery using
+``ROW_NUMBER`` that is prone to performance issues as well as SQL construction
+issues for complex statements. However, this approach is supported by all
+Oracle Database versions. See notes below.
Notes on LIMIT / OFFSET emulation (when fetch() method cannot be used)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If using :meth:`_sql.Select.limit` and :meth:`_sql.Select.offset`, or with the
ORM the :meth:`_orm.Query.limit` and :meth:`_orm.Query.offset` methods on an
-Oracle version prior to 12c, the following notes apply:
+Oracle Database version prior to 12c, the following notes apply:
* SQLAlchemy currently makes use of ROWNUM to achieve
LIMIT/OFFSET; the exact methodology is taken from
to :func:`_sa.create_engine`.
.. versionchanged:: 1.4
- The Oracle dialect renders limit/offset integer values using a "post
- compile" scheme which renders the integer directly before passing the
- statement to the cursor for execution. The ``use_binds_for_limits`` flag
- no longer has an effect.
+
+ The Oracle Database dialect renders limit/offset integer values using a
+ "post compile" scheme which renders the integer directly before passing
+ the statement to the cursor for execution. The ``use_binds_for_limits``
+ flag no longer has an effect.
.. seealso::
RETURNING Support
-----------------
-The Oracle database supports RETURNING fully for INSERT, UPDATE and DELETE
-statements that are invoked with a single collection of bound parameters
-(that is, a ``cursor.execute()`` style statement; SQLAlchemy does not generally
+Oracle Database supports RETURNING fully for INSERT, UPDATE and DELETE
+statements that are invoked with a single collection of bound parameters (that
+is, a ``cursor.execute()`` style statement; SQLAlchemy does not generally
support RETURNING with :term:`executemany` statements). Multiple rows may be
returned as well.
-.. versionchanged:: 2.0 the Oracle backend has full support for RETURNING
- on parity with other backends.
+.. versionchanged:: 2.0 the Oracle Database backend has full support for
+ RETURNING on parity with other backends.
ON UPDATE CASCADE
-----------------
-Oracle doesn't have native ON UPDATE CASCADE functionality. A trigger based
-solution is available at
+Oracle Database doesn't have native ON UPDATE CASCADE functionality. A trigger
+based solution is available at
https://web.archive.org/web/20090317041251/https://asktom.oracle.com/tkyte/update_cascade/index.html
When using the SQLAlchemy ORM, the ORM has limited ability to manually issue
"deferrable=True, initially='deferred'" keyword arguments,
and specify "passive_updates=False" on each relationship().
-Oracle 8 Compatibility
-----------------------
+Oracle Database 8 Compatibility
+-------------------------------
-.. warning:: The status of Oracle 8 compatibility is not known for SQLAlchemy
- 2.0.
+.. warning:: The status of Oracle Database 8 compatibility is not known for
+ SQLAlchemy 2.0.
-When Oracle 8 is detected, the dialect internally configures itself to the
-following behaviors:
+When Oracle Database 8 is detected, the dialect internally configures itself to
+the following behaviors:
* the use_ansi flag is set to False. This has the effect of converting all
JOIN phrases into the WHERE clause, and in the case of LEFT OUTER JOIN
some_table = Table('some_table', autoload_with=some_engine,
oracle_resolve_synonyms=True)
-When this flag is set, the given name (such as ``some_table`` above) will
-be searched not just in the ``ALL_TABLES`` view, but also within the
+When this flag is set, the given name (such as ``some_table`` above) will be
+searched not just in the ``ALL_TABLES`` view, but also within the
``ALL_SYNONYMS`` view to see if this name is actually a synonym to another
-name. If the synonym is located and refers to a DBLINK, the oracle dialect
-knows how to locate the table's information using DBLINK syntax(e.g.
+name. If the synonym is located and refers to a DBLINK, the Oracle Database
+dialects know how to locate the table's information using DBLINK syntax(e.g.
``@dblink``).
``oracle_resolve_synonyms`` is accepted wherever reflection arguments are
Constraint Reflection
---------------------
-The Oracle dialect can return information about foreign key, unique, and
-CHECK constraints, as well as indexes on tables.
+The Oracle Database dialects can return information about foreign key, unique,
+and CHECK constraints, as well as indexes on tables.
Raw information regarding these constraints can be acquired using
:meth:`_reflection.Inspector.get_foreign_keys`,
:meth:`_reflection.Inspector.get_check_constraints`, and
:meth:`_reflection.Inspector.get_indexes`.
-.. versionchanged:: 1.2 The Oracle dialect can now reflect UNIQUE and
+.. versionchanged:: 1.2 The Oracle Database dialect can now reflect UNIQUE and
CHECK constraints.
When using reflection at the :class:`_schema.Table` level, the
Note the following caveats:
* When using the :meth:`_reflection.Inspector.get_check_constraints` method,
- Oracle
- builds a special "IS NOT NULL" constraint for columns that specify
- "NOT NULL". This constraint is **not** returned by default; to include
- the "IS NOT NULL" constraints, pass the flag ``include_all=True``::
+ Oracle Database builds a special "IS NOT NULL" constraint for columns that
+ specify "NOT NULL". This constraint is **not** returned by default; to
+ include the "IS NOT NULL" constraints, pass the flag ``include_all=True``::
from sqlalchemy import create_engine, inspect
- engine = create_engine("oracle+cx_oracle://s:t@dsn")
+ engine = create_engine("oracle+oracledb://scott:tiger@localhost:1521?service_name=freepdb1")
inspector = inspect(engine)
all_check_constraints = inspector.get_check_constraints(
"some_table", include_all=True)
-* in most cases, when reflecting a :class:`_schema.Table`,
- a UNIQUE constraint will
- **not** be available as a :class:`.UniqueConstraint` object, as Oracle
- mirrors unique constraints with a UNIQUE index in most cases (the exception
- seems to be when two or more unique constraints represent the same columns);
- the :class:`_schema.Table` will instead represent these using
- :class:`.Index`
- with the ``unique=True`` flag set.
+* in most cases, when reflecting a :class:`_schema.Table`, a UNIQUE constraint
+ will **not** be available as a :class:`.UniqueConstraint` object, as Oracle
+ Database mirrors unique constraints with a UNIQUE index in most cases (the
+ exception seems to be when two or more unique constraints represent the same
+ columns); the :class:`_schema.Table` will instead represent these using
+ :class:`.Index` with the ``unique=True`` flag set.
-* Oracle creates an implicit index for the primary key of a table; this index
- is **excluded** from all index results.
+* Oracle Database creates an implicit index for the primary key of a table;
+ this index is **excluded** from all index results.
* the list of columns reflected for an index will not include column names
that start with SYS_NC.
# exclude SYSAUX and SOME_TABLESPACE, but not SYSTEM
e = create_engine(
- "oracle+cx_oracle://scott:tiger@xe",
+ "oracle+oracledb://scott:tiger@localhost:1521/?service_name=freepdb1",
exclude_tablespaces=["SYSAUX", "SOME_TABLESPACE"])
DateTime Compatibility
----------------------
-Oracle has no datatype known as ``DATETIME``, it instead has only ``DATE``,
-which can actually store a date and time value. For this reason, the Oracle
-dialect provides a type :class:`_oracle.DATE` which is a subclass of
-:class:`.DateTime`. This type has no special behavior, and is only
-present as a "marker" for this type; additionally, when a database column
-is reflected and the type is reported as ``DATE``, the time-supporting
+Oracle Database has no datatype known as ``DATETIME``, it instead has only
+``DATE``, which can actually store a date and time value. For this reason, the
+Oracle Database dialects provide a type :class:`_oracle.DATE` which is a
+subclass of :class:`.DateTime`. This type has no special behavior, and is only
+present as a "marker" for this type; additionally, when a database column is
+reflected and the type is reported as ``DATE``, the time-supporting
:class:`_oracle.DATE` type is used.
.. _oracle_table_options:
-Oracle Table Options
---------------------
+Oracle Database Table Options
+-----------------------------
-The CREATE TABLE phrase supports the following options with Oracle
-in conjunction with the :class:`_schema.Table` construct:
+The CREATE TABLE phrase supports the following options with Oracle Database
+dialects in conjunction with the :class:`_schema.Table` construct:
* ``ON COMMIT``::
.. _oracle_index_options:
-Oracle Specific Index Options
------------------------------
+Oracle Database Specific Index Options
+--------------------------------------
Bitmap Indexes
~~~~~~~~~~~~~~
Index compression
~~~~~~~~~~~~~~~~~
-Oracle has a more efficient storage mode for indexes containing lots of
-repeated values. Use the ``oracle_compress`` parameter to turn on key
+Oracle Database has a more efficient storage mode for indexes containing lots
+of repeated values. Use the ``oracle_compress`` parameter to turn on key
compression::
Index('my_index', my_table.c.data, oracle_compress=True)
# https://www.oracletutorial.com/oracle-basics/oracle-float/
estimated_binary_precision = int(precision / 0.30103)
raise exc.ArgumentError(
- "Oracle FLOAT types use 'binary precision', which does "
- "not convert cleanly from decimal 'precision'. Please "
- "specify "
- f"this type with a separate Oracle variant, such as "
- f"{type_.__class__.__name__}(precision={precision})."
+ "Oracle Database FLOAT types use 'binary precision', "
+ "which does not convert cleanly from decimal "
+ "'precision'. Please specify "
+ "this type with a separate Oracle Database variant, such "
+ f"as {type_.__class__.__name__}(precision={precision})."
f"with_variant(oracle.FLOAT"
f"(binary_precision="
f"{estimated_binary_precision}), 'oracle'), so that the "
- "Oracle specific 'binary_precision' may be specified "
- "accurately."
+ "Oracle Database specific 'binary_precision' may be "
+ "specified accurately."
)
else:
precision = binary_precision
and not self.dialect._supports_update_returning_computed_cols
):
util.warn(
- "Computed columns don't work with Oracle UPDATE "
+ "Computed columns don't work with Oracle Database UPDATE "
"statements that use RETURNING; the value of the column "
"*before* the UPDATE takes place is returned. It is "
- "advised to not use RETURNING with an Oracle computed "
- "column. Consider setting implicit_returning to False on "
- "the Table object in order to avoid implicit RETURNING "
- "clauses from being generated for this Table."
+ "advised to not use RETURNING with an Oracle Database "
+ "computed column. Consider setting implicit_returning "
+ "to False on the Table object in order to avoid implicit "
+ "RETURNING clauses from being generated for this Table."
)
if column.type._has_column_expression:
col_expr = column.type.column_expression(column)
raise exc.InvalidRequestError(
"Using explicit outparam() objects with "
"UpdateBase.returning() in the same Core DML statement "
- "is not supported in the Oracle dialect."
+ "is not supported in the Oracle Database dialects."
)
self._oracle_returning = True
return "RETURNING " + ", ".join(columns) + " INTO " + ", ".join(binds)
def _row_limit_clause(self, select, **kw):
- """ORacle 12c supports OFFSET/FETCH operators
+ """Oracle Database 12c supports OFFSET/FETCH operators
Use it instead subquery with row_number
"""
# https://web.archive.org/web/20090317041251/https://asktom.oracle.com/tkyte/update_cascade/index.html
if constraint.onupdate is not None:
util.warn(
- "Oracle does not contain native UPDATE CASCADE "
+ "Oracle Database does not contain native UPDATE CASCADE "
"functionality - onupdates will not be rendered for foreign "
"keys. Consider using deferrable=True, initially='deferred' "
"or triggers."
)
if generated.persisted is True:
raise exc.CompileError(
- "Oracle computed columns do not support 'stored' persistence; "
- "set the 'persisted' flag to None or False for Oracle support."
+ "Oracle Database computed columns do not support 'stored' "
+ "persistence; set the 'persisted' flag to None or False for "
+ "Oracle Database support."
)
elif generated.persisted is False:
text += " VIRTUAL"
@util.deprecated_params(
use_binds_for_limits=(
"1.4",
- "The ``use_binds_for_limits`` Oracle dialect parameter is "
- "deprecated. The dialect now renders LIMIT /OFFSET integers "
+ "The ``use_binds_for_limits`` Oracle Database dialect parameter "
+ "is deprecated. The dialect now renders LIMIT / OFFSET integers "
"inline in all cases using a post-compilation hook, so that the "
"value is still represented by a 'bound parameter' on the Core "
"Expression side.",
# mypy: ignore-errors
-r"""
-.. dialect:: oracle+cx_oracle
+r""".. dialect:: oracle+cx_oracle
:name: cx-Oracle
:dbapi: cx_oracle
:connectstring: oracle+cx_oracle://user:pass@hostname:port[/dbname][?service_name=<service>[&key=value&key=value...]]
:url: https://oracle.github.io/python-cx_Oracle/
+Description
+-----------
+
+cx_Oracle was the original driver for Oracle Database. It was superseded by
+python-oracledb which should be used instead.
+
DSN vs. Hostname connections
-----------------------------
Hostname Connections with Easy Connect Syntax
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-Given a hostname, port and service name of the target Oracle Database, for
-example from Oracle's `Easy Connect syntax
-<https://cx-oracle.readthedocs.io/en/latest/user_guide/connection_handling.html#easy-connect-syntax-for-connection-strings>`_,
-then connect in SQLAlchemy using the ``service_name`` query string parameter::
+Given a hostname, port and service name of the target database, for example
+from Oracle Database's Easy Connect syntax then connect in SQLAlchemy using the
+``service_name`` query string parameter::
- engine = create_engine("oracle+cx_oracle://scott:tiger@hostname:port/?service_name=myservice&encoding=UTF-8&nencoding=UTF-8")
+ engine = create_engine("oracle+cx_oracle://scott:tiger@hostname:port?service_name=myservice&encoding=UTF-8&nencoding=UTF-8")
-The `full Easy Connect syntax
-<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-B0437826-43C1-49EC-A94D-B650B6A4A6EE>`_
-is not supported. Instead, use a ``tnsnames.ora`` file and connect using a
-DSN.
+Note that the default driver value for encoding and nencoding was changed to
+“UTF-8” in cx_Oracle 8.0 so these parameters can be omitted when using that
+version, or later.
-Connections with tnsnames.ora or Oracle Cloud
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+To use a full Easy Connect string, pass it as the ``dsn`` key value in a
+:paramref:`_sa.create_engine.connect_args` dictionary::
-Alternatively, if no port, database name, or ``service_name`` is provided, the
-dialect will use an Oracle DSN "connection string". This takes the "hostname"
-portion of the URL as the data source name. For example, if the
-``tnsnames.ora`` file contains a `Net Service Name
-<https://cx-oracle.readthedocs.io/en/latest/user_guide/connection_handling.html#net-service-names-for-connection-strings>`_
-of ``myalias`` as below::
+ import cx_Oracle
+ e = create_engine(
+ "oracle+cx_oracle://@",
+ connect_args={
+ "user": "scott",
+ "password": "tiger",
+ "dsn": "hostname:port/myservice?transport_connect_timeout=30&expire_time=60"
+ }
+ )
+
+Connections with tnsnames.ora or to Oracle Autonomous Database
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Alternatively, if no port, database name, or service name is provided, the
+dialect will use an Oracle Database DSN "connection string". This takes the
+"hostname" portion of the URL as the data source name. For example, if the
+``tnsnames.ora`` file contains a TNS Alias of ``myalias`` as below::
myalias =
(DESCRIPTION =
hostname portion of the URL, without specifying a port, database name or
``service_name``::
- engine = create_engine("oracle+cx_oracle://scott:tiger@myalias/?encoding=UTF-8&nencoding=UTF-8")
+ engine = create_engine("oracle+cx_oracle://scott:tiger@myalias")
-Users of Oracle Cloud should use this syntax and also configure the cloud
+Users of Oracle Autonomous Database should use this syntax. If the database is
+configured for mutural TLS ("mTLS"), then you must also configure the cloud
wallet as shown in cx_Oracle documentation `Connecting to Autononmous Databases
<https://cx-oracle.readthedocs.io/en/latest/user_guide/connection_handling.html#autonomousdb>`_.
SID Connections
^^^^^^^^^^^^^^^
-To use Oracle's obsolete SID connection syntax, the SID can be passed in a
-"database name" portion of the URL as below::
+To use Oracle Database's obsolete System Identifier connection syntax, the SID
+can be passed in a "database name" portion of the URL::
- engine = create_engine("oracle+cx_oracle://scott:tiger@hostname:1521/dbname?encoding=UTF-8&nencoding=UTF-8")
+ engine = create_engine("oracle+cx_oracle://scott:tiger@hostname:port/dbname")
Above, the DSN passed to cx_Oracle is created by ``cx_Oracle.makedsn()`` as
follows::
>>> cx_Oracle.makedsn("hostname", 1521, sid="dbname")
'(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=hostname)(PORT=1521))(CONNECT_DATA=(SID=dbname)))'
+Note that although the SQLAlchemy syntax ``hostname:port/dbname`` looks like
+Oracle's Easy Connect syntax it is different. It uses a SID in place of the
+service name required by Easy Connect. The Easy Connect syntax does not
+support SIDs.
+
Passing cx_Oracle connect arguments
-----------------------------------
-Additional connection arguments can usually be passed via the URL
-query string; particular symbols like ``cx_Oracle.SYSDBA`` are intercepted
-and converted to the correct symbol::
+Additional connection arguments can usually be passed via the URL query string;
+particular symbols like ``SYSDBA`` are intercepted and converted to the correct
+symbol::
e = create_engine(
"oracle+cx_oracle://user:pass@dsn?encoding=UTF-8&nencoding=UTF-8&mode=SYSDBA&events=true")
-.. versionchanged:: 1.3 the cx_oracle dialect now accepts all argument names
+.. versionchanged:: 1.3 the cx_Oracle dialect now accepts all argument names
within the URL string itself, to be passed to the cx_Oracle DBAPI. As
was the case earlier but not correctly documented, the
:paramref:`_sa.create_engine.connect_args` parameter also accepts all
}
)
-Note that the default value for ``encoding`` and ``nencoding`` was changed to
-"UTF-8" in cx_Oracle 8.0 so these parameters can be omitted when using that
-version, or later.
+Note that the default driver value for ``encoding`` and ``nencoding`` was
+changed to "UTF-8" in cx_Oracle 8.0 so these parameters can be omitted when
+using that version, or later.
Options consumed by the SQLAlchemy cx_Oracle dialect outside of the driver
--------------------------------------------------------------------------
to ``None``, indicating that the driver default should be used (typically
the value is 100). This setting controls how many rows are buffered when
fetching rows, and can have a significant effect on performance when
- modified. The setting is used for both ``cx_Oracle`` as well as
- ``oracledb``.
+ modified.
.. versionchanged:: 2.0.26 - changed the default value from 50 to None,
to use the default value of the driver itself.
Using cx_Oracle SessionPool
---------------------------
-The cx_Oracle library provides its own connection pool implementation that may
-be used in place of SQLAlchemy's pooling functionality. This can be achieved
-by using the :paramref:`_sa.create_engine.creator` parameter to provide a
-function that returns a new connection, along with setting
+The cx_Oracle driver provides its own connection pool implementation that may
+be used in place of SQLAlchemy's pooling functionality. The driver pool
+supports Oracle Database features such dead connection detection, connection
+draining for planned database downtime, support for Oracle Application
+Continuity and Transparent Application Continuity, and gives support for
+Database Resident Connection Pooling (DRCP).
+
+Using the driver pool can be achieved by using the
+:paramref:`_sa.create_engine.creator` parameter to provide a function that
+returns a new connection, along with setting
:paramref:`_sa.create_engine.pool_class` to ``NullPool`` to disable
SQLAlchemy's pooling::
pool = cx_Oracle.SessionPool(
user="scott", password="tiger", dsn="orclpdb",
- min=2, max=5, increment=1, threaded=True,
- encoding="UTF-8", nencoding="UTF-8"
+ min=1, max=4, increment=1, threaded=True,
+ encoding="UTF-8", nencoding="UTF-8"
)
engine = create_engine("oracle+cx_oracle://", creator=pool.acquire, poolclass=NullPool)
connection pooling::
with engine.connect() as conn:
- print(conn.scalar("select 1 FROM dual"))
-
+ print(conn.scalar("select 1 from dual"))
As well as providing a scalable solution for multi-user applications, the
cx_Oracle session pool supports some Oracle features such as DRCP and
`Application Continuity
<https://cx-oracle.readthedocs.io/en/latest/user_guide/ha.html#application-continuity-ac>`_.
+Note that the pool creation parameters ``threaded``, ``encoding`` and
+``nencoding`` were deprecated in later cx_Oracle releases.
+
Using Oracle Database Resident Connection Pooling (DRCP)
--------------------------------------------------------
-When using Oracle's `DRCP
-<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-015CA8C1-2386-4626-855D-CC546DDC1086>`_,
-the best practice is to pass a connection class and "purity" when acquiring a
-connection from the SessionPool. Refer to the `cx_Oracle DRCP documentation
+When using Oracle Database's DRCP, the best practice is to pass a connection
+class and "purity" when acquiring a connection from the SessionPool. Refer to
+the `cx_Oracle DRCP documentation
<https://cx-oracle.readthedocs.io/en/latest/user_guide/connection_handling.html#database-resident-connection-pooling-drcp>`_.
This can be achieved by wrapping ``pool.acquire()``::
pool = cx_Oracle.SessionPool(
user="scott", password="tiger", dsn="orclpdb",
min=2, max=5, increment=1, threaded=True,
- encoding="UTF-8", nencoding="UTF-8"
+ encoding="UTF-8", nencoding="UTF-8"
)
def creator():
pooling and Oracle Database additionally uses DRCP::
with engine.connect() as conn:
- print(conn.scalar("select 1 FROM dual"))
+ print(conn.scalar("select 1 from dual"))
.. _cx_oracle_unicode:
-------
As is the case for all DBAPIs under Python 3, all strings are inherently
-Unicode strings. In all cases however, the driver requires an explicit
+Unicode strings. In all cases however, the driver requires an explicit
encoding configuration.
Ensuring the Correct Client Encoding
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The long accepted standard for establishing client encoding for nearly all
-Oracle related software is via the `NLS_LANG <https://www.oracle.com/database/technologies/faq-nls-lang.html>`_
-environment variable. cx_Oracle like most other Oracle drivers will use
-this environment variable as the source of its encoding configuration. The
-format of this variable is idiosyncratic; a typical value would be
-``AMERICAN_AMERICA.AL32UTF8``.
+Oracle Database related software is via the `NLS_LANG
+<https://www.oracle.com/database/technologies/faq-nls-lang.html>`_ environment
+variable. Older versions of cx_Oracle use this environment variable as the
+source of its encoding configuration. The format of this variable is
+Territory_Country.CharacterSet; a typical value would be
+``AMERICAN_AMERICA.AL32UTF8``. cx_Oracle version 8 and later use the character
+set "UTF-8" by default, and ignore the character set component of NLS_LANG.
-The cx_Oracle driver also supports a programmatic alternative which is to
-pass the ``encoding`` and ``nencoding`` parameters directly to its
-``.connect()`` function. These can be present in the URL as follows::
+The cx_Oracle driver also supported a programmatic alternative which is to pass
+the ``encoding`` and ``nencoding`` parameters directly to its ``.connect()``
+function. These can be present in the URL as follows::
- engine = create_engine("oracle+cx_oracle://scott:tiger@orclpdb/?encoding=UTF-8&nencoding=UTF-8")
+ engine = create_engine("oracle+cx_oracle://scott:tiger@tnsalias?encoding=UTF-8&nencoding=UTF-8")
For the meaning of the ``encoding`` and ``nencoding`` parameters, please
consult
Unicode-specific Column datatypes
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-The Core expression language handles unicode data by use of the :class:`.Unicode`
-and :class:`.UnicodeText`
-datatypes. These types correspond to the VARCHAR2 and CLOB Oracle datatypes by
-default. When using these datatypes with Unicode data, it is expected that
-the Oracle database is configured with a Unicode-aware character set, as well
-as that the ``NLS_LANG`` environment variable is set appropriately, so that
-the VARCHAR2 and CLOB datatypes can accommodate the data.
+The Core expression language handles unicode data by use of the
+:class:`.Unicode` and :class:`.UnicodeText` datatypes. These types correspond
+to the VARCHAR2 and CLOB Oracle Database datatypes by default. When using
+these datatypes with Unicode data, it is expected that the database is
+configured with a Unicode-aware character set, as well as that the ``NLS_LANG``
+environment variable is set appropriately (this applies to older versions of
+cx_Oracle), so that the VARCHAR2 and CLOB datatypes can accommodate the data.
-In the case that the Oracle database is not configured with a Unicode character
+In the case that Oracle Database is not configured with a Unicode character
set, the two options are to use the :class:`_types.NCHAR` and
:class:`_oracle.NCLOB` datatypes explicitly, or to pass the flag
-``use_nchar_for_unicode=True`` to :func:`_sa.create_engine`,
-which will cause the
-SQLAlchemy dialect to use NCHAR/NCLOB for the :class:`.Unicode` /
+``use_nchar_for_unicode=True`` to :func:`_sa.create_engine`, which will cause
+the SQLAlchemy dialect to use NCHAR/NCLOB for the :class:`.Unicode` /
:class:`.UnicodeText` datatypes instead of VARCHAR/CLOB.
-.. versionchanged:: 1.3 The :class:`.Unicode` and :class:`.UnicodeText`
- datatypes now correspond to the ``VARCHAR2`` and ``CLOB`` Oracle datatypes
- unless the ``use_nchar_for_unicode=True`` is passed to the dialect
+.. versionchanged:: 1.3 The :class:`.Unicode` and :class:`.UnicodeText`
+ datatypes now correspond to the ``VARCHAR2`` and ``CLOB`` Oracle Database
+ datatypes unless the ``use_nchar_for_unicode=True`` is passed to the dialect
when :func:`_sa.create_engine` is called.
Encoding Errors
^^^^^^^^^^^^^^^
-For the unusual case that data in the Oracle database is present with a broken
+For the unusual case that data in Oracle Database is present with a broken
encoding, the dialect accepts a parameter ``encoding_errors`` which will be
passed to Unicode decoding functions in order to affect how decoding errors are
handled. The value is ultimately consumed by the Python `decode
-------------------------------------------------------------------------------
The cx_Oracle DBAPI has a deep and fundamental reliance upon the usage of the
-DBAPI ``setinputsizes()`` call. The purpose of this call is to establish the
+DBAPI ``setinputsizes()`` call. The purpose of this call is to establish the
datatypes that are bound to a SQL statement for Python values being passed as
parameters. While virtually no other DBAPI assigns any use to the
``setinputsizes()`` call, the cx_Oracle DBAPI relies upon it heavily in its
-interactions with the Oracle client interface, and in some scenarios it is not
-possible for SQLAlchemy to know exactly how data should be bound, as some
-settings can cause profoundly different performance characteristics, while
+interactions with the Oracle Database client interface, and in some scenarios
+it is not possible for SQLAlchemy to know exactly how data should be bound, as
+some settings can cause profoundly different performance characteristics, while
altering the type coercion behavior at the same time.
Users of the cx_Oracle dialect are **strongly encouraged** to read through
if dbapitype is CLOB:
del inputsizes[bindparam]
-.. _cx_oracle_returning:
-
-RETURNING Support
------------------
-
-The cx_Oracle dialect implements RETURNING using OUT parameters.
-The dialect supports RETURNING fully.
-
.. _cx_oracle_lob:
LOB Datatypes
--------------
LOB datatypes refer to the "large object" datatypes such as CLOB, NCLOB and
-BLOB. Modern versions of cx_Oracle and oracledb are optimized for these
-datatypes to be delivered as a single buffer. As such, SQLAlchemy makes use of
-these newer type handlers by default.
+BLOB. Modern versions of cx_Oracle is optimized for these datatypes to be
+delivered as a single buffer. As such, SQLAlchemy makes use of these newer type
+handlers by default.
To disable the use of newer type handlers and deliver LOB objects as classic
buffered objects with a ``read()`` method, the parameter
``auto_convert_lobs=False`` may be passed to :func:`_sa.create_engine`,
which takes place only engine-wide.
-Two Phase Transactions Not Supported (use oracledb)
----------------------------------------------------
+.. _cx_oracle_returning:
+
+RETURNING Support
+-----------------
+
+The cx_Oracle dialect implements RETURNING using OUT parameters.
+The dialect supports RETURNING fully.
+
+Two Phase Transactions Not Supported
+------------------------------------
Two phase transactions are **not supported** under cx_Oracle due to poor driver
-support. The newer :ref:`oracledb` dialect however **does** support two phase
-transactions and should be preferred.
+support. The newer :ref:`oracledb` dialect however **does** support two phase
+transactions.
.. _cx_oracle_numeric:
``Decimal`` objects or float objects. When a :class:`.Numeric` object, or a
subclass such as :class:`.Float`, :class:`_oracle.DOUBLE_PRECISION` etc. is in
use, the :paramref:`.Numeric.asdecimal` flag determines if values should be
-coerced to ``Decimal`` upon return, or returned as float objects. To make
-matters more complicated under Oracle, Oracle's ``NUMBER`` type can also
-represent integer values if the "scale" is zero, so the Oracle-specific
-:class:`_oracle.NUMBER` type takes this into account as well.
+coerced to ``Decimal`` upon return, or returned as float objects. To make
+matters more complicated under Oracle Database, the ``NUMBER`` type can also
+represent integer values if the "scale" is zero, so the Oracle
+Database-specific :class:`_oracle.NUMBER` type takes this into account as well.
The cx_Oracle dialect makes extensive use of connection- and cursor-level
"outputtypehandler" callables in order to coerce numeric values as requested.
These callables are specific to the specific flavor of :class:`.Numeric` in
-use, as well as if no SQLAlchemy typing objects are present. There are
-observed scenarios where Oracle may sends incomplete or ambiguous information
-about the numeric types being returned, such as a query where the numeric types
-are buried under multiple levels of subquery. The type handlers do their best
-to make the right decision in all cases, deferring to the underlying cx_Oracle
-DBAPI for all those cases where the driver can make the best decision.
+use, as well as if no SQLAlchemy typing objects are present. There are
+observed scenarios where Oracle Database may send incomplete or ambiguous
+information about the numeric types being returned, such as a query where the
+numeric types are buried under multiple levels of subquery. The type handlers
+do their best to make the right decision in all cases, deferring to the
+underlying cx_Oracle DBAPI for all those cases where the driver can make the
+best decision.
When no typing objects are present, as when executing plain SQL strings, a
default "outputtypehandler" is present which will generally return numeric
# the MIT License: https://www.opensource.org/licenses/mit-license.php
# mypy: ignore-errors
-r"""
-.. dialect:: oracle+oracledb
+r""".. dialect:: oracle+oracledb
:name: python-oracledb
:dbapi: oracledb
:connectstring: oracle+oracledb://user:pass@hostname:port[/dbname][?service_name=<service>[&key=value&key=value...]]
Description
-----------
-python-oracledb is released by Oracle to supersede the cx_Oracle driver.
-It is fully compatible with cx_Oracle and features both a "thin" client
-mode that requires no dependencies, as well as a "thick" mode that uses
-the Oracle Client Interface in the same way as cx_Oracle.
+Python-oracledb is the Oracle Database driver for Python. It features a default
+"thin" client mode that requires no dependencies, and an optional "thick" mode
+that uses Oracle Client libraries. It supports SQLAlchemy features including
+two phase transactions and Asyncio.
-.. seealso::
-
- :ref:`cx_oracle` - all of cx_Oracle's notes apply to the oracledb driver
- as well, with the exception that oracledb supports two phase transactions.
+Python-oracle is the renamed, updated cx_Oracle driver. Oracle is no longer
+doing any releases in the cx_Oracle namespace.
The SQLAlchemy ``oracledb`` dialect provides both a sync and an async
implementation under the same dialect name. The proper version is
selected depending on how the engine is created:
* calling :func:`_sa.create_engine` with ``oracle+oracledb://...`` will
- automatically select the sync version, e.g.::
+ automatically select the sync version::
from sqlalchemy import create_engine
- sync_engine = create_engine("oracle+oracledb://scott:tiger@localhost/?service_name=XEPDB1")
+ sync_engine = create_engine("oracle+oracledb://scott:tiger@localhost?service_name=FREEPDB1")
-* calling :func:`_asyncio.create_async_engine` with
- ``oracle+oracledb://...`` will automatically select the async version,
- e.g.::
+* calling :func:`_asyncio.create_async_engine` with ``oracle+oracledb://...``
+ will automatically select the async version::
from sqlalchemy.ext.asyncio import create_async_engine
- asyncio_engine = create_async_engine("oracle+oracledb://scott:tiger@localhost/?service_name=XEPDB1")
+ asyncio_engine = create_async_engine("oracle+oracledb://scott:tiger@localhost?service_name=FREEPDB1")
-The asyncio version of the dialect may also be specified explicitly using the
-``oracledb_async`` suffix, as::
+ The asyncio version of the dialect may also be specified explicitly using the
+ ``oracledb_async`` suffix::
- from sqlalchemy.ext.asyncio import create_async_engine
- asyncio_engine = create_async_engine("oracle+oracledb_async://scott:tiger@localhost/?service_name=XEPDB1")
+ from sqlalchemy.ext.asyncio import create_async_engine
+ asyncio_engine = create_async_engine("oracle+oracledb_async://scott:tiger@localhost?service_name=FREEPDB1")
.. versionadded:: 2.0.25 added support for the async version of oracledb.
Thick mode support
------------------
-By default the ``python-oracledb`` is started in thin mode, that does not
-require oracle client libraries to be installed in the system. The
-``python-oracledb`` driver also support a "thick" mode, that behaves
-similarly to ``cx_oracle`` and requires that Oracle Client Interface (OCI)
-is installed.
+By default, the python-oracledb driver runs in a "thin" mode that does not
+require Oracle Client libraries to be installed. The driver also supports a
+"thick" mode that uses Oracle Client libraries to get functionality such as
+Oracle Application Continuity.
-To enable this mode, the user may call ``oracledb.init_oracle_client``
-manually, or by passing the parameter ``thick_mode=True`` to
-:func:`_sa.create_engine`. To pass custom arguments to ``init_oracle_client``,
-like the ``lib_dir`` path, a dict may be passed to this parameter, as in::
+To enable thick mode, call `oracledb.init_oracle_client()
+<https://python-oracledb.readthedocs.io/en/latest/api_manual/module.html#oracledb.init_oracle_client>`_
+explicitly, or pass the parameter ``thick_mode=True`` to
+:func:`_sa.create_engine`. To pass custom arguments to
+``init_oracle_client()``, like the ``lib_dir`` path, a dict may be passed, for
+example::
engine = sa.create_engine("oracle+oracledb://...", thick_mode={
- "lib_dir": "/path/to/oracle/client/lib", "driver_name": "my-app"
+ "lib_dir": "/path/to/oracle/client/lib",
+ "config_dir": "/path/to/network_config_file_directory",
+ "driver_name": "my-app : 1.0.0"
})
+Note that passing a ``lib_dir`` path should only be done on macOS or
+Windows. On Linux it does not behave as you might expect.
+
.. seealso::
- https://python-oracledb.readthedocs.io/en/latest/api_manual/module.html#oracledb.init_oracle_client
+ python-oracledb documentation `Enabling python-oracledb Thick mode
+ <https://python-oracledb.readthedocs.io/en/latest/user_guide/initialization.html#enabling-python-oracledb-thick-mode>`_
+
+Connecting to Oracle Database
+-----------------------------
+
+python-oracledb provides several methods of indicating the target database.
+The dialect translates from a series of different URL forms.
+
+Given the hostname, port and service name of the target database, you can
+connect in SQLAlchemy using the ``service_name`` query string parameter::
+
+ engine = create_engine("oracle+oracledb://scott:tiger@hostname:port?service_name=myservice")
+
+Connecting with Easy Connect strings
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+You can pass any valid python-oracledb connection string as the ``dsn`` key
+value in a :paramref:`_sa.create_engine.connect_args` dictionary. See
+python-oracledb documentation `Oracle Net Services Connection Strings
+<https://python-oracledb.readthedocs.io/en/latest/user_guide/connection_handling.html#oracle-net-services-connection-strings>`_.
+
+For example to use an `Easy Connect string
+<https://download.oracle.com/ocomdocs/global/Oracle-Net-Easy-Connect-Plus.pdf>`_
+with a timeout to prevent connection establishment from hanging if the network
+transport to the database cannot be establishd in 30 seconds, and also setting
+a keep-alive time of 60 seconds to stop idle network connections from being
+terminated by a firewall::
+
+ e = create_engine(
+ "oracle+oracledb://@",
+ connect_args={
+ "user": "scott",
+ "password": "tiger",
+ "dsn": "hostname:port/myservice?transport_connect_timeout=30&expire_time=60"
+ }
+ )
+
+The Easy Connect syntax has been enhanced during the life of Oracle Database.
+Review the documentation for your database version. The current documentation
+is at `Understanding the Easy Connect Naming Method
+<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-B0437826-43C1-49EC-A94D-B650B6A4A6EE>`_.
+
+The general syntax is similar to::
+
+ [[protocol:]//]host[:port][/[service_name]][?parameter_name=value{¶meter_name=value}]
+
+Note that although the SQLAlchemy URL syntax ``hostname:port/dbname`` looks
+like Oracle's Easy Connect syntax, it is different. SQLAlchemy's URL requires a
+system identifier (SID) for the ``dbname`` component::
+
+ engine = create_engine("oracle+oracledb://scott:tiger@hostname:port/sid")
+
+Easy Connect syntax does not support SIDs. It uses services names, which are
+the preferred choice for connecting to Oracle Database.
+
+Passing python-oracledb connect arguments
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Other python-oracledb driver `connection options
+<https://python-oracledb.readthedocs.io/en/latest/api_manual/module.html#oracledb.connect>`_
+can be passed in ``connect_args``. For example::
+
+ e = create_engine(
+ "oracle+oracledb://@",
+ connect_args={
+ "user": "scott",
+ "password": "tiger",
+ "dsn": "hostname:port/myservice",
+ "events": True,
+ "mode": oracledb.AUTH_MODE_SYSDBA
+ }
+ )
+
+Connecting with tnsnames.ora TNS aliases
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+If no port, database name, or service name is provided, the dialect will use an
+Oracle Database DSN "connection string". This takes the "hostname" portion of
+the URL as the data source name. For example, if the ``tnsnames.ora`` file
+contains a `TNS Alias
+<https://python-oracledb.readthedocs.io/en/latest/user_guide/connection_handling.html#tns-aliases-for-connection-strings>`_
+of ``myalias`` as below::
+
+ myalias =
+ (DESCRIPTION =
+ (ADDRESS = (PROTOCOL = TCP)(HOST = mymachine.example.com)(PORT = 1521))
+ (CONNECT_DATA =
+ (SERVER = DEDICATED)
+ (SERVICE_NAME = orclpdb1)
+ )
+ )
+
+The python-oracledb dialect connects to this database service when ``myalias`` is the
+hostname portion of the URL, without specifying a port, database name or
+``service_name``::
+
+ engine = create_engine("oracle+oracledb://scott:tiger@myalias")
+
+Connecting to Oracle Autonomous Database
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Users of Oracle Autonomous Database should use either use the TNS Alias URL
+shown above, or pass the TNS Alias as the ``dsn`` key value in a
+:paramref:`_sa.create_engine.connect_args` dictionary.
+
+If Oracle Autonomous Database is configured for mutual TLS ("mTLS")
+connections, then additional configuration is required as shown in `Connecting
+to Oracle Cloud Autonomous Databases
+<https://python-oracledb.readthedocs.io/en/latest/user_guide/connection_handling.html#connecting-to-oracle-cloud-autonomous-databases>`_. In
+summary, Thick mode users should configure file locations and set the wallet
+path in ``sqlnet.ora`` appropriately::
+
+ e = create_engine(
+ "oracle+oracledb://@",
+ thick_mode={
+ # directory containing tnsnames.ora and cwallet.so
+ "config_dir": "/opt/oracle/wallet_dir",
+ },
+ connect_args={
+ "user": "scott",
+ "password": "tiger",
+ "dsn": "mydb_high"
+ }
+ )
+
+Thin mode users of mTLS should pass the appropriate directories and PEM wallet
+password when creating the engine, similar to::
+
+ e = create_engine(
+ "oracle+oracledb://@",
+ connect_args={
+ "user": "scott",
+ "password": "tiger",
+ "dsn": "mydb_high",
+ "config_dir": "/opt/oracle/wallet_dir", # directory containing tnsnames.ora
+ "wallet_location": "/opt/oracle/wallet_dir", # directory containing ewallet.pem
+ "wallet_password": "top secret" # password for the PEM file
+ }
+ )
+
+Typically ``config_dir`` and ``wallet_location`` are the same directory, which
+is where the Oracle Autonomous Database wallet zip file was extracted. Note
+this directory should be protected.
+
+Connection Pooling
+------------------
+
+Applications with multiple concurrent users should use connection pooling. A
+minimal sized connection pool is also beneficial for long-running, single-user
+applications that do not frequently use a connection.
+
+The python-oracledb driver provides its own connection pool implementation that
+may be used in place of SQLAlchemy's pooling functionality. The driver pool
+gives support for high availability features such as dead connection detection,
+connection draining for planned database downtime, support for Oracle
+Application Continuity and Transparent Application Continuity, and gives
+support for `Database Resident Connection Pooling (DRCP)
+<https://python-oracledb.readthedocs.io/en/latest/user_guide/connection_handling.html#database-resident-connection-pooling-drcp>`_.
+
+To take advantage of python-oracledb's pool, use the
+:paramref:`_sa.create_engine.creator` parameter to provide a function that
+returns a new connection, along with setting
+:paramref:`_sa.create_engine.pool_class` to ``NullPool`` to disable
+SQLAlchemy's pooling::
+
+ import oracledb
+ from sqlalchemy import create_engine
+ from sqlalchemy import text
+ from sqlalchemy.pool import NullPool
+
+ # Uncomment to use the optional python-oracledb Thick mode.
+ # Review the python-oracledb doc for the appropriate parameters
+ #oracledb.init_oracle_client(<your parameters>)
+
+ pool = oracledb.create_pool(user="scott", password="tiger", dsn="localhost:1521/freepdb1",
+ min=1, max=4, increment=1)
+ engine = create_engine("oracle+oracledb://", creator=pool.acquire, poolclass=NullPool)
+
+The above engine may then be used normally. Internally, python-oracledb handles
+connection pooling::
+
+ with engine.connect() as conn:
+ print(conn.scalar(text("select 1 from dual")))
+
+Refer to the python-oracledb documentation for `oracledb.create_pool()
+<https://python-oracledb.readthedocs.io/en/latest/api_manual/module.html#oracledb.create_pool>`_
+for the arguments that can be used when creating a connection pool.
+
+.. _drcp:
+
+Using Oracle Database Resident Connection Pooling (DRCP)
+--------------------------------------------------------
+
+When using Oracle Database's Database Resident Connection Pooling (DRCP), the
+best practice is to specify a connection class and "purity". Refer to the
+`python-oracledb documentation on DRCP
+<https://python-oracledb.readthedocs.io/en/latest/user_guide/connection_handling.html#database-resident-connection-pooling-drcp>`_.
+For example::
+
+ import oracledb
+ from sqlalchemy import create_engine
+ from sqlalchemy import text
+ from sqlalchemy.pool import NullPool
+
+ # Uncomment to use the optional python-oracledb Thick mode.
+ # Review the python-oracledb doc for the appropriate parameters
+ #oracledb.init_oracle_client(<your parameters>)
+
+ pool = oracledb.create_pool(user="scott", password="tiger", dsn="localhost:1521/freepdb1",
+ min=1, max=4, increment=1,
+ cclass="MYCLASS", purity=oracledb.PURITY_SELF)
+ engine = create_engine("oracle+oracledb://", creator=pool.acquire, poolclass=NullPool)
+
+The above engine may then be used normally where python-oracledb handles
+application connection pooling and Oracle Database additionally uses DRCP::
+
+ with engine.connect() as conn:
+ print(conn.scalar(text("select 1 from dual")))
+
+If you wish to use different connection classes or purities for different
+connections, then wrap ``pool.acquire()``::
+
+ import oracledb
+ from sqlalchemy import create_engine
+ from sqlalchemy import text
+ from sqlalchemy.pool import NullPool
+
+ # Uncomment to use python-oracledb Thick mode.
+ # Review the python-oracledb doc for the appropriate parameters
+ #oracledb.init_oracle_client(<your parameters>)
+
+ pool = oracledb.create_pool(user="scott", password="tiger", dsn="localhost:1521/freepdb1",
+ min=1, max=4, increment=1,
+ cclass="MYCLASS", purity=oracledb.PURITY_SELF)
+
+ def creator():
+ return pool.acquire(cclass="MYOTHERCLASS", purity=oracledb.PURITY_NEW)
+
+ engine = create_engine("oracle+oracledb://", creator=creator, poolclass=NullPool)
+
+Engine Options consumed by the SQLAlchemy oracledb dialect outside of the driver
+--------------------------------------------------------------------------------
+
+There are also options that are consumed by the SQLAlchemy oracledb dialect
+itself. These options are always passed directly to :func:`_sa.create_engine`,
+such as::
+
+ e = create_engine(
+ "oracle+oracledb://user:pass@tnsalias", arraysize=500)
+
+The parameters accepted by the oracledb dialect are as follows:
+
+* ``arraysize`` - set the driver cursor.arraysize value. It defaults to
+ ``None``, indicating that the driver default value of 100 should be used.
+ This setting controls how many rows are buffered when fetching rows, and can
+ have a significant effect on performance if increased for queries that return
+ large numbers of rows.
+
+ .. versionchanged:: 2.0.26 - changed the default value from 50 to None,
+ to use the default value of the driver itself.
+
+* ``auto_convert_lobs`` - defaults to True; See :ref:`oracledb_lob`.
+
+* ``coerce_to_decimal`` - see :ref:`oracledb_numeric` for detail.
+
+* ``encoding_errors`` - see :ref:`oracledb_unicode_encoding_errors` for detail.
-Two Phase Transactions Supported
---------------------------------
+.. _oracledb_unicode:
-Two phase transactions are fully supported under oracledb. Starting with
-oracledb 2.3 two phase transactions are supported also in thin mode. APIs
-for two phase transactions are provided at the Core level via
-:meth:`_engine.Connection.begin_twophase` and :paramref:`_orm.Session.twophase`
-for transparent ORM use.
+Unicode
+-------
+
+As is the case for all DBAPIs under Python 3, all strings are inherently
+Unicode strings.
+
+Ensuring the Correct Client Encoding
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+In python-oracledb, the encoding used for all character data is "UTF-8".
+
+Unicode-specific Column datatypes
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The Core expression language handles unicode data by use of the
+:class:`.Unicode` and :class:`.UnicodeText` datatypes. These types correspond
+to the VARCHAR2 and CLOB Oracle Database datatypes by default. When using
+these datatypes with Unicode data, it is expected that the database is
+configured with a Unicode-aware character set so that the VARCHAR2 and CLOB
+datatypes can accommodate the data.
+
+In the case that Oracle Database is not configured with a Unicode character
+set, the two options are to use the :class:`_types.NCHAR` and
+:class:`_oracle.NCLOB` datatypes explicitly, or to pass the flag
+``use_nchar_for_unicode=True`` to :func:`_sa.create_engine`, which will cause
+the SQLAlchemy dialect to use NCHAR/NCLOB for the :class:`.Unicode` /
+:class:`.UnicodeText` datatypes instead of VARCHAR/CLOB.
+
+.. versionchanged:: 1.3 The :class:`.Unicode` and :class:`.UnicodeText`
+ datatypes now correspond to the ``VARCHAR2`` and ``CLOB`` Oracle Database
+ datatypes unless the ``use_nchar_for_unicode=True`` is passed to the dialect
+ when :func:`_sa.create_engine` is called.
+
+
+.. _oracledb_unicode_encoding_errors:
+
+Encoding Errors
+^^^^^^^^^^^^^^^
+
+For the unusual case that data in Oracle Database is present with a broken
+encoding, the dialect accepts a parameter ``encoding_errors`` which will be
+passed to Unicode decoding functions in order to affect how decoding errors are
+handled. The value is ultimately consumed by the Python `decode
+<https://docs.python.org/3/library/stdtypes.html#bytes.decode>`_ function, and
+is passed both via python-oracledb's ``encodingErrors`` parameter consumed by
+``Cursor.var()``, as well as SQLAlchemy's own decoding function, as the
+python-oracledb dialect makes use of both under different circumstances.
+
+.. versionadded:: 1.3.11
+
+
+.. _oracledb_setinputsizes:
+
+Fine grained control over python-oracledb data binding with setinputsizes
+-------------------------------------------------------------------------
+
+The python-oracle DBAPI has a deep and fundamental reliance upon the usage of
+the DBAPI ``setinputsizes()`` call. The purpose of this call is to establish
+the datatypes that are bound to a SQL statement for Python values being passed
+as parameters. While virtually no other DBAPI assigns any use to the
+``setinputsizes()`` call, the python-oracledb DBAPI relies upon it heavily in
+its interactions with the Oracle Database, and in some scenarios it is not
+possible for SQLAlchemy to know exactly how data should be bound, as some
+settings can cause profoundly different performance characteristics, while
+altering the type coercion behavior at the same time.
+
+Users of the oracledb dialect are **strongly encouraged** to read through
+python-oracledb's list of built-in datatype symbols at `Database Types
+<https://python-oracledb.readthedocs.io/en/latest/api_manual/module.html#database-types>`_
+Note that in some cases, significant performance degradation can occur when
+using these types vs. not.
+
+On the SQLAlchemy side, the :meth:`.DialectEvents.do_setinputsizes` event can
+be used both for runtime visibility (e.g. logging) of the setinputsizes step as
+well as to fully control how ``setinputsizes()`` is used on a per-statement
+basis.
+
+.. versionadded:: 1.2.9 Added :meth:`.DialectEvents.setinputsizes`
+
+
+Example 1 - logging all setinputsizes calls
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The following example illustrates how to log the intermediary values from a
+SQLAlchemy perspective before they are converted to the raw ``setinputsizes()``
+parameter dictionary. The keys of the dictionary are :class:`.BindParameter`
+objects which have a ``.key`` and a ``.type`` attribute::
+
+ from sqlalchemy import create_engine, event
+
+ engine = create_engine("oracle+oracledb://scott:tiger@localhost:1521?service_name=freepdb1")
+
+ @event.listens_for(engine, "do_setinputsizes")
+ def _log_setinputsizes(inputsizes, cursor, statement, parameters, context):
+ for bindparam, dbapitype in inputsizes.items():
+ log.info(
+ "Bound parameter name: %s SQLAlchemy type: %r "
+ "DBAPI object: %s",
+ bindparam.key, bindparam.type, dbapitype)
+
+Example 2 - remove all bindings to CLOB
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+For performance, fetching LOB datatypes from Oracle Database is set by default
+for the ``Text`` type within SQLAlchemy. This setting can be modified as
+follows::
+
+
+ from sqlalchemy import create_engine, event
+ from oracledb import CLOB
+
+ engine = create_engine("oracle+oracledb://scott:tiger@localhost:1521?service_name=freepdb1")
+
+ @event.listens_for(engine, "do_setinputsizes")
+ def _remove_clob(inputsizes, cursor, statement, parameters, context):
+ for bindparam, dbapitype in list(inputsizes.items()):
+ if dbapitype is CLOB:
+ del inputsizes[bindparam]
+
+.. _oracledb_lob:
+
+LOB Datatypes
+--------------
+
+LOB datatypes refer to the "large object" datatypes such as CLOB, NCLOB and
+BLOB. Oracle Database can efficiently return these datatypes as a single
+buffer. SQLAlchemy makes use of type handlers to do this by default.
+
+To disable the use of the type handlers and deliver LOB objects as classic
+buffered objects with a ``read()`` method, the parameter
+``auto_convert_lobs=False`` may be passed to :func:`_sa.create_engine`.
+
+.. _oracledb_returning:
+
+RETURNING Support
+-----------------
+
+The oracledb dialect implements RETURNING using OUT parameters. The dialect
+supports RETURNING fully.
+
+Two Phase Transaction Support
+-----------------------------
+
+Two phase transactions are fully supported with python-oracledb. (Thin mode
+requires python-oracledb 2.3). APIs for two phase transactions are provided at
+the Core level via :meth:`_engine.Connection.begin_twophase` and
+:paramref:`_orm.Session.twophase` for transparent ORM use.
.. versionchanged:: 2.0.32 added support for two phase transactions
-.. versionadded:: 2.0.0 added support for oracledb driver.
+.. _oracledb_numeric:
+
+Precision Numerics
+------------------
+
+SQLAlchemy's numeric types can handle receiving and returning values as Python
+``Decimal`` objects or float objects. When a :class:`.Numeric` object, or a
+subclass such as :class:`.Float`, :class:`_oracle.DOUBLE_PRECISION` etc. is in
+use, the :paramref:`.Numeric.asdecimal` flag determines if values should be
+coerced to ``Decimal`` upon return, or returned as float objects. To make
+matters more complicated under Oracle Database, the ``NUMBER`` type can also
+represent integer values if the "scale" is zero, so the Oracle
+Database-specific :class:`_oracle.NUMBER` type takes this into account as well.
+
+The oracledb dialect makes extensive use of connection- and cursor-level
+"outputtypehandler" callables in order to coerce numeric values as requested.
+These callables are specific to the specific flavor of :class:`.Numeric` in
+use, as well as if no SQLAlchemy typing objects are present. There are
+observed scenarios where Oracle Database may send incomplete or ambiguous
+information about the numeric types being returned, such as a query where the
+numeric types are buried under multiple levels of subquery. The type handlers
+do their best to make the right decision in all cases, deferring to the
+underlying python-oracledb DBAPI for all those cases where the driver can make
+the best decision.
+
+When no typing objects are present, as when executing plain SQL strings, a
+default "outputtypehandler" is present which will generally return numeric
+values which specify precision and scale as Python ``Decimal`` objects. To
+disable this coercion to decimal for performance reasons, pass the flag
+``coerce_to_decimal=False`` to :func:`_sa.create_engine`::
+
+ engine = create_engine("oracle+oracledb://scott:tiger@tnsalias", coerce_to_decimal=False)
+
+The ``coerce_to_decimal`` flag only impacts the results of plain string
+SQL statements that are not otherwise associated with a :class:`.Numeric`
+SQLAlchemy type (or a subclass of such).
+
+.. versionchanged:: 1.2 The numeric handling system for the oracle dialects has
+ been reworked to take advantage of newer driver features as well as better
+ integration of outputtypehandlers.
+
+.. versionadded:: 2.0.0 added support for the python-oracledb driver.
""" # noqa
from __future__ import annotations
# cx_Oracle seems to occasionally leak open connections when a large
# suite it run, even if we confirm we have zero references to
# connection objects.
- # while there is a "kill session" command in Oracle,
+ # while there is a "kill session" command in Oracle Database,
# it unfortunately does not release the connection sufficiently.
_ora_drop_ignore(conn, ident)
_ora_drop_ignore(conn, "%s_ts1" % ident)
class FLOAT(sqltypes.FLOAT):
- """Oracle FLOAT.
+ """Oracle Database FLOAT.
This is the same as :class:`_sqltypes.FLOAT` except that
- an Oracle-specific :paramref:`_oracle.FLOAT.binary_precision`
+ an Oracle Database -specific :paramref:`_oracle.FLOAT.binary_precision`
parameter is accepted, and
the :paramref:`_sqltypes.Float.precision` parameter is not accepted.
- Oracle FLOAT types indicate precision in terms of "binary precision", which
- defaults to 126. For a REAL type, the value is 63. This parameter does not
- cleanly map to a specific number of decimal places but is roughly
- equivalent to the desired number of decimal places divided by 0.3103.
+ Oracle Database FLOAT types indicate precision in terms of "binary
+ precision", which defaults to 126. For a REAL type, the value is 63. This
+ parameter does not cleanly map to a specific number of decimal places but
+ is roughly equivalent to the desired number of decimal places divided by
+ 0.3103.
.. versionadded:: 2.0
r"""
Construct a FLOAT
- :param binary_precision: Oracle binary precision value to be rendered
- in DDL. This may be approximated to the number of decimal characters
- using the formula "decimal precision = 0.30103 * binary precision".
- The default value used by Oracle for FLOAT / DOUBLE PRECISION is 126.
+ :param binary_precision: Oracle Database binary precision value to be
+ rendered in DDL. This may be approximated to the number of decimal
+ characters using the formula "decimal precision = 0.30103 * binary
+ precision". The default value used by Oracle Database for FLOAT /
+ DOUBLE PRECISION is 126.
:param asdecimal: See :paramref:`_sqltypes.Float.asdecimal`
class DATE(_OracleDateLiteralRender, sqltypes.DateTime):
- """Provide the oracle DATE type.
+ """Provide the Oracle Database DATE type.
This type has no special Python behavior, except that it subclasses
- :class:`_types.DateTime`; this is to suit the fact that the Oracle
+ :class:`_types.DateTime`; this is to suit the fact that the Oracle Database
``DATE`` type supports a time value.
"""
class TIMESTAMP(sqltypes.TIMESTAMP):
- """Oracle implementation of ``TIMESTAMP``, which supports additional
- Oracle-specific modes
+ """Oracle Database implementation of ``TIMESTAMP``, which supports
+ additional Oracle Database-specific modes
.. versionadded:: 2.0
"""Construct a new :class:`_oracle.TIMESTAMP`.
:param timezone: boolean. Indicates that the TIMESTAMP type should
- use Oracle's ``TIMESTAMP WITH TIME ZONE`` datatype.
+ use Oracle Database's ``TIMESTAMP WITH TIME ZONE`` datatype.
:param local_timezone: boolean. Indicates that the TIMESTAMP type
- should use Oracle's ``TIMESTAMP WITH LOCAL TIME ZONE`` datatype.
+ should use Oracle Database's ``TIMESTAMP WITH LOCAL TIME ZONE``
+ datatype.
"""
class ROWID(sqltypes.TypeEngine):
- """Oracle ROWID type.
+ """Oracle Database ROWID type.
When used in a cast() or similar, generates ROWID.
:param stream_results: Available on: :class:`_engine.Connection`,
:class:`_sql.Executable`.
- Indicate to the dialect that results should be
- "streamed" and not pre-buffered, if possible. For backends
- such as PostgreSQL, MySQL and MariaDB, this indicates the use of
- a "server side cursor" as opposed to a client side cursor.
- Other backends such as that of Oracle may already use server
- side cursors by default.
+ Indicate to the dialect that results should be "streamed" and not
+ pre-buffered, if possible. For backends such as PostgreSQL, MySQL
+ and MariaDB, this indicates the use of a "server side cursor" as
+ opposed to a client side cursor. Other backends such as that of
+ Oracle Database may already use server side cursors by default.
The usage of
:paramref:`_engine.Connection.execution_options.stream_results` is
``cursor.description`` to set up the keys for the result set,
including the names of columns for the :class:`_engine.Row` object as
well as the dictionary keys when using :attr:`_engine.Row._mapping`.
- On backends that use "name normalization" such as Oracle to correct
- for lower case names being converted to all uppercase, this behavior
- is turned off and the raw UPPERCASE names in cursor.description will
- be present.
+ On backends that use "name normalization" such as Oracle Database to
+ correct for lower case names being converted to all uppercase, this
+ behavior is turned off and the raw UPPERCASE names in
+ cursor.description will be present.
.. versionadded:: 2.1
available if the dialect in use has opted into using the
"use_insertmanyvalues" feature. If they haven't opted into that, then
this attribute is False, unless the dialect in question overrides this
- and provides some other implementation (such as the Oracle dialect).
+ and provides some other implementation (such as the Oracle Database
+ dialects).
"""
return self.insert_returning and self.use_insertmanyvalues
If the dialect in use hasn't opted into that, then this attribute is
False, unless the dialect in question overrides this and provides some
- other implementation (such as the Oracle dialect).
+ other implementation (such as the Oracle Database dialects).
"""
return self.insert_returning and self.use_insertmanyvalues
style of ``setinputsizes()`` on the cursor, using DB-API types
from the bind parameter's ``TypeEngine`` objects.
- This method only called by those dialects which set
- the :attr:`.Dialect.bind_typing` attribute to
- :attr:`.BindTyping.SETINPUTSIZES`. cx_Oracle is the only DBAPI
- that requires setinputsizes(), pyodbc offers it as an option.
+ This method only called by those dialects which set the
+ :attr:`.Dialect.bind_typing` attribute to
+ :attr:`.BindTyping.SETINPUTSIZES`. Python-oracledb and cx_Oracle are
+ the only DBAPIs that requires setinputsizes(); pyodbc offers it as an
+ option.
Prior to SQLAlchemy 2.0, the setinputsizes() approach was also used
for pg8000 and asyncpg, which has been changed to inline rendering
The setinputsizes hook overall is only used for dialects which include
the flag ``use_setinputsizes=True``. Dialects which use this
- include cx_Oracle, pg8000, asyncpg, and pyodbc dialects.
+ include python-oracledb, cx_Oracle, pg8000, asyncpg, and pyodbc
+ dialects.
.. note::
"""Use the pep-249 setinputsizes method.
This is only implemented for DBAPIs that support this method and for which
- the SQLAlchemy dialect has the appropriate infrastructure for that
- dialect set up. Current dialects include cx_Oracle as well as
+ the SQLAlchemy dialect has the appropriate infrastructure for that dialect
+ set up. Current dialects include python-oracledb, cx_Oracle as well as
optional support for SQL Server using pyodbc.
When using setinputsizes, dialects also have a means of only using the
the statement multiple times for a series of batches when large numbers
of rows are given.
- The parameter is False for the default dialect, and is set to
- True for SQLAlchemy internal dialects SQLite, MySQL/MariaDB, PostgreSQL,
- SQL Server. It remains at False for Oracle, which provides native
- "executemany with RETURNING" support and also does not support
- ``supports_multivalues_insert``. For MySQL/MariaDB, those MySQL
- dialects that don't support RETURNING will not report
+ The parameter is False for the default dialect, and is set to True for
+ SQLAlchemy internal dialects SQLite, MySQL/MariaDB, PostgreSQL, SQL Server.
+ It remains at False for Oracle Database, which provides native "executemany
+ with RETURNING" support and also does not support
+ ``supports_multivalues_insert``. For MySQL/MariaDB, those MySQL dialects
+ that don't support RETURNING will not report
``insert_executemany_returning`` as True.
.. versionadded:: 2.0
established on a :class:`.Table` object which will be passed as
"reflection options" when using :paramref:`.Table.autoload_with`.
- Current example is "oracle_resolve_synonyms" in the Oracle dialect.
+ Current example is "oracle_resolve_synonyms" in the Oracle Database
+ dialects.
"""
r"""Return a list of temporary table names for the current bind.
This method is unsupported by most dialects; currently
- only Oracle, PostgreSQL and SQLite implements it.
+ only Oracle Database, PostgreSQL and SQLite implements it.
:param \**kw: Additional keyword argument to pass to the dialect
specific implementation. See the documentation of the dialect
given name was created.
This currently includes some options that apply to MySQL and Oracle
- tables.
+ Database tables.
:param table_name: string name of the table. For special quoting,
use :class:`.quoted_name`.
@compiles(coalesce, 'oracle')
def compile(element, compiler, **kw):
if len(element.clauses) > 2:
- raise TypeError("coalesce only supports two arguments on Oracle")
+ raise TypeError("coalesce only supports two arguments on "
+ "Oracle Database")
return "nvl(%s)" % compiler.process(element.clauses, **kw)
* :class:`.ExecutableDDLElement` - The root of all DDL expressions,
)
statement._label_style = self.label_style
- # Oracle however does not allow FOR UPDATE on the subquery,
- # and the Oracle dialect ignores it, plus for PostgreSQL, MySQL
- # we expect that all elements of the row are locked, so also put it
- # on the outside (except in the case of PG when OF is used)
+ # Oracle Database however does not allow FOR UPDATE on the subquery,
+ # and the Oracle Database dialects ignore it, plus for PostgreSQL,
+ # MySQL we expect that all elements of the row are locked, so also put
+ # it on the outside (except in the case of PG when OF is used)
if (
self._for_update_arg is not None
and self._for_update_arg.of is None
:param quote:
True if this parameter name requires quoting and is not
currently known as a SQLAlchemy reserved word; this currently
- only applies to the Oracle backend, where bound names must
+ only applies to the Oracle Database backends, where bound names must
sometimes be quoted.
:param isoutparam:
if True, the parameter should be treated like a stored procedure
- "OUT" parameter. This applies to backends such as Oracle which
+ "OUT" parameter. This applies to backends such as Oracle Database which
support OUT parameters.
:param expanding:
"""Called when a SELECT statement has no froms, and no FROM clause is
to be appended.
- Gives Oracle a chance to tack on a ``FROM DUAL`` to the string output.
+ Gives Oracle Database a chance to tack on a ``FROM DUAL`` to the string
+ output.
"""
return ""
``rank()``, ``dense_rank()``, etc.
It's supported only by certain database backends, such as PostgreSQL,
- Oracle and MS SQL Server.
+ Oracle Database and MS SQL Server.
The :class:`.WithinGroup` construct extracts its type from the
method :meth:`.FunctionElement.within_group_type`. If this returns
A :class:`.quoted_name` object with ``quote=True`` is also
prevented from being modified in the case of a so-called
"name normalize" option. Certain database backends, such as
- Oracle, Firebird, and DB2 "normalize" case-insensitive names
+ Oracle Database, Firebird, and DB2 "normalize" case-insensitive names
as uppercase. The SQLAlchemy dialects for these backends
convert from SQLAlchemy's lower-case-means-insensitive convention
to the upper-case-means-insensitive conventions of those backends.
from sqlalchemy import inspect
from sqlalchemy.sql import quoted_name
- engine = create_engine("oracle+cx_oracle://some_dsn")
+ engine = create_engine("oracle+oracledb://some_dsn")
print(inspect(engine).has_table(quoted_name("some_table", True)))
- The above logic will run the "has table" logic against the Oracle backend,
- passing the name exactly as ``"some_table"`` without converting to
+ The above logic will run the "has table" logic against the Oracle Database
+ backend, passing the name exactly as ``"some_table"`` without converting to
upper case.
.. versionchanged:: 1.2 The :class:`.quoted_name` construct is now
:class:`_mysql.match` - MySQL specific construct with
additional features.
- * Oracle - renders ``CONTAINS(x, y)``
+ * Oracle Database - renders ``CONTAINS(x, y)``
* other backends may provide special implementations.
* Backends without any special implementation will emit
the operator as "MATCH". This is compatible with SQLite, for
Examples include:
* PostgreSQL - renders ``x ~ y`` or ``x !~ y`` when negated.
- * Oracle - renders ``REGEXP_LIKE(x, y)``
+ * Oracle Database - renders ``REGEXP_LIKE(x, y)``
* SQLite - uses SQLite's ``REGEXP`` placeholder operator and calls into
the Python ``re.match()`` builtin.
* other backends may provide special implementations.
the operator as "REGEXP" or "NOT REGEXP". This is compatible with
SQLite and MySQL, for example.
- Regular expression support is currently implemented for Oracle,
- PostgreSQL, MySQL and MariaDB. Partial support is available for
- SQLite. Support among third-party dialects may vary.
+ Regular expression support is currently implemented for Oracle
+ Database, PostgreSQL, MySQL and MariaDB. Partial support is available
+ for SQLite. Support among third-party dialects may vary.
:param pattern: The regular expression pattern string or column
clause.
**not backend agnostic**.
Regular expression replacement support is currently implemented for
- Oracle, PostgreSQL, MySQL 8 or greater and MariaDB. Support among
- third-party dialects may vary.
+ Oracle Database, PostgreSQL, MySQL 8 or greater and MariaDB. Support
+ among third-party dialects may vary.
:param pattern: The regular expression pattern string or column
clause.
unless they are a reserved word. Names with any number of upper
case characters will be quoted and sent exactly. Note that this
behavior applies even for databases which standardize upper
- case names as case insensitive such as Oracle.
+ case names as case insensitive such as Oracle Database.
The name field may be omitted at construction time and applied
later, at any time before the Column is associated with a
will imply that database-specific keywords such as PostgreSQL
``SERIAL``, MySQL ``AUTO_INCREMENT``, or ``IDENTITY`` on SQL Server
should also be rendered. Not every database backend has an
- "implied" default generator available; for example the Oracle
- backend always needs an explicit construct such as
+ "implied" default generator available; for example the Oracle Database
+ backends alway needs an explicit construct such as
:class:`.Identity` to be included with a :class:`.Column` in order
for the DDL rendered to include auto-generating constructs to also
be produced in the database.
is not included as this is unnecessary and not recommended
by the database vendor. See the section
:ref:`sqlite_autoincrement` for more background.
- * Oracle - The Oracle dialect has no default "autoincrement"
+ * Oracle Database - The Oracle Database dialects have no default "autoincrement"
feature available at this time, instead the :class:`.Identity`
construct is recommended to achieve this (the :class:`.Sequence`
construct may also be used).
(see
`https://www.python.org/dev/peps/pep-0249/#lastrowid
<https://www.python.org/dev/peps/pep-0249/#lastrowid>`_)
- * PostgreSQL, SQL Server, Oracle - use RETURNING or an equivalent
+ * PostgreSQL, SQL Server, Oracle Database - use RETURNING or an equivalent
construct when rendering an INSERT statement, and then retrieving
the newly generated primary key values after execution
- * PostgreSQL, Oracle for :class:`_schema.Table` objects that
+ * PostgreSQL, Oracle Database for :class:`_schema.Table` objects that
set :paramref:`_schema.Table.implicit_returning` to False -
for a :class:`.Sequence` only, the :class:`.Sequence` is invoked
explicitly before the INSERT statement takes place so that the
@util.deprecated_params(
order=(
"2.1",
- "This parameter is supported only by Oracle, "
+ "This parameter is supported only by Oracle Database, "
"use ``oracle_order`` instead.",
)
)
:param cache: optional integer value; number of future values in the
sequence which are calculated in advance. Renders the CACHE keyword
- understood by Oracle and PostgreSQL.
+ understood by Oracle Database and PostgreSQL.
:param order: optional boolean value; if ``True``, renders the
- ORDER keyword, understood by Oracle, indicating the sequence is
- definitively ordered. May be necessary to provide deterministic
+ ORDER keyword, understood by Oracle Database, indicating the sequence
+ is definitively ordered. May be necessary to provide deterministic
ordering using Oracle RAC.
:param data_type: The type to be returned by the sequence, for
@util.deprecated_params(
order=(
"2.1",
- "This parameter is supported only by Oracle, "
+ "This parameter is supported only by Oracle Database, "
"use ``oracle_order`` instead.",
),
on_null=(
"2.1",
- "This parameter is supported only by Oracle, "
+ "This parameter is supported only by Oracle Database, "
"use ``oracle_on_null`` instead.",
),
)
:param on_null:
Set to ``True`` to specify ON NULL in conjunction with a
``always=False`` identity column. This option is only supported on
- some backends, like Oracle.
+ some backends, like Oracle Database.
:param start: the starting index of the sequence.
:param increment: the increment value of the sequence.
:meth:`_expression.Select.prefix_with` - generic SELECT prefixing
which also can suit some database-specific HINT syntaxes such as
- MySQL or Oracle optimizer hints
+ MySQL or Oracle Database optimizer hints
"""
return self._with_hint(None, text, dialect_name)
**specific to a single table** to a statement, in a location that
is **dialect-specific**. To add generic optimizer hints to the
**beginning** of a statement ahead of the SELECT keyword such as
- for MySQL or Oracle, use the :meth:`_expression.Select.prefix_with`
- method. To add optimizer hints to the **end** of a statement such
- as for PostgreSQL, use the
+ for MySQL or Oracle Database, use the
+ :meth:`_expression.Select.prefix_with` method. To add optimizer
+ hints to the **end** of a statement such as for PostgreSQL, use the
:meth:`_expression.Select.with_statement_hint` method.
The text of the hint is rendered in the appropriate
``selectable`` argument. The dialect implementation
typically uses Python string substitution syntax
with the token ``%(name)s`` to render the name of
- the table or alias. E.g. when using Oracle, the
+ the table or alias. E.g. when using Oracle Database, the
following::
select(mytable).\
The ``dialect_name`` option will limit the rendering of a particular
hint to a particular backend. Such as, to add hints for both Oracle
- and Sybase simultaneously::
+ Database and Sybase simultaneously::
select(mytable).\
with_hint(mytable, "index(%(name)s ix_mytable)", 'oracle').\
:meth:`_expression.Select.prefix_with` - generic SELECT prefixing
which also can suit some database-specific HINT syntaxes such as
- MySQL or Oracle optimizer hints
+ MySQL or Oracle Database optimizer hints
"""
A :class:`_sql.TableValuedColumn` is a :class:`_sql.ColumnElement` that
represents a complete row in a table. Support for this construct is
backend dependent, and is supported in various forms by backends
- such as PostgreSQL, Oracle and SQL Server.
+ such as PostgreSQL, Oracle Database and SQL Server.
E.g.:
Represents an alias, as typically applied to any table or
sub-select within a SQL statement using the ``AS`` keyword (or
- without the keyword on certain databases such as Oracle).
+ without the keyword on certain databases such as Oracle Database).
This object is constructed from the :func:`_expression.alias` module
level function as well as the :meth:`_expression.FromClause.alias`
stmt = select(table).with_for_update(nowait=True)
- On a database like PostgreSQL or Oracle, the above would render a
- statement like::
+ On a database like PostgreSQL or Oracle Database, the above would
+ render a statement like::
SELECT table.a, table.b FROM table FOR UPDATE NOWAIT
variants.
:param nowait: boolean; will render ``FOR UPDATE NOWAIT`` on Oracle
- and PostgreSQL dialects.
+ Database and PostgreSQL dialects.
:param read: boolean; will render ``LOCK IN SHARE MODE`` on MySQL,
``FOR SHARE`` on PostgreSQL. On PostgreSQL, when combined with
:param of: SQL expression or list of SQL expression elements,
(typically :class:`_schema.Column` objects or a compatible expression,
for some backends may also be a table expression) which will render
- into a ``FOR UPDATE OF`` clause; supported by PostgreSQL, Oracle, some
- MySQL versions and possibly others. May render as a table or as a
- column depending on backend.
+ into a ``FOR UPDATE OF`` clause; supported by PostgreSQL, Oracle
+ Database, some MySQL versions and possibly others. May render as a
+ table or as a column depending on backend.
- :param skip_locked: boolean, will render ``FOR UPDATE SKIP LOCKED``
- on Oracle and PostgreSQL dialects or ``FOR SHARE SKIP LOCKED`` if
- ``read=True`` is also specified.
+ :param skip_locked: boolean, will render ``FOR UPDATE SKIP LOCKED`` on
+ Oracle Database and PostgreSQL dialects or ``FOR SHARE SKIP LOCKED``
+ if ``read=True`` is also specified.
:param key_share: boolean, will render ``FOR NO KEY UPDATE``,
or if combined with ``read=True`` will render ``FOR KEY SHARE``,
"""Return a new selectable with the given FETCH FIRST criterion
applied.
- This is a numeric value which usually renders as
- ``FETCH {FIRST | NEXT} [ count ] {ROW | ROWS} {ONLY | WITH TIES}``
- expression in the resulting select. This functionality is
- is currently implemented for Oracle, PostgreSQL, MSSQL.
+ This is a numeric value which usually renders as ``FETCH {FIRST | NEXT}
+ [ count ] {ROW | ROWS} {ONLY | WITH TIES}`` expression in the resulting
+ select. This functionality is is currently implemented for Oracle
+ Database, PostgreSQL, MSSQL.
Use :meth:`_sql.GenerativeSelect.offset` to specify the offset.
The :class:`.Unicode` type is a :class:`.String` subclass that assumes
input and output strings that may contain non-ASCII characters, and for
some backends implies an underlying column type that is explicitly
- supporting of non-ASCII data, such as ``NVARCHAR`` on Oracle and SQL
- Server. This will impact the output of ``CREATE TABLE`` statements and
+ supporting of non-ASCII data, such as ``NVARCHAR`` on Oracle Database and
+ SQL Server. This will impact the output of ``CREATE TABLE`` statements and
``CAST`` functions at the dialect level.
The character encoding used by the :class:`.Unicode` type that is used to
:meth:`.DialectEvents.do_setinputsizes`
-
"""
__visit_name__ = "unicode"
indicates a number of digits for the generic
:class:`_sqltypes.Float` datatype.
- .. note:: For the Oracle backend, the
+ .. note:: For the Oracle Database backend, the
:paramref:`_sqltypes.Float.precision` parameter is not accepted
- when rendering DDL, as Oracle does not support float precision
+ when rendering DDL, as Oracle Database does not support float precision
specified as a number of decimal places. Instead, use the
- Oracle-specific :class:`_oracle.FLOAT` datatype and specify the
+ Oracle Database-specific :class:`_oracle.FLOAT` datatype and specify the
:paramref:`_oracle.FLOAT.binary_precision` parameter. This is new
in version 2.0 of SQLAlchemy.
To create a database agnostic :class:`_types.Float` that
- separately specifies binary precision for Oracle, use
+ separately specifies binary precision for Oracle Database, use
:meth:`_types.TypeEngine.with_variant` as follows::
from sqlalchemy import Column
to make use of the :class:`_types.TIMESTAMP` datatype directly when
using this flag, as some databases include separate generic
date/time-holding types distinct from the timezone-capable
- TIMESTAMP datatype, such as Oracle.
+ TIMESTAMP datatype, such as Oracle Database.
"""
class Interval(Emulated, _AbstractInterval, TypeDecorator[dt.timedelta]):
"""A type for ``datetime.timedelta()`` objects.
- The Interval type deals with ``datetime.timedelta`` objects. In
- PostgreSQL and Oracle, the native ``INTERVAL`` type is used; for others,
- the value is stored as a date which is relative to the "epoch"
- (Jan. 1, 1970).
+ The Interval type deals with ``datetime.timedelta`` objects. In PostgreSQL
+ and Oracle Database, the native ``INTERVAL`` type is used; for others, the
+ value is stored as a date which is relative to the "epoch" (Jan. 1, 1970).
Note that the ``Interval`` type does not currently provide date arithmetic
operations on platforms which do not support interval types natively. Such
:param native: when True, use the actual
INTERVAL type provided by the database, if
- supported (currently PostgreSQL, Oracle).
+ supported (currently PostgreSQL, Oracle Database).
Otherwise, represent the interval data as
an epoch value regardless.
:param second_precision: For native interval types
which support a "fractional seconds precision" parameter,
- i.e. Oracle and PostgreSQL
+ i.e. Oracle Database and PostgreSQL
:param day_precision: for native interval types which
- support a "day precision" parameter, i.e. Oracle.
+ support a "day precision" parameter, i.e. Oracle Database.
"""
super().__init__()
class TIMESTAMP(DateTime):
"""The SQL TIMESTAMP type.
- :class:`_types.TIMESTAMP` datatypes have support for timezone
- storage on some backends, such as PostgreSQL and Oracle. Use the
+ :class:`_types.TIMESTAMP` datatypes have support for timezone storage on
+ some backends, such as PostgreSQL and Oracle Database. Use the
:paramref:`~types.TIMESTAMP.timezone` argument in order to enable
"TIMESTAMP WITH TIMEZONE" for these backends.
class CLOB(Text):
"""The CLOB type.
- This type is found in Oracle and Informix.
+ This type is found in Oracle Database and Informix.
"""
__visit_name__ = "CLOB"
-"""Drop Oracle, SQL Server databases that are left over from a
+"""Drop Oracle Database, SQL Server databases that are left over from a
multiprocessing test run.
Currently the cx_Oracle driver seems to sometimes not release a
def _get_version(conn):
# this is the suggested way of finding the mode, from
- # https://python-oracledb.readthedocs.io/en/latest/user_guide/tracing.html#vsessconinfo
+ # https://python-oracledb.readthedocs.io/en/latest/user_guide/tracing.html#finding-the-python-oracledb-mode
sql = (
"SELECT UNIQUE CLIENT_DRIVER "
"FROM V$SESSION_CONNECT_INFO "
def test_use_binds_for_limits_disabled_one_legacy(self):
t = table("sometable", column("col1"), column("col2"))
with testing.expect_deprecated(
- "The ``use_binds_for_limits`` Oracle dialect parameter is "
- "deprecated."
+ "The ``use_binds_for_limits`` Oracle Database dialect parameter "
+ "is deprecated."
):
dialect = oracle.OracleDialect(
use_binds_for_limits=False, enable_offset_fetch=False
def test_use_binds_for_limits_disabled_two_legacy(self):
t = table("sometable", column("col1"), column("col2"))
with testing.expect_deprecated(
- "The ``use_binds_for_limits`` Oracle dialect parameter is "
- "deprecated."
+ "The ``use_binds_for_limits`` Oracle Database dialect parameter "
+ "is deprecated."
):
dialect = oracle.OracleDialect(
use_binds_for_limits=False, enable_offset_fetch=False
def test_use_binds_for_limits_disabled_three_legacy(self):
t = table("sometable", column("col1"), column("col2"))
with testing.expect_deprecated(
- "The ``use_binds_for_limits`` Oracle dialect parameter is "
- "deprecated."
+ "The ``use_binds_for_limits`` Oracle Database dialect parameter "
+ "is deprecated."
):
dialect = oracle.OracleDialect(
use_binds_for_limits=False, enable_offset_fetch=False
def test_use_binds_for_limits_enabled_one_legacy(self):
t = table("sometable", column("col1"), column("col2"))
with testing.expect_deprecated(
- "The ``use_binds_for_limits`` Oracle dialect parameter is "
- "deprecated."
+ "The ``use_binds_for_limits`` Oracle Database dialect parameter "
+ "is deprecated."
):
dialect = oracle.OracleDialect(
use_binds_for_limits=True, enable_offset_fetch=False
def test_use_binds_for_limits_enabled_two_legacy(self):
t = table("sometable", column("col1"), column("col2"))
with testing.expect_deprecated(
- "The ``use_binds_for_limits`` Oracle dialect parameter is "
- "deprecated."
+ "The ``use_binds_for_limits`` Oracle Database dialect parameter "
+ "is deprecated."
):
dialect = oracle.OracleDialect(
use_binds_for_limits=True, enable_offset_fetch=False
def test_use_binds_for_limits_enabled_three_legacy(self):
t = table("sometable", column("col1"), column("col2"))
with testing.expect_deprecated(
- "The ``use_binds_for_limits`` Oracle dialect parameter is "
- "deprecated."
+ "The ``use_binds_for_limits`` Oracle Database dialect parameter "
+ "is deprecated."
):
dialect = oracle.OracleDialect(
use_binds_for_limits=True, enable_offset_fetch=False
)
with testing.expect_warnings(
- "Computed columns don't work with Oracle UPDATE"
+ "Computed columns don't work with Oracle Database UPDATE"
):
self.assert_compile(
t1.update().values(id=1, foo=5).returning(t1.c.bar),
)
assert_raises_message(
exc.CompileError,
- r".*Oracle computed columns do not support 'stored' ",
+ r".*Oracle Database computed columns do not support 'stored' ",
schema.CreateTable(t).compile,
dialect=oracle.dialect(),
)
eq_(result.returned_defaults, (52,))
else:
with testing.expect_warnings(
- "Computed columns don't work with Oracle UPDATE"
+ "Computed columns don't work with Oracle Database UPDATE"
):
result = conn.execute(
test.update().values(foo=10).return_defaults()
exc.InvalidRequestError,
r"Using explicit outparam\(\) objects with "
r"UpdateBase.returning\(\) in the same Core DML statement "
- "is not supported in the Oracle dialect.",
+ "is not supported in the Oracle Database dialects.",
):
connection.execute(stmt)
def test_no_decimal_float_precision(self):
with expect_raises_message(
exc.ArgumentError,
- "Oracle FLOAT types use 'binary precision', which does not "
- "convert cleanly from decimal 'precision'. Please specify this "
- "type with a separate Oracle variant, such as "
+ "Oracle Database FLOAT types use 'binary precision', which does "
+ "not convert cleanly from decimal 'precision'. Please specify "
+ "this type with a separate Oracle Database variant, such as "
r"FLOAT\(precision=5\).with_variant\(oracle.FLOAT\("
r"binary_precision=16\), 'oracle'\), so that the Oracle "
- "specific 'binary_precision' may be specified accurately.",
+ "Database specific 'binary_precision' may be specified "
+ "accurately.",
):
FLOAT(5).compile(dialect=oracle.dialect())
)
def test_numerics_broken_inspection(self, metadata, connection):
- """Numeric scenarios where Oracle type info is 'broken',
+ """Numeric scenarios where Oracle Databasee type info is 'broken',
returning us precision, scale of the form (0, 0) or (0, -127).
We convert to Decimal and let int()/float() processors take over.