Documentation updates, including changes for PEP 8 compliance, to take

into account the fact that the default branch has changed to main, etc.
This commit is contained in:
Anthony Tuininga 2021-05-18 16:53:31 -06:00
parent 97be497fc9
commit 4ed562c205
33 changed files with 742 additions and 575 deletions

View File

@ -39,7 +39,7 @@ See [/test][11].
## Contributing
See [CONTRIBUTING](https://github.com/oracle/python-cx_Oracle/blob/master/CONTRIBUTING.md)
See [CONTRIBUTING](https://github.com/oracle/python-cx_Oracle/blob/main/CONTRIBUTING.md)
## License
@ -47,13 +47,13 @@ cx_Oracle is licensed under a BSD license which you can find [here][3].
[1]: https://www.python.org/dev/peps/pep-0249
[2]: http://cx-oracle.readthedocs.io
[3]: https://github.com/oracle/python-cx_Oracle/blob/master/LICENSE.txt
[3]: https://github.com/oracle/python-cx_Oracle/blob/main/LICENSE.txt
[5]: http://lists.sourceforge.net/lists/listinfo/cx-oracle-users
[6]: https://github.com/oracle/python-cx_Oracle/tree/master/samples/tutorial
[6]: https://github.com/oracle/python-cx_Oracle/tree/main/samples/tutorial
[7]: http://cx-oracletools.sourceforge.net
[8]: http://cx-pyoraclelib.sourceforge.net
[9]: https://github.com/oracle/python-cx_Oracle/issues
[11]: https://github.com/oracle/python-cx_Oracle/tree/master/test
[12]: https://github.com/oracle/python-cx_Oracle/tree/master/samples
[11]: https://github.com/oracle/python-cx_Oracle/tree/main/test
[12]: https://github.com/oracle/python-cx_Oracle/tree/main/samples
[14]: https://cx-oracle.readthedocs.io/en/latest/release_notes.html
[15]: https://cx-oracle.readthedocs.io/en/latest/user_guide/installation.html

View File

@ -74,13 +74,18 @@ Connection Object
that a single round-trip to the database may take before a timeout will
occur. A value of 0 means that no timeout will take place.
If a timeout occurs, the error *DPI-1067* will be returned if the
connection is still usable. Alternatively the error *DPI-1080* will be
returned if the connection has become invalid and can no longer be used.
.. versionadded:: 7.0
.. versionchanged:: 8.2
For consistency and compliance with the PEP 8 naming style, the
attribute `callTimeout` was renamed to `call_timeout`. The old name
will continue to work for a period of time.
will continue to work for a period of time. The error *DPI-1080* was
also introduced in this release.
.. note::

View File

@ -67,7 +67,7 @@ Cursor Object
Array variables can only be used for PL/SQL associative arrays with
contiguous keys. For PL/SQL associative arrays with sparsely populated keys
or for varrays and nested tables, the approach shown in this
`example <https://github.com/oracle/python-cx_Oracle/blob/master/
`example <https://github.com/oracle/python-cx_Oracle/blob/main/
samples/plsql_collection.py>`__ needs to be used.
.. note::

View File

@ -35,7 +35,7 @@ if applicable. The most recent deprecations are listed first.
* - Positional parameters to :meth:`cx_Oracle.connect()`
- Replace with keyword parameters in order to comply with the Python
database API.
* - positional parameters to :meth:`cx_Oracle.SessionPool()`
* - Positional parameters to :meth:`cx_Oracle.SessionPool()`
- Replace with keyword parameters in order to comply with the Python
database API.
* - `threaded` parameter to :meth:`cx_Oracle.SessionPool()`

View File

@ -97,7 +97,7 @@ Module Interface
See the :ref:`globalization <globalization>` section for details on the
encoding and nencoding parameters. Note the default encoding and nencoding
values changed to "UTF-8" in cx_Oracle 8, and any character set in NLS_LANG
is ignored.
is ignored. In a future release of cx_Oracle, only UTF-8 will be supported.
The edition parameter is expected to be a string if specified and sets the
edition to use for the session. It is only relevant if both the client and
@ -208,7 +208,7 @@ Module Interface
.. function:: SessionPool(user=None, password=None, dsn=None, min=1, max=2, \
increment=1, connectiontype=cx_Oracle.Connection, threaded=False, \
increment=1, connectiontype=cx_Oracle.Connection, threaded=True, \
getmode=cx_Oracle.SPOOL_ATTRVAL_NOWAIT, events=False, \
homogeneous=True, externalauth=False, encoding=None, nencoding=None, \
edition=None, timeout=0, wait_timeout=0, max_lifetime_session=0, \
@ -275,7 +275,8 @@ Module Interface
values transferred between cx_Oracle and Oracle Database, see
:ref:`Character Sets and Globalization <globalization>`. Note the default
encoding and nencoding values changed to "UTF-8" in cx_Oracle 8, and any
character set in NLS_LANG is ignored.
character set in NLS_LANG is ignored. In a future release of cx_Oracle,
only UTF-8 will be supported.
The edition parameter is expected to be a string, if specified, and sets the
edition to use for the sessions in the pool. It is only relevant if both the
@ -285,7 +286,9 @@ Module Interface
The timeout parameter is expected to be an integer, if specified, and sets
the length of time (in seconds) after which idle sessions in the pool are
terminated. Note that termination only occurs when the pool is accessed.
The default value of 0 means that no idle sessions are terminated.
The default value of 0 means that no idle sessions are terminated. The
initial pool timeout must be non-zero if you subsequently want to change
the timeout with :meth:`SessionPool.reconfigure()`.
The wait_timeout parameter is expected to be an integer, if specified, and
sets the length of time (in milliseconds) that the caller should wait for
@ -350,7 +353,8 @@ Module Interface
`session_callback` and the parameter `maxSessionsPerShard` was renamed
to `max_sessions_per_shard`. The old names will continue to work as
keyword parameters for a period of time. The `threaded` parameter value
is ignored and threading is always enabled.
is ignored and threading is always enabled; in previous versions the
default was False.
.. function:: Time(hour, minute, second)

View File

@ -71,6 +71,20 @@ SessionPool Object
connection has been established.
.. attribute:: SessionPool.getmode
This read-write attribute determines how connections are returned from the
pool. If :data:`~cx_Oracle.SPOOL_ATTRVAL_FORCEGET` is specified, a new
connection will be returned even if there are no free sessions in the pool.
:data:`~cx_Oracle.SPOOL_ATTRVAL_NOWAIT` will raise an exception if there
are no free sessions are available in the pool. If
:data:`~cx_Oracle.SPOOL_ATTRVAL_WAIT` is specified and there are no free
sessions in the pool, the caller will wait until a free session is
available. :data:`~cx_Oracle.SPOOL_ATTRVAL_TIMEDWAIT` uses the value of
:data:`~SessionPool.wait_timeout` to determine how long the caller should
wait for a session to become available before returning an error.
.. attribute:: SessionPool.homogeneous
This read-write boolean attribute indicates whether the pool is considered
@ -128,11 +142,11 @@ SessionPool Object
This read-write integer attribute specifies the pool ping interval in
seconds. When a connection is acquired from the pool, a check is first made
to see how long it has been since the connection was put into the pool. If
this idle time exceeds ``ping_interval``, then a :ref:`round-trip <roundtrips>`
ping to the database is performed. If the connection is unusable, it is
discarded and a different connection is selected to be returned by
:meth:`SessionPool.acquire()`. Setting ``ping_interval`` to a negative
value disables pinging. Setting it to 0 forces a ping for every
this idle time exceeds ``ping_interval``, then a :ref:`round-trip
<roundtrips>` ping to the database is performed. If the connection is
unusable, it is discarded and a different connection is selected to be
returned by :meth:`SessionPool.acquire()`. Setting ``ping_interval`` to a
negative value disables pinging. Setting it to 0 forces a ping for every
``aquire()`` and is not recommended.
Prior to cx_Oracle 8.2, the ping interval was fixed at 60 seconds.

View File

@ -256,9 +256,11 @@ SODA Collection Object
The hint parameter, if specified, supplies a hint to the database when
processing the SODA operation. This is expected to be a string in the same
format as SQL hints but without the enclosing comment characters. Use of
this parameter requires Oracle Client 21.3 or higher (or Oracle Client 19
from 19.11).
format as SQL hints but without any comment characters, for example
``hint="MONITOR"``. While you could use this to pass any SQL hint, the
hints ``MONITOR`` (turn on monitoring) and ``NO_MONITOR`` (turn off
monitoring) are the most useful. Use of the hint parameter requires Oracle
Client 21.3 or higher (or Oracle Client 19 from 19.11).
.. note::
@ -288,9 +290,11 @@ SODA Collection Object
The hint parameter, if specified, supplies a hint to the database when
processing the SODA operation. This is expected to be a string in the same
format as SQL hints but without the enclosing comment characters. Use of
this parameter requires Oracle Client 21.3 or higher (or Oracle Client 19
from 19.11).
format as SQL hints but without any comment characters, for example
``hint="MONITOR"``. While you could use this to pass any SQL hint, the
hints ``MONITOR`` (turn on monitoring) and ``NO_MONITOR`` (turn off
monitoring) are the most useful. Use of the hint parameter requires Oracle
Client 21.3 or higher (or Oracle Client 19 from 19.11).
.. versionadded:: 7.0
@ -339,9 +343,11 @@ SODA Collection Object
The hint parameter, if specified, supplies a hint to the database when
processing the SODA operation. This is expected to be a string in the same
format as SQL hints but without the enclosing comment characters. Use of
this parameter requires Oracle Client 21.3 or higher (or Oracle Client 19
from 19.11).
format as SQL hints but without any comment characters, for example
``hint="MONITOR"``. While you could use this to pass any SQL hint, the
hints ``MONITOR`` (turn on monitoring) and ``NO_MONITOR`` (turn off
monitoring) are the most useful. Use of the hint parameter requires Oracle
Client 21.3 or higher (or Oracle Client 19 from 19.11).
This method requires Oracle Client 19.9 or higher in addition to the usual
SODA requirements.
@ -560,8 +566,10 @@ SODA Operation Object
Specifies a hint that will be provided to the SODA operation when it is
performed. This is expected to be a string in the same format as SQL hints
but without the enclosing comment characters. Use of this method
requires Oracle Client 21.3 or higher (or Oracle Client 19 from 19.11).
but without any comment characters. While you could use this to pass any SQL
hint, the hints ``MONITOR`` (turn on monitoring) and ``NO_MONITOR`` (turn
off monitoring) are the most useful. Use of this method requires Oracle
Client 21.3 or higher (or Oracle Client 19 from 19.11).
As a convenience, the SodaOperation object is returned so that further
criteria can be specified by chaining methods together.

View File

@ -28,8 +28,8 @@ templates_path = ['.templates']
# The suffix of source filenames.
source_suffix = '.rst'
# The master toctree document.
master_doc = 'index'
# The main toctree document.
main_doc = 'index'
# General substitutions.
project = 'cx_Oracle'

View File

@ -5,23 +5,16 @@
cx_Oracle Release Notes
=======================
For any deprecations, see :ref:`Deprecations <deprecations>`.
Version 8.2 (TBD)
-----------------
#) Updated embedded ODPI-C to `version 4.2.0
<https://oracle.github.io/odpi/doc/releasenotes.html#
version-4-2-tbd>`__.
#) Added :ref:`SODA metadata cache <sodametadatacache>` support to connection
pools. This significantly improves the performance of methods
:meth:`SodaDatabase.createCollection()` (when not specifying a value for
the metadata parameter) and :meth:`SodaDatabase.openCollection()`. Caching
is available when using Oracle Client version 19.11 and higher.
#) Added support for supplying hints to SODA operations. A new non-terminal
method :meth:`~SodaOperation.hint()` was added and a `hint` parameter was
added to the methods :meth:`SodaCollection.insertOneAndGet()`,
:meth:`SodaCollection.insertManyAndGet()` and
:meth:`SodaCollection.saveAndGet()`. All of these require Oracle Client
21.3 or higher (or Oracle Client 19 from 19.11).
#) Threaded mode is now always enabled when creating connection pools with
:meth:`cx_Oracle.SessionPool()`. Any `threaded` parameter value is ignored.
#) Added parameter `stmtcachesize` to :meth:`cx_Oracle.connect()` and
:meth:`cx_Oracle.SessionPool()` in order to permit specifying the size of
the statement cache during the creation of pools and standalone
@ -31,20 +24,39 @@ Version 8.2 (TBD)
attribute :data:`SessionPool.ping_interval` was added in order to permit
making adjustments after the pool has been created. In previous cx_Oracle
releases a fixed ping interval of 60 seconds was used.
#) Added parameter `soda_metadata_cache` to :meth:`cx_Oracle.SessionPool()` for
:ref:`SODA metadata cache <sodametadatacache>` support. In addition, the
attribute :data:`SessionPool.soda_metadata_cache` was added in order to
permit making adjustments after the pool has been created. This feature
significantly improves the performance of methods
:meth:`SodaDatabase.createCollection()` (when not specifying a value for the
metadata parameter) and :meth:`SodaDatabase.openCollection()`. Caching is
available when using Oracle Client version 19.11 and higher.
#) Added support for supplying hints to SODA operations. A new non-terminal
method :meth:`~SodaOperation.hint()` was added and a `hint` parameter was
added to the methods :meth:`SodaCollection.insertOneAndGet()`,
:meth:`SodaCollection.insertManyAndGet()` and
:meth:`SodaCollection.saveAndGet()`. All of these require Oracle Client
21.3 or higher (or Oracle Client 19 from 19.11).
#) Added parameter `bypass_decode` to :meth:`Cursor.var()` in order to allow
the `decode` step to be bypassed when converting data from Oracle Database
into Python strings
(`issue 385 <https://github.com/oracle/python-cx_Oracle/issues/385>`__).
Initial work was done in `PR 549
<https://github.com/oracle/python-cx_Oracle/pull/549>`__.
#) Threaded mode is now always enabled when creating connection pools with
:meth:`cx_Oracle.SessionPool()`. Any `threaded` parameter value is ignored.
#) Enhanced dead connection detection. If an Oracle Database error indicates
that a connection is no longer usable, the error `DPI-1080: connection was
closed by ORA-%d` is now returned. The `%d` will be the Oracle error
causing the connection to be closed. Using the connection after this will
give `DPI-1010: not connected`. This behavior also applies for
:data:`Connection.call_timeout` errors that result in an unusable
connection.
#) Eliminated a memory leak when calling :meth:`SodaOperation.filter()` with a
dictionary.
#) The distributed transaction handle assosciated with the connection is now
cleared on commit or rollback (`issue 530
<https://github.com/oracle/python-cx_Oracle/issues/530>`__).
#) Added check to ensure that when setting variables or object attributes, the
#) Added a check to ensure that when setting variables or object attributes, the
type of the temporary LOB must match the expected type.
#) A small number of parameter, method, and attribute names were updated to
follow the PEP 8 style guide. This brings better consistency to the
@ -1020,10 +1032,10 @@ Version 6.0 beta 1 (April 2017)
tagging.
#) Added parameter edition to the :meth:`cx_Oracle.SessionPool` method.
#) Added support for
`universal rowids <https://github.com/oracle/python-cx_Oracle/blob/master/
`universal rowids <https://github.com/oracle/python-cx_Oracle/blob/main/
samples/universal_rowids.py>`__.
#) Added support for `DML Returning of multiple rows
<https://github.com/oracle/python-cx_Oracle/blob/master/samples/
<https://github.com/oracle/python-cx_Oracle/blob/main/samples/
dml_returning_multiple_rows.py>`__.
#) Added attributes :attr:`Variable.actualElements` and
:attr:`Variable.values` to variables.
@ -1053,19 +1065,19 @@ Version 6.0 beta 1 (April 2017)
#) Dropped deprecated parameters action, module and clientinfo from the
:meth:`cx_Oracle.connect` method. The appcontext parameter should be used
instead as shown in this `sample <https://github.com/oracle/
python-cx_Oracle/blob/master/samples/app_context.py>`__.
python-cx_Oracle/blob/main/samples/app_context.py>`__.
#) Dropped deprecated attribute numbersAsString from
:ref:`cursor objects <cursorobj>`. Use an output type handler instead as
shown in this `sample <https://github.com/oracle/python-cx_Oracle/blob/
master/samples/return_numbers_as_decimals.py>`__.
main/samples/return_numbers_as_decimals.py>`__.
#) Dropped deprecated attributes cqqos and rowids from
:ref:`subscription objects <subscrobj>`. Use the qos attribute instead as
shown in this `sample <https://github.com/oracle/python-cx_Oracle/blob/
master/samples/cqn.py>`__.
main/samples/cqn.py>`__.
#) Dropped deprecated parameters cqqos and rowids from the
:meth:`Connection.subscribe()` method. Use the qos parameter instead as
shown in this `sample <https://github.com/oracle/python-cx_Oracle/blob/
master/samples/cqn.py>`__.
main/samples/cqn.py>`__.
Version 5.3 (March 2017)

View File

@ -14,7 +14,7 @@ cx_Oracle 7.2 introduced an updated interface for Oracle Advanced
Queuing.
There are Advanced Queuing examples in the `GitHub examples
<https://github.com/oracle/python-cx_Oracle/tree/master/samples>`__ directory.
<https://github.com/oracle/python-cx_Oracle/tree/main/samples>`__ directory.
Creating a Queue
@ -46,7 +46,7 @@ queue can be used for enqueuing, dequeuing, or both as needed.
queue = connection.queue("DEMO_RAW_QUEUE")
Now messages can be queued using :meth:`Queue.enqOne()`. To send three
Now messages can be queued using :meth:`~Queue.enqone()`. To send three
messages:
.. code-block:: python
@ -57,7 +57,7 @@ messages:
"The third message"
]
for data in PAYLOAD_DATA:
queue.enqOne(connection.msgproperties(payload=data))
queue.enqone(connection.msgproperties(payload=data))
connection.commit()
Since the queue sending the messages is a RAW queue, the strings in this
@ -69,7 +69,7 @@ Dequeuing Messages
==================
Dequeuing is performed similarly. To dequeue a message call the method
:meth:`Queue.deqOne()` as shown. Note that if the message is expected to be a
:meth:`~Queue.deqone()` as shown. Note that if the message is expected to be a
string, the bytes must be decoded using :attr:`Connection.encoding`.
.. code-block:: python
@ -110,25 +110,25 @@ You can queue messages:
.. code-block:: python
booksType = connection.gettype("UDT_BOOK")
queue = connection.queue("DEMO_BOOK_QUEUE", booksType)
book_type = connection.gettype("UDT_BOOK")
queue = connection.queue("DEMO_BOOK_QUEUE", book_type)
book = booksType.newobject()
book = book_type.newobject()
book.TITLE = "Quick Brown Fox"
book.AUTHORS = "The Dog"
book.PRICE = 123
queue.enqOne(connection.msgproperties(payload=book))
queue.enqone(connection.msgproperties(payload=book))
connection.commit()
Dequeuing is done like this:
.. code-block:: python
booksType = connection.gettype("UDT_BOOK")
queue = connection.queue("DEMO_BOOK_QUEUE", booksType)
book_type = connection.gettype("UDT_BOOK")
queue = connection.queue("DEMO_BOOK_QUEUE", book_type)
msg = queue.deqOne()
msg = queue.deqone()
connection.commit()
print(msg.payload.TITLE) # will print Quick Brown Fox
@ -148,7 +148,7 @@ messages:
.. code-block:: python
queue = connection.queue("DEMO_RAW_QUEUE")
queue.enqOptions.visibility = cx_Oracle.ENQ_IMMEDIATE
queue.enqoptions.visibility = cx_Oracle.ENQ_IMMEDIATE
Dequeue options can also be set. For example, to specify not to block on
dequeuing if no messages are available:
@ -156,14 +156,14 @@ dequeuing if no messages are available:
.. code-block:: python
queue = connection.queue("DEMO_RAW_QUEUE")
queue.deqOptions.wait = cx_Oracle.DEQ_NO_WAIT
queue.deqoptions.wait = cx_Oracle.DEQ_NO_WAIT
Message properties can be set when enqueuing. For example, to set an
expiration of 60 seconds on a message:
.. code-block:: python
queue.enqOne(connection.msgproperties(payload="Message", expiration=60))
queue.enqone(connection.msgproperties(payload="Message", expiration=60))
This means that if no dequeue operation occurs within 60 seconds that the
message will be dropped from the queue.
@ -172,10 +172,10 @@ message will be dropped from the queue.
Bulk Enqueue and Dequeue
========================
The :meth:`Queue.enqMany()` and :meth:`Queue.deqMany()` methods can be used for
efficient bulk message handling.
The :meth:`~Queue.enqmany()` and :meth:`~Queue.deqmany()` methods can be used
for efficient bulk message handling.
:meth:`Queue.enqMany()` is similar to :meth:`Queue.enqOne()` but accepts an
:meth:`~Queue.enqmany()` is similar to :meth:`~Queue.enqone()` but accepts an
array of messages:
.. code-block:: python
@ -186,22 +186,25 @@ array of messages:
"The third message",
]
queue = connection.queue("DEMO_RAW_QUEUE")
queue.enqMany(connection.msgproperties(payload=m) for m in messages)
queue.enqmany(connection.msgproperties(payload=m) for m in messages)
connection.commit()
Warning: calling :meth:`Queue.enqMany()` in parallel on different connections
acquired from the same pool may fail due to Oracle bug 29928074. Ensure that
this function is not run in parallel, use standalone connections or connections
from different pools, or make multiple calls to :meth:`Queue.enqOne()` instead.
The function :meth:`Queue.deqMany()` call is not affected.
.. warning::
To dequeue multiple messages at one time, use :meth:`Queue.deqMany()`. This
Calling :meth:`~Queue.enqmany()` in parallel on different connections
acquired from the same pool may fail due to Oracle bug 29928074. Ensure
that this function is not run in parallel, use standalone connections or
connections from different pools, or make multiple calls to
:meth:`~Queue.enqone()` instead. The function :meth:`~Queue.deqmany()` call
is not affected.
To dequeue multiple messages at one time, use :meth:`~Queue.deqmany()`. This
takes an argument specifying the maximum number of messages to dequeue at one
time:
.. code-block:: python
for m in queue.deqMany(maxMessages=10):
for m in queue.deqmany(10):
print(m.payload.decode(connection.encoding))
Depending on the queue properties and the number of messages available to

View File

@ -12,7 +12,7 @@ The :meth:`~Cursor.executemany()` method can also be used to execute PL/SQL
statements multiple times at once.
There are examples in the `GitHub examples
<https://github.com/oracle/python-cx_Oracle/tree/master/samples>`__
<https://github.com/oracle/python-cx_Oracle/tree/main/samples>`__
directory.
The following tables will be used in the samples that follow:
@ -42,14 +42,14 @@ The following example inserts five rows into the table ``ParentTable``:
.. code-block:: python
dataToInsert = [
data = [
(10, 'Parent 10'),
(20, 'Parent 20'),
(30, 'Parent 30'),
(40, 'Parent 40'),
(50, 'Parent 50')
]
cursor.executemany("insert into ParentTable values (:1, :2)", dataToInsert)
cursor.executemany("insert into ParentTable values (:1, :2)", data)
This code requires only one :ref:`round-trip <roundtrips>` from the client to
the database instead of the five round-trips that would be required for
@ -70,14 +70,14 @@ example:
.. code-block:: python
dataToInsert = [
data = [
(10, 'Parent 10'),
(20, 'Parent 20'),
(30, 'Parent 30'),
(40, 'Parent 40'),
(50, 'Parent 50')
]
cursor.executemany("begin mypkg.create_parent(:1, :2); end;", dataToInsert)
cursor.executemany("begin mypkg.create_parent(:1, :2); end;", data)
Note that the ``batcherrors`` parameter (discussed below) cannot be used with
PL/SQL block execution.
@ -104,7 +104,7 @@ This example shows how data errors can be identified:
.. code-block:: python
dataToInsert = [
data = [
(60, 'Parent 60'),
(70, 'Parent 70'),
(70, 'Parent 70 (duplicate)'),
@ -112,8 +112,8 @@ This example shows how data errors can be identified:
(80, 'Parent 80 (duplicate)'),
(90, 'Parent 90')
]
cursor.executemany("insert into ParentTable values (:1, :2)", dataToInsert,
batcherrors=True)
cursor.executemany("insert into ParentTable values (:1, :2)", data,
batcherrors=True)
for error in cursor.getbatcherrors():
print("Error", error.message, "at row offset", error.offset)
@ -142,16 +142,16 @@ affected by each row of data that is bound you must set the parameter
.. code-block:: python
parentIdsToDelete = [20, 30, 50]
parent_ids_to_delete = [20, 30, 50]
cursor.executemany("delete from ChildTable where ParentId = :1",
[(i,) for i in parentIdsToDelete],
arraydmlrowcounts=True)
rowCounts = cursor.getarraydmlrowcounts()
for parentId, count in zip(parentIdsToDelete, rowCounts):
print("Parent ID:", parentId, "deleted", count, "rows.")
[(i,) for i in parent_ids_to_delete],
arraydmlrowcounts=True)
row_counts = cursor.getarraydmlrowcounts()
for parent_id, count in zip(parent_ids_to_delete, row_counts):
print("Parent ID:", parent_id, "deleted", count, "rows.")
Using the data found in the `GitHub samples
<https://github.com/oracle/python-cx_Oracle/tree/master/samples>`__ the output
<https://github.com/oracle/python-cx_Oracle/tree/main/samples>`__ the output
is as follows::
Parent ID: 20 deleted 3 rows.
@ -172,17 +172,17 @@ you could use the following code:
.. code-block:: python
parentIdsToDelete = [20, 30, 50]
childIdVar = cursor.var(int, arraysize=len(parentIdsToDelete))
cursor.setinputsizes(None, childIdVar)
parent_ids_to_delete = [20, 30, 50]
child_id_var = cursor.var(int, arraysize=len(parent_ids_to_delete))
cursor.setinputsizes(None, child_id_var)
cursor.executemany("""
delete from ChildTable
where ParentId = :1
returning ChildId into :2""",
[(i,) for i in parentIdsToDelete])
for ix, parentId in enumerate(parentIdsToDelete):
print("Child IDs deleted for parent ID", parentId, "are",
childIdVar.getvalue(ix))
[(i,) for i in parent_ids_to_delete])
for ix, parent_id in enumerate(parent_ids_to_delete):
print("Child IDs deleted for parent ID", parent_id, "are",
child_id_var.getvalue(ix))
The output would then be::
@ -216,10 +216,10 @@ Consider the following code:
.. code-block:: python
data = [
( 110, "Parent 110"),
( 2000, "Parent 2000"),
( 30000, "Parent 30000"),
( 400000, "Parent 400000"),
(110, "Parent 110"),
(2000, "Parent 2000"),
(30000, "Parent 30000"),
(400000, "Parent 400000"),
(5000000, "Parent 5000000")
]
cursor.setinputsizes(None, 20)

View File

@ -29,7 +29,7 @@ statements:
# !! Never do this !!
sql = f"""insert into departments (department_id, department_name)
values ({did}, {dnm})"""
values ({did}, '{dnm}')"""
cursor.execute(sql)
Bind variables reduce parsing and execution costs when statements are executed
@ -58,7 +58,7 @@ bind variables in a statement are associated with a name. For example:
# alternatively, the parameters can be passed as a dictionary instead of as
# keyword parameters
data = { "dept_id": 280, "dept_name": "Facility" }
data = dict(dept_id=280, dept_name="Facility")
cursor.execute("""
insert into departments (department_id, department_name)
values (:dept_id, :dept_name)""", data)
@ -105,12 +105,13 @@ integers 8 and 7 and stores the result in an OUT bind variable of type integer:
.. code-block:: python
outVal = cursor.var(int)
out_val = cursor.var(int)
cursor.execute("""
begin
:outVal := :inBindVar1 + :inBindVar2;
end;""", outVal=outVal, inBindVar1=8, inBindVar2=7)
print(outVal.getvalue()) # will print 15
:out_val := :in_bind_var1 + :in_bind_var2;
end;""",
out_val=out_val, in_bind_var1=8, in_bind_var2=7)
print(out_val.getvalue()) # will print 15
If instead of simply getting data back you wish to supply an initial value to
the database, you can set the variable's initial value. This example is the
@ -118,13 +119,15 @@ same as the previous one but it sets the initial value first:
.. code-block:: python
inOutVal = cursor.var(int)
inOutVal.setvalue(0, 25)
in_out_var = cursor.var(int)
in_out_var.setvalue(0, 25)
cursor.execute("""
begin
:inOutBindVar := :inOutBindVar + :inBindVar1 + :inBindVar2;
end;""", inOutBindVar=inOutVal, inBindVar1=8, inBindVar2=7)
print(inOutVal.getvalue()) # will print 40
:in_out_bind_var := :in_out_bind_var + :in_bind_var1 +
:in_bind_var2;
end;""",
in_out_bind_var=in_out_var, in_bind_var1=8, in_bind_var2=7)
print(in_out_var.getvalue()) # will print 40
When binding data to parameters of PL/SQL procedures that are declared as OUT
parameters, it is worth noting that any value that is set in the bind variable
@ -257,9 +260,9 @@ cursor which had executed a SQL query:
.. code-block:: python
refCursor = connection.cursor()
cursor.callproc("find_employees", ['Smith', refCursor])
for row in refCursor:
ref_cursor = connection.cursor()
cursor.callproc("find_employees", ['Smith', ref_cursor])
for row in ref_cursor:
print(row)
With Oracle's `sample HR schema
@ -274,8 +277,9 @@ return type of :meth:`Cursor.callfunc()`:
.. code-block:: python
refCursor = cursor.callfunc('example_package.f_get_cursor', cx_Oracle.DB_TYPE_CURSOR)
for row in refCursor:
ref_cursor = cursor.callfunc('example_package.f_get_cursor',
cx_Oracle.DB_TYPE_CURSOR)
for row in ref_cursor:
print(row)
See :ref:`tuning` for information on how to tune REF CURSORS.
@ -322,8 +326,8 @@ Then the Python code:
.. code-block:: python
values = ["String One", "String Two", "String Three"]
returnVal = cursor.callfunc("mypkg.DemoCollectionIn", int, [values])
print(returnVal) # will print 32
return_val = cursor.callfunc("mypkg.DemoCollectionIn", int, [values])
print(return_val) # will print 32
In order get values back from the database, a bind variable must be created
using :meth:`Cursor.arrayvar()`. The first parameter to this method is a Python
@ -388,9 +392,9 @@ language array`` would be raised.
.. code-block:: python
outArrayVar = cursor.arrayvar(str, 10, 100)
cursor.callproc("mypkg.DemoCollectionOut", [5, outArrayVar])
for val in outArrayVar.getvalue():
out_array_var = cursor.arrayvar(str, 10, 100)
cursor.callproc("mypkg.DemoCollectionOut", [5, out_array_var])
for val in out_array_var.getvalue():
print(val)
This would produce the following output::
@ -408,10 +412,10 @@ initial value.
.. code-block:: python
inValues = ["String One", "String Two", "String Three", "String Four"]
inOutArrayVar = cursor.arrayvar(str, inValues)
cursor.callproc("mypkg.DemoCollectionInOut", [inOutArrayVar])
for val in inOutArrayVar.getvalue():
in_values = ["String One", "String Two", "String Three", "String Four"]
in_out_array_var = cursor.arrayvar(str, in_values)
cursor.callproc("mypkg.DemoCollectionInOut", [in_out_array_var])
for val in in_out_array_var.getvalue():
print(val)
This would produce the following output::
@ -427,8 +431,8 @@ used instead:
.. code-block:: python
inOutArrayVar = cursor.arrayvar(str, 10, 100)
inOutArrayVar.setvalue(0, ["String One", "String Two"])
in_out_array_var = cursor.arrayvar(str, 10, 100)
in_out_array_var.setvalue(0, ["String One", "String Two"])
All of the collections that have been bound in preceding examples have used
contiguous array elements. If an associative array with sparse array elements
@ -470,8 +474,8 @@ process this collection looks like this instead:
.. code-block:: python
collectionType = connection.gettype("MYPKG.UDT_STRINGLIST")
collection = collectionType.newobject()
collection_type = connection.gettype("MYPKG.UDT_STRINGLIST")
collection = collection_type.newobject()
cursor.callproc("mypkg.DemoCollectionOut", [collection])
print(collection.aslist())
@ -570,8 +574,8 @@ update the record:
.. code-block:: python
# create and populate a record
recordType = connection.gettype("MYPKG.UDT_DEMORECORD")
record = recordType.newobject()
record_type = connection.gettype("MYPKG.UDT_DEMORECORD")
record = record_type.newobject()
record.NUMBERVALUE = 6
record.STRINGVALUE = "Test String"
record.DATEVALUE = datetime.datetime(2016, 5, 28)
@ -639,36 +643,38 @@ objects seamlessly:
.. code-block:: python
# A standard Python object
class Building(object):
def __init__(self, buildingId, description, numFloors, dateBuilt):
self.buildingId = buildingId
class Building:
def __init__(self, build_id, description, num_floors, date_built):
self.building_id = build_id
self.description = description
self.numFloors = numFloors
self.dateBuilt = dateBuilt
self.num_floors = num_floors
self.date_built = date_built
building = Building(1, "Skyscraper 1", 5, datetime.date(2001, 5, 24))
# Get Python representation of the Oracle user defined type UDT_BUILDING
objType = con.gettype("UDT_BUILDING")
obj_type = con.gettype("UDT_BUILDING")
# convert a Python Building object to the Oracle user defined type UDT_BUILDING
def BuildingInConverter(value):
obj = objType.newobject()
obj.BUILDINGID = value.buildingId
# convert a Python Building object to the Oracle user defined type
# UDT_BUILDING
def building_in_converter(value):
obj = obj_type.newobject()
obj.BUILDINGID = value.building_id
obj.DESCRIPTION = value.description
obj.NUMFLOORS = value.numFloors
obj.DATEBUILT = value.dateBuilt
obj.NUMFLOORS = value.num_floors
obj.DATEBUILT = value.date_built
return obj
def InputTypeHandler(cursor, value, numElements):
def input_type_handler(cursor, value, num_elements):
if isinstance(value, Building):
return cursor.var(cx_Oracle.DB_TYPE_OBJECT, arraysize = numElements,
inconverter = BuildingInConverter, typename = objType.name)
return cursor.var(obj_type, arraysize=num_elements,
inconverter=building_in_converter)
# With the input type handler, the bound Python object is converted
# to the required Oracle object before being inserted
cur.inputtypehandler = InputTypeHandler
cur.inputtypehandler = input_type_handler
cur.execute("insert into myTable values (:1, :2)", (1, building))
@ -746,11 +752,11 @@ means to validate the data in order to avoid SQL Injection security issues:
.. code-block:: python
tableAllowList = ['employees', 'departments']
tableName = getTableName() # get the table name from user input
if tableName not in tableAllowList:
table_allow_list = ['employees', 'departments']
table_name = get_table_name() # get the table name from user input
if table_name.lower() not in table_allow_list:
raise Exception('Invalid table name')
sql = 'select * from ' + tableName
sql = f'select * from {table_name}'
Binding column names can be done either by using the above method or by using a
CASE statement. The example below demonstrates binding a column name in an
@ -766,8 +772,8 @@ ORDER BY clause:
ELSE MANAGER_ID
END"""
columnName = getColumnName() # Obtain a column name from the user
cursor.execute(sql, [colname])
col_name = get_column_name() # Obtain a column name from the user
cursor.execute(sql, [col_name])
Depending on the name provided by the user, the query results will be
ordered either by the column ``DEPARTMENT_ID`` or the column ``MANAGER_ID``.

View File

@ -44,7 +44,9 @@ enabling :ref:`network encryption <netencrypt>`.
userpwd = ". . ." # Obtain password string from a user prompt or environment variable
connection = cx_Oracle.connect("hr", userpwd, "dbhost.example.com/orclpdb1", encoding="UTF-8")
connection = cx_Oracle.connect(user="hr", password=userpwd,
dsn="dbhost.example.com/orclpdb1",
encoding="UTF-8")
cx_Oracle also supports :ref:`external authentication <extauth>` so
passwords do not need to be in the application.
@ -61,11 +63,12 @@ the use of a "with" block, for example:
.. code-block:: python
with cx_Oracle.connect(userName, password, "dbhost.example.com/orclpdb1",
encoding="UTF-8") as connection:
with cx_Oracle.connect(user=user, password=password,
dsn="dbhost.example.com/orclpdb1",
encoding="UTF-8") as connection:
cursor = connection.cursor()
cursor.execute("insert into SomeTable values (:1, :2)",
(1, "Some string"))
(1, "Some string"))
connection.commit()
This code ensures that, once the block is completed, the connection is closed
@ -103,15 +106,21 @@ such as ``tnsnames.ora``.
For example, to connect to the Oracle Database service ``orclpdb1`` that is
running on the host ``dbhost.example.com`` with the default Oracle
Database port 1521, use::
Database port 1521, use:
connection = cx_Oracle.connect("hr", userpwd, "dbhost.example.com/orclpdb1",
encoding="UTF-8")
.. code-block:: python
If the database is using a non-default port, it must be specified::
connection = cx_Oracle.connect(user="hr", password=userpwd,
dsn="dbhost.example.com/orclpdb1",
encoding="UTF-8")
connection = cx_Oracle.connect("hr", userpwd, "dbhost.example.com:1984/orclpdb1",
encoding="UTF-8")
If the database is using a non-default port, it must be specified:
.. code-block:: python
connection = cx_Oracle.connect(user="hr", password=userpwd,
dsn="dbhost.example.com:1984/orclpdb1",
encoding="UTF-8")
The Easy Connect syntax supports Oracle Database service names. It cannot be
used with the older System Identifiers (SID).
@ -143,10 +152,13 @@ syntax.
For example, to connect to the Oracle Database service ``orclpdb1`` that is
running on the host ``dbhost.example.com`` with the default Oracle
Database port 1521, use::
Database port 1521, use:
.. code-block:: python
dsn = cx_Oracle.makedsn("dbhost.example.com", 1521, service_name="orclpdb1")
connection = cx_Oracle.connect("hr", userpwd, dsn, encoding="UTF-8")
connection = cx_Oracle.connect(user="hr", password=userpwd, dsn=dsn,
encoding="UTF-8")
Note the use of the named argument ``service_name``. By default, the third
parameter of :meth:`~cx_Oracle.makedsn()` is a database System Identifier (SID),
@ -158,7 +170,9 @@ The value of ``dsn`` in this example is the connect descriptor string::
You can manually create similar connect descriptor strings. This lets you
extend the syntax, for example to support failover. These strings can be
embedded directly in the application::
embedded directly in the application:
.. code-block:: python
dsn = """(DESCRIPTION=
(FAILOVER=on)
@ -167,7 +181,8 @@ embedded directly in the application::
(ADDRESS=(PROTOCOL=tcp)(HOST=sales2-svr)(PORT=1521)))
(CONNECT_DATA=(SERVICE_NAME=sales.example.com)))"""
connection = cx_Oracle.connect("hr", userpwd, dsn, encoding="UTF-8")
connection = cx_Oracle.connect(user="hr", password=userpwd, dsn=dsn,
encoding="UTF-8")
.. _netservice:
@ -189,9 +204,12 @@ given a ``tnsnames.ora`` file with the following contents::
)
)
then you could connect using the following code::
then you could connect using the following code:
connection = cx_Oracle.connect("hr", userpwd, "orclpdb1", encoding="UTF-8")
.. code-block:: python
connection = cx_Oracle.connect(user="hr", password=userpwd, dsn="orclpdb1",
encoding="UTF-8")
For more information about Net Service Names, see
`Database Net Services Reference
@ -210,9 +228,13 @@ for example::
jdbc:oracle:thin:@dbhost.example.com:1521/orclpdb1
then use Oracle's Easy Connect syntax in cx_Oracle::
then use Oracle's Easy Connect syntax in cx_Oracle:
connection = cx_Oracle.connect("hr", userpwd, "dbhost.example.com:1521/orclpdb1", encoding="UTF-8")
.. code-block:: python
connection = cx_Oracle.connect(user="hr", password=userpwd,
dsn="dbhost.example.com:1521/orclpdb1",
encoding="UTF-8")
Alternatively, if a JDBC connection string uses an old-style Oracle SID "system
identifier", and the database does not have a service name::
@ -224,10 +246,13 @@ for example::
jdbc:oracle:thin:@dbhost.example.com:1521:orcl
then a connect descriptor string from ``makedsn()`` can be used in the
application::
application:
.. code-block:: python
dsn = cx_Oracle.makedsn("dbhost.example.com", 1521, sid="orcl")
connection = cx_Oracle.connect("hr", userpwd, dsn, encoding="UTF-8")
connection = cx_Oracle.connect(user="hr", password=userpwd, dsn=dsn,
encoding="UTF-8")
Alternatively, create a ``tnsnames.ora`` (see :ref:`optnetfiles`) entry, for
example::
@ -240,9 +265,12 @@ example::
)
)
This can be referenced in cx_Oracle::
This can be referenced in cx_Oracle:
connection = cx_Oracle.connect("hr", userpwd, "finance", encoding="UTF-8")
.. code-block:: python
connection = cx_Oracle.connect(user="hr", password=userpwd, dsn="finance",
encoding="UTF-8")
.. _connpool:
@ -289,8 +317,9 @@ connection pool:
.. code-block:: python
# Create the session pool
pool = cx_Oracle.SessionPool("hr", userpwd,
"dbhost.example.com/orclpdb1", min=2, max=5, increment=1, encoding="UTF-8")
pool = cx_Oracle.SessionPool(user="hr", password=userpwd,
dsn="dbhost.example.com/orclpdb1", min=2,
max=5, increment=1, encoding="UTF-8")
# Acquire a connection from the pool
connection = pool.acquire()
@ -306,18 +335,22 @@ connection pool:
# Close the pool
pool.close()
Other :meth:`cx_Oracle.SessionPool()` options can be used at pool creation. For
example the ``getmode`` value can be set so that any ``aquire()`` call will wait
for a connection to become available if all are currently in use, for example:
Other :meth:`cx_Oracle.SessionPool()` options can be used at pool creation.
For example the ``getmode`` value can be set so that any ``aquire()`` call will
wait for a connection to become available if all are currently in use, for
example:
.. code-block:: python
# Create the session pool
pool = cx_Oracle.SessionPool("hr", userpwd, "dbhost.example.com/orclpdb1",
min=2, max=5, increment=1, getmode=cx_Oracle.SPOOL_ATTRVAL_WAIT, encoding="UTF-8")
pool = cx_Oracle.SessionPool(user="hr", password=userpwd,
dsn="dbhost.example.com/orclpdb1", min=2,
max=5, increment=1,
getmode=cx_Oracle.SPOOL_ATTRVAL_WAIT,
encoding="UTF-8")
See `ConnectionPool.py
<https://github.com/oracle/python-cx_Oracle/tree/master/samples/ConnectionPool.py>`__
<https://github.com/oracle/python-cx_Oracle/tree/main/samples/ConnectionPool.py>`__
for an example.
Before :meth:`SessionPool.acquire()` returns, cx_Oracle does a lightweight check
@ -386,7 +419,7 @@ However, because pools can grow, or connections in the pool can be recreated,
there is no guarantee a subsequent :meth:`~SessionPool.acquire()` call will
return a database connection that has any particular state.
The :meth:`~cx_Oracle.SessionPool()` parameter ``sessionCallback``
The :meth:`~cx_Oracle.SessionPool()` parameter ``session_callback``
enables efficient setting of session state so that connections have a
known session state, without requiring that state to be explicitly set
after each :meth:`~SessionPool.acquire()` call.
@ -401,7 +434,7 @@ necessary changes.
The session callback can be a Python function or a PL/SQL procedure.
There are three common scenarios for ``sessionCallback``:
There are three common scenarios for ``session_callback``:
- When all connections in the pool should have the same state, use a
Python callback without tagging.
@ -414,7 +447,7 @@ There are three common scenarios for ``sessionCallback``:
**Python Callback**
If the ``sessionCallback`` parameter is a Python procedure, it will be called
If the ``session_callback`` parameter is a Python procedure, it will be called
whenever :meth:`~SessionPool.acquire()` will return a newly created database
connection that has not been used before. It is also called when connection
tagging is being used and the requested tag is not identical to the tag in the
@ -425,24 +458,25 @@ An example is:
.. code-block:: python
# Set the NLS_DATE_FORMAT for a session
def initSession(connection, requestedTag):
def init_session(connection, requested_tag):
cursor = connection.cursor()
cursor.execute("ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI'")
# Create the pool with session callback defined
pool = cx_Oracle.SessionPool("hr", userpwd, "orclpdb1",
sessionCallback=initSession, encoding="UTF-8")
pool = cx_Oracle.SessionPool(user="hr", password=userpwd, dsn="orclpdb1",
session_callback=init_session,
encoding="UTF-8")
# Acquire a connection from the pool (will always have the new date format)
connection = pool.acquire()
If needed, the ``initSession()`` procedure is called internally before
If needed, the ``init_session()`` procedure is called internally before
``acquire()`` returns. It will not be called when previously used connections
are returned from the pool. This means that the ALTER SESSION does not need to
be executed after every ``acquire()`` call. This improves performance and
scalability.
In this example tagging was not being used, so the ``requestedTag`` parameter
In this example tagging was not being used, so the ``requested_tag`` parameter
is ignored.
Note: if you need to execute multiple SQL statements in the callback, use an
@ -483,25 +517,26 @@ The example below demonstrates connection tagging:
.. code-block:: python
def initSession(connection, requestedTag):
if requestedTag == "NLS_DATE_FORMAT=SIMPLE":
def init_session(connection, requested_tag):
if requested_tag == "NLS_DATE_FORMAT=SIMPLE":
sql = "ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD'"
elif requestedTag == "NLS_DATE_FORMAT=FULL":
elif requested_tag == "NLS_DATE_FORMAT=FULL":
sql = "ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI'"
cursor = connection.cursor()
cursor.execute(sql)
connection.tag = requestedTag
connection.tag = requested_tag
pool = cx_Oracle.SessionPool("hr", userpwd, "orclpdb1",
sessionCallback=initSession, encoding="UTF-8")
pool = cx_Oracle.SessionPool(user="hr", password=userpwd, dsn="orclpdb1",
session_callback=init_session,
encoding="UTF-8")
# Two connections with different session state:
connection1 = pool.acquire(tag = "NLS_DATE_FORMAT=SIMPLE")
connection2 = pool.acquire(tag = "NLS_DATE_FORMAT=FULL")
connection1 = pool.acquire(tag="NLS_DATE_FORMAT=SIMPLE")
connection2 = pool.acquire(tag="NLS_DATE_FORMAT=FULL")
See `SessionCallback.py
<https://github.com/oracle/python-cx_Oracle/tree/master/
samples/SessionCallback.py>`__ for an example.
See `session_callback.py
<https://github.com/oracle/python-cx_Oracle/tree/main/
samples/session_callback.py>`__ for an example.
**PL/SQL Callback**
@ -533,21 +568,24 @@ Oracle 'multi-property tags' must be used. The tag string must be of the form
of one or more "name=value" pairs separated by a semi-colon, for example
``"loc=uk;lang=cy"``.
In cx_Oracle set ``sessionCallback`` to the name of the PL/SQL procedure. For
In cx_Oracle set ``session_callback`` to the name of the PL/SQL procedure. For
example:
.. code-block:: python
pool = cx_Oracle.SessionPool("hr", userpwd, "dbhost.example.com/orclpdb1:pooled",
sessionCallback="myPlsqlCallback", encoding="UTF-8")
pool = cx_Oracle.SessionPool(user="hr", password=userpwd,
dsn="dbhost.example.com/orclpdb1:pooled",
session_callback="MyPlsqlCallback",
encoding="UTF-8")
connection = pool.acquire(tag="NLS_DATE_FORMAT=SIMPLE",
# DRCP options, if you are using DRCP
cclass='MYCLASS', purity=cx_Oracle.ATTR_PURITY_SELF)
# DRCP options, if you are using DRCP
cclass='MYCLASS',
purity=cx_Oracle.ATTR_PURITY_SELF)
See `SessionCallbackPLSQL.py
<https://github.com/oracle/python-cx_Oracle/tree/master/
samples/SessionCallbackPLSQL.py>`__ for an example.
See `session_callback_plsql.py
<https://github.com/oracle/python-cx_Oracle/tree/main/
samples/session_callback_plsql.py>`__ for an example.
.. _connpooltypes:
@ -568,8 +606,8 @@ may be passed to :meth:`~SessionPool.acquire()` as shown in this example:
.. code-block:: python
pool = cx_Oracle.SessionPool(dsn="dbhost.example.com/orclpdb1", homogeneous=False,
encoding="UTF-8")
pool = cx_Oracle.SessionPool(dsn="dbhost.example.com/orclpdb1",
homogeneous=False, encoding="UTF-8")
connection = pool.acquire(user="hr", password=userpwd)
.. _drcp:
@ -697,14 +735,16 @@ Using Oracles Easy Connect syntax, the connection would look like:
.. code-block:: python
connection = cx_Oracle.connect("hr", userpwd, "dbhost.example.com/orcl:pooled",
encoding="UTF-8")
connection = cx_Oracle.connect(user="hr", password=userpwd,
dsn="dbhost.example.com/orcl:pooled",
encoding="UTF-8")
Or if you connect using a Net Service Name named ``customerpool``:
.. code-block:: python
connection = cx_Oracle.connect("hr", userpwd, "customerpool", encoding="UTF-8")
connection = cx_Oracle.connect(user="hr", password=userpwd,
dsn="customerpool", encoding="UTF-8")
Then only the Oracle Network configuration file ``tnsnames.ora`` needs
to be modified::
@ -729,17 +769,22 @@ Resident Connection Pooling:
.. code-block:: python
connection = cx_Oracle.connect("hr", userpwd, "dbhost.example.com/orcl:pooled",
cclass="MYCLASS", purity=cx_Oracle.ATTR_PURITY_SELF, encoding="UTF-8")
connection = cx_Oracle.connect(user="hr", password=userpwd,
dsn="dbhost.example.com/orcl:pooled",
cclass="MYCLASS",
purity=cx_Oracle.ATTR_PURITY_SELF,
encoding="UTF-8")
The example below shows connecting to Oracle Database using DRCP and
cx_Oracle's connection pooling:
.. code-block:: python
mypool = cx_Oracle.SessionPool("hr", userpwd, "dbhost.example.com/orcl:pooled",
encoding="UTF-8")
connection = mypool.acquire(cclass="MYCLASS", purity=cx_Oracle.ATTR_PURITY_SELF)
mypool = cx_Oracle.SessionPool(user="hr", password=userpwd,
dsn="dbhost.example.com/orcl:pooled",
encoding="UTF-8")
connection = mypool.acquire(cclass="MYCLASS",
purity=cx_Oracle.ATTR_PURITY_SELF)
For more information about DRCP see `Oracle Database Concepts Guide
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&
@ -902,14 +947,18 @@ Standalone connection examples:
.. code-block:: python
# Basic Authentication without a proxy
connection = cx_Oracle.connect("myproxyuser", "myproxyuserpw", "dbhost.example.com/orclpdb1",
encoding="UTF-8")
connection = cx_Oracle.connect(user="myproxyuser",
password="myproxyuserpw",
dsn="dbhost.example.com/orclpdb1",
encoding="UTF-8")
# PROXY_USER: None
# SESSION_USER: MYPROXYUSER
# Basic Authentication with a proxy
connection = cx_Oracle.connect(user="myproxyuser[mysessionuser]", "myproxyuserpw",
"dbhost.example.com/orclpdb1", encoding="UTF-8")
connection = cx_Oracle.connect(user="myproxyuser[mysessionuser]",
password="myproxyuserpw",
dsn="dbhost.example.com/orclpdb1",
encoding="UTF-8")
# PROXY_USER: MYPROXYUSER
# SESSION_USER: MYSESSIONUSER
@ -918,15 +967,18 @@ Pooled connection examples:
.. code-block:: python
# Basic Authentication without a proxy
pool = cx_Oracle.SessionPool("myproxyuser", "myproxyuser", "dbhost.example.com/orclpdb1",
encoding="UTF-8")
pool = cx_Oracle.SessionPool(user="myproxyuser", password="myproxyuser",
dsn="dbhost.example.com/orclpdb1",
encoding="UTF-8")
connection = pool.acquire()
# PROXY_USER: None
# SESSION_USER: MYPROXYUSER
# Basic Authentication with proxy
pool = cx_Oracle.SessionPool("myproxyuser[mysessionuser]", "myproxyuser",
"dbhost.example.com/orclpdb1", homogeneous=False, encoding="UTF-8")
pool = cx_Oracle.SessionPool(user="myproxyuser[mysessionuser]",
password="myproxyuser",
dsn="dbhost.example.com/orclpdb1",
homogeneous=False, encoding="UTF-8")
connection = pool.acquire()
# PROXY_USER: MYPROXYUSER
# SESSION_USER: MYSESSIONUSER
@ -1021,14 +1073,18 @@ your DBA, skip to step 3.
set to the directory containing them. See :ref:`optnetfiles`.
With an Oracle wallet configured, and readable by you, your scripts
can connect using::
can connect using:
.. code-block:: python
connection = cx_Oracle.connect(dsn="mynetalias", encoding="UTF-8")
or::
or:
pool = cx_Oracle.SessionPool(externalauth=True, homogeneous=False, dsn="mynetalias",
encoding="UTF-8")
.. code-block:: python
pool = cx_Oracle.SessionPool(externalauth=True, homogeneous=False,
dsn="mynetalias", encoding="UTF-8")
pool.acquire()
The ``dsn`` must match the one used in the wallet.
@ -1068,7 +1124,8 @@ Standalone connection example:
.. code-block:: python
# External Authentication with proxy
connection = cx_Oracle.connect(user="[mysessionuser]", dsn="mynetalias", encoding="UTF-8")
connection = cx_Oracle.connect(user="[mysessionuser]", dsn="mynetalias",
encoding="UTF-8")
# PROXY_USER: MYUSER
# SESSION_USER: MYSESSIONUSER
@ -1077,8 +1134,8 @@ Pooled connection example:
.. code-block:: python
# External Authentication with proxy
pool = cx_Oracle.SessionPool(externalauth=True, homogeneous=False, dsn="mynetalias",
encoding="UTF-8")
pool = cx_Oracle.SessionPool(externalauth=True, homogeneous=False,
dsn="mynetalias", encoding="UTF-8")
pool.acquire(user="[mysessionuser]")
# PROXY_USER: MYUSER
# SESSION_USER: MYSESSIONUSER
@ -1087,8 +1144,9 @@ The following usage is not supported:
.. code-block:: python
pool = cx_Oracle.SessionPool("[mysessionuser]", externalauth=True, homogeneous=False,
dsn="mynetalias", encoding="UTF-8")
pool = cx_Oracle.SessionPool(user="[mysessionuser]", externalauth=True,
homogeneous=False, dsn="mynetalias",
encoding="UTF-8")
pool.acquire()
@ -1119,7 +1177,9 @@ to implement OS Authentication on Linux.
CREATE USER ops$oracle IDENTIFIED EXTERNALLY;
GRANT CONNECT, RESOURCE TO ops$oracle;
In Python, connect using the following code::
In Python, connect using the following code:
.. code-block:: python
connection = cx_Oracle.connect(dsn="mynetalias", encoding="UTF-8")
@ -1144,8 +1204,9 @@ The example below shows how to connect to Oracle Database as SYSDBA:
.. code-block:: python
connection = cx_Oracle.connect("sys", syspwd, "dbhost.example.com/orclpdb1",
mode=cx_Oracle.SYSDBA, encoding="UTF-8")
connection = cx_Oracle.connect(user="sys", password=syspwd,
dsn="dbhost.example.com/orclpdb1",
mode=cx_Oracle.SYSDBA, encoding="UTF-8")
cursor = con.cursor()
sql = "GRANT SYSOPER TO hr"
@ -1232,8 +1293,8 @@ After connecting, passwords can be changed by calling
.. code-block:: python
# Get the passwords from somewhere, such as prompting the user
oldpwd = getpass.getpass("Old Password for %s: " % username)
newpwd = getpass.getpass("New Password for %s: " % username)
oldpwd = getpass.getpass(f"Old Password for {username}: ")
newpwd = getpass.getpass(f"New Password for {username}: ")
connection.changepassword(oldpwd, newpwd)
@ -1244,11 +1305,12 @@ of the function :meth:`cx_Oracle.connect()` constructor:
.. code-block:: python
# Get the passwords from somewhere, such as prompting the user
oldpwd = getpass.getpass("Old Password for %s: " % username)
newpwd = getpass.getpass("New Password for %s: " % username)
oldpwd = getpass.getpass(f"Old Password for {username}: ")
newpwd = getpass.getpass(f"New Password for {username}: ")
connection = cx_Oracle.connect(username, oldpwd, "dbhost.example.com/orclpdb1",
newpassword=newpwd, encoding="UTF-8")
connection = cx_Oracle.connect(user=username, password=oldpwd,
dsn="dbhost.example.com/orclpdb1",
newpassword=newpwd, encoding="UTF-8")
.. _autononmousdb:
@ -1293,7 +1355,8 @@ a net service name, for example:
.. code-block:: python
connection = cx_Oracle.connect("scott", userpwd, "cjdb1_high", encoding="UTF-8")
connection = cx_Oracle.connect(user="scott", password=userpwd,
dsn="cjdb1_high", encoding="UTF-8")
Once you have set Oracle environment variables required by your application,
such as ``TNS_ADMIN``, you can start your application.
@ -1314,13 +1377,13 @@ in the connect descriptor. Successful connection depends on specific proxy
configurations. Oracle does not recommend doing this when performance is
critical.
Edit ``sqlnet.ora`` and add a line:
Edit ``sqlnet.ora`` and add a line::
SQLNET.USE_HTTPS_PROXY=on
Edit ``tnsnames.ora`` and add an ``HTTPS_PROXY`` proxy name and
``HTTPS_PROXY_PORT`` port to the connect descriptor address list of any service
name you plan to use, for example:
name you plan to use, for example::
cjdb1_high = (description=
@ -1382,15 +1445,17 @@ then direct connection to a shard can be made by passing a single sharding key:
.. code-block:: python
connection = cx_Oracle.connect("hr", userpwd, "dbhost.example.com/orclpdb1",
encoding="UTF-8", shardingkey=["SCOTT"])
connection = cx_Oracle.connect(user="hr", password=userpwd,
dsn="dbhost.example.com/orclpdb1",
encoding="UTF-8", shardingkey=["SCOTT"])
Numbers keys can be used in a similar way:
.. code-block:: python
connection = cx_Oracle.connect("hr", userpwd, "dbhost.example.com/orclpdb1",
encoding="UTF-8", shardingkey=[110])
connection = cx_Oracle.connect(user="hr", password=userpwd,
dsn="dbhost.example.com/orclpdb1",
encoding="UTF-8", shardingkey=[110])
When sharding by DATE, you can connect like:
@ -1400,8 +1465,9 @@ When sharding by DATE, you can connect like:
d = datetime.datetime(2014, 7, 3)
connection = cx_Oracle.connect("hr", userpwd, "dbhost.example.com/orclpdb1",
encoding="UTF-8", shardingkey=[d])
connection = cx_Oracle.connect(user="hr", password=userpwd,
dsn="dbhost.example.com/orclpdb1",
encoding="UTF-8", shardingkey=[d])
When sharding by RAW, you can connect like:
@ -1409,21 +1475,26 @@ When sharding by RAW, you can connect like:
b = b'\x01\x04\x08';
connection = cx_Oracle.connect("hr", userpwd, "dbhost.example.com/orclpdb1",
encoding="UTF-8", shardingkey=[b])
connection = cx_Oracle.connect(user="hr", password=userpwd,
dsn="dbhost.example.com/orclpdb1",
encoding="UTF-8", shardingkey=[b])
Multiple keys can be specified, for example:
.. code-block:: python
keyArray = [70, "SCOTT", "gold", b'\x00\x01\x02']
key_list = [70, "SCOTT", "gold", b'\x00\x01\x02']
connection = cx_Oracle.connect("hr", userpwd, "dbhost.example.com/orclpdb1",
encoding="UTF-8", shardingkey=keyArray)
connection = cx_Oracle.connect(user="hr", password=userpwd,
dsn="dbhost.example.com/orclpdb1",
encoding="UTF-8", shardingkey=key_list)
A super sharding key example is:
.. code-block:: python
connection = cx_Oracle.connect("hr", userpwd, "dbhost.example.com/orclpdb1",
encoding="UTF-8", supershardingkey=["goldclass"], shardingkey=["SCOTT"])
connection = cx_Oracle.connect(user="hr", password=userpwd,
dsn="dbhost.example.com/orclpdb1",
encoding="UTF-8",
supershardingkey=["goldclass"],
shardingkey=["SCOTT"])

View File

@ -45,12 +45,14 @@ example:
.. code-block:: python
connection = cx_Oracle.connect(userName, password, "dbhost.example.com/orclpdb1", events=True)
connection = cx_Oracle.connect(user=user, password=password,
dsn="dbhost.example.com/orclpdb1",
events=True)
The default CQN connection mode means the database must be able to connect back
to the application using cx_Oracle in order to receive notification events.
Alternatively, when using Oracle Database and Oracle client libraries 19.4, or
later, subscriptions can set the optional ``clientInitiated`` parameter to
later, subscriptions can set the optional ``client_initiated`` parameter to
``True``, see ``Connection.subscribe()`` below.
The default CQN connection mode typically means that the machine running
@ -71,8 +73,7 @@ For example, a basic CQN subscription might be created like:
.. code-block:: python
connection.subscribe(namespace=cx_Oracle.SUBSCR_NAMESPACE_DBCHANGE,
callback=MyCallback)
connection.subscribe(callback=my_callback)
See :meth:`Connection.subscribe()` for details on all of the parameters.
@ -87,11 +88,11 @@ See :ref:`subscrobj` for more details on the subscription object that is
created.
When using Oracle Database and Oracle client libraries 19.4, or later, the
optional subscription parameter ``clientInitiated`` can be set:
optional subscription parameter ``client_initiated`` can be set:
.. code-block:: python
connection.subscribe(namespace= . . ., callback=MyCallback, clientInitiated=True)
connection.subscribe(callback=my_callback, client_initiated=True)
This enables CQN "client initiated" connections which internally use the same
approach as normal cx_Oracle connections to the database, and do not require the
@ -113,7 +114,7 @@ changes is:
.. code-block:: python
def CQNCallback(message):
def cqn_callback(message):
print("Notification:")
for query in message.queries:
for tab in query.tables:
@ -125,10 +126,9 @@ changes is:
if row.operation & cx_Oracle.OPCODE_DELETE:
print("DELETE of rowid:", row.rowid)
subscr = connection.subscribe(namespace=cx_Oracle.SUBSCR_NAMESPACE_DBCHANGE,
callback=CQNCallback,
operations=cx_Oracle.OPCODE_INSERT | cx_Oracle.OPCODE_DELETE,
qos = cx_Oracle.SUBSCR_QOS_QUERY | cx_Oracle.SUBSCR_QOS_ROWIDS)
subscr = connection.subscribe(callback=cqn_callback,
operations=cx_Oracle.OPCODE_INSERT | cx_Oracle.OPCODE_DELETE,
qos=cx_Oracle.SUBSCR_QOS_QUERY | cx_Oracle.SUBSCR_QOS_ROWIDS)
subscr.registerquery("select * from regions")
input("Hit enter to stop CQN demo\n")
@ -153,5 +153,5 @@ which should print something like the following::
INSERT of rowid: AAA7EsAAHAAAFS/AAA
See `GitHub Samples
<https://github.com/oracle/python-cx_Oracle/blob/master/samples/cqn.py>`__
<https://github.com/oracle/python-cx_Oracle/blob/main/samples/cqn.py>`__
for a runnable CQN example.

