Compare commits
39 Commits
Author | SHA1 | Date |
---|---|---|
![]() |
6766bcaf27 | |
![]() |
a05b9a5233 | |
![]() |
5cfbb7d9e4 | |
![]() |
fde577bf1f | |
![]() |
1ad43aa912 | |
![]() |
3db3e3772e | |
![]() |
59c41535e3 | |
![]() |
5728cf534e | |
![]() |
3a40eeacaa | |
![]() |
fde9ec78fc | |
![]() |
45118e0c31 | |
![]() |
29ca919445 | |
![]() |
ae687ce736 | |
![]() |
2d33fec37a | |
![]() |
9db9d6907a | |
![]() |
00dc44eade | |
![]() |
76157dd28a | |
![]() |
83148ec574 | |
![]() |
eb37d27464 | |
![]() |
05a9097847 | |
![]() |
438c885c20 | |
![]() |
1347b04976 | |
![]() |
702a91be51 | |
![]() |
08117db459 | |
![]() |
440163efe5 | |
![]() |
c665d2efca | |
![]() |
dfeebc3358 | |
![]() |
5cce9efd49 | |
![]() |
cc067bf83e | |
![]() |
abb666706b | |
![]() |
4229a6d8ad | |
![]() |
59558714ac | |
![]() |
a61b14a5c6 | |
![]() |
5dccb9fb5f | |
![]() |
206e85e4a2 | |
![]() |
df80067f47 | |
![]() |
d585cf06df | |
![]() |
ce4713c6f7 | |
![]() |
31d94e7bf1 |
|
@ -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
|
||||
|
||||
-->
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
-->
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
-->
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
34
README.md
34
README.md
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
sphinx>=4.2.0
|
||||
sphinx-rtd-theme>=0.5.2
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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::
|
||||
|
|
|
@ -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, \
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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>`
|
||||
|
|
|
@ -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)
|
||||
----------------------
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
==============================
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
--------------
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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
|
||||
====================
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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
|
||||
====================
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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
2
odpi
|
@ -1 +1 @@
|
|||
Subproject commit 5574630dcf41ce0c09124059b8ee2ba5bc07efb9
|
||||
Subproject commit f73a7c13d643b3fe252614bafc930afbd8e287dd
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
#------------------------------------------------------------------------------
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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.
|
||||
#------------------------------------------------------------------------------
|
||||
|
|
|
@ -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.
|
||||
#------------------------------------------------------------------------------
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -15,8 +15,9 @@
|
|||
#
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
import sys
|
||||
import json
|
||||
import sys
|
||||
|
||||
import cx_Oracle as oracledb
|
||||
import sample_env
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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.
|
||||
#------------------------------------------------------------------------------
|
||||
|
|
|
@ -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.
|
||||
#------------------------------------------------------------------------------
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
#------------------------------------------------------------------------------
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]
|
||||
#
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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.
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
2
setup.py
2
setup.py
|
@ -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 = []
|
||||
|
|
|
@ -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 ||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 },
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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.")
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
/
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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):
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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 = (
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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):
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue