Compare commits

...

39 Commits
v8.2.x ... main

Author SHA1 Message Date
Anthony Tuininga 6766bcaf27 Update ReadTheDocs configuration to avoid deprecation warnings with
ReadTheDocs.
2023-08-16 18:33:24 -06:00
Anthony Tuininga a05b9a5233 Add more doc redirects. 2023-06-03 09:37:29 -06:00
Anthony Tuininga 5cfbb7d9e4 Remove semicolons in Python code examples (resolves #629). 2022-06-08 13:12:35 -06:00
Anthony Tuininga fde577bf1f python-oracledb 1.0.0 has been released! 2022-05-25 14:43:26 -06:00
Anthony Tuininga 1ad43aa912 Doc improvements. 2022-05-25 14:41:35 -06:00
Anthony Tuininga 3db3e3772e Fix stale OCA link. 2022-05-25 14:40:44 -06:00
Anthony Tuininga 59c41535e3 Improved AQ test. 2022-05-25 14:37:50 -06:00
Anthony Tuininga 5728cf534e Try newer version of Sphinx. 2021-11-04 16:02:28 -06:00
Anthony Tuininga 3a40eeacaa ReadTheDocs only supports up to Python 3.8. 2021-11-04 15:58:51 -06:00
Anthony Tuininga fde9ec78fc ReadTheDocs requires configuration so make it happy. 2021-11-04 15:57:32 -06:00
Anthony Tuininga 45118e0c31 Preparing to release cx_Oracle 8.3. 2021-11-04 13:20:41 -06:00
Anthony Tuininga 29ca919445 Add official support for Python 3.10. 2021-11-04 13:20:11 -06:00
Anthony Tuininga ae687ce736 Improve documentation for WHERE IN clauses. 2021-11-04 13:19:26 -06:00
Anthony Tuininga 2d33fec37a Test suite improvements. 2021-11-04 13:19:04 -06:00
Anthony Tuininga 9db9d6907a Batch loading documentation improvements. 2021-11-04 13:16:44 -06:00
Anthony Tuininga 00dc44eade Update ODPI-C. 2021-11-04 11:30:34 -06:00
Anthony Tuininga 76157dd28a Add note that change to MessageProperties.msgid marked the attribute
read only.
2021-09-04 14:40:55 -06:00
Anthony Tuininga 83148ec574 Added test cases to verify that MessageProperties.msgid is calculated
correctly.
2021-09-03 13:57:20 -06:00
Anthony Tuininga eb37d27464 Documentation improvements. 2021-09-03 11:00:47 -06:00
Anthony Tuininga 05a9097847 Add more tests. 2021-09-03 10:57:19 -06:00
Anthony Tuininga 438c885c20 Correct calculation of MessageProperties.msgid. 2021-09-03 10:56:24 -06:00
Anthony Tuininga 1347b04976 Update ODPI-C. 2021-09-02 11:16:16 -06:00
Anthony Tuininga 702a91be51 Update ODPI-C. 2021-09-01 11:12:51 -06:00
Anthony Tuininga 08117db459 Expand ADB documentation. 2021-07-26 13:32:18 -06:00
Anthony Tuininga 440163efe5 Improved samples and test suite. 2021-07-26 13:31:57 -06:00
Anthony Tuininga c665d2efca Update formatting links. 2021-07-26 13:28:32 -06:00
Anthony Tuininga dfeebc3358 Update ODPI-C. 2021-07-26 13:28:02 -06:00
Anthony Tuininga 5cce9efd49 Minor tweak to samples README. 2021-06-08 11:15:44 -06:00
Anthony Tuininga cc067bf83e Binary integer variables now explicitly convert values to integers (since
implicit conversion to integer has become an error in Python 3.10) and
values that are not `int`, `float` or `decimal.Decimal` are explicitly
rejected.
2021-06-08 11:15:13 -06:00
Anthony Tuininga abb666706b Update ODPI-C. 2021-06-08 11:14:34 -06:00
Anthony Tuininga 4229a6d8ad cx_Oracle 8.2.1 is about to be released. 2021-06-01 13:02:07 -06:00
Anthony Tuininga 59558714ac Update SODA doc. 2021-06-01 12:03:03 -06:00
Anthony Tuininga a61b14a5c6 Update ODPI-C. 2021-06-01 12:00:42 -06:00
Anthony Tuininga 5dccb9fb5f Use PEP 8 variable names. 2021-05-28 14:48:38 -06:00
Anthony Tuininga 206e85e4a2 Update ODPI-C. 2021-05-28 14:48:05 -06:00
Anthony Tuininga df80067f47 Update ODPI-C. 2021-05-21 21:39:27 -06:00
Anthony Tuininga d585cf06df Fixed crash when using the deprecated parameter name keywordParameters
with Cursor.callproc(); add test cases to cover this and other similar
situations.
2021-05-21 21:38:45 -06:00
Anthony Tuininga ce4713c6f7 Fix typo. 2021-05-21 21:36:58 -06:00
Anthony Tuininga 31d94e7bf1 Bump version in preparation for new changes being made. 2021-05-21 21:36:30 -06:00
102 changed files with 1384 additions and 475 deletions

View File

@ -15,7 +15,7 @@ See https://www.oracle.com/corporate/security-practices/assurance/vulnerability/
Please answer these questions so we can help you.
Use Markdown syntax, see https://help.github.com/github/writing-on-github/basic-writing-and-formatting-syntax
Use Markdown syntax, see https://docs.github.com/github/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax
-->

View File

@ -13,7 +13,7 @@ Thank you for using cx_Oracle.
Please answer these questions so we can help you.
Use Markdown syntax, see https://help.github.com/github/writing-on-github/basic-writing-and-formatting-syntax
Use Markdown syntax, see https://docs.github.com/github/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax
-->

View File

@ -15,7 +15,7 @@ Review existing enhancement requests: https://github.com/oracle/python-cx_Oracle
Please answer these questions so we can help you.
Use Markdown syntax, see https://help.github.com/github/writing-on-github/basic-writing-and-formatting-syntax
Use Markdown syntax, see https://docs.github.com/github/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax
-->

View File

@ -15,7 +15,7 @@ Review the user manual: https://cx-oracle.readthedocs.io/en/latest/index.html
Please answer these questions so we can help you.
Use Markdown syntax, see https://help.github.com/github/writing-on-github/basic-writing-and-formatting-syntax
Use Markdown syntax, see https://docs.github.com/github/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax
GitHub issues that are not updated for a month may be automatically closed. Feel free to update them at any time.

View File

@ -1,8 +1,7 @@
Thanks for contributing!
Before submitting PRs for cx_Oracle you must have your signed *Oracle
Contributor Agreement* accepted. See
https://www.oracle.com/technetwork/community/oca-486395.html
Contributor Agreement* accepted. See https://oca.opensource.oracle.com
If the problem solved is small, you may find it easier to open an Issue
describing the problem and its cause so we can create the fix.

16
.readthedocs.yaml Normal file
View File

@ -0,0 +1,16 @@
# required
version: 2
build:
os: ubuntu-20.04
tools:
python: "3.9"
# Build documentation in the doc/src directory with Sphinx
sphinx:
configuration: doc/src/conf.py
# declare Python requirements required to build docs
python:
install:
- requirements: doc/requirements.txt

View File

@ -1,4 +1,18 @@
# cx_Oracle version 8.2
# Python cx_Oracle
# News
**cx_Oracle has a major new release under a new name and homepage
[python-oracledb](https://oracle.github.io/python-oracledb/).**
**The source code has moved to
[github.com/oracle/python-oracledb](https://github.com/oracle/python-oracledb).**
New projects should install python-oracledb instead of cx_Oracle. Critical
patches and binary packages for new Python releases may continue to be made in
the cx_Oracle namespace for a limited time, subject to demand.
# About
cx_Oracle is a Python extension module that enables access to Oracle
Database. It conforms to the [Python database API 2.0
@ -7,12 +21,12 @@ of exclusions. See the
[homepage](https://oracle.github.io/python-cx_Oracle/index.html) for a
feature list.
cx_Oracle 8.2 has been tested with Python versions 3.6 through 3.9. You can use
cx_Oracle with Oracle 11.2, 12c, 18c, 19c and 21c client libraries. Oracle's
standard client-server version interoperability allows connection to both older
and newer databases. For example Oracle 19c client libraries can connect to
Oracle Database 11.2. Older versions of cx_Oracle may work with older
versions of Python.
cx_Oracle 8.3 was tested with Python versions 3.6 through 3.10. You can
use cx_Oracle with Oracle 11.2, 12c, 18c, 19c and 21c client libraries.
Oracle's standard client-server version interoperability allows connection to
both older and newer databases. For example Oracle 19c client libraries can
connect to Oracle Database 11.2. Older versions of cx_Oracle may work with
older versions of Python.
## Installation
@ -45,10 +59,10 @@ See [CONTRIBUTING](https://github.com/oracle/python-cx_Oracle/blob/main/CONTRIBU
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
[1]: https://peps.python.org/pep-0249/
[2]: https://cx-oracle.readthedocs.io
[3]: https://github.com/oracle/python-cx_Oracle/blob/main/LICENSE.txt
[5]: http://lists.sourceforge.net/lists/listinfo/cx-oracle-users
[5]: https://sourceforge.net/projects/cx-oracle/lists/cx-oracle-users
[6]: https://github.com/oracle/python-cx_Oracle/tree/main/samples/tutorial
[7]: http://cx-oracletools.sourceforge.net
[8]: http://cx-pyoraclelib.sourceforge.net

View File

@ -1,5 +1,7 @@
Please see the cx_Oracle home page for links to documentation, source, build
and installation instructions:
An enhanced cx_Oracle release is now under the python-oracledb namespace. See
https://oracle.github.io/python-oracledb/index.html for how to install and use
this updated driver.
For information about cx_Oracle itself, see
https://oracle.github.io/python-cx_Oracle/index.html

2
doc/requirements.txt Normal file
View File

@ -0,0 +1,2 @@
sphinx>=4.2.0
sphinx-rtd-theme>=0.5.2

View File

@ -4,6 +4,13 @@
Advanced Queuing (AQ)
*********************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
See :ref:`aqusermanual` for more information about using AQ in cx_Oracle.
.. note::
@ -321,8 +328,9 @@ Message Properties
.. attribute:: MessageProperties.msgid
This attribute specifies the id of the message in the last queue that
generated this message.
This read-only attribute specifies the id of the message in the last queue
that enqueued or dequeued the message. If the message has never been
dequeued or enqueued, the value will be `None`.
.. attribute:: MessageProperties.payload

View File

@ -4,6 +4,13 @@
Connection Object
*****************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
.. note::
Any outstanding changes will be rolled back when the connection object

View File

@ -5,6 +5,13 @@ Cursor Object
*************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
.. method:: Cursor.__enter__()
The entry point for the cursor as a context manager. It returns itself.
@ -290,7 +297,7 @@ Cursor Object
See :ref:`fetching` for an example.
.. method:: Cursor.fetchmany(num_rows=cursor.arraysize)
.. method:: Cursor.fetchmany(numRows=cursor.arraysize)
Fetch the next set of rows of a query result, returning a list of tuples.
An empty list is returned if no more rows are available. Note that the

View File

@ -4,6 +4,13 @@
Deprecations
************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
The following tables contains all of the deprecations in the cx_Oracle API,
when they were first deprecated and a comment on what should be used instead,
if applicable. The most recent deprecations are listed first.

View File

@ -4,6 +4,13 @@
LOB Objects
***********
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
See :ref:`lobdata` for more information about using LOBs.
.. note::

View File

@ -6,6 +6,13 @@
Module Interface
****************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
.. data:: __future__
Special object which contains attributes which control the behavior of
@ -40,7 +47,7 @@ Module Interface
mode=cx_Oracle.DEFAULT_AUTH, handle=0, pool=None, threaded=False, \
events=False, cclass=None, purity=cx_Oracle.ATTR_PURITY_DEFAULT, \
newpassword=None, encoding=None, nencoding=None, edition=None, \
appcontext=[], tag=None, matchanytag=None, shardingkey=[], \
appcontext=[], tag=None, matchanytag=False, shardingkey=[], \
supershardingkey=[], stmtcachesize=20)
Connection(user=None, password=None, dsn=None, \
mode=cx_Oracle.DEFAULT_AUTH, handle=0, pool=None, threaded=False, \

View File

@ -4,6 +4,13 @@
Object Type Objects
*******************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
.. note::
This object is an extension to the DB API. It is returned by the

View File

@ -4,6 +4,13 @@
SessionPool Object
******************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
.. note::
This object is an extension to the DB API.
@ -160,7 +167,7 @@ SessionPool Object
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.
``acquire()`` and is not recommended.
Prior to cx_Oracle 8.2, the ping interval was fixed at 60 seconds.

View File

@ -4,6 +4,13 @@
SODA
****
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
`Oracle Database Simple Oracle Document Access (SODA)
<https://docs.oracle.com/en/database/oracle/simple-oracle-document-access>`__
allows documents to be inserted, queried, and retrieved from Oracle Database
@ -256,11 +263,16 @@ 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 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).
format as a SQL hint but without any comment characters, for example
``hint="MONITOR"``. Pass only the hint ``"MONITOR"`` (turn on monitoring)
or ``"NO_MONITOR"`` (turn off monitoring). See the Oracle Database SQL
Tuning Guide documentation `MONITOR and NO_MONITOR Hints
<https://www.oracle.com/pls/topic/lookup?
ctx=dblatest&id=GUID-19E0F73C-A959-41E4-A168-91E436DEE1F1>`__
and `Monitoring Database Operations
<https://www.oracle.com/pls/topic/lookup?
ctx=dblatest&id=GUID-C941CE9D-97E1-42F8-91ED-4949B2B710BF>`__
for more information.
.. note::
@ -270,7 +282,8 @@ SODA Collection Object
.. versionchanged:: 8.2
The parameter `hint` was added.
The parameter `hint` was added. Use of the hint parameter requires
Oracle Client 21.3 or higher (or Oracle Client 19 from 19.11).
.. method:: SodaCollection.insertOne(doc)
@ -290,17 +303,23 @@ 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 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).
format as a SQL hint but without any comment characters, for example
``hint="MONITOR"``. Pass only the hint ``"MONITOR"`` (turn on monitoring)
or ``"NO_MONITOR"`` (turn off monitoring). See the Oracle Database SQL
Tuning Guide documentation `MONITOR and NO_MONITOR Hints
<https://www.oracle.com/pls/topic/lookup?
ctx=dblatest&id=GUID-19E0F73C-A959-41E4-A168-91E436DEE1F1>`__
and `Monitoring Database Operations
<https://www.oracle.com/pls/topic/lookup?
ctx=dblatest&id=GUID-C941CE9D-97E1-42F8-91ED-4949B2B710BF>`__
for more information.
.. versionadded:: 7.0
.. versionchanged:: 8.2
The parameter `hint` was added.
The parameter `hint` was added. Use of the hint parameter requires
Oracle Client 21.3 or higher (or Oracle Client 19 from 19.11).
.. attribute:: SodaCollection.metadata
@ -343,11 +362,16 @@ 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 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).
format as a SQL hint but without any comment characters, for example
``hint="MONITOR"``. Pass only the hint ``"MONITOR"`` (turn on monitoring)
or ``"NO_MONITOR"`` (turn off monitoring). See the Oracle Database SQL
Tuning Guide documentation `MONITOR and NO_MONITOR Hints
<https://www.oracle.com/pls/topic/lookup?
ctx=dblatest&id=GUID-19E0F73C-A959-41E4-A168-91E436DEE1F1>`__
and `Monitoring Database Operations
<https://www.oracle.com/pls/topic/lookup?
ctx=dblatest&id=GUID-C941CE9D-97E1-42F8-91ED-4949B2B710BF>`__
for more information.
This method requires Oracle Client 19.9 or higher in addition to the usual
SODA requirements.
@ -356,7 +380,8 @@ SODA Collection Object
.. versionchanged:: 8.2
The parameter `hint` was added.
The parameter `hint` was added. Use of the hint parameter requires
Oracle Client 21.3 or higher (or Oracle Client 19 from 19.11).
.. method:: SodaCollection.truncate()
@ -565,15 +590,22 @@ SODA Operation Object
.. method:: SodaOperation.hint(value)
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 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).
performed. This is expected to be a string in the same format as a SQL hint
but without any comment characters, for example ``hint("MONITOR")``. Pass
only the hint ``"MONITOR"`` (turn on monitoring) or ``"NO_MONITOR"`` (turn
off monitoring). See the Oracle Database SQL Tuning Guide documentation
`MONITOR and NO_MONITOR Hints
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-19E0F73C-A959-41E4-A168-91E436DEE1F1>`__
and `Monitoring Database Operations
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-C941CE9D-97E1-42F8-91ED-4949B2B710BF>`__
for more information.
As a convenience, the SodaOperation object is returned so that further
criteria can be specified by chaining methods together.
Use of this method requires Oracle Client 21.3 or higher (or Oracle Client
19 from 19.11).
.. versionadded:: 8.2

View File

@ -4,6 +4,13 @@
Subscription Object
*******************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
.. note::
This object is an extension the DB API.

View File

@ -4,6 +4,13 @@
Variable Objects
****************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
.. note::
The DB API definition does not define this object.

View File

@ -40,9 +40,9 @@ author = 'Oracle'
# other places throughout the built documents.
#
# The short X.Y version.
version = '8.2'
version = '8.3'
# The full version, including alpha/beta/rc tags.
release = '8.2.0'
release = '8.3.0'
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:

View File

@ -1,10 +1,17 @@
Welcome to cx_Oracle's documentation!
=====================================
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
**cx_Oracle** is a module that enables access to Oracle Database and conforms
to the Python database API specification. This module is currently tested
against Oracle Client 21c, 19c, 18c, 12c, and 11.2, and Python 3.6, 3.7, 3.8
and 3.9. Older versions of cx_Oracle may be used with previous Python
against Oracle Client 21c, 19c, 18c, 12c, and 11.2, and Python 3.6, 3.7, 3.8,
3.9 and 3.10. Older versions of cx_Oracle may be used with previous Python
releases.
**cx_Oracle** is distributed under an open-source :ref:`license <license>`

View File

@ -5,8 +5,49 @@
cx_Oracle Release Notes
=======================
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
For any deprecations, see :ref:`Deprecations <deprecations>`.
Version 8.3 (November 2021)
---------------------------
#) Updated embedded ODPI-C to `version 4.3.0
<https://oracle.github.io/odpi/doc/releasenotes.html#
version-4-3-november-4-2021>`__.
#) Added official support for Python 3.10.
#) Support for dequeuing messages from Oracle Transactional Event Queue (TEQ)
queues was restored.
#) Corrected calculation of attribute :data:`MessageProperties.msgid`. Note
that the attribute is now also read only.
#) Binary integer variables now explicitly convert values to integers (since
implicit conversion to integer has become an error in Python 3.10) and
values that are not `int`, `float` or `decimal.Decimal` are explicitly
rejected.
#) Improved samples and test suite.
Version 8.2.1 (June 2021)
-------------------------
#) Updated embedded ODPI-C to `version 4.2.1
<https://oracle.github.io/odpi/doc/releasenotes.html#
version-4-2-1-june-1-2021>`__.
#) Added support for caching the database version in pooled connections with
Oracle Client 19 and earlier (later Oracle Clients handle this caching
internally). This optimization eliminates a round-trip previously often
required when reusing a pooled connection.
#) Fixed a regression with error messages when creating a connection fails.
#) Fixed crash when using the deprecated parameter name `keywordParameters`
with :meth:`Cursor.callproc()`.
#) Improved documentation and the test suite.
Version 8.2 (May 2021)
----------------------

View File

@ -4,6 +4,13 @@
Oracle Advanced Queuing (AQ)
****************************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
`Oracle Advanced Queuing
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=ADQUE>`__ is a highly
configurable and scalable messaging feature of Oracle Database. It has

View File

@ -4,6 +4,13 @@
Batch Statement Execution and Bulk Loading
******************************************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
Inserting or updating multiple rows can be performed efficiently with
:meth:`Cursor.executemany()`, making it easy to work with large data sets with
cx_Oracle. This method can significantly outperform repeated calls to
@ -238,7 +245,7 @@ processing will be sufficient.
Loading CSV Files into Oracle Database
======================================
The :meth:`Cursor.executemany()` method and `csv module
The :meth:`Cursor.executemany()` method and Python's `csv module
<https://docs.python.org/3/library/csv.html#module-csv>`__ can be used to
efficiently load CSV (Comma Separated Values) files. For example, consider the
file ``data.csv``::
@ -255,21 +262,24 @@ And the schema:
create table test (id number, name varchar2(25));
Instead of looping through each line of the CSV file and inserting it
individually, you can insert batches of records using
:meth:`Cursor.executemany()`:
Data loading can be done in batches of records since the number of records may
prevent all data being inserted at once:
.. code-block:: python
import cx_Oracle
import csv
. . .
# Predefine the memory areas to match the table definition
# Predefine the memory areas to match the table definition.
# This can improve performance by avoiding memory reallocations.
# Here, one parameter is passed for each of the columns.
# "None" is used for the ID column, since the size of NUMBER isn't
# variable. The "25" matches the maximum expected data size for the
# NAME column
cursor.setinputsizes(None, 25)
# Adjust the batch size to meet your memory and performance requirements
# Adjust the number of rows to be inserted in each iteration
# to meet your memory and performance requirements
batch_size = 10000
with open('testsp.csv', 'r') as csv_file:
@ -284,3 +294,8 @@ individually, you can insert batches of records using
if data:
cursor.executemany(sql, data)
con.commit()
Depending on data sizes and business requirements, database changes such as
temporarily disabling redo logging on the table, or disabling indexes may also
be beneficial.

View File

@ -4,6 +4,13 @@
Using Bind Variables
********************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
SQL and PL/SQL statements that pass data to and from Oracle Database should use
placeholders in SQL and PL/SQL statements that mark where data is supplied or
returned. These placeholders are referred to as bind variables or bind
@ -681,8 +688,9 @@ objects seamlessly:
Binding Multiple Values to a SQL WHERE IN Clause
================================================
To use an IN clause with multiple values in a WHERE clause, you must define and
bind multiple values. You cannot bind an array of values. For example:
To use a SQL IN clause with multiple values, use one bind variable per
value. You cannot directly bind a Python list or dictionary to a single bind
variable. For example, to use two values in an IN clause:
.. code-block:: python
@ -694,18 +702,18 @@ bind multiple values. You cannot bind an array of values. For example:
for row in cursor:
print(row)
This will produce the following output::
This gives the output::
(159, 'Lindsey', 'Smith')
(171, 'William', 'Smith')
(176, 'Jonathon', 'Taylor')
(180, 'Winston', 'Taylor')
If this sort of query is executed multiple times with differing numbers of
values, a bind variable should be included for each possible value up to the
maximum number of values that can be provided. Missing values can be bound with
the value ``None``. For example, if the query above is used for up to 5 values,
the code should be adjusted as follows:
If the query is executed multiple times with differing numbers of values, a
bind variable should be included for each possible value. When the statement is
executed but the maximum number of values has not been supplied, the value
``None`` can be bound for missing values. For example, if the query above is
used for up to 5 values, the code would be:
.. code-block:: python
@ -717,31 +725,56 @@ the code should be adjusted as follows:
for row in cursor:
print(row)
This will produce the same output as the original example.
This will produce the same output as the original example. Reusing the same SQL
statement like this for a variable number of values, instead of constructing a
unique statement per set of values, allows best reuse of Oracle Database
resources.
If the number of values is only going to be known at runtime, then a SQL
statement can be built up as follows:
However, if the statement is not going to be re-executed, or the number of
values is only going to be known at runtime, then a SQL statement can be built
up as follows:
.. code-block:: python
bindValues = ["Gates", "Marvin", "Fay"]
bindNames = [":" + str(i + 1) for i in range(len(bindValues))]
bind_values = ["Gates", "Marvin", "Fay"]
bind_names = [":" + str(i + 1) for i in range(len(bind_values))]
sql = "select employee_id, first_name, last_name from employees " + \
"where last_name in (%s)" % (",".join(bindNames))
cursor.execute(sql, bindValues)
"where last_name in (%s)" % (",".join(bind_names))
cursor.execute(sql, bind_values)
for row in cursor:
print(row)
Another solution for a larger number of values is to construct a SQL
A general solution for a larger number of values is to construct a SQL
statement like::
SELECT ... WHERE col IN ( <something that returns a list of rows> )
SELECT ... WHERE col IN ( <something that returns a list of values> )
The easiest way to do the '<something that returns a list of rows>'
will depend on how the data is initially represented and the number of
items. You might look at using CONNECT BY or nested tables. Or,
for really large numbers of items, you might prefer to use a global
temporary table.
The best way to do the '<something that returns a list of values>' will depend
on how the data is initially represented and the number of items. You might
look at using CONNECT BY or at using a global temporary table.
One method is to use an Oracle collection with the ``TABLE()`` clause. For
example, if the following type was created::
SQL> CREATE OR REPLACE TYPE name_array AS TABLE OF VARCHAR2(25);
2 /
then the application could do:
.. code-block:: python
type_obj = connection.gettype("NAME_ARRAY")
obj = type_obj.newobject()
obj.extend(["Smith", "Taylor"])
cursor.execute("""select employee_id, first_name, last_name
from employees
where last_name in (select * from table(:1))""",
[obj])
for row in cursor:
print(row)
For efficiency, retain the return value of ``gettype()`` for reuse instead of
making repeated calls to get the type information.
Binding Column and Table Names
==============================

View File

@ -4,6 +4,13 @@
Connecting to Oracle Database
*****************************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
Connections between cx_Oracle and Oracle Database are used for executing
:ref:`SQL <sqlexecution>`, :ref:`PL/SQL <plsqlexecution>`, and :ref:`SODA
<sodausermanual>`.
@ -336,7 +343,7 @@ connection 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
For example the ``getmode`` value can be set so that any ``acquire()`` call will
wait for a connection to become available if all are currently in use, for
example:
@ -349,8 +356,8 @@ example:
getmode=cx_Oracle.SPOOL_ATTRVAL_WAIT,
encoding="UTF-8")
See `ConnectionPool.py
<https://github.com/oracle/python-cx_Oracle/tree/main/samples/ConnectionPool.py>`__
See `connection_pool.py
<https://github.com/oracle/python-cx_Oracle/tree/main/samples/connection_pool.py>`__
for an example.
Before :meth:`SessionPool.acquire()` returns, cx_Oracle does a lightweight check
@ -1348,34 +1355,53 @@ of the function :meth:`cx_Oracle.connect()` constructor:
dsn="dbhost.example.com/orclpdb1",
newpassword=newpwd, encoding="UTF-8")
.. _autononmousdb:
.. _autonomousdb:
Connecting to Autononmous Databases
===================================
Connecting to Oracle Cloud Autonomous Databases
===============================================
To enable connection to Oracle Autonomous Database in Oracle Cloud, a wallet
needs be downloaded from the cloud GUI, and cx_Oracle needs to be configured to
use it. A database username and password is still required. The wallet only
enables SSL/TLS.
needs be downloaded from the cloud, and cx_Oracle needs to be configured to use
it. The wallet gives mutual TLS which provides enhanced security for
authentication and encryption. A database username and password is still
required for your application connections.
Install the Wallet and Network Configuration Files
--------------------------------------------------
From the Oracle Cloud console for the database, download the wallet zip file. It
contains the wallet and network configuration files. Note: keep wallet files in
a secure location and share them only with authorized users.
From the Oracle Cloud console for the database, download the wallet zip file.
It contains the wallet and network configuration files. Note: keep wallet
files in a secure location and share them only with authorized users.
Unzip the wallet zip file.
For cx_Oracle, only these files from the zip are needed:
Unzip the wallet zip file. For cx_Oracle, only these files from the zip are needed:
- ``tnsnames.ora`` - Maps net service names used for application connection strings to your database services
- ``sqlnet.ora`` - Configures Oracle Network settings
- ``cwallet.sso`` - Enables SSL/TLS connections
The other files and the wallet password are not needed.
There are now two options:
Place these files as shown in :ref:`Optional Oracle Net Configuration Files <optnetfiles>`.
- Move the three files to the ``network/admin`` directory of the client
libraries used by your application. For example if you are using Instant
Client 19c and it is in ``$HOME/instantclient_19_11``, then you would put the
wallet files in ``$HOME/instantclient_19_11/network/admin/``.
- Alternatively, move them to any accessible directory, for example
``/opt/OracleCloud/MYDB``.
Then edit ``sqlnet.ora`` and change the wallet location directory to the
directory containing the ``cwallet.sso`` file. For example::
WALLET_LOCATION = (SOURCE = (METHOD = file) (METHOD_DATA = (DIRECTORY="/opt/OracleCloud/MYDB")))
SSL_SERVER_DN_MATCH=yes
Since the ``tnsnames.ora`` and ``sqlnet.ora`` files are not in the default
location, your application needs to indicate where they are, either with the
``config_dir`` parameter to :meth:`cx_Oracle.init_oracle_client()`, or using
the ``TNS_ADMIN`` environment variable. See :ref:`Optional Oracle Net
Configuration Files <optnetfiles>`. Neither of these settings are needed,
and you don't need to edit ``sqlnet.ora``, if you have put all the files in
the ``network/admin`` directory.
Run Your Application
--------------------
@ -1383,7 +1409,7 @@ Run Your Application
The ``tnsnames.ora`` file contains net service names for various levels of
database service. For example, if you create a database called CJDB1 with the
Always Free services from the `Oracle Cloud Free Tier
<https://www.oracle.com//cloud/free/>`__, then you might decide to use the
<https://www.oracle.com/cloud/free/>`__, then you might decide to use the
connection string in ``tnsnames.ora`` called ``cjdb1_high``.
Update your application to use your schema username, its database password, and
@ -1394,14 +1420,14 @@ a net service name, for example:
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.
Once you have set optional Oracle environment variables used by your
application, such as ``TNS_ADMIN``, you can start your application.
If you need to create a new database schema so you do not login as the
privileged ADMIN user, refer to the relevant Oracle Cloud documentation, for
example see `Create Database Users
<https://docs.oracle.com/en/cloud/paas/atp-cloud/atpud/manage.html>`__ in the
Oracle Autonomous Transaction Processing Dedicated Deployments manual.
<https://docs.oracle.com/en/cloud/paas/autonomous-database/adbdu/managing-database-users.html#GUID-5B94EA60-554A-4BA4-96A3-1D5A3ED5878D>`__
in the Oracle Autonomous Database manual.
Access Through a Proxy
----------------------
@ -1427,6 +1453,43 @@ name you plan to use, for example::
(https_proxy=myproxy.example.com)(https_proxy_port=80)
(protocol=tcps)(port=1522)(host= . . . )
Using the Easy Connect Syntax with Autonomous Database
------------------------------------------------------
When cx_Oracle is using Oracle Client libraries 19c or later, you can
optionally use the :ref:`Easy Connect <easyconnect>` syntax to connect to
Oracle Autonomous Database.
The mapping from the cloud ``tnsnames.ora`` entries to an Easy Connect Plus
string is::
protocol://host:port/service_name?wallet_location=/my/dir&retry_count=N&retry_delay=N
For example, if your ``tnsnames.ora`` file had an entry::
cjjson_high = (description=(retry_count=20)(retry_delay=3)
(address=(protocol=tcps)(port=1522)
(host=adb.ap-sydney-1.oraclecloud.com))
(connect_data=(service_name=abc_cjjson_high.adb.oraclecloud.com))
(security=(ssl_server_cert_dn="CN=adb.ap-sydney-1.oraclecloud.com,OU=Oracle ADB SYDNEY,O=Oracle Corporation,L=Redwood City,ST=California,C=US")))
Then your applications can connect using the connection string:
.. code-block:: python
dsn = "tcps://adb.ap-sydney-1.oraclecloud.com:1522/abc_cjjson_high.adb.oraclecloud.com?wallet_location=/Users/cjones/Cloud/CJJSON&retry_count=20&retry_delay=3"
connection = cx_Oracle.connect(user="hr", password=userpwd, dsn=dsn,
encoding="UTF-8")
The ``wallet_location`` parameter needs to be set to the directory containing
the ``cwallet.sso`` file from the wallet ZIP. The other wallet files,
including ``tnsnames.ora``, are not needed when you use the Easy Connect Plus
syntax.
You can add other Easy Connect parameters to the connection string, for example::
dsn = dsn + "&https_proxy=myproxy.example.com&https_proxy_port=80"
.. _connsharding:
Connecting to Sharded Databases

View File

@ -4,6 +4,13 @@
Continuous Query Notification (CQN)
***********************************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
`Continuous Query Notification (CQN)
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&
id=GUID-373BAF72-3E63-42FE-8BEA-8A2AEFBF1C35>`__ allows applications to receive
@ -19,14 +26,14 @@ what types of SQL should trigger a notification, whether notifications should
survive database loss, and control over unsubscription. You can also choose
whether notification messages will include ROWIDs of affected rows.
By default, object-level (previously known as Database Change Notification)
occurs and the Python notification method is invoked whenever a database
transaction is committed that changes an object that a registered query
references, regardless of whether the actual query result changed. However if
the :meth:`subscription <Connection.subscribe>` option ``qos`` is
:data:`cx_Oracle.SUBSCR_QOS_QUERY` then query-level notification occurs. In
this mode, the database notifies the application whenever a transaction changing
the result of the registered query is committed.
By default, object-level notification (previously known as Database Change
Notification) occurs. With this mode a Python notification method is invoked
whenever a database transaction is committed that changes an object referenced
by a registered query. However if the :meth:`subscription
<Connection.subscribe>` option ``qos`` is :data:`cx_Oracle.SUBSCR_QOS_QUERY`
then query-level notification occurs. In this mode, the database notifies the
application whenever a committed transaction changes the result of a registered
query.
CQN is best used to track infrequent data changes.
@ -109,7 +116,7 @@ calling :meth:`Subscription.registerquery()`. Registering a query behaves
similarly to :meth:`Cursor.execute()`, but only queries are permitted and the
``args`` parameter must be a sequence or dictionary.
An example script to receive query notifications when the 'CUSTOMER' table data
An example script to receive query notifications when the 'REGIONS' table data
changes is:
.. code-block:: python
@ -129,6 +136,7 @@ changes is:
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")

View File

@ -4,6 +4,13 @@
Exception Handling
******************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
All exceptions raised by cx_Oracle are inherited from :attr:`cx_Oracle.Error`.
See :ref:`Exceptions <exceptions>` for more details on the various exceptions
defined by cx_Oracle. See the exception handling section in the

View File

@ -4,6 +4,13 @@
Character Sets and Globalization
********************************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
Data fetched from, and sent to, Oracle Database will be mapped between the
database character set and the "Oracle client" character set of the Oracle
Client libraries used by cx_Oracle. If data cannot be correctly mapped between

View File

@ -4,6 +4,13 @@
High Availability with cx_Oracle
********************************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
Applications can utilize many features for high availability (HA) during planned and
unplanned outages in order to:

View File

@ -4,6 +4,13 @@
cx_Oracle 8 Initialization
**************************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
The cx_Oracle module loads Oracle Client libraries which communicate over
Oracle Net to an existing database. The Oracle Client libraries need to be
installed separately. See :ref:`installation`. Oracle Net is not a separate
@ -168,8 +175,8 @@ example, if the Oracle Instant Client Libraries are in
cx_Oracle.init_oracle_client(lib_dir=lib_dir)
except Exception as err:
print("Whoops!")
print(err);
sys.exit(1);
print(err)
sys.exit(1)
Note the use of a 'raw' string ``r"..."`` on Windows so that backslashes are
treated as directory separators.
@ -220,8 +227,8 @@ you can call :meth:`cx_Oracle.init_oracle_client()`:
cx_Oracle.init_oracle_client(config_dir="/etc/my-oracle-config")
except Exception as err:
print("Whoops!")
print(err);
sys.exit(1);
print(err)
sys.exit(1)
This is equivalent to setting the environment variable `TNS_ADMIN
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-12C94B15-2CE1-4B98-9D0C-8226A9DDF4CB>`__
@ -241,7 +248,7 @@ located with, or separately from, the ``tnsnames.ora`` and ``sqlnet.ora``
files. It should be securely stored. The ``sqlnet.ora`` file's
``WALLET_LOCATION`` path should be set to the directory containing
``cwallet.sso``. For Oracle Autonomous Database use of wallets, see
:ref:`autononmousdb`.
:ref:`autonomousdb`.
Note the :ref:`easyconnect` can set many common configuration options without
needing ``tnsnames.ora`` or ``sqlnet.ora`` files.
@ -393,8 +400,8 @@ parameters is:
error_url="https://example.com/MyInstallInstructions.html")
except Exception as err:
print("Whoops!")
print(err);
sys.exit(1);
print(err)
sys.exit(1)
The convention for ``driver_name`` is to separate the product name from the
product version by a colon and single blank characters. The value will be shown

View File

@ -4,12 +4,19 @@
cx_Oracle 8 Installation
************************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
Overview
========
To use cx_Oracle 8 with Python and Oracle Database you need:
To use cx_Oracle 8.3 with Python and Oracle Database you need:
- Python 3.5 and higher. Older versions of cx_Oracle may work with older
- Python 3.6 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
@ -35,18 +42,12 @@ 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:
You can:
- Install `Python <https://www.python.org/downloads>`__ 3, if not already
available. On macOS you must always install your own Python.
Python 3.5 and higher are supported by cx_Oracle 8. If you use Python 2,
Python 3.6 and higher are supported by cx_Oracle 8.3. If you use Python 2,
then the older cx_Oracle 7.3 will install.
- Install cx_Oracle from `PyPI
@ -191,6 +192,13 @@ Installing cx_Oracle on Linux
This section discusses the generic installation methods on Linux. To use Python
and cx_Oracle RPM packages from yum on Oracle Linux, see :ref:`oraclelinux`.
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
Install cx_Oracle
-----------------
@ -424,6 +432,13 @@ Developers <https://yum.oracle.com/oracle-linux-python.html>`__.
Installing cx_Oracle on Windows
===============================
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
Install cx_Oracle
-----------------
@ -491,10 +506,11 @@ To use cx_Oracle with Oracle Instant Client zip files:
a 64-bit or 32-bit architecture to match Instant Client's architecture.
Each Instant Client version requires a different redistributable version:
- For Instant Client 19 install `VS 2017 <https://support.microsoft.com/en-us/help/2977003/the-latest-supported-visual-c-downloads>`__.
- For Instant Client 18 or 12.2 install `VS 2013 <https://support.microsoft.com/en-us/kb/2977003#bookmark-vs2013>`__
- For Instant Client 12.1 install `VS 2010 <https://support.microsoft.com/en-us/kb/2977003#bookmark-vs2010>`__
- For Instant Client 11.2 install `VS 2005 64-bit <https://www.microsoft.com/en-us/download/details.aspx?id=18471>`__ or `VS 2005 32-bit <https://www.microsoft.com/en-ca/download/details.aspx?id=3387>`__
- For Instant Client 21 install `VS 2019 <https://docs.microsoft.com/en-US/cpp/windows/latest-supported-vc-redist?view=msvc-170>`__ or later.
- For Instant Client 19 install `VS 2017 <https://docs.microsoft.com/en-US/cpp/windows/latest-supported-vc-redist?view=msvc-170>`__.
- For Instant Client 18 or 12.2 install `VS 2013 <https://docs.microsoft.com/en-US/cpp/windows/latest-supported-vc-redist?view=msvc-170#visual-studio-2013-vc-120>`__
- For Instant Client 12.1 install `VS 2010 <https://docs.microsoft.com/en-US/cpp/windows/latest-supported-vc-redist?view=msvc-170#visual-studio-2010-vc-100-sp1-no-longer-supported>`__
- For Instant Client 11.2 install `VS 2005 64-bit <https://docs.microsoft.com/en-US/cpp/windows/latest-supported-vc-redist?view=msvc-170#visual-studio-2005-vc-80-sp1-no-longer-supported>`__
Configure Oracle Instant Client
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -571,6 +587,13 @@ Python architecture.
Installing cx_Oracle on macOS (Intel x86)
=========================================
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
Install Python
--------------

View File

@ -9,6 +9,13 @@ Database. It conforms to the `Python Database API v2.0 Specification
<https://www.python.org/dev/peps/pep-0249/>`__ with a considerable number of
additions and a couple of exclusions.
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
Architecture
------------
@ -50,7 +57,7 @@ Features
The cx_Oracle feature highlights are:
* Easily installed from PyPI
* Easy installation from PyPI
* Support for multiple Oracle Client and Database versions
* Execution of SQL and PL/SQL statements
* Extensive Oracle data type support, including large objects (CLOB and
@ -104,7 +111,7 @@ Simple :ref:`connection <connhandling>` to the database requires a username,
password and connection string. Locate your Oracle Database `user name and
password <https://www.youtube.com/watch?v=WDJacg0NuLo>`_ and the database
:ref:`connection string <connstr>`, and use them in ``query.py``. For
cx_Oracle the connection string is commonly of the format
cx_Oracle, the connection string is commonly of the format
``hostname/servicename``, using the host name where the database is running and
the Oracle Database service name of the database instance.
@ -131,12 +138,6 @@ 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/main/samples>`__. A `Python
cx_Oracle tutorial

View File

@ -4,6 +4,13 @@
Working with the JSON Data Type
*******************************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
Native support for JSON data was introduced in Oracle Database 12c. You can
use JSON with relational database features, including transactions, indexing,
declarative querying, and views. You can project JSON data relationally,

View File

@ -4,6 +4,13 @@
Using CLOB and BLOB Data
************************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
Oracle Database uses :ref:`lobobj` to store large data such as text, images,
videos and other multimedia formats. The maximum size of a LOB is limited to
the size of the tablespace storing it.

View File

@ -4,6 +4,13 @@
PL/SQL Execution
****************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
PL/SQL stored procedures, functions and anonymous blocks can be called from
cx_Oracle.

View File

@ -4,6 +4,13 @@
Simple Oracle Document Access (SODA)
************************************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
Overview
========
@ -130,18 +137,6 @@ SODA metadata can be cached to improve the performance of
: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:
@ -153,8 +148,13 @@ The metadata cache can be turned on when creating a connection pool with
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
The cache is not available for standalone connections. Applications using these
should retain and reuse the :ref:`collection <sodacoll>` returned from
``createCollection()`` or ``openCollection()`` wherever possible, instead of
making repeated calls to those methods.
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
@ -173,6 +173,13 @@ you will find it more efficient to use logic similar to:
collection = soda.createCollection("mycollection", mymetadata)
collection.insertOne(mycontent)
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`.
Use a second call to ``reconfigure()`` or set ``soda_metadata_cache`` to
re-enable the cache.
Committing SODA Work
====================

View File

@ -4,6 +4,13 @@
SQL Execution
*************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
Executing SQL statements is the primary way in which a Python application
communicates with Oracle Database. Statements are executed using the methods
:meth:`Cursor.execute()` or :meth:`Cursor.executemany()`. Statements include

View File

@ -4,6 +4,13 @@
Starting and Stopping Oracle Database
*************************************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
This chapter covers how to start up and shutdown Oracle Database using
cx_Oracle.

View File

@ -4,6 +4,13 @@
Tracing SQL and PL/SQL Statements
*********************************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
Subclass Connections
====================

View File

@ -4,6 +4,13 @@
Tuning cx_Oracle
****************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
Some general tuning tips are:
* Tune your application architecture.

View File

@ -4,6 +4,13 @@
Transaction Management
**********************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
A database transaction is a grouping of SQL statements that make a logical data
change to the database.

View File

@ -4,6 +4,13 @@
Working with XMLTYPE
********************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
Oracle XMLType columns are fetched as strings by default. This is currently
limited to the maximum length of a ``VARCHAR2`` column. To return longer XML
values, they must be queried as LOB values instead.

2
odpi

@ -1 +1 @@
Subproject commit 5574630dcf41ce0c09124059b8ee2ba5bc07efb9
Subproject commit f73a7c13d643b3fe252614bafc930afbd8e287dd

View File

@ -1,6 +1,19 @@
# cx_Oracle Examples
# Samples
This directory contains samples for [cx_Oracle][6]. Documentation is [here][7].
## News
**cx_Oracle has a major new release under a new name and homepage
[python-oracledb](https://oracle.github.io/python-oracledb/).**
**New projects should install python-oracledb instead of cx_Oracle.**
**The new source code and samples can be found at
[github.com/oracle/python-oracledb](https://github.com/oracle/python-oracledb).**
## cx_Oracle Examples
This directory contains samples for [cx_Oracle][6]. Documentation is
[here][7]. A separate tutorial is [here][8].
1. The schemas and SQL objects that are referenced in the samples can be
created by running the Python script [setup_samples.py][1]. The script
@ -19,7 +32,7 @@ This directory contains samples for [cx_Oracle][6]. Documentation is [here][7].
2. Run a Python script, for example:
python Query.py
python query.py
3. After running cx_Oracle samples, the schemas and SQL objects can be
dropped by running the Python script [drop_samples.py][4]. The script
@ -43,3 +56,4 @@ This directory contains samples for [cx_Oracle][6]. Documentation is [here][7].
[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
[8]: https://oracle.github.io/python-cx_Oracle/samples/tutorial/Python-and-Oracle-Database-Scripting-for-the-Future.html

View File

@ -10,8 +10,8 @@
#------------------------------------------------------------------------------
# bulk_aq.py
# This script demonstrates how to use bulk enqueuing and dequeuing of
# messages with advanced queuing using cx_Oracle. It makes use of a RAW queue
# created in the sample setup.
# messages with advanced queuing. It makes use of a RAW queue created in the
# sample setup.
#
# This script requires cx_Oracle 8.2 and higher.
#------------------------------------------------------------------------------

View File

@ -4,8 +4,8 @@
#------------------------------------------------------------------------------
# connection_pool.py
# This script demonstrates the use of connection pooling in cx_Oracle. Pools
# can significantly reduce connection times for long running applications that
# This script demonstrates the use of connection pooling. Pools can
# significantly reduce connection times for long running applications that
# repeatedly open and close connections. Internal features help protect against
# dead connections, and also aid use of Oracle Database features such as FAN
# and Application Continuity.
@ -27,8 +27,8 @@ import sample_env
# Create a Connection Pool
pool = oracledb.SessionPool(user=sample_env.get_main_user(),
password=sample_env.get_main_password(),
dsn=sample_env.get_connect_string(), min=2,
max=5, increment=1)
dsn=sample_env.get_connect_string(), min=2, max=5,
increment=1)
def the_long_query():
with pool.acquire() as conn:

View File

@ -12,7 +12,7 @@
# This script demonstrates using continuous query notification in Python, a
# feature that is available in Oracle 11g and later. Once this script is
# running, use another session to insert, update or delete rows from the table
# cx_Oracle.TestTempTable and you will see the notification of that change.
# TestTempTable and you will see the notification of that change.
#
# This script requires cx_Oracle 5.3 and higher.
#------------------------------------------------------------------------------

View File

@ -12,7 +12,7 @@
# This script demonstrates using database change notification in Python, a
# feature that is available in Oracle 10g Release 2. Once this script is
# running, use another session to insert, update or delete rows from the table
# cx_Oracle.TestTempTable and you will see the notification of that change.
# TestTempTable and you will see the notification of that change.
#
# This script requires cx_Oracle 5.3 and higher.
#------------------------------------------------------------------------------

View File

@ -10,6 +10,7 @@
#------------------------------------------------------------------------------
import collections
import cx_Oracle as oracledb
import sample_env
@ -21,7 +22,7 @@ class Connection(oracledb.Connection):
class Cursor(oracledb.Cursor):
def execute(self, statement, args = None):
def execute(self, statement, args=None):
prepare_needed = (self.statement != statement)
result = super().execute(statement, args or [])
if prepare_needed:

View File

@ -15,8 +15,9 @@
#
#------------------------------------------------------------------------------
import sys
import json
import sys
import cx_Oracle as oracledb
import sample_env

View File

@ -10,8 +10,9 @@
# For JSON with older databases see json_blob.py
#------------------------------------------------------------------------------
import sys
import json
import sys
import cx_Oracle as oracledb
import sample_env

View File

@ -9,8 +9,8 @@
#------------------------------------------------------------------------------
# multi_consumer_aq.py
# This script demonstrates how to use multi-consumer advanced queuing using
# cx_Oracle. It makes use of a RAW queue created in the sample setup.
# This script demonstrates how to use multi-consumer advanced queuing. It
# makes use of a RAW queue created in the sample setup.
#
# This script requires cx_Oracle 8.2 and higher.
#------------------------------------------------------------------------------

View File

@ -9,9 +9,8 @@
#------------------------------------------------------------------------------
# object_aq.py
# This script demonstrates how to use advanced queuing with objects using
# cx_Oracle. It makes use of a simple type and queue created in the sample
# setup.
# This script demonstrates how to use advanced queuing with objects. It makes
# use of a simple type and queue created in the sample setup.
#
# This script requires cx_Oracle 8.2 and higher.
#------------------------------------------------------------------------------

View File

@ -7,8 +7,7 @@
#
# Demonstrate how to bind (in and out) a PL/SQL record.
#
# This feature is new in cx_Oracle 5.3 and is only available in Oracle
# Database 12.1 and higher.
# This feature is only available in Oracle Database 12.1 and higher.
#------------------------------------------------------------------------------
import datetime

View File

@ -9,8 +9,8 @@
#------------------------------------------------------------------------------
# raw_aq.py
# This script demonstrates how to use advanced queuing with RAW data using
# cx_Oracle. It makes use of a RAW queue created in the sample setup.
# This script demonstrates how to use advanced queuing with RAW data. It
# makes use of a RAW queue created in the sample setup.
#
# This script requires cx_Oracle 8.2 and higher.
#------------------------------------------------------------------------------

View File

@ -4,7 +4,7 @@
#------------------------------------------------------------------------------
# ref_cursor.py
# Demonstrates the use of REF cursors with cx_Oracle.
# Demonstrates the use of REF cursors.
#------------------------------------------------------------------------------
import cx_Oracle as oracledb

View File

@ -3,9 +3,9 @@
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# Sets the environment used by most Python cx_Oracle samples. Production
# applications should consider using External Authentication to
# avoid hard coded credentials.
# Sets the environment used by the sample scripts. Production applications
# should consider using External Authentication to avoid hard coded
# credentials.
#
# You can set values in environment variables to bypass the sample requesting
# the information it requires.
@ -24,8 +24,8 @@
# Net Service Name from a tnsnames.ora file or external naming service,
# or it can be the name of a local Oracle database instance.
#
# If cx_Oracle is using Instant Client, then an Easy Connect string is
# generally appropriate. The syntax is:
# If using Instant Client, then an Easy Connect string is generally
# appropriate. The syntax is:
#
# [//]host_name[:port][/service_name][:server_type][/instance_name]
#

View File

@ -29,7 +29,8 @@ import sample_env
pool = oracledb.SessionPool(user=sample_env.get_main_user(),
password=sample_env.get_main_password(),
dsn=sample_env.get_connect_string(), min=2, max=5,
increment=1, session_callback="pkg_SessionCallback.TheCallback")
increment=1,
session_callback="pkg_SessionCallback.TheCallback")
# truncate table logging calls to PL/SQL session callback
with pool.acquire() as conn:

View File

@ -6,7 +6,7 @@
# setup_samples.py
#
# Creates users and populates their schemas with the tables and packages
# necessary for the cx_Oracle samples. An edition is also created for the
# necessary for running the sample scripts. An edition is also created for the
# demonstration of PL/SQL editioning.
#------------------------------------------------------------------------------

View File

@ -5,7 +5,7 @@
/*-----------------------------------------------------------------------------
* setup_samples_exec.sql
* This script performs the actual work of creating and populating the
* schemas with the database objects used by the cx_Oracle samples. An edition
* schemas with the database objects used by the sample scripts. An edition
* is also created for the demonstration of PL/SQL editioning. It is called by
* the setup_samples.sql file after acquiring the necessary parameters and also
* by the Python script setup_samples.py.

View File

@ -5,9 +5,9 @@
#------------------------------------------------------------------------------
# subclassing.py
#
# Demonstrate how to subclass cx_Oracle connections and cursors in order to
# add additional functionality (like logging) or create specialized interfaces
# for paticular applications.
# Demonstrate how to subclass connections and cursors in order to add
# additional functionality (like logging) or create specialized interfaces for
# paticular applications.
#------------------------------------------------------------------------------
import cx_Oracle as oracledb

View File

@ -16,7 +16,7 @@ if sys.version_info[:2] < (3, 6):
pkg_resources.require("setuptools>=40.6.0")
# define build constants
BUILD_VERSION = "8.2.0"
BUILD_VERSION = "8.3.0"
# setup extra link and compile args
extra_link_args = []

View File

@ -623,7 +623,7 @@ static int cxoConnection_init(cxoConnection *conn, PyObject *args,
// determine if session callback should be invoked; this takes place if
// the connection is newly created by the pool or if the requested tag
// does not match the actal tag
// does not match the actual tag
invokeSessionCallback = 0;
if (dpiCreateParams.outNewSession ||
dpiCreateParams.outTagLength != params.tagBuffer.size ||

View File

@ -1263,7 +1263,8 @@ static PyObject *cxoCursor_callProc(cxoCursor *cursor, PyObject *args,
// parse arguments
listOfArguments = keywordArguments = keywordArgumentsDeprecated = NULL;
if (!PyArg_ParseTupleAndKeywords(args, keywordArgs, "O|OOO", keywordList,
&name, &listOfArguments, &keywordArguments))
&name, &listOfArguments, &keywordArguments,
&keywordArgumentsDeprecated))
return NULL;
if (keywordArgumentsDeprecated) {
if (keywordArguments) {

View File

@ -182,15 +182,15 @@ static PyObject *cxoMsgProps_getExpiration(cxoMsgProps *props, void *unused)
//-----------------------------------------------------------------------------
// cxoMsgProps_getOriginalMsgId()
// Get the value of the expiration property.
// cxoMsgProps_getMsgId()
// Get the value of the msgid property.
//-----------------------------------------------------------------------------
static PyObject *cxoMsgProps_getOriginalMsgId(cxoMsgProps *props, void *unused)
static PyObject *cxoMsgProps_getMsgId(cxoMsgProps *props, void *unused)
{
uint32_t valueLength;
const char *value;
if (dpiMsgProps_getOriginalMsgId(props->handle, &value, &valueLength) < 0)
if (dpiMsgProps_getMsgId(props->handle, &value, &valueLength) < 0)
return cxoError_raiseAndReturnNull();
if (!value)
Py_RETURN_NONE;
@ -285,25 +285,6 @@ static int cxoMsgProps_setExpiration(cxoMsgProps *props, PyObject *valueObj,
}
//-----------------------------------------------------------------------------
// cxoMsgProps_setOriginalMsgId()
// Set the value of the original message id property.
//-----------------------------------------------------------------------------
static int cxoMsgProps_setOriginalMsgId(cxoMsgProps *props, PyObject *valueObj,
void *unused)
{
Py_ssize_t valueLength;
char *value;
if (PyBytes_AsStringAndSize(valueObj, &value, &valueLength) < 0)
return -1;
if (dpiMsgProps_setOriginalMsgId(props->handle, value,
(uint32_t) valueLength) < 0)
return cxoError_raiseAndReturnInt();
return 0;
}
//-----------------------------------------------------------------------------
// cxoMsgProps_setPriority()
// Set the value of the expiration property.
@ -339,8 +320,7 @@ static PyGetSetDef cxoCalcMembers[] = {
(setter) cxoMsgProps_setExceptionQ, 0, 0 },
{ "expiration", (getter) cxoMsgProps_getExpiration,
(setter) cxoMsgProps_setExpiration, 0, 0 },
{ "msgid", (getter) cxoMsgProps_getOriginalMsgId,
(setter) cxoMsgProps_setOriginalMsgId, 0, 0 },
{ "msgid", (getter) cxoMsgProps_getMsgId, 0, 0, 0 },
{ "priority", (getter) cxoMsgProps_getPriority,
(setter) cxoMsgProps_setPriority, 0, 0 },
{ "state", (getter) cxoMsgProps_getState, 0, 0, 0 },

View File

@ -244,7 +244,7 @@ int cxoTransform_fromPython(cxoTransformNum transformNum,
dpiIntervalDS *interval;
PyDateTime_Delta *delta;
int32_t deltaSeconds;
PyObject *textValue;
PyObject *tempValue;
cxoObject *obj;
cxoLob *lob;
int status;
@ -316,10 +316,21 @@ int cxoTransform_fromPython(cxoTransformNum transformNum,
dbValue->asInt64 = (pyValue == Py_True);
return 0;
}
dbValue->asInt64 = PyLong_AsLong(pyValue);
if (PyErr_Occurred())
if (!PyFloat_Check(pyValue) &&
!PyLong_Check(pyValue) &&
!PyObject_TypeCheck(pyValue, cxoPyTypeDecimal)) {
PyErr_SetString(PyExc_TypeError,
"expecting number or boolean");
return -1;
return 0;
}
tempValue = PyObject_CallFunctionObjArgs((PyObject*) &PyLong_Type,
pyValue, NULL);
if (!tempValue)
return -1;
dbValue->asInt64 = PyLong_AsLong(tempValue);
status = (PyErr_Occurred()) ? -1 : 0;
Py_DECREF(tempValue);
return status;
case CXO_TRANSFORM_INT:
case CXO_TRANSFORM_DECIMAL:
case CXO_TRANSFORM_FLOAT:
@ -334,11 +345,11 @@ int cxoTransform_fromPython(cxoTransformNum transformNum,
PyErr_SetString(PyExc_TypeError, "expecting number");
return -1;
}
textValue = PyObject_Str(pyValue);
if (!textValue)
tempValue = PyObject_Str(pyValue);
if (!tempValue)
return -1;
status = cxoBuffer_fromObject(buffer, textValue, encoding);
Py_DECREF(textValue);
status = cxoBuffer_fromObject(buffer, tempValue, encoding);
Py_DECREF(tempValue);
if (status < 0)
return -1;
}

View File

@ -1,14 +1,14 @@
#------------------------------------------------------------------------------
# Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# drop_test.py
#
# Drops the database objects used for the cx_Oracle test suite.
# Drops the database objects used by the test suite.
#------------------------------------------------------------------------------
import cx_Oracle
import cx_Oracle as oracledb
import test_env
def drop_tests(conn):
@ -18,6 +18,6 @@ def drop_tests(conn):
proxy_user=test_env.get_proxy_user())
if __name__ == "__main__":
conn = cx_Oracle.connect(test_env.get_admin_connect_string())
conn = oracledb.connect(test_env.get_admin_connect_string())
drop_tests(conn)
print("Done.")

View File

@ -6,16 +6,15 @@
# setup_test.py
#
# Creates users and populates their schemas with the tables and packages
# necessary for the cx_Oracle test suite.
# necessary for the test suite.
#------------------------------------------------------------------------------
import cx_Oracle
import test_env
import cx_Oracle as oracledb
import drop_test
import test_env
# connect as administrative user (usually SYSTEM or ADMIN)
conn = cx_Oracle.connect(test_env.get_admin_connect_string())
conn = oracledb.connect(test_env.get_admin_connect_string())
# drop existing users and editions, if applicable
drop_test.drop_tests(conn)

View File

@ -172,15 +172,21 @@ create table &main_user..TestXML (
)
/
create table &main_user..TestTempXML (
IntCol number(9) not null,
XMLCol xmltype not null
)
/
create table &main_user..TestLongs (
IntCol number(9) not null,
LongCol long not null
LongCol long
) nocompress
/
create table &main_user..TestLongRaws (
IntCol number(9) not null,
LongRawCol long raw not null
LongRawCol long raw
) nocompress
/

View File

@ -6,12 +6,12 @@
1000 - Module for testing top-level module methods
"""
import test_env
import cx_Oracle as oracledb
import datetime
import time
import cx_Oracle as oracledb
import test_env
class TestCase(test_env.BaseTestCase):
requires_connection = False

View File

@ -11,12 +11,14 @@
1100 - Module for testing connections
"""
import test_env
import cx_Oracle as oracledb
import random
import string
import threading
import time
import unittest
import cx_Oracle as oracledb
import test_env
class TestCase(test_env.BaseTestCase):
requires_connection = False
@ -29,6 +31,14 @@ class TestCase(test_env.BaseTestCase):
count, = cursor.fetchone()
self.assertEqual(count, 10)
def __verify_fetched_data(self, connection):
expected_data = [f"String {i + 1}" for i in range(10)]
sql = "select StringCol from TestStrings order by IntCol"
for i in range(5):
with connection.cursor() as cursor:
fetched_data = [s for s, in cursor.execute(sql)]
self.assertEqual(fetched_data, expected_data)
def __verify_args(self, connection):
self.assertEqual(connection.username, test_env.get_main_user(),
"user name differs")
@ -68,9 +78,9 @@ class TestCase(test_env.BaseTestCase):
def test_1102_app_context_negative(self):
"1102 - test invalid use of application context"
self.assertRaises(TypeError, oracledb.connect,
test_env.get_main_user(),
test_env.get_main_password(),
test_env.get_connect_string(),
user=test_env.get_main_user(),
password=test_env.get_main_password(),
dsn=test_env.get_connect_string(),
appcontext=[('userenv', 'action')])
def test_1103_attributes(self):
@ -125,9 +135,9 @@ class TestCase(test_env.BaseTestCase):
def test_1106_bad_password(self):
"1106 - connection to database with bad password"
self.assertRaises(oracledb.DatabaseError, oracledb.connect,
test_env.get_main_user(),
test_env.get_main_password() + "X",
test_env.get_connect_string())
user=test_env.get_main_user(),
password=test_env.get_main_password() + "X",
dsn=test_env.get_connect_string())
def test_1107_change_password(self):
"1107 - test changing password"
@ -138,8 +148,9 @@ class TestCase(test_env.BaseTestCase):
new_password = "".join(sys_random.choice(string.ascii_letters) \
for i in range(20))
connection.changepassword(test_env.get_main_password(), new_password)
cconnection = oracledb.connect(test_env.get_main_user(), new_password,
test_env.get_connect_string())
connection = oracledb.connect(dsn=test_env.get_connect_string(),
user=test_env.get_main_user(),
password=new_password)
connection.changepassword(new_password, test_env.get_main_password())
def test_1108_change_password_negative(self):
@ -220,7 +231,7 @@ class TestCase(test_env.BaseTestCase):
cursor.execute("""
insert into TestTempTable (IntCol, StringCol)
values (:val, null)""", val=int_value)
connection2 = oracledb.connect(handle = connection.handle)
connection2 = oracledb.connect(handle=connection.handle)
cursor = connection2.cursor()
cursor.execute("select IntCol from TestTempTable")
fetched_int_value, = cursor.fetchone()
@ -279,7 +290,7 @@ class TestCase(test_env.BaseTestCase):
self.assertEqual(count, 0)
def test_1119_threading(self):
"1119 - connection to database with multiple threads"
"1119 - multiple connections to database with multiple threads"
threads = []
for i in range(20):
thread = threading.Thread(None, self.__connect_and_drop)
@ -465,5 +476,118 @@ class TestCase(test_env.BaseTestCase):
xid = (0x1234, "%032x" % id_, "%032x" % 9)
self.assertRaises(oracledb.DatabaseError, connection.begin, *xid)
def test_1129_threading_single_connection(self):
"1129 - single connection to database with multiple threads"
with test_env.get_connection(threaded=True) as connection:
threads = [threading.Thread(target=self.__verify_fetched_data,
args=(connection,)) for i in range(3)]
for t in threads:
t.start()
for t in threads:
t.join()
def test_1130_cancel(self):
"1130 - test connection cancel"
conn = test_env.get_connection()
def perform_cancel():
time.sleep(0.1)
conn.cancel()
thread = threading.Thread(target=perform_cancel)
thread.start()
try:
with conn.cursor() as cursor:
self.assertRaises(oracledb.OperationalError, cursor.callproc,
test_env.get_sleep_proc_name(), [2])
finally:
thread.join()
with conn.cursor() as cursor:
cursor.execute("select user from dual")
user, = cursor.fetchone()
self.assertEqual(user, test_env.get_main_user().upper())
def test_1131_change_password_during_connect(self):
"1131 - test changing password during connect"
connection = test_env.get_connection()
if self.is_on_oracle_cloud(connection):
self.skipTest("passwords on Oracle Cloud are strictly controlled")
sys_random = random.SystemRandom()
new_password = "".join(sys_random.choice(string.ascii_letters) \
for i in range(20))
connection = oracledb.connect(dsn=test_env.get_connect_string(),
user=test_env.get_main_user(),
password=test_env.get_main_password(),
newpassword=new_password)
connection = oracledb.connect(dsn=test_env.get_connect_string(),
user=test_env.get_main_user(),
password=new_password)
connection.changepassword(new_password, test_env.get_main_password())
def test_1132_autocommit_during_reexecute(self):
"1132 - test use of autocommit during reexecute"
sql = "insert into TestTempTable (IntCol, StringCol) values (:1, :2)"
data_to_insert = [
(1, "Test String #1"),
(2, "Test String #2")
]
connection = test_env.get_connection()
cursor = connection.cursor()
other_connection = test_env.get_connection()
other_cursor = other_connection.cursor()
cursor.execute("truncate table TestTempTable")
cursor.execute(sql, data_to_insert[0])
other_cursor.execute("select IntCol, StringCol from TestTempTable")
rows = other_cursor.fetchall()
self.assertEqual(rows, [])
connection.autocommit = True
cursor.execute(sql, data_to_insert[1])
other_cursor.execute("select IntCol, StringCol from TestTempTable")
rows = other_cursor.fetchall()
self.assertEqual(rows, data_to_insert)
def test_1133_current_schema(self):
"1133 - test current_schame is set properly"
conn = test_env.get_connection()
self.assertEqual(conn.current_schema, None)
user = test_env.get_main_user().upper()
proxy_user = test_env.get_proxy_user().upper()
cursor = conn.cursor()
cursor.execute(f'alter session set current_schema={proxy_user}')
self.assertEqual(conn.current_schema, proxy_user)
conn.current_schema = user
self.assertEqual(conn.current_schema, user)
cursor.execute("""
select sys_context('userenv', 'current_schema')
from dual""")
result, = cursor.fetchone()
self.assertEqual(result, user)
def test_1134_dbms_output(self):
"1134 - test dbms_output package"
conn = test_env.get_connection()
cursor = conn.cursor()
test_string = "Testing DBMS_OUTPUT package"
cursor.callproc("dbms_output.enable")
cursor.execute("""
begin
dbms_output.put_line(:val);
end; """, val=test_string)
string_var = cursor.var(str)
number_var = cursor.var(int)
cursor.callproc("dbms_output.get_line", (string_var, number_var))
self.assertEqual(string_var.getvalue(), test_string)
@unittest.skipIf(test_env.get_client_version() < (18, 1),
"unsupported client")
def test_1135_calltimeout(self):
"1135 - test connection call_timeout"
conn = test_env.get_connection()
conn.call_timeout = 500 # milliseconds
self.assertEqual(conn.call_timeout, 500)
self.assertRaises(oracledb.DatabaseError, conn.cursor().callproc,
test_env.get_sleep_proc_name(), [2])
if __name__ == "__main__":
test_env.run_test_cases()

View File

@ -1,5 +1,5 @@
#------------------------------------------------------------------------------
# Copyright (c) 2016, 2021 Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
#
# Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
#
@ -11,10 +11,10 @@
1200 - Module for testing cursors
"""
import test_env
import cx_Oracle as oracledb
import decimal
import datetime
import cx_Oracle as oracledb
import test_env
class TestCase(test_env.BaseTestCase):
@ -397,7 +397,7 @@ class TestCase(test_env.BaseTestCase):
cursor.fetchmany()
self.assertTrue(cursor.arraysize > 1,
"array size must exceed 1 for this test to work correctly")
cursor.scroll(1, mode = "absolute")
cursor.scroll(1, mode="absolute")
row = cursor.fetchone()
self.assertEqual(row[0], 1.25)
self.assertEqual(cursor.rowcount, 1)
@ -410,7 +410,7 @@ class TestCase(test_env.BaseTestCase):
select NumberCol
from TestNumbers
order by IntCol""")
cursor.scroll(6, mode = "absolute")
cursor.scroll(6, mode="absolute")
row = cursor.fetchone()
self.assertEqual(row[0], 7.5)
self.assertEqual(cursor.rowcount, 6)
@ -515,9 +515,9 @@ class TestCase(test_env.BaseTestCase):
self.cursor.execute("truncate table TestTempTable")
cursor = self.connection.cursor(scrollable=True)
cursor.execute("select * from TestTempTable")
cursor.scroll(mode = "last")
cursor.scroll(mode="last")
self.assertEqual(cursor.fetchall(), [])
cursor.scroll(mode = "first")
cursor.scroll(mode="first")
self.assertEqual(cursor.fetchall(), [])
self.assertRaises(oracledb.DatabaseError, cursor.scroll, 1,
mode="absolute")
@ -637,8 +637,8 @@ class TestCase(test_env.BaseTestCase):
select IntCol, StringCol
from TestTempTable
order by IntCol""")
self.assertEqual(self.cursor.fetchall(),
[(0, "Value should be 0"), (1, "Value should be 1")])
expected_value = [(0, "Value should be 0"), (1, "Value should be 1")]
self.assertEqual(self.cursor.fetchall(), expected_value)
def test_1259_as_context_manager(self):
"1259 - test using a cursor as a context manager"
@ -1001,5 +1001,35 @@ class TestCase(test_env.BaseTestCase):
self.assertEqual(self.cursor.statement, sql)
self.assertEqual(self.cursor.description, None)
def test_1285_executemany_with_plsql_binds(self):
"1285 - test executing plsql statements multiple times (with binds)"
var = self.cursor.var(int, arraysize=5)
self.cursor.setinputsizes(var)
data = [[25], [30], [None], [35], [None]]
exepected_data = [25, 30, None, 35, None]
self.cursor.executemany("declare t number; begin t := :1; end;", data)
self.assertEqual(var.values, exepected_data)
def test_1286_encodingErrors_deprecation(self):
"1286 - test to verify encodingErrors is deprecated"
errors = 'strict'
self.assertRaises(oracledb.ProgrammingError, self.cursor.var,
oracledb.NUMBER, encoding_errors=errors,
encodingErrors=errors)
def test_1287_keywordParameters_deprecation(self):
"1287 - test to verify keywordParameters is deprecated"
out_value = self.cursor.var(oracledb.NUMBER)
kwargs = dict(a_OutValue=out_value)
self.assertRaises(oracledb.ProgrammingError, self.cursor.callproc,
"proc_Test", ("hi", 5), kwargs,
keywordParameters=kwargs)
extra_amount = self.cursor.var(oracledb.NUMBER)
extra_amount.setvalue(0, 5)
kwargs = dict(a_ExtraAmount=extra_amount, a_String="hi")
self.assertRaises(oracledb.ProgrammingError, self.cursor.callfunc,
"func_Test", oracledb.NUMBER, [], kwargs,
keywordParameters=kwargs)
if __name__ == "__main__":
test_env.run_test_cases()

View File

@ -1,5 +1,5 @@
#------------------------------------------------------------------------------
# Copyright (c) 2016, 2021 Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
#
# Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
#
@ -11,10 +11,10 @@
1300 - Module for testing cursor variables
"""
import test_env
import sys
import cx_Oracle as oracledb
import sys
import test_env
class TestCase(test_env.BaseTestCase):
@ -27,9 +27,10 @@ class TestCase(test_env.BaseTestCase):
open :cursor for select 'X' StringValue from dual;
end;""",
cursor=cursor)
varchar_ratio, nvarchar_ratio = test_env.get_charset_ratios()
expected_value = [
('STRINGVALUE', oracledb.DB_TYPE_CHAR, 1,
test_env.get_charset_ratio(), None, None, 1)
('STRINGVALUE', oracledb.DB_TYPE_CHAR, 1, varchar_ratio, None,
None, True)
]
self.assertEqual(cursor.description, expected_value)
self.assertEqual(cursor.fetchall(), [('X',)])
@ -39,10 +40,11 @@ class TestCase(test_env.BaseTestCase):
cursor = self.connection.cursor()
self.assertEqual(cursor.description, None)
self.cursor.callproc("pkg_TestRefCursors.TestOutCursor", (2, cursor))
varchar_ratio, nvarchar_ratio = test_env.get_charset_ratios()
expected_value = [
('INTCOL', oracledb.DB_TYPE_NUMBER, 10, None, 9, 0, 0),
('STRINGCOL', oracledb.DB_TYPE_VARCHAR, 20,
20 * test_env.get_charset_ratio(), None, None, 0)
('INTCOL', oracledb.DB_TYPE_NUMBER, 10, None, 9, 0, False),
('STRINGCOL', oracledb.DB_TYPE_VARCHAR, 20, 20 * varchar_ratio,
None, None, False)
]
self.assertEqual(cursor.description, expected_value)
self.assertEqual(cursor.fetchall(), [(1, 'String 1'), (2, 'String 2')])
@ -85,8 +87,9 @@ class TestCase(test_env.BaseTestCase):
from TestNumbers
order by IntCol""")
expected_value = [
('INTCOL', oracledb.DB_TYPE_NUMBER, 10, None, 9, 0, 0),
('CURSORVALUE', oracledb.DB_TYPE_CURSOR, None, None, None, None, 1)
('INTCOL', oracledb.DB_TYPE_NUMBER, 10, None, 9, 0, False),
('CURSORVALUE', oracledb.DB_TYPE_CURSOR, None, None, None, None,
True)
]
self.assertEqual(self.cursor.description, expected_value)
for i in range(1, 11):

View File

@ -11,12 +11,12 @@
1400 - Module for testing date/time variables
"""
import test_env
import cx_Oracle as oracledb
import datetime
import time
import cx_Oracle as oracledb
import test_env
class TestCase(test_env.BaseTestCase):
def setUp(self):
@ -56,9 +56,11 @@ class TestCase(test_env.BaseTestCase):
def test_1402_bind_date_in_datetime_var(self):
"1402 - test binding date in a datetime variable"
var = self.cursor.var(oracledb.DATETIME)
dateVal = datetime.date.today()
var.setvalue(0, dateVal)
self.assertEqual(var.getvalue().date(), dateVal)
date_val = datetime.date.today()
var.setvalue(0, date_val)
self.cursor.execute("select :1 from dual", [var])
result, = self.cursor.fetchone()
self.assertEqual(result.date(), date_val)
def test_1403_bind_date_after_string(self):
"1403 - test binding in a date after setting input sizes to a string"
@ -213,9 +215,9 @@ class TestCase(test_env.BaseTestCase):
"1414 - test cursor description is accurate"
self.cursor.execute("select * from TestDates")
expected_value = [
('INTCOL', oracledb.DB_TYPE_NUMBER, 10, None, 9, 0, 0),
('DATECOL', oracledb.DB_TYPE_DATE, 23, None, None, None, 0),
('NULLABLECOL', oracledb.DB_TYPE_DATE, 23, None, None, None, 1)
('INTCOL', oracledb.DB_TYPE_NUMBER, 10, None, 9, 0, False),
('DATECOL', oracledb.DB_TYPE_DATE, 23, None, None, None, False),
('NULLABLECOL', oracledb.DB_TYPE_DATE, 23, None, None, None, True)
]
self.assertEqual(self.cursor.description, expected_value)

View File

@ -8,10 +8,10 @@ including the synonyms retained for backwards compatibility. This module also
tests for pickling/unpickling of database types and API types.
"""
import test_env
import pickle
import cx_Oracle as oracledb
import pickle
import test_env
class TestCase(test_env.BaseTestCase):
requires_connection = False

View File

@ -6,9 +6,8 @@
1600 - Module for testing DML returning clauses
"""
import test_env
import cx_Oracle as oracledb
import test_env
class TestCase(test_env.BaseTestCase):

View File

@ -11,10 +11,10 @@
1700 - Module for testing error objects
"""
import test_env
import pickle
import cx_Oracle as oracledb
import pickle
import test_env
class TestCase(test_env.BaseTestCase):

View File

@ -11,10 +11,10 @@
1800 - Module for testing interval variables
"""
import test_env
import datetime
import cx_Oracle as oracledb
import datetime
import test_env
class TestCase(test_env.BaseTestCase):
@ -119,9 +119,11 @@ class TestCase(test_env.BaseTestCase):
"1807 - test cursor description is accurate"
self.cursor.execute("select * from TestIntervals")
expected_value = [
('INTCOL', oracledb.DB_TYPE_NUMBER, 10, None, 9, 0, 0),
('INTERVALCOL', oracledb.DB_TYPE_INTERVAL_DS, None, None, 2, 6, 0),
('NULLABLECOL', oracledb.DB_TYPE_INTERVAL_DS, None, None, 2, 6, 1)
('INTCOL', oracledb.DB_TYPE_NUMBER, 10, None, 9, 0, False),
('INTERVALCOL', oracledb.DB_TYPE_INTERVAL_DS, None, None, 2, 6,
False),
('NULLABLECOL', oracledb.DB_TYPE_INTERVAL_DS, None, None, 2, 6,
True)
]
self.assertEqual(self.cursor.description, expected_value)
@ -151,5 +153,12 @@ class TestCase(test_env.BaseTestCase):
self.assertEqual(self.cursor.fetchone(), self.data_by_key[4])
self.assertEqual(self.cursor.fetchone(), None)
def test_1811_bind_and_fetch_negative_interval(self):
"1811 - test binding and fetching a negative interval"
value = datetime.timedelta(days=-1, seconds=86314, microseconds=431152)
self.cursor.execute("select :1 from dual", [value])
result, = self.cursor.fetchone()
self.assertEqual(result, value)
if __name__ == "__main__":
test_env.run_test_cases()

View File

@ -1,5 +1,5 @@
#------------------------------------------------------------------------------
# Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
#
# Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
#
@ -11,16 +11,15 @@
1900 - Module for testing LOB (CLOB and BLOB) variables
"""
import test_env
import cx_Oracle as oracledb
import test_env
class TestCase(test_env.BaseTestCase):
def __get_temp_lobs(self, sid):
cursor = self.connection.cursor()
cursor.execute("""
select abstract_lobs
select cache_lobs + nocache_lobs + abstract_lobs
from v$temporary_lobs
where sid = :sid""", sid = sid)
row = cursor.fetchone()
@ -38,7 +37,7 @@ class TestCase(test_env.BaseTestCase):
long_string += char * 25000
elif input_type is not db_type:
continue
self.cursor.setinputsizes(long_string = input_type)
self.cursor.setinputsizes(long_string=input_type)
if lob_type == "BLOB":
bind_value = long_string.encode()
else:
@ -134,16 +133,16 @@ class TestCase(test_env.BaseTestCase):
prev_char = chr(ord('A') + integer_value - 2)
long_string += char * 25000
if lob_type == "BLOB":
actualValue = long_string.encode("ascii")
expected_value = long_string.encode("ascii")
char = char.encode("ascii")
prev_char = prev_char.encode("ascii")
else:
actualValue = long_string
self.assertEqual(lob.size(), len(actualValue))
self.assertEqual(lob.read(), actualValue)
expected_value = long_string
self.assertEqual(lob.size(), len(expected_value))
self.assertEqual(lob.read(), expected_value)
if lob_type == "CLOB":
self.assertEqual(str(lob), actualValue)
self.assertEqual(lob.read(len(actualValue)), char)
self.assertEqual(str(lob), expected_value)
self.assertEqual(lob.read(len(expected_value)), char)
if integer_value > 1:
offset = (integer_value - 1) * 25000 - 4
string = prev_char * 5 + char * 5
@ -183,8 +182,8 @@ class TestCase(test_env.BaseTestCase):
"1905 - test cursor description is accurate for CLOBs"
self.cursor.execute("select * from TestCLOBs")
expected_value = [
('INTCOL', oracledb.DB_TYPE_NUMBER, 10, None, 9, 0, 0),
('CLOBCOL', oracledb.DB_TYPE_CLOB, None, None, None, None, 0)
('INTCOL', oracledb.DB_TYPE_NUMBER, 10, None, 9, 0, False),
('CLOBCOL', oracledb.DB_TYPE_CLOB, None, None, None, None, False)
]
self.assertEqual(self.cursor.description, expected_value)
@ -232,24 +231,20 @@ class TestCase(test_env.BaseTestCase):
"1914 - test binding and fetching NCLOB data (directly)"
self.__perform_test("NCLOB", oracledb.DB_TYPE_NCLOB)
def test_1915_nclob_different_encodings(self):
"1915 - test binding and fetching NCLOB data (different encodings)"
connection = oracledb.connect(test_env.get_main_user(),
test_env.get_main_password(),
test_env.get_connect_string(),
encoding="UTF-8", nencoding="UTF-16")
def test_1915_nclob_non_ascii_chars(self):
"1915 - test binding and fetching NCLOB data (with non-ASCII chars)"
value = "\u03b4\u4e2a"
cursor = connection.cursor()
cursor.execute("truncate table TestNCLOBs")
cursor.setinputsizes(val=oracledb.DB_TYPE_NVARCHAR)
cursor.execute("insert into TestNCLOBs values (1, :val)", val=value)
cursor.execute("select NCLOBCol from TestNCLOBs")
nclob, = cursor.fetchone()
cursor.setinputsizes(val=oracledb.DB_TYPE_NVARCHAR)
cursor.execute("update TestNCLOBs set NCLOBCol = :val",
val=nclob.read() + value)
cursor.execute("select NCLOBCol from TestNCLOBs")
nclob, = cursor.fetchone()
self.cursor.execute("truncate table TestNCLOBs")
self.cursor.setinputsizes(val=oracledb.DB_TYPE_NVARCHAR)
self.cursor.execute("insert into TestNCLOBs values (1, :val)",
val=value)
self.cursor.execute("select NCLOBCol from TestNCLOBs")
nclob, = self.cursor.fetchone()
self.cursor.setinputsizes(val=oracledb.DB_TYPE_NVARCHAR)
self.cursor.execute("update TestNCLOBs set NCLOBCol = :val",
val=nclob.read() + value)
self.cursor.execute("select NCLOBCol from TestNCLOBs")
nclob, = self.cursor.fetchone()
self.assertEqual(nclob.read(), value + value)
def test_1916_nclob_indirect(self):
@ -280,7 +275,7 @@ class TestCase(test_env.BaseTestCase):
temp_lobs = self.__get_temp_lobs(sid)
self.assertEqual(temp_lobs, 0)
def test_1919_AssignStringBeyondArraySize(self):
def test_1919_assign_string_beyond_array_size(self):
"1919 - test assign string to NCLOB beyond array size"
nclobVar = self.cursor.var(oracledb.DB_TYPE_NCLOB)
self.assertRaises(IndexError, nclobVar.setvalue, 1, "test char")

View File

@ -11,33 +11,35 @@
2000 - Module for testing long and long raw variables
"""
import test_env
import cx_Oracle as oracledb
import test_env
class TestCase(test_env.BaseTestCase):
def __perform_test(self, typ):
name_part = "Long" if typ is oracledb.DB_TYPE_LONG else "LongRaw"
self.cursor.execute("truncate table Test%ss" % name_part)
self.cursor.execute(f"truncate table Test{name_part}s")
self.cursor.setinputsizes(long_string=typ)
long_string = ""
for i in range(1, 11):
char = chr(ord('A') + i - 1)
long_string += char * 25000
self.cursor.setinputsizes(long_string=typ)
if typ is oracledb.DB_TYPE_LONG_RAW:
bind_value = long_string.encode()
if i % 3 == 1:
bind_value = None
else:
bind_value = long_string
self.cursor.execute("""
insert into Test%ss (
if typ is oracledb.DB_TYPE_LONG_RAW:
bind_value = long_string.encode()
else:
bind_value = long_string
self.cursor.execute(f"""
insert into Test{name_part}s (
IntCol,
%sCol
{name_part}Col
) values (
:integer_value,
:long_string
)""" % (name_part, name_part),
)""",
integer_value=i,
long_string=bind_value)
self.connection.commit()
@ -49,12 +51,16 @@ class TestCase(test_env.BaseTestCase):
for integer_value, fetched_value in self.cursor:
char = chr(ord('A') + integer_value - 1)
long_string += char * 25000
if typ is oracledb.DB_TYPE_LONG_RAW:
actual_value = long_string.encode()
if integer_value % 3 == 1:
expected_value = None
else:
actual_value = long_string
self.assertEqual(len(fetched_value), integer_value * 25000)
self.assertEqual(fetched_value, actual_value)
if typ is oracledb.DB_TYPE_LONG_RAW:
expected_value = long_string.encode()
else:
expected_value = long_string
if fetched_value is not None:
self.assertEqual(len(fetched_value), integer_value * 25000)
self.assertEqual(fetched_value, expected_value)
def test_2000_longs(self):
"2000 - test binding and fetching long data"
@ -82,18 +88,20 @@ class TestCase(test_env.BaseTestCase):
"2003 - test cursor description is accurate for longs"
self.cursor.execute("select * from TestLongs")
expected_value = [
('INTCOL', oracledb.DB_TYPE_NUMBER, 10, None, 9, 0, 0),
('LONGCOL', oracledb.DB_TYPE_LONG, None, None, None, None, 0)
('INTCOL', oracledb.DB_TYPE_NUMBER, 10, None, 9, 0, False),
('LONGCOL', oracledb.DB_TYPE_LONG, None, None, None, None, True)
]
self.assertEqual(self.cursor.description, expected_value)
def test_2004_long_raw_cursor_description(self):
"2004 - test cursor description is accurate for long raws"
self.cursor.execute("select * from TestLongRaws")
self.assertEqual(self.cursor.description,
[ ('INTCOL', oracledb.DB_TYPE_NUMBER, 10, None, 9, 0, 0),
('LONGRAWCOL', oracledb.DB_TYPE_LONG_RAW, None, None, None,
None, 0) ])
expected_value = [
('INTCOL', oracledb.DB_TYPE_NUMBER, 10, None, 9, 0, False),
('LONGRAWCOL', oracledb.DB_TYPE_LONG_RAW, None, None, None, None,
True)
]
self.assertEqual(self.cursor.description, expected_value)
def test_2005_array_size_too_large(self):
"2005 - test array size too large generates an exception"

View File

@ -11,9 +11,8 @@
2100 - Module for testing NCHAR variables
"""
import test_env
import cx_Oracle as oracledb
import test_env
class TestCase(test_env.BaseTestCase):
@ -202,11 +201,15 @@ class TestCase(test_env.BaseTestCase):
def test_2114_cursor_description(self):
"2114 - test cursor description is accurate"
self.cursor.execute("select * from TestUnicodes")
varchar_ratio, nvarchar_ratio = test_env.get_charset_ratios()
expected_value = [
('INTCOL', oracledb.DB_TYPE_NUMBER, 10, None, 9, 0, 0),
('UNICODECOL', oracledb.DB_TYPE_NVARCHAR, 20, 80, None, None, 0),
('FIXEDUNICODECOL', oracledb.DB_TYPE_NCHAR, 40, 160, None, None, 0),
('NULLABLECOL', oracledb.DB_TYPE_NVARCHAR, 50, 200, None, None, 1)
('INTCOL', oracledb.DB_TYPE_NUMBER, 10, None, 9, 0, False),
('UNICODECOL', oracledb.DB_TYPE_NVARCHAR, 20, 20 * nvarchar_ratio,
None, None, False),
('FIXEDUNICODECOL', oracledb.DB_TYPE_NCHAR, 40,
40 * nvarchar_ratio, None, None, False),
('NULLABLECOL', oracledb.DB_TYPE_NVARCHAR, 50, 50 * nvarchar_ratio,
None, None, True)
]
self.assertEqual(self.cursor.description, expected_value)

View File

@ -11,12 +11,12 @@
2200 - Module for testing number variables
"""
import test_env
import cx_Oracle as oracledb
import decimal
import sys
import cx_Oracle as oracledb
import test_env
class TestCase(test_env.BaseTestCase):
def output_type_handler_binary_int(self, cursor, name, default_type, size,
@ -273,13 +273,13 @@ class TestCase(test_env.BaseTestCase):
"2220 - test cursor description is accurate"
self.cursor.execute("select * from TestNumbers")
expected_value = [
('INTCOL', oracledb.DB_TYPE_NUMBER, 10, None, 9, 0, 0),
('LONGINTCOL', oracledb.DB_TYPE_NUMBER, 17, None, 16, 0, 0),
('NUMBERCOL', oracledb.DB_TYPE_NUMBER, 13, None, 9, 2, 0),
('FLOATCOL', oracledb.DB_TYPE_NUMBER, 127, None, 126, -127, 0),
('INTCOL', oracledb.DB_TYPE_NUMBER, 10, None, 9, 0, False),
('LONGINTCOL', oracledb.DB_TYPE_NUMBER, 17, None, 16, 0, False),
('NUMBERCOL', oracledb.DB_TYPE_NUMBER, 13, None, 9, 2, False),
('FLOATCOL', oracledb.DB_TYPE_NUMBER, 127, None, 126, -127, False),
('UNCONSTRAINEDCOL', oracledb.DB_TYPE_NUMBER, 127, None, 0, -127,
0),
('NULLABLECOL', oracledb.DB_TYPE_NUMBER, 39, None, 38, 0, 1)
False),
('NULLABLECOL', oracledb.DB_TYPE_NUMBER, 39, None, 38, 0, True)
]
self.assertEqual(self.cursor.description, expected_value)

View File

@ -11,12 +11,12 @@
2300 - Module for testing object variables
"""
import test_env
import cx_Oracle as oracledb
import datetime
import decimal
import cx_Oracle as oracledb
import test_env
class TestCase(test_env.BaseTestCase):
def __test_data(self, expected_int_value, expected_obj_value,
@ -103,9 +103,10 @@ class TestCase(test_env.BaseTestCase):
from TestObjects
order by IntCol""")
expected_value = [
('INTCOL', oracledb.DB_TYPE_NUMBER, 10, None, 9, 0, 0),
('OBJECTCOL', oracledb.DB_TYPE_OBJECT, None, None, None, None, 1),
('ARRAYCOL', oracledb.DB_TYPE_OBJECT, None, None, None, None, 1)
('INTCOL', oracledb.DB_TYPE_NUMBER, 10, None, 9, 0, False),
('OBJECTCOL', oracledb.DB_TYPE_OBJECT, None, None, None, None,
True),
('ARRAYCOL', oracledb.DB_TYPE_OBJECT, None, None, None, None, True)
]
self.assertEqual(self.cursor.description, expected_value)
expected_value = (

View File

@ -32,6 +32,44 @@ class TestCase(test_env.BaseTestCase):
self.assertRaises(oracledb.DatabaseError, cursor.execute,
"select 1 / 0 from dual")
def __callable_session_callback(self, conn, requested_tag):
self.session_called = True
supported_formats = {
"SIMPLE" : "'YYYY-MM-DD HH24:MI'",
"FULL" : "'YYYY-MM-DD HH24:MI:SS'"
}
supported_time_zones = {
"UTC" : "'UTC'",
"MST" : "'-07:00'"
}
supported_keys = {
"NLS_DATE_FORMAT" : supported_formats,
"TIME_ZONE" : supported_time_zones
}
if requested_tag is not None:
state_parts = []
for directive in requested_tag.split(";"):
parts = directive.split("=")
if len(parts) != 2:
raise ValueError("Tag must contain key=value pairs")
key, value = parts
value_dict = supported_keys.get(key)
if value_dict is None:
raise ValueError("Tag only supports keys: %s" % \
(", ".join(supported_keys)))
actual_value = value_dict.get(value)
if actual_value is None:
raise ValueError("Key %s only supports values: %s" % \
(key, ", ".join(value_dict)))
state_parts.append("%s = %s" % (key, actual_value))
sql = "alter session set %s" % " ".join(state_parts)
cursor = conn.cursor()
cursor.execute(sql)
conn.tag = requested_tag
def __perform_reconfigure_test(self, parameter_name, parameter_value,
min=3, max=30, increment=4, timeout=5,
wait_timeout=5000, stmtcachesize=25,
@ -357,7 +395,7 @@ class TestCase(test_env.BaseTestCase):
self.assertEqual(pool.opened, 1, "opened (4)")
def test_2414_create_new_pure_connection(self):
"2414 - test to ensure pure connections and being created correctly"
"2414 - test to ensure pure connections are being created correctly"
pool = test_env.get_pool(min=1, max=2, increment=1,
getmode=oracledb.SPOOL_ATTRVAL_WAIT)
connection_1 = pool.acquire()
@ -441,5 +479,80 @@ class TestCase(test_env.BaseTestCase):
self.assertEqual(pool.stmtcachesize, 25, "stmtcachesize (25)")
self.assertEqual(pool.ping_interval, 25, "ping_interval (25)")
def test_2418_deprecations(self):
"2418 - test to verify deprecations"
callback = "pkg_SessionCallback.TheCallback"
self.assertRaises(oracledb.ProgrammingError, test_env.get_pool,
min=1, max=2, increment=1, wait_timeout=10,
waitTimeout=10)
self.assertRaises(oracledb.ProgrammingError, test_env.get_pool,
min=1, max=2, increment=1, max_lifetime_session=20,
maxLifetimeSession=20)
self.assertRaises(oracledb.ProgrammingError, test_env.get_pool,
min=1, max=2, increment=1, max_sessions_per_shard=1,
maxSessionsPerShard=1)
self.assertRaises(oracledb.ProgrammingError, test_env.get_pool,
min=2, max=8, increment=3,
getmode=oracledb.SPOOL_ATTRVAL_NOWAIT,
session_callback=callback, sessionCallback=callback)
def test_2419_statement_cache_size(self):
"2419 - test to verify statement cache size is retained"
pool = test_env.get_pool(min=1, max=2, increment=1,
getmode=oracledb.SPOOL_ATTRVAL_WAIT,
stmtcachesize=25)
self.assertEqual(pool.stmtcachesize, 25, "stmtcachesize (25)")
pool.stmtcachesize = 35
self.assertEqual(pool.stmtcachesize, 35, "stmtcachesize (35)")
def test_2420_callable_session_callbacks(self):
"2420 - test that session callbacks are being called correctly"
pool = test_env.get_pool(min=2, max=5, increment=1,
session_callback=self.__callable_session_callback)
# new connection with a tag should invoke the session callback
with pool.acquire(tag="NLS_DATE_FORMAT=SIMPLE") as conn:
cursor = conn.cursor()
cursor.execute("select to_char(2021-05-20) from dual")
result, = cursor.fetchone()
self.assertEqual(self.session_called, True)
# acquiring a connection with the same tag should not invoke the
# session callback
self.session_called = False
with pool.acquire(tag="NLS_DATE_FORMAT=SIMPLE") as conn:
cursor = conn.cursor()
cursor.execute("select to_char(2021-05-20) from dual")
result, = cursor.fetchone()
self.assertEqual(self.session_called, False)
# acquiring a connection with a new tag should invoke the session
# callback
self.session_called = False
with pool.acquire(tag="NLS_DATE_FORMAT=FULL;TIME_ZONE=UTC") as conn:
cursor = conn.cursor()
cursor.execute("select to_char(current_date) from dual")
result, = cursor.fetchone()
self.assertEqual(self.session_called, True)
# acquiring a connection with a new tag and specifying that a
# connection with any tag can be acquired should invoke the session
# callback
self.session_called = False
with pool.acquire(tag="NLS_DATE_FORMAT=FULL;TIME_ZONE=MST", \
matchanytag=True) as conn:
cursor = conn.cursor()
cursor.execute("select to_char(current_date) from dual")
result, = cursor.fetchone()
self.assertEqual(self.session_called, True)
# new session with no tag should invoke the session callback
self.session_called = False
with pool.acquire() as conn:
cursor = conn.cursor()
cursor.execute("select to_char(current_date) from dual")
result, = cursor.fetchone()
self.assertEqual(self.session_called, True)
if __name__ == "__main__":
test_env.run_test_cases()

View File

@ -1,5 +1,5 @@
#------------------------------------------------------------------------------
# Copyright (c) 2016, 2021 Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
#
# Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
#
@ -11,12 +11,12 @@
2500 - Module for testing string variables
"""
import test_env
import datetime
import random
import string
import cx_Oracle as oracledb
import datetime
import string
import random
import test_env
class TestCase(test_env.BaseTestCase):
@ -297,15 +297,16 @@ class TestCase(test_env.BaseTestCase):
def test_2522_cursor_description(self):
"2522 - test cursor description is accurate"
self.cursor.execute("select * from TestStrings")
varchar_ratio, nvarchar_ratio = test_env.get_charset_ratios()
expected_value = [
('INTCOL', oracledb.DB_TYPE_NUMBER, 10, None, 9, 0, 0),
('STRINGCOL', oracledb.DB_TYPE_VARCHAR, 20,
20 * test_env.get_charset_ratio(), None, None, 0),
('RAWCOL', oracledb.DB_TYPE_RAW, 30, 30, None, None, 0),
('FIXEDCHARCOL', oracledb.DB_TYPE_CHAR, 40,
40 * test_env.get_charset_ratio(), None, None, 0),
('NULLABLECOL', oracledb.DB_TYPE_VARCHAR, 50,
50 * test_env.get_charset_ratio(), None, None, 1)
('INTCOL', oracledb.DB_TYPE_NUMBER, 10, None, 9, 0, False),
('STRINGCOL', oracledb.DB_TYPE_VARCHAR, 20, 20 * varchar_ratio,
None, None, False),
('RAWCOL', oracledb.DB_TYPE_RAW, 30, 30, None, None, False),
('FIXEDCHARCOL', oracledb.DB_TYPE_CHAR, 40, 40 * varchar_ratio,
None, None, False),
('NULLABLECOL', oracledb.DB_TYPE_VARCHAR, 50, 50 * varchar_ratio,
None, None, True)
]
self.assertEqual(self.cursor.description, expected_value)
@ -426,10 +427,11 @@ class TestCase(test_env.BaseTestCase):
random_string = ''.join(random.choice(chars) for _ in range(1024))
int_val = 200
xml_string = '<data>' + random_string + '</data>'
self.cursor.execute("truncate table TestTempXML")
self.cursor.execute("""
insert into TestXML (IntCol, XMLCol)
insert into TestTempXML (IntCol, XMLCol)
values (:1, :2)""", (int_val, xml_string))
self.cursor.execute("select XMLCol from TestXML where intCol = :1",
self.cursor.execute("select XMLCol from TestTempXML where intCol = :1",
(int_val,))
actual_value, = self.cursor.fetchone()
self.assertEqual(actual_value.strip(), xml_string)
@ -451,11 +453,19 @@ class TestCase(test_env.BaseTestCase):
self.cursor.execute("truncate table TestTempTable")
string_val = "I bought a cafetière on the Champs-Élysées"
sql = "insert into TestTempTable (IntCol, StringCol) values (:1, :2)"
self.cursor.execute(sql, (1, string_val))
self.cursor.outputtypehandler = self.__return_strings_as_bytes
self.cursor.execute("select IntCol, StringCol from TestTempTable")
expected_value = (1, string_val.encode())
self.assertEqual(self.cursor.fetchone(), expected_value)
with self.connection.cursor() as cursor:
cursor.execute(sql, (1, string_val))
cursor.execute("select IntCol, StringCol from TestTempTable")
self.assertEqual(cursor.fetchone(), (1, string_val))
with self.connection.cursor() as cursor:
cursor.outputtypehandler = self.__return_strings_as_bytes
cursor.execute("select IntCol, StringCol from TestTempTable")
expected_value = (1, string_val.encode())
self.assertEqual(cursor.fetchone(), (1, string_val.encode()))
with self.connection.cursor() as cursor:
cursor.outputtypehandler = None
cursor.execute("select IntCol, StringCol from TestTempTable")
self.assertEqual(cursor.fetchone(), (1, string_val))
if __name__ == "__main__":
test_env.run_test_cases()

View File

@ -11,10 +11,10 @@
2600 - Module for testing timestamp variables
"""
import test_env
import time
import cx_Oracle as oracledb
import time
import test_env
class TestCase(test_env.BaseTestCase):
@ -115,9 +115,10 @@ class TestCase(test_env.BaseTestCase):
"2606 - test cursor description is accurate"
self.cursor.execute("select * from TestTimestamps")
expected_value = [
('INTCOL', oracledb.DB_TYPE_NUMBER, 10, None, 9, 0, 0),
('TIMESTAMPCOL', oracledb.DB_TYPE_TIMESTAMP, 23, None, 0, 6, 0),
('NULLABLECOL', oracledb.DB_TYPE_TIMESTAMP, 23, None, 0, 6, 1)
('INTCOL', oracledb.DB_TYPE_NUMBER, 10, None, 9, 0, False),
('TIMESTAMPCOL', oracledb.DB_TYPE_TIMESTAMP, 23, None, 0, 6,
False),
('NULLABLECOL', oracledb.DB_TYPE_TIMESTAMP, 23, None, 0, 6, True)
]
self.assertEqual(self.cursor.description, expected_value)

View File

@ -6,12 +6,12 @@
2700 - Module for testing AQ
"""
import test_env
import cx_Oracle as oracledb
import decimal
import threading
import cx_Oracle as oracledb
import test_env
class TestCase(test_env.BaseTestCase):
book_type_name = "UDT_BOOK"
book_queue_name = "TEST_BOOK_QUEUE"
@ -23,23 +23,21 @@ class TestCase(test_env.BaseTestCase):
def __clear_books_queue(self):
books_type = self.connection.gettype(self.book_type_name)
book = books_type.newobject()
options = self.connection.deqoptions()
options.wait = oracledb.DEQ_NO_WAIT
options.deliverymode = oracledb.MSG_PERSISTENT_OR_BUFFERED
options.visibility = oracledb.ENQ_IMMEDIATE
props = self.connection.msgproperties()
while self.connection.deq(self.book_queue_name, options, props, book):
queue = self.connection.queue(self.book_queue_name, books_type)
queue.deqoptions.wait = oracledb.DEQ_NO_WAIT
queue.deqoptions.deliverymode = oracledb.MSG_PERSISTENT_OR_BUFFERED
queue.deqoptions.visibility = oracledb.DEQ_IMMEDIATE
while queue.deqone():
pass
def __deq_in_thread(self, results):
connection = test_env.get_connection()
connection = test_env.get_connection(threaded=True)
books_type = connection.gettype(self.book_type_name)
book = books_type.newobject()
options = connection.deqoptions()
options.wait = 10
props = connection.msgproperties()
if connection.deq(self.book_queue_name, options, props, book):
queue = connection.queue(self.book_queue_name, books_type)
queue.deqoptions.wait = 10
props = queue.deqone()
if props is not None:
book = props.payload
results.append((book.TITLE, book.AUTHORS, book.PRICE))
connection.commit()
@ -122,8 +120,7 @@ class TestCase(test_env.BaseTestCase):
"2704 - test waiting for dequeue"
self.__clear_books_queue()
results = []
thread = threading.Thread(target = self.__deq_in_thread,
args = (results,))
thread = threading.Thread(target=self.__deq_in_thread, args=(results,))
thread.start()
books_type = self.connection.gettype(self.book_type_name)
book = books_type.newobject()
@ -164,7 +161,6 @@ class TestCase(test_env.BaseTestCase):
self.__verify_attr(props, "expiration", 30)
self.assertEqual(props.attempts, 0)
self.__verify_attr(props, "priority", 1)
self.__verify_attr(props, "msgid", b'mID')
self.assertEqual(props.state, oracledb.MSG_READY)
self.assertEqual(props.deliverymode, 0)
@ -371,5 +367,29 @@ class TestCase(test_env.BaseTestCase):
otherPrice = book.PRICE
self.assertEqual(otherPrice, expectedPrice)
def test_2716_payloadType_deprecation(self):
"2716 - test to verify payloadType is deprecated"
self.__clear_books_queue()
books_type = self.connection.gettype(self.book_type_name)
self.assertRaises(oracledb.ProgrammingError, self.connection.queue,
self.book_queue_name, books_type,
payloadType=books_type)
def test_2718_verify_msgid(self):
"2718 - verify that the msgid property is returned correctly"
self.__clear_books_queue()
books_type = self.connection.gettype(self.book_type_name)
book = books_type.newobject()
book.TITLE, book.AUTHORS, book.PRICE = self.book_data[0]
queue = self.connection.queue(self.book_queue_name, books_type)
props = self.connection.msgproperties(payload=book)
self.assertEqual(props.msgid, None)
queue.enqone(props)
self.cursor.execute("select msgid from book_queue_tab")
actual_msgid, = self.cursor.fetchone()
self.assertEqual(props.msgid, actual_msgid)
props = queue.deqone()
self.assertEqual(props.msgid, actual_msgid)
if __name__ == "__main__":
test_env.run_test_cases()

View File

@ -6,12 +6,12 @@
2800 - Module for testing AQ Bulk enqueue/dequeue
"""
import test_env
import cx_Oracle as oracledb
import decimal
import threading
import cx_Oracle as oracledb
import test_env
RAW_QUEUE_NAME = "TEST_RAW_QUEUE"
RAW_PAYLOAD_DATA = [
"The first message",
@ -131,5 +131,19 @@ class TestCase(test_env.BaseTestCase):
messages = other_queue.deqmany(5)
self.assertEqual(len(messages), 0)
def test_2806_verify_msgid(self):
"2806 - verify that the msgid property is returned correctly"
queue = self.__get_and_clear_raw_queue()
messages = [self.connection.msgproperties(payload=d) \
for d in RAW_PAYLOAD_DATA]
queue.enqmany(messages)
self.cursor.execute("select msgid from raw_queue_tab")
actual_msgids = set(m for m, in self.cursor)
msgids = set(m.msgid for m in messages)
self.assertEqual(msgids, actual_msgids)
messages = queue.deqmany(len(RAW_PAYLOAD_DATA))
msgids = set(m.msgid for m in messages)
self.assertEqual(msgids, actual_msgids)
if __name__ == "__main__":
test_env.run_test_cases()

View File

@ -6,9 +6,8 @@
2900 - Module for testing Rowids
"""
import test_env
import cx_Oracle as oracledb
import test_env
class TestCase(test_env.BaseTestCase):

View File

@ -1,45 +1,66 @@
#------------------------------------------------------------------------------
# Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
#------------------------------------------------------------------------------
"""
3000 - Module for testing subscriptions
"""
import test_env
import threading
import unittest
import cx_Oracle as oracledb
import threading
import test_env
class SubscriptionData(object):
class SubscriptionData:
def __init__(self, num_messages_expected):
self.condition = threading.Condition()
self.num_messages_expected = num_messages_expected
self.num_messages_received = 0
def _process_message(self, message):
pass
def callback_handler(self, message):
if message.type != oracledb.EVENT_DEREG:
self._process_message(message)
self.num_messages_received += 1
if message.type == oracledb.EVENT_DEREG or \
self.num_messages_received == self.num_messages_expected:
with self.condition:
self.condition.notify()
def wait_for_messages(self):
if self.num_messages_received < self.num_messages_expected:
with self.condition:
self.condition.wait(10)
class AQSubscriptionData(SubscriptionData):
pass
class DMLSubscriptionData(SubscriptionData):
def __init__(self, num_messages_expected):
super().__init__(num_messages_expected)
self.table_operations = []
self.row_operations = []
self.rowids = []
def CallbackHandler(self, message):
if message.type != oracledb.EVENT_DEREG:
table, = message.tables
self.table_operations.append(table.operation)
for row in table.rows:
self.row_operations.append(row.operation)
self.rowids.append(row.rowid)
self.num_messages_received += 1
if message.type == oracledb.EVENT_DEREG or \
self.num_messages_received == self.num_messages_expected:
self.condition.acquire()
self.condition.notify()
self.condition.release()
def _process_message(self, message):
table, = message.tables
self.table_operations.append(table.operation)
for row in table.rows:
self.row_operations.append(row.operation)
self.rowids.append(row.rowid)
class TestCase(test_env.BaseTestCase):
def test_3000_subscription(self):
"3000 - test Subscription for insert, update, delete and truncate"
def test_3000_dml_subscription(self):
"3000 - test subscription for insert, update, delete and truncate"
# skip if running on the Oracle Cloud, which does not support
# subscriptions currently
@ -67,9 +88,9 @@ class TestCase(test_env.BaseTestCase):
rowids = []
# set up subscription
data = SubscriptionData(5)
data = DMLSubscriptionData(5)
connection = test_env.get_connection(threaded=True, events=True)
sub = connection.subscribe(callback=data.CallbackHandler,
sub = connection.subscribe(callback=data.callback_handler,
timeout=10, qos=oracledb.SUBSCR_QOS_ROWIDS)
sub.registerquery("select * from TestTempTable")
connection.autocommit = True
@ -105,8 +126,7 @@ class TestCase(test_env.BaseTestCase):
cursor.execute("truncate table TestTempTable")
# wait for all messages to be sent
data.condition.acquire()
data.condition.wait(10)
data.wait_for_messages()
# verify the correct messages were sent
self.assertEqual(data.table_operations, table_operations)
@ -119,5 +139,45 @@ class TestCase(test_env.BaseTestCase):
(test_env.get_main_user(), test_env.get_connect_string())
self.assertEqual(str(sub), expected)
def test_3001_deprecations(self):
"3001 - test to verify deprecations"
connection = test_env.get_connection(threaded=True, events=True)
self.assertRaises(oracledb.ProgrammingError, connection.subscribe,
ip_address='www.oracle.in',
ipAddress='www.oracle.in')
self.assertRaises(oracledb.ProgrammingError, connection.subscribe,
grouping_class=1, groupingClass=1)
self.assertRaises(oracledb.ProgrammingError, connection.subscribe,
grouping_value=3, groupingValue=3)
self.assertRaises(oracledb.ProgrammingError, connection.subscribe,
grouping_type=2, groupingType=2)
self.assertRaises(oracledb.ProgrammingError, connection.subscribe,
client_initiated=True, clientInitiated=True)
@unittest.skip("multiple subscriptions cannot be created simultaneously")
def test_3002_aq_subscription(self):
"3002 - test subscription for AQ"
# create queue and clear it of all messages
queue = self.connection.queue("TEST_RAW_QUEUE")
queue.deqoptions.wait = oracledb.DEQ_NO_WAIT
while queue.deqone():
pass
self.connection.commit()
# set up subscription
data = AQSubscriptionData(1)
connection = test_env.get_connection(events=True)
sub = connection.subscribe(namespace=oracledb.SUBSCR_NAMESPACE_AQ,
name=queue.name, timeout=10,
callback=data.callback_handler)
# enqueue a message
queue.enqone(self.connection.msgproperties(payload="Some data"))
self.connection.commit()
# wait for all messages to be sent
data.wait_for_messages()
if __name__ == "__main__":
test_env.run_test_cases()

View File

@ -12,9 +12,9 @@
"""
import unittest
import test_env
import cx_Oracle as oracledb
import test_env
@unittest.skipUnless(test_env.get_client_version() >= (12, 1),
"unsupported client")

View File

@ -1,5 +1,5 @@
#------------------------------------------------------------------------------
# Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
#
# Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
#
@ -11,12 +11,12 @@
3200 - Module for testing features introduced in 12.1
"""
import test_env
import cx_Oracle as oracledb
import datetime
import unittest
import cx_Oracle as oracledb
import test_env
@unittest.skipUnless(test_env.get_client_version() >= (12, 1),
"unsupported client")
class TestCase(test_env.BaseTestCase):
@ -360,7 +360,6 @@ class TestCase(test_env.BaseTestCase):
c1 sys_refcursor;
c2 sys_refcursor;
begin
open c1 for
select NumberCol
from TestNumbers
@ -374,7 +373,6 @@ class TestCase(test_env.BaseTestCase):
where IntCol between 7 and 10;
dbms_sql.return_result(c2);
end;""")
results = self.cursor.getimplicitresults()
self.assertEqual(len(results), 2)
@ -469,5 +467,26 @@ class TestCase(test_env.BaseTestCase):
self.assertEqual(self.cursor.getarraydmlrowcounts(), [1, 2, 0, 0, 1])
self.assertEqual(self.cursor.rowcount, 4)
def test_3225_implicit_results(self):
"3225 - test using implicit cursors to execute new statements"
cursor = self.connection.cursor()
cursor.execute("""
declare
c1 sys_refcursor;
begin
open c1 for
select NumberCol
from TestNumbers
where IntCol between 3 and 5;
dbms_sql.return_result(c1);
end;""")
results = cursor.getimplicitresults()
self.assertEqual(len(results), 1)
self.assertEqual([n for n, in results[0]], [3.75, 5, 6.25])
results[0].execute("select :1 from dual", (7,))
row, = results[0].fetchone()
self.assertEqual(row, 7)
if __name__ == "__main__":
test_env.run_test_cases()

View File

@ -6,12 +6,12 @@
3300 - Module for testing Simple Oracle Document Access (SODA) Database
"""
import test_env
import cx_Oracle as oracledb
import json
import unittest
import cx_Oracle as oracledb
import test_env
@unittest.skipIf(test_env.skip_soda_tests(),
"unsupported client/server combination")
class TestCase(test_env.BaseTestCase):

View File

@ -1,15 +1,15 @@
#------------------------------------------------------------------------------
# Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
#------------------------------------------------------------------------------
"""
3400 - Module for testing Simple Oracle Document Access (SODA) Collections
"""
import test_env
import unittest
import cx_Oracle as oracledb
import unittest
import test_env
@unittest.skipIf(test_env.skip_soda_tests(),
"unsupported client/server combination")
@ -148,7 +148,7 @@ class TestCase(test_env.BaseTestCase):
self.connection.commit()
coll.drop()
def test_3406_CreateAndDropIndex(self):
def test_3406_create_and_drop_index(self):
"3406 - test create and drop Index"
index_name = "cxoTestIndexes_ix_1"
index_spec = {
@ -301,5 +301,41 @@ class TestCase(test_env.BaseTestCase):
self.assertEqual(coll.find().count(), 0)
coll.drop()
@unittest.skipIf(test_env.skip_client_version_old_multi((19, 11), (21, 3)),
"unsupported client")
def test_3414_soda_hint(self):
"3414 - verify hints are reflected in the executed SQL statement"
soda_db = self.connection.getSodaDatabase()
cursor = self.connection.cursor()
statement = """
SELECT
( SELECT t2.sql_fulltext
FROM v$sql t2
WHERE t2.sql_id = t1.prev_sql_id
AND t2.child_number = t1.prev_child_number
)
FROM v$session t1
WHERE t1.audsid = sys_context('userenv', 'sessionid')"""
coll = soda_db.createCollection("cxoSodaHint")
coll.find().remove()
values_to_insert = [
{"name": "George", "age": 47},
{"name": "Susan", "age": 39},
]
coll.insertOneAndGet(values_to_insert[0], hint="MONITOR")
cursor.execute(statement)
result, = cursor.fetchone()
self.assertTrue('MONITOR' in result.read())
coll.find().hint("MONITOR").getOne().getContent()
cursor.execute(statement)
result, = cursor.fetchone()
self.assertTrue('MONITOR' in result.read())
coll.insertOneAndGet(values_to_insert[1], hint="NO_MONITOR")
cursor.execute(statement)
result, = cursor.fetchone()
self.assertTrue('NO_MONITOR' in result.read())
if __name__ == "__main__":
test_env.run_test_cases()

View File

@ -6,12 +6,13 @@
3500 - Module for testing the JSON data type.
"""
import cx_Oracle as oracledb
import test_env
import datetime
import decimal
import unittest
import cx_Oracle as oracledb
import test_env
@unittest.skipUnless(test_env.get_client_version() >= (21, 0),
"unsupported client")
@unittest.skipUnless(test_env.get_server_version() >= (21, 0),
@ -77,7 +78,7 @@ class TestCase(test_env.BaseTestCase):
self.assertEqual(result, self.json_data)
def test_3501_execute_with_dml_returning(self):
"3502 - inserting single rows with JSON and DML returning"
"3501 - inserting single rows with JSON and DML returning"
json_val = self.json_data[11]
self.cursor.execute("truncate table TestJson")
json_out = self.cursor.var(oracledb.DB_TYPE_JSON)
@ -116,7 +117,7 @@ class TestCase(test_env.BaseTestCase):
self.assertEqual(out_json_var.values, [[v] for v in self.json_data])
def test_3504_boolean(self):
"3509 - test binding boolean values as scalar JSON values"
"3504 - test binding boolean values as scalar JSON values"
data = [
True,
False,
@ -128,7 +129,7 @@ class TestCase(test_env.BaseTestCase):
self.__bind_scalar_as_json(data)
def test_3505_strings_and_bytes(self):
"3509 - test binding strings/bytes values as scalar JSON values"
"3505 - test binding strings/bytes values as scalar JSON values"
data = [
"String 1",
b"A raw value",

View File

@ -6,14 +6,14 @@
3600 - Module for testing the conversions of outputtype handler.
"""
import test_env
import cx_Oracle as oracledb
import datetime
import decimal
import sys
import datetime
import unittest
import cx_Oracle as oracledb
import test_env
class TestCase(test_env.BaseTestCase):
def __test_type_handler(self, input_type, output_type, in_value,

View File

@ -6,13 +6,14 @@
3700 - Module for testing all variable types.
"""
import test_env
import cx_Oracle as oracledb
import decimal
import datetime
import decimal
import time
import unittest
import cx_Oracle as oracledb
import test_env
class TestCase(test_env.BaseTestCase):
def _test_positive_set_and_get(self, var_type, value_to_set,

View File

@ -6,10 +6,10 @@
3800 - Module for testing the input and output type handlers.
"""
import test_env
import json
import cx_Oracle as oracledb
import json
import test_env
class Building(object):

Some files were not shown because too many files have changed in this diff Show More