View File

@ -32,9 +32,9 @@ code can be used:
try:
cursor.execute("insert into customer values (101, 'Customer A')")
except cx_Oracle.IntegrityError as e:
errorObj, = e.args
error_obj, = e.args
print("Customer ID already exists")
print("Error Code:", errorObj.code)
print("Error Message:", errorObj.message)
print("Error Code:", error_obj.code)
print("Error Message:", error_obj.message)
else:
print("Customer added")

View File

@ -29,8 +29,12 @@ specify different Oracle Client character sets. For example:
.. code-block:: python
import cx_Oracle
connection = cx_Oracle.connect(connectString, encoding="US-ASCII",
nencoding="UTF-8")
connection = cx_Oracle.connect(dsn=connect_string, encoding="US-ASCII",
nencoding="UTF-8")
.. note::
In a future release of cx_Oracle, only UTF-8 will be supported.
The ``encoding`` parameter affects character data such as VARCHAR2 and CLOB
columns. The ``nencoding`` parameter affects "National Character" data such as
@ -66,8 +70,9 @@ database.
.. code-block:: python
connection = cx_Oracle.connect(userName, password, "dbhost.example.com/orclpdb1",
encoding="US-ASCII")
connection = cx_Oracle.connect(user=user, password=password,
dsn="dbhost.example.com/orclpdb1",
encoding="US-ASCII")
cursor = connection.cursor()
for row in cursor.execute("select nvarchar2_column from nchar_test"):
print(row)
@ -77,11 +82,13 @@ Because the '€' symbol is not supported by the ``US-ASCII`` character set, all
('¿',)
When the ``encoding`` parameter is removed (or set to "UTF-8") during connection:
When the ``encoding`` parameter is removed (or set to "UTF-8") during
connection:
.. code-block:: python
connection = cx_Oracle.connect(userName, password, "dbhost.example.com/orclpdb1")
connection = cx_Oracle.connect(user=user, password=password,
dsn="dbhost.example.com/orclpdb1")
Then the output displays the Euro symbol as desired::

View File

@ -212,5 +212,5 @@ In the Python application code:
the last call was completed successfully or not.
See the `Transaction Guard Sample
<https://github.com/oracle/python-cx_Oracle/blob/master/
<https://github.com/oracle/python-cx_Oracle/blob/main/
samples/transaction_guard.py>`__ for further details.

View File

@ -40,7 +40,7 @@ Support's `Doc ID 207303.1
you will need to have previously set your environment to use that
software installation, otherwise files such as message files will not be
located. On Windows when the path contains backslashes, use a 'raw'
string like ``lib_dir = r"C:\instantclient_19_6"``. If the Oracle Client
string like ``lib_dir=r"C:\instantclient_19_6"``. If the Oracle Client
libraries cannot be loaded from ``lib_dir``, then an exception is raised.
- If ``lib_dir`` was not specified, then Oracle Client libraries are looked
@ -164,7 +164,8 @@ example, if the Oracle Instant Client Libraries are in
"instantclient_19_8")
cx_Oracle.init_oracle_client(lib_dir=lib_dir)
elif sys.platform.startswith("win32"):
cx_Oracle.init_oracle_client(lib_dir=r"C:\oracle\instantclient_19_9")
lib_dir=r"C:\oracle\instantclient_19_9"
cx_Oracle.init_oracle_client(lib_dir=lib_dir)
except Exception as err:
print("Whoops!")
print(err);
@ -388,8 +389,8 @@ parameters is:
import sys
try:
cx_Oracle.init_oracle_client(driver_name = "My Great App : 3.1.4",
error_url: "https://example.com/MyInstallInstructions.html")
cx_Oracle.init_oracle_client(driver_name="My Great App : 3.1.4",
error_url="https://example.com/MyInstallInstructions.html")
except Exception as err:
print("Whoops!")
print(err);

View File

@ -12,15 +12,14 @@ To use cx_Oracle 8 with Python and Oracle Database you need:
- Python 3.5 and higher. Older versions of cx_Oracle may work with older
versions of Python.
- Oracle Client libraries. These can be from the free `Oracle Instant
Client
<https://www.oracle.com/database/technologies/instant-client.html>`__,
or those included in Oracle Database if Python is on the same
machine as the database. Oracle client libraries versions 19, 18, 12,
and 11.2 are supported on Linux, Windows and macOS (Intel x86). Users have
also reported success with other platforms. Use the latest client possible:
Oracle's standard client-server version interoperability allows connection to
both older and newer databases.
- Oracle Client libraries. These can be from the free `Oracle Instant Client
<https://www.oracle.com/database/technologies/instant-client.html>`__, from a
full Oracle Client installation, or from those included in Oracle Database if
Python is on the same machine as the database. Oracle client libraries
versions 21, 19, 18, 12, and 11.2 are supported where available on Linux,
Windows and macOS (Intel x86). Users have also reported success with other
platforms. Use the latest client possible: Oracle's standard client-server
version interoperability allows connection to both older and newer databases.
- An Oracle Database, either local or remote.
@ -36,6 +35,14 @@ product: it is how the Oracle Client and Oracle Database communicate.
Quick Start cx_Oracle Installation
==================================
The `Quick Start: Developing Python Applications for Oracle Database
<https://www.oracle.com/database/technologies/appdev/python/quickstartpythononprem.html>`__
and `Quick Start: Developing Python Applications for Oracle Autonomous Database
<https://www.oracle.com/database/technologies/appdev/python/quickstartpython.html>`__
instructions have steps for Windows, Linux, and macOS.
Alternatively you can:
- Install `Python <https://www.python.org/downloads>`__ 3, if not already
available. On macOS you must always install your own Python.
@ -63,7 +70,7 @@ Quick Start cx_Oracle Installation
If you are behind a proxy, add a proxy server to the command, for example add
``--proxy=http://proxy.example.com:80``
- Add Oracle 19, 18, 12 or 11.2 client libraries to your operating system
- Add Oracle 21, 19, 18, 12 or 11.2 client libraries to your operating system
library search path such as ``PATH`` on Windows or ``LD_LIBRARY_PATH`` on
Linux. On macOS use :meth:`~cx_Oracle.init_oracle_client()` in your
application to pass the Oracle Client directory name, see
@ -88,6 +95,7 @@ Quick Start cx_Oracle Installation
<https://www.oracle.com/database/technologies/appdev/xe.html>`__
release.
Version 21 client libraries can connect to Oracle Database 12.1 or greater.
Version 19, 18 and 12.2 client libraries can connect to Oracle Database 11.2
or greater. Version 12.1 client libraries can connect to Oracle Database 10.2
or greater. Version 11.2 client libraries can connect to Oracle Database 9.2
@ -102,7 +110,8 @@ Quick Start cx_Oracle Installation
import cx_Oracle
# Connect as user "hr" with password "welcome" to the "orclpdb1" service running on this computer.
connection = cx_Oracle.connect("hr", "welcome", "localhost/orclpdb1")
connection = cx_Oracle.connect(user="hr", password="welcome",
dsn="localhost/orclpdb1")
cursor = connection.cursor()
cursor.execute("""
@ -126,7 +135,7 @@ Quick Start cx_Oracle Installation
You can learn how to use cx_Oracle from the :ref:`API documentation <module>`
and `samples
<https://github.com/oracle/python-cx_Oracle/blob/master/samples>`__.
<https://github.com/oracle/python-cx_Oracle/blob/main/samples>`__.
If you run into installation trouble, check out the section on `Troubleshooting`_.
@ -150,12 +159,12 @@ connections between different versions of Oracle Client libraries and
Oracle Database. For certified configurations see Oracle Support's
`Doc ID 207303.1
<https://support.oracle.com/epmos/faces/DocumentDisplay?id=207303.1>`__.
In summary, Oracle Client 19, 18 and 12.2 can connect to Oracle Database 11.2 or
In summary, Oracle Client 21 can connect to Oracle Database 12.1 or greater.
Oracle Client 19, 18 and 12.2 can connect to Oracle Database 11.2 or
greater. Oracle Client 12.1 can connect to Oracle Database 10.2 or
greater. Oracle Client 11.2 can connect to Oracle Database 9.2 or
greater. The technical restrictions on creating connections may be
more flexible. For example Oracle Client 12.2 can successfully
connect to Oracle Database 10.2.
greater. Oracle Client 11.2 can connect to Oracle Database 9.2 or greater. The
technical restrictions on creating connections may be more flexible. For
example Oracle Client 12.2 can successfully connect to Oracle Database 10.2.
cx_Oracle uses the shared library loading mechanism available on each
supported platform to load the Oracle Client libraries at runtime. It
@ -169,26 +178,12 @@ file available with 12.1 or later clients, session pool improvements,
improved high availability features, call timeouts, and `other enhancements
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-D60519C3-406F-4588-8DA1-D475D5A3E1F6>`__.
The cx_Oracle function :func:`~cx_Oracle.clientversion()` can be used
to determine which Oracle Client version is in use and the attribute
:attr:`Connection.version` can be used to determine which Oracle
Database version a connection is accessing. These can then be used to
adjust application behavior accordingly. Attempts to use some Oracle
features that are not supported by a particular client/server
combination may result in runtime errors. These include:
- when attempting to access attributes that are not supported by the
current Oracle Client library you will get the error "ORA-24315: illegal
attribute type"
- when attempting to use implicit results with Oracle Client 11.2
against Oracle Database 12c you will get the error "ORA-29481:
Implicit results cannot be returned to client"
- when attempting to get array DML row counts with Oracle Client
11.2 you will get the error "DPI-1050: Oracle Client library must be at
version 12.1 or higher"
The cx_Oracle function :func:`~cx_Oracle.clientversion()` can be used to
determine which Oracle Client version is in use. The attribute
:attr:`Connection.version` can be used to determine which Oracle Database
version a connection is accessing. These can then be used to adjust application
behavior accordingly. Attempts to use Oracle features that are not supported by
a particular client/server library combination will result in runtime errors.
Installing cx_Oracle on Linux
=============================
@ -251,14 +246,15 @@ Oracle Instant Client Zip Files
To use cx_Oracle with Oracle Instant Client zip files:
1. Download an Oracle 19, 18, 12, or 11.2 "Basic" or "Basic Light" zip file: `64-bit
<https://www.oracle.com/database/technologies/instant-client/linux-x86-64-downloads.html>`__
or `32-bit
<https://www.oracle.com/database/technologies/instant-client/linux-x86-32-downloads.html>`__, matching your
Python architecture.
1. Download an Oracle 21, 19, 18, 12, or 11.2 "Basic" or "Basic Light" zip file
matching your Python 64-bit or 32-bit architecture:
The latest version is recommended. Oracle Instant Client 19 will
connect to Oracle Database 11.2 or later.
- `x86-64 64-bit <https://www.oracle.com/database/technologies/instant-client/linux-x86-64-downloads.html>`__
- `x86 32-bit <https://www.oracle.com/database/technologies/instant-client/linux-x86-32-downloads.html>`__
- `ARM (aarch64) 64-bit <https://www.oracle.com/database/technologies/instant-client/linux-arm-aarch64-downloads.html>`__
The latest version is recommended. Oracle Instant Client 21 will connect to
Oracle Database 12.1 or later.
2. Unzip the package into a single directory that is accessible to your
application. For example:
@ -267,7 +263,7 @@ To use cx_Oracle with Oracle Instant Client zip files:
mkdir -p /opt/oracle
cd /opt/oracle
unzip instantclient-basic-linux.x64-19.9.0.0.0dbru.zip
unzip instantclient-basic-linux.x64-21.1.0.0.0.zip
3. Install the ``libaio`` package with sudo or as the root user. For example::
@ -275,8 +271,8 @@ To use cx_Oracle with Oracle Instant Client zip files:
On some Linux distributions this package is called ``libaio1`` instead.
On recent Linux versions, such as Oracle Linux 8, you may also need to
install the ``libnsl`` package.
On recent Linux versions such as Oracle Linux 8, you may also need to
install the ``libnsl`` package when using Oracle Instant Client 19.
4. If there is no other Oracle software on the machine that will be
impacted, permanently add Instant Client to the runtime link
@ -284,14 +280,14 @@ To use cx_Oracle with Oracle Instant Client zip files:
.. code-block:: shell
sudo sh -c "echo /opt/oracle/instantclient_19_9 > /etc/ld.so.conf.d/oracle-instantclient.conf"
sudo sh -c "echo /opt/oracle/instantclient_21_1 > /etc/ld.so.conf.d/oracle-instantclient.conf"
sudo ldconfig
Alternatively, set the environment variable ``LD_LIBRARY_PATH`` to
the appropriate directory for the Instant Client version. For
example::
export LD_LIBRARY_PATH=/opt/oracle/instantclient_19_9:$LD_LIBRARY_PATH
export LD_LIBRARY_PATH=/opt/oracle/instantclient_21_1:$LD_LIBRARY_PATH
5. If you use optional Oracle configuration files such as ``tnsnames.ora``,
``sqlnet.ora`` or ``oraaccess.xml`` with Instant Client, then put the files
@ -306,7 +302,7 @@ To use cx_Oracle with Oracle Instant Client zip files:
Or set the environment variable ``TNS_ADMIN`` to that directory name.
Alternatively, put the files in the ``network/admin`` subdirectory of Instant
Client, for example in ``/opt/oracle/instantclient_19_9/network/admin``.
Client, for example in ``/opt/oracle/instantclient_21_1/network/admin``.
This is the default Oracle configuration directory for executables linked
with this Instant Client.
@ -315,35 +311,36 @@ Oracle Instant Client RPMs
To use cx_Oracle with Oracle Instant Client RPMs:
1. Download an Oracle 19, 18, 12, or 11.2 "Basic" or "Basic Light" RPM: `64-bit
<https://www.oracle.com/database/technologies/instant-client/linux-x86-64-downloads.html>`__
or `32-bit
<https://www.oracle.com/database/technologies/instant-client/linux-x86-32-downloads.html>`__, matching your
Python architecture.
1. Download an Oracle 21,19, 18, 12, or 11.2 "Basic" or "Basic Light" RPM
matching your Python architecture:
Oracle's yum server has `Instant Client RPMs for Oracle Linux 8
<https://yum.oracle.com/repo/OracleLinux/OL8/oracle/instantclient/x86_64/index.html>`__,
`Instant Client RPMs for Oracle Linux 7
<https://yum.oracle.com/repo/OracleLinux/OL7/oracle/instantclient/x86_64/index.html>`__
and `Instant Client RPMs for Oracle Linux 6
<https://yum.oracle.com/repo/OracleLinux/OL6/oracle/instantclient/x86_64/index.html>`__
that can be downloaded without needing a click-through.
- `x86-64 64-bit <https://www.oracle.com/database/technologies/instant-client/linux-x86-64-downloads.html>`__
- `x86 32-bit <https://www.oracle.com/database/technologies/instant-client/linux-x86-32-downloads.html>`__
- `ARM (aarch64) 64-bit <https://www.oracle.com/database/technologies/instant-client/linux-arm-aarch64-downloads.html>`__
The latest version is recommended. Oracle Instant Client 19 will
connect to Oracle Database 11.2 or later.
Oracle's yum server has convenient repositories:
- `Instant Client 21 RPMs for Oracle Linux x86-64 8 <https://yum.oracle.com/repo/OracleLinux/OL8/oracle/instantclient21/x86_64/index.html>`__, `Older Instant Client RPMs for Oracle Linux x86-64 8 <https://yum.oracle.com/repo/OracleLinux/OL8/oracle/instantclient/x86_64/index.html>`__
- `Instant Client 21 RPMs for Oracle Linux x86-64 7 <https://yum.oracle.com/repo/OracleLinux/OL7/oracle/instantclient21/x86_64/index.html>`__, `Older Instant Client RPMs for Oracle Linux x86-64 7 <https://yum.oracle.com/repo/OracleLinux/OL7/oracle/instantclient/x86_64/index.html>`__
- `Instant Client RPMs for Oracle Linux x86-64 6 <https://yum.oracle.com/repo/OracleLinux/OL6/oracle/instantclient/x86_64/index.html>`__
- `Instant Client RPMs for Oracle Linux ARM (aarch64) 8 <https://yum.oracle.com/repo/OracleLinux/OL8/oracle/instantclient/aarch64/index.html>`__
- `Instant Client RPMs for Oracle Linux ARM (aarch64) 7 <https://yum.oracle.com/repo/OracleLinux/OL7/oracle/instantclient/aarch64/index.html>`__
The latest version is recommended. Oracle Instant Client 21 will connect to
Oracle Database 12.1 or later.
2. Install the downloaded RPM with sudo or as the root user. For example:
.. code-block:: shell
sudo yum install oracle-instantclient19.9-basic-19.9.0.0.0-1.x86_64.rpm
sudo yum install oracle-instantclient-basic-21.1.0.0.0-1.x86_64.rpm
Yum will automatically install required dependencies, such as ``libaio``.
On recent Linux versions, such as Oracle Linux 8, you may need to manually
install the ``libnsl`` package.
install the ``libnsl`` package when using Oracle Instant Client 19.
3. For Instant Client 19, the system library search path is
3. For Instant Client 19, or later, the system library search path is
automatically configured during installation.
For older versions, if there is no other Oracle software on the machine that will be
@ -352,7 +349,7 @@ To use cx_Oracle with Oracle Instant Client RPMs:
.. code-block:: shell
sudo sh -c "echo /usr/lib/oracle/18.3/client64/lib > /etc/ld.so.conf.d/oracle-instantclient.conf"
sudo sh -c "echo /usr/lib/oracle/18.5/client64/lib > /etc/ld.so.conf.d/oracle-instantclient.conf"
sudo ldconfig
Alternatively, for version 18 and earlier, every shell running
@ -360,7 +357,7 @@ To use cx_Oracle with Oracle Instant Client RPMs:
``LD_LIBRARY_PATH`` set to the appropriate directory for the
Instant Client version. For example::
export LD_LIBRARY_PATH=/usr/lib/oracle/18.3/client64/lib:$LD_LIBRARY_PATH
export LD_LIBRARY_PATH=/usr/lib/oracle/18.5/client64/lib:$LD_LIBRARY_PATH
4. If you use optional Oracle configuration files such as ``tnsnames.ora``,
``sqlnet.ora`` or ``oraaccess.xml`` with Instant Client, then put the files
@ -375,14 +372,14 @@ To use cx_Oracle with Oracle Instant Client RPMs:
Or set the environment variable ``TNS_ADMIN`` to that directory name.
Alternatively, put the files in the ``network/admin`` subdirectory of Instant
Client, for example in ``/usr/lib/oracle/19.9/client64/lib/network/admin``.
Client, for example in ``/usr/lib/oracle/21/client64/lib/network/admin``.
This is the default Oracle configuration directory for executables linked
with this Instant Client.
Local Database or Full Oracle Client
++++++++++++++++++++++++++++++++++++
cx_Oracle applications can use Oracle Client 19, 18, 12, or 11.2 libraries
cx_Oracle applications can use Oracle Client 21, 19, 18, 12, or 11.2 libraries
from a local Oracle Database or full Oracle Client installation.
The libraries must be either 32-bit or 64-bit, matching your
@ -487,8 +484,8 @@ To use cx_Oracle with Oracle Instant Client zip files:
2. Unzip the package into a directory that is accessible to your
application. For example unzip
``instantclient-basic-windows.x64-19.9.0.0.0dbru.zip`` to
``C:\oracle\instantclient_19_9``.
``instantclient-basic-windows.x64-19.11.0.0.0dbru.zip`` to
``C:\oracle\instantclient_19_11``.
3. Oracle Instant Client libraries require a Visual Studio redistributable with
a 64-bit or 32-bit architecture to match Instant Client's architecture.
@ -511,7 +508,7 @@ Configure Oracle Instant Client
.. code-block:: python
import cx_Oracle
cx_Oracle.init_oracle_client(lib_dir=r"C:\oracle\instantclient_19_9")
cx_Oracle.init_oracle_client(lib_dir=r"C:\oracle\instantclient_19_11")
Note a 'raw' string is used because backslashes occur in the path.
@ -536,14 +533,14 @@ Configure Oracle Instant Client
.. code-block:: python
import cx_Oracle
cx_Oracle.init_oracle_client(lib_dir=r"C:\oracle\instantclient_19_9",
cx_Oracle.init_oracle_client(lib_dir=r"C:\oracle\instantclient_19_11",
config_dir=r"C:\oracle\your_config_dir")
Or set the environment variable ``TNS_ADMIN`` to that directory name.
Alternatively, put the files in a ``network\admin`` subdirectory of
Instant Client, for example in
``C:\oracle\instantclient_19_9\network\admin``. This is the default
``C:\oracle\instantclient_19_11\network\admin``. This is the default
Oracle configuration directory for executables linked with this
Instant Client.
@ -630,6 +627,8 @@ Manual Installation
/Volumes/instantclient-basic-macos.x64-19.8.0.0.0dbru/install_ic.sh
This copies the contents to ``$HOME/Downloads/instantclient_19_8``.
Applications may not have access to the ``Downloads`` directory, so you
should move Instant Client somewhere convenient.
* In Finder, eject the mounted Instant Client package.
@ -651,6 +650,8 @@ Instant Client installation can alternatively be scripted, for example:
hdiutil unmount /Volumes/instantclient-basic-macos.x64-19.8.0.0.0dbru
The Instant Client directory will be ``$HOME/Downloads/instantclient_19_8``.
Applications may not have access to the ``Downloads`` directory, so you should
move Instant Client somewhere convenient.
Configure Oracle Instant Client
@ -682,6 +683,20 @@ Configure Oracle Instant Client
default Oracle configuration directory for executables linked with this
Instant Client.
Linux Containers
================
Sample Dockerfiles are on `GitHub
<https://github.com/oracle/docker-images/tree/main/OracleLinuxDevelopers>`__.
Pre-built images for Python and cx_Oracle are in the `GitHub Container Registry
<https://github.com/orgs/oracle/packages>`__. These are easily used. For
example, to pull an Oracle Linux 8 image with Python 3.6 and cx_Oracle,
execute::
docker pull ghcr.io/oracle/oraclelinux7-python:3.6-oracledb
Installing cx_Oracle without Internet Access
============================================
@ -711,10 +726,10 @@ you will also need to download an `ODPI-C
<https://github.com/oracle/odpi>`__ source zip file and extract it
inside the directory called "odpi".
cx_Oracle source code is also available from oss.oracle.com. This can
cx_Oracle source code is also available from opensource.oracle.com. This can
be cloned with::
git clone git://oss.oracle.com/git/oracle/python-cx_Oracle.git cx_Oracle
git clone git://opensource.oracle.com/git/oracle/python-cx_Oracle.git cx_Oracle
cd cx_Oracle
git submodule init
git submodule update
@ -734,8 +749,8 @@ which the following commands should be run::
Upgrading from Older Versions
=============================
Review the :ref:`release notes <releasenotes>` for deprecations and modify any
affected code.
Review the :ref:`release notes <releasenotes>` and :ref:`Deprecations
<deprecations>` for changes. Modify affected code.
If you are upgrading from cx_Oracle 7 note these changes:

View File

@ -23,12 +23,15 @@ the same machine as Python, or it can be remote.
cx_Oracle is typically installed from `PyPI
<https://pypi.org/project/cx-Oracle/>`__ using `pip
<https://pip.pypa.io/en/latest/installing/>`__. The Oracle Client
libraries need to be installed separately. The libraries can be obtained from
an installation of `Oracle Instant Client
<https://pip.pypa.io/en/latest/installing/>`__. The Oracle Client libraries
need to be installed separately. The libraries can be from an installation of
`Oracle Instant Client
<https://www.oracle.com/database/technologies/instant-client.html>`__, from a
full Oracle Client installation, or even from an Oracle Database installation
(if Python is running on the same machine as the database).
(if Python is running on the same machine as the database). Oracles standard
client-server version interoperability allows connection to both older and
newer databases from different Client library versions, see :ref:`cx_Oracle
Installation <installation>`.
Some behaviors of the Oracle Client libraries can optionally be configured with
an ``oraaccess.xml`` file, for example to enable auto-tuning of a statement
@ -74,20 +77,21 @@ Create a script ``query.py`` as shown below:
import cx_Oracle
# Establish the database connection
connection = cx_Oracle.connect("hr", userpwd, "dbhost.example.com/orclpdb1")
connection = cx_Oracle.connect(user="hr", password=userpwd,
dsn="dbhost.example.com/orclpdb1")
# Obtain a cursor
cursor = connection.cursor()
# Data for binding
managerId = 145
firstName = "Peter"
manager_id = 145
first_name = "Peter"
# Execute the query
sql = """SELECT first_name, last_name
FROM employees
WHERE manager_id = :mid AND first_name = :fn"""
cursor.execute(sql, mid = managerId, fn = firstName)
cursor.execute(sql, mid=manager_id, fn=first_name)
# Loop over the result set
for row in cursor:
@ -127,8 +131,14 @@ The output is::
Examples and Tutorials
----------------------
The `Quick Start: Developing Python Applications for Oracle Database
<https://www.oracle.com/database/technologies/appdev/python/quickstartpythononprem.html>`__
and `Quick Start: Developing Python Applications for Oracle Autonomous Database
<https://www.oracle.com/database/technologies/appdev/python/quickstartpython.html>`__
instructions have steps for Windows, Linux, and macOS.
Runnable examples are in the `GitHub samples directory
<https://github.com/oracle/python-cx_Oracle/tree/master/samples>`__. A `Python
<https://github.com/oracle/python-cx_Oracle/tree/main/samples>`__. A `Python
cx_Oracle tutorial
<https://oracle.github.io/python-cx_Oracle/samples/tutorial/Python-and-Oracle-Database-Scripting-for-the-Future.html>`__
is also available.

View File

@ -29,7 +29,7 @@ cx_Oracle. This makes LOBs easy to work with, and has significant performance
benefits over streaming. However it requires the entire LOB data to be present
in Python memory, which may not be possible.
See `GitHub <https://github.com/oracle/python-cx_Oracle/tree/master/samples>`__ for LOB examples.
See `GitHub <https://github.com/oracle/python-cx_Oracle/tree/main/samples>`__ for LOB examples.
Simple Insertion of LOBs
@ -51,15 +51,15 @@ bytes as needed:
.. code-block:: python
with open('example.txt', 'r') as f:
textdata = f.read()
text_data = f.read()
with open('image.png', 'rb') as f:
imgdata = f.read()
img_data = f.read()
cursor.execute("""
insert into lob_tbl (id, c, b)
values (:lobid, :clobdata, :blobdata)""",
lobid=10, clobdata=textdata, blobdata=imgdata)
lobid=10, clobdata=text_data, blobdata=img_data)
Note that with this approach, LOB data is limited to 1 GB in size.
@ -76,25 +76,25 @@ to be used as shown in this example:
.. code-block:: python
def OutputTypeHandler(cursor, name, defaultType, size, precision, scale):
if defaultType == cx_Oracle.DB_TYPE_CLOB:
def output_type_handler(cursor, name, default_type, size, precision, scale):
if default_type == cx_Oracle.DB_TYPE_CLOB:
return cursor.var(cx_Oracle.DB_TYPE_LONG, arraysize=cursor.arraysize)
if defaultType == cx_Oracle.DB_TYPE_BLOB:
if default_type == cx_Oracle.DB_TYPE_BLOB:
return cursor.var(cx_Oracle.DB_TYPE_LONG_RAW, arraysize=cursor.arraysize)
idVal = 1
textData = "The quick brown fox jumps over the lazy dog"
bytesData = b"Some binary data"
id_val = 1
text_data = "The quick brown fox jumps over the lazy dog"
binary_data = b"Some binary data"
cursor.execute("insert into lob_tbl (id, c, b) values (:1, :2, :3)",
[idVal, textData, bytesData])
[id_val, text_data, binary_data])
connection.outputtypehandler = OutputTypeHandler
cursor.execute("select c, b from lob_tbl where id = :1", [idVal])
clobData, blobData = cursor.fetchone()
print("CLOB length:", len(clobData))
print("CLOB data:", clobData)
print("BLOB length:", len(blobData))
print("BLOB data:", blobData)
connection.outputtypehandler = output_type_handler
cursor.execute("select c, b from lob_tbl where id = :1", [id_val])
clob_data, blob_data = cursor.fetchone()
print("CLOB length:", len(clob_data))
print("CLOB data:", clob_data)
print("BLOB length:", len(blob_data))
print("BLOB data:", blob_data)
This displays::
@ -114,13 +114,13 @@ calling :meth:`LOB.size()` and the data can be read by calling
.. code-block:: python
idVal = 1
textData = "The quick brown fox jumps over the lazy dog"
bytesData = b"Some binary data"
id_val = 1
text_data = "The quick brown fox jumps over the lazy dog"
binary_data = b"Some binary data"
cursor.execute("insert into lob_tbl (id, c, b) values (:1, :2, :3)",
[idVal, textData, bytesData])
[id_val, text_data, binary_data])
cursor.execute("select b, c from lob_tbl where id = :1", [idVal])
cursor.execute("select b, c from lob_tbl where id = :1", [id_val])
b, c = cursor.fetchone()
print("CLOB length:", c.size())
print("CLOB data:", c.read())
@ -140,13 +140,13 @@ repeatedly until all of the data has been read, as shown below:
cursor.execute("select b from lob_tbl where id = :1", [10])
blob, = cursor.fetchone()
offset = 1
numBytesInChunk = 65536
num_bytes_in_chunk = 65536
with open("image.png", "wb") as f:
while True:
data = blob.read(offset, numBytesInChunk)
data = blob.read(offset, num_bytes_in_chunk)
if data:
f.write(data)
if len(data) < numBytesInChunk:
if len(data) < num_bytes_in_chunk:
break
offset += len(data)
@ -161,21 +161,21 @@ in the following code:
.. code-block:: python
idVal = 9
lobVar = cursor.var(cx_Oracle.DB_TYPE_BLOB)
id_val = 9
lob_var = cursor.var(cx_Oracle.DB_TYPE_BLOB)
cursor.execute("""
insert into lob_tbl (id, b)
values (:1, empty_blob())
returning b into :2""", [idVal, lobVar])
returning b into :2""", [id_val, lob_var])
blob, = lobVar.getvalue()
offset = 1
numBytesInChunk = 65536
num_bytes_in_chunk = 65536
with open("image.png", "rb") as f:
while True:
data = f.read(numBytesInChunk)
data = f.read(num_bytes_in_chunk)
if data:
blob.write(data, offset)
if len(data) < numBytesInChunk:
if len(data) < num_bytes_in_chunk:
break
offset += len(data)
connection.commit()

View File

@ -30,16 +30,16 @@ then the following Python code can be used to call it:
.. code-block:: python
outVal = cursor.var(int)
cursor.callproc('myproc', [123, outVal])
print(outVal.getvalue()) # will print 246
out_val = cursor.var(int)
cursor.callproc('myproc', [123, out_val])
print(out_val.getvalue()) # will print 246
Calling :meth:`Cursor.callproc()` actually generates an anonymous PL/SQL block
as shown below, which is then executed:
.. code-block:: python
cursor.execute("begin myproc(:1,:2); end;", [123, outval])
cursor.execute("begin myproc(:1,:2); end;", [123, out_val])
See :ref:`bind` for information on binding.
@ -71,8 +71,8 @@ then the following Python code can be used to call it:
.. code-block:: python
returnVal = cursor.callfunc("myfunc", int, ["a string", 15])
print(returnVal) # will print 38
return_val = cursor.callfunc("myfunc", int, ["a string", 15])
print(return_val) # will print 38
A more complex example that returns a spatial (SDO) object can be seen below.
First, the SQL statements necessary to set up the example:
@ -104,10 +104,10 @@ The Python code that will call this procedure looks as follows:
.. code-block:: python
objType = connection.gettype("SDO_POINT_TYPE")
obj_type = connection.gettype("SDO_POINT_TYPE")
cursor = connection.cursor()
returnVal = cursor.callfunc("spatial_queryfn", objType, [1])
print("(%d, %d, %d)" % (returnVal.X, returnVal.Y, returnVal.Z))
return_val = cursor.callfunc("spatial_queryfn", obj_type, [1])
print(f"({return_val.X}, {return_val.Y}, {return_val.Z})")
# will print (125, 375, 0)
See :ref:`bind` for information on binding.
@ -123,8 +123,8 @@ An anonymous PL/SQL block can be called as shown:
var = cursor.var(int)
cursor.execute("""
begin
:outVal := length(:inVal);
end;""", inVal="A sample string", outVal=var)
:out_val := length(:in_val);
end;""", in_val="A sample string", out_val=var)
print(var.getvalue()) # will print 15
See :ref:`bind` for information on binding.
@ -223,18 +223,18 @@ This will produce the following output::
This is the cx_Oracle manual
Demonstrating use of DBMS_OUTPUT
An alternative is to call ``DBMS_OUTPUT.GET_LINE()`` once per output line, which
may be much slower:
An alternative is to call ``DBMS_OUTPUT.GET_LINE()`` once per output line,
which may be much slower:
.. code-block:: python
textVar = cursor.var(str)
statusVar = cursor.var(int)
text_var = cursor.var(str)
status_var = cursor.var(int)
while True:
cursor.callproc("dbms_output.get_line", (textVar, statusVar))
if statusVar.getvalue() != 0:
cursor.callproc("dbms_output.get_line", (text_var, status_var))
if status_var.getvalue() != 0:
break
print(textVar.getvalue())
print(text_var.getvalue())
Implicit results
----------------
@ -260,8 +260,8 @@ An example using implicit results is as shown:
dbms_sql.return_result(sales_cur);
end;""")
for implicitCursor in cursor.getimplicitresults():
for row in implicitCursor:
for implicit_cursor in cursor.getimplicitresults():
for row in implicit_cursor:
print(row)
Data from both the result sets are returned::
@ -289,8 +289,9 @@ The simplest way to set an edition is to pass the ``edition`` parameter to
.. code-block:: python
connection = cx_Oracle.connect("hr", userpwd, "dbhost.example.com/orclpdb1",
edition="newsales", encoding="UTF-8")
connection = cx_Oracle.connect(user="hr", password=userpwd,
dsn="dbhost.example.com/orclpdb1",
edition="newsales", encoding="UTF-8")
The edition could also be set by setting the environment variable
@ -353,22 +354,24 @@ function as shown:
.. code-block:: python
connection = cx_Oracle.connect(<username>, <password>, "dbhost.example.com/orclpdb1",
encoding="UTF-8")
connection = cx_Oracle.connect(user=user, password=password,
dsn="dbhost.example.com/orclpdb1",
encoding="UTF-8")
print("Edition is:", repr(connection.edition))
cursor = connection.cursor()
discountedPrice = cursor.callfunc("Discount", int, [100])
print("Price after discount is:", discountedPrice)
discounted_price = cursor.callfunc("Discount", int, [100])
print("Price after discount is:", discounted_price)
# Use the edition parameter for the connection
connection = cx_Oracle.connect(<username>, <password>, "dbhost.example.com/orclpdb1",
edition = "demo", encoding="UTF-8")
connection = cx_Oracle.connect(user=user, password=password,
dsn="dbhost.example.com/orclpdb1",
edition="demo", encoding="UTF-8")
print("Edition is:", repr(connection.edition))
cursor = connection.cursor()
discountedPrice = cursor.callfunc("Discount", int, [100])
print("Price after discount is:", discountedPrice)
discounted_price = cursor.callfunc("Discount", int, [100])
print("Price after discount is:", discounted_price)
The output of the function call for the default and demo edition is as shown::

View File

@ -73,53 +73,6 @@ cx_Oracle uses the following objects for SODA:
then used by a terminal method to find, count, replace, or remove documents.
This is an internal object that should not be directly accessed.
.. _sodametadatacache:
Using the SODA Metadata Cache
=============================
SODA metadata can be cached to improve the performance of
:meth:`SodaDatabase.createCollection()` and
:meth:`SodaDatabase.openCollection()` by reducing :ref:`round-trips
<roundtrips>` to the database. Caching is available with Oracle Client 21.3 (or
later). The feature is also available in Oracle Client 19 from 19.11 onwards.
Note: if collection metadata changes are made externally, the cache can become
invalid.
Caching can be enabled for pooled connections but not standalone connections.
Each pool has its own cache. Applications using standalone connections should
retain and reuse the :ref:`collection <sodacoll>` returned from
``createCollection()`` or ``openCollection()`` wherever possible, instead of
making repeated calls to those methods.
The metadata cache can be turned on when creating a connection pool
with :meth:`cx_Oracle.SessionPool()`:
.. code-block:: python
# Create the session pool
pool = cx_Oracle.SessionPool("hr", userpwd, "dbhost.example.com/orclpdb1",
soda_metadata_cache=True)
Note the cache is not used by ``createCollection()`` when explicitly passing
metadata. In this case, instead of using only ``createCollection()`` and
relying on its behavior of opening an existing collection like:
.. code-block:: python
mymetadata = { . . . }
collection = soda.createCollection("mycollection", mymetadata) # open existing or create new collection
collection.insertOne(mycontent)
you may find it more efficient to use logic similar to:
.. code-block:: python
collection = soda.openCollection("mycollection")
if (collection is None):
mymetadata = { . . . }
collection = soda.createCollection("mycollection", mymetadata)
collection.insertOne(mycontent)
SODA Examples
=============
@ -138,8 +91,8 @@ Creating and adding documents to a collection can be done as follows:
# document, the content can be a simple Python dictionary which will
# internally be converted to a JSON document
content = {'name': 'Matilda', 'address': {'city': 'Melbourne'}}
returnedDoc = collection.insertOneAndGet(content)
key = returnedDoc.key
returned_doc = collection.insertOneAndGet(content)
key = returned_doc.key
print('The key of the new SODA document is: ', key)
By default, a system generated key is created when documents are inserted.
@ -163,12 +116,65 @@ You can also search for documents using query-by-example syntax:
print(content["name"])
See the `samples directory
<https://github.com/oracle/python-cx_Oracle/tree/master/samples>`__
<https://github.com/oracle/python-cx_Oracle/tree/main/samples>`__
for runnable SODA examples.
--------------------
.. _sodametadatacache:
Using the SODA Metadata Cache
=============================
SODA metadata can be cached to improve the performance of
:meth:`SodaDatabase.createCollection()` and
:meth:`SodaDatabase.openCollection()` by reducing :ref:`round-trips
<roundtrips>` to the database. Caching is available with Oracle Client 21.3 (or
later). The feature is also available in Oracle Client 19 from 19.11 onwards.
Note: if collection metadata changes are made externally, the cache can become
invalid. If this happens, the cache can be cleared by calling
:meth:`SessionPool.reconfigure()` with ``soda_metadata_cache`` set to `False`,
or by setting the attribute :attr:`SessionPool.soda_metadata_cache` to `False`.
A second call to ``reconfigure()`` or a direct setting of the
``soda_metadata_cache`` attribute can then be performed to re-enable the cache.
Caching can be enabled for pooled connections but not standalone
connections. Applications using standalone connections should retain and reuse
the :ref:`collection <sodacoll>` returned from ``createCollection()`` or
``openCollection()`` wherever possible, instead of making repeated calls to
those methods.
The metadata cache can be turned on when creating a connection pool with
:meth:`cx_Oracle.SessionPool()`. Each pool has its own cache:
.. code-block:: python
# Create the session pool
pool = cx_Oracle.SessionPool(user="hr", password=userpwd,
dsn="dbhost.example.com/orclpdb1",
soda_metadata_cache=True)
Note the cache is not used by ``createCollection()`` when explicitly passing
metadata. In this case, instead of using only ``createCollection()`` and
relying on its behavior of opening an existing collection like:
.. code-block:: python
mymetadata = { . . . }
collection = soda.createCollection("mycollection", mymetadata) # open existing or create new collection
collection.insertOne(mycontent)
you will find it more efficient to use logic similar to:
.. code-block:: python
collection = soda.openCollection("mycollection")
if collection is None:
mymetadata = { . . . }
collection = soda.createCollection("mycollection", mymetadata)
collection.insertOne(mycontent)
Committing SODA Work
--------------------
====================
The general recommendation for SODA applications is to turn on
:attr:`~Connection.autocommit` globally:

View File

