Compare commits

...

No commits in common. "main" and "gh-pages" have entirely different histories.

246 changed files with 484 additions and 46834 deletions

8
.gitattributes vendored
View File

@ -1,8 +0,0 @@
* text=auto
*.c text
*.h text
*.in text
*.py text
*.rst text
*.txt text

View File

@ -1,10 +0,0 @@
---
name: Announcements
about: Use this if you are sharing something interesting
title: ''
labels: announcement
assignees: ''
---
<!-- Let us know if you are speaking at a conference on cx_Oracle, or have a new package or app that uses cx_Oracle, or something similarly exciting. -->

View File

@ -1,70 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: ''
---
<!--
Thank you for using cx_Oracle.
See https://www.oracle.com/corporate/security-practices/assurance/vulnerability/reporting.html for how to report security issues
Please answer these questions so we can help you.
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
-->
1. What versions are you using?
<!--
Give your database version.
Also run Python and show the output of:
import sys
import platform
print("platform.platform:", platform.platform())
print("sys.maxsize > 2**32:", sys.maxsize > 2**32)
print("platform.python_version:", platform.python_version())
And:
import cx_Oracle
print("cx_Oracle.version:", cx_Oracle.version)
print("cx_Oracle.clientversion:", cx_Oracle.clientversion())
-->
2. Is it an error or a hang or a crash?
3. What error(s) or behavior you are seeing?
<!--
Cut and paste text showing the command you ran. No screenshots.
Use a gist for long screen output and logs: see https://gist.github.com/
-->
4. Include a runnable Python script that shows the problem.
<!--
Include all SQL needed to create the database schema.
Format code by using three backticks on a line before and after code snippets, for example:
```
import cx_Oracle
```
-->

View File

@ -1 +0,0 @@
blank_issues_enabled: false

View File

@ -1,24 +0,0 @@
---
name: Documentation and Example Improvements
about: Use this to suggest changes to documentation and examples
title: ''
labels: enhancement
assignees: ''
---
<!--
Thank you for using cx_Oracle.
Please answer these questions so we can help you.
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
-->
1. What is the link to the documentation section that needs improving?
2. Describe the confusion
3. Suggest changes that would help

View File

@ -1,24 +0,0 @@
---
name: Enhancement Requests
about: Use this for enhancement requests
title: ''
labels: enhancement
assignees: ''
---
<!--
Thank you for using cx_Oracle.
Review existing enhancement requests: https://github.com/oracle/python-cx_Oracle/labels/enhancement
Please answer these questions so we can help you.
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
-->
1. Describe your new request in detail
2. Give supporting information about tools and operating systems. Give relevant product version numbers

View File

@ -1,65 +0,0 @@
---
name: Questions and Runtime Problems
about: For general cx_Oracle questions
title: ''
labels: question
assignees: ''
---
<!--
Thank you for using cx_Oracle.
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://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. What versions are you using?
<!--
Give your database version.
Also run Python and show the output of:
import sys
import platform
print("platform.platform:", platform.platform())
print("sys.maxsize > 2**32:", sys.maxsize > 2**32)
print("platform.python_version:", platform.python_version())
And:
import cx_Oracle
print("cx_Oracle.version:", cx_Oracle.version)
print("cx_Oracle.clientversion:", cx_Oracle.clientversion())
-->
2. Describe the problem
<!-- Cut and paste text showing the command you ran. No screenshots. -->
3. Include a runnable Python script that shows the problem.
<!--
Include all SQL needed to create the database schema.
Use a gist for long code: see https://gist.github.com/
Format code by using three backticks on a line before and after code snippets, for example:
```
import cx_Oracle
```
-->

View File

@ -1,57 +0,0 @@
---
name: Installation Problems
about: Use this for cx_Oracle installation questions
title: ''
labels: install & configuration
assignees: ''
---
<!--
Thank you for using cx_Oracle.
Do these before creating a new issue:
Review and follow the Installation Instructions: https://cx-oracle.readthedocs.io/en/latest/user_guide/installation.html
Review the troubleshooting tips: https://cx-oracle.readthedocs.io/en/latest/user_guide/installation.html#troubleshooting
Review the user manual: https://cx-oracle.readthedocs.io/en/latest/index.html
If you have a `DPI-1047`, `DPI-1050` or `DPI-1072` error, re-review the links above.
Google any errors.
Then please answer these questions so we can help you.
GitHub issues that are not updated for a month may be automatically closed. Feel free to update them at any time.
-->
1. What versions are you using?
<!--
Give your database version.
Also run Python and show the output of:
import sys
import platform
print("platform.platform:", platform.platform())
print("sys.maxsize > 2**32:", sys.maxsize > 2**32)
print("platform.python_version:", platform.python_version())
-->
2. Describe the problem
<!-- Cut and paste text showing the command you ran. No screenshots. -->
3. Show the directory listing where your Oracle Client libraries are installed (e.g. the Instant Client directory). Is it 64-bit or 32-bit?
4. Show what the `PATH` environment variable (on Windows) or `LD_LIBRARY_PATH` (on Linux) is set to?
5. Show any Oracle environment variables set (e.g. ORACLE_HOME, ORACLE_BASE).

13
.github/SECURITY.md vendored
View File

@ -1,13 +0,0 @@
# Reporting Security Vulnerabilities
Oracle values the independent security research community and believes that responsible disclosure of security vulnerabilities helps us ensure the security and privacy of all our users.
Please do NOT raise a GitHub Issue to report a security vulnerability. If you believe you have found a security vulnerability, please submit a report to secalert_us@oracle.com preferably with a proof of concept. We provide additional information on [how to report security vulnerabilities to Oracle](https://www.oracle.com/corporate/security-practices/assurance/vulnerability/reporting.html) which includes public encryption keys for secure email.
We ask that you do not use other channels or contact project contributors directly.
Non-vulnerability related security issues such as great new ideas for security features are welcome on GitHub Issues.
## Security-Related Information
We will provide security related information such as a threat model, considerations for secure use, or any known security issues in our documentation. Please note that labs and sample code are intended to demonstrate a concept and may not be sufficiently hardened for production use.

32
.github/SUPPORT.md vendored
View File

@ -1,32 +0,0 @@
# Python cx_Oracle Support
cx_Oracle is an Open Source project, so do some searching and reading
before asking questions.
## cx_Oracle Installation issues
Read the [Installation instructions](http://cx-oracle.readthedocs.io/en/latest/installation.html)
## SQL and PL/SQL Questions
Ask SQL and PL/SQL questions at [AskTOM](https://asktom.oracle.com/)
Try out SQL and find code snippets on our hosted database
with [LIVE SQL](https://livesql.oracle.com/)
## Database and other Oracle Issues
Ask Database and other Oracle issues on
an [OTN Forum](https://community.oracle.com/community/database/)
## cx_Oracle Documentation
The cx_Oracle documentation
is [here](http://cx-oracle.readthedocs.io/en/latest/)
## Got a cx_Oracle question?
Ask at [GitHub](https://github.com/oracle/python-cx_Oracle/issues)
When opening a new issue, fill in the template that will be shown.
Include enough information for people to understand your problem.

View File

@ -1,20 +0,0 @@
Thanks for contributing!
Before submitting PRs for cx_Oracle you must have your signed *Oracle
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.
The bottom of your commit message must have the following line using your name
and e-mail address as it appears in the OCA Signatories list.
```
Signed-off-by: Your Name <you@example.org>
```
This can be automatically added to pull requests by committing with:
```
git commit --signoff
````

23
.github/stale.yml vendored
View File

@ -1,23 +0,0 @@
# https://probot.github.io/apps/stale/
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 30
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
# Issues with these labels will never be considered stale
exemptLabels:
- pinned
- enhancement
- bug
- announcement
- OCA accepted
# Label to use when marking an issue as stale
staleLabel: inactive
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as inactive because it has not been
updated recently. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: >
This issue has been automatically closed because it has not been updated for a month.

7
.gitignore vendored
View File

@ -1,7 +0,0 @@
*.pyc
.tox/
build/
dist/
doc/build
cx_Oracle.egg-info/
MANIFEST

3
.gitmodules vendored
View File

@ -1,3 +0,0 @@
[submodule "odpi"]
path = odpi
url = ../odpi.git

0
.nojekyll Normal file
View File

View File

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

View File

@ -1,44 +0,0 @@
# Contributing
We welcome your contributions! There are multiple ways to contribute.
## Issues
For bugs or enhancement requests, please file a GitHub issue unless it's security related. When filing a bug remember that the better written the bug is, the more likely it is to be fixed. If you think you've found a security vulnerability, do not raise a GitHub issue and follow the instructions on our [Security Policy](./.github/SECURITY.md).
## Contributing Code
We welcome your code contributions. To get started, you will need to sign the [Oracle Contributor Agreement](https://oca.opensource.oracle.com) (OCA).
For pull requests to be accepted, the bottom of your commit message must have
the following line using the name and e-mail address you used for the OCA.
```text
Signed-off-by: Your Name <you@example.org>
```
This can be automatically added to pull requests by committing with:
```text
git commit --signoff
```
Only pull requests from committers that can be verified as having
signed the OCA can be accepted.
### Pull request process
1. Fork this repository
1. Create a branch in your fork to implement the changes. We recommend using
the issue number as part of your branch name, e.g. `1234-fixes`
1. Ensure that any documentation is updated with the changes that are required
by your fix.
1. Ensure that any samples are updated if the base image has been changed.
1. Submit the pull request. *Do not leave the pull request blank*. Explain exactly
what your changes are meant to do and provide simple steps on how to validate
your changes. Ensure that you reference the issue you created as well.
1. We will review your PR before it is merged.
## Code of Conduct
Follow the [Golden Rule](https://en.wikipedia.org/wiki/Golden_Rule). If you'd like more specific guidelines see the [Contributor Covenant Code of Conduct](https://www.contributor-covenant.org/version/1/4/code-of-conduct/)

View File

@ -1,36 +0,0 @@
LICENSE AGREEMENT FOR CX_ORACLE
Copyright 2016, 2018, Oracle and/or its affiliates. All rights reserved.
Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
Portions Copyright 2001-2007, Computronix (Canada) Ltd., Edmonton, Alberta,
Canada. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions, and the disclaimer that follows.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions, and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the names of the copyright holders nor the names of any contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
DISCLAIMER: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
*AS IS* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Computronix is a registered trademark of Computronix (Canada) Ltd.

View File

@ -1,10 +0,0 @@
include MANIFEST.in
include *.txt
recursive-include odpi *.c
recursive-include odpi *.h
prune odpi/test
prune odpi/samples
recursive-include src *.c
recursive-include src *.h
recursive-include samples *.py *.sql
recursive-include test *.py *.sql

View File

@ -1,73 +0,0 @@
# 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
specification][1] with a considerable number of additions and a couple
of exclusions. See the
[homepage](https://oracle.github.io/python-cx_Oracle/index.html) for a
feature list.
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
See [cx_Oracle Installation][15].
## Documentation
See the [cx_Oracle Documentation][2] and [Release Notes][14].
## Samples
See the [/samples][12] directory and the [tutorial][6]. You can also
look at the scripts in [cx_OracleTools][7] and the modules in
[cx_PyOracleLib][8].
## Help
Issues and questions can be raised with the cx_Oracle community on
[GitHub][9] or on the [mailing list][5].
## Tests
See [/test][11].
## Contributing
See [CONTRIBUTING](https://github.com/oracle/python-cx_Oracle/blob/main/CONTRIBUTING.md)
## License
cx_Oracle is licensed under a BSD license which you can find [here][3].
[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]: 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
[9]: https://github.com/oracle/python-cx_Oracle/issues
[11]: https://github.com/oracle/python-cx_Oracle/tree/main/test
[12]: https://github.com/oracle/python-cx_Oracle/tree/main/samples
[14]: https://cx-oracle.readthedocs.io/en/latest/release_notes.html
[15]: https://cx-oracle.readthedocs.io/en/latest/user_guide/installation.html

View File

@ -1,7 +0,0 @@
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

210
base.css Normal file

File diff suppressed because one or more lines are too long

View File

@ -1,23 +0,0 @@
# Makefile to generate cx_Oracle documentation using Sphinx
SPHINXOPTS =
SPHINXBUILD = sphinx-build
SOURCEDIR = src
BUILDDIR = build
.PHONY: html
html:
@$(SPHINXBUILD) -M html $(SOURCEDIR) $(BUILDDIR) $(SPHINXOPTS)
.PHONY: epub
epub:
@$(SPHINXBUILD) -M epub $(SOURCEDIR) $(BUILDDIR) $(SPHINXOPTS)
.PHONY: pdf
pdf:
@$(SPHINXBUILD) -M latexpdf $(SOURCEDIR) $(BUILDDIR) $(SPHINXOPTS)
.PHONY: clean
clean:
rm -rf $(BUILDDIR)/*

View File

@ -1,13 +0,0 @@
The generated cx_Oracle documentation is at http://cx-oracle.readthedocs.io/
This directory contains the documentation source. It is written using reST
(re-Structured Text) format source files which are processed using Sphinx and
turned into HTML, PDF or ePub documents. If you wish to build these yourself,
you need to install Sphinx. Sphinx is available on many Linux distributions as a
pre-built package. You can also install Sphinx on all platforms using the Python
package manager "pip". For more information on Sphinx, please visit this page:
http://www.sphinx-doc.org
Once Sphinx is installed, the supplied Makefile can be used to build the
different targets.

View File

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

View File

@ -1,358 +0,0 @@
.. _aq:
*********************
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::
All of these objects are extensions to the DB API.
.. _queue:
------
Queues
------
These objects are created using the :meth:`Connection.queue()` method and are
used to enqueue and dequeue messages.
.. attribute:: Queue.connection
This read-only attribute returns a reference to the connection object on
which the queue was created.
.. method:: Queue.deqmany(maxMessages)
Dequeues up to the specified number of messages from the queue and returns
a list of these messages. Each element of the returned list is a
:ref:`message property<msgproperties>` object.
.. versionchanged:: 8.2
For consistency and compliance with the PEP 8 naming style, the name of
the method was changed from `deqMany()`. The old name will continue to
work for a period of time.
.. method:: Queue.deqone()
Dequeues at most one message from the queue. If a message is dequeued, it
will be a :ref:`message property<msgproperties>` object; otherwise, it will
be the value None.
.. versionchanged:: 8.2
For consistency and compliance with the PEP 8 naming style, the name of
the method was changed from `deqOne()`. The old name will continue to
work for a period of time.
.. attribute:: Queue.deqoptions
This read-only attribute returns a reference to the :ref:`options
<deqoptions>` that will be used when dequeuing messages from the queue.
.. versionchanged:: 8.2
For consistency and compliance with the PEP 8 naming style, the name of
the attribute was changed from `deqOptions`. The old name will continue
to work for a period of time.
.. method:: Queue.enqmany(messages)
Enqueues multiple messages into the queue. The messages parameter must be a
sequence containing :ref:`message property <msgproperties>` objects which
have all had their payload attribute set to a value that the queue
supports.
Warning: calling this function in parallel on different connections
acquired from the same pool may fail due to Oracle bug 29928074. Ensure
that this function is not run in parallel, use standalone connections or
connections from different pools, or make multiple calls to
:meth:`Queue.enqone()` instead. The function :meth:`Queue.deqmany()`
call is not affected.
.. versionchanged:: 8.2
For consistency and compliance with the PEP 8 naming style, the name of
the method was changed from `enqMany()`. The old name will continue
to work for a period of time.
.. method:: Queue.enqone(message)
Enqueues a single message into the queue. The message must be a
:ref:`message property<msgproperties>` object which has had its payload
attribute set to a value that the queue supports.
.. versionchanged:: 8.2
For consistency and compliance with the PEP 8 naming style, the name of
the method was changed from `enqOne()`. The old name will continue
to work for a period of time.
.. attribute:: Queue.enqoptions
This read-only attribute returns a reference to the :ref:`options
<enqoptions>` that will be used when enqueuing messages into the queue.
.. versionchanged:: 8.2
For consistency and compliance with the PEP 8 naming style, the name of
the attribute was changed from `enqOptions`. The old name will continue
to work for a period of time.
.. attribute:: Queue.name
This read-only attribute returns the name of the queue.
.. attribute:: Queue.payload_type
This read-only attribute returns the object type for payloads that can be
enqueued and dequeued. If using a raw queue, this returns the value None.
.. versionchanged:: 8.2
For consistency and compliance with the PEP 8 naming style, the name of
the attribute was changed from `payloadType`. The old name will
continue to work for a period of time.
.. _deqoptions:
---------------
Dequeue Options
---------------
.. note::
These objects are used to configure how messages are dequeued from queues.
An instance of this object is found in the attribute
:attr:`Queue.deqOptions`.
.. attribute:: DeqOptions.condition
This attribute specifies a boolean expression similar to the where clause
of a SQL query. The boolean expression can include conditions on message
properties, user data properties and PL/SQL or SQL functions. The default
is to have no condition specified.
.. attribute:: DeqOptions.consumername
This attribute specifies the name of the consumer. Only messages matching
the consumer name will be accessed. If the queue is not set up for multiple
consumers this attribute should not be set. The default is to have no
consumer name specified.
.. attribute:: DeqOptions.correlation
This attribute specifies the correlation identifier of the message to be
dequeued. Special pattern-matching characters, such as the percent sign (%)
and the underscore (_), can be used. If multiple messages satisfy the
pattern, the order of dequeuing is indeterminate. The default is to have no
correlation specified.
.. attribute:: DeqOptions.deliverymode
This write-only attribute specifies what types of messages should be
dequeued. It should be one of the values :data:`~cx_Oracle.MSG_PERSISTENT`
(default), :data:`~cx_Oracle.MSG_BUFFERED` or
:data:`~cx_Oracle.MSG_PERSISTENT_OR_BUFFERED`.
.. attribute:: DeqOptions.mode
This attribute specifies the locking behaviour associated with the dequeue
operation. It should be one of the values :data:`~cx_Oracle.DEQ_BROWSE`,
:data:`~cx_Oracle.DEQ_LOCKED`,
:data:`~cx_Oracle.DEQ_REMOVE` (default), or
:data:`~cx_Oracle.DEQ_REMOVE_NODATA`.
.. attribute:: DeqOptions.msgid
This attribute specifies the identifier of the message to be dequeued. The
default is to have no message identifier specified.
.. attribute:: DeqOptions.navigation
This attribute specifies the position of the message that is retrieved. It
should be one of the values :data:`~cx_Oracle.DEQ_FIRST_MSG`,
:data:`~cx_Oracle.DEQ_NEXT_MSG` (default), or
:data:`~cx_Oracle.DEQ_NEXT_TRANSACTION`.
.. attribute:: DeqOptions.transformation
This attribute specifies the name of the transformation that must be
applied after the message is dequeued from the database but before it is
returned to the calling application. The transformation must be created
using dbms_transform. The default is to have no transformation specified.
.. attribute:: DeqOptions.visibility
This attribute specifies the transactional behavior of the dequeue request.
It should be one of the values :data:`~cx_Oracle.DEQ_ON_COMMIT` (default)
or :data:`~cx_Oracle.DEQ_IMMEDIATE`. This attribute is ignored when using
the :data:`~cx_Oracle.DEQ_BROWSE` mode. Note the value of
:attr:`~Connection.autocommit` is always ignored.
.. attribute:: DeqOptions.wait
This attribute specifies the time to wait, in seconds, for a message
matching the search criteria to become available for dequeuing. One of the
values :data:`~cx_Oracle.DEQ_NO_WAIT` or
:data:`~cx_Oracle.DEQ_WAIT_FOREVER` can also be used. The default is
:data:`~cx_Oracle.DEQ_WAIT_FOREVER`.
.. _enqoptions:
---------------
Enqueue Options
---------------
.. note::
These objects are used to configure how messages are enqueued into queues.
An instance of this object is found in the attribute
:attr:`Queue.enqOptions`.
.. attribute:: EnqOptions.deliverymode
This write-only attribute specifies what type of messages should be
enqueued. It should be one of the values :data:`~cx_Oracle.MSG_PERSISTENT`
(default) or :data:`~cx_Oracle.MSG_BUFFERED`.
.. attribute:: EnqOptions.transformation
This attribute specifies the name of the transformation that must be
applied before the message is enqueued into the database. The
transformation must be created using dbms_transform. The default is to have
no transformation specified.
.. attribute:: EnqOptions.visibility
This attribute specifies the transactional behavior of the enqueue request.
It should be one of the values :data:`~cx_Oracle.ENQ_ON_COMMIT` (default)
or :data:`~cx_Oracle.ENQ_IMMEDIATE`. Note the value of
:attr:`~Connection.autocommit` is ignored.
.. _msgproperties:
------------------
Message Properties
------------------
.. note::
These objects are used to identify the properties of messages that are
enqueued and dequeued in queues. They are created by the method
:meth:`Connection.msgproperties()`. They are used by the methods
:meth:`Queue.enqone()` and :meth:`Queue.enqmany()` and
returned by the methods :meth:`Queue.deqone()` and :meth:`Queue.deqmany()`.
.. attribute:: MessageProperties.attempts
This read-only attribute specifies the number of attempts that have been
made to dequeue the message.
.. attribute:: MessageProperties.correlation
This attribute specifies the correlation used when the message was
enqueued.
.. attribute:: MessageProperties.delay
This attribute specifies the number of seconds to delay an enqueued
message. Any integer is acceptable but the constant
:data:`~cx_Oracle.MSG_NO_DELAY` can also be used indicating that the
message is available for immediate dequeuing.
.. attribute:: MessageProperties.deliverymode
This read-only attribute specifies the type of message that was dequeued.
It will be one of the values :data:`~cx_Oracle.MSG_PERSISTENT` or
:data:`~cx_Oracle.MSG_BUFFERED`.
.. attribute:: MessageProperties.enqtime
This read-only attribute specifies the time that the message was enqueued.
.. attribute:: MessageProperties.exceptionq
This attribute specifies the name of the queue to which the message is
moved if it cannot be processed successfully. Messages are moved if the
number of unsuccessful dequeue attempts has exceeded the maximum number of
retries or if the message has expired. All messages in the exception queue
are in the :data:`~cx_Oracle.MSG_EXPIRED` state. The default value is the
name of the exception queue associated with the queue table.
.. attribute:: MessageProperties.expiration
This attribute specifies, in seconds, how long the message is available for
dequeuing. This attribute is an offset from the delay attribute. Expiration
processing requires the queue monitor to be running. Any integer is
accepted but the constant :data:`~cx_Oracle.MSG_NO_EXPIRATION` can also be
used indicating that the message never expires.
.. attribute:: MessageProperties.msgid
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
This attribute identifies the payload that will be enqueued or the payload
that was dequeued when using a :ref:`queue <queue>`. When enqueuing, the
value is checked to ensure that it conforms to the type expected by that
queue. For RAW queues, the value can be a bytes object or a string. If the
value is a string it will first be converted to bytes by encoding in the
encoding identified by the attribute :attr:`Connection.encoding`.
.. attribute:: MessageProperties.priority
This attribute specifies the priority of the message. A smaller number
indicates a higher priority. The priority can be any integer, including
negative numbers. The default value is zero.
.. attribute:: MessageProperties.state
This read-only attribute specifies the state of the message at the time of
the dequeue. It will be one of the values :data:`~cx_Oracle.MSG_WAITING`,
:data:`~cx_Oracle.MSG_READY`, :data:`~cx_Oracle.MSG_PROCESSED` or
:data:`~cx_Oracle.MSG_EXPIRED`.

View File

@ -1,759 +0,0 @@
.. _connobj:
*****************
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
is destroyed or closed.
.. method:: Connection.__enter__()
The entry point for the connection as a context manager. It returns itself.
.. note::
This method is an extension to the DB API definition.
.. method:: Connection.__exit__()
The exit point for the connection as a context manager. This will close
the connection and roll back any uncommitted transaction.
.. note::
This method is an extension to the DB API definition.
.. attribute:: Connection.action
This write-only attribute sets the action column in the v$session table. It
is a string attribute and cannot be set to None -- use the empty string
instead.
.. note::
This attribute is an extension to the DB API definition.
.. attribute:: Connection.autocommit
This read-write attribute determines whether autocommit mode is on or off.
When autocommit mode is on, all statements are committed as soon as they
have completed executing.
.. note::
This attribute is an extension to the DB API definition.
.. method:: Connection.begin([formatId, transactionId, branchId])
Explicitly begin a new transaction. Without parameters, this explicitly
begins a local transaction; otherwise, this explicitly begins a distributed
(global) transaction with the given parameters. See the Oracle
documentation for more details.
Note that in order to make use of global (distributed) transactions, the
:attr:`~Connection.internal_name` and :attr:`~Connection.external_name`
attributes must be set.
.. note::
This method is an extension to the DB API definition.
.. attribute:: Connection.call_timeout
This read-write attribute specifies the amount of time (in milliseconds)
that a single round-trip to the database may take before a timeout will
occur. A value of 0 means that no timeout will take place.
If a timeout occurs, the error *DPI-1067* will be returned if the
connection is still usable. Alternatively the error *DPI-1080* will be
returned if the connection has become invalid and can no longer be used.
.. versionadded:: 7.0
.. versionchanged:: 8.2
For consistency and compliance with the PEP 8 naming style, the
attribute `callTimeout` was renamed to `call_timeout`. The old name
will continue to work for a period of time. The error *DPI-1080* was
also introduced in this release.
.. note::
This attribute is an extension to the DB API definition and is only
available in Oracle Client 18c and higher.
.. method:: Connection.cancel()
Break a long-running transaction.
.. note::
This method is an extension to the DB API definition.
.. method:: Connection.changepassword(oldpassword, newpassword)
Change the password of the logon.
.. note::
This method is an extension to the DB API definition.
.. attribute:: Connection.client_identifier
This write-only attribute sets the client_identifier column in the
v$session table.
.. note::
This attribute is an extension to the DB API definition.
.. attribute:: Connection.clientinfo
This write-only attribute sets the client_info column in the v$session
table.
.. note::
This attribute is an extension to the DB API definition.
.. method:: Connection.close()
Close the connection now, rather than whenever __del__ is called. The
connection will be unusable from this point forward; an Error exception
will be raised if any operation is attempted with the connection.
All open cursors and LOBs created by the connection will be closed and will
also no longer be usable.
Internally, references to the connection are held by cursor objects,
LOB objects, subscription objects, etc. Once all of these references are
released, the connection itself will be closed automatically. Either
control references to these related objects carefully or explicitly close
connections in order to ensure sufficient resources are available.
.. method:: Connection.commit()
Commit any pending transactions to the database.
.. method:: Connection.createlob(lobType)
Create and return a new temporary :ref:`LOB object <lobobj>` of the
specified type. The lobType parameter should be one of
:data:`cx_Oracle.CLOB`, :data:`cx_Oracle.BLOB` or :data:`cx_Oracle.NCLOB`.
.. versionadded:: 6.2
.. note::
This method is an extension to the DB API definition.
.. attribute:: Connection.current_schema
This read-write attribute sets the current schema attribute for the
session. Setting this value is the same as executing the SQL statement
"ALTER SESSION SET CURRENT_SCHEMA". The attribute is set (and verified) on
the next call that does a round trip to the server. The value is placed
before unqualified database objects in SQL statements you then execute.
.. note::
This attribute is an extension to the DB API definition.
.. method:: Connection.cursor()
Return a new :ref:`cursor object <cursorobj>` using the connection.
.. attribute:: Connection.dbop
This write-only attribute sets the database operation that is to be
monitored. This can be viewed in the DBOP_NAME column of the V$SQL_MONITOR
table.
.. note::
This attribute is an extension to the DB API definition.
.. method:: Connection.deq(name, options, msgproperties, payload)
Returns a message id after successfully dequeuing a message. The options
object can be created using :meth:`~Connection.deqoptions()` and the
msgproperties object can be created using
:meth:`~Connection.msgproperties()`. The payload must be an object created
using :meth:`ObjectType.newobject()`.
.. versionadded:: 5.3
.. deprecated:: 7.2
Use the methods :meth:`Queue.deqone()` or :meth:`Queue.deqmany()`
instead.
.. note::
This method is an extension to the DB API definition.
.. method:: Connection.deqoptions()
Returns an object specifying the options to use when dequeuing messages.
See :ref:`deqoptions` for more information.
.. versionadded:: 5.3
.. deprecated:: 7.2
Use the attribute :attr:`Queue.deqoptions` instead.
.. note::
This method is an extension to the DB API definition.
.. attribute:: Connection.dsn
This read-only attribute returns the TNS entry of the database to which a
connection has been established.
.. note::
This attribute is an extension to the DB API definition.
.. attribute:: Connection.edition
This read-only attribute gets the session edition and is only available in
Oracle Database 11.2 (both client and server must be at this level or
higher for this to work).
.. versionadded:: 5.3
.. note::
This attribute is an extension to the DB API definition.
.. attribute:: Connection.encoding
This read-only attribute returns the IANA character set name of the
character set in use by the Oracle client for regular strings.
.. deprecated:: 8.2
.. note::
This attribute is an extension to the DB API definition.
.. method:: Connection.enq(name, options, msgproperties, payload)
Returns a message id after successfully enqueuing a message. The options
object can be created using :meth:`~Connection.enqoptions()` and the
msgproperties object can be created using
:meth:`~Connection.msgproperties()`. The payload must be an object created
using :meth:`ObjectType.newobject()`.
.. versionadded:: 5.3
.. deprecated:: 7.2
Use the methods :meth:`Queue.enqone()` or :meth:`Queue.enqmany()`
instead.
.. note::
This method is an extension to the DB API definition.
.. method:: Connection.enqoptions()
Returns an object specifying the options to use when enqueuing messages.
See :ref:`enqoptions` for more information.
.. versionadded:: 5.3
.. deprecated:: 7.2
Use the attribute :attr:`Queue.enqoptions` instead.
.. note::
This method is an extension to the DB API definition.
.. attribute:: Connection.external_name
This read-write attribute specifies the external name that is used by the
connection when logging distributed transactions.
.. versionadded:: 5.3
.. note::
This attribute is an extension to the DB API definition.
.. method:: Connection.getSodaDatabase()
Return a :ref:`SodaDatabase <sodadb>` object for Simple Oracle Document
Access (SODA). All SODA operations are performed either on the returned
SodaDatabase object or from objects created by the returned SodaDatabase
object. See `here <https://www.oracle.com/pls/topic/lookup?
ctx=dblatest&id=GUID-BE42F8D3-B86B-43B4-B2A3-5760A4DF79FB>`__ for
additional information on SODA.
.. versionadded:: 7.0
.. note::
This method is an extension to the DB API definition.
.. method:: Connection.gettype(name)
Return a :ref:`type object <objecttype>` given its name. This can then be
used to create objects which can be bound to cursors created by this
connection.
.. versionadded:: 5.3
.. note::
This method is an extension to the DB API definition.
.. attribute:: Connection.handle
This read-only attribute returns the OCI service context handle for the
connection. It is primarily provided to facilitate testing the creation of
a connection using the OCI service context handle.
.. note::
This attribute is an extension to the DB API definition.
.. attribute:: Connection.inputtypehandler
This read-write attribute specifies a method called for each value that is
bound to a statement executed on any cursor associated with this
connection. The method signature is handler(cursor, value, arraysize) and
the return value is expected to be a variable object or None in which case
a default variable object will be created. If this attribute is None, the
default behavior will take place for all values bound to statements.
.. note::
This attribute is an extension to the DB API definition.
.. attribute:: Connection.internal_name
This read-write attribute specifies the internal name that is used by the
connection when logging distributed transactions.
.. versionadded:: 5.3
.. note::
This attribute is an extension to the DB API definition.
.. attribute:: Connection.ltxid
This read-only attribute returns the logical transaction id for the
connection. It is used within Oracle Transaction Guard as a means of
ensuring that transactions are not duplicated. See the Oracle documentation
and the provided sample for more information.
.. versionadded:: 5.3
.. note:
This attribute is an extension to the DB API definition. It is only
available when Oracle Database 12.1 or higher is in use on both the
server and the client.
.. attribute:: Connection.maxBytesPerCharacter
This read-only attribute returns the maximum number of bytes each character
can use for the client character set.
.. deprecated:: 8.2
.. note::
This attribute is an extension to the DB API definition.
.. attribute:: Connection.module
This write-only attribute sets the module column in the v$session table.
The maximum length for this string is 48 and if you exceed this length you
will get ORA-24960.
.. note:
This attribute is an extension to the DB API definition.
.. method:: Connection.msgproperties(payload, correlation, delay, exceptionq, \
expiration, priority)
Returns an object specifying the properties of messages used in advanced
queuing. See :ref:`msgproperties` for more information.
Each of the parameters are optional. If specified, they act as a shortcut
for setting each of the equivalently named properties.
.. versionadded:: 5.3
.. versionchanged:: 7.2 Added parameters
.. note::
This method is an extension to the DB API definition.
.. attribute:: Connection.nencoding
This read-only attribute returns the IANA character set name of the
national character set in use by the Oracle client.
.. deprecated:: 8.2
.. note::
This attribute is an extension to the DB API definition.
.. attribute:: Connection.outputtypehandler
This read-write attribute specifies a method called for each column that is
going to be fetched from any cursor associated with this connection. The
method signature is handler(cursor, name, defaultType, length, precision,
scale) and the return value is expected to be a variable object or None in
which case a default variable object will be created. If this attribute is
None, the default behavior will take place for all columns fetched from
cursors.
See :ref:`outputtypehandlers`.
.. note::
This attribute is an extension to the DB API definition.
.. method:: Connection.ping()
Ping the server which can be used to test if the connection is still
active.
.. note::
This method is an extension to the DB API definition.
.. method:: Connection.prepare()
Prepare the distributed (global) transaction for commit. Return a boolean
indicating if a transaction was actually prepared in order to avoid the
error ORA-24756 (transaction does not exist).
.. note::
This method is an extension to the DB API definition.
.. method:: Connection.queue(name, payload_type=None)
Creates a :ref:`queue <queue>` which is used to enqueue and dequeue
messages in Advanced Queueing.
The name parameter is expected to be a string identifying the queue in
which messages are to be enqueued or dequeued.
The payload_type parameter, if specified, is expected to be an
:ref:`object type <objecttype>` that identifies the type of payload the
queue expects. If not specified, RAW data is enqueued and dequeued.
.. versionadded:: 7.2
.. versionchanged:: 8.2
For consistency and compliance with the PEP 8 naming style, the
parameter `payloadType` was renamed to `payload_type`. The old name
will continue to work as a keyword parameter for a period of time.
.. note::
This method is an extension to the DB API definition.
.. method:: Connection.rollback()
Rollback any pending transactions.
.. method:: Connection.shutdown([mode])
Shutdown the database. In order to do this the connection must be connected
as :data:`~cx_Oracle.SYSDBA` or :data:`~cx_Oracle.SYSOPER`. Two calls must
be made unless the mode specified is :data:`~cx_Oracle.DBSHUTDOWN_ABORT`.
An example is shown below:
::
import cx_Oracle
connection = cx_Oracle.connect(mode = cx_Oracle.SYSDBA)
connection.shutdown(mode = cx_Oracle.DBSHUTDOWN_IMMEDIATE)
cursor = connection.cursor()
cursor.execute("alter database close normal")
cursor.execute("alter database dismount")
connection.shutdown(mode = cx_Oracle.DBSHUTDOWN_FINAL)
.. note::
This method is an extension to the DB API definition.
.. method:: Connection.startup(force=False, restrict=False, pfile=None)
Startup the database. This is equivalent to the SQL\*Plus command "startup
nomount". The connection must be connected as :data:`~cx_Oracle.SYSDBA` or
:data:`~cx_Oracle.SYSOPER` with the :data:`~cx_Oracle.PRELIM_AUTH` option
specified for this to work.
The pfile parameter, if specified, is expected to be a string identifying
the location of the parameter file (PFILE) which will be used instead of
the stored parameter file (SPFILE).
An example is shown below:
::
import cx_Oracle
connection = cx_Oracle.connect(
mode=cx_Oracle.SYSDBA | cx_Oracle.PRELIM_AUTH)
connection.startup()
connection = cx_Oracle.connect(mode=cx_Oracle.SYSDBA)
cursor = connection.cursor()
cursor.execute("alter database mount")
cursor.execute("alter database open")
.. note::
This method is an extension to the DB API definition.
.. attribute:: Connection.stmtcachesize
This read-write attribute specifies the size of the statement cache. This
value can make a significant difference in performance if you have a small
number of statements that you execute repeatedly.
The default value is 20.
See :ref:`Statement Caching <stmtcache>` for more information.
.. note::
This attribute is an extension to the DB API definition.
.. method:: Connection.subscribe(namespace=cx_Oracle.SUBSCR_NAMESPACE_DBCHANGE, protocol=cx_Oracle.SUBSCR_PROTO_OCI, callback=None, timeout=0, operations=OPCODE_ALLOPS, port=0, qos=0, ip_address=None, grouping_class=0, grouping_value=0, grouping_type=cx_Oracle.SUBSCR_GROUPING_TYPE_SUMMARY, name=None, client_initiated=False)
Return a new :ref:`subscription object <subscrobj>` that receives
notifications for events that take place in the database that match the
given parameters.
The namespace parameter specifies the namespace the subscription uses. It
can be one of :data:`cx_Oracle.SUBSCR_NAMESPACE_DBCHANGE` or
:data:`cx_Oracle.SUBSCR_NAMESPACE_AQ`.
The protocol parameter specifies the protocol to use when notifications are
sent. Currently the only valid value is :data:`cx_Oracle.SUBSCR_PROTO_OCI`.
The callback is expected to be a callable that accepts a single parameter.
A :ref:`message object <msgobjects>` is passed to this callback whenever a
notification is received.
The timeout value specifies that the subscription expires after the given
time in seconds. The default value of 0 indicates that the subscription
never expires.
The operations parameter enables filtering of the messages that are sent
(insert, update, delete). The default value will send notifications for all
operations. This parameter is only used when the namespace is set to
:data:`cx_Oracle.SUBSCR_NAMESPACE_DBCHANGE`.
The port parameter specifies the listening port for callback notifications
from the database server. If not specified, an unused port will be selected
by the Oracle Client libraries.
The qos parameter specifies quality of service options. It should be one or
more of the following flags, OR'ed together:
:data:`cx_Oracle.SUBSCR_QOS_RELIABLE`,
:data:`cx_Oracle.SUBSCR_QOS_DEREG_NFY`,
:data:`cx_Oracle.SUBSCR_QOS_ROWIDS`,
:data:`cx_Oracle.SUBSCR_QOS_QUERY`,
:data:`cx_Oracle.SUBSCR_QOS_BEST_EFFORT`.
The ip_address parameter specifies the IP address (IPv4 or IPv6) in
standard string notation to bind for callback notifications from the
database server. If not specified, the client IP address will be determined
by the Oracle Client libraries.
The grouping_class parameter specifies what type of grouping of
notifications should take place. Currently, if set, this value can only be
set to the value :data:`cx_Oracle.SUBSCR_GROUPING_CLASS_TIME`, which
will group notifications by the number of seconds specified in the
grouping_value parameter. The grouping_type parameter should be one of the
values :data:`cx_Oracle.SUBSCR_GROUPING_TYPE_SUMMARY` (the default) or
:data:`cx_Oracle.SUBSCR_GROUPING_TYPE_LAST`.
The name parameter is used to identify the subscription and is specific to
the selected namespace. If the namespace parameter is
:data:`cx_Oracle.SUBSCR_NAMESPACE_DBCHANGE` then the name is optional and
can be any value. If the namespace parameter is
:data:`cx_Oracle.SUBSCR_NAMESPACE_AQ`, however, the name must be in the
format '<QUEUE_NAME>' for single consumer queues and
'<QUEUE_NAME>:<CONSUMER_NAME>' for multiple consumer queues, and identifies
the queue that will be monitored for messages. The queue name may include
the schema, if needed.
The client_initiated parameter is used to determine if client initiated
connections or server initiated connections (the default) will be
established. Client initiated connections are only available in Oracle
Client 19.4 and Oracle Database 19.4 and higher.
.. versionadded:: 6.4
The parameters ipAddress, groupingClass, groupingValue, groupingType
and name were added.
.. versionadded:: 7.3
The parameter clientInitiated was added.
.. versionchanged:: 8.2
For consistency and compliance with the PEP 8 naming style, the
parameter `ipAddress` was renamed to `ip_address`, the parameter
`groupingClass` was renamed to `grouping_class`, the parameter
`groupingValue` was renamed to `grouping_value`, the parameter
`groupingType` was renamed to `grouping_type` and the parameter
`clientInitiated` was renamed to `client_initiated`. The old names will
continue to work as keyword parameters for a period of time.
.. note::
This method is an extension to the DB API definition.
.. note::
The subscription can be deregistered in the database by calling the
function :meth:`~Connection.unsubscribe()`. If this method is not
called and the connection that was used to create the subscription is
explicitly closed using the function :meth:`~Connection.close()`, the
subscription will not be deregistered in the database.
.. attribute:: Connection.tag
This read-write attribute initially contains the actual tag of the session
that was acquired from a pool by :meth:`SessionPool.acquire()`. If the
connection was not acquired from a pool or no tagging parameters were
specified (tag and matchanytag) when the connection was acquired from the
pool, this value will be None. If the value is changed, it must be a string
containing name=value pairs like "k1=v1;k2=v2".
If this value is not None when the connection is released back to the pool
it will be used to retag the session. This value can be overridden in the
call to :meth:`SessionPool.release()`.
.. note::
This attribute is an extension to the DB API definition.
.. versionadded:: 7.1
.. attribute:: Connection.tnsentry
This read-only attribute returns the TNS entry of the database to which a
connection has been established.
.. deprecated:: 8.2
Use the attribute :attr:`~Connection.dsn` instead.
.. note::
This attribute is an extension to the DB API definition.
.. method:: Connection.unsubscribe(subscr)
Unsubscribe from events in the database that were originally subscribed to
using :meth:`~Connection.subscribe()`. The connection used to unsubscribe
should be the same one used to create the subscription, or should access
the same database and be connected as the same user name.
.. versionadded:: 6.4
.. attribute:: Connection.username
This read-only attribute returns the name of the user which established the
connection to the database.
.. note::
This attribute is an extension to the DB API definition.
.. attribute:: Connection.version
This read-only attribute returns the version of the database to which a
connection has been established.
.. note::
This attribute is an extension to the DB API definition.
.. note::
If you connect to Oracle Database 18 or higher with client libraries
12.2 or lower that you will only receive the base version (such as
18.0.0.0.0) instead of the full version (18.3.0.0.0).

View File

@ -1,678 +0,0 @@
.. _cursorobj:
*************
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.
.. note::
This method is an extension to the DB API definition.
.. method:: Cursor.__exit__()
The exit point for the cursor as a context manager. It closes the cursor.
.. note::
This method is an extension to the DB API definition.
.. attribute:: Cursor.arraysize
This read-write attribute can be used to tune the number of rows internally
fetched and buffered by internal calls to the database when fetching rows
from SELECT statements and REF CURSORS. The value can drastically affect
the performance of a query since it directly affects the number of network
round trips between Python and the database. For methods like
:meth:`~Cursor.fetchone()` and :meth:`~Cursor.fetchall()` it does not change
how many rows are returned to the application. For
:meth:`~Cursor.fetchmany()` it is the default number of rows to fetch.
Due to the performance benefits, the default ``Cursor.arraysize`` is 100
instead of the 1 that the DB API recommends. This value means that 100 rows
are fetched by each internal call to the database.
See :ref:`Tuning Fetch Performance <tuningfetch>` for more information.
.. attribute:: Cursor.bindarraysize
This read-write attribute specifies the number of rows to bind at a time
and is used when creating variables via :meth:`~Cursor.setinputsizes()` or
:meth:`~Cursor.var()`. It defaults to 1 meaning to bind a single row at a
time.
.. note::
The DB API definition does not define this attribute.
.. method:: Cursor.arrayvar(typ, value, [size])
Create an array variable associated with the cursor of the given type and
size and return a :ref:`variable object <varobj>`. The value is either an
integer specifying the number of elements to allocate or it is a list and
the number of elements allocated is drawn from the size of the list. If the
value is a list, the variable is also set with the contents of the list. If
the size is not specified and the type is a string or binary, 4000 bytes
is allocated. This is needed for passing arrays to PL/SQL (in cases where
the list might be empty and the type cannot be determined automatically) or
returning arrays from PL/SQL.
Array variables can only be used for PL/SQL associative arrays with
contiguous keys. For PL/SQL associative arrays with sparsely populated keys
or for varrays and nested tables, the approach shown in this
`example <https://github.com/oracle/python-cx_Oracle/blob/main/
samples/plsql_collection.py>`__ needs to be used.
.. note::
The DB API definition does not define this method.
.. method:: Cursor.bindnames()
Return the list of bind variable names bound to the statement. Note that a
statement must have been prepared first.
.. note::
The DB API definition does not define this method.
.. attribute:: Cursor.bindvars
This read-only attribute provides the bind variables used for the last
execute. The value will be either a list or a dictionary depending on
whether binding was done by position or name. Care should be taken when
referencing this attribute. In particular, elements should not be removed
or replaced.
.. note::
The DB API definition does not define this attribute.
.. method:: Cursor.callfunc(name, returnType, parameters=[], \
keyword_parameters={})
Call a function with the given name. The return type is specified in the
same notation as is required by :meth:`~Cursor.setinputsizes()`. The
sequence of parameters must contain one entry for each parameter that the
function expects. Any keyword parameters will be included after the
positional parameters. The result of the call is the return value of the
function.
See :ref:`plsqlfunc` for an example.
.. versionchanged:: 8.2
For consistency and compliance with the PEP 8 naming style, the
parameter `keywordParameters` was renamed to `keyword_parameters`. The
old name will continue to work as a keyword parameter for a period of
time.
.. note::
The DB API definition does not define this method.
.. note::
If you intend to call :meth:`Cursor.setinputsizes()` on the cursor
prior to making this call, then note that the first item in the
parameter list refers to the return value of the function.
.. method:: Cursor.callproc(name, parameters=[], keyword_parameters={})
Call a procedure with the given name. The sequence of parameters must
contain one entry for each parameter that the procedure expects. The result
of the call is a modified copy of the input sequence. Input parameters are
left untouched; output and input/output parameters are replaced with
possibly new values. Keyword parameters will be included after the
positional parameters and are not returned as part of the output sequence.
See :ref:`plsqlproc` for an example.
.. versionchanged:: 8.2
For consistency and compliance with the PEP 8 naming style, the
parameter `keywordParameters` was renamed to `keyword_parameters`. The
old name will continue to work as a keyword parameter for a period of
time.
.. note::
The DB API definition does not allow for keyword parameters.
.. method:: Cursor.close()
Close the cursor now, rather than whenever __del__ is called. The cursor
will be unusable from this point forward; an Error exception will be raised
if any operation is attempted with the cursor.
.. attribute:: Cursor.connection
This read-only attribute returns a reference to the connection object on
which the cursor was created.
.. note::
This attribute is an extension to the DB API definition but it is
mentioned in PEP 249 as an optional extension.
.. data:: Cursor.description
This read-only attribute is a sequence of 7-item sequences. Each of these
sequences contains information describing one result column: (name, type,
display_size, internal_size, precision, scale, null_ok). This attribute
will be None for operations that do not return rows or if the cursor has
not had an operation invoked via the :meth:`~Cursor.execute()` method yet.
The type will be one of the :ref:`database type constants <dbtypes>`
defined at the module level.
.. method:: Cursor.execute(statement, parameters=[], ** keyword_parameters)
Execute a statement against the database. See :ref:`sqlexecution`.
Parameters may be passed as a dictionary or sequence or as keyword
parameters. If the parameters are a dictionary, the values will be bound by
name and if the parameters are a sequence the values will be bound by
position. Note that if the values are bound by position, the order of the
variables is from left to right as they are encountered in the statement
and SQL statements are processed differently than PL/SQL statements. For
this reason, it is generally recommended to bind parameters by name instead
of by position.
Parameters passed as a dictionary are name and value pairs. The name maps
to the bind variable name used by the statement and the value maps to the
Python value you wish bound to that bind variable.
A reference to the statement will be retained by the cursor. If None or the
same string object is passed in again, the cursor will execute that
statement again without performing a prepare or rebinding and redefining.
This is most effective for algorithms where the same statement is used, but
different parameters are bound to it (many times). Note that parameters
that are not passed in during subsequent executions will retain the value
passed in during the last execution that contained them.
For maximum efficiency when reusing an statement, it is best to use the
:meth:`~Cursor.setinputsizes()` method to specify the parameter types and
sizes ahead of time; in particular, None is assumed to be a string of
length 1 so any values that are later bound as numbers or dates will raise
a TypeError exception.
If the statement is a query, the cursor is returned as a convenience to the
caller (so it can be used directly as an iterator over the rows in the
cursor); otherwise, ``None`` is returned.
.. note::
The DB API definition does not define the return value of this method.
.. method:: Cursor.executemany(statement, parameters, batcherrors=False, \
arraydmlrowcounts=False)
Prepare a statement for execution against a database and then execute it
against all parameter mappings or sequences found in the sequence
parameters. See :ref:`batchstmnt`.
The statement is managed in the same way as the :meth:`~Cursor.execute()`
method manages it. If the size of the buffers allocated for any of the
parameters exceeds 2 GB, you will receive the error "DPI-1015: array size
of <n> is too large", where <n> varies with the size of each element being
allocated in the buffer. If you receive this error, decrease the number of
elements in the sequence parameters.
If there are no parameters, or parameters have previously been bound, the
number of iterations can be specified as an integer instead of needing to
provide a list of empty mappings or sequences.
When true, the batcherrors parameter enables batch error support within
Oracle and ensures that the call succeeds even if an exception takes place
in one or more of the sequence of parameters. The errors can then be
retrieved using :meth:`~Cursor.getbatcherrors()`.
When true, the arraydmlrowcounts parameter enables DML row counts to be
retrieved from Oracle after the method has completed. The row counts can
then be retrieved using :meth:`~Cursor.getarraydmlrowcounts()`.
Both the batcherrors parameter and the arraydmlrowcounts parameter can only
be true when executing an insert, update, delete or merge statement; in all
other cases an error will be raised.
For maximum efficiency, it is best to use the
:meth:`~Cursor.setinputsizes()` method to specify the parameter types and
sizes ahead of time; in particular, None is assumed to be a string of
length 1 so any values that are later bound as numbers or dates will raise
a TypeError exception.
.. method:: Cursor.executemanyprepared(num_iters)
Execute the previously prepared and bound statement the given number of
times. The variables that are bound must have already been set to their
desired value before this call is made. This method was designed for the
case where optimal performance is required as it comes at the expense of
compatibility with the DB API.
.. note::
The DB API definition does not define this method.
.. deprecated:: 6.4
Use :meth:`~Cursor.executemany()` instead with None for the statement
argument and an integer for the parameters argument.
.. method:: Cursor.fetchall()
Fetch all (remaining) rows of a query result, returning them as a list of
tuples. An empty list is returned if no more rows are available. Note that
the cursor's arraysize attribute can affect the performance of this
operation, as internally reads from the database are done in batches
corresponding to the arraysize.
An exception is raised if the previous call to :meth:`~Cursor.execute()`
did not produce any result set or no call was issued yet.
See :ref:`fetching` for an example.
.. 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
cursor's arraysize attribute can affect the performance of this operation.
The number of rows to fetch is specified by the parameter. If it is not
given, the cursor's arraysize attribute determines the number of rows to be
fetched. If the number of rows available to be fetched is fewer than the
amount requested, fewer rows will be returned.
An exception is raised if the previous call to :meth:`~Cursor.execute()`
did not produce any result set or no call was issued yet.
See :ref:`fetching` for an example.
.. method:: Cursor.fetchone()
Fetch the next row of a query result set, returning a single tuple or None
when no more data is available.
An exception is raised if the previous call to :meth:`~Cursor.execute()`
did not produce any result set or no call was issued yet.
See :ref:`fetching` for an example.
.. method:: Cursor.fetchraw(num_rows=cursor.arraysize)
Fetch the next set of rows of a query result into the internal buffers of
the defined variables for the cursor. The number of rows actually fetched
is returned.
An exception is raised if the previous call to :meth:`~Cursor.execute()`
did not produce any result set or no call was issued yet.
.. deprecated:: 8.2
Use :meth:`Cursor.fetchmany()` instead.
.. note::
The DB API definition does not define this method.
.. attribute:: Cursor.fetchvars
This read-only attribute specifies the list of variables created for the
last query that was executed on the cursor. Care should be taken when
referencing this attribute. In particular, elements should not be removed
or replaced.
.. note::
The DB API definition does not define this attribute.
.. method:: Cursor.getarraydmlrowcounts()
Retrieve the DML row counts after a call to :meth:`~Cursor.executemany()`
with arraydmlrowcounts enabled. This will return a list of integers
corresponding to the number of rows affected by the DML statement for each
element of the array passed to :meth:`~Cursor.executemany()`.
.. note::
The DB API definition does not define this method and it is only
available for Oracle 12.1 and higher.
.. method:: Cursor.getbatcherrors()
Retrieve the exceptions that took place after a call to
:meth:`~Cursor.executemany()` with batcherrors enabled. This will return a
list of Error objects, one error for each iteration that failed. The offset
can be determined by looking at the offset attribute of the error object.
.. note::
The DB API definition does not define this method.
.. method:: Cursor.getimplicitresults()
Return a list of cursors which correspond to implicit results made
available from a PL/SQL block or procedure without the use of OUT ref
cursor parameters. The PL/SQL block or procedure opens the cursors and
marks them for return to the client using the procedure
dbms_sql.return_result. Cursors returned in this fashion should not be
closed. They will be closed automatically by the parent cursor when it is
closed. Closing the parent cursor will invalidate the cursors returned by
this method.
.. versionadded:: 5.3
.. note::
The DB API definition does not define this method and it is only
available for Oracle Database 12.1 (both client and server must be at
this level or higher). It is most like the DB API method nextset(), but
unlike that method (which requires that the next result set overwrite
the current result set), this method returns cursors which can be
fetched independently of each other.
.. attribute:: Cursor.inputtypehandler
This read-write attribute specifies a method called for each value that is
bound to a statement executed on the cursor and overrides the attribute
with the same name on the connection if specified. The method signature is
handler(cursor, value, arraysize) and the return value is expected to be a
variable object or None in which case a default variable object will be
created. If this attribute is None, the value of the attribute with the
same name on the connection is used.
.. note::
This attribute is an extension to the DB API definition.
.. method:: Cursor.__iter__()
Returns the cursor itself to be used as an iterator.
.. note::
This method is an extension to the DB API definition but it is
mentioned in PEP 249 as an optional extension.
.. data:: Cursor.lastrowid
This read-only attribute returns the rowid of the last row modified by the
cursor. If no row was modified by the last operation performed on the
cursor, the value None is returned.
.. versionadded:: 7.3
.. attribute:: Cursor.outputtypehandler
This read-write attribute specifies a method called for each column that is
to be fetched from this cursor. The method signature is
handler(cursor, name, defaultType, length, precision, scale) and the return
value is expected to be a variable object or None in which case a default
variable object will be created. If this attribute is None, the value of
the attribute with the same name on the connection is used instead.
See :ref:`outputtypehandlers`.
.. note::
This attribute is an extension to the DB API definition.
.. method:: Cursor.parse(statement)
This can be used to parse a statement without actually executing it (this
step is done automatically by Oracle when a statement is executed).
.. note::
The DB API definition does not define this method.
.. note::
You can parse any DML or DDL statement. DDL statements are executed
immediately and an implied commit takes place.
.. attribute:: Cursor.prefetchrows
This read-write attribute can be used to tune the number of rows that the
Oracle Client library fetches when a SELECT statement is executed. This
value can reduce the number of round-trips to the database that are required
to fetch rows but at the cost of additional memory. Setting this value to 0
can be useful when the timing of fetches must be explicitly controlled.
See :ref:`Tuning Fetch Performance <tuningfetch>` for more information.
.. note::
The DB API definition does not define this method.
.. method:: Cursor.prepare(statement, [tag])
This can be used before a call to :meth:`~Cursor.execute()` to define the
statement that will be executed. When this is done, the prepare phase will
not be performed when the call to :meth:`~Cursor.execute()` is made with
None or the same string object as the statement. If specified the
statement will be returned to the statement cache with the given tag. See
the Oracle documentation for more information about the statement cache.
See :ref:`Statement Caching <stmtcache>` for more information.
.. note::
The DB API definition does not define this method.
.. attribute:: Cursor.rowcount
This read-only attribute specifies the number of rows that have currently
been fetched from the cursor (for select statements), that have been
affected by the operation (for insert, update, delete and merge
statements), or the number of successful executions of the statement
(for PL/SQL statements).
.. attribute:: Cursor.rowfactory
This read-write attribute specifies a method to call for each row that is
retrieved from the database. Ordinarily a tuple is returned for each row
but if this attribute is set, the method is called with the tuple that
would normally be returned, and the result of the method is returned
instead.
See :ref:`rowfactories`.
.. note::
The DB API definition does not define this attribute.
.. method:: Cursor.scroll(value=0, mode="relative")
Scroll the cursor in the result set to a new position according to the
mode.
If mode is "relative" (the default value), the value is taken as an offset
to the current position in the result set. If set to "absolute", value
states an absolute target position. If set to "first", the cursor is
positioned at the first row and if set to "last", the cursor is set to the
last row in the result set.
An error is raised if the mode is "relative" or "absolute" and the scroll
operation would position the cursor outside of the result set.
.. versionadded:: 5.3
.. note::
This method is an extension to the DB API definition but it is
mentioned in PEP 249 as an optional extension.
.. attribute:: Cursor.scrollable
This read-write boolean attribute specifies whether the cursor can be
scrolled or not. By default, cursors are not scrollable, as the server
resources and response times are greater than nonscrollable cursors. This
attribute is checked and the corresponding mode set in Oracle when calling
the method :meth:`~Cursor.execute()`.
.. versionadded:: 5.3
.. note::
The DB API definition does not define this attribute.
.. method:: Cursor.setinputsizes(\*args, \*\*keywordArgs)
This can be used before a call to :meth:`~Cursor.execute()`,
:meth:`~Cursor.callfunc()` or :meth:`~Cursor.callproc()` to predefine
memory areas for the operation's parameters. Each parameter should be a
type object corresponding to the input that will be used or it should be an
integer specifying the maximum length of a string parameter. Use keyword
parameters when binding by name and positional parameters when binding by
position. The singleton None can be used as a parameter when using
positional parameters to indicate that no space should be reserved for that
position.
.. note::
If you plan to use :meth:`~Cursor.callfunc()` then be aware that the
first parameter in the list refers to the return value of the function.
.. method:: Cursor.setoutputsize(size, [column])
This method does nothing and is retained solely for compatibility with the
DB API. The module automatically allocates as much space as needed to fetch
LONG and LONG RAW columns (or CLOB as string and BLOB as bytes).
.. attribute:: Cursor.statement
This read-only attribute provides the string object that was previously
prepared with :meth:`~Cursor.prepare()` or executed with
:meth:`~Cursor.execute()`.
.. note::
The DB API definition does not define this attribute.
.. method:: Cursor.var(typ, [size, arraysize, inconverter, outconverter, \
typename, encoding_errors, bypass_decode])
Create a variable with the specified characteristics. This method was
designed for use with PL/SQL in/out variables where the length or type
cannot be determined automatically from the Python object passed in or for
use in input and output type handlers defined on cursors or connections.
The typ parameter specifies the type of data that should be stored in the
variable. This should be one of the :ref:`database type constants
<dbtypes>`, :ref:`DB API constants <types>`, an object type returned from
the method :meth:`Connection.gettype()` or one of the following Python
types:
.. list-table::
:header-rows: 1
* - Python Type
- Database Type
* - bool
- :attr:`cx_Oracle.DB_TYPE_BOOLEAN`
* - bytes
- :attr:`cx_Oracle.DB_TYPE_RAW`
* - datetime.date
- :attr:`cx_Oracle.DB_TYPE_DATE`
* - datetime.datetime
- :attr:`cx_Oracle.DB_TYPE_DATE`
* - datetime.timedelta
- :attr:`cx_Oracle.DB_TYPE_INTERVAL_DS`
* - decimal.Decimal
- :attr:`cx_Oracle.DB_TYPE_NUMBER`
* - float
- :attr:`cx_Oracle.DB_TYPE_NUMBER`
* - int
- :attr:`cx_Oracle.DB_TYPE_NUMBER`
* - str
- :attr:`cx_Oracle.DB_TYPE_VARCHAR`
The size parameter specifies the length of string and raw variables and is
ignored in all other cases. If not specified for string and raw variables,
the value 4000 is used.
The arraysize parameter specifies the number of elements the variable will
have. If not specified the bind array size (usually 1) is used. When a
variable is created in an output type handler this parameter should be set
to the cursor's array size.
The inconverter and outconverter parameters specify methods used for
converting values to/from the database. More information can be found in
the section on :ref:`variable objects<varobj>`.
The typename parameter specifies the name of a SQL object type and must be
specified when using type :data:`cx_Oracle.OBJECT` unless the type object
was passed directly as the first parameter.
The encoding_errors parameter specifies what should happen when decoding
byte strings fetched from the database into strings. It should be one of
the values noted in the builtin
`decode <https://docs.python.org/3/library/stdtypes.html#bytes.decode>`__
function.
The bypass_decode parameter, if specified, should be passed as a
boolean value. Passing a `True` value causes values of database types
:data:`~cx_Oracle.DB_TYPE_VARCHAR`, :data:`~cx_Oracle.DB_TYPE_CHAR`,
:data:`~cx_Oracle.DB_TYPE_NVARCHAR`, :data:`~cx_Oracle.DB_TYPE_NCHAR` and
:data:`~cx_Oracle.DB_TYPE_LONG` to be returned as `bytes` instead of `str`,
meaning that cx_Oracle doesn't do any decoding. See :ref:`Fetching raw
data <fetching-raw-data>` for more information.
.. versionadded:: 8.2
The parameter `bypass_decode` was added.
.. versionchanged:: 8.2
For consistency and compliance with the PEP 8 naming style, the
parameter `encodingErrors` was renamed to `encoding_errors`. The old
name will continue to work as a keyword parameter for a period of time.
.. note::
The DB API definition does not define this method.

View File

@ -1,184 +0,0 @@
.. _deprecations:
************
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.
.. list-table:: Deprecated in 8.2
:header-rows: 1
:widths: 25 75
:width: 100%
:name: _deprecations_8_2
* - Name
- Comments
* - `encoding` parameter to :meth:`cx_Oracle.connect()`
- No longer needed as the use of encodings other than UTF-8 is
deprecated. Encoding is handled internally between cx_Oracle and Oracle
Database.
* - `nencoding` parameter to :meth:`cx_Oracle.connect()`
- No longer needed as the use of encodings other than UTF-8 is
deprecated.
* - `encoding` parameter to :meth:`cx_Oracle.SessionPool()`
- No longer needed as the use of encodings other than UTF-8 is
deprecated.
* - `nencoding` parameter to :meth:`cx_Oracle.SessionPool()`
- No longer needed as the use of encodings other than UTF-8 is
deprecated.
* - Connection.maxBytesPerCharacter
- No longer needed as the use of encodings other than UTF-8 is
deprecated. The constant value 4 can be used instead.
* - Positional parameters to :meth:`cx_Oracle.connect()`
- Replace with keyword parameters in order to comply with the Python
database API.
* - Positional parameters to :meth:`cx_Oracle.SessionPool()`
- Replace with keyword parameters in order to comply with the Python
database API.
* - `threaded` parameter to :meth:`cx_Oracle.SessionPool()`
- The value of this parameter is ignored. Threading is now always used.
* - `waitTimeout` parameter to :meth:`cx_Oracle.SessionPool()`
- Replace with parameter name `wait_timeout`
* - `maxLifetimeSession` parameter to :meth:`cx_Oracle.SessionPool()`
- Replace with parameter name `max_lifetime_session`
* - `sessionCallback` parameter to :meth:`cx_Oracle.SessionPool()`
- Replace with parameter name `session_callback`
* - `maxSessionsPerShard` parameter to :meth:`cx_Oracle.SessionPool()`
- Replace with parameter name `max_sessions_per_shard`
* - `SessionPool.tnsentry`
- Replace with :data:`SessionPool.dsn`
* - `payloadType` parameter to :meth:`Connection.queue()`
- Replace with parameter name `payload_type` if using keyword parameters.
* - `ipAddress` parameter to :meth:`Connection.subscribe()`
- Replace with parameter name `ip_address`
* - `groupingClass` parameter to :meth:`Connection.subscribe()`
- Replace with parameter name `grouping_class`
* - `groupingValue` parameter to :meth:`Connection.subscribe()`
- Replace with parameter name `grouping_value`
* - `groupingType` parameter to :meth:`Connection.subscribe()`
- Replace with parameter name `grouping_type`
* - `clientInitiated` parameter to :meth:`Connection.subscribe()`
- Replace with parameter name `client_initiated`
* - `Connection.callTimeout`
- Replace with :data:`Connection.call_timeout`
* - `Connection.tnsentry`
- Replace with :data:`Connection.dsn`
* - `keywordParameters` parameter to :meth:`Cursor.callfunc()`
- Replace with parameter name `keyword_parameters`
* - `keywordParameters` parameter to :meth:`Cursor.callproc()`
- Replace with parameter name `keyword_parameters`
* - `encodingErrors` parameter to :meth:`Cursor.var()`
- Replace with parameter name `encoding_errors`
* - `Cursor.fetchraw()`
- Replace with :meth:`Cursor.fetchmany()`
* - `newSize` parameter to :meth:`LOB.trim()`
- Replace with parameter name `new_size`
* - `Queue.deqMany`
- Replace with :meth:`Queue.deqmany()`
* - `Queue.deqOne`
- Replace with :meth:`Queue.deqone()`
* - `Queue.enqMany`
- Replace with :meth:`Queue.enqmany()`
* - `Queue.enqOne`
- Replace with :meth:`Queue.enqone()`
* - `Queue.deqOptions`
- Replace with :data:`Queue.deqoptions`
* - `Queue.enqOptions`
- Replace with :meth:`Queue.enqoptions`
* - `Queue.payloadType`
- Replace with :meth:`Queue.payload_type`
* - `Subscription.ipAddress`
- Replace with :attr:`Subscription.ip_address`
* - `Message.consumerName`
- Replace with :attr:`Message.consumer_name`
* - `Message.queueName`
- Replace with :attr:`Message.queue_name`
* - `Variable.actualElements`
- Replace with :attr:`Variable.actual_elements`
* - `Variable.bufferSize`
- Replace with :attr:`Variable.buffer_size`
* - `Variable.numElements`
- Replace with :attr:`Variable.num_elements`
.. list-table:: Deprecated in 8.0
:header-rows: 1
:widths: 25 75
:width: 100%
:name: _deprecations_8_0
* - Name
- Comments
* - cx_Oracle.BFILE
- Replace with :data:`cx_Oracle.DB_TYPE_BFILE`
* - cx_Oracle.BLOB
- Replace with :data:`cx_Oracle.DB_TYPE_BLOB`
* - cx_Oracle.BOOLEAN
- Replace with :data:`cx_Oracle.DB_TYPE_BOOLEAN`
* - cx_Oracle.CLOB
- Replace with :data:`cx_Oracle.DB_TYPE_CLOB`
* - cx_Oracle.CURSOR
- Replace with :data:`cx_Oracle.DB_TYPE_CURSOR`
* - cx_Oracle.FIXED_CHAR
- Replace with :data:`cx_Oracle.DB_TYPE_CHAR`
* - cx_Oracle.FIXED_NCHAR
- Replace with :data:`cx_Oracle.DB_TYPE_NCHAR`
* - cx_Oracle.INTERVAL
- Replace with :data:`cx_Oracle.DB_TYPE_INTERVAL_DS`
* - cx_Oracle.LONG_BINARY
- Replace with :data:`cx_Oracle.DB_TYPE_LONG_RAW`
* - cx_Oracle.LONG_STRING
- Replace with :data:`cx_Oracle.DB_TYPE_LONG`
* - cx_Oracle.NATIVE_FLOAT
- Replace with :data:`cx_Oracle.DB_TYPE_BINARY_DOUBLE`
* - cx_Oracle.NATIVE_INT
- Replace with :data:`cx_Oracle.DB_TYPE_BINARY_INTEGER`
* - cx_Oracle.NCHAR
- Replace with :data:`cx_Oracle.DB_TYPE_NVARCHAR`
* - cx_Oracle.NCLOB
- Replace with :data:`cx_Oracle.DB_TYPE_NCLOB`
* - cx_Oracle.OBJECT
- Replace with :data:`cx_Oracle.DB_TYPE_OBJECT`
* - cx_Oracle.TIMESTAMP
- Replace with :data:`cx_Oracle.DB_TYPE_TIMESTAMP`
.. list-table:: Deprecated in 7.2
:header-rows: 1
:widths: 25 75
:width: 100%
:name: _deprecations_7_2
* - Name
- Comments
* - Connection.deq()
- Replace with :meth:`Queue.deqone()` or :meth:`Queue.deqmany()`.
* - Connection.deqoptions()
- Replace with attribute :attr:`Queue.deqoptions`.
* - Connection.enq()
- Replace with :meth:`Queue.enqone()` or :meth:`Queue.enqmany()`.
* - Connection.enqoptions()
- Replace with attribute :attr:`Queue.enqoptions`.
.. list-table:: Deprecated in 6.4
:header-rows: 1
:widths: 25 75
:width: 100%
:name: _deprecations_6_4
* - Name
- Comments
* - Cursor.executemanyprepared()
- Replace with :meth:`~Cursor.executemany()` with None for the statement
argument and an integer for the parameters argument.

View File

@ -1,105 +0,0 @@
.. _lobobj:
***********
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::
This object is an extension the DB API. It is returned whenever Oracle
:data:`CLOB`, :data:`BLOB` and :data:`BFILE` columns are fetched.
.. method:: LOB.close()
Close the LOB. Call this when writing is completed so that the indexes
associated with the LOB can be updated -- but only if :meth:`~LOB.open()`
was called first.
.. method:: LOB.fileexists()
Return a boolean indicating if the file referenced by the BFILE type LOB
exists.
.. method:: LOB.getchunksize()
Return the chunk size for the internal LOB. Reading and writing to the LOB
in chunks of multiples of this size will improve performance.
.. method:: LOB.getfilename()
Return a two-tuple consisting of the directory alias and file name for a
BFILE type LOB.
.. method:: LOB.isopen()
Return a boolean indicating if the LOB has been opened using the method
:meth:`~LOB.open()`.
.. method:: LOB.open()
Open the LOB for writing. This will improve performance when writing to a
LOB in chunks and there are functional or extensible indexes associated
with the LOB. If this method is not called, each write will perform an open
internally followed by a close after the write has been completed.
.. method:: LOB.read([offset=1, [amount]])
Return a portion (or all) of the data in the LOB object. Note that the
amount and offset are in bytes for BLOB and BFILE type LOBs and in UCS-2
code points for CLOB and NCLOB type LOBs. UCS-2 code points are equivalent
to characters for all but supplemental characters. If supplemental
characters are in the LOB, the offset and amount will have to be chosen
carefully to avoid splitting a character.
.. method:: LOB.setfilename(dirAlias, name)
Set the directory alias and name of the BFILE type LOB.
.. method:: LOB.size()
Returns the size of the data in the LOB object. For BLOB and BFILE type
LOBs this is the number of bytes. For CLOB and NCLOB type LOBs this is the
number of UCS-2 code points. UCS-2 code points are equivalent to characters
for all but supplemental characters.
.. method:: LOB.trim(new_size=0)
Trim the LOB to the new size.
.. attribute:: LOB.type
This read-only attribute returns the type of the LOB as one of the
:ref:`database type constants <dbtypes>`.
.. versionadded:: 8.0
.. method:: LOB.write(data, offset=1)
Write the data to the LOB object at the given offset. The offset is in
bytes for BLOB type LOBs and in UCS-2 code points for CLOB and NCLOB type
LOBs. UCS-2 code points are equivalent to characters for all but
supplemental characters. If supplemental characters are in the LOB, the
offset will have to be chosen carefully to avoid splitting a character.
Note that if you want to make the LOB value smaller, you must use the
:meth:`~LOB.trim()` function.

File diff suppressed because it is too large Load Diff

View File

@ -1,197 +0,0 @@
.. _objecttype:
*******************
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
:meth:`Connection.gettype()` call and is available as the
:data:`Variable.type` for variables containing Oracle objects.
.. method:: ObjectType([sequence])
The object type may be called directly and serves as an alternative way of
calling :meth:`~ObjectType.newobject()`.
.. attribute:: ObjectType.attributes
This read-only attribute returns a list of the :ref:`attributes
<objectattr>` that make up the object type.
.. attribute:: ObjectType.iscollection
This read-only attribute returns a boolean indicating if the object type
refers to a collection or not.
.. attribute:: ObjectType.name
This read-only attribute returns the name of the type.
.. attribute:: ObjectType.element_type
This read-only attribute returns the type of elements found in collections
of this type, if :attr:`~ObjectType.iscollection` is ``True``; otherwise,
it returns ``None``. If the collection contains objects, this will be
another object type; otherwise, it will be one of the
:ref:`database type constants <dbtypes>`.
.. versionadded:: 8.0
.. method:: ObjectType.newobject([sequence])
Return a new Oracle object of the given type. This object can then be
modified by setting its attributes and then bound to a cursor for
interaction with Oracle. If the object type refers to a collection, a
sequence may be passed and the collection will be initialized with the
items in that sequence.
.. attribute:: ObjectType.schema
This read-only attribute returns the name of the schema that owns the type.
Object Objects
--------------
.. note::
This object is an extension to the DB API. It is returned by the
:meth:`ObjectType.newobject()` call and can be bound to variables of
type :data:`~cx_Oracle.OBJECT`. Attributes can be retrieved and set
directly.
.. method:: Object.append(element)
Append an element to the collection object. If no elements exist in the
collection, this creates an element at index 0; otherwise, it creates an
element immediately following the highest index available in the
collection.
.. method:: Object.asdict()
Return a dictionary where the collection's indexes are the keys and the
elements are its values.
.. versionadded:: 7.0
.. method:: Object.aslist()
Return a list of each of the collection's elements in index order.
.. method:: Object.copy()
Create a copy of the object and return it.
.. method:: Object.delete(index)
Delete the element at the specified index of the collection. If the
element does not exist or is otherwise invalid, an error is raised. Note
that the indices of the remaining elements in the collection are not
changed. In other words, the delete operation creates holes in the
collection.
.. method:: Object.exists(index)
Return True or False indicating if an element exists in the collection at
the specified index.
.. method:: Object.extend(sequence)
Append all of the elements in the sequence to the collection. This is
the equivalent of performing :meth:`~Object.append()` for each element
found in the sequence.
.. method:: Object.first()
Return the index of the first element in the collection. If the collection
is empty, None is returned.
.. method:: Object.getelement(index)
Return the element at the specified index of the collection. If no element
exists at that index, an exception is raised.
.. method:: Object.last()
Return the index of the last element in the collection. If the collection
is empty, None is returned.
.. method:: Object.next(index)
Return the index of the next element in the collection following the
specified index. If there are no elements in the collection following the
specified index, None is returned.
.. method:: Object.prev(index)
Return the index of the element in the collection preceding the specified
index. If there are no elements in the collection preceding the
specified index, None is returned.
.. method:: Object.setelement(index, value)
Set the value in the collection at the specified index to the given value.
.. method:: Object.size()
Return the number of elements in the collection.
.. method:: Object.trim(num)
Remove the specified number of elements from the end of the collection.
.. _objectattr:
Object Attribute Objects
------------------------
.. note::
This object is an extension to the DB API. The elements of
:attr:`ObjectType.attributes` are instances of this type.
.. attribute:: ObjectAttribute.name
This read-only attribute returns the name of the attribute.
.. attribute:: ObjectAttribute.type
This read-only attribute returns the type of the attribute. This will be an
:ref:`Oracle Object Type <objecttype>` if the variable binds
Oracle objects; otherwise, it will be one of the
:ref:`database type constants <dbtypes>`.
.. versionadded:: 8.0

View File

@ -1,309 +0,0 @@
.. _sesspool:
******************
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.
Connection pooling in cx_Oracle is handled by SessionPool objects.
See :ref:`connpool` for information on connection pooling.
.. method:: SessionPool.acquire(user=None, password=None, cclass=None, \
purity=cx_Oracle.ATTR_PURITY_DEFAULT, tag=None, matchanytag=False, \
shardingkey=[], supershardingkey=[])
Acquire a connection from the session pool and return a
:ref:`connection object <connobj>`.
If the pool is homogeneous, the user and password parameters cannot be
specified. If they are, an exception will be raised.
The cclass parameter, if specified, should be a string corresponding to the
connection class for database resident connection pooling (DRCP).
The purity parameter is expected to be one of
:data:`~cx_Oracle.ATTR_PURITY_NEW`, :data:`~cx_Oracle.ATTR_PURITY_SELF`, or
:data:`~cx_Oracle.ATTR_PURITY_DEFAULT`.
The tag parameter, if specified, is expected to be a string with name=value
pairs like "k1=v1;k2=v2" and will limit the sessions that can be returned
from a session pool unless the matchanytag parameter is set to True. In
that case sessions with the specified tag will be preferred over others,
but if no such sessions are available a session with a different tag may be
returned instead. In any case, untagged sessions will always be returned if
no sessions with the specified tag are available. Sessions are tagged when
they are :meth:`released <SessionPool.release>` back to the pool.
The shardingkey and supershardingkey parameters, if specified, are expected
to be a sequence of values which will be used to identify the database
shard to connect to. The key values can be strings, numbers, bytes or
dates.
.. attribute:: SessionPool.busy
This read-only attribute returns the number of sessions currently acquired.
.. method:: SessionPool.close(force=False)
Close the session pool now, rather than when the last reference to it is
released, which makes it unusable for further work.
If any connections have been acquired and not released back to the pool
this method will fail unless the force parameter is set to True.
.. method:: SessionPool.drop(connection)
Drop the connection from the pool which is useful if the connection is no
longer usable (such as when the session is killed).
.. attribute:: SessionPool.dsn
This read-only attribute returns the TNS entry of the database to which a
connection has been established.
.. attribute:: SessionPool.getmode
This read-write attribute determines how connections are returned from the
pool. If :data:`~cx_Oracle.SPOOL_ATTRVAL_FORCEGET` is specified, a new
connection will be returned even if there are no free sessions in the pool.
:data:`~cx_Oracle.SPOOL_ATTRVAL_NOWAIT` will raise an exception if there
are no free sessions are available in the pool. If
:data:`~cx_Oracle.SPOOL_ATTRVAL_WAIT` is specified and there are no free
sessions in the pool, the caller will wait until a free session is
available. :data:`~cx_Oracle.SPOOL_ATTRVAL_TIMEDWAIT` uses the value of
:data:`~SessionPool.wait_timeout` to determine how long the caller should
wait for a session to become available before returning an error.
.. attribute:: SessionPool.homogeneous
This read-write boolean attribute indicates whether the pool is considered
homogeneous or not. If the pool is not homogeneous different authentication
can be used for each connection acquired from the pool.
.. attribute:: SessionPool.increment
This read-only attribute returns the number of sessions that will be
established when additional sessions need to be created.
.. attribute:: SessionPool.max
This read-only attribute returns the maximum number of sessions that the
session pool can control.
.. attribute:: SessionPool.max_lifetime_session
This read-write attribute returns the maximum length of time (in seconds)
that a pooled session may exist. Sessions that are in use will not be
closed. They become candidates for termination only when they are released
back to the pool and have existed for longer than max_lifetime_session
seconds. Note that termination only occurs when the pool is accessed. A
value of 0 means that there is no maximum length of time that a pooled
session may exist. This attribute is only available in Oracle Database
12.1.
.. versionadded:: 5.3
.. attribute:: SessionPool.max_sessions_per_shard
This read-write attribute returns the number of sessions that can be created
per shard in the pool. Setting this attribute greater than zero specifies
the maximum number of sessions in the pool that can be used for any given
shard in a sharded database. This lets connections in the pool be balanced
across the shards. A value of zero will not set any maximum number of
sessions for each shard. This attribute is only available in Oracle Client
18.3 and higher.
.. versionadded:: 8.2
.. attribute:: SessionPool.min
This read-only attribute returns the number of sessions with which the
session pool was created and the minimum number of sessions that will be
controlled by the session pool.
.. attribute:: SessionPool.name
This read-only attribute returns the name assigned to the session pool by
Oracle.
.. attribute:: SessionPool.opened
This read-only attribute returns the number of sessions currently opened by
the session pool.
.. attribute:: SessionPool.ping_interval
This read-write integer attribute specifies the pool ping interval in
seconds. When a connection is acquired from the pool, a check is first made
to see how long it has been since the connection was put into the pool. If
this idle time exceeds ``ping_interval``, then a :ref:`round-trip
<roundtrips>` ping to the database is performed. If the connection is
unusable, it is discarded and a different connection is selected to be
returned by :meth:`SessionPool.acquire()`. Setting ``ping_interval`` to a
negative value disables pinging. Setting it to 0 forces a ping for every
``acquire()`` and is not recommended.
Prior to cx_Oracle 8.2, the ping interval was fixed at 60 seconds.
.. versionadded:: 8.2
.. method:: SessionPool.reconfigure([min, max, increment, getmode, timeout, \
wait_timeout, max_lifetime_session, max_sessions_per_shard, \
soda_metadata_cache, stmtcachesize, ping_interval])
Reconfigures various parameters of a connection pool. The pool size can be
altered with ``reconfigure()`` by passing values for
:data:`~SessionPool.min`, :data:`~SessionPool.max` or
:data:`~SessionPool.increment`. The :data:`~SessionPool.getmode`,
:data:`~SessionPool.timeout`, :data:`~SessionPool.wait_timeout`,
:data:`~SessionPool.max_lifetime_session`,
:data:`~SessionPool.max_sessions_per_shard`,
:data:`~SessionPool.soda_metadata_cache`, :data:`~SessionPool.stmtcachesize`
and :data:`~SessionPool.ping_interval` attributes can be set directly or
with ``reconfigure()``.
All parameters are optional. Unspecified parameters will leave those pool
attributes unchanged. The parameters are processed in two stages. After any
size change has been processed, reconfiguration on the other parameters is
done sequentially. If an error such as an invalid value occurs when changing
one attribute, then an exception will be generated but any already changed
attributes will retain their new values.
During reconfiguration of a pool's size, the behavior of
:meth:`SessionPool.acquire()` depends on the ``getmode`` in effect when
``acquire()`` is called:
* With mode :data:`~cx_Oracle.SPOOL_ATTRVAL_FORCEGET`, an ``acquire()`` call
will wait until the pool has been reconfigured.
* With mode :data:`~cx_Oracle.SPOOL_ATTRVAL_TIMEDWAIT`, an ``acquire()`` call
will try to acquire a connection in the time specified by
:data:`~SessionPool.wait_timeout` and return an error if the time taken
exceeds that value.
* With mode :data:`~cx_Oracle.SPOOL_ATTRVAL_WAIT`, an ``acquire()`` call
will wait until after the pool has been reconfigured and a connection is
available.
* With mode :data:`~cx_Oracle.SPOOL_ATTRVAL_NOWAIT`, if the number of busy
connections is less than the pool size, ``acquire()`` will return a new
connection after pool reconfiguration is complete.
Closing connections with :meth:`SessionPool.release()` or
:meth:`Connection.close()` will wait until any pool size reconfiguration is
complete.
Closing the connection pool with :meth:`SessionPool.close()` will wait until
reconfiguration is complete.
See :ref:`Connection Pool Reconfiguration <poolreconfiguration>`.
.. versionadded:: 8.2
.. method:: SessionPool.release(connection, tag=None)
Release the connection back to the pool now, rather than whenever __del__
is called. The connection will be unusable from this point forward; an
Error exception will be raised if any operation is attempted with the
connection. Any cursors or LOBs created by the connection will also be
marked unusable and an Error exception will be raised if any operation is
attempted with them.
Internally, references to the connection are held by cursor objects,
LOB objects, etc. Once all of these references are released, the connection
itself will be released back to the pool automatically. Either control
references to these related objects carefully or explicitly release
connections back to the pool in order to ensure sufficient resources are
available.
If the tag is not None, it is expected to be a string with name=value pairs
like "k1=v1;k2=v2" and will override the value in the property
:attr:`Connection.tag`. If either :attr:`Connection.tag` or the tag
parameter are not None, the connection will be retagged when it is released
back to the pool.
.. attribute:: SessionPool.soda_metadata_cache
This read-write boolean attribute returns whether the SODA metadata cache
is enabled or not. Enabling the cache significantly improves the
performance of methods :meth:`SodaDatabase.createCollection()` (when not
specifying a value for the metadata parameter) and
:meth:`SodaDatabase.openCollection()`. Note that the cache can become out
of date if changes to the metadata of cached collections are made
externally.
.. versionadded:: 8.2
.. attribute:: SessionPool.stmtcachesize
This read-write attribute specifies the size of the statement cache that
will be used for connections obtained from the pool.
See :ref:`Statement Caching <stmtcache>` for more information.
.. versionadded:: 6.0
.. attribute:: SessionPool.timeout
This read-write attribute specifies the time (in seconds) after which idle
sessions will be terminated in order to maintain an optimum number of open
sessions. Note that termination only occurs when the pool is accessed. A
value of 0 means that no idle sessions are terminated.
.. attribute:: SessionPool.tnsentry
This read-only attribute returns the TNS entry of the database to which a
connection has been established.
.. deprecated:: 8.2
Use the attribute :attr:`~SessionPool.dsn` instead.
.. attribute:: SessionPool.username
This read-only attribute returns the name of the user which established the
connection to the database.
.. attribute:: SessionPool.wait_timeout
This read-write attribute specifies the time (in milliseconds) that the
caller should wait for a session to become available in the pool before
returning with an error. This value is only used if the getmode parameter
to :meth:`cx_Oracle.SessionPool()` was the value
:data:`cx_Oracle.SPOOL_ATTRVAL_TIMEDWAIT`.
.. versionadded:: 6.4

View File

@ -1,706 +0,0 @@
.. _soda:
****
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
using a set of NoSQL-style cx_Oracle methods. By default, documents are JSON
strings. See the :ref:`user manual <sodausermanual>` for examples.
.. _sodarequirements:
-----------------
SODA Requirements
-----------------
To use SODA, the role SODA_APP must be granted to the user. To create
collections, users need the CREATE TABLE privilege. These can be granted by a
DBA:
.. code-block:: sql
SQL> grant soda_app, create table to myuser;
Advanced users who are using Oracle sequences for keys will also need the CREATE
SEQUENCE privilege.
SODA requires Oracle Client 18.3 or higher and Oracle Database 18.1 and higher.
.. note::
If you are using Oracle Database 21c (or later) and create new collections
you need to do one of the following:
- Use Oracle Client libraries 21c (or later).
- Or, explicitly use collection metadata when creating collections and set
the data storage type to BLOB, for example::
{
"keyColumn": {
"name":"ID"
},
"contentColumn": {
"name": "JSON_DOCUMENT",
"sqlType": "BLOB"
},
"versionColumn": {
"name": "VERSION",
"method": "UUID"
},
"lastModifiedColumn": {
"name": "LAST_MODIFIED"
},
"creationTimeColumn": {
"name": "CREATED_ON"
}
}
- Or, set the database initialization parameter `compatible
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&
id=GUID-A2E90F08-BC9F-4688-A9D0-4A948DD3F7A9>`__ to 19 or lower.
Otherwise you may get errors such as "ORA-40842: unsupported value JSON in
the metadata for the field sqlType" or "ORA-40659: Data type does not match
the specification in the collection metadata".
.. _sodadb:
--------------------
SODA Database Object
--------------------
.. note::
This object is an extension the DB API. It is returned by the method
:meth:`Connection.getSodaDatabase()`.
.. method:: SodaDatabase.createCollection(name, metadata=None, mapMode=False)
Creates a SODA collection with the given name and returns a new
:ref:`SODA collection object <sodacoll>`. If you try to create a
collection, and a collection with the same name and metadata already
exists, then that existing collection is opened without error.
If metadata is specified, it is expected to be a string containing valid
JSON or a dictionary that will be transformed into a JSON string. This JSON
permits you to specify the configuration of the collection including
storage options; specifying the presence or absence of columns for creation
timestamp, last modified timestamp and version; whether the collection can
store only JSON documents; and methods of key and version generation. The
default metadata creates a collection that only supports JSON documents and
uses system generated keys. See this `collection metadata reference
<https://www.oracle.com/pls/topic/
lookup?ctx=dblatest&id=GUID-49EFF3D3-9FAB-4DA6-BDE2-2650383566A3>`__
for more information.
If the mapMode parameter is set to True, the new collection is mapped to an
existing table instead of creating a table. If a collection is created in
this way, dropping the collection will not drop the existing table either.
.. versionadded:: 7.0
.. method:: SodaDatabase.createDocument(content, key=None, mediaType="application/json")
Creates a :ref:`SODA document <sodadoc>` usable for SODA write operations.
You only need to use this method if your collection requires
client-assigned keys or has non-JSON content; otherwise, you can pass your
content directly to SODA write operations. SodaDocument attributes
'createdOn', 'lastModified' and 'version' will be None.
The content parameter can be a dictionary or list which will be transformed
into a JSON string and then UTF-8 encoded. It can also be a string which
will be UTF-8 encoded or it can be a bytes object which will be stored
unchanged. If a bytes object is provided and the content is expected to be
JSON, note that SODA only supports UTF-8, UTF-16LE and UTF-16BE encodings.
The key parameter should only be supplied if the collection in which the
document is to be placed requires client-assigned keys.
The mediaType parameter should only be supplied if the collection in which
the document is to be placed supports non-JSON documents and the content
for this document is non-JSON. Using a standard MIME type for this value is
recommended but any string will be accepted.
.. versionadded:: 7.0
.. method:: SodaDatabase.getCollectionNames(startName=None, limit=0)
Returns a list of the names of collections in the database that match the
criteria, in alphabetical order.
If the startName parameter is specified, the list of names returned will
start with this value and also contain any names that fall after this value
in alphabetical order.
If the limit parameter is specified and is non-zero, the number of
collection names returned will be limited to this value.
.. versionadded:: 7.0
.. method:: SodaDatabase.openCollection(name)
Opens an existing collection with the given name and returns a new
:ref:`SODA collection object <sodacoll>`. If a collection with that name
does not exist, None is returned.
.. versionadded:: 7.0
.. _sodacoll:
----------------------
SODA Collection Object
----------------------
.. note::
This object is an extension the DB API. It is used to represent SODA
collections and is created by methods
:meth:`SodaDatabase.createCollection()` and
:meth:`SodaDatabase.openCollection()`.
.. method:: SodaCollection.createIndex(spec)
Creates an index on a SODA collection. The spec is expected to be a
dictionary or a JSON-encoded string. See this `overview
<https://www.oracle.com/pls/topic/
lookup?ctx=dblatest&id=GUID-4848E6A0-58A7-44FD-8D6D-A033D0CCF9CB>`__
for information on indexes in SODA.
Note that a commit should be performed before attempting to create an
index.
.. versionadded:: 7.0
.. method:: SodaCollection.drop()
Drops the collection from the database, if it exists. Note that if the
collection was created with mapMode set to True the underlying table will
not be dropped.
A boolean value is returned indicating if the collection was actually
dropped.
.. versionadded:: 7.0
.. method:: SodaCollection.dropIndex(name, force=False)
Drops the index with the specified name, if it exists.
The force parameter, if set to True, can be used to force the dropping of
an index that the underlying Oracle Database domain index doesn't normally
permit. This is only applicable to spatial and JSON search indexes.
See `here <https://www.oracle.com/pls/topic/
lookup?ctx=dblatest&id=GUID-F60F75DF-2866-4F93-BB7F-8FCE64BF67B6>`__
for more information.
A boolean value is returned indicating if the index was actually dropped.
.. versionadded:: 7.0
.. method:: SodaCollection.find()
This method is used to begin an operation that will act upon documents in
the collection. It creates and returns a
:ref:`SodaOperation object <sodaop>` which is used to specify the criteria
and the operation that will be performed on the documents that match that
criteria.
.. versionadded:: 7.0
.. method:: SodaCollection.getDataGuide()
Returns a :ref:`SODA document object <sodadoc>` containing property names,
data types and lengths inferred from the JSON documents in the collection.
It can be useful for exploring the schema of a collection. Note that this
method is only supported for JSON-only collections where a JSON search
index has been created with the 'dataguide' option enabled. If there are
no documents in the collection, None is returned.
.. versionadded:: 7.0
.. method:: SodaCollection.insertMany(docs)
Inserts a list of documents into the collection at one time. Each of the
input documents can be a dictionary or list or an existing :ref:`SODA
document object <sodadoc>`.
.. note::
This method requires Oracle Client 18.5 and higher and is available
only as a preview.
.. versionadded:: 7.2
.. method:: SodaCollection.insertManyAndGet(docs, hint=None)
Similarly to :meth:`~SodaCollection.insertMany()` this method inserts a
list of documents into the collection at one time. The only difference is
that it returns a list of :ref:`SODA Document objects <sodadoc>`. Note that
for performance reasons the returned documents do not contain the content.
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 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::
This method requires Oracle Client 18.5 and higher.
.. versionadded:: 7.2
.. versionchanged:: 8.2
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)
Inserts a given document into the collection. The input document can be a
dictionary or list or an existing :ref:`SODA document object <sodadoc>`.
.. versionadded:: 7.0
.. method:: SodaCollection.insertOneAndGet(doc, hint=None)
Similarly to :meth:`~SodaCollection.insertOne()` this method inserts a
given document into the collection. The only difference is that it
returns a :ref:`SODA Document object <sodadoc>`. Note that for performance
reasons the returned document does not contain the content.
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 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. Use of the hint parameter requires
Oracle Client 21.3 or higher (or Oracle Client 19 from 19.11).
.. attribute:: SodaCollection.metadata
This read-only attribute returns a dictionary containing the metadata that
was used to create the collection. See this `collection metadata reference
<https://www.oracle.com/pls/topic/
lookup?ctx=dblatest&id=GUID-49EFF3D3-9FAB-4DA6-BDE2-2650383566A3>`__
for more information.
.. versionadded:: 7.0
.. attribute:: SodaCollection.name
This read-only attribute returns the name of the collection.
.. versionadded:: 7.0
.. method:: SodaCollection.save(doc)
Saves a document into the collection. This method is equivalent to
:meth:`~SodaCollection.insertOne()` except that if client-assigned keys are
used, and the document with the specified key already exists in the
collection, it will be replaced with the input document.
This method requires Oracle Client 19.9 or higher in addition to the usual
SODA requirements.
.. versionadded:: 8.0
.. method:: SodaCollection.saveAndGet(doc, hint=None)
Saves a document into the collection. This method is equivalent to
:meth:`~SodaCollection.insertOneAndGet()` except that if client-assigned
keys are used, and the document with the specified key already exists in
the collection, it will be replaced with the input document.
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 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.
.. versionadded:: 8.0
.. versionchanged:: 8.2
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()
Removes all of the documents in the collection, similarly to what is done
for rows in a table by the TRUNCATE TABLE statement.
.. versionadded:: 8.0
.. _sodadoc:
--------------------
SODA Document Object
--------------------
.. note::
This object is an extension the DB API. It is returned by the methods
:meth:`SodaDatabase.createDocument()`,
:meth:`SodaOperation.getDocuments()` and
:meth:`SodaOperation.getOne()` as well as by iterating over
:ref:`SODA document cursors <sodadoccur>`.
.. attribute:: SodaDoc.createdOn
This read-only attribute returns the creation time of the document in
`ISO 8601 <https://www.iso.org/iso-8601-date-and-time-format.html>`__
format. Documents created by :meth:`SodaDatabase.createDocument()` or
fetched from collections where this attribute is not stored will return
None.
.. versionadded:: 7.0
.. method:: SodaDoc.getContent()
Returns the content of the document as a dictionary or list. This method
assumes that the content is application/json and will raise an exception if
this is not the case. If there is no content, however, None will be
returned.
.. versionadded:: 7.0
.. method:: SodaDoc.getContentAsBytes()
Returns the content of the document as a bytes object. If there is no
content, however, None will be returned.
.. versionadded:: 7.0
.. method:: SodaDoc.getContentAsString()
Returns the content of the document as a string. If the document encoding
is not known, UTF-8 will be used. If there is no content, however, None
will be returned.
.. versionadded:: 7.0
.. attribute:: SodaDoc.key
This read-only attribute returns the unique key assigned to this document.
Documents created by :meth:`SodaDatabase.createDocument()` may not have a
value assigned to them and return None.
.. versionadded:: 7.0
.. attribute:: SodaDoc.lastModified
This read-only attribute returns the last modified time of the document in
`ISO 8601 <https://www.iso.org/iso-8601-date-and-time-format.html>`__
format. Documents created by :meth:`SodaDatabase.createDocument()` or
fetched from collections where this attribute is not stored will return
None.
.. versionadded:: 7.0
.. attribute:: SodaDoc.mediaType
This read-only attribute returns the media type assigned to the document.
By convention this is expected to be a MIME type but no checks are
performed on this value. If a value is not specified when calling
:meth:`SodaDatabase.createDocument()` or the document is fetched from a
collection where this component is not stored, the string
"application/json" is returned.
.. versionadded:: 7.0
.. attribute:: SodaDoc.version
This read-only attribute returns the version assigned to this document.
Documents created by :meth:`SodaDatabase.createDocument()` or fetched
from collections where this attribute is not stored will return None.
.. versionadded:: 7.0
.. _sodadoccur:
---------------------------
SODA Document Cursor Object
---------------------------
.. note::
This object is an extension the DB API. It is returned by the method
:meth:`SodaOperation.getCursor()` and implements the iterator protocol.
Each iteration will return a :ref:`SODA document object <sodadoc>`.
.. method:: SodaDocCursor.close()
Close the cursor now, rather than whenever __del__ is called. The cursor
will be unusable from this point forward; an Error exception will be raised
if any operation is attempted with the cursor.
.. versionadded:: 7.0
.. _sodaop:
---------------------
SODA Operation Object
---------------------
.. note::
This object is an extension to the DB API. It represents an operation that
will be performed on all or some of the documents in a SODA collection. It
is created by the method :meth:`SodaCollection.find()`.
.. method:: SodaOperation.count()
Returns a count of the number of documents in the collection that match
the criteria. If :meth:`~SodaOperation.skip()` or
:meth:`~SodaOperation.limit()` were called on this object, an exception is
raised.
.. versionadded:: 7.0
.. method:: SodaOperation.fetchArraySize(value)
This is a tuning method to specify the number of documents that are
internally fetched in batches by calls to :meth:`~SodaOperation.getCursor()`
and :meth:`~SodaOperation.getDocuments()`. It does not affect how many
documents are returned to the application. A value of 0 will use the default
value (100). This method is only available in Oracle Client 19.5 and higher.
As a convenience, the SodaOperation object is returned so that further
criteria can be specified by chaining methods together.
.. versionadded:: 8.0
.. method:: SodaOperation.filter(value)
Sets a filter specification for complex document queries and ordering of
JSON documents. Filter specifications must be provided as a dictionary or
JSON-encoded string and can include comparisons, regular expressions,
logical and spatial operators, among others. See the
`overview of SODA filter specifications
<https://www.oracle.com/pls/topic/
lookup?ctx=dblatest&id=GUID-CB09C4E3-BBB1-40DC-88A8-8417821B0FBE>`__
for more information.
As a convenience, the SodaOperation object is returned so that further
criteria can be specified by chaining methods together.
.. versionadded:: 7.0
.. method:: SodaOperation.getCursor()
Returns a :ref:`SODA Document Cursor object <sodadoccur>` that can be used
to iterate over the documents that match the criteria.
.. versionadded:: 7.0
.. method:: SodaOperation.getDocuments()
Returns a list of :ref:`SODA Document objects <sodadoc>` that match the
criteria.
.. versionadded:: 7.0
.. method:: SodaOperation.getOne()
Returns a single :ref:`SODA Document object <sodadoc>` that matches the
criteria. Note that if multiple documents match the criteria only the first
one is returned.
.. versionadded:: 7.0
.. 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 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
.. method:: SodaOperation.key(value)
Specifies that the document with the specified key should be returned.
This causes any previous calls made to this method and
:meth:`~SodaOperation.keys()` to be ignored.
As a convenience, the SodaOperation object is returned so that further
criteria can be specified by chaining methods together.
.. versionadded:: 7.0
.. method:: SodaOperation.keys(seq)
Specifies that documents that match the keys found in the supplied sequence
should be returned. This causes any previous calls made to this method and
:meth:`~SodaOperation.key()` to be ignored.
As a convenience, the SodaOperation object is returned so that further
criteria can be specified by chaining methods together.
.. versionadded:: 7.0
.. method:: SodaOperation.limit(value)
Specifies that only the specified number of documents should be returned.
This method is only usable for read operations such as
:meth:`~SodaOperation.getCursor()` and
:meth:`~SodaOperation.getDocuments()`. For write operations, any value set
using this method is ignored.
As a convenience, the SodaOperation object is returned so that further
criteria can be specified by chaining methods together.
.. versionadded:: 7.0
.. method:: SodaOperation.remove()
Removes all of the documents in the collection that match the criteria. The
number of documents that have been removed is returned.
.. versionadded:: 7.0
.. method:: SodaOperation.replaceOne(doc)
Replaces a single document in the collection with the specified document.
The input document can be a dictionary or list or an existing
:ref:`SODA document object <sodadoc>`. A boolean indicating if a document
was replaced or not is returned.
Currently the method :meth:`~SodaOperation.key()` must be called before
this method can be called.
.. versionadded:: 7.0
.. method:: SodaOperation.replaceOneAndGet(doc)
Similarly to :meth:`~SodaOperation.replaceOne()`, this method replaces a
single document in the collection with the specified document. The only
difference is that it returns a :ref:`SODA document object <sodadoc>`.
Note that for performance reasons the returned document does not contain
the content.
.. versionadded:: 7.0
.. method:: SodaOperation.skip(value)
Specifies the number of documents that match the other criteria that will
be skipped. This method is only usable for read operations such as
:meth:`~SodaOperation.getCursor()` and
:meth:`~SodaOperation.getDocuments()`. For write operations, any value set
using this method is ignored.
As a convenience, the SodaOperation object is returned so that further
criteria can be specified by chaining methods together.
.. versionadded:: 7.0
.. method:: SodaOperation.version(value)
Specifies that documents with the specified version should be returned.
Typically this is used with :meth:`~SodaOperation.key()` to implement
optimistic locking, so that the write operation called later does not
affect a document that someone else has modified.
As a convenience, the SodaOperation object is returned so that further
criteria can be specified by chaining methods together.
.. versionadded:: 7.0

View File

@ -1,282 +0,0 @@
.. _subscrobj:
*******************
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.
.. attribute:: Subscription.callback
This read-only attribute returns the callback that was registered when the
subscription was created.
.. attribute:: Subscription.connection
This read-only attribute returns the connection that was used to register
the subscription when it was created.
.. attribute:: Subscription.id
This read-only attribute returns the value of ``REGID`` found in the
database view ``USER_CHANGE_NOTIFICATION_REGS`` or the value of ``REG_ID``
found in the database view ``USER_SUBSCR_REGISTRATIONS``. For AQ
subscriptions, the value is 0.
.. attribute:: Subscription.ip_address
This read-only attribute returns the IP address used for callback
notifications from the database server. If not set during construction,
this value is None.
.. versionadded:: 6.4
.. versionchanged:: 8.2
For consistency and compliance with the PEP 8 naming style, the
attribute `ipAddress` was renamed to `ip_address`. The old name will
continue to work for a period of time.
.. attribute:: Subscription.name
This read-only attribute returns the name used to register the subscription
when it was created.
.. versionadded:: 6.4
.. attribute:: Subscription.namespace
This read-only attribute returns the namespace used to register the
subscription when it was created.
.. attribute:: Subscription.operations
This read-only attribute returns the operations that will send
notifications for each table or query that is registered using this
subscription.
.. attribute:: Subscription.port
This read-only attribute returns the port used for callback notifications
from the database server. If not set during construction, this value is
zero.
.. attribute:: Subscription.protocol
This read-only attribute returns the protocol used to register the
subscription when it was created.
.. attribute:: Subscription.qos
This read-only attribute returns the quality of service flags used to
register the subscription when it was created.
.. method:: Subscription.registerquery(statement, [args])
Register the query for subsequent notification when tables referenced by
the query are changed. This behaves similarly to cursor.execute() but only
queries are permitted and the args parameter must be a sequence or
dictionary. If the qos parameter included the flag
cx_Oracle.SUBSCR_QOS_QUERY when the subscription was created, then the ID
for the registered query is returned; otherwise, None is returned.
.. attribute:: Subscription.timeout
This read-only attribute returns the timeout (in seconds) that was
specified when the subscription was created. A value of 0 indicates that
there is no timeout.
.. _msgobjects:
Message Objects
---------------
.. note::
This object is created internally when notification is received and passed
to the callback procedure specified when a subscription is created.
.. attribute:: Message.consumer_name
This read-only attribute returns the name of the consumer which generated
the notification. It will be populated if the subscription was created with
the namespace :data:`cx_Oracle.SUBSCR_NAMESPACE_AQ` and the queue is a
multiple consumer queue.
.. versionadded:: 6.4
.. versionchanged:: 8.2
For consistency and compliance with the PEP 8 naming style, the
attribute `consumerName` was renamed to `consumer_name`. The old name
will continue to work for a period of time.
.. attribute:: Message.dbname
This read-only attribute returns the name of the database that generated
the notification.
.. attribute:: Message.queries
This read-only attribute returns a list of message query objects that give
information about query result sets changed for this notification. This
attribute will be None if the qos parameter did not include the flag
:data:`~cx_Oracle.SUBSCR_QOS_QUERY` when the subscription was created.
.. attribute:: Message.queue_name
This read-only attribute returns the name of the queue which generated the
notification. It will only be populated if the subscription was created
with the namespace :data:`cx_Oracle.SUBSCR_NAMESPACE_AQ`.
.. versionadded:: 6.4
.. versionchanged:: 8.2
For consistency and compliance with the PEP 8 naming style, the
attribute `queueName` was renamed to `queue_name`. The old name will
continue to work for a period of time.
.. attribute:: Message.registered
This read-only attribute returns whether the subscription which generated
this notification is still registered with the database. The subscription
is automatically deregistered with the database when the subscription
timeout value is reached or when the first notification is sent (when the
quality of service flag :data:`cx_Oracle.SUBSCR_QOS_DEREG_NFY` is used).
.. versionadded:: 6.4
.. attribute:: Message.subscription
This read-only attribute returns the subscription object for which this
notification was generated.
.. attribute:: Message.tables
This read-only attribute returns a list of message table objects that give
information about the tables changed for this notification. This
attribute will be None if the qos parameter included the flag
:data:`~cx_Oracle.SUBSCR_QOS_QUERY` when the subscription was created.
.. attribute:: Message.txid
This read-only attribute returns the id of the transaction that generated
the notification.
.. attribute:: Message.type
This read-only attribute returns the type of message that has been sent.
See the constants section on event types for additional information.
Message Table Objects
---------------------
.. note::
This object is created internally for each table changed when notification
is received and is found in the tables attribute of message objects, and
the tables attribute of message query objects.
.. attribute:: MessageTable.name
This read-only attribute returns the name of the table that was changed.
.. attribute:: MessageTable.operation
This read-only attribute returns the operation that took place on the table
that was changed.
.. attribute:: MessageTable.rows
This read-only attribute returns a list of message row objects that give
information about the rows changed on the table. This value is only filled
in if the qos parameter to the :meth:`Connection.subscribe()` method
included the flag :data:`~cx_Oracle.SUBSCR_QOS_ROWIDS`.
Message Row Objects
-------------------
.. note::
This object is created internally for each row changed on a table when
notification is received and is found in the rows attribute of message
table objects.
.. attribute:: MessageRow.operation
This read-only attribute returns the operation that took place on the row
that was changed.
.. attribute:: MessageRow.rowid
This read-only attribute returns the rowid of the row that was changed.
Message Query Objects
---------------------
.. note::
This object is created internally for each query result set changed when
notification is received and is found in the queries attribute of message
objects.
.. attribute:: MessageQuery.id
This read-only attribute returns the query id of the query for which the
result set changed. The value will match the value returned by
Subscription.registerquery when the related query was registered.
.. attribute:: MessageQuery.operation
This read-only attribute returns the operation that took place on the query
result set that was changed. Valid values for this attribute are
:data:`~cx_Oracle.EVENT_DEREG` and :data:`~cx_Oracle.EVENT_QUERYCHANGE`.
.. attribute:: MessageQuery.tables
This read-only attribute returns a list of message table objects that give
information about the table changes that caused the query result set to
change for this notification.

View File

@ -1,114 +0,0 @@
.. _varobj:
****************
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.
.. attribute:: Variable.actual_elements
This read-only attribute returns the actual number of elements in the
variable. This corresponds to the number of elements in a PL/SQL index-by
table for variables that are created using the method
:func:`Cursor.arrayvar()`. For all other variables this value will be
identical to the attribute :attr:`~Variable.numElements`.
.. versionchanged:: 8.2
For consistency and compliance with the PEP 8 naming style, the
attribute `actualElements` was renamed to `actual_elements`. The old
name will continue to work for a period of time.
.. attribute:: Variable.buffer_size
This read-only attribute returns the size of the buffer allocated for each
element in bytes.
.. versionchanged:: 8.2
For consistency and compliance with the PEP 8 naming style, the
attribute `bufferSize` was renamed to `buffer_size`. The old
name will continue to work for a period of time.
.. method:: Variable.getvalue([pos=0])
Return the value at the given position in the variable. For variables
created using the method :func:`Cursor.arrayvar()` the value returned will
be a list of each of the values in the PL/SQL index-by table. For variables
bound to DML returning statements, the value returned will also be a list
corresponding to the returned data for the given execution of the statement
(as identified by the pos parameter).
.. attribute:: Variable.inconverter
This read-write attribute specifies the method used to convert data from
Python to the Oracle database. The method signature is converter(value)
and the expected return value is the value to bind to the database. If this
attribute is None, the value is bound directly without any conversion.
.. attribute:: Variable.num_elements
This read-only attribute returns the number of elements allocated in an
array, or the number of scalar items that can be fetched into the variable
or bound to the variable.
.. versionchanged:: 8.2
For consistency and compliance with the PEP 8 naming style, the
attribute `numElements` was renamed to `num_elements`. The old
name will continue to work for a period of time.
.. attribute:: Variable.outconverter
This read-write attribute specifies the method used to convert data from
the Oracle database to Python. The method signature is converter(value)
and the expected return value is the value to return to Python. If this
attribute is None, the value is returned directly without any conversion.
.. method:: Variable.setvalue(pos, value)
Set the value at the given position in the variable.
.. attribute:: Variable.size
This read-only attribute returns the size of the variable. For strings this
value is the size in characters. For all others, this is same value as the
attribute bufferSize.
.. attribute:: Variable.type
This read-only attribute returns the type of the variable. This will be an
:ref:`Oracle Object Type <objecttype>` if the variable binds
Oracle objects; otherwise, it will be one of the
:ref:`database type constants <dbtypes>`.
.. versionchanged:: 8.0
Database type constants are now used when the variable is not used for
binding Oracle objects.
.. attribute:: Variable.values
This read-only attribute returns a copy of the value of all actual
positions in the variable as a list. This is the equivalent of calling
:meth:`~Variable.getvalue()` for each valid position and the length will
correspond to the value of the :attr:`~Variable.actualElements` attribute.

View File

@ -1,134 +0,0 @@
# -*- coding: utf-8 -*-
#
# cx_Oracle documentation build configuration file
#
# This file is execfile()d with the current directory set to its containing dir.
#
# The contents of this file are pickled, so don't put values in the namespace
# that aren't pickleable (module imports are okay, they're removed automatically).
#
# All configuration values have a default value; values that are commented out
# serve to show the default value.
import sys
# If your extensions are in another directory, add it here.
#sys.path.append('some/directory')
# General configuration
# ---------------------
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
#extensions = []
# Add any paths that contain templates here, relative to this directory.
templates_path = ['.templates']
# The suffix of source filenames.
source_suffix = '.rst'
# The root toctree document.
root_doc = master_doc = 'index'
# General substitutions.
project = 'cx_Oracle'
copyright = u'2016, 2020, Oracle and/or its affiliates. All rights reserved. Portions Copyright © 2007-2015, Anthony Tuininga. All rights reserved. Portions Copyright © 2001-2007, Computronix (Canada) Ltd., Edmonton, Alberta, Canada. All rights reserved'
author = 'Oracle'
# The default replacements for |version| and |release|, also used in various
# other places throughout the built documents.
#
# The short X.Y version.
version = '8.3'
# The full version, including alpha/beta/rc tags.
release = '8.3.0'
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
today_fmt = '%B %d, %Y'
# List of documents that shouldn't be included in the build.
#unused_docs = []
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# Options for HTML output
# -----------------------
# The style sheet to use for HTML and HTML Help pages. A file of that name
# must exist either in Sphinx' static/ path, or in one of the custom paths
# given in html_static_path.
html_style = 'default.css'
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
#html_static_path = ['.static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Content template for the index page.
#html_index = ''
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_use_modindex = True
# If true, the reST sources are included in the HTML build as _sources/<name>.
html_copy_source = False
# Output file base name for HTML help builder.
htmlhelp_basename = 'cx_Oracledoc'
numfig = True
# Options for LaTeX output
# ------------------------
# The paper size ('letter' or 'a4').
#latex_paper_size = 'letter'
# The font size ('10pt', '11pt' or '12pt').
#latex_font_size = '10pt'
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, document class [howto/manual]).
#latex_documents = []
# Additional stuff for the LaTeX preamble.
#latex_preamble = ''
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_use_modindex = True

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

View File

@ -1,75 +0,0 @@
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,
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>`
(the BSD license). A detailed description of cx_Oracle changes can be found in
the :ref:`release notes <releasenotes>`.
Contents:
User Guide
==========
.. toctree::
:maxdepth: 3
user_guide/introduction.rst
user_guide/installation.rst
user_guide/initialization.rst
user_guide/connection_handling.rst
user_guide/sql_execution.rst
user_guide/plsql_execution.rst
user_guide/bind.rst
user_guide/lob_data.rst
user_guide/json_data_type.rst
user_guide/soda.rst
user_guide/xml_data_type.rst
user_guide/batch_statement.rst
user_guide/exception_handling.rst
user_guide/aq.rst
user_guide/cqn.rst
user_guide/txn_management.rst
user_guide/tuning.rst
user_guide/globalization.rst
user_guide/startup.rst
user_guide/ha.rst
user_guide/tracing_sql.rst
API Manual
==========
.. toctree::
:maxdepth: 3
api_manual/module.rst
api_manual/connection.rst
api_manual/cursor.rst
api_manual/variable.rst
api_manual/session_pool.rst
api_manual/subscription.rst
api_manual/lob.rst
api_manual/object_type.rst
api_manual/aq.rst
api_manual/soda.rst
api_manual/deprecations.rst
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

View File

@ -1,46 +0,0 @@
:orphan:
.. _license:
*******
License
*******
.. include:: <isonum.txt>
.. centered:: **LICENSE AGREEMENT FOR CX_ORACLE**
Copyright |copy| 2016, 2020, Oracle and/or its affiliates. All rights reserved.
Copyright |copy| 2007-2015, Anthony Tuininga. All rights reserved.
Copyright |copy| 2001-2007, Computronix (Canada) Ltd., Edmonton, Alberta,
Canada. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
#. Redistributions of source code must retain the above copyright notice, this
list of conditions, and the disclaimer that follows.
#. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions, and the following disclaimer in the documentation
and/or other materials provided with the distribution.
#. Neither the names of the copyright holders nor the names of any contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
DISCLAIMER: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
\*AS IS\* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Computronix |reg| is a registered trademark of Computronix (Canada) Ltd.

File diff suppressed because it is too large Load Diff

View File

@ -1,218 +0,0 @@
.. _aqusermanual:
****************************
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
interfaces in various languages, letting you integrate multiple tools in your
architecture.
cx_Oracle 7.2 introduced an updated interface for Oracle Advanced
Queuing.
There are Advanced Queuing examples in the `GitHub examples
<https://github.com/oracle/python-cx_Oracle/tree/main/samples>`__ directory.
Creating a Queue
================
Before being used, queues need to be created in the database, for example in
SQL*Plus:
.. code-block:: sql
begin
dbms_aqadm.create_queue_table('MY_QUEUE_TABLE', 'RAW');
dbms_aqadm.create_queue('DEMO_RAW_QUEUE', 'MY_QUEUE_TABLE');
dbms_aqadm.start_queue('DEMO_RAW_QUEUE');
end;
/
This examples creates a RAW queue suitable for sending string or raw bytes
messages.
Enqueuing Messages
==================
To send messages in Python you connect and get a :ref:`queue <queue>`. The
queue can be used for enqueuing, dequeuing, or both as needed.
.. code-block:: python
queue = connection.queue("DEMO_RAW_QUEUE")
Now messages can be queued using :meth:`~Queue.enqone()`. To send three
messages:
.. code-block:: python
PAYLOAD_DATA = [
"The first message",
"The second message",
"The third message"
]
for data in PAYLOAD_DATA:
queue.enqone(connection.msgproperties(payload=data))
connection.commit()
Since the queue sending the messages is a RAW queue, the strings in this
example will be internally encoded to bytes using :attr:`Connection.encoding`
before being enqueued.
Dequeuing Messages
==================
Dequeuing is performed similarly. To dequeue a message call the method
:meth:`~Queue.deqone()` as shown. Note that if the message is expected to be a
string, the bytes must be decoded using :attr:`Connection.encoding`.
.. code-block:: python
queue = connection.queue("DEMO_RAW_QUEUE")
msg = queue.deqOne()
connection.commit()
print(msg.payload.decode(connection.encoding))
Using Object Queues
===================
Named Oracle objects can be enqueued and dequeued as well. Given an object
type called ``UDT_BOOK``:
.. code-block:: sql
CREATE OR REPLACE TYPE udt_book AS OBJECT (
Title VARCHAR2(100),
Authors VARCHAR2(100),
Price NUMBER(5,2)
);
/
And a queue that accepts this type:
.. code-block:: sql
begin
dbms_aqadm.create_queue_table('BOOK_QUEUE_TAB', 'UDT_BOOK');
dbms_aqadm.create_queue('DEMO_BOOK_QUEUE', 'BOOK_QUEUE_TAB');
dbms_aqadm.start_queue('DEMO_BOOK_QUEUE');
end;
/
You can queue messages:
.. code-block:: python
book_type = connection.gettype("UDT_BOOK")
queue = connection.queue("DEMO_BOOK_QUEUE", book_type)
book = book_type.newobject()
book.TITLE = "Quick Brown Fox"
book.AUTHORS = "The Dog"
book.PRICE = 123
queue.enqone(connection.msgproperties(payload=book))
connection.commit()
Dequeuing is done like this:
.. code-block:: python
book_type = connection.gettype("UDT_BOOK")
queue = connection.queue("DEMO_BOOK_QUEUE", book_type)
msg = queue.deqone()
connection.commit()
print(msg.payload.TITLE) # will print Quick Brown Fox
Changing Queue and Message Options
==================================
Refer to the :ref:`cx_Oracle AQ API <aq>` and
`Oracle Advanced Queuing documentation
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=ADQUE>`__ for details
on all of the enqueue and dequeue options available.
Enqueue options can be set. For example, to make it so that an explicit
call to :meth:`~Connection.commit()` on the connection is not needed to commit
messages:
.. code-block:: python
queue = connection.queue("DEMO_RAW_QUEUE")
queue.enqoptions.visibility = cx_Oracle.ENQ_IMMEDIATE
Dequeue options can also be set. For example, to specify not to block on
dequeuing if no messages are available:
.. code-block:: python
queue = connection.queue("DEMO_RAW_QUEUE")
queue.deqoptions.wait = cx_Oracle.DEQ_NO_WAIT
Message properties can be set when enqueuing. For example, to set an
expiration of 60 seconds on a message:
.. code-block:: python
queue.enqone(connection.msgproperties(payload="Message", expiration=60))
This means that if no dequeue operation occurs within 60 seconds that the
message will be dropped from the queue.
Bulk Enqueue and Dequeue
========================
The :meth:`~Queue.enqmany()` and :meth:`~Queue.deqmany()` methods can be used
for efficient bulk message handling.
:meth:`~Queue.enqmany()` is similar to :meth:`~Queue.enqone()` but accepts an
array of messages:
.. code-block:: python
messages = [
"The first message",
"The second message",
"The third message",
]
queue = connection.queue("DEMO_RAW_QUEUE")
queue.enqmany(connection.msgproperties(payload=m) for m in messages)
connection.commit()
.. warning::
Calling :meth:`~Queue.enqmany()` in parallel on different connections
acquired from the same pool may fail due to Oracle bug 29928074. Ensure
that this function is not run in parallel, use standalone connections or
connections from different pools, or make multiple calls to
:meth:`~Queue.enqone()` instead. The function :meth:`~Queue.deqmany()` call
is not affected.
To dequeue multiple messages at one time, use :meth:`~Queue.deqmany()`. This
takes an argument specifying the maximum number of messages to dequeue at one
time:
.. code-block:: python
for m in queue.deqmany(10):
print(m.payload.decode(connection.encoding))
Depending on the queue properties and the number of messages available to
dequeue, this code will print out from zero to ten messages.

View File

@ -1,301 +0,0 @@
.. _batchstmnt:
******************************************
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
:meth:`Cursor.execute()` by reducing network transfer costs and database overheads.
The :meth:`~Cursor.executemany()` method can also be used to execute PL/SQL
statements multiple times at once.
There are examples in the `GitHub examples
<https://github.com/oracle/python-cx_Oracle/tree/main/samples>`__
directory.
The following tables will be used in the samples that follow:
.. code-block:: sql
create table ParentTable (
ParentId number(9) not null,
Description varchar2(60) not null,
constraint ParentTable_pk primary key (ParentId)
);
create table ChildTable (
ChildId number(9) not null,
ParentId number(9) not null,
Description varchar2(60) not null,
constraint ChildTable_pk primary key (ChildId),
constraint ChildTable_fk foreign key (ParentId)
references ParentTable
);
Batch Execution of SQL
======================
The following example inserts five rows into the table ``ParentTable``:
.. code-block:: python
data = [
(10, 'Parent 10'),
(20, 'Parent 20'),
(30, 'Parent 30'),
(40, 'Parent 40'),
(50, 'Parent 50')
]
cursor.executemany("insert into ParentTable values (:1, :2)", data)
This code requires only one :ref:`round-trip <roundtrips>` from the client to
the database instead of the five round-trips that would be required for
repeated calls to :meth:`~Cursor.execute()`. For very large data sets there
may be an external buffer or network limits to how many rows can be processed,
so repeated calls to ``executemany()`` may be required. The limits are based
on both the number of rows being processed as well as the "size" of each row
that is being processed. Repeated calls to :meth:`~Cursor.executemany()` are
still better than repeated calls to :meth:`~Cursor.execute()`.
Batch Execution of PL/SQL
=========================
PL/SQL functions and procedures and anonymous PL/SQL blocks can also be called
using :meth:`~Cursor.executemany()` in order to improve performance. For
example:
.. code-block:: python
data = [
(10, 'Parent 10'),
(20, 'Parent 20'),
(30, 'Parent 30'),
(40, 'Parent 40'),
(50, 'Parent 50')
]
cursor.executemany("begin mypkg.create_parent(:1, :2); end;", data)
Note that the ``batcherrors`` parameter (discussed below) cannot be used with
PL/SQL block execution.
Handling Data Errors
====================
Large datasets may contain some invalid data. When using batch execution as
discussed above, the entire batch will be discarded if a single error is
detected, potentially eliminating the performance benefits of batch execution
and increasing the complexity of the code required to handle those errors. If
the parameter ``batchErrors`` is set to the value ``True`` when calling
:meth:`~Cursor.executemany()`, however, processing will continue even if there
are data errors in some rows, and the rows containing errors can be examined
afterwards to determine what course the application should take. Note that if
any errors are detected, a transaction will be started but not committed, even
if :attr:`Connection.autocommit` is set to ``True``. After examining the errors
and deciding what to do with them, the application needs to explicitly commit
or roll back the transaction with :meth:`Connection.commit()` or
:meth:`Connection.rollback()`, as needed.
This example shows how data errors can be identified:
.. code-block:: python
data = [
(60, 'Parent 60'),
(70, 'Parent 70'),
(70, 'Parent 70 (duplicate)'),
(80, 'Parent 80'),
(80, 'Parent 80 (duplicate)'),
(90, 'Parent 90')
]
cursor.executemany("insert into ParentTable values (:1, :2)", data,
batcherrors=True)
for error in cursor.getbatcherrors():
print("Error", error.message, "at row offset", error.offset)
The output is::
Error ORA-00001: unique constraint (PYTHONDEMO.PARENTTABLE_PK) violated at row offset 2
Error ORA-00001: unique constraint (PYTHONDEMO.PARENTTABLE_PK) violated at row offset 4
The row offset is the index into the array of the data that could not be
inserted due to errors. The application could choose to commit or rollback the
other rows that were successfully inserted. Alternatively, it could correct
the data for the two invalid rows and attempt to insert them again before
committing.
Identifying Affected Rows
=========================
When executing a DML statement using :meth:`~Cursor.execute()`, the number of
rows affected can be examined by looking at the attribute
:attr:`~Cursor.rowcount`. When performing batch executing with
:meth:`Cursor.executemany()`, however, the row count will return the *total*
number of rows that were affected. If you want to know the total number of rows
affected by each row of data that is bound you must set the parameter
``arraydmlrowcounts`` to ``True``, as shown:
.. code-block:: python
parent_ids_to_delete = [20, 30, 50]
cursor.executemany("delete from ChildTable where ParentId = :1",
[(i,) for i in parent_ids_to_delete],
arraydmlrowcounts=True)
row_counts = cursor.getarraydmlrowcounts()
for parent_id, count in zip(parent_ids_to_delete, row_counts):
print("Parent ID:", parent_id, "deleted", count, "rows.")
Using the data found in the `GitHub samples
<https://github.com/oracle/python-cx_Oracle/tree/main/samples>`__ the output
is as follows::
Parent ID: 20 deleted 3 rows.
Parent ID: 30 deleted 2 rows.
Parent ID: 50 deleted 4 rows.
DML RETURNING
=============
DML statements like INSERT, UPDATE, DELETE and MERGE can return values by using
the DML RETURNING syntax. A bind variable can be created to accept this data.
See :ref:`bind` for more information.
If, instead of merely deleting the rows as shown in the previous example, you
also wanted to know some information about each of the rows that were deleted,
you could use the following code:
.. code-block:: python
parent_ids_to_delete = [20, 30, 50]
child_id_var = cursor.var(int, arraysize=len(parent_ids_to_delete))
cursor.setinputsizes(None, child_id_var)
cursor.executemany("""
delete from ChildTable
where ParentId = :1
returning ChildId into :2""",
[(i,) for i in parent_ids_to_delete])
for ix, parent_id in enumerate(parent_ids_to_delete):
print("Child IDs deleted for parent ID", parent_id, "are",
child_id_var.getvalue(ix))
The output would then be::
Child IDs deleted for parent ID 20 are [1002, 1003, 1004]
Child IDs deleted for parent ID 30 are [1005, 1006]
Child IDs deleted for parent ID 50 are [1012, 1013, 1014, 1015]
Note that the bind variable created to accept the returned data must have an
arraysize large enough to hold data for each row that is processed. Also,
the call to :meth:`Cursor.setinputsizes()` binds this variable immediately so
that it does not have to be passed in each row of data.
Predefining Memory Areas
========================
When multiple rows of data are being processed there is the possibility that
the data is not uniform in type and size. In such cases, cx_Oracle makes some
effort to accommodate such differences. Type determination for each column is
deferred until a value that is not ``None`` is found in the column's data. If
all values in a particular column are ``None``, then cx_Oracle assumes the type
is a string and has a length of 1. cx_Oracle will also adjust the size of the
buffers used to store strings and bytes when a longer value is encountered in
the data. These sorts of operations incur overhead as memory has to be
reallocated and data copied. To eliminate this overhead, using
:meth:`~Cursor.setinputsizes()` tells cx_Oracle about the type and size of the
data that is going to be used.
Consider the following code:
.. code-block:: python
data = [
(110, "Parent 110"),
(2000, "Parent 2000"),
(30000, "Parent 30000"),
(400000, "Parent 400000"),
(5000000, "Parent 5000000")
]
cursor.setinputsizes(None, 20)
cursor.executemany("""
insert into ParentTable (ParentId, Description)
values (:1, :2)""", data)
In this example, without the call to :meth:`~Cursor.setinputsizes()`, cx_Oracle
would perform five allocations of increasing size as it discovered each new,
longer string. However ``cursor.setinputsizes(None, 20)`` tells cx_Oracle that
the maximum size of the strings that will be processed is 20 characters. Since
cx_Oracle allocates memory for each row based on this value, it is best not to
oversize it. The first parameter of ``None`` tells cx_Oracle that its default
processing will be sufficient.
Loading CSV Files into Oracle Database
======================================
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``::
101,Abel
154,Baker
132,Charlie
199,Delta
. . .
And the schema:
.. code-block:: sql
create table test (id number, name varchar2(25));
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.
# 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 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:
csv_reader = csv.reader(csv_file, delimiter=',')
sql = "insert into test (id,name) values (:1, :2)"
data = []
for line in csv_reader:
data.append((line[0], line[1]))
if len(data) % batch_size == 0:
cursor.executemany(sql, data)
data = []
if data:
cursor.executemany(sql, data)
con.commit()
Depending on data sizes and business requirements, database changes such as
temporarily disabling redo logging on the table, or disabling indexes may also
be beneficial.

View File

@ -1,812 +0,0 @@
.. _bind:
********************
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
parameters A bind variable is a colon-prefixed identifier or numeral. For
example, there are two bind variables (``dept_id`` and ``dept_name``) in this
SQL statement:
.. code-block:: python
sql = """insert into departments (department_id, department_name)
values (:dept_id, :dept_name)"""
cursor.execute(sql, [280, "Facility"])
Using bind variables is important for scalability and security. They help avoid
SQL Injection security problems because data is never treated as part of an
executable statement. Never concatenate or interpolate user data into SQL
statements:
.. code-block:: python
did = 280
dnm = "Facility"
# !! Never do this !!
sql = f"""insert into departments (department_id, department_name)
values ({did}, '{dnm}')"""
cursor.execute(sql)
Bind variables reduce parsing and execution costs when statements are executed
more than once with different data values. If you do not use bind variables,
Oracle must reparse and cache multiple statements. When using bind variables,
Oracle Database may be able to reuse the statement execution plan and context.
Bind variables can be used to substitute data, but cannot be used to substitute
the text of the statement. You cannot, for example, use a bind variable where
a column name or a table name is required. Bind variables also cannot be used
in Data Definition Language (DDL) statements, such as CREATE TABLE or ALTER
statements.
Binding By Name or Position
===========================
Binding can be done by name or by position. A named bind is performed when the
bind variables in a statement are associated with a name. For example:
.. code-block:: python
cursor.execute("""
insert into departments (department_id, department_name)
values (:dept_id, :dept_name)""", dept_id=280,
dept_name="Facility")
# alternatively, the parameters can be passed as a dictionary instead of as
# keyword parameters
data = dict(dept_id=280, dept_name="Facility")
cursor.execute("""
insert into departments (department_id, department_name)
values (:dept_id, :dept_name)""", data)
In the above example, the keyword parameter names or the keys of the dictionary
must match the bind variable names. The advantages of this approach are that
the location of the bind variables in the statement is not important, the
names can be meaningful and the names can be repeated while still only
supplying the value once.
A positional bind is performed when a list of bind values are passed to the
execute() call. For example:
.. code-block:: python
cursor.execute("""
insert into departments (department_id, department_name)
values (:dept_id, :dept_name)""", [280, "Facility"])
Note that for SQL statements, the order of the bind values must exactly match
the order of each bind variable and duplicated names must have their values
repeated. For PL/SQL statements, however, the order of the bind values must
exactly match the order of each **unique** bind variable found in the PL/SQL
block and values should not be repeated. In order to avoid this difference,
binding by name is recommended when bind variable names are repeated.
Bind Direction
==============
The caller can supply data to the database (IN), the database can return
data to the caller (OUT) or the caller can supply initial data to the
database and the database can supply the modified data back to the caller
(IN/OUT). This is known as the bind direction.
The examples shown above have all supplied data to the database and are
therefore classified as IN bind variables. In order to have the database return
data to the caller, a variable must be created. This is done by calling the
method :func:`Cursor.var()`, which identifies the type of data that will be
found in that bind variable and its maximum size among other things.
Here is an example showing how to use OUT binds. It calculates the sum of the
integers 8 and 7 and stores the result in an OUT bind variable of type integer:
.. code-block:: python
out_val = cursor.var(int)
cursor.execute("""
begin
:out_val := :in_bind_var1 + :in_bind_var2;
end;""",
out_val=out_val, in_bind_var1=8, in_bind_var2=7)
print(out_val.getvalue()) # will print 15
If instead of simply getting data back you wish to supply an initial value to
the database, you can set the variable's initial value. This example is the
same as the previous one but it sets the initial value first:
.. code-block:: python
in_out_var = cursor.var(int)
in_out_var.setvalue(0, 25)
cursor.execute("""
begin
:in_out_bind_var := :in_out_bind_var + :in_bind_var1 +
:in_bind_var2;
end;""",
in_out_bind_var=in_out_var, in_bind_var1=8, in_bind_var2=7)
print(in_out_var.getvalue()) # will print 40
When binding data to parameters of PL/SQL procedures that are declared as OUT
parameters, it is worth noting that any value that is set in the bind variable
will be ignored. In addition, any parameters declared as IN/OUT that do not
have a value set will start out with a value of ``null``.
Binding Null Values
===================
In cx_Oracle, null values are represented by the Python singleton ``None``.
For example:
.. code-block:: python
cursor.execute("""
insert into departments (department_id, department_name)
values (:dept_id, :dept_name)""", dept_id=280, dept_name=None)
In this specific case, because the ``DEPARTMENT_NAME`` column is defined as a
``NOT NULL`` column, an error will occur::
cx_Oracle.IntegrityError: ORA-01400: cannot insert NULL into ("HR"."DEPARTMENTS"."DEPARTMENT_NAME")
If this value is bound directly, cx_Oracle assumes it to be a string
(equivalent to a VARCHAR2 column). If you need to use a different Oracle type
you will need to make a call to :func:`Cursor.setinputsizes()` or create a bind
variable with the correct type by calling :func:`Cursor.var()`.
Binding ROWID Values
====================
The pseudo-column ``ROWID`` uniquely identifies a row within a table. In
cx_Oracle, ROWID values are represented as strings. The example below shows
fetching a row and then updating that row by binding its rowid:
.. code-block:: python
# fetch the row
cursor.execute("""
select rowid, manager_id
from departments
where department_id = :dept_id""", dept_id=280)
rowid, manager_id = cursor.fetchone()
# update the row by binding ROWID
cursor.execute("""
update departments set
manager_id = :manager_id
where rowid = :rid""", manager_id=205, rid=rowid)
DML RETURNING Bind Variables
============================
When a RETURNING clause is used with a DML statement like UPDATE,
INSERT, or DELETE, the values are returned to the application through
the use of OUT bind variables. Consider the following example:
.. code-block:: python
# The RETURNING INTO bind variable is a string
dept_name = cursor.var(str)
cursor.execute("""
update departments set
location_id = :loc_id
where department_id = :dept_id
returning department_name into :dept_name""",
loc_id=1700, dept_id=50, dept_name=dept_name)
print(dept_name.getvalue()) # will print ['Shipping']
In the above example, since the WHERE clause matches only one row, the output
contains a single item in the list. If the WHERE clause matched multiple rows,
however, the output would contain as many items as there were rows that were
updated.
No duplicate binds are allowed in a DML statement with a RETURNING clause, and
no duplication is allowed between bind variables in the DML section and the
RETURNING section of the statement.
LOB Bind Variables
==================
Database CLOBs, NCLOBS, BLOBs and BFILEs can be bound with types
:attr:`cx_Oracle.DB_TYPE_CLOB`, :attr:`cx_Oracle.DB_TYPE_NCLOB`,
:attr:`cx_Oracle.DB_TYPE_BLOB` and :attr:`cx_Oracle.DB_TYPE_BFILE`
respectively. LOBs fetched from the database or created with
:meth:`Connection.createlob()` can also be bound.
LOBs may represent Oracle Database persistent LOBs (those stored in tables) or
temporary LOBs (such as those created with :meth:`Connection.createlob()` or
returned by some SQL and PL/SQL operations).
LOBs can be used as IN, OUT or IN/OUT bind variables.
See :ref:`lobdata` for examples.
.. _refcur:
REF CURSOR Bind Variables
=========================
cx_Oracle provides the ability to bind and define PL/SQL REF cursors. As an
example, consider the PL/SQL procedure:
.. code-block:: sql
CREATE OR REPLACE PROCEDURE find_employees (
p_query IN VARCHAR2,
p_results OUT SYS_REFCURSOR
) AS
BEGIN
OPEN p_results FOR
SELECT employee_id, first_name, last_name
FROM employees
WHERE UPPER(first_name || ' ' || last_name || ' ' || email)
LIKE '%' || UPPER(p_query) || '%';
END;
/
A newly opened cursor can be bound to the REF CURSOR parameter, as shown in the
following Python code. After the PL/SQL procedure has been called with
:meth:`Cursor.callproc()`, the cursor can then be fetched just like any other
cursor which had executed a SQL query:
.. code-block:: python
ref_cursor = connection.cursor()
cursor.callproc("find_employees", ['Smith', ref_cursor])
for row in ref_cursor:
print(row)
With Oracle's `sample HR schema
<https://github.com/oracle/db-sample-schemas>`__ there are two
employees with the last name 'Smith' so the result is::
(159, 'Lindsey', 'Smith')
(171, 'William', 'Smith')
To return a REF CURSOR from a PL/SQL function, use ``cx_Oracle.DB_TYPE_CURSOR`` for the
return type of :meth:`Cursor.callfunc()`:
.. code-block:: python
ref_cursor = cursor.callfunc('example_package.f_get_cursor',
cx_Oracle.DB_TYPE_CURSOR)
for row in ref_cursor:
print(row)
See :ref:`tuning` for information on how to tune REF CURSORS.
Binding PL/SQL Collections
==========================
PL/SQL Collections like Associative Arrays can be bound as IN, OUT, and IN/OUT
variables. When binding IN values, an array can be passed directly as shown in
this example, which sums up the lengths of all of the strings in the provided
array. First the PL/SQL package definition:
.. code-block:: sql
create or replace package mypkg as
type udt_StringList is table of varchar2(100) index by binary_integer;
function DemoCollectionIn (
a_Values udt_StringList
) return number;
end;
/
create or replace package body mypkg as
function DemoCollectionIn (
a_Values udt_StringList
) return number is
t_ReturnValue number := 0;
begin
for i in 1..a_Values.count loop
t_ReturnValue := t_ReturnValue + length(a_Values(i));
end loop;
return t_ReturnValue;
end;
end;
/
Then the Python code:
.. code-block:: python
values = ["String One", "String Two", "String Three"]
return_val = cursor.callfunc("mypkg.DemoCollectionIn", int, [values])
print(return_val) # will print 32
In order get values back from the database, a bind variable must be created
using :meth:`Cursor.arrayvar()`. The first parameter to this method is a Python
type that cx_Oracle knows how to handle or one of the cx_Oracle :ref:`types`.
The second parameter is the maximum number of elements that the array can hold
or an array providing the value (and indirectly the maximum length). The final
parameter is optional and only used for strings and bytes. It identifies the
maximum length of the strings and bytes that can be stored in the array. If not
specified, the length defaults to 4000 bytes.
Consider the following PL/SQL package:
.. code-block:: sql
create or replace package mypkg as
type udt_StringList is table of varchar2(100) index by binary_integer;
procedure DemoCollectionOut (
a_NumElements number,
a_Values out nocopy udt_StringList
);
procedure DemoCollectionInOut (
a_Values in out nocopy udt_StringList
);
end;
/
create or replace package body mypkg as
procedure DemoCollectionOut (
a_NumElements number,
a_Values out nocopy udt_StringList
) is
begin
for i in 1..a_NumElements loop
a_Values(i) := 'Demo out element #' || to_char(i);
end loop;
end;
procedure DemoCollectionInOut (
a_Values in out nocopy udt_StringList
) is
begin
for i in 1..a_Values.count loop
a_Values(i) := 'Converted element #' || to_char(i) ||
' originally had length ' || length(a_Values(i));
end loop;
end;
end;
/
The Python code to process an OUT collection would look as follows. Note the
call to :meth:`Cursor.arrayvar()` which creates space for an array of strings.
Each string would permit up to 100 bytes and only 10 strings would be
permitted. If the PL/SQL block exceeds the maximum number of strings allowed
the error ``ORA-06513: PL/SQL: index for PL/SQL table out of range for host
language array`` would be raised.
.. code-block:: python
out_array_var = cursor.arrayvar(str, 10, 100)
cursor.callproc("mypkg.DemoCollectionOut", [5, out_array_var])
for val in out_array_var.getvalue():
print(val)
This would produce the following output::
Demo out element #1
Demo out element #2
Demo out element #3
Demo out element #4
Demo out element #5
The Python code to process an IN/OUT collections is similar. Note the different
call to :meth:`Cursor.arrayvar()` which creates space for an array of strings,
but uses an array to determine both the maximum length of the array and its
initial value.
.. code-block:: python
in_values = ["String One", "String Two", "String Three", "String Four"]
in_out_array_var = cursor.arrayvar(str, in_values)
cursor.callproc("mypkg.DemoCollectionInOut", [in_out_array_var])
for val in in_out_array_var.getvalue():
print(val)
This would produce the following output::
Converted element #1 originally had length 10
Converted element #2 originally had length 10
Converted element #3 originally had length 12
Converted element #4 originally had length 11
If an array variable needs to have an initial value but also needs to allow
for more elements than the initial value contains, the following code can be
used instead:
.. code-block:: python
in_out_array_var = cursor.arrayvar(str, 10, 100)
in_out_array_var.setvalue(0, ["String One", "String Two"])
All of the collections that have been bound in preceding examples have used
contiguous array elements. If an associative array with sparse array elements
is needed, a different approach is required. Consider the following PL/SQL
code:
.. code-block:: sql
create or replace package mypkg as
type udt_StringList is table of varchar2(100) index by binary_integer;
procedure DemoCollectionOut (
a_Value out nocopy udt_StringList
);
end;
/
create or replace package body mypkg as
procedure DemoCollectionOut (
a_Value out nocopy udt_StringList
) is
begin
a_Value(-1048576) := 'First element';
a_Value(-576) := 'Second element';
a_Value(284) := 'Third element';
a_Value(8388608) := 'Fourth element';
end;
end;
/
Note that the collection element indices are separated by large values. The
technique used above would fail with the exception ``ORA-06513: PL/SQL: index
for PL/SQL table out of range for host language array``. The code required to
process this collection looks like this instead:
.. code-block:: python
collection_type = connection.gettype("MYPKG.UDT_STRINGLIST")
collection = collection_type.newobject()
cursor.callproc("mypkg.DemoCollectionOut", [collection])
print(collection.aslist())
This produces the output::
['First element', 'Second element', 'Third element', 'Fourth element']
Note the use of :meth:`Object.aslist()` which returns the collection element
values in index order as a simple Python list. The indices themselves are lost
in this approach. Starting from cx_Oracle 7.0, the associative array can be
turned into a Python dictionary using :meth:`Object.asdict()`. If that value
was printed in the previous example instead, the output would be::
{-1048576: 'First element', -576: 'Second element', 284: 'Third element', 8388608: 'Fourth element'}
If the elements need to be traversed in index order, the methods
:meth:`Object.first()` and :meth:`Object.next()` can be used. The method
:meth:`Object.getelement()` can be used to acquire the element at a particular
index. This is shown in the following code:
.. code-block:: python
ix = collection.first()
while ix is not None:
print(ix, "->", collection.getelement(ix))
ix = collection.next(ix)
This produces the output::
-1048576 -> First element
-576 -> Second element
284 -> Third element
8388608 -> Fourth element
Similarly, the elements can be traversed in reverse index order using the
methods :meth:`Object.last()` and :meth:`Object.prev()` as shown in the
following code:
.. code-block:: python
ix = collection.last()
while ix is not None:
print(ix, "->", collection.getelement(ix))
ix = collection.prev(ix)
This produces the output::
8388608 -> Fourth element
284 -> Third element
-576 -> Second element
-1048576 -> First element
Binding PL/SQL Records
======================
PL/SQL record type objects can also be bound for IN, OUT and IN/OUT
bind variables. For example:
.. code-block:: sql
create or replace package mypkg as
type udt_DemoRecord is record (
NumberValue number,
StringValue varchar2(30),
DateValue date,
BooleanValue boolean
);
procedure DemoRecordsInOut (
a_Value in out nocopy udt_DemoRecord
);
end;
/
create or replace package body mypkg as
procedure DemoRecordsInOut (
a_Value in out nocopy udt_DemoRecord
) is
begin
a_Value.NumberValue := a_Value.NumberValue * 2;
a_Value.StringValue := a_Value.StringValue || ' (Modified)';
a_Value.DateValue := a_Value.DateValue + 5;
a_Value.BooleanValue := not a_Value.BooleanValue;
end;
end;
/
Then this Python code can be used to call the stored procedure which will
update the record:
.. code-block:: python
# create and populate a record
record_type = connection.gettype("MYPKG.UDT_DEMORECORD")
record = record_type.newobject()
record.NUMBERVALUE = 6
record.STRINGVALUE = "Test String"
record.DATEVALUE = datetime.datetime(2016, 5, 28)
record.BOOLEANVALUE = False
# show the original values
print("NUMBERVALUE ->", record.NUMBERVALUE)
print("STRINGVALUE ->", record.STRINGVALUE)
print("DATEVALUE ->", record.DATEVALUE)
print("BOOLEANVALUE ->", record.BOOLEANVALUE)
print()
# call the stored procedure which will modify the record
cursor.callproc("mypkg.DemoRecordsInOut", [record])
# show the modified values
print("NUMBERVALUE ->", record.NUMBERVALUE)
print("STRINGVALUE ->", record.STRINGVALUE)
print("DATEVALUE ->", record.DATEVALUE)
print("BOOLEANVALUE ->", record.BOOLEANVALUE)
This will produce the following output::
NUMBERVALUE -> 6
STRINGVALUE -> Test String
DATEVALUE -> 2016-05-28 00:00:00
BOOLEANVALUE -> False
NUMBERVALUE -> 12
STRINGVALUE -> Test String (Modified)
DATEVALUE -> 2016-06-02 00:00:00
BOOLEANVALUE -> True
Note that when manipulating records, all of the attributes must be set by the
Python program in order to avoid an Oracle Client bug which will result in
unexpected values or the Python application segfaulting.
.. _spatial:
Binding Spatial Datatypes
=========================
Oracle Spatial datatypes objects can be represented by Python objects and their
attribute values can be read and updated. The objects can further be bound and
committed to database. This is similar to the examples above.
An example of fetching SDO_GEOMETRY is in :ref:`Oracle Database Objects and
Collections <fetchobjects>`.
.. _inputtypehandlers:
Changing Bind Data Types using an Input Type Handler
====================================================
Input Type Handlers allow applications to change how data is bound to
statements, or even to enable new types to be bound directly.
An input type handler is enabled by setting the attribute
:attr:`Cursor.inputtypehandler` or :attr:`Connection.inputtypehandler`.
Input type handlers can be combined with variable converters to bind Python
objects seamlessly:
.. code-block:: python
# A standard Python object
class Building:
def __init__(self, build_id, description, num_floors, date_built):
self.building_id = build_id
self.description = description
self.num_floors = num_floors
self.date_built = date_built
building = Building(1, "Skyscraper 1", 5, datetime.date(2001, 5, 24))
# Get Python representation of the Oracle user defined type UDT_BUILDING
obj_type = con.gettype("UDT_BUILDING")
# convert a Python Building object to the Oracle user defined type
# UDT_BUILDING
def building_in_converter(value):
obj = obj_type.newobject()
obj.BUILDINGID = value.building_id
obj.DESCRIPTION = value.description
obj.NUMFLOORS = value.num_floors
obj.DATEBUILT = value.date_built
return obj
def input_type_handler(cursor, value, num_elements):
if isinstance(value, Building):
return cursor.var(obj_type, arraysize=num_elements,
inconverter=building_in_converter)
# With the input type handler, the bound Python object is converted
# to the required Oracle object before being inserted
cur.inputtypehandler = input_type_handler
cur.execute("insert into myTable values (:1, :2)", (1, building))
Binding Multiple Values to a SQL WHERE IN Clause
================================================
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
cursor.execute("""
select employee_id, first_name, last_name
from employees
where last_name in (:name1, :name2)""",
name1="Smith", name2="Taylor")
for row in cursor:
print(row)
This gives the output::
(159, 'Lindsey', 'Smith')
(171, 'William', 'Smith')
(176, 'Jonathon', 'Taylor')
(180, 'Winston', 'Taylor')
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
cursor.execute("""
select employee_id, first_name, last_name
from employees
where last_name in (:name1, :name2, :name3, :name4, :name5)""",
name1="Smith", name2="Taylor", name3=None, name4=None, name5=None)
for row in cursor:
print(row)
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.
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
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(bind_names))
cursor.execute(sql, bind_values)
for row in cursor:
print(row)
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 values> )
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
==============================
Column and table names cannot be bound in SQL queries. You can concatenate
text to build up a SQL statement, but make sure you use an Allow List or other
means to validate the data in order to avoid SQL Injection security issues:
.. code-block:: python
table_allow_list = ['employees', 'departments']
table_name = get_table_name() # get the table name from user input
if table_name.lower() not in table_allow_list:
raise Exception('Invalid table name')
sql = f'select * from {table_name}'
Binding column names can be done either by using the above method or by using a
CASE statement. The example below demonstrates binding a column name in an
ORDER BY clause:
.. code-block:: python
sql = """
SELECT * FROM departments
ORDER BY
CASE :bindvar
WHEN 'department_id' THEN DEPARTMENT_ID
ELSE MANAGER_ID
END"""
col_name = get_column_name() # Obtain a column name from the user
cursor.execute(sql, [col_name])
Depending on the name provided by the user, the query results will be
ordered either by the column ``DEPARTMENT_ID`` or the column ``MANAGER_ID``.

File diff suppressed because it is too large Load Diff

View File

@ -1,165 +0,0 @@
.. _cqn:
***********************************
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
notifications when a table changes, such as when rows have been updated,
regardless of the user or the application that made the change. This can be
useful in many circumstances, such as near real-time monitoring, auditing
applications, or for such purposes as mid-tier cache invalidation. A cache
might hold some values that depend on data in a table. If the data in the
table changes, the cached values must then be updated with the new information.
CQN notification behavior is widely configurable. Choices include specifying
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 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.
Requirements
============
Before using CQN, users must have appropriate permissions:
.. code-block:: sql
GRANT CHANGE NOTIFICATION TO <user-name>;
To use CQN, connections must have ``events`` mode set to ``True``, for
example:
.. code-block:: python
connection = cx_Oracle.connect(user=user, password=password,
dsn="dbhost.example.com/orclpdb1",
events=True)
The default CQN connection mode means the database must be able to connect back
to the application using cx_Oracle in order to receive notification events.
Alternatively, when using Oracle Database and Oracle client libraries 19.4, or
later, subscriptions can set the optional ``client_initiated`` parameter to
``True``, see ``Connection.subscribe()`` below.
The default CQN connection mode typically means that the machine running
cx_Oracle needs a fixed IP address. Note :meth:`Connection.subscribe()` does
not verify that this reverse connection is possible. If there is any problem
sending a notification, then the callback method will not be invoked.
Configuration options can include an IP address and port on which cx_Oracle will
listen for notifications; otherwise, the database chooses values.
Creating a Subscription
=======================
Subscriptions allow Python to receives notifications for events that take place
in the database that match the given parameters.
For example, a basic CQN subscription might be created like:
.. code-block:: python
connection.subscribe(callback=my_callback)
See :meth:`Connection.subscribe()` for details on all of the parameters.
See :ref:`cqn-operation-codes` for the types of operations that are supported.
See :ref:`subscr-qos` for the quality of service values that are supported.
See :ref:`subscr-namespaces` and :ref:`subscr-protocols` for the namespaces and
protocols that are supported.
See :ref:`subscrobj` for more details on the subscription object that is
created.
When using Oracle Database and Oracle client libraries 19.4, or later, the
optional subscription parameter ``client_initiated`` can be set:
.. code-block:: python
connection.subscribe(callback=my_callback, client_initiated=True)
This enables CQN "client initiated" connections which internally use the same
approach as normal cx_Oracle connections to the database, and do not require the
database to be able to connect back to the application. Since client initiated
connections do not need special network configuration they have ease-of-use and
security advantages.
Registering Queries
===================
Once a subscription has been created, one or more queries must be registered by
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 'REGIONS' table data
changes is:
.. code-block:: python
def cqn_callback(message):
print("Notification:")
for query in message.queries:
for tab in query.tables:
print("Table:", tab.name)
print("Operation:", tab.operation)
for row in tab.rows:
if row.operation & cx_Oracle.OPCODE_INSERT:
print("INSERT of rowid:", row.rowid)
if row.operation & cx_Oracle.OPCODE_DELETE:
print("DELETE of rowid:", row.rowid)
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")
Running the above script, shows the initial output as::
Hit enter to stop CQN demo
Use SQL*Plus or another tool to commit a change to the table:
.. code-block:: sql
insert into regions values(120, 'L');
commit;
When the commit is executed, a notification will be received by the callback
which should print something like the following::
Hit enter to stop CQN demo
Notification:
Table: HR.REGIONS
Operation: 2
INSERT of rowid: AAA7EsAAHAAAFS/AAA
See `GitHub Samples
<https://github.com/oracle/python-cx_Oracle/blob/main/samples/cqn.py>`__
for a runnable CQN example.

View File

@ -1,47 +0,0 @@
.. _exception:
******************
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
:ref:`API manual <exchandling>` for more details on the information available
when an exception is raised.
Applications can catch exceptions as needed. For example, when trying to add a
customer that already exists in the database, the following could be used
to catch the exception:
.. code-block:: python
try:
cursor.execute("insert into customer values (101, 'Customer A')")
except cx_Oracle.IntegrityError:
print("Customer ID already exists")
else:
print("Customer added")
If information about the exception needs to be processed instead, the following
code can be used:
.. code-block:: python
try:
cursor.execute("insert into customer values (101, 'Customer A')")
except cx_Oracle.IntegrityError as e:
error_obj, = e.args
print("Customer ID already exists")
print("Error Code:", error_obj.code)
print("Error Message:", error_obj.message)
else:
print("Customer added")

View File

@ -1,164 +0,0 @@
.. _globalization:
********************************
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
client and server character sets, then it may be corrupted or queries may fail
with :ref:`"codec can't decode byte" <codecerror>`.
cx_Oracle uses Oracles National Language Support (NLS) to assist in
globalizing applications. As well as character set support, there are many
other features that will be useful in applications. See the
`Database Globalization Support Guide
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=NLSPG>`__.
Setting the Client Character Set
================================
In cx_Oracle 8 the default encoding used for all character data changed to
"UTF-8". This universal encoding is suitable for most applications. If you
have a special need, you can pass the ``encoding`` and ``nencoding`` parameters
to the :meth:`cx_Oracle.connect` and :meth:`cx_Oracle.SessionPool` methods to
specify different Oracle Client character sets. For example:
.. code-block:: python
import cx_Oracle
connection = cx_Oracle.connect(dsn=connect_string, encoding="US-ASCII",
nencoding="UTF-8")
.. note::
In a future release of cx_Oracle, only UTF-8 will be supported.
The ``encoding`` parameter affects character data such as VARCHAR2 and CLOB
columns. The ``nencoding`` parameter affects "National Character" data such as
NVARCHAR2 and NCLOB. If you are not using national character types, then you
can omit ``nencoding``. Both the ``encoding`` and ``nencoding`` parameters are
expected to be one of the `Python standard encodings
<https://docs.python.org/3/library/codecs.html#standard-encodings>`__ such as
``UTF-8``. Do not accidentally use ``UTF8``, which Oracle uses to specify the
older Unicode 3.0 Universal character set, ``CESU-8``. Note that Oracle does
not recognize all of the encodings that Python recognizes. You can see which
encodings are usable in cx_Oracle by issuing this query:
.. code-block:: sql
select distinct utl_i18n.map_charset(value)
from v$nls_valid_values
where parameter = 'CHARACTERSET'
and utl_i18n.map_charset(value) is not null
order by 1
.. note::
From cx_Oracle 8, it is no longer possible to change the character set
using the ``NLS_LANG`` environment variable. The character set component
of that variable is ignored. The language and territory components of
``NLS_LANG`` are still respected by the Oracle Client libraries.
Character Set Example
---------------------
The script below tries to display data containing a Euro symbol from the
database.
.. code-block:: python
connection = cx_Oracle.connect(user=user, password=password,
dsn="dbhost.example.com/orclpdb1",
encoding="US-ASCII")
cursor = connection.cursor()
for row in cursor.execute("select nvarchar2_column from nchar_test"):
print(row)
Because the '€' symbol is not supported by the ``US-ASCII`` character set, all
'€' characters are replaced by '¿' in the cx_Oracle output::
('¿',)
When the ``encoding`` parameter is removed (or set to "UTF-8") during
connection:
.. code-block:: python
connection = cx_Oracle.connect(user=user, password=password,
dsn="dbhost.example.com/orclpdb1")
Then the output displays the Euro symbol as desired::
('€',)
.. _findingcharset:
Finding the Database and Client Character Set
---------------------------------------------
To find the database character set, execute the query:
.. code-block:: sql
SELECT value AS db_charset
FROM nls_database_parameters
WHERE parameter = 'NLS_CHARACTERSET';
To find the database 'national character set' used for NCHAR and related types,
execute the query:
.. code-block:: sql
SELECT value AS db_ncharset
FROM nls_database_parameters
WHERE parameter = 'NLS_NCHAR_CHARACTERSET';
To find the current "client" character set used by cx_Oracle, execute the
query:
.. code-block:: sql
SELECT DISTINCT client_charset AS client_charset
FROM v$session_connect_info
WHERE sid = SYS_CONTEXT('USERENV', 'SID');
If these character sets do not match, characters transferred over Oracle Net
will be mapped from one character set to another. This may impact performance
and may result in invalid data.
Setting the Oracle Client Locale
================================
You can use the ``NLS_LANG`` environment variable to set the language and
territory used by the Oracle Client libraries. For example, on Linux you could
set::
export NLS_LANG=JAPANESE_JAPAN
The language ("JAPANESE" in this example) specifies conventions such as the
language used for Oracle Database messages, sorting, day names, and month
names. The territory ("JAPAN") specifies conventions such as the default date,
monetary, and numeric formats. If the language is not specified, then the value
defaults to AMERICAN. If the territory is not specified, then the value is
derived from the language value. See `Choosing a Locale with the NLS_LANG
Environment Variable
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-86A29834-AE29-4BA5-8A78-E19C168B690A>`__
If the ``NLS_LANG`` environment variable is set in the application with
``os.environ['NLS_LANG']``, it must be set before any connection pool is
created, or before any standalone connections are created.
Other Oracle globalization variables, such as ``NLS_DATE_FORMAT`` can also be
set to change the behavior of cx_Oracle, see `Setting NLS Parameters
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&
id=GUID-6475CA50-6476-4559-AD87-35D431276B20>`__.

View File

@ -1,223 +0,0 @@
.. _highavailability:
********************************
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:
* Reduce application downtime
* Eliminate compromises between high availability and performance
* Increase operational productivity
.. _harecommend:
General HA Recommendations
--------------------------
General recommendations for creating highly available cx_Oracle programs are:
* Tune operating system and Oracle Network parameters to avoid long TCP timeouts, to prevent firewalls killing connections, and to avoid connection storms.
* Implement application error handling and recovery.
* Use the most recent version of the Oracle client libraries. New versions have improvements to features such as dead database server detection, and make it easier to set connection options.
* Use the most recent version of Oracle Database. New database versions introduce, and enhance, features such as Application Continuity (AC) and Transparent Application Continuity (TAC).
* Utilize Oracle Database technologies such as `RAC <https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=RACAD>`__ or standby databases.
* Configure database services to emit :ref:`FAN <fan>` events.
* Use a :ref:`connection pool <connpool>`, because pools can handle database events and take proactive and corrective action for draining, run time load balancing, and fail over. Set the minimum and maximum pool sizes to the same values to avoid connection storms. Remove resource manager or user profiles that prematurely close sessions.
* Test all scenarios thoroughly.
.. _hanetwork:
Network Configuration
---------------------
The operating system TCP and :ref:`Oracle Net configuration <optnetfiles>`
should be configured for performance and availability.
Options such as `SQLNET.OUTBOUND_CONNECT_TIMEOUT
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-0857C817-675F-4CF0-BFBB-C3667F119176>`__,
`SQLNET.RECV_TIMEOUT
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-4A19D81A-75F0-448E-B271-24E5187B5909>`__
and `SQLNET.SEND_TIMEOUT
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-48547756-9C0B-4D14-BE85-E7ADDD1A3A66>`__
can be explored.
`Oracle Net Services
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=NETRF>`__ options may
also be useful for high availability and performance tuning. For example the
database's `listener.ora` file can have `RATE_LIMIT
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-F302BF91-64F2-4CE8-A3C7-9FDB5BA6DCF8>`__
and `QUEUESIZE
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-FF87387C-1779-4CC3-932A-79BB01391C28>`__
parameters that can help handle connection storms.
With Oracle Client 19c, `EXPIRE_TIME
<https://docs.oracle.com/en/database/oracle/oracle-database/20/netrf/local-naming-parameters-in-tns-ora-file.html#GUID-6140611A-83FC-4C9C-B31F-A41FC2A5B12D>`__
can be used in :ref:`tnsnames.ora <optnetfiles>` connect descriptors to prevent
firewalls from terminating idle connections and to adjust keepalive timeouts.
The general recommendation for ``EXPIRE_TIME`` is to use a value that is
slightly less than half of the termination period. In older versions of Oracle
Client, a ``tnsnames.ora`` connect descriptor option `ENABLE=BROKEN
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-7A18022A-E40D-4880-B3CE-7EE9864756CA>`_
can be used instead of ``EXPIRE_TIME``. These settings can also aid detection
of a terminated remote database server.
When cx_Oracle uses :ref:`Oracle Client libraries 19c <archfig>`, then the
:ref:`Easy Connect Plus syntax <easyconnect>` syntax enables some options to be
used without needing a ``sqlnet.ora`` file. For example, if your firewall times
out every 4 minutes, and you cannot alter the firewall settings, then you may
decide to use ``EXPIRE_TIME`` in your connect string to send a probe every 2
minutes to the database to keep connections 'alive'::
connection = cx_Oracle.connect("hr", userpwd, "dbhost.example.com/orclpdb1?expire_time=2")
.. _fan:
Fast Application Notification (FAN)
-----------------------------------
Users of `Oracle Database FAN
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-F3FBE48B-468B-4393-8B0C-D5C8E0E4374D>`__
must connect to a FAN-enabled database service. The application should have
``events`` set to True when connecting. This value can also be changed via
:ref:`Oracle Client Configuration <optclientfiles>`.
FAN support is useful for planned and unplanned outages. It provides immediate
notification to cx_Oracle following outages related to the database, computers,
and networks. Without FAN, cx_Oracle can hang until a TCP timeout occurs and an
error is returned, which might be several minutes.
FAN allows cx_Oracle to provide high availability features without the
application being aware of an outage. Unused, idle connections in a
:ref:`connection pool <connpool>` will be automatically cleaned up. A future
:meth:`SessionPool.acquire()` call will establish a fresh connection to a
surviving database instance without the application being aware of any service
disruption.
To handle errors that affect active connections, you can add application logic
to re-connect (this will connect to a surviving database instance) and replay
application logic without having to return an error to the application user.
FAN benefits users of Oracle Database's clustering technology `Oracle RAC
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-D04AA2A7-2E68-4C5C-BD6E-36C62427B98E>`__
because connections to surviving database instances can be immediately made.
Users of Oracle's Data Guard with a broker will get FAN events generated when
the standby database goes online. Standalone databases will send FAN events
when the database restarts.
For a more information on FAN see the `white paper on Fast Application
Notification
<https://www.oracle.com/technetwork/database/options/clustering/applicationcontinuity/learnmore/fastapplicationnotification12c-2538999.pdf>`__.
.. _appcont:
Application Continuity (AC)
---------------------------
Oracle Application Continuity and Transparent Application Continuity are Oracle
Database technologies that record application interaction with the database and,
in the event of a database instance outage, attempt to replay the interaction on
a surviving database instance. If successful, users will be unaware of any
database issue. AC and TAC are best suited for OLTP applications.
When AC or TAC are configured on the database service, they are transparently
available to cx_Oracle applications.
You must thoroughly test your application because not all lower level calls in
the cx_Oracle implementation can be replayed.
See `OCI and Application Continuity
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-A8DD9422-2F82-42A9-9555-134296416E8F>`__
for more information.
.. _tg:
Transaction Guard
-----------------
cx_Oracle supports `Transaction Guard
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&
id=GUID-A675AF7B-6FF0-460D-A6E6-C15E7C328C8F>`__ which enables Python
application to verify the success or failure of the last transaction in the
event of an unplanned outage. This feature is available when both client and
database are 12.1 or higher.
Using Transaction Guard helps to:
* Preserve the commit outcome
* Ensure a known outcome for every transaction
See `Oracle Database Development Guide
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&
id=GUID-6C5880E5-C45F-4858-A069-A28BB25FD1DB>`__ for more information about
using Transaction Guard.
When an error occurs during commit, the Python application can acquire the
logical transaction id (``ltxid``) from the connection and then call a
procedure to determine the outcome of the commit for this logical transaction
id.
Follow the steps below to use the Transaction Guard feature in Python:
1. Grant execute privileges to the database users who will be checking the
outcome of the commit. Login as SYSDBA and run the following command:
.. code-block:: sql
GRANT EXECUTE ON DBMS_APP_CONT TO <username>;
2. Create a new service by executing the following PL/SQL block as SYSDBA.
Replace the ``<service-name>``, ``<network-name>`` and
``<retention-value>`` values with suitable values. It is important that the
``COMMIT_OUTCOME`` parameter be set to true for Transaction Guard to
function properly.
.. code-block:: sql
DECLARE
t_Params dbms_service.svc_parameter_array;
BEGIN
t_Params('COMMIT_OUTCOME') := 'true';
t_Params('RETENTION_TIMEOUT') := <retention-value>;
DBMS_SERVICE.CREATE_SERVICE('<service-name>', '<network-name>', t_Params);
END;
/
3. Start the service by executing the following PL/SQL block as SYSDBA:
.. code-block:: sql
BEGIN
DBMS_SERVICE.start_service('<service-name>');
END;
/
Ensure the service is running by examining the output of the following query:
.. code-block:: sql
SELECT name, network_name FROM V$ACTIVE_SERVICES ORDER BY 1;
**Python Application code requirements to use Transaction Guard**
In the Python application code:
* Use the connection attribute :attr:`~Connection.ltxid` to determine the
logical transaction id.
* Call the ``DBMS_APP_CONT.GET_LTXID_OUTCOME`` PL/SQL procedure with the
logical transaction id acquired from the connection attribute. This returns
a boolean value indicating if the last transaction was committed and whether
the last call was completed successfully or not.
See the `Transaction Guard Sample
<https://github.com/oracle/python-cx_Oracle/blob/main/
samples/transaction_guard.py>`__ for further details.

View File

@ -1,415 +0,0 @@
.. _initialization:
**************************
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
product: it is how the Oracle Client and Oracle Database communicate.
.. figure:: /images/cx_Oracle_arch.png
cx_Oracle Architecture
.. _libinit:
Locating the Oracle Client Libraries
====================================
cx_Oracle dynamically loads the Oracle Client libraries using a search
heuristic. Only the first set of libraries found are loaded. The libraries
can be in an installation of Oracle Instant Client, in a full Oracle Client
installation, or in an Oracle Database installation (if Python is running on
the same machine as the database). The versions of Oracle Client and Oracle
Database do not have to be the same. For certified configurations see Oracle
Support's `Doc ID 207303.1
<https://support.oracle.com/epmos/faces/DocumentDisplay?id=207303.1>`__.
.. _wininit:
* On Windows, cx_Oracle looks for the Oracle Client libraries as follows:
- In the ``lib_dir`` directory specified in a call to
:meth:`cx_Oracle.init_oracle_client()`. This directory should contain
the libraries from an unzipped Instant Client 'Basic' or 'Basic Light'
package. If you pass the library directory from a full client or
database installation, such as Oracle Database "XE" Express Edition, then
you will need to have previously set your environment to use that
software installation, otherwise files such as message files will not be
located. On Windows when the path contains backslashes, use a 'raw'
string like ``lib_dir=r"C:\instantclient_19_6"``. If the Oracle Client
libraries cannot be loaded from ``lib_dir``, then an exception is raised.
- If ``lib_dir`` was not specified, then Oracle Client libraries are looked
for in the directory where the cx_Oracle binary module is installed.
This directory should contain the libraries from an unzipped Instant
Client 'Basic' or 'Basic Light' package. If the libraries are not found,
no exception is raised and the search continues, see next bullet point.
- In the directories on the system library search path, e.g. the ``PATH``
environment variable. If the Oracle Client libraries cannot be loaded,
then an exception is raised.
.. _macinit:
* On macOS, cx_Oracle looks for the Oracle Client libraries as follows:
- In the ``lib_dir`` directory specified in a call to
:meth:`cx_Oracle.init_oracle_client()`. This directory should contain
the libraries from an unzipped Instant Client 'Basic' or 'Basic Light'
package. If the Oracle Client libraries cannot be loaded from
``lib_dir``, then an exception is raised.
- If ``lib_dir`` was not specified, then Oracle Client libraries are looked
for in the directory where the cx_Oracle binary module is. This directory
should contain the libraries from an unzipped Instant Client 'Basic' or
'Basic Light' package. For example if
``/Users/your_username/Library/Python/3.8/lib/python/site-packages``
contains ``cx_Oracle.cpython-38-darwin.so``, then you could run ``ln -s
~/instantclient_19_3/libclntsh.dylib
~/Library/Python/3.8/lib/python/site-packages``. If the libraries are not
found, no exception is raised and the search continues, see next bullet
point.
- In the directories on the system library search path, e.g. ``~/lib/`` and
``/usr/local/lib``, or in ``$DYLD_LIBRARY_PATH``. These paths will vary
with macOS version and Python version. Any value in
``DYLD_LIBRARY_PATH`` will not propagate to a sub-shell. If the Oracle
Client libraries cannot be loaded, then an exception is raised.
.. _linuxinit:
* On Linux and related platforms, cx_Oracle looks for the Oracle Client
libraries as follows:
- In the ``lib_dir`` directory specified in a call to
:meth:`cx_Oracle.init_oracle_client()`.
**Note this is only useful to force immediate loading of the libraries
because on Linux and related platforms the libraries must always be in the
system library search path**.
The ``lib_dir`` directory should contain the libraries from an unzipped
Instant Client 'Basic' or 'Basic Light' package. If you pass the library
directory from a full client or database installation, such as Oracle
Database "XE" Express Edition then you will need to have previously set
the ``ORACLE_HOME`` environment variable. If the Oracle Client libraries
cannot be loaded from ``lib_dir``, then an exception is raised.
- If ``lib_dir`` was not specified, then Oracle Client libraries are looked
for in the operating system library search path, such as configured with
``ldconfig`` or set in the environment variable ``LD_LIBRARY_PATH``. On
some UNIX platforms an OS specific equivalent, such as ``LIBPATH`` or
``SHLIB_PATH`` is used instead of ``LD_LIBRARY_PATH``. If the libraries
are not found, no exception is raised and the search continues, see next
bullet point.
- In ``$ORACLE_HOME/lib``. Note the environment variable ``ORACLE_HOME``
should only ever be set when you have a full database installation or
full client installation. It should not be set if you are using Oracle
Instant Client. The ``ORACLE_HOME`` variable, and other necessary
variables, should be set before starting Python. See :ref:`envset`. If
the Oracle Client libraries cannot be loaded, then an exception is
raised.
If you call :meth:`cx_Oracle.init_oracle_client()` with a ``lib_dir``
parameter, the Oracle Client libraries are loaded immediately from that
directory. If you call :meth:`cx_Oracle.init_oracle_client()` but do *not* set
the ``lib_dir`` parameter, the Oracle Client libraries are loaded immediately
using the search heuristic above. If you do not call
:meth:`cx_Oracle.init_oracle_client()`, then the libraries are loaded using the
search heuristic when the first cx_Oracle function that depends on the
libraries is called, for example when a connection pool is created. If there
is a problem loading the libraries, then an exception is raised.
Make sure the Python process has directory and file access permissions for the
Oracle Client libraries. On Linux ensure a ``libclntsh.so`` file exists. On
macOS ensure a ``libclntsh.dylib`` file exists. cx_Oracle will not directly
load ``libclntsh.*.XX.1`` files in ``lib_dir`` or from the directory where the
cx_Oracle binary module is. Note other libraries used by ``libclntsh*`` are
also required.
To trace the loading of Oracle Client libraries, the environment variable
``DPI_DEBUG_LEVEL`` can be set to 64 before starting Python. For example, on
Linux, you might use::
$ export DPI_DEBUG_LEVEL=64
$ python myapp.py 2> log.txt
.. _usinginitoracleclient:
Using cx_Oracle.init_oracle_client() to set the Oracle Client directory
-----------------------------------------------------------------------
Applications can call the function :meth:`cx_Oracle.init_oracle_client()` to
specify the directory containing Oracle Instant Client libraries. The Oracle
Client Libraries are loaded when ``init_oracle_client()`` is called. For
example, if the Oracle Instant Client Libraries are in
``C:\oracle\instantclient_19_9`` on Windows or
``$HOME/Downloads/instantclient_19_8`` on macOS, then you can use:
.. code-block:: python
import cx_Oracle
import sys
import os
try:
if sys.platform.startswith("darwin"):
lib_dir = os.path.join(os.environ.get("HOME"), "Downloads",
"instantclient_19_8")
cx_Oracle.init_oracle_client(lib_dir=lib_dir)
elif sys.platform.startswith("win32"):
lib_dir=r"C:\oracle\instantclient_19_9"
cx_Oracle.init_oracle_client(lib_dir=lib_dir)
except Exception as err:
print("Whoops!")
print(err)
sys.exit(1)
Note the use of a 'raw' string ``r"..."`` on Windows so that backslashes are
treated as directory separators.
The :meth:`~cx_Oracle.init_oracle_client()` function can only be called once.
**Note if you set** ``lib_dir`` **on Linux and related platforms, you must still
have configured the system library search path to include that directory before
starting Python**.
On any operating system, if you set ``lib_dir`` to the library directory of a
full database or full client installation, you will need to have previously set
the Oracle environment, for example by setting the ``ORACLE_HOME`` environment
variable. Otherwise you will get errors like ORA-1804. You should set this,
and other Oracle environment variables, before starting Python, as
shown in :ref:`envset`.
.. _optnetfiles:
Optional Oracle Net Configuration Files
=======================================
Optional Oracle Net configuration files are read when cx_Oracle is loaded.
These files affect connections and applications. The common files are:
* ``tnsnames.ora``: A configuration file that defines databases addresses
for establishing connections. See :ref:`Net Service Name for Connection
Strings <netservice>`.
* ``sqlnet.ora``: A profile configuration file that may contain information
on features such as connection failover, network encryption, logging, and
tracing. See `Oracle Net Services Reference
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&
id=GUID-19423B71-3F6C-430F-84CC-18145CC2A818>`__ for more information.
The files should be in a directory accessible to Python, not on the database
server host.
For example, if the file ``/etc/my-oracle-config/tnsnames.ora`` should be used,
you can call :meth:`cx_Oracle.init_oracle_client()`:
.. code-block:: python
import cx_Oracle
import sys
try:
cx_Oracle.init_oracle_client(config_dir="/etc/my-oracle-config")
except Exception as err:
print("Whoops!")
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>`__
to ``/etc/my-oracle-config``.
If :meth:`~cx_Oracle.init_oracle_client()` is not called, or it is called but
``config_dir`` is not specified, then default directories searched for the
configuration files. They include:
* ``$TNS_ADMIN``
* ``/opt/oracle/instantclient_19_6/network/admin`` if Instant Client is in ``/opt/oracle/instantclient_19_6``.
* ``/usr/lib/oracle/19.6/client64/lib/network/admin`` if Oracle 19.6 Instant Client RPMs are used on Linux.
* ``$ORACLE_HOME/network/admin`` if cx_Oracle is using libraries from a database installation.
A wallet configuration file ``cwallet.sso`` for secure connection can be
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:`autonomousdb`.
Note the :ref:`easyconnect` can set many common configuration options without
needing ``tnsnames.ora`` or ``sqlnet.ora`` files.
The section :ref:`Network Configuration <hanetwork>` has some discussion about
Oracle Net configuration.
.. _optclientfiles:
Optional Oracle Client Configuration Files
==========================================
When cx_Oracle uses Oracle Client libraries version 12.1, or later, an optional
client parameter file called ``oraaccess.xml`` can be used to configure some
behviors of those libraries, such as statement caching and prefetching. This can
be useful if the application cannot be altered. The file is read from the same
directory as the `Optional Oracle Net Configuration Files`_.
A sample ``oraaccess.xml`` file that sets the Oracle client prefetch value to
1000 rows. This value affects every SQL query in the application::
<?xml version="1.0"?>
<oraaccess xmlns="http://xmlns.oracle.com/oci/oraaccess"
xmlns:oci="http://xmlns.oracle.com/oci/oraaccess"
schemaLocation="http://xmlns.oracle.com/oci/oraaccess
http://xmlns.oracle.com/oci/oraaccess.xsd">
<default_parameters>
<prefetch>
<rows>1000</rows>
</prefetch>
</default_parameters>
</oraaccess>
Prefetching is the number of additional rows the underlying Oracle client
library fetches whenever cx_Oracle requests query data from the database.
Prefetching is a tuning option to maximize data transfer efficiency and minimize
:ref:`round-trips <roundtrips>` to the database. The prefetch size does not
affect when, or how many, rows are returned by cx_Oracle to the application.
The cache management is transparently handled by the Oracle client libraries.
Note, standard cx_Oracle fetch tuning is via :attr:`Cursor.arraysize`, but
changing the prefetch value can be useful in some cases such as when modifying
the application is not feasible.
The `oraaccess.xml` file has other uses including:
- Changing the value of Fast Application Notification :ref:`FAN <fan>` events which affects notifications and Runtime Load Balancing (RLB).
- Configuring `Client Result Caching <https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-D2FA7B29-301B-4AB8-8294-2B1B015899F9>`__ parameters
- Turning on `Client Statement Cache Auto-tuning <https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-6E21AA56-5BBE-422A-802C-197CAC8AAEA4>`__
Refer to the documentation on `oraaccess.xml
<https://www.oracle.com/pls/topic/lookup?
ctx=dblatest&id=GUID-9D12F489-EC02-46BE-8CD4-5AECED0E2BA2>`__
for more details.
.. _envset:
Oracle Environment Variables
============================
Some common environment variables that influence cx_Oracle are shown below. The
variables that may be needed depend on how Python is installed, how you connect
to the database, and what optional settings are desired. It is recommended to
set Oracle variables in the environment before invoking Python, however they may
also be set in the application with ``os.putenv()`` before the first connection
is established. System environment variables like ``LD_LIBRARY_PATH`` must be
set before Python starts.
.. list-table:: Common Oracle environment variables
:header-rows: 1
:widths: 1 2
:align: left
* - Oracle Environment Variables
- Purpose
* - LD_LIBRARY_PATH
- The library search path for platforms like Linux should include the
Oracle libraries, for example ``$ORACLE_HOME/lib`` or
``/opt/instantclient_19_3``. This variable is not needed if the
libraries are located by an alternative method, such as with
``ldconfig``. On other UNIX platforms you may need to set an OS
specific equivalent, such as ``LIBPATH`` or ``SHLIB_PATH``.
* - PATH
- The library search path for Windows should include the location where
``OCI.DLL`` is found. Not needed if you set ``lib_dir`` in a call to
:meth:`cx_Oracle.init_oracle_client()`
* - TNS_ADMIN
- The directory of optional Oracle Client configuration files such as
``tnsnames.ora`` and ``sqlnet.ora``. Not needed if the configuration
files are in a default location or if ``config_dir`` was not used in
:meth:`cx_Oracle.init_oracle_client()`. See :ref:`optnetfiles`.
* - ORA_SDTZ
- The default session time zone.
* - ORA_TZFILE
- The name of the Oracle time zone file to use. See below.
* - ORACLE_HOME
- The directory containing the Oracle Database software. The directory
and various configuration files must be readable by the Python process.
This variable should not be set if you are using Oracle Instant Client.
* - NLS_LANG
- Determines the 'national language support' globalization options for
cx_Oracle. Note: from cx_Oracle 8, the character set component is
ignored and only the language and territory components of ``NLS_LANG``
are used. The character set can instead be specified during connection
or connection pool creation. See :ref:`globalization`.
* - NLS_DATE_FORMAT, NLS_TIMESTAMP_FORMAT
- Often set in Python applications to force a consistent date format
independent of the locale. The variables are ignored if the environment
variable ``NLS_LANG`` is not set.
Oracle Instant Client includes a small and big time zone file, for example
``timezone_32.dat`` and ``timezlrg_32.dat``. The versions can be shown by running
the utility ``genezi -v`` located in the Instant Client directory. The small file
contains only the most commonly used time zones. By default the larger
``timezlrg_n.dat`` file is used. If you want to use the smaller ``timezone_n.dat``
file, then set the ``ORA_TZFILE`` environment variable to the name of the file
without any directory prefix, for example ``export ORA_TZFILE=timezone_32.dat``.
With Oracle Instant Client 12.2 or later, you can also use an external time zone
file. Create a subdirectory ``oracore/zoneinfo`` under the Instant Client
directory, and move the file into it. Then set ``ORA_TZFILE`` to the file name,
without any directory prefix. The ``genezi -v`` utility will show the time zone
file in use.
If cx_Oracle is using Oracle Client libraries from an Oracle Database or full
Oracle Client software installation, and you want to use a non-default time zone
file, then set ``ORA_TZFILE`` to the file name with a directory prefix, for
example: ``export ORA_TZFILE=/opt/oracle/myconfig/timezone_31.dat``.
The Oracle Database documentation contains more information about time zone
files, see `Choosing a Time Zone File
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-805AB986-DE12-4FEA-AF56-5AABCD2132DF>`__.
.. _otherinit:
Other cx_Oracle Initialization
==============================
The :meth:`cx_Oracle.init_oracle_client()` function allows ``driver_name`` and
``error_url`` parameters to be set. These are useful for applications whose
end-users are not aware cx_Oracle is being used. An example of setting the
parameters is:
.. code-block:: python
import cx_Oracle
import sys
try:
cx_Oracle.init_oracle_client(driver_name="My Great App : 3.1.4",
error_url="https://example.com/MyInstallInstructions.html")
except Exception as err:
print("Whoops!")
print(err)
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
in Oracle Database views like ``V$SESSION_CONNECT_INFO``. If this parameter is
not specified, then the value "cx_Oracle : *version*" is used.
The ``error_url`` string will be shown in the exception raised if
``init_oracle_client()`` cannot load the Oracle Client libraries. This allows
applications that use cx_Oracle to refer users to application-specific
installation instructions. If this value is not specified, then the
:ref:`installation` URL is used.

View File

@ -1,936 +0,0 @@
.. _installation:
************************
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.3 with Python and Oracle Database you need:
- 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
<https://www.oracle.com/database/technologies/instant-client.html>`__, from a
full Oracle Client installation, or from those included in Oracle Database if
Python is on the same machine as the database. Oracle client libraries
versions 21, 19, 18, 12, and 11.2 are supported where available on Linux,
Windows and macOS (Intel x86). Users have also reported success with other
platforms. Use the latest client possible: Oracle's standard client-server
version interoperability allows connection to both older and newer databases.
- An Oracle Database, either local or remote.
The cx_Oracle module loads Oracle Client libraries which communicate
over Oracle Net to an existing database. Oracle Net is not a separate
product: it is how the Oracle Client and Oracle Database communicate.
.. figure:: /images/cx_Oracle_arch.png
cx_Oracle Architecture
Quick Start cx_Oracle Installation
==================================
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.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
<https://pypi.org/project/cx-Oracle/>`__ with:
.. code-block:: shell
python -m pip install cx_Oracle --upgrade
Note: if a binary wheel package is not available for your platform,
the source package will be downloaded instead. This will be compiled
and the resulting binary installed.
The ``--user`` option may be useful, if you don't have permission to write to
system directories:
.. code-block:: shell
python -m pip install cx_Oracle --upgrade --user
If you are behind a proxy, add a proxy server to the command, for example add
``--proxy=http://proxy.example.com:80``
- Add Oracle 21, 19, 18, 12 or 11.2 client libraries to your operating system
library search path such as ``PATH`` on Windows or ``LD_LIBRARY_PATH`` on
Linux. On macOS use :meth:`~cx_Oracle.init_oracle_client()` in your
application to pass the Oracle Client directory name, see
:ref:`usinginitoracleclient`. This is also usable on Windows.
To get the libraries:
- If your database is on a remote computer, then download and unzip the client
libraries from the free `Oracle Instant Client
<https://www.oracle.com/database/technologies/instant-client.html>`__
"Basic" or "Basic Light" package for your operating system
architecture.
Instant Client on Windows requires an appropriate Microsoft Windows
Redistributables, see :ref:`wininstall`. On Linux, the ``libaio``
(sometimes called ``libaio1``) package is needed. Oracle Linux 8 also
needs the ``libnsl`` package.
- Alternatively, use the client libraries already available in a
locally installed database such as the free `Oracle Database
Express Edition ("XE")
<https://www.oracle.com/database/technologies/appdev/xe.html>`__
release.
Version 21 client libraries can connect to Oracle Database 12.1 or greater.
Version 19, 18 and 12.2 client libraries can connect to Oracle Database 11.2
or greater. Version 12.1 client libraries can connect to Oracle Database 10.2
or greater. Version 11.2 client libraries can connect to Oracle Database 9.2
or greater.
- Create a script like the one below:
.. code-block:: python
# myscript.py
import cx_Oracle
# Connect as user "hr" with password "welcome" to the "orclpdb1" service running on this computer.
connection = cx_Oracle.connect(user="hr", password="welcome",
dsn="localhost/orclpdb1")
cursor = connection.cursor()
cursor.execute("""
SELECT first_name, last_name
FROM employees
WHERE department_id = :did AND employee_id > :eid""",
did = 50,
eid = 190)
for fname, lname in cursor:
print("Values:", fname, lname)
Locate your Oracle Database username and password, and the database
connection string. The connection string is commonly of the format
``hostname/servicename``, using the hostname where the database is
running, and using the service name of the Oracle Database instance.
Substitute your username, password and connection string in the
code. Run the Python script, for example::
python myscript.py
You can learn how to use cx_Oracle from the :ref:`API documentation <module>`
and `samples
<https://github.com/oracle/python-cx_Oracle/blob/main/samples>`__.
If you run into installation trouble, check out the section on `Troubleshooting`_.
Oracle Client and Oracle Database Interoperability
==================================================
cx_Oracle requires Oracle Client libraries. The libraries provide the
necessary network connectivity to access an Oracle Database instance.
They also provide basic and advanced connection management and data
features to cx_Oracle.
The simplest way to get Oracle Client libraries is to install the free
`Oracle Instant Client
<https://www.oracle.com/database/technologies/instant-client.html>`__
"Basic" or "Basic Light" package. The libraries are also available in
any Oracle Database installation or full Oracle Client installation.
Oracle's standard client-server network interoperability allows
connections between different versions of Oracle Client libraries and
Oracle Database. For certified configurations see Oracle Support's
`Doc ID 207303.1
<https://support.oracle.com/epmos/faces/DocumentDisplay?id=207303.1>`__.
In summary, Oracle Client 21 can connect to Oracle Database 12.1 or greater.
Oracle Client 19, 18 and 12.2 can connect to Oracle Database 11.2 or
greater. Oracle Client 12.1 can connect to Oracle Database 10.2 or
greater. Oracle Client 11.2 can connect to Oracle Database 9.2 or greater. The
technical restrictions on creating connections may be more flexible. For
example Oracle Client 12.2 can successfully connect to Oracle Database 10.2.
cx_Oracle uses the shared library loading mechanism available on each
supported platform to load the Oracle Client libraries at runtime. It
does not need to be rebuilt for different versions of the libraries.
Since a single cx_Oracle binary can use different client versions and
also access multiple database versions, it is important your
application is tested in your intended release environments. Newer
Oracle clients support new features, such as the `oraaccess.xml
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-9D12F489-EC02-46BE-8CD4-5AECED0E2BA2>`__ external configuration
file available with 12.1 or later clients, session pool improvements,
improved high availability features, call timeouts, and `other enhancements
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-D60519C3-406F-4588-8DA1-D475D5A3E1F6>`__.
The cx_Oracle function :func:`~cx_Oracle.clientversion()` can be used to
determine which Oracle Client version is in use. The attribute
:attr:`Connection.version` can be used to determine which Oracle Database
version a connection is accessing. These can then be used to adjust application
behavior accordingly. Attempts to use Oracle features that are not supported by
a particular client/server library combination will result in runtime errors.
Installing cx_Oracle on Linux
=============================
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
-----------------
The generic way to install cx_Oracle on Linux is to use Python's `Pip
<https://pip.readthedocs.io/en/latest/installing/>`__ package to
install cx_Oracle from `PyPI
<https://pypi.org/project/cx-Oracle/>`__:
.. code-block:: shell
python -m pip install cx_Oracle --upgrade
The ``--user`` option may be useful, if you don't have permission to write to
system directories:
.. code-block:: shell
python -m pip install cx_Oracle --upgrade --user
If you are behind a proxy, add a proxy server to the command, for example add
``--proxy=http://proxy.example.com:80``
This will download and install a pre-compiled binary `if one is
available <https://pypi.org/project/cx-Oracle/>`__ for your
architecture. If a pre-compiled binary is not available, the source
will be downloaded, compiled, and the resulting binary installed.
Compiling cx_Oracle requires the ``Python.h`` header file. If you are
using the default ``python`` package, this file is in the ``python-devel``
package or equivalent.
Install Oracle Client
---------------------
Using cx_Oracle requires Oracle Client libraries to be installed.
These provide the necessary network connectivity allowing cx_Oracle
to access an Oracle Database instance.
- If your database is on a remote computer, then download the free `Oracle
Instant Client
<https://www.oracle.com/database/technologies/instant-client.html>`__
"Basic" or "Basic Light" package for your operating system
architecture. Use the RPM or ZIP packages, based on your
preferences.
- Alternatively, use the client libraries already available in a
locally installed database such as the free `Oracle Database
Express Edition ("XE")
<https://www.oracle.com/database/technologies/appdev/xe.html>`__
release.
Oracle Instant Client Zip Files
+++++++++++++++++++++++++++++++
To use cx_Oracle with Oracle Instant Client zip files:
1. Download an Oracle 21, 19, 18, 12, or 11.2 "Basic" or "Basic Light" zip file
matching your Python 64-bit or 32-bit architecture:
- `x86-64 64-bit <https://www.oracle.com/database/technologies/instant-client/linux-x86-64-downloads.html>`__
- `x86 32-bit <https://www.oracle.com/database/technologies/instant-client/linux-x86-32-downloads.html>`__
- `ARM (aarch64) 64-bit <https://www.oracle.com/database/technologies/instant-client/linux-arm-aarch64-downloads.html>`__
The latest version is recommended. Oracle Instant Client 21 will connect to
Oracle Database 12.1 or later.
2. Unzip the package into a single directory that is accessible to your
application. For example:
.. code-block:: shell
mkdir -p /opt/oracle
cd /opt/oracle
unzip instantclient-basic-linux.x64-21.1.0.0.0.zip
3. Install the ``libaio`` package with sudo or as the root user. For example::
sudo yum install libaio
On some Linux distributions this package is called ``libaio1`` instead.
On recent Linux versions such as Oracle Linux 8, you may also need to
install the ``libnsl`` package when using Oracle Instant Client 19.
4. If there is no other Oracle software on the machine that will be
impacted, permanently add Instant Client to the runtime link
path. For example, with sudo or as the root user:
.. code-block:: shell
sudo sh -c "echo /opt/oracle/instantclient_21_1 > /etc/ld.so.conf.d/oracle-instantclient.conf"
sudo ldconfig
Alternatively, set the environment variable ``LD_LIBRARY_PATH`` to
the appropriate directory for the Instant Client version. For
example::
export LD_LIBRARY_PATH=/opt/oracle/instantclient_21_1:$LD_LIBRARY_PATH
5. If you use optional Oracle configuration files such as ``tnsnames.ora``,
``sqlnet.ora`` or ``oraaccess.xml`` with Instant Client, then put the files
in an accessible directory, for example in
``/opt/oracle/your_config_dir``. Then use:
.. code-block:: python
import cx_Oracle
cx_Oracle.init_oracle_client(config_dir="/home/your_username/oracle/your_config_dir")
Or set the environment variable ``TNS_ADMIN`` to that directory name.
Alternatively, put the files in the ``network/admin`` subdirectory of Instant
Client, for example in ``/opt/oracle/instantclient_21_1/network/admin``.
This is the default Oracle configuration directory for executables linked
with this Instant Client.
Oracle Instant Client RPMs
++++++++++++++++++++++++++
To use cx_Oracle with Oracle Instant Client RPMs:
1. Download an Oracle 21,19, 18, 12, or 11.2 "Basic" or "Basic Light" RPM
matching your Python architecture:
- `x86-64 64-bit <https://www.oracle.com/database/technologies/instant-client/linux-x86-64-downloads.html>`__
- `x86 32-bit <https://www.oracle.com/database/technologies/instant-client/linux-x86-32-downloads.html>`__
- `ARM (aarch64) 64-bit <https://www.oracle.com/database/technologies/instant-client/linux-arm-aarch64-downloads.html>`__
Oracle's yum server has convenient repositories:
- `Instant Client 21 RPMs for Oracle Linux x86-64 8 <https://yum.oracle.com/repo/OracleLinux/OL8/oracle/instantclient21/x86_64/index.html>`__, `Older Instant Client RPMs for Oracle Linux x86-64 8 <https://yum.oracle.com/repo/OracleLinux/OL8/oracle/instantclient/x86_64/index.html>`__
- `Instant Client 21 RPMs for Oracle Linux x86-64 7 <https://yum.oracle.com/repo/OracleLinux/OL7/oracle/instantclient21/x86_64/index.html>`__, `Older Instant Client RPMs for Oracle Linux x86-64 7 <https://yum.oracle.com/repo/OracleLinux/OL7/oracle/instantclient/x86_64/index.html>`__
- `Instant Client RPMs for Oracle Linux x86-64 6 <https://yum.oracle.com/repo/OracleLinux/OL6/oracle/instantclient/x86_64/index.html>`__
- `Instant Client RPMs for Oracle Linux ARM (aarch64) 8 <https://yum.oracle.com/repo/OracleLinux/OL8/oracle/instantclient/aarch64/index.html>`__
- `Instant Client RPMs for Oracle Linux ARM (aarch64) 7 <https://yum.oracle.com/repo/OracleLinux/OL7/oracle/instantclient/aarch64/index.html>`__
The latest version is recommended. Oracle Instant Client 21 will connect to
Oracle Database 12.1 or later.
2. Install the downloaded RPM with sudo or as the root user. For example:
.. code-block:: shell
sudo yum install oracle-instantclient-basic-21.1.0.0.0-1.x86_64.rpm
Yum will automatically install required dependencies, such as ``libaio``.
On recent Linux versions, such as Oracle Linux 8, you may need to manually
install the ``libnsl`` package when using Oracle Instant Client 19.
3. For Instant Client 19, or later, the system library search path is
automatically configured during installation.
For older versions, if there is no other Oracle software on the machine that will be
impacted, permanently add Instant Client to the runtime link
path. For example, with sudo or as the root user:
.. code-block:: shell
sudo sh -c "echo /usr/lib/oracle/18.5/client64/lib > /etc/ld.so.conf.d/oracle-instantclient.conf"
sudo ldconfig
Alternatively, for version 18 and earlier, every shell running
Python will need to have the environment variable
``LD_LIBRARY_PATH`` set to the appropriate directory for the
Instant Client version. For example::
export LD_LIBRARY_PATH=/usr/lib/oracle/18.5/client64/lib:$LD_LIBRARY_PATH
4. If you use optional Oracle configuration files such as ``tnsnames.ora``,
``sqlnet.ora`` or ``oraaccess.xml`` with Instant Client, then put the files
in an accessible directory, for example in
``/opt/oracle/your_config_dir``. Then use:
.. code-block:: python
import cx_Oracle
cx_Oracle.init_oracle_client(config_dir="/opt/oracle/your_config_dir")
Or set the environment variable ``TNS_ADMIN`` to that directory name.
Alternatively, put the files in the ``network/admin`` subdirectory of Instant
Client, for example in ``/usr/lib/oracle/21/client64/lib/network/admin``.
This is the default Oracle configuration directory for executables linked
with this Instant Client.
Local Database or Full Oracle Client
++++++++++++++++++++++++++++++++++++
cx_Oracle applications can use Oracle Client 21, 19, 18, 12, or 11.2 libraries
from a local Oracle Database or full Oracle Client installation.
The libraries must be either 32-bit or 64-bit, matching your
Python architecture.
1. Set required Oracle environment variables by running the Oracle environment
script. For example:
.. code-block:: shell
source /usr/local/bin/oraenv
For Oracle Database Express Edition ("XE") 11.2, run:
.. code-block:: shell
source /u01/app/oracle/product/11.2.0/xe/bin/oracle_env.sh
2. Optional Oracle configuration files such as ``tnsnames.ora``,
``sqlnet.ora`` or ``oraaccess.xml`` can be placed in
``$ORACLE_HOME/network/admin``.
Alternatively, Oracle configuration files can be put in another,
accessible directory. Then set the environment variable
``TNS_ADMIN`` to that directory name.
.. _oraclelinux:
Installing cx_Oracle RPMs on Oracle Linux
=========================================
Python and cx_Oracle RPM packages are available from the `Oracle Linux yum server
<https://yum.oracle.com/>`__. Various versions of Python are easily installed.
Using the yum server makes it easy to keep up to date.
Installation instructions are at `Oracle Linux for Python
Developers <https://yum.oracle.com/oracle-linux-python.html>`__.
.. _wininstall:
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
-----------------
Use Python's `Pip <https://pip.readthedocs.io/en/latest/installing/>`__
package to install cx_Oracle from `PyPI
<https://pypi.org/project/cx-Oracle/>`__::
python -m pip install cx_Oracle --upgrade
If you are behind a proxy, specify your proxy server:
.. code-block:: shell
python -m pip install cx_Oracle --proxy=http://proxy.example.com:80 --upgrade
This will download and install a pre-compiled binary `if one is
available <https://pypi.org/project/cx-Oracle/>`__ for your
architecture. If a pre-compiled binary is not available, the source
will be downloaded, compiled, and the resulting binary installed.
Install Oracle Client
---------------------
Using cx_Oracle requires Oracle Client libraries to be installed.
These provide the necessary network connectivity allowing cx_Oracle
to access an Oracle Database instance. Oracle Client versions 19, 18,
12 and 11.2 are supported.
- If your database is on a remote computer, then download the free `Oracle
Instant Client
<https://www.oracle.com/database/technologies/instant-client.html>`__
"Basic" or "Basic Light" package for your operating system
architecture.
- Alternatively, use the client libraries already available in a
locally installed database such as the free `Oracle Database
Express Edition ("XE")
<https://www.oracle.com/database/technologies/appdev/xe.html>`__
release.
Oracle Instant Client Zip Files
+++++++++++++++++++++++++++++++
To use cx_Oracle with Oracle Instant Client zip files:
1. Download an Oracle 19, 18, 12, or 11.2 "Basic" or "Basic Light" zip
file: `64-bit
<https://www.oracle.com/database/technologies/instant-client/winx64-64-downloads.html>`__
or `32-bit
<https://www.oracle.com/database/technologies/instant-client/microsoft-windows-32-downloads.html>`__, matching your
Python architecture.
The latest version is recommended. Oracle Instant Client 19 will
connect to Oracle Database 11.2 or later.
Windows 7 users: Note that Oracle 19c is not supported on Windows 7.
2. Unzip the package into a directory that is accessible to your
application. For example unzip
``instantclient-basic-windows.x64-19.11.0.0.0dbru.zip`` to
``C:\oracle\instantclient_19_11``.
3. Oracle Instant Client libraries require a Visual Studio redistributable with
a 64-bit or 32-bit architecture to match Instant Client's architecture.
Each Instant Client version requires a different redistributable version:
- 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
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1. There are several alternative ways to tell cx_Oracle where your Oracle Client
libraries are, see :ref:`initialization`.
* With Oracle Instant Client you can use :meth:`~cx_Oracle.init_oracle_client()`
in your application, for example:
.. code-block:: python
import cx_Oracle
cx_Oracle.init_oracle_client(lib_dir=r"C:\oracle\instantclient_19_11")
Note a 'raw' string is used because backslashes occur in the path.
* Alternatively, add the Oracle Instant Client directory to the ``PATH``
environment variable. The directory must occur in ``PATH`` before any
other Oracle directories. Restart any open command prompt windows.
* Another way to set ``PATH`` is to use a batch file that sets it before Python
is executed, for example::
REM mypy.bat
SET PATH=C:\oracle\instantclient_19_9;%PATH%
python %*
Invoke this batch file every time you want to run Python.
2. If you use optional Oracle configuration files such as ``tnsnames.ora``,
``sqlnet.ora`` or ``oraaccess.xml`` with Instant Client, then put the files
in an accessible directory, for example in
``C:\oracle\your_config_dir``. Then use:
.. code-block:: python
import cx_Oracle
cx_Oracle.init_oracle_client(lib_dir=r"C:\oracle\instantclient_19_11",
config_dir=r"C:\oracle\your_config_dir")
Or set the environment variable ``TNS_ADMIN`` to that directory name.
Alternatively, put the files in a ``network\admin`` subdirectory of
Instant Client, for example in
``C:\oracle\instantclient_19_11\network\admin``. This is the default
Oracle configuration directory for executables linked with this
Instant Client.
Local Database or Full Oracle Client
++++++++++++++++++++++++++++++++++++
cx_Oracle applications can use Oracle Client 19, 18, 12, or 11.2
libraries libraries from a local Oracle Database or full Oracle
Client.
The Oracle libraries must be either 32-bit or 64-bit, matching your
Python architecture.
1. Set the environment variable ``PATH`` to include the path that contains
``OCI.DLL``, if it is not already set.
Restart any open command prompt windows.
2. Optional Oracle configuration files such as ``tnsnames.ora``,
``sqlnet.ora`` or ``oraaccess.xml`` can be placed in the
``network\admin`` subdirectory of the Oracle Database software
installation.
Alternatively, pass ``config_dir`` to :meth:`~cx_Oracle.init_oracle_client()`
as shown in the previous section, or set ``TNS_ADMIN`` to the directory name.
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
--------------
Make sure you are not using the bundled Python. This has restricted
entitlements and will fail to load Oracle client libraries. Instead use
`Homebrew <https://brew.sh>`__ or `Python.org
<https://www.python.org/downloads>`__.
A C compiler is needed, for example Xcode and its command line tools.
Install cx_Oracle
-----------------
Use Python's `Pip <https://pip.readthedocs.io/en/latest/installing/>`__
package to install cx_Oracle from `PyPI
<https://pypi.org/project/cx-Oracle/>`__:
.. code-block:: shell
export ARCHFLAGS="-arch x86_64"
python -m pip install cx_Oracle --upgrade
The ``--user`` option may be useful, if you don't have permission to write to
system directories:
.. code-block:: shell
python -m pip install cx_Oracle --upgrade --user
If you are behind a proxy, add a proxy server to the command, for example add
``--proxy=http://proxy.example.com:80``
The source will be downloaded, compiled, and the resulting binary
installed.
Install Oracle Instant Client
-----------------------------
Oracle Instant Client provides the network connectivity for accessing Oracle
Database.
Manual Installation
+++++++++++++++++++
* Download the **Basic** 64-bit DMG from `Oracle
<https://www.oracle.com/database/technologies/instant-client/macos-intel-x86-downloads.html>`__.
* In Finder, double click on the DMG to mount it.
* Open a terminal window and run the install script in the mounted package, for example:
.. code-block:: shell
/Volumes/instantclient-basic-macos.x64-19.8.0.0.0dbru/install_ic.sh
This copies the contents to ``$HOME/Downloads/instantclient_19_8``.
Applications may not have access to the ``Downloads`` directory, so you
should move Instant Client somewhere convenient.
* In Finder, eject the mounted Instant Client package.
If you have multiple Instant Client DMG packages mounted, you only need to run
``install_ic.sh`` once. It will copy all mounted Instant Client DMG packages at
the same time.
Scripted Installation
+++++++++++++++++++++
Instant Client installation can alternatively be scripted, for example:
.. code-block:: shell
cd $HOME/Downloads
curl -O https://download.oracle.com/otn_software/mac/instantclient/198000/instantclient-basic-macos.x64-19.8.0.0.0dbru.dmg
hdiutil mount instantclient-basic-macos.x64-19.8.0.0.0dbru.dmg
/Volumes/instantclient-basic-macos.x64-19.8.0.0.0dbru/install_ic.sh
hdiutil unmount /Volumes/instantclient-basic-macos.x64-19.8.0.0.0dbru
The Instant Client directory will be ``$HOME/Downloads/instantclient_19_8``.
Applications may not have access to the ``Downloads`` directory, so you should
move Instant Client somewhere convenient.
Configure Oracle Instant Client
-------------------------------
1. Call :meth:`~cx_Oracle.init_oracle_client()` once in your application:
.. code-block:: python
import cx_Oracle
cx_Oracle.init_oracle_client(lib_dir="/Users/your_username/Downloads/instantclient_19_8")
2. If you use optional Oracle configuration files such as ``tnsnames.ora``,
``sqlnet.ora`` or ``oraaccess.xml`` with Oracle Instant Client, then put the
files in an accessible directory, for example in
``/Users/your_username/oracle/your_config_dir``. Then use:
.. code-block:: python
import cx_Oracle
cx_Oracle.init_oracle_client(lib_dir="/Users/your_username/Downloads/instantclient_19_8",
config_dir="/Users/your_username/oracle/your_config_dir")
Or set the environment variable ``TNS_ADMIN`` to that directory name.
Alternatively, put the files in the ``network/admin`` subdirectory of Oracle
Instant Client, for example in
``/Users/your_username/Downloads/instantclient_19_8/network/admin``. This is the
default Oracle configuration directory for executables linked with this
Instant Client.
Linux Containers
================
Sample Dockerfiles are on `GitHub
<https://github.com/oracle/docker-images/tree/main/OracleLinuxDevelopers>`__.
Pre-built images for Python and cx_Oracle are in the `GitHub Container Registry
<https://github.com/orgs/oracle/packages>`__. These are easily used. For
example, to pull an Oracle Linux 8 image with Python 3.6 and cx_Oracle,
execute::
docker pull ghcr.io/oracle/oraclelinux7-python:3.6-oracledb
Installing cx_Oracle without Internet Access
============================================
To install cx_Oracle on a computer that is not connected to the
internet, download the appropriate cx_Oracle file from `PyPI
<https://pypi.org/project/cx-Oracle/#files>`__. Transfer this file to
the offline computer and install it with::
python -m pip install "<file_name>"
Then follow the general cx_Oracle platform installation instructions
to install Oracle client libraries.
Install Using GitHub
====================
In order to install using the source on GitHub, use the following commands::
git clone https://github.com/oracle/python-cx_Oracle.git cx_Oracle
cd cx_Oracle
git submodule init
git submodule update
python setup.py install
Note that if you download a source zip file directly from GitHub then
you will also need to download an `ODPI-C
<https://github.com/oracle/odpi>`__ source zip file and extract it
inside the directory called "odpi".
cx_Oracle source code is also available from opensource.oracle.com. This can
be cloned with::
git clone git://opensource.oracle.com/git/oracle/python-cx_Oracle.git cx_Oracle
cd cx_Oracle
git submodule init
git submodule update
Install Using Source from PyPI
==============================
The source package can be downloaded manually from
`PyPI <https://pypi.org/project/cx-Oracle/>`__ and extracted, after
which the following commands should be run::
python setup.py build
python setup.py install
Upgrading from Older Versions
=============================
Review the :ref:`release notes <releasenotes>` and :ref:`Deprecations
<deprecations>` for changes. Modify affected code.
If you are upgrading from cx_Oracle 7 note these changes:
- The default character set used by cx_Oracle 8 is now "UTF-8". Also, the
character set component of the ``NLS_LANG`` environment variable is
ignored. If you need to change the character set, then pass ``encoding``
and ``nendcoding`` parameters when creating a connection or connection
pool. See :ref:`globalization`.
- Any uses of ``type(var)`` need to be changed to ``var.type``.
- Any uses of ``var.type is not None`` need to be changed to
``isinstance(var.type, cx_Oracle.ObjectType)``
- Note that ``TIMESTAMP WITH TIME ZONE`` columns will now be reported as
:data:`cx_Oracle.DB_TYPE_TIMESTAMP_TZ` instead of
:data:`cx_Oracle.TIMESTAMP` in :data:`Cursor.description`.
- Note that ``TIMESTAMP WITH LOCAL TIME ZONE`` columns will now be reported
as :data:`cx_Oracle.DB_TYPE_TIMESTAMP_LTZ` instead of
:data:`cx_Oracle.TIMESTAMP` in :data:`Cursor.description`.
- Note that ``BINARY_FLOAT`` columns will now be reported as
:data:`cx_Oracle.DB_TYPE_BINARY_FLOAT` instead of
:data:`cx_Oracle.NATIVE_DOUBLE` in :data:`Cursor.description`.
If you are upgrading from cx_Oracle 5 note these installation changes:
- When using Oracle Instant Client, you should not set ``ORACLE_HOME``.
- On Linux, cx_Oracle 6 and higher no longer uses Instant Client RPMs
automatically. You must set ``LD_LIBRARY_PATH`` or use ``ldconfig`` to
locate the Oracle client library.
- PyPI no longer allows Windows installers or Linux RPMs to be
hosted. Use the supplied cx_Oracle Wheels instead, or use RPMs
from Oracle, see :ref:`oraclelinux`.
.. _python2:
Installing cx_Oracle in Python 2
================================
cx_Oracle 7.3 was the last version with support for Python 2.
If you install cx_Oracle in Python 2 using the commands provided above, then
cx_Oracle 7.3 will be installed. This is equivalent to using a command like::
python -m pip install cx_Oracle==7.3 --upgrade --user
For other installation options such as installing through a proxy, see
instructions above. Make sure the Oracle Client libraries are in the system
library search path because cx_Oracle 7 does not support the
:meth:`cx_Oracle.init_oracle_client()` method and does not support loading the
Oracle Client libraries from the directory containing the cx_Oracle module
binary.
Installing cx_Oracle 5.3
========================
If you require cx_Oracle 5.3, download a Windows installer from `PyPI
<https://pypi.org/project/cx-Oracle/>`__ or use ``python -m pip
install cx-oracle==5.3`` to install from source.
Very old versions of cx_Oracle can be found in the files section at
`SourceForce <https://sourceforge.net/projects/cx-oracle/files/>`__.
Troubleshooting
===============
If installation fails:
- Use option ``-v`` with pip. Review your output and logs. Try to install
using a different method. **Google anything that looks like an error.**
Try some potential solutions.
- Was there a network connection error? Do you need to set the
environment variables ``http_proxy`` and/or ``https_proxy``? Or
try ``pip install --proxy=http://proxy.example.com:80 cx_Oracle
--upgrade``?
- If upgrading gave no errors but the old version is still
installed, try ``pip install cx_Oracle --upgrade
--force-reinstall``
- If you do not have access to modify your system version of
Python, can you use ``pip install cx_Oracle --upgrade --user``
or venv?
- Do you get the error "``No module named pip``"? The pip module is builtin
to Python but is sometimes removed by the OS. Use the venv module
(builtin to Python 3.x) or virtualenv module instead.
- Do you get the error "``fatal error: dpi.h: No such file or directory``"
when building from source code? Ensure that your source installation has
a subdirectory called "odpi" containing files. If missing, review the
section on `Install Using GitHub`_.
If using cx_Oracle fails:
- Do you get the error "``DPI-1047: Oracle Client library cannot be
loaded``"?
- On Windows and macOS, try using :meth:`~cx_Oracle.init_oracle_client()`.
See :ref:`usinginitoracleclient`.
- Check that Python and your Oracle Client libraries are both 64-bit, or
both 32-bit. The ``DPI-1047`` message will tell you whether the 64-bit
or 32-bit Oracle Client is needed for your Python.
- Set the environment variable ``DPI_DEBUG_LEVEL`` to 64 and restart
cx_Oracle. The trace messages will show how and where cx_Oracle is
looking for the Oracle Client libraries.
At a Windows command prompt, this could be done with::
set DPI_DEBUG_LEVEL=64
On Linux and macOS, you might use::
export DPI_DEBUG_LEVEL=64
- On Windows, if you used :meth:`~cx_Oracle.init_oracle_client()` and have
a full database installation, make sure this database is the `currently
configured database
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-33D575DD-47FF-42B1-A82F-049D3F2A8791>`__.
- On Windows, if you are not using
:meth:`~cx_Oracle.init_oracle_client()`, then restart your command prompt
and use ``set PATH`` to check the environment variable has the correct
Oracle Client listed before any other Oracle directories.
- On Windows, use the ``DIR`` command to verify that ``OCI.DLL`` exists in
the directory passed to ``init_oracle_client()`` or set in ``PATH``.
- On Windows, check that the correct `Windows Redistributables
<https://oracle.github.io/odpi/doc/installation.html#windows>`__ have
been installed.
- On Linux, check the ``LD_LIBRARY_PATH`` environment variable contains
the Oracle Client library directory. If you are using Oracle Instant
Client, a preferred alternative is to ensure a file in the
``/etc/ld.so.conf.d`` directory contains the path to the Instant Client
directory, and then run ``ldconfig``.
- On macOS, make sure you are not using the bundled Python (use `Homebrew
<https://brew.sh>`__ or `Python.org
<https://www.python.org/downloads>`__ instead). If you are not using
:meth:`~cx_Oracle.init_oracle_client()`, then put the Oracle Instant
Client libraries in ``~/lib`` or ``/usr/local/lib``.
- If you got "``DPI-1072: the Oracle Client library version is
unsupported``", then review the installation requirements. cx_Oracle
needs Oracle client libraries 11.2 or later. Note that version 19 is not
supported on Windows 7. Similar steps shown above for ``DPI-1047`` may
help.
- If you have multiple versions of Python installed, make sure you are
using the correct python and pip (or python3 and pip3) executables.

View File

@ -1,145 +0,0 @@
.. _introduction:
*************************
Introduction to cx_Oracle
*************************
cx_Oracle is a Python extension module that enables Python access to Oracle
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
------------
Python programs call cx_Oracle functions. Internally cx_Oracle dynamically
loads Oracle Client libraries to access Oracle Database. The database can be on
the same machine as Python, or it can be remote.
.. _archfig:
.. figure:: /images/cx_Oracle_arch.png
cx_Oracle Architecture
cx_Oracle is typically installed from `PyPI
<https://pypi.org/project/cx-Oracle/>`__ using `pip
<https://pip.pypa.io/en/latest/installing/>`__. The Oracle Client libraries
need to be installed separately. The libraries can be from an installation of
`Oracle Instant Client
<https://www.oracle.com/database/technologies/instant-client.html>`__, from a
full Oracle Client installation, or even from an Oracle Database installation
(if Python is running on the same machine as the database). Oracles standard
client-server version interoperability allows connection to both older and
newer databases from different Client library versions, see :ref:`cx_Oracle
Installation <installation>`.
Some behaviors of the Oracle Client libraries can optionally be configured with
an ``oraaccess.xml`` file, for example to enable auto-tuning of a statement
cache. See :ref:`optclientfiles`.
The Oracle Net layer can optionally be configured with files such as
``tnsnames.ora`` and ``sqlnet.ora``, for example to enable :ref:`network
encryption <netencrypt>`. See :ref:`optnetfiles`.
Oracle environment variables that are set before cx_Oracle first creates a
database connection will affect cx_Oracle behavior. Optional variables include
NLS_LANG, NLS_DATE_FORMAT and TNS_ADMIN. See :ref:`envset`.
Features
--------
The cx_Oracle feature highlights are:
* 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
BLOB) and binding of SQL objects
* Connection management, including connection pooling
* Oracle Database High Availability features
* Full use of Oracle Network Service infrastructure, including encrypted
network traffic and security features
A complete list of supported features can be seen `here
<https://oracle.github.io/python-cx_Oracle/index.html#features>`_.
Getting Started
---------------
Install cx_Oracle using the :ref:`installation <installation>` steps.
Create a script ``query.py`` as shown below:
.. code-block:: python
# query.py
import cx_Oracle
# Establish the database connection
connection = cx_Oracle.connect(user="hr", password=userpwd,
dsn="dbhost.example.com/orclpdb1")
# Obtain a cursor
cursor = connection.cursor()
# Data for binding
manager_id = 145
first_name = "Peter"
# Execute the query
sql = """SELECT first_name, last_name
FROM employees
WHERE manager_id = :mid AND first_name = :fn"""
cursor.execute(sql, mid=manager_id, fn=first_name)
# Loop over the result set
for row in cursor:
print(row)
This uses Oracle's `sample HR schema
<https://github.com/oracle/db-sample-schemas>`__.
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
``hostname/servicename``, using the host name where the database is running and
the Oracle Database service name of the database instance.
The :ref:`cursor <cursorobj>` is the object that allows statements to be
executed and results (if any) fetched.
The data values in ``managerId`` and ``firstName`` are 'bound' to the statement
placeholder 'bind variables' ``:mid`` and ``:fn`` when the statement is
executed. This separates the statement text from the data, which helps avoid
SQL Injection security risks. :ref:`Binding <bind>` is also important for
performance and scalability.
The cursor allows rows to be iterated over and displayed.
Run the script::
python query.py
The output is::
('Peter', 'Hall')
('Peter', 'Tucker')
Examples and Tutorials
----------------------
Runnable examples are in the `GitHub samples directory
<https://github.com/oracle/python-cx_Oracle/tree/main/samples>`__. A `Python
cx_Oracle tutorial
<https://oracle.github.io/python-cx_Oracle/samples/tutorial/Python-and-Oracle-Database-Scripting-for-the-Future.html>`__
is also available.

View File

@ -1,317 +0,0 @@
.. _jsondatatype:
*******************************
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,
making it available for relational processes and tools. Also see
:ref:`Simple Oracle Document Access (SODA) <sodausermanual>`, which allows
access to JSON documents through a set of NoSQL-style APIs.
Prior to Oracle Database 21, JSON in relational tables is stored as BLOB, CLOB
or VARCHAR2 data, allowing easy access with cx_Oracle. Oracle Database 21
introduced a dedicated JSON data type with a new `binary storage format
<https://blogs.oracle.com/jsondb/osonformat>`__ that improves performance and
functionality. To use the new dedicated JSON type, the Oracle Database and
Oracle Client libraries must be version 21, or later. Also cx_Oracle must be
8.1, or later.
For more information about using JSON in Oracle Database see the
`Database JSON Developer's Guide
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=ADJSN>`__.
In Oracle Database 21, to create a table with a column called ``JSON_DATA`` for
JSON data:
.. code-block:: sql
create table customers (
id integer not null primary key,
json_data json
);
For older Oracle Database versions the syntax is:
.. code-block:: sql
create table customers (
id integer not null primary key,
json_data blob check (json_data is json)
);
The check constraint with the clause ``IS JSON`` ensures only JSON data is
stored in that column.
The older syntax can still be used in Oracle Database 21, however the
recommendation is to move to the new JSON type. With the old syntax, the
storage can be BLOB, CLOB or VARCHAR2. Of these, BLOB is preferred to avoid
character set conversion overheads.
Using Oracle Database 21 and Oracle Client 21 with cx_Oracle 8.1 (or later),
you can insert by binding as shown below:
.. code-block:: python
import datetime
json_data = [
2.78,
True,
'Ocean Beach',
b'Some bytes',
{'keyA': 1, 'KeyB': 'Melbourne'},
datetime.date.today()
]
var = cursor.var(cx_Oracle.DB_TYPE_JSON)
var.setvalue(0, json_data)
cursor.execute("insert into customers values (:1, :2)", [123, var])
# or these two lines can replace the three previous lines
cursor.setinputsizes(None, cx_Oracle.DB_TYPE_JSON)
cursor.execute("insert into customers values (:1, :2)", [123, json_data])
Fetching with:
.. code-block:: python
for row in cursor.execute("SELECT c.json_data FROM customers c"):
print(row)
gives output like::
([Decimal('2.78'), True, 'Ocean Beach',
b'Some bytes',
{'keyA': Decimal('1'), 'KeyB': 'Melbourne'},
datetime.datetime(2020, 12, 2, 0, 0)],)
With the older BLOB storage, or to insert JSON strings, use:
.. code-block:: python
import json
customer_data = dict(name="Rod", dept="Sales", location="Germany")
cursor.execute("insert into customers (id, json_data) values (:1, :2)",
[1, json.dumps(customer_data)])
IN Bind Type Mapping
====================
When binding to a JSON value, the type parameter for the variable must be
specified as :data:`cx_Oracle.DB_TYPE_JSON`. Python values are converted to
JSON values as shown in the following table. The 'SQL Equivalent' syntax can
be used in SQL INSERT and UPDATE statements if specific attribute types are
needed but there is no direct mapping from Python.
.. list-table::
:header-rows: 1
:widths: 1 1 1
:align: left
* - Python Type or Value
- JSON Attribute Type or Value
- SQL Equivalent Example
* - None
- null
- NULL
* - True
- true
- n/a
* - False
- false
- n/a
* - int
- NUMBER
- json_scalar(1)
* - float
- NUMBER
- json_scalar(1)
* - decimal.Decimal
- NUMBER
- json_scalar(1)
* - str
- VARCHAR2
- json_scalar('String')
* - datetime.date
- TIMESTAMP
- json_scalar(to_timestamp('2020-03-10', 'YYYY-MM-DD'))
* - datetime.datetime
- TIMESTAMP
- json_scalar(to_timestamp('2020-03-10', 'YYYY-MM-DD'))
* - bytes
- RAW
- json_scalar(utl_raw.cast_to_raw('A raw value'))
* - list
- Array
- json_array(1, 2, 3 returning json)
* - dict
- Object
- json_object(key 'Fred' value json_scalar(5), key 'George' value json_scalar('A string') returning json)
* - n/a
- CLOB
- json_scalar(to_clob('A short CLOB'))
* - n/a
- BLOB
- json_scalar(to_blob(utl_raw.cast_to_raw('A short BLOB')))
* - n/a
- DATE
- json_scalar(to_date('2020-03-10', 'YYYY-MM-DD'))
* - n/a
- INTERVAL YEAR TO MONTH
- json_scalar(to_yminterval('+5-9'))
* - n/a
- INTERVAL DAY TO SECOND
- json_scalar(to_dsinterval('P25DT8H25M'))
* - n/a
- BINARY_DOUBLE
- json_scalar(to_binary_double(25))
* - n/a
- BINARY_FLOAT
- json_scalar(to_binary_float(15.5))
An example of creating a CLOB attribute with key ``mydocument`` in a JSON column
using SQL is:
.. code-block:: python
cursor.execute("""
insert into mytab (myjsoncol) values
(json_object(key 'mydocument' value json_scalar(to_clob(:b))
returning json))""",
['A short CLOB'])
When `mytab` is queried in cx_Oracle, the CLOB data will be returned as a
Python string, as shown by the following table. Output might be like::
{mydocument: 'A short CLOB'}
Query and OUT Bind Type Mapping
===============================
When getting Oracle Database 21 JSON values from the database, the following
attribute mapping occurs:
.. list-table::
:header-rows: 1
:widths: 1 1
:align: left
* - Database JSON Attribute Type or Value
- Python Type or Value
* - null
- None
* - false
- False
* - true
- True
* - NUMBER
- decimal.Decimal
* - VARCHAR2
- str
* - RAW
- bytes
* - CLOB
- str
* - BLOB
- bytes
* - DATE
- datetime.datetime
* - TIMESTAMP
- datetime.datetime
* - INTERVAL YEAR TO MONTH
- not supported
* - INTERVAL DAY TO SECOND
- datetime.timedelta
* - BINARY_DOUBLE
- float
* - BINARY_FLOAT
- float
* - Arrays
- list
* - Objects
- dict
SQL/JSON Path Expressions
=========================
Oracle Database provides SQL access to JSON data using SQL/JSON path
expressions. A path expression selects zero or more JSON values that match, or
satisfy, it. Path expressions can use wildcards and array ranges. A simple
path expression is ``$.friends`` which is the value of the JSON field
``friends``.
For example, the previously created ``customers`` table with JSON column
``json_data`` can be queried like:
.. code-block:: sql
select c.json_data.location FROM customers c
With the JSON ``'{"name":"Rod","dept":"Sales","location":"Germany"}'`` stored
in the table, the queried value would be ``Germany``.
The JSON_EXISTS functions tests for the existence of a particular value within
some JSON data. To look for JSON entries that have a ``location`` field:
.. code-block:: python
for blob, in cursor.execute("""
select json_data
from customers
where json_exists(json_data, '$.location')"""):
data = json.loads(blob.read())
print(data)
This query might display::
{'name': 'Rod', 'dept': 'Sales', 'location': 'Germany'}
The SQL/JSON functions ``JSON_VALUE`` and ``JSON_QUERY`` can also be used.
Note that the default error-handling behavior for these functions is
``NULL ON ERROR``, which means that no value is returned if an error occurs.
To ensure that an error is raised, use ``ERROR ON ERROR``.
For more information, see `SQL/JSON Path Expressions
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&
id=GUID-2DC05D71-3D62-4A14-855F-76E054032494>`__
in the Oracle JSON Developer's Guide.
Accessing Relational Data as JSON
=================================
In Oracle Database 12.2, or later, the `JSON_OBJECT
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-1EF347AE-7FDA-4B41-AFE0-DD5A49E8B370>`__
function is a great way to convert relational table data to JSON:
.. code-block:: python
cursor.execute("""
select json_object('deptId' is d.department_id, 'name' is d.department_name) department
from departments d
where department_id < :did
order by d.department_id""",
[50]);
for row in cursor:
print(row)
This produces::
('{"deptId":10,"name":"Administration"}',)
('{"deptId":20,"name":"Marketing"}',)
('{"deptId":30,"name":"Purchasing"}',)
('{"deptId":40,"name":"Human Resources"}',)

View File

@ -1,207 +0,0 @@
.. _lobdata:
************************
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.
There are four types of LOB (large object):
* BLOB - Binary Large Object, used for storing binary data. cx_Oracle uses
the type :attr:`cx_Oracle.DB_TYPE_BLOB`.
* CLOB - Character Large Object, used for string strings in the database
character set format. cx_Oracle uses the type
:attr:`cx_Oracle.DB_TYPE_CLOB`.
* NCLOB - National Character Large Object, used for string strings in the
national character set format. cx_Oracle uses the type
:attr:`cx_Oracle.DB_TYPE_NCLOB`.
* BFILE - External Binary File, used for referencing a file stored on the
host operating system outside of the database. cx_Oracle uses the type
:attr:`cx_Oracle.DB_TYPE_BFILE`.
LOBs can be streamed to, and from, Oracle Database.
LOBs up to 1 GB in length can be also be handled directly as strings or bytes in
cx_Oracle. This makes LOBs easy to work with, and has significant performance
benefits over streaming. However it requires the entire LOB data to be present
in Python memory, which may not be possible.
See `GitHub <https://github.com/oracle/python-cx_Oracle/tree/main/samples>`__ for LOB examples.
Simple Insertion of LOBs
------------------------
Consider a table with CLOB and BLOB columns:
.. code-block:: sql
CREATE TABLE lob_tbl (
id NUMBER,
c CLOB,
b BLOB
);
With cx_Oracle, LOB data can be inserted in the table by binding strings or
bytes as needed:
.. code-block:: python
with open('example.txt', 'r') as f:
text_data = f.read()
with open('image.png', 'rb') as f:
img_data = f.read()
cursor.execute("""
insert into lob_tbl (id, c, b)
values (:lobid, :clobdata, :blobdata)""",
lobid=10, clobdata=text_data, blobdata=img_data)
Note that with this approach, LOB data is limited to 1 GB in size.
.. _directlobs:
Fetching LOBs as Strings and Bytes
----------------------------------
CLOBs and BLOBs smaller than 1 GB can queried from the database directly as
strings and bytes. This can be much faster than streaming.
A :attr:`Connection.outputtypehandler` or :attr:`Cursor.outputtypehandler` needs
to be used as shown in this example:
.. code-block:: python
def output_type_handler(cursor, name, default_type, size, precision, scale):
if default_type == cx_Oracle.DB_TYPE_CLOB:
return cursor.var(cx_Oracle.DB_TYPE_LONG, arraysize=cursor.arraysize)
if default_type == cx_Oracle.DB_TYPE_BLOB:
return cursor.var(cx_Oracle.DB_TYPE_LONG_RAW, arraysize=cursor.arraysize)
id_val = 1
text_data = "The quick brown fox jumps over the lazy dog"
binary_data = b"Some binary data"
cursor.execute("insert into lob_tbl (id, c, b) values (:1, :2, :3)",
[id_val, text_data, binary_data])
connection.outputtypehandler = output_type_handler
cursor.execute("select c, b from lob_tbl where id = :1", [id_val])
clob_data, blob_data = cursor.fetchone()
print("CLOB length:", len(clob_data))
print("CLOB data:", clob_data)
print("BLOB length:", len(blob_data))
print("BLOB data:", blob_data)
This displays::
CLOB length: 43
CLOB data: The quick brown fox jumps over the lazy dog
BLOB length: 16
BLOB data: b'Some binary data'
Streaming LOBs (Read)
---------------------
Without the output type handler, the CLOB and BLOB values are fetched as
:ref:`LOB objects<lobobj>`. The size of the LOB object can be obtained by
calling :meth:`LOB.size()` and the data can be read by calling
:meth:`LOB.read()`:
.. code-block:: python
id_val = 1
text_data = "The quick brown fox jumps over the lazy dog"
binary_data = b"Some binary data"
cursor.execute("insert into lob_tbl (id, c, b) values (:1, :2, :3)",
[id_val, text_data, binary_data])
cursor.execute("select b, c from lob_tbl where id = :1", [id_val])
b, c = cursor.fetchone()
print("CLOB length:", c.size())
print("CLOB data:", c.read())
print("BLOB length:", b.size())
print("BLOB data:", b.read())
This approach produces the same results as the previous example but it will
perform more slowly because it requires more :ref:`round-trips <roundtrips>` to
Oracle Database and has higher overhead. It is needed, however, if the LOB data
cannot be fetched as one block of data from the server.
To stream the BLOB column, the :meth:`LOB.read()` method can be called
repeatedly until all of the data has been read, as shown below:
.. code-block:: python
cursor.execute("select b from lob_tbl where id = :1", [10])
blob, = cursor.fetchone()
offset = 1
num_bytes_in_chunk = 65536
with open("image.png", "wb") as f:
while True:
data = blob.read(offset, num_bytes_in_chunk)
if data:
f.write(data)
if len(data) < num_bytes_in_chunk:
break
offset += len(data)
Streaming LOBs (Write)
----------------------
If a row containing a LOB is being inserted or updated, and the quantity of
data that is to be inserted or updated cannot fit in a single block of data,
the data can be streamed using the method :meth:`LOB.write()` instead as shown
in the following code:
.. code-block:: python
id_val = 9
lob_var = cursor.var(cx_Oracle.DB_TYPE_BLOB)
cursor.execute("""
insert into lob_tbl (id, b)
values (:1, empty_blob())
returning b into :2""", [id_val, lob_var])
blob, = lobVar.getvalue()
offset = 1
num_bytes_in_chunk = 65536
with open("image.png", "rb") as f:
while True:
data = f.read(num_bytes_in_chunk)
if data:
blob.write(data, offset)
if len(data) < num_bytes_in_chunk:
break
offset += len(data)
connection.commit()
Temporary LOBs
--------------
All of the examples shown thus far have made use of permanent LOBs. These are
LOBs that are stored in the database. Oracle also supports temporary LOBs that
are not stored in the database but can be used to pass large quantities of
data. These LOBs use space in the temporary tablespace until all variables
referencing them go out of scope or the connection in which they are created is
explicitly closed.
When calling PL/SQL procedures with data that exceeds 32,767 bytes in length,
cx_Oracle automatically creates a temporary LOB internally and passes that
value through to the procedure. If the data that is to be passed to the
procedure exceeds that which can fit in a single block of data, however, you
can use the method :meth:`Connection.createlob()` to create a temporary LOB.
This LOB can then be read and written just like in the examples shown above for
persistent LOBs.

View File

@ -1,388 +0,0 @@
.. _plsqlexecution:
****************
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.
.. _plsqlproc:
PL/SQL Stored Procedures
------------------------
The :meth:`Cursor.callproc()` method is used to call PL/SQL procedures.
If a procedure with the following definition exists:
.. code-block:: sql
create or replace procedure myproc (
a_Value1 number,
a_Value2 out number
) as
begin
a_Value2 := a_Value1 * 2;
end;
then the following Python code can be used to call it:
.. code-block:: python
out_val = cursor.var(int)
cursor.callproc('myproc', [123, out_val])
print(out_val.getvalue()) # will print 246
Calling :meth:`Cursor.callproc()` actually generates an anonymous PL/SQL block
as shown below, which is then executed:
.. code-block:: python
cursor.execute("begin myproc(:1,:2); end;", [123, out_val])
See :ref:`bind` for information on binding.
.. _plsqlfunc:
PL/SQL Stored Functions
-----------------------
The :meth:`Cursor.callfunc()` method is used to call PL/SQL functions.
The ``returnType`` parameter for :meth:`~Cursor.callfunc()` is
expected to be a Python type, one of the :ref:`cx_Oracle types <types>` or
an :ref:`Object Type <objecttype>`.
If a function with the following definition exists:
.. code-block:: sql
create or replace function myfunc (
a_StrVal varchar2,
a_NumVal number
) return number as
begin
return length(a_StrVal) + a_NumVal * 2;
end;
then the following Python code can be used to call it:
.. code-block:: python
return_val = cursor.callfunc("myfunc", int, ["a string", 15])
print(return_val) # will print 38
A more complex example that returns a spatial (SDO) object can be seen below.
First, the SQL statements necessary to set up the example:
.. code-block:: sql
create table MyPoints (
id number(9) not null,
point sdo_point_type not null
);
insert into MyPoints values (1, sdo_point_type(125, 375, 0));
create or replace function spatial_queryfn (
a_Id number
) return sdo_point_type is
t_Result sdo_point_type;
begin
select point
into t_Result
from MyPoints
where Id = a_Id;
return t_Result;
end;
/
The Python code that will call this procedure looks as follows:
.. code-block:: python
obj_type = connection.gettype("SDO_POINT_TYPE")
cursor = connection.cursor()
return_val = cursor.callfunc("spatial_queryfn", obj_type, [1])
print(f"({return_val.X}, {return_val.Y}, {return_val.Z})")
# will print (125, 375, 0)
See :ref:`bind` for information on binding.
Anonymous PL/SQL Blocks
-----------------------
An anonymous PL/SQL block can be called as shown:
.. code-block:: python
var = cursor.var(int)
cursor.execute("""
begin
:out_val := length(:in_val);
end;""", in_val="A sample string", out_val=var)
print(var.getvalue()) # will print 15
See :ref:`bind` for information on binding.
Creating Stored Procedures and Packages
---------------------------------------
To create PL/SQL stored procedures and packages, use :meth:`Cursor.execute()`
with a SQL CREATE command.
Creation warning messages can be found from database views like USER_ERRORS.
For example, creating a procedure with an error could be like:
.. code-block:: python
with connection.cursor() as cursor:
cursor.execute("""
create or replace procedure badproc (a in number) as
begin
WRONG WRONG WRONG
end;""")
cursor.execute("""
select line, position, text
from user_errors
where name = 'BADPROC' and type = 'PROCEDURE'
order by name, type, line, position""")
errors = cursor.fetchall()
if errors:
for info in errors:
print("Error at line {} position {}:\n{}".format(*info))
else:
print("Created successfully")
The output would be::
PLS-00103: Encountered the symbol "WRONG" when expecting one of the following:
:= . ( @ % ;
Using DBMS_OUTPUT
-----------------
The standard way to print output from PL/SQL is with the package `DBMS_OUTPUT
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&
id=GUID-C1400094-18D5-4F36-A2C9-D28B0E12FD8C>`__. Note, PL/SQL code that uses
``DBMS_OUTPUT`` runs to completion before any output is available to the user.
Also, other database connections cannot access the buffer.
To use DBMS_OUTPUT:
* Call the PL/SQL procedure ``DBMS_OUTPUT.ENABLE()`` to enable output to be
buffered for the connection.
* Execute some PL/SQL that calls ``DBMS_OUTPUT.PUT_LINE()`` to put text in the
buffer.
* Call ``DBMS_OUTPUT.GET_LINE()`` or ``DBMS_OUTPUT.GET_LINES()`` repeatedly to
fetch the text from the buffer until there is no more output.
For example:
.. code-block:: python
# enable DBMS_OUTPUT
cursor.callproc("dbms_output.enable")
# execute some PL/SQL that calls DBMS_OUTPUT.PUT_LINE
cursor.execute("""
begin
dbms_output.put_line('This is the cx_Oracle manual');
dbms_output.put_line('Demonstrating how to use DBMS_OUTPUT');
end;""")
# tune this size for your application
chunk_size = 100
# create variables to hold the output
lines_var = cursor.arrayvar(str, chunk_size)
num_lines_var = cursor.var(int)
num_lines_var.setvalue(0, chunk_size)
# fetch the text that was added by PL/SQL
while True:
cursor.callproc("dbms_output.get_lines", (lines_var, num_lines_var))
num_lines = num_lines_var.getvalue()
lines = lines_var.getvalue()[:num_lines]
for line in lines:
print(line or "")
if num_lines < chunk_size:
break
This will produce the following output::
This is the cx_Oracle manual
Demonstrating use of DBMS_OUTPUT
An alternative is to call ``DBMS_OUTPUT.GET_LINE()`` once per output line,
which may be much slower:
.. code-block:: python
text_var = cursor.var(str)
status_var = cursor.var(int)
while True:
cursor.callproc("dbms_output.get_line", (text_var, status_var))
if status_var.getvalue() != 0:
break
print(text_var.getvalue())
Implicit results
----------------
Implicit results permit a Python program to consume cursors returned by a
PL/SQL block without the requirement to use OUT REF CURSOR parameters. The
method :meth:`Cursor.getimplicitresults()` can be used for this purpose. It
requires both the Oracle Client and Oracle Database to be 12.1 or higher.
An example using implicit results is as shown:
.. code-block:: python
cursor.execute("""
declare
cust_cur sys_refcursor;
sales_cur sys_refcursor;
begin
open cust_cur for SELECT * FROM cust_table;
dbms_sql.return_result(cust_cur);
open sales_cur for SELECT * FROM sales_table;
dbms_sql.return_result(sales_cur);
end;""")
for implicit_cursor in cursor.getimplicitresults():
for row in implicit_cursor:
print(row)
Data from both the result sets are returned::
(1, 'Tom')
(2, 'Julia')
(1000, 1, 'BOOKS')
(2000, 2, 'FURNITURE')
.. _ebr:
Edition-Based Redefinition (EBR)
--------------------------------
Oracle Database's `Edition-Based Redefinition
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&
id=GUID-58DE05A0-5DEF-4791-8FA8-F04D11964906>`__ feature enables upgrading of
the database component of an application while it is in use, thereby minimizing
or eliminating down time. This feature allows multiple versions of views,
synonyms, PL/SQL objects and SQL Translation profiles to be used concurrently.
Different versions of the database objects are associated with an "edition".
The simplest way to set an edition is to pass the ``edition`` parameter to
:meth:`cx_Oracle.connect()` or :meth:`cx_Oracle.SessionPool()`:
.. code-block:: python
connection = cx_Oracle.connect(user="hr", password=userpwd,
dsn="dbhost.example.com/orclpdb1",
edition="newsales", encoding="UTF-8")
The edition could also be set by setting the environment variable
``ORA_EDITION`` or by executing the SQL statement:
.. code-block:: sql
alter session set edition = <edition name>;
Regardless of which method is used to set the edition, the value that is in use
can be seen by examining the attribute :attr:`Connection.edition`. If no value
has been set, the value will be None. This corresponds to the database default
edition ``ORA$BASE``.
Consider an example where one version of a PL/SQL function ``Discount`` is
defined in the database default edition ``ORA$BASE`` and the other version of
the same function is defined in a user created edition ``DEMO``.
.. code-block:: sql
connect <username>/<password>
-- create function using the database default edition
CREATE OR REPLACE FUNCTION Discount(price IN NUMBER) RETURN NUMBER IS
BEGIN
return price * 0.9;
END;
/
A new edition named 'DEMO' is created and the user given permission to use
editions. The use of ``FORCE`` is required if the user already contains one or
more objects whose type is editionable and that also have non-editioned
dependent objects.
.. code-block:: sql
connect system/<password>
CREATE EDITION demo;
ALTER USER <username> ENABLE EDITIONS FORCE;
GRANT USE ON EDITION demo to <username>;
The ``Discount`` function for the demo edition is as follows:
.. code-block:: sql
connect <username>/<password>
alter session set edition = demo;
-- Function for the demo edition
CREATE OR REPLACE FUNCTION Discount(price IN NUMBER) RETURN NUMBER IS
BEGIN
return price * 0.5;
END;
/
The Python application can then call the required version of the PL/SQL
function as shown:
.. code-block:: python
connection = cx_Oracle.connect(user=user, password=password,
dsn="dbhost.example.com/orclpdb1",
encoding="UTF-8")
print("Edition is:", repr(connection.edition))
cursor = connection.cursor()
discounted_price = cursor.callfunc("Discount", int, [100])
print("Price after discount is:", discounted_price)
# Use the edition parameter for the connection
connection = cx_Oracle.connect(user=user, password=password,
dsn="dbhost.example.com/orclpdb1",
edition="demo", encoding="UTF-8")
print("Edition is:", repr(connection.edition))
cursor = connection.cursor()
discounted_price = cursor.callfunc("Discount", int, [100])
print("Price after discount is:", discounted_price)
The output of the function call for the default and demo edition is as shown::
Edition is: None
Price after discount is: 90
Edition is: 'DEMO'
Price after discount is: 50

View File

@ -1,216 +0,0 @@
.. _sodausermanual:
************************************
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
========
Oracle Database Simple Oracle Document Access (SODA) allows documents to be
inserted, queried, and retrieved from Oracle Database using a set of
NoSQL-style cx_Oracle methods. Documents are generally JSON data but they can
be any data at all (including video, images, sounds, or other binary content).
Documents can be fetched from the database by key lookup or by using
query-by-example (QBE) pattern-matching.
SODA uses a SQL schema to store documents but you do not need to know SQL or
how the documents are stored. However, access via SQL does allow use of
advanced Oracle Database functionality such as analytics for reporting.
Oracle SODA implementations are also available in `Node.js
<https://oracle.github.io/node-oracledb/doc/api.html#sodaoverview>`__, `Java
<https://docs.oracle.com/en/database/oracle/simple-oracle-document-access/java/adsda/index.html>`__,
`PL/SQL <https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=ADSDP>`__,
`Oracle Call Interface
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-23206C89-891E-43D7-827C-5C6367AD62FD>`__
and via `REST
<https://docs.oracle.com/en/database/oracle/simple-oracle-document-access/rest/index.html>`__.
For general information on SODA, see the `SODA home page
<https://docs.oracle.com/en/database/oracle/simple-oracle-document-access/index.html>`__
and the Oracle Database `Introduction to Simple Oracle Document Access (SODA)
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=ADSDI>`__ manual.
For specific requirements see the cx_Oracle :ref:`SODA requirements <sodarequirements>`.
cx_Oracle uses the following objects for SODA:
* :ref:`SODA Database Object <sodadb>`: The top level object for cx_Oracle SODA
operations. This is acquired from an Oracle Database connection. A 'SODA
database' is an abstraction, allowing access to SODA collections in that
'SODA database', which then allow access to documents in those collections.
A SODA database is analogous to an Oracle Database user or schema, a
collection is analogous to a table, and a document is analogous to a table
row with one column for a unique document key, a column for the document
content, and other columns for various document attributes.
* :ref:`SODA Collection Object <sodacoll>`: Represents a collection of SODA
documents. By default, collections allow JSON documents to be stored. This
is recommended for most SODA users. However optional metadata can set
various details about a collection, such as its database storage, whether it
should track version and time stamp document components, how such components
are generated, and what document types are supported. By default, the name of
the Oracle Database table storing a collection is the same as the collection
name. Note: do not use SQL to drop the database table, since SODA metadata
will not be correctly removed. Use the :meth:`SodaCollection.drop()` method
instead.
* :ref:`SODA Document Object <sodadoc>`: Represents a document. Typically the
document content will be JSON. The document has properties including the
content, a key, timestamps, and the media type. By default, document keys
are automatically generated. See :ref:`SODA Document objects <sodadoc>` for
the forms of SodaDoc.
* :ref:`SODA Document Cursor <sodadoccur>`: A cursor object representing the
result of the :meth:`SodaOperation.getCursor()` method from a
:meth:`SodaCollection.find()` operation. It can be iterated over to access
each SodaDoc.
* :ref:`SODA Operation Object <sodaop>`: An internal object used with
:meth:`SodaCollection.find()` to perform read and write operations on
documents. Chained methods set properties on a SodaOperation object which is
then used by a terminal method to find, count, replace, or remove documents.
This is an internal object that should not be directly accessed.
SODA Examples
=============
Creating and adding documents to a collection can be done as follows:
.. code-block:: python
soda = connection.getSodaDatabase()
# create a new SODA collection; this will open an existing collection, if
# the name is already in use
collection = soda.createCollection("mycollection")
# insert a document into the collection; for the common case of a JSON
# document, the content can be a simple Python dictionary which will
# internally be converted to a JSON document
content = {'name': 'Matilda', 'address': {'city': 'Melbourne'}}
returned_doc = collection.insertOneAndGet(content)
key = returned_doc.key
print('The key of the new SODA document is: ', key)
By default, a system generated key is created when documents are inserted.
With a known key, you can retrieve a document:
.. code-block:: python
# this will return a dictionary (as was inserted in the previous code)
content = collection.find().key(key).getOne().getContent()
print(content)
You can also search for documents using query-by-example syntax:
.. code-block:: python
# Find all documents with names like 'Ma%'
print("Names matching 'Ma%'")
qbe = {'name': {'$like': 'Ma%'}}
for doc in collection.find().filter(qbe).getDocuments():
content = doc.getContent()
print(content["name"])
See the `samples directory
<https://github.com/oracle/python-cx_Oracle/tree/main/samples>`__
for runnable SODA examples.
.. _sodametadatacache:
Using the SODA Metadata Cache
=============================
SODA metadata can be cached to improve the performance of
:meth:`SodaDatabase.createCollection()` and
:meth:`SodaDatabase.openCollection()` by reducing :ref:`round-trips
<roundtrips>` to the database. Caching is available with Oracle Client 21.3 (or
later). The feature is also available in Oracle Client 19 from 19.11 onwards.
The metadata cache can be turned on when creating a connection pool with
:meth:`cx_Oracle.SessionPool()`. Each pool has its own cache:
.. code-block:: python
# Create the session pool
pool = cx_Oracle.SessionPool(user="hr", password=userpwd,
dsn="dbhost.example.com/orclpdb1",
soda_metadata_cache=True)
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
mymetadata = { . . . }
collection = soda.createCollection("mycollection", mymetadata) # open existing or create new collection
collection.insertOne(mycontent)
you will find it more efficient to use logic similar to:
.. code-block:: python
collection = soda.openCollection("mycollection")
if collection is None:
mymetadata = { . . . }
collection = soda.createCollection("mycollection", mymetadata)
collection.insertOne(mycontent)
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
====================
The general recommendation for SODA applications is to turn on
:attr:`~Connection.autocommit` globally:
.. code-block:: python
connection.autocommit = True
If your SODA document write operations are mostly independent of each other,
this removes the overhead of application transaction management and the need for
explicit :meth:`Connection.commit()` calls.
When deciding how to commit transactions, beware of transactional consistency
and performance requirements. If you are using individual SODA calls to insert
or update a large number of documents with individual calls, you should turn
:attr:`~Connection.autocommit` off and issue a single, explicit
:meth:`~Connection.commit()` after all documents have been processed. Also
consider using :meth:`SodaCollection.insertMany()` or
:meth:`SodaCollection.insertManyAndGet()` which have performance benefits.
If you are not autocommitting, and one of the SODA operations in your
transaction fails, then previous uncommitted operations will not be rolled back.
Your application should explicitly roll back the transaction with
:meth:`Connection.rollback()` to prevent any later commits from committing a
partial transaction.
Note:
- SODA DDL operations do not commit an open transaction the way that SQL always does for DDL statements.
- When :attr:`~Connection.autocommit` is ``True``, most SODA methods will issue a commit before successful return.
- SODA provides optimistic locking, see :meth:`SodaOperation.version()`.
- When mixing SODA and relational access, any commit or rollback on the connection will affect all work.

View File

@ -1,812 +0,0 @@
.. _sqlexecution:
*************
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
queries, Data Manipulation Language (DML), and Data Definition Language (DDL).
A few other `specialty statements
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&
id=GUID-E1749EF5-2264-44DF-99EF-AEBEB943BED6>`__ can also be executed.
PL/SQL statements are discussed in :ref:`plsqlexecution`. Other chapters
contain information on specific data types and features. See :ref:`batchstmnt`,
:ref:`lobdata`, :ref:`jsondatatype`, and :ref:`xmldatatype`.
cx_Oracle can be used to execute individual statements, one at a time. It does
not read SQL*Plus ".sql" files. To read SQL files, use a technique like the one
in ``run_sql_script()`` in `samples/sample_env.py
<https://github.com/oracle/python-cx_Oracle/blob/main/samples/sample_env.py>`__
SQL statements should not contain a trailing semicolon (";") or forward slash
("/"). This will fail:
.. code-block:: python
cur.execute("select * from MyTable;")
This is correct:
.. code-block:: python
cur.execute("select * from MyTable")
SQL Queries
===========
Queries (statements beginning with SELECT or WITH) can only be executed using
the method :meth:`Cursor.execute()`. Rows can then be iterated over, or can be
fetched using one of the methods :meth:`Cursor.fetchone()`,
:meth:`Cursor.fetchmany()` or :meth:`Cursor.fetchall()`. There is a
:ref:`default type mapping <defaultfetchtypes>` to Python types that can be
optionally :ref:`overridden <outputtypehandlers>`.
.. IMPORTANT::
Interpolating or concatenating user data with SQL statements, for example
``cur.execute("SELECT * FROM mytab WHERE mycol = '" + myvar + "'")``, is a security risk
and impacts performance. Use :ref:`bind variables <bind>` instead. For
example, ``cur.execute("SELECT * FROM mytab WHERE mycol = :mybv", mybv=myvar)``.
.. _fetching:
Fetch Methods
-------------
After :meth:`Cursor.execute()`, the cursor is returned as a convenience. This
allows code to iterate over rows like:
.. code-block:: python
cur = connection.cursor()
for row in cur.execute("select * from MyTable"):
print(row)
Rows can also be fetched one at a time using the method
:meth:`Cursor.fetchone()`:
.. code-block:: python
cur = connection.cursor()
cur.execute("select * from MyTable")
while True:
row = cur.fetchone()
if row is None:
break
print(row)
If rows need to be processed in batches, the method :meth:`Cursor.fetchmany()`
can be used. The size of the batch is controlled by the ``numRows`` parameter,
which defaults to the value of :attr:`Cursor.arraysize`.
.. code-block:: python
cur = connection.cursor()
cur.execute("select * from MyTable")
num_rows = 10
while True:
rows = cur.fetchmany(num_rows)
if not rows:
break
for row in rows:
print(row)
If all of the rows need to be fetched, and can be contained in memory, the
method :meth:`Cursor.fetchall()` can be used.
.. code-block:: python
cur = connection.cursor()
cur.execute("select * from MyTable")
rows = cur.fetchall()
for row in rows:
print(row)
The fetch methods return data as tuples. To return results as dictionaries, see
:ref:`rowfactories`.
Closing Cursors
---------------
A cursor may be used to execute multiple statements. Once it is no longer
needed, it should be closed by calling :meth:`~Cursor.close()` in order to
reclaim resources in the database. It will be closed automatically when the
variable referencing it goes out of scope (and no further references are
retained). One other way to control the lifetime of a cursor is to use a "with"
block, which ensures that a cursor is closed once the block is completed. For
example:
.. code-block:: python
with connection.cursor() as cursor:
for row in cursor.execute("select * from MyTable"):
print(row)
This code ensures that, once the block is completed, the cursor is closed and
resources have been reclaimed by the database. In addition, any attempt to use
the variable ``cursor`` outside of the block will simply fail.
.. _querymetadata:
Query Column Metadata
---------------------
After executing a query, the column metadata such as column names and data types
can be obtained using :attr:`Cursor.description`:
.. code-block:: python
cur = connection.cursor()
cur.execute("select * from MyTable")
for column in cur.description:
print(column)
This could result in metadata like::
('ID', <class 'cx_Oracle.DB_TYPE_NUMBER'>, 39, None, 38, 0, 0)
('NAME', <class 'cx_Oracle.DB_TYPE_VARCHAR'>, 20, 20, None, None, 1)
.. _defaultfetchtypes:
Fetch Data Types
----------------
The following table provides a list of all of the data types that cx_Oracle
knows how to fetch. The middle column gives the type that is returned in the
:ref:`query metadata <querymetadata>`. The last column gives the type of
Python object that is returned by default. Python types can be changed with
:ref:`Output Type Handlers <outputtypehandlers>`.
.. list-table::
:header-rows: 1
:widths: 1 1 1
:align: left
* - Oracle Database Type
- cx_Oracle Database Type
- Default Python type
* - BFILE
- :attr:`cx_Oracle.DB_TYPE_BFILE`
- :ref:`cx_Oracle.LOB <lobobj>`
* - BINARY_DOUBLE
- :attr:`cx_Oracle.DB_TYPE_BINARY_DOUBLE`
- float
* - BINARY_FLOAT
- :attr:`cx_Oracle.DB_TYPE_BINARY_FLOAT`
- float
* - BLOB
- :attr:`cx_Oracle.DB_TYPE_BLOB`
- :ref:`cx_Oracle.LOB <lobobj>`
* - CHAR
- :attr:`cx_Oracle.DB_TYPE_CHAR`
- str
* - CLOB
- :attr:`cx_Oracle.DB_TYPE_CLOB`
- :ref:`cx_Oracle.LOB <lobobj>`
* - CURSOR
- :attr:`cx_Oracle.DB_TYPE_CURSOR`
- :ref:`cx_Oracle.Cursor <cursorobj>`
* - DATE
- :attr:`cx_Oracle.DB_TYPE_DATE`
- datetime.datetime
* - INTERVAL DAY TO SECOND
- :attr:`cx_Oracle.DB_TYPE_INTERVAL_DS`
- datetime.timedelta
* - JSON
- :attr:`cx_Oracle.DB_TYPE_JSON`
- dict, list or a scalar value [4]_
* - LONG
- :attr:`cx_Oracle.DB_TYPE_LONG`
- str
* - LONG RAW
- :attr:`cx_Oracle.DB_TYPE_LONG_RAW`
- bytes
* - NCHAR
- :attr:`cx_Oracle.DB_TYPE_NCHAR`
- str
* - NCLOB
- :attr:`cx_Oracle.DB_TYPE_NCLOB`
- :ref:`cx_Oracle.LOB <lobobj>`
* - NUMBER
- :attr:`cx_Oracle.DB_TYPE_NUMBER`
- float or int [1]_
* - NVARCHAR2
- :attr:`cx_Oracle.DB_TYPE_NVARCHAR`
- str
* - OBJECT [3]_
- :attr:`cx_Oracle.DB_TYPE_OBJECT`
- :ref:`cx_Oracle.Object <objecttype>`
* - RAW
- :attr:`cx_Oracle.DB_TYPE_RAW`
- bytes
* - ROWID
- :attr:`cx_Oracle.DB_TYPE_ROWID`
- str
* - TIMESTAMP
- :attr:`cx_Oracle.DB_TYPE_TIMESTAMP`
- datetime.datetime
* - TIMESTAMP WITH LOCAL TIME ZONE
- :attr:`cx_Oracle.DB_TYPE_TIMESTAMP_LTZ`
- datetime.datetime [2]_
* - TIMESTAMP WITH TIME ZONE
- :attr:`cx_Oracle.DB_TYPE_TIMESTAMP_TZ`
- datetime.datetime [2]_
* - UROWID
- :attr:`cx_Oracle.DB_TYPE_ROWID`
- str
* - VARCHAR2
- :attr:`cx_Oracle.DB_TYPE_VARCHAR`
- str
.. [1] If the precision and scale obtained from query column metadata indicate
that the value can be expressed as an integer, the value will be
returned as an int. If the column is unconstrained (no precision and
scale specified), the value will be returned as a float or an int
depending on whether the value itself is an integer. In all other cases
the value is returned as a float.
.. [2] The timestamps returned are naive timestamps without any time zone
information present.
.. [3] These include all user-defined types such as VARRAY, NESTED TABLE, etc.
.. [4] If the JSON is an object, then a dict is returned. If it is an array,
then a list is returned. If it is a scalar value, then that particular
scalar value is returned.
.. _outputtypehandlers:
Changing Fetched Data Types with Output Type Handlers
-----------------------------------------------------
Sometimes the default conversion from an Oracle Database type to a Python type
must be changed in order to prevent data loss or to fit the purposes of the
Python application. In such cases, an output type handler can be specified for
queries. Output type handlers do not affect values returned from
:meth:`Cursor.callfunc()` or :meth:`Cursor.callproc()`.
Output type handlers can be specified on the :attr:`connection
<Connection.outputtypehandler>` or on the :attr:`cursor
<Cursor.outputtypehandler>`. If specified on the cursor, fetch type handling is
only changed on that particular cursor. If specified on the connection, all
cursors created by that connection will have their fetch type handling changed.
The output type handler is expected to be a function with the following
signature::
handler(cursor, name, defaultType, size, precision, scale)
The parameters are the same information as the query column metadata found in
:attr:`Cursor.description`. The function is called once for each column that is
going to be fetched. The function is expected to return a
:ref:`variable object <varobj>` (generally by a call to :func:`Cursor.var()`)
or the value ``None``. The value ``None`` indicates that the default type
should be used.
Examples of output handlers are shown in :ref:`numberprecision`,
:ref:`directlobs` and :ref:`fetching-raw-data`. Also see samples such as `samples/type_handlers.py
<https://github.com/oracle/python-cx_Oracle/blob/main/samples/type_handlers.py>`__
.. _numberprecision:
Fetched Number Precision
------------------------
One reason for using an output type handler is to ensure that numeric precision
is not lost when fetching certain numbers. Oracle Database uses decimal numbers
and these cannot be converted seamlessly to binary number representations like
Python floats. In addition, the range of Oracle numbers exceeds that of
floating point numbers. Python has decimal objects which do not have these
limitations and cx_Oracle knows how to perform the conversion between Oracle
numbers and Python decimal values if directed to do so.
The following code sample demonstrates the issue:
.. code-block:: python
cur = connection.cursor()
cur.execute("create table test_float (X number(5, 3))")
cur.execute("insert into test_float values (7.1)")
connection.commit()
cur.execute("select * from test_float")
val, = cur.fetchone()
print(val, "* 3 =", val * 3)
This displays ``7.1 * 3 = 21.299999999999997``
Using Python decimal objects, however, there is no loss of precision:
.. code-block:: python
import decimal
def number_to_decimal(cursor, name, default_type, size, precision, scale):
if default_type == cx_Oracle.DB_TYPE_NUMBER:
return cursor.var(decimal.Decimal, arraysize=cursor.arraysize)
cur = connection.cursor()
cur.outputtypehandler = number_to_decimal
cur.execute("select * from test_float")
val, = cur.fetchone()
print(val, "* 3 =", val * 3)
This displays ``7.1 * 3 = 21.3``
The Python ``decimal.Decimal`` converter gets called with the string
representation of the Oracle number. The output from ``decimal.Decimal`` is
returned in the output tuple.
See `samples/return_numbers_as_decimals.py
<https://github.com/oracle/python-cx_Oracle/blob/main/samples/return_numbers_as_decimals.py>`__
.. _outconverters:
Changing Query Results with Outconverters
-----------------------------------------
cx_Oracle "outconverters" can be used with :ref:`output type handlers
<outputtypehandlers>` to change returned data.
For example, to make queries return empty strings instead of NULLs:
.. code-block:: python
def out_converter(value):
if value is None:
return ''
return value
def output_type_handler(cursor, name, default_type, size, precision, scale):
if default_type in (cx_Oracle.DB_TYPE_VARCHAR, cx_Oracle.DB_TYPE_CHAR):
return cursor.var(str, size, arraysize=cur.arraysize,
outconverter=out_converter)
connection.outputtypehandler = output_type_handler
.. _rowfactories:
Changing Query Results with Rowfactories
----------------------------------------
cx_Oracle "rowfactories" are methods called for each row that is retrieved from
the database. The :meth:`Cursor.rowfactory` method is called with the tuple that
would normally be returned from the database. The method can convert the tuple
to a different value and return it to the application in place of the tuple.
For example, to fetch each row of a query as a dictionary:
.. code-block:: python
cursor.execute("select * from locations where location_id = 1000")
columns = [col[0] for col in cursor.description]
cursor.rowfactory = lambda *args: dict(zip(columns, args))
data = cursor.fetchone()
print(data)
The output is::
{'LOCATION_ID': 1000, 'STREET_ADDRESS': '1297 Via Cola di Rie', 'POSTAL_CODE': '00989', 'CITY': 'Roma', 'STATE_PROVINCE': None, 'COUNTRY_ID': 'IT'}
If you join tables where the same column name occurs in both tables with
different meanings or values, then use a column alias in the query. Otherwise
only one of the similarly named columns will be included in the dictionary:
.. code-block:: sql
select
cat_name,
cats.color as cat_color,
dog_name,
dogs.color
from cats, dogs
.. _scrollablecursors:
Scrollable Cursors
------------------
Scrollable cursors enable applications to move backwards, forwards, to skip
rows, and to move to a particular row in a query result set. The result set is
cached on the database server until the cursor is closed. In contrast, regular
cursors are restricted to moving forward.
A scrollable cursor is created by setting the parameter ``scrollable=True``
when creating the cursor. The method :meth:`Cursor.scroll()` is used to move to
different locations in the result set.
Examples are:
.. code-block:: python
cursor = connection.cursor(scrollable=True)
cursor.execute("select * from ChildTable order by ChildId")
cursor.scroll(mode="last")
print("LAST ROW:", cursor.fetchone())
cursor.scroll(mode="first")
print("FIRST ROW:", cursor.fetchone())
cursor.scroll(8, mode="absolute")
print("ROW 8:", cursor.fetchone())
cursor.scroll(6)
print("SKIP 6 ROWS:", cursor.fetchone())
cursor.scroll(-4)
print("SKIP BACK 4 ROWS:", cursor.fetchone())
.. _fetchobjects:
Fetching Oracle Database Objects and Collections
------------------------------------------------
Oracle Database named object types and user-defined types can be fetched
directly in queries. Each item is represented as a :ref:`Python object
<objecttype>` corresponding to the Oracle Database object. This Python object
can be traversed to access its elements. Attributes including
:attr:`ObjectType.name` and :attr:`ObjectType.iscollection`, and methods
including :meth:`Object.aslist` and :meth:`Object.asdict` are available.
For example, if a table ``mygeometrytab`` contains a column ``geometry`` of
Oracle's predefined Spatial object type `SDO_GEOMETRY
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-683FF8C5-A773-4018-932D-2AF6EC8BC119>`__,
then it can be queried and printed:
.. code-block:: python
cur.execute("select geometry from mygeometrytab")
for obj, in cur:
dumpobject(obj)
Where ``dumpobject()`` is defined as:
.. code-block:: python
def dumpobject(obj, prefix = ""):
if obj.type.iscollection:
print(prefix, "[")
for value in obj.aslist():
if isinstance(value, cx_Oracle.Object):
dumpobject(value, prefix + " ")
else:
print(prefix + " ", repr(value))
print(prefix, "]")
else:
print(prefix, "{")
for attr in obj.type.attributes:
value = getattr(obj, attr.name)
if isinstance(value, cx_Oracle.Object):
print(prefix + " " + attr.name + ":")
dumpobject(value, prefix + " ")
else:
print(prefix + " " + attr.name + ":", repr(value))
print(prefix, "}")
This might produce output like::
{
SDO_GTYPE: 2003
SDO_SRID: None
SDO_POINT:
{
X: 1
Y: 2
Z: 3
}
SDO_ELEM_INFO:
[
1
1003
3
]
SDO_ORDINATES:
[
1
1
5
7
]
}
Other information on using Oracle objects is in :ref:`Using Bind Variables
<bind>`.
Performance-sensitive applications should consider using scalar types instead of
objects. If you do use objects, avoid calling :meth:`Connection.gettype()`
unnecessarily, and avoid objects with large numbers of attributes.
.. _rowlimit:
Limiting Rows
-------------
Query data is commonly broken into one or more sets:
- To give an upper bound on the number of rows that a query has to process,
which can help improve database scalability.
- To perform 'Web pagination' that allows moving from one set of rows to a
next, or previous, set on demand.
- For fetching of all data in consecutive small sets for batch processing.
This happens because the number of records is too large for Python to handle
at one time.
The latter can be handled by calling :meth:`Cursor.fetchmany()` with one
execution of the SQL query.
'Web pagination' and limiting the maximum number of rows are discussed in this
section. For each 'page' of results, a SQL query is executed to get the
appropriate set of rows from a table. Since the query may be executed more
than once, make sure to use :ref:`bind variables <bind>` for row numbers and
row limits.
Oracle Database 12c SQL introduced an ``OFFSET`` / ``FETCH`` clause which is
similar to the ``LIMIT`` keyword of MySQL. In Python you can fetch a set of
rows using:
.. code-block:: python
myoffset = 0 // do not skip any rows (start at row 1)
mymaxnumrows = 20 // get 20 rows
sql =
"""SELECT last_name
FROM employees
ORDER BY last_name
OFFSET :offset ROWS FETCH NEXT :maxnumrows ROWS ONLY"""
cur = connection.cursor()
for row in cur.execute(sql, offset=myoffset, maxnumrows=mymaxnumrows):
print(row)
In applications where the SQL query is not known in advance, this method
sometimes involves appending the ``OFFSET`` clause to the 'real' user query. Be
very careful to avoid SQL injection security issues.
For Oracle Database 11g and earlier there are several alternative ways
to limit the number of rows returned. The old, canonical paging query
is::
SELECT *
FROM (SELECT a.*, ROWNUM AS rnum
FROM (YOUR_QUERY_GOES_HERE -- including the order by) a
WHERE ROWNUM <= MAX_ROW)
WHERE rnum >= MIN_ROW
Here, ``MIN_ROW`` is the row number of first row and ``MAX_ROW`` is the row
number of the last row to return. For example::
SELECT *
FROM (SELECT a.*, ROWNUM AS rnum
FROM (SELECT last_name FROM employees ORDER BY last_name) a
WHERE ROWNUM <= 20)
WHERE rnum >= 1
This always has an 'extra' column, here called RNUM.
An alternative and preferred query syntax for Oracle Database 11g uses the
analytic ``ROW_NUMBER()`` function. For example to get the 1st to 20th names the
query is::
SELECT last_name FROM
(SELECT last_name,
ROW_NUMBER() OVER (ORDER BY last_name) AS myr
FROM employees)
WHERE myr BETWEEN 1 and 20
Make sure to use :ref:`bind variables <bind>` for the upper and lower limit
values.
.. _crc:
Client Result Cache
-------------------
Python cx_Oracle applications can use Oracle Database's `Client Result Cache
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-35CB2592-7588-4C2D-9075-6F639F25425E>`__
The CRC enables client-side caching of SQL query (SELECT statement) results in
client memory for immediate use when the same query is re-executed. This is
useful for reducing the cost of queries for small, mostly static, lookup tables,
such as for postal codes. CRC reduces network :ref:`round-trips <roundtrips>`,
and also reduces database server CPU usage.
The cache is at the application process level. Access and invalidation is
managed by the Oracle Client libraries. This removes the need for extra
application logic, or external utilities, to implement a cache.
CRC can be enabled by setting the `database parameters
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-A9D4A5F5-B939-48FF-80AE-0228E7314C7D>`__
``CLIENT_RESULT_CACHE_SIZE`` and ``CLIENT_RESULT_CACHE_LAG``, and then
restarting the database. For example, to set the parameters:
.. code-block:: sql
SQL> ALTER SYSTEM SET CLIENT_RESULT_CACHE_LAG = 3000 SCOPE=SPFILE;
SQL> ALTER SYSTEM SET CLIENT_RESULT_CACHE_SIZE = 64K SCOPE=SPFILE;
CRC can alternatively be configured in an :ref:`oraaccess.xml <optclientfiles>`
or :ref:`sqlnet.ora <optnetfiles>` file on the Python host, see `Client
Configuration Parameters
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-E63D75A1-FCAA-4A54-A3D2-B068442CE766>`__.
Tables can then be created, or altered, so repeated queries use CRC. This
allows existing applications to use CRC without needing modification. For example:
.. code-block:: sql
SQL> CREATE TABLE cities (id number, name varchar2(40)) RESULT_CACHE (MODE FORCE);
SQL> ALTER TABLE locations RESULT_CACHE (MODE FORCE);
Alternatively, hints can be used in SQL statements. For example:
.. code-block:: sql
SELECT /*+ result_cache */ postal_code FROM locations
.. _fetching-raw-data:
Fetching Raw Data
-----------------
Sometimes cx_Oracle may have problems converting data stored in the database to
Python strings. This can occur if the data stored in the database doesn't match
the character set defined by the database. The `encoding_errors` parameter to
:meth:`Cursor.var()` permits the data to be returned with some invalid data
replaced, but for additional control the parameter `bypass_decode` can be set
to `True` and cx_Oracle will bypass the decode step and return `bytes` instead
of `str` for data stored in the database as strings. The data can then be
examined and corrected as required. This approach should only be used for
troubleshooting and correcting invalid data, not for general use!
The following sample demonstrates how to use this feature:
.. code-block:: python
# define output type handler
def return_strings_as_bytes(cursor, name, default_type, size,
precision, scale):
if default_type == cx_Oracle.DB_TYPE_VARCHAR:
return cursor.var(str, arraysize=cursor.arraysize,
bypass_decode=True)
# set output type handler on cursor before fetching data
with connection.cursor() as cursor:
cursor.outputtypehandler = return_strings_as_bytes
cursor.execute("select content, charset from SomeTable")
data = cursor.fetchall()
This will produce output as::
[(b'Fianc\xc3\xa9', b'UTF-8')]
Note that last ``\xc3\xa9`` is é in UTF-8. Since this is valid UTF-8 you can then
perform a decode on the data (the part that was bypassed):
.. code-block:: python
value = data[0][0].decode("UTF-8")
This will return the value "Fiancé".
If you want to save ``b'Fianc\xc3\xa9'`` into the database directly without
using a Python string, you will need to create a variable using
:meth:`Cursor.var()` that specifies the type as
:data:`~cx_Oracle.DB_TYPE_VARCHAR` (otherwise the value will be treated as
:data:`~cx_Oracle.DB_TYPE_RAW`). The following sample demonstrates this:
.. code-block:: python
with cx_Oracle.connect(user="hr", password=userpwd,
dsn="dbhost.example.com/orclpdb1") as conn:
with conn.cursor() cursor:
var = cursor.var(cx_Oracle.DB_TYPE_VARCHAR)
var.setvalue(0, b"Fianc\xc4\x9b")
cursor.execute("""
update SomeTable set
SomeColumn = :param
where id = 1""",
param=var)
.. warning::
The database will assume that the bytes provided are in the character set
expected by the database so only use this for troubleshooting or as
directed.
.. _codecerror:
Querying Corrupt Data
---------------------
If queries fail with the error "codec can't decode byte" when you select data,
then:
* Check your :ref:`character set <globalization>` is correct. Review the
:ref:`client and database character sets <findingcharset>`. Check with
:ref:`fetching-raw-data`. Consider using UTF-8, if this is appropriate:
.. code-block:: python
connection = cx_Oracle.connect(user="hr", password=userpwd,
dsn="dbhost.example.com/orclpdb1",
encoding="UTF-8", nencoding="UTF-8")
* Check for corrupt data in the database.
If data really is corrupt, you can pass options to the internal `decode()
<https://docs.python.org/3/library/stdtypes.html#bytes.decode>`__ used by
cx_Oracle to allow it to be selected and prevent the whole query failing. Do
this by creating an :ref:`outputtypehandler <outputtypehandlers>` and setting
``encoding_errors``. For example to replace corrupt characters in character
columns:
.. code-block:: python
def output_type_handler(cursor, name, default_type, size, precision, scale):
if default_type == cx_Oracle.DB_TYPE_VARCHAR:
return cursor.var(default_type, size, arraysize=cursor.arraysize,
encoding_errors="replace")
cursor.outputtypehandler = output_type_handler
cursor.execute("select column1, column2 from SomeTableWithBadData")
Other codec behaviors can be chosen for ``encoding_errors``, see `Error Handlers
<https://docs.python.org/3/library/codecs.html#error-handlers>`__.
.. _dml:
INSERT and UPDATE Statements
============================
SQL Data Manipulation Language statements (DML) such as INSERT and UPDATE can
easily be executed with cx_Oracle. For example:
.. code-block:: python
cur = connection.cursor()
cur.execute("insert into MyTable values (:idbv, :nmbv)", [1, "Fredico"])
Do not concatenate or interpolate user data into SQL statements. See
:ref:`bind` instead.
See :ref:`txnmgmnt` for best practices on committing and rolling back data
changes.
When handling multiple data values, use :meth:`~Cursor.executemany()` for
performance. See :ref:`batchstmnt`
Inserting NULLs
---------------
Oracle requires a type, even for null values. When you pass the value None, then
cx_Oracle assumes the type is STRING. If this is not the desired type, you can
explicitly set it. For example, to insert a null :ref:`Oracle Spatial
SDO_GEOMETRY <spatial>` object:
.. code-block:: python
type_obj = connection.gettype("SDO_GEOMETRY")
cur = connection.cursor()
cur.setinputsizes(type_obj)
cur.execute("insert into sometable values (:1)", [None])

View File

@ -1,69 +0,0 @@
.. _startup:
*************************************
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.
===========================
Starting Oracle Database Up
===========================
cx_Oracle can start up a database instance. A privileged connection is
required. This example shows a script that could be run as the 'oracle'
operating system user who administers a local database installation on Linux.
It assumes that the environment variable ``ORACLE_SID`` has been set to the SID
of the database that should be started:
.. code-block:: python
# the connection must be in PRELIM_AUTH mode to perform startup
connection = cx_Oracle.connect(mode=cx_Oracle.SYSDBA | cx_Oracle.PRELIM_AUTH)
connection.startup()
# the following statements must be issued in normal SYSDBA mode
connection = cx_Oracle.connect(mode=cx_Oracle.SYSDBA, encoding="UTF-8")
cursor = connection.cursor()
cursor.execute("alter database mount")
cursor.execute("alter database open")
To start up a remote database, you may need to configure the Oracle Net
listener to use `static service registration
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&
id=GUID-0203C8FA-A4BE-44A5-9A25-3D1E578E879F>`_
by adding a ``SID_LIST_LISTENER`` entry to the database `listener.ora` file.
=============================
Shutting Oracle Database Down
=============================
cx_Oracle has the ability to shutdown the database using a privileged
connection. This example also assumes that the environment variable
``ORACLE_SID`` has been set:
.. code-block:: python
# need to connect as SYSDBA or SYSOPER
connection = cx_Oracle.connect(mode=cx_Oracle.SYSDBA)
# first shutdown() call must specify the mode, if DBSHUTDOWN_ABORT is used,
# there is no need for any of the other steps
connection.shutdown(mode=cx_Oracle.DBSHUTDOWN_IMMEDIATE)
# now close and dismount the database
cursor = connection.cursor()
cursor.execute("alter database close normal")
cursor.execute("alter database dismount")
# perform the final shutdown call
connection.shutdown(mode=cx_Oracle.DBSHUTDOWN_FINAL)

View File

@ -1,175 +0,0 @@
.. _tracingsql:
*********************************
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
====================
Subclassing enables applications to add "hooks" for connection and statement
execution. This can be used to alter, or log, connection and execution
parameters, and to extend cx_Oracle functionality.
The example below demonstrates subclassing a connection to log SQL execution
to a file. This example also shows how connection credentials can be embedded
in the custom subclass, so application code does not need to supply them.
.. code-block:: python
class Connection(cx_Oracle.Connection):
log_file_name = "log.txt"
def __init__(self):
connect_string = "hr/hr_password@dbhost.example.com/orclpdb1"
self._log("Connect to the database")
return super(Connection, self).__init__(connect_string)
def _log(self, message):
with open(self.log_file_name, "a") as f:
print(message, file=f)
def execute(self, sql, parameters):
self._log(sql)
cursor = self.cursor()
try:
return cursor.execute(sql, parameters)
except cx_Oracle.Error as e:
error_obj, = e.args
self._log(error_obj.message)
raise
connection = Connection()
connection.execute("""
select department_name
from departments
where department_id = :id""", dict(id=270))
The messages logged in ``log.txt`` are::
Connect to the database
select department_name
from departments
where department_id = :id
If an error occurs, perhaps due to a missing table, the log file would contain
instead::
Connect to the database
select department_name
from departments
where department_id = :id
ORA-00942: table or view does not exist
In production applications be careful not to log sensitive information.
See `Subclassing.py
<https://github.com/oracle/python-cx_Oracle/blob/main/
samples/subclassing.py>`__ for an example.
.. _endtoendtracing:
Oracle Database End-to-End Tracing
==================================
Oracle Database End-to-end application tracing simplifies diagnosing application
code flow and performance problems in multi-tier or multi-user environments.
The connection attributes, :attr:`~Connection.client_identifier`,
:attr:`~Connection.clientinfo`, :attr:`~Connection.dbop`,
:attr:`~Connection.module` and :attr:`~Connection.action`, set the metadata for
end-to-end tracing. You can use data dictionary and ``V$`` views to monitor
tracing or use other application tracing utilities.
The attributes are sent to the database when the next :ref:`round-trip
<roundtrips>` to the database occurs, for example when the next SQL statement is
executed.
The attribute values will remain set in connections released back to connection
pools. When the application re-acquires a connection from the pool it should
initialize the values to a desired state before using that connection.
The example below shows setting the action, module and client identifier
attributes on the connection object:
.. code-block:: python
# Set the tracing metadata
connection.client_identifier = "pythonuser"
connection.action = "Query Session tracing parameters"
connection.module = "End-to-end Demo"
for row in cursor.execute("""
SELECT username, client_identifier, module, action
FROM V$SESSION
WHERE username = 'SYSTEM'"""):
print(row)
The output will be::
('SYSTEM', 'pythonuser', 'End-to-end Demo', 'Query Session tracing parameters')
The values can also be manually set as shown by calling
`DBMS_APPLICATION_INFO procedures
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&
id=GUID-14484F86-44F2-4B34-B34E-0C873D323EAD>`__
or `DBMS_SESSION.SET_IDENTIFIER
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&
id=GUID-988EA930-BDFE-4205-A806-E54F05333562>`__. These incur round-trips to
the database, however, reducing scalability.
.. code-block:: sql
BEGIN
DBMS_SESSION.SET_IDENTIFIER('pythonuser');
DBMS_APPLICATION_INFO.set_module('End-to-End Demo');
DBMS_APPLICATION_INFO.set_action(action_name => 'Query Session tracing parameters');
END;
Low Level SQL Tracing in cx_Oracle
==================================
cx_Oracle is implemented using the `ODPI-C <https://oracle.github.io/odpi>`__
wrapper on top of the Oracle Client libraries. The ODPI-C tracing capability
can be used to log executed cx_Oracle statements to the standard error stream.
Before executing Python, set the environment variable ``DPI_DEBUG_LEVEL`` to
16.
At a Windows command prompt, this could be done with::
set DPI_DEBUG_LEVEL=16
On Linux, you might use::
export DPI_DEBUG_LEVEL=16
After setting the variable, run the Python Script, for example on Linux::
python end-to-endtracing.py 2> log.txt
For an application that does a single query, the log file might contain a
tracing line consisting of the prefix 'ODPI', a thread identifier, a timestamp,
and the SQL statement executed::
ODPI [26188] 2019-03-26 09:09:03.909: ODPI-C 3.1.1
ODPI [26188] 2019-03-26 09:09:03.909: debugging messages initialized at level 16
ODPI [26188] 2019-03-26 09:09:09.917: SQL SELECT * FROM jobss
Traceback (most recent call last):
File "end-to-endtracing.py", line 14, in <module>
cursor.execute("select * from jobss")
cx_Oracle.DatabaseError: ORA-00942: table or view does not exist
See `ODPI-C Debugging
<https://oracle.github.io/odpi/doc/user_guide/debugging.html>`__ for
documentation on ``DPI_DEBUG_LEVEL``.

View File

@ -1,406 +0,0 @@
.. _tuning:
****************
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.
A general application goal is to reduce the number of :ref:`round-trips
<roundtrips>` between cx_Oracle and the database.
For multi-user applications, make use of connection pooling. Create the pool
once during application initialization. Do not oversize the pool, see
:ref:`connpool` . Use a session callback function to set session state, see
:ref:`Session CallBacks for Setting Pooled Connection State <sessioncallback>`.
Make use of efficient cx_Oracle functions. For example, to insert
multiple rows use :meth:`Cursor.executemany()` instead of
:meth:`Cursor.execute()`.
* Tune your SQL statements. See the `SQL Tuning Guide
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=TGSQL>`__.
Use :ref:`bind variables <bind>` to avoid statement reparsing.
Tune :attr:`Cursor.arraysize` and :attr:`Cursor.prefetchrows` for each query,
see :ref:`Tuning Fetch Performance <tuningfetch>`.
Do simple optimizations like :ref:`limiting the number of rows <rowlimit>` and
avoiding selecting columns not used in the application.
It may be faster to work with simple scalar relational values than to use
Oracle Database object types.
Make good use of PL/SQL to avoid executing many individual statements from
cx_Oracle.
Tune the :ref:`Statement Cache <stmtcache>`.
Enable :ref:`Client Result Caching <clientresultcache>` for small lookup tables.
* Tune your database. See the `Database Performance Tuning Guide
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=TGDBA>`__.
* Tune your network. For example, when inserting or retrieving a large number
of rows (or for large data), or when using a slow network, then tune the
Oracle Network Session Data Unit (SDU) and socket buffer sizes, see `Oracle
Net Services: Best Practices for Database Performance and High Availability
<https://static.rainfocus.com/oracle/oow19/sess/1553616880266001WLIh/PF/OOW19_Net_CON4641_1569022126580001esUl.pdf>`__.
* Do not commit or rollback unnecessarily. Use :attr:`Connection.autocommit` on
the last of a sequence of DML statements.
.. _tuningfetch:
Tuning Fetch Performance
========================
To tune queries you can adjust cx_Oracle's internal buffer sizes to improve the
speed of fetching rows across the network from the database, and to optimize
memory usage. Regardless of which cx_Oracle method is used to get query
results, internally all rows are fetched in batches from the database and
buffered before being returned to the application. The internal buffer sizes
can have a significant performance impact. The sizes do not affect how, or
when, rows are returned to your application. They do not affect the minimum or
maximum number of rows returned by a query.
For best performance, tune "array fetching" with :attr:`Cursor.arraysize` and
"row prefetching" with :attr:`Cursor.prefetchrows` before calling
:meth:`Cursor.execute()`. Queries that return LOBs and similar types will never
prefetch rows, so the ``prefetchrows`` value is ignored in those cases.
The common query tuning scenario is for SELECT statements that return a large
number of rows over a slow network. Increasing ``arraysize`` can improve
performance by reducing the number of :ref:`round-trips <roundtrips>` to the
database. However increasing this value increases the amount of memory
required. Adjusting ``prefetchrows`` will also affect performance and memory
usage.
Row prefetching and array fetching are both internal buffering techniques to
reduce :ref:`round-trips <roundtrips>` to the database. The difference is the
code layer that is doing the buffering, and when the buffering occurs. The
Oracle Client libraries used by cx_Oracle have separate "execute SQL statement"
and "fetch data" calls. Prefetching allows query results to be returned to the
application when the successful statement execution acknowledgment is returned
from the database. This means that a subsequent internal "fetch data" operation
does not always need to make a round-trip to the database because rows are
already buffered in the Oracle Client libraries. Reducing round-trips helps
performance and scalability. An overhead of prefetching is the need for an
additional data copy from Oracle Client's prefetch buffers.
Choosing values for ``arraysize`` and ``prefetchrows``
++++++++++++++++++++++++++++++++++++++++++++++++++++++
The best :attr:`Cursor.arraysize` and :attr:`Cursor.prefetchrows` values can be
found by experimenting with your application under the expected load of normal
application use. This is because the cost of the extra memory copy from the
prefetch buffers when fetching a large quantity of rows or very "wide" rows may
outweigh the cost of a round-trip for a single cx_Oracle user on a fast network.
However under production application load, the reduction of round-trips may help
performance and overall system scalability. The documentation in
:ref:`round-trips <roundtrips>` shows how to measure round-trips.
Here are some suggestions for the starting point to begin your tuning:
* To tune queries that return an unknown number of rows, estimate the number of
rows returned and start with an appropriate :attr:`Cursor.arraysize` value.
The default is 100. Then set :attr:`Cursor.prefetchrows` to the ``arraysize``
value. For example:
.. code-block:: python
cur = connection.cursor()
cur.prefetchrows = 1000
cur.arraysize = 1000
for row in cur.execute("SELECT * FROM very_big_table"):
print(row)
Adjust the values as needed for performance, memory and round-trip usage. Do
not make the sizes unnecessarily large. For a large quantity of rows or very
"wide" rows on fast networks you may prefer to leave ``prefetchrows`` at its
default value of 2. Keep ``arraysize`` as big, or bigger than,
``prefetchrows``.
* If you are fetching a fixed number of rows, start your tuning by setting
``arraysize`` to the number of expected rows, and set ``prefetchrows`` to one
greater than this value. (Adding one removes the need for a round-trip to check
for end-of-fetch). For example, if you are querying 20 rows, perhaps to
:ref:`display a page <rowlimit>` of data, set ``prefetchrows`` to 21 and
``arraysize`` to 20:
.. code-block:: python
cur = connection.cursor()
cur.prefetchrows = 21
cur.arraysize = 20
for row in cur.execute("""
SELECT last_name
FROM employees
ORDER BY last_name
OFFSET 0 ROWS FETCH NEXT 20 ROWS ONLY"""):
print(row)
This will return all rows for the query in one round-trip.
* If you know that a query returns just one row then set :attr:`Cursor.arraysize`
to 1 to minimize memory usage. The default prefetch value of 2 allows minimal
round-trips for single-row queries:
.. code-block:: python
cur = connection.cursor()
cur.arraysize = 1
cur.execute("select * from MyTable where id = 1"):
row = cur.fetchone()
print(row)
In cx_Oracle, the ``arraysize`` and ``prefetchrows`` values are only examined
when a statement is executed the first time. To change the values, create a new
cursor. For example, to change ``arraysize`` for a repeated statement:
.. code-block:: python
array_sizes = (10, 100, 1000)
for size in array_sizes:
cursor = connection.cursor()
cursor.arraysize = size
start = time.time()
cursor.execute(sql).fetchall()
elapsed = time.time() - start
print("Time for", size, elapsed, "seconds")
There are two cases that will benefit from setting :attr:`Cursor.prefetchrows`
to 0:
* When passing REF CURSORS into PL/SQL packages. Setting ``prefetchrows`` to 0
can stop rows being prematurely (and silently) fetched into cx_Oracle's
internal buffers, making them unavailable to the PL/SQL code that receives the
REF CURSOR.
* When querying a PL/SQL function that uses PIPE ROW to emit rows at
intermittent intervals. By default, several rows needs to be emitted by the
function before cx_Oracle can return them to the application. Setting
``prefetchrows`` to 0 helps give a consistent flow of data to the application.
Prefetching can also be enabled in an external :ref:`oraaccess.xml
<optclientfiles>` file, which may be useful for tuning an application when
modifying its code is not feasible. Setting the size in ``oraaccess.xml`` will
affect the whole application, so it should not be the first tuning choice.
One place where increasing ``arraysize`` is particularly useful is in copying
data from one database to another:
.. code-block:: python
# setup cursors
source_cursor = source_connection.cursor()
source_cursor.arraysize = 1000
target_cursor = target_connection.cursor()
# perform fetch and bulk insertion
source_cursor.execute("select * from MyTable")
while True:
rows = source_cursor.fetchmany()
if not rows:
break
target_cursor.executemany("insert into MyTable values (:1, :2)", rows)
target_connection.commit()
Tuning REF CURSORS
++++++++++++++++++
In cx_Oracle, REF CURSORS can also be tuned by setting the values of ``arraysize``
and ``prefetchrows``. The prefetchrows value must be set before calling the PL/SQL
procedure as the REF CURSOR is executed on the server.
For example:
.. code-block:: python
# Set the arraysize and prefetch rows of the REF cursor
ref_cursor = connection.cursor()
ref_cursor.prefetchrows = 1000
ref_cursor.arraysize = 1000
# Perform the tuned fetch
sum_rows = 0
cursor.callproc("myrefcursorproc", [ref_cursor])
print("Sum of IntCol for", num_rows, "rows:")
for row in ref_cursor:
sum_rows += row[0]
print(sum_rows)
.. _roundtrips:
Database Round-trips
====================
A round-trip is defined as the trip from the Oracle Client libraries (used by
cx_Oracle) to the database and back. Calling each cx_Oracle function, or
accessing each attribute, will require zero or more round-trips. Along with
tuning an application's architecture and `tuning its SQL statements
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=TGSQL>`__, a general
performance and scalability goal is to minimize `round-trips
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-9B2F05F9-D841-4493-A42D-A7D89694A2D1>`__.
Some general tips for reducing round-trips are:
* Tune :attr:`Cursor.arraysize` and :attr:`Cursor.prefetchrows` for each query.
* Use :meth:`Cursor.executemany()` for optimal DML execution.
* Only commit when necessary. Use :attr:`Connection.autocommit` on the last statement of a transaction.
* For connection pools, use a callback to set connection state, see :ref:`Session CallBacks for Setting Pooled Connection State <sessioncallback>`.
* Make use of PL/SQL procedures which execute multiple SQL statements instead of executing them individually from cx_Oracle.
* Use scalar types instead of Oracle Database object types.
* Avoid overuse of :meth:`Connection.ping()`.
* Avoid setting :data:`SessionPool.ping_interval` to 0 or a small value.
* When using SODA, use pooled connections and enable the :ref:`SODA metadata cache <sodametadatacache>`.
Finding the Number of Round-Trips
+++++++++++++++++++++++++++++++++
Oracle's `Automatic Workload Repository
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-56AEF38E-9400-427B-A818-EDEC145F7ACD>`__
(AWR) reports show 'SQL*Net roundtrips to/from client' and are useful for
finding the overall behavior of a system.
Sometimes you may wish to find the number of round-trips used for a
specific application. Snapshots of the ``V$SESSTAT`` view taken before
and after doing some work can be used for this:
.. code-block:: sql
SELECT ss.value, sn.display_name
FROM v$sesstat ss, v$statname sn
WHERE ss.sid = SYS_CONTEXT('USERENV','SID')
AND ss.statistic# = sn.statistic#
AND sn.name LIKE '%roundtrip%client%';
.. _stmtcache:
Statement Caching
=================
cx_Oracle's :meth:`Cursor.execute()` and :meth:`Cursor.executemany()` functions
use the `Oracle Call Interface statement cache
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-4947CAE8-1F00-4897-BB2B-7F921E495175>`__
for efficient re-execution of statements. Statement caching lets Oracle
Database cursors be used without re-parsing the statement. Statement caching
also reduces metadata transfer costs between cx_Oracle and the database.
Performance and scalability are improved.
Each standalone or pooled connection has its own cache of statements with a
default size of 20. The size can be set when creating connection pools or
standalone connections. The size can subsequently be changed with
:attr:`Connection.stmtcachesize` or :attr:`SessionPool.stmtcachesize`. In
general, set the statement cache size to the size of the working set of
statements being executed by the application. To manually tune the cache,
monitor the general application load and the `Automatic Workload Repository
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-56AEF38E-9400-427B-A818-EDEC145F7ACD>`__
(AWR) "bytes sent via SQL*Net to client" values. The latter statistic should
benefit from not shipping statement metadata to cx_Oracle. Adjust the statement
cache size to your satisfaction. With Oracle Database 12c, or later, the
statement cache size can be automatically tuned using an :ref:`oraaccess.xml
<optclientfiles>` file.
Statement caching can be disabled by setting the size to 0. Disabling
the cache may be beneficial when the quantity or order of statements
causes cache entries to be flushed before they get a chance to be
reused. For example if there are more distinct statements than cache
slots, and the order of statement execution causes older statements to
be flushed from the cache before the statements are re-executed.
With connection pools, the effect of changing :attr:`SessionPool.stmtcachesize`
after pool creation depends on the Oracle Client version:
- When using Oracle Client 21 (or later), changing the cache size does not
immediately affect connections previously acquired and currently in use. When
those connections are subsequently released to the pool and re-acquired, they
will then use the new value. If it is neccessary to change the size on a
connection because it is not being released to the pool, use
:data:`Connection.stmtcachesize`.
- When using Oracle Client prior to version 21, changing the pool's statement
cache size has no effect on connections that already exist in the pool but
will affect new connections that are subsequently created, for example when
the pool grows. To change the size on a connection, use
:data:`Connection.stmtcachesize`.
When it is inconvenient to pass statement text through an application, the
:meth:`Cursor.prepare()` call can be used to avoid statement re-parsing.
Subsequent ``execute()`` calls use the value ``None`` instead of the SQL text:
.. code-block:: python
cur.prepare("select * from dept where deptno = :id order by deptno")
cur.execute(None, id = 20)
res = cur.fetchall()
print(res)
cur.execute(None, id = 10)
res = cur.fetchall()
print(res)
Statements passed to :meth:`~Cursor.prepare()` are also stored in the statement
cache.
.. _clientresultcache:
Client Result Caching
=====================
cx_Oracle applications can use Oracle Database's `Client Result Cache
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-35CB2592-7588-4C2D-9075-6F639F25425E>`__.
The CRC enables client-side caching of SQL query (SELECT statement) results in
client memory for immediate use when the same query is re-executed. This is
useful for reducing the cost of queries for small, mostly static, lookup tables,
such as for postal codes. CRC reduces network :ref:`round-trips <roundtrips>`,
and also reduces database server CPU usage.
The cache is at the application process level. Access and invalidation is
managed by the Oracle Client libraries. This removes the need for extra
application logic, or external utilities, to implement a cache.
CRC can be enabled by setting the `database parameters
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-A9D4A5F5-B939-48FF-80AE-0228E7314C7D>`__
``CLIENT_RESULT_CACHE_SIZE`` and ``CLIENT_RESULT_CACHE_LAG``, and then
restarting the database, for example:
.. code-block:: sql
SQL> ALTER SYSTEM SET CLIENT_RESULT_CACHE_LAG = 3000 SCOPE=SPFILE;
SQL> ALTER SYSTEM SET CLIENT_RESULT_CACHE_SIZE = 64K SCOPE=SPFILE;
SQL> STARTUP FORCE
CRC can alternatively be configured in an :ref:`oraaccess.xml <optclientfiles>`
or :ref:`sqlnet.ora <optnetfiles>` file on the Python host, see `Client
Configuration Parameters
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-E63D75A1-FCAA-4A54-A3D2-B068442CE766>`__.
Tables can then be created, or altered, so repeated queries use CRC. This
allows existing applications to use CRC without needing modification. For example:
.. code-block:: sql
SQL> CREATE TABLE cities (id number, name varchar2(40)) RESULT_CACHE (MODE FORCE);
SQL> ALTER TABLE locations RESULT_CACHE (MODE FORCE);
Alternatively, hints can be used in SQL statements. For example:
.. code-block:: sql
SELECT /*+ result_cache */ postal_code FROM locations

View File

@ -1,84 +0,0 @@
.. _txnmgmnt:
**********************
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.
When :meth:`Cursor.execute()` executes a SQL statement, a transaction is
started or continued. By default, cx_Oracle does not commit this transaction
to the database. The methods :meth:`Connection.commit()` and
:meth:`Connection.rollback()` methods can be used to explicitly commit
or rollback a transaction:
.. code-block:: python
cursor.execute("INSERT INTO mytab (name) VALUES ('John')")
connection.commit()
When a database connection is closed, such as with :meth:`Connection.close()`,
or when variables referencing the connection go out of scope, any uncommitted
transaction will be rolled back.
Autocommitting
==============
An alternative way to commit is to set the attribute
:attr:`~Connection.autocommit` of the connection to ``True``. This ensures all
:ref:`DML <dml>` statements (INSERT, UPDATE etc) are committed as they are
executed. Unlike :meth:`Connection.commit()`, this does not require an
additional :ref:`round-trip <roundtrips>` to the database so it is more
efficient when used appropriately.
Note that irrespective of the autocommit value, Oracle Database will always
commit an open transaction when a DDL statement is executed.
When executing multiple DML statements that constitute a single transaction, it
is recommended to use autocommit mode only for the last DML statement in the
sequence of operations. Unnecessarily committing causes extra database load,
and can destroy transactional consistency.
The example below shows a new customer being added to the table ``CUST_TABLE``.
The corresponding ``SALES`` table is updated with a purchase of 3000 pens from
the customer. The final insert uses autocommit mode to commit both new
records:
.. code-block:: python
# Add a new customer
id_var = cursor.var(int)
connection.autocommit = False # make sure any previous value is off
cursor.execute("""
INSERT INTO cust_table (name) VALUES ('John')
RETURNING id INTO :bvid""", bvid=id_var)
# Add sales data for the new customer and commit all new values
id_val = id_var.getvalue()[0]
connection.autocommit = True
cursor.execute("INSERT INTO sales_table VALUES (:bvid, 'pens', 3000)",
bvid=id_val)
Explicit Transactions
=====================
The method :meth:`Connection.begin()` can be used to explicitly start a local
or global transaction.
Without parameters, this explicitly begins a local transaction; otherwise, this
explicitly begins a distributed (global) transaction with the given parameters.
See the Oracle documentation for more details.
Note that in order to make use of global (distributed) transactions, the
attributes :attr:`Connection.internal_name` and
:attr:`Connection.external_name` attributes must be set.

View File

@ -1,75 +0,0 @@
.. _xmldatatype:
********************
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.
The examples below demonstrate using XMLType data with cx_Oracle. The
following table will be used in these examples:
.. code-block:: sql
CREATE TABLE xml_table (
id NUMBER,
xml_data SYS.XMLTYPE
);
Inserting into the table can be done by simply binding a string as shown:
.. code-block:: python
xml_data = """<?xml version="1.0"?>
<customer>
<name>John Smith</name>
<Age>43</Age>
<Designation>Professor</Designation>
<Subject>Mathematics</Subject>
</customer>"""
cursor.execute("insert into xml_table values (:id, :xml)",
id=1, xml=xml_data)
This approach works with XML strings up to 1 GB in size. For longer strings, a
temporary CLOB must be created using :meth:`Connection.createlob()` and bound
as shown:
.. code-block:: python
clob = connection.createlob(cx_Oracle.DB_TYPE_CLOB)
clob.write(xml_data)
cursor.execute("insert into xml_table values (:id, sys.xmltype(:xml))",
id=2, xml=clob)
Fetching XML data can be done simply for values that are shorter than the
length of a VARCHAR2 column, as shown:
.. code-block:: python
cursor.execute("select xml_data from xml_table where id = :id", id=1)
xml_data, = cursor.fetchone()
print(xml_data) # will print the string that was originally stored
For values that exceed the length of a VARCHAR2 column, a CLOB must be returned
instead by using the function ``XMLTYPE.GETCLOBVAL()`` as shown:
.. code-block:: python
cursor.execute("""
select xmltype.getclobval(xml_data)
from xml_table
where id = :id""", id=1)
clob, = cursor.fetchone()
print(clob.read())
The LOB that is returned can be streamed or a string can be returned instead of
a CLOB. See :ref:`lobdata` for more information about processing LOBs.

BIN
favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

255
index.html Normal file
View File

@ -0,0 +1,255 @@
<!DOCTYPE html>
<html itemscope="itemscope" itemtype="http://schema.org/WebPage" lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>cx_Oracle - Python Interface for Oracle Database</title>
<link rel="stylesheet" href="base.css" type="text/css" />
<link rel="shortcut icon" type="image/ico" href="favicon.ico" />
</head>
<body>
<div class="oracleHeader">
<div class="container">
<a class="oracleLogo" href="https://www.oracle.com/">Oracle</a>
</div>
</div>
<header class="header" role="banner">
<div class="container">
<div class="headerLogoContainer">
<img class="headerLogo" alt="cx_Oracle logo" src="logo.png" />
</div>
<div class="headerContent">
<h1 class="headerTitle">Python cx_Oracle</h1>
<nav class="headerNav" role="navigation">
<ul>
<li><a href="https://cx-oracle.readthedocs.io/en/latest/index.html">Documentation</a></li>
<li><a href="https://cx-oracle.readthedocs.io/en/latest/user_guide/installation.html" >Installation</a></li>
<li><a href="https://cx-oracle.readthedocs.io/en/latest/release_notes.html#releasenotes">Release Notes</a></li>
<li><a href="https://github.com/oracle/python-cx_Oracle">Source code</a></li>
<li><a href="https://github.com/oracle/python-cx_Oracle/issues">Help</a></li>
</ul>
</nav>
</div>
</div>
</header>
<main class="mainContent" role="main">
<div class="container">
<div class="announcement">
<p><strong>cx_Oracle has a major new release under a new name and
homepage <a href="https://oracle.github.io/python-oracledb/"
>python-oracledb</a>.</strong></p>
<p><strong>Follow the python-oracledb <a
href="https://python-oracledb.readthedocs.io/en/latest/user_guide/installation.html"
>installation instructions</a> to start using
the upgrade today.</strong></p>
</div> <!-- announcement -->
<div id="about">
<h2>About cx_Oracle</h2>
<p><strong>cx_Oracle</strong> is a Python extension module that
enables access to Oracle Database. It conforms to the Python
database API 2.0 <a
href="https://peps.python.org/pep-0249/">
specification</a> with a considerable number of additions and a
couple of exclusions.</p>
<p>cx_Oracle 8.3 was tested with Python versions 3.6 through 3.10.
Older versions of cx_Oracle may be used with previous Python releases.
You can use cx_Oracle with Oracle 11.2, 12, 18, 19 and 21 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.</p>
</div> <!-- /about -->
<div id="quickstart">
<h2>Getting Started</h2>
See <a
href="https://cx-oracle.readthedocs.io/en/latest/user_guide/installation.html#quick-start-cx-oracle-installation"
>Quick Start cx_Oracle Installation</a> and the <a
href="samples/tutorial/Python-and-Oracle-Database-Scripting-for-the-Future.html">Python
and Oracle Database Tutorial: Scripting for the Future</a>.
</div> <!-- /quickstart -->
<div id="installation">
<h2>Installation</h2>
See <a
href="https://cx-oracle.readthedocs.io/en/latest/user_guide/installation.html"
>cx_Oracle Installation</a> for detailed instructions.
</div> <!-- /installation -->
<div id="documentation">
<h2>Documentation</h2>
See the <a href="https://cx-oracle.readthedocs.io" >cx_Oracle
Documentation</a> and <a
href="https://cx-oracle.readthedocs.io/en/latest/release_notes.html#releasenotes"
>Release Notes</a>.
</div> <!-- /documentation -->
<div id="example">
<h2>Samples</h2>
See the <a
href="https://github.com/oracle/python-cx_Oracle/tree/main/samples"
>/samples</a> directory. You can also look at the scripts in <a
href="https://github.com/anthony-tuininga/cx_OracleTools">cx_OracleTools</a>
and the modules in <a
href="https://github.com/anthony-tuininga/cx_PyOracleLib">cx_PyOracleLib</a>.
</div> <!-- /example -->
<div id="help">
<h2>Help</h2>
<p>Issues and questions can be raised with the cx_Oracle community on
<a href="https://github.com/oracle/python-cx_Oracle/issues"
>GitHub</a> or on the <a
href="https://sourceforge.net/projects/cx-oracle/lists/cx-oracle-users"
>mailing list</a>.</p>
</div> <!-- /help -->
<div id="tests">
<h2>Tests</h2>
See the <a href="https://github.com/oracle/python-cx_Oracle/tree/main/test" >test suite</a>.
</div> <!-- /tests -->
<div id="contribuing">
<h2>Contributing</h2>
See <a href="https://github.com/oracle/python-cx_Oracle/blob/main/CONTRIBUTING.md" >CONTRIBUTING</a>.
</div> <!-- /contributing -->
<div id="features">
<h2>Features</h2>
<ul>
<li><p>Easily installed from PyPI.</p></li>
<li><p>Support for Python 3.6 and higher. Older versions of cx_Oracle may
be used with previous Python releases.</p></li>
<li><p>Support for Oracle Client 11.2, 12, 18, 19 and 21.
Oracle's standard cross-version interoperability, allows easy upgrades
and connectivity to different Oracle Database versions.</p></li>
<li><p>Connect to Oracle Database 9.2, 10, 11, 12, 18, 19 or 21
(depending on the Oracle Client version used).</p></li>
<li><p>SQL and PL/SQL Execution. The underlying Oracle Client
libraries have significant optimizations including compressed fetch,
pre-fetching, client and server result set caching, and statement
caching with auto-tuning.</p></li>
<li><p>Full use of Oracle Network Service infrastructure, including
encrypted network traffic and security features.</p></li>
<li><p>Extensive Oracle data type support, including large object
support (CLOB and BLOB).</p></li>
<li><p>Direct binding to SQL objects. One great use case is binding
Python objects to Oracle Spatial SDO objects.</p></li>
<li><p>JSON datatype support.</p></li>
<li><p>SODA (Simple Oracle Document Access).</p></li>
<li><p>Array operations for efficient INSERT and UPDATEs.</p></li>
<li><p>Array row counts and batch error handling for array operations.</p></li>
<li><p>Fetching of large result sets.</p></li>
<li><p>REF CURSOR support.</p></li>
<li><p>Support for scrollable cursors. Go back and forth through your
query results.</p></li>
<li><p>Fetch PL/SQL Implicit Results. Easily return query results from
PL/SQL.</p></li>
<li><p>Row Prefetching. Efficient use of the network.</p></li>
<li><p>Client Result Caching. Improve performance of frequently
executed look-up statements.</p></li>
<li><p>Support for Advanced Queuing. Use database notifications to
build micro-service applications.</p></li>
<li><p>Continuous Query Notification (CQN). Get notified when data
changes.</p></li>
<li><p>Support for Edition Based Redefinition. Easily switch
applications to use updated PL/SQL logic.</p></li>
<li><p>Support for setting application context during the creation of
a connection, making application metadata more accessible to the
database, including in LOGON triggers.</p></li>
<li><p>End-to-end monitoring and tracing.</p></li>
<li><p>Transaction Management.</p></li>
<li><p>Session Pooling, with tagging and session state fix-up callback.</p></li>
<li><p>Database Resident Connection Pooling (DRCP).</p></li>
<li><p>Privileged Connections.</p></li>
<li><p>External Authentication.</p></li>
<li><p>Database startup and shutdown.</p></li>
<li><p>Sharded Databases.</p></li>
<li><p>Oracle Database High Availability Features, such as FAN
notifications, Application Continuity, and Transaction Guard support.</p></li>
</ul>
<p>DB API specification exclusions: The time data type is not
supported by Oracle and is therefore not implemented. The method
<code>cursor.nextset()</code> is not implemented either as the DB API
specification assumes an implementation of cursors that does not fit
well with Oracle's implementation of cursors and implicit results. See
the method
<a href="https://cx-oracle.readthedocs.io/en/latest/api_manual/cursor.html#Cursor.getimplicitresults">cursor.getimplicitresults()</a>
for more information.
</p>
</div> <!-- /features -->
<div id="license">
<h2>License</h2>
<p>cx_Oracle is licensed under a BSD license which you can find <a
href="https://github.com/oracle/python-cx_Oracle/blob/main/LICENSE.txt"
>here</a>. The cx_Oracle project is open source and maintained by Oracle Corp.</p>
</div> <!-- /license -->
</div>
</main>
</body>
</html>

BIN
logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

1
odpi

@ -1 +0,0 @@
Subproject commit f73a7c13d643b3fe252614bafc930afbd8e287dd

View File

@ -1,3 +0,0 @@
[build-system]
requires = ["setuptools >= 40.6.0", "wheel"]
build-backend = "setuptools.build_meta"

View File

@ -1,59 +0,0 @@
# Samples
## 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
requires SYSDBA privileges and will prompt for these credentials as well as
the names of the schemas and edition that will be created, unless a number
of environment variables are set as documented in the Python script
[sample_env.py][2]. Run the script using the following command:
python setup_samples.py
Alternatively, the [SQL script][3] can be run directly via SQL\*Plus, which
will always prompt for the names of the schemas and edition that will be
created.
sqlplus sys/syspassword@hostname/servicename @sql/setup_samples.sql
2. Run a Python script, for example:
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
requires SYSDBA privileges and will prompt for these credentials as well as
the names of the schemas and edition that will be dropped, unless a number
of environment variables are set as documented in the Python script
[sample_env.py][2]. Run the script using the following command:
python drop_samples.py
Alternatively, the [SQL script][5] can be run directly via SQL\*Plus, which
will always prompt for the names of the schemas and edition that will be
dropped.
sqlplus sys/syspassword@hostname/servicename @sql/drop_samples.sql
[1]: https://github.com/oracle/python-cx_Oracle/blob/main/samples/setup_samples.py
[2]: https://github.com/oracle/python-cx_Oracle/blob/main/samples/sample_env.py
[3]: https://github.com/oracle/python-cx_Oracle/blob/main/samples/sql/setup_samples.sql
[4]: https://github.com/oracle/python-cx_Oracle/blob/main/samples/drop_samples.py
[5]: https://github.com/oracle/python-cx_Oracle/blob/main/samples/sql/drop_samples.sql
[6]: https://oracle.github.io/python-cx_Oracle/
[7]: http://cx-oracle.readthedocs.org/en/latest/index.html
[8]: https://oracle.github.io/python-cx_Oracle/samples/tutorial/Python-and-Oracle-Database-Scripting-for-the-Future.html

View File

@ -1,36 +0,0 @@
#------------------------------------------------------------------------------
# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
#
# Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
#
# Portions Copyright 2001-2007, Computronix (Canada) Ltd., Edmonton, Alberta,
# Canada. All rights reserved.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# app_context.py
# This script demonstrates the use of application context. Application
# context is available within logon triggers and can be retrieved by using the
# function sys_context().
#
# This script requires cx_Oracle 5.3 and higher.
#------------------------------------------------------------------------------
import cx_Oracle as oracledb
import sample_env
# define constants used throughout the script; adjust as desired
APP_CTX_NAMESPACE = "CLIENTCONTEXT"
APP_CTX_ENTRIES = [
( APP_CTX_NAMESPACE, "ATTR1", "VALUE1" ),
( APP_CTX_NAMESPACE, "ATTR2", "VALUE2" ),
( APP_CTX_NAMESPACE, "ATTR3", "VALUE3" )
]
connection = oracledb.connect(sample_env.get_main_connect_string(),
appcontext=APP_CTX_ENTRIES)
cursor = connection.cursor()
for namespace, name, value in APP_CTX_ENTRIES:
cursor.execute("select sys_context(:1, :2) from dual", (namespace, name))
value, = cursor.fetchone()
print("Value of context key", name, "is", value)

View File

@ -1,46 +0,0 @@
#------------------------------------------------------------------------------
# Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# aq_notification.py
# This script demonstrates using advanced queuing notification. Once this
# script is running, use another session to enqueue a few messages to the
# "DEMO_BOOK_QUEUE" queue. This is most easily accomplished by running the
# object_aq.py sample.
#
# This script requires cx_Oracle 6.4 and higher.
#------------------------------------------------------------------------------
import time
import cx_Oracle as oracledb
import sample_env
registered = True
def process_messages(message):
global registered
print("Message type:", message.type)
if message.type == oracledb.EVENT_DEREG:
print("Deregistration has taken place...")
registered = False
return
print("Queue name:", message.queueName)
print("Consumer name:", message.consumerName)
connection = oracledb.connect(sample_env.get_main_connect_string(),
events=True)
sub = connection.subscribe(namespace=oracledb.SUBSCR_NAMESPACE_AQ,
name="DEMO_BOOK_QUEUE", callback=process_messages,
timeout=300)
print("Subscription:", sub)
print("--> Connection:", sub.connection)
print("--> Callback:", sub.callback)
print("--> Namespace:", sub.namespace)
print("--> Protocol:", sub.protocol)
print("--> Timeout:", sub.timeout)
while registered:
print("Waiting for notifications....")
time.sleep(5)

View File

@ -1,48 +0,0 @@
#------------------------------------------------------------------------------
# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# array_dml_rowcounts.py
#
# Demonstrate the use of the 12.1 feature that allows cursor.executemany()
# to return the number of rows affected by each individual execution as a list.
# The parameter "arraydmlrowcounts" must be set to True in the call to
# cursor.executemany() after which cursor.getarraydmlrowcounts() can be called.
#
# This script requires cx_Oracle 5.2 and higher.
#------------------------------------------------------------------------------
import cx_Oracle as oracledb
import sample_env
connection = oracledb.connect(sample_env.get_main_connect_string())
cursor = connection.cursor()
# show the number of rows for each parent ID as a means of verifying the
# output from the delete statement
for parent_id, count in cursor.execute("""
select ParentId, count(*)
from ChildTable
group by ParentId
order by ParentId"""):
print("Parent ID:", parent_id, "has", int(count), "rows.")
print()
# delete the following parent IDs only
parent_ids_to_delete = [20, 30, 50]
print("Deleting Parent IDs:", parent_ids_to_delete)
print()
# enable array DML row counts for each iteration executed in executemany()
cursor.executemany("""
delete from ChildTable
where ParentId = :1""",
[(i,) for i in parent_ids_to_delete],
arraydmlrowcounts = True)
# display the number of rows deleted for each parent ID
row_counts = cursor.getarraydmlrowcounts()
for parent_id, count in zip(parent_ids_to_delete, row_counts):
print("Parent ID:", parent_id, "deleted", count, "rows.")

View File

@ -1,86 +0,0 @@
#------------------------------------------------------------------------------
# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# batch_errors.py
#
# Demonstrate the use of the Oracle Database 12.1 feature that allows
# cursor.executemany() to complete successfully, even if errors take
# place during the execution of one or more of the individual
# executions. The parameter "batcherrors" must be set to True in the
# call to cursor.executemany() after which cursor.getbatcherrors() can
# be called, which will return a list of error objects.
#
# This script requires cx_Oracle 5.2 and higher.
#------------------------------------------------------------------------------
import cx_Oracle as oracledb
import sample_env
connection = oracledb.connect(sample_env.get_main_connect_string())
cursor = connection.cursor()
# define data to insert
data_to_insert = [
(1016, 10, 'Child B of Parent 10'),
(1017, 10, 'Child C of Parent 10'),
(1018, 20, 'Child D of Parent 20'),
(1018, 20, 'Child D of Parent 20'), # duplicate key
(1019, 30, 'Child C of Parent 30'),
(1020, 30, 'Child D of Parent 40'),
(1021, 60, 'Child A of Parent 60'), # parent does not exist
(1022, 40, 'Child F of Parent 40'),
]
# retrieve the number of rows in the table
cursor.execute("""
select count(*)
from ChildTable""")
count, = cursor.fetchone()
print("number of rows in child table:", int(count))
print("number of rows to insert:", len(data_to_insert))
# old method: executemany() with data errors results in stoppage after the
# first error takes place; the row count is updated to show how many rows
# actually succeeded
try:
cursor.executemany("insert into ChildTable values (:1, :2, :3)",
data_to_insert)
except oracledb.DatabaseError as e:
error, = e.args
print("FAILED with error:", error.message)
print("number of rows which succeeded:", cursor.rowcount)
# demonstrate that the row count is accurate
cursor.execute("""
select count(*)
from ChildTable""")
count, = cursor.fetchone()
print("number of rows in child table after failed insert:", int(count))
# roll back so we can perform the same work using the new method
connection.rollback()
# new method: executemany() with batch errors enabled (and array DML row counts
# also enabled) results in no immediate error being raised
cursor.executemany("insert into ChildTable values (:1, :2, :3)",
data_to_insert, batcherrors=True, arraydmlrowcounts=True)
# where errors have taken place, the row count is 0; otherwise it is 1
row_counts = cursor.getarraydmlrowcounts()
print("Array DML row counts:", row_counts)
# display the errors that have taken place
errors = cursor.getbatcherrors()
print("number of errors which took place:", len(errors))
for error in errors:
print("Error", error.message.rstrip(), "at row offset", error.offset)
# demonstrate that all of the rows without errors have been successfully
# inserted
cursor.execute("""
select count(*)
from ChildTable""")
count, = cursor.fetchone()
print("number of rows in child table after successful insert:", int(count))

View File

@ -1,75 +0,0 @@
#------------------------------------------------------------------------------
# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# bind_insert.py
#
# Demonstrate how to insert a row into a table using bind variables.
#------------------------------------------------------------------------------
import cx_Oracle as oracledb
import sample_env
connection = oracledb.connect(sample_env.get_main_connect_string())
#------------------------------------------------------------------------------
# "Bind by position"
#------------------------------------------------------------------------------
rows = [
(1, "First"),
(2, "Second"),
(3, "Third"),
(4, "Fourth"),
(5, None), # Insert a NULL value
(6, "Sixth"),
(7, "Seventh")
]
cursor = connection.cursor()
# predefine maximum string size to avoid data scans and memory reallocations;
# the None value indicates that the default processing can take place
cursor.setinputsizes(None, 20)
cursor.executemany("insert into mytab(id, data) values (:1, :2)", rows)
#------------------------------------------------------------------------------
# "Bind by name"
#------------------------------------------------------------------------------
rows = [
{"d": "Eighth", "i": 8},
{"d": "Ninth", "i": 9},
{"d": "Tenth", "i": 10}
]
cursor = connection.cursor()
# Predefine maximum string size to avoid data scans and memory reallocations
cursor.setinputsizes(d=20)
cursor.executemany("insert into mytab(id, data) values (:i, :d)", rows)
#------------------------------------------------------------------------------
# Inserting a single bind still needs tuples
#------------------------------------------------------------------------------
rows = [
("Eleventh",),
("Twelth",)
]
cursor = connection.cursor()
cursor.executemany("insert into mytab(id, data) values (11, :1)", rows)
#------------------------------------------------------------------------------
# Now query the results back
#------------------------------------------------------------------------------
# Don't commit - this lets the demo be run multiple times
#connection.commit()
for row in cursor.execute('select * from mytab'):
print(row)

View File

@ -1,31 +0,0 @@
#------------------------------------------------------------------------------
# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# bind_query.py
#
# Demonstrate how to perform a simple query limiting the rows retrieved using
# a bind variable. Since the query that is executed is identical, no additional
# parsing is required, thereby reducing overhead and increasing performance. It
# also permits data to be bound without having to be concerned about escaping
# special characters or SQL injection attacks.
#------------------------------------------------------------------------------
import cx_Oracle as oracledb
import sample_env
connection = oracledb.connect(sample_env.get_main_connect_string())
cursor = connection.cursor()
sql = 'select * from SampleQueryTab where id = :bvid'
print("Query results with id = 4")
for row in cursor.execute(sql, bvid = 4):
print(row)
print()
print("Query results with id = 1")
for row in cursor.execute(sql, bvid = 1):
print(row)
print()

View File

@ -1,75 +0,0 @@
#------------------------------------------------------------------------------
# Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
#
# Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
#
# Portions Copyright 2001-2007, Computronix (Canada) Ltd., Edmonton, Alberta,
# Canada. All rights reserved.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# bulk_aq.py
# This script demonstrates how to use bulk enqueuing and dequeuing of
# 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.
#------------------------------------------------------------------------------
import cx_Oracle as oracledb
import sample_env
QUEUE_NAME = "DEMO_RAW_QUEUE"
PAYLOAD_DATA = [
"The first message",
"The second message",
"The third message",
"The fourth message",
"The fifth message",
"The sixth message",
"The seventh message",
"The eighth message",
"The ninth message",
"The tenth message",
"The eleventh message",
"The twelfth and final message"
]
# connect to database
connection = oracledb.connect(sample_env.get_main_connect_string())
cursor = connection.cursor()
# create queue
queue = connection.queue(QUEUE_NAME)
queue.deqoptions.wait = oracledb.DEQ_NO_WAIT
queue.deqoptions.navigation = oracledb.DEQ_FIRST_MSG
# dequeue all existing messages to ensure the queue is empty, just so that
# the results are consistent
while queue.deqone():
pass
# enqueue a few messages
print("Enqueuing messages...")
batch_size = 6
data_to_enqueue = PAYLOAD_DATA
while data_to_enqueue:
batch_data = data_to_enqueue[:batch_size]
data_to_enqueue = data_to_enqueue[batch_size:]
messages = [connection.msgproperties(payload=d) for d in batch_data]
for data in batch_data:
print(data)
queue.enqmany(messages)
connection.commit()
# dequeue the messages
print("\nDequeuing messages...")
batch_size = 8
while True:
messages = queue.deqmany(batch_size)
if not messages:
break
for props in messages:
print(props.payload.decode())
connection.commit()
print("\nDone.")

View File

@ -1,41 +0,0 @@
#------------------------------------------------------------------------------
# Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# call_timeout.py
#
# Demonstrate the use of the Oracle Client 18c feature that enables round trips
# to the database to time out if a specified amount of time (in milliseconds)
# has passed without a response from the database.
#
# This script requires cx_Oracle 7.0 and higher and Oracle Client 18.1 and
# higher.
#------------------------------------------------------------------------------
import cx_Oracle as oracledb
import sample_env
connection = oracledb.connect(sample_env.get_main_connect_string())
connection.call_timeout = 2000
print("Call timeout set at", connection.call_timeout, "milliseconds...")
cursor = connection.cursor()
cursor.execute("select sysdate from dual")
today, = cursor.fetchone()
print("Fetch of current date before timeout:", today)
# dbms_session.sleep() replaces dbms_lock.sleep() from Oracle Database 18c
sleep_proc_name = "dbms_session.sleep" \
if int(connection.version.split(".")[0]) >= 18 \
else "dbms_lock.sleep"
print("Sleeping...should time out...")
try:
cursor.callproc(sleep_proc_name, (3,))
except oracledb.DatabaseError as e:
print("ERROR:", e)
cursor.execute("select sysdate from dual")
today, = cursor.fetchone()
print("Fetch of current date after timeout:", today)

View File

@ -1,78 +0,0 @@
#------------------------------------------------------------------------------
# Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# connection_pool.py
# 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.
# The script uses threading to show multiple users of the pool. One thread
# performs a database sleep while another performs a query. A more typical
# application might be a web service that handles requests from multiple users.
# Note only one operation (such as an execute or fetch) can take place at a time
# on each connection.
#
# Also see session_callback.py.
#
#------------------------------------------------------------------------------
import threading
import cx_Oracle as oracledb
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)
def the_long_query():
with pool.acquire() as conn:
cursor = conn.cursor()
cursor.arraysize = 25000
print("the_long_query(): beginning execute...")
cursor.execute("""
select *
from
TestNumbers
cross join TestNumbers
cross join TestNumbers
cross join TestNumbers
cross join TestNumbers
cross join TestNumbers""")
print("the_long_query(): done execute...")
while True:
rows = cursor.fetchmany()
if not rows:
break
print("the_long_query(): fetched", len(rows), "rows...")
print("the_long_query(): all done!")
def do_a_lock():
with pool.acquire() as conn:
# dbms_session.sleep() replaces dbms_lock.sleep()
# from Oracle Database 18c
sleep_proc_name = "dbms_session.sleep" \
if int(conn.version.split(".")[0]) >= 18 \
else "dbms_lock.sleep"
cursor = conn.cursor()
print("do_a_lock(): beginning execute...")
cursor.callproc(sleep_proc_name, (5,))
print("do_a_lock(): done execute...")
thread1 = threading.Thread(target=the_long_query)
thread1.start()
thread2 = threading.Thread(target=do_a_lock)
thread2.start()
thread1.join()
thread2.join()
print("All done!")

View File

@ -1,68 +0,0 @@
#------------------------------------------------------------------------------
# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
#
# Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
#
# Portions Copyright 2001-2007, Computronix (Canada) Ltd., Edmonton, Alberta,
# Canada. All rights reserved.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# cqn.py
# 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
# TestTempTable and you will see the notification of that change.
#
# This script requires cx_Oracle 5.3 and higher.
#------------------------------------------------------------------------------
import time
import cx_Oracle as oracledb
import sample_env
registered = True
def callback(message):
global registered
print("Message type:", message.type)
if not message.registered:
print("Deregistration has taken place...")
registered = False
return
print("Message database name:", message.dbname)
print("Message tranasction id:", message.txid)
print("Message queries:")
for query in message.queries:
print("--> Query ID:", query.id)
print("--> Query Operation:", query.operation)
for table in query.tables:
print("--> --> Table Name:", table.name)
print("--> --> Table Operation:", table.operation)
if table.rows is not None:
print("--> --> Table Rows:")
for row in table.rows:
print("--> --> --> Row RowId:", row.rowid)
print("--> --> --> Row Operation:", row.operation)
print("-" * 60)
print("=" * 60)
connection = oracledb.connect(sample_env.get_main_connect_string(),
events=True)
qos = oracledb.SUBSCR_QOS_QUERY | oracledb.SUBSCR_QOS_ROWIDS
sub = connection.subscribe(callback=callback, timeout=1800, qos=qos)
print("Subscription:", sub)
print("--> Connection:", sub.connection)
print("--> Callback:", sub.callback)
print("--> Namespace:", sub.namespace)
print("--> Protocol:", sub.protocol)
print("--> Timeout:", sub.timeout)
print("--> Operations:", sub.operations)
print("--> Rowids?:", bool(sub.qos & oracledb.SUBSCR_QOS_ROWIDS))
query_id = sub.registerquery("select * from TestTempTable")
print("Registered query:", query_id)
while registered:
print("Waiting for notifications....")
time.sleep(5)

View File

@ -1,74 +0,0 @@
#------------------------------------------------------------------------------
# Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# cqn2.py
# 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
# TestTempTable and you will see the notification of that change.
#
# This script differs from cqn.py in that it shows how a connection can be
# acquired from a session pool and used to query the changes that have been
# made.
#
# This script requires cx_Oracle 7 or higher.
#------------------------------------------------------------------------------
import time
import cx_Oracle as oracledb
import sample_env
registered = True
def callback(message):
global registered
if not message.registered:
print("Deregistration has taken place...")
registered = False
return
connection = pool.acquire()
for query in message.queries:
for table in query.tables:
if table.rows is None:
print("Too many row changes detected in table", table.name)
continue
num_rows_deleted = 0
print(len(table.rows), "row changes detected in table", table.name)
for row in table.rows:
if row.operation & oracledb.OPCODE_DELETE:
num_rows_deleted += 1
continue
ops = []
if row.operation & oracledb.OPCODE_INSERT:
ops.append("inserted")
if row.operation & oracledb.OPCODE_UPDATE:
ops.append("updated")
cursor = connection.cursor()
cursor.execute("""
select IntCol
from TestTempTable
where rowid = :rid""",
rid=row.rowid)
int_col, = cursor.fetchone()
print(" Row with IntCol", int_col, "was", " and ".join(ops))
if num_rows_deleted > 0:
print(" ", num_rows_deleted, "rows deleted")
print("=" * 60)
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, events=True)
with pool.acquire() as connection:
qos = oracledb.SUBSCR_QOS_QUERY | oracledb.SUBSCR_QOS_ROWIDS
sub = connection.subscribe(callback=callback, timeout=1800, qos=qos)
print("Subscription created with ID:", sub.id)
query_id = sub.registerquery("select * from TestTempTable")
print("Registered query with ID:", query_id)
while registered:
print("Waiting for notifications....")
time.sleep(5)

View File

@ -1,65 +0,0 @@
#------------------------------------------------------------------------------
# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
#
# Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
#
# Portions Copyright 2001-2007, Computronix (Canada) Ltd., Edmonton, Alberta,
# Canada. All rights reserved.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# database_change_notification.py
# 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
# TestTempTable and you will see the notification of that change.
#
# This script requires cx_Oracle 5.3 and higher.
#------------------------------------------------------------------------------
import time
import cx_Oracle as oracledb
import sample_env
registered = True
def callback(message):
global registered
print("Message type:", message.type)
if not message.registered:
print("Deregistration has taken place...")
registered = False
return
print("Message database name:", message.dbname)
print("Message tranasction id:", message.txid)
print("Message tables:")
for table in message.tables:
print("--> Table Name:", table.name)
print("--> Table Operation:", table.operation)
if table.rows is not None:
print("--> Table Rows:")
for row in table.rows:
print("--> --> Row RowId:", row.rowid)
print("--> --> Row Operation:", row.operation)
print("-" * 60)
print("=" * 60)
connection = oracledb.connect(sample_env.get_main_connect_string(),
events=True)
sub = connection.subscribe(callback=callback, timeout=1800,
qos=oracledb.SUBSCR_QOS_ROWIDS)
print("Subscription:", sub)
print("--> Connection:", sub.connection)
print("--> ID:", sub.id)
print("--> Callback:", sub.callback)
print("--> Namespace:", sub.namespace)
print("--> Protocol:", sub.protocol)
print("--> Timeout:", sub.timeout)
print("--> Operations:", sub.operations)
print("--> Rowids?:", bool(sub.qos & oracledb.SUBSCR_QOS_ROWIDS))
sub.registerquery("select * from TestTempTable")
while registered:
print("Waiting for notifications....")
time.sleep(5)

View File

@ -1,34 +0,0 @@
#------------------------------------------------------------------------------
# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
#
# Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
#
# Portions Copyright 2001-2007, Computronix (Canada) Ltd., Edmonton, Alberta,
# Canada. All rights reserved.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# database_shutdown.py
# This script demonstrates shutting down a database using Python. The
# connection used assumes that the environment variable ORACLE_SID has been
# set.
#
# This script requires cx_Oracle 4.3 and higher.
#------------------------------------------------------------------------------
import cx_Oracle as oracledb
# need to connect as SYSDBA or SYSOPER
connection = oracledb.connect(mode=oracledb.SYSDBA)
# first shutdown() call must specify the mode, if DBSHUTDOWN_ABORT is used,
# there is no need for any of the other steps
connection.shutdown(mode=oracledb.DBSHUTDOWN_IMMEDIATE)
# now close and dismount the database
cursor = connection.cursor()
cursor.execute("alter database close normal")
cursor.execute("alter database dismount")
# perform the final shutdown call
connection.shutdown(mode=oracledb.DBSHUTDOWN_FINAL)

View File

@ -1,29 +0,0 @@
#------------------------------------------------------------------------------
# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
#
# Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
#
# Portions Copyright 2001-2007, Computronix (Canada) Ltd., Edmonton, Alberta,
# Canada. All rights reserved.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# database_startup.py
# This script demonstrates starting up a database using Python. The
# connection used assumes that the environment variable ORACLE_SID has been
# set.
#
# This script requires cx_Oracle 4.3 and higher.
#------------------------------------------------------------------------------
import cx_Oracle as oracledb
# the connection must be in PRELIM_AUTH mode
connection = oracledb.connect(mode=oracledb.SYSDBA | oracledb.PRELIM_AUTH)
connection.startup()
# the following statements must be issued in normal SYSDBA mode
connection = oracledb.connect("/", mode=oracledb.SYSDBA)
cursor = connection.cursor()
cursor.execute("alter database mount")
cursor.execute("alter database open")

View File

@ -1,44 +0,0 @@
#------------------------------------------------------------------------------
# Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# dbms_output.py
# This script demonstrates one method of fetching the lines produced by
# the DBMS_OUTPUT package.
#------------------------------------------------------------------------------
import cx_Oracle as oracledb
import sample_env
connection = oracledb.connect(sample_env.get_main_connect_string())
cursor = connection.cursor()
# enable DBMS_OUTPUT
cursor.callproc("dbms_output.enable")
# execute some PL/SQL that generates output with DBMS_OUTPUT.PUT_LINE
cursor.execute("""
begin
dbms_output.put_line('This is the cx_Oracle manual');
dbms_output.put_line('');
dbms_output.put_line('Demonstrating use of DBMS_OUTPUT');
end;""")
# tune this size for your application
chunk_size = 10
# create variables to hold the output
lines_var = cursor.arrayvar(str, chunk_size)
num_lines_var = cursor.var(int)
num_lines_var.setvalue(0, chunk_size)
# fetch the text that was added by PL/SQL
while True:
cursor.callproc("dbms_output.get_lines", (lines_var, num_lines_var))
num_lines = num_lines_var.getvalue()
lines = lines_var.getvalue()[:num_lines]
for line in lines:
print(line or "")
if num_lines < chunk_size:
break

View File

@ -1,44 +0,0 @@
#------------------------------------------------------------------------------
# Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
#
# Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
#
# Portions Copyright 2001-2007, Computronix (Canada) Ltd., Edmonton, Alberta,
# Canada. All rights reserved.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# dml_returning_multiple_rows.py
# This script demonstrates the use of DML returning with multiple rows being
# returned at once.
#
# This script requires cx_Oracle 6.0 and higher.
#------------------------------------------------------------------------------
import cx_Oracle as oracledb
import sample_env
# truncate table first so that script can be rerun
connection = oracledb.connect(sample_env.get_main_connect_string())
cursor = connection.cursor()
print("Truncating table...")
cursor.execute("truncate table TestTempTable")
# populate table with a few rows
for i in range(5):
data = (i + 1, "Test String #%d" % (i + 1))
print("Adding row", data)
cursor.execute("insert into TestTempTable values (:1, :2)", data)
# now delete them and use DML returning to return the data that was inserted
int_col = cursor.var(int)
string_col = cursor.var(str)
print("Deleting data with DML returning...")
cursor.execute("""
delete from TestTempTable
returning IntCol, StringCol into :int_col, :string_col""",
int_col=int_col,
string_col=string_col)
print("Data returned:")
for int_val, string_val in zip(int_col.getvalue(), string_col.getvalue()):
print(tuple([int_val, string_val]))

View File

@ -1,43 +0,0 @@
#------------------------------------------------------------------------------
# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
#
# Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
#
# Portions Copyright 2001-2007, Computronix (Canada) Ltd., Edmonton, Alberta,
# Canada. All rights reserved.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# drcp.py
# This script demonstrates the use of Database Resident Connection Pooling
# (DRCP) which provides a connection pool in the database server, thereby
# reducing the cost of creating and tearing down client connections. The pool
# can be started and stopped in the database by issuing the following commands
# in SQL*Plus:
#
# exec dbms_connection_pool.start_pool()
# exec dbms_connection_pool.stop_pool()
#
# Statistics regarding the pool can be acquired from the following query:
#
# select * from v$cpool_cc_stats;
#
# There is no difference in how a connection is used once it has been
# established.
#
# DRCP has most benefit when used in conjunction with cx_Oracle's local
# connection pool, see the cx_Oracle documentation.
#
# This script requires cx_Oracle 5.0 or higher.
#
#------------------------------------------------------------------------------
import cx_Oracle as oracledb
import sample_env
conn = oracledb.connect(sample_env.get_drcp_connect_string(),
cclass="PYCLASS", purity=oracledb.ATTR_PURITY_SELF)
cursor = conn.cursor()
print("Performing query using DRCP...")
for row in cursor.execute("select * from TestNumbers order by IntCol"):
print(row)

View File

@ -1,24 +0,0 @@
#------------------------------------------------------------------------------
# Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# drop_samples.py
#
# Drops the database objects used for the cx_Oracle samples.
#------------------------------------------------------------------------------
import cx_Oracle as oracledb
import sample_env
def drop_samples(conn):
print("Dropping sample schemas and edition...")
sample_env.run_sql_script(conn, "drop_samples",
main_user=sample_env.get_main_user(),
edition_user=sample_env.get_edition_user(),
edition_name=sample_env.get_edition_name())
if __name__ == "__main__":
conn = oracledb.connect(sample_env.get_admin_connect_string())
drop_samples(conn)
print("Done.")

View File

@ -1,76 +0,0 @@
#------------------------------------------------------------------------------
# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
#
# Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
#
# Portions Copyright 2001-2007, Computronix (Canada) Ltd., Edmonton, Alberta,
# Canada. All rights reserved.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# editioning.py
# This script demonstrates the use of Edition-Based Redefinition, available
# in Oracle# Database 11.2 and higher. See the Oracle documentation on the
# subject for additional information. Adjust the contants at the top of the
# script for your own database as needed.
#
# This script requires cx_Oracle 5.3 and higher.
#------------------------------------------------------------------------------
import os
import cx_Oracle as oracledb
import sample_env
# connect to the editions user and create a procedure
edition_connect_string = sample_env.get_edition_connect_string()
edition_name = sample_env.get_edition_name()
connection = oracledb.connect(edition_connect_string)
print("Edition should be None, actual value is:", repr(connection.edition))
cursor = connection.cursor()
cursor.execute("""
create or replace function TestEditions return varchar2 as
begin
return 'Base Procedure';
end;""")
result = cursor.callfunc("TestEditions", str)
print("Function should return 'Base Procedure', actually returns:",
repr(result))
# next, change the edition and recreate the procedure in the new edition
cursor.execute("alter session set edition = %s" % edition_name)
print("Edition should be", repr(edition_name.upper()),
"actual value is:", repr(connection.edition))
cursor.execute("""
create or replace function TestEditions return varchar2 as
begin
return 'Edition 1 Procedure';
end;""")
result = cursor.callfunc("TestEditions", str)
print("Function should return 'Edition 1 Procedure', actually returns:",
repr(result))
# next, change the edition back to the base edition and demonstrate that the
# original function is being called
cursor.execute("alter session set edition = ORA$BASE")
result = cursor.callfunc("TestEditions", str)
print("Function should return 'Base Procedure', actually returns:",
repr(result))
# the edition can be set upon connection
connection = oracledb.connect(edition_connect_string,
edition=edition_name.upper())
cursor = connection.cursor()
result = cursor.callfunc("TestEditions", str)
print("Function should return 'Edition 1 Procedure', actually returns:",
repr(result))
# it can also be set via the environment variable ORA_EDITION
os.environ["ORA_EDITION"] = edition_name.upper()
connection = oracledb.connect(edition_connect_string)
print("Edition should be", repr(edition_name.upper()),
"actual value is:", repr(connection.edition))
cursor = connection.cursor()
result = cursor.callfunc("TestEditions", str)
print("Function should return 'Edition 1 Procedure', actually returns:",
repr(result))

View File

@ -1,47 +0,0 @@
#------------------------------------------------------------------------------
# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# generic_row_factory.py
#
# Demonstrate the ability to return named tuples for all queries using a
# subclassed cursor and row factory.
#------------------------------------------------------------------------------
import collections
import cx_Oracle as oracledb
import sample_env
class Connection(oracledb.Connection):
def cursor(self):
return Cursor(self)
class Cursor(oracledb.Cursor):
def execute(self, statement, args=None):
prepare_needed = (self.statement != statement)
result = super().execute(statement, args or [])
if prepare_needed:
description = self.description
if description is not None:
names = [d[0] for d in description]
self.rowfactory = collections.namedtuple("GenericQuery", names)
return result
# create new subclassed connection and cursor
connection = Connection(sample_env.get_main_connect_string())
cursor = connection.cursor()
# the names are now available directly for each query executed
for row in cursor.execute("select ParentId, Description from ParentTable"):
print(row.PARENTID, "->", row.DESCRIPTION)
print()
for row in cursor.execute("select ChildId, Description from ChildTable"):
print(row.CHILDID, "->", row.DESCRIPTION)
print()

View File

@ -1,49 +0,0 @@
#------------------------------------------------------------------------------
# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
#
# Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
#
# Portions Copyright 2001-2007, Computronix (Canada) Ltd., Edmonton, Alberta,
# Canada. All rights reserved.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# implicit_results.py
# This script demonstrates the use of the 12.1 feature that allows PL/SQL
# procedures to return result sets implicitly, without having to explicitly
# define them.
#
# This script requires cx_Oracle 5.3 and higher.
#------------------------------------------------------------------------------
import cx_Oracle as oracledb
import sample_env
connection = oracledb.connect(sample_env.get_main_connect_string())
cursor = connection.cursor()
# use PL/SQL block to return two cursors
cursor.execute("""
declare
c1 sys_refcursor;
c2 sys_refcursor;
begin
open c1 for
select * from TestNumbers;
dbms_sql.return_result(c1);
open c2 for
select * from TestStrings;
dbms_sql.return_result(c2);
end;""")
# display results
for ix, result_set in enumerate(cursor.getimplicitresults()):
print("Result Set #" + str(ix + 1))
for row in result_set:
print(row)
print()

View File

@ -1,55 +0,0 @@
#------------------------------------------------------------------------------
# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
#
# Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
#
# Portions Copyright 2001-2007, Computronix (Canada) Ltd., Edmonton, Alberta,
# Canada. All rights reserved.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# insert_geometry.py
# This script demonstrates the ability to create Oracle objects (this example
# uses SDO_GEOMETRY) and insert them into a table.
#
# This script requires cx_Oracle 5.3 and higher.
#------------------------------------------------------------------------------
import cx_Oracle as oracledb
import sample_env
# create and populate Oracle objects
connection = oracledb.connect(sample_env.get_main_connect_string())
type_obj = connection.gettype("MDSYS.SDO_GEOMETRY")
element_info_type_obj = connection.gettype("MDSYS.SDO_ELEM_INFO_ARRAY")
ordinate_type_obj = connection.gettype("MDSYS.SDO_ORDINATE_ARRAY")
obj = type_obj.newobject()
obj.SDO_GTYPE = 2003
obj.SDO_ELEM_INFO = element_info_type_obj.newobject()
obj.SDO_ELEM_INFO.extend([1, 1003, 3])
obj.SDO_ORDINATES = ordinate_type_obj.newobject()
obj.SDO_ORDINATES.extend([1, 1, 5, 7])
print("Created object", obj)
# create table, if necessary
cursor = connection.cursor()
cursor.execute("""
select count(*)
from user_tables
where table_name = 'TESTGEOMETRY'""")
count, = cursor.fetchone()
if count == 0:
print("Creating table...")
cursor.execute("""
create table TestGeometry (
IntCol number(9) not null,
Geometry MDSYS.SDO_GEOMETRY not null
)""")
# remove all existing rows and then add a new one
print("Removing any existing rows...")
cursor.execute("delete from TestGeometry")
print("Adding row to table...")
cursor.execute("insert into TestGeometry values (1, :obj)", obj=obj)
connection.commit()
print("Success!")

View File

@ -1,89 +0,0 @@
#------------------------------------------------------------------------------
# Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# json_blob.py
# Shows how to use a BLOB as a JSON column store.
#
# Note: with Oracle Database 21c using the new JSON type is recommended
# instead, see json_direct.py
#
# Documentation:
# cx_Oracle: https://cx-oracle.readthedocs.io/en/latest/user_guide/json_data_type.html
# Oracle Database: https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=ADJSN
#
#------------------------------------------------------------------------------
import json
import sys
import cx_Oracle as oracledb
import sample_env
connection = oracledb.connect(sample_env.get_main_connect_string())
client_version = oracledb.clientversion()[0]
db_version = int(connection.version.split(".")[0])
# Minimum database vesion is 12
if db_version < 12:
sys.exit("This example requires Oracle Database 12.1.0.2 or later")
# Create a table
cursor = connection.cursor()
cursor.execute("""
begin
execute immediate 'drop table customers';
exception when others then
if sqlcode <> -942 then
raise;
end if;
end;""")
cursor.execute("""
create table customers (
id integer not null primary key,
json_data blob check (json_data is json)
) lob (json_data) store as (cache)""")
# Insert JSON data
data = dict(name="Rod", dept="Sales", location="Germany")
inssql = "insert into customers values (:1, :2)"
if client_version >= 21 and db_version >= 21:
# Take advantage of direct binding
cursor.setinputsizes(None, oracledb.DB_TYPE_JSON)
cursor.execute(inssql, [1, data])
else:
# Insert the data as a JSON string
cursor.execute(inssql, [1, json.dumps(data)])
# Select JSON data
sql = "SELECT c.json_data FROM customers c"
for j, in cursor.execute(sql):
print(json.loads(j.read()))
# Using JSON_VALUE to extract a value from a JSON column
sql = """SELECT JSON_VALUE(json_data, '$.location')
FROM customers
OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY"""
for r in cursor.execute(sql):
print(r)
# Using dot-notation to extract a value from a JSON (BLOB storage) column
sql = """SELECT c.json_data.location
FROM customers c
OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY"""
for j, in cursor.execute(sql):
print(j)
# Using JSON_OBJECT to extract relational data as JSON
sql = """SELECT JSON_OBJECT('key' IS d.dummy) dummy
FROM dual d"""
for r in cursor.execute(sql):
print(r)

View File

@ -1,94 +0,0 @@
#------------------------------------------------------------------------------
# Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# json_direct.py
# Shows some JSON features of Oracle Database 21c.
# See https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=ADJSN
#
# For JSON with older databases see json_blob.py
#------------------------------------------------------------------------------
import json
import sys
import cx_Oracle as oracledb
import sample_env
connection = oracledb.connect(sample_env.get_main_connect_string())
client_version = oracledb.clientversion()[0]
db_version = int(connection.version.split(".")[0])
# this script only works with Oracle Database 21
if db_version < 21:
sys.exit("This example requires Oracle Database 21.1 or later. "
"Try json_blob.py")
# Create a table
cursor = connection.cursor()
cursor.execute("""
begin
execute immediate 'drop table customers';
exception when others then
if sqlcode <> -942 then
raise;
end if;
end;""")
cursor.execute("""
create table customers (
id integer not null primary key,
json_data json
)""")
# Insert JSON data
data = dict(name="Rod", dept="Sales", location="Germany")
inssql = "insert into customers values (:1, :2)"
if client_version >= 21:
# Take advantage of direct binding
cursor.setinputsizes(None, oracledb.DB_TYPE_JSON)
cursor.execute(inssql, [1, data])
else:
# Insert the data as a JSON string
cursor.execute(inssql, [1, json.dumps(data)])
# Select JSON data
sql = "SELECT c.json_data FROM customers c"
if client_version >= 21:
for j, in cursor.execute(sql):
print(j)
else:
for j, in cursor.execute(sql):
print(json.loads(j.read()))
# Using JSON_VALUE to extract a value from a JSON column
sql = """SELECT JSON_VALUE(json_data, '$.location')
FROM customers
OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY"""
for r in cursor.execute(sql):
print(r)
# Using dot-notation to extract a value from a JSON column
sql = """SELECT c.json_data.location
FROM customers c
OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY"""
if client_version >= 21:
for j, in cursor.execute(sql):
print(j)
else:
for j, in cursor.execute(sql):
print(json.loads(j.read()))
# Using JSON_OBJECT to extract relational data as JSON
sql = """SELECT JSON_OBJECT('key' IS d.dummy) dummy
FROM dual d"""
for r in cursor.execute(sql):
print(r)

View File

@ -1,56 +0,0 @@
#------------------------------------------------------------------------------
# Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# last_rowid.py
# Demonstrates the use of the cursor.lastrowid attribute.
#
# This script requires cx_Oracle 7.3 and higher.
#------------------------------------------------------------------------------
import cx_Oracle as oracledb
import sample_env
connection = oracledb.connect(sample_env.get_main_connect_string())
row1 = [1, "First"]
row2 = [2, "Second"]
# insert a couple of rows and retain the rowid of each
cursor = connection.cursor()
cursor.execute("insert into mytab (id, data) values (:1, :2)", row1)
rowid1 = cursor.lastrowid
print("Row 1:", row1)
print("Rowid 1:", rowid1)
print()
cursor.execute("insert into mytab (id, data) values (:1, :2)", row2)
rowid2 = cursor.lastrowid
print("Row 2:", row2)
print("Rowid 2:", rowid2)
print()
# the row can be fetched with the rowid that was retained
cursor.execute("select id, data from mytab where rowid = :1", [rowid1])
print("Row 1:", cursor.fetchone())
cursor.execute("select id, data from mytab where rowid = :1", [rowid2])
print("Row 2:", cursor.fetchone())
print()
# updating multiple rows only returns the rowid of the last updated row
cursor.execute("update mytab set data = data || ' (Modified)'")
cursor.execute("select id, data from mytab where rowid = :1",
[cursor.lastrowid])
print("Last updated row:", cursor.fetchone())
# deleting multiple rows only returns the rowid of the last deleted row
cursor.execute("delete from mytab")
print("Rowid of last deleted row:", cursor.lastrowid)
# deleting no rows results in a value of None
cursor.execute("delete from mytab")
print("Rowid when no rows are deleted:", cursor.lastrowid)
# Don't commit - this lets us run the demo multiple times
#connection.commit()

View File

@ -1,67 +0,0 @@
#------------------------------------------------------------------------------
# Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
#
# Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
#
# Portions Copyright 2001-2007, Computronix (Canada) Ltd., Edmonton, Alberta,
# Canada. All rights reserved.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# multi_consumer_aq.py
# 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.
#------------------------------------------------------------------------------
import cx_Oracle as oracledb
import sample_env
QUEUE_NAME = "DEMO_RAW_QUEUE_MULTI"
PAYLOAD_DATA = [
"The first message",
"The second message",
"The third message",
"The fourth and final message"
]
# connect to database
connection = oracledb.connect(sample_env.get_main_connect_string())
cursor = connection.cursor()
# create queue
queue = connection.queue(QUEUE_NAME)
queue.deqoptions.wait = oracledb.DEQ_NO_WAIT
queue.deqoptions.navigation = oracledb.DEQ_FIRST_MSG
# enqueue a few messages
print("Enqueuing messages...")
for data in PAYLOAD_DATA:
print(data)
queue.enqone(connection.msgproperties(payload=data))
connection.commit()
print()
# dequeue the messages for consumer A
print("Dequeuing the messages for consumer A...")
queue.deqoptions.consumername = "SUBSCRIBER_A"
while True:
props = queue.deqone()
if not props:
break
print(props.payload.decode())
connection.commit()
print()
# dequeue the message for consumer B
print("Dequeuing the messages for consumer B...")
queue.deqoptions.consumername = "SUBSCRIBER_B"
while True:
props = queue.deqone()
if not props:
break
print(props.payload.decode())
connection.commit()
print("\nDone.")

View File

@ -1,66 +0,0 @@
#------------------------------------------------------------------------------
# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
#
# Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
#
# Portions Copyright 2001-2007, Computronix (Canada) Ltd., Edmonton, Alberta,
# Canada. All rights reserved.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# object_aq.py
# 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.
#------------------------------------------------------------------------------
import decimal
import cx_Oracle as oracledb
import sample_env
BOOK_TYPE_NAME = "UDT_BOOK"
QUEUE_NAME = "DEMO_BOOK_QUEUE"
BOOK_DATA = [
("The Fellowship of the Ring", "Tolkien, J.R.R.",
decimal.Decimal("10.99")),
("Harry Potter and the Philosopher's Stone", "Rowling, J.K.",
decimal.Decimal("7.99"))
]
# connect to database
connection = oracledb.connect(sample_env.get_main_connect_string())
cursor = connection.cursor()
# create queue
books_type = connection.gettype(BOOK_TYPE_NAME)
queue = connection.queue(QUEUE_NAME, payload_type=books_type)
queue.deqoptions.wait = oracledb.DEQ_NO_WAIT
queue.deqoptions.navigation = oracledb.DEQ_FIRST_MSG
# dequeue all existing messages to ensure the queue is empty, just so that
# the results are consistent
while queue.deqone():
pass
# enqueue a few messages
print("Enqueuing messages...")
for title, authors, price in BOOK_DATA:
book = books_type.newobject()
book.TITLE = title
book.AUTHORS = authors
book.PRICE = price
print(title)
queue.enqone(connection.msgproperties(payload=book))
connection.commit()
# dequeue the messages
print("\nDequeuing messages...")
while True:
props = queue.deqone()
if not props:
break
print(props.payload.TITLE)
connection.commit()
print("\nDone.")

View File

@ -1,46 +0,0 @@
#------------------------------------------------------------------------------
# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# plsql_collection.py
#
# Demonstrate how to get the value of a PL/SQL collection from a stored
# procedure.
#
# This feature is new in cx_Oracle 5.3 and is only available in Oracle
# Database 12.1 and higher. The ability to get the collection as a dictionary
# is new in cx_Oracle 7.0.
#------------------------------------------------------------------------------
import cx_Oracle as oracledb
import sample_env
connection = oracledb.connect(sample_env.get_main_connect_string())
# create new empty object of the correct type
# note the use of a PL/SQL type defined in a package
type_obj = connection.gettype("PKG_DEMO.UDT_STRINGLIST")
obj = type_obj.newobject()
# call the stored procedure which will populate the object
cursor = connection.cursor()
cursor.callproc("pkg_Demo.DemoCollectionOut", (obj,))
# show the indexes that are used by the collection
print("Indexes and values of collection:")
ix = obj.first()
while ix is not None:
print(ix, "->", obj.getelement(ix))
ix = obj.next(ix)
print()
# show the values as a simple list
print("Values of collection as list:")
print(obj.aslist())
print()
# show the values as a simple dictionary
print("Values of collection as dictionary:")
print(obj.asdict())
print()

View File

@ -1,18 +0,0 @@
#------------------------------------------------------------------------------
# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# plsql_function.py
#
# Demonstrate how to call a PL/SQL function and get its return value.
#------------------------------------------------------------------------------
import cx_Oracle as oracledb
import sample_env
connection = oracledb.connect(sample_env.get_main_connect_string())
cursor = connection.cursor()
res = cursor.callfunc('myfunc', int, ('abc', 2))
print(res)

View File

@ -1,20 +0,0 @@
#------------------------------------------------------------------------------
# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# plsql_procedure.py
#
# Demonstrate how to call a PL/SQL stored procedure and get the results of an
# OUT variable.
#------------------------------------------------------------------------------
import cx_Oracle as oracledb
import sample_env
connection = oracledb.connect(sample_env.get_main_connect_string())
cursor = connection.cursor()
myvar = cursor.var(int)
cursor.callproc('myproc', (123, myvar))
print(myvar.getvalue())

View File

@ -1,46 +0,0 @@
#------------------------------------------------------------------------------
# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# plsql_record.py
#
# Demonstrate how to bind (in and out) a PL/SQL record.
#
# This feature is only available in Oracle Database 12.1 and higher.
#------------------------------------------------------------------------------
import datetime
import cx_Oracle as oracledb
import sample_env
connection = oracledb.connect(sample_env.get_main_connect_string())
# create new object of the correct type
# note the use of a PL/SQL record defined in a package
# a table record identified by TABLE%ROWTYPE can also be used
type_obj = connection.gettype("PKG_DEMO.UDT_DEMORECORD")
obj = type_obj.newobject()
obj.NUMBERVALUE = 6
obj.STRINGVALUE = "Test String"
obj.DATEVALUE = datetime.datetime(2016, 5, 28)
obj.BOOLEANVALUE = False
# show the original values
print("NUMBERVALUE ->", obj.NUMBERVALUE)
print("STRINGVALUE ->", obj.STRINGVALUE)
print("DATEVALUE ->", obj.DATEVALUE)
print("BOOLEANVALUE ->", obj.BOOLEANVALUE)
print()
# call the stored procedure which will modify the object
cursor = connection.cursor()
cursor.callproc("pkg_Demo.DemoRecordsInOut", (obj,))
# show the modified values
print("NUMBERVALUE ->", obj.NUMBERVALUE)
print("STRINGVALUE ->", obj.STRINGVALUE)
print("DATEVALUE ->", obj.DATEVALUE)
print("BOOLEANVALUE ->", obj.BOOLEANVALUE)
print()

View File

@ -1,46 +0,0 @@
#------------------------------------------------------------------------------
# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# query.py
#
# Demonstrate how to perform a query in different ways.
#------------------------------------------------------------------------------
import cx_Oracle as oracledb
import sample_env
connection = oracledb.connect(sample_env.get_main_connect_string())
sql = """
select * from SampleQueryTab
where id < 6
order by id"""
print("Get all rows via iterator")
cursor = connection.cursor()
for result in cursor.execute(sql):
print(result)
print()
print("Query one row at a time")
cursor.execute(sql)
row = cursor.fetchone()
print(row)
row = cursor.fetchone()
print(row)
print()
print("Fetch many rows")
cursor.execute(sql)
res = cursor.fetchmany(3)
print(res)
print()
print("Fetch each row as a Dictionary")
cursor.execute(sql)
columns = [col[0] for col in cursor.description]
cursor.rowfactory = lambda *args: dict(zip(columns, args))
for row in cursor:
print(row)

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