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:
parent
97be497fc9
commit
4ed562c205
10
README.md
10
README.md
@ -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
|
||||
|
||||
@ -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::
|
||||
|
||||
|
||||
@ -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::
|
||||
|
||||
@ -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()`
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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'
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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``.
|
||||
|
||||
@ -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 Oracle’s 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"])
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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")
|
||||
|
||||
@ -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::
|
||||
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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:
|
||||
|
||||
|
||||
@ -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). Oracle’s 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.
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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::
|
||||
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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])
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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.
|
||||
|
||||
|
||||
|
||||
@ -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
|
||||
++++++++++++++++++
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user