@ -19,7 +19,7 @@ contain information on specific data types and features. See :ref:`batchstmnt`,
cx_Oracle can be used to execute individual statements, one at a time. It does
not read SQL*Plus ".sql" files. To read SQL files, use a technique like the one
in ``run_sql_script()`` in `samples/sample_env.py
<https://github.com/oracle/python-cx_Oracle/blob/master/samples/sample_env.py>`__
<https://github.com/oracle/python-cx_Oracle/blob/main/samples/sample_env.py>`__
SQL statements should not contain a trailing semicolon (";") or forward slash
("/"). This will fail:
@ -87,9 +87,9 @@ which defaults to the value of :attr:`Cursor.arraysize`.
cur = connection.cursor()
cur.execute("select * from MyTable")
numRows = 10
num_rows = 10
while True:
rows = cur.fetchmany(numRows)
rows = cur.fetchmany(num_rows)
if not rows:
break
for row in rows:
@ -289,7 +289,7 @@ should be used.
Examples of output handlers are shown in :ref:`numberprecision`,
:ref:`directlobs` and :ref:`fetching-raw-data`. Also see samples such as `samples/type_handlers.py
<https://github.com/oracle/python-cx_Oracle/blob/master/samples/type_handlers.py>`__
<https://github.com/oracle/python-cx_Oracle/blob/main/samples/type_handlers.py>`__
.. _numberprecision:
@ -324,12 +324,12 @@ Using Python decimal objects, however, there is no loss of precision:
import decimal
def NumberToDecimal(cursor, name, defaultType, size, precision, scale):
if defaultType == cx_Oracle.DB_TYPE_NUMBER:
def number_to_decimal(cursor, name, default_type, size, precision, scale):
if default_type == cx_Oracle.DB_TYPE_NUMBER:
return cursor.var(decimal.Decimal, arraysize=cursor.arraysize)
cur = connection.cursor()
cur.outputtypehandler = NumberToDecimal
cur.outputtypehandler = number_to_decimal
cur.execute("select * from test_float")
val, = cur.fetchone()
print(val, "* 3 =", val * 3)
@ -341,7 +341,7 @@ representation of the Oracle number. The output from ``decimal.Decimal`` is
returned in the output tuple.
See `samples/return_numbers_as_decimals.py
<https://github.com/oracle/python-cx_Oracle/blob/master/samples/return_numbers_as_decimals.py>`__
<https://github.com/oracle/python-cx_Oracle/blob/main/samples/return_numbers_as_decimals.py>`__
.. _outconverters:
@ -356,16 +356,17 @@ For example, to make queries return empty strings instead of NULLs:
.. code-block:: python
def OutConverter(value):
def out_converter(value):
if value is None:
return ''
return value
def OutputTypeHandler(cursor, name, defaultType, size, precision, scale):
if defaultType in (cx_Oracle.DB_TYPE_VARCHAR, cx_Oracle.DB_TYPE_CHAR):
return cursor.var(str, size, cur.arraysize, outconverter=OutConverter)
def output_type_handler(cursor, name, default_type, size, precision, scale):
if default_type in (cx_Oracle.DB_TYPE_VARCHAR, cx_Oracle.DB_TYPE_CHAR):
return cursor.var(str, size, arraysize=cur.arraysize,
outconverter=out_converter)
connection.outputtypehandler = OutputTypeHandler
connection.outputtypehandler = output_type_handler
.. _rowfactories:
@ -673,15 +674,15 @@ The following sample demonstrates how to use this feature:
# define output type handler
def return_strings_as_bytes(cursor, name, default_type, size,
precision, scale):
if default_type == cx_Oracle.DB_TYPE_VARCHAR:
return cursor.var(str, arraysize=cursor.arraysize,
if default_type == cx_Oracle.DB_TYPE_VARCHAR:
return cursor.var(str, arraysize=cursor.arraysize,
bypass_decode=True)
# set output type handler on cursor before fetching data
with connection.cursor() as cursor:
cursor.outputtypehandler = return_strings_as_bytes
cursor.execute("select content, charset from SomeTable")
data = cursor.fetchall()
# set output type handler on cursor before fetching data
with connection.cursor() as cursor:
cursor.outputtypehandler = return_strings_as_bytes
cursor.execute("select content, charset from SomeTable")
data = cursor.fetchall()
This will produce output as::
@ -708,13 +709,13 @@ using a Python string, you will need to create a variable using
with cx_Oracle.connect(user="hr", password=userpwd,
dsn="dbhost.example.com/orclpdb1") as conn:
with conn.cursor() cursor:
var = cursor.var(cx_Oracle.DB_TYPE_VARCHAR)
var.setvalue(0, b"Fianc\xc4\x9b")
cursor.execute("""
update SomeTable set
SomeColumn = :param
where id = 1""",
param=var)
var = cursor.var(cx_Oracle.DB_TYPE_VARCHAR)
var.setvalue(0, b"Fianc\xc4\x9b")
cursor.execute("""
update SomeTable set
SomeColumn = :param
where id = 1""",
param=var)
.. warning::
@ -737,8 +738,9 @@ then:
.. code-block:: python
connection = cx_Oracle.connect("hr", userpwd, "dbhost.example.com/orclpdb1",
encoding="UTF-8", nencoding="UTF-8")
connection = cx_Oracle.connect(user="hr", password=userpwd,
dsn="dbhost.example.com/orclpdb1",
encoding="UTF-8", nencoding="UTF-8")
* Check for corrupt data in the database.
@ -746,21 +748,21 @@ If data really is corrupt, you can pass options to the internal `decode()
<https://docs.python.org/3/library/stdtypes.html#bytes.decode>`__ used by
cx_Oracle to allow it to be selected and prevent the whole query failing. Do
this by creating an :ref:`outputtypehandler <outputtypehandlers>` and setting
``encodingErrors``. For example to replace corrupt characters in character
``encoding_errors``. For example to replace corrupt characters in character
columns:
.. code-block:: python
def OutputTypeHandler(cursor, name, defaultType, size, precision, scale):
if defaultType == cx_Oracle.STRING:
return cursor.var(defaultType, size, arraysize=cursor.arraysize,
encodingErrors="replace")
def output_type_handler(cursor, name, default_type, size, precision, scale):
if default_type == cx_Oracle.DB_TYPE_VARCHAR:
return cursor.var(default_type, size, arraysize=cursor.arraysize,
encoding_errors="replace")
cursor.outputtypehandler = OutputTypeHandler
cursor.outputtypehandler = output_type_handler
cursor.execute("select column1, column2 from SomeTableWithBadData")
Other codec behaviors can be chosen for ``encodingErrors``, see `Error Handlers
Other codec behaviors can be chosen for ``encoding_errors``, see `Error Handlers
<https://docs.python.org/3/library/codecs.html#error-handlers>`__.
.. _dml:
@ -797,7 +799,7 @@ SDO_GEOMETRY <spatial>` object:
.. code-block:: python
typeObj = connection.gettype("SDO_GEOMETRY")
type_obj = connection.gettype("SDO_GEOMETRY")
cur = connection.cursor()
cur.setinputsizes(typeObj)
cur.setinputsizes(type_obj)
cur.execute("insert into sometable values (:1)", [None])

View File

@ -20,12 +20,11 @@ of the database that should be started:
.. code-block:: python
# the connection must be in PRELIM_AUTH mode to perform startup
connection = cx_Oracle.connect("/",
mode = cx_Oracle.SYSDBA | cx_Oracle.PRELIM_AUTH)
connection = cx_Oracle.connect(mode=cx_Oracle.SYSDBA | cx_Oracle.PRELIM_AUTH)
connection.startup()
# the following statements must be issued in normal SYSDBA mode
connection = cx_Oracle.connect("/", mode = cx_Oracle.SYSDBA, encoding="UTF-8")
connection = cx_Oracle.connect(mode=cx_Oracle.SYSDBA, encoding="UTF-8")
cursor = connection.cursor()
cursor.execute("alter database mount")
cursor.execute("alter database open")
@ -48,11 +47,11 @@ connection. This example also assumes that the environment variable
.. code-block:: python
# need to connect as SYSDBA or SYSOPER
connection = cx_Oracle.connect("/", mode = cx_Oracle.SYSDBA)
connection = cx_Oracle.connect(mode=cx_Oracle.SYSDBA)
# first shutdown() call must specify the mode, if DBSHUTDOWN_ABORT is used,
# there is no need for any of the other steps
connection.shutdown(mode = cx_Oracle.DBSHUTDOWN_IMMEDIATE)
connection.shutdown(mode=cx_Oracle.DBSHUTDOWN_IMMEDIATE)
# now close and dismount the database
cursor = connection.cursor()
@ -60,4 +59,4 @@ connection. This example also assumes that the environment variable
cursor.execute("alter database dismount")
# perform the final shutdown call
connection.shutdown(mode = cx_Oracle.DBSHUTDOWN_FINAL)
connection.shutdown(mode=cx_Oracle.DBSHUTDOWN_FINAL)

View File

@ -18,15 +18,15 @@ in the custom subclass, so application code does not need to supply them.
.. code-block:: python
class Connection(cx_Oracle.Connection):
logFileName = "log.txt"
log_file_name = "log.txt"
def __init__(self):
connectString = "hr/hr_password@dbhost.example.com/orclpdb1"
connect_string = "hr/hr_password@dbhost.example.com/orclpdb1"
self._log("Connect to the database")
return super(Connection, self).__init__(connectString)
return super(Connection, self).__init__(connect_string)
def _log(self, message):
with open(self.logFileName, "a") as f:
with open(self.log_file_name, "a") as f:
print(message, file=f)
def execute(self, sql, parameters):
@ -35,8 +35,9 @@ in the custom subclass, so application code does not need to supply them.
try:
return cursor.execute(sql, parameters)
except cx_Oracle.Error as e:
errorObj, = e.args
self._log(errorObj.message)
error_obj, = e.args
self._log(error_obj.message)
raise
connection = Connection()
connection.execute("""
@ -65,7 +66,7 @@ instead::
In production applications be careful not to log sensitive information.
See `Subclassing.py
<https://github.com/oracle/python-cx_Oracle/blob/master/
<https://github.com/oracle/python-cx_Oracle/blob/main/
samples/subclassing.py>`__ for an example.

View File

@ -200,18 +200,18 @@ data from one database to another:
.. code-block:: python
# setup cursors
sourceCursor = sourceConnection.cursor()
sourceCursor.arraysize = 1000
targetCursor = targetConnection.cursor()
source_cursor = source_connection.cursor()
source_cursor.arraysize = 1000
target_cursor = target_connection.cursor()
# perform fetch and bulk insertion
sourceCursor.execute("select * from MyTable")
source_cursor.execute("select * from MyTable")
while True:
rows = sourceCursor.fetchmany()
rows = source_cursor.fetchmany()
if not rows:
break
targetCursor.executemany("insert into MyTable values (:1, :2)", rows)
targetConnection.commit()
target_cursor.executemany("insert into MyTable values (:1, :2)", rows)
target_connection.commit()
Tuning REF CURSORS
++++++++++++++++++

View File

@ -49,17 +49,17 @@ records:
.. code-block:: python
# Add a new customer
idVar = cursor.var(int)
id_var = cursor.var(int)
connection.autocommit = False # make sure any previous value is off
cursor.execute("""
INSERT INTO cust_table (name) VALUES ('John')
RETURNING id INTO :bvid""", bvid=idVar)
RETURNING id INTO :bvid""", bvid=id_var)
# Add sales data for the new customer and commit all new values
idVal = idVar.getvalue()[0]
id_val = id_var.getvalue()[0]
connection.autocommit = True
cursor.execute("INSERT INTO sales_table VALUES (:bvid, 'pens', 3000)",
bvid=idVal)
bvid=id_val)
Explicit Transactions

View File

@ -22,7 +22,7 @@ Inserting into the table can be done by simply binding a string as shown:
.. code-block:: python
xmlData = """<?xml version="1.0"?>
xml_data = """<?xml version="1.0"?>
<customer>
<name>John Smith</name>
<Age>43</Age>
@ -30,7 +30,7 @@ Inserting into the table can be done by simply binding a string as shown:
<Subject>Mathematics</Subject>
</customer>"""
cursor.execute("insert into xml_table values (:id, :xml)",
id=1, xml=xmlData)
id=1, xml=xml_data)
This approach works with XML strings up to 1 GB in size. For longer strings, a
temporary CLOB must be created using :meth:`Connection.createlob()` and bound
@ -39,9 +39,9 @@ as shown:
.. code-block:: python
clob = connection.createlob(cx_Oracle.DB_TYPE_CLOB)
clob.write(xmlData)
clob.write(xml_data)
cursor.execute("insert into xml_table values (:id, sys.xmltype(:xml))",
id=2, xml=clob)
id=2, xml=clob)
Fetching XML data can be done simply for values that are shorter than the
length of a VARCHAR2 column, as shown:
@ -49,8 +49,8 @@ length of a VARCHAR2 column, as shown:
.. code-block:: python
cursor.execute("select xml_data from xml_table where id = :id", id=1)
xmlData, = cursor.fetchone()
print(xmlData) # will print the string that was originally stored
xml_data, = cursor.fetchone()
print(xml_data) # will print the string that was originally stored
For values that exceed the length of a VARCHAR2 column, a CLOB must be returned
instead by using the function ``XMLTYPE.GETCLOBVAL()`` as shown:

View File

@ -36,10 +36,10 @@ This directory contains samples for [cx_Oracle][6]. Documentation is [here][7].
sqlplus sys/syspassword@hostname/servicename @sql/drop_samples.sql
[1]: https://github.com/oracle/python-cx_Oracle/blob/master/samples/setup_samples.py
[2]: https://github.com/oracle/python-cx_Oracle/blob/master/samples/sample_env.py
[3]: https://github.com/oracle/python-cx_Oracle/blob/master/samples/sql/setup_samples.sql
[4]: https://github.com/oracle/python-cx_Oracle/blob/master/samples/drop_samples.py
[5]: https://github.com/oracle/python-cx_Oracle/blob/master/samples/sql/drop_samples.sql
[1]: https://github.com/oracle/python-cx_Oracle/blob/main/samples/setup_samples.py
[2]: https://github.com/oracle/python-cx_Oracle/blob/main/samples/sample_env.py
[3]: https://github.com/oracle/python-cx_Oracle/blob/main/samples/sql/setup_samples.sql
[4]: https://github.com/oracle/python-cx_Oracle/blob/main/samples/drop_samples.py
[5]: https://github.com/oracle/python-cx_Oracle/blob/main/samples/sql/drop_samples.sql
[6]: https://oracle.github.io/python-cx_Oracle/
[7]: http://cx-oracle.readthedocs.org/en/latest/index.html

View File

@ -117,7 +117,7 @@
href="http://cx-oracle.readthedocs.org/en/latest/index.html" >cx_Oracle
documention</a>. </p>
<p>The master copy of these instructions that you are reading is <a
<p>The original copy of these instructions that you are reading is <a
href="https://oracle.github.io/python-cx_Oracle/samples/tutorial/Python-and-Oracle-Database-Scripting-for-the-Future.html"
>here</a>.</p>
@ -165,9 +165,9 @@
<li>
<h4>Download the tutorial scripts</h4>
<p>The Python scripts used in this example are in the <a href="https://github.com/oracle/python-cx_Oracle/tree/master/samples/tutorial" >cx_Oracle GitHub repository</a>.</p>
<p>The Python scripts used in this example are in the <a href="https://github.com/oracle/python-cx_Oracle/tree/main/samples/tutorial" >cx_Oracle GitHub repository</a>.</p>
<p>Download a zip file of the repository from <a href="https://github.com/oracle/python-cx_Oracle/archive/master.zip" >here</a> and unzip it. Alternatively you can use 'git' to clone the repository with <code>git clone https://github.com/oracle/python-cx_Oracle.git</code></p>
<p>Download a zip file of the repository from <a href="https://github.com/oracle/python-cx_Oracle/archive/main.zip" >here</a> and unzip it. Alternatively you can use 'git' to clone the repository with <code>git clone https://github.com/oracle/python-cx_Oracle.git</code></p>
<p>The <code>samples/tutorial</code> directory has scripts to run and
modify. The <code>samples/tutorial/solutions</code> directory has scripts

View File

@ -10,7 +10,7 @@ license = BSD License
url = https://oracle.github.io/python-cx_Oracle
project_urls =
Installation = https://cx-oracle.readthedocs.io/en/latest/user_guide/installation.html
Samples = https://github.com/oracle/python-cx_Oracle/tree/master/samples
Samples = https://github.com/oracle/python-cx_Oracle/tree/main/samples
Documentation = http://cx-oracle.readthedocs.io
Release Notes = https://cx-oracle.readthedocs.io/en/latest/release_notes.html#releasenotes
Issues = https://github.com/oracle/python-cx_Oracle/issues

View File

@ -46,8 +46,8 @@ This directory contains the test suite for cx_Oracle.
sqlplus system/systempassword@hostname/servicename @sql/drop_test.sql
[1]: https://github.com/oracle/python-cx_Oracle/blob/master/test/setup_test.py
[2]: https://github.com/oracle/python-cx_Oracle/blob/master/test/test_env.py
[3]: https://github.com/oracle/python-cx_Oracle/blob/master/test/sql/setup_test.sql
[4]: https://github.com/oracle/python-cx_Oracle/blob/master/test/drop_test.py
[5]: https://github.com/oracle/python-cx_Oracle/blob/master/test/sql/drop_test.sql
[1]: https://github.com/oracle/python-cx_Oracle/blob/main/test/setup_test.py
[2]: https://github.com/oracle/python-cx_Oracle/blob/main/test/test_env.py
[3]: https://github.com/oracle/python-cx_Oracle/blob/main/test/sql/setup_test.sql
[4]: https://github.com/oracle/python-cx_Oracle/blob/main/test/drop_test.py
[5]: https://github.com/oracle/python-cx_Oracle/blob/main/test/sql/drop_test.sql