Compare commits
13 Commits
Author | SHA1 | Date |
---|---|---|
![]() |
ec62806c18 | |
![]() |
33f4093ad1 | |
![]() |
cd70b4474b | |
![]() |
104ec0331b | |
![]() |
23af6a748e | |
![]() |
7076712234 | |
![]() |
ecd8956d42 | |
![]() |
d73e43acad | |
![]() |
cc52daf97b | |
![]() |
cebde524d0 | |
![]() |
b07a524373 | |
![]() |
1d1e17144d | |
![]() |
ace0d52ce7 |
|
@ -7,9 +7,9 @@ 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][1] preferably with a proof of concept. Please review
|
||||
some additional information on [how to report security vulnerabilities to
|
||||
Oracle][2]. We encourage people who contact Oracle Security to use email
|
||||
encryption using [our encryption key][3].
|
||||
some additional information on [how to report security vulnerabilities to Oracle][2].
|
||||
We encourage people who contact Oracle Security to use email encryption using
|
||||
[our encryption key][3].
|
||||
|
||||
We ask that you do not use other channels or contact the project maintainers
|
||||
directly.
|
||||
|
@ -20,16 +20,17 @@ security features are welcome on GitHub Issues.
|
|||
## Security updates, alerts and bulletins
|
||||
|
||||
Security updates will be released on a regular cadence. Many of our projects
|
||||
will typically release security fixes in conjunction with the Oracle Critical
|
||||
Patch Update program. Additional information, including past advisories, is
|
||||
available on our [security alerts][4] page.
|
||||
will typically release security fixes in conjunction with the
|
||||
[Oracle Critical Patch Update][3] program. Additional
|
||||
information, including past advisories, is available on our [security alerts][4]
|
||||
page.
|
||||
|
||||
## 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.
|
||||
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.
|
||||
|
||||
[1]: mailto:secalert_us@oracle.com
|
||||
[2]: https://www.oracle.com/corporate/security-practices/assurance/vulnerability/reporting.html
|
|
@ -6,4 +6,3 @@ build/
|
|||
dist/
|
||||
doc/build
|
||||
src/oracledb/*.c
|
||||
.ipynb_checkpoints/
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.4.0
|
||||
hooks:
|
||||
- id: trailing-whitespace
|
||||
- id: end-of-file-fixer
|
||||
- id: check-yaml
|
||||
- id: check-added-large-files
|
||||
- repo: https://github.com/psf/black-pre-commit-mirror
|
||||
rev: 23.9.1
|
||||
hooks:
|
||||
- id: black
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.0.291
|
||||
hooks:
|
||||
- id: ruff
|
|
@ -1,58 +1,51 @@
|
|||
# Contributing to this repository
|
||||
# Contributing
|
||||
|
||||
We welcome your contributions! There are multiple ways to contribute.
|
||||
|
||||
## Opening issues
|
||||
## 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 in our
|
||||
[security policy](./SECURITY.md).
|
||||
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
|
||||
## Contributing Code
|
||||
|
||||
We welcome your code contributions. Before submitting code via a pull request,
|
||||
you will need to have signed the [Oracle Contributor Agreement][OCA] (OCA) and
|
||||
your commits need to include the following line using the name and e-mail
|
||||
address you used to sign the OCA:
|
||||
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
|
||||
`--sign-off` or `-s`, e.g.
|
||||
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.
|
||||
Only pull requests from committers that can be verified as having
|
||||
signed the OCA can be accepted.
|
||||
|
||||
## Pull request process
|
||||
### Pull request process
|
||||
|
||||
1. Ensure there is an issue created to track and discuss the fix or enhancement
|
||||
you intend to submit.
|
||||
1. Fork this repository.
|
||||
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`.
|
||||
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 change.
|
||||
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 assign the pull request to 2-3 people for review before it is merged.
|
||||
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.
|
||||
|
||||
Note we merge to an internal repo first before pushing back to GitHub.
|
||||
|
||||
## Code of conduct
|
||||
## 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][COC].
|
||||
|
||||
[OCA]: https://oca.opensource.oracle.com
|
||||
[COC]: https://www.contributor-covenant.org/version/1/4/code-of-conduct/
|
||||
like more specific guidelines see the [Contributor Covenant Code of
|
||||
Conduct](https://www.contributor-covenant.org/version/1/4/code-of-conduct/)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
Copyright (c) 2016, 2023 Oracle and/or its affiliates.
|
||||
Copyright (c) 2016, 2022 Oracle and/or its affiliates.
|
||||
|
||||
This software is dual-licensed to you under the Universal Permissive License
|
||||
(UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
||||
|
|
|
@ -1 +1 @@
|
|||
Copyright (c) 2016, 2023, Oracle and/or its affiliates.
|
||||
Copyright (c) 2016, 2022, Oracle and/or its affiliates.
|
||||
|
|
20
README.md
20
README.md
|
@ -8,8 +8,6 @@ The module conforms to the [Python Database API 2.0 specification][pep249] with
|
|||
a considerable number of additions and a couple of minor exclusions, see the
|
||||
[feature list][features].
|
||||
|
||||
Synchronous and [concurrent][concurrent] coding styles are supported.
|
||||
|
||||
## Installation
|
||||
|
||||
Run `python -m pip install oracledb`
|
||||
|
@ -18,10 +16,10 @@ See [python-oracledb Installation][installation].
|
|||
|
||||
## Dependencies and Interoperability
|
||||
|
||||
- Python versions 3.7 through 3.12.
|
||||
- Python versions 3.6 through 3.11.
|
||||
|
||||
Prebuilt packages are available for these Python versions on Windows, on
|
||||
macOS and on Linux.
|
||||
Prebuilt packages are available on Windows for Python 3.7 or later, on macOS
|
||||
for Python 3.7 or later, and on Linux for Python 3.6 or later.
|
||||
|
||||
Source code is also available.
|
||||
|
||||
|
@ -68,18 +66,11 @@ See [/tests][tests]
|
|||
|
||||
## Contributing
|
||||
|
||||
This project welcomes contributions from the community. Before submitting a
|
||||
pull request, please [review our contribution guide](./CONTRIBUTING.md).
|
||||
|
||||
## Security
|
||||
|
||||
Please consult the [security guide](./SECURITY.md) for our responsible security
|
||||
vulnerability disclosure process.
|
||||
See [CONTRIBUTING](https://github.com/oracle/python-oracledb/blob/main/CONTRIBUTING.md)
|
||||
|
||||
## License
|
||||
|
||||
See [LICENSE][license], [THIRD_PARTY_LICENSES][tplicense], and
|
||||
[NOTICE][notice].
|
||||
See [LICENSE][license], [THIRD_PARTY_LICENSES][tplicense], and [NOTICE][notice].
|
||||
|
||||
[python]: https://www.python.org/
|
||||
[oracledb]: https://www.oracle.com/database/
|
||||
|
@ -97,4 +88,3 @@ See [LICENSE][license], [THIRD_PARTY_LICENSES][tplicense], and
|
|||
[samples]: https://github.com/oracle/python-oracledb/tree/main/samples
|
||||
[installation]: https://python-oracledb.readthedocs.io/en/latest/user_guide/installation.html
|
||||
[features]: https://oracle.github.io/python-oracledb/#features
|
||||
[concurrent]: https://python-oracledb.readthedocs.io/en/latest/user_guide/asyncio.html
|
||||
|
|
|
@ -2,3 +2,4 @@ Please see the python-oracledb home page for links to documentation,
|
|||
installation instructions, and source code:
|
||||
|
||||
https://oracle.github.io/python-oracledb/index.html
|
||||
|
||||
|
|
|
@ -453,3 +453,4 @@ 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.
|
||||
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
sphinx>=4.2.0
|
||||
sphinx-rtd-theme>=0.5.2
|
||||
sphinx-rtd-theme
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2022, 2023, Oracle and/or its affiliates.
|
||||
#------------------------------------------------------------------------------
|
||||
# Copyright (c) 2022, Oracle and/or its affiliates.
|
||||
#
|
||||
# This software is dual-licensed to you under the Universal Permissive License
|
||||
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
||||
|
@ -20,21 +20,20 @@
|
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
# oracle_deprecated.py
|
||||
#
|
||||
# Overrides the 'deprecated' directive so that a componment name can be used in
|
||||
# conjunction with the version.
|
||||
# -----------------------------------------------------------------------------
|
||||
# Overrides the 'deprecated' directive so that it can a componment name can be
|
||||
# used in conjunction with the version.
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.parsers.rst import Directive
|
||||
from sphinx import addnodes
|
||||
|
||||
|
||||
class DriverDeprecated(Directive):
|
||||
has_content = True
|
||||
required_arguments = 1
|
||||
|
@ -44,22 +43,22 @@ class DriverDeprecated(Directive):
|
|||
def run(self):
|
||||
node = addnodes.versionmodified()
|
||||
node.document = self.state.document
|
||||
node["type"] = self.name
|
||||
node["version"] = self.arguments[0]
|
||||
text = "Deprecated since {}.".format(self.arguments[0])
|
||||
classes = ["versionmodified", "deprecated"]
|
||||
para = nodes.paragraph(
|
||||
"", "", nodes.inline("", text, classes=classes), translatable=False
|
||||
)
|
||||
node['type'] = self.name
|
||||
node['version'] = self.arguments[0]
|
||||
text = 'Deprecated since {}.'.format(self.arguments[0])
|
||||
classes = ['versionmodified', 'deprecated']
|
||||
para = nodes.paragraph('', '',
|
||||
nodes.inline('', text, classes=classes),
|
||||
translatable=False)
|
||||
node.append(para)
|
||||
return [node]
|
||||
|
||||
ret: List[Node] = [node]
|
||||
return ret
|
||||
|
||||
def setup(app):
|
||||
app.add_directive("deprecated", DriverDeprecated, override=True)
|
||||
|
||||
return {
|
||||
"version": "0.1",
|
||||
"parallel_read_safe": True,
|
||||
"parallel_write_safe": True,
|
||||
'version': '0.1',
|
||||
'parallel_read_safe': True,
|
||||
'parallel_write_safe': True,
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
# Copyright (c) 2022, Oracle and/or its affiliates.
|
||||
#
|
||||
# This software is dual-licensed to you under the Universal Permissive License
|
||||
|
@ -20,14 +20,14 @@
|
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
# table_with_summary.py
|
||||
#
|
||||
# Defines a directive (list-table-with-summary) that adds support for a summary
|
||||
# option on top of the regular "list-table" directive.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
import sphinx
|
||||
from docutils.parsers.rst import directives
|
||||
|
@ -35,14 +35,14 @@ from docutils.parsers.rst.directives import tables
|
|||
|
||||
from packaging import version
|
||||
|
||||
|
||||
class ListTableWithSummary(tables.ListTable):
|
||||
option_spec = {"summary": directives.unchanged}
|
||||
|
||||
option_spec = {'summary': directives.unchanged}
|
||||
option_spec.update(tables.ListTable.option_spec)
|
||||
|
||||
def run(self):
|
||||
result = super().run()
|
||||
summary = self.options.get("summary")
|
||||
summary = self.options.get('summary')
|
||||
if summary:
|
||||
table_node = result[0]
|
||||
table_node["summary"] = summary
|
||||
|
@ -50,29 +50,29 @@ class ListTableWithSummary(tables.ListTable):
|
|||
|
||||
|
||||
class HTMLTranslator(sphinx.writers.html5.HTML5Translator):
|
||||
|
||||
def visit_table(self, node):
|
||||
if version.parse(sphinx.__version__) > version.parse("4.2.0"):
|
||||
if version.parse(sphinx.__version__) > version.parse('4.2.0'):
|
||||
self._table_row_indices = [0]
|
||||
else:
|
||||
self._table_row_index = 0
|
||||
|
||||
atts = {}
|
||||
classes = [
|
||||
cls.strip(" \t\n") for cls in self.settings.table_style.split(",")
|
||||
]
|
||||
classes = [cls.strip(' \t\n') \
|
||||
for cls in self.settings.table_style.split(',')]
|
||||
classes.insert(0, "docutils") # compat
|
||||
|
||||
# set align-default if align not specified to give a default style
|
||||
classes.append("align-%s" % node.get("align", "default"))
|
||||
classes.append('align-%s' % node.get('align', 'default'))
|
||||
|
||||
if "width" in node:
|
||||
atts["style"] = "width: %s" % node["width"]
|
||||
if "summary" in node:
|
||||
atts["summary"] = node["summary"]
|
||||
tag = self.starttag(node, "table", CLASS=" ".join(classes), **atts)
|
||||
if 'width' in node:
|
||||
atts['style'] = 'width: %s' % node['width']
|
||||
if 'summary' in node:
|
||||
atts['summary'] = node['summary']
|
||||
tag = self.starttag(node, 'table', CLASS=' '.join(classes), **atts)
|
||||
self.body.append(tag)
|
||||
|
||||
|
||||
def setup(app):
|
||||
app.add_directive("list-table-with-summary", ListTableWithSummary)
|
||||
app.add_directive('list-table-with-summary', ListTableWithSummary)
|
||||
app.set_translator("html", HTMLTranslator, override=True)
|
||||
|
|
|
@ -340,7 +340,7 @@ Message Properties
|
|||
:data:`~oracledb.MSG_READY`, :data:`~oracledb.MSG_PROCESSED` or
|
||||
:data:`~oracledb.MSG_EXPIRED`.
|
||||
|
||||
.. attribute:: MessageProperties.recipients
|
||||
.. attribute:: Messageproperties.recipient
|
||||
|
||||
This read-write attribute specifies a list of recipient names that can be
|
||||
associated with a message at the time of enqueuing the message. This allows a
|
||||
|
|
|
@ -1,334 +0,0 @@
|
|||
.. _asyncconnobj:
|
||||
|
||||
****************************
|
||||
API: AsyncConnection Objects
|
||||
****************************
|
||||
|
||||
An AsyncConnection object can be created with :meth:`oracledb.connect_async()`
|
||||
or with :meth:`AsyncConnectionPool.acquire()`. AsyncConnections support use of
|
||||
concurrent programming with `asyncio <https://docs.python.org/3/library/
|
||||
asyncio.html>`__. Unless explicitly noted as synchronous, the AsyncConnection
|
||||
methods should be used with ``await``. This object is an extension to the DB
|
||||
API.
|
||||
|
||||
.. versionadded:: 2.0.0
|
||||
|
||||
.. note::
|
||||
|
||||
The Asynchronous I/O (asyncio) support in python-oracledb 2.0.0 is a
|
||||
pre-release and may change in the next version.
|
||||
|
||||
.. note::
|
||||
|
||||
AsyncConnection objects are only supported in the python-oracledb Thin
|
||||
mode.
|
||||
|
||||
.. note::
|
||||
|
||||
Any outstanding database transaction will be rolled back when the
|
||||
connection object is destroyed or closed. You must perform a
|
||||
:meth:`commit <AsyncConnection.commit>` first if you want data to
|
||||
persist in the database, see :ref:`txnasync`.
|
||||
|
||||
.. _asyncconnmeth:
|
||||
|
||||
AsyncConnection Methods
|
||||
=======================
|
||||
|
||||
.. method:: AsyncConnection.__aenter__()
|
||||
|
||||
The entry point for the asynchronous connection as a context manager. It
|
||||
returns itself.
|
||||
|
||||
.. method:: AsyncConnection.__aexit__()
|
||||
|
||||
The exit point for the asynchronous connection as a context manager. This
|
||||
will close the connection and roll back any uncommitted transaction.
|
||||
|
||||
.. method:: AsyncConnection.callfunc(name, return_type, parameters=[], \
|
||||
keyword_parameters={})
|
||||
|
||||
Calls a PL/SQL function with the given name.
|
||||
|
||||
This is a shortcut for creating a cursor, calling the stored function with
|
||||
the cursor, and then closing the cursor.
|
||||
|
||||
.. method:: AsyncConnection.callproc(name, parameters=[], \
|
||||
keyword_parameters={})
|
||||
|
||||
Calls a PL/SQL procedure with the given name.
|
||||
|
||||
This is a shortcut for creating a cursor, calling the stored procedure
|
||||
with the cursor, and then closing the cursor.
|
||||
|
||||
.. method:: AsyncConnection.cancel()
|
||||
|
||||
A synchronous method that breaks a long-running statement.
|
||||
|
||||
.. method:: AsyncConnection.changepassword(old_password, new_password)
|
||||
|
||||
Changes the password for the user to which the connection is connected.
|
||||
|
||||
.. method:: AsyncConnection.close()
|
||||
|
||||
Closes the connection.
|
||||
|
||||
.. method:: AsyncConnection.commit()
|
||||
|
||||
Commits any pending transaction to the database.
|
||||
|
||||
.. method:: AsyncConnection.createlob(lob_type)
|
||||
|
||||
Creates and returns a new temporary LOB of the specified type.
|
||||
|
||||
.. method:: AsyncConnection.cursor(scrollable=False)
|
||||
|
||||
A synchronous method that returns a cursor associated with the connection.
|
||||
|
||||
.. method:: AsyncConnection.execute(statement, parameters=[])
|
||||
|
||||
Executes a statement against the database.
|
||||
|
||||
This is a shortcut for creating a cursor, executing a statement with the
|
||||
cursor, and then closing the cursor.
|
||||
|
||||
.. method:: AsyncConnection.executemany(statement, parameters=[])
|
||||
|
||||
Prepares a statement for execution against a database and then executes it
|
||||
against all parameter mappings or sequences found in the sequence
|
||||
parameters.
|
||||
|
||||
This is a shortcut for creating a cursor, calling
|
||||
:meth:`AsyncCursor.executemany()` on the cursor, and then closing the
|
||||
cursor.
|
||||
|
||||
.. method:: AsyncConnection.fetchall(statement, parameters=None, \
|
||||
arraysize=None, rowfactory=None)
|
||||
|
||||
Executes a query and returns all of the rows. After the rows are
|
||||
fetched, the cursor is closed.
|
||||
|
||||
.. method:: AsyncConnection.fetchmany(statement, parameters=None, \
|
||||
num_rows=None, rowfactory=None)
|
||||
|
||||
Executes a query and returns up to the specified number of rows. After the
|
||||
rows are fetched, the cursor is closed.
|
||||
|
||||
.. method:: AsyncConnection.fetchone(statement, parameters=None, \
|
||||
rowfactory=None)
|
||||
|
||||
Executes a query and returns the first row of the result set if one exists
|
||||
(or None if no rows exist). After the row is fetched, the cursor is
|
||||
closed.
|
||||
|
||||
.. method:: AsyncConnection.gettype(name)
|
||||
|
||||
Returns a :ref:`type object <dbobjecttype>` given its name. This can then
|
||||
be used to create objects which can be bound to cursors created by this
|
||||
connection.
|
||||
|
||||
.. method:: AsyncConnection.is_healthy()
|
||||
|
||||
A synchronous method that returns a boolean indicating the health status
|
||||
of a connection.
|
||||
|
||||
Connections may become unusable in several cases, such as, if the network
|
||||
socket is broken, if an Oracle error indicates the connection is unusable,
|
||||
or, after receiving a planned down notification from the database.
|
||||
|
||||
This function is best used before starting a new database request on an
|
||||
existing standalone connection. Pooled connections internally perform this
|
||||
check before returning a connection to the application.
|
||||
|
||||
If this function returns False, the connection should be not be used by the
|
||||
application and a new connection should be established instead.
|
||||
|
||||
This function performs a local check. To fully check a connection's health,
|
||||
use :meth:`AsyncConnection.ping()` which performs a round-trip to the
|
||||
database.
|
||||
|
||||
.. method:: AsyncConnection.ping()
|
||||
|
||||
Pings the database to verify if the connection is valid.
|
||||
|
||||
.. method:: AsyncConnection.rollback()
|
||||
|
||||
Rolls back any pending transaction.
|
||||
|
||||
.. _asynconnattr:
|
||||
|
||||
AsyncConnection Attributes
|
||||
==========================
|
||||
|
||||
.. attribute:: AsyncConnection.action
|
||||
|
||||
This write-only attribute sets the action column in the v$session table. It
|
||||
is a string attribute but the value None is accepted and treated as an
|
||||
empty string.
|
||||
|
||||
.. attribute:: AsyncConnection.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.
|
||||
|
||||
.. attribute:: AsyncConnection.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.
|
||||
|
||||
.. attribute:: AsyncConnection.client_identifier
|
||||
|
||||
This write-only attribute sets the client_identifier column in the
|
||||
v$session table.
|
||||
|
||||
.. attribute:: AsyncConnection.clientinfo
|
||||
|
||||
This write-only attribute sets the client_info column in the v$session
|
||||
table.
|
||||
|
||||
.. attribute:: AsyncConnection.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.
|
||||
|
||||
.. attribute:: AsyncConnection.db_domain
|
||||
|
||||
This read-only attribute specifies the Oracle Database domain name
|
||||
associated with the connection. It is the same value returned by the SQL
|
||||
``SELECT value FROM V$PARAMETER WHERE NAME = 'db_domain'``.
|
||||
|
||||
.. attribute:: AsyncConnection.db_name
|
||||
|
||||
This read-only attribute specifies the Oracle Database name associated with
|
||||
the connection. It is the same value returned by the SQL
|
||||
``SELECT NAME FROM V$DATABASE``.
|
||||
|
||||
.. attribute:: AsyncConnection.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.
|
||||
|
||||
.. attribute:: AsyncConnection.dsn
|
||||
|
||||
This read-only attribute returns the TNS entry of the database to which a
|
||||
connection has been established.
|
||||
|
||||
.. attribute:: AsyncConnection.econtext_id
|
||||
|
||||
This write-only attribute specifies the execution context id. This
|
||||
value can be found as ecid in the v$session table and econtext_id in the
|
||||
auditing tables. The maximum length is 64 bytes.
|
||||
|
||||
.. attribute:: AsyncConnection.edition
|
||||
|
||||
This read-only attribute gets the session edition and is only available in
|
||||
Oracle Database 11.2 (the server must be at this level or higher for this
|
||||
to work). This attribute is ignored in python-oracledb Thin mode.
|
||||
|
||||
.. attribute:: AsyncConnection.external_name
|
||||
|
||||
This read-write attribute specifies the external name that is used by the
|
||||
connection when logging distributed transactions.
|
||||
|
||||
.. attribute:: AsyncConnection.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.
|
||||
|
||||
.. attribute:: AsyncConnection.instance_name
|
||||
|
||||
This read-only attribute specifies the Oracle Database instance name
|
||||
associated with the connection. It is the same value as the SQL expression
|
||||
``sys_context('userenv', 'instance_name')``.
|
||||
|
||||
.. attribute:: AsyncConnection.internal_name
|
||||
|
||||
This read-write attribute specifies the internal name that is used by the
|
||||
connection when logging distributed transactions.
|
||||
|
||||
.. attribute:: AsyncConnection.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.
|
||||
|
||||
.. note:
|
||||
|
||||
This attribute is only available when Oracle Database 12.1 or later is
|
||||
in use
|
||||
|
||||
.. attribute:: AsyncConnection.max_open_cursors
|
||||
|
||||
This read-only attribute specifies the maximum number of cursors that the
|
||||
database can have open concurrently. It is the same value returned by the
|
||||
SQL ``SELECT VALUE FROM V$PARAMETER WHERE NAME = 'open_cursors'``.
|
||||
|
||||
.. attribute:: AsyncConnection.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.
|
||||
|
||||
.. attribute:: AsyncConnection.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, metadata)`` and the return value is
|
||||
expected to be a :ref:`variable object<varobj>` 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`.
|
||||
|
||||
.. attribute:: AsyncConnection.sdu
|
||||
|
||||
This read-only attribute specifies the size of the Session Data Unit (SDU)
|
||||
that is being used by the connection. The value will be the lesser of the
|
||||
requested python-oracledb size and the maximum size allowed by the database
|
||||
network configuration.
|
||||
|
||||
.. attribute:: AsyncConnection.service_name
|
||||
|
||||
This read-only attribute specifies the Oracle Database service name
|
||||
associated with the connection. This is the same value returned by the SQL
|
||||
``SELECT SYS_CONTEXT('USERENV', 'SERVICE_NAME') FROM DUAL``.
|
||||
|
||||
.. attribute:: AsyncConnection.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.
|
||||
|
||||
.. attribute:: AsyncConnection.transaction_in_progress
|
||||
|
||||
This read-only attribute specifies whether a transaction is currently in
|
||||
progress on the database associated with the connection.
|
||||
|
||||
.. attribute:: AsyncConnection.username
|
||||
|
||||
This read-only attribute returns the name of the user which established the
|
||||
connection to the database.
|
||||
|
||||
.. attribute:: AsyncConnection.version
|
||||
|
||||
This read-only attribute returns the version of the database to which a
|
||||
connection has been established.
|
|
@ -1,213 +0,0 @@
|
|||
.. _asyncconnpoolobj:
|
||||
|
||||
********************************
|
||||
API: AsyncConnectionPool Objects
|
||||
********************************
|
||||
|
||||
An AsyncConnectionPool object can be created with
|
||||
:meth:`oracledb.create_pool_async()`. This object is an extension to the DB
|
||||
API.
|
||||
|
||||
.. versionadded:: 2.0.0
|
||||
|
||||
.. note::
|
||||
|
||||
The Asynchronous I/O (asyncio) support in python-oracledb 2.0.0 is a
|
||||
pre-release and may change in the next version.
|
||||
|
||||
.. note::
|
||||
|
||||
AsyncConnectionPool objects are only supported in the python-oracledb Thin
|
||||
mode.
|
||||
|
||||
.. _asynconnpoolmeth:
|
||||
|
||||
AsyncConnectionPool Methods
|
||||
===========================
|
||||
|
||||
.. method:: AsyncConnectionPool.acquire(user=None, password=None, cclass=None, \
|
||||
purity=oracledb.PURITY_DEFAULT, tag=None, matchanytag=False, \
|
||||
shardingkey=[], supershardingkey=[])
|
||||
|
||||
Acquires a connection from the pool and returns an
|
||||
:ref:`asynchronous connection object <asyncconnobj>`.
|
||||
|
||||
If the pool is :ref:`homogeneous <connpooltypes>`, 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:`~oracledb.PURITY_NEW`, :data:`~oracledb.PURITY_ANY`, or
|
||||
:data:`~oracledb.PURITY_DEFAULT`.
|
||||
|
||||
The ``tag``, ``matchanytag``, ``shardingkey``, and ``supershardingkey``
|
||||
parameters are ignored in python-oracledb Thin mode.
|
||||
|
||||
.. method:: AsyncConnectionPool.close(force=False)
|
||||
|
||||
Closes the 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:: AsyncConnectionPool.drop(connection)
|
||||
|
||||
Drops the connection from the pool which is useful if the connection is no
|
||||
longer usable (such as when the session is killed).
|
||||
|
||||
.. method:: AsyncConnectionPool.release(connection, tag=None)
|
||||
|
||||
Releases 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, and so on. 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.
|
||||
|
||||
The ``tag`` parameter is ignored in python-oracledb Thin mode.
|
||||
|
||||
.. _asyncconnpoolattr:
|
||||
|
||||
AsyncConnectionPool Attributes
|
||||
==============================
|
||||
|
||||
.. attribute:: AsyncConnectionPool.busy
|
||||
|
||||
This read-only attribute returns the number of connections currently
|
||||
acquired.
|
||||
|
||||
.. attribute:: AsyncConnectionPool.dsn
|
||||
|
||||
This read-only attribute returns the TNS entry of the database to which a
|
||||
connection has been established.
|
||||
|
||||
.. attribute:: AsyncConnectionPool.getmode
|
||||
|
||||
This read-write attribute determines how connections are returned from the
|
||||
pool. If :data:`~oracledb.POOL_GETMODE_FORCEGET` is specified, a new
|
||||
connection will be returned even if there are no free connections in the
|
||||
pool. :data:`~oracledb.POOL_GETMODE_NOWAIT` will raise an exception if
|
||||
there are no free connections are available in the pool. If
|
||||
:data:`~oracledb.POOL_GETMODE_WAIT` is specified and there are no free
|
||||
connections in the pool, the caller will wait until a free connection is
|
||||
available. :data:`~oracledb.POOL_GETMODE_TIMEDWAIT` uses the value of
|
||||
:data:`~ConnectionPool.wait_timeout` to determine how long the caller
|
||||
should wait for a connection to become available before returning an error.
|
||||
|
||||
.. attribute:: AsyncConnectionPool.homogeneous
|
||||
|
||||
This read-only boolean attribute indicates whether the pool is considered
|
||||
:ref:`homogeneous <connpooltypes>` or not. If the pool is not homogeneous,
|
||||
different authentication can be used for each connection acquired from the
|
||||
pool.
|
||||
|
||||
.. attribute:: AsyncConnectionPool.increment
|
||||
|
||||
This read-only attribute returns the number of connections that will be
|
||||
established when additional connections need to be created.
|
||||
|
||||
.. attribute:: AsyncConnectionPool.max
|
||||
|
||||
This read-only attribute returns the maximum number of connections that the
|
||||
pool can control.
|
||||
|
||||
.. attribute:: AsyncConnectionPool.max_lifetime_session
|
||||
|
||||
This read-write attribute returns the maximum length of time (in seconds)
|
||||
that a pooled connection may exist. Connections 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
|
||||
connection may exist. This attribute is only available in Oracle Database
|
||||
12.1 or later.
|
||||
|
||||
.. attribute:: AsyncConnectionPool.max_sessions_per_shard
|
||||
|
||||
This read-write attribute returns the number of sessions that can be
|
||||
created per shard in the pool. This attribute cannot be used in
|
||||
python-oracledb Thin mode.
|
||||
|
||||
.. attribute:: AsyncConnectionPool.min
|
||||
|
||||
This read-only attribute returns the number of connections with which the
|
||||
connection pool was created and the minimum number of connections that will
|
||||
be controlled by the connection pool.
|
||||
|
||||
.. attribute:: AsyncConnectionPool.name
|
||||
|
||||
This read-only attribute returns the name assigned to the pool by Oracle.
|
||||
|
||||
.. attribute:: AsyncConnectionPool.opened
|
||||
|
||||
This read-only attribute returns the number of connections currently opened
|
||||
by the pool.
|
||||
|
||||
.. attribute:: AsyncConnectionPool.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:`AsyncConnectionPool.acquire()`. Setting
|
||||
``ping_interval`` to a negative value disables pinging. Setting it to 0
|
||||
forces a ping for every :meth:`AsyncConnectionPool.acquire()` and is not
|
||||
recommended.
|
||||
|
||||
Prior to cx_Oracle 8.2, the ping interval was fixed at 60 seconds.
|
||||
|
||||
.. attribute:: AsyncConnectionPool.soda_metadata_cache
|
||||
|
||||
This read-write boolean attribute returns whether the SODA metadata cache
|
||||
is enabled or not. This attribute cannot be used in python-oracledb Thin
|
||||
mode.
|
||||
|
||||
.. attribute:: AsyncConnectionPool.stmtcachesize
|
||||
|
||||
This read-write attribute specifies the size of the statement cache that
|
||||
will be used for connections obtained from the pool. Once a connection is
|
||||
created, that connection’s statement cache size can only be changed by
|
||||
setting the stmtcachesize attribute on the connection itself.
|
||||
|
||||
See :ref:`Statement Caching <stmtcache>` for more information.
|
||||
|
||||
.. attribute:: AsyncConnectionPool.thin
|
||||
|
||||
This attribute returns a boolean which indicates the python-oracledb mode
|
||||
in which the pool was created. If the value of this attribute is True, it
|
||||
indicates that the pool was created in the python-oracledb Thin mode. If
|
||||
the value of this attribute is False, it indicates that the pool was created
|
||||
in the python-oracledb Thick mode.
|
||||
|
||||
.. attribute:: AsyncConnectionPool.timeout
|
||||
|
||||
This read-write attribute specifies the time (in seconds) after which idle
|
||||
connections will be terminated in order to maintain an optimum number of
|
||||
open connections. A value of 0 means that no idle connections are
|
||||
terminated.
|
||||
|
||||
.. attribute:: AsyncConnectionPool.username
|
||||
|
||||
This read-only attribute returns the name of the user which established the
|
||||
connection to the database.
|
||||
|
||||
.. attribute:: AsyncConnectionPool.wait_timeout
|
||||
|
||||
This read-write attribute specifies the time (in milliseconds) that the
|
||||
caller should wait for a connection to become available in the pool before
|
||||
returning with an error. This value is only used if the ``getmode``
|
||||
parameter to :meth:`oracledb.create_pool_async()` was the value
|
||||
:data:`oracledb.POOL_GETMODE_TIMEDWAIT`.
|
|
@ -1,488 +0,0 @@
|
|||
.. _asynccursorobj:
|
||||
|
||||
************************
|
||||
API: AsyncCursor Objects
|
||||
************************
|
||||
|
||||
An AsyncCursor object can be created with :meth:`AsyncConnection.cursor()`.
|
||||
Unless explicitly noted as synchronous, the AsyncCursor methods should be used
|
||||
with ``await``. This object is an extension to the DB API.
|
||||
|
||||
.. versionadded:: 2.0.0
|
||||
|
||||
.. note::
|
||||
|
||||
The Asynchronous I/O (asyncio) support in python-oracledb 2.0.0 is a
|
||||
pre-release and may change in the next version.
|
||||
|
||||
.. note::
|
||||
|
||||
AsyncCursor objects are only supported in the python-oracledb Thin mode.
|
||||
|
||||
.. _asynccursormeth:
|
||||
|
||||
AsyncCursor Methods
|
||||
===================
|
||||
|
||||
.. method:: AsyncCursor.__aiter__()
|
||||
|
||||
Returns the cursor itself to be used as an asynchronous iterator.
|
||||
|
||||
.. method:: AsyncCursor.__enter__()
|
||||
|
||||
The entry point for the cursor as a context manager. It returns itself.
|
||||
|
||||
.. method:: AsyncCursor.__exit__()
|
||||
|
||||
The exit point for the cursor as a context manager. It closes the cursor.
|
||||
|
||||
.. method:: AsyncCursor.arrayvar(typ, value, [size])
|
||||
|
||||
A synchronous method that creates an array variable associated with the
|
||||
cursor of the given type and size and returns 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-oracledb/blob/main/
|
||||
samples/plsql_collection.py>`__ needs to be used.
|
||||
|
||||
.. method:: AsyncCursor.bindnames()
|
||||
|
||||
A synchronous method that returns the list of bind variable names bound to
|
||||
the statement. Note that a statement must have been prepared first.
|
||||
|
||||
.. method:: AsyncCursor.callfunc(name, returnType, parameters=[], \
|
||||
keyword_parameters={})
|
||||
|
||||
Calls a function with the given name. The return type is specified in the
|
||||
same notation as is required by :meth:`~AsyncCursor.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.
|
||||
|
||||
.. note::
|
||||
|
||||
If you intend to call :meth:`AsyncCursor.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:: AsyncCursor.callproc(name, parameters=[], keyword_parameters={})
|
||||
|
||||
Calls 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.
|
||||
|
||||
.. method:: AsyncCursor.close()
|
||||
|
||||
A synchronous method that closes 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.
|
||||
|
||||
.. method:: AsyncCursor.execute(statement, parameters=[], ** keyword_parameters)
|
||||
|
||||
Executes 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 a statement, it is best to use the
|
||||
:meth:`~AsyncCursor.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.
|
||||
|
||||
.. method:: AsyncCursor.executemany(statement, parameters, batcherrors=False, \
|
||||
arraydmlrowcounts=False)
|
||||
|
||||
Prepares 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`` parameter is managed in the same way as the
|
||||
:meth:`~AsyncCursor.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:`~AsyncCursor.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:`~AsyncCursor.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:`~AsyncCursor.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:: AsyncCursor.fetchall()
|
||||
|
||||
Fetches 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 ``arraysize``.
|
||||
|
||||
An exception is raised if the previous call to
|
||||
:meth:`~AsyncCursor.execute()` did not produce any result set or no call
|
||||
was issued yet.
|
||||
|
||||
.. method:: AsyncCursor.fetchmany(size=cursor.arraysize)
|
||||
|
||||
Fetches 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:`~AsyncCursor.execute()` did not produce any result set or no call
|
||||
was issued yet.
|
||||
|
||||
.. method:: AsyncCursor.fetchone()
|
||||
|
||||
Fetches 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:`~AsyncCursor.execute()` did not produce any result set or no call
|
||||
was issued yet.
|
||||
|
||||
.. method:: AsyncCursor.getarraydmlrowcounts()
|
||||
|
||||
A synchronous method that retrieves the DML row counts after a call to
|
||||
:meth:`~AsyncCursor.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:`~AsyncCursor.executemany()`.
|
||||
|
||||
.. note::
|
||||
|
||||
This method is only available for Oracle 12.1 and later.
|
||||
|
||||
.. method:: AsyncCursor.getbatcherrors()
|
||||
|
||||
A synchronous method that retrieves the exceptions that took place after a
|
||||
call to :meth:`~AsyncCursor.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.
|
||||
|
||||
.. method:: AsyncCursor.getimplicitresults()
|
||||
|
||||
A synchronous method that returns 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 driver 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.
|
||||
|
||||
.. note::
|
||||
|
||||
This method is only available with Oracle Database 12.1 or later. 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.
|
||||
|
||||
.. method:: AsyncCursor.parse(statement)
|
||||
|
||||
This can be used to parse a statement without actually executing it
|
||||
(parsing step is done automatically by Oracle when a statement is
|
||||
:meth:`executed <AsyncCursor.execute>`).
|
||||
|
||||
.. note::
|
||||
|
||||
You can parse any DML or DDL statement. DDL statements are executed
|
||||
immediately and an implied commit takes place.
|
||||
|
||||
.. method:: AsyncCursor.prepare(statement, tag, cache_statement=True)
|
||||
|
||||
A synchronous method that can be used before a call to
|
||||
:meth:`~AsyncCursor.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:`~AsyncCursor.execute()` is made with None or the same
|
||||
string object as the statement.
|
||||
|
||||
If the ``tag`` parameter is specified and the ``cache_statement`` parameter
|
||||
is True, the statement will be returned to the statement cache with the
|
||||
given tag.
|
||||
|
||||
If the ``cache_statement`` parameter is False, the statement will be
|
||||
removed from the statement cache (if it was found there) or will simply not
|
||||
be cached.
|
||||
|
||||
See :ref:`Statement Caching <stmtcache>` for more information.
|
||||
|
||||
.. method:: AsyncCursor.setinputsizes(*args, **keywordArgs)
|
||||
|
||||
A synchronous method that can be used before a call to
|
||||
:meth:`~AsyncCursor.execute()`, :meth:`~AsyncCursor.executemany()`,
|
||||
:meth:`~AsyncCursor.callfunc()` or :meth:`~AsyncCursor.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:`~AsyncCursor.callfunc()` then be aware that the
|
||||
first parameter in the list refers to the return value of the function.
|
||||
|
||||
.. method:: AsyncCursor.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).
|
||||
|
||||
.. method:: AsyncCursor.var(typ, [size, arraysize, inconverter, outconverter, \
|
||||
typename, encoding_errors, bypass_decode, convert_nulls])
|
||||
|
||||
A synchronous method that creates 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:`AsyncConnection.gettype()` or one of the following Python
|
||||
types:
|
||||
|
||||
.. list-table-with-summary::
|
||||
:header-rows: 1
|
||||
:class: wy-table-responsive
|
||||
:align: center
|
||||
:summary: The first column is the Python Type. The second column is the corresponding Database Type.
|
||||
|
||||
* - Python Type
|
||||
- Database Type
|
||||
* - bool
|
||||
- :attr:`oracledb.DB_TYPE_BOOLEAN`
|
||||
* - bytes
|
||||
- :attr:`oracledb.DB_TYPE_RAW`
|
||||
* - datetime.date
|
||||
- :attr:`oracledb.DB_TYPE_DATE`
|
||||
* - datetime.datetime
|
||||
- :attr:`oracledb.DB_TYPE_DATE`
|
||||
* - datetime.timedelta
|
||||
- :attr:`oracledb.DB_TYPE_INTERVAL_DS`
|
||||
* - decimal.Decimal
|
||||
- :attr:`oracledb.DB_TYPE_NUMBER`
|
||||
* - float
|
||||
- :attr:`oracledb.DB_TYPE_NUMBER`
|
||||
* - int
|
||||
- :attr:`oracledb.DB_TYPE_NUMBER`
|
||||
* - str
|
||||
- :attr:`oracledb.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:`oracledb.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:`~oracledb.DB_TYPE_VARCHAR`, :data:`~oracledb.DB_TYPE_CHAR`,
|
||||
:data:`~oracledb.DB_TYPE_NVARCHAR`, :data:`~oracledb.DB_TYPE_NCHAR` and
|
||||
:data:`~oracledb.DB_TYPE_LONG` to be returned as `bytes` instead of `str`,
|
||||
meaning that python-oracledb does not do any decoding. See :ref:`Fetching raw
|
||||
data <fetching-raw-data>` for more information.
|
||||
|
||||
The ``convert_nulls`` parameter, if specified, should be passed as a boolean
|
||||
value. Passing the value ``True`` causes the ``outconverter`` to be called
|
||||
when a null value is fetched from the database; otherwise, the
|
||||
``outconverter`` is only called when non-null values are fetched from the
|
||||
database.
|
||||
|
||||
.. _asynccursorattr:
|
||||
|
||||
AsyncCursor Attributes
|
||||
======================
|
||||
|
||||
.. attribute:: AsyncCursor.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:`~AsyncCursor.fetchone()` and :meth:`~AsyncCursor.fetchall()` it
|
||||
does not change how many rows are returned to the application. For
|
||||
:meth:`~AsyncCursor.fetchmany()` it is the default number of rows to fetch.
|
||||
|
||||
The attribute is only used for tuning row and SODA document fetches from
|
||||
the database. It does not affect data inserts.
|
||||
|
||||
Due to the performance benefits, the default ``Cursor.arraysize`` is 100
|
||||
instead of the 1 that the Python DB API recommends.
|
||||
|
||||
See :ref:`Tuning Fetch Performance <tuningfetch>` for more information.
|
||||
|
||||
.. attribute:: AsyncCursor.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.
|
||||
|
||||
.. attribute:: AsyncCursor.description
|
||||
|
||||
This read-only attribute is a sequence of :ref:`FetchInfo<fetchinfoobj>`
|
||||
objects. 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:`~AsyncCursor.execute()` method yet.
|
||||
|
||||
.. attribute:: AsyncCursor.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.
|
||||
|
||||
.. attribute:: AsyncCursor.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 default behavior will take place
|
||||
for all values bound to the statements.
|
||||
|
||||
.. attribute:: AsyncCursor.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.
|
||||
|
||||
.. attribute:: AsyncCursor.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, metadata) and the return value is expected to be a
|
||||
:ref:`variable object<varobj>` or None in which case a default variable
|
||||
object will be created. If this attribute is None, then the default
|
||||
behavior will take place for all columns fetched from this cursor.
|
||||
|
||||
See :ref:`outputtypehandlers`.
|
||||
|
||||
.. attribute:: AsyncCursor.prefetchrows
|
||||
|
||||
This read-write attribute can be used to tune the number of rows that the
|
||||
python-oracledb 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.
|
||||
|
||||
The attribute is only used for tuning row fetches from the database. It
|
||||
does not affect data inserts.
|
||||
|
||||
See :ref:`Tuning Fetch Performance <tuningfetch>` for more information.
|
||||
|
||||
.. attribute:: AsyncCursor.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:: AsyncCursor.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`.
|
||||
|
||||
.. attribute:: AsyncCursor.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:`~AsyncCursor.execute()`.
|
|
@ -1,102 +0,0 @@
|
|||
.. _asynclobobj:
|
||||
|
||||
*********************
|
||||
API: AsyncLOB Objects
|
||||
*********************
|
||||
|
||||
An AsyncLOB object can be created with :meth:`AsyncConnection.createlob()`.
|
||||
Also, this object is returned whenever Oracle :data:`CLOB`, :data:`BLOB` and
|
||||
:data:`BFILE` columns are fetched. This object is an extension to the DB API.
|
||||
|
||||
See :ref:`lobdata` for more information about using LOBs.
|
||||
|
||||
.. note::
|
||||
|
||||
The Asynchronous I/O (asyncio) support in python-oracledb 2.0.0 is a
|
||||
pre-release and may change in the next version.
|
||||
|
||||
.. note::
|
||||
|
||||
AsyncLOB objects are only supported in the python-oracledb Thin mode.
|
||||
|
||||
.. _asynclobmeth:
|
||||
|
||||
AsyncLOB Methods
|
||||
================
|
||||
|
||||
.. method:: AsyncLOB.close()
|
||||
|
||||
Closes the LOB. Call this when writing is completed so that the indexes
|
||||
associated with the LOB can be updated -- but only if :meth:`~AsyncLOB.open()`
|
||||
was called first.
|
||||
|
||||
.. method:: AsyncLOB.fileexists()
|
||||
|
||||
Returns a boolean indicating if the file referenced by the BFILE type LOB
|
||||
exists.
|
||||
|
||||
.. method:: AsyncLOB.getchunksize()
|
||||
|
||||
Returns the chunk size for the internal LOB. Reading and writing to the LOB
|
||||
in chunks of multiples of this size will improve performance.
|
||||
|
||||
.. method:: AsyncLOB.getfilename()
|
||||
|
||||
Returns a two-tuple consisting of the directory alias and file name for a
|
||||
BFILE type LOB.
|
||||
|
||||
.. method:: AsyncLOB.isopen()
|
||||
|
||||
Returns a boolean indicating if the LOB has been opened using the method
|
||||
:meth:`~AsyncLOB.open()`.
|
||||
|
||||
.. method:: AsyncLOB.open()
|
||||
|
||||
Opens 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:: AsyncLOB.read([offset=1, [amount]])
|
||||
|
||||
Returns 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:: AsyncLOB.setfilename(dirAlias, name)
|
||||
|
||||
Sets the directory alias and name of the BFILE type LOB.
|
||||
|
||||
.. method:: AsyncLOB.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:: AsyncLOB.trim(new_size=0)
|
||||
|
||||
Trims the LOB to the new size.
|
||||
|
||||
.. method:: AsyncLOB.write(data, offset=1)
|
||||
|
||||
Writes 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:`~AsyncLOB.trim()` function.
|
||||
|
||||
.. _asynclobattr:
|
||||
|
||||
AsyncLOB Attributes
|
||||
===================
|
||||
|
||||
.. attribute:: AsyncLOB.type
|
||||
|
||||
This read-only attribute returns the type of the LOB as one of the
|
||||
:ref:`database type constants <dbtypes>`.
|
|
@ -18,46 +18,31 @@ ConnectParams Methods
|
|||
|
||||
.. method:: ConnectParams.copy()
|
||||
|
||||
Creates a copy of the ConnectParams instance and returns it.
|
||||
Creates a copy of the ConnectParams instance and returns it.
|
||||
|
||||
.. method:: ConnectParams.get_connect_string()
|
||||
|
||||
Returns the connection string associated with the ConnectParams instance.
|
||||
Returns the connection string associated with the ConnectParams instance.
|
||||
|
||||
.. method:: ConnectParams.parse_connect_string(connect_string)
|
||||
|
||||
Parses the connect string into its components and stores the parameters.
|
||||
Parses the connect string into its components and stores the parameters.
|
||||
|
||||
The ``connect string`` parameter can be an Easy Connect string, name-value
|
||||
pairs, or a simple alias which is looked up in ``tnsnames.ora``. Parameters
|
||||
that are found in the connect string override any currently stored values.
|
||||
|
||||
.. method:: ConnectParams.parse_dsn_with_credentials(dsn)
|
||||
|
||||
Parses a DSN in the form <user>/<password>@<connect_string> or in the form
|
||||
<user>/<password> and returns a 3-tuple containing the parsed user,
|
||||
password and connect string. Empty strings are returned as the value
|
||||
``None``.
|
||||
|
||||
.. versionadded:: 1.3.0
|
||||
The ``connect string`` parameter can be an Easy Connect string, name-value
|
||||
pairs, or a simple alias which is looked up in ``tnsnames.ora``. Parameters
|
||||
that are found in the connect string override any currently stored values.
|
||||
|
||||
.. method:: ConnectParams.set(user=None, proxy_user=None, password=None, \
|
||||
newpassword=None, wallet_password=None, access_token=None, host=None, \
|
||||
port=None, protocol=None, https_proxy=None, https_proxy_port=None, \
|
||||
service_name=None, sid=None, server_type=None, cclass=None, \
|
||||
purity=None, expire_time=None, retry_count=None, retry_delay=None, \
|
||||
tcp_connect_timeout=None, ssl_server_dn_match=None, \
|
||||
ssl_server_cert_dn=None, wallet_location=None, events=None, \
|
||||
externalauth=None, mode=None, disable_oob=None, stmtcachesize=None, \
|
||||
edition=None, tag=None, matchanytag=None, config_dir=None, \
|
||||
appcontext=[], shardingkey=[], supershardingkey=[], debug_jdwp=None, \
|
||||
connection_id_prefix=None, ssl_context=None, sdu=None, handle=None)
|
||||
newpassword=None, wallet_password=None, access_token=None, host=None, \
|
||||
port=None, protocol=None, https_proxy=None, https_proxy_port=None, service_name=None, \
|
||||
sid=None, server_type=None, cclass=None, purity=None, expire_time=None, retry_count=None, \
|
||||
retry_delay=None, tcp_connect_timeout=None, ssl_server_dn_match=None, \
|
||||
ssl_server_cert_dn=None, wallet_location=None, events=None, externalauth=None, \
|
||||
mode=None, disable_oob=None, stmtcachesize=None, edition=None, tag=None, \
|
||||
matchanytag=None, config_dir=None, appcontext=[], shardingkey=[], supershardingkey=[], \
|
||||
debug_jdwp=None, handle=None)
|
||||
|
||||
Sets the default values for one or more of the parameters of an empty
|
||||
ConnectParams object. A default will be overriden when a connection string
|
||||
with that attribute is parsed. After a ConnectParams object has been
|
||||
populated by parsing a connection string, ``ConnectParams.set()`` will not
|
||||
override any values.
|
||||
Sets one or more of the parameters.
|
||||
|
||||
|
||||
.. _connparamsattr:
|
||||
|
@ -67,312 +52,276 @@ ConnectParams Attributes
|
|||
|
||||
.. attribute:: ConnectParams.appcontext
|
||||
|
||||
This read-only attribute is a list that specifies the application context
|
||||
used by the connection. It is a list of 3-tuples that includes the
|
||||
namespace, name, and value. Each entry in the tuple is a string.
|
||||
This read-only attribute is a list that specifies the application context used by
|
||||
the connection. It is a list of 3-tuples that includes the namespace, name, and value.
|
||||
Each entry in the tuple is a string.
|
||||
|
||||
This attribute is only supported in the python-oracledb Thick mode.
|
||||
This attribute is only supported in the python-oracledb Thick mode.
|
||||
|
||||
.. attribute:: ConnectParams.cclass
|
||||
|
||||
This read-only attribute is a string that specifies the connection class
|
||||
to use for Database Resident Connection Pooling (DRCP).
|
||||
This read-only attribute is a string that specifies the connection class
|
||||
to use for Database Resident Connection Pooling (DRCP).
|
||||
|
||||
This attribute is supported in the python-oracledb Thin and Thick modes.
|
||||
This attribute is supported in the python-oracledb Thin and Thick modes.
|
||||
|
||||
.. attribute:: ConnectParams.config_dir
|
||||
|
||||
This read-only attribute is a string that identifies the directory in which
|
||||
the configuration files such as tnsnames.ora are found. The default is the
|
||||
value of :attr:`defaults.config_dir`.
|
||||
This read-only attribute is a string that identifies the directory in which
|
||||
the configuration files such as tnsnames.ora are found. The default is the
|
||||
value of :attr:`defaults.config_dir`.
|
||||
|
||||
This attribute is only supported in the python-oracledb Thin mode.
|
||||
This attribute is only supported in the python-oracledb Thin mode.
|
||||
|
||||
For the python-oracledb Thick mode, use the ``config_dir`` parameter of
|
||||
:func:`oracledb.init_oracle_client`.
|
||||
|
||||
.. attribute:: ConnectParams.connection_id_prefix
|
||||
|
||||
This read-only attribute is a string that is added to the beginning of the
|
||||
generated ``connection_id`` that is sent to the database for
|
||||
`tracing <https://www.oracle.com/pls/topic/lookup?
|
||||
ctx=dblatest&id=GUID-B0FC69F9-2EBC-44E8-ACB2-62FBA14ABD5C>`__.
|
||||
|
||||
.. versionadded:: 1.4.0
|
||||
For the python-oracledb Thick mode, use the ``config_dir`` parameter of
|
||||
:func:`oracledb.init_oracle_client`.
|
||||
|
||||
.. attribute:: ConnectParams.debug_jdwp
|
||||
|
||||
This read-only attribute is a string with the format
|
||||
"host=<host>;port=<port>" that specifies the host and port of the PL/SQL
|
||||
debugger. This allows the Java Debug Wire Protocol (JDWP) to debug the
|
||||
PL/SQL code invoked by the python-oracledb driver. The default value is the
|
||||
value of the environment variable ``ORA_DEBUG_JDWP``.
|
||||
This read-only attribute is a string with the format "host=<host>;port=<port>"
|
||||
that specifies the host and port of the PL/SQL debugger. This allows the
|
||||
Java Debug Wire Protocol (JDWP) to debug the PL/SQL code invoked by the
|
||||
python-oracledb driver. The default value is the value of the environment
|
||||
variable ``ORA_DEBUG_JDWP``.
|
||||
|
||||
This attribute is only supported in the python-oracledb Thin mode. For
|
||||
the python-oracledb Thick mode, set the ``ORA_DEBUG_JDWP`` environment
|
||||
variable which has the same syntax. See :ref:`applntracing` for more
|
||||
information.
|
||||
This attribute is only supported in the python-oracledb Thin mode. For
|
||||
the python-oracledb Thick mode, set the ``ORA_DEBUG_JDWP`` environment
|
||||
variable which has the same syntax. See :ref:`applntracing` for more
|
||||
information.
|
||||
|
||||
.. attribute:: ConnectParams.disable_oob
|
||||
|
||||
This read-only attribute is a boolean that indicates whether out-of-band
|
||||
breaks should be disabled. The default value is False. Note that this value
|
||||
has no effect on Windows, which does not support this functionality.
|
||||
This read-only attribute is a boolean that indicates whether out-of-band
|
||||
breaks should be disabled. The default value is False. Note that this value
|
||||
has no effect on Windows, which does not support this functionality.
|
||||
|
||||
This attribute is only supported in the python-oracledb Thin mode.
|
||||
This attribute is only supported in the python-oracledb Thin mode.
|
||||
|
||||
For the python-oracledb Thick mode, set the equivalent option in a
|
||||
``sqlnet.ora`` file.
|
||||
For the python-oracledb Thick mode, set the equivalent option in a
|
||||
``sqlnet.ora`` file.
|
||||
|
||||
.. attribute:: ConnectParams.edition
|
||||
|
||||
This read-only attribute is a string that specifies the edition to use
|
||||
for the connection. This attribute cannot be used simultaneously with the
|
||||
:attr:`ConnectParams.cclass` attribute.
|
||||
This read-only attribute is a string that specifies the edition to use
|
||||
for the connection. This attribute cannot be used simultaneously with the
|
||||
:attr:`ConnectParams.cclass` attribute.
|
||||
|
||||
This attribute is supported in the python-oracledb Thin and Thick modes.
|
||||
This attribute is supported in the python-oracledb Thin and Thick modes.
|
||||
|
||||
.. attribute:: ConnectParams.events
|
||||
|
||||
This read-only attribute is a boolean that specifies whether the events
|
||||
mode should be enabled.
|
||||
This read-only attribute is a boolean that specifies whether the events mode
|
||||
should be enabled.
|
||||
|
||||
This attribute is needed for continuous query notification (CQN) and high
|
||||
availability event notifications. The default value is False.
|
||||
This attribute is needed for continuous query notification (CQN) and high
|
||||
availability event notifications. The default value is False.
|
||||
|
||||
This attribute is only supported in the python-oracledb Thick mode.
|
||||
This attribute is only supported in the python-oracledb Thick mode.
|
||||
|
||||
.. attribute:: ConnectParams.expire_time
|
||||
|
||||
This read-only attribute is an integer that returns the number of minutes
|
||||
between the sending of keepalive probes.
|
||||
This read-only attribute is an integer that returns the number of minutes
|
||||
between the sending of keepalive probes.
|
||||
The default value is 0. If this attribute is set to a value greater than zero,
|
||||
it enables keepalive.
|
||||
|
||||
The default value is 0. If this attribute is set to a value greater than
|
||||
zero, it enables keepalive.
|
||||
|
||||
This attribute is supported in the python-oracledb Thin and Thick modes.
|
||||
This attribute is supported in the python-oracledb Thin and Thick modes.
|
||||
|
||||
.. attribute:: ConnectParams.externalauth
|
||||
|
||||
This read-only attribute is a boolean that specifies whether external
|
||||
authentication should be used. The default value is False.
|
||||
This read-only attribute is a boolean that specifies whether external
|
||||
authentication should be used. The default value is False.
|
||||
|
||||
For standalone connections, external authentication occurs when the
|
||||
``user`` and ``password`` attributes are not used. If these attributes,
|
||||
are not used, you can optionally set the ``externalauth`` attribute to
|
||||
True, which may aid code auditing.
|
||||
For standalone connections, external authentication occurs when the
|
||||
``user`` and ``password`` attributes are not used. If these attributes,
|
||||
are not used, you can optionally set the ``externalauth`` attribute to
|
||||
True, which may aid code auditing.
|
||||
|
||||
This attribute is only supported in the python-oracledb Thick mode.
|
||||
This attribute is only supported in the python-oracledb Thick mode.
|
||||
|
||||
.. attribute:: ConnectParams.host
|
||||
|
||||
This read-only attribute is a string that returns the name or IP address of
|
||||
the machine hosting the database.
|
||||
This read-only attribute is a string that returns the name or IP address of
|
||||
the machine hosting the database.
|
||||
|
||||
This attribute is supported in the python-oracledb Thin and Thick modes.
|
||||
This attribute is supported in the python-oracledb Thin and Thick modes.
|
||||
|
||||
.. attribute:: ConnectParams.https_proxy
|
||||
|
||||
This read-only attribute is a string that returns the name or IP address of
|
||||
a proxy host that is to be used for tunneling secure connections.
|
||||
This read-only attribute is a string that returns the name or IP address of
|
||||
a proxy host that is to be used for tunneling secure connections.
|
||||
|
||||
This attribute is supported in the python-oracledb Thin and Thick modes.
|
||||
This attribute is supported in the python-oracledb Thin and Thick modes.
|
||||
|
||||
.. attribute:: ConnectParams.https_proxy_port
|
||||
|
||||
This read-only attribute is an integer that returns the port to be used to
|
||||
communicate with the proxy host. The default value is 0.
|
||||
This read-only attribute is an integer that returns the port to be used to
|
||||
communicate with the proxy host.
|
||||
The default value is 0.
|
||||
|
||||
This attribute is supported in the python-oracledb Thin and Thick modes.
|
||||
This attribute is supported in the python-oracledb Thin and Thick modes.
|
||||
|
||||
.. attribute:: ConnectParams.matchanytag
|
||||
|
||||
This read-only attribute is a boolean that specifies whether any tag can be
|
||||
used when acquiring a connection from the pool. The default value is False.
|
||||
This read-only attribute is a boolean that specifies whether any tag can be
|
||||
used when acquiring a connection from the pool.
|
||||
The default value is False.
|
||||
|
||||
This attribute is only supported in the python-oracledb Thick mode.
|
||||
This attribute is only supported in the python-oracledb Thick mode.
|
||||
|
||||
.. attribute:: ConnectParams.mode
|
||||
|
||||
This read-only attribute is an integer that specifies the authorization mode
|
||||
to use. The default value is :data:`~oracledb.AUTH_MODE_DEFAULT`.
|
||||
This read-only attribute is an integer that specifies the authorization mode
|
||||
to use.
|
||||
The default value is :data:`~oracledb.AUTH_MODE_DEFAULT`.
|
||||
|
||||
This attribute is supported in the python-oracledb Thin and Thick modes.
|
||||
This attribute is supported in the python-oracledb Thin and Thick modes.
|
||||
|
||||
.. attribute:: ConnectParams.port
|
||||
|
||||
This read-only attribute is an integer that returns the port number on
|
||||
which the database listener is listening. The default value is 1521.
|
||||
This read-only attribute is an integer that returns the port number on which
|
||||
the database listener is listening. The default value is 1521.
|
||||
|
||||
This attribute is supported in the python-oracledb Thin and Thick modes.
|
||||
This attribute is supported in the python-oracledb Thin and Thick modes.
|
||||
|
||||
.. attribute:: ConnectParams.protocol
|
||||
|
||||
This read-only attribute is a string that indicates whether unencrypted
|
||||
network traffic or encrypted network traffic (TLS) is used and it can have
|
||||
the value "tcp" or "tcps". The default value is "tcp".
|
||||
This read-only attribute is a string that indicates whether unencrypted network
|
||||
traffic or encrypted network traffic (TLS) is used and it can have the value
|
||||
tcp or tcps.
|
||||
The default value is tcp.
|
||||
|
||||
This attribute is supported in the python-oracledb Thin and Thick modes.
|
||||
This attribute is supported in the python-oracledb Thin and Thick modes.
|
||||
|
||||
.. attribute:: ConnectParams.proxy_user
|
||||
|
||||
This read-only attribute is a string that specifies the name of the proxy
|
||||
user to connect to. If this value is not specified, then it will be parsed
|
||||
out of the user if the user attribute is in the form "user[proxy_user]".
|
||||
This read-only attribute is a string that specifies the name of the proxy user to connect to.
|
||||
If this value is not specified, then it will be parsed out of the user if the user attribute
|
||||
is in the form "user[proxy_user]".
|
||||
|
||||
This attribute is supported in the python-oracledb Thin and Thick modes.
|
||||
This attribute is supported in the python-oracledb Thin and Thick modes.
|
||||
|
||||
|
||||
.. attribute:: ConnectParams.purity
|
||||
|
||||
This read-only attribute is an integer that returns the purity used for
|
||||
DRCP. When the value of this attribute is :attr:`oracledb.PURITY_DEFAULT`,
|
||||
then any standalone connection will use :attr:`oracledb.PURITY_NEW` and any
|
||||
pooled connection will use :attr:`oracledb.PURITY_SELF`. The default value
|
||||
is :data:`~oracledb.PURITY_DEFAULT`.
|
||||
This read-only attribute is an integer that returns the purity used for DRCP.
|
||||
When the value of this attribute is :attr:`oracledb.PURITY_DEFAULT`, then any
|
||||
standalone connection will use :attr:`oracledb.PURITY_NEW` and any pooled
|
||||
connection will use :attr:`oracledb.PURITY_SELF`. The default value is
|
||||
:data:`~oracledb.PURITY_DEFAULT`.
|
||||
|
||||
This attribute is supported in the python-oracledb Thin and Thick modes.
|
||||
This attribute is supported in the python-oracledb Thin and Thick modes.
|
||||
|
||||
.. attribute:: ConnectParams.retry_count
|
||||
|
||||
This read-only attribute is an integer that returns the number of times
|
||||
that a connection attempt should be retried before the attempt is
|
||||
terminated. The default value is 0.
|
||||
This read-only attribute is an integer that returns the number of times that a
|
||||
connection attempt should be retried before the attempt is terminated.
|
||||
The default value is 0.
|
||||
|
||||
This attribute is supported in the python-oracledb Thin and Thick modes.
|
||||
This attribute is supported in the python-oracledb Thin and Thick modes.
|
||||
|
||||
.. attribute:: ConnectParams.retry_delay
|
||||
|
||||
This read-only attribute is an integer that returns the number of seconds
|
||||
to wait before making a new connection attempt. The default value is 0.
|
||||
This read-only attribute is an integer that returns the number of seconds to
|
||||
wait before making a new connection attempt.
|
||||
The default value is 0.
|
||||
|
||||
This attribute is supported in the python-oracledb Thin and Thick modes.
|
||||
|
||||
.. attribute:: ConnectParams.sdu
|
||||
|
||||
This read-only attribute is an integer that returns the requested size of
|
||||
the Session Data Unit (SDU), in bytes. The value tunes internal buffers
|
||||
used for communication to the database. Bigger values can increase
|
||||
throughput for large queries or bulk data loads, but at the cost of higher
|
||||
memory use. The SDU size that will actually be used is negotiated down to
|
||||
the lower of this value and the database network SDU configuration value.
|
||||
See the `SQL*Net documentation
|
||||
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&
|
||||
id=GUID-86D61D6F-AD26-421A-BABA-77949C8A2B04>`__ for more details.
|
||||
|
||||
This attribute is supported in the python-oracledb Thin and Thick modes.
|
||||
|
||||
.. versionadded:: 2.0.0
|
||||
This attribute is supported in the python-oracledb Thin and Thick modes.
|
||||
|
||||
.. attribute:: ConnectParams.server_type
|
||||
|
||||
This read-only attribute is a string that returns the type of server
|
||||
connection that should be established. If specified, it should be one of
|
||||
`dedicated`, `shared`, or `pooled`.
|
||||
This read-only attribute is a string that returns the type of server connection
|
||||
that should be established. If specified, it should be one of `dedicated`, `shared`,
|
||||
or `pooled`.
|
||||
|
||||
This attribute is supported in the python-oracledb Thin and Thick modes.
|
||||
This attribute is supported in the python-oracledb Thin and Thick modes.
|
||||
|
||||
.. attribute:: ConnectParams.service_name
|
||||
|
||||
This read-only attribute is a string that returns the service name of the
|
||||
database.
|
||||
This read-only attribute is a string that returns the service name of the database.
|
||||
|
||||
This attribute is supported in the python-oracledb Thin and Thick modes.
|
||||
This attribute is supported in the python-oracledb Thin and Thick modes.
|
||||
|
||||
.. attribute:: ConnectParams.shardingkey
|
||||
|
||||
This read-only attribute is a list that specifies a sequence of strings,
|
||||
numbers, bytes, or dates that identify the database shard to connect to.
|
||||
This read-only attribute is a list that specifies a sequence of strings, numbers,
|
||||
bytes, or dates that identify the database shard to connect to.
|
||||
|
||||
This attribute is only supported in the python-oracledb Thick mode.
|
||||
This attribute is only supported in the python-oracledb Thick mode.
|
||||
|
||||
.. attribute:: ConnectParams.sid
|
||||
|
||||
This read-only attribute is a string that returns the SID of the database.
|
||||
It is recommended to use the :attr:`ConnectParams.service_name` instead.
|
||||
This read-only attribute is a string that returns the SID of the database.
|
||||
It is recommended to use the :attr:`ConnectParams.service_name` instead.
|
||||
|
||||
This attribute is supported in the python-oracledb Thin and Thick modes.
|
||||
|
||||
.. attribute:: ConnectParams.ssl_context
|
||||
|
||||
This read-only attribute is an `SSLContext object
|
||||
<https://docs.python.org/3/library/ssl.html#ssl-contexts>`__ which is used
|
||||
for connecting to the database using TLS. This SSL context will be modified
|
||||
to include the private key or any certificates found in a separately
|
||||
supplied wallet. This parameter should only be specified if the default
|
||||
SSLContext object cannot be used.
|
||||
|
||||
This attribute is only supported in the python-oracledb Thin mode.
|
||||
|
||||
.. versionadded:: 2.0.0
|
||||
This attribute is supported in the python-oracledb Thin and Thick modes.
|
||||
|
||||
.. attribute:: ConnectParams.ssl_server_cert_dn
|
||||
|
||||
This read-only attribute is a string that returns the distinguished name
|
||||
(DN), which should be matched with the server. If this value is specified,
|
||||
then it is used for any verification. Otherwise, the hostname will be used.
|
||||
This read-only attribute is a string that returns the distinguished name (DN),
|
||||
which should be matched with the server. If this value is specified, then it is
|
||||
used for any verification. Otherwise, the hostname will be used.
|
||||
|
||||
This value is ignored if the :attr:`~ConnectParams.ssl_server_dn_match`
|
||||
attribute is not set to the value `True`.
|
||||
This value is ignored if the :attr:`~ConnectParams.ssl_server_dn_match`
|
||||
attribute is not set to the value `True`.
|
||||
|
||||
This attribute is supported in the python-oracledb Thin and Thick modes.
|
||||
This attribute is supported in the python-oracledb Thin and Thick modes.
|
||||
|
||||
.. attribute:: ConnectParams.ssl_server_dn_match
|
||||
|
||||
This read-only attribute is a boolean that indicates whether the server
|
||||
certificate distinguished name (DN) should be matched in addition to the
|
||||
regular certificate verification that is performed. The default value is
|
||||
True.
|
||||
This read-only attribute is a boolean that indicates whether the server certificate
|
||||
distinguished name (DN) should be matched in addition to the regular
|
||||
certificate verification that is performed. The default value is True.
|
||||
|
||||
Note that if the :attr:`~ConnectParams.ssl_server_cert_dn` attribute is not
|
||||
specified, then host name matching is performed instead.
|
||||
Note that if the :attr:`~ConnectParams.ssl_server_cert_dn` attribute is not specified,
|
||||
then host name matching is performed instead.
|
||||
|
||||
This attribute is supported in the python-oracledb Thin and Thick modes.
|
||||
This attribute is supported in the python-oracledb Thin and Thick modes.
|
||||
|
||||
.. attribute:: ConnectParams.stmtcachesize
|
||||
|
||||
This read-only attribute is an integer that identifies the initial size of
|
||||
the statement cache. The default is the value of
|
||||
:attr:`defaults.stmtcachesize`.
|
||||
This read-only attribute is an integer that identifies the initial size of
|
||||
the statement cache. The default is the value of
|
||||
:attr:`defaults.stmtcachesize`.
|
||||
|
||||
This attribute is supported in the python-oracledb Thin and Thick modes.
|
||||
This attribute is supported in the python-oracledb Thin and Thick modes.
|
||||
|
||||
.. attribute:: ConnectParams.supershardingkey
|
||||
|
||||
This read-only attribute is a list that specifies a sequence of strings,
|
||||
numbers, bytes, or dates that identify the database shard to connect to.
|
||||
This read-only attribute is a list that specifies a sequence of strings, numbers,
|
||||
bytes, or dates that identify the database shard to connect to.
|
||||
|
||||
This attribute is only supported in python-oracledb Thick mode.
|
||||
This attribute is only supported in python-oracledb Thick mode.
|
||||
|
||||
.. attribute:: ConnectParams.tag
|
||||
|
||||
This read-only attribute is a string that identifies the type of connection
|
||||
that should be returned from a pool.
|
||||
This read-only attribute is a string that identifies the type of connection that
|
||||
should be returned from a pool.
|
||||
|
||||
This attribute is only supported in python-oracledb Thick mode.
|
||||
This attribute is only supported in python-oracledb Thick mode.
|
||||
|
||||
.. attribute:: ConnectParams.tcp_connect_timeout
|
||||
|
||||
This read-only attribute is a float that indicates the maximum number of
|
||||
seconds to wait for a connection to be established to the database host.
|
||||
The default value is 60.0.
|
||||
This read-only attribute is a float that indicates the maximum number of seconds
|
||||
to wait for a connection to be established to the database host.
|
||||
The default value is 60.0.
|
||||
|
||||
This attribute is supported in the python-oracledb Thin and Thick modes.
|
||||
This attribute is supported in the python-oracledb Thin and Thick modes.
|
||||
|
||||
.. attribute:: ConnectParams.user
|
||||
|
||||
This read-only attribute is a string that specifies the name of the user to
|
||||
connect to.
|
||||
This read-only attribute is a string that specifies the name of the user to
|
||||
connect to.
|
||||
|
||||
This attribute is supported in the python-oracledb Thin and Thick modes.
|
||||
This attribute is supported in the python-oracledb Thin and Thick modes.
|
||||
|
||||
.. attribute:: ConnectParams.wallet_location
|
||||
|
||||
This read-only attribute is a string that specifies the directory where the
|
||||
wallet can be found.
|
||||
This read-only attribute is a string that specifies the directory where the
|
||||
wallet can be found.
|
||||
|
||||
In python-oracledb Thin mode, this attribute is the directory containing
|
||||
the PEM-encoded wallet file, ewallet.pem. In python-oracledb Thick mode,
|
||||
this attribute is the directory containing the file, cwallet.sso.
|
||||
In python-oracledb Thin mode, this attribute is the directory containing the
|
||||
PEM-encoded wallet file, ewallet.pem. In python-oracledb Thick mode, this
|
||||
attribute is the directory containing the file, cwallet.sso.
|
||||
|
||||
This attribute is supported in the python-oracledb Thin and Thick modes.
|
||||
This attribute is supported in the python-oracledb Thin and Thick modes.
|
||||
|
|
|
@ -4,8 +4,7 @@
|
|||
API: Connection Objects
|
||||
***********************
|
||||
|
||||
A Connection object can be created with :meth:`oracledb.connect()` or with
|
||||
:meth:`ConnectionPool.acquire()`.
|
||||
A Connection object can be created with :meth:`oracledb.connect()`.
|
||||
|
||||
.. note::
|
||||
|
||||
|
@ -24,6 +23,7 @@ Connection Methods
|
|||
|
||||
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
|
||||
|
@ -33,6 +33,7 @@ Connection Methods
|
|||
|
||||
This method is an extension to the DB API definition.
|
||||
|
||||
|
||||
.. method:: Connection.begin([formatId, transactionId, branchId])
|
||||
|
||||
Explicitly begins a new transaction. Without parameters, this explicitly
|
||||
|
@ -60,6 +61,7 @@ Connection Methods
|
|||
|
||||
This method is an extension to the DB API definition.
|
||||
|
||||
|
||||
.. method:: Connection.changepassword(oldpassword, newpassword)
|
||||
|
||||
Changes the password for the user to which the connection is
|
||||
|
@ -88,19 +90,11 @@ Connection Methods
|
|||
|
||||
Commits any pending transactions to the database.
|
||||
|
||||
.. method:: Connection.createlob(lob_type, data=None)
|
||||
.. method:: Connection.createlob(lobType)
|
||||
|
||||
Creates and returns a new temporary :ref:`LOB object <lobobj>` of the
|
||||
specified type. The ``lob_type`` parameter should be one of
|
||||
:data:`oracledb.DB_TYPE_CLOB`, :data:`oracledb.DB_TYPE_BLOB`, or
|
||||
:data:`oracledb.DB_TYPE_NCLOB`.
|
||||
|
||||
If data is supplied, it will be written to the temporary LOB before it is
|
||||
returned.
|
||||
|
||||
.. versionchanged:: 2.0
|
||||
|
||||
The parameter ``data`` was added.
|
||||
specified type. The ``lobType`` parameter should be one of
|
||||
:data:`oracledb.CLOB`, :data:`oracledb.BLOB` or :data:`oracledb.NCLOB`.
|
||||
|
||||
.. note::
|
||||
|
||||
|
@ -123,6 +117,7 @@ Connection Methods
|
|||
|
||||
This method is an extension to the DB API definition.
|
||||
|
||||
|
||||
.. method:: Connection.gettype(name)
|
||||
|
||||
Returns a :ref:`type object <dbobjecttype>` given its name. This can then be
|
||||
|
@ -133,6 +128,7 @@ Connection Methods
|
|||
|
||||
This method is an extension to the DB API definition.
|
||||
|
||||
|
||||
.. method:: Connection.is_healthy()
|
||||
|
||||
This function returns a boolean indicating the health status of a connection.
|
||||
|
@ -171,6 +167,7 @@ Connection Methods
|
|||
|
||||
This method is an extension to the DB API definition.
|
||||
|
||||
|
||||
.. method:: Connection.prepare()
|
||||
|
||||
Prepares the distributed (global) transaction for commit. Return a boolean
|
||||
|
@ -185,6 +182,7 @@ Connection Methods
|
|||
|
||||
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
|
||||
|
@ -206,10 +204,12 @@ Connection Methods
|
|||
|
||||
This method is an extension to the DB API definition.
|
||||
|
||||
|
||||
.. method:: Connection.rollback()
|
||||
|
||||
Rolls back any pending transactions.
|
||||
|
||||
|
||||
.. method:: Connection.shutdown([mode])
|
||||
|
||||
Shuts down the database. In order to do this the connection must be connected
|
||||
|
@ -352,7 +352,7 @@ Connection Methods
|
|||
explicitly closed using the function :meth:`~Connection.close()`, the
|
||||
subscription will not be deregistered in the database.
|
||||
|
||||
.. method:: Connection.tpc_begin(xid, flags, timeout)
|
||||
.. method:: Connection.tpc_begin(xid, flags)
|
||||
|
||||
Begins a Two-Phase Commit (TPC) on a global transaction using the specified
|
||||
transaction identifier (xid).
|
||||
|
@ -364,19 +364,10 @@ Connection Methods
|
|||
:data:`oracledb.TPC_BEGIN_NEW`, :data:`oracledb.TPC_BEGIN_PROMOTE`, or
|
||||
:data:`oracledb.TPC_BEGIN_RESUME`. The default is :data:`oracledb.TPC_BEGIN_NEW`.
|
||||
|
||||
The ``timeout`` parameter is the number of seconds to wait for a transaction to
|
||||
become available for resumption when :data:`~oracledb.TPC_BEGIN_RESUME` is
|
||||
specified in the ``flags`` parameter. When :data:`~oracledb.TPC_BEGIN_NEW` is
|
||||
specified in the ``flags`` parameter, the ``timeout`` parameter indicates the
|
||||
number of seconds the transaction can be inactive before it is automatically
|
||||
terminated by the system. A transaction is inactive between the time it is
|
||||
detached with :meth:`Connection.tpc_end()` and the time it is resumed with
|
||||
:meth:`Connection.tpc_begin()`.The default is 0 seconds.
|
||||
|
||||
The following code sample demonstrates the ``tpc_begin()`` function::
|
||||
|
||||
connection.tpc_begin(xid=x, flags=oracledb.TPC_BEGIN_NEW)
|
||||
x = connection.xid(format_id=1, global_transaction_id="tx1", branch_qualifier="br1")
|
||||
connection.tpc_begin(xid=x, flags=oracledb.TPC_BEGIN_NEW, timeout=30)
|
||||
|
||||
See :ref:`tcp` for information on TPC.
|
||||
|
||||
|
@ -401,8 +392,8 @@ Connection Methods
|
|||
|
||||
The following code sample demonstrates the ``tpc_commit()`` function::
|
||||
|
||||
x = connection.xid(format_id=1, global_transaction_id="tx1", branch_qualifier="br1")
|
||||
connection.tpc_commit(xid=x, one_phase=False)
|
||||
x = connection.xid(format_id=1, global_transaction_id="tx1", branch_qualifier="br1")
|
||||
|
||||
See :ref:`tcp` for information on TPC.
|
||||
|
||||
|
@ -424,8 +415,8 @@ Connection Methods
|
|||
|
||||
The following code sample demonstrates the ``tpc_end()`` function::
|
||||
|
||||
x = connection.xid(format_id=1, global_transaction_id="tx1", branch_qualifier="br1")
|
||||
connection.tpc_end(xid=x, flags=oracledb.TPC_END_NORMAL)
|
||||
x = connection.xid(format_id=1, global_transaction_id="tx1", branch_qualifier="br1")
|
||||
|
||||
See :ref:`tcp` for information on TPC.
|
||||
|
||||
|
@ -439,8 +430,8 @@ Connection Methods
|
|||
|
||||
The following code sample demonstrates the ``tpc_forget()`` function::
|
||||
|
||||
x = connection.xid(format_id=1, global_transaction_id="tx1", branch_qualifier="br1")
|
||||
connection.tpc_forget(xid=x)
|
||||
x = connection.xid(format_id=1, global_transaction_id="tx1", branch_qualifier="br1")
|
||||
|
||||
See :ref:`tcp` for information on TPC.
|
||||
|
||||
|
@ -461,8 +452,8 @@ Connection Methods
|
|||
|
||||
The following code sample demonstrates the ``tpc_prepare()`` function::
|
||||
|
||||
x = connection.xid(format_id=1, global_transaction_id="tx1", branch_qualifier="br1")
|
||||
connection.tpc_prepare(xid=x)
|
||||
x = connection.xid(format_id=1, global_transaction_id="tx1", branch_qualifier="br1")
|
||||
|
||||
See :ref:`tcp` for information on TPC.
|
||||
|
||||
|
@ -496,8 +487,8 @@ Connection Methods
|
|||
|
||||
The following code sample demonstrates the ``tpc_rollback()`` function::
|
||||
|
||||
x = connection.xid(format_id=1, global_transaction_id="tx1", branch_qualifier="br1")
|
||||
connection.tpc_rollback(xid=x)
|
||||
x = connection.xid(format_id=1, global_transaction_id="tx1", branch_qualifier="br1")
|
||||
|
||||
See :ref:`tcp` for information on TPC.
|
||||
|
||||
|
@ -540,13 +531,14 @@ Connection Attributes
|
|||
.. attribute:: Connection.action
|
||||
|
||||
This write-only attribute sets the action column in the v$session table. It
|
||||
is a string attribute but the value None is accepted and treated as an
|
||||
empty string.
|
||||
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.
|
||||
|
@ -586,6 +578,7 @@ Connection Attributes
|
|||
|
||||
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
|
||||
|
@ -607,35 +600,11 @@ Connection Attributes
|
|||
|
||||
This attribute is an extension to the DB API definition.
|
||||
|
||||
.. attribute:: Connection.db_domain
|
||||
|
||||
This read-only attribute specifies the Oracle Database domain name
|
||||
associated with the connection. It is the same value returned by the SQL
|
||||
``SELECT value FROM V$PARAMETER WHERE NAME = 'db_domain'``.
|
||||
|
||||
.. versionadded:: 2.0.0
|
||||
|
||||
.. note::
|
||||
|
||||
This attribute is an extension to the DB API definition.
|
||||
|
||||
.. attribute:: Connection.db_name
|
||||
|
||||
This read-only attribute specifies the Oracle Database name associated with
|
||||
the connection. It is the same value returned by the SQL
|
||||
``SELECT NAME FROM V$DATABASE``.
|
||||
|
||||
.. versionadded:: 2.0.0
|
||||
|
||||
.. note::
|
||||
|
||||
This attribute is an extension to the DB API definition.
|
||||
|
||||
.. 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.
|
||||
``V$SQL_MONITOR`` table.
|
||||
|
||||
.. note::
|
||||
|
||||
|
@ -666,6 +635,18 @@ Connection Attributes
|
|||
|
||||
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. The
|
||||
encodings in use are always UTF-8.
|
||||
|
||||
.. deprecated:: cx_Oracle 8.2
|
||||
|
||||
.. note::
|
||||
|
||||
This attribute 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
|
||||
|
@ -677,9 +658,9 @@ Connection Attributes
|
|||
|
||||
.. attribute:: Connection.handle
|
||||
|
||||
This read-only attribute returns the Oracle Call Interface (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.
|
||||
This read-only attribute returns the Oracle Call Interface (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.
|
||||
|
||||
This property is only relevant in the python-oracledb Thick mode.
|
||||
|
||||
|
@ -687,6 +668,7 @@ Connection Attributes
|
|||
|
||||
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
|
||||
|
@ -700,17 +682,6 @@ Connection Attributes
|
|||
|
||||
This attribute is an extension to the DB API definition.
|
||||
|
||||
.. attribute:: Connection.instance_name
|
||||
|
||||
This read-only attribute specifies the Oracle Database instance name
|
||||
associated with the connection. It is the same value as the SQL expression
|
||||
``sys_context('userenv', 'instance_name')``.
|
||||
|
||||
.. versionadded:: 1.4.0
|
||||
|
||||
.. note::
|
||||
|
||||
This attribute is an extension to the DB API definition.
|
||||
|
||||
.. attribute:: Connection.internal_name
|
||||
|
||||
|
@ -735,18 +706,21 @@ Connection Attributes
|
|||
server and the client.
|
||||
|
||||
|
||||
.. attribute:: Connection.max_open_cursors
|
||||
.. attribute:: Connection.maxBytesPerCharacter
|
||||
|
||||
This read-only attribute specifies the maximum number of cursors that the
|
||||
database can have open concurrently. It is the same value returned by the
|
||||
SQL ``SELECT VALUE FROM V$PARAMETER WHERE NAME = 'open_cursors'``.
|
||||
This deprecated, read-only attribute returns the value 4 since encodings
|
||||
are always UTF-8.
|
||||
|
||||
.. versionadded:: 2.0.0
|
||||
Previously it returned the maximum number of bytes each character can use
|
||||
for the client character set.
|
||||
|
||||
.. deprecated:: cx_Oracle 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.
|
||||
|
@ -757,61 +731,29 @@ Connection Attributes
|
|||
|
||||
This attribute 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. This is always the value "UTF-8".
|
||||
|
||||
.. deprecated:: cx_Oracle 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, metadata)`` and the return value is
|
||||
expected to be a :ref:`variable object<varobj>` 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.
|
||||
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`.
|
||||
|
||||
.. versionchanged:: 1.4
|
||||
|
||||
The method signature was changed. The previous signature
|
||||
``handler(cursor, name, default_type, length, precision, scale)`` will
|
||||
still work but is deprecated and will be removed in a future version.
|
||||
|
||||
.. note::
|
||||
|
||||
This attribute is an extension to the DB API definition.
|
||||
|
||||
.. attribute:: Connection.proxy_user
|
||||
|
||||
This read-only attribute returns the name of the user which was used as a
|
||||
proxy when creating the connection to the database.
|
||||
|
||||
.. versionadded:: 2.0.0
|
||||
|
||||
.. note::
|
||||
|
||||
This attribute is an extension to the DB API definition.
|
||||
|
||||
.. attribute:: Connection.sdu
|
||||
|
||||
This read-only attribute specifies the size of the Session Data Unit (SDU)
|
||||
that is being used by the connection. The value will be the lesser of the
|
||||
requested python-oracledb size and the maximum size allowed by the database
|
||||
network configuration. It is available only in the python-oracledb Thin
|
||||
mode.
|
||||
|
||||
.. versionadded:: 2.0.0
|
||||
|
||||
.. note::
|
||||
|
||||
This attribute is an extension to the DB API definition.
|
||||
|
||||
.. attribute:: Connection.service_name
|
||||
|
||||
This read-only attribute specifies the Oracle Database service name
|
||||
associated with the connection. This is the same value returned by the SQL
|
||||
``SELECT SYS_CONTEXT('USERENV', 'SERVICE_NAME') FROM DUAL``.
|
||||
|
||||
.. versionadded:: 2.0.0
|
||||
|
||||
.. note::
|
||||
|
||||
This attribute is an extension to the DB API definition.
|
||||
|
@ -856,12 +798,14 @@ Connection Attributes
|
|||
|
||||
This attribute is an extension to the DB API definition.
|
||||
|
||||
.. attribute:: Connection.transaction_in_progress
|
||||
.. attribute:: Connection.tnsentry
|
||||
|
||||
This read-only attribute specifies whether a transaction is currently in
|
||||
progress on the database associated with the connection.
|
||||
This read-only attribute returns the TNS entry of the database to which a
|
||||
connection has been established.
|
||||
|
||||
.. versionadded:: 2.0.0
|
||||
.. deprecated:: cx_Oracle 8.2
|
||||
|
||||
Use the attribute :attr:`~Connection.dsn` instead.
|
||||
|
||||
.. note::
|
||||
|
||||
|
@ -887,37 +831,6 @@ Connection Attributes
|
|||
|
||||
.. note::
|
||||
|
||||
If you connect to Oracle Database 18 or higher using Oracle Client
|
||||
libraries 12.2 or lower you will only receive the base version (such as
|
||||
18.0.0.0.0) instead of the full version (such as 18.3.0.0.0).
|
||||
|
||||
.. attribute:: Connection.warning
|
||||
|
||||
This read-only attribute provides an :ref:`oracledb._Error<exchandling>`
|
||||
object giving information about any database warnings (such as the password
|
||||
being in the grace period, or the pool being created with a smaller than
|
||||
requested size due to database resource restrictions) that were generated
|
||||
during connection establishment or by :meth:`oracledb.create_pool()`. The
|
||||
attribute will be present if there was a warning, but creation otherwise
|
||||
completed successfully. The connection will be usable despite the warning.
|
||||
|
||||
For :ref:`standalone connections <standaloneconnection>`,
|
||||
``Connection.warning`` will be present for the lifetime of the connection.
|
||||
|
||||
For :ref:`pooled connections <connpooling>`, ``Connection.warning`` will be
|
||||
cleared when a connection is released to the pool such as with
|
||||
:meth:`ConnectionPool.release()`.
|
||||
|
||||
In python-oracledb Thick mode, warnings may be generated during pool
|
||||
creation itself. These warnings will be placed on new connections created
|
||||
by the pool, provided no warnings were generated by the individual
|
||||
connection creations, in which case those connection warnings will be
|
||||
returned.
|
||||
|
||||
If no warning was generated the value ``None`` is returned.
|
||||
|
||||
.. versionadded:: 2.0.0
|
||||
|
||||
.. note::
|
||||
|
||||
This attribute is an extension to the DB API definition.
|
||||
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).
|
||||
|
|
|
@ -77,6 +77,7 @@ ConnectionPool Methods
|
|||
database shard to connect to. The key values can be strings, numbers, bytes
|
||||
or dates.
|
||||
|
||||
|
||||
.. method:: ConnectionPool.close(force=False)
|
||||
|
||||
Closes the pool now, rather than when the last reference to it is
|
||||
|
@ -85,11 +86,13 @@ ConnectionPool Methods
|
|||
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:: ConnectionPool.drop(connection)
|
||||
|
||||
Drops the connection from the pool which is useful if the connection is no
|
||||
longer usable (such as when the session is killed).
|
||||
|
||||
|
||||
.. method:: ConnectionPool.reconfigure([min, max, increment, getmode, \
|
||||
timeout, wait_timeout, max_lifetime_session, max_sessions_per_shard, \
|
||||
soda_metadata_cache, stmtcachesize, ping_interval])
|
||||
|
@ -142,6 +145,7 @@ ConnectionPool Methods
|
|||
|
||||
See :ref:`Connection Pool Reconfiguration <poolreconfiguration>`.
|
||||
|
||||
|
||||
.. method:: ConnectionPool.release(connection, tag=None)
|
||||
|
||||
Releases the connection back to the pool now, rather than whenever __del__
|
||||
|
@ -164,6 +168,7 @@ ConnectionPool Methods
|
|||
parameter are not None, the connection will be retagged when it is released
|
||||
back to the pool.
|
||||
|
||||
|
||||
ConnectionPool Attributes
|
||||
=========================
|
||||
|
||||
|
@ -172,11 +177,13 @@ ConnectionPool Attributes
|
|||
This read-only attribute returns the number of connections currently
|
||||
acquired.
|
||||
|
||||
|
||||
.. attribute:: ConnectionPool.dsn
|
||||
|
||||
This read-only attribute returns the TNS entry of the database to which a
|
||||
connection has been established.
|
||||
|
||||
|
||||
.. attribute:: ConnectionPool.getmode
|
||||
|
||||
This read-write attribute determines how connections are returned from the
|
||||
|
@ -192,21 +199,24 @@ ConnectionPool Attributes
|
|||
|
||||
.. attribute:: ConnectionPool.homogeneous
|
||||
|
||||
This read-only boolean attribute indicates whether the pool is considered
|
||||
This read-write boolean attribute indicates whether the pool is considered
|
||||
:ref:`homogeneous <connpooltypes>` or not. If the pool is not homogeneous,
|
||||
different authentication can be used for each connection acquired from the
|
||||
pool.
|
||||
|
||||
|
||||
.. attribute:: ConnectionPool.increment
|
||||
|
||||
This read-only attribute returns the number of connections that will be
|
||||
established when additional connections need to be created.
|
||||
|
||||
|
||||
.. attribute:: ConnectionPool.max
|
||||
|
||||
This read-only attribute returns the maximum number of connections that the
|
||||
pool can control.
|
||||
|
||||
|
||||
.. attribute:: ConnectionPool.max_lifetime_session
|
||||
|
||||
This read-write attribute returns the maximum length of time (in seconds)
|
||||
|
@ -216,7 +226,7 @@ ConnectionPool Attributes
|
|||
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
|
||||
connection may exist. This attribute is only available in Oracle Database
|
||||
12.1 or later.
|
||||
12.1.
|
||||
|
||||
.. attribute:: ConnectionPool.max_sessions_per_shard
|
||||
|
||||
|
@ -228,21 +238,25 @@ ConnectionPool Attributes
|
|||
of sessions for each shard. This attribute is only available in Oracle
|
||||
Client 18.3 and higher.
|
||||
|
||||
|
||||
.. attribute:: ConnectionPool.min
|
||||
|
||||
This read-only attribute returns the number of connections with which the
|
||||
connection pool was created and the minimum number of connections that will
|
||||
be controlled by the connection pool.
|
||||
|
||||
|
||||
.. attribute:: ConnectionPool.name
|
||||
|
||||
This read-only attribute returns the name assigned to the pool by Oracle.
|
||||
|
||||
|
||||
.. attribute:: ConnectionPool.opened
|
||||
|
||||
This read-only attribute returns the number of connections currently opened
|
||||
by the pool.
|
||||
|
||||
|
||||
.. attribute:: ConnectionPool.ping_interval
|
||||
|
||||
This read-write integer attribute specifies the pool ping interval in
|
||||
|
@ -276,6 +290,7 @@ ConnectionPool Attributes
|
|||
|
||||
See :ref:`Statement Caching <stmtcache>` for more information.
|
||||
|
||||
|
||||
.. attribute:: ConnectionPool.thin
|
||||
|
||||
This attribute returns a boolean which indicates the python-oracledb mode
|
||||
|
@ -292,12 +307,22 @@ ConnectionPool Attributes
|
|||
terminated. Note that in python-oracledb Thick mode with older Oracle
|
||||
Client Libraries, the termination only occurs when the pool is accessed.
|
||||
|
||||
.. attribute:: ConnectionPool.tnsentry
|
||||
|
||||
This read-only attribute returns the TNS entry of the database to which a
|
||||
connection has been established.
|
||||
|
||||
.. deprecated:: cx_Oracle 8.2
|
||||
|
||||
Use the attribute :attr:`~ConnectionPool.dsn` instead.
|
||||
|
||||
|
||||
.. attribute:: ConnectionPool.username
|
||||
|
||||
This read-only attribute returns the name of the user which established the
|
||||
connection to the database.
|
||||
|
||||
|
||||
.. attribute:: ConnectionPool.wait_timeout
|
||||
|
||||
This read-write attribute specifies the time (in milliseconds) that the
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
API: Cursor Objects
|
||||
*******************
|
||||
|
||||
A cursor object can be created with :meth:`Connection.cursor()`.
|
||||
A cursor object can be created with :meth:`Connection.cursor`.
|
||||
|
||||
Cursor Methods
|
||||
==============
|
||||
|
@ -26,14 +26,6 @@ Cursor Methods
|
|||
|
||||
This method 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.
|
||||
|
||||
.. method:: Cursor.arrayvar(typ, value, [size])
|
||||
|
||||
|
@ -57,6 +49,7 @@ Cursor Methods
|
|||
|
||||
The DB API definition does not define this method.
|
||||
|
||||
|
||||
.. method:: Cursor.bindnames()
|
||||
|
||||
Returns the list of bind variable names bound to the statement. Note that a
|
||||
|
@ -93,6 +86,7 @@ Cursor Methods
|
|||
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={})
|
||||
|
||||
Calls a procedure with the given name. The sequence of parameters must
|
||||
|
@ -144,7 +138,7 @@ Cursor Methods
|
|||
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 a statement, it is best to use the
|
||||
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
|
||||
|
@ -158,6 +152,7 @@ Cursor Methods
|
|||
|
||||
The DB API definition does not define the return value of this method.
|
||||
|
||||
|
||||
.. method:: Cursor.executemany(statement, parameters, batcherrors=False, \
|
||||
arraydmlrowcounts=False)
|
||||
|
||||
|
@ -195,6 +190,7 @@ Cursor Methods
|
|||
length 1 so any values that are later bound as numbers or dates will raise
|
||||
a TypeError exception.
|
||||
|
||||
|
||||
.. method:: Cursor.fetchall()
|
||||
|
||||
Fetches all (remaining) rows of a query result, returning them as a list of
|
||||
|
@ -208,6 +204,7 @@ Cursor Methods
|
|||
|
||||
See :ref:`fetching` for an example.
|
||||
|
||||
|
||||
.. method:: Cursor.fetchmany(size=cursor.arraysize)
|
||||
|
||||
Fetches the next set of rows of a query result, returning a list of tuples.
|
||||
|
@ -234,6 +231,7 @@ Cursor Methods
|
|||
|
||||
See :ref:`fetching` for an example.
|
||||
|
||||
|
||||
.. method:: Cursor.getarraydmlrowcounts()
|
||||
|
||||
Retrieves the DML row counts after a call to :meth:`~Cursor.executemany()`
|
||||
|
@ -244,7 +242,8 @@ Cursor Methods
|
|||
.. note::
|
||||
|
||||
The DB API definition does not define this method and it is only
|
||||
available for Oracle 12.1 and later.
|
||||
available for Oracle 12.1 and higher.
|
||||
|
||||
|
||||
.. method:: Cursor.getbatcherrors()
|
||||
|
||||
|
@ -257,6 +256,7 @@ Cursor Methods
|
|||
|
||||
The DB API definition does not define this method.
|
||||
|
||||
|
||||
.. method:: Cursor.getimplicitresults()
|
||||
|
||||
Returns a list of cursors which correspond to implicit results made
|
||||
|
@ -277,11 +277,21 @@ Cursor Methods
|
|||
the current result set), this method returns cursors which can be
|
||||
fetched independently of each other.
|
||||
|
||||
|
||||
.. 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.
|
||||
|
||||
|
||||
.. method:: Cursor.parse(statement)
|
||||
|
||||
This can be used to parse a statement without actually executing it
|
||||
(parsing step is done automatically by Oracle when a statement is
|
||||
:meth:`executed <Cursor.execute>`).
|
||||
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::
|
||||
|
||||
|
@ -292,6 +302,7 @@ Cursor Methods
|
|||
You can parse any DML or DDL statement. DDL statements are executed
|
||||
immediately and an implied commit takes place.
|
||||
|
||||
|
||||
.. method:: Cursor.prepare(statement, tag, cache_statement=True)
|
||||
|
||||
This can be used before a call to :meth:`~Cursor.execute()` to define the
|
||||
|
@ -313,6 +324,7 @@ Cursor Methods
|
|||
|
||||
The DB API definition does not define this method.
|
||||
|
||||
|
||||
.. method:: Cursor.scroll(value=0, mode="relative")
|
||||
|
||||
Scrolls the cursor in the result set to a new position according to the
|
||||
|
@ -332,31 +344,34 @@ Cursor Methods
|
|||
This method is an extension to the DB API definition but it is
|
||||
mentioned in PEP 249 as an optional extension.
|
||||
|
||||
.. method:: Cursor.setinputsizes(*args, **keywordArgs)
|
||||
|
||||
.. method:: Cursor.setinputsizes(\*args, \*\*keywordArgs)
|
||||
|
||||
This can be used before a call to :meth:`~Cursor.execute()`,
|
||||
:meth:`~Cursor.executemany()`, :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.
|
||||
: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).
|
||||
|
||||
|
||||
.. method:: Cursor.var(typ, [size, arraysize, inconverter, outconverter, \
|
||||
typename, encoding_errors, bypass_decode, convert_nulls])
|
||||
typename, encoding_errors, bypass_decode])
|
||||
|
||||
Creates a variable with the specified characteristics. This method was
|
||||
designed for use with PL/SQL in/out variables where the length or type
|
||||
|
@ -427,20 +442,10 @@ Cursor Methods
|
|||
meaning that python-oracledb does not do any decoding. See :ref:`Fetching raw
|
||||
data <fetching-raw-data>` for more information.
|
||||
|
||||
The ``convert_nulls`` parameter, if specified, should be passed as a boolean
|
||||
value. Passing the value ``True`` causes the ``outconverter`` to be called
|
||||
when a null value is fetched from the database; otherwise, the
|
||||
``outconverter`` is only called when non-null values are fetched from the
|
||||
database.
|
||||
|
||||
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.
|
||||
|
||||
.. versionchanged:: 1.4.0
|
||||
|
||||
The ``convert_nulls`` parameter was added.
|
||||
|
||||
.. note::
|
||||
|
||||
The DB API definition does not define this method.
|
||||
|
@ -489,18 +494,16 @@ Cursor Attributes
|
|||
This attribute is an extension to the DB API definition but it is
|
||||
mentioned in PEP 249 as an optional extension.
|
||||
|
||||
.. attribute:: Cursor.description
|
||||
.. data:: Cursor.description
|
||||
|
||||
This read-only attribute is a sequence of :ref:`FetchInfo<fetchinfoobj>`
|
||||
objects. 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.
|
||||
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.
|
||||
|
||||
.. versionchanged:: 1.4.0
|
||||
|
||||
Previously, this attribute was a sequence of 7-item sequences. Each
|
||||
of these sequences contained information describing one result column:
|
||||
(name, type, display_size, internal_size, precision, scale, null_ok).
|
||||
The type will be one of the :ref:`database type constants <dbtypes>`
|
||||
defined at the module level.
|
||||
|
||||
.. attribute:: Cursor.fetchvars
|
||||
|
||||
|
@ -527,29 +530,24 @@ Cursor Attributes
|
|||
|
||||
This attribute is an extension to the DB API definition.
|
||||
|
||||
.. attribute:: Cursor.lastrowid
|
||||
.. 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.
|
||||
|
||||
|
||||
.. 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, metadata) and the return value is expected to be a
|
||||
:ref:`variable object<varobj>` or None in which case a default variable
|
||||
object will be created. If this attribute is None, then the default
|
||||
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, then the default
|
||||
behavior will take place for all columns fetched from this cursor.
|
||||
|
||||
See :ref:`outputtypehandlers`.
|
||||
|
||||
.. versionchanged:: 1.4.0
|
||||
|
||||
The method signature was changed. The previous signature
|
||||
handler(cursor, name, default_type, length, precision, scale) will
|
||||
still work but is deprecated and will be removed in a future version.
|
||||
|
||||
.. note::
|
||||
|
||||
This attribute is an extension to the DB API definition.
|
||||
|
@ -565,9 +563,6 @@ Cursor Attributes
|
|||
The attribute is only used for tuning row fetches from the database. It
|
||||
does not affect data inserts.
|
||||
|
||||
Queries that return LOBs and similar types will never prefetch rows, so the
|
||||
``prefetchrows`` value is ignored in those cases.
|
||||
|
||||
See :ref:`Tuning Fetch Performance <tuningfetch>` for more information.
|
||||
|
||||
.. note::
|
||||
|
@ -582,6 +577,7 @@ Cursor Attributes
|
|||
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
|
||||
|
@ -617,21 +613,3 @@ Cursor Attributes
|
|||
.. note::
|
||||
|
||||
The DB API definition does not define this attribute.
|
||||
|
||||
.. attribute:: Cursor.warning
|
||||
|
||||
This read-only attribute provides an :ref:`oracledb._Error<exchandling>`
|
||||
object giving information about any database warnings (such as PL/SQL
|
||||
compilation warnings) that were generated during the last call to
|
||||
:meth:`~Cursor.execute()` or :meth:`~Cursor.executemany()`. This value is
|
||||
automatically cleared on the next call to :meth:`~Cursor.execute()` or
|
||||
:meth:`~Cursor.executemany()`. If no warning was generated the value
|
||||
``None`` is returned.
|
||||
|
||||
See :ref:`plsqlwarning` for more information.
|
||||
|
||||
.. versionadded:: 2.0.0
|
||||
|
||||
.. note::
|
||||
|
||||
The DB API definition does not define this attribute.
|
||||
|
|
|
@ -39,8 +39,7 @@ Defaults Attributes
|
|||
|
||||
.. attribute:: defaults.fetch_decimals
|
||||
|
||||
Identifies whether numbers should be fetched as `decimal.Decimal
|
||||
<https://docs.python.org/3/library/decimal.html#decimal-objects>`__ values.
|
||||
Identifies whether numbers should be fetched as ``decimal.Decimal`` values.
|
||||
This can help avoid issues with converting numbers from Oracle Database's
|
||||
decimal format to Python's binary format.
|
||||
|
||||
|
@ -48,7 +47,7 @@ Defaults Attributes
|
|||
`return_numbers_as_decimals.py <https://github.com/oracle/python-cx_Oracle/
|
||||
blob/main/samples/return_numbers_as_decimals.py>`__) can alternatively be
|
||||
used to adjust the returned type. If a type handler exists and returns a
|
||||
variable (that is, ``cursor.var(...)``), then that return variable is used.
|
||||
variable (that is, `cursor.var(...)`), then that return variable is used.
|
||||
If the type handler returns None, then the value of
|
||||
``oracledb.defaults.fetch_decimals`` is used to determine whether to return
|
||||
``decimal.Decimal`` values.
|
||||
|
@ -57,11 +56,10 @@ Defaults Attributes
|
|||
|
||||
.. attribute:: defaults.fetch_lobs
|
||||
|
||||
When the value of this attribute is True, then queries to LOB columns
|
||||
return LOB locators. When the value of this attribute is False, then CLOBs
|
||||
and NCLOBs are fetched as strings, and BLOBs are fetched as bytes. If LOBs
|
||||
are larger than 1 GB, then this attribute should be set to True and the
|
||||
LOBs should be streamed. See :ref:`lobdata`.
|
||||
When the value of this attribute is True, then queries to LOB columns return
|
||||
LOB locators. When the value of this attribute is False, then strings or bytes
|
||||
are fetched. If LOBs are larger than 1 GB, then this attribute should be set to
|
||||
True and the LOBs should be streamed. See :ref:`lobdata`.
|
||||
|
||||
An output type handler such as the one previously required in cx_Oracle (see
|
||||
`return_lobs_as_strings.py <https://github.com/oracle/python-cx_Oracle/blob/main/samples/
|
||||
|
@ -70,9 +68,6 @@ Defaults Attributes
|
|||
that return variable is used. If the type handler returns None, then the value of
|
||||
``oracledb.defaults.fetch_lobs`` is used.
|
||||
|
||||
The value of ``oracledb.defaults.fetch_lobs`` does not affect LOBs returned
|
||||
as OUT binds.
|
||||
|
||||
This attribute has an initial value of True.
|
||||
|
||||
.. attribute:: defaults.prefetchrows
|
||||
|
|
|
@ -8,78 +8,6 @@ The following tables contain all of the deprecations in the python-oracledb 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-with-summary:: Desupported in python-oracledb 2.0
|
||||
:header-rows: 1
|
||||
:class: wy-table-responsive
|
||||
:summary: The first column, Name, displays the desupported feature. The second column, Comments, includes information about the desupport and what replacement to make, if applicable.
|
||||
:name: _desupported_2_0
|
||||
|
||||
* - Name
|
||||
- Comments
|
||||
* - ``oracledb.__future__.old_json_col_as_obj``
|
||||
- VARCHAR2 and LOB columns created with the ``IS JSON`` check constraint
|
||||
are now always fetched as JSON. Use an :ref:`output type handler
|
||||
<outputtypehandlers>` if the old behavior is required.
|
||||
* - Parameters ``encoding`` and ``nencoding`` of :func:`oracledb.connect()`
|
||||
and :func:`oracledb.create_pool()`, and the related attributes on the
|
||||
objects created
|
||||
- The driver encodings are always UTF-8. Remove uses of ``encoding`` and
|
||||
``nencoding`` from your code.
|
||||
* - Parameter ``threaded`` of :func:`oracledb.connect()` and
|
||||
:func:`oracledb.create_pool()`
|
||||
- Threading is always used. Remove uses of ``threaded`` from your code.
|
||||
* - Parameter ``waitTimeout`` of :func:`oracledb.create_pool()` and
|
||||
``oracledb.SessionPool()``
|
||||
- Replace with parameter ``wait_timeout``
|
||||
* - Parameter ``maxLifetimeSession`` of :func:`oracledb.create_pool()` and
|
||||
``oracledb.SessionPool()``
|
||||
- Replace with parameter ``max_lifetime_session``
|
||||
* - Parameter ``sessionCallback`` of :func:`oracledb.create_pool()` and
|
||||
``oracledb.SessionPool()``
|
||||
- Replace with parameter ``session_callback``
|
||||
* - Parameter ``maxSessionsPerShard`` of :func:`oracledb.create_pool()` and
|
||||
``oracledb.SessionPool()``
|
||||
- Replace with parameter ``max_sessions_per_shard``
|
||||
* - Attribute ``maxBytesPerCharacter`` of the :ref:`connection object
|
||||
<connobj>`
|
||||
- The driver encodings are always UTF-8 so this attribute can be replaced by
|
||||
the constant value 4
|
||||
* - ``Connection.tnsentry``
|
||||
- Replace with :attr:`Connection.dsn`
|
||||
* - ``SessionPool.tnsentry``
|
||||
- Replace with :attr:`ConnectionPool.dsn`
|
||||
|
||||
.. list-table-with-summary:: Deprecated in python-oracledb 2.0
|
||||
:header-rows: 1
|
||||
:class: wy-table-responsive
|
||||
:summary: The first column, Name, displays the deprecated feature. The second column, Comments, includes information about the deprecatation and what replacement to use, if applicable.
|
||||
:name: _deprecations_2_0
|
||||
|
||||
* - Name
|
||||
- Comments
|
||||
* - Calling :meth:`Variable.setvalue()` with a string value when the
|
||||
variable type is one of :data:`oracledb.DB_TYPE_BLOB`,
|
||||
:data:`oracledb.DB_TYPE_CLOB` or :data:`oracledb.DB_TYPE_NCLOB`.
|
||||
- Call :meth:`Connection.createlob()` with the value instead and pass the
|
||||
result to :meth:`Variable.setvalue()`.
|
||||
* - Setting an attribute of type :data:`oracledb.DB_TYPE_BLOB`,
|
||||
:data:`oracledb.DB_TYPE_CLOB` or :data:`oracledb.DB_TYPE_NCLOB` on a
|
||||
database object to a string value.
|
||||
- Call :meth:`Connection.createlob()` with the value instead and set the
|
||||
attribute with the result.
|
||||
|
||||
.. list-table-with-summary:: Deprecated in python-oracledb 1.4
|
||||
:header-rows: 1
|
||||
:class: wy-table-responsive
|
||||
:summary: The first column, Name, displays the deprecated feature. The second column, Comments, includes information about the deprecatation and what replacement to use, if applicable.
|
||||
:name: _deprecations_1_4
|
||||
|
||||
* - Name
|
||||
- Comments
|
||||
* - Output type handler with arguments
|
||||
``handler(cursor, name, default_type, length, precision, scale)``
|
||||
- Replace with ``handler(cursor, metadata)``. See
|
||||
:ref:`outputtypehandlers`.
|
||||
|
||||
.. list-table-with-summary:: Deprecated in python-oracledb 1.0
|
||||
:header-rows: 1
|
||||
|
@ -182,7 +110,9 @@ python-oracledb are listed below:
|
|||
.. list-table-with-summary:: Deprecated in cx_Oracle 8.2
|
||||
:header-rows: 1
|
||||
:class: wy-table-responsive
|
||||
:summary: The first column, Name, displays the deprecated feature. The second column, Comments, includes information about the deprecatation and what replacement to use, if applicable.
|
||||
:summary: The first column, Name, displays the deprecated API name. The second column,
|
||||
Comments, includes information about when the API was deprecated and what API to use,
|
||||
if applicable.
|
||||
:name: _deprecations_8_2
|
||||
|
||||
* - Name
|
||||
|
@ -220,7 +150,7 @@ python-oracledb are listed below:
|
|||
* - ``maxSessionsPerShard`` parameter to `cx_Oracle.SessionPool() <https://cx-oracle.readthedocs.io/en/latest/api_manual/module.html#cx_Oracle.SessionPool>`_
|
||||
- Replace with parameter name ``max_sessions_per_shard``
|
||||
* - ``SessionPool.tnsentry``
|
||||
- Replace with :attr:`ConnectionPool.dsn`
|
||||
- Replace with `SessionPool.dsn <https://cx-oracle.readthedocs.io/en/latest/api_manual/session_pool.html#SessionPool.dsn>`_
|
||||
* - ``payloadType`` parameter to `Connection.queue() <https://cx-oracle.readthedocs.io/en/latest/api_manual/connection.html#Connection.queue>`_
|
||||
- Replace with parameter name ``payload_type`` if using keyword parameters.
|
||||
* - ``ipAddress`` parameter to `Connection.subscribe() <https://cx-oracle.readthedocs.io/en/latest/api_manual/connection.html#Connection.subscribe>`_
|
||||
|
@ -236,7 +166,7 @@ python-oracledb are listed below:
|
|||
* - ``Connection.callTimeout``
|
||||
- Replace with `Connection.call_timeout <https://cx-oracle.readthedocs.io/en/latest/api_manual/connection.html#Connection.call_timeout>`_
|
||||
* - ``Connection.tnsentry``
|
||||
- Replace with :attr:`Connection.dsn`
|
||||
- Replace with `Connection.dsn <https://cx-oracle.readthedocs.io/en/latest/api_manual/connection.html#Connection.dsn>`_
|
||||
* - `keywordParameters` parameter to `Cursor.callfunc() <https://cx-oracle.readthedocs.io/en/latest/api_manual/cursor.html#Cursor.callfunc>`_
|
||||
- Replace with parameter name ``keyword_parameters``
|
||||
* - ``keywordParameters`` parameter to `Cursor.callproc() <https://cx-oracle.readthedocs.io/en/latest/api_manual/cursor.html#Cursor.callproc>`_
|
||||
|
@ -278,7 +208,7 @@ python-oracledb are listed below:
|
|||
.. list-table-with-summary:: Deprecated in cx_Oracle 8.0
|
||||
:header-rows: 1
|
||||
:class: wy-table-responsive
|
||||
:summary: The first column, Name, displays the deprecated feature. The second column, Comments, includes information about the deprecatation and what replacement to use, if applicable.
|
||||
:summary: The first column, Name, displays the deprecated API name. The second column, Comments, includes information about when the API was deprecated and what API to use, if applicable.
|
||||
:name: _deprecations_8_0
|
||||
|
||||
* - Name
|
||||
|
@ -320,7 +250,7 @@ python-oracledb are listed below:
|
|||
.. list-table-with-summary:: Deprecated in cx_Oracle 7.2
|
||||
:header-rows: 1
|
||||
:class: wy-table-responsive
|
||||
:summary: The first column, Name, displays the deprecated feature. The second column, Comments, includes information about the deprecatation and what replacement to use, if applicable.
|
||||
:summary: The first column, Name, displays the deprecated API name. The second column, Comments, includes information about when the API was deprecated and what API to use, if applicable.
|
||||
:name: _deprecations_7_2
|
||||
|
||||
* - Name
|
||||
|
@ -338,7 +268,7 @@ python-oracledb are listed below:
|
|||
.. list-table-with-summary:: Deprecated in cx_Oracle 6.4
|
||||
:header-rows: 1
|
||||
:class: wy-table-responsive
|
||||
:summary: The first column, Name, displays the deprecated feature. The second column, Comments, includes information about the deprecatation and what replacement to use, if applicable.
|
||||
:summary: The first column, Name, displays the deprecated API name. The second column, Comments, includes information about when the API was deprecated and what API to use, if applicable.
|
||||
:name: _deprecations_6_4
|
||||
|
||||
* - Name
|
||||
|
|
|
@ -1,106 +0,0 @@
|
|||
.. _fetchinfoobj:
|
||||
|
||||
**********************
|
||||
API: FetchInfo Objects
|
||||
**********************
|
||||
|
||||
FetchInfo objects are created internally when a query is executed. They are found
|
||||
in the sequence :data:`Cursor.description`. There is one FetchInfo object for
|
||||
each column. For compatibility with the Python Database API, this object
|
||||
behaves as a 7-tuple containing the values for the attributes ``name``,
|
||||
``type_code``, ``display_size``, ``internal_size``, ``precision``, ``scale``,
|
||||
and ``null_ok`` in that order. For example, if ``fetch_info`` is of type
|
||||
FetchInfo, then ``fetch_info[2]`` is the same as ``fetch_info.display_size``.
|
||||
|
||||
.. versionadded:: 1.4.0
|
||||
|
||||
.. note::
|
||||
|
||||
This object is an extension the DB API.
|
||||
|
||||
FetchInfo Attributes
|
||||
====================
|
||||
|
||||
.. attribute:: FetchInfo.annotations
|
||||
|
||||
This read-only attribute returns a dictionary containing the `annotations
|
||||
<https://docs.oracle.com/en/database/oracle/oracle-database/23/sqlrf/
|
||||
annotations_clause.html#GUID-1AC16117-BBB6-4435-8794-2B99F8F68052>`__
|
||||
associated with the fetched column. If there are no annotations, the value
|
||||
``None`` is returned. Annotations require Oracle Database 23c. If using
|
||||
python-oracledb Thick mode, Oracle Client 23c is also required.
|
||||
|
||||
.. versionadded:: 2.0.0
|
||||
|
||||
.. attribute:: FetchInfo.display_size
|
||||
|
||||
This read-only attribute returns the display size of the column as mandated
|
||||
by the Python Database API.
|
||||
|
||||
.. attribute:: FetchInfo.domain_name
|
||||
|
||||
This read-only attribute returns the name of the `SQL domain
|
||||
<https://docs.oracle.com/en/database/oracle/oracle-database/23/sqlrf/
|
||||
create-domain.html#GUID-17D3A9C6-D993-4E94-BF6B-CACA56581F41>`__
|
||||
associated with the fetched column. If there is no SQL domain, the value
|
||||
``None`` is returned. SQL domains require Oracle Database 23c. If using
|
||||
python-oracledb Thick mode, Oracle Client 23c is also required.
|
||||
|
||||
.. versionadded:: 2.0.0
|
||||
|
||||
.. attribute:: FetchInfo.domain_schema
|
||||
|
||||
This read-only attribute returns the schema of the `SQL domain
|
||||
<https://docs.oracle.com/en/database/oracle/oracle-database/23/sqlrf/
|
||||
create-domain.html#GUID-17D3A9C6-D993-4E94-BF6B-CACA56581F41>`__
|
||||
associated with the fetched column. If there is no SQL domain, the value
|
||||
``None`` is returned. SQL domains require Oracle Database 23c. If using
|
||||
python-oracledb Thick mode, Oracle Client 23c is also required.
|
||||
|
||||
.. versionadded:: 2.0.0
|
||||
|
||||
.. attribute:: FetchInfo.internal_size
|
||||
|
||||
This read-only attribute returns the internal size of the column as
|
||||
mandated by the Python Database API.
|
||||
|
||||
.. attribute:: FetchInfo.is_json
|
||||
|
||||
This read-only attribute returns whether the column is known to contain
|
||||
JSON data. This will be ``True`` when the type code is
|
||||
``oracledb.DB_TYPE_JSON`` as well as when an "IS JSON" constraint is
|
||||
enabled on LOB and VARCHAR2 columns.
|
||||
|
||||
.. attribute:: FetchInfo.name
|
||||
|
||||
This read-only attribute returns the name of the column as mandated by the
|
||||
Python Database API.
|
||||
|
||||
.. attribute:: FetchInfo.null_ok
|
||||
|
||||
This read-only attribute returns whether nulls are allowed in the column as
|
||||
mandated by the Python Database API.
|
||||
|
||||
.. attribute:: FetchInfo.precision
|
||||
|
||||
This read-only attribute returns the precision of the column as mandated by
|
||||
the Python Database API.
|
||||
|
||||
.. attribute:: FetchInfo.scale
|
||||
|
||||
This read-only attribute returns the scale of the column as mandated by
|
||||
the Python Database API.
|
||||
|
||||
.. attribute:: FetchInfo.type
|
||||
|
||||
This read-only attribute returns the type of the column. This will be an
|
||||
:ref:`Oracle Object Type <dbobjecttype>` if the column contains Oracle
|
||||
objects; otherwise, it will be one of the :ref:`database type constants
|
||||
<dbtypes>` defined at the module level.
|
||||
|
||||
|
||||
.. attribute:: FetchInfo.type_code
|
||||
|
||||
This read-only attribute returns the type of the column as mandated by the
|
||||
Python Database API. The type will be one of the :ref:`database type
|
||||
constants <dbtypes>` defined at the module level.
|
|
@ -4,8 +4,7 @@
|
|||
API: LOB Objects
|
||||
****************
|
||||
|
||||
A LOB object can be created with :meth:`Connection.createlob()`. See
|
||||
:ref:`lobdata` for more information about using LOBs.
|
||||
See :ref:`lobdata` for more information about using LOBs.
|
||||
|
||||
.. note::
|
||||
|
||||
|
@ -21,26 +20,31 @@ LOB Methods
|
|||
associated with the LOB can be updated -- but only if :meth:`~LOB.open()`
|
||||
was called first.
|
||||
|
||||
|
||||
.. method:: LOB.fileexists()
|
||||
|
||||
Returns a boolean indicating if the file referenced by the BFILE type LOB
|
||||
exists.
|
||||
|
||||
|
||||
.. method:: LOB.getchunksize()
|
||||
|
||||
Returns 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()
|
||||
|
||||
Returns a two-tuple consisting of the directory alias and file name for a
|
||||
BFILE type LOB.
|
||||
|
||||
|
||||
.. method:: LOB.isopen()
|
||||
|
||||
Returns a boolean indicating if the LOB has been opened using the method
|
||||
:meth:`~LOB.open()`.
|
||||
|
||||
|
||||
.. method:: LOB.open()
|
||||
|
||||
Opens the LOB for writing. This will improve performance when writing to a
|
||||
|
@ -48,6 +52,7 @@ LOB Methods
|
|||
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]])
|
||||
|
||||
Returns a portion (or all) of the data in the LOB object. Note that the
|
||||
|
@ -57,10 +62,12 @@ LOB Methods
|
|||
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)
|
||||
|
||||
Sets 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
|
||||
|
@ -68,10 +75,12 @@ LOB Methods
|
|||
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)
|
||||
|
||||
Trims the LOB to the new size.
|
||||
|
||||
|
||||
.. method:: LOB.write(data, offset=1)
|
||||
|
||||
Writes the data to the LOB object at the given offset. The offset is in
|
||||
|
@ -83,7 +92,7 @@ LOB Methods
|
|||
:meth:`~LOB.trim()` function.
|
||||
|
||||
LOB Attributes
|
||||
==============
|
||||
===============
|
||||
|
||||
.. attribute:: LOB.type
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -32,21 +32,18 @@ PoolParams Methods
|
|||
which is looked up in ``tnsnames.ora``. Parameters that are found in the connect string
|
||||
override any currently stored values.
|
||||
|
||||
.. method:: PoolParams.set(min=None, max=None, increment=None, \
|
||||
connectiontype=None, getmode=None, homogeneous=None, timeout=None, \
|
||||
wait_timeout=None, max_lifetime_session=None, session_callback=None, \
|
||||
max_sessions_per_shard=None, soda_metadata_cache=None, \
|
||||
ping_interval=None, user=None, proxy_user=None, password=None, \
|
||||
newpassword=None, wallet_password=None, access_token=None, host=None, \
|
||||
port=None, protocol=None, https_proxy=None, https_proxy_port=None, \
|
||||
service_name=None, sid=None, server_type=None, cclass=None, \
|
||||
purity=None, expire_time=None, retry_count=None, retry_delay=None, \
|
||||
tcp_connect_timeout=None, ssl_server_dn_match=None, \
|
||||
ssl_server_cert_dn=None, wallet_location=None, events=None, \
|
||||
externalauth=None, mode=None, disable_oob=None, stmtcachesize=None, \
|
||||
edition=None, tag=None, matchanytag=None, config_dir=None, \
|
||||
appcontext=[], shardingkey=[], supershardingkey=[], debug_jdwp=None, \
|
||||
connection_id_prefix=None, ssl_context=None, sdu=None, handle=None)
|
||||
.. method:: PoolParams.set(min=None, max=None, increment=None, connectiontype=None, \
|
||||
getmode=None, homogeneous=None, timeout=None, wait_timeout=None, \
|
||||
max_lifetime_session=None, session_callback=None, max_sessions_per_shard=None, \
|
||||
soda_metadata_cache=None, ping_interval=None, user=None, proxy_user=None,\
|
||||
password=None, newpassword=None, wallet_password=None, access_token=None, \
|
||||
host=None, port=None, protocol=None, https_proxy=None, https_proxy_port=None, \
|
||||
service_name=None, sid=None, server_type=None, cclass=None, purity=None, \
|
||||
expire_time=None, retry_count=None, retry_delay=None, tcp_connect_timeout=None, \
|
||||
ssl_server_dn_match=None, ssl_server_cert_dn=None, wallet_location=None, \
|
||||
events=None, externalauth=None, mode=None, disable_oob=None, stmtcachesize=None, \
|
||||
edition=None, tag=None, matchanytag=None, config_dir=None, appcontext=[], \
|
||||
shardingkey=[], supershardingkey=[], debug_jdwp=None, handle=None)
|
||||
|
||||
Sets one or more of the parameters.
|
||||
|
||||
|
@ -58,20 +55,19 @@ PoolParams Attributes
|
|||
.. attribute:: PoolParams.connectiontype
|
||||
|
||||
This read-only attribute specifies the class of the connection that should
|
||||
be returned during calls to :meth:`ConnectionPool.acquire()`. It must be
|
||||
Connection or a subclass of Connection. This attribute is of type
|
||||
Type["oracledb.connection"]. The default value is ``oracledb.Connection``.
|
||||
be returned during calls to :meth:`ConnectionPool.acquire()`. It must be Connection
|
||||
or a subclass of Connection. This attribute is of type Type["oracledb.connection"].
|
||||
The default value is ``oracledb.Connection``.
|
||||
|
||||
This attribute is supported in the python-oracledb Thin and Thick modes.
|
||||
|
||||
.. attribute:: PoolParams.getmode
|
||||
|
||||
This read-write attribute is an integer that determines the behavior of
|
||||
:meth:`ConnectionPool.acquire()`. The value of this attribute can be one of
|
||||
the constants :data:`oracledb.POOL_GETMODE_WAIT`,
|
||||
:data:`oracledb.POOL_GETMODE_NOWAIT`, :data:`oracledb.POOL_GETMODE_FORCEGET`,
|
||||
or :data:`oracledb.POOL_GETMODE_TIMEDWAIT`. The default value is
|
||||
:data:`oracledb.POOL_GETMODE_WAIT`.
|
||||
:meth:`ConnectionPool.acquire()`. The value of this attribute can be one of the
|
||||
constants :data:`oracledb.POOL_GETMODE_WAIT`, :data:`oracledb.POOL_GETMODE_NOWAIT`,
|
||||
:data:`oracledb.POOL_GETMODE_FORCEGET`, or :data:`oracledb.POOL_GETMODE_TIMEDWAIT`.
|
||||
The default value is :data:`oracledb.POOL_GETMODE_WAIT`.
|
||||
|
||||
This attribute is supported in the python-oracledb Thin and Thick modes.
|
||||
|
||||
|
@ -129,10 +125,9 @@ PoolParams Attributes
|
|||
(in seconds) after which an unused connection in the pool will be a
|
||||
candidate for pinging when :meth:`ConnectionPool.acquire()` is called.
|
||||
If the ping to the database indicates that the connection is not alive,
|
||||
then a replacement connection will be returned by
|
||||
:meth:`ConnectionPool.acquire()`. If the ``ping_interval`` is a negative
|
||||
value, then the ping functionality will be disabled. The default value is 60
|
||||
seconds.
|
||||
then a replacement connection will be returned by :meth:`ConnectionPool.acquire()`.
|
||||
If the ``ping_interval`` is a negative value, then the ping functionality
|
||||
will be disabled. The default value is 60 seconds.
|
||||
|
||||
This attribute is supported in the python-oracledb Thin and Thick modes.
|
||||
|
||||
|
|
|
@ -217,6 +217,7 @@ SodaCollection Methods
|
|||
index has been created with the 'dataguide' option enabled. If there are
|
||||
no documents in the collection, None is returned.
|
||||
|
||||
|
||||
.. method:: SodaCollection.insertMany(docs)
|
||||
|
||||
Inserts a list of documents into the collection at one time. Each of the
|
||||
|
@ -286,14 +287,6 @@ SodaCollection Methods
|
|||
|
||||
Use of the ``hint`` parameter requires Oracle Client 21.3 or higher (or Oracle Client 19 from 19.11).
|
||||
|
||||
.. method:: SodaCollection.listIndexes()
|
||||
|
||||
Returns a list of specifications for the indexes found on the collection.
|
||||
|
||||
This method requires Oracle Client 21.3 or later (or Oracle Client 19 from
|
||||
19.13).
|
||||
|
||||
.. versionadded:: 1.4.0
|
||||
|
||||
.. method:: SodaCollection.save(doc)
|
||||
|
||||
|
@ -544,6 +537,7 @@ SodaOperation Methods
|
|||
Use of this method requires Oracle Client 21.3 or higher (or Oracle Client
|
||||
19 from 19.11).
|
||||
|
||||
|
||||
.. method:: SodaOperation.key(value)
|
||||
|
||||
Specifies that the document with the specified key should be returned.
|
||||
|
@ -576,29 +570,6 @@ SodaOperation Methods
|
|||
criteria can be specified by chaining methods together.
|
||||
|
||||
|
||||
.. method:: SodaOperation.lock()
|
||||
|
||||
Specifies whether the documents fetched from the collection should be
|
||||
locked (equivalent to SQL "select for update").
|
||||
|
||||
The next commit or rollback on the connection made after the operation is
|
||||
performed will "unlock" the documents. Ensure that the connection is not in
|
||||
autocommit mode or the documents will be unlocked immediately after the
|
||||
operation is complete.
|
||||
|
||||
This method should only be used with read operations (other than
|
||||
:func:`~SodaOperation.count()`) and should not be used in
|
||||
conjunction with non-terminal methods :meth:`~SodaOperation.skip()` and
|
||||
:meth:`~SodaOperation.limit()`.
|
||||
|
||||
If this method is specified in conjunction with a write operation this
|
||||
method is ignored.
|
||||
|
||||
This method is only supported in Oracle Client 21.3 or later (or
|
||||
Oracle Client 19 from 19.11).
|
||||
|
||||
.. versionadded:: 1.4.0
|
||||
|
||||
.. method:: SodaOperation.remove()
|
||||
|
||||
Removes all of the documents in the collection that match the criteria. The
|
||||
|
|
|
@ -136,9 +136,8 @@ Message Objects
|
|||
|
||||
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 an empty list if the ``qos`` parameter did not include
|
||||
the flag :data:`~oracledb.SUBSCR_QOS_QUERY` when the subscription was
|
||||
created.
|
||||
attribute will be None if the ``qos`` parameter did not include the flag
|
||||
:data:`~oracledb.SUBSCR_QOS_QUERY` when the subscription was created.
|
||||
|
||||
|
||||
.. attribute:: Message.queue_name
|
||||
|
@ -171,7 +170,7 @@ Message Objects
|
|||
|
||||
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 an empty list if the ``qos`` parameter included the flag
|
||||
attribute will be None if the ``qos`` parameter included the flag
|
||||
:data:`~oracledb.SUBSCR_QOS_QUERY` when the subscription was created.
|
||||
|
||||
|
||||
|
|
|
@ -50,13 +50,6 @@ Variable Attributes
|
|||
name will continue to work for a period of time.
|
||||
|
||||
|
||||
.. attribute:: Variable.convert_nulls
|
||||
|
||||
This read-only attribute returns whether the :attr:`~Variable.outconverter`
|
||||
method is called when null values are fetched from the database.
|
||||
|
||||
.. versionadded:: 1.4.0
|
||||
|
||||
.. attribute:: Variable.inconverter
|
||||
|
||||
This read-write attribute specifies the method used to convert data from
|
||||
|
|
|
@ -2,11 +2,10 @@
|
|||
#
|
||||
# python-oracledb documentation build configuration file
|
||||
#
|
||||
# This file is execfile()d with the current directory set to its containing dir
|
||||
# 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).
|
||||
# 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.
|
||||
|
@ -20,28 +19,23 @@ sys.path.append(os.path.abspath("_ext"))
|
|||
# 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 = ["table_with_summary", "oracle_deprecated", "sphinx_rtd_theme"]
|
||||
# Add any Sphinx extension module names here, as strings. They can be extensions
|
||||
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||
extensions = ["table_with_summary", "oracle_deprecated"]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = [".templates"]
|
||||
templates_path = ['.templates']
|
||||
|
||||
# The suffix of source filenames.
|
||||
source_suffix = ".rst"
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The root toctree document.
|
||||
root_doc = master_doc = "index"
|
||||
root_doc = master_doc = 'index'
|
||||
|
||||
# General substitutions.
|
||||
project = "python-oracledb"
|
||||
copyright = (
|
||||
"2016, 2023, 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"
|
||||
project = 'python-oracledb'
|
||||
copyright = u'2016, 2023, 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.
|
||||
|
@ -62,26 +56,26 @@ release = local_vars["__version__"]
|
|||
|
||||
# There are two options for replacing |today|: either, you set today to some
|
||||
# non-false value, then it is used:
|
||||
# today = ''
|
||||
#today = ''
|
||||
# Else, today_fmt is used as the format for a strftime call.
|
||||
today_fmt = "%B %d, %Y"
|
||||
today_fmt = '%B %d, %Y'
|
||||
|
||||
# List of documents that shouldn't be included in the build.
|
||||
# unused_docs = []
|
||||
#unused_docs = []
|
||||
|
||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||
# add_function_parentheses = True
|
||||
#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
|
||||
#add_module_names = True
|
||||
|
||||
# If true, sectionauthor and moduleauthor directives will be shown in the
|
||||
# output. They are ignored by default.
|
||||
# show_authors = False
|
||||
#show_authors = False
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = "sphinx"
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
|
||||
# Options for HTML output
|
||||
|
@ -93,67 +87,64 @@ pygments_style = "sphinx"
|
|||
# html_style = 'default.css'
|
||||
|
||||
# The theme to use for readthedocs.
|
||||
html_theme = "sphinx_rtd_theme"
|
||||
html_theme = 'sphinx_rtd_theme'
|
||||
|
||||
# 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"]
|
||||
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"
|
||||
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
|
||||
#html_use_smartypants = True
|
||||
|
||||
# Content template for the index page.
|
||||
# html_index = ''
|
||||
#html_index = ''
|
||||
|
||||
# Custom sidebar templates, maps document names to template names.
|
||||
# html_sidebars = {}
|
||||
#html_sidebars = {}
|
||||
|
||||
# Additional templates that should be rendered to pages, maps page names to
|
||||
# template names.
|
||||
# html_additional_pages = {}
|
||||
#html_additional_pages = {}
|
||||
|
||||
# If false, no module index is generated.
|
||||
# html_use_modindex = True
|
||||
#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 = "oracledbdoc"
|
||||
htmlhelp_basename = 'oracledbdoc'
|
||||
|
||||
numfig = True
|
||||
|
||||
|
||||
# Display tables with no horizontal scrollbar
|
||||
def setup(app):
|
||||
app.add_css_file("custom.css")
|
||||
|
||||
app.add_css_file('custom.css')
|
||||
|
||||
# Options for LaTeX output
|
||||
# ------------------------
|
||||
|
||||
# The paper size ('letter' or 'a4').
|
||||
# latex_paper_size = 'letter'
|
||||
#latex_paper_size = 'letter'
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
# latex_font_size = '10pt'
|
||||
#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 = []
|
||||
# (source start file, target name, title, author, document class [howto/manual]).
|
||||
#latex_documents = []
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
# latex_preamble = ''
|
||||
#latex_preamble = ''
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
# latex_appendices = []
|
||||
#latex_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
# latex_use_modindex = True
|
||||
#latex_use_modindex = True
|
||||
|
|
|
@ -6,11 +6,10 @@ Python-oracledb is the new name for the Python `cx_Oracle driver
|
|||
an open source module that enables Python programs to access 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. Synchronous and
|
||||
:ref:`concurrent <asyncio>` coding styles are supported.
|
||||
additions and a couple of exclusions.
|
||||
|
||||
This module is currently tested with Python 3.7, 3.8, 3.9, 3.10, 3.11 and 3.12
|
||||
against Oracle Database 23c, 21c, 19c, 18c, 12c, and 11gR2.
|
||||
This module is currently tested with Python 3.6, 3.7, 3.8, 3.9, 3.10 and 3.11
|
||||
against Oracle Database 21c, 19c, 18c, 12c, and 11.2.
|
||||
|
||||
**python-oracledb** is distributed under an open-source
|
||||
:ref:`license <license>`. Changes in python-oracledb releases can be found in
|
||||
|
@ -46,11 +45,9 @@ User Guide
|
|||
user_guide/two_phase_commit.rst
|
||||
user_guide/startup.rst
|
||||
user_guide/ha.rst
|
||||
user_guide/globalization.rst
|
||||
user_guide/asyncio.rst
|
||||
user_guide/exception_handling.rst
|
||||
user_guide/tracing.rst
|
||||
user_guide/troubleshooting.rst
|
||||
user_guide/globalization.rst
|
||||
user_guide/exception_handling.rst
|
||||
user_guide/appendix_a.rst
|
||||
user_guide/appendix_b.rst
|
||||
user_guide/appendix_c.rst
|
||||
|
@ -69,17 +66,12 @@ API Manual
|
|||
api_manual/connection_pool.rst
|
||||
api_manual/pool_params.rst
|
||||
api_manual/cursor.rst
|
||||
api_manual/fetch_info.rst
|
||||
api_manual/variable.rst
|
||||
api_manual/subscription.rst
|
||||
api_manual/lob.rst
|
||||
api_manual/dbobject_type.rst
|
||||
api_manual/aq.rst
|
||||
api_manual/soda.rst
|
||||
api_manual/async_connection.rst
|
||||
api_manual/async_connection_pool.rst
|
||||
api_manual/async_cursor.rst
|
||||
api_manual/async_lob.rst
|
||||
api_manual/deprecations.rst
|
||||
|
||||
.. toctree::
|
||||
|
|
|
@ -7,476 +7,6 @@ python-oracledb Release Notes
|
|||
|
||||
For deprecations, see :ref:`Deprecations <deprecations>`.
|
||||
|
||||
oracledb 2.0.1 (TBD)
|
||||
--------------------
|
||||
|
||||
Thin Mode Changes
|
||||
+++++++++++++++++
|
||||
|
||||
#) Added support for using alternative event loop implementations like uvloop
|
||||
(`issue 276 <https://github.com/oracle/python-oracledb/issues/276>`__).
|
||||
#) Added support for the asynchronous context manager protocol on the
|
||||
AsyncCursor class as a convenience.
|
||||
#) Fixed regression when connecting to a database using listener redirects
|
||||
with either a connection pool or using asyncio
|
||||
(`issue 275 <https://github.com/oracle/python-oracledb/issues/275>`__).
|
||||
#) Fixed bug with intermittent hang on some versions of Oracle Database when
|
||||
using asyncio and the database raises an error and output variables are
|
||||
present
|
||||
(`issue 278 <https://github.com/oracle/python-oracledb/issues/278>`__).
|
||||
#) Fixed bug when fetch variables contain output converters and a query is
|
||||
re-executed
|
||||
(`issue 271 <https://github.com/oracle/python-oracledb/issues/271>`__).
|
||||
#) Internal change to ensure that pools are closed gracefully when the main
|
||||
thread terminates.
|
||||
#) Internal change to slightly improve performance of LOB reads and writes.
|
||||
#) Corrected typing declaration for :meth:`oracledb.connect_async()`.
|
||||
|
||||
Common Changes
|
||||
++++++++++++++
|
||||
|
||||
#) Fixed regression which prevented a null value from being set on DbObject
|
||||
attributes or used as elements of collections
|
||||
(`issue 273 <https://github.com/oracle/python-oracledb/issues/273>`__).
|
||||
#) Fixed regression from cx_Oracle which ignored the value of the
|
||||
``encoding_errors`` parameter when creating variables by calling the method
|
||||
:meth:`Cursor.var()`
|
||||
(`issue 279 <https://github.com/oracle/python-oracledb/issues/279>`__).
|
||||
#) Bumped minimum requirement of Cython to 3.0.
|
||||
|
||||
|
||||
oracledb 2.0.0 (December 2023)
|
||||
------------------------------
|
||||
|
||||
Thin Mode Changes
|
||||
+++++++++++++++++
|
||||
|
||||
#) Added support for :ref:`concurrent programming with asyncio <asyncio>`
|
||||
(`issue 6 <https://github.com/oracle/python-oracledb/issues/6>`__).
|
||||
#) Added parameter :attr:`ConnectParams.sdu` for configuring the Session Data
|
||||
Unit (SDU) size for sizing internal buffers used for tuning communication
|
||||
with the database. The connection property :attr:`Connection.sdu` was also
|
||||
added.
|
||||
#) Added parameter :data:`ConnectParams.ssl_context` to modify the SSL context
|
||||
used when connecting via TLS
|
||||
(`issue 259 <https://github.com/oracle/python-oracledb/issues/259>`__).
|
||||
#) Added support for an Oracle Database 23c JSON feature allowing field names
|
||||
with more than 255 UTF-8 encoded bytes.
|
||||
#) Added support for the ``FAILOVER`` clause in full connect descriptors.
|
||||
#) Fixed bug in detecting the current time zone
|
||||
(`issue 257 <https://github.com/oracle/python-oracledb/issues/257>`__).
|
||||
#) Fixed bug in handling database response in certain unusual circumstances.
|
||||
#) Fixed bug in handling exceptions raised during connection establishment.
|
||||
#) Fixed bug in identifying bind variables in SQL statements containing
|
||||
multiple line comments with multiple asterisks before the closing slash.
|
||||
#) A more meaningful error is raised when the wrong type of data is passed to
|
||||
:meth:`LOB.write()`.
|
||||
#) Internal change to support an Oracle Database 23c JSON feature improving
|
||||
JSON storage usage.
|
||||
#) Internal change to ensure that all connections in a pool have been closed
|
||||
gracefully before the pool is closed.
|
||||
#) Internal changes to improve handling of the network protocol between
|
||||
python-oracledb and Oracle Database.
|
||||
#) Internal changes to improve handling of multiple address and description
|
||||
lists in full connect descriptors.
|
||||
|
||||
Thick Mode Changes
|
||||
++++++++++++++++++
|
||||
|
||||
#) Fixed bug in return value of :meth:`SodaOperation.replaceOne()`.
|
||||
|
||||
Common Changes
|
||||
++++++++++++++
|
||||
|
||||
#) Dropped support for Python 3.6.
|
||||
#) Desupported a number of parameters and attributes that were previously
|
||||
deprecated. See :ref:`desupport notices<_desupported_2_0>` for details.
|
||||
#) Added property :attr:`Cursor.warning` for database warnings (such as PL/SQL
|
||||
compilation warnings) generated by calls to :meth:`Cursor.execute()` or
|
||||
:meth:`Cursor.executemany()`.
|
||||
#) Added property :attr:`Connection.warning` for warnings (such as the password
|
||||
being in the grace period) generated during connection.
|
||||
#) Added properties that provide information about the database:
|
||||
:attr:`Connection.db_domain`, :attr:`Connection.db_name`,
|
||||
:attr:`Connection.max_open_cursors`, :attr:`Connection.service_name`
|
||||
and :attr:`Connection.transaction_in_progress`.
|
||||
#) Added property :data:`Connection.proxy_user` to show the name of the user
|
||||
which was used as a proxy when connecting (`issue 250
|
||||
<https://github.com/oracle/python-oracledb/issues/250>`__).
|
||||
#) Added properties :data:`FetchInfo.domain_schema`,
|
||||
:data:`FetchInfo.domain_name` and :data:`FetchInfo.annotations` for the
|
||||
`SQL domain <https://docs.oracle.com/en/database/oracle/oracle-database/
|
||||
23/sqlrf/create-domain.html#GUID-17D3A9C6-D993-4E94-BF6B-CACA56581F41>`__
|
||||
and `annotations <https://docs.oracle.com/en/database/oracle/
|
||||
oracle-database/23/sqlrf/annotations_clause.html#
|
||||
GUID-1AC16117-BBB6-4435-8794-2B99F8F68052>`__
|
||||
associated with columns that are being fetched. SQL domains and annotations
|
||||
require Oracle Database 23c. If using python-oracledb Thick mode, Oracle
|
||||
Client 23c is also required.
|
||||
#) Added parameter ``data`` to :meth:`Connection.createlob()` to allow data to
|
||||
be written at LOB creation time.
|
||||
#) Added type :data:`~oracledb.DB_TYPE_XMLTYPE` to represent data of type
|
||||
``SYS.XMLTYPE`` in the database. Previously the value of
|
||||
:data:`FetchInfo.type_code` for data of this type was
|
||||
:data:`~oracledb.DB_TYPE_LONG` in Thick mode and
|
||||
:data:`~oracledb.DB_TYPE_OBJECT` in Thin mode.
|
||||
#) Attribute and element values of :ref:`Oracle Object <dbobject>` instances
|
||||
that contain strings or bytes now have their maximum size constraints
|
||||
checked. Errors ``DPY-2043`` (attributes) and ``DPY-2044`` (element values)
|
||||
are now raised when constraints are violated.
|
||||
#) Attribute and element values of :ref:`Oracle Object <dbobject>` instances
|
||||
that are numbers are now returned as integers if the precision and scale
|
||||
allow for it. This is the same way that numbers are fetched from the
|
||||
database
|
||||
(`issue 99 <https://github.com/oracle/python-oracledb/issues/99>`__).
|
||||
#) Errors that have entries in the
|
||||
:ref:`troubleshooting documentation <troubleshooting>` now have links to
|
||||
that documentation shown in the message text.
|
||||
#) Fixed bug with binding boolean values with Oracle Database 23c
|
||||
(`issue 263 <https://github.com/oracle/python-oracledb/issues/263>`__).
|
||||
#) Fixed bug with getting unknown attributes from :ref:`Oracle Object
|
||||
<dbobject>` instances.
|
||||
#) Error ``DPY-4029: errors in array DML exceed 65535`` is now raised when the
|
||||
number of batch errors exceeds 65535 when calling
|
||||
:meth:`Cursor.executemany()` with the parameter ``batcherrors`` set to the
|
||||
value ``True``. Note that in thick mode this error is not raised unless the
|
||||
number of batch errors is a multiple of 65536; instead, the number of batch
|
||||
errors returned is modulo 65536
|
||||
(`issue 262 <https://github.com/oracle/python-oracledb/issues/262>`__).
|
||||
#) Black is now used to format Python code and ruff to lint Python code.
|
||||
|
||||
|
||||
oracledb 1.4.2 (October 2023)
|
||||
-----------------------------
|
||||
|
||||
Thick Changes
|
||||
+++++++++++++
|
||||
|
||||
#) Fixed bug resulting in a segfault on some platforms when using two-phase
|
||||
commit.
|
||||
|
||||
Common Changes
|
||||
++++++++++++++
|
||||
|
||||
#) Pre-built binaries are now being created for Python 3.12
|
||||
(`issue 237 <https://github.com/oracle/python-oracledb/issues/237>`__).
|
||||
|
||||
|
||||
oracledb 1.4.1 (September 2023)
|
||||
-------------------------------
|
||||
|
||||
Thin Mode Changes
|
||||
+++++++++++++++++
|
||||
|
||||
#) Improved statement bind variable placeholder parser performance, handle
|
||||
statements which use the `Alternative Quoting Mechanism
|
||||
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-1824CBAA-6E16-4921-B2A6-112FB02248DA>`__
|
||||
('Q' strings), and fix some issues identifying bind variable placeholders
|
||||
in embedded quotes and in JSON syntax.
|
||||
|
||||
Thick Changes
|
||||
+++++++++++++
|
||||
|
||||
#) Fixed error checking when getting or setting the connection pool parameters
|
||||
``ping_interval`` and ``soda_metadata_cache``.
|
||||
|
||||
Common Changes
|
||||
++++++++++++++
|
||||
|
||||
#) Fixed bug when calling :meth:`Cursor.execute()` or
|
||||
:meth:`Cursor.executemany()` with missing bind data after calling
|
||||
:meth:`Cursor.setinputsizes()` with at least one of the values supplied as
|
||||
``None``
|
||||
(`issue 217 <https://github.com/oracle/python-oracledb/issues/217>`__).
|
||||
#) SQL statement parsing now raises ``DPY-2041: missing ending quote (') in
|
||||
string`` or ``DPY-2042: missing ending quote (") in identifier`` for
|
||||
statements with the noted invalid syntax. Previously, thick mode gave
|
||||
``ORA-1756`` or ``ORA-1740``, respectively, while thin mode did not throw
|
||||
an error.
|
||||
#) Added missing ">" to ``repr()`` of :ref:`sodadb`.
|
||||
|
||||
|
||||
oracledb 1.4.0 (August 2023)
|
||||
----------------------------
|
||||
|
||||
Thin Mode Changes
|
||||
+++++++++++++++++
|
||||
|
||||
#) Added support for an Oracle Database 23c feature that can improve the
|
||||
performance of connection creation by reducing the number of round trips
|
||||
required to create the second and subsequent connections to the same
|
||||
database.
|
||||
#) Added support for shrinking the connection pool back to the specified
|
||||
minimum size when the pool is idle for :data:`ConnectionPool.timeout`
|
||||
seconds.
|
||||
#) Added support for growing the connection pool back to the minimum number of
|
||||
connections after connections are killed or otherwise made unusable.
|
||||
#) A default connection class is now generated when DRCP is used with a
|
||||
connection pool and no connection class was specified when the pool was
|
||||
created. The default connection class will be of the form ``DPY:`` followed
|
||||
by a 16-byte unique identifier converted to base64 encoding.
|
||||
#) Changed internal connection feature negotiation for more accurate Oracle
|
||||
Database 23c support.
|
||||
#) Added support for sending a generated connection identifier to the
|
||||
database used for tracing. An application specific prefix is prepended to
|
||||
this value if specified via a new ``connection_id_prefix`` parameter when
|
||||
creating standalone connections or connection pools.
|
||||
#) Added URL to the Oracle Database Error Help Portal in Oracle Database
|
||||
error messages similar to when Thick mode uses Oracle Client 23c.
|
||||
#) Added support for the ``ORA_SDTZ`` environment variable used to set the
|
||||
session time zone used by the database.
|
||||
#) Fixed bug when a dynamically sized connection pool is created with an
|
||||
``increment`` of zero and the pool needs to grow.
|
||||
#) Fixed bug affecting connection reuse when connections were acquired from
|
||||
the connection pool with a ``cclass`` different to the one used to
|
||||
create the pool.
|
||||
#) Fixed bug when a connection is discarded from the connection pool during
|
||||
:meth:`ConnectionPool.acquire()` and the ping check fails due to the
|
||||
connection being dead.
|
||||
#) Fixed bug when an output type handler is used and the value of
|
||||
:attr:`Cursor.prefetchrows` exceeds :attr:`Cursor.arraysize`
|
||||
(`issue 173 <https://github.com/oracle/python-oracledb/issues/173>`__).
|
||||
#) Fixed bug when an Application Continuity replay context is returned during
|
||||
connection to the database
|
||||
(`issue 176 <https://github.com/oracle/python-oracledb/issues/176>`__).
|
||||
#) Fixed bug when socket is not closed immediately upon failure to establish a
|
||||
connection to the database
|
||||
(`issue 211 <https://github.com/oracle/python-oracledb/issues/211>`__).
|
||||
|
||||
Thick Mode Changes
|
||||
++++++++++++++++++
|
||||
|
||||
#) Added function :meth:`SodaCollection.listIndexes()` for getting the indexes
|
||||
on a SODA collection.
|
||||
#) Added support for specifying if documents should be locked when fetched
|
||||
from SODA collections. A new non-terminal method
|
||||
:meth:`~SodaOperation.lock()` was added which requires Oracle Client
|
||||
21.3 or higher (or Oracle Client 19 from 19.11).
|
||||
#) Relaxed restriction for end-to-end tracing string connection
|
||||
attributes. These values can now be set to the value ``None`` which will be
|
||||
treated the same as an empty string.
|
||||
#) Fixed bug when using external authentication with an Easy Connect
|
||||
connection string.
|
||||
#) Fixed memory leak when accessing objects embedded within other objects.
|
||||
|
||||
Common Changes
|
||||
++++++++++++++
|
||||
|
||||
#) Use of Python 3.6 and 3.7 is deprecated and support for them will be
|
||||
removed in a future release. A warning is issued when these versions are
|
||||
used but otherwise they will continue to function as usual. The warning can
|
||||
be suppressed by importing `warnings
|
||||
<https://docs.python.org/3/library/warnings.html>`__ and adding a call like
|
||||
``warnings.filterwarnings(action='ignore', module="oracledb")``
|
||||
*before* importing ``oracledb``.
|
||||
#) Added support for the :attr:`~Variable.outconverter` being called when a
|
||||
null value is fetched from the database and the new parameter
|
||||
``convert_nulls`` to the method :meth:`Cursor.var()` is passed the value
|
||||
``True``
|
||||
(`issue 107 <https://github.com/oracle/python-oracledb/issues/107>`__).
|
||||
#) Replaced fixed 7-tuple for the cursor metadata found in
|
||||
:data:`Cursor.description` with a class which provides additional
|
||||
information such as the database object type and whether the column
|
||||
contains JSON data.
|
||||
#) Changed the signature for output type handlers to
|
||||
``handler(cursor, metadata)`` where the ``metadata`` parameter is a
|
||||
:ref:`FetchInfo<fetchinfoobj>` object containing the same information found
|
||||
in :data:`Cursor.description`. The original signature for output type
|
||||
handlers is deprecated and will be removed in a future version.
|
||||
#) Added support for fetching VARCHAR2 and LOB columns which contain JSON (and
|
||||
have the "IS JSON" check constraint enabled) in the same way as columns of
|
||||
type JSON (which requires Oracle Database 21c or higher) are fetched. In
|
||||
thick mode this requires Oracle Client 19c or higher. The attribute
|
||||
``oracledb.__future__.old_json_col_as_obj`` must be set to the value
|
||||
``True`` for this behavior to occur. In version 2.0 this will become the
|
||||
normal behavior and setting this attribute will no longer be needed.
|
||||
#) Added new property :attr:`Connection.instance_name` which provides the
|
||||
Oracle Database instance name associated with the connection. This is the
|
||||
same value as the SQL expression
|
||||
``sys_context('userenv', 'instance_name')``.
|
||||
#) Added support for relational queries on the underlying tables of SODA
|
||||
collections created in Oracle Database 23c if they contain JSON documents
|
||||
with embedded OIDs.
|
||||
#) Automatically retry a query if the error ``ORA-00932: inconsistent data
|
||||
types`` is raised (which can occur if a table or view is recreated with a
|
||||
data type that is incompatible with the column's previous data type).
|
||||
#) The ``repr()`` value of the DbObject class now shows the string "DbObject"
|
||||
instead of the string "Object" for consistency with the name of the class
|
||||
and the other ``repr()`` values for DbObjectType and DbObjectAttr.
|
||||
#) Fixed bug when binding sequences other than lists and tuples
|
||||
(`issue 205 <https://github.com/oracle/python-oracledb/issues/205>`__).
|
||||
#) Added support for using the Cython 3.0 release
|
||||
(`issue 204 <https://github.com/oracle/python-oracledb/issues/204>`__).
|
||||
#) Improved test suite and documentation.
|
||||
|
||||
oracledb 1.3.2 (June 2023)
|
||||
--------------------------
|
||||
|
||||
Thin Mode Changes
|
||||
+++++++++++++++++
|
||||
|
||||
#) Fixed bug using :attr:`Cursor.arraysize` for tuning data fetches from REF
|
||||
CURSORS.
|
||||
#) Fixed bug connecting to databases with older 11g password verifiers
|
||||
(`issue 189 <https://github.com/oracle/python-oracledb/issues/189>`__).
|
||||
#) Fixed bugs in the implementation of the statement cache.
|
||||
#) Fixed bug which caused a cursor leak if an error was thrown while
|
||||
processing the execution of a query.
|
||||
#) Eliminated unneeded round trip when using token authentication to connect
|
||||
to the database.
|
||||
#) Fixed bug which could cause a redirect loop with improperly configured
|
||||
listener redirects.
|
||||
#) Fixed bug when executing PL/SQL with a large number of binds.
|
||||
#) Fixed bug when using DRCP with Oracle Database 23c.
|
||||
|
||||
Thick Mode Changes
|
||||
++++++++++++++++++
|
||||
|
||||
#) Fixed bug when using external authentication with a Net Service Name
|
||||
connection string
|
||||
(`issue 178 <https://github.com/oracle/python-oracledb/issues/178>`__).
|
||||
#) Fixed bug when using external authentication with an Easy Connect
|
||||
connection string.
|
||||
|
||||
Common Changes
|
||||
++++++++++++++
|
||||
|
||||
#) When fetching rows from REF CURSORS, the cursor's
|
||||
:attr:`~Cursor.prefetchrows` attribute is now ignored. Use
|
||||
:attr:`Cursor.arraysize` for tuning these fetches. This change allows
|
||||
consistency between Thin and Thick modes.
|
||||
|
||||
|
||||
oracledb 1.3.1 (April 2023)
|
||||
---------------------------
|
||||
|
||||
Thin Mode Changes
|
||||
+++++++++++++++++
|
||||
|
||||
#) Improved performance of regular expressions used for parsing SQL
|
||||
(`issue 172 <https://github.com/oracle/python-oracledb/issues/172>`__).
|
||||
#) Fixed bug with Oracle Database 23c when SQL is executed after first being
|
||||
parsed.
|
||||
#) Fixed bug when :data:`ConnectionPool.timeout` is not `None` when creating a
|
||||
connection pool
|
||||
(`issue 166 <https://github.com/oracle/python-oracledb/issues/166>`__).
|
||||
#) Fixed bug when a query is re-executed after an underlying table is dropped
|
||||
and recreated, and the query select list contains LOBs or JSON data.
|
||||
#) Fixed bug when warning message such as for impending password expiry is
|
||||
encountered during connect
|
||||
(`issue 171 <https://github.com/oracle/python-oracledb/issues/171>`__).
|
||||
|
||||
Common Changes
|
||||
++++++++++++++
|
||||
|
||||
#) Improved test suite and samples.
|
||||
|
||||
|
||||
oracledb 1.3.0 (March 2023)
|
||||
---------------------------
|
||||
|
||||
Thin Mode Changes
|
||||
+++++++++++++++++
|
||||
|
||||
#) Added direct support for the Oracle Database 21c JSON data type, removing
|
||||
the need to use an output type handler.
|
||||
#) Added implementation for :data:`ConnectionPool.timeout` to allow pools to
|
||||
shrink to ``min`` connections.
|
||||
#) Added check to prevent adding too many elements to bounded database
|
||||
collections.
|
||||
#) Removed internally set fixed size for database collections. Collections of
|
||||
any size supported by the database can now be created.
|
||||
#) Added support for connecting to databases that accept passwords longer than
|
||||
30 UTF-8 encoded bytes.
|
||||
#) Detect the time zone on the OS and set the session timezone using this
|
||||
value to be consistent with thick mode
|
||||
(`issue 144 <https://github.com/oracle/python-oracledb/issues/144>`__).
|
||||
#) Improved BOOLEAN handling.
|
||||
#) Error ``DPY-6005: cannot connect to database`` is now raised for all
|
||||
failures to connect to the database and the phrase ``cannot connect to
|
||||
database`` is removed from all other error messages (since this can be
|
||||
confusing when these errors are raised from
|
||||
:meth:`ConnectParams.parse_connect_string()`).
|
||||
#) Fixed bug when calling :meth:`Cursor.executemany()` with PL/SQL when the
|
||||
size of the bound data increases on subsequent calls
|
||||
(`issue 132 <https://github.com/oracle/python-oracledb/issues/132>`__).
|
||||
#) Fixed bug when binding data of type TIMESTAMP WITH TIME ZONE but with
|
||||
zero fractional seconds.
|
||||
#) Fixed bug with incorrect values of :data:`Cursor.rowcount` when fetching
|
||||
data
|
||||
(`issue 147 <https://github.com/oracle/python-oracledb/issues/147>`__).
|
||||
#) Fixed bug with SQL containing multibyte characters with certain database
|
||||
character sets
|
||||
(`issue 133 <https://github.com/oracle/python-oracledb/issues/133>`__).
|
||||
#) Fixed bug with ordering of binds in SQL when the database version is 12.1
|
||||
(`issue 135 <https://github.com/oracle/python-oracledb/issues/135>`__).
|
||||
#) Fixed bug with ordering of binds in PL/SQL when the bind variable may
|
||||
potentially exceed the 32767 byte limit but the actual value bound does not
|
||||
(`issue 146 <https://github.com/oracle/python-oracledb/issues/146>`__).
|
||||
#) Fixed bug connecting to an IPv6 address with IAM tokens.
|
||||
#) Fixed bug determining RETURNING binds in a SQL statement when RETURNING and
|
||||
INTO keywords are not separated by whitespace, but are separated by
|
||||
parentheses.
|
||||
#) The exception ``DPY-3022: named time zones are not supported in thin mode``
|
||||
is now raised when attempting to fetch data of type TIMESTAMP WITH TIME
|
||||
ZONE when the time zone associated with the data is a named time zone.
|
||||
Previously invalid data was returned
|
||||
(`disc 131 <https://github.com/oracle/python-oracledb/discussions/131>`__).
|
||||
#) Internal implementation changes:
|
||||
|
||||
- Added internal support for prefetching the LOB size and chunk size,
|
||||
thereby eliminating a :ref:`round-trip<roundtrips>` when calling
|
||||
:meth:`LOB.size()` and :meth:`LOB.getchunksize()`.
|
||||
- Made the pool implementation LIFO to improve locality, reduce the number
|
||||
of times any session callback must be invoked, and allow connections to
|
||||
be timed out.
|
||||
- Removed packet for negotiating network services which are not supported
|
||||
in thin mode.
|
||||
- Removed unneeded packet for changing the password of the connected user.
|
||||
|
||||
|
||||
Thick Mode Changes
|
||||
++++++++++++++++++
|
||||
|
||||
#) Raise a more meaningful error when an unsupported type in a JSON value is
|
||||
detected.
|
||||
#) Added support for the "signed int", "signed long" and "decimal128" scalar
|
||||
types in JSON (generally only seen when converting from MongoDB).
|
||||
#) Defer raising an exception when calling :meth:`Connection.gettype()`
|
||||
for a type containing an attribute or element with an unsupported data type
|
||||
until the first attempt to reference the attribute or element with the
|
||||
unsupported data type.
|
||||
#) Fixed bug when attempting to create bequeath connections when the DSN
|
||||
contains credentials.
|
||||
|
||||
Common Changes
|
||||
++++++++++++++
|
||||
|
||||
#) Improved type annotations.
|
||||
#) Added method :meth:`ConnectParams.parse_dsn_with_credentials()` for parsing
|
||||
a DSN that contains credentials.
|
||||
#) Error ``DPY-2038: element at index {index} does not exist`` is now raised
|
||||
whenever an element in a database collection is missing. Previously, thick
|
||||
mode raised ``DPI-1024: element at index {index} does not exist`` and thin
|
||||
mode raised ``KeyError`` or ``IndexError``.
|
||||
#) Error ``DPY-2039: given index {index} must be in the range of {min_index}
|
||||
to {max_index}`` is now raised whenever an element in a database collection
|
||||
is set outside the bounds of the collection. Previously, thick mode raised
|
||||
``OCI-22165: given index [{index}] must be in the range of [{min_index}] to
|
||||
[{max_index}]`` and thin mode raised ``IndexError``.
|
||||
#) Error ``DPY-2040: parameters "batcherrors" and "arraydmlrowcounts" may only
|
||||
be true when used with insert, update, delete and merge statements`` is now
|
||||
raised when either of the parameters `batcherrors` and `arraydmlrowcounts`
|
||||
is set to the value `True` when calling :meth:`Cursor.executemany()`.
|
||||
Previously, thick mode raised ``DPI-1063: modes DPI_MODE_EXEC_BATCH_ERRORS
|
||||
and DPI_MODE_EXEC_ARRAY_DML_ROWCOUNTS can only be used with insert, update,
|
||||
delete and merge statements`` and thin mode raised
|
||||
``ORA-03137: malformed TTC packet from client rejected``
|
||||
(`issue 128 <https://github.com/oracle/python-oracledb/issues/128>`__).
|
||||
#) Internal changes to ensure that errors taking place while raising
|
||||
exceptions are handled more gracefully.
|
||||
|
||||
|
||||
oracledb 1.2.2 (January 2023)
|
||||
-----------------------------
|
||||
|
||||
|
|
|
@ -86,22 +86,14 @@ see :ref:`driverdiff` and :ref:`compatibility`.
|
|||
- No
|
||||
- Yes
|
||||
- Yes
|
||||
* - Lightweight Directory Access Protocol (LDAP) connections
|
||||
- No
|
||||
- Yes
|
||||
- Yes
|
||||
* - Proxy connections (see :ref:`proxyauth`)
|
||||
- Yes
|
||||
- Yes
|
||||
- Yes
|
||||
* - Socket Secure (SOCKS) Proxy connections
|
||||
- No
|
||||
- No
|
||||
- No
|
||||
* - Connection mode privileges (see :ref:`connection-authorization-modes`)
|
||||
- Yes
|
||||
- Yes - only :data:`~oracledb.AUTH_MODE_SYSDBA` is supported
|
||||
- Yes - only :data:`~oracledb.AUTH_MODE_SYSDBA` is supported
|
||||
- Yes - only :data:`~oracledb.AUTH_MODE_SYSDBA` is supported in Thick mode
|
||||
- Yes
|
||||
* - Preliminary connections
|
||||
- No
|
||||
- Yes
|
||||
|
@ -122,7 +114,7 @@ see :ref:`driverdiff` and :ref:`compatibility`.
|
|||
- No
|
||||
- Yes - No TIMESTAMP support
|
||||
- Yes - No TIMESTAMP support
|
||||
* - Oracle Database Native Network Encryption (NNE) (see :ref:`nne`)
|
||||
* - Oracle Database Native Network Encryption (see :ref:`nne`)
|
||||
- No
|
||||
- Yes
|
||||
- Yes
|
||||
|
@ -186,7 +178,7 @@ see :ref:`driverdiff` and :ref:`compatibility`.
|
|||
- Yes for scalar types. Yes for collection types using array interface.
|
||||
- Yes
|
||||
- Yes
|
||||
* - Simple Oracle Document Access (SODA) API (see :ref:`SODA <soda>`)
|
||||
* - Simple Oracle Document Access (SODA) API (:ref:`SODA <soda>`)
|
||||
- No
|
||||
- Yes
|
||||
- Yes
|
||||
|
@ -214,10 +206,10 @@ see :ref:`driverdiff` and :ref:`compatibility`.
|
|||
- No - All NLS environment variables are ignored. Use Python globalization support instead
|
||||
- Yes - NLS environment variables are respected except character set in NLS_LANG
|
||||
- Yes - NLS environment variables are respected except character set in NLS_LANG
|
||||
* - Row prefetching on first query execute (see :attr:`prefetchrows`)
|
||||
- Yes - unless the row contains LOBs or similar types
|
||||
- Yes - unless the row contains LOBs or similar types
|
||||
- Yes - unless the row contains LOBs or similar types
|
||||
* - Row prefetching on first query execute.(see :attr:`prefetchrows`)
|
||||
- Yes
|
||||
- Yes
|
||||
- Yes
|
||||
* - Array fetching for queries (see :attr:`arraysize`)
|
||||
- Yes
|
||||
- Yes
|
||||
|
@ -282,10 +274,6 @@ see :ref:`driverdiff` and :ref:`compatibility`.
|
|||
- No
|
||||
- Yes
|
||||
- Yes
|
||||
* - Concurrent programming with asyncio (see :ref:`asyncio`)
|
||||
- Yes
|
||||
- No
|
||||
- No
|
||||
* - End-to-end monitoring and tracing attributes (see :ref:`tracingsql`)
|
||||
- Yes
|
||||
- Yes
|
||||
|
@ -300,7 +288,7 @@ see :ref:`driverdiff` and :ref:`compatibility`.
|
|||
- Yes
|
||||
* - Two-phase Commit (TPC)
|
||||
- No
|
||||
- Yes - improved support. See :ref:`tcp`.
|
||||
- Yes - improved support (see :ref:`tcp`)
|
||||
- Yes - limited support
|
||||
* - REF CURSORs and Nested Cursors
|
||||
- Yes
|
||||
|
@ -322,14 +310,70 @@ see :ref:`driverdiff` and :ref:`compatibility`.
|
|||
- Yes
|
||||
- Yes
|
||||
- Yes
|
||||
* - LOB length prefetching
|
||||
- Yes
|
||||
- Yes
|
||||
- Yes
|
||||
* - LOB prefetching
|
||||
- No
|
||||
- No - does have LOB length prefetch
|
||||
- No - does have LOB length prefetch
|
||||
* - LOB locator operations such as trim
|
||||
- Yes
|
||||
- Yes
|
||||
- Yes
|
||||
* - CHAR, VARCHAR2, NUMBER, FLOAT, DATE, and LONG data types
|
||||
- Yes
|
||||
- Yes
|
||||
- Yes
|
||||
* - BLOB and CLOB data types
|
||||
- Yes
|
||||
- Yes
|
||||
- Yes
|
||||
* - BINARY_DOUBLE and BINARY_FLOAT data types
|
||||
- Yes
|
||||
- Yes
|
||||
- Yes
|
||||
* - RAW and LONG RAW data types
|
||||
- Yes
|
||||
- Yes
|
||||
- Yes
|
||||
* - INTERVAL DAY TO SECOND data type (see :data:`~oracledb.DB_TYPE_INTERVAL_DS`)
|
||||
- Yes
|
||||
- Yes
|
||||
- Yes
|
||||
* - INTERVAL YEAR TO MONTH data type (see :data:`~oracledb.DB_TYPE_INTERVAL_YM`)
|
||||
- No
|
||||
- No
|
||||
- No
|
||||
* - Oracle 12c JSON
|
||||
- Yes
|
||||
- Yes
|
||||
- Yes
|
||||
* - Oracle 21c JSON data type (see :data:`~oracledb.DB_TYPE_JSON`)
|
||||
- No - can fetch with an output type handler, see :ref:`Fetching JSON Differences <fetchJSON>`
|
||||
- Yes
|
||||
- Yes
|
||||
* - ROWID, UROWID data types
|
||||
- Yes
|
||||
- Yes
|
||||
- Yes
|
||||
* - TIMESTAMP, TIMESTAMP WITH TIME ZONE, TIMESTAMP WITH LOCAL TIME ZONE data types
|
||||
- Yes
|
||||
- Yes
|
||||
- Yes
|
||||
* - NCHAR, NVARCHAR2, NCLOB data types
|
||||
- Yes
|
||||
- Yes
|
||||
- Yes
|
||||
* - PL/SQL data types BOOLEAN, PLS_INTEGER and BINARY_INTEGER
|
||||
- Yes
|
||||
- Yes
|
||||
- Yes
|
||||
* - XMLType data type (see :ref:`xmldatatype`)
|
||||
- Yes
|
||||
- Yes - may need to fetch as CLOB
|
||||
- Yes - may need to fetch as CLOB
|
||||
* - BFILE data type (see :data:`~oracledb.DB_TYPE_BFILE`)
|
||||
- No
|
||||
- Yes
|
||||
- Yes
|
||||
|
||||
.. _supporteddbtypes:
|
||||
|
||||
|
@ -350,133 +394,198 @@ values.
|
|||
:header-rows: 1
|
||||
:class: wy-table-responsive
|
||||
:align: center
|
||||
:summary: The first column displays the database data type. The second column displays the python-oracledb constant Name. The third column contains notes. The fourth column shows Python types that can be used.
|
||||
:summary: The first column displays the database data type. The second column displays the python-oracledb constant Name. The third column indicates if the type is supported in python-oracledb.
|
||||
|
||||
* - Oracle Database Type
|
||||
- python-oracledb Constant Name
|
||||
- Notes
|
||||
- Supported in python-oracledb
|
||||
- Supported Python Types
|
||||
* - VARCHAR2
|
||||
- :data:`~oracledb.DB_TYPE_VARCHAR`
|
||||
-
|
||||
- DB_TYPE_VARCHAR
|
||||
- Yes
|
||||
- bytes, str
|
||||
* - NVARCHAR2
|
||||
- :data:`~oracledb.DB_TYPE_NVARCHAR`
|
||||
-
|
||||
- DB_TYPE_NVARCHAR
|
||||
- Yes
|
||||
- bytes, str
|
||||
* - NUMBER, FLOAT
|
||||
- :data:`~oracledb.DB_TYPE_NUMBER`
|
||||
-
|
||||
- DB_TYPE_NUMBER
|
||||
- Yes
|
||||
- bool, int, float, decimal.Decimal
|
||||
* - DATE
|
||||
- :data:`~oracledb.DB_TYPE_DATE`
|
||||
-
|
||||
- DB_TYPE_DATE
|
||||
- Yes
|
||||
- datetime.date, datetime.datetime
|
||||
* - BOOLEAN (PL/SQL and Oracle Database 23c SQL)
|
||||
- :data:`~oracledb.DB_TYPE_BOOLEAN`
|
||||
-
|
||||
- Any type convertible to bool
|
||||
* - BOOLEAN (PL/SQL)
|
||||
- DB_TYPE_BOOLEAN
|
||||
- Yes
|
||||
- ANY (converted to bool)
|
||||
* - BINARY_DOUBLE
|
||||
- :data:`~oracledb.DB_TYPE_BINARY_DOUBLE`
|
||||
-
|
||||
- DB_TYPE_BINARY_DOUBLE
|
||||
- Yes
|
||||
- bool, int, float, decimal.Decimal
|
||||
* - BINARY_FLOAT
|
||||
- :data:`~oracledb.DB_TYPE_BINARY_FLOAT`
|
||||
-
|
||||
- DB_TYPE_BINARY_FLOAT
|
||||
- Yes
|
||||
- bool, int, float, decimal.Decimal
|
||||
* - TIMESTAMP
|
||||
- :data:`~oracledb.DB_TYPE_TIMESTAMP`
|
||||
-
|
||||
- DB_TYPE_TIMESTAMP
|
||||
- Yes
|
||||
- datetime.date, datetime.datetime
|
||||
* - TIMESTAMP WITH TIME ZONE
|
||||
- :data:`~oracledb.DB_TYPE_TIMESTAMP_TZ`
|
||||
-
|
||||
- DB_TYPE_TIMESTAMP_TZ
|
||||
- Yes
|
||||
- datetime.date, datetime.datetime
|
||||
* - TIMESTAMP WITH LOCAL TIME ZONE
|
||||
- :data:`~oracledb.DB_TYPE_TIMESTAMP_LTZ`
|
||||
-
|
||||
- DB_TYPE_TIMESTAMP_LTZ
|
||||
- Yes
|
||||
- datetime.date, datetime.datetime
|
||||
* - INTERVAL YEAR TO MONTH
|
||||
- :data:`~oracledb.DB_TYPE_INTERVAL_YM`
|
||||
- Not supported in python-oracledb.
|
||||
- Cannot be set
|
||||
- DB_TYPE_INTERVAL_YM
|
||||
- Not supported in python-oracledb
|
||||
- cannot be set
|
||||
* - INTERVAL DAY TO SECOND
|
||||
- :data:`~oracledb.DB_TYPE_INTERVAL_DS`
|
||||
-
|
||||
- DB_TYPE_INTERVAL_DS
|
||||
- Yes
|
||||
- datetime.timedelta
|
||||
* - RAW
|
||||
- :data:`~oracledb.DB_TYPE_RAW`
|
||||
-
|
||||
- DB_TYPE_RAW
|
||||
- Yes
|
||||
- bytes, str
|
||||
* - LONG
|
||||
- :data:`~oracledb.DB_TYPE_LONG`
|
||||
-
|
||||
- DB_TYPE_LONG
|
||||
- Yes
|
||||
- bytes, str
|
||||
* - LONG RAW
|
||||
- :data:`~oracledb.DB_TYPE_LONG_RAW`
|
||||
-
|
||||
- DB_TYPE_LONG_RAW
|
||||
- Yes
|
||||
- bytes, str
|
||||
* - ROWID
|
||||
- :data:`~oracledb.DB_TYPE_ROWID`
|
||||
-
|
||||
- DB_TYPE_ROWID
|
||||
- Yes
|
||||
- bytes, str
|
||||
* - UROWID
|
||||
- :data:`~oracledb.DB_TYPE_ROWID`, :data:`~oracledb.DB_TYPE_UROWID` (only supported in python-oracledb Thin mode)
|
||||
- May show :data:`~oracledb.DB_TYPE_UROWID` in metadata. See :ref:`Query Metadata Differences <querymetadatadiff>`.
|
||||
- DB_TYPE_ROWID, DB_TYPE_UROWID (only supported in python-oracledb Thin mode)
|
||||
- Yes. May show DB_TYPE_UROWID in metadata. See :ref:`Query Metadata Differences <querymetadatadiff>`.
|
||||
- bytes, str
|
||||
* - CHAR
|
||||
- :data:`~oracledb.DB_TYPE_CHAR`
|
||||
-
|
||||
- DB_TYPE_CHAR
|
||||
- Yes
|
||||
- bytes, str
|
||||
* - BLOB
|
||||
- :data:`~oracledb.DB_TYPE_BLOB`
|
||||
-
|
||||
- :ref:`oracledb.LOB <lobobj>`, bytes, str
|
||||
- DB_TYPE_BLOB
|
||||
- Yes
|
||||
- BLOB, bytes, str
|
||||
* - CLOB
|
||||
- :data:`~oracledb.DB_TYPE_CLOB`
|
||||
-
|
||||
- :ref:`oracledb.LOB <lobobj>`, bytes, str
|
||||
- DB_TYPE_CLOB
|
||||
- Yes
|
||||
- CLOB, bytes, str
|
||||
* - NCHAR
|
||||
- :data:`~oracledb.DB_TYPE_NCHAR`
|
||||
-
|
||||
- DB_TYPE_NCHAR
|
||||
- Yes
|
||||
- bytes, str
|
||||
* - NCLOB
|
||||
- :data:`~oracledb.DB_TYPE_NCLOB`, :data:`~oracledb.DB_TYPE_LONG_NVARCHAR` (if fetching NCLOB as a string)
|
||||
-
|
||||
- :ref:`oracledb.LOB <lobobj>`, bytes, str
|
||||
- DB_TYPE_NCLOB
|
||||
- Yes
|
||||
- NCLOB, bytes, str
|
||||
* - BFILE
|
||||
- :data:`~oracledb.DB_TYPE_BFILE`
|
||||
- Not supported in python-oracledb Thin mode.
|
||||
- Cannot be set
|
||||
- DB_TYPE_BFILE
|
||||
- Not supported in python-oracledb Thin mode
|
||||
- cannot be set
|
||||
* - JSON
|
||||
- :data:`~oracledb.DB_TYPE_JSON`
|
||||
-
|
||||
- Any type convertible to Oracle JSON
|
||||
- DB_TYPE_JSON
|
||||
- Yes. In python-oracledb Thin mode use an output type handler to fetch this Oracle Database 21c data type. See :ref:`jsondatatype`.
|
||||
- ANY (converted)
|
||||
* - REF CURSOR (PL/SQL OR nested cursor)
|
||||
- :data:`~oracledb.DB_TYPE_CURSOR`
|
||||
-
|
||||
- :ref:`oracledb.Cursor <cursorobj>`
|
||||
- DB_TYPE_CURSOR
|
||||
- Yes
|
||||
- CURSOR
|
||||
* - PLS_INTEGER
|
||||
- :data:`~oracledb.DB_TYPE_BINARY_INTEGER`
|
||||
-
|
||||
- DB_TYPE_BINARY_INTEGER
|
||||
- Yes
|
||||
- bool, int, float, decimal.Decimal
|
||||
* - BINARY_INTEGER
|
||||
- :data:`~oracledb.DB_TYPE_BINARY_INTEGER`
|
||||
-
|
||||
- DB_TYPE_BINARY_INTEGER
|
||||
- Yes
|
||||
- bool, int, float, decimal.Decimal
|
||||
* - REF
|
||||
- n/a
|
||||
- Not supported in python-oracledb Thin mode
|
||||
- n/a
|
||||
* - XMLType
|
||||
- :data:`~oracledb.DB_TYPE_XMLTYPE`
|
||||
- May need to use ``xmltype.getclobval()`` to fetch in python-oracledb Thick mode. See :ref:`xmldatatype`
|
||||
- bytes, str
|
||||
- n/a
|
||||
- Not supported in python-oracledb. Use ``xmltype.getclobval()`` to fetch.
|
||||
- n/a
|
||||
* - User-defined types (object type, VARRAY, records, collections, SDO_*types)
|
||||
- :data:`~oracledb.DB_TYPE_OBJECT`
|
||||
-
|
||||
- DB_TYPE_OBJECT
|
||||
- Yes
|
||||
- OBJECT of specific type
|
||||
|
||||
Binding of contiguous PL/SQL Index-by BINARY_INTEGER arrays of string, number, and date are
|
||||
supported in python-oracledb Thin and Thick modes. Use :meth:`Cursor.arrayvar()` to build
|
||||
these arrays.
|
||||
|
||||
|
||||
.. Python Types supported for each Oracle Database Type are shown below... list-table-with-summary:: Oracle Database Types Supported
|
||||
:header-rows: 1
|
||||
:align: center
|
||||
:summary: The first column displays the Oracle Database type. The second column displays the Python types that are supported for each of the database types.
|
||||
|
||||
* - Oracle Database Type
|
||||
- Python Types supported
|
||||
* - DB_TYPE_BFILE
|
||||
- cannot be set
|
||||
* - DB_TYPE_BINARY_DOUBLE
|
||||
- bool, int, float, decimal.Decimal
|
||||
* - DB_TYPE_BINARY_FLOAT
|
||||
- bool, int, float, decimal.Decimal
|
||||
* - DB_TYPE_BINARY_INTEGER
|
||||
- bool, int, float, decimal.Decimal
|
||||
* - DB_TYPE_BLOB
|
||||
- BLOB, bytes, str
|
||||
* - DB_TYPE_BOOLEAN
|
||||
- ANY (converted to bool)
|
||||
* - DB_TYPE_CHAR
|
||||
- bytes, str
|
||||
* - DB_TYPE_CLOB
|
||||
- CLOB, bytes, str
|
||||
* - DB_TYPE_CURSOR
|
||||
- CURSOR
|
||||
* - DB_TYPE_DATE
|
||||
- datetime.date, datetime.datetime
|
||||
* - DB_TYPE_INTERVAL_DS
|
||||
- datetime.timedelta
|
||||
* - DB_TYPE_INTERVAL_YM
|
||||
- cannot be set
|
||||
* - DB_TYPE_JSON
|
||||
- ANY (converted)
|
||||
* - DB_TYPE_LONG
|
||||
- bytes, str
|
||||
* - DB_TYPE_LONG_NVARCHAR
|
||||
- bytes, str
|
||||
* - DB_TYPE_LONG_RAW
|
||||
- bytes, str
|
||||
* - DB_TYPE_NCHAR
|
||||
- bytes, str
|
||||
* - DB_TYPE_NCLOB
|
||||
- NCLOB, bytes, str
|
||||
* - DB_TYPE_NUMBER
|
||||
- bool, int, float, decimal.Decimal
|
||||
* - DB_TYPE_NVARCHAR
|
||||
- bytes, str
|
||||
* - DB_TYPE_OBJECT
|
||||
- OBJECT of specific type
|
||||
* - DB_TYPE_RAW
|
||||
- bytes, str
|
||||
* - DB_TYPE_ROWID
|
||||
- bytes, str
|
||||
* - DB_TYPE_TIMESTAMP
|
||||
- datetime.date, datetime.datetime
|
||||
* - DB_TYPE_TIMESTAMP_LTZ
|
||||
- datetime.date, datetime.datetime
|
||||
* - DB_TYPE_TIMESTAMP_TZ
|
||||
- datetime.date, datetime.datetime
|
||||
* - DB_TYPE_UROWID
|
||||
- bytes, str
|
||||
* - DB_TYPE_VARCHAR
|
||||
- bytes, str
|
||||
|
|
|
@ -152,7 +152,7 @@ In python-oracledb Thin mode, using the ``POOL_CONNECTION_CLASS`` or
|
|||
equivalent attributes when creating a connection or connection pool.
|
||||
|
||||
In python-oracledb Thick mode, the ``POOL_CONNECTION_CLASS`` or ``POOL_PURITY``
|
||||
values will only work when connected to Oracle Database 21c, or later. Note if
|
||||
values will only work when connected to Oracle Database 21c. Note if
|
||||
``POOL_PURITY=SELF`` is used in a connect string, then python-oracledb Thick
|
||||
mode applications will ignore the action to drop the session when attempting to
|
||||
remove an unusable connections from a pool in some uncommon error cases. It is
|
||||
|
@ -164,6 +164,11 @@ attributes.
|
|||
The ``ENABLE=BROKEN`` connect descriptor option is not supported in
|
||||
python-oracledb Thin mode. Use ``expire_time`` instead.
|
||||
|
||||
The ``Session Data Unit (SDU)`` connect descriptor option that is used to tune
|
||||
network transfers is not supported in python-oracledb Thin mode. The value is
|
||||
hard-coded as 8 KB. In python-oracledb Thick mode, the SDU connect descriptor
|
||||
option and equivalent ``sqlnet.ora`` setting are used.
|
||||
|
||||
If a name is given as a connect string, then the python-oracledb Thin mode will
|
||||
consider it as a Net Service Name and not as the minimal Easy Connect string of
|
||||
a hostname. The given connect string will be looked up in a ``tnsnames.ora``
|
||||
|
@ -212,11 +217,7 @@ See :ref:`enablingthick`.
|
|||
For example, if you use python-oracledb Thin mode and try to connect to the
|
||||
Oracle Cloud Infrastructure (OCI) Oracle Base Database where by default native
|
||||
network encryption is set to REQUIRED in the ``sqlnet.ora`` file of the OCI
|
||||
Oracle Base Database server, the connection will fail with an error like::
|
||||
|
||||
DPY-4011: the database or network closed the connection
|
||||
|
||||
or::
|
||||
Oracle Base Database server, the connection will fail with the error::
|
||||
|
||||
DPY-6000: cannot connect to database. Listener refused connection.
|
||||
(Similar to ORA-12660)
|
||||
|
@ -316,6 +317,15 @@ not supported in the Oracle Client libraries that are used in python-oracledb
|
|||
Thick mode. Note changing the type of bind variables for the same SQL text is
|
||||
inappropriate and gives indeterminate results in both modes.
|
||||
|
||||
.. _fetchJSON:
|
||||
|
||||
Fetching JSON in Thin and Thick Modes
|
||||
=====================================
|
||||
|
||||
The python-oracledb Thin mode does not natively handle the Oracle Database 21c
|
||||
JSON data type but a type handler can be used when fetching the type, see
|
||||
:ref:`jsondatatype`.
|
||||
|
||||
Error Handling in Thin and Thick Modes
|
||||
======================================
|
||||
|
||||
|
@ -325,8 +335,9 @@ The python-oracledb Thin and Thick modes handle some errors differently. See
|
|||
Globalization in Thin and Thick Modes
|
||||
=====================================
|
||||
|
||||
All NLS environment variables, and the ``ORA_TZFILE`` environment variable, are
|
||||
ignored by the python-oracledb Thin mode. Use Python's capabilities instead.
|
||||
All NLS environment variables, and the ``ORA_SDTZ`` and ``ORA_TZFILE``
|
||||
environment variables, are ignored by the python-oracledb Thin mode. Use
|
||||
Python's capabilities instead.
|
||||
|
||||
The python-oracledb Thin mode can only use NCHAR, NVARCHAR2, and NCLOB data
|
||||
when Oracle Database's secondary character set is AL16UTF16.
|
||||
|
|
|
@ -89,7 +89,7 @@ from cx_Oracle:
|
|||
can be used to encapsulate connection properties. See :ref:`usingconnparams`
|
||||
for more information.
|
||||
|
||||
- The following parameters are desupported:
|
||||
- The following parameters are deprecated and ignored:
|
||||
|
||||
- ``encoding`` and ``nencoding``: The encodings in use are always UTF-8.
|
||||
|
||||
|
@ -348,9 +348,8 @@ to python-oracledb:
|
|||
See :ref:`Features Supported <featuresummary>` for details.
|
||||
|
||||
- python-oracledb can be used in SQLAlchemy, Django, Pandas, and other
|
||||
frameworks and Object-relational Mappers (ORMs). To use python-oracledb in
|
||||
versions of these libraries that don't have native support for the new name,
|
||||
you can override the use of cx_Oracle with a few lines of code. See
|
||||
frameworks and Object-relational Mappers (ORMs). Until they add native
|
||||
support, you can override the use of cx_Oracle with a few lines of code. See
|
||||
:ref:`frameworks`.
|
||||
|
||||
- python-oracledb connection and pool creation calls require keyword arguments
|
||||
|
@ -368,8 +367,8 @@ to python-oracledb:
|
|||
oracledb.connect("scott", pw, "localhost/orclpdb")
|
||||
|
||||
- The python-oracledb Thin mode ignores all NLS environment variables. It also
|
||||
ignores the ``ORA_TZFILE`` environment variable. Thick mode does use these
|
||||
variables. See :ref:`globalization` for alternatives.
|
||||
ignores ``ORA_SDTZ`` and ``ORA_TZFILE`` environment variables. Thick mode does use
|
||||
these variables. See :ref:`globalization` for alternatives.
|
||||
|
||||
- To use a ``tnsnames.ora`` file in the python-oracledb Thin mode, you must
|
||||
explicitly set the environment variable ``TNS_ADMIN`` to the directory
|
||||
|
@ -485,15 +484,15 @@ following steps:
|
|||
|
||||
6. The default value of the ``oracledb.SessionPool()`` parameter
|
||||
:attr:`~Connection.getmode` now waits for an available connection. That is the
|
||||
default is now :data:`~oracledb.POOL_GETMODE_WAIT` instead of
|
||||
:data:`~oracledb.POOL_GETMODE_NOWAIT`. The new default value improves the
|
||||
default is now :data:`~oracledb.SPOOL_ATTRVAL_WAIT` instead of
|
||||
:data:`~oracledb.SPOOL_ATTRVAL_NOWAIT`. The new default value improves the
|
||||
behavior for most applications. If the pool is in the middle of growing, the
|
||||
new value prevents transient connection creation errors from occurring when
|
||||
using the Thin mode, or when using the Thick mode with recent Oracle
|
||||
Client libraries.
|
||||
|
||||
If the old default value is required, modify any pool creation code to
|
||||
explicitly specify ``getmode=oracledb.POOL_GETMODE_NOWAIT``.
|
||||
explicitly specify ``getmode=oracledb.POOL_SPOOL_ATTRVAL_NOWAIT``.
|
||||
|
||||
Note a :ref:`ConnectionPool class <connpool>` deprecates the equivalent
|
||||
SessionPool class. The method :meth:`oracledb.create_pool()` deprecates the
|
||||
|
@ -517,7 +516,7 @@ following steps:
|
|||
the code.
|
||||
|
||||
9. Modernize code as needed or desired. See :ref:`deprecations` for the list
|
||||
of deprecations in python-oracledb.
|
||||
of deprecations in python-oracledb 1.0.
|
||||
|
||||
Additional Upgrade Steps to use python-oracledb Thin Mode
|
||||
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
@ -559,7 +558,8 @@ addition to the common :ref:`commonupgrade`:
|
|||
this behavior is also similar in recent versions of the Oracle Call
|
||||
Interface (OCI) Session Pool used by the Thick mode. Unless the
|
||||
``oracledb.SessionPool()`` function's parameter ``getmode`` is
|
||||
:data:`oracledb.POOL_GETMODE_WAIT`, then applications should not call
|
||||
``SPOOL_ATTRVAL_WAIT`` (or the new equivalent
|
||||
:data:`oracledb.POOL_GETMODE_WAIT`), then applications should not call
|
||||
:meth:`ConnectionPool.acquire()` until sufficient time has passed for
|
||||
connections in the pool to be created.
|
||||
|
||||
|
@ -676,9 +676,9 @@ Python Frameworks, SQL Generators, and ORMs
|
|||
The python-oracledb Thin mode features in the python-oracledb cover the needs
|
||||
of frameworks that depend upon the Python Database API.
|
||||
|
||||
For versions of SQLAlchemy, Django, other frameworks, object-relational mappers
|
||||
(ORMs), and libraries that don't have native support for python-oracledb, you
|
||||
can add temporary code like this to use python-oracledb in-place of cx_Oracle:
|
||||
Until SQLAlchemy, Django, other frameworks, object-relational mappers (ORMs),
|
||||
and libraries add native support for python-oracledb, you can add temporary
|
||||
code like this to use python-oracledb in-place of cx_Oracle:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
@ -692,7 +692,3 @@ can add temporary code like this to use python-oracledb in-place of cx_Oracle:
|
|||
|
||||
The import of cx_Oracle occurs last. This code must be run before the
|
||||
library code does its own import of cx_Oracle.
|
||||
|
||||
|
||||
SQLAlchemy 2 and Django 5 have native support for python-oracledb so this code
|
||||
snippet is not needed in those versions.
|
||||
|
|
|
@ -1,292 +0,0 @@
|
|||
.. _asyncio:
|
||||
|
||||
***********************************
|
||||
Concurrent Programming with asyncio
|
||||
***********************************
|
||||
|
||||
The `Asynchronous I/O (asyncio) <https://docs.python.org/3/library/asyncio.
|
||||
html>`__ Python library can be used with python-oracledb Thin mode for
|
||||
concurrent programming. This library allows you to run operations in parallel,
|
||||
for example to run a long-running operation in the background without blocking
|
||||
the rest of the application. With asyncio, you can easily write concurrent code
|
||||
with the ``async`` and ``await`` syntax. See Python's `Developing with asyncio
|
||||
<https://docs.python.org/3/library/asyncio-dev.html>`__ documentation for
|
||||
useful tips.
|
||||
|
||||
.. note::
|
||||
|
||||
The asyncio support in python-oracledb 2.0.0 is a pre-release and may
|
||||
change in the next version.
|
||||
|
||||
The python-oracledb asynchronous API is a part of the standard python-oracledb
|
||||
module. All the synchronous methods that require a round-trip to the database
|
||||
now have corresponding asynchronous counterparts. You can choose whether to
|
||||
use the synchronous API or the asynchronous API in your code. It is
|
||||
recommended to *not* use both at the same time in your application.
|
||||
|
||||
The asynchronous API classes are :ref:`AsyncConnection <asyncconnobj>`,
|
||||
:ref:`AsyncConnectionPool <asyncconnpool>`,
|
||||
:ref:`AsyncCursor <asynccursorobj>`, and :ref:`AsyncLOB <asynclobobj>`.
|
||||
|
||||
.. note::
|
||||
|
||||
Concurrent programming with asyncio is only supported in the
|
||||
python-oracledb Thin mode.
|
||||
|
||||
.. _connasync:
|
||||
|
||||
Connecting to Oracle Database Asynchronously
|
||||
============================================
|
||||
|
||||
With python-oracledb, you can create an asynchronous connection to Oracle
|
||||
Database using either :ref:`standalone connections <asyncstandalone>` or
|
||||
:ref:`pooled connections <asyncconnpool>`. (For discussion of synchronous
|
||||
programming, see :ref:`connhandling`.)
|
||||
|
||||
.. _asyncstandalone:
|
||||
|
||||
Standalone Connections
|
||||
----------------------
|
||||
|
||||
Standalone connections are useful for applications that need only a single
|
||||
connection to a database.
|
||||
|
||||
An asynchronous standalone connection can be created by calling the
|
||||
asynchronous method :meth:`oracledb.connect_async()` which establishes a
|
||||
connection to the database and returns an :ref:`AsyncConnection Object
|
||||
<asyncconnobj>`. Once connections are created, all objects created by these
|
||||
connections follow the asynchronous programming model. Subject to appropriate
|
||||
use of ``await`` for calls that require a round-trip to the database,
|
||||
asynchronous connections are used in the same way that synchronous programs use
|
||||
:ref:`standaloneconnection`.
|
||||
|
||||
Asynchronous connections should be released when they are no longer needed to
|
||||
ensure Oracle Database gracefully cleans up. A preferred method is to use an
|
||||
asynchronous context manager. For example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import asyncio
|
||||
import oracledb
|
||||
|
||||
async def main():
|
||||
|
||||
async with oracledb.connect_async(user="hr", password=userpwd,
|
||||
dsn="localhost/orclpdb") as connection:
|
||||
with connection.cursor() as cursor:
|
||||
await cursor.execute("select user from dual")
|
||||
async for result in cursor:
|
||||
print(result)
|
||||
|
||||
asyncio.run(main())
|
||||
|
||||
This code ensures that once the block is completed, the connection is closed
|
||||
and resources are reclaimed by the database. In addition, any attempt to use
|
||||
the variable ``connection`` outside of the block will fail.
|
||||
|
||||
If you do not use a context manager, you should explicitly close connections
|
||||
when they are no longer needed, for example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
connection = await oracle.connect_async(user="hr", password=userpwd,
|
||||
dsn="localhost/orclpdb")
|
||||
|
||||
cursor = connection.cursor()
|
||||
|
||||
await cursor.execute("select user from dual")
|
||||
async for result in cursor:
|
||||
print(result)
|
||||
|
||||
cursor.close()
|
||||
await connection.close()
|
||||
|
||||
|
||||
.. _asyncconnpool:
|
||||
|
||||
Connection Pools
|
||||
----------------
|
||||
|
||||
Connection pooling allows applications to create and maintain a pool of open
|
||||
connections to the database. Connection pooling is important for performance
|
||||
and scalability when applications need to handle a large number of users who do
|
||||
database work for short periods of time but have relatively long periods when
|
||||
the connections are not needed. The high availability features of pools also
|
||||
make small pools useful for applications that want a few connections available
|
||||
for infrequent use and requires them to be immediately usable when acquired.
|
||||
|
||||
An asynchronous connection pool can be created by calling
|
||||
:meth:`oracledb.create_pool_async()` which returns an :ref:`AsyncConnectionPool
|
||||
Object <asyncconnpoolobj>`. Note that this method is *synchronous* and does not
|
||||
use ``await``. Once the pool has been created, your application can get a
|
||||
connection from it by calling :meth:`AsyncConnectionPool.acquire()`. After
|
||||
your application has used a connection, it should be released back to the pool
|
||||
to make it available for other users. This can be done by explicitly closing
|
||||
the connection or by using an asynchronous context manager, for example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import asyncio
|
||||
import oracledb
|
||||
|
||||
async def main():
|
||||
|
||||
pool = oracle.create_pool_async(user="hr", password=userpwd,
|
||||
dsn="localhost/orclpdb",
|
||||
min=1, max=4, increment=1)
|
||||
|
||||
async with pool.acquire() as connection:
|
||||
with connection.cursor() as cursor:
|
||||
await cursor.execute("select user from dual")
|
||||
async for result in cursor:
|
||||
print(result)
|
||||
|
||||
await pool.close()
|
||||
|
||||
asyncio.run(main())
|
||||
|
||||
|
||||
.. _sqlexecuteasync:
|
||||
|
||||
Executing SQL Using Asynchronous Methods
|
||||
========================================
|
||||
|
||||
This section covers executing SQL using the asynchronous programming model.
|
||||
For discussion of synchronous programming, see :ref:`sqlexecution`.
|
||||
|
||||
Your application communicates with Oracle Database by executing SQL
|
||||
statements. Statements such as queries (statements beginning with SELECT or
|
||||
WITH), Data Manipulation Language (DML), and Data Definition Language (DDL) are
|
||||
executed using the asynchronous methods :meth:`AsyncCursor.execute()` or
|
||||
:meth:`AsyncCursor.executemany()`. Rows can be iterated over, or fetched using
|
||||
one of the methods :meth:`AsyncCursor.fetchone()`,
|
||||
:meth:`AsyncCursor.fetchone()`, :meth:`AsyncCursor.fetchmany()`, or
|
||||
:meth:`AsyncCursor.fetchall()`.
|
||||
|
||||
You can also use shortcut methods on the :ref:`asyncconnobj` object such as
|
||||
:meth:`AsyncConnection.execute()` or
|
||||
:meth:`AsyncConnection.executemany()`. Rows can be fetched using one of the
|
||||
shortcut methods :meth:`AsyncConnection.fetchone()`,
|
||||
:meth:`AsyncConnection.fetchmany()`, or :meth:`AsyncConnection.fetchall()`.
|
||||
|
||||
An example of using :meth:`AsyncConnection.fetchall()`:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import asyncio
|
||||
import oracledb
|
||||
|
||||
async def main():
|
||||
|
||||
async with oracledb.connect_async(user="hr", password=userpwd,
|
||||
dsn="localhost/orclpdb") as connection:
|
||||
res = await connection.fetchall("select * from locations")
|
||||
print(res)
|
||||
|
||||
asyncio.run(main())
|
||||
|
||||
An example that uses asyncio for parallelization and shows the execution of
|
||||
multiple coroutines:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import asyncio
|
||||
import oracledb
|
||||
|
||||
# Number of coroutines to run
|
||||
CONCURRENCY = 5
|
||||
|
||||
# Query the unique session identifier/serial number combination of a connection
|
||||
SQL = """SELECT UNIQUE CURRENT_TIMESTAMP AS CT, sid||'-'||serial# AS SIDSER
|
||||
FROM v$session_connect_info
|
||||
WHERE sid = SYS_CONTEXT('USERENV', 'SID')"""
|
||||
|
||||
# Show the unique session identifier/serial number of each connection that the
|
||||
# pool opens
|
||||
async def init_session(connection, requested_tag):
|
||||
res = await connection.fetchone(SQL)
|
||||
print(res[0].strftime("%H:%M:%S.%f"), '- init_session with SID-SERIAL#', res[1])
|
||||
|
||||
# The coroutine simply shows the session identifier/serial number of the
|
||||
# connection returned by the pool.acquire() call
|
||||
async def query(pool):
|
||||
async with pool.acquire() as connection:
|
||||
await connection.callproc("dbms_session.sleep", [1])
|
||||
res = await connection.fetchone(SQL)
|
||||
print(res[0].strftime("%H:%M:%S.%f"), '- query with SID-SERIAL#', res[1])
|
||||
|
||||
async def main():
|
||||
|
||||
pool = oracledb.create_pool_async(user="hr", password=userpwd,
|
||||
dsn="localhost/orclpdb",
|
||||
min=1, max=CONCURRENCY,
|
||||
session_callback=init_session)
|
||||
|
||||
coroutines = [ query(pool) for i in range(CONCURRENCY) ]
|
||||
|
||||
await asyncio.gather(*coroutines)
|
||||
|
||||
await pool.close()
|
||||
|
||||
asyncio.run(main())
|
||||
|
||||
When you run this, you will see that multiple connections (identified by the
|
||||
unique Session Identifier and Serial Number combination) are opened and are
|
||||
used by ``query()``. For example::
|
||||
|
||||
12:09:29.711525 - init_session with SID-SERIAL# 36-38096
|
||||
12:09:29.909769 - init_session with SID-SERIAL# 33-56225
|
||||
12:09:30.085537 - init_session with SID-SERIAL# 14-31431
|
||||
12:09:30.257232 - init_session with SID-SERIAL# 285-40270
|
||||
12:09:30.434538 - init_session with SID-SERIAL# 282-32608
|
||||
12:09:30.730166 - query with SID-SERIAL# 36-38096
|
||||
12:09:30.933957 - query with SID-SERIAL# 33-56225
|
||||
12:09:31.115008 - query with SID-SERIAL# 14-31431
|
||||
12:09:31.283593 - query with SID-SERIAL# 285-40270
|
||||
12:09:31.457474 - query with SID-SERIAL# 282-32608
|
||||
|
||||
Your results may vary depending how fast your environment is.
|
||||
|
||||
See `async_gather.py <https://github.com/oracle/python-oracledb/tree/main/
|
||||
samples/async_gather.py>`__ for a runnable example.
|
||||
|
||||
.. _txnasync:
|
||||
|
||||
Managing Transactions Using Asynchronous Methods
|
||||
================================================
|
||||
|
||||
This section covers managing transactions using the asynchronous programming
|
||||
model. For discussion of synchronous programming, see :ref:`txnmgmnt`.
|
||||
|
||||
When :meth:`AsyncCursor.execute()` or :meth:`AsyncCursor.executemany()`
|
||||
executes a SQL statement, a transaction is started or continued. By default,
|
||||
python-oracledb does not commit this transaction to the database. The methods
|
||||
:meth:`AsyncConnection.commit()` and :meth:`AsyncConnection.rollback()`
|
||||
methods can be used to explicitly commit or rollback a transaction:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
async def main():
|
||||
async with oracledb.connect_async(user="hr", password=userpwd,
|
||||
dsn="localhost/orclpdb") as connection:
|
||||
|
||||
with connection.cursor as cursor:
|
||||
await cursor.execute("INSERT INTO mytab (name) VALUES ('John')")
|
||||
await connection.commit()
|
||||
|
||||
When a database connection is closed, such as with
|
||||
:meth:`AsyncConnection.close()`, or when variables referencing the connection
|
||||
go out of scope, any uncommitted transaction will be rolled back.
|
||||
|
||||
An alternative way to commit is to set the attribute
|
||||
:attr:`AsyncConnection.autocommit` of the connection to ``True``. This
|
||||
ensures all :ref:`DML <dml>` statements (INSERT, UPDATE, and so on) are
|
||||
committed as they are executed.
|
||||
|
||||
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.
|
|
@ -102,11 +102,6 @@ since numeric data is already stored efficiently. Since python-oracledb
|
|||
allocates memory for each row based on the supplied values, do not oversize
|
||||
them.
|
||||
|
||||
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.
|
||||
|
||||
Batch Execution of PL/SQL
|
||||
=========================
|
||||
|
||||
|
@ -311,42 +306,3 @@ be beneficial.
|
|||
|
||||
See `load_csv.py <https://github.com/oracle/python-oracledb/tree/main/
|
||||
samples/load_csv.py>`__ for a runnable example.
|
||||
|
||||
|
||||
Copying Data between Databases
|
||||
==============================
|
||||
|
||||
The :meth:`Cursor.executemany()` function is useful for efficiently copying
|
||||
data from one database to another:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# Connect to both databases
|
||||
source_connection = oracledb.connect(user=un1, password=pw1, dsn=cs1)
|
||||
target_connection = oracledb.connect(user=un2, password=pw2, dsn=cs2)
|
||||
|
||||
# Setup cursors
|
||||
source_cursor = source_connection.cursor()
|
||||
source_cursor.arraysize = 1000 # tune this for query performance
|
||||
|
||||
target_cursor = target_connection.cursor()
|
||||
target_cursor.setinputsizes(None, 25) # set according to column types
|
||||
|
||||
# Perform bulk fetch and insertion
|
||||
source_cursor.execute("select c1, c2 from MySrcTable")
|
||||
while True:
|
||||
rows = source_cursor.fetchmany()
|
||||
if not rows:
|
||||
break
|
||||
target_cursor.executemany("insert into MyDestTable values (:1, :2)", rows)
|
||||
|
||||
target_connection.commit()
|
||||
|
||||
Tune the :attr:`~Cursor.arraysize` value according to notes in
|
||||
:ref:`tuningfetch`. Use ``setinputsizes()`` according to `Predefining Memory
|
||||
Areas`_.
|
||||
|
||||
Note that it may be preferable to create a `database link
|
||||
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-D966642A-B19E-449D-9968-1121AF06D793>`__
|
||||
between the databases and use an INSERT INTO SELECT statement so that data is
|
||||
not copied to, and back from, the Python process.
|
||||
|
|
|
@ -6,124 +6,71 @@ Using Bind Variables
|
|||
|
||||
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. A bind variable placeholder is a colon-prefixed identifier or
|
||||
numeral. For example, ``:dept_id`` and ``:dept_name`` are the two bind variable
|
||||
placeholders in this SQL statement:
|
||||
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)"""
|
||||
values (:dept_id, :dept_name)"""
|
||||
cursor.execute(sql, [280, "Facility"])
|
||||
|
||||
As part of execution, the supplied bind variable values ``280`` and
|
||||
``"Facility"`` are substituted for the placeholders by the database. This is
|
||||
called binding.
|
||||
|
||||
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 when it is parsed.
|
||||
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.
|
||||
|
||||
.. note::
|
||||
|
||||
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)
|
||||
|
||||
This is a security risk and can impact performance and scalability.
|
||||
|
||||
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
|
||||
placeholder where a column name or a table name is required. Bind variable
|
||||
placeholders also cannot be used in Data Definition Language (DDL) statements,
|
||||
such as CREATE TABLE or ALTER statements.
|
||||
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".
|
||||
|
||||
Bind by Name
|
||||
------------
|
||||
|
||||
A named bind is performed when the bind variables in the Python statement use
|
||||
the names of placeholders in the SQL or PL/SQL statement. For example:
|
||||
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:
|
||||
|
||||
.. code-block:: python
|
||||
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 examples, the keyword parameter names or the keys of the
|
||||
dictionary must match the bind variable placeholder names.
|
||||
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.
|
||||
|
||||
The advantages of named binding are that the order of the bind values in the
|
||||
``execute()`` parameter is not important, the names can be meaningful, and the
|
||||
placeholder names can be repeated while still only supplying the value once in
|
||||
the application.
|
||||
|
||||
An example of reusing a bind variable placeholder is:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
cursor.execute("""
|
||||
update departments set department_id = :dept_id + 10
|
||||
where department_id = :dept_id""",
|
||||
dept_id=280)
|
||||
|
||||
|
||||
Bind by Position
|
||||
----------------
|
||||
|
||||
Positional binding occurs when a list or tuple of bind values is passed to the
|
||||
``execute()`` call. For example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
cursor.execute("""
|
||||
insert into departments (department_id, department_name)
|
||||
values (:1, :2)""", [280, "Facility"])
|
||||
|
||||
The following example (which changes the order of the bind placeholder names)
|
||||
has exactly the same behavior. The value used to substitute the placeholder
|
||||
":2" will be the first element of the list and ":1" will be replaced by the
|
||||
second element. Bind by position works from left to right and pays no
|
||||
attention to the name of the bind variable:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
cursor.execute("""
|
||||
insert into departments (department_id, department_name)
|
||||
values (:2, :1)""", [280, "Facility"])
|
||||
|
||||
The following example is also bind by position despite the bind placeholders
|
||||
having alphabetic names. The actual process of binding uses the list positions
|
||||
of the input data to associate the data with the placeholder locations:
|
||||
A positional bind is performed when a list of bind values are passed to the
|
||||
execute() call. For example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
@ -131,25 +78,12 @@ of the input data to associate the data with the placeholder locations:
|
|||
insert into departments (department_id, department_name)
|
||||
values (:dept_id, :dept_name)""", [280, "Facility"])
|
||||
|
||||
|
||||
Python tuples can also be used for binding by position:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
cursor.execute("""
|
||||
insert into departments (department_id, department_name)
|
||||
values (:1, :2)""", (280, "Facility"))
|
||||
|
||||
If only a single bind placeholder is used in the SQL or PL/SQL statement, the
|
||||
data can be a list like ``[280]`` or a single element tuple like ``(280,)``.
|
||||
|
||||
When using bind by position 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.
|
||||
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
|
||||
|
@ -794,12 +728,11 @@ variable. For example, to use two values in an IN clause:
|
|||
|
||||
.. code-block:: python
|
||||
|
||||
items = ["Smith", "Taylor"]
|
||||
cursor.execute("""
|
||||
select employee_id, first_name, last_name
|
||||
from employees
|
||||
where last_name in (:1, :2)""",
|
||||
items)
|
||||
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)
|
||||
|
||||
|
@ -818,12 +751,11 @@ used for up to 5 values, the code will be:
|
|||
|
||||
.. code-block:: python
|
||||
|
||||
items = ["Smith", "Taylor", None, None, None]
|
||||
cursor.execute("""
|
||||
select employee_id, first_name, last_name
|
||||
from employees
|
||||
where last_name in (:1, :2, :3, :4, :5)""",
|
||||
items)
|
||||
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)
|
||||
|
||||
|
@ -832,55 +764,31 @@ statement like this for a variable number of values, instead of constructing a
|
|||
unique statement per set of values, allows best reuse of Oracle Database
|
||||
resources.
|
||||
|
||||
If other bind variables are required in the statement, adjust the bind variable
|
||||
placeholder numbers:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
items = ["Smith", "Taylor", None, None, None]
|
||||
binds = [120] + items
|
||||
cursor.execute("""
|
||||
select employee_id, first_name, last_name
|
||||
from employees
|
||||
where employee_id > :1
|
||||
and last_name in (:2, :3, :4, :5, :6)""",
|
||||
binds)
|
||||
for row in cursor:
|
||||
print(row)
|
||||
|
||||
If a statement containing WHERE IN 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:
|
||||
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 = ",".join(":" + str(i + 1) for i in range(len(bind_values)))
|
||||
sql = f"select first_name, last_name from employees where last_name in ({bind_names})"
|
||||
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)
|
||||
|
||||
To exceed the IN clause value limit, you can add OR clauses like:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
sql = """select . . .
|
||||
where key in (:0,:1,:2,:3,:4,:5,:6,:7,:8,:9,:10,:11,...)
|
||||
or key in (:50,:51,:52,:53,:54,:55,:56,:57,:58,:59,...)
|
||||
or key in (:100,:101,:102,:103,:104,:105,:106,:107,:108,:109,...)"""
|
||||
|
||||
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>' depends on
|
||||
how the data is initially represented and the number of items. For example you
|
||||
might look at using a global temporary table.
|
||||
The best way to do the '<something that returns a list of values>' depends
|
||||
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 for up to 32K values is to use an Oracle collection with the
|
||||
``TABLE()`` clause. For example, if the following type was created::
|
||||
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 /
|
||||
|
@ -899,9 +807,8 @@ then the application could do:
|
|||
for row in cursor:
|
||||
print(row)
|
||||
|
||||
For efficiency, retain the return value of ``gettype()`` for reuse where
|
||||
possible instead of making repeated calls to get the type information.
|
||||
|
||||
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
|
||||
==============================
|
||||
|
@ -925,15 +832,12 @@ ORDER BY clause:
|
|||
.. code-block:: python
|
||||
|
||||
sql = """
|
||||
select *
|
||||
from departments
|
||||
order by
|
||||
case :bindvar
|
||||
when 'DEPARTMENT_ID' then
|
||||
department_id
|
||||
else
|
||||
manager_id
|
||||
end"""
|
||||
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])
|
||||
|
|
|
@ -16,9 +16,6 @@ Oracle Client libraries are used. See :ref:`enablingthick`. Both modes have
|
|||
comprehensive functionality supporting the Python Database API v2.0
|
||||
Specification.
|
||||
|
||||
This chapter covers python-oracledb's synchronous programming model. For
|
||||
discussion of asynchronous programming, see :ref:`asyncio`.
|
||||
|
||||
If you intend to use the Thick mode, then you *must* call
|
||||
:func:`~oracledb.init_oracle_client()` in the application before any standalone
|
||||
connection or pool is created. The python-oracledb Thick mode loads Oracle
|
||||
|
@ -507,7 +504,7 @@ attributes. For example, to get the stored host name:
|
|||
|
||||
Attributes such as the password are not gettable.
|
||||
|
||||
You can set individual default attributes using :meth:`ConnectParams.set()`:
|
||||
You can set individual attributes using :meth:`ConnectParams.set()`:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
@ -519,9 +516,6 @@ You can set individual default attributes using :meth:`ConnectParams.set()`:
|
|||
# change both the port and service name
|
||||
cp.set(port=1523, service_name="orclpdb")
|
||||
|
||||
Note :meth:`ConnectParams.set()` has no effect after
|
||||
:meth:`ConnectParams.parse_connect_string()` has been called.
|
||||
|
||||
Some values such as the database host name can be specified as
|
||||
:func:`oracledb.connect()`, parameters, as part of the connect string, and in
|
||||
the ``params`` object. If a ``dsn`` is passed, the python-oracledb :ref:`Thick
|
||||
|
@ -534,21 +528,6 @@ that values in any ``dsn`` parameter override values passed as individual
|
|||
parameters, which themselves override values set in the ``params`` object.
|
||||
Similar precedence rules also apply to other values.
|
||||
|
||||
The :meth:`ConnectParams.parse_dsn_with_credentials()` can be used to extract
|
||||
the username, password and connection string from a DSN:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
cp = oracledb.ConnectParams()
|
||||
(un,pw,cs) = cp.parse_dsn_with_credentials("scott/tiger@localhost/orclpdb")
|
||||
|
||||
Empty values are returned as ``None``.
|
||||
|
||||
When creating a standalone connection or connection pool the equivalent
|
||||
internal extraction is done automatically when a value is passed to the ``dsn``
|
||||
parameter of :meth:`oracledb.connect()` or :meth:`oracledb.create_pool()` but
|
||||
no value is passed to the ``user`` password.
|
||||
|
||||
.. _connpooling:
|
||||
|
||||
Connection Pooling
|
||||
|
@ -685,18 +664,14 @@ initiates pool growth will return after the first new connection is created,
|
|||
regardless of how big ``increment`` is. The pool will then continue to
|
||||
re-establish connections in a background thread.
|
||||
|
||||
A connection pool can shrink back to its minimum size ``min`` when connections
|
||||
opened by the pool are not used by the application. This frees up database
|
||||
resources while allowing pools to retain connections for active users. If
|
||||
connections are idle in the pool (i.e. not currently acquired by the
|
||||
application) and are unused for longer than the pool creation attribute
|
||||
``timeout`` value, then they will be closed. The check occurs every
|
||||
``timeout`` interval and hence in the worst case it may take twice the
|
||||
``timeout`` time to close the idle connections. The default ``timeout`` is 0
|
||||
seconds signifying an infinite time and meaning idle connections will never be
|
||||
closed.
|
||||
|
||||
In python-oracledb Thick mode, the pool creation parameter
|
||||
A connection pool can shrink back to its minimum size when connections opened
|
||||
by the pool are not used by the application. This frees up database resources
|
||||
while allowing pools to retain connections for active users. Note this is
|
||||
currently applicable to Thick mode only. If connections are idle in the pool
|
||||
(i.e. not currently acquired by the application) and are unused for longer than
|
||||
the pool creation attribute ``timeout`` value , then they will be closed. The
|
||||
default ``timeout`` is 0 seconds signifying an infinite time and meaning idle
|
||||
connections will never be closed. The pool creation parameter
|
||||
``max_lifetime_session`` also allows pools to shrink. This parameter bounds
|
||||
the total length of time that a connection can exist starting from the time the
|
||||
pool created it. If a connection was created ``max_lifetime_session`` or
|
||||
|
@ -827,7 +802,7 @@ can be set directly, for example:
|
|||
|
||||
.. _sessioncallback:
|
||||
|
||||
Session Callbacks for Setting Pooled Connection State
|
||||
Session CallBacks for Setting Pooled Connection State
|
||||
-----------------------------------------------------
|
||||
|
||||
Applications can set "session" state in each connection. Examples of session
|
||||
|
@ -1222,44 +1197,38 @@ Coding Applications to use DRCP
|
|||
|
||||
To use DRCP, application connection establishment must request a DRCP pooled
|
||||
server. The best practice is also to specify a user-chosen connection class
|
||||
name when creating a connection pool. A 'purity' of the connection session
|
||||
state can optionally be specified. See the Oracle Database documentation on
|
||||
`benefiting from scalability <https://www.oracle.com/pls/topic/lookup?ctx=
|
||||
dblatest&id=GUID-661BB906-74D2-4C5D-9C7E-2798F76501B3>`__ for more information
|
||||
on purity and connection classes.
|
||||
name. A 'purity' of the connection session state can optionally be specified.
|
||||
See the Oracle Database documentation on `benefiting from scalability
|
||||
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-661BB906-74D2-4C5D-9C7E-2798F76501B3>`__
|
||||
for more information on purity and connection classes.
|
||||
|
||||
**Requesting a Pooled Server**
|
||||
To request the database, use a DRCP pooled server and you can use a specific
|
||||
connection string in :meth:`oracledb.create_pool()` or
|
||||
:meth:`oracledb.connect()` like one of the following syntaxes.
|
||||
|
||||
To request a DRCP pooled server, you can:
|
||||
For example with the :ref:`Easy Connect syntax <easyconnect>`:
|
||||
|
||||
- Use a specific connection string in :meth:`oracledb.create_pool()` or
|
||||
:meth:`oracledb.connect()`. For example with the
|
||||
:ref:`Easy Connect syntax <easyconnect>`:
|
||||
.. code-block:: python
|
||||
|
||||
.. code-block:: python
|
||||
dsn = "dbhost.example.com/orcl:pooled"
|
||||
|
||||
pool = oracledb.create_pool(user="hr", password=userpwd, dsn="dbhost.example.com/orclpdb:pooled",
|
||||
min=2, max=5, increment=1,
|
||||
cclass="MYAPP")
|
||||
|
||||
- Alternatively, add ``(SERVER=POOLED)`` to the connect descriptor such as
|
||||
used in an Oracle Network configuration file ``tnsnames.ora``::
|
||||
Alternatively, add ``(SERVER=POOLED)`` to the connect descriptor such as used in
|
||||
an Oracle Network configuration file ``tnsnames.ora``::
|
||||
|
||||
customerpool = (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)
|
||||
(HOST=dbhost.example.com)
|
||||
(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=CUSTOMER)
|
||||
(SERVER=POOLED)))
|
||||
|
||||
- Another way to use a DRCP pooled server is to set the ``server_type``
|
||||
parameter during standalone connection creation or python-oracledb
|
||||
connection pool creation. For example:
|
||||
You can also specify to use a DRCP pooled server by setting the ``server_type``
|
||||
parameter when creating a standalone connection or creating a python-oracledb
|
||||
connection pool. For example:
|
||||
|
||||
.. code-block:: python
|
||||
.. code-block:: python
|
||||
|
||||
pool = oracledb.create_pool(user="hr", password=userpwd, dsn="dbhost.example.com/orclpdb",
|
||||
min=2, max=5, increment=1,
|
||||
server_type="pooled",
|
||||
cclass="MYAPP")
|
||||
server_type="pooled")
|
||||
|
||||
|
||||
**DRCP Connection Class Names**
|
||||
|
@ -1272,12 +1241,8 @@ processes are started. A class name also allows better DRCP usage tracking in
|
|||
the database. In the database monitoring views, the class name shown will be
|
||||
the value specified in the application prefixed with the user name.
|
||||
|
||||
If ``cclass`` was not specified during pool creation, then the python-oracledb
|
||||
Thin mode generates a unique connection class with the prefix "DPY" while the
|
||||
Thick mode generates a unique connection class with the prefix "OCI".
|
||||
|
||||
To create a connection pool requesting a DRCP pooled server and specifying a
|
||||
class name, you can call:
|
||||
class name you can call:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
@ -1285,19 +1250,12 @@ class name, you can call:
|
|||
min=2, max=5, increment=1,
|
||||
cclass="MYAPP")
|
||||
|
||||
Once the pool has been created, your application can get a connection from it
|
||||
by calling:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
connection = pool.acquire()
|
||||
|
||||
The python-oracledb connection pool size does not need to match the DRCP pool
|
||||
size. The limit on overall execution parallelism is determined by the DRCP
|
||||
pool size.
|
||||
|
||||
Connection class names can also be passed to :meth:`~ConnectionPool.acquire()`,
|
||||
if you want to use a connection with a different class:
|
||||
if desired:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
@ -1335,22 +1293,21 @@ allocated each time :meth:`~ConnectionPool.acquire()` is called:
|
|||
|
||||
**Setting the Connection Class and Purity in the Connection String**
|
||||
|
||||
Using python-oracledb Thin mode with Oracle Database 21c, you can specify the
|
||||
class and purity in the connection string itself. This removes the need to
|
||||
modify an existing application when you want to use DRCP:
|
||||
For the python-oracledb Thin mode, you can specify the class and purity in the
|
||||
connection string itself. This removes the need to modify an existing
|
||||
application when you want to use DRCP:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
dsn = "localhost/orclpdb:pooled?pool_connection_class=MYAPP&pool_purity=self"
|
||||
|
||||
For python-oracledb Thick mode, this syntax is supported if you are using
|
||||
Oracle Database 21c and Oracle Client 19c (or later). However, explicitly
|
||||
specifying the purity as *SELF* in this way may cause some unusable connections
|
||||
in a python-oracledb Thick mode connection pool to not be terminated. In
|
||||
summary, if you cannot programmatically set the class name and purity, or
|
||||
cannot use python-oracledb Thin mode, then avoid explicitly setting the purity
|
||||
as a connection string parameter when using a python-oracledb connection
|
||||
pooling in Thick mode.
|
||||
Recent versions of Oracle Client libraries also support this syntax. However,
|
||||
explicitly specifying the purity as SELF in this way may cause some unusable
|
||||
connections in a python-oracledb Thick mode connection pool not to be
|
||||
terminated. In summary, if you cannot programmatically set the class name and
|
||||
purity, or cannot use python-oracledb Thin mode, then avoid explicitly setting
|
||||
the purity as a connection string parameter when using a python-oracledb
|
||||
connection pooling in Thick mode.
|
||||
|
||||
**Closing Connections when using DRCP**
|
||||
|
||||
|
@ -1380,10 +1337,6 @@ other users:
|
|||
. . .
|
||||
connection.close();
|
||||
|
||||
See `drcp_pool.py
|
||||
<https://github.com/oracle/python-oracledb/tree/main/samples/drcp_pool.py>`__
|
||||
for a runnable example of DRCP.
|
||||
|
||||
.. _monitoringdrcp:
|
||||
|
||||
Monitoring DRCP
|
||||
|
@ -2054,7 +2007,7 @@ alternatively, you can specify it inside a connect descriptor stored in
|
|||
(ADDRESS=(PROTOCOL=TCPS)(PORT=1522)(HOST=xxx.oraclecloud.com))
|
||||
(CONNECT_DATA=(SERVICE_NAME=xxx.adb.oraclecloud.com))
|
||||
(SECURITY =
|
||||
(SSL_SERVER_CERT_DN="CN=xxx.oraclecloud.com, \
|
||||
(SSL_SERVER_CERT_DN="CN=xxx.oraclecloud.com,OU=Oracle BMCS US, \
|
||||
O=Oracle Corporation,L=Redwood City,ST=California,C=US")
|
||||
(TOKEN_AUTH=OAUTH)
|
||||
(TOKEN_LOCATION="/home/user1/mytokens/oauthtoken")
|
||||
|
@ -2292,7 +2245,7 @@ Alternatively, you can specify it in a connect descriptor, for example::
|
|||
(ADDRESS=(PROTOCOL=TCPS)(PORT=1522)(HOST=xxx.oraclecloud.com))
|
||||
(CONNECT_DATA=(SERVICE_NAME=xxx.adb.oraclecloud.com))
|
||||
(SECURITY =
|
||||
(SSL_SERVER_CERT_DN="CN=xxx.oraclecloud.com, \
|
||||
(SSL_SERVER_CERT_DN="CN=xxx.oraclecloud.com,OU=Oracle BMCS US, \
|
||||
O=Oracle Corporation,L=Redwood City,ST=California,C=US")
|
||||
(TOKEN_AUTH=OCI_TOKEN)
|
||||
)
|
||||
|
@ -2311,7 +2264,7 @@ sqlnet.ora file or in a connect descriptor stored inside
|
|||
(ADDRESS=(PROTOCOL=TCPS)(PORT=1522)(HOST=xxx.oraclecloud.com))
|
||||
(CONNECT_DATA=(SERVICE_NAME=xxx.adb.oraclecloud.com))
|
||||
(SECURITY =
|
||||
(SSL_SERVER_CERT_DN="CN=xxx.oraclecloud.com, \
|
||||
(SSL_SERVER_CERT_DN="CN=xxx.oraclecloud.com,OU=Oracle BMCS US, \
|
||||
O=Oracle Corporation,L=Redwood City,ST=California,C=US")
|
||||
(TOKEN_AUTH=OCI_TOKEN)
|
||||
(TOKEN_LOCATION="/path/to/token/folder")
|
||||
|
@ -2358,28 +2311,9 @@ This is equivalent to executing the following in SQL*Plus:
|
|||
|
||||
.. code-block:: sql
|
||||
|
||||
CONNECT sys/syspwd@dbhost.example.com/orclpdb AS SYSDBA
|
||||
CONNECT sys/syspwd AS SYSDBA
|
||||
GRANT SYSOPER TO hr;
|
||||
|
||||
|
||||
In python-oracledb Thick mode, when python-oracledb uses Oracle Client
|
||||
libraries from a database software installation, you can use "bequeath"
|
||||
connections to databases that are also using the same libraries. Do this by
|
||||
setting the standard Oracle environment variables such as ``ORACLE_HOME`` and
|
||||
``ORACLE_SID`` and connecting in Python like:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
oracledb.init_oracle_client()
|
||||
|
||||
conn = oracledb.connect(mode=oracledb.SYSDBA)
|
||||
|
||||
This is equivalent to executing the following in SQL*Plus:
|
||||
|
||||
.. code-block:: sql
|
||||
|
||||
CONNECT / AS SYSDBA
|
||||
|
||||
.. _netencrypt:
|
||||
|
||||
Securely Encrypting Network Traffic to Oracle Database
|
||||
|
@ -2446,37 +2380,11 @@ requirements and read the documentation for your Oracle version. In particular,
|
|||
review the available algorithms for security and performance.
|
||||
|
||||
The ``NETWORK_SERVICE_BANNER`` column of the database view
|
||||
`V$SESSION_CONNECT_INFO <https://www.oracle.com/pls/topic/lookup?ctx=dblatest&
|
||||
`V$SESSION_CONNECT_INFO
|
||||
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&
|
||||
id=GUID-9F0DCAEA-A67E-4183-89E7-B1555DC591CE>`__ can be used to verify the
|
||||
encryption status of a connection. For example with SQL*Plus::
|
||||
encryption status of a connection.
|
||||
|
||||
SQL> SELECT network_service_banner FROM v$session_connect_info;
|
||||
|
||||
If the connection is encrypted, then this query prints an output that includes
|
||||
the available encryption service, the crypto-checksumming service, and the
|
||||
algorithms in use, such as::
|
||||
|
||||
NETWORK_SERVICE_BANNER
|
||||
-------------------------------------------------------------------------------------
|
||||
TCP/IP NT Protocol Adapter for Linux: Version 19.0.0.0.0 - Production
|
||||
Encryption service for Linux: Version 19.0.1.0.0 - Production
|
||||
AES256 Encryption service adapter for Linux: Version 19.0.1.0.0 - Production
|
||||
Crypto-checksumming service for Linux: Version 19.0.1.0.0 - Production
|
||||
SHA256 Crypto-checksumming service adapter for Linux: Version 19.0.1.0.0 - Production
|
||||
|
||||
If the connection is unencrypted, then the query will only print the
|
||||
available encryption and crypto-checksumming services in the output. For example::
|
||||
|
||||
NETWORK_SERVICE_BANNER
|
||||
-------------------------------------------------------------------------------------
|
||||
TCP/IP NT Protocol Adapter for Linux: Version 19.0.0.0.0 - Production
|
||||
Encryption service for Linux: Version 19.0.1.0.0 - Production
|
||||
Crypto-checksumming service for Linux: Version 19.0.1.0.0 - Production
|
||||
|
||||
For more information about Oracle Data Network Encryption and Integrity,
|
||||
and for information about configuring TLS network encryption, refer to
|
||||
the `Oracle Database Security Guide <https://www.oracle.com/pls/topic/
|
||||
lookup?ctx=dblatest&id=DBSEG>`__.
|
||||
|
||||
Resetting Passwords
|
||||
===================
|
||||
|
@ -2572,7 +2480,7 @@ ADMIN user:
|
|||
|
||||
cs = '''(description = (retry_count=20)(retry_delay=3)(address=(protocol=tcps)
|
||||
(port=1522)(host=xxx.oraclecloud.com))(connect_data=(service_name=xxx.adb.oraclecloud.com))
|
||||
(security=(ssl_server_dn_match=yes)(ssl_server_cert_dn="CN=xxx.oraclecloud.com,
|
||||
(security=(ssl_server_dn_match=yes)(ssl_server_cert_dn="CN=xxx.oraclecloud.com,OU=Oracle BMCS US,
|
||||
O=Oracle Corporation, L=Redwood City, T=California, C=US")))'''
|
||||
|
||||
connection = oracledb.connect(user="admin", password=pw, dsn=cs)
|
||||
|
@ -2696,7 +2604,7 @@ to two or more Oracle Autonomous Databases, move each ``cwallet.sso`` file to
|
|||
its own directory. For each connection use different connection string
|
||||
``WALLET_LOCATION`` parameters to specify the directory of each ``cwallet.sso``
|
||||
file. It is recommended to use Oracle Client libraries 19.17 (or later) when
|
||||
using :ref:`multiple wallets <connmultiwallets>`.
|
||||
using multiple wallets.
|
||||
|
||||
Access Through a Proxy
|
||||
+++++++++++++++++++++++
|
||||
|
@ -2765,15 +2673,15 @@ For example, if your ``tnsnames.ora`` file had an entry::
|
|||
|
||||
cjjson_high = (description=(retry_count=20)(retry_delay=3)
|
||||
(address=(protocol=tcps)(port=1522)
|
||||
(host=xxx.oraclecloud.com))
|
||||
(host=adb.ap-sydney-1.oraclecloud.com))
|
||||
(connect_data=(service_name=abc_cjjson_high.adb.oraclecloud.com))
|
||||
(security=(ssl_server_cert_dn="CN=xxx.oraclecloud.com,O=Oracle Corporation,L=Redwood City,ST=California,C=US")))
|
||||
(security=(ssl_server_cert_dn="CN=adb.ap-sydney-1.oraclecloud.com,OU=Oracle ADB SYDNEY,O=Oracle Corporation,L=Redwood City,ST=California,C=US")))
|
||||
|
||||
Then your applications can connect using the connection string:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
dsn = "tcps://xxx.oraclecloud.com:1522/abc_cjjson_high.adb.oraclecloud.com?wallet_location=/Users/cjones/Cloud/CJJSON&retry_count=20&retry_delay=3"
|
||||
dsn = "tcps://adb.ap-sydney-1.oraclecloud.com:1522/abc_cjjson_high.adb.oraclecloud.com?wallet_location=/Users/cjones/Cloud/CJJSON&retry_count=20&retry_delay=3"
|
||||
connection = oracledb.connect(user="hr", password=userpwd, dsn=dsn)
|
||||
|
||||
The ``wallet_location`` parameter needs to be set to the directory containing
|
||||
|
@ -2864,60 +2772,6 @@ location as the ``wallet_location`` parameter to :func:`oracledb.connect()` or
|
|||
f.write(cert.public_bytes(Encoding.PEM))
|
||||
print("PEM file", pem_file_name, "written.")
|
||||
|
||||
.. _connmultiwallets:
|
||||
|
||||
Connecting using Multiple Wallets
|
||||
=================================
|
||||
|
||||
You can make multiple connections with different wallets in one Python
|
||||
process.
|
||||
|
||||
**In python-oracledb Thin mode**
|
||||
|
||||
To use multiple wallets in python-oracledb Thin mode, pass the different
|
||||
connection strings, wallet locations, and wallet password (if required) in each
|
||||
:meth:`oracledb.connect()` call or when creating a :ref:`connection pool
|
||||
<connpooling>`:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
connection = oracledb.connect(user=user_name, password=userpw, dsn=dsn,
|
||||
config_dir="path_to_extracted_wallet_zip",
|
||||
wallet_location="location_of_pem_file",
|
||||
wallet_password=walletpw)
|
||||
|
||||
The ``config_dir`` parameter is the directory containing the :ref:`tnsnames.ora
|
||||
<optnetfiles>` file. The ``wallet_location`` parameter is the directory
|
||||
containing the ``ewallet.pem`` file. If you are using Oracle Autonomous
|
||||
Database, both of these paths are typically the same directory where the
|
||||
``wallet.zip`` file was extracted. The ``dsn`` should specify a TCPS
|
||||
connection.
|
||||
|
||||
**In python-oracledb Thick mode**
|
||||
|
||||
To use multiple wallets in python-oracledb Thick mode, a TCPS connection string
|
||||
containing the ``MY_WALLET_DIRECTORY`` option needs to be created:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
dsn = "mydb_high" # one of the network aliases from tnsnames.ora
|
||||
params = oracledb.ConnectParams(config_dir="path_to_extracted_wallet_zip",
|
||||
wallet_location="path_location_of_sso_file")
|
||||
params.parse_connect_string(dsn)
|
||||
dsn = params.get_connect_string()
|
||||
connection = oracledb.connect(user=user_name, password=password, dsn=dsn)
|
||||
|
||||
The ``config_dir`` parameter should be the directory containing the
|
||||
:ref:`tnsnames.ora <optnetfiles>` and ``sqlnet.ora`` files. The
|
||||
``wallet_location`` parameter is the directory containing the ``cwallet.sso``
|
||||
file. If you are using Oracle Autonomous Database, both of these paths are
|
||||
typically the same directory where the ``wallet.zip`` file was extracted.
|
||||
|
||||
.. note::
|
||||
|
||||
Use Oracle Client libraries 19.17, or later, or use Oracle Client 21c.
|
||||
They contain important bug fixes for using multiple wallets in the one
|
||||
process.
|
||||
|
||||
.. _connsharding:
|
||||
|
||||
|
|
|
@ -105,19 +105,12 @@ Thin Mode Locale-aware Number and Date Conversions
|
|||
.. note::
|
||||
|
||||
All NLS environment variables are ignored by the python-oracledb Thin mode.
|
||||
Also the ``ORA_TZFILE`` variable is ignored.
|
||||
|
||||
.. note::
|
||||
|
||||
Trying to access TIMESTAMP WITH TIME ZONE data that contains a named time
|
||||
zone will throw ``DPY-3022: named time zones are not supported in thin
|
||||
mode``. Data stored with a numeric offset such as ``+00:00`` can be
|
||||
fetched.
|
||||
Also the ``ORA_SDTZ`` and ``ORA_TZFILE`` variables are ignored.
|
||||
|
||||
In the python-oracledb Thin mode, output type handlers need to be used to
|
||||
perform date and number localizations. The examples below show a simple
|
||||
conversion and also how the Python locale module can be used. Type handlers
|
||||
like those below can also be used in python-oracledb Thick mode.
|
||||
perform similar conversions. The examples below show a simple conversion and
|
||||
also how the Python locale module can be used. Type handlers like those below
|
||||
can also be used in python-oracledb Thick mode.
|
||||
|
||||
To convert numbers:
|
||||
|
||||
|
@ -133,16 +126,16 @@ To convert numbers:
|
|||
locale.setlocale(locale.LC_ALL, 'de_DE.UTF-8')
|
||||
|
||||
# simple naive conversion
|
||||
def type_handler1(cursor, metadata):
|
||||
if metadata.type_code is oracledb.DB_TYPE_NUMBER:
|
||||
def type_handler1(cursor, name, default_type, size, precision, scale):
|
||||
if default_type == oracledb.DB_TYPE_NUMBER:
|
||||
return cursor.var(oracledb.DB_TYPE_VARCHAR, arraysize=cursor.arraysize,
|
||||
outconverter=lambda v: v.replace('.', ','))
|
||||
outconverter=lambda v: v.replace('.', ','))
|
||||
|
||||
# locale conversion
|
||||
def type_handler2(cursor, metadata):
|
||||
if metadata.type_code is oracledb.DB_TYPE_NUMBER:
|
||||
return cursor.var(metadata.type_code, arraysize=cursor.arraysize,
|
||||
outconverter=lambda v: locale.format_string("%g", v))
|
||||
def type_handler2(cursor, name, default_type, size, precision, scale):
|
||||
if default_type == oracledb.DB_TYPE_NUMBER:
|
||||
return cursor.var(default_type, arraysize=cursor.arraysize,
|
||||
outconverter=lambda v: locale.format_string("%g", v))
|
||||
|
||||
|
||||
connection = oracledb.connect(user="hr", password=userpwd,
|
||||
|
@ -186,16 +179,16 @@ To convert dates:
|
|||
locale_date_format = locale.nl_langinfo(locale.D_T_FMT)
|
||||
|
||||
# simple naive conversion
|
||||
def type_handler3(cursor, metadata):
|
||||
if metadata.type_code is oracledb.DB_TYPE_DATE:
|
||||
return cursor.var(metadata.type_code, arraysize=cursor.arraysize,
|
||||
outconverter=lambda v: v.strftime("%Y-%m-%d %H:%M:%S"))
|
||||
def type_handler3(cursor, name, default_type, size, precision, scale):
|
||||
if default_type == oracledb.DB_TYPE_DATE:
|
||||
return cursor.var(default_type, arraysize=cursor.arraysize,
|
||||
outconverter=lambda v: v.strftime("%Y-%m-%d %H:%M:%S"))
|
||||
|
||||
# locale conversion
|
||||
def type_handler4(cursor, name, default_type, size, precision, scale):
|
||||
if metadata.type_code is oracledb.DB_TYPE_DATE:
|
||||
return cursor.var(metadata.type_code, arraysize=cursor.arraysize,
|
||||
outconverter=lambda v: v.strftime(locale_date_format))
|
||||
if default_type == oracledb.DB_TYPE_DATE:
|
||||
return cursor.var(default_type, arraysize=cursor.arraysize,
|
||||
outconverter=lambda v: v.strftime(locale_date_format))
|
||||
|
||||
|
||||
connection = oracledb.connect(user="hr", password=userpwd,
|
||||
|
|
|
@ -16,103 +16,76 @@ supporting the Python Database API v2.0 Specification.
|
|||
Enabling python-oracledb Thick mode
|
||||
===================================
|
||||
|
||||
If you are upgrading a cx_Oracle application to python-oracledb, then refer to
|
||||
Changing from the default Thin mode to the Thick mode requires the addition of
|
||||
a call to :func:`oracledb.init_oracle_client()` as shown in sections below.
|
||||
Other small code updates may also be required, see :ref:`driverdiff` . If you are
|
||||
upgrading a cx_Oracle application to python-oracledb, then refer to
|
||||
:ref:`upgrading83` for changes that may be needed.
|
||||
|
||||
To change from the default Thin mode to the Thick mode:
|
||||
.. note::
|
||||
|
||||
- Oracle Client libraries must be available to handle communication to your
|
||||
database. These need to be installed separately, see :ref:`installation`.
|
||||
To use python-oracledb in Thick mode you *must* call
|
||||
:func:`~oracledb.init_oracle_client()` in the application. It must be
|
||||
called before any :ref:`standalone connection <standaloneconnection>` or
|
||||
:ref:`connection pool <connpooling>` is created. If a connection or pool
|
||||
is first created, then the Thick mode cannot be enabled.
|
||||
|
||||
Various versions of Oracle Client libraries can be used. They do not have to
|
||||
match the version of Oracle Database. Python-oracledb can use the Client
|
||||
Libraries from:
|
||||
All connections in an application use the same mode.
|
||||
|
||||
- an installation of `Oracle Instant Client
|
||||
<https://www.oracle.com/database/technologies/instant-client.html>`__
|
||||
Once the Thick mode is enabled, you cannot go back to Thin mode except by
|
||||
restarting the application.
|
||||
|
||||
- or a full Oracle Client installation (installed by running the Oracle
|
||||
Universal installer ``runInstaller``)
|
||||
Enabling the python-oracledb Thick mode loads Oracle Client libraries which
|
||||
handle communication to your database. The Oracle Client libraries need to be
|
||||
installed separately. See :ref:`installation`.
|
||||
|
||||
- or an Oracle Database installation, if Python is running on the same
|
||||
machine as the database
|
||||
.. figure:: /images/python-oracledb-thick-arch.png
|
||||
:alt: architecture of the python-oracledb driver in Thick mode
|
||||
|
||||
- Your application *must* call the function
|
||||
:meth:`oracledb.init_oracle_client()`. For example, if the Oracle Instant
|
||||
Client libraries are in ``C:\oracle\instantclient_19_17`` on Windows or
|
||||
``$HOME/Downloads/instantclient_19_8`` on macOS (Intel x86), then you can
|
||||
use:
|
||||
Architecture of the python-oracledb driver in Thick mode
|
||||
|
||||
.. code-block:: python
|
||||
You can validate python-oracledb is running in Thick mode by querying the
|
||||
``CLIENT_DRIVER`` column of ``V$SESSION_CONNECT_INFO`` and verifying the value
|
||||
of the column begins with ``python-oracledb thk``. See :ref:`vsessconinfo`.
|
||||
|
||||
import os
|
||||
import platform
|
||||
|
||||
import oracledb
|
||||
.. _libinit:
|
||||
|
||||
d = None # default suitable for Linux
|
||||
if platform.system() == "Darwin" and platform.machine() == "x86_64": # macOS
|
||||
d = os.environ.get("HOME")+("/Downloads/instantclient_19_8")
|
||||
elif platform.system() == "Windows":
|
||||
d = r"C:\oracle\instantclient_19_18"
|
||||
oracledb.init_oracle_client(lib_dir=d)
|
||||
Setting the Oracle Client Library Directory
|
||||
-------------------------------------------
|
||||
|
||||
The use of a ‘raw’ string ``r"..."`` on Windows means that backslashes are
|
||||
treated as directory separators.
|
||||
When :meth:`~oracledb.init_oracle_client()` is called, python-oracledb
|
||||
dynamically loads Oracle Client libraries using a search heuristic. The
|
||||
libraries can be:
|
||||
|
||||
More details and options are shown in the later sections
|
||||
:ref:`wininit`, :ref:`macinit`, and :ref:`linuxinit`.
|
||||
- in an installation of Oracle Instant Client
|
||||
- or in a full Oracle Client installation
|
||||
- or in an Oracle Database installation (if Python is running on the same
|
||||
machine as the database).
|
||||
|
||||
All connections in an application use the same mode.
|
||||
See :ref:`installation` for information about installing Oracle Client
|
||||
libraries.
|
||||
|
||||
Once the Thick mode is enabled, you cannot go back to the Thin mode except by
|
||||
removing calls to :meth:`~oracledb.init_oracle_client()` and restarting the
|
||||
application.
|
||||
The versions of Oracle Client libraries 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>`__.
|
||||
|
||||
See :ref:`vsessconinfo` to verify which mode is in use.
|
||||
.. note::
|
||||
|
||||
**Notes on calling init_oracle_client()**
|
||||
|
||||
- The :meth:`~oracledb.init_oracle_client()` function must be called before
|
||||
any :ref:`standalone connection <standaloneconnection>` or
|
||||
:ref:`connection pool <connpooling>` is created. If a connection or pool
|
||||
is first created, then the Thick mode cannot be enabled.
|
||||
|
||||
- If you call :meth:`~oracledb.init_oracle_client()` with a ``lib_dir`` parameter,
|
||||
the Oracle Client libraries are loaded immediately from that directory. If
|
||||
you call :meth:`~oracledb.init_oracle_client()` but do *not* set the ``lib_dir``
|
||||
parameter, the Oracle Client libraries are loaded immediately using the
|
||||
search heuristics discussed in later sections.
|
||||
|
||||
- If Oracle Client libraries cannot be loaded then
|
||||
:meth:`~oracledb.init_oracle_client()` will raise an error ``DPI-1047:
|
||||
Oracle Client library cannot be loaded``. To resolve this, review the
|
||||
platform-specific instructions below or see :ref:`runtimetroubleshooting`.
|
||||
Alternatively, remove the call to :meth:`~oracledb.init_oracle_client()` and
|
||||
use Thin mode. The features supported by Thin mode can be found in
|
||||
:ref:`driverdiff`.
|
||||
|
||||
- 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 (such as from running
|
||||
``runInstaller``), 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 variable, and other
|
||||
Oracle environment variables, before starting Python, as shown in :ref:`Oracle
|
||||
Environment Variables <envset>`.
|
||||
|
||||
- The :meth:`~oracledb.init_oracle_client()` function may be called multiple
|
||||
times in your application but must always pass the same arguments.
|
||||
If Oracle Client libraries cannot be loaded then
|
||||
:meth:`~oracledb.init_oracle_client()` will raise an error ``DPI-1047:
|
||||
Oracle Client library cannot be loaded``. To resolve this, review the
|
||||
platform-specific instructions below or see :ref:`runtimetroubleshooting`.
|
||||
Alternatively remove the call to :meth:`~oracledb.init_oracle_client()` and
|
||||
use Thin mode. The features supported by Thin mode can be found in
|
||||
:ref:`driverdiff`.
|
||||
|
||||
.. _wininit:
|
||||
|
||||
Enabling python-oracledb Thick Mode on Windows
|
||||
----------------------------------------------
|
||||
Setting the Oracle Client Library Directory on Windows
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
On Windows, the alternative ways to enable Thick mode are:
|
||||
On Windows, python-oracledb Thick mode can be enabled as follows:
|
||||
|
||||
- By passing the ``lib_dir`` parameter in a call to
|
||||
:meth:`~oracledb.init_oracle_client()`, for example:
|
||||
|
@ -121,25 +94,22 @@ On Windows, the alternative ways to enable Thick mode are:
|
|||
|
||||
import oracledb
|
||||
|
||||
oracledb.init_oracle_client(lib_dir=r"C:\instantclient_19_18")
|
||||
oracledb.init_oracle_client(lib_dir=r"C:\instantclient_19_14")
|
||||
|
||||
On Windows, when the path contains backslashes, use a 'raw' string like
|
||||
``r"C:\instantclient_19_18"``.
|
||||
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 same software installation. Otherwise, files
|
||||
such as message files will not be located and you may have library
|
||||
version clashes. On Windows, when the path contains backslashes, use a
|
||||
'raw' string like ``r"C:\instantclient_19_14"``.
|
||||
|
||||
This directory should contain the libraries from an unzipped `Instant Client
|
||||
'Basic' or 'Basic Light' <https://www.oracle.com/au/database/technologies/
|
||||
instant-client.html>`__ package. If you pass the library directory from a
|
||||
full client or database installation, such as `Oracle Database “XE” Express
|
||||
Edition <https://www.oracle.com/database/technologies/appdev/xe.html>`__,
|
||||
then you will need to have previously set your environment to use that same
|
||||
software installation. Otherwise, files such as message files will not be
|
||||
located and you may have library version clashes.
|
||||
If the Oracle Client libraries cannot be loaded from ``lib_dir``, then an
|
||||
exception is raised.
|
||||
|
||||
If the Oracle Client libraries cannot be loaded, then an exception is
|
||||
raised.
|
||||
|
||||
- Alternatively, you can call :meth:`~oracledb.init_oracle_client()` without
|
||||
passing a ``lib_dir`` parameter:
|
||||
- By calling :meth:`~oracledb.init_oracle_client()` without passing a
|
||||
``lib_dir`` parameter:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
@ -147,11 +117,10 @@ On Windows, the alternative ways to enable Thick mode are:
|
|||
|
||||
oracledb.init_oracle_client()
|
||||
|
||||
In this case, Oracle Client libraries are first looked for in the directory
|
||||
where the python-oracledb binary module is installed. This directory should
|
||||
contain the libraries from an unzipped `Instant Client 'Basic' or 'Basic
|
||||
Light' <https://www.oracle.com/au/database/technologies/instant-client
|
||||
.html>`__ package.
|
||||
In this case, Oracle Client libraries are first looked for in the
|
||||
directory where the python-oracledb 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 there, the search looks at the directories
|
||||
on the system library search path, for example, the ``PATH`` environment
|
||||
|
@ -162,10 +131,10 @@ On Windows, the alternative ways to enable Thick mode are:
|
|||
|
||||
.. _macinit:
|
||||
|
||||
Enabling python-oracledb Thick Mode on macOS
|
||||
--------------------------------------------
|
||||
Setting the Oracle Client Library Directory on macOS
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
On macOS, the alternative ways to enable Thick mode are:
|
||||
On macOS, python-oracledb Thick mode can be enabled as follows:
|
||||
|
||||
- By passing the ``lib_dir`` parameter in a call to
|
||||
:meth:`~oracledb.init_oracle_client()`, for example:
|
||||
|
@ -176,26 +145,24 @@ On macOS, the alternative ways to enable Thick mode are:
|
|||
|
||||
oracledb.init_oracle_client(lib_dir="/Users/your_username/Downloads/instantclient_19_8")
|
||||
|
||||
This directory should contain the libraries from an unzipped `Instant Client
|
||||
'Basic' or 'Basic Light' <https://www.oracle.com/au/database/technologies/
|
||||
instant-client.html>`__ package.
|
||||
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.
|
||||
|
||||
- Alternatively, you can call :meth:`~oracledb.init_oracle_client()` without
|
||||
passing a ``lib_dir`` parameter:
|
||||
- By calling :meth:`~oracledb.init_oracle_client()` without passing a
|
||||
``lib_dir`` parameter:
|
||||
|
||||
.. code-block:: python
|
||||
.. code-block:: python
|
||||
|
||||
import oracledb
|
||||
import oracledb
|
||||
|
||||
oracledb.init_oracle_client()
|
||||
oracledb.init_oracle_client()
|
||||
|
||||
In this case, the Oracle Client libraries are first looked for in the
|
||||
directory where the python-oracledb Thick mode binary module is installed.
|
||||
This directory should contain the libraries from an unzipped `Instant Client
|
||||
'Basic' or 'Basic Light'
|
||||
<https://www.oracle.com/au/database/technologies/instant-client.html>`__
|
||||
package, or a symbolic link to the main Oracle Client library if Instant
|
||||
Client is in a different directory.
|
||||
This directory should contain the libraries from an unzipped Instant Client
|
||||
'Basic' or 'Basic Light' package, or a symbolic link to the main Oracle
|
||||
Client library if Instant Client is in a different directory.
|
||||
|
||||
You can find the directory containing the Thick mode binary module by calling
|
||||
the python CLI without specifying a Python script, executing ``import
|
||||
|
@ -225,65 +192,101 @@ On macOS, the alternative ways to enable Thick mode are:
|
|||
os.symlink(os.path.join(CLIENT_DIR, LIB_NAME),
|
||||
os.path.join(target_dir, LIB_NAME))
|
||||
|
||||
If python-oracledb does not find the Oracle Client library in that directory,
|
||||
the directories on the system library search path may be used, for example,
|
||||
``~/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, so do not rely on
|
||||
setting it.
|
||||
If python-oracledb does not find the Oracle Client library in that
|
||||
directory, the directories on the system library search path may be used,
|
||||
for example, ``~/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:
|
||||
|
||||
Setting the Oracle Client Library Directory on Linux and Related Platforms
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
On Linux and related platforms, python-oracledb Thick mode can be enabled as
|
||||
follows:
|
||||
|
||||
- By calling :meth:`~oracledb.init_oracle_client()` without passing a
|
||||
``lib_dir`` parameter:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import oracledb
|
||||
|
||||
oracledb.init_oracle_client()
|
||||
|
||||
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 libraries are not found in the system library search path, then
|
||||
``$ORACLE_HOME/lib`` will be used. Note that the environment variable
|
||||
``ORACLE_HOME`` should only ever be set when you have a full database
|
||||
installation or full client installation (such as installed with the Oracle
|
||||
GUI installer). 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.
|
||||
|
||||
Ensure that the Python process has directory and file access permissions for
|
||||
the Oracle Client libraries.
|
||||
the Oracle Client libraries. On some platforms OS restrictions may prevent the
|
||||
opening of Oracle Client libraries installed in unsafe paths, such as from a
|
||||
user directory. On Linux ensure a ``libclntsh.so`` file exists. On macOS
|
||||
ensure a ``libclntsh.dylib`` file exists. Python-oracledb Thick mode will not
|
||||
directly load ``libclntsh.*.XX.1`` files in ``lib_dir`` or from the directory
|
||||
where the python-oracledb binary module is available. Note that other
|
||||
libraries used by ``libclntsh*`` are also required.
|
||||
|
||||
.. _linuxinit:
|
||||
.. _usinginitoracleclient:
|
||||
|
||||
Enabling python-oracledb Thick Mode on Linux and Related Platforms
|
||||
------------------------------------------------------------------
|
||||
Example Calling oracledb.init_oracle_client()
|
||||
+++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
On Linux and related platforms, enable Thick mode by calling
|
||||
:meth:`~oracledb.init_oracle_client()` without passing a ``lib_dir``
|
||||
parameter.
|
||||
Oracle Client Libraries are loaded when :meth:`oracledb.init_oracle_client()`
|
||||
is called. In some environments, applications can use the ``lib_dir``
|
||||
parameter to specify the directory containing the Oracle Client libraries.
|
||||
Otherwise, the system library search path should contain the relevant library
|
||||
directory before Python is invoked.
|
||||
|
||||
For example, if the Oracle Instant Client Libraries are in
|
||||
``C:\oracle\instantclient_19_17`` on Windows or
|
||||
``$HOME/Downloads/instantclient_19_8`` on macOS (Intel x86), then you can use:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import oracledb
|
||||
import os
|
||||
import platform
|
||||
|
||||
oracledb.init_oracle_client()
|
||||
d = None # default suitable for Linux
|
||||
if platform.system() == "Darwin" and platform.machine() == "x86_64":
|
||||
d = os.environ.get("HOME")+"/Downloads/instantclient_19_8")
|
||||
elif platform.system() == "Windows":
|
||||
d = r"C:\oracle\instantclient_19_17"
|
||||
oracledb.init_oracle_client(lib_dir=d)
|
||||
|
||||
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``. Web servers and other daemons commonly reset environment
|
||||
variables so using ``ldconfig`` is generally preferred instead. On some UNIX
|
||||
platforms an OS specific equivalent, such as ``LIBPATH`` or ``SHLIB_PATH``, is
|
||||
used instead of ``LD_LIBRARY_PATH``.
|
||||
The use of a 'raw' string ``r"..."`` on Windows means that backslashes are
|
||||
treated as directory separators.
|
||||
|
||||
If libraries are not found in the system library search path, then libraries
|
||||
in ``$ORACLE_HOME/lib`` will be used. Note that the environment variable
|
||||
``ORACLE_HOME`` should only ever be set when you have a full database
|
||||
installation or full client installation (such as installed with the Oracle
|
||||
GUI installer). It should not be set if you are using `Oracle Instant Client
|
||||
<https://www.oracle.com/au/database/technologies/instant-client.html>`__. If
|
||||
being used, ``ORACLE_HOME`` and other necessary Oracle environment variables
|
||||
should be set before starting Python. See :ref:`envset`.
|
||||
**Note that 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**.
|
||||
|
||||
If the Oracle Client libraries cannot be loaded, then an exception is
|
||||
raised.
|
||||
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
|
||||
along with other Oracle environment variables before starting Python as
|
||||
shown in :ref:`envset`.
|
||||
|
||||
On Linux, python-oracledb Thick mode will not automatically load Oracle Client
|
||||
library files from the directory where the python-oracledb binary module is
|
||||
located. One of the above methods should be used instead.
|
||||
|
||||
Ensure that the Python process has directory and file access permissions for
|
||||
the Oracle Client libraries. OS restrictions may prevent the opening of Oracle
|
||||
Client libraries installed in unsafe paths, such as from a user directory. You
|
||||
may need to install the Oracle Client libraries under a directory like ``/opt``
|
||||
or ``/usr/local``.
|
||||
|
||||
Tracing Oracle Client Libraries Loading
|
||||
---------------------------------------
|
||||
**Tracing Oracle Client Libraries Loading**
|
||||
|
||||
To trace the loading of Oracle Client libraries, the environment variable
|
||||
``DPI_DEBUG_LEVEL`` can be set to 64 before starting Python. At a Windows
|
||||
|
@ -295,18 +298,12 @@ On Linux and macOS, you might use::
|
|||
|
||||
export DPI_DEBUG_LEVEL=64
|
||||
|
||||
When your python-oracledb application is run, logging output is shown on the
|
||||
terminal.
|
||||
|
||||
.. _optconfigfiles:
|
||||
|
||||
Optional Oracle Configuration Files
|
||||
===================================
|
||||
When your python-oracledb application is run, logging output is shown.
|
||||
|
||||
.. _optnetfiles:
|
||||
|
||||
Optional Oracle Net Configuration Files
|
||||
---------------------------------------
|
||||
=======================================
|
||||
|
||||
Optional Oracle Net configuration files may be read by python-oracledb. These
|
||||
files affect connections and applications. The common files are:
|
||||
|
@ -322,30 +319,109 @@ files affect connections and applications. The common files are:
|
|||
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&
|
||||
id=GUID-19423B71-3F6C-430F-84CC-18145CC2A818>`__ for more information.
|
||||
|
||||
The ``sqlnet.ora`` file is only used in the python-oracledb Thick mode. See
|
||||
:ref:`enablingthick`. In the python-oracledb Thin mode, many of the
|
||||
equivalent settings can be defined as connection time parameters, for
|
||||
example by using the :ref:`ConnectParams Class <connparam>`.
|
||||
.. note::
|
||||
|
||||
See :ref:`usingconfigfiles` to understand how python-oracledb locates the
|
||||
files.
|
||||
The ``sqlnet.ora`` file is only supported in the python-oracledb Thick
|
||||
mode. See :ref:`enablingthick`.
|
||||
|
||||
In the python-oracledb Thin mode, many of the equivalent settings can be
|
||||
defined as connection time parameters, for example by using the
|
||||
:ref:`ConnectParams Class <connparam>`.
|
||||
|
||||
**python-oracledb Thin mode**
|
||||
|
||||
In python-oracledb Thin mode applications, you specify the directory that
|
||||
contains the ``tnsnames.ora`` file by:
|
||||
|
||||
- setting the `TNS_ADMIN
|
||||
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-12C94B15-2CE1-4B98-9D0C-8226A9DDF4CB>`__
|
||||
environment variable to the directory containing the file
|
||||
|
||||
- setting :attr:`defaults.config_dir` to the directory containing the file
|
||||
|
||||
- setting the ``config_dir`` parameter to the directory containing the file
|
||||
when :func:`connecting <oracledb.connect()>` or creating a
|
||||
:func:`connection pool <oracledb.create_pool()>`.
|
||||
|
||||
For example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import oracledb
|
||||
|
||||
oracledb.defaults.config_dir = "/opt/oracle/config"
|
||||
|
||||
.. note::
|
||||
|
||||
In Thin mode, you must explicitly set the directory because traditional
|
||||
"default" locations such as the Instant Client ``network/admin/``
|
||||
subdirectory, or ``$ORACLE_HOME/network/admin/``, or
|
||||
``$ORACLE_BASE/homes/XYZ/network/admin/`` (in a read-only Oracle Database
|
||||
home) are not automatically looked in.
|
||||
|
||||
**python-oracledb Thick mode**
|
||||
|
||||
In python-oracledb Thick mode, the files are loaded from default locations
|
||||
(shown below), from the directory also specified in the ``$TNS_ADMIN``
|
||||
environment variable, or from the directory specified as a parameter in the
|
||||
:meth:`oracledb.init_oracle_client()` call. For example, if the file
|
||||
``/opt/oracle/config/tnsnames.ora`` should be used, you can call:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import oracledb
|
||||
import sys
|
||||
|
||||
try:
|
||||
oracledb.init_oracle_client(config_dir="/opt/oracle/config")
|
||||
except Exception as err:
|
||||
print("Whoops!")
|
||||
print(err)
|
||||
sys.exit(1)
|
||||
|
||||
.. note::
|
||||
|
||||
In python-oracledb Thick mode, once an application has created its first
|
||||
connection, trying to change the configuration directory will not have any
|
||||
effect.
|
||||
|
||||
If :meth:`~oracledb.init_oracle_client()` is called to enable Thick mode but
|
||||
``config_dir`` is not specified, then default directories are searched for the
|
||||
configuration files. They include:
|
||||
|
||||
- ``$TNS_ADMIN``
|
||||
|
||||
- ``/opt/oracle/instantclient_19_14/network/admin`` if Instant Client is in
|
||||
``/opt/oracle/instantclient_19_14``.
|
||||
|
||||
- ``/usr/lib/oracle/19.14/client64/lib/network/admin`` if Oracle 19.6 Instant
|
||||
Client RPMs are used on Linux.
|
||||
|
||||
- ``$ORACLE_HOME/network/admin`` if python-oracledb Thick is using libraries
|
||||
from a database installation.
|
||||
|
||||
Note that the :ref:`easyconnect` can set many common configuration options
|
||||
without needing ``tnsnames.ora`` or ``sqlnet.ora`` files.
|
||||
|
||||
The section :ref:`Network Configuration <hanetwork>` has additional information
|
||||
about Oracle Net configuration.
|
||||
|
||||
.. _optclientfiles:
|
||||
|
||||
Optional Oracle Client Configuration File
|
||||
-----------------------------------------
|
||||
=========================================
|
||||
|
||||
When python-oracledb Thick mode uses Oracle Client libraries version 12.1 or
|
||||
later, an optional client parameter file called ``oraaccess.xml`` can be used
|
||||
to configure some behaviors of those libraries, such as statement caching and
|
||||
When python-oracledb uses Oracle Client libraries version 12.1 or later, an
|
||||
optional client parameter file called ``oraaccess.xml`` can be used to
|
||||
configure some behaviors 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`_.
|
||||
|
||||
.. note::
|
||||
|
||||
The ``oraaccess.xml`` file is only used in the python-oracledb Thick mode.
|
||||
See :ref:`enablingthick`.
|
||||
The ``oraaccess.xml`` file is only supported in the python-oracledb Thick
|
||||
mode. See :ref:`enablingthick`.
|
||||
|
||||
A sample ``oraaccess.xml`` file that sets the Oracle client 'prefetch' value to
|
||||
1000 rows. This value affects every SQL query in the application::
|
||||
|
@ -362,120 +438,27 @@ A sample ``oraaccess.xml`` file that sets the Oracle client 'prefetch' value to
|
|||
</default_parameters>
|
||||
</oraaccess>
|
||||
|
||||
See :ref:`tuningfetch` for information about prefetching.
|
||||
Prefetching is the number of additional rows that the underlying Oracle Client
|
||||
library fetches whenever python-oracledb Thick 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 the Thick mode to the application.
|
||||
The cache management is transparently handled by the Oracle Client libraries.
|
||||
Note that standard Thick mode fetch tuning is done using :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:
|
||||
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-75169FE4-DE2C-431F-BBA7-3691C7C33360>`__.
|
||||
- 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-75169FE4-DE2C-431F-BBA7-3691C7C33360>`__
|
||||
|
||||
Refer to the documentation on `oraaccess.xml <https://www.oracle.com/pls/topic
|
||||
/lookup?ctx=dblatest&id=GUID-9D12F489-EC02-46BE-8CD4-5AECED0E2BA2>`__
|
||||
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.
|
||||
|
||||
See :ref:`usingconfigfiles` to understand how python-oracledb locates the
|
||||
files.
|
||||
|
||||
.. _usingconfigfiles:
|
||||
|
||||
Using Optional Oracle Configuration Files
|
||||
-----------------------------------------
|
||||
|
||||
If you use optional Oracle configuration files such as ``tnsnames.ora``,
|
||||
``sqlnet.ora`` or ``oraaccess.xml``, then put the files in an accessible
|
||||
directory and follow the Thin or Thick mode instructions below.
|
||||
|
||||
The files should be in a directory accessible to Python, not on the database
|
||||
server host.
|
||||
|
||||
**For python-oracledb Thin mode**
|
||||
|
||||
In python-oracledb Thin mode, you must specify the directory that contains the
|
||||
``tnsnames.ora`` file by either:
|
||||
|
||||
- Setting the `TNS_ADMIN <https://www.oracle.com/pls/topic/lookup?ctx=dblatest
|
||||
&id=GUID-12C94B15-2CE1-4B98-9D0C-8226A9DDF4CB>`__ environment variable to the
|
||||
directory containing the file
|
||||
|
||||
- Or setting :attr:`defaults.config_dir` to the directory containing the file.
|
||||
For example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import oracledb
|
||||
|
||||
oracledb.defaults.config_dir = "/opt/oracle/config"
|
||||
|
||||
- Or setting the ``config_dir`` parameter to the directory containing the file
|
||||
when :func:`connecting <oracledb.connect()>` or creating a
|
||||
:func:`connection pool <oracledb.create_pool()>`. For example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
connection = oracledb.connect(user="hr", password=userpwd, dsn="orclpdb",
|
||||
config_dir="/opt/oracle/config")
|
||||
|
||||
On Windows, when the path contains backslashes, use a 'raw' string like
|
||||
``r"C:\instantclient_19_18"``.
|
||||
|
||||
.. note::
|
||||
|
||||
In Thin mode, you must explicitly set the directory because traditional
|
||||
"default" locations such as the Instant Client ``network/admin/``
|
||||
subdirectory, or ``$ORACLE_HOME/network/admin/``, or
|
||||
``$ORACLE_BASE/homes/XYZ/network/admin/`` (in a read-only Oracle Database
|
||||
home) are not automatically looked in.
|
||||
|
||||
**For python-oracledb Thick mode**
|
||||
|
||||
In python-oracledb Thick mode, the directory containing the optional files can
|
||||
be explicitly specified or a default location will be used. Do one of:
|
||||
|
||||
- Set the ``config_dir`` parameter to the directory containing the files
|
||||
in the :meth:`oracledb.init_oracle_client()` call:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
oracledb.init_oracle_client(config_dir="/opt/oracle/config")
|
||||
|
||||
On Windows, when the path contains backslashes, use a 'raw' string like
|
||||
``r"C:\instantclient_19_18"``.
|
||||
|
||||
.. note::
|
||||
|
||||
In python-oracledb Thick mode, once an application has created its first
|
||||
connection, trying to change the configuration directory will not have any
|
||||
effect.
|
||||
|
||||
- If :meth:`~oracledb.init_oracle_client()` is called to enable Thick mode but
|
||||
``config_dir`` is not specified, then default directories are searched for the
|
||||
configuration files. They include:
|
||||
|
||||
- The directory specified by the `TNS_ADMIN <https://www.oracle.com/pls/
|
||||
topic/lookup?ctx=dblatest&id=GUID-12C94B15-2CE1-4B98-9D0C-8226A9DDF4CB>`__
|
||||
environment variable.
|
||||
|
||||
- For Oracle Instant Client ZIP files, the ``network/admin`` subdirectory of
|
||||
Instant Client, for example
|
||||
``/opt/oracle/instantclient_19_18/network/admin``.
|
||||
|
||||
- For Oracle Instant RPMs, the ``network/admin`` subdirectory of Instant
|
||||
Client, for example ``/usr/lib/oracle/19.18/client64/lib/network/admin``.
|
||||
|
||||
- When using libraries from a local Oracle Database or full client
|
||||
installation, in ``$ORACLE_HOME/network/admin`` or
|
||||
``$ORACLE_BASE_HOME/network/admin``.
|
||||
|
||||
Note that the :ref:`easyconnect` can set many common configuration options
|
||||
without needing ``tnsnames.ora`` or ``sqlnet.ora`` files.
|
||||
|
||||
The section :ref:`Network Configuration <hanetwork>` has additional information
|
||||
about Oracle Net configuration.
|
||||
|
||||
.. _envset:
|
||||
|
||||
Oracle Environment Variables for python-oracledb Thick Mode
|
||||
|
@ -491,9 +474,8 @@ first connection is established. System environment variables like
|
|||
|
||||
.. note::
|
||||
|
||||
The variables listed below are only supported in the python-oracledb Thick
|
||||
mode, with the exception of ``TNS_ADMIN`` and ``ORA_SDTZ`` which are also
|
||||
supported in the python-oracledb Thin mode.
|
||||
These variables, with the exception of ``TNS_ADMIN``, are only supported in
|
||||
the python-oracledb Thick mode. See :ref:`enablingthick`.
|
||||
|
||||
.. list-table-with-summary:: Common Oracle environment variables
|
||||
:header-rows: 1
|
||||
|
@ -507,7 +489,7 @@ first connection is established. System environment variables like
|
|||
* - 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_18``. This variable is not needed if the
|
||||
``/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``.
|
||||
|
@ -559,8 +541,8 @@ 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>`__.
|
||||
files, see `Choosing a Time Zone File
|
||||
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-805AB986-DE12-4FEA-AF56-5AABCD2132DF>`__.
|
||||
|
||||
.. _otherinit:
|
||||
|
||||
|
@ -569,19 +551,27 @@ Other python-oracledb Thick Mode Initialization
|
|||
|
||||
The :meth:`oracledb.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 that python-oracledb is being used. An example of
|
||||
setting the parameters is:
|
||||
end-users are not aware that python-oracledb is being used. An example of setting
|
||||
the parameters is:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
oracledb.init_oracle_client(driver_name="My Great App : 3.1.4",
|
||||
error_url="https://example.com/MyInstallInstructions.html")
|
||||
import oracledb
|
||||
import sys
|
||||
|
||||
try:
|
||||
oracledb.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 a value like ``python-oracledb thk : 1.2.0``
|
||||
is shown, see :ref:`vsessconinfo`.
|
||||
parameter is not specified, then a value like "python-oracledb thk : 1.0.0" is
|
||||
shown, see :ref:`vsessconinfo`.
|
||||
|
||||
The ``error_url`` string will be shown in the exception raised if
|
||||
``init_oracle_client()`` cannot load the Oracle Client libraries. This allows
|
||||
|
@ -614,4 +604,4 @@ If you have been using python-oracledb in Thick mode, you can use Thin mode by:
|
|||
|
||||
You can validate the python-oracledb mode by querying the ``CLIENT_DRIVER``
|
||||
column of ``V$SESSION_CONNECT_INFO`` and verifying if the value of the column
|
||||
begins with the text ``python-oracledb thn``. See :ref:`vsessconinfo`.
|
||||
begins with ``python-oracledb thn``. See :ref:`vsessconinfo`.
|
||||
|
|
|
@ -29,23 +29,30 @@ Specification.
|
|||
Quick Start python-oracledb Installation
|
||||
========================================
|
||||
|
||||
This section contains the steps needed to install python-oracledb.
|
||||
This section contains the steps that you need to perform to install python-oracledb
|
||||
quickly.
|
||||
|
||||
1. Install `Python 3 <https://www.python.org/downloads>`__ if it is not already
|
||||
available. Use any version from Python 3.7 through 3.12.
|
||||
1. Install `Python 3 <https://www.python.org/downloads>`__, if it is not already
|
||||
available. The version of Python to be used depends on the operating system (OS):
|
||||
|
||||
2. Install python-oracledb from `PyPI <https://pypi.org/project/oracledb/>`__,
|
||||
for example:
|
||||
- On Windows, use Python 3.7 to 3.11
|
||||
- On macOS, use Python 3.7 to 3.11
|
||||
- On Linux, use Python 3.6 to 3.11
|
||||
|
||||
By default, python-oracledb connects directly to Oracle Database. This lets
|
||||
it be used when Oracle Client libraries are not available (such Apple M1 or
|
||||
Alpine Linux), or where the client libraries are not easily installable (such
|
||||
as some cloud environments). Note not all environments are tested.
|
||||
|
||||
2. Install python-oracledb from `PyPI <https://pypi.org/project/oracledb/>`__:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
python -m pip install oracledb --upgrade
|
||||
|
||||
On some platforms the binary may be called ``python3`` instead of ``python``.
|
||||
|
||||
If a python-oracledb binary package is not available for your platform, the
|
||||
source package will be downloaded. This will be compiled and the resulting
|
||||
binary installed.
|
||||
If a binary 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 do not have permission to write to
|
||||
system directories:
|
||||
|
@ -54,27 +61,21 @@ This section contains the steps needed to install python-oracledb.
|
|||
|
||||
python -m pip install oracledb --upgrade --user
|
||||
|
||||
If you are behind a proxy, use the ``--proxy`` option. For example:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
python -m pip install oracledb --upgrade --proxy=http://proxy.example.com:80
|
||||
|
||||
By default, python-oracledb connects directly to Oracle Database. This lets
|
||||
it be used immediately without needing any additional installation of Oracle
|
||||
Client libraries.
|
||||
If you are behind a proxy, add a proxy server to the command, for example add
|
||||
``--proxy=http://proxy.example.com:80``
|
||||
|
||||
3. Create a file ``test.py`` such as:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import getpass
|
||||
# test.py
|
||||
|
||||
import oracledb
|
||||
import os
|
||||
|
||||
un = 'scott'
|
||||
cs = 'localhost/orclpdb'
|
||||
pw = getpass.getpass(f'Enter password for {un}@{cs}: ')
|
||||
un = os.environ.get('PYTHON_USERNAME')
|
||||
pw = os.environ.get('PYTHON_PASSWORD')
|
||||
cs = os.environ.get('PYTHON_CONNECTSTRING')
|
||||
|
||||
with oracledb.connect(user=un, password=pw, dsn=cs) as connection:
|
||||
with connection.cursor() as cursor:
|
||||
|
@ -82,43 +83,33 @@ This section contains the steps needed to install python-oracledb.
|
|||
for r in cursor.execute(sql):
|
||||
print(r)
|
||||
|
||||
4. Edit ``test.py`` and set the ``un`` and ``cs`` variables to your own
|
||||
database username and the database connection string, respectively.
|
||||
4. In your integrated development environment (IDE) or terminal window, set
|
||||
the three environment variables used by the test program.
|
||||
|
||||
A simple :ref:`connection <connhandling>` to the database requires an Oracle
|
||||
Database `user name and password
|
||||
<https://www.youtube.com/watch?v=WDJacg0NuLo>`_ and a database
|
||||
:ref:`connection string <connstr>`. For python-oracledb, a common
|
||||
connection string format is ``hostname:port/servicename``, using the host
|
||||
name where the database is running, the Oracle Database service name of the
|
||||
database instance, and the port that the database is using. If the default
|
||||
port 1521 is being used, then this component of the connection string is
|
||||
often omitted.
|
||||
|
||||
The database can be on-premises or in the Cloud. The python-oracledb driver
|
||||
does not include a database.
|
||||
A simple :ref:`connection <connhandling>` to the database requires an Oracle
|
||||
Database `user name and password
|
||||
<https://www.youtube.com/watch?v=WDJacg0NuLo>`_ and a database
|
||||
:ref:`connection string <connstr>`. Set the environment variables to your
|
||||
values. For python-oracledb, 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 database
|
||||
can be on-premises or in the Cloud. It should be version 12.1 or later. The
|
||||
python-oracledb driver does not include a database.
|
||||
|
||||
5. Run the program as shown below:
|
||||
|
||||
.. code-block:: shell
|
||||
.. code-block:: shell
|
||||
|
||||
python test.py
|
||||
|
||||
Enter the database password when prompted and the queried date will be shown,
|
||||
for example:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
Enter password for cj@localhost/orclpdb: xxxxxxxxxx
|
||||
(datetime.datetime(2023, 9, 21, 8, 24, 4),)
|
||||
|
||||
If you run into installation trouble, refer to detailed instructions below, or
|
||||
see :ref:`troubleshooting`.
|
||||
The date will be shown.
|
||||
|
||||
You can learn more about python-oracledb from the `python-oracledb
|
||||
documentation <https://python-oracledb.readthedocs.io/en/latest/index.html>`__
|
||||
and `samples <https://github.com/oracle/python-oracledb/tree/main/samples>`__.
|
||||
|
||||
If you run into installation trouble, see `Troubleshooting`_.
|
||||
|
||||
Supported Oracle Database Versions
|
||||
==================================
|
||||
|
||||
|
@ -126,15 +117,14 @@ When python-oracledb is used in the default Thin mode, it connects directly to
|
|||
the Oracle Database and does not require Oracle Client libraries. Connections
|
||||
in this mode can be made to Oracle Database 12.1 or later.
|
||||
|
||||
To connect to older Oracle Database releases you must have Oracle Client
|
||||
libraries installed, and enable python-oracledb's :ref:`Thick mode
|
||||
<enablingthick>`. Connections in this mode can be made to Oracle Database 9.2,
|
||||
or later, depending on the Oracle Client library version.
|
||||
To use the :ref:`Thick mode features <featuresummary>` of python-oracledb,
|
||||
additional Oracle Client libraries must be installed, as detailed in the
|
||||
subsequent sections. Connections in this mode can be made to Oracle
|
||||
Database 9.2, or later, depending on the Oracle Client library version.
|
||||
|
||||
In python-oracledb Thick mode, Oracle Database's standard client-server network
|
||||
interoperability allows connections between different versions of Oracle Client
|
||||
libraries and Oracle Database. For current or previously certified
|
||||
configurations, see Oracle Support's `Doc ID 207303.1
|
||||
Oracle's standard client-server network interoperability allows connections
|
||||
between different versions of Oracle Client libraries and Oracle Database. For
|
||||
currently certified configurations, see Oracle Support's `Doc ID 207303.1
|
||||
<https://support.oracle.com/epmos/faces/DocumentDisplay?id=207303.1>`__. In
|
||||
summary:
|
||||
|
||||
|
@ -155,14 +145,16 @@ then be used to adjust the application behavior accordingly. Any attempt to
|
|||
use Oracle features that are not supported by a particular mode or client
|
||||
library/database combination will result in runtime errors.
|
||||
|
||||
.. _instreq:
|
||||
|
||||
Installation Requirements
|
||||
=========================
|
||||
==========================
|
||||
|
||||
To use python-oracledb, you need:
|
||||
|
||||
- Python 3.7, 3.8, 3.9, 3.10, 3.11 or 3.12
|
||||
- Python 3.6, 3.7, 3.8, 3.9, 3.10 or 3.11 depending on the operating system:
|
||||
|
||||
- Windows: Use Python 3.7 to 3.11
|
||||
- macOS: Use Python 3.7 to 3.11
|
||||
- Linux: Use Python 3.6 to 3.11
|
||||
|
||||
- The Python cryptography package. This package is automatically installed as a
|
||||
dependency of python-oracledb. It is strongly recommended that you keep the
|
||||
|
@ -196,7 +188,7 @@ repository `PyPI <https://pypi.org/project/oracledb/>`__:
|
|||
|
||||
.. code-block:: shell
|
||||
|
||||
python -m pip install oracledb --upgrade
|
||||
python -m pip install oracledb
|
||||
|
||||
This will download and install a pre-compiled binary from `PyPI
|
||||
<https://pypi.org/project/oracledb/>`__ if one is available for your
|
||||
|
@ -210,7 +202,7 @@ install with:
|
|||
|
||||
.. code-block:: shell
|
||||
|
||||
python3 -m pip install oracledb --upgrade --user
|
||||
python3 -m pip install oracledb --user
|
||||
|
||||
The ``--user`` option is useful when you do not have permission to write to
|
||||
system directories.
|
||||
|
@ -218,11 +210,8 @@ system directories.
|
|||
Other versions of Python can be used on Oracle Linux, see `Python for Oracle
|
||||
Linux <https://yum.oracle.com/oracle-linux-python.html>`__.
|
||||
|
||||
If you are behind a proxy, use the ``--proxy`` option. For example:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
python -m pip install oracledb --upgrade --proxy=http://proxy.example.com:80
|
||||
If you are behind a proxy, add a proxy server to the command, for example add
|
||||
``--proxy=http://proxy.example.com:80``
|
||||
|
||||
|
||||
Optionally Install Oracle Client
|
||||
|
@ -240,8 +229,8 @@ Oracle Client libraries installed. Oracle Client versions 21, 19, 18, 12 and
|
|||
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 23c Free
|
||||
<https://www.oracle.com/database/free/>`__ release.
|
||||
installed database such as the free `Oracle Database Express Edition ("XE")
|
||||
<https://www.oracle.com/database/technologies/appdev/xe.html>`__ release.
|
||||
|
||||
To use python-oracledb in Thick mode you must call
|
||||
:meth:`oracledb.init_oracle_client()` in your application, see
|
||||
|
@ -270,12 +259,8 @@ To use python-oracledb Thick mode with Oracle Instant Client zip files:
|
|||
- `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 Database 19c is a Long Term Support Release whereas Oracle Database
|
||||
21c is an Innovation Release. It is recommended to keep up to date with the
|
||||
latest Oracle Instant Client release updates of your desired major version.
|
||||
|
||||
Oracle Instant Client 19c will connect to Oracle Database 11.2 or later.
|
||||
Oracle Instant Client 21c will connect to Oracle Database 12.1 or later.
|
||||
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:
|
||||
|
@ -314,10 +299,6 @@ To use python-oracledb Thick mode with Oracle Instant Client zip files:
|
|||
|
||||
export LD_LIBRARY_PATH=/opt/oracle/instantclient_21_6:$LD_LIBRARY_PATH
|
||||
|
||||
Make sure this is set in each shell that invokes Python. Web servers and
|
||||
other daemons commonly reset environment variables so using ``ldconfig`` is
|
||||
generally preferred instead.
|
||||
|
||||
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
|
||||
|
@ -359,12 +340,8 @@ To use python-oracledb with Oracle Instant Client RPMs:
|
|||
- `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>`__
|
||||
|
||||
Oracle Database 19c is a Long Term Support Release whereas Oracle Database
|
||||
21c is an Innovation Release. It is recommended to keep up to date with the
|
||||
latest Oracle Instant Client release updates of your desired major version.
|
||||
|
||||
Oracle Instant Client 19c will connect to Oracle Database 11.2 or later.
|
||||
Oracle Instant Client 21c will connect to Oracle Database 12.1 or later.
|
||||
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:
|
||||
|
||||
|
@ -396,9 +373,6 @@ To use python-oracledb with Oracle Instant Client RPMs:
|
|||
|
||||
export LD_LIBRARY_PATH=/usr/lib/oracle/18.5/client64/lib:$LD_LIBRARY_PATH
|
||||
|
||||
Web servers and other daemons commonly reset environment variables so using
|
||||
``ldconfig`` is generally preferred instead.
|
||||
|
||||
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
|
||||
|
@ -466,13 +440,14 @@ Use Python's `pip <https://pip.pypa.io/en/latest/installation/>`__ package
|
|||
to install python-oracledb from Python's package repository `PyPI
|
||||
<https://pypi.org/project/oracledb/>`__::
|
||||
|
||||
python -m pip install oracledb --upgrade
|
||||
python -m pip install oracledb
|
||||
|
||||
If you are behind a proxy, use the ``--proxy`` option. For example:
|
||||
If you are behind a proxy, add a proxy server to the command, for example add
|
||||
``--proxy=http://proxy.example.com:80``
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
python -m pip install oracledb --upgrade --proxy=http://proxy.example.com:80
|
||||
python -m pip install oracledb --proxy=http://proxy.example.com:80 --upgrade
|
||||
|
||||
This will download and install a pre-compiled binary `if one is available
|
||||
<https://pypi.org/project/oracledb/>`__ for your architecture. If a
|
||||
|
@ -659,27 +634,27 @@ to install python-oracledb from Python's package repository `PyPI
|
|||
|
||||
.. code-block:: shell
|
||||
|
||||
python -m pip install oracledb --upgrade
|
||||
python -m pip install oracledb
|
||||
|
||||
The ``--user`` option may be useful if you do not have permission to write to
|
||||
system directories:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
python -m pip install oracledb --upgrade --user
|
||||
|
||||
If you are behind a proxy, use the ``--proxy`` option. For example:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
python -m pip install oracledb --upgrade --proxy=http://proxy.example.com:80
|
||||
python -m pip install oracledb --user
|
||||
|
||||
To install into the system Python, you may need to use ``/usr/bin/python3``
|
||||
instead of ``python``:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
/usr/bin/python3 -m pip install oracledb --upgrade --user
|
||||
/usr/bin/python3 -m pip install oracledb --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.
|
||||
|
||||
Optionally Install Oracle Client
|
||||
--------------------------------
|
||||
|
@ -812,8 +787,6 @@ code:
|
|||
|
||||
- C Compiler: A C99 compiler is needed.
|
||||
|
||||
.. _installgh:
|
||||
|
||||
Install Using GitHub
|
||||
--------------------
|
||||
|
||||
|
@ -824,11 +797,6 @@ In order to install using the source on GitHub, use the following commands::
|
|||
python setup.py build
|
||||
python setup.py install
|
||||
|
||||
If you do not have access to system directories, the ``--user`` option can be
|
||||
used to install into a local directory::
|
||||
|
||||
python setup.py install --user
|
||||
|
||||
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 put the extracted contents inside the "odpi" subdirectory, for example
|
||||
|
@ -842,6 +810,12 @@ can be installed with::
|
|||
python setup.py build
|
||||
python setup.py install
|
||||
|
||||
If you do not have access to system directories, the ``--user`` option can be
|
||||
used to install into a local directory::
|
||||
|
||||
python setup.py install --user
|
||||
|
||||
|
||||
Install Using Source from PyPI
|
||||
------------------------------
|
||||
|
||||
|
@ -856,3 +830,131 @@ If you do not have access to system directories, the ``--user`` option can be
|
|||
used to install into a local directory::
|
||||
|
||||
python setup.py install --user
|
||||
|
||||
.. _troubleshooting:
|
||||
|
||||
Troubleshooting
|
||||
===============
|
||||
|
||||
Installation Troubleshooting
|
||||
----------------------------
|
||||
|
||||
If installation fails:
|
||||
|
||||
- An error such as ``not a supported wheel on this platform.`` indicates that
|
||||
you may be using an older `pip` version. Upgrade it with the following
|
||||
command:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
python -m pip install pip --upgrade --user
|
||||
|
||||
- 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.
|
||||
|
||||
- If there was a network connection error, check if you need to set the
|
||||
environment variables ``http_proxy`` and/or ``https_proxy`` or
|
||||
try ``python -m pip install --proxy=http://proxy.example.com:80 oracledb
|
||||
--upgrade``.
|
||||
|
||||
- If the upgrade did not give any errors but the old version is still
|
||||
installed, try ``python -m pip install oracledb --upgrade
|
||||
--force-reinstall``.
|
||||
|
||||
- If you do not have access to modify your system version of
|
||||
Python, then use ``python -m pip install oracledb --upgrade --user``
|
||||
or venv.
|
||||
|
||||
- If you get the error ``No module named pip``, it means that the pip module
|
||||
that is built into Python may sometimes be removed by the OS. Use the venv
|
||||
module (built into Python 3.x) or virtualenv module instead.
|
||||
|
||||
- If you get the error ``fatal error: dpi.h: No such file or directory``
|
||||
when building from source code, then ensure that your source installation has
|
||||
a subdirectory called "odpi" containing files. If this is missing, review the
|
||||
section on `Install Using GitHub`_.
|
||||
|
||||
.. _runtimetroubleshooting:
|
||||
|
||||
Runtime Error Troubleshooting
|
||||
-----------------------------
|
||||
|
||||
If using python-oracledb fails:
|
||||
|
||||
- If you have multiple versions of Python installed, ensure that you are
|
||||
using the correct python and pip (or python3 and pip3) executables.
|
||||
|
||||
- If you get the error ``DPI-1047: Oracle Client library cannot be
|
||||
loaded``:
|
||||
|
||||
- Review the :ref:`features available in python-oracledb's default Thin mode
|
||||
<featuresummary>`. If Thin mode suits your requirements, then remove calls
|
||||
in your application to :meth:`oracledb.init_oracle_client()` since this
|
||||
loads the Oracle Client library to enable Thick mode.
|
||||
|
||||
- On Windows and macOS, pass the ``lib_dir`` library directory parameter
|
||||
in your :meth:`oracledb.init_oracle_client()` call. The parameter
|
||||
should be the location of your Oracle Client libraries. Do not pass
|
||||
this parameter on Linux.
|
||||
|
||||
- Check that the Python process has permission to open the Oracle Client
|
||||
libraries. OS restrictions may prevent the opening of libraries installed
|
||||
in unsafe paths, such as from a user directory. On Linux you may need to
|
||||
install the Oracle Client libraries under a directory like ``/opt`` or
|
||||
``/usr/local``.
|
||||
|
||||
- Check if 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
|
||||
python-oracledb. The trace messages will show how and where
|
||||
python-oracledb 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 have a full database installation, ensure that 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 passing a library directory parameter
|
||||
to :meth:`oracledb.init_oracle_client()`, then restart your command
|
||||
prompt and use ``set PATH`` to check if 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 :meth:`oracledb.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 if the ``LD_LIBRARY_PATH`` environment variable contains
|
||||
the Oracle Client library directory. Some environments such as web servers
|
||||
reset environment variables. If you are using Oracle Instant Client, a
|
||||
preferred alternative to ``LD_LIBRARY_PATH`` is to ensure that a file in
|
||||
the ``/etc/ld.so.conf.d`` directory contains the path to the Instant Client
|
||||
directory, and then run ``ldconfig``.
|
||||
|
||||
- If you get the error ``DPY-3010: connections to this database server
|
||||
version are not supported by python-oracledb in thin mode`` when
|
||||
connecting to Oracle Database 11.2, then you need to enable Thick mode by
|
||||
installing Oracle Client libraries and calling
|
||||
:meth:`oracledb.init_oracle_client()` in your code. Alternatively,
|
||||
upgrade your database.
|
||||
|
||||
- If you get the error ``DPI-1072: the Oracle Client library version is
|
||||
unsupported``, then review the installation requirements. The Thick
|
||||
mode of python-oracledb 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. You may be able to use Thin mode which
|
||||
can be done by removing calls :meth:`oracledb.init_oracle_client()` from
|
||||
your code.
|
||||
|
|
|
@ -8,7 +8,6 @@ The python-oracledb driver is a Python extension module that enables access to
|
|||
Oracle Database. It has comprehensive functionality supporting 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.
|
||||
Synchronous and :ref:`concurrent <asyncio>` coding styles are supported.
|
||||
|
||||
The python-oracledb driver is the renamed, major version successor to
|
||||
`cx_Oracle 8.3 <https://oracle.github.io/python-cx_Oracle/>`__. For upgrade
|
||||
|
|
|
@ -15,34 +15,13 @@ 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>`__.
|
||||
|
||||
**Oracle Database 21c JSON Data Type**
|
||||
|
||||
Oracle Database 21c introduced a dedicated JSON data type with a new `binary
|
||||
storage format <https://blogs.oracle.com/jsondb/osonformat>`__ that improves
|
||||
performance and functionality compared with earlier releases. To take
|
||||
advantage of the dedicated JSON type with Oracle Database 21c, or later, you
|
||||
can use python-oracledb in Thin or Thick modes. With Thick mode the Oracle
|
||||
Client libraries should be version 21, or later.
|
||||
|
||||
To create a table with a column called ``JSON_DATA`` for JSON data you might
|
||||
use:
|
||||
|
||||
.. code-block:: sql
|
||||
|
||||
create table CustomersAsJson (
|
||||
id integer not null primary key,
|
||||
json_data json
|
||||
);
|
||||
|
||||
|
||||
**Oracle Database 12c JSON Data Type**
|
||||
|
||||
In Oracle Database 12c, or later, JSON in relational tables can be stored as
|
||||
BLOB, CLOB or VARCHAR2 data. All of these types can be used with
|
||||
python-oracledb in Thin or Thick modes. BLOB is preferred to avoid character
|
||||
set conversion overheads.
|
||||
In Oracle Database 12c, JSON in relational tables is stored as BLOB, CLOB or
|
||||
VARCHAR2 data. All of these types can be used with python-oracledb in Thin or
|
||||
Thick modes.
|
||||
|
||||
The syntax to create a table with a JSON column using BLOB storage is like:
|
||||
The older syntax to create a table with a JSON column is like:
|
||||
|
||||
.. code-block:: sql
|
||||
|
||||
|
@ -54,15 +33,35 @@ The syntax to create a table with a JSON column using BLOB storage is like:
|
|||
The check constraint with the clause ``IS JSON`` ensures only JSON data is
|
||||
stored in that column.
|
||||
|
||||
This older syntax can still be used in Oracle Database 21c (and later);
|
||||
however, the recommendation is to move to the new JSON type.
|
||||
The older syntax can still be used in Oracle Database 21c; 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 the Oracle Database 21c JSON Type in python-oracledb
|
||||
==========================================================
|
||||
**Oracle Database 21c JSON Data Type**
|
||||
|
||||
Using python-oracledb Thin mode with Oracle Database 21c, or using Thick mode
|
||||
with Oracle Database 21c and Oracle Client 21c (or later), you can insert by
|
||||
binding as shown below:
|
||||
Oracle Database 21c introduced a dedicated JSON data type with a new `binary
|
||||
storage format <https://blogs.oracle.com/jsondb/osonformat>`__ that improves
|
||||
performance and functionality. To fully take advantage of the dedicated JSON
|
||||
type, use python-oracledb in Thick mode with Oracle Client libraries version
|
||||
21, or later.
|
||||
|
||||
In Oracle Database 21, to create a table with a column called ``JSON_DATA`` for
|
||||
JSON data you might use:
|
||||
|
||||
.. code-block:: sql
|
||||
|
||||
create table CustomersAsJson (
|
||||
id integer not null primary key,
|
||||
json_data json
|
||||
);
|
||||
|
||||
|
||||
Using the Oracle Database 21c JSON Type in python-oracledb Thick Mode
|
||||
=====================================================================
|
||||
|
||||
Using python-oracledb Thick mode with Oracle Database 21c and Oracle Client 21c
|
||||
(or later), you can insert by binding as shown below:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
@ -75,8 +74,6 @@ binding as shown below:
|
|||
cursor.setinputsizes(None, oracledb.DB_TYPE_JSON)
|
||||
cursor.execute(insert_sql, [1, data])
|
||||
|
||||
.. _json21fetch:
|
||||
|
||||
To fetch a JSON column, use:
|
||||
|
||||
.. code-block:: python
|
||||
|
@ -85,49 +82,84 @@ To fetch a JSON column, use:
|
|||
print(row)
|
||||
|
||||
See `json_direct.py
|
||||
<https://github.com/oracle/python-oracledb/tree/main/samples/json_direct.py>`__
|
||||
<https://github.com/oracle/python-oracledb/tree/main/samplesjson_direct.py>`__
|
||||
for a runnable example. The example also shows how to use this type when
|
||||
python-oracledb Thick mode uses older Oracle Client libraries.
|
||||
|
||||
Using the Oracle Database 21c JSON Type and python-oracledb Thin Mode
|
||||
=====================================================================
|
||||
|
||||
Using python-oracledb Thin mode with Oracle Database 21c, you can insert into a
|
||||
JSON column as shown below:
|
||||
|
||||
.. code:: python
|
||||
|
||||
data = [
|
||||
(1, dict(name="Rod", dept="Sales", location="Germany")),
|
||||
(2, dict(name="George", dept="Marketing", location="Bangalore")),
|
||||
(3, dict(name="Sam", dept="Sales", location="Mumbai")),
|
||||
(4, dict(name="Jill", dept="Marketing", location="Germany"))
|
||||
]
|
||||
|
||||
insert_sql = "insert into CustomersAsJson values (:1, :2)"
|
||||
|
||||
# Insert the data as a JSON string
|
||||
cursor.executemany(insert_sql, [(i, json.dumps(j)) for i, j in data])
|
||||
|
||||
For python-oracledb Thin mode, a type handler is required to fetch the Oracle
|
||||
21c JSON datatype. If a type handler is used in the python-oracledb Thick
|
||||
mode, then the behavior is same in both the python-oracledb modes. The
|
||||
following example shows a type handler:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def my_type_handler(cursor, name, default_type, size, precision, scale):
|
||||
if default_type == oracledb.DB_TYPE_JSON:
|
||||
return cursor.var(str, arraysize=cursor.arraysize, outconverter=json.loads)
|
||||
|
||||
cursor.outputtypehandler = my_type_handler
|
||||
|
||||
for row in cursor.execute("select * from CustomersAsJson"):
|
||||
print(row)
|
||||
|
||||
With a type handler, the python-oracledb Thin mode is equivalent
|
||||
to using the python-oracledb Thick mode with Oracle Client 21c. The
|
||||
python-oracledb Thin mode returns timestamps in a string representation.
|
||||
Without a type handler, the python-oracledb Thin mode gives an error that
|
||||
``DB_TYPE_JSON`` is not supported.
|
||||
|
||||
A type handler is not needed when fetching from the Oracle Database 19c JSON
|
||||
type, since this is represented as VARCHAR2 or LOB.
|
||||
|
||||
See `json_type.py
|
||||
<https://github.com/oracle/python-oracledb/tree/main/samplesjson_type.py>`__
|
||||
for a runnable example.
|
||||
|
||||
Using the Oracle 12c JSON type in python-oracledb
|
||||
=================================================
|
||||
|
||||
When using Oracle Database 12c or later with JSON using BLOB storage, you can
|
||||
insert JSON strings like:
|
||||
When using Oracle Database 12c or later with JSON using BLOB storage to insert
|
||||
JSON strings, use:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import json
|
||||
|
||||
data = dict(name="Rod", dept="Sales", location="Germany")
|
||||
inssql = "insert into CustomersAsBlob values (:1, :2)"
|
||||
|
||||
cursor.execute(inssql, [1, json.dumps(data)])
|
||||
|
||||
You can fetch VARCHAR2 and LOB columns that contain JSON data in the same way
|
||||
that :ref:`JSON type columns <json21fetch>` are fetched when using Oracle
|
||||
Database 21c or later. If you are using python-oracledb Thick mode, you must
|
||||
use Oracle Client 19c (or later). For example:
|
||||
To fetch JSON strings, use:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
for row in cursor.execute("select * from CustomersAsBlob"):
|
||||
print(row)
|
||||
import json
|
||||
|
||||
.. versionchanged:: 2.0
|
||||
|
||||
Previously, the ``oracledb.__future__.old_json_col_as_obj`` attribute
|
||||
needed to be set to *True* to fetch VARCHAR2 and LOB columns that
|
||||
contained JSON data. Also, you could fetch JSON data without setting this
|
||||
attribute with a call to ``json.loads()`` on the returned data. With this
|
||||
change, the ``oracledb.__future__.old_json_col_as_obj`` attribute is
|
||||
desupported. VARCHAR2 and LOB columns containing JSON data can now be
|
||||
fetched directly without setting the
|
||||
``oracledb.__future__.old_json_col_as_obj`` attribute or without needing
|
||||
to call ``json.loads()`` on the value.
|
||||
sql = "SELECT c.json_data FROM CustomersAsBlob c"
|
||||
for j, in cursor.execute(sql):
|
||||
print(json.loads(j.read()))
|
||||
|
||||
See `json_blob.py
|
||||
<https://github.com/oracle/python-oracledb/tree/main/samples/json_blob.py>`__
|
||||
<https://github.com/oracle/python-oracledb/tree/main/samplesjson_blob.py>`__
|
||||
for a runnable example.
|
||||
|
||||
IN Bind Type Mapping
|
||||
|
@ -213,18 +245,17 @@ 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'])
|
||||
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 python-oracledb, 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
|
||||
===============================
|
||||
|
||||
|
@ -298,16 +329,10 @@ some JSON data. To look for JSON entries that have a ``location`` field:
|
|||
|
||||
.. code-block:: python
|
||||
|
||||
import json
|
||||
|
||||
for blob, in cursor.execute("""
|
||||
select
|
||||
json_data
|
||||
from
|
||||
customers
|
||||
where
|
||||
json_exists(json_data,
|
||||
'$.location')"""):
|
||||
select json_data
|
||||
from customers
|
||||
where json_exists(json_data, '$.location')"""):
|
||||
data = json.loads(blob.read())
|
||||
print(data)
|
||||
|
||||
|
@ -326,6 +351,7 @@ For more information, see `SQL/JSON Path Expressions
|
|||
id=GUID-2DC05D71-3D62-4A14-855F-76E054032494>`__
|
||||
in the Oracle JSON Developer's Guide.
|
||||
|
||||
|
||||
Accessing Relational Data as JSON
|
||||
=================================
|
||||
|
||||
|
@ -336,15 +362,10 @@ 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""",
|
||||
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)
|
||||
|
@ -355,30 +376,3 @@ This produces::
|
|||
('{"deptId":20,"name":"Marketing"}',)
|
||||
('{"deptId":30,"name":"Purchasing"}',)
|
||||
('{"deptId":40,"name":"Human Resources"}',)
|
||||
|
||||
To select a result set from a relational query as a single object you can use
|
||||
`JSON_ARRAYAGG
|
||||
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-6D56077D-78DE-4CC0-9498-225DDC42E054>`__,
|
||||
for example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
oracledb.defaults.fetch_lobs = False
|
||||
|
||||
cursor.execute("""
|
||||
select
|
||||
json_arrayagg(
|
||||
json_object('deptid' is d.department_id,
|
||||
'name' is d.department_name) returning clob)
|
||||
from
|
||||
departments d
|
||||
where
|
||||
department_id < :did""",
|
||||
[50]);
|
||||
j, = cursor.fetchone()
|
||||
print(j)
|
||||
|
||||
|
||||
This produces::
|
||||
|
||||
[{"deptid":10,"name":"Administration"},{"deptid":20,"name":"Marketing"},{"deptid":30,"name":"Purchasing"},{"deptid":40,"name":"Human Resources"}]
|
||||
|
|
|
@ -107,12 +107,12 @@ handler:
|
|||
|
||||
.. code-block:: python
|
||||
|
||||
def output_type_handler(cursor, metadata):
|
||||
if metadata.type_code is oracledb.DB_TYPE_CLOB:
|
||||
def output_type_handler(cursor, name, default_type, size, precision, scale):
|
||||
if default_type == oracledb.DB_TYPE_CLOB:
|
||||
return cursor.var(oracledb.DB_TYPE_LONG, arraysize=cursor.arraysize)
|
||||
if metadata.type_code is oracledb.DB_TYPE_BLOB:
|
||||
if default_type == oracledb.DB_TYPE_BLOB:
|
||||
return cursor.var(oracledb.DB_TYPE_LONG_RAW, arraysize=cursor.arraysize)
|
||||
if metadata.type_code is oracledb.DB_TYPE_NCLOB:
|
||||
if default_type == oracledb.DB_TYPE_NCLOB:
|
||||
return cursor.var(oracledb.DB_TYPE_LONG_NVARCHAR, arraysize=cursor.arraysize)
|
||||
|
||||
connection.outputtypehandler = output_type_handler
|
||||
|
|
|
@ -34,8 +34,8 @@ then the following Python code can be used to call it:
|
|||
cursor.callproc('myproc', [123, out_val])
|
||||
print(out_val.getvalue()) # will print 246
|
||||
|
||||
Calling :meth:`Cursor.callproc()` internally generates an :ref:`anonymous PL/SQL
|
||||
block <anonplsql>` and executes it. This is equivalent to the application code:
|
||||
Calling :meth:`Cursor.callproc()` actually generates an anonymous PL/SQL block
|
||||
as shown below, which is then executed:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
@ -113,8 +113,6 @@ The Python code that will call this procedure looks as follows:
|
|||
See :ref:`bind` for information on binding.
|
||||
|
||||
|
||||
.. _anonplsql:
|
||||
|
||||
Anonymous PL/SQL Blocks
|
||||
-----------------------
|
||||
|
||||
|
@ -136,56 +134,34 @@ Creating Stored Procedures and Packages
|
|||
---------------------------------------
|
||||
|
||||
To create PL/SQL stored procedures and packages, use :meth:`Cursor.execute()`
|
||||
with a CREATE command. For example:
|
||||
with a SQL CREATE command.
|
||||
|
||||
.. code-block:: python
|
||||
Creation warning messages can be found from database views like USER_ERRORS.
|
||||
|
||||
cursor.execute("""
|
||||
create or replace procedure myprocedure
|
||||
(p_in in number, p_out out number) as
|
||||
begin
|
||||
p_out := p_in * 2;
|
||||
end;""")
|
||||
|
||||
.. _plsqlwarning:
|
||||
|
||||
PL/SQL Compilation Warnings
|
||||
+++++++++++++++++++++++++++
|
||||
|
||||
When creating PL/SQL procedures and functions (or creating types) in
|
||||
python-oracledb, the statement might succeed without throwing an error, but
|
||||
there may be additional informational messages. (These messages are sometimes
|
||||
known in Oracle as "success with info" messages). If your application needs to
|
||||
show such messages, they must be explicitly looked for using
|
||||
:attr:`Cursor.warning`. A subsequent query from a table like ``USER_ERRORS``
|
||||
will show more details. For example:
|
||||
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 as
|
||||
create or replace procedure badproc (a in number) as
|
||||
begin
|
||||
WRONG WRONG WRONG
|
||||
end;""")
|
||||
|
||||
if cursor.warning and cursor.warning.full_code == "DPY-7000":
|
||||
print(cursor.warning)
|
||||
|
||||
# Get details
|
||||
cursor.execute("""
|
||||
select line, position, text
|
||||
from user_errors
|
||||
where name = 'BADPROC' and type = 'PROCEDURE'
|
||||
order by line, position""")
|
||||
for info in cursor:
|
||||
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::
|
||||
|
||||
DPY-7000: creation succeeded with compilation errors
|
||||
Error at line 3 position 23:
|
||||
PLS-00103: Encountered the symbol "WRONG" when expecting one of the following:
|
||||
|
||||
:= . ( @ % ;
|
||||
|
|
|
@ -16,27 +16,23 @@ 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`.
|
||||
|
||||
Python-oracledb can be used to execute individual statements, one at a time.
|
||||
Once a statement has finished execution, only then will the next statement
|
||||
execute. If you try to execute statements concurrently, the statements are
|
||||
queued and run consecutively in the order they are in the code.
|
||||
|
||||
Python-oracledb 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-oracledb/blob/main/samples/sample_env.py>`__.
|
||||
Python-oracledb 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-oracledb/blob/main/samples/sample_env.py>`__
|
||||
|
||||
SQL statements should not contain a trailing semicolon (";") or forward slash
|
||||
("/"). This will fail:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
cursor.execute("select * from MyTable;")
|
||||
cur.execute("select * from MyTable;")
|
||||
|
||||
This is correct:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
cursor.execute("select * from MyTable")
|
||||
cur.execute("select * from MyTable")
|
||||
|
||||
|
||||
SQL Queries
|
||||
|
@ -52,107 +48,87 @@ optionally :ref:`overridden <outputtypehandlers>`.
|
|||
.. IMPORTANT::
|
||||
|
||||
Interpolating or concatenating user data with SQL statements, for example
|
||||
``cursor.execute("SELECT * FROM mytab WHERE mycol = '" + myvar + "'")``, is a security risk
|
||||
``cur.execute("SELECT * FROM mytab WHERE mycol = '" + myvar + "'")``, is a security risk
|
||||
and impacts performance. Use :ref:`bind variables <bind>` instead. For
|
||||
example, ``cursor.execute("SELECT * FROM mytab WHERE mycol = :mybv", mybv=myvar)``.
|
||||
example, ``cur.execute("SELECT * FROM mytab WHERE mycol = :mybv", mybv=myvar)``.
|
||||
|
||||
.. _fetching:
|
||||
|
||||
Fetch Methods
|
||||
-------------
|
||||
|
||||
Rows can be fetched in various ways.
|
||||
After :meth:`Cursor.execute()`, the cursor is returned as a convenience. This
|
||||
allows code to iterate over rows like:
|
||||
|
||||
- After :meth:`Cursor.execute()`, the cursor is returned as a convenience. This
|
||||
allows code to iterate over rows like:
|
||||
.. code-block:: python
|
||||
|
||||
.. code-block:: python
|
||||
cur = connection.cursor()
|
||||
for row in cur.execute("select * from MyTable"):
|
||||
print(row)
|
||||
|
||||
cursor = connection.cursor()
|
||||
for row in cursor.execute("select * from MyTable"):
|
||||
print(row)
|
||||
Rows can also be fetched one at a time using the method
|
||||
:meth:`Cursor.fetchone()`:
|
||||
|
||||
- Rows can also be fetched one at a time using the method
|
||||
:meth:`Cursor.fetchone()`:
|
||||
.. code-block:: python
|
||||
|
||||
.. code-block:: python
|
||||
cur = connection.cursor()
|
||||
cur.execute("select * from MyTable")
|
||||
while True:
|
||||
row = cur.fetchone()
|
||||
if row is None:
|
||||
break
|
||||
print(row)
|
||||
|
||||
cursor = connection.cursor()
|
||||
cursor.execute("select * from MyTable")
|
||||
while True:
|
||||
row = cursor.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`.
|
||||
|
||||
- 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 ``size`` parameter,
|
||||
which defaults to the value of :attr:`Cursor.arraysize`.
|
||||
.. code-block:: python
|
||||
|
||||
.. 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)
|
||||
|
||||
cursor = connection.cursor()
|
||||
cursor.execute("select * from MyTable")
|
||||
num_rows = 10
|
||||
while True:
|
||||
rows = cursor.fetchmany(size=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.
|
||||
|
||||
Note the ``size`` parameter only affects the number of rows returned to the
|
||||
application, not to the internal buffer size used for tuning fetch
|
||||
performance. That internal buffer size is controlled only by changing
|
||||
:attr:`Cursor.arraysize`, see :ref:`tuningfetch`.
|
||||
.. code-block:: python
|
||||
|
||||
- If all of the rows need to be fetched and can be contained in memory, the
|
||||
method :meth:`Cursor.fetchall()` can be used.
|
||||
cur = connection.cursor()
|
||||
cur.execute("select * from MyTable")
|
||||
rows = cur.fetchall()
|
||||
for row in rows:
|
||||
print(row)
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
cursor = connection.cursor()
|
||||
cursor.execute("select * from MyTable")
|
||||
rows = cursor.fetchall()
|
||||
for row in rows:
|
||||
print(row)
|
||||
|
||||
The fetch methods return data as tuples. To return results as dictionaries, see
|
||||
:ref:`rowfactories`.
|
||||
The fetch methods return data as tuples. To return results as dictionaries, see
|
||||
:ref:`rowfactories`.
|
||||
|
||||
Closing Cursors
|
||||
---------------
|
||||
|
||||
Once cursors are no longer needed, they should be closed in order to reclaim
|
||||
resources in the database. Note cursors may be used to execute multiple
|
||||
statements.
|
||||
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:
|
||||
|
||||
Cursors can be closed in various ways:
|
||||
.. code-block:: python
|
||||
|
||||
- A cursor will be closed automatically when the variable referencing it goes out
|
||||
of scope (and no further references are retained). A ``with`` block is a
|
||||
convenient way to ensure this. 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
|
||||
database resources can be reclaimed. In addition, any attempt to use the
|
||||
variable ``cursor`` outside of the block will fail.
|
||||
|
||||
- Cursors can be explicitly closed by calling :meth:`~Cursor.close()`
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
cursor = connection.cursor()
|
||||
|
||||
...
|
||||
|
||||
cursor.close()
|
||||
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:
|
||||
|
||||
|
@ -164,9 +140,9 @@ can be obtained using :attr:`Cursor.description`:
|
|||
|
||||
.. code-block:: python
|
||||
|
||||
cursor = connection.cursor()
|
||||
cursor.execute("select * from MyTable")
|
||||
for column in cursor.description:
|
||||
cur = connection.cursor()
|
||||
cur.execute("select * from MyTable")
|
||||
for column in cur.description:
|
||||
print(column)
|
||||
|
||||
This could result in metadata like::
|
||||
|
@ -284,155 +260,132 @@ Python object that is returned by default. Python types can be changed with
|
|||
scalar value is returned.
|
||||
|
||||
|
||||
.. _changingdata:
|
||||
|
||||
Changing Fetched Data
|
||||
---------------------
|
||||
|
||||
Data returned by python-oracledb queries can be changed by using output type
|
||||
handlers, by using "outconverters", or by using row factories.
|
||||
|
||||
.. _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. This asks the database to do a conversion from the column type to a
|
||||
different type before the data is returned from the database to
|
||||
python-oracledb. If the database does not support such a mapping, an error
|
||||
will be returned. Output type handlers only affect query output and do not
|
||||
affect values returned from :meth:`Cursor.callfunc()` or
|
||||
:meth:`Cursor.callproc()`.
|
||||
queries. Output type handlers do not affect values returned from
|
||||
:meth:`Cursor.callfunc()` or :meth:`Cursor.callproc()`.
|
||||
|
||||
Output type handlers can be specified on a :attr:`connection
|
||||
<Connection.outputtypehandler>` or on a :attr:`cursor
|
||||
<Cursor.outputtypehandler>`. If specified on a cursor, fetch type handling is
|
||||
only changed on that particular cursor. If specified on a connection, all
|
||||
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, metadata)
|
||||
handler(cursor, name, defaultType, size, precision, scale)
|
||||
|
||||
The metadata parameter is a :ref:`FetchInfo object<fetchinfoobj>`, which is the
|
||||
same value found in :attr:`Cursor.description`.
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
For example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def output_type_handler(cursor, metadata):
|
||||
if metadata.type_code is oracledb.DB_TYPE_NUMBER:
|
||||
return cursor.var(oracledb.DB_TYPE_VARCHAR, arraysize=cursor.arraysize)
|
||||
|
||||
This output type handler is called once for each column in the SELECT query.
|
||||
For each numeric column, the database will now return a string representation
|
||||
of each row's value. Using it in a query:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
cursor.outputtypehandler = output_type_handler
|
||||
|
||||
cursor.execute("select 123 from dual")
|
||||
r = cursor.fetchone()
|
||||
print(r)
|
||||
|
||||
prints ``('123',)`` showing the number was converted to a string. Without the
|
||||
type handler, the output would have been ``(123,)``.
|
||||
|
||||
When creating variables using :meth:`Cursor.var()` in a handler, the
|
||||
``arraysize`` parameter should be the same as the :attr:`~Cursor.arraysize` of
|
||||
the query cursor. In python-oracledb Thick mode, the query (and ``var()``)
|
||||
arraysize multiplied by the byte size of the particular column must be less
|
||||
than INT_MAX.
|
||||
|
||||
To unset an output type handler, set it to ``None``. For example if you had
|
||||
previously set a type handler on a cursor, you can remove it with:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
cursor.outputtypehandler = None
|
||||
|
||||
Other 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
|
||||
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-oracledb/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 python-oracledb 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 == oracledb.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-oracledb/blob/main/samples/return_numbers_as_decimals.py>`__
|
||||
|
||||
|
||||
.. _outconverters:
|
||||
|
||||
Changing Query Results with Outconverters
|
||||
+++++++++++++++++++++++++++++++++++++++++
|
||||
-----------------------------------------
|
||||
|
||||
Python-oracledb "outconverters" can be used with :ref:`output type handlers
|
||||
<outputtypehandlers>` to change returned data.
|
||||
|
||||
For example:
|
||||
For example, to make queries return empty strings instead of NULLs:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def output_type_handler(cursor, metadata):
|
||||
def out_converter(value):
|
||||
if value is None:
|
||||
return ''
|
||||
return value
|
||||
|
||||
def out_converter(d):
|
||||
if isinstance(d, str):
|
||||
return f"{d} was a string"
|
||||
else:
|
||||
return f"{d} was not a string"
|
||||
def output_type_handler(cursor, name, default_type, size, precision, scale):
|
||||
if default_type in (oracledb.DB_TYPE_VARCHAR, oracledb.DB_TYPE_CHAR):
|
||||
return cursor.var(str, size, arraysize=cur.arraysize,
|
||||
outconverter=out_converter)
|
||||
|
||||
if metadata.type_code is oracledb.DB_TYPE_NUMBER:
|
||||
return cursor.var(oracledb.DB_TYPE_VARCHAR,
|
||||
arraysize=cursor.arraysize, outconverter=out_converter)
|
||||
connection.outputtypehandler = output_type_handler
|
||||
|
||||
The output type handler is called once for each column in the SELECT query.
|
||||
For each numeric column, the database will now return a string representation
|
||||
of each row's value. The outconverter will then be called in Python for each
|
||||
of those values. Using it in a query:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
cursor.outputtypehandler = output_type_handler
|
||||
|
||||
cursor.execute("select 123 as col1, 'abc' as col2 from dual")
|
||||
for r in cursor.fetchall():
|
||||
print(r)
|
||||
|
||||
prints::
|
||||
|
||||
('123 was a string', 'abc')
|
||||
|
||||
This shows that the number was first converted to a string by the database, as
|
||||
requested in the output type handler. The ``out_converter`` function then
|
||||
appended "was a string" to the data before the value was returned to the
|
||||
application.
|
||||
|
||||
Note outconverters are not called for NULL data values unless the value
|
||||
specified in the ``convert_nulls`` parameter was *True* when the variable was
|
||||
created using :meth:`Cursor.var()`.
|
||||
|
||||
.. _rowfactories:
|
||||
|
||||
Changing Query Results with Rowfactories
|
||||
++++++++++++++++++++++++++++++++++++++++
|
||||
----------------------------------------
|
||||
|
||||
Python-oracledb "rowfactories" are methods called for each row retrieved from
|
||||
the database. The :meth:`Cursor.rowfactory` method is called with the tuple
|
||||
fetched from the database before it is returned to the application. The method
|
||||
can convert the tuple to a different value.
|
||||
Python-oracledb "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()
|
||||
|
@ -440,9 +393,7 @@ For example, to fetch each row of a query as a dictionary:
|
|||
|
||||
The output is::
|
||||
|
||||
{'LOCATION_ID': 1000, 'STREET_ADDRESS': '1297 Via Cola di Rie',
|
||||
'POSTAL_CODE': '00989', 'CITY': 'Roma', 'STATE_PROVINCE': None,
|
||||
'COUNTRY_ID': 'IT'}
|
||||
{'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,
|
||||
|
@ -457,103 +408,6 @@ only one of the similarly named columns will be included in the dictionary:
|
|||
dogs.color
|
||||
from cats, dogs
|
||||
|
||||
An example showing an :ref:`output type handler <outputtypehandlers>`, an
|
||||
:ref:`outconverter <outconverters>`, and a row factory is:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def output_type_handler(cursor, metadata):
|
||||
|
||||
def out_converter(d):
|
||||
if type(d) is str:
|
||||
return f"{d} was a string"
|
||||
else:
|
||||
return f"{d} was not a string"
|
||||
|
||||
if metadata.type_code is oracledb.DB_TYPE_NUMBER:
|
||||
return cursor.var(oracledb.DB_TYPE_VARCHAR,
|
||||
arraysize=cursor.arraysize, outconverter=out_converter)
|
||||
|
||||
cursor.outputtypehandler = output_type_handler
|
||||
|
||||
cursor.execute("select 123 as col1, 'abc' as col2 from dual")
|
||||
|
||||
columns = [col[0] for col in cursor.description]
|
||||
cursor.rowfactory = lambda *args: dict(zip(columns, args))
|
||||
for r in cursor.fetchall():
|
||||
print(r)
|
||||
|
||||
The database converts the number to a string before it is returned to
|
||||
python-oracledb. The outconverter appends "was a string" to this value.
|
||||
Finally the row factory changes the complete row to a dictionary. The output
|
||||
is::
|
||||
|
||||
{'COL1': '123 was a string', 'COL2': 'abc'}
|
||||
|
||||
.. _numberprecision:
|
||||
|
||||
Fetched Number Precision
|
||||
------------------------
|
||||
|
||||
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. In python-oracledb you can set
|
||||
``oracledb.defaults.fetch_decimals`` so that Decimals are returned to the
|
||||
application, ensuring that numeric precision is not lost when fetching certain
|
||||
numbers.
|
||||
|
||||
The following code sample demonstrates the issue:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
cursor.execute("create table test_float (X number(5, 3))")
|
||||
cursor.execute("insert into test_float values (7.1)")
|
||||
|
||||
cursor.execute("select * from test_float")
|
||||
val, = cursor.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
|
||||
|
||||
oracledb.defaults.fetch_decimals = True
|
||||
|
||||
cursor.execute("select * from test_float")
|
||||
val, = cursor.fetchone()
|
||||
print(val, "* 3 =", val * 3)
|
||||
|
||||
This displays ``7.1 * 3 = 21.3``
|
||||
|
||||
See `samples/return_numbers_as_decimals.py
|
||||
<https://github.com/oracle/python-oracledb/blob/main/samples/return_numbers_as_decimals.py>`__
|
||||
|
||||
An equivalent, longer, older coding idiom to :attr:`Defaults.fetch_decimals` is
|
||||
to use an :ref:`output type handler <outputtypehandlers>` do the conversion.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import decimal
|
||||
|
||||
def number_to_decimal(cursor, metadata):
|
||||
if metadata.type_code is oracledb.DB_TYPE_NUMBER:
|
||||
return cursor.var(decimal.Decimal, arraysize=cursor.arraysize)
|
||||
|
||||
cursor.outputtypehandler = number_to_decimal
|
||||
|
||||
cursor.execute("select * from test_float")
|
||||
val, = cursor.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.
|
||||
|
||||
.. _scrollablecursors:
|
||||
|
||||
Scrollable Cursors
|
||||
|
@ -614,8 +468,8 @@ then it can be queried and printed:
|
|||
|
||||
.. code-block:: python
|
||||
|
||||
cursor.execute("select geometry from mygeometrytab")
|
||||
for obj, in cursor:
|
||||
cur.execute("select geometry from mygeometrytab")
|
||||
for obj, in cur:
|
||||
dumpobject(obj)
|
||||
|
||||
Where ``dumpobject()`` is defined as:
|
||||
|
@ -716,8 +570,8 @@ rows using:
|
|||
ORDER BY last_name
|
||||
OFFSET :offset ROWS FETCH NEXT :maxnumrows ROWS ONLY"""
|
||||
|
||||
cursor = connection.cursor()
|
||||
for row in cursor.execute(sql, offset=myoffset, maxnumrows=mymaxnumrows):
|
||||
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
|
||||
|
@ -830,8 +684,9 @@ The following sample demonstrates how to use this feature:
|
|||
.. code-block:: python
|
||||
|
||||
# define output type handler
|
||||
def return_strings_as_bytes(cursor, metadata):
|
||||
if metadata.type_code is oracledb.DB_TYPE_VARCHAR:
|
||||
def return_strings_as_bytes(cursor, name, default_type, size,
|
||||
precision, scale):
|
||||
if default_type == oracledb.DB_TYPE_VARCHAR:
|
||||
return cursor.var(str, arraysize=cursor.arraysize,
|
||||
bypass_decode=True)
|
||||
|
||||
|
@ -905,10 +760,9 @@ columns:
|
|||
|
||||
.. code-block:: python
|
||||
|
||||
def output_type_handler(cursor, metadata):
|
||||
if metadata.type_code is oracledb.DB_TYPE_VARCHAR:
|
||||
return cursor.var(metadata.type_code, size,
|
||||
arraysize=cursor.arraysize,
|
||||
def output_type_handler(cursor, name, default_type, size, precision, scale):
|
||||
if default_type == oracledb.DB_TYPE_VARCHAR:
|
||||
return cursor.var(default_type, size, arraysize=cursor.arraysize,
|
||||
encoding_errors="replace")
|
||||
|
||||
cursor.outputtypehandler = output_type_handler
|
||||
|
@ -929,8 +783,8 @@ easily be executed with python-oracledb. For example:
|
|||
|
||||
.. code-block:: python
|
||||
|
||||
cursor = connection.cursor()
|
||||
cursor.execute("insert into MyTable values (:idbv, :nmbv)", [1, "Fredico"])
|
||||
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.
|
||||
|
@ -953,6 +807,6 @@ SDO_GEOMETRY <spatial>` object:
|
|||
.. code-block:: python
|
||||
|
||||
type_obj = connection.gettype("SDO_GEOMETRY")
|
||||
cursor = connection.cursor()
|
||||
cursor.setinputsizes(type_obj)
|
||||
cursor.execute("insert into sometable values (:1)", [None])
|
||||
cur = connection.cursor()
|
||||
cur.setinputsizes(type_obj)
|
||||
cur.execute("insert into sometable values (:1)", [None])
|
||||
|
|
|
@ -21,15 +21,11 @@ There are multiple approaches for application tracing and monitoring:
|
|||
tracing capabilities <https://docs.python.org/3/library/trace.html>`__ can be
|
||||
used.
|
||||
|
||||
- The Java Debug Wire Protocol (JDWP) for debugging PL/SQL can be used. See
|
||||
:ref:`jdwp`.
|
||||
- The Java Debug Wire Protocol (JDWP) for debugging PL/SQL can be used. See :ref:`jdwp`.
|
||||
|
||||
- Python-oracledb in Thick mode can dump a trace of SQL statements
|
||||
executed. See :ref:`lowlevelsqltrace`.
|
||||
|
||||
- The connection identifiers that appear in the traces and logs can be used
|
||||
to resolve connectivity errors. See :ref:`connectionid`.
|
||||
|
||||
.. _endtoendtracing:
|
||||
|
||||
Oracle Database End-to-End Tracing
|
||||
|
@ -238,61 +234,9 @@ See `ODPI-C Debugging
|
|||
<https://oracle.github.io/odpi/doc/user_guide/debugging.html>`__ for
|
||||
documentation on ``DPI_DEBUG_LEVEL``.
|
||||
|
||||
.. _connectionid:
|
||||
|
||||
Using Connection Identifiers
|
||||
----------------------------
|
||||
|
||||
A unique connection identifier (``CONNECTION_ID``) is generated for each
|
||||
connection to the Oracle Database. The connection identifier is shown in some
|
||||
Oracle Network error messages and logs, which helps in better tracing and
|
||||
diagnosing of connection failures. For example::
|
||||
|
||||
DPY-6005: cannot connect to database (CONNECTION_ID=m0PfUY6hYSmWPcgrHZCQIQ==)
|
||||
|
||||
You can define a prefix value which is added to the beginning of the
|
||||
``CONNECTION_ID``. This prefix aids in identifying the connections from a
|
||||
specific application.
|
||||
|
||||
In python-oracledb Thin mode, you can specify a prefix in the
|
||||
``connection_id_prefix`` parameter when creating
|
||||
:meth:`standalone connections <oracledb.connect()>`, or
|
||||
:meth:`pooled connections <oracledb.create_pool()>`. Also, you can specify
|
||||
the connection identifier in :meth:`oracledb.ConnectParams()` or
|
||||
:meth:`oracledb.PoolParams()`. For example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
connection = oracledb.connect(user="hr", password=userpwd,
|
||||
dsn="localhost/orclpdb",
|
||||
connection_id_prefix="MYAPP")
|
||||
|
||||
If this connection to the database fails, ``MYAPP`` is added as a prefix to the
|
||||
``CONNECTION_ID`` as shown in the error message below::
|
||||
|
||||
DPY-6005: cannot connect to database (CONNECTION_ID=MYAPPm0PfUY6hYSmWPcgrHZCQIQ==).
|
||||
|
||||
In python-oracledb Thick mode, you can specify the connection identifier prefix in
|
||||
a connection string. For example::
|
||||
|
||||
mydb = (DESCRIPTION =
|
||||
(ADDRESS_LIST= (ADDRESS=...) (ADDRESS=...))
|
||||
(CONNECT_DATA=
|
||||
(SERVICE_NAME=sales.us.example.com)
|
||||
(CONNECTION_ID_PREFIX=MYAPP)
|
||||
)
|
||||
)
|
||||
|
||||
Depending on the Oracle Database version in use, the information that is shown
|
||||
in logs varies.
|
||||
|
||||
See `Troubleshooting Oracle Net Services <https://www.oracle.com/pls/topic/
|
||||
lookup?ctx=dblatest&id=GUID-3F42D057-C9AC-4747-B48B-5A5FF7672E5D>`_ for more
|
||||
information on connection identifiers.
|
||||
|
||||
.. _vsessconinfo:
|
||||
|
||||
Finding the python-oracledb Mode
|
||||
Finding the Python-oracledb Mode
|
||||
================================
|
||||
|
||||
The boolean attributes :attr:`Connection.thin` and :attr:`ConnectionPool.thin`
|
||||
|
|
|
@ -1,369 +0,0 @@
|
|||
.. _troubleshooting:
|
||||
|
||||
**********************
|
||||
Troubleshooting Errors
|
||||
**********************
|
||||
|
||||
Use the troubleshooting information documented in this section to address
|
||||
errors that may appear while :ref:`installing <instllntroubleshooting>` or
|
||||
:ref:`using <runtimetroubleshooting>` python-oracledb in Thin or Thick mode.
|
||||
|
||||
.. _instllntroubleshooting:
|
||||
|
||||
Installation Errors
|
||||
===================
|
||||
|
||||
You may encounter issues while installing python-oracledb. Review the
|
||||
python-oracledb :ref:`instreq`. To understand the problem better, you can
|
||||
display more output by using the ``-v`` option with the pip install command.
|
||||
Review your output and logs.
|
||||
|
||||
If you need to modify your system version of Python and do not have the
|
||||
necessary access to modify it, then use:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
python -m pip install oracledb --upgrade --user
|
||||
|
||||
Or you can use the venv module (built into Python 3.x).
|
||||
|
||||
This section covers some specific errors or problems that you may run into
|
||||
during python-oracledb installation, and possible solutions to resolve them.
|
||||
|
||||
If the installation problem still persists, then try to install
|
||||
python-oracledb using a different method. **Google anything that looks like an
|
||||
error.** Try some potential solutions.
|
||||
|
||||
.. _wheelerr:
|
||||
|
||||
"Not a supported wheel on this platform" Error
|
||||
----------------------------------------------
|
||||
|
||||
**Cause:** The python-oracledb installation failed with this error because
|
||||
you may be using an older version of ``pip``.
|
||||
|
||||
**Action:** Upgrade your pip version with the following command:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
python -m pip install pip --upgrade --user
|
||||
|
||||
.. _networkerr:
|
||||
|
||||
Network Connection Error
|
||||
------------------------
|
||||
|
||||
**Cause:** The python-oracledb installation failed because of a network
|
||||
connection error.
|
||||
|
||||
**Action:** To resolve this issue:
|
||||
|
||||
- Check if you need to set the environment variables ``http_proxy`` and/or
|
||||
``https_proxy``.
|
||||
|
||||
- Or try the following command:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
python -m pip install --proxy=http://proxy.example.com:80 oracledb --upgrade
|
||||
|
||||
.. _upgradeerr:
|
||||
|
||||
Upgrade to Latest Version Failed Without Any Errors
|
||||
---------------------------------------------------
|
||||
|
||||
**Cause:** The upgrade to the latest python-oracledb version failed without
|
||||
any errors because the old version is still installed.
|
||||
|
||||
**Action:** To reinstall the latest version, try the following command:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
python -m pip install oracledb --upgrade --force-reinstall
|
||||
|
||||
.. _nomodpiperr:
|
||||
|
||||
"No module named pip" Error
|
||||
---------------------------
|
||||
|
||||
**Cause:** The python-oracledb installation failed with this error because
|
||||
the pip module that is built into Python may sometimes be removed by the OS.
|
||||
|
||||
**Action:** Instead, use the venv module (built into Python 3.x) or virtualenv
|
||||
module.
|
||||
|
||||
.. _dpiherr:
|
||||
|
||||
"fatal error: dpi.h: No such file or directory" Error
|
||||
-----------------------------------------------------
|
||||
|
||||
**Cause:** The python-oracledb installation from source code failed because a
|
||||
subdirectory called "odpi" may be missing.
|
||||
|
||||
**Action:** Check if your source installation has a subdirectory called
|
||||
"odpi" containing files. If this is missing, review the section on
|
||||
:ref:`installgh`.
|
||||
|
||||
.. _warningmsgs:
|
||||
|
||||
Warning Messages
|
||||
================
|
||||
|
||||
Some warnings may appear while using python-oracledb in Thick or Thin mode.
|
||||
|
||||
.. _pythwarning:
|
||||
|
||||
Deprecated Python Versions 3.6 and 3.7 Warning
|
||||
----------------------------------------------
|
||||
|
||||
**Warning:** ``Python 3.6 is no longer supported by the Python core team.
|
||||
Therefore, support for it is deprecated in python-oracledb and will be removed
|
||||
in a future release.`` (A similar warning will also be displayed for Python
|
||||
version 3.7.)
|
||||
|
||||
**Cause:** ``import oracledb`` gives this warning because you are using
|
||||
deprecated Python versions 3.6 or 3.7 which will be removed in a future
|
||||
release by the Python core team.
|
||||
|
||||
**Action:** You can either:
|
||||
|
||||
- Upgrade your Python version to 3.8 or later.
|
||||
|
||||
- Or you can temporarily suppress the warning by importing the
|
||||
`warnings <https://docs.python.org/3/library/warnings.html>`__ module and
|
||||
adding a call like ``warnings.filterwarnings(action='ignore',
|
||||
module="oracledb")`` *before* importing ``oracledb``.
|
||||
|
||||
.. _runtimetroubleshooting:
|
||||
|
||||
Error Messages
|
||||
==============
|
||||
|
||||
While using python-oracledb in Thin or Thick mode, you may encounter
|
||||
errors. Some common :ref:`DPI <dpierr>` and :ref:`DPY <dpyerr>` errors are
|
||||
detailed in this section with information about the probable cause of the
|
||||
error, and the recommended action which may resolve the error.
|
||||
|
||||
If you have multiple versions of Python installed, ensure that you are
|
||||
using the correct python and pip (or python3 and pip3) executables.
|
||||
|
||||
.. _dpierr:
|
||||
|
||||
DPI Error Messages
|
||||
------------------
|
||||
|
||||
The error messages with prefix ``DPI`` are generated by the
|
||||
`ODPI-C <https://oracle.github.io/odpi/>`_ code which is used by the
|
||||
python-oracledb Thick mode.
|
||||
|
||||
DPI-1047
|
||||
++++++++
|
||||
|
||||
**Message:** ``DPI-1047: Oracle Client library cannot be loaded``
|
||||
|
||||
**Cause:** The connection to Oracle Database failed because the Oracle
|
||||
Client library could not be loaded.
|
||||
|
||||
**Action:** Perform the following steps:
|
||||
|
||||
- Review the :ref:`features available in python-oracledb's default Thin mode
|
||||
<featuresummary>`. If Thin mode suits your requirements, then remove the
|
||||
calls in your application to :meth:`oracledb.init_oracle_client()` since
|
||||
this loads the Oracle Client library to :ref:`enable Thick mode
|
||||
<enablingthick>`.
|
||||
|
||||
- On Windows and macOS, pass the ``lib_dir`` library directory parameter
|
||||
in your :meth:`oracledb.init_oracle_client()` call. The parameter
|
||||
should be the location of your Oracle Client libraries. Do not pass
|
||||
this parameter on Linux.
|
||||
|
||||
- Check if the Python process has permission to open the Oracle Client
|
||||
libraries. OS restrictions may prevent the opening of libraries installed
|
||||
in unsafe paths, such as from a user directory. On Linux you may need to
|
||||
install the Oracle Client libraries under a directory like ``/opt`` or
|
||||
``/usr/local``.
|
||||
|
||||
- Check if 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
|
||||
python-oracledb. The trace messages will show how and where
|
||||
python-oracledb 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 have a full database installation, ensure that this database is the
|
||||
`currently configured database <https://docs.oracle.com/pls/topic/lookup?
|
||||
ctx=db21&id=RIWIN-GUID-33D575DD-47FF-42B1-A82F-049D3F2A8791>`__.
|
||||
|
||||
- If you are not passing a library directory parameter to
|
||||
:meth:`oracledb.init_oracle_client()`, then restart your command prompt
|
||||
and use ``set PATH`` to check if the environment variable has the correct
|
||||
Oracle Client listed before any other Oracle directories.
|
||||
|
||||
- Use the ``DIR`` command to verify that ``OCI.DLL`` exists in the directory
|
||||
passed to :meth:`oracledb.init_oracle_client()` or set in ``PATH``.
|
||||
|
||||
- Check if the correct `Windows Redistributables <https://oracle.github.io/odpi/
|
||||
doc/installation.html#windows>`__ have been installed.
|
||||
|
||||
- On Linux:
|
||||
|
||||
- Check if the ``LD_LIBRARY_PATH`` environment variable contains the Oracle
|
||||
Client library directory. Some environments such as web servers and
|
||||
daemons reset environment variables.
|
||||
|
||||
- If you are using Oracle Instant Client, a preferred alternative to
|
||||
``LD_LIBRARY_PATH`` is to ensure that a file in the ``/etc/ld.so.conf.d``
|
||||
directory contains the path to the Instant Client directory, and then run
|
||||
``ldconfig``.
|
||||
|
||||
DPI-1072
|
||||
++++++++
|
||||
|
||||
**Message:** ``DPI-1072: the Oracle Client library version is unsupported``
|
||||
|
||||
**Cause:** The connection to Oracle Database failed because the Oracle Client
|
||||
library version used is not supported by python-oracledb Thick mode. The Thick
|
||||
mode needs Oracle Client library 11.2 or later. Note that version 19 is not
|
||||
supported on Windows 7.
|
||||
|
||||
**Action:** Review the :ref:`instreq`. You can either:
|
||||
|
||||
- Follow the steps documented in `dpi-1047`_ which may help.
|
||||
|
||||
- Or may be use python-oracledb Thin mode which can be done by removing calls
|
||||
to :meth:`oracledb.init_oracle_client()` from your code.
|
||||
|
||||
.. _dpyerr:
|
||||
|
||||
DPY Error Messages
|
||||
------------------
|
||||
|
||||
The python-oracledb Thin mode code and python-oracledb Thick mode code
|
||||
generates error messages with the prefix ``DPY``.
|
||||
|
||||
DPY-3010
|
||||
++++++++
|
||||
|
||||
**Message:** ``DPY-3010: connections to this database server version are not
|
||||
supported by python-oracledb in thin mode``
|
||||
|
||||
**Cause:** The connection to Oracle Database with python-oracledb Thin mode
|
||||
failed because you are using Oracle Database version 11.2 or earlier. Using
|
||||
python-oracledb Thin mode, you can connect directly to Oracle Database 12.1
|
||||
or later.
|
||||
|
||||
**Action:** You can either:
|
||||
|
||||
- :ref:`Enable python-oracledb Thick mode <enablingthick>` since this mode can
|
||||
connect to Oracle Database 9.2 or later. For Thick mode, you need to install
|
||||
Oracle Client libraries and call :meth:`oracledb.init_oracle_client()` in
|
||||
your code.
|
||||
|
||||
- Upgrade your Oracle database to python-oracledb Thin mode supported versions
|
||||
12.1 or later.
|
||||
|
||||
DPY-3015
|
||||
++++++++
|
||||
|
||||
**Message:** ``DPY-3015: password verifier type 0x939 is not supported by
|
||||
python-oracledb in thin mode``
|
||||
|
||||
**Cause:** The connection to Oracle Database with python-oracledb Thin mode
|
||||
failed because your user account was only created with the 10G password
|
||||
verifier. The python-oracledb Thin mode supports password verifiers 11G and
|
||||
later.
|
||||
|
||||
**Action:** You can either:
|
||||
|
||||
- :ref:`Enable Thick mode <enablingthick>` since python-oracledb Thick mode
|
||||
supports password verifiers 10G and later.
|
||||
|
||||
- Or you can:
|
||||
|
||||
1. Ensure that the database initialization parameter
|
||||
``sec_case_sensitive_logon`` is not *FALSE*. To check the value, connect
|
||||
as SYSDBA in SQL*Plus and run::
|
||||
|
||||
show parameter sec_case_sensitive_logon
|
||||
|
||||
Note this parameter has been `removed in Oracle Database 21c
|
||||
<https://docs.oracle.com/en/database/oracle/oracle-database/21/nfcon/
|
||||
security-solutions.html#GUID-FAF4C7A6-A2CD-4B9B-9A64-3705F693ECF0>`__
|
||||
so only step 2 is required for this, or subsequent, database versions.
|
||||
|
||||
2. Regenerate passwords for users who have old password verifiers. You can
|
||||
find such users with the query:
|
||||
|
||||
.. code-block:: sql
|
||||
|
||||
select username from dba_users
|
||||
where (password_versions = '10G ' or password_versions = '10G HTTP ')
|
||||
and username <> 'ANONYMOUS';
|
||||
|
||||
You can reset passwords for these users with commands like::
|
||||
|
||||
alter user x identified by y
|
||||
|
||||
.. seealso::
|
||||
|
||||
`Finding and Resetting User Passwords That Use the 10G Password
|
||||
Version <https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=
|
||||
GUID-D7B09DFE-F55D-449A-8F8A-174D89936304>`__ for more information.
|
||||
|
||||
DPY-4011
|
||||
++++++++
|
||||
|
||||
**Message:** ``DPY-4011: the database or network closed the connection``
|
||||
|
||||
**Cause:** The connection failed because the Oracle Database that you are
|
||||
trying to connect to using python-oracledb Thin mode may have Native Network
|
||||
Encryption (NNE) enabled. NNE is only supported in python-oracledb Thick mode.
|
||||
|
||||
**Action:** To verify if NNE is enabled, you can use the following query::
|
||||
|
||||
SELECT network_service_banner FROM v$session_connect_info;
|
||||
|
||||
If NNE is enabled, then this query prints output that includes the
|
||||
available encryption service, the crypto-checksumming service, and the
|
||||
algorithms in use, such as::
|
||||
|
||||
NETWORK_SERVICE_BANNER
|
||||
-------------------------------------------------------------------------------------
|
||||
TCP/IP NT Protocol Adapter for Linux: Version 19.0.0.0.0 - Production
|
||||
Encryption service for Linux: Version 19.0.1.0.0 - Production
|
||||
AES256 Encryption service adapter for Linux: Version 19.0.1.0.0 - Production
|
||||
Crypto-checksumming service for Linux: Version 19.0.1.0.0 - Production
|
||||
SHA256 Crypto-checksumming service adapter for Linux: Version 19.0.1.0.0 - Production
|
||||
|
||||
If NNE is not enabled, then the query will only print the available encryption
|
||||
and crypto-checksumming services in the output. For example::
|
||||
|
||||
NETWORK_SERVICE_BANNER
|
||||
-------------------------------------------------------------------------------------
|
||||
TCP/IP NT Protocol Adapter for Linux: Version 19.0.0.0.0 - Production
|
||||
Encryption service for Linux: Version 19.0.1.0.0 - Production
|
||||
|
||||
If NNE is enabled, you can resolve this error by either:
|
||||
|
||||
- Changing the architecture to use Transport Layer Security (TLS) which is
|
||||
supported in python-oracledb Thin mode instead of using NNE.
|
||||
- Or :ref:`enabling python-oracledb Thick mode <enablingthick>` since NNE is
|
||||
supported in Thick mode.
|
||||
|
||||
.. seealso::
|
||||
|
||||
`Oracle Database Security Guide <https://www.oracle.com/pls/topic/lookup?
|
||||
ctx=dblatest&id=DBSEG>`__ for more information about Oracle Data Network
|
||||
Encryption and Integrity, and for information about configuring TLS
|
||||
network encryption.
|
|
@ -14,7 +14,7 @@ Some general tuning tips are:
|
|||
For multi-user applications, make use of connection pooling. Create the pool
|
||||
once during application initialization. Do not oversize the pool, see
|
||||
:ref:`connpooling` . Use a session callback function to set session state, see
|
||||
:ref:`Session Callbacks for Setting Pooled Connection State <sessioncallback>`.
|
||||
:ref:`Session CallBacks for Setting Pooled Connection State <sessioncallback>`.
|
||||
|
||||
Make use of efficient python-oracledb functions. For example, to insert
|
||||
multiple rows use :meth:`Cursor.executemany()` instead of
|
||||
|
@ -46,26 +46,12 @@ Some general tuning tips are:
|
|||
|
||||
* 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
|
||||
`Configuring Session Data Unit
|
||||
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-86D61D6F-AD26-421A-BABA-77949C8A2B04>`__
|
||||
and `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>`__.
|
||||
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>`__.
|
||||
|
||||
In python-oracledb Thick mode the SDU size is configured in the
|
||||
:ref:`optnetfiles`. In python-oracledb Thin mode, the SDU size can be passed
|
||||
as a connection or pool creation parameter. In both modes it may optionally
|
||||
be set in the connection :ref:`Easy Connect string <easyconnect>` or
|
||||
:ref:`connect descriptor <netservice>`.
|
||||
|
||||
* Do not commit or rollback unnecessarily. Use :attr:`Connection.autocommit`
|
||||
on the last of a sequence of DML statements.
|
||||
|
||||
* If Python's Global Interpreter Lock (GIL) is limiting
|
||||
:ref:`concurrent program performance <asyncio>`, then explore using parallel
|
||||
Python processes.
|
||||
* Do not commit or rollback unnecessarily. Use :attr:`Connection.autocommit` on
|
||||
the last of a sequence of DML statements.
|
||||
|
||||
.. _tuningfetch:
|
||||
|
||||
|
@ -74,62 +60,74 @@ Tuning Fetch Performance
|
|||
|
||||
To tune queries, you can adjust python-oracledb's internal buffer sizes to
|
||||
improve the speed of fetching rows across the network from the database, and to
|
||||
optimize memory usage. This can reduce :ref:`round-trips <roundtrips>` which
|
||||
helps performance and scalability. Tune "array fetching" with
|
||||
:attr:`Cursor.arraysize` and tune "row prefetching" with
|
||||
:attr:`Cursor.prefetchrows`. Set these before calling
|
||||
:meth:`Cursor.execute()`. The value used for prefetching can also be set in an
|
||||
``oraaccess.xml`` file, see :ref:`optclientfiles`. In python-oracledb Thick
|
||||
mode, the internal buffers allocated for ``prefetchrows`` and ``arraysize`` are
|
||||
separate, so increasing both settings will require more Python process memory.
|
||||
Queries that return LOBs and similar types will never prefetch rows, so the
|
||||
``prefetchrows`` value is ignored in those cases.
|
||||
optimize memory usage. Regardless of which :ref:`python-oracledb method
|
||||
<fetching>` 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 buffer 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.
|
||||
|
||||
The internal buffer sizes do not affect how or when rows are returned to your
|
||||
application regardless of which :ref:`python-oracledb method <fetching>` is
|
||||
used to fetch query results. 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 difference between row prefetching and array fetching is when the internal
|
||||
buffering occurs. Internally python-oracledb performs separate "execute SQL
|
||||
statement" and "fetch data" steps. Prefetching allows query results to be
|
||||
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 when
|
||||
the buffering occurs. Internally python-oracledb performs separate "execute
|
||||
SQL statement" and "fetch data" steps. Prefetching allows query results to be
|
||||
returned to the application when the acknowledgment of successful statement
|
||||
execution is returned from the database. This means that the subsequent
|
||||
internal "fetch data" operation does not always need to make a round-trip to
|
||||
the database because rows are already buffered in python-oracledb or in the
|
||||
Oracle Client libraries. An overhead of prefetching when using the
|
||||
python-oracledb Thick mode is the need for additional data copies from Oracle
|
||||
Client's prefetch buffer when fetching the first batch of rows. This cost may
|
||||
outweigh the benefits of using prefetching in some cases.
|
||||
Oracle Client libraries. Reducing round-trips helps performance and
|
||||
scalability. An overhead of prefetching when using the python-oracledb Thick
|
||||
mode is the need for additional data copies from Oracle Client's prefetch
|
||||
buffer.
|
||||
|
||||
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. 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.
|
||||
application use. This is because the cost of the extra memory copy from the
|
||||
prefetch buffer when fetching a large quantity of rows or very "wide" rows may
|
||||
outweigh the cost of a round-trip for a single python-oracledb 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 tuning:
|
||||
|
||||
* To tune queries that return an unknown, large, number of rows, estimate the
|
||||
number of rows returned and increase the :attr:`Cursor.arraysize` value for
|
||||
best performance, memory and round-trip usage. The default is 100. For
|
||||
example:
|
||||
* 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)
|
||||
|
||||
In general for this scenario, leave ``prefetchrows`` at its default value.
|
||||
If you do change it, then set ``arraysize`` as big, or bigger. Do not make
|
||||
the sizes unnecessarily large.
|
||||
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, set ``arraysize`` to the number
|
||||
of expected rows, and set ``prefetchrows`` to one greater than this value.
|
||||
|
@ -160,60 +158,11 @@ Here are some suggestions for tuning:
|
|||
.. code-block:: python
|
||||
|
||||
cur = connection.cursor()
|
||||
|
||||
cur.arraysize = 1
|
||||
|
||||
cur.execute("select * from MyTable where id = 1"):
|
||||
row = cur.fetchone()
|
||||
print(row)
|
||||
|
||||
The following table shows the number of round-trips required to fetch various
|
||||
numbers of rows with different ``prefetchrows`` and ``arraysize`` values.
|
||||
|
||||
.. list-table-with-summary:: Effect of ``prefetchrows`` and ``arraysize`` on the number of round-trips
|
||||
:header-rows: 1
|
||||
:class: wy-table-responsive
|
||||
:align: center
|
||||
:summary: The first column is the number of rows used for the example. The second column is the prefetchrows value. The third column is the arraysize value. The final column shows how many round-trips it would take to fetch all data from the database.
|
||||
|
||||
* - Number of rows
|
||||
- ``prefetchrows``
|
||||
- ``arraysize``
|
||||
- Round-trips
|
||||
* - 1
|
||||
- 2
|
||||
- 100
|
||||
- 1
|
||||
* - 100
|
||||
- 2
|
||||
- 100
|
||||
- 2
|
||||
* - 1000
|
||||
- 2
|
||||
- 100
|
||||
- 11
|
||||
* - 10000
|
||||
- 2
|
||||
- 100
|
||||
- 101
|
||||
* - 10000
|
||||
- 2
|
||||
- 1000
|
||||
- 11
|
||||
* - 10000
|
||||
- 1000
|
||||
- 1000
|
||||
- 11
|
||||
* - 20
|
||||
- 20
|
||||
- 20
|
||||
- 2
|
||||
* - 20
|
||||
- 21
|
||||
- 20
|
||||
- 1
|
||||
|
||||
|
||||
Application Default Prefetchrows and Arraysize Values
|
||||
+++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
|
@ -257,50 +206,70 @@ a re-executed statement, create a new cursor. For example, to change
|
|||
Avoiding Premature Prefetching
|
||||
++++++++++++++++++++++++++++++
|
||||
|
||||
There are two cases that will benefit from setting ``prefetchrows`` to zero:
|
||||
There are two cases that will benefit from setting ``prefetchrows`` to 0:
|
||||
|
||||
* When passing REF CURSORS *into* PL/SQL packages. Setting ``prefetchrows`` to
|
||||
0 can stop rows being prematurely (and silently) fetched into the
|
||||
python-oracledb internal buffer, making those rows unavailable to the PL/SQL
|
||||
code that receives the REF CURSOR.
|
||||
* When passing REF CURSORS into PL/SQL packages. Setting ``prefetchrows`` to 0
|
||||
can stop rows being prematurely (and silently) fetched into the
|
||||
python-oracledb or Oracle Client (in python-oracledb Thick mode) internal
|
||||
buffer, making those rows 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 python-oracledb can return them to the application. Setting
|
||||
``prefetchrows`` to 0 helps give a consistent flow of data to the
|
||||
application.
|
||||
``prefetchrows`` to 0 helps give a consistent flow of data to the application.
|
||||
|
||||
Tuning Data Copies between Databases
|
||||
------------------------------------
|
||||
|
||||
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()
|
||||
|
||||
Note that it may be preferable to use database links between the databases and
|
||||
use an INSERT INTO SELECT statement so that data is not copied to, and from,
|
||||
Python.
|
||||
|
||||
Tuning Fetching from REF CURSORS
|
||||
--------------------------------
|
||||
|
||||
The internal buffering and performance of fetching data from REF CURSORS can be
|
||||
tuned by setting the value of ``arraysize`` before rows are fetched from the
|
||||
cursor. The ``prefetchrows`` value is ignored when fetching *from* REF CURSORS.
|
||||
In python-oracledb, fetching data from REF CURSORS can be tuned by setting the
|
||||
values of ``arraysize`` and ``prefetchrows``. The ``prefetchrows`` value must
|
||||
be set before calling the PL/SQL procedure because 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()
|
||||
cursor.callproc("myrefcursorproc", [ref_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)
|
||||
|
||||
The ``arraysize`` value can also be set before calling the procedure:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
ref_cursor = connection.cursor()
|
||||
ref_cursor.arraysize = 1000
|
||||
|
||||
cursor.callproc("myrefcursorproc", [ref_cursor])
|
||||
for row in ref_cursor:
|
||||
. . .
|
||||
|
||||
.. _roundtrips:
|
||||
|
||||
Also see `Avoiding Premature Prefetching`_.
|
||||
|
@ -308,41 +277,31 @@ Also see `Avoiding Premature Prefetching`_.
|
|||
Database Round-trips
|
||||
====================
|
||||
|
||||
A round-trip is defined as the travel of a message from python-oracledb to the
|
||||
database and back. Calling each python-oracledb function, or accessing each
|
||||
attribute, will require zero or more round-trips. For example, inserting a
|
||||
simple row involves sending data to the database and getting a success response
|
||||
back. This is a round-trip. Along with tuning an application's architecture
|
||||
and `tuning its SQL statements
|
||||
A round-trip is defined as the trip from the Oracle Client libraries (used by
|
||||
python-oracledb) to the database and back. Calling each python-oracledb 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>`__ because they impact application performance and
|
||||
overall system scalability.
|
||||
<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.
|
||||
* 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 python-oracledb.
|
||||
* 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 python-oracledb.
|
||||
* Use scalar types instead of Oracle Database object types.
|
||||
* Avoid overuse of :meth:`Connection.ping()`.
|
||||
* Avoid setting :attr:`ConnectionPool.ping_interval` to 0 or a small value.
|
||||
* When using :ref:`SODA <sodausermanual>`, use pooled connections and enable
|
||||
the :ref:`SODA metadata cache <sodametadatacache>`.
|
||||
* When using :ref:`SODA <sodausermanual>`, 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>`__
|
||||
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.
|
||||
|
||||
|
@ -350,57 +309,26 @@ 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:: python
|
||||
.. code-block:: sql
|
||||
|
||||
# Get the connection's session id
|
||||
def get_session_id(connection):
|
||||
sql = "select sys_context('userenv','sid') from dual"
|
||||
result, = connection.cursor().execute(sql).fetchone()
|
||||
return result
|
||||
|
||||
# Get the number of round-trips a session has made so far
|
||||
def get_round_trips(systemconn, sid):
|
||||
sql = """select
|
||||
ss.value
|
||||
from
|
||||
v$sesstat ss,
|
||||
v$statname sn
|
||||
where
|
||||
ss.sid = :sid
|
||||
and ss.statistic# = sn.statistic#
|
||||
and sn.name like '%roundtrip%client%'"""
|
||||
round_trips, = systemconn.cursor().execute(sql, [sid]).fetchone()
|
||||
return round_trips
|
||||
|
||||
|
||||
systemconn = oracledb.connect(user="system", password=spw, dsn=cs)
|
||||
connection = oracledb.connect(user=un, password=pw, dsn=cs)
|
||||
|
||||
sid = get_session_id(connection)
|
||||
round_trips_before = get_round_trips(systemconn, sid)
|
||||
|
||||
# Do some "work"
|
||||
cursor.execute("select ...")
|
||||
rows = cursor.fetchall()
|
||||
|
||||
round_trips_after = get_round_trips(systemconn, sid)
|
||||
|
||||
print(f"Round-trips required for query: {round_trips_after - round_trips_before}")
|
||||
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
|
||||
=================
|
||||
|
||||
Python-oracledb's :meth:`Cursor.execute()` and :meth:`Cursor.executemany()`
|
||||
methods use statement caching to make re-execution of statements efficient.
|
||||
Statement caching lets Oracle Database cursors be used without re-parsing the
|
||||
statement. Statement caching also reduces metadata transfer costs between
|
||||
python-oracledb and the database. Performance and scalability are improved.
|
||||
|
||||
The python-oracledb Thick mode uses `Oracle Call Interface statement cache
|
||||
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-4947CAE8-1F00-
|
||||
4897-BB2B-7F921E495175>`__, whereas the Thin mode uses its own implementation.
|
||||
Python-oracledb'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 python-oracledb 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 default size of the statement cache can be changed
|
||||
|
@ -408,19 +336,18 @@ using the :attr:`defaults.stmtcachesize` attribute. The size can be set when
|
|||
creating connection pools or standalone connections. 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
|
||||
python-oracledb. 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.
|
||||
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 python-oracledb. 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.
|
||||
|
||||
Setting the Statement Cache
|
||||
---------------------------
|
||||
|
||||
The statement cache size can be set globally with
|
||||
:attr:`defaults.stmtcachesize`:
|
||||
The statement cache size can be set globally with :attr:`defaults.stmtcachesize`:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
@ -428,22 +355,20 @@ The statement cache size can be set globally with
|
|||
|
||||
oracledb.defaults.stmtcachesize = 40
|
||||
|
||||
The value can be overridden in an :meth:`oracledb.connect()` call, or when
|
||||
creating a pool with :meth:`oracledb.create_pool()`. For example:
|
||||
The value can be overridden in an :meth:`oracledb.connect()` call, or when creating a pool
|
||||
with :meth:`oracledb.create_pool()`. For example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
oracledb.create_pool(user="scott", password=userpwd, dsn="dbhost.example.com/orclpb",
|
||||
min=2, max=5, increment=1, stmtcachesize=50)
|
||||
|
||||
When python-oracledb Thick mode uses Oracle Client 21 (or later), changing the
|
||||
cache size with :meth:`ConnectionPool.reconfigure()` 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. When the Thick mode uses 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.
|
||||
When using Oracle Client 21 (or later), changing the cache size with :meth:`ConnectionPool.reconfigure()`
|
||||
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.
|
||||
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.
|
||||
|
||||
Tuning the Statement Cache
|
||||
--------------------------
|
||||
|
@ -453,9 +378,8 @@ statements being executed by the application. :ref:`SODA <sodausermanual>`
|
|||
internally makes SQL calls, so tuning the cache is also beneficial for SODA
|
||||
applications.
|
||||
|
||||
In python-oracledb Thick mode with Oracle Client Libraries 12c (or later), the
|
||||
statement cache size can be automatically tuned with the Oracle Client
|
||||
Configuration :ref:`oraaccess.xml <optclientfiles>` file.
|
||||
With Oracle Client Libraries 12c, or later, the statement cache size can be automatically tuned
|
||||
with the Oracle Client Configuration oraaccess.xml file.
|
||||
|
||||
For manual tuning use views like V$SYSSTAT:
|
||||
|
||||
|
@ -463,15 +387,12 @@ For manual tuning use views like V$SYSSTAT:
|
|||
|
||||
SELECT value FROM V$SYSSTAT WHERE name = 'parse count (total)'
|
||||
|
||||
Find the value before and after running application load to give the number of
|
||||
statement parses during the load test. Alter the statement cache size and
|
||||
repeat the test until you find a minimal number of parses.
|
||||
Find the value before and after running application load to give the number of statement parses
|
||||
during the load test. Alter the statement cache size and repeat the test until you find a minimal number of parses.
|
||||
|
||||
If you have Automatic Workload Repository (AWR) reports you can monitor
|
||||
general application load and the "bytes sent via SQL*Net to client" values.
|
||||
The latter statistic should benefit from not shipping statement metadata to
|
||||
python-oracledb. Adjust the statement cache size and re-run the test to find
|
||||
the best cache size.
|
||||
If you have Automatic Workload Repository (AWR) reports you can monitor general application load and
|
||||
the "bytes sent via SQL*Net to client" values. The latter statistic should benefit from not shipping
|
||||
statement metadata to python-oracledb. Adjust the statement cache size and re-run the test to find the best cache size.
|
||||
|
||||
Disabling the Statement Cache
|
||||
-----------------------------
|
||||
|
@ -488,27 +409,24 @@ 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.
|
||||
|
||||
Disabling the statement cache may also be helpful in test and development
|
||||
environments. The statement cache can become invalid if connections remain
|
||||
open and database schema objects are recreated. Applications can then receive
|
||||
errors such as ``ORA-3106``. However, after a statement execution error is
|
||||
returned once to the application, python-oracledb automatically drops that
|
||||
statement from the cache. This lets subsequent re-executions of the statement
|
||||
on that connection to succeed.
|
||||
Disabling the statement cache may also be helpful in test and development environments.
|
||||
The statement cache can become invalid if connections remain open and database schema
|
||||
objects are recreated. This can also happen when a connection uses identical query text
|
||||
with different ``fetchAsString`` or ``fetchInfo`` data types. Applications can receive
|
||||
errors such as ORA-3106. After a statement execution error is returned once to the application,
|
||||
python-oracledb automatically drops that statement from the cache. This lets subsequent
|
||||
re-executions of the statement on that connection to succeed.
|
||||
|
||||
When it is inconvenient to pass statement text through an application, the
|
||||
:meth:`Cursor.prepare()` call can be used to avoid statement re-parsing.
|
||||
If the ``cache_statement`` parameter in the :meth:`Cursor.prepare()` method is
|
||||
True and the statement cache size is greater than 0, then the statements will
|
||||
be added to the cache, if not already present. If the ``cache_statement``
|
||||
parameter in the :meth:`Cursor.prepare()` method is False and the statement
|
||||
cache size is greater than 0, then the statement will be removed from the
|
||||
statement cache (if present) or will not be cached (if not present). The
|
||||
subsequent ``execute()`` calls use the value None instead of the SQL text.
|
||||
If the ``cache_statement`` parameter in the :meth:`Cursor.prepare()` method is True and the statement cache size
|
||||
is greater than 0, then the statements will be added to the cache, if not already present.
|
||||
If the ``cache_statement`` parameter in the :meth:`Cursor.prepare()` method is False and the statement cache size
|
||||
is greater than 0, then the statement will be removed from the statement cache (if present)
|
||||
or will not be cached (if not present). The subsequent ``execute()`` calls use the value None instead of the SQL text.
|
||||
|
||||
This feature can prevent a rarely executed statement from flushing a potential
|
||||
more frequently executed one from a full cache. For example, if a statement
|
||||
will only ever be executed once:
|
||||
This feature can prevent a rarely executed statement from flushing a potential more frequently executed one from a full cache.
|
||||
For example, if a statement will only ever be executed once:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
@ -532,25 +450,24 @@ Client Result Caching (CRC)
|
|||
===========================
|
||||
|
||||
Python-oracledb 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.
|
||||
<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.
|
||||
|
||||
.. note::
|
||||
|
||||
Client Result Caching is only supported in the python-oracledb Thick mode.
|
||||
See :ref:`enablingthick`.
|
||||
Client Result Caching is only supported in the python-oracledb Thick mode.
|
||||
See :ref:`enablingthick`.
|
||||
|
||||
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>`__
|
||||
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:
|
||||
|
||||
|
@ -562,12 +479,11 @@ restarting the database, for example:
|
|||
|
||||
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>`__.
|
||||
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:
|
||||
allows existing applications to use CRC without needing modification. For example:
|
||||
|
||||
.. code-block:: sql
|
||||
|
||||
|
|
|
@ -7,11 +7,11 @@ Managing Transactions
|
|||
A database transaction is a grouping of SQL statements that make a logical data
|
||||
change to the database.
|
||||
|
||||
When :meth:`Cursor.execute()` or :meth:`Cursor.executemany()` executes a SQL
|
||||
statement, a transaction is started or continued. By default, python-oracledb
|
||||
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:
|
||||
When :meth:`Cursor.execute()` executes a SQL statement, a transaction is
|
||||
started or continued. By default, python-oracledb 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
|
||||
|
||||
|
|
|
@ -1,13 +1,3 @@
|
|||
[build-system]
|
||||
requires = ["setuptools >= 40.6.0", "wheel", "cython"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[tool.black]
|
||||
line-length = 79
|
||||
target-version = ["py37", "py38", "py39", "py310", "py311", "py312"]
|
||||
required-version = 23
|
||||
|
||||
[tool.ruff]
|
||||
line-length = 79
|
||||
target-version = "py38"
|
||||
exclude = ["templates"]
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
## Python-oracledb Examples
|
||||
|
||||
This directory contains samples for python-oracledb.
|
||||
|
||||
### Basic Examples
|
||||
|
||||
1. The schemas and SQL objects that are referenced in the samples can be
|
||||
created by running the Python script [create_schema.py][1]. The script
|
||||
requires SYSDBA privileges and will prompt for these credentials as well as
|
||||
|
@ -26,16 +22,6 @@ This directory contains samples for python-oracledb.
|
|||
|
||||
python drop_schema.py
|
||||
|
||||
### Examples in a Container
|
||||
|
||||
The [sample_container](./sample_container) directory has a Dockerfile that will
|
||||
build a container with the samples and a running Oracle Database.
|
||||
|
||||
### Notebooks
|
||||
|
||||
The [sample_notebooks](./sample_notebooks) directory has Jupyter notebooks with
|
||||
runnable examples.
|
||||
|
||||
[1]: https://github.com/oracle/python-oracledb/blob/main/samples/create_schema.py
|
||||
[2]: https://github.com/oracle/python-oracledb/blob/main/samples/sample_env.py
|
||||
[3]: https://github.com/oracle/python-oracledb/blob/main/samples/drop_schema.py
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2016, 2023, Oracle and/or its affiliates.
|
||||
#------------------------------------------------------------------------------
|
||||
# Copyright (c) 2016, 2022, Oracle and/or its affiliates.
|
||||
#
|
||||
# Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
|
||||
#
|
||||
|
@ -25,15 +25,15 @@
|
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
# app_context.py
|
||||
#
|
||||
# Demonstrates the use of application context. Application context is available
|
||||
# within logon triggers and can be retrieved by using the function
|
||||
# sys_context().
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
import oracledb
|
||||
import sample_env
|
||||
|
@ -44,22 +44,20 @@ oracledb.init_oracle_client(lib_dir=sample_env.get_oracle_client())
|
|||
# client context attributes to be set
|
||||
APP_CTX_NAMESPACE = "CLIENTCONTEXT"
|
||||
APP_CTX_ENTRIES = [
|
||||
(APP_CTX_NAMESPACE, "ATTR1", "VALUE1"),
|
||||
(APP_CTX_NAMESPACE, "ATTR2", "VALUE2"),
|
||||
(APP_CTX_NAMESPACE, "ATTR3", "VALUE3"),
|
||||
( APP_CTX_NAMESPACE, "ATTR1", "VALUE1" ),
|
||||
( APP_CTX_NAMESPACE, "ATTR2", "VALUE2" ),
|
||||
( APP_CTX_NAMESPACE, "ATTR3", "VALUE3" )
|
||||
]
|
||||
|
||||
connection = oracledb.connect(
|
||||
user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string(),
|
||||
appcontext=APP_CTX_ENTRIES,
|
||||
)
|
||||
connection = oracledb.connect(user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string(),
|
||||
appcontext=APP_CTX_ENTRIES)
|
||||
|
||||
with connection.cursor() as cursor:
|
||||
|
||||
for namespace, name, value in APP_CTX_ENTRIES:
|
||||
cursor.execute(
|
||||
"select sys_context(:1, :2) from dual", (namespace, name)
|
||||
)
|
||||
(value,) = cursor.fetchone()
|
||||
cursor.execute("select sys_context(:1, :2) from dual",
|
||||
(namespace, name))
|
||||
value, = cursor.fetchone()
|
||||
print("Value of context key", name, "is", value)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2018, 2023, Oracle and/or its affiliates.
|
||||
#------------------------------------------------------------------------------
|
||||
# Copyright (c) 2018, 2022, Oracle and/or its affiliates.
|
||||
#
|
||||
# This software is dual-licensed to you under the Universal Permissive License
|
||||
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
||||
|
@ -20,15 +20,15 @@
|
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
# aq_notification.py
|
||||
#
|
||||
# Demonstrates using advanced queuing notification. Once this script is
|
||||
# running, run object_aq.py in another terminal to enqueue a few messages to
|
||||
# the "DEMO_BOOK_QUEUE" queue.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
import time
|
||||
|
||||
|
@ -40,7 +40,6 @@ oracledb.init_oracle_client(lib_dir=sample_env.get_oracle_client())
|
|||
|
||||
registered = True
|
||||
|
||||
|
||||
def process_messages(message):
|
||||
global registered
|
||||
print("Message type:", message.type)
|
||||
|
@ -52,20 +51,14 @@ def process_messages(message):
|
|||
print("Consumer name:", message.consumer_name)
|
||||
print("Message id:", message.msgid)
|
||||
|
||||
connection = oracledb.connect(user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string(),
|
||||
events=True)
|
||||
|
||||
connection = oracledb.connect(
|
||||
user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string(),
|
||||
events=True,
|
||||
)
|
||||
|
||||
sub = connection.subscribe(
|
||||
namespace=oracledb.SUBSCR_NAMESPACE_AQ,
|
||||
name="DEMO_BOOK_QUEUE",
|
||||
callback=process_messages,
|
||||
timeout=300,
|
||||
)
|
||||
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)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2016, 2023, Oracle and/or its affiliates.
|
||||
#------------------------------------------------------------------------------
|
||||
# Copyright (c) 2016, 2022, Oracle and/or its affiliates.
|
||||
#
|
||||
# This software is dual-licensed to you under the Universal Permissive License
|
||||
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
||||
|
@ -20,16 +20,16 @@
|
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
# array_dml_rowcounts.py
|
||||
#
|
||||
# Demonstrates 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.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
import oracledb
|
||||
import sample_env
|
||||
|
@ -38,23 +38,19 @@ import sample_env
|
|||
if not sample_env.get_is_thin():
|
||||
oracledb.init_oracle_client(lib_dir=sample_env.get_oracle_client())
|
||||
|
||||
connection = oracledb.connect(
|
||||
user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string(),
|
||||
)
|
||||
connection = oracledb.connect(user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string())
|
||||
|
||||
with connection.cursor() as 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
|
||||
"""
|
||||
):
|
||||
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()
|
||||
|
||||
|
@ -65,11 +61,11 @@ with connection.cursor() as cursor:
|
|||
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,
|
||||
)
|
||||
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()
|
||||
|
|
|
@ -1,84 +0,0 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2023, Oracle and/or its affiliates.
|
||||
#
|
||||
# This software is dual-licensed to you under the Universal Permissive License
|
||||
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
||||
# 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
|
||||
# either license.
|
||||
#
|
||||
# If you elect to accept the software under the Apache License, Version 2.0,
|
||||
# the following applies:
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# array_dml_rowcounts_async.py
|
||||
#
|
||||
# An asynchronous version of array_dml_rowcounts.py
|
||||
#
|
||||
# Demonstrates 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.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
import asyncio
|
||||
|
||||
import oracledb
|
||||
import sample_env
|
||||
|
||||
|
||||
async def main():
|
||||
connection = await oracledb.connect_async(
|
||||
user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string(),
|
||||
)
|
||||
|
||||
with connection.cursor() as cursor:
|
||||
# show the number of rows for each parent ID as a means of verifying
|
||||
# the output from the delete statement
|
||||
await cursor.execute(
|
||||
"""
|
||||
select ParentId, count(*)
|
||||
from ChildTable
|
||||
group by ParentId
|
||||
order by ParentId
|
||||
"""
|
||||
)
|
||||
async for parent_id, count in cursor:
|
||||
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()
|
||||
await 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.")
|
||||
|
||||
|
||||
asyncio.run(main())
|
|
@ -1,81 +0,0 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2023, Oracle and/or its affiliates.
|
||||
#
|
||||
# This software is dual-licensed to you under the Universal Permissive License
|
||||
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
||||
# 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
|
||||
# either license.
|
||||
#
|
||||
# If you elect to accept the software under the Apache License, Version 2.0,
|
||||
# the following applies:
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# async_gather.py
|
||||
#
|
||||
# Demonstrates using a connection pool with asyncio and gather().
|
||||
#
|
||||
# Multiple database sessions will be opened and used by each coroutine. The
|
||||
# number of connections opened can depend on the speed of your environment.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
import asyncio
|
||||
|
||||
import oracledb
|
||||
import sample_env
|
||||
|
||||
# Number of coroutines to run
|
||||
CONCURRENCY = 5
|
||||
|
||||
# Query the unique session identifier/serial number combination of a connection
|
||||
SQL = """SELECT UNIQUE CURRENT_TIMESTAMP AS CT, sid||'-'||serial# AS SIDSER
|
||||
FROM v$session_connect_info
|
||||
WHERE sid = SYS_CONTEXT('USERENV', 'SID')"""
|
||||
|
||||
|
||||
# Show the unique session identifier/serial number of each connection that the
|
||||
# pool opens
|
||||
async def init_session(connection, requested_tag):
|
||||
res = await connection.fetchone(SQL)
|
||||
print(res[0].strftime("%H:%M:%S.%f"), "- init_session SID-SERIAL#", res[1])
|
||||
|
||||
|
||||
# The coroutine simply shows the session identifier/serial number of the
|
||||
# connection returned by the pool.acquire() call
|
||||
async def query(pool):
|
||||
async with pool.acquire() as connection:
|
||||
await connection.callproc("dbms_session.sleep", [1])
|
||||
res = await connection.fetchone(SQL)
|
||||
print(res[0].strftime("%H:%M:%S.%f"), "- query SID-SERIAL#", res[1])
|
||||
|
||||
|
||||
async def main():
|
||||
pool = oracledb.create_pool_async(
|
||||
user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string(),
|
||||
min=1,
|
||||
max=CONCURRENCY,
|
||||
session_callback=init_session,
|
||||
)
|
||||
|
||||
coroutines = [query(pool) for i in range(CONCURRENCY)]
|
||||
|
||||
await asyncio.gather(*coroutines)
|
||||
|
||||
await pool.close()
|
||||
|
||||
|
||||
asyncio.run(main())
|
|
@ -1,5 +1,5 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2016, 2023, Oracle and/or its affiliates.
|
||||
#------------------------------------------------------------------------------
|
||||
# Copyright (c) 2016, 2022, Oracle and/or its affiliates.
|
||||
#
|
||||
# This software is dual-licensed to you under the Universal Permissive License
|
||||
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
||||
|
@ -20,9 +20,9 @@
|
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
# batch_errors.py
|
||||
#
|
||||
# Demonstrates the use of the Oracle Database 12.1 feature that allows
|
||||
|
@ -31,7 +31,7 @@
|
|||
# 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.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
import oracledb
|
||||
import sample_env
|
||||
|
@ -40,28 +40,29 @@ import sample_env
|
|||
if not sample_env.get_is_thin():
|
||||
oracledb.init_oracle_client(lib_dir=sample_env.get_oracle_client())
|
||||
|
||||
connection = oracledb.connect(
|
||||
user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string(),
|
||||
)
|
||||
connection = oracledb.connect(user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string())
|
||||
|
||||
with connection.cursor() as cursor:
|
||||
|
||||
# retrieve the number of rows in the table
|
||||
cursor.execute("select count(*) from ChildTable")
|
||||
(count,) = cursor.fetchone()
|
||||
cursor.execute("""
|
||||
select count(*)
|
||||
from ChildTable""")
|
||||
count, = cursor.fetchone()
|
||||
print("Number of rows in child table:", int(count))
|
||||
|
||||
# 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"),
|
||||
(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'),
|
||||
]
|
||||
print("Number of rows to insert:", len(data_to_insert))
|
||||
|
||||
|
@ -69,17 +70,18 @@ with connection.cursor() as cursor:
|
|||
# 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
|
||||
)
|
||||
cursor.executemany("insert into ChildTable values (:1, :2, :3)",
|
||||
data_to_insert)
|
||||
except oracledb.DatabaseError as e:
|
||||
(error,) = e.args
|
||||
error, = e.args
|
||||
print("Failure with error:", error.message)
|
||||
print("Number of rows successfully inserted:", cursor.rowcount)
|
||||
|
||||
# demonstrate that the row count is accurate
|
||||
cursor.execute("select count(*) from ChildTable")
|
||||
(count,) = cursor.fetchone()
|
||||
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
|
||||
|
@ -87,12 +89,9 @@ with connection.cursor() as cursor:
|
|||
|
||||
# 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,
|
||||
)
|
||||
cursor.executemany("insert into ChildTable values (:1, :2, :3)",
|
||||
data_to_insert, batcherrors=True,
|
||||
arraydmlrowcounts=True)
|
||||
|
||||
# display the errors that have taken place
|
||||
errors = cursor.getbatcherrors()
|
||||
|
@ -107,10 +106,9 @@ with connection.cursor() as cursor:
|
|||
|
||||
# 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 insert with batcherrors "
|
||||
"enabled:",
|
||||
int(count),
|
||||
)
|
||||
cursor.execute("""
|
||||
select count(*)
|
||||
from ChildTable""")
|
||||
count, = cursor.fetchone()
|
||||
print("Number of rows in child table after insert with batcherrors "
|
||||
"enabled:", int(count))
|
||||
|
|
|
@ -1,123 +0,0 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2023, Oracle and/or its affiliates.
|
||||
#
|
||||
# This software is dual-licensed to you under the Universal Permissive License
|
||||
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
||||
# 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
|
||||
# either license.
|
||||
#
|
||||
# If you elect to accept the software under the Apache License, Version 2.0,
|
||||
# the following applies:
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# batch_errors_async.py
|
||||
#
|
||||
# An asynchronous version of batch_errors.py
|
||||
#
|
||||
# Demonstrates 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.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
import asyncio
|
||||
|
||||
import oracledb
|
||||
import sample_env
|
||||
|
||||
|
||||
async def main():
|
||||
connection = await oracledb.connect_async(
|
||||
user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string(),
|
||||
)
|
||||
|
||||
with connection.cursor() as cursor:
|
||||
# retrieve the number of rows in the table
|
||||
await cursor.execute("select count(*) from ChildTable")
|
||||
(count,) = await cursor.fetchone()
|
||||
print("Number of rows in child table:", int(count))
|
||||
|
||||
# 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"),
|
||||
]
|
||||
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:
|
||||
await cursor.executemany(
|
||||
"insert into ChildTable values (:1, :2, :3)", data_to_insert
|
||||
)
|
||||
except oracledb.DatabaseError as e:
|
||||
(error,) = e.args
|
||||
print("Failure with error:", error.message)
|
||||
print("Number of rows successfully inserted:", cursor.rowcount)
|
||||
|
||||
# demonstrate that the row count is accurate
|
||||
await cursor.execute("select count(*) from ChildTable")
|
||||
(count,) = await 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
|
||||
await connection.rollback()
|
||||
|
||||
# new method: executemany() with batch errors enabled (and array DML
|
||||
# row counts also enabled) results in no immediate error being raised
|
||||
await cursor.executemany(
|
||||
"insert into ChildTable values (:1, :2, :3)",
|
||||
data_to_insert,
|
||||
batcherrors=True,
|
||||
arraydmlrowcounts=True,
|
||||
)
|
||||
|
||||
# display the errors that have taken place
|
||||
errors = cursor.getbatcherrors()
|
||||
print("Number of rows with bad values:", len(errors))
|
||||
for error in errors:
|
||||
print(
|
||||
"Error", error.message.rstrip(), "at row offset", error.offset
|
||||
)
|
||||
|
||||
# arraydmlrowcounts also shows rows with invalid data: they have a row
|
||||
# count of 0; otherwise 1 is shown
|
||||
row_counts = cursor.getarraydmlrowcounts()
|
||||
print("Array DML row counts:", row_counts)
|
||||
|
||||
# demonstrate that all of the rows without errors have been
|
||||
# successfully inserted
|
||||
await cursor.execute("select count(*) from ChildTable")
|
||||
(count,) = await cursor.fetchone()
|
||||
print(
|
||||
"Number of rows in child table after insert with batcherrors "
|
||||
"enabled:",
|
||||
int(count),
|
||||
)
|
||||
|
||||
|
||||
asyncio.run(main())
|
|
@ -1,5 +1,5 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2016, 2023, Oracle and/or its affiliates.
|
||||
#------------------------------------------------------------------------------
|
||||
# Copyright (c) 2016, 2022, Oracle and/or its affiliates.
|
||||
#
|
||||
# This software is dual-licensed to you under the Universal Permissive License
|
||||
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
||||
|
@ -20,13 +20,13 @@
|
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
# bind_insert.py
|
||||
#
|
||||
# Demonstrates how to insert rows into a table using bind variables.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
import oracledb
|
||||
import sample_env
|
||||
|
@ -35,27 +35,26 @@ import sample_env
|
|||
if not sample_env.get_is_thin():
|
||||
oracledb.init_oracle_client(lib_dir=sample_env.get_oracle_client())
|
||||
|
||||
connection = oracledb.connect(
|
||||
user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string(),
|
||||
)
|
||||
connection = oracledb.connect(user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string())
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
# "Bind by position"
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
rows = [
|
||||
(1, "First"),
|
||||
(2, "Second"),
|
||||
(3, "Third"),
|
||||
(4, "Fourth"),
|
||||
(5, None), # Insert a NULL value
|
||||
(5, None), # Insert a NULL value
|
||||
(6, "Sixth"),
|
||||
(7, "Seventh"),
|
||||
(7, "Seventh")
|
||||
]
|
||||
|
||||
with connection.cursor() as cursor:
|
||||
|
||||
# predefine the maximum string size to avoid data scans and memory
|
||||
# reallocations. The value 'None' indicates that the default processing
|
||||
# can take place
|
||||
|
@ -63,29 +62,33 @@ with connection.cursor() as cursor:
|
|||
|
||||
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},
|
||||
{"i": 11}, # Insert a NULL value
|
||||
{"d": "Ninth", "i": 9},
|
||||
{"d": "Tenth", "i": 10},
|
||||
{"i": 11} # Insert a NULL value
|
||||
]
|
||||
|
||||
with connection.cursor() as 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",)]
|
||||
rows = [
|
||||
("Eleventh",),
|
||||
("Twelth",)
|
||||
]
|
||||
|
||||
with connection.cursor() as cursor:
|
||||
cursor.executemany("insert into mytab(id, data) values (12, :1)", rows)
|
||||
|
@ -93,9 +96,9 @@ with connection.cursor() as cursor:
|
|||
# Don't commit - this lets the demo be run multiple times
|
||||
# connection.commit()
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
# Now query the results back
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
with connection.cursor() as cursor:
|
||||
for row in cursor.execute("select * from mytab order by id"):
|
||||
|
|
|
@ -1,111 +0,0 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2023, Oracle and/or its affiliates.
|
||||
#
|
||||
# This software is dual-licensed to you under the Universal Permissive License
|
||||
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
||||
# 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
|
||||
# either license.
|
||||
#
|
||||
# If you elect to accept the software under the Apache License, Version 2.0,
|
||||
# the following applies:
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# bind_insert_async.py
|
||||
#
|
||||
# An asynchronous version of bind_insert.py
|
||||
#
|
||||
# Demonstrates how to insert rows into a table using bind variables.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
import asyncio
|
||||
|
||||
import oracledb
|
||||
import sample_env
|
||||
|
||||
|
||||
async def main():
|
||||
connection = await oracledb.connect_async(
|
||||
user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string(),
|
||||
)
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# "Bind by position"
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
rows = [
|
||||
(1, "First"),
|
||||
(2, "Second"),
|
||||
(3, "Third"),
|
||||
(4, "Fourth"),
|
||||
(5, None), # Insert a NULL value
|
||||
(6, "Sixth"),
|
||||
(7, "Seventh"),
|
||||
]
|
||||
|
||||
with connection.cursor() as cursor:
|
||||
# predefine the maximum string size to avoid data scans and memory
|
||||
# reallocations. The value 'None' indicates that the default
|
||||
# processing can take place
|
||||
cursor.setinputsizes(None, 20)
|
||||
|
||||
await 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},
|
||||
{"i": 11}, # Insert a NULL value
|
||||
]
|
||||
|
||||
with connection.cursor() as cursor:
|
||||
# Predefine maximum string size to avoid data scans and memory
|
||||
# reallocations
|
||||
cursor.setinputsizes(d=20)
|
||||
|
||||
await cursor.executemany(
|
||||
"insert into mytab(id, data) values (:i, :d)", rows
|
||||
)
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Inserting a single bind still needs tuples
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
rows = [("Eleventh",), ("Twelth",)]
|
||||
|
||||
await connection.executemany(
|
||||
"insert into mytab(id, data) values (12, :1)", rows
|
||||
)
|
||||
|
||||
# Don't commit - this lets the demo be run multiple times
|
||||
# await connection.commit()
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Now query the results back
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
for row in await connection.fetchall("select * from mytab order by id"):
|
||||
print(row)
|
||||
|
||||
|
||||
asyncio.run(main())
|
|
@ -1,5 +1,5 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2016, 2023, Oracle and/or its affiliates.
|
||||
#------------------------------------------------------------------------------
|
||||
# Copyright (c) 2016, 2022, Oracle and/or its affiliates.
|
||||
#
|
||||
# This software is dual-licensed to you under the Universal Permissive License
|
||||
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
||||
|
@ -20,9 +20,9 @@
|
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
# bind_query.py
|
||||
#
|
||||
# Demonstrates the use of bind variables in queries. Binding is important for
|
||||
|
@ -31,7 +31,7 @@
|
|||
# increasing performance. It also permits data to be bound without having to be
|
||||
# concerned about escaping special characters, or be concerned about SQL
|
||||
# injection attacks.
|
||||
# -----------------------------------------------------------------------------
|
||||
##------------------------------------------------------------------------------
|
||||
|
||||
import oracledb
|
||||
import sample_env
|
||||
|
@ -40,22 +40,21 @@ import sample_env
|
|||
if not sample_env.get_is_thin():
|
||||
oracledb.init_oracle_client(lib_dir=sample_env.get_oracle_client())
|
||||
|
||||
connection = oracledb.connect(
|
||||
user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string(),
|
||||
)
|
||||
connection = oracledb.connect(user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string())
|
||||
|
||||
# Bind by position with lists
|
||||
with connection.cursor() as cursor:
|
||||
|
||||
print("1. Bind by position: single value list")
|
||||
sql = "select * from SampleQueryTab where id = :bvid"
|
||||
sql = 'select * from SampleQueryTab where id = :bvid'
|
||||
for row in cursor.execute(sql, [1]):
|
||||
print(row)
|
||||
print()
|
||||
|
||||
print("2. Bind by position: multiple values")
|
||||
sql = "select * from SampleQueryTab where id = :bvid and 123 = :otherbind"
|
||||
sql = 'select * from SampleQueryTab where id = :bvid and 123 = :otherbind'
|
||||
for row in cursor.execute(sql, [2, 123]):
|
||||
print(row)
|
||||
print()
|
||||
|
@ -64,10 +63,8 @@ with connection.cursor() as cursor:
|
|||
# order of the placeholders used in the SQL statement. The bind list data
|
||||
# order is not associated by the name of the bind variable placeholders in
|
||||
# the SQL statement, even though those names are ":1" and ":2".
|
||||
print(
|
||||
"3. Bind by position: multiple values with numeric placeholder names"
|
||||
)
|
||||
sql = "select * from SampleQueryTab where id = :2 and 456 = :1"
|
||||
print("3. Bind by position: multiple values with numeric placeholder names")
|
||||
sql = 'select * from SampleQueryTab where id = :2 and 456 = :1'
|
||||
for row in cursor.execute(sql, [3, 456]):
|
||||
print(row)
|
||||
print()
|
||||
|
@ -75,7 +72,7 @@ with connection.cursor() as cursor:
|
|||
# With bind-by-position, repeated use of bind placeholder names in the SQL
|
||||
# statement requires the input list data to be repeated.
|
||||
print("4. Bind by position: multiple values with a repeated placeholder")
|
||||
sql = "select * from SampleQueryTab where id = :2 and 3 = :2"
|
||||
sql = 'select * from SampleQueryTab where id = :2 and 3 = :2'
|
||||
for row in cursor.execute(sql, [3, 3]):
|
||||
print(row)
|
||||
print()
|
||||
|
@ -83,22 +80,24 @@ with connection.cursor() as cursor:
|
|||
|
||||
# Bind by position with tuples
|
||||
with connection.cursor() as cursor:
|
||||
|
||||
print("5. Bind by position with single value tuple")
|
||||
sql = "select * from SampleQueryTab where id = :bvid"
|
||||
sql = 'select * from SampleQueryTab where id = :bvid'
|
||||
for row in cursor.execute(sql, (4,)):
|
||||
print(row)
|
||||
print()
|
||||
|
||||
print("6. Bind by position with a multiple value tuple")
|
||||
sql = "select * from SampleQueryTab where id = :bvid and 789 = :otherbind"
|
||||
for row in cursor.execute(sql, (4, 789)):
|
||||
sql = 'select * from SampleQueryTab where id = :bvid and 789 = :otherbind'
|
||||
for row in cursor.execute(sql, (4,789)):
|
||||
print(row)
|
||||
print()
|
||||
|
||||
# Bind by name with a dictionary
|
||||
with connection.cursor() as cursor:
|
||||
|
||||
print("7. Bind by name with a dictionary")
|
||||
sql = "select * from SampleQueryTab where id = :bvid"
|
||||
sql = 'select * from SampleQueryTab where id = :bvid'
|
||||
for row in cursor.execute(sql, {"bvid": 4}):
|
||||
print(row)
|
||||
print()
|
||||
|
@ -106,7 +105,7 @@ with connection.cursor() as cursor:
|
|||
# With bind-by-name, repeated use of bind placeholder names in the SQL
|
||||
# statement lets you supply the data once.
|
||||
print("8. Bind by name with multiple value dict and repeated placeholders")
|
||||
sql = "select * from SampleQueryTab where id = :bvid and 4 = :bvid"
|
||||
sql = 'select * from SampleQueryTab where id = :bvid and 4 = :bvid'
|
||||
for row in cursor.execute(sql, {"bvid": 4}):
|
||||
print(row)
|
||||
print()
|
||||
|
@ -114,14 +113,15 @@ with connection.cursor() as cursor:
|
|||
# Bind by name with parameters. The execute() parameter names match the bind
|
||||
# variable placeholder names.
|
||||
with connection.cursor() as cursor:
|
||||
|
||||
print("9. Bind by name using parameters")
|
||||
sql = "select * from SampleQueryTab where id = :bvid"
|
||||
sql = 'select * from SampleQueryTab where id = :bvid'
|
||||
for row in cursor.execute(sql, bvid=5):
|
||||
print(row)
|
||||
print()
|
||||
|
||||
print("10. Bind by name using multiple parameters")
|
||||
sql = "select * from SampleQueryTab where id = :bvid and 101 = :otherbind"
|
||||
sql = 'select * from SampleQueryTab where id = :bvid and 101 = :otherbind'
|
||||
for row in cursor.execute(sql, bvid=5, otherbind=101):
|
||||
print(row)
|
||||
print()
|
||||
|
@ -129,14 +129,14 @@ with connection.cursor() as cursor:
|
|||
# With bind-by-name, repeated use of bind placeholder names in the SQL
|
||||
# statement lets you supply the data once.
|
||||
print("11. Bind by name: multiple values with repeated placeholder names")
|
||||
sql = "select * from SampleQueryTab where id = :bvid and 6 = :bvid"
|
||||
sql = 'select * from SampleQueryTab where id = :bvid and 6 = :bvid'
|
||||
for row in cursor.execute(sql, bvid=6):
|
||||
print(row)
|
||||
print()
|
||||
|
||||
# Rexcuting a query with different data values
|
||||
with connection.cursor() as cursor:
|
||||
sql = "select * from SampleQueryTab where id = :bvid"
|
||||
sql = 'select * from SampleQueryTab where id = :bvid'
|
||||
|
||||
print("12. Query results with id = 7")
|
||||
for row in cursor.execute(sql, [4]):
|
||||
|
|
|
@ -1,136 +0,0 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2023, Oracle and/or its affiliates.
|
||||
#
|
||||
# This software is dual-licensed to you under the Universal Permissive License
|
||||
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
||||
# 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
|
||||
# either license.
|
||||
#
|
||||
# If you elect to accept the software under the Apache License, Version 2.0,
|
||||
# the following applies:
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# bind_query_async.py
|
||||
#
|
||||
# An asynchronous version of bind_query.py
|
||||
#
|
||||
# Demonstrates the use of bind variables in queries. Binding is important for
|
||||
# scalability and security. Since the text of a query that is re-executed is
|
||||
# unchanged, 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 be concerned about SQL
|
||||
# injection attacks.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
import asyncio
|
||||
|
||||
import oracledb
|
||||
import sample_env
|
||||
|
||||
|
||||
async def main():
|
||||
connection = await oracledb.connect_async(
|
||||
user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string(),
|
||||
)
|
||||
|
||||
# Bind by position with lists
|
||||
print("1. Bind by position: single value list")
|
||||
sql = "select * from SampleQueryTab where id = :bvid"
|
||||
print(await connection.fetchone(sql, [1]))
|
||||
print()
|
||||
|
||||
print("2. Bind by position: multiple values")
|
||||
sql = "select * from SampleQueryTab where id = :bvid and 123 = :otherbind"
|
||||
print(await connection.fetchone(sql, [2, 123]))
|
||||
print()
|
||||
|
||||
# With bind-by-position, the order of the data in the bind list matches
|
||||
# the order of the placeholders used in the SQL statement. The bind
|
||||
# list data order is not associated by the name of the bind variable
|
||||
# placeholders in the SQL statement, even though those names are ":1"
|
||||
# and ":2".
|
||||
print(
|
||||
"3. Bind by position: multiple values with numeric placeholder names"
|
||||
)
|
||||
sql = "select * from SampleQueryTab where id = :2 and 456 = :1"
|
||||
print(await connection.fetchone(sql, [3, 456]))
|
||||
print()
|
||||
|
||||
# With bind-by-position, repeated use of bind placeholder names in the
|
||||
# SQL statement requires the input list data to be repeated.
|
||||
print("4. Bind by position: multiple values with a repeated placeholder")
|
||||
sql = "select * from SampleQueryTab where id = :2 and 3 = :2"
|
||||
print(await connection.fetchall(sql, [3, 3]))
|
||||
print()
|
||||
|
||||
# Bind by position with tuples
|
||||
print("5. Bind by position with single value tuple")
|
||||
sql = "select * from SampleQueryTab where id = :bvid"
|
||||
print(await connection.fetchone(sql, (4,)))
|
||||
print()
|
||||
|
||||
print("6. Bind by position with a multiple value tuple")
|
||||
sql = "select * from SampleQueryTab where id = :bvid and 789 = :otherbind"
|
||||
print(await connection.fetchone(sql, (4, 789)))
|
||||
print()
|
||||
|
||||
# Bind by name with a dictionary
|
||||
print("7. Bind by name with a dictionary")
|
||||
sql = "select * from SampleQueryTab where id = :bvid"
|
||||
print(await connection.fetchone(sql, {"bvid": 4}))
|
||||
print()
|
||||
|
||||
# With bind-by-name, repeated use of bind placeholder names in the SQL
|
||||
# statement lets you supply the data once.
|
||||
print("8. Bind by name with multiple value dict and repeated placeholders")
|
||||
sql = "select * from SampleQueryTab where id = :bvid and 4 = :bvid"
|
||||
print(await connection.fetchone(sql, {"bvid": 4}))
|
||||
print()
|
||||
|
||||
# Bind by name with parameters. The execute() parameter names match the
|
||||
# bind variable placeholder names.
|
||||
print("9. Bind by name using parameters")
|
||||
sql = "select * from SampleQueryTab where id = :bvid"
|
||||
print(await connection.fetchone(sql, dict(bvid=5)))
|
||||
print()
|
||||
|
||||
print("10. Bind by name using multiple parameters")
|
||||
sql = "select * from SampleQueryTab where id = :bvid and 101 = :otherbind"
|
||||
print(await connection.fetchone(sql, dict(bvid=5, otherbind=101)))
|
||||
print()
|
||||
|
||||
# With bind-by-name, repeated use of bind placeholder names in the SQL
|
||||
# statement lets you supply the data once.
|
||||
print("11. Bind by name: multiple values with repeated placeholder names")
|
||||
sql = "select * from SampleQueryTab where id = :bvid and 6 = :bvid"
|
||||
print(await connection.fetchone(sql, dict(bvid=6)))
|
||||
print()
|
||||
|
||||
# Rexcuting a query with different data values
|
||||
sql = "select * from SampleQueryTab where id = :bvid"
|
||||
|
||||
print("12. Query results with id = 7")
|
||||
print(await connection.fetchone(sql, [4]))
|
||||
print()
|
||||
|
||||
print("13. Rexcuted query results with id = 1")
|
||||
print(await connection.fetchone(sql, [1]))
|
||||
print()
|
||||
|
||||
|
||||
asyncio.run(main())
|
|
@ -1,5 +1,5 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2019, 2023, Oracle and/or its affiliates.
|
||||
#------------------------------------------------------------------------------
|
||||
# Copyright (c) 2019, 2022, Oracle and/or its affiliates.
|
||||
#
|
||||
# Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
|
||||
#
|
||||
|
@ -25,14 +25,14 @@
|
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
# bulk_aq.py
|
||||
#
|
||||
# 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.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
import oracledb
|
||||
import sample_env
|
||||
|
@ -50,18 +50,16 @@ PAYLOAD_DATA = [
|
|||
"The ninth message",
|
||||
"The tenth message",
|
||||
"The eleventh message",
|
||||
"The twelfth and final message",
|
||||
"The twelfth and final message"
|
||||
]
|
||||
|
||||
# this script is currently only supported in python-oracledb thick mode
|
||||
oracledb.init_oracle_client(lib_dir=sample_env.get_oracle_client())
|
||||
|
||||
# connect to database
|
||||
connection = oracledb.connect(
|
||||
user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string(),
|
||||
)
|
||||
connection = oracledb.connect(user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string())
|
||||
|
||||
# create a queue
|
||||
with connection.cursor() as cursor:
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2019, 2023, Oracle and/or its affiliates.
|
||||
#------------------------------------------------------------------------------
|
||||
# Copyright (c) 2019, 2022, Oracle and/or its affiliates.
|
||||
#
|
||||
# This software is dual-licensed to you under the Universal Permissive License
|
||||
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
||||
|
@ -20,9 +20,9 @@
|
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
# call_timeout.py
|
||||
#
|
||||
# Demonstrates the use of the Oracle Client 18c feature that enables round
|
||||
|
@ -30,7 +30,7 @@
|
|||
# (in milliseconds) has passed without a response from the database.
|
||||
#
|
||||
# This script requires Oracle Client 18.1 and higher when using thick mode.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
import oracledb
|
||||
import sample_env
|
||||
|
@ -39,26 +39,23 @@ import sample_env
|
|||
if not sample_env.get_is_thin():
|
||||
oracledb.init_oracle_client(lib_dir=sample_env.get_oracle_client())
|
||||
|
||||
connection = oracledb.connect(
|
||||
user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string(),
|
||||
)
|
||||
connection = oracledb.connect(user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string())
|
||||
|
||||
connection.call_timeout = 2000
|
||||
print("Call timeout set at", connection.call_timeout, "milliseconds...")
|
||||
|
||||
with connection.cursor() as cursor:
|
||||
|
||||
cursor.execute("select sysdate from dual")
|
||||
(today,) = cursor.fetchone()
|
||||
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"
|
||||
)
|
||||
sleep_proc_name = "dbms_session.sleep" \
|
||||
if int(connection.version.split(".")[0]) >= 18 \
|
||||
else "dbms_lock.sleep"
|
||||
|
||||
print("Sleeping...should time out...")
|
||||
try:
|
||||
|
@ -67,5 +64,5 @@ with connection.cursor() as cursor:
|
|||
print("ERROR:", e)
|
||||
|
||||
cursor.execute("select sysdate from dual")
|
||||
(today,) = cursor.fetchone()
|
||||
today, = cursor.fetchone()
|
||||
print("Fetch of current date after timeout:", today)
|
||||
|
|
|
@ -1,73 +0,0 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2023, Oracle and/or its affiliates.
|
||||
#
|
||||
# This software is dual-licensed to you under the Universal Permissive License
|
||||
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
||||
# 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
|
||||
# either license.
|
||||
#
|
||||
# If you elect to accept the software under the Apache License, Version 2.0,
|
||||
# the following applies:
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# call_timeout_async.py
|
||||
#
|
||||
# An asynchronous version of call_timeout.py
|
||||
#
|
||||
# Demonstrates the use of the 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.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
import asyncio
|
||||
|
||||
import oracledb
|
||||
import sample_env
|
||||
|
||||
|
||||
async def main():
|
||||
connection = await oracledb.connect_async(
|
||||
user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string(),
|
||||
)
|
||||
|
||||
connection.call_timeout = 2000
|
||||
print("Call timeout set at", connection.call_timeout, "milliseconds...")
|
||||
|
||||
with connection.cursor() as cursor:
|
||||
(today,) = await connection.fetchone("select sysdate from dual")
|
||||
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:
|
||||
await cursor.callproc(sleep_proc_name, (3,))
|
||||
except oracledb.DatabaseError as e:
|
||||
print("ERROR:", e)
|
||||
|
||||
(today,) = await connection.fetchone("select sysdate from dual")
|
||||
print("Fetch of current date after timeout:", today)
|
||||
|
||||
|
||||
asyncio.run(main())
|
|
@ -1,5 +1,5 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2022, 2023, Oracle and/or its affiliates.
|
||||
#------------------------------------------------------------------------------
|
||||
# Copyright (c) 2022, Oracle and/or its affiliates.
|
||||
#
|
||||
# This software is dual-licensed to you under the Universal Permissive License
|
||||
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
||||
|
@ -20,9 +20,9 @@
|
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
# connection_pool.py
|
||||
#
|
||||
# Demonstrates the use of connection pooling using a Flask web application.
|
||||
|
@ -56,7 +56,7 @@
|
|||
# To insert new a user 'fred' you can call:
|
||||
# http://127.0.0.1:8080/post/fred
|
||||
#
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
@ -67,17 +67,17 @@ import oracledb
|
|||
import sample_env
|
||||
|
||||
# Port to listen on
|
||||
port = int(os.environ.get("PORT", "8080"))
|
||||
port = int(os.environ.get('PORT', '8080'))
|
||||
|
||||
# determine whether to use python-oracledb thin mode or thick mode
|
||||
if not sample_env.get_is_thin():
|
||||
oracledb.init_oracle_client(lib_dir=sample_env.get_oracle_client())
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# start_pool(): starts the connection pool
|
||||
def start_pool():
|
||||
|
||||
# Generally a fixed-size pool is recommended, i.e. pool_min=pool_max. Here
|
||||
# the pool contains 4 connections, which will allow 4 concurrent users.
|
||||
|
||||
|
@ -85,19 +85,16 @@ def start_pool():
|
|||
pool_max = 4
|
||||
pool_inc = 0
|
||||
|
||||
pool = oracledb.create_pool(
|
||||
user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string(),
|
||||
min=pool_min,
|
||||
max=pool_max,
|
||||
increment=pool_inc,
|
||||
session_callback=init_session,
|
||||
)
|
||||
pool = oracledb.create_pool(user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string(),
|
||||
min=pool_min,
|
||||
max=pool_max,
|
||||
increment=pool_inc,
|
||||
session_callback=init_session)
|
||||
|
||||
return pool
|
||||
|
||||
|
||||
# init_session(): a 'session callback' to efficiently set any initial state
|
||||
# that each connection should have.
|
||||
#
|
||||
|
@ -110,81 +107,63 @@ def start_pool():
|
|||
#
|
||||
def init_session(connection, requestedTag_ignored):
|
||||
with connection.cursor() as cursor:
|
||||
cursor.execute(
|
||||
"""
|
||||
cursor.execute("""
|
||||
alter session set
|
||||
time_zone = 'UTC'
|
||||
nls_date_format = 'YYYY-MM-DD HH24:MI'
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
time_zone = 'UTC'
|
||||
nls_date_format = 'YYYY-MM-DD HH24:MI'""")
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# create_schema(): drop and create the demo table, and add a row
|
||||
def create_schema():
|
||||
with pool.acquire() as connection:
|
||||
with connection.cursor() as cursor:
|
||||
cursor.execute(
|
||||
"""
|
||||
cursor.execute("""
|
||||
begin
|
||||
begin
|
||||
execute immediate 'drop table demo';
|
||||
begin
|
||||
execute immediate 'drop table demo';
|
||||
exception when others then
|
||||
if sqlcode <> -942 then
|
||||
raise;
|
||||
end if;
|
||||
end;
|
||||
if sqlcode <> -942 then
|
||||
raise;
|
||||
end if;
|
||||
end;
|
||||
|
||||
execute immediate 'create table demo (
|
||||
id number generated by default as identity,
|
||||
username varchar2(40)
|
||||
)';
|
||||
execute immediate 'create table demo (
|
||||
id number generated by default as identity,
|
||||
username varchar2(40))';
|
||||
|
||||
execute immediate 'insert into demo (username) values
|
||||
(''chris'')';
|
||||
execute immediate 'insert into demo (username) values (''chris'')';
|
||||
|
||||
commit;
|
||||
end;
|
||||
"""
|
||||
)
|
||||
commit;
|
||||
end;""")
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
|
||||
# Display a welcome message on the 'home' page
|
||||
@app.route("/")
|
||||
@app.route('/')
|
||||
def index():
|
||||
return "Welcome to the demo app"
|
||||
|
||||
|
||||
# Add a new username
|
||||
#
|
||||
# The new user's id is generated by the database and returned in the OUT bind
|
||||
# variable 'idbv'.
|
||||
@app.route("/post/<string:username>")
|
||||
@app.route('/post/<string:username>')
|
||||
def post(username):
|
||||
with pool.acquire() as connection:
|
||||
with connection.cursor() as cursor:
|
||||
connection.autocommit = True
|
||||
idbv = cursor.var(int)
|
||||
cursor.execute(
|
||||
"""
|
||||
cursor.execute("""
|
||||
insert into demo (username)
|
||||
values (:unbv)
|
||||
returning id into :idbv
|
||||
""",
|
||||
[username, idbv],
|
||||
)
|
||||
return f"Inserted {username} with id {idbv.getvalue()[0]}"
|
||||
|
||||
returning id into :idbv""", [username, idbv])
|
||||
return f'Inserted {username} with id {idbv.getvalue()[0]}'
|
||||
|
||||
# Show the username for a given id
|
||||
@app.route("/user/<int:id>")
|
||||
@app.route('/user/<int:id>')
|
||||
def show_username(id):
|
||||
with pool.acquire() as connection:
|
||||
with connection.cursor() as cursor:
|
||||
|
@ -192,10 +171,10 @@ def show_username(id):
|
|||
r = cursor.fetchone()
|
||||
return r[0] if r is not None else "Unknown user id"
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
if __name__ == '__main__':
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Start a pool of connections
|
||||
pool = start_pool()
|
||||
|
||||
|
@ -203,7 +182,7 @@ if __name__ == "__main__":
|
|||
create_schema()
|
||||
|
||||
m = f"\nTry loading http://127.0.0.1:{port}/user/1 in a browser\n"
|
||||
sys.modules["flask.cli"].show_server_banner = lambda *x: print(m)
|
||||
sys.modules['flask.cli'].show_server_banner = lambda *x: print(m)
|
||||
|
||||
# Start a webserver
|
||||
app.run(port=port)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2016, 2023, Oracle and/or its affiliates.
|
||||
#------------------------------------------------------------------------------
|
||||
# Copyright (c) 2016, 2022, Oracle and/or its affiliates.
|
||||
#
|
||||
# Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
|
||||
#
|
||||
|
@ -25,16 +25,16 @@
|
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
# cqn.py
|
||||
#
|
||||
# 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.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
import time
|
||||
|
||||
|
@ -46,7 +46,6 @@ oracledb.init_oracle_client(lib_dir=sample_env.get_oracle_client())
|
|||
|
||||
registered = True
|
||||
|
||||
|
||||
def callback(message):
|
||||
global registered
|
||||
print("Message type:", message.type)
|
||||
|
@ -71,18 +70,14 @@ def callback(message):
|
|||
print("-" * 60)
|
||||
print("=" * 60)
|
||||
|
||||
|
||||
connection = oracledb.connect(
|
||||
user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string(),
|
||||
events=True,
|
||||
)
|
||||
connection = oracledb.connect(user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string(),
|
||||
events=True)
|
||||
|
||||
qos = oracledb.SUBSCR_QOS_QUERY | oracledb.SUBSCR_QOS_ROWIDS
|
||||
sub = connection.subscribe(
|
||||
callback=callback, timeout=1800, qos=qos, client_initiated=True
|
||||
)
|
||||
sub = connection.subscribe(callback=callback, timeout=1800,
|
||||
qos=qos, client_initiated=True)
|
||||
print("Subscription:", sub)
|
||||
print("--> Connection:", sub.connection)
|
||||
print("--> Callback:", sub.callback)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2020, 2023, Oracle and/or its affiliates.
|
||||
#------------------------------------------------------------------------------
|
||||
# Copyright (c) 2020, 2022, Oracle and/or its affiliates.
|
||||
#
|
||||
# This software is dual-licensed to you under the Universal Permissive License
|
||||
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
||||
|
@ -20,9 +20,9 @@
|
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
# cqn_pool.py
|
||||
#
|
||||
# Demonstrates using continuous query notification in Python, a feature that is
|
||||
|
@ -33,7 +33,7 @@
|
|||
# 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.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
import time
|
||||
|
||||
|
@ -45,7 +45,6 @@ oracledb.init_oracle_client(lib_dir=sample_env.get_oracle_client())
|
|||
|
||||
registered = True
|
||||
|
||||
|
||||
def callback(message):
|
||||
global registered
|
||||
if not message.registered:
|
||||
|
@ -70,36 +69,26 @@ def callback(message):
|
|||
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()
|
||||
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.create_pool(
|
||||
user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string(),
|
||||
min=1,
|
||||
max=4,
|
||||
increment=1,
|
||||
events=True,
|
||||
)
|
||||
pool = oracledb.create_pool(user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string(),
|
||||
min=1, max=4, 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, client_initiated=True
|
||||
)
|
||||
sub = connection.subscribe(callback=callback, timeout=1800,
|
||||
qos=qos, client_initiated=True)
|
||||
print("Subscription created with ID:", sub.id)
|
||||
query_id = sub.registerquery("select * from TestTempTable")
|
||||
print("Registered query with ID:", query_id)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2020, 2023, Oracle and/or its affiliates.
|
||||
#------------------------------------------------------------------------------
|
||||
# Copyright (c) 2020, 2022, Oracle and/or its affiliates.
|
||||
#
|
||||
# This software is dual-licensed to you under the Universal Permissive License
|
||||
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
||||
|
@ -20,38 +20,33 @@
|
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
# create_schema.py
|
||||
#
|
||||
# Creates users and populates their schemas with the tables and packages
|
||||
# necessary for running the python-oracledb sample scripts. An edition is also
|
||||
# created for the demonstration of PL/SQL editioning.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
import oracledb
|
||||
|
||||
import drop_schema
|
||||
import sample_env
|
||||
|
||||
# connect as administrative user (usually SYSTEM or ADMIN)
|
||||
conn = sample_env.get_admin_connection()
|
||||
conn = oracledb.connect(sample_env.get_admin_connect_string())
|
||||
|
||||
# drop existing users and editions, if applicable
|
||||
drop_schema.drop_schema(conn)
|
||||
|
||||
# create sample schema and edition
|
||||
print("Creating sample schemas and edition...")
|
||||
sample_env.run_sql_script(
|
||||
conn,
|
||||
"create_schema",
|
||||
main_user=sample_env.get_main_user(),
|
||||
main_password=sample_env.get_main_password(),
|
||||
edition_user=sample_env.get_edition_user(),
|
||||
edition_password=sample_env.get_edition_password(),
|
||||
edition_name=sample_env.get_edition_name(),
|
||||
)
|
||||
if sample_env.get_server_version() >= (21, 0):
|
||||
sample_env.run_sql_script(
|
||||
conn, "create_schema_21", main_user=sample_env.get_main_user()
|
||||
)
|
||||
sample_env.run_sql_script(conn, "create_schema",
|
||||
main_user=sample_env.get_main_user(),
|
||||
main_password=sample_env.get_main_password(),
|
||||
edition_user=sample_env.get_edition_user(),
|
||||
edition_password=sample_env.get_edition_password(),
|
||||
edition_name=sample_env.get_edition_name())
|
||||
print("Done.")
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2016, 2023, Oracle and/or its affiliates.
|
||||
#------------------------------------------------------------------------------
|
||||
# Copyright (c) 2016, 2022, Oracle and/or its affiliates.
|
||||
#
|
||||
# Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
|
||||
#
|
||||
|
@ -25,16 +25,16 @@
|
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
# database_change_notification.py
|
||||
#
|
||||
# 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.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
import time
|
||||
|
||||
|
@ -46,7 +46,6 @@ oracledb.init_oracle_client(lib_dir=sample_env.get_oracle_client())
|
|||
|
||||
registered = True
|
||||
|
||||
|
||||
def callback(message):
|
||||
global registered
|
||||
print("Message type:", message.type)
|
||||
|
@ -68,20 +67,13 @@ def callback(message):
|
|||
print("-" * 60)
|
||||
print("=" * 60)
|
||||
|
||||
connection = oracledb.connect(user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string(),
|
||||
events=True)
|
||||
|
||||
connection = oracledb.connect(
|
||||
user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string(),
|
||||
events=True,
|
||||
)
|
||||
|
||||
sub = connection.subscribe(
|
||||
callback=callback,
|
||||
timeout=1800,
|
||||
qos=oracledb.SUBSCR_QOS_ROWIDS,
|
||||
client_initiated=True,
|
||||
)
|
||||
sub = connection.subscribe(callback=callback, timeout=1800,
|
||||
qos=oracledb.SUBSCR_QOS_ROWIDS, client_initiated=True)
|
||||
print("Subscription:", sub)
|
||||
print("--> Connection:", sub.connection)
|
||||
print("--> ID:", sub.id)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2016, 2023, Oracle and/or its affiliates.
|
||||
#------------------------------------------------------------------------------
|
||||
# Copyright (c) 2016, 2022, Oracle and/or its affiliates.
|
||||
#
|
||||
# Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
|
||||
#
|
||||
|
@ -25,14 +25,14 @@
|
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
# database_shutdown.py
|
||||
#
|
||||
# Demonstrates shutting down a database using Python. The connection used
|
||||
# assumes that the environment variable ORACLE_SID has been set.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
import oracledb
|
||||
import sample_env
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2016, 2023, Oracle and/or its affiliates.
|
||||
#------------------------------------------------------------------------------
|
||||
# Copyright (c) 2016, 2022, Oracle and/or its affiliates.
|
||||
#
|
||||
# Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
|
||||
#
|
||||
|
@ -25,14 +25,14 @@
|
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
# database_startup.py
|
||||
#
|
||||
# Demonstrates starting up a database using Python. The connection used
|
||||
# assumes that the environment variable ORACLE_SID has been set.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
import oracledb
|
||||
import sample_env
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2020, 2023, Oracle and/or its affiliates.
|
||||
#------------------------------------------------------------------------------
|
||||
# Copyright (c) 2020, 2022, Oracle and/or its affiliates.
|
||||
#
|
||||
# This software is dual-licensed to you under the Universal Permissive License
|
||||
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
||||
|
@ -20,14 +20,14 @@
|
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
# dbms_output.py
|
||||
#
|
||||
# Demonstrates one method of fetching the lines produced by the DBMS_OUTPUT
|
||||
# package.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
import oracledb
|
||||
import sample_env
|
||||
|
@ -36,26 +36,22 @@ import sample_env
|
|||
if not sample_env.get_is_thin():
|
||||
oracledb.init_oracle_client(lib_dir=sample_env.get_oracle_client())
|
||||
|
||||
connection = oracledb.connect(
|
||||
user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string(),
|
||||
)
|
||||
connection = oracledb.connect(user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string())
|
||||
|
||||
with connection.cursor() as 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 some text');
|
||||
dbms_output.put_line('');
|
||||
dbms_output.put_line('Demonstrating use of DBMS_OUTPUT');
|
||||
end;
|
||||
"""
|
||||
)
|
||||
cursor.execute("""
|
||||
begin
|
||||
dbms_output.put_line('This is some text');
|
||||
dbms_output.put_line('');
|
||||
dbms_output.put_line('Demonstrating use of DBMS_OUTPUT');
|
||||
end;""")
|
||||
|
||||
# tune this size for your application
|
||||
chunk_size = 10
|
||||
|
|
|
@ -1,83 +0,0 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2023, Oracle and/or its affiliates.
|
||||
#
|
||||
# This software is dual-licensed to you under the Universal Permissive License
|
||||
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
||||
# 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
|
||||
# either license.
|
||||
#
|
||||
# If you elect to accept the software under the Apache License, Version 2.0,
|
||||
# the following applies:
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# dbms_output_async.py
|
||||
#
|
||||
# An asynchronous version of dbms_output.py
|
||||
#
|
||||
# Demonstrates one method of fetching the lines produced by the DBMS_OUTPUT
|
||||
# package.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
import asyncio
|
||||
|
||||
import oracledb
|
||||
import sample_env
|
||||
|
||||
|
||||
async def main():
|
||||
connection = await oracledb.connect_async(
|
||||
user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string(),
|
||||
)
|
||||
|
||||
with connection.cursor() as cursor:
|
||||
# enable DBMS_OUTPUT
|
||||
await cursor.callproc("dbms_output.enable")
|
||||
|
||||
# execute some PL/SQL that generates output with DBMS_OUTPUT.PUT_LINE
|
||||
await cursor.execute(
|
||||
"""
|
||||
begin
|
||||
dbms_output.put_line('This is some text');
|
||||
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:
|
||||
await 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
|
||||
|
||||
|
||||
asyncio.run(main())
|
|
@ -1,5 +1,5 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2017, 2023, Oracle and/or its affiliates.
|
||||
#------------------------------------------------------------------------------
|
||||
# Copyright (c) 2017, 2022, Oracle and/or its affiliates.
|
||||
#
|
||||
# Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
|
||||
#
|
||||
|
@ -25,14 +25,14 @@
|
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
# dml_returning_multiple_rows.py
|
||||
#
|
||||
# Demonstrates the use of DML returning with multiple rows being returned at
|
||||
# once.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
import oracledb
|
||||
import sample_env
|
||||
|
@ -41,13 +41,12 @@ import sample_env
|
|||
if not sample_env.get_is_thin():
|
||||
oracledb.init_oracle_client(lib_dir=sample_env.get_oracle_client())
|
||||
|
||||
connection = oracledb.connect(
|
||||
user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string(),
|
||||
)
|
||||
connection = oracledb.connect(user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string())
|
||||
|
||||
with connection.cursor() as cursor:
|
||||
|
||||
# truncate table first so that script can be rerun
|
||||
print("Truncating table...")
|
||||
cursor.execute("truncate table TestTempTable")
|
||||
|
@ -63,14 +62,11 @@ with connection.cursor() as cursor:
|
|||
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,
|
||||
)
|
||||
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]))
|
||||
|
|
|
@ -1,80 +0,0 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2023, Oracle and/or its affiliates.
|
||||
#
|
||||
# This software is dual-licensed to you under the Universal Permissive License
|
||||
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
||||
# 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
|
||||
# either license.
|
||||
#
|
||||
# If you elect to accept the software under the Apache License, Version 2.0,
|
||||
# the following applies:
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# dml_returning_multiple_rows_async.py
|
||||
#
|
||||
# An asynchronous version of dml_returning_multiple_rows.py
|
||||
#
|
||||
# Demonstrates the use of DML returning with multiple rows being returned at
|
||||
# once.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
import asyncio
|
||||
|
||||
import oracledb
|
||||
import sample_env
|
||||
|
||||
|
||||
async def main():
|
||||
connection = await oracledb.connect_async(
|
||||
user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string(),
|
||||
)
|
||||
|
||||
with connection.cursor() as cursor:
|
||||
# truncate table first so that script can be rerun
|
||||
print("Truncating table...")
|
||||
await 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)
|
||||
await cursor.execute(
|
||||
"insert into TestTempTable values (:1, :2)", data
|
||||
)
|
||||
|
||||
# now delete them and use DML returning to return the data that was
|
||||
# deleted
|
||||
int_col = cursor.var(int)
|
||||
string_col = cursor.var(str)
|
||||
print("Deleting data with DML returning...")
|
||||
await 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]))
|
||||
|
||||
|
||||
asyncio.run(main())
|
|
@ -1,5 +1,5 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2022, 2023, Oracle and/or its affiliates.
|
||||
#------------------------------------------------------------------------------
|
||||
# Copyright (c) 2022, Oracle and/or its affiliates.
|
||||
#
|
||||
# This software is dual-licensed to you under the Universal Permissive License
|
||||
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
||||
|
@ -20,9 +20,9 @@
|
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
# drcp_pool.py
|
||||
#
|
||||
# Demonstrates the use of Database Resident Connection Pooling (DRCP)
|
||||
|
@ -93,18 +93,18 @@
|
|||
# Then you can query the data dictionary:
|
||||
#
|
||||
# select cclass_name, num_requests, num_hits,
|
||||
# num_misses, num_waits, num_authentications as num_auths
|
||||
# num_misses, num_waits, num_authentications
|
||||
# from v$cpool_cc_stats;
|
||||
#
|
||||
# Output will be like:
|
||||
#
|
||||
# CCLASS_NAME NUM_REQUESTS NUM_HITS NUM_MISSES NUM_WAITS NUM_AUTHS
|
||||
# ---------------- ------------ -------- ---------- --------- ---------
|
||||
# PYTHONDEMO.MYAPP 1001 997 4 0 4
|
||||
# CCLASS_NAME NUM_REQUESTS NUM_HITS NUM_MISSES NUM_WAITS NUM_AUTHENTICATIONS
|
||||
# ---------------- ------------ -------- ---------- --------- -------------------
|
||||
# PYTHONDEMO.MYAPP 1001 997 4 0 4
|
||||
#
|
||||
# With ADB-S databases, query V$CPOOL_CONN_INFO instead.
|
||||
#
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
@ -115,17 +115,17 @@ import oracledb
|
|||
import sample_env
|
||||
|
||||
# Port to listen on
|
||||
port = int(os.environ.get("PORT", "8080"))
|
||||
port = int(os.environ.get('PORT', '8080'))
|
||||
|
||||
# determine whether to use python-oracledb thin mode or thick mode
|
||||
if not sample_env.get_is_thin():
|
||||
oracledb.init_oracle_client(lib_dir=sample_env.get_oracle_client())
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# start_pool(): starts the connection pool
|
||||
def start_pool():
|
||||
|
||||
# Generally a fixed-size pool is recommended, i.e. pool_min=pool_max. Here
|
||||
# the pool contains 4 connections, which will allow 4 concurrent users.
|
||||
|
||||
|
@ -133,21 +133,16 @@ def start_pool():
|
|||
pool_max = 4
|
||||
pool_inc = 0
|
||||
|
||||
pool = oracledb.create_pool(
|
||||
user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_drcp_connect_string(),
|
||||
min=pool_min,
|
||||
max=pool_max,
|
||||
increment=pool_inc,
|
||||
session_callback=init_session,
|
||||
cclass="MYAPP",
|
||||
purity=oracledb.ATTR_PURITY_SELF,
|
||||
)
|
||||
pool = oracledb.create_pool(user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_drcp_connect_string(),
|
||||
min=pool_min, max=pool_max, increment=pool_inc,
|
||||
session_callback=init_session,
|
||||
cclass="MYAPP",
|
||||
purity=oracledb.ATTR_PURITY_SELF)
|
||||
|
||||
return pool
|
||||
|
||||
|
||||
# init_session(): a 'session callback' to efficiently set any initial state
|
||||
# that each connection should have.
|
||||
#
|
||||
|
@ -160,81 +155,63 @@ def start_pool():
|
|||
#
|
||||
def init_session(connection, requestedTag_ignored):
|
||||
with connection.cursor() as cursor:
|
||||
cursor.execute(
|
||||
"""
|
||||
cursor.execute("""
|
||||
alter session set
|
||||
time_zone = 'UTC'
|
||||
nls_date_format = 'YYYY-MM-DD HH24:MI'
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
time_zone = 'UTC'
|
||||
nls_date_format = 'YYYY-MM-DD HH24:MI'""")
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# create_schema(): drop and create the demo table, and add a row
|
||||
def create_schema():
|
||||
with pool.acquire() as connection:
|
||||
with connection.cursor() as cursor:
|
||||
cursor.execute(
|
||||
"""
|
||||
cursor.execute("""
|
||||
begin
|
||||
begin
|
||||
execute immediate 'drop table demo';
|
||||
begin
|
||||
execute immediate 'drop table demo';
|
||||
exception when others then
|
||||
if sqlcode <> -942 then
|
||||
raise;
|
||||
end if;
|
||||
end;
|
||||
if sqlcode <> -942 then
|
||||
raise;
|
||||
end if;
|
||||
end;
|
||||
|
||||
execute immediate 'create table demo (
|
||||
id number generated by default as identity,
|
||||
username varchar2(40)
|
||||
)';
|
||||
execute immediate 'create table demo (
|
||||
id number generated by default as identity,
|
||||
username varchar2(40))';
|
||||
|
||||
execute immediate 'insert into demo (username)
|
||||
values (''chris'')';
|
||||
execute immediate 'insert into demo (username) values (''chris'')';
|
||||
|
||||
commit;
|
||||
end;
|
||||
"""
|
||||
)
|
||||
commit;
|
||||
end;""")
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
|
||||
# Display a welcome message on the 'home' page
|
||||
@app.route("/")
|
||||
@app.route('/')
|
||||
def index():
|
||||
return "Welcome to the demo app"
|
||||
|
||||
|
||||
# Add a new username
|
||||
#
|
||||
# The new user's id is generated by the database and returned in the OUT bind
|
||||
# variable 'idbv'.
|
||||
@app.route("/post/<string:username>")
|
||||
@app.route('/post/<string:username>')
|
||||
def post(username):
|
||||
with pool.acquire() as connection:
|
||||
with connection.cursor() as cursor:
|
||||
connection.autocommit = True
|
||||
idbv = cursor.var(int)
|
||||
cursor.execute(
|
||||
"""
|
||||
cursor.execute("""
|
||||
insert into demo (username)
|
||||
values (:unbv)
|
||||
returning id into :idbv
|
||||
""",
|
||||
[username, idbv],
|
||||
)
|
||||
return f"Inserted {username} with id {idbv.getvalue()[0]}"
|
||||
|
||||
returning id into :idbv""", [username, idbv])
|
||||
return f'Inserted {username} with id {idbv.getvalue()[0]}'
|
||||
|
||||
# Show the username for a given id
|
||||
@app.route("/user/<int:id>")
|
||||
@app.route('/user/<int:id>')
|
||||
def show_username(id):
|
||||
with pool.acquire() as connection:
|
||||
with connection.cursor() as cursor:
|
||||
|
@ -242,10 +219,10 @@ def show_username(id):
|
|||
r = cursor.fetchone()
|
||||
return r[0] if r is not None else "Unknown user id"
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
if __name__ == '__main__':
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Start a pool of connections
|
||||
pool = start_pool()
|
||||
|
||||
|
@ -253,7 +230,7 @@ if __name__ == "__main__":
|
|||
create_schema()
|
||||
|
||||
m = f"\nTry loading http://127.0.0.1:{port}/user/1 in a browser\n"
|
||||
sys.modules["flask.cli"].show_server_banner = lambda *x: print(m)
|
||||
sys.modules['flask.cli'].show_server_banner = lambda *x: print(m)
|
||||
|
||||
# Start a webserver
|
||||
app.run(port=port)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2020, 2023, Oracle and/or its affiliates.
|
||||
#------------------------------------------------------------------------------
|
||||
# Copyright (c) 2020, 2022, Oracle and/or its affiliates.
|
||||
#
|
||||
# This software is dual-licensed to you under the Universal Permissive License
|
||||
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
||||
|
@ -20,9 +20,9 @@
|
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
# drop_schema.py
|
||||
#
|
||||
# Drops the database objects used by the python-oracledb samples.
|
||||
|
@ -30,23 +30,19 @@
|
|||
# This script is also executed by the Python script sample_setup.py for
|
||||
# dropping the existing users and editions, if applicable, before creating the
|
||||
# sample schemas and editions.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
import oracledb
|
||||
import sample_env
|
||||
|
||||
|
||||
def drop_schema(conn):
|
||||
print("Dropping sample schemas and edition...")
|
||||
sample_env.run_sql_script(
|
||||
conn,
|
||||
"drop_schema",
|
||||
main_user=sample_env.get_main_user(),
|
||||
edition_user=sample_env.get_edition_user(),
|
||||
edition_name=sample_env.get_edition_name(),
|
||||
)
|
||||
|
||||
sample_env.run_sql_script(conn, "drop_schema",
|
||||
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 = sample_env.get_admin_connection()
|
||||
conn = oracledb.connect(sample_env.get_admin_connect_string())
|
||||
drop_schema(conn)
|
||||
print("Done.")
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2016, 2023, Oracle and/or its affiliates.
|
||||
#------------------------------------------------------------------------------
|
||||
# Copyright (c) 2016, 2022, Oracle and/or its affiliates.
|
||||
#
|
||||
# Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
|
||||
#
|
||||
|
@ -25,16 +25,16 @@
|
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
# editioning.py
|
||||
#
|
||||
# Demonstrates the use of Edition-Based Redefinition, a feature that is
|
||||
# available in Oracle Database 11.2 and higher. See the Oracle documentation on
|
||||
# the subject for additional information. Adjust the contents at the top of the
|
||||
# script for your own database as needed.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
import os
|
||||
|
||||
|
@ -50,72 +50,49 @@ 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;
|
||||
"""
|
||||
)
|
||||
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)
|
||||
)
|
||||
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;
|
||||
"""
|
||||
)
|
||||
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),
|
||||
)
|
||||
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)
|
||||
)
|
||||
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()
|
||||
)
|
||||
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),
|
||||
)
|
||||
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),
|
||||
)
|
||||
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),
|
||||
)
|
||||
print("Function should return 'Edition 1 Procedure', actually returns:",
|
||||
repr(result))
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2016, 2023, Oracle and/or its affiliates.
|
||||
#------------------------------------------------------------------------------
|
||||
# Copyright (c) 2016, 2022, Oracle and/or its affiliates.
|
||||
#
|
||||
# This software is dual-licensed to you under the Universal Permissive License
|
||||
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
||||
|
@ -20,14 +20,14 @@
|
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
# generic_row_factory.py
|
||||
#
|
||||
# Demonstrates the ability to return named tuples for all queries using a
|
||||
# subclassed cursor and row factory.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
import collections
|
||||
|
||||
|
@ -38,32 +38,32 @@ import sample_env
|
|||
if not sample_env.get_is_thin():
|
||||
oracledb.init_oracle_client(lib_dir=sample_env.get_oracle_client())
|
||||
|
||||
|
||||
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
|
||||
prepare_needed = (self.statement != statement)
|
||||
result = super().execute(statement, args or [])
|
||||
if prepare_needed:
|
||||
description = self.description
|
||||
if description is not None:
|
||||
names = [d.name for d in description]
|
||||
names = [d[0] for d in description]
|
||||
self.rowfactory = collections.namedtuple("GenericQuery", names)
|
||||
return result
|
||||
|
||||
|
||||
# create a new subclassed connection and cursor
|
||||
connection = Connection(
|
||||
user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string(),
|
||||
)
|
||||
connection = Connection(user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string())
|
||||
|
||||
with connection.cursor() as 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)
|
||||
|
|
|
@ -1,80 +0,0 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2023, Oracle and/or its affiliates.
|
||||
#
|
||||
# This software is dual-licensed to you under the Universal Permissive License
|
||||
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
||||
# 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
|
||||
# either license.
|
||||
#
|
||||
# If you elect to accept the software under the Apache License, Version 2.0,
|
||||
# the following applies:
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# generic_row_factory_async.py
|
||||
#
|
||||
# An asynchronous version of generic_row_factory.py
|
||||
#
|
||||
# Demonstrates the ability to return named tuples for all queries using a
|
||||
# subclassed cursor and row factory.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
import asyncio
|
||||
import collections
|
||||
|
||||
import oracledb
|
||||
import sample_env
|
||||
|
||||
|
||||
class Connection(oracledb.AsyncConnection):
|
||||
def cursor(self):
|
||||
return Cursor(self)
|
||||
|
||||
|
||||
class Cursor(oracledb.AsyncCursor):
|
||||
async def execute(self, statement, args=None):
|
||||
prepare_needed = self.statement != statement
|
||||
result = await super().execute(statement, args or [])
|
||||
if prepare_needed:
|
||||
description = self.description
|
||||
if description is not None:
|
||||
names = [d.name for d in description]
|
||||
self.rowfactory = collections.namedtuple("GenericQuery", names)
|
||||
return result
|
||||
|
||||
|
||||
async def main():
|
||||
# create a new subclassed connection and cursor
|
||||
connection = await oracledb.connect_async(
|
||||
conn_class=Connection,
|
||||
user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string(),
|
||||
)
|
||||
|
||||
with connection.cursor() as cursor:
|
||||
# the names are now available directly for each query executed
|
||||
await cursor.execute("select ParentId, Description from ParentTable")
|
||||
async for row in cursor:
|
||||
print(row.PARENTID, "->", row.DESCRIPTION)
|
||||
print()
|
||||
|
||||
await cursor.execute("select ChildId, Description from ChildTable")
|
||||
async for row in cursor:
|
||||
print(row.CHILDID, "->", row.DESCRIPTION)
|
||||
print()
|
||||
|
||||
|
||||
asyncio.run(main())
|
|
@ -1,5 +1,5 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2016, 2023, Oracle and/or its affiliates.
|
||||
#------------------------------------------------------------------------------
|
||||
# Copyright (c) 2016, 2022, Oracle and/or its affiliates.
|
||||
#
|
||||
# Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
|
||||
#
|
||||
|
@ -25,15 +25,15 @@
|
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
# implicit_results.py
|
||||
#
|
||||
# Demonstrates the use of the Oracle Database 12.1 feature that allows PL/SQL
|
||||
# procedures to return result sets implicitly, without having to explicitly
|
||||
# define them.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
import oracledb
|
||||
import sample_env
|
||||
|
@ -42,34 +42,30 @@ import sample_env
|
|||
if not sample_env.get_is_thin():
|
||||
oracledb.init_oracle_client(lib_dir=sample_env.get_oracle_client())
|
||||
|
||||
connection = oracledb.connect(
|
||||
user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string(),
|
||||
)
|
||||
connection = oracledb.connect(user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string())
|
||||
|
||||
with connection.cursor() as cursor:
|
||||
|
||||
# A PL/SQL block that returns two cursors
|
||||
cursor.execute(
|
||||
"""
|
||||
declare
|
||||
c1 sys_refcursor;
|
||||
c2 sys_refcursor;
|
||||
begin
|
||||
cursor.execute("""
|
||||
declare
|
||||
c1 sys_refcursor;
|
||||
c2 sys_refcursor;
|
||||
begin
|
||||
|
||||
open c1 for
|
||||
select * from TestNumbers;
|
||||
open c1 for
|
||||
select * from TestNumbers;
|
||||
|
||||
dbms_sql.return_result(c1);
|
||||
dbms_sql.return_result(c1);
|
||||
|
||||
open c2 for
|
||||
select * from TestStrings;
|
||||
open c2 for
|
||||
select * from TestStrings;
|
||||
|
||||
dbms_sql.return_result(c2);
|
||||
dbms_sql.return_result(c2);
|
||||
|
||||
end;
|
||||
"""
|
||||
)
|
||||
end;""")
|
||||
|
||||
# display results
|
||||
for ix, result_set in enumerate(cursor.getimplicitresults()):
|
||||
|
|
|
@ -1,79 +0,0 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2023, Oracle and/or its affiliates.
|
||||
#
|
||||
# This software is dual-licensed to you under the Universal Permissive License
|
||||
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
||||
# 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
|
||||
# either license.
|
||||
#
|
||||
# If you elect to accept the software under the Apache License, Version 2.0,
|
||||
# the following applies:
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# implicit_results_async.py
|
||||
#
|
||||
# An asynchronous version of implicit_results.py
|
||||
#
|
||||
# Demonstrates the use of the Oracle Database 12.1 feature that allows PL/SQL
|
||||
# procedures to return result sets implicitly, without having to explicitly
|
||||
# define them.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
import asyncio
|
||||
|
||||
import oracledb
|
||||
import sample_env
|
||||
|
||||
|
||||
async def main():
|
||||
connection = await oracledb.connect_async(
|
||||
user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string(),
|
||||
)
|
||||
|
||||
with connection.cursor() as cursor:
|
||||
# A PL/SQL block that returns two cursors
|
||||
await 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))
|
||||
async for row in result_set:
|
||||
print(row)
|
||||
print()
|
||||
|
||||
|
||||
asyncio.run(main())
|
|
@ -1,5 +1,5 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2016, 2023, Oracle and/or its affiliates.
|
||||
#------------------------------------------------------------------------------
|
||||
# Copyright (c) 2016, 2022, Oracle and/or its affiliates.
|
||||
#
|
||||
# Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
|
||||
#
|
||||
|
@ -25,14 +25,14 @@
|
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
# insert_geometry.py
|
||||
#
|
||||
# Demonstrates the ability to create Oracle objects (this example uses
|
||||
# SDO_GEOMETRY) and insert them into a table.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
import oracledb
|
||||
import sample_env
|
||||
|
@ -41,11 +41,9 @@ import sample_env
|
|||
if not sample_env.get_is_thin():
|
||||
oracledb.init_oracle_client(lib_dir=sample_env.get_oracle_client())
|
||||
|
||||
connection = oracledb.connect(
|
||||
user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string(),
|
||||
)
|
||||
connection = oracledb.connect(user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string())
|
||||
|
||||
# create and populate Oracle objects
|
||||
type_obj = connection.gettype("MDSYS.SDO_GEOMETRY")
|
||||
|
@ -60,7 +58,25 @@ obj.SDO_ORDINATES.extend([1, 1, 5, 7])
|
|||
print("Created object", obj)
|
||||
|
||||
with connection.cursor() as cursor:
|
||||
cursor.execute("truncate table TestGeometry")
|
||||
|
||||
# create sample table
|
||||
cursor.execute("""
|
||||
begin
|
||||
begin
|
||||
execute immediate 'drop table TestGeometry';
|
||||
exception
|
||||
when others then
|
||||
if sqlcode <> -942 then
|
||||
raise;
|
||||
end if;
|
||||
end;
|
||||
|
||||
execute immediate 'create table TestGeometry (
|
||||
IntCol number(9) not null,
|
||||
Geometry MDSYS.SDO_GEOMETRY)';
|
||||
end;""")
|
||||
|
||||
|
||||
print("Adding row to table...")
|
||||
cursor.execute("insert into TestGeometry values (1, :objbv)", objbv=obj)
|
||||
connection.commit()
|
||||
|
|
|
@ -1,71 +0,0 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2023, Oracle and/or its affiliates.
|
||||
#
|
||||
# This software is dual-licensed to you under the Universal Permissive License
|
||||
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
||||
# 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
|
||||
# either license.
|
||||
#
|
||||
# If you elect to accept the software under the Apache License, Version 2.0,
|
||||
# the following applies:
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# insert_geometry_async.py
|
||||
#
|
||||
# An asynchronous version of insert_geometry.py
|
||||
#
|
||||
# Demonstrates the ability to create Oracle objects (this example uses
|
||||
# SDO_GEOMETRY) and insert them into a table.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
import asyncio
|
||||
|
||||
import oracledb
|
||||
import sample_env
|
||||
|
||||
|
||||
async def main():
|
||||
connection = await oracledb.connect_async(
|
||||
user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string(),
|
||||
)
|
||||
|
||||
# create and populate Oracle objects
|
||||
type_obj = await connection.gettype("MDSYS.SDO_GEOMETRY")
|
||||
element_info_type_obj = await connection.gettype(
|
||||
"MDSYS.SDO_ELEM_INFO_ARRAY"
|
||||
)
|
||||
ordinate_type_obj = await 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)
|
||||
|
||||
with connection.cursor() as cursor:
|
||||
await cursor.execute("truncate table TestGeometry")
|
||||
print("Adding row to table...")
|
||||
await cursor.execute(
|
||||
"insert into TestGeometry values (1, :objbv)", objbv=obj
|
||||
)
|
||||
await connection.commit()
|
||||
print("Success!")
|
||||
|
||||
|
||||
asyncio.run(main())
|
|
@ -1,5 +1,5 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2020, 2023, Oracle and/or its affiliates.
|
||||
#------------------------------------------------------------------------------
|
||||
# Copyright (c) 2020, 2022, Oracle and/or its affiliates.
|
||||
#
|
||||
# This software is dual-licensed to you under the Universal Permissive License
|
||||
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
||||
|
@ -20,9 +20,9 @@
|
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
# json_blob.py
|
||||
#
|
||||
# Demonstrates how to use a BLOB as a JSON column store.
|
||||
|
@ -34,7 +34,7 @@
|
|||
# Documentation:
|
||||
# python-oracledb: https://oracledb.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
|
||||
|
@ -46,11 +46,9 @@ import sample_env
|
|||
if not sample_env.get_is_thin():
|
||||
oracledb.init_oracle_client(lib_dir=sample_env.get_oracle_client())
|
||||
|
||||
connection = oracledb.connect(
|
||||
user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string(),
|
||||
)
|
||||
connection = oracledb.connect(user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string())
|
||||
|
||||
if not connection.thin:
|
||||
client_version = oracledb.clientversion()[0]
|
||||
|
@ -62,10 +60,11 @@ if db_version < 12:
|
|||
|
||||
# Insert JSON data
|
||||
with connection.cursor() as cursor:
|
||||
|
||||
data = dict(name="Rod", dept="Sales", location="Germany")
|
||||
inssql = "insert into CustomersAsBlob values (:1, :2)"
|
||||
|
||||
if (connection.thin or client_version >= 21) and db_version >= 21:
|
||||
if not connection.thin and client_version >= 21 and db_version >= 21:
|
||||
# Take advantage of direct binding
|
||||
cursor.setinputsizes(None, oracledb.DB_TYPE_JSON)
|
||||
cursor.execute(inssql, [1, data])
|
||||
|
@ -75,40 +74,30 @@ with connection.cursor() as cursor:
|
|||
|
||||
# Select JSON data
|
||||
with connection.cursor() as cursor:
|
||||
sql = "select c.json_data from CustomersAsBlob c"
|
||||
for (j,) in cursor.execute(sql):
|
||||
print(j)
|
||||
|
||||
sql = "SELECT c.json_data FROM CustomersAsBlob 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 CustomersAsBlob
|
||||
offset 0 rows fetch next 1 rows only"""
|
||||
sql = """SELECT JSON_VALUE(json_data, '$.location')
|
||||
FROM CustomersAsBlob
|
||||
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 CustomersAsBlob c
|
||||
offset 0 rows fetch next 1 rows only"""
|
||||
for (j,) in cursor.execute(sql):
|
||||
sql = """SELECT c.json_data.location
|
||||
FROM CustomersAsBlob 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)
|
||||
|
||||
# Using JSON_ARRAYAGG to extract a whole relational table as JSON
|
||||
|
||||
oracledb.defaults.fetch_lobs = False
|
||||
sql = """select json_arrayagg(
|
||||
json_object('key' is c.id,
|
||||
'name' is c.json_data)
|
||||
returning clob)
|
||||
from CustomersAsBlob c"""
|
||||
sql = """SELECT JSON_OBJECT('key' IS d.dummy) dummy
|
||||
FROM dual d"""
|
||||
for r in cursor.execute(sql):
|
||||
print(r)
|
||||
|
|
|
@ -1,121 +0,0 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2023, Oracle and/or its affiliates.
|
||||
#
|
||||
# This software is dual-licensed to you under the Universal Permissive License
|
||||
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
||||
# 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
|
||||
# either license.
|
||||
#
|
||||
# If you elect to accept the software under the Apache License, Version 2.0,
|
||||
# the following applies:
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# json_blob_async.py
|
||||
#
|
||||
# An asynchronous version of json_blob.py
|
||||
#
|
||||
# Demonstrates how to use a BLOB as a JSON column store.
|
||||
#
|
||||
# Note: Oracle Database 12c lets JSON be stored in VARCHAR2 or LOB columns.
|
||||
# With Oracle Database 21c using the new JSON type is recommended
|
||||
# instead, see json_direct_async.py
|
||||
#
|
||||
# Documentation:
|
||||
# python-oracledb: https://oracledb.readthedocs.io/en/latest/user_guide/json_data_type.html
|
||||
# Oracle Database: https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=ADJSN
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import sys
|
||||
|
||||
import oracledb
|
||||
import sample_env
|
||||
|
||||
|
||||
async def main():
|
||||
connection = await oracledb.connect_async(
|
||||
user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string(),
|
||||
)
|
||||
|
||||
# Minimum database vesion is 12
|
||||
db_version = int(connection.version.split(".")[0])
|
||||
if db_version < 12:
|
||||
sys.exit("This example requires Oracle Database 12.1.0.2 or later")
|
||||
|
||||
# Insert JSON data
|
||||
with connection.cursor() as cursor:
|
||||
data = dict(name="Rod", dept="Sales", location="Germany")
|
||||
inssql = "insert into CustomersAsBlob values (:1, :2)"
|
||||
|
||||
if db_version >= 21:
|
||||
# Take advantage of direct binding
|
||||
cursor.setinputsizes(None, oracledb.DB_TYPE_JSON)
|
||||
await cursor.execute(inssql, [1, data])
|
||||
else:
|
||||
# Insert the data as a JSON string
|
||||
await cursor.execute(inssql, [1, json.dumps(data)])
|
||||
|
||||
# Select JSON data
|
||||
with connection.cursor() as cursor:
|
||||
sql = "select c.json_data from CustomersAsBlob c"
|
||||
await cursor.execute(sql)
|
||||
async for (j,) in cursor:
|
||||
print(j)
|
||||
|
||||
# Using JSON_VALUE to extract a value from a JSON column
|
||||
|
||||
sql = """select json_value(json_data, '$.location')
|
||||
from CustomersAsBlob
|
||||
offset 0 rows fetch next 1 rows only"""
|
||||
await cursor.execute(sql)
|
||||
async for (r,) in cursor:
|
||||
print(r)
|
||||
|
||||
# Using dot-notation to extract a value from a JSON (BLOB storage)
|
||||
# column
|
||||
|
||||
sql = """select c.json_data.location
|
||||
from CustomersAsBlob c
|
||||
offset 0 rows fetch next 1 rows only"""
|
||||
await cursor.execute(sql)
|
||||
async for (j,) in cursor:
|
||||
print(j)
|
||||
|
||||
# Using JSON_OBJECT to extract relational data as JSON
|
||||
|
||||
sql = """select json_object('key' is d.dummy) dummy
|
||||
from dual d"""
|
||||
await cursor.execute(sql)
|
||||
async for r in cursor:
|
||||
print(r)
|
||||
|
||||
# Using JSON_ARRAYAGG to extract a whole relational table as JSON
|
||||
|
||||
oracledb.defaults.fetch_lobs = False
|
||||
sql = """select json_arrayagg(
|
||||
json_object('key' is c.id,
|
||||
'name' is c.json_data)
|
||||
returning clob)
|
||||
from CustomersAsBlob c"""
|
||||
await cursor.execute(sql)
|
||||
async for r in cursor:
|
||||
print(r)
|
||||
|
||||
|
||||
asyncio.run(main())
|
|
@ -1,5 +1,5 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2020, 2023, Oracle and/or its affiliates.
|
||||
#------------------------------------------------------------------------------
|
||||
# Copyright (c) 2020, 2022, Oracle and/or its affiliates.
|
||||
#
|
||||
# This software is dual-licensed to you under the Universal Permissive License
|
||||
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
||||
|
@ -20,9 +20,9 @@
|
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
# json_direct.py
|
||||
#
|
||||
# Demonstrates the use of some JSON features with the JSON type that is
|
||||
|
@ -31,7 +31,9 @@
|
|||
# See https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=ADJSN
|
||||
#
|
||||
# For JSON with older databases see json_blob.py
|
||||
# -----------------------------------------------------------------------------
|
||||
#
|
||||
# Note: To use the JSON type in python-oracledb thin mode see json_type.py
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
import json
|
||||
import sys
|
||||
|
@ -39,32 +41,27 @@ import sys
|
|||
import oracledb
|
||||
import sample_env
|
||||
|
||||
# determine whether to use python-oracledb thin mode or thick mode
|
||||
if not sample_env.get_is_thin():
|
||||
oracledb.init_oracle_client(lib_dir=sample_env.get_oracle_client())
|
||||
# this script is currently only supported in python-oracledb thick mode
|
||||
oracledb.init_oracle_client(lib_dir=sample_env.get_oracle_client())
|
||||
|
||||
connection = oracledb.connect(
|
||||
user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string(),
|
||||
)
|
||||
connection = oracledb.connect(user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string())
|
||||
|
||||
if not connection.thin:
|
||||
client_version = oracledb.clientversion()[0]
|
||||
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 instead"
|
||||
)
|
||||
sys.exit("This example requires Oracle Database 21.1 or later. "
|
||||
"Try json_blob.py")
|
||||
|
||||
# Insert JSON data
|
||||
with connection.cursor() as cursor:
|
||||
|
||||
data = dict(name="Rod", dept="Sales", location="Germany")
|
||||
inssql = "insert into CustomersAsJson values (:1, :2)"
|
||||
if connection.thin or client_version >= 21:
|
||||
if client_version >= 21:
|
||||
# Take advantage of direct binding
|
||||
cursor.setinputsizes(None, oracledb.DB_TYPE_JSON)
|
||||
cursor.execute(inssql, [1, data])
|
||||
|
@ -74,12 +71,13 @@ with connection.cursor() as cursor:
|
|||
|
||||
# Select JSON data
|
||||
with connection.cursor() as cursor:
|
||||
|
||||
sql = "select c.json_data from CustomersAsJson c"
|
||||
if connection.thin or client_version >= 21:
|
||||
for (j,) in cursor.execute(sql):
|
||||
if client_version >= 21:
|
||||
for j, in cursor.execute(sql):
|
||||
print(j)
|
||||
else:
|
||||
for (j,) in cursor.execute(sql):
|
||||
for j, in cursor.execute(sql):
|
||||
print(json.loads(j.read()))
|
||||
|
||||
# Using JSON_VALUE to extract a value from a JSON column
|
||||
|
@ -95,11 +93,11 @@ with connection.cursor() as cursor:
|
|||
sql = """select c.json_data.location
|
||||
from CustomersAsJson c
|
||||
offset 0 rows fetch next 1 rows only"""
|
||||
if connection.thin or client_version >= 21:
|
||||
for (j,) in cursor.execute(sql):
|
||||
if client_version >= 21:
|
||||
for j, in cursor.execute(sql):
|
||||
print(j)
|
||||
else:
|
||||
for (j,) in cursor.execute(sql):
|
||||
for j, in cursor.execute(sql):
|
||||
print(json.loads(j.read()))
|
||||
|
||||
# Using JSON_OBJECT to extract relational data as JSON
|
||||
|
@ -108,14 +106,3 @@ with connection.cursor() as cursor:
|
|||
from dual d"""
|
||||
for r in cursor.execute(sql):
|
||||
print(r)
|
||||
|
||||
# Using JSON_ARRAYAGG to extract a whole relational table as JSON
|
||||
|
||||
oracledb.defaults.fetch_lobs = False
|
||||
sql = """select json_arrayagg(
|
||||
json_object('key' is c.id,
|
||||
'name' is c.json_data)
|
||||
returning clob)
|
||||
from CustomersAsJson c"""
|
||||
for r in cursor.execute(sql):
|
||||
print(r)
|
||||
|
|
|
@ -1,113 +0,0 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2023, Oracle and/or its affiliates.
|
||||
#
|
||||
# This software is dual-licensed to you under the Universal Permissive License
|
||||
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
||||
# 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
|
||||
# either license.
|
||||
#
|
||||
# If you elect to accept the software under the Apache License, Version 2.0,
|
||||
# the following applies:
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# json_direct_async.py
|
||||
#
|
||||
# An asynchronous version of json_direct.py
|
||||
#
|
||||
# Demonstrates the use of some JSON features with the JSON type that is
|
||||
# available in Oracle Database 21c and higher.
|
||||
#
|
||||
# See https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=ADJSN
|
||||
#
|
||||
# For JSON with older databases see json_blob_async.py
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
import asyncio
|
||||
import sys
|
||||
|
||||
import oracledb
|
||||
import sample_env
|
||||
|
||||
|
||||
async def main():
|
||||
connection = await oracledb.connect_async(
|
||||
user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string(),
|
||||
)
|
||||
|
||||
# this script only works with Oracle Database 21
|
||||
db_version = int(connection.version.split(".")[0])
|
||||
if db_version < 21:
|
||||
sys.exit(
|
||||
"This example requires Oracle Database 21.1 or later. "
|
||||
"Try json_blob.py instead"
|
||||
)
|
||||
|
||||
# Insert JSON data
|
||||
with connection.cursor() as cursor:
|
||||
data = dict(name="Rod", dept="Sales", location="Germany")
|
||||
inssql = "insert into CustomersAsJson values (:1, :2)"
|
||||
cursor.setinputsizes(None, oracledb.DB_TYPE_JSON)
|
||||
await cursor.execute(inssql, [1, data])
|
||||
|
||||
# Select JSON data
|
||||
with connection.cursor() as cursor:
|
||||
sql = "select c.json_data from CustomersAsJson c"
|
||||
await cursor.execute(sql)
|
||||
async for (j,) in cursor:
|
||||
print(j)
|
||||
|
||||
# Using JSON_VALUE to extract a value from a JSON column
|
||||
|
||||
sql = """select json_value(json_data, '$.location')
|
||||
from CustomersAsJson
|
||||
offset 0 rows fetch next 1 rows only"""
|
||||
await cursor.execute(sql)
|
||||
async for r in cursor:
|
||||
print(r)
|
||||
|
||||
# Using dot-notation to extract a value from a JSON column
|
||||
|
||||
sql = """select c.json_data.location
|
||||
from CustomersAsJson c
|
||||
offset 0 rows fetch next 1 rows only"""
|
||||
await cursor.execute(sql)
|
||||
async for (j,) in cursor:
|
||||
print(j)
|
||||
|
||||
# Using JSON_OBJECT to extract relational data as JSON
|
||||
|
||||
sql = """select json_object('key' is d.dummy) dummy
|
||||
from dual d"""
|
||||
await cursor.execute(sql)
|
||||
async for r in cursor:
|
||||
print(r)
|
||||
|
||||
# Using JSON_ARRAYAGG to extract a whole relational table as JSON
|
||||
|
||||
oracledb.defaults.fetch_lobs = False
|
||||
sql = """select json_arrayagg(
|
||||
json_object('key' is c.id,
|
||||
'name' is c.json_data)
|
||||
returning clob)
|
||||
from CustomersAsJson c"""
|
||||
await cursor.execute(sql)
|
||||
async for r in cursor:
|
||||
print(r)
|
||||
|
||||
|
||||
asyncio.run(main())
|
|
@ -0,0 +1,97 @@
|
|||
#------------------------------------------------------------------------------
|
||||
# Copyright (c) 2022, Oracle and/or its affiliates.
|
||||
#
|
||||
# This software is dual-licensed to you under the Universal Permissive License
|
||||
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
||||
# 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
|
||||
# either license.
|
||||
#
|
||||
# If you elect to accept the software under the Apache License, Version 2.0,
|
||||
# the following applies:
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# json_type.py
|
||||
#
|
||||
# Demonstrates storing and fetching the JSON data into/from a Oracle Database
|
||||
# 21c JSON type column.
|
||||
#
|
||||
# In order to use the JSON type in python-oracledb thin mode a type handler is
|
||||
# needed to fetch the 21c JSON datatype.
|
||||
#
|
||||
# Note: The type handler is not needed when using python-oracledb thick mode
|
||||
# and Oracle Client 21.1 or higher. However, if a type handler is used
|
||||
# the behavior is the same in python-oracledb thin and thick modes.
|
||||
#
|
||||
# This script requires Oracle Database 21.1 or higher.
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
import json
|
||||
import sys
|
||||
|
||||
import oracledb
|
||||
import sample_env
|
||||
|
||||
# determine whether to use python-oracledb thin mode or thick mode
|
||||
if not sample_env.get_is_thin():
|
||||
oracledb.init_oracle_client(lib_dir=sample_env.get_oracle_client())
|
||||
|
||||
connection = oracledb.connect(user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string())
|
||||
|
||||
if not connection.thin:
|
||||
client_version = oracledb.clientversion()[0]
|
||||
db_version = int(connection.version.split(".")[0])
|
||||
|
||||
# Minimum database vesion is 21
|
||||
if db_version < 21:
|
||||
sys.exit("This example requires Oracle Database 21.1 or later.")
|
||||
|
||||
def type_handler(cursor, name, default_type, size, precision, scale):
|
||||
# to fetch the 21c JSON datatype when using python-oracledb thin mode
|
||||
if default_type == oracledb.DB_TYPE_JSON:
|
||||
return cursor.var(str, arraysize=cursor.arraysize,
|
||||
outconverter=json.loads)
|
||||
# if using Oracle Client version < 21, then the database returns the
|
||||
# BLOB data type instead of the JSON data type
|
||||
elif default_type == oracledb.DB_TYPE_BLOB:
|
||||
return cursor.var(default_type, arraysize=cursor.arraysize,
|
||||
outconverter=lambda v: json.loads(v.read()))
|
||||
|
||||
# Insert JSON data into a JSON column
|
||||
with connection.cursor() as cursor:
|
||||
data = [
|
||||
(1, dict(name="Rod", dept="Sales", location="Germany")),
|
||||
(2, dict(name="George", dept="Marketing", location="Bangalore")),
|
||||
(3, dict(name="Sam", dept="Sales", location="Mumbai")),
|
||||
(4, dict(name="Jill", dept="Marketing", location="Germany"))
|
||||
]
|
||||
insert_sql = "insert into CustomersAsJson values (:1, :2)"
|
||||
if not connection.thin and client_version >= 21:
|
||||
# Take advantage of direct binding
|
||||
cursor.setinputsizes(None, oracledb.DB_TYPE_JSON)
|
||||
cursor.executemany(insert_sql, data)
|
||||
else:
|
||||
# Insert the data as a JSON string
|
||||
cursor.executemany(insert_sql, [(i, json.dumps(j)) for i, j in data])
|
||||
|
||||
# Select JSON data from a JSON column
|
||||
with connection.cursor() as cursor:
|
||||
if connection.thin or client_version < 21:
|
||||
cursor.outputtypehandler = type_handler
|
||||
|
||||
for row in cursor.execute("select * from CustomersAsJson"):
|
||||
print(row)
|
|
@ -1,5 +1,5 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2019, 2023, Oracle and/or its affiliates.
|
||||
#------------------------------------------------------------------------------
|
||||
# Copyright (c) 2019, 2022, Oracle and/or its affiliates.
|
||||
#
|
||||
# This software is dual-licensed to you under the Universal Permissive License
|
||||
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
||||
|
@ -20,13 +20,13 @@
|
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
# last_rowid.py
|
||||
#
|
||||
# Demonstrates the use of the cursor.lastrowid attribute.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
import oracledb
|
||||
import sample_env
|
||||
|
@ -35,13 +35,12 @@ import sample_env
|
|||
if not sample_env.get_is_thin():
|
||||
oracledb.init_oracle_client(lib_dir=sample_env.get_oracle_client())
|
||||
|
||||
connection = oracledb.connect(
|
||||
user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string(),
|
||||
)
|
||||
connection = oracledb.connect(user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string())
|
||||
|
||||
with connection.cursor() as cursor:
|
||||
|
||||
# insert a couple of rows and retain the rowid of each
|
||||
row1 = [1, "First"]
|
||||
row2 = [2, "Second"]
|
||||
|
@ -67,9 +66,8 @@ with connection.cursor() as cursor:
|
|||
|
||||
# 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]
|
||||
)
|
||||
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
|
||||
|
@ -81,4 +79,4 @@ with connection.cursor() as cursor:
|
|||
print("Rowid when no rows are deleted:", cursor.lastrowid)
|
||||
|
||||
# Don't commit - this lets us run the demo multiple times
|
||||
# connection.commit()
|
||||
#connection.commit()
|
||||
|
|
|
@ -1,97 +0,0 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2023, Oracle and/or its affiliates.
|
||||
#
|
||||
# This software is dual-licensed to you under the Universal Permissive License
|
||||
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
||||
# 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
|
||||
# either license.
|
||||
#
|
||||
# If you elect to accept the software under the Apache License, Version 2.0,
|
||||
# the following applies:
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# last_rowid_async.py
|
||||
#
|
||||
# An asynchronous version of last_rowid.py
|
||||
#
|
||||
# Demonstrates the use of the cursor.lastrowid attribute.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
import asyncio
|
||||
|
||||
import oracledb
|
||||
import sample_env
|
||||
|
||||
|
||||
async def main():
|
||||
connection = await oracledb.connect_async(
|
||||
user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string(),
|
||||
)
|
||||
|
||||
with connection.cursor() as cursor:
|
||||
# insert a couple of rows and retain the rowid of each
|
||||
row1 = [1, "First"]
|
||||
row2 = [2, "Second"]
|
||||
|
||||
await cursor.execute(
|
||||
"insert into mytab (id, data) values (:1, :2)", row1
|
||||
)
|
||||
rowid1 = cursor.lastrowid
|
||||
print("Row 1:", row1)
|
||||
print("Rowid 1:", rowid1)
|
||||
print()
|
||||
|
||||
await 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 returned
|
||||
await cursor.execute(
|
||||
"select id, data from mytab where rowid = :1", [rowid1]
|
||||
)
|
||||
print("Row 1:", await cursor.fetchone())
|
||||
await cursor.execute(
|
||||
"select id, data from mytab where rowid = :1", [rowid2]
|
||||
)
|
||||
print("Row 2:", await cursor.fetchone())
|
||||
print()
|
||||
|
||||
# updating multiple rows only returns the rowid of the last updated row
|
||||
await cursor.execute("update mytab set data = data || ' (Modified)'")
|
||||
await cursor.execute(
|
||||
"select id, data from mytab where rowid = :1", [cursor.lastrowid]
|
||||
)
|
||||
print("Last updated row:", await cursor.fetchone())
|
||||
|
||||
# deleting multiple rows only returns the rowid of the last deleted row
|
||||
await cursor.execute("delete from mytab")
|
||||
print("Rowid of last deleted row:", cursor.lastrowid)
|
||||
|
||||
# deleting no rows results in a value of None
|
||||
await 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
|
||||
# await connection.commit()
|
||||
|
||||
|
||||
asyncio.run(main())
|
|
@ -1,5 +1,5 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2022, 2023, Oracle and/or its affiliates.
|
||||
#------------------------------------------------------------------------------
|
||||
# Copyright (c) 2022, Oracle and/or its affiliates.
|
||||
#
|
||||
# This software is dual-licensed to you under the Universal Permissive License
|
||||
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
||||
|
@ -20,13 +20,13 @@
|
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
# load_csv.py
|
||||
#
|
||||
# A sample showing how to load CSV data.
|
||||
# -----------------------------------------------------------------------------
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
import csv
|
||||
import os
|
||||
|
@ -40,7 +40,7 @@ if not sample_env.get_is_thin():
|
|||
|
||||
# CSV file. This sample file has both valid rows and some rows with data too
|
||||
# large to insert.
|
||||
FILE_NAME = os.path.join("data", "load_csv.csv")
|
||||
FILE_NAME = os.path.join('data', 'load_csv.csv')
|
||||
|
||||
# Adjust the number of rows to be inserted in each iteration to meet your
|
||||
# memory and performance requirements. Typically this is a large-ish value to
|
||||
|
@ -49,12 +49,9 @@ FILE_NAME = os.path.join("data", "load_csv.csv")
|
|||
# behavior of the code.
|
||||
BATCH_SIZE = 19
|
||||
|
||||
connection = oracledb.connect(
|
||||
user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string(),
|
||||
)
|
||||
|
||||
connection = oracledb.connect(user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string())
|
||||
|
||||
def process_batch(batch_number, cursor, data):
|
||||
print("processing batch", batch_number + 1)
|
||||
|
@ -63,10 +60,10 @@ def process_batch(batch_number, cursor, data):
|
|||
line_num = (batch_number * BATCH_SIZE) + error.offset + 1
|
||||
print("Error", error.message, "at line", line_num)
|
||||
|
||||
|
||||
with connection.cursor() as cursor:
|
||||
|
||||
# Clean up the table for demonstration purposes
|
||||
cursor.execute("truncate table LoadCsvTab")
|
||||
cursor.execute('truncate table LoadCsvTab');
|
||||
|
||||
# Predefine the memory areas to match the table definition.
|
||||
# This can improve performance by avoiding memory reallocations.
|
||||
|
@ -77,8 +74,8 @@ with connection.cursor() as cursor:
|
|||
cursor.setinputsizes(None, 25)
|
||||
|
||||
# Loop over the data and insert it in batches
|
||||
with open(FILE_NAME, "r") as csv_file:
|
||||
csv_reader = csv.reader(csv_file, delimiter=",")
|
||||
with open(FILE_NAME, 'r') as csv_file:
|
||||
csv_reader = csv.reader(csv_file, delimiter=',')
|
||||
sql = "insert into LoadCsvTab (id, name) values (:1, :2)"
|
||||
data = []
|
||||
batch_number = 0
|
||||
|
|
|
@ -1,100 +0,0 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2023, Oracle and/or its affiliates.
|
||||
#
|
||||
# This software is dual-licensed to you under the Universal Permissive License
|
||||
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
||||
# 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
|
||||
# either license.
|
||||
#
|
||||
# If you elect to accept the software under the Apache License, Version 2.0,
|
||||
# the following applies:
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# load_csv_async.py
|
||||
#
|
||||
# An asynchronous version of load_csv.py
|
||||
#
|
||||
# A sample showing how to load CSV data.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
import asyncio
|
||||
import csv
|
||||
import os
|
||||
|
||||
import oracledb
|
||||
import sample_env
|
||||
|
||||
# CSV file. This sample file has both valid rows and some rows with data too
|
||||
# large to insert.
|
||||
FILE_NAME = os.path.join("data", "load_csv.csv")
|
||||
|
||||
# Adjust the number of rows to be inserted in each iteration to meet your
|
||||
# memory and performance requirements. Typically this is a large-ish value to
|
||||
# reduce the number of calls to executemany() to a reasonable size. For this
|
||||
# demo with a small CSV file a smaller number is used to show the looping
|
||||
# behavior of the code.
|
||||
BATCH_SIZE = 19
|
||||
|
||||
|
||||
async def main():
|
||||
connection = await oracledb.connect_async(
|
||||
user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string(),
|
||||
)
|
||||
|
||||
async def process_batch(batch_number, cursor, data):
|
||||
print("processing batch", batch_number + 1)
|
||||
await cursor.executemany(sql, data, batcherrors=True)
|
||||
for error in cursor.getbatcherrors():
|
||||
line_num = (batch_number * BATCH_SIZE) + error.offset + 1
|
||||
print("Error", error.message, "at line", line_num)
|
||||
|
||||
with connection.cursor() as cursor:
|
||||
# Clean up the table for demonstration purposes
|
||||
await cursor.execute("truncate table LoadCsvTab")
|
||||
|
||||
# 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)
|
||||
|
||||
# Loop over the data and insert it in batches
|
||||
with open(FILE_NAME, "r") as csv_file:
|
||||
csv_reader = csv.reader(csv_file, delimiter=",")
|
||||
sql = "insert into LoadCsvTab (id, name) values (:1, :2)"
|
||||
data = []
|
||||
batch_number = 0
|
||||
for line in csv_reader:
|
||||
data.append((line[0], line[1]))
|
||||
if len(data) % BATCH_SIZE == 0:
|
||||
await process_batch(batch_number, cursor, data)
|
||||
data = []
|
||||
batch_number += 1
|
||||
if data:
|
||||
await process_batch(batch_number, cursor, data)
|
||||
|
||||
# In a production system you might choose to fix any invalid rows,
|
||||
# re-insert them, and then commit. Or you could rollback
|
||||
# everything. In this sample we simply commit and ignore the
|
||||
# invalid rows that couldn't be inserted.
|
||||
await connection.commit()
|
||||
|
||||
|
||||
asyncio.run(main())
|
|
@ -1,5 +1,5 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2020, 2023, Oracle and/or its affiliates.
|
||||
#------------------------------------------------------------------------------
|
||||
# Copyright (c) 2020, 2022, Oracle and/or its affiliates.
|
||||
#
|
||||
# Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
|
||||
#
|
||||
|
@ -25,14 +25,14 @@
|
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
# multi_consumer_aq.py
|
||||
#
|
||||
# Demonstrates how to use multi-consumer advanced queuing. It makes use of a
|
||||
# RAW queue created in the sample setup.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
import oracledb
|
||||
import sample_env
|
||||
|
@ -45,15 +45,13 @@ PAYLOAD_DATA = [
|
|||
"The first message",
|
||||
"The second message",
|
||||
"The third message",
|
||||
"The fourth and final message",
|
||||
"The fourth and final message"
|
||||
]
|
||||
|
||||
# connect to database
|
||||
connection = oracledb.connect(
|
||||
user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string(),
|
||||
)
|
||||
connection = oracledb.connect(user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string())
|
||||
|
||||
# create a queue
|
||||
queue = connection.queue(QUEUE_NAME)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2016, 2023, Oracle and/or its affiliates.
|
||||
#------------------------------------------------------------------------------
|
||||
# Copyright (c) 2016, 2022, Oracle and/or its affiliates.
|
||||
#
|
||||
# Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
|
||||
#
|
||||
|
@ -25,14 +25,14 @@
|
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
# object_aq.py
|
||||
#
|
||||
# Demonstrates how to use advanced queuing with objects. It makes use of a
|
||||
# simple type and queue created in the sample setup.
|
||||
# -----------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
import decimal
|
||||
|
||||
|
@ -45,24 +45,16 @@ oracledb.init_oracle_client(lib_dir=sample_env.get_oracle_client())
|
|||
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"),
|
||||
),
|
||||
("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(
|
||||
user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string(),
|
||||
)
|
||||
connection = oracledb.connect(user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string())
|
||||
|
||||
# create a queue
|
||||
books_type = connection.gettype(BOOK_TYPE_NAME)
|
||||
|
|
|
@ -1,111 +0,0 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2023, Oracle and/or its affiliates.
|
||||
#
|
||||
# This software is dual-licensed to you under the Universal Permissive License
|
||||
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
||||
# 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
|
||||
# either license.
|
||||
#
|
||||
# If you elect to accept the software under the Apache License, Version 2.0,
|
||||
# the following applies:
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# object_dump.py
|
||||
#
|
||||
# Shows how to pretty-print an Oracle object or collection.
|
||||
# Also shows how to insert a Python object to an Oracle object column.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
import oracledb
|
||||
import sample_env
|
||||
|
||||
# determine whether to use python-oracledb thin mode or thick mode
|
||||
if not sample_env.get_is_thin():
|
||||
oracledb.init_oracle_client(lib_dir=sample_env.get_oracle_client())
|
||||
|
||||
# Create Oracle connection and cursor objects
|
||||
connection = oracledb.connect(
|
||||
user=sample_env.get_main_user(),
|
||||
password=sample_env.get_main_password(),
|
||||
dsn=sample_env.get_connect_string(),
|
||||
)
|
||||
cursor = connection.cursor()
|
||||
|
||||
|
||||
# Create a Python class equivalent to an Oracle SDO object
|
||||
class MySDO(object):
|
||||
def __init__(self, gtype, elem_info, ordinates):
|
||||
self.gtype = gtype
|
||||
self.elem_info = elem_info
|
||||
self.ordinates = ordinates
|
||||
|
||||
|
||||
# Get Oracle type information
|
||||
obj_type = 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")
|
||||
|
||||
|
||||
# Convert a Python object to MDSYS.SDO_GEOMETRY
|
||||
def sdo_input_type_handler(cursor, value, num_elements):
|
||||
def sdo_in_converter(value):
|
||||
obj = obj_type.newobject()
|
||||
obj.SDO_GTYPE = value.gtype
|
||||
obj.SDO_ELEM_INFO = element_info_type_obj.newobject()
|
||||
obj.SDO_ELEM_INFO.extend(value.elem_info)
|
||||
obj.SDO_ORDINATES = ordinate_type_obj.newobject()
|
||||
obj.SDO_ORDINATES.extend(value.ordinates)
|
||||
return obj
|
||||
|
||||
if isinstance(value, MySDO):
|
||||
return cursor.var(
|
||||
obj_type, arraysize=num_elements, inconverter=sdo_in_converter
|
||||
)
|
||||
|
||||
|
||||
# Create and insert a Python object
|
||||
sdo = MySDO(2003, [1, 1003, 3], [1, 1, 5, 7])
|
||||
cursor.inputtypehandler = sdo_input_type_handler
|
||||
cursor.execute("truncate table TestGeometry")
|
||||
cursor.execute("insert into TestGeometry values (1, :1)", [sdo])
|
||||
|
||||
|
||||
# Define a function to pretty-print the contents of an Oracle object
|
||||
def dump_object(obj, prefix=""):
|
||||
if obj.type.iscollection:
|
||||
print(f"{prefix}[")
|
||||
for value in obj.aslist():
|
||||
if isinstance(value, oracledb.DbObject):
|
||||
dump_object(value, prefix + " ")
|
||||
else:
|
||||
print(f"{prefix} {repr(value)}")
|
||||
print(f"{prefix}]")
|
||||
else:
|
||||
print(f"{prefix}{{")
|
||||
for attr in obj.type.attributes:
|
||||
value = getattr(obj, attr.name)
|
||||
if isinstance(value, oracledb.DbObject):
|
||||
print(f"{prefix} {attr.name}:")
|
||||
dump_object(value, prefix + " ")
|
||||
else:
|
||||
print(f"{prefix} {attr.name}: {repr(value)}")
|
||||
print(f"{prefix}}}")
|
||||
|
||||
|
||||
# Query the row back
|
||||
cursor.execute("select geometry from TestGeometry")
|
||||
for (obj,) in cursor:
|
||||
dump_object(obj)
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue