Samples and documentation improvements.
|
@ -6,3 +6,4 @@ build/
|
|||
dist/
|
||||
doc/build
|
||||
src/oracledb/*.c
|
||||
.ipynb_checkpoints/
|
||||
|
|
|
@ -8,6 +8,8 @@ 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`
|
||||
|
@ -95,3 +97,4 @@ 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
|
||||
|
|
|
@ -0,0 +1,334 @@
|
|||
.. _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.
|
|
@ -0,0 +1,213 @@
|
|||
.. _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`.
|
|
@ -0,0 +1,488 @@
|
|||
.. _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()`.
|
|
@ -0,0 +1,102 @@
|
|||
.. _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>`.
|
|
@ -24,7 +24,6 @@ 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
|
||||
|
@ -34,7 +33,6 @@ 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
|
||||
|
@ -62,7 +60,6 @@ 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
|
||||
|
@ -126,7 +123,6 @@ 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
|
||||
|
@ -137,7 +133,6 @@ 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.
|
||||
|
@ -176,7 +171,6 @@ 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
|
||||
|
@ -191,7 +185,6 @@ 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
|
||||
|
@ -213,12 +206,10 @@ 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
|
||||
|
@ -556,7 +547,6 @@ Connection Attributes
|
|||
|
||||
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.
|
||||
|
@ -596,7 +586,6 @@ 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
|
||||
|
@ -646,7 +635,7 @@ Connection Attributes
|
|||
|
||||
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::
|
||||
|
||||
|
@ -688,9 +677,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.
|
||||
|
||||
|
@ -698,7 +687,6 @@ 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
|
||||
|
@ -712,7 +700,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
|
||||
|
@ -760,7 +747,6 @@ Connection Attributes
|
|||
|
||||
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.
|
||||
|
|
|
@ -77,7 +77,6 @@ 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
|
||||
|
@ -86,13 +85,11 @@ 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])
|
||||
|
@ -145,7 +142,6 @@ 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__
|
||||
|
@ -168,7 +164,6 @@ ConnectionPool Methods
|
|||
parameter are not None, the connection will be retagged when it is released
|
||||
back to the pool.
|
||||
|
||||
|
||||
ConnectionPool Attributes
|
||||
=========================
|
||||
|
||||
|
@ -177,13 +172,11 @@ 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
|
||||
|
@ -204,19 +197,16 @@ ConnectionPool Attributes
|
|||
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)
|
||||
|
@ -238,25 +228,21 @@ 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
|
||||
|
@ -290,7 +276,6 @@ ConnectionPool Attributes
|
|||
|
||||
See :ref:`Statement Caching <stmtcache>` for more information.
|
||||
|
||||
|
||||
.. attribute:: ConnectionPool.thin
|
||||
|
||||
This attribute returns a boolean which indicates the python-oracledb mode
|
||||
|
@ -313,7 +298,6 @@ ConnectionPool Attributes
|
|||
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,6 +26,14 @@ 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])
|
||||
|
||||
|
@ -49,7 +57,6 @@ 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
|
||||
|
@ -86,7 +93,6 @@ 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
|
||||
|
@ -138,7 +144,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 an statement, it is best to use the
|
||||
For maximum efficiency when reusing a 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
|
||||
|
@ -152,7 +158,6 @@ Cursor Methods
|
|||
|
||||
The DB API definition does not define the return value of this method.
|
||||
|
||||
|
||||
.. method:: Cursor.executemany(statement, parameters, batcherrors=False, \
|
||||
arraydmlrowcounts=False)
|
||||
|
||||
|
@ -190,7 +195,6 @@ 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
|
||||
|
@ -204,7 +208,6 @@ 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.
|
||||
|
@ -231,7 +234,6 @@ Cursor Methods
|
|||
|
||||
See :ref:`fetching` for an example.
|
||||
|
||||
|
||||
.. method:: Cursor.getarraydmlrowcounts()
|
||||
|
||||
Retrieves the DML row counts after a call to :meth:`~Cursor.executemany()`
|
||||
|
@ -242,8 +244,7 @@ Cursor Methods
|
|||
.. note::
|
||||
|
||||
The DB API definition does not define this method and it is only
|
||||
available for Oracle 12.1 and higher.
|
||||
|
||||
available for Oracle 12.1 and later.
|
||||
|
||||
.. method:: Cursor.getbatcherrors()
|
||||
|
||||
|
@ -256,7 +257,6 @@ 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,21 +277,11 @@ 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 (this
|
||||
step is done automatically by Oracle when a statement is executed).
|
||||
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>`).
|
||||
|
||||
.. note::
|
||||
|
||||
|
@ -302,7 +292,6 @@ 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
|
||||
|
@ -324,7 +313,6 @@ 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
|
||||
|
@ -344,8 +332,7 @@ 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
|
||||
|
@ -362,14 +349,12 @@ Cursor Methods
|
|||
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])
|
||||
|
||||
|
@ -504,7 +489,7 @@ Cursor Attributes
|
|||
This attribute is an extension to the DB API definition but it is
|
||||
mentioned in PEP 249 as an optional extension.
|
||||
|
||||
.. data:: Cursor.description
|
||||
.. attribute:: 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
|
||||
|
@ -542,13 +527,12 @@ Cursor Attributes
|
|||
|
||||
This attribute is an extension to the DB API definition.
|
||||
|
||||
.. data:: Cursor.lastrowid
|
||||
.. attribute:: 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
|
||||
|
@ -598,7 +582,6 @@ 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
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
API: LOB Objects
|
||||
****************
|
||||
|
||||
See :ref:`lobdata` for more information about using LOBs.
|
||||
A LOB object can be created with :meth:`Connection.createlob()`. See
|
||||
:ref:`lobdata` for more information about using LOBs.
|
||||
|
||||
.. note::
|
||||
|
||||
|
@ -20,31 +21,26 @@ 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
|
||||
|
@ -52,7 +48,6 @@ 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
|
||||
|
@ -62,12 +57,10 @@ 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
|
||||
|
@ -75,12 +68,10 @@ 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
|
||||
|
@ -92,7 +83,7 @@ LOB Methods
|
|||
:meth:`~LOB.trim()` function.
|
||||
|
||||
LOB Attributes
|
||||
===============
|
||||
==============
|
||||
|
||||
.. attribute:: LOB.type
|
||||
|
||||
|
|
|
@ -221,17 +221,17 @@ Oracledb Methods
|
|||
|
||||
The ``events`` parameter is expected to be a boolean that specifies whether
|
||||
the events mode should be enabled. This value is only used in the
|
||||
python-oracledb Thick mode. This parameter is needed for continuous
|
||||
query notification and high availability event notifications. The default
|
||||
value is False.
|
||||
python-oracledb Thick mode and is ignored in the Thin mode. This parameter
|
||||
is needed for continuous query notification and high availability event
|
||||
notifications. The default value is False.
|
||||
|
||||
The ``externalauth`` parameter is a boolean that specifies whether external
|
||||
authentication should be used. This value is only used in the
|
||||
python-oracledb Thick mode. 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.
|
||||
python-oracledb Thick mode and is ignored in the Thin mode. 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.
|
||||
|
||||
If the ``mode`` parameter is specified, it must be one of the
|
||||
:ref:`connection authorization modes <connection-authorization-modes>`
|
||||
|
@ -251,17 +251,18 @@ Oracledb Methods
|
|||
|
||||
The ``edition`` parameter is expected to be a string that indicates the
|
||||
edition to use for the connection. This parameter cannot be used
|
||||
simultaneously with the ``cclass`` parameter. This value is used in the
|
||||
python-oracledb Thick mode.
|
||||
simultaneously with the ``cclass`` parameter. This value is only used in
|
||||
the python-oracledb Thick mode and is ignored in the Thin mode.
|
||||
|
||||
The ``tag`` parameter is expected to be a string that identifies the type
|
||||
of connection that should be returned from a pool. This value is only used
|
||||
in the python-oracledb Thick mode.
|
||||
in the python-oracledb Thick mode and is ignored in the Thin mode.
|
||||
|
||||
The ``matchanytag`` parameter is expected to be a boolean specifying
|
||||
whether any tag can be used when acquiring a connection from the pool. This
|
||||
value is only used in the python-oracledb Thick mode when acquiring a
|
||||
connection from a pool. The default value is False.
|
||||
connection from a pool. This value is ignored in the python-oracledb Thin
|
||||
mode. The default value is False.
|
||||
|
||||
The ``config_dir`` parameter is expected to be a string that indicates the
|
||||
directory in which configuration files (tnsnames.ora) are found. This value
|
||||
|
@ -273,13 +274,13 @@ Oracledb Methods
|
|||
identifies the application context used by the connection. This parameter
|
||||
should contain namespace, name, and value and each entry in the tuple
|
||||
should be a string. This value is only used in the python-oracledb Thick
|
||||
mode.
|
||||
mode and is ignored in the Thin mode.
|
||||
|
||||
The ``shardingkey`` parameter and ``supershardingkey`` parameters, if
|
||||
specified, are expected to be a sequence of values which identifies the
|
||||
database shard to connect to. The key values can be a list of strings,
|
||||
numbers, bytes, or dates. This value is only used in the python-oracledb
|
||||
Thick mode.
|
||||
numbers, bytes, or dates. These values are only used in the
|
||||
python-oracledb Thick mode and are ignored in the Thin mode.
|
||||
|
||||
The ``debug_jdwp`` parameter is expected to be a string with the format
|
||||
`host=<host>;port=<port>` that specifies the host and port of the PL/SQL
|
||||
|
@ -318,13 +319,234 @@ Oracledb Methods
|
|||
and is only of use when embedding Python in an application (like
|
||||
PowerBuilder) which has already made the connection. The connection thus
|
||||
created should *never* be used after the source handle has been closed or
|
||||
destroyed. This value is only used in the python-oracledb Thick mode. It
|
||||
should be used with extreme caution. The default value is 0.
|
||||
destroyed. This value is only used in the python-oracledb Thick mode and
|
||||
is ignored in the Thin mode. It should be used with extreme caution. The
|
||||
default value is 0.
|
||||
|
||||
.. versionchanged:: 2.0.0
|
||||
|
||||
The ``ssl_context`` and ``sdu`` parameters were added.
|
||||
|
||||
.. function:: connect_async(dsn=None, pool=None, conn_class=None, params=None, \
|
||||
user=None, proxy_user=None, password=None, newpassword=None, \
|
||||
wallet_password=None, access_token=None, host=None, port=1521, \
|
||||
protocol="tcp", https_proxy=None, https_proxy_port=0, \
|
||||
service_name=None, sid=None, server_type=None, cclass=None, \
|
||||
purity=oracledb.PURITY_DEFAULT, expire_time=0, retry_count=0, \
|
||||
retry_delay=0, tcp_connect_timeout=60.0, ssl_server_dn_match=True, \
|
||||
ssl_server_cert_dn=None, wallet_location=None, events=False, \
|
||||
externalauth=False, mode=oracledb.AUTH_MODE_DEFAULT, \
|
||||
disable_oob=False, stmtcachesize=oracledb.defaults.stmtcachesize, \
|
||||
edition=None, tag=None, matchanytag=False, \
|
||||
config_dir=oracledb.defaults.config_dir, appcontext=[], \
|
||||
shardingkey=[], supershardingkey=[], debug_jdwp=None, \
|
||||
connection_id_prefix=None, ssl_context=None, sdu=8192, handle=0)
|
||||
|
||||
Constructor for creating a connection to the database. Returns an
|
||||
:ref:`AsyncConnection Object <asyncconnobj>`. All parameters are optional
|
||||
and can be specified as keyword parameters. See
|
||||
:ref:`standaloneconnection` information about connections.
|
||||
|
||||
.. note::
|
||||
|
||||
The asyncio support in python-oracledb 2.0.0 is a pre-release and may
|
||||
change in the next version. This method can only be used in
|
||||
python-oracledb Thin mode.
|
||||
|
||||
.. versionadded:: 2.0.0
|
||||
|
||||
Some values, such as the database host name, can be specified as
|
||||
parameters, as part of the connect string, and in the params object.
|
||||
The precedence is that values in the ``dsn`` parameter override values
|
||||
passed as individual parameters, which themselves override values set in
|
||||
the ``params`` parameter object. Similar precedence rules also apply to
|
||||
other values.
|
||||
|
||||
The ``dsn`` (data source name) parameter can be a string in the format
|
||||
``user/password@connect_string`` or can simply be the connect string (in
|
||||
which case authentication credentials such as the username and password
|
||||
need to be specified separately). See :ref:`connstr` for more information.
|
||||
|
||||
The ``pool`` parameter is expected to be an AsyncConnectionPool object. The
|
||||
use of this parameter is the equivalent of calling
|
||||
:meth:`AsyncConnectionPool.acquire()`.
|
||||
|
||||
The ``conn_class`` parameter is expected to be AsyncConnection or a
|
||||
subclass of AsyncConnection.
|
||||
|
||||
The ``params`` parameter is expected to be of type :ref:`ConnectParams
|
||||
<connparam>` and contains connection parameters that will be used when
|
||||
establishing the connection. If this parameter is not specified, the
|
||||
additional keyword parameters will be used to create an instance of
|
||||
ConnectParams. If both the params parameter and additional keyword
|
||||
parameters are specified, the values in the keyword parameters have
|
||||
precedence. Note that if a ``dsn`` is also supplied, then the values of the
|
||||
parameters specified (if any) within the ``dsn`` will override the values
|
||||
passed as additional keyword parameters, which themselves override the
|
||||
values set in the ``params`` parameter object.
|
||||
|
||||
The ``user`` parameter is expected to be a string which indicates the name
|
||||
of the user to connect to.
|
||||
|
||||
The ``proxy_user`` parameter is expected to be a string which indicates the
|
||||
name of the proxy user to connect to. If this value is not specified, it
|
||||
will be parsed out of user if user is in the form "user[proxy_user]".
|
||||
|
||||
The ``password`` parameter expected to be a string which indicates the
|
||||
password for the user.
|
||||
|
||||
The ``newpassword`` parameter is expected to be a string which indicates
|
||||
the new password for the user. The new password will take effect
|
||||
immediately upon a successful connection to the database.
|
||||
|
||||
The ``wallet_password`` parameter is expected to be a string which
|
||||
indicates the password to use to decrypt the PEM-encoded wallet, if it is
|
||||
encrypted.
|
||||
|
||||
The ``access_token`` parameter is expected to be a string or a 2-tuple or
|
||||
a callable. If it is a string, it specifies an Azure AD OAuth2 token used
|
||||
for Open Authorization (OAuth 2.0) token based authentication. If it is a
|
||||
2-tuple, it specifies the token and private key strings used for Oracle
|
||||
Cloud Infrastructure (OCI) Identity and Access Management (IAM) token based
|
||||
authentication. If it is a callable, it returns either a string or a
|
||||
2-tuple used for OAuth 2.0 or OCI IAM token based authentication and is
|
||||
useful when the pool needs to expand and create new connections but the
|
||||
current authentication token has expired.
|
||||
|
||||
The ``host`` parameter is expected to be a string which specifies the name
|
||||
or IP address of the machine hosting the listener, which handles the
|
||||
initial connection to the database.
|
||||
|
||||
The ``port`` parameter is expected to be an integer which indicates the
|
||||
port number on which the listener is listening. The default value is 1521.
|
||||
|
||||
The ``protocol`` parameter is expected to be one of the strings "tcp" or
|
||||
"tcps" which indicates whether to use unencrypted network traffic or
|
||||
encrypted network traffic (TLS). The default value is tcp.
|
||||
|
||||
The ``https_proxy`` parameter is expected to be a string which indicates
|
||||
the name or IP address of a proxy host to use for tunneling secure
|
||||
connections.
|
||||
|
||||
The ``https_proxy_port`` parameter is expected to be an integer which
|
||||
indicates the port that is to be used to communicate with the proxy host.
|
||||
The default value is 0.
|
||||
|
||||
The ``service_name`` parameter is expected to be a string which indicates
|
||||
the service name of the database.
|
||||
|
||||
The ``sid`` parameter is expected to be a string which indicates the SID of
|
||||
the database. It is recommended to use ``service_name`` instead.
|
||||
|
||||
The ``server_type`` parameter is expected to be a string that indicates the
|
||||
type of server connection that should be established. If specified, it
|
||||
should be one of `dedicated`, `shared`, or `pooled`.
|
||||
|
||||
The ``cclass`` parameter is expected to be a string that identifies the
|
||||
connection class to use for Database Resident Connection Pooling (DRCP).
|
||||
|
||||
The ``purity`` parameter is expected to be one of the
|
||||
:ref:`oracledb.PURITY_* <drcppurityconsts>` constants that identifies the
|
||||
purity to use for DRCP. The purity will internally default to
|
||||
:data:`~oracledb.PURITY_SELF` for pooled connections. For standalone
|
||||
connections, the purity will internally default to
|
||||
:data:`~oracledb.PURITY_NEW`.
|
||||
|
||||
The ``expire_time`` parameter is expected to be an integer which indicates
|
||||
the number of minutes between the sending of keepalive probes. If this
|
||||
parameter is set to a value greater than zero it enables keepalive. The
|
||||
default value is 0.
|
||||
|
||||
The ``retry_count`` parameter is expected to be an integer that identifies
|
||||
the number of times that a connection attempt should be retried before the
|
||||
attempt is terminated. The default value is 0.
|
||||
|
||||
The ``retry_delay`` parameter is expected to be an integer that identifies
|
||||
the number of seconds to wait before making a new connection attempt. The
|
||||
default value is 0.
|
||||
|
||||
The ``tcp_connect_timeout`` parameter is expected to be a float that
|
||||
indicates the maximum number of seconds to wait for establishing a
|
||||
connection to the database host. The default value is 60.0.
|
||||
|
||||
The ``ssl_server_dn_match`` parameter is expected to be a boolean that
|
||||
indicates whether the server certificate distinguished name (DN) should be
|
||||
matched in addition to the regular certificate verification that is
|
||||
performed. Note that if the ``ssl_server_cert_dn`` parameter is not
|
||||
provided, host name matching is performed instead. The default value is
|
||||
True.
|
||||
|
||||
The ``ssl_server_cert_dn`` parameter is expected to be a string that
|
||||
indicates the distinguished name (DN) which should be matched with the
|
||||
server. This value is ignored if the ``ssl_server_dn_match`` parameter is
|
||||
not set to the value True.
|
||||
|
||||
The ``wallet_location`` parameter is expected to be a string that
|
||||
identifies the directory where the wallet can be found. In python-oracledb
|
||||
Thin mode, this must be the directory of the PEM-encoded wallet file,
|
||||
ewallet.pem.
|
||||
|
||||
The ``events`` parameter is ignored in the python-oracledb Thin mode.
|
||||
|
||||
The ``externalauth`` parameter is ignored in the python-oracledb Thin mode.
|
||||
|
||||
If the ``mode`` parameter is specified, it must be one of the
|
||||
:ref:`connection authorization modes <connection-authorization-modes>`
|
||||
which are defined at the module level. The default value is
|
||||
:data:`oracledb.AUTH_MODE_DEFAULT`.
|
||||
|
||||
The ``disable_oob`` parameter is expected to be a boolean that indicates
|
||||
whether out-of-band breaks should be disabled. This value has no effect on
|
||||
Windows which does not support this functionality. The default value is
|
||||
False.
|
||||
|
||||
The ``stmtcachesize`` parameter is expected to be an integer which
|
||||
specifies the initial size of the statement cache. The default is the
|
||||
value of :attr:`defaults.stmtcachesize`.
|
||||
|
||||
The ``edition`` parameter is ignored in the python-oracledb Thin mode.
|
||||
|
||||
The ``tag`` parameter is ignored in the python-oracledb Thin mode.
|
||||
|
||||
The ``matchanytag`` parameter is ignored in the python-oracledb Thin mode.
|
||||
|
||||
The ``config_dir`` parameter is expected to be a string that indicates the
|
||||
directory in which configuration files (tnsnames.ora) are found. The
|
||||
default is the value of :attr:`defaults.config_dir`.
|
||||
|
||||
The ``appcontext`` parameter is ignored in the python-oracledb Thin mode.
|
||||
|
||||
The ``shardingkey`` parameter and ``supershardingkey`` parameters are
|
||||
ignored in the python-oracledb Thin mode.
|
||||
|
||||
The ``debug_jdwp`` parameter is expected to be a string with the format
|
||||
`host=<host>;port=<port>` that specifies the host and port of the PL/SQL
|
||||
debugger. This allows using the Java Debug Wire Protocol (JDWP) to debug
|
||||
PL/SQL code called by python-oracledb.
|
||||
|
||||
The ``connection_id_prefix`` parameter is expected to be a string and 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>`__.
|
||||
|
||||
The ``ssl_context`` parameter is expected to be an SSLContext object 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.
|
||||
|
||||
The ``sdu`` parameter is expected to be 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. The default value is 8192 bytes.
|
||||
|
||||
The ``handle`` parameter is ignored in the python-oracledb Thin mode.
|
||||
|
||||
.. function:: ConnectParams(user=None, proxy_user=None, password=None, \
|
||||
newpassword=None, wallet_password=None, access_token=None, host=None, \
|
||||
port=1521, protocol="tcp", https_proxy=None, https_proxy_port=0, \
|
||||
|
@ -687,12 +909,14 @@ Oracledb Methods
|
|||
connection tag differs from the one requested.
|
||||
|
||||
The ``max_sessions_per_shard`` parameter is the maximum number of
|
||||
connections that may be associated with a particular shard. The default
|
||||
value is 0.
|
||||
connections that may be associated with a particular shard. This value is
|
||||
only used in the python-oracledb Thick mode and is ignored in the
|
||||
python-oracledb Thin mode. The default value is 0.
|
||||
|
||||
The ``soda_metadata_cache`` parameter is a boolean that indicates whether
|
||||
or not the SODA metadata cache should be enabled. The default value is
|
||||
False.
|
||||
or not the SODA metadata cache should be enabled. This value is only used
|
||||
in the python-oracledb Thick mode and is ignored in the python-oracledb
|
||||
Thin mode. The default value is False.
|
||||
|
||||
The ``ping_interval`` parameter is the length of time (in seconds) after
|
||||
which an unused connection in the pool will be a candidate for pinging when
|
||||
|
@ -819,13 +1043,13 @@ Oracledb Methods
|
|||
|
||||
The ``events`` parameter is expected to be a boolean that specifies whether
|
||||
the events mode should be enabled. This value is only used in the
|
||||
python-oracledb Thick mode. This parameter is needed for continuous
|
||||
query notification and high availability event notifications. The default
|
||||
value is False.
|
||||
python-oracledb Thick mode and is ignored in the Thin mode. This parameter
|
||||
is needed for continuous query notification and high availability event
|
||||
notifications. The default value is False.
|
||||
|
||||
The ``externalauth`` parameter is a boolean that determines whether to use
|
||||
external authentication. This value is only used in the python-oracledb
|
||||
Thick mode. The default value is False.
|
||||
Thick mode and is ignored in the Thin mode. The default value is False.
|
||||
|
||||
If the ``mode`` parameter is specified, it must be one of the
|
||||
:ref:`connection authorization modes <connection-authorization-modes>`
|
||||
|
@ -846,16 +1070,17 @@ Oracledb Methods
|
|||
The ``edition`` parameter is expected to be a string that indicates the
|
||||
edition to use for the connection. This parameter cannot be used
|
||||
simultaneously with the ``cclass`` parameter. This value is used in the
|
||||
python-oracledb Thick mode.
|
||||
python-oracledb Thick mode and is ignored in the Thin mode.
|
||||
|
||||
The ``tag`` parameter is expected to be a string that identifies the type
|
||||
of connection that should be returned from a pool. This value is only used
|
||||
in the python-oracledb Thick mode.
|
||||
in the python-oracledb Thick mode and is ignored in the Thin mode.
|
||||
|
||||
The ``matchanytag`` parameter is expected to be a boolean specifying
|
||||
whether any tag can be used when acquiring a connection from the pool. This
|
||||
value is only used in the python-oracledb Thick mode when acquiring a
|
||||
connection from a pool. The default value is False.
|
||||
connection from a pool. This value is ignored in the python-oracledb Thin
|
||||
mode. The default value is False.
|
||||
|
||||
The ``config_dir`` parameter is expected to be a string that indicates the
|
||||
directory in which configuration files (tnsnames.ora) are found. This value
|
||||
|
@ -867,13 +1092,13 @@ Oracledb Methods
|
|||
identifies the application context used by the connection. This parameter
|
||||
should contain namespace, name, and value and each entry in the tuple
|
||||
should be a string. This value is only used in the python-oracledb Thick
|
||||
mode.
|
||||
mode and is ignored in the Thin mode.
|
||||
|
||||
The ``shardingkey`` parameter and ``supershardingkey`` parameters, if
|
||||
specified, are expected to be a sequence of values which identifies the
|
||||
database shard to connect to. The key values can be a list of strings,
|
||||
numbers, bytes, or dates. This value is only used in the python-oracledb
|
||||
Thick mode.
|
||||
numbers, bytes, or dates. These values are only used in the
|
||||
python-oracledb Thick mode and are ignored in the Thin mode.
|
||||
|
||||
The ``debug_jdwp`` parameter is expected to be a string with the format
|
||||
`host=<host>;port=<port>` that specifies the host and port of the PL/SQL
|
||||
|
@ -912,8 +1137,9 @@ Oracledb Methods
|
|||
and is only of use when embedding Python in an application (like
|
||||
PowerBuilder) which has already made the connection. The connection thus
|
||||
created should *never* be used after the source handle has been closed or
|
||||
destroyed. This value is only used in the python-oracledb Thick mode. It
|
||||
should be used with extreme caution. The default value is 0.
|
||||
destroyed. This value is only used in the python-oracledb Thick mode and
|
||||
is ignored in the Thin mode. It should be used with extreme caution. The
|
||||
default value is 0.
|
||||
|
||||
In the python-oracledb Thick mode, connection pooling is handled by
|
||||
Oracle's `Session pooling <https://www.oracle.com/pls/topic/lookup?
|
||||
|
@ -926,6 +1152,277 @@ Oracledb Methods
|
|||
|
||||
The ``ssl_context`` and ``sdu`` parameters were added.
|
||||
|
||||
.. function:: create_pool_async(dsn=None, pool_class=oracledb.AsyncConnectionPool, \
|
||||
params=None, min=1, max=2, increment=1, \
|
||||
connectiontype=oracledb.Connection, \
|
||||
getmode=oracledb.POOL_GETMODE_WAIT, homogeneous=True, timeout=0, \
|
||||
wait_timeout=0, max_lifetime_session=0, session_callback=None, \
|
||||
max_sessions_per_shard=0, soda_metadata_cache=False, ping_interval=60, \
|
||||
user=None, proxy_user=None, password=None, newpassword=None, \
|
||||
wallet_password=None, access_token=None, host=None, port=1521, \
|
||||
protocol="tcp", https_proxy=None, https_proxy_port=0, \
|
||||
service_name=None, sid=None, server_type=None, cclass=None, \
|
||||
purity=oracledb.PURITY_DEFAULT, expire_time=0, retry_count=0, \
|
||||
retry_delay=0, tcp_connect_timeout=60.0, ssl_server_dn_match=True, \
|
||||
ssl_server_cert_dn=None, wallet_location=None, events=False, \
|
||||
externalauth=False, mode=oracledb.AUTH_MODE_DEFAULT, \
|
||||
disable_oob=False, stmtcachesize=oracledb.defaults.stmtcachesize, \
|
||||
edition=None, tag=None, matchanytag=False, \
|
||||
config_dir=oracledb.defaults.config_dir, appcontext=[], \
|
||||
shardingkey=[], supershardingkey=[], debug_jdwp=None, \
|
||||
connection_id_prefix=None, ssl_context=None, sdu=8192, handle=0)
|
||||
|
||||
Creates a connection pool with the supplied parameters and returns the
|
||||
:ref:`AsyncConnectionPool object <asyncconnpoolobj>` for the pool.
|
||||
``create_pool_async()`` is a synchronous method. See
|
||||
:ref:`Connection pooling <asyncconnpool>` for more information.
|
||||
|
||||
.. note::
|
||||
|
||||
The asyncio support in python-oracledb 2.0.0 is a pre-release and may
|
||||
change in the next version. This method can only used in
|
||||
python-oracledb Thin mode.
|
||||
|
||||
.. versionadded:: 2.0.0
|
||||
|
||||
Some values, such as the database host name, can be specified as
|
||||
parameters, as part of the connect string, and in the params object.
|
||||
The precedence is that values in the ``dsn`` parameter override values
|
||||
passed as individual parameters, which themselves override values set in
|
||||
the ``params`` parameter object. Similar precedence rules also apply to
|
||||
other values.
|
||||
|
||||
The ``user``, ``password``, and ``dsn`` parameters are the same as for
|
||||
:meth:`oracledb.connect_async()`.
|
||||
|
||||
The ``pool_class`` parameter is expected to be a
|
||||
:ref:`AsyncConnectionPool Object <asyncconnpoolobj>` or a subclass of
|
||||
AsyncConnectionPool.
|
||||
|
||||
The ``params`` parameter is expected to be of type :ref:`PoolParams
|
||||
<poolparam>` and contains parameters that are used to create the pool.
|
||||
If this parameter is not specified, the additional keyword parameters will
|
||||
be used to create an instance of PoolParams. If both the params parameter
|
||||
and additional keyword parameters are specified, the values in the keyword
|
||||
parameters have precedence. Note that if a ``dsn`` is also supplied, then
|
||||
the values of the parameters specified (if any) within the ``dsn`` will
|
||||
override the values passed as additional keyword parameters, which
|
||||
themselves override the values set in the ``params`` parameter object.
|
||||
|
||||
The ``min``, ``max`` and ``increment`` parameters control pool growth
|
||||
behavior. A fixed pool size where ``min`` equals ``max`` is
|
||||
:ref:`recommended <connpoolsize>` to help prevent connection storms and to
|
||||
help overall system stability. The ``min`` parameter is the number of
|
||||
connections opened when the pool is created. The default value of the
|
||||
``min`` parameter is 1. The ``increment`` parameter is the number of
|
||||
connections that are opened whenever a connection request exceeds the
|
||||
number of currently open connections. The default value of the
|
||||
``increment`` parameter is 1. The ``max`` parameter is the maximum number
|
||||
of connections that can be open in the connection pool. The default value
|
||||
of the ``max`` parameter is 2.
|
||||
|
||||
If the ``connectiontype`` parameter is specified, all calls to
|
||||
:meth:`AsyncConnectionPool.acquire()` will create connection objects of
|
||||
that type, rather than the base type defined at the module level.
|
||||
|
||||
The ``getmode`` parameter determines the behavior of
|
||||
:meth:`AsyncConnectionPool.acquire()`. 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`.
|
||||
|
||||
The ``homogeneous`` parameter is a boolean that indicates whether the
|
||||
connections are homogeneous (same user) or heterogeneous (multiple
|
||||
users). The default value is True.
|
||||
|
||||
The ``timeout`` parameter is the length of time (in seconds) that a
|
||||
connection may remain idle in the pool before it is terminated. This
|
||||
applies only when the pool has more than ``min`` connections open, allowing
|
||||
it to shrink to the specified minimum size. If the value of this parameter
|
||||
is 0, then the connections are never terminated. The default value is 0.
|
||||
|
||||
The ``wait_timeout`` parameter is the length of time (in milliseconds) that
|
||||
a caller should wait when acquiring a connection from the pool with
|
||||
``getmode`` set to :data:`oracledb.POOL_GETMODE_TIMEDWAIT`. The default
|
||||
value is 0.
|
||||
|
||||
The ``max_lifetime_session`` parameter is the length of time (in seconds)
|
||||
that connections can remain in the pool. If the value of this parameter is
|
||||
0, then the connections may remain in the pool indefinitely. The default
|
||||
value is 0.
|
||||
|
||||
The ``session_callback`` parameter is a callable that is invoked when a
|
||||
connection is returned from the pool for the first time, or when the
|
||||
connection tag differs from the one requested.
|
||||
|
||||
The ``max_sessions_per_shard`` parameter is ignored in the python-oracledb
|
||||
Thin mode.
|
||||
|
||||
The ``soda_metadata_cache`` parameter is ignored in the python-oracledb
|
||||
Thin mode.
|
||||
|
||||
The ``ping_interval`` parameter is the length of time (in seconds) after
|
||||
which an unused connection in the pool will be a candidate for pinging when
|
||||
:meth:`AsyncConnectionPool.acquire()` is called. If the ping to the
|
||||
database indicates the connection is not alive a replacement connection
|
||||
will be returned by :meth:`~AsyncConnectionPool.acquire()`. If
|
||||
``ping_interval`` is a negative value, then the ping functionality will be
|
||||
disabled. The default value is 60 seconds.
|
||||
|
||||
The ``proxy_user`` parameter is expected to be a string which indicates the
|
||||
name of the proxy user to connect to. If this value is not specified, it
|
||||
will be parsed out of user if user is in the form "user[proxy_user]".
|
||||
|
||||
The ``newpassword`` parameter is expected to be a string which indicates
|
||||
the new password for the user. The new password will take effect
|
||||
immediately upon a successful connection to the database.
|
||||
|
||||
The ``wallet_password`` parameter is expected to be a string which
|
||||
indicates the password to use to decrypt the PEM-encoded wallet, if it is
|
||||
encrypted.
|
||||
|
||||
The ``access_token`` parameter is expected to be a string or a 2-tuple or
|
||||
a callable. If it is a string, it specifies an Azure AD OAuth2 token used
|
||||
for Open Authorization (OAuth 2.0) token based authentication. If it is a
|
||||
2-tuple, it specifies the token and private key strings used for Oracle
|
||||
Cloud Infrastructure (OCI) Identity and Access Management (IAM) token based
|
||||
authentication. If it is a callable, it returns either a string or a
|
||||
2-tuple used for OAuth 2.0 or OCI IAM token based authentication and is
|
||||
useful when the pool needs to expand and create new connections but the
|
||||
current authentication token has expired.
|
||||
|
||||
The ``host`` parameter is expected to be a string which specifies the name
|
||||
or IP address of the machine hosting the listener, which handles the
|
||||
initial connection to the database.
|
||||
|
||||
The ``port`` parameter is expected to be an integer which indicates the
|
||||
port number on which the listener is listening. The default value is 1521.
|
||||
|
||||
The ``protocol`` parameter is expected to be one of the strings "tcp" or
|
||||
"tcps" which indicates whether to use unencrypted network traffic or
|
||||
encrypted network traffic (TLS). The default value is tcp.
|
||||
|
||||
The ``https_proxy`` parameter is expected to be a string which indicates
|
||||
the name or IP address of a proxy host to use for tunneling secure
|
||||
connections.
|
||||
|
||||
The ``https_proxy_port`` parameter is expected to be an integer which
|
||||
indicates the port that is to be used to communicate with the proxy host.
|
||||
The default value is 0.
|
||||
|
||||
The ``service_name`` parameter is expected to be a string which indicates
|
||||
the service name of the database.
|
||||
|
||||
The ``sid`` parameter is expected to be a string which indicates the SID of
|
||||
the database. It is recommended to use ``service_name`` instead.
|
||||
|
||||
The ``server_type`` parameter is expected to be a string that indicates the
|
||||
type of server connection that should be established. If specified, it
|
||||
should be one of `dedicated`, `shared`, or `pooled`.
|
||||
|
||||
The ``cclass`` parameter is expected to be a string that identifies the
|
||||
connection class to use for Database Resident Connection Pooling (DRCP).
|
||||
|
||||
The ``purity`` parameter is expected to be one of the
|
||||
:ref:`oracledb.PURITY_* <drcppurityconsts>` constants that identifies the
|
||||
purity to use for DRCP. The purity will internally default to
|
||||
:data:`~oracledb.PURITY_SELF` for pooled connections.
|
||||
|
||||
The ``expire_time`` parameter is expected to be an integer which indicates
|
||||
the number of minutes between the sending of keepalive probes. If this
|
||||
parameter is set to a value greater than zero it enables keepalive. The
|
||||
default value is 0.
|
||||
|
||||
The ``retry_count`` parameter is expected to be an integer that identifies
|
||||
the number of times that a connection attempt should be retried before the
|
||||
attempt is terminated. The default value is 0.
|
||||
|
||||
The ``retry_delay`` parameter is expected to be an integer that identifies
|
||||
the number of seconds to wait before making a new connection attempt. The
|
||||
default value is 0.
|
||||
|
||||
The ``tcp_connect_timeout`` parameter is expected to be a float that
|
||||
indicates the maximum number of seconds to wait for establishing a
|
||||
connection to the database host. The default value is 60.0.
|
||||
|
||||
The ``ssl_server_dn_match`` parameter is expected to be a boolean that
|
||||
indicates whether the server certificate distinguished name (DN) should be
|
||||
matched in addition to the regular certificate verification that is
|
||||
performed. Note that if the ``ssl_server_cert_dn`` parameter is not
|
||||
provided, host name matching is performed instead. The default value is
|
||||
True.
|
||||
|
||||
The ``ssl_server_cert_dn`` parameter is expected to be a string that
|
||||
indicates the distinguished name (DN) which should be matched with the
|
||||
server. This value is ignored if the ``ssl_server_dn_match`` parameter is
|
||||
not set to the value True.
|
||||
|
||||
The ``wallet_location`` parameter is expected to be a string that
|
||||
identifies the directory where the wallet can be found. In python-oracledb
|
||||
Thin mode, this must be the directory of the PEM-encoded wallet file,
|
||||
ewallet.pem.
|
||||
|
||||
The ``events`` parameter is ignored in the python-oracledb Thin mode.
|
||||
|
||||
The ``externalauth`` parameter is ignored in the python-oracledb Thin mode.
|
||||
|
||||
If the ``mode`` parameter is specified, it must be one of the
|
||||
:ref:`connection authorization modes <connection-authorization-modes>`
|
||||
which are defined at the module level. The default value is
|
||||
:data:`oracledb.AUTH_MODE_DEFAULT`.
|
||||
|
||||
The ``disable_oob`` parameter is expected to be a boolean that indicates
|
||||
whether out-of-band breaks should be disabled. This value has no effect
|
||||
on Windows which does not support this functionality. The default value
|
||||
is False.
|
||||
|
||||
The ``stmtcachesize`` parameter is expected to be an integer which
|
||||
specifies the initial size of the statement cache. The default is the
|
||||
value of :attr:`defaults.stmtcachesize`.
|
||||
|
||||
The ``edition`` parameter is ignored in the python-oracledb Thin mode.
|
||||
|
||||
The ``tag`` parameter is ignored in the python-oracledb Thin mode.
|
||||
|
||||
The ``matchanytag`` parameter is ignored in the python-oracledb Thin mode.
|
||||
|
||||
The ``config_dir`` parameter is expected to be a string that indicates the
|
||||
directory in which configuration files (tnsnames.ora) are found. The
|
||||
default is the value of :attr:`defaults.config_dir`.
|
||||
|
||||
The ``appcontext`` parameter is ignored in the python-oracledb Thin mode.
|
||||
|
||||
The ``shardingkey`` parameter and ``supershardingkey`` parameters are
|
||||
ignored in the python-oracledb Thin mode.
|
||||
|
||||
The ``debug_jdwp`` parameter is expected to be a string with the format
|
||||
`host=<host>;port=<port>` that specifies the host and port of the PL/SQL
|
||||
debugger. This allows using the Java Debug Wire Protocol (JDWP) to debug
|
||||
PL/SQL code invoked by python-oracledb.
|
||||
|
||||
The ``connection_id_prefix`` parameter is expected to be a string and 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>`__.
|
||||
|
||||
The ``ssl_context`` parameter is expected to be an SSLContext object 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.
|
||||
|
||||
The ``sdu`` parameter is expected to be 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. The default value is 8192 bytes.
|
||||
|
||||
The ``handle`` parameter is ignored in the python-oracledb Thin mode.
|
||||
|
||||
.. function:: Cursor(connection)
|
||||
|
||||
|
@ -2232,6 +2729,8 @@ All of these types are extensions to the DB API definition. They are found in
|
|||
query and object metadata. They can also be used to specify the database type
|
||||
when binding data.
|
||||
|
||||
Also see the table :ref:`supporteddbtypes`.
|
||||
|
||||
.. data:: DB_TYPE_BFILE
|
||||
|
||||
Describes columns, attributes or array elements in a database that are of
|
||||
|
|
|
@ -6,7 +6,8 @@ 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.
|
||||
additions and a couple of exclusions. Synchronous and
|
||||
:ref:`concurrent <asyncio>` coding styles are supported.
|
||||
|
||||
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.
|
||||
|
@ -45,9 +46,10 @@ User Guide
|
|||
user_guide/two_phase_commit.rst
|
||||
user_guide/startup.rst
|
||||
user_guide/ha.rst
|
||||
user_guide/tracing.rst
|
||||
user_guide/globalization.rst
|
||||
user_guide/asyncio.rst
|
||||
user_guide/exception_handling.rst
|
||||
user_guide/tracing.rst
|
||||
user_guide/troubleshooting.rst
|
||||
user_guide/appendix_a.rst
|
||||
user_guide/appendix_b.rst
|
||||
|
@ -74,6 +76,10 @@ API Manual
|
|||
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::
|
||||
|
|
|
@ -13,7 +13,7 @@ oracledb 2.0.0 (TBD)
|
|||
Thin Mode Changes
|
||||
+++++++++++++++++
|
||||
|
||||
#) Added support for asyncio
|
||||
#) 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
|
||||
|
@ -103,7 +103,8 @@ Common Changes
|
|||
: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.
|
||||
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.
|
||||
|
||||
|
||||
|
|
|
@ -282,6 +282,10 @@ 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
|
||||
|
@ -296,7 +300,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
|
||||
|
@ -326,62 +330,6 @@ see :ref:`driverdiff` and :ref:`compatibility`.
|
|||
- 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`)
|
||||
- Yes
|
||||
- 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:
|
||||
|
||||
|
@ -402,198 +350,133 @@ 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 indicates if the type is supported in python-oracledb.
|
||||
: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.
|
||||
|
||||
* - Oracle Database Type
|
||||
- python-oracledb Constant Name
|
||||
- Supported in python-oracledb
|
||||
- Notes
|
||||
- Supported Python Types
|
||||
* - VARCHAR2
|
||||
- DB_TYPE_VARCHAR
|
||||
- Yes
|
||||
- :data:`~oracledb.DB_TYPE_VARCHAR`
|
||||
-
|
||||
- bytes, str
|
||||
* - NVARCHAR2
|
||||
- DB_TYPE_NVARCHAR
|
||||
- Yes
|
||||
- :data:`~oracledb.DB_TYPE_NVARCHAR`
|
||||
-
|
||||
- bytes, str
|
||||
* - NUMBER, FLOAT
|
||||
- DB_TYPE_NUMBER
|
||||
- Yes
|
||||
- :data:`~oracledb.DB_TYPE_NUMBER`
|
||||
-
|
||||
- bool, int, float, decimal.Decimal
|
||||
* - DATE
|
||||
- DB_TYPE_DATE
|
||||
- Yes
|
||||
- :data:`~oracledb.DB_TYPE_DATE`
|
||||
-
|
||||
- datetime.date, datetime.datetime
|
||||
* - BOOLEAN (PL/SQL)
|
||||
- DB_TYPE_BOOLEAN
|
||||
- Yes
|
||||
- ANY (converted to bool)
|
||||
* - BOOLEAN (PL/SQL and Oracle Database 23c SQL)
|
||||
- :data:`~oracledb.DB_TYPE_BOOLEAN`
|
||||
-
|
||||
- Any type convertible to bool
|
||||
* - BINARY_DOUBLE
|
||||
- DB_TYPE_BINARY_DOUBLE
|
||||
- Yes
|
||||
- :data:`~oracledb.DB_TYPE_BINARY_DOUBLE`
|
||||
-
|
||||
- bool, int, float, decimal.Decimal
|
||||
* - BINARY_FLOAT
|
||||
- DB_TYPE_BINARY_FLOAT
|
||||
- Yes
|
||||
- :data:`~oracledb.DB_TYPE_BINARY_FLOAT`
|
||||
-
|
||||
- bool, int, float, decimal.Decimal
|
||||
* - TIMESTAMP
|
||||
- DB_TYPE_TIMESTAMP
|
||||
- Yes
|
||||
- :data:`~oracledb.DB_TYPE_TIMESTAMP`
|
||||
-
|
||||
- datetime.date, datetime.datetime
|
||||
* - TIMESTAMP WITH TIME ZONE
|
||||
- DB_TYPE_TIMESTAMP_TZ
|
||||
- Yes
|
||||
- :data:`~oracledb.DB_TYPE_TIMESTAMP_TZ`
|
||||
-
|
||||
- datetime.date, datetime.datetime
|
||||
* - TIMESTAMP WITH LOCAL TIME ZONE
|
||||
- DB_TYPE_TIMESTAMP_LTZ
|
||||
- Yes
|
||||
- :data:`~oracledb.DB_TYPE_TIMESTAMP_LTZ`
|
||||
-
|
||||
- datetime.date, datetime.datetime
|
||||
* - INTERVAL YEAR TO MONTH
|
||||
- DB_TYPE_INTERVAL_YM
|
||||
- Not supported in python-oracledb
|
||||
- cannot be set
|
||||
- :data:`~oracledb.DB_TYPE_INTERVAL_YM`
|
||||
- Not supported in python-oracledb.
|
||||
- Cannot be set
|
||||
* - INTERVAL DAY TO SECOND
|
||||
- DB_TYPE_INTERVAL_DS
|
||||
- Yes
|
||||
- :data:`~oracledb.DB_TYPE_INTERVAL_DS`
|
||||
-
|
||||
- datetime.timedelta
|
||||
* - RAW
|
||||
- DB_TYPE_RAW
|
||||
- Yes
|
||||
- :data:`~oracledb.DB_TYPE_RAW`
|
||||
-
|
||||
- bytes, str
|
||||
* - LONG
|
||||
- DB_TYPE_LONG
|
||||
- Yes
|
||||
- :data:`~oracledb.DB_TYPE_LONG`
|
||||
-
|
||||
- bytes, str
|
||||
* - LONG RAW
|
||||
- DB_TYPE_LONG_RAW
|
||||
- Yes
|
||||
- :data:`~oracledb.DB_TYPE_LONG_RAW`
|
||||
-
|
||||
- bytes, str
|
||||
* - ROWID
|
||||
- DB_TYPE_ROWID
|
||||
- Yes
|
||||
- :data:`~oracledb.DB_TYPE_ROWID`
|
||||
-
|
||||
- bytes, str
|
||||
* - UROWID
|
||||
- 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>`.
|
||||
- :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>`.
|
||||
- bytes, str
|
||||
* - CHAR
|
||||
- DB_TYPE_CHAR
|
||||
- Yes
|
||||
- :data:`~oracledb.DB_TYPE_CHAR`
|
||||
-
|
||||
- bytes, str
|
||||
* - BLOB
|
||||
- DB_TYPE_BLOB
|
||||
- Yes
|
||||
- BLOB, bytes, str
|
||||
- :data:`~oracledb.DB_TYPE_BLOB`
|
||||
-
|
||||
- :ref:`oracledb.LOB <lobobj>`, bytes, str
|
||||
* - CLOB
|
||||
- DB_TYPE_CLOB
|
||||
- Yes
|
||||
- CLOB, bytes, str
|
||||
- :data:`~oracledb.DB_TYPE_CLOB`
|
||||
-
|
||||
- :ref:`oracledb.LOB <lobobj>`, bytes, str
|
||||
* - NCHAR
|
||||
- DB_TYPE_NCHAR
|
||||
- Yes
|
||||
- :data:`~oracledb.DB_TYPE_NCHAR`
|
||||
-
|
||||
- bytes, str
|
||||
* - NCLOB
|
||||
- DB_TYPE_NCLOB
|
||||
- Yes
|
||||
- NCLOB, bytes, str
|
||||
- :data:`~oracledb.DB_TYPE_NCLOB`, :data:`~oracledb.DB_TYPE_LONG_NVARCHAR` (if fetching NCLOB as a string)
|
||||
-
|
||||
- :ref:`oracledb.LOB <lobobj>`, bytes, str
|
||||
* - BFILE
|
||||
- DB_TYPE_BFILE
|
||||
- Not supported in python-oracledb Thin mode
|
||||
- cannot be set
|
||||
- :data:`~oracledb.DB_TYPE_BFILE`
|
||||
- Not supported in python-oracledb Thin mode.
|
||||
- Cannot be set
|
||||
* - JSON
|
||||
- DB_TYPE_JSON
|
||||
- Yes
|
||||
- ANY (converted)
|
||||
- :data:`~oracledb.DB_TYPE_JSON`
|
||||
-
|
||||
- Any type convertible to Oracle JSON
|
||||
* - REF CURSOR (PL/SQL OR nested cursor)
|
||||
- DB_TYPE_CURSOR
|
||||
- Yes
|
||||
- CURSOR
|
||||
- :data:`~oracledb.DB_TYPE_CURSOR`
|
||||
-
|
||||
- :ref:`oracledb.Cursor <cursorobj>`
|
||||
* - PLS_INTEGER
|
||||
- DB_TYPE_BINARY_INTEGER
|
||||
- Yes
|
||||
- :data:`~oracledb.DB_TYPE_BINARY_INTEGER`
|
||||
-
|
||||
- bool, int, float, decimal.Decimal
|
||||
* - BINARY_INTEGER
|
||||
- DB_TYPE_BINARY_INTEGER
|
||||
- Yes
|
||||
- :data:`~oracledb.DB_TYPE_BINARY_INTEGER`
|
||||
-
|
||||
- bool, int, float, decimal.Decimal
|
||||
* - REF
|
||||
- n/a
|
||||
- Not supported in python-oracledb Thin mode
|
||||
- n/a
|
||||
* - XMLType
|
||||
- DB_TYPE_XMLTYPE
|
||||
- Yes. May need to use ``xmltype.getclobval()`` to fetch in python-oracledb Thick mode.
|
||||
- :data:`~oracledb.DB_TYPE_XMLTYPE`
|
||||
- May need to use ``xmltype.getclobval()`` to fetch in python-oracledb Thick mode. See :ref:`xmldatatype`
|
||||
- bytes, str
|
||||
* - User-defined types (object type, VARRAY, records, collections, SDO_*types)
|
||||
- DB_TYPE_OBJECT
|
||||
- Yes
|
||||
- :data:`~oracledb.DB_TYPE_OBJECT`
|
||||
-
|
||||
- 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
|
||||
|
|
|
@ -348,8 +348,9 @@ 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). Until they add native
|
||||
support, you can override the use of cx_Oracle with a few lines of code. See
|
||||
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
|
||||
:ref:`frameworks`.
|
||||
|
||||
- python-oracledb connection and pool creation calls require keyword arguments
|
||||
|
@ -675,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.
|
||||
|
||||
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:
|
||||
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:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
@ -691,3 +692,7 @@ 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.
|
||||
|
|
|
@ -0,0 +1,292 @@
|
|||
.. _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,6 +102,11 @@ 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
|
||||
=========================
|
||||
|
||||
|
|
|
@ -16,6 +16,9 @@ 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
|
||||
|
|
|
@ -8,6 +8,7 @@ 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
|
||||
|
|
|
@ -170,7 +170,7 @@ will show more details. For example:
|
|||
WRONG WRONG WRONG
|
||||
end;""")
|
||||
|
||||
if cursor.warning.full_code == "DPY-7000":
|
||||
if cursor.warning and cursor.warning.full_code == "DPY-7000":
|
||||
print(cursor.warning)
|
||||
|
||||
# Get details
|
||||
|
@ -178,14 +178,14 @@ will show more details. For example:
|
|||
select line, position, text
|
||||
from user_errors
|
||||
where name = 'BADPROC' and type = 'PROCEDURE'
|
||||
order by name, type, line, position""")
|
||||
order by line, position""")
|
||||
for info in cursor:
|
||||
print("Error at line {} position {}:\n{}".format(*info))
|
||||
|
||||
The output would be::
|
||||
|
||||
DPY-7000: creation succeeded with compilation errors
|
||||
Error at line 3 position 27:
|
||||
Error at line 3 position 23:
|
||||
PLS-00103: Encountered the symbol "WRONG" when expecting one of the following:
|
||||
|
||||
:= . ( @ % ;
|
||||
|
|
|
@ -63,6 +63,10 @@ Some general tuning tips are:
|
|||
* 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.
|
||||
|
||||
.. _tuningfetch:
|
||||
|
||||
Tuning Fetch Performance
|
||||
|
|
|
@ -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()` 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()` 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:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
## 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
|
||||
|
@ -22,6 +26,16 @@ 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
|
||||
|
|
|
@ -53,7 +53,7 @@ async def init_session(connection, requested_tag):
|
|||
|
||||
|
||||
# The coroutine simply shows the session identifier/serial number of the
|
||||
# conneciton returned by the pool.acquire() call
|
||||
# connection returned by the pool.acquire() call
|
||||
async def query(pool):
|
||||
async with pool.acquire() as connection:
|
||||
await connection.callproc("dbms_session.sleep", [1])
|
||||
|
|
|
@ -13,9 +13,9 @@
|
|||
# USAGE
|
||||
#
|
||||
# Get an Oracle Database container (see
|
||||
# https://hub.docker.com/r/gvenzl/oracle-xe):
|
||||
# https://hub.docker.com/r/gvenzl/oracle-free):
|
||||
#
|
||||
# podman pull docker.io/gvenzl/oracle-xe:21-slim
|
||||
# podman pull docker.io/gvenzl/oracle-free
|
||||
#
|
||||
# Create a container with the database, Python, python-oracledb and the
|
||||
# samples. Choose a password for the sample schemas and pass it as an
|
||||
|
@ -40,10 +40,12 @@
|
|||
#
|
||||
# python bind_insert.py
|
||||
#
|
||||
# Use `vim` to edit files, if required.
|
||||
#
|
||||
# The database will persist across container shutdowns, but will be deleted
|
||||
# when the container is deleted.
|
||||
|
||||
FROM docker.io/gvenzl/oracle-xe:21-slim
|
||||
FROM docker.io/gvenzl/oracle-free
|
||||
|
||||
USER root
|
||||
|
||||
|
@ -54,12 +56,14 @@ RUN microdnf module disable python36 && \
|
|||
|
||||
WORKDIR /samples/
|
||||
|
||||
COPY setup.py setup.py
|
||||
|
||||
RUN curl -LO https://github.com/oracle/python-oracledb/archive/refs/heads/main.zip && \
|
||||
unzip main.zip && mv python-oracledb-main/samples/* . && \
|
||||
unzip main.zip && \
|
||||
cp python-oracledb-main/samples/sample_container/setup.py . && \
|
||||
/bin/rm -rf python-oracledb-main/samples/sample_container/ python-oracledb-main/samples/sample_notebooks/ && \
|
||||
mv python-oracledb-main/samples/* . && \
|
||||
/bin/rm -rf python-oracledb-main samples main.zip && \
|
||||
cat create_schema.py >> /samples/setup.py && chown -R oracle.oinstall /samples/
|
||||
cat create_schema.py >> /samples/setup.py && \
|
||||
chown -R oracle.oinstall /samples/
|
||||
|
||||
USER oracle
|
||||
|
||||
|
@ -72,8 +76,8 @@ ENV PYO_SAMPLES_MAIN_PASSWORD=${PYO_PASSWORD}
|
|||
ENV PYO_SAMPLES_EDITION_USER=pythoneditions
|
||||
ENV PYO_SAMPLES_EDITION_PASSWORD=${PYO_PASSWORD}
|
||||
ENV PYO_SAMPLES_EDITION_NAME=python_e1
|
||||
ENV PYO_SAMPLES_CONNECT_STRING="localhost/xepdb1"
|
||||
ENV PYO_SAMPLES_DRCP_CONNECT_STRING="localhost/xepdb1:pooled"
|
||||
ENV PYO_SAMPLES_CONNECT_STRING="localhost/freepdb1"
|
||||
ENV PYO_SAMPLES_DRCP_CONNECT_STRING="localhost/freepdb1:pooled"
|
||||
ENV PYO_SAMPLES_ADMIN_USER=system
|
||||
|
||||
# Run the samples using the default python-oracledb 'Thin' mode, if possible
|
||||
|
|
|
@ -9,10 +9,12 @@ It has been tested in an Oracle Linux 8 environment using 'podman', but
|
|||
## Usage
|
||||
|
||||
- Get an Oracle Database container (see
|
||||
https://hub.docker.com/r/gvenzl/oracle-xe):
|
||||
https://hub.docker.com/r/gvenzl/oracle-free):
|
||||
|
||||
The steps below use 'podman', but 'docker' will also work.
|
||||
|
||||
```
|
||||
podman pull docker.io/gvenzl/oracle-xe:21-slim
|
||||
podman pull docker.io/gvenzl/oracle-free
|
||||
```
|
||||
|
||||
- Create a container with the database, Python, python-oracledb and the
|
||||
|
|
|
@ -29,7 +29,7 @@ for i in range(30):
|
|||
c = oracledb.connect(
|
||||
user="system",
|
||||
password=pw,
|
||||
dsn="localhost/xepdb1",
|
||||
dsn="localhost/freepdb1",
|
||||
tcp_connect_timeout=5,
|
||||
)
|
||||
break
|
||||
|
@ -63,7 +63,7 @@ cursor.execute("alter database mount")
|
|||
cursor.execute("alter database open")
|
||||
|
||||
c = oracledb.connect(
|
||||
user="sys", password=pw, dsn="localhost/xepdb1", mode=oracledb.SYSDBA
|
||||
user="sys", password=pw, dsn="localhost/freepdb1", mode=oracledb.SYSDBA
|
||||
)
|
||||
cursor = c.cursor()
|
||||
cursor.callproc("dbms_connection_pool.start_pool")
|
||||
|
|
|
@ -0,0 +1,383 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# python-oracledb Introduction"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This Jupyter Notebook shows how to use [python-oracledb](https://oracle.github.io/python-oracledb/) in its default 'Thin' mode that connects directly to Oracle Database."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# python-oracledb Connection"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Architecture\n",
|
||||
"\n",
|
||||
"Documentation reference link: [Introduction to python-oracledb](https://python-oracledb.readthedocs.io/en/latest/user_guide/introduction.html)\n",
|
||||
"\n",
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Installation\n",
|
||||
"\n",
|
||||
"Documentation reference link: [python-oracledb Installation](https://python-oracledb.readthedocs.io/en/latest/user_guide/installation.html)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### **Install python-oracledb**\n",
|
||||
"\n",
|
||||
"Install with a command like one of the following:\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"$ python3 -m pip install oracledb --upgrade\n",
|
||||
"$ python3 -m pip install oracledb --upgrade --user\n",
|
||||
"$ python3 -m pip install oracledb --upgrade --user --proxy=http://proxy.example.com:80\n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"To use python-oracledb, your application code can import the module:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import oracledb"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Connecting to a Database\n",
|
||||
"\n",
|
||||
"**Connections are used for executing SQL and PL/SQL in an Oracle Database**\n",
|
||||
"\n",
|
||||
"Documentation reference link: [Connecting to Oracle Database](https://python-oracledb.readthedocs.io/en/latest/user_guide/connection_handling.html)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Credentials\n",
|
||||
"un = \"pythondemo\"\n",
|
||||
"pw = \"welcome\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Instead of hard coding the password, you could prompt for a value, pass it as an environment variable, or use Oracle \"external authentication\"."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Easy Connect Syntax: \"hostname/servicename\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"scrolled": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"cs = \"localhost/orclpdb1\"\n",
|
||||
"\n",
|
||||
"connection = oracledb.connect(user=un, password=pw, dsn=cs)\n",
|
||||
"print(connection)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Oracle Client 19c improved [Easy Connect Plus](https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-8C85D289-6AF3-41BC-848B-BF39D32648BA) syntax with additional optional settings, for example:\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"cs = \"tcps://my.cloud.com:1522/orclpdb1?connect_timeout=4&expire_time=10\"\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"<!-- See the [technical brief](https://download.oracle.com/ocomdocs/global/Oracle-Net-19c-Easy-Connect-Plus.pdf). -->"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Oracle Network and Oracle Client Configuration Files\n",
|
||||
"\n",
|
||||
"Oracle Database's `tnsnames.ora` file can be used. This file maps a connect descriptor to an alias. \n",
|
||||
"\n",
|
||||
"Documentation reference link: [Optional configuration files](https://python-oracledb.readthedocs.io/en/latest/user_guide/initialization.html#optional-oracle-net-configuration-files)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "raw",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n",
|
||||
"# tnsnames.ora in /opt/oracle/configdir\n",
|
||||
" \n",
|
||||
"highperfdb = (description= \n",
|
||||
" (retry_count=5)(retry_delay=3)\n",
|
||||
" (address=(protocol=tcps)(port=1522)(host=xxxxxx.oraclecloud.com))\n",
|
||||
" (connect_data=(service_name=yyyyyyyyyy.oraclecloud.com))\n",
|
||||
" (security=(ssl_server_cert_dn=\n",
|
||||
" \"CN=zzzzzzzz.oraclecloud.com,OU=Oracle ADB,O=Oracle Corporation,L=Redwood City,ST=California,C=US\")))\n",
|
||||
" "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Your Python code could use the alias as the connection `dsn` value:\n",
|
||||
"```\n",
|
||||
"connection = oracledb.connect(user=un, password=pw, dsn=\"highperfdb\", config_dir=\"/opt/oracle/configdir\")\n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Connection Types"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Standalone Connections\n",
|
||||
"\n",
|
||||
"Standalone connections are simple to create."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Stand-alone Connections\n",
|
||||
"\n",
|
||||
"connection = oracledb.connect(user=un, password=pw, dsn=cs)\n",
|
||||
"\n",
|
||||
"print(connection)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Pooled Connections"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### Pools are highly recommended if you have:\n",
|
||||
"- a lot of connections that will be used for short periods of time\n",
|
||||
"- or a small number of connections that are idle for long periods of time\n",
|
||||
"\n",
|
||||
"#### Pool advantages\n",
|
||||
"- Reduced cost of setting up and tearing down connections\n",
|
||||
"- Dead connection detection and automatic re-establishment"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Pooled Connections\n",
|
||||
"\n",
|
||||
"# Call once during application initization\n",
|
||||
"pool = oracledb.create_pool(user=un, password=pw, dsn=cs,\n",
|
||||
" min=1, max=10, increment=1)\n",
|
||||
"\n",
|
||||
"# Get a connection when needed in the application body\n",
|
||||
"with pool.acquire() as connection:\n",
|
||||
" # do_something_useful(connection)\n",
|
||||
" print(f\"Got a connection to Oracle Database {connection.version}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**Tip** Use a fixed size pool `min` = `max` and `increment = 0`. See [Guideline for Preventing Connection Storms: Use Static Pools](https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-7DFBA826-7CC0-4D16-B19C-31D168069B54)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Closing Connections"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Close connections when not needed. This is important for pooled connections.\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"connection.close()\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"To avoid resource closing order issues, you may want to use `with` or let resources be closed at end of scope:\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"with pool.acquire() as connection:\n",
|
||||
" do_something(connection)\n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Database Resident Connection Pooling\n",
|
||||
"\n",
|
||||
"**Connection pooling on the database tier**\n",
|
||||
"\n",
|
||||
"Documentation reference link: [Database Resident Connection Pooling (DRCP)](https://python-oracledb.readthedocs.io/en/latest/user_guide/connection_handling.html#database-resident-connection-pooling-drcp)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Dedicated server processes are the default in the database, but DRCP is an alternative when the database server is short of memory."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Use DRCP if and only if:\n",
|
||||
"- The database computer doesn't have enough memory for all the server processes for all open application connections\n",
|
||||
"- When you have thousands of users which need access to a database server session for a short period of time\n",
|
||||
"- Applications mostly use same database credentials, and have identical session settings\n",
|
||||
"\n",
|
||||
"Using DRCP in conjunction with a python-oracledb connection pool is recommended."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### Memory example with 5000 application users and a DRCP pool of size 100\n",
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"In Python, the connect string must request a pooled server, for example with ':pooled'. For best efficiency to allow database server session re-use, set a connection class and use the purity 'PURITY_SELF'.\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"pool = oracledb.create_pool(user=un, password=pw, dsn=\"dbhost.example.com/orclpdb1:pooled\",\n",
|
||||
" cclass=\"MYCLASS\", purity=oracledb.PURITY_SELF)\n",
|
||||
"\n",
|
||||
"connection = pool.acquire()\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"Don't forget to start the pool first!:\n",
|
||||
"```\n",
|
||||
"SQL> execute dbms_connection_pool.start_pool()\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"Note DRCP is pre-enabled on Oracle Autonomous Database."
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.9.6"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 4
|
||||
}
|
|
@ -0,0 +1,527 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Queries - SELECT and WITH Statements"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import oracledb"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"un = \"pythondemo\"\n",
|
||||
"pw = \"welcome\"\n",
|
||||
"\n",
|
||||
"adminun = \"system\"\n",
|
||||
"adminpw = \"oracle\"\n",
|
||||
"\n",
|
||||
"cs = \"localhost/orclpdb1\"\n",
|
||||
"\n",
|
||||
"connection = oracledb.connect(user=un, password=pw, dsn=cs)\n",
|
||||
"\n",
|
||||
"systemconnection = oracledb.connect(user=adminun, password=adminpw, dsn=cs)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Fetching Rows\n",
|
||||
"\n",
|
||||
"Documentation reference link: [Fetch Methods](https://python-oracledb.readthedocs.io/en/latest/user_guide/sql_execution.html#fetch-methods)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Fetching single rows\n",
|
||||
"\n",
|
||||
"with connection.cursor() as cursor:\n",
|
||||
" \n",
|
||||
" cursor.execute(\"select * from SampleQueryTab where id = :1\", [6])\n",
|
||||
" \n",
|
||||
" row = cursor.fetchone()\n",
|
||||
" print(row)\n",
|
||||
" "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Fetching all rows from a small table of not too big size\n",
|
||||
"\n",
|
||||
"with connection.cursor() as cursor:\n",
|
||||
" \n",
|
||||
" cursor.execute(\"select * from SampleQueryTab\")\n",
|
||||
" \n",
|
||||
" rows = cursor.fetchall()\n",
|
||||
" \n",
|
||||
" for r in rows:\n",
|
||||
" print(r)\n",
|
||||
" "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Fetching all rows from a big table\n",
|
||||
"\n",
|
||||
"with connection.cursor() as cursor:\n",
|
||||
" \n",
|
||||
" cursor.execute(\"select * from SampleQueryTab\") # pretend this is big\n",
|
||||
" \n",
|
||||
" while True:\n",
|
||||
" rows = cursor.fetchmany() # get a batch rows (of size cursor.arraysize=100)\n",
|
||||
" for r in rows:\n",
|
||||
" print(r)\n",
|
||||
" if len(rows) < cursor.arraysize:\n",
|
||||
" break\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## A key tuning goal is to reduce \"round-trips\"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"> \"A server round-trip is defined as the trip from the client to the server and back to the client.\"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"Round-trips affect performance and system scalability.\n",
|
||||
"\n",
|
||||
"Make every round-trip useful:\n",
|
||||
"\n",
|
||||
"- fetch multiple rows at a time\n",
|
||||
"- insert multiple rows at a time\n",
|
||||
"- don't select more data than needed\n",
|
||||
"- don't overuse commit or rollback"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Round-trip comparison - prefetchrows & arraysize\n",
|
||||
"\n",
|
||||
"Documentation reference link: [Tuning python-oracledb](https://python-oracledb.readthedocs.io/en/latest/user_guide/tuning.html)\n",
|
||||
"\n",
|
||||
"Regardless of which fetch method is used there are two tuning parameters that affect internal buffering of fetched rows. This alters the number of round-trips required to fetch all the query data from the database. These parameters do not affect how, or when, rows are returned to the application itself.\n",
|
||||
"\n",
|
||||
"Here's a demo counting round-trips:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"scrolled": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def get_session_id(connection):\n",
|
||||
" sid, = connection.cursor().execute(\"SELECT sys_context('userenv', 'sid') FROM dual\").fetchone()\n",
|
||||
" return sid\n",
|
||||
"\n",
|
||||
"def get_round_trips(systemconnection, sid):\n",
|
||||
" sql = \"\"\"SELECT ss.value\n",
|
||||
" FROM v$sesstat ss, v$statname sn\n",
|
||||
" WHERE ss.sid = :sid\n",
|
||||
" AND ss.statistic# = sn.statistic#\n",
|
||||
" AND sn.name LIKE '%roundtrip%client%'\"\"\" \n",
|
||||
" roundtrips, = systemconnection.cursor().execute(sql, [sid]).fetchone()\n",
|
||||
" return roundtrips\n",
|
||||
"\n",
|
||||
"sid = get_session_id(connection)\n",
|
||||
"\n",
|
||||
"def do_query(connection, numrows, prefetchrows, arraysize):\n",
|
||||
"\n",
|
||||
" roundtrips = get_round_trips(systemconnection, sid)\n",
|
||||
"\n",
|
||||
" with connection.cursor() as cursor:\n",
|
||||
" cursor.prefetchrows = prefetchrows\n",
|
||||
" cursor.arraysize = arraysize\n",
|
||||
" cursor.execute(\"select * from all_objects where rownum <= :nr\", [numrows])\n",
|
||||
" rows = cursor.fetchall()\n",
|
||||
"\n",
|
||||
" roundtrips = get_round_trips(systemconnection, sid) - roundtrips\n",
|
||||
"\n",
|
||||
" print(\"Number of rows: {:5}, prefetchrows {:4} arraysize {:4} roundtrips {:3} \".format(len(rows), prefetchrows, arraysize, roundtrips))\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# do_query(connection, number of rows, prefetchrows, arraysize)\n",
|
||||
"\n",
|
||||
"print(\"Default prefetch & arraysize values:\")\n",
|
||||
"do_query(connection, 1, 2, 100)\n",
|
||||
"do_query(connection, 100, 2, 100)\n",
|
||||
"do_query(connection, 1000, 2, 100)\n",
|
||||
"do_query(connection, 10000, 2, 100)\n",
|
||||
"\n",
|
||||
"print(\"\\n'Unknown' large number of rows:\")\n",
|
||||
"do_query(connection, 10000, 2, 1000)\n",
|
||||
"do_query(connection, 10000, 1000, 1000)\n",
|
||||
"\n",
|
||||
"print(\"\\n'Page' of rows:\")\n",
|
||||
"do_query(connection, 20, 20, 20)\n",
|
||||
"do_query(connection, 20, 21, 20)\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Your tuning goal is to reduce round-trips (thus improving performance) without using too much internal buffer memory.\n",
|
||||
"\n",
|
||||
"When selecting a huge number of rows, tuning `arraysize` is important. In general there is no need to set `prefetchrows` in this scenario.\n",
|
||||
"\n",
|
||||
"When selecting a known, small number of rows such as for 'paging' through a result set, then set `prefetchrows` to be one larger than the number of rows returned."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Querying LOB Columns\n",
|
||||
"\n",
|
||||
"Documentation reference link: [Using CLOB and BLOB Data](https://python-oracledb.readthedocs.io/en/latest/user_guide/lob_data.html)\n",
|
||||
"\n",
|
||||
"When fetching LOBs there are two modes that can be used:\n",
|
||||
"- Fetching as a \"locator\" for streaming use\n",
|
||||
"- Fetching directly as a string or buffer"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Fetching LOBs for streaming\n",
|
||||
"\n",
|
||||
"- this is the default\n",
|
||||
"- it requires more round trips and has more overhead\n",
|
||||
"- it is useful when very long LOBs are being used"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"with connection.cursor() as cursor:\n",
|
||||
"\n",
|
||||
" id = 1\n",
|
||||
" textData = \"The quick brown fox jumps over the lazy dog\"\n",
|
||||
" cursor.execute(\"truncate table TestClobs\")\n",
|
||||
" cursor.execute(\"insert into TestClobs (IntCol, ClobCol) values (:1, :2)\", [id, textData])\n",
|
||||
"\n",
|
||||
" cursor.execute(\"select ClobCol from TestClobs where IntCol = :ic1\", [id])\n",
|
||||
" c, = cursor.fetchone()\n",
|
||||
" print(\"CLOB length:\", c.size())\n",
|
||||
" print(\"CLOB data:\", c.read())"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Fetching CLOBs as String\n",
|
||||
"\n",
|
||||
"- this is much faster than the streaming method\n",
|
||||
"- LOBs are limited to 1 GB (and obviously must all be in memory at once)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"oracledb.defaults.fetch_lobs = False\n",
|
||||
"\n",
|
||||
"with connection.cursor() as cursor:\n",
|
||||
" id = 1\n",
|
||||
" cursor.execute(\"select ClobCol from TestClobs where IntCol = :ic2\", [id])\n",
|
||||
" c, = cursor.fetchone()\n",
|
||||
"\n",
|
||||
" print(\"CLOB length:\", len(c))\n",
|
||||
" print(\"CLOB data:\", c)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"The same `defaults` setting will return BLOBs as buffers."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Sample benchmark\n",
|
||||
"A sample benchmark shows the performance benefit of querying using the direct String method compared with using the default locator stream method. \n",
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Fetching Numbers as Decimals\n",
|
||||
"\n",
|
||||
"Oracle's NUMBER format is Decimal but Python uses floating point so there can be conversion artifacts.\n",
|
||||
"\n",
|
||||
"Documentation reference link: [Fetched Number Precision](https://python-oracledb.readthedocs.io/en/latest/user_guide/sql_execution.html#fetched-number-precision)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"with connection.cursor() as cursor:\n",
|
||||
" cursor.execute(\"select 0.1 as d1 from dual\")\n",
|
||||
" v, = cursor.fetchone()\n",
|
||||
" print('Value =', v, '\\tValue * 3 =', v * 3)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Fetching as Decimal may be useful."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import decimal\n",
|
||||
"\n",
|
||||
"oracledb.defaults.fetch_decimals = True\n",
|
||||
"\n",
|
||||
"with connection.cursor() as cursor:\n",
|
||||
" cursor.execute(\"select 0.1 as d2 from dual\")\n",
|
||||
" v, = cursor.fetchone()\n",
|
||||
" print('Value =', v, '\\tValue * 3 =', v * 3)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Multiple Values in \"WHERE ... IN\" Clauses\n",
|
||||
"\n",
|
||||
"Documentation reference link: [Binding Multiple Values to a SQL WHERE IN Clause](https://python-oracledb.readthedocs.io/en/latest/user_guide/bind.html#binding-multiple-values-to-a-sql-where-in-clause)\n",
|
||||
"\n",
|
||||
"### A fixed number of binds\n",
|
||||
"\n",
|
||||
"It's important to use bind variables for security. For small numbers of binds this is simple. One placeholder must be used for each value in the IN clause."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"sql = \"\"\"select name\n",
|
||||
" from SampleQueryTab\n",
|
||||
" where id in (:id1, :id2, :id3, :id4, :id5)\n",
|
||||
" order by id\"\"\"\n",
|
||||
"\n",
|
||||
"with connection.cursor() as cursor:\n",
|
||||
" cursor.execute(sql,\n",
|
||||
" id1=5, id2=7, id3=1, id4=3, id5=2)\n",
|
||||
" for row, in cursor:\n",
|
||||
" print(row) "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"If statements are re-executed but the number of values varies, then pass None (i.e. NULL) for 'missing' values. This lets the database execute the same statement text as before, which helps performance and scalability. "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"with connection.cursor() as cursor:\n",
|
||||
" cursor.execute(sql,\n",
|
||||
" id1=2, id2=4, id3=1, id4=None, id5=None)\n",
|
||||
" for row, in cursor:\n",
|
||||
" print(row) "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"When using character data and the size of the values varies between statement execution, then using `setinputsizes()` with the column size or maximum expected input data size can help reduce the number of SQL 'versions' of the statement used by the database optimizer, although this is not often an issue and it's not uncommon to see SQL statements with tens or low hundreds of versions.\n",
|
||||
"\n",
|
||||
"For example with the query:\n",
|
||||
"```\n",
|
||||
"sql = \"\"\"select name\n",
|
||||
" from SampleQueryTab\n",
|
||||
" where name in (:n1, :n2, :n3, :n4, :n5)\n",
|
||||
" order by id\"\"\"\n",
|
||||
"```\n",
|
||||
"the statement\n",
|
||||
"```\n",
|
||||
"cursor.setinputsizes(n1=20, n2=20, n3=20, n4=20, n5=20)\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"indicates that each value bound will be a string of no more than 20 characters."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"sql = \"\"\"select name\n",
|
||||
" from SampleQueryTab\n",
|
||||
" where name in (:n1, :n2, :n3, :n4, :n5)\n",
|
||||
" order by id\"\"\"\n",
|
||||
"\n",
|
||||
"with connection.cursor() as cursor:\n",
|
||||
" cursor.setinputsizes(n1=20, n2=20, n3=20, n4=20, n5=20)\n",
|
||||
" cursor.execute(sql,\n",
|
||||
" n1='Anthony', n2='Barbie', n3='Bogus', n4=None, n5=None)\n",
|
||||
" for row, in cursor:\n",
|
||||
" print(row) "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Dynamically creating the statement\n",
|
||||
"\n",
|
||||
"If the number of bind values is not known, and the statement is never rexecuted, you can consider dynamically creating a statement."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"bind_values = [5, 7, 1, 3, 2, 6]\n",
|
||||
"bind_names = [\":\" + str(i + 1) for i in range(len(bind_values))]\n",
|
||||
"sql = \"\"\"select name from SampleQueryTab where id in (%s)\"\"\" % (\",\".join(bind_names))\n",
|
||||
"print(sql, \"\\n\")\n",
|
||||
"with connection.cursor() as cursor:\n",
|
||||
" cursor.execute(sql, bind_values)\n",
|
||||
" for row, in cursor:\n",
|
||||
" print(row)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Binding using an Oracle type \n",
|
||||
"\n",
|
||||
"One solution when matching a huge number of values is to use the SQL `table()` clause and an Oracle type. This works for up to 32K values."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"type_obj = connection.gettype(\"SYS.ODCINUMBERLIST\")\n",
|
||||
"\n",
|
||||
"with connection.cursor() as cursor:\n",
|
||||
" obj = type_obj.newobject()\n",
|
||||
" obj.extend([3, 4, 7])\n",
|
||||
" cursor.execute(\"\"\"select name\n",
|
||||
" from SampleQueryTab\n",
|
||||
" where id in (select * from table(:1))\"\"\",\n",
|
||||
" [obj])\n",
|
||||
" for row, in cursor:\n",
|
||||
" print(row)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"The presupplied types `SYS.ODCIVARCHAR2LIST` or `SYS.ODCIDATELIST` can similarly be used for VARCHAR2 and DATE, respectively."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Accessing object type information takes a few round-trips so the earlier methods are better for small numbers of values. If you use this solution in a more complex statement, check the optimizer plan is still OK. "
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.9.6"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 4
|
||||
}
|
|
@ -0,0 +1,316 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# DML - INSERT, UPDATE, DELETE, and MERGE Statements"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import oracledb"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"un = \"pythondemo\"\n",
|
||||
"pw = \"welcome\"\n",
|
||||
"cs = \"localhost/orclpdb1\"\n",
|
||||
"\n",
|
||||
"connection = oracledb.connect(user=un, password=pw, dsn=cs)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"cursor = connection.cursor()\n",
|
||||
"cursor.execute(\"drop table mytab\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"cursor.execute(\"create table mytab (id number, data varchar2(1000))\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Binding for Insertion\n",
|
||||
"\n",
|
||||
"Documentation reference link: [Using Bind Variables](https://python-oracledb.readthedocs.io/en/latest/user_guide/bind.html)\n",
|
||||
"\n",
|
||||
"Binding is very, very important. It:\n",
|
||||
"- eliminates escaping special characters and helps prevent SQL injection attacks\n",
|
||||
"- is important for performance and scalability"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"with connection.cursor() as cursor:\n",
|
||||
" cursor.execute(\"truncate table mytab\")\n",
|
||||
"\n",
|
||||
" sql = \"insert into mytab (id, data) values (:idVal, :dataVal)\"\n",
|
||||
"\n",
|
||||
" # bind by position using a sequence (list or tuple)\n",
|
||||
" cursor.execute(sql, [1, \"String 1\"])\n",
|
||||
" cursor.execute(sql, (2, \"String 2\"))\n",
|
||||
"\n",
|
||||
" # bind by name using a dictionary\n",
|
||||
" cursor = connection.cursor()\n",
|
||||
" cursor.execute(sql, {\"idVal\": 3, \"dataVal\": \"String 3\"})\n",
|
||||
"\n",
|
||||
" # bind by name using keyword arguments\n",
|
||||
" cursor.execute(sql, idVal=4, dataVal=\"String 4\")\n",
|
||||
"\n",
|
||||
" print(\"Done\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Batch execution - Inserting multiple rows with executemany()\n",
|
||||
"\n",
|
||||
"Documentation reference link: [Executing Batch Statements and Bulk Loading](https://python-oracledb.readthedocs.io/en/latest/user_guide/batch_statement.html)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"with connection.cursor() as cursor:\n",
|
||||
" cursor.execute(\"truncate table mytab\")\n",
|
||||
"\n",
|
||||
" rows = [ (1, \"First\" ),\n",
|
||||
" (2, \"Second\" ),\n",
|
||||
" (3, \"Third\" ),\n",
|
||||
" (4, \"Fourth\" ),\n",
|
||||
" (5, \"Fifth\" ),\n",
|
||||
" (6, \"Sixth\" ),\n",
|
||||
" (7, \"Seventh\" ) ]\n",
|
||||
"\n",
|
||||
" # Using setinputsizes helps avoid memory reallocations.\n",
|
||||
" # The parameters correspond to the insert columns. \n",
|
||||
" # The value None says use python-oracledb's default size for a NUMBER column. \n",
|
||||
" # The second value is the maximum input data (or column) width for the VARCHAR2 column\n",
|
||||
" cursor.setinputsizes(None, 7)\n",
|
||||
"\n",
|
||||
" cursor.executemany(\"insert into mytab(id, data) values (:1, :2)\", rows)\n",
|
||||
"\n",
|
||||
" # Now query the results back\n",
|
||||
"\n",
|
||||
" for row in cursor.execute('select * from mytab'):\n",
|
||||
" print(row)\n",
|
||||
"\n",
|
||||
" connection.rollback()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Benchmark - executemany() vs execute()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"import time\n",
|
||||
"\n",
|
||||
"cursor = connection.cursor()\n",
|
||||
"cursor.execute(\"truncate table mytab\")\n",
|
||||
"\n",
|
||||
"# Row counts to test inserting\n",
|
||||
"numrows = (1, 5, 10, 100, 1000)\n",
|
||||
"\n",
|
||||
"longstring = \"x\" * 1000\n",
|
||||
"\n",
|
||||
"def create_data(n):\n",
|
||||
" d = []\n",
|
||||
" for i in range(n):\n",
|
||||
" d.append((i, longstring))\n",
|
||||
" return d\n",
|
||||
"\n",
|
||||
"ex = [] # seconds for execute() loop\n",
|
||||
"em = [] # seconds for executemany()\n",
|
||||
"\n",
|
||||
"for n in numrows:\n",
|
||||
" \n",
|
||||
" rows = create_data(n)\n",
|
||||
" \n",
|
||||
" ############################################################\n",
|
||||
" #\n",
|
||||
" # Loop over each row\n",
|
||||
" #\n",
|
||||
"\n",
|
||||
" start=time.time()\n",
|
||||
"\n",
|
||||
" for r in rows:\n",
|
||||
" cursor.execute(\"insert into mytab(id, data) values (:1, :2)\", r) # <==== Loop over execute()\n",
|
||||
" \n",
|
||||
" elapsed = time.time() - start\n",
|
||||
" ex.append(elapsed)\n",
|
||||
" \n",
|
||||
" r, = cursor.execute(\"select count(*) from mytab\").fetchone()\n",
|
||||
" print(\"execute() loop {:6d} rows in {:06.4f} seconds\".format(r, elapsed)) \n",
|
||||
" connection.rollback()\n",
|
||||
" \n",
|
||||
" ############################################################# \n",
|
||||
" #\n",
|
||||
" # Insert all rows in one call\n",
|
||||
" #\n",
|
||||
"\n",
|
||||
" start = time.time()\n",
|
||||
"\n",
|
||||
" cursor.executemany(\"insert into mytab(id, data) values (:1, :2)\", rows) # <==== One executemany()\n",
|
||||
" \n",
|
||||
" elapsed = time.time() - start\n",
|
||||
" em.append(elapsed)\n",
|
||||
" \n",
|
||||
" r, = cursor.execute(\"select count(*) from mytab\").fetchone()\n",
|
||||
" print(\"executemany() {:6d} rows in {:06.4f} seconds\".format(r, elapsed)) \n",
|
||||
" connection.rollback()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"print(\"Plot is:\")\n",
|
||||
"plt.xticks(numrows)\n",
|
||||
"plt.plot(numrows, ex, label=\"execute() loop\", marker=\"o\")\n",
|
||||
"plt.plot(numrows, em, label=\"one executemany()\", marker=\"o\")\n",
|
||||
"plt.xscale(\"log\")\n",
|
||||
"plt.xlabel('Number of rows')\n",
|
||||
"plt.ylabel('Seconds')\n",
|
||||
"plt.legend(loc=\"upper left\")\n",
|
||||
"plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Noisy Data - Batch Errors\n",
|
||||
"\n",
|
||||
"Dealing with bad data is easy with the `batcherrors` parameter."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"scrolled": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Initial data\n",
|
||||
"\n",
|
||||
"with connection.cursor() as cursor:\n",
|
||||
"\n",
|
||||
" for row in cursor.execute(\"select * from ParentTable order by ParentId\"):\n",
|
||||
" print(row)\n",
|
||||
"\n",
|
||||
" for row in cursor.execute(\"select * from ChildTable order by ChildId\"):\n",
|
||||
" print(row)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"dataToInsert = [\n",
|
||||
" (1016, 10, 'Child Red'),\n",
|
||||
" (1018, 20, 'Child Blue'),\n",
|
||||
" (1018, 30, 'Child Green'), # duplicate key\n",
|
||||
" (1022, 40, 'Child Yellow'),\n",
|
||||
" (1021, 75, 'Child Orange') # parent does not exist\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"with connection.cursor() as cursor:\n",
|
||||
" \n",
|
||||
" cursor.executemany(\"insert into ChildTable values (:1, :2, :3)\", dataToInsert, batcherrors=True)\n",
|
||||
" \n",
|
||||
" print(\"\\nErrors in rows that were not inserted:\\n\")\n",
|
||||
" for error in cursor.getbatcherrors():\n",
|
||||
" print(\"Error\", error.message, \"at row offset\", error.offset) \n",
|
||||
" \n",
|
||||
" print(\"\\nRows that were successfully inserted:\\n\")\n",
|
||||
" for row in cursor.execute(\"select * from ChildTable order by ChildId\"):\n",
|
||||
" print(row)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Now you can choose whether or not to fix failed records and reinsert them.\n",
|
||||
"You can then rollback or commit.\n",
|
||||
"\n",
|
||||
"This is true even if you had enabled autocommit mode - no commit will occur if there are batch errors."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"connection.rollback()"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.9.6"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 4
|
||||
}
|
|
@ -0,0 +1,261 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "04c694cd",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "b739ae65",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Loading and Unloading Data: Working with Comma Separated Values (CSV) files"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "2b027728",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"CSV is not a well-defined standard! "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "581e9486",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\"Unhelpful\" (that's a joke) suggestions for Python programmers:\n",
|
||||
"- Don't use CSV files: Keep the data in the database.\n",
|
||||
"- Don't use Excel - use Oracle APEX\n",
|
||||
"- Use Oracle Data Pump to load CSV files into Oracle Database\n",
|
||||
"<hr>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "6cb0a244",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Helpful suggestions:\n",
|
||||
"- Python's [\"csv\" module](https://docs.python.org/3/library/csv.html) has extensive reading and writing support"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "9cda404e",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import oracledb"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "1d9c084a",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"un = \"pythondemo\"\n",
|
||||
"pw = \"welcome\"\n",
|
||||
"cs = \"localhost/orclpdb1\"\n",
|
||||
"\n",
|
||||
"connection = oracledb.connect(user=un, password=pw, dsn=cs)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "3ae66a62",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Reading CSV Files and Inserting Data into Oracle Database\n",
|
||||
"\n",
|
||||
"Set up the schema:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "ed1517dd",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"with connection.cursor() as cursor:\n",
|
||||
" try:\n",
|
||||
" cursor.execute(\"drop table t\")\n",
|
||||
" except:\n",
|
||||
" ;\n",
|
||||
"\n",
|
||||
" cursor.execute(\"\"\"create table t (k number, \n",
|
||||
" first_name varchar2(30), \n",
|
||||
" last_name varchar2(30), \n",
|
||||
" country varchar2(30))\"\"\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "8dba72c1",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Data in the external CSV file looks like:\n",
|
||||
"```\n",
|
||||
"1,Fred,Nurke,UK\n",
|
||||
"2,Henry,Crun,UK\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"The Python csv module has extensive functionality. One sample is shown below. For python-oracledb users the important points are to use `executemany()` and send batches of rows to the database. Tuning in your environment will determine the best batch size."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "bace97d8",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import csv\n",
|
||||
"\n",
|
||||
"# The batch size determines how many records are inserted at a time.\n",
|
||||
"# Adjust the size to meet your memory and performance requirements.\n",
|
||||
"batch_size = 10000\n",
|
||||
"\n",
|
||||
"with connection.cursor() as cursor:\n",
|
||||
" \n",
|
||||
" sql = \"insert into t (k, first_name, last_name, country) values (:1, :2, :3, :4)\"\n",
|
||||
" \n",
|
||||
" # Predefine memory areas to match the table definition (or max data) to avoid memory re-allocs\n",
|
||||
" cursor.setinputsizes(None, 30, 30, 30)\n",
|
||||
"\n",
|
||||
" with open(\"csv/data1.csv\", \"r\") as csv_file:\n",
|
||||
" csv_reader = csv.reader(csv_file, delimiter=',')\n",
|
||||
" data = []\n",
|
||||
" for line in csv_reader:\n",
|
||||
" data.append((line[0], line[1], line[2], line[3])) # e.g [('1', 'Fred', 'Nurke', 'UK')]\n",
|
||||
" if len(data) % batch_size == 0:\n",
|
||||
" cursor.executemany(sql, data)\n",
|
||||
" data = []\n",
|
||||
" if data:\n",
|
||||
" cursor.executemany(sql, data)\n",
|
||||
" connection.commit()\n",
|
||||
"\n",
|
||||
"print(\"Done\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "4a0b4215",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Check the results\n",
|
||||
"\n",
|
||||
"with connection.cursor() as cursor:\n",
|
||||
" sql = \"select * from t order by k\"\n",
|
||||
" for r in cursor.execute(sql):\n",
|
||||
" print(r)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "7ff76bf5",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Tuning database features may also be beneficial. For example, disabling logging and/or indexes."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "08f9bc4e",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Writing CSV Files from Queried Data\n",
|
||||
"\n",
|
||||
"This example shows just one way to write CSV files. The important point for python-oracledb users is to tune `cursor.arraysize` for your data and network."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "bbc9db48",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import time\n",
|
||||
"\n",
|
||||
"sql = \"select * from all_objects where rownum <= 10000\"\n",
|
||||
"\n",
|
||||
"with connection.cursor() as cursor:\n",
|
||||
"\n",
|
||||
" start = time.time()\n",
|
||||
"\n",
|
||||
" cursor.arraysize = 1000\n",
|
||||
"\n",
|
||||
" with open(\"testwrite.csv\", \"w\", encoding=\"utf-8\") as outputfile:\n",
|
||||
" writer = csv.writer(outputfile, lineterminator=\"\\n\")\n",
|
||||
" results = cursor.execute(sql)\n",
|
||||
" writer.writerows(results)\n",
|
||||
"\n",
|
||||
" elapsed = time.time() - start\n",
|
||||
" print(\"Writing CSV: 10000 rows in {:06.4f} seconds\".format(elapsed)) "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "7b3ddf5e",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"If you change the arraysize and rerun the cell, the time taken may vary."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "62a7ecfe",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Confirm the number of lines in the output file is correct\n",
|
||||
"\n",
|
||||
"import os\n",
|
||||
"\n",
|
||||
"r = os.system(\"wc -l testwrite.csv\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "e812be8c-339e-4f14-9b5b-1ea5163cee93",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.9.6"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
|
@ -0,0 +1,206 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "a9825ce4",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "7b00c7cf",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Working with JSON Data\n",
|
||||
"\n",
|
||||
"Documentation reference link: [Using JSON Data](https://python-oracledb.readthedocs.io/en/latest/user_guide/json_data_type.html)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "4933ee95",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import oracledb"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "1e091ca8",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"un = \"pythondemo\"\n",
|
||||
"pw = \"welcome\"\n",
|
||||
"cs = \"localhost/orclpdb1\"\n",
|
||||
"\n",
|
||||
"connection = oracledb.connect(user=un, password=pw, dsn=cs)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "a81ba26a",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### JSON Storage:\n",
|
||||
"\n",
|
||||
"- Oracle Database 12c introduced JSON stored as a LOB or VARCHAR2\n",
|
||||
"\n",
|
||||
"- Oracle Database 21c a new optimized native binary format and a dedicated JSON type\n",
|
||||
"\n",
|
||||
"**Careful coding is required for apps that run in a mixed version environment**\n",
|
||||
"\n",
|
||||
"The first JSON example assumes you are Oracle Database 21c or later.\n",
|
||||
"\n",
|
||||
"Setup the schema:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "caa04809",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"with connection.cursor() as cursor:\n",
|
||||
" try:\n",
|
||||
" cursor.execute(\"drop table customers\")\n",
|
||||
" except:\n",
|
||||
" ;\n",
|
||||
" cursor.execute(\"create table customers (k number, json_data json)\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "a84dfaeb",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"With Oracle Database 21c or later, you can bind Python objects directly to the JSON column:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "e14826f4",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import datetime\n",
|
||||
"\n",
|
||||
"json_data = [\n",
|
||||
" 2.78,\n",
|
||||
" True,\n",
|
||||
" 'Ocean Beach',\n",
|
||||
" b'Some bytes',\n",
|
||||
" {'keyA': 1, 'KeyB': 'Melbourne'},\n",
|
||||
" datetime.date.today()\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"with connection.cursor() as cursor:\n",
|
||||
" cursor.setinputsizes(oracledb.DB_TYPE_JSON)\n",
|
||||
" cursor.execute(\"insert into customers (k, json_data) values (1, :jbv)\", [json_data])\n",
|
||||
" \n",
|
||||
"print(\"Done\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "c21d71e3",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Querying returns the JSON in a familiar Python data structure:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "d84a494d",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"with connection.cursor() as cursor:\n",
|
||||
" for row, in cursor.execute(\"select c.json_data from customers c where k = 1\"):\n",
|
||||
" print(row)\n",
|
||||
" \n",
|
||||
"# With Oracle Database 21c or later, this gives:\n",
|
||||
"# [Decimal('2.78'), True, 'Ocean Beach', b'Some bytes', {'keyA': Decimal('1'), 'KeyB': 'Melbourne'}, datetime.datetime(2022, 3, 4, 0, 0)]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "e18fc3b4",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"If you don't have a recent database, then you can still easily work with JSON. Store it using BLOB and work with JSON strings. The Python \"json\" package can be used with many Python types:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "a54a7bca-c8d9-4f47-89a2-edaf6ada0a44",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import json\n",
|
||||
"\n",
|
||||
"with connection.cursor() as cursor:\n",
|
||||
" try:\n",
|
||||
" cursor.execute(\"drop table customersblob\")\n",
|
||||
" except:\n",
|
||||
" ;\n",
|
||||
" cursor.execute(\"\"\"create table customersblob (k number, \n",
|
||||
" json_data blob check (json_data is json)) \n",
|
||||
" lob (json_data) store as (cache)\"\"\")\n",
|
||||
" \n",
|
||||
"# INSERT\n",
|
||||
"\n",
|
||||
"with connection.cursor() as cursor:\n",
|
||||
" data = json_data = [\n",
|
||||
" 2.78,\n",
|
||||
" True,\n",
|
||||
" 'Ocean Beach',\n",
|
||||
" {'keyA': 1, 'KeyB': 'Melbourne'},\n",
|
||||
" ]\n",
|
||||
" cursor.execute(\"insert into customersblob (k, json_data) values (2, :jbv)\", [json.dumps(data)])\n",
|
||||
" \n",
|
||||
"# FETCH\n",
|
||||
"\n",
|
||||
"# Allow the BLOB column to be automatically recognized as storing JSON and not as storing arbitrary binary data.\n",
|
||||
"# Without this, you would need to use the Python json package on the returned row.\n",
|
||||
"oracledb.__future__.old_json_col_as_obj = True\n",
|
||||
"\n",
|
||||
"with connection.cursor() as cursor:\n",
|
||||
" for row, in cursor.execute(\"SELECT c.json_data FROM customersblob c where k = 2\"):\n",
|
||||
" print(row)\n",
|
||||
" \n",
|
||||
"connection.rollback() "
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.9.6"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
|
@ -0,0 +1,293 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Calling PL/SQL\n",
|
||||
"\n",
|
||||
"Documentation reference link: [Executing PL/SQL](https://python-oracledb.readthedocs.io/en/latest/user_guide/plsql_execution.html)\n",
|
||||
"\n",
|
||||
"PL/SQL is a 'stored' procedural language that is stored and run inside the database itself. PL/SQL lets you capture business logic for reuse across all your applications. You can call stored procedures and functions easily from python-oracledb."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import oracledb"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"un = \"pythondemo\"\n",
|
||||
"pw = \"welcome\"\n",
|
||||
"cs = \"localhost/orclpdb1\"\n",
|
||||
"\n",
|
||||
"connection = oracledb.connect(user=un, password=pw, dsn=cs)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## PL/SQL Procedures\n",
|
||||
"\n",
|
||||
"This shows the PL/SQL procedure `MYPROC` used in this demo:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"with connection.cursor() as cursor:\n",
|
||||
" \n",
|
||||
" cursor.execute(\"select dbms_metadata.get_ddl('PROCEDURE', 'MYPROC') from dual\")\n",
|
||||
" ddl, = cursor.fetchone()\n",
|
||||
" print(ddl.read())"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"You can use `callproc()` to call the procedure. Bind variables are passed by position:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"with connection.cursor() as cursor:\n",
|
||||
"\n",
|
||||
" myinvar = 22\n",
|
||||
" myoutvar = cursor.var(int) # allocate a 'variable' of integer type to hold the OUT bind parameter\n",
|
||||
"\n",
|
||||
" cursor.callproc('myproc', [myinvar, myoutvar])\n",
|
||||
" print(myoutvar.getvalue())"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"You can also call PL/SQL procedures via an 'anonymous' PL/SQL block. This can be useful if you want to use named bind placeholders:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"with connection.cursor() as cursor:\n",
|
||||
"\n",
|
||||
" myinvar = 33\n",
|
||||
" myoutvar = cursor.var(int)\n",
|
||||
"\n",
|
||||
" cursor.execute(' begin myproc(:v1, :v2); end;', {\"v1\": myinvar, \"v2\": myoutvar})\n",
|
||||
" print(myoutvar.getvalue())"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## PL/SQL Functions\n",
|
||||
"\n",
|
||||
"This shows the PL/SQL function `MYFUNC` used in this demo:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"with connection.cursor() as cursor:\n",
|
||||
" \n",
|
||||
" cursor.execute(\"select dbms_metadata.get_ddl('FUNCTION', 'MYFUNC') from dual\")\n",
|
||||
" ddl, = cursor.fetchone()\n",
|
||||
" print(ddl.read())"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"You can use `callfunc()` to call the function. Bind variables are passed by position. The second argument to `callfunc()` is the type of the PL/SQL function return value. Here it is an integer:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"with connection.cursor() as cursor:\n",
|
||||
"\n",
|
||||
" data = \"abc\"\n",
|
||||
" id = 3\n",
|
||||
" res = cursor.callfunc('myfunc', int, (data, id))\n",
|
||||
" print(res)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Similar to calling PL/SQL procedures, you can also invoke PL/SQL procedures via an anonymous block, and optionally used named bind placeholders:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"with connection.cursor() as cursor:\n",
|
||||
"\n",
|
||||
" data = \"def\"\n",
|
||||
" id = 4\n",
|
||||
" ret = cursor.var(int)\n",
|
||||
"\n",
|
||||
" cursor.execute(' begin :ret := myfunc(:data, :id); end;', {\"ret\": ret, \"data\": data, \"id\": id})\n",
|
||||
" print(ret.getvalue())"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## REF CURSORS\n",
|
||||
"\n",
|
||||
"REF CURSORS let result sets be returned to python-oracledb, commonly from PL/SQL.\n",
|
||||
"\n",
|
||||
"Here is the PL/SQL procedure used in this example:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"scrolled": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"with connection.cursor() as cursor:\n",
|
||||
"\n",
|
||||
" cursor.execute(\"\"\"select text from all_source \n",
|
||||
" where name = 'MYREFCURSORPROC' and type = 'PROCEDURE' \n",
|
||||
" order by line\"\"\")\n",
|
||||
" rows = cursor.fetchall()\n",
|
||||
" for r, in rows:\n",
|
||||
" print(r, end=\"\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Use `callproc()` as shown before to call the PL/SQL procedure. The `ref_cursor` variable needs to be defined as a cursor so it can hold the returned REF CURSOR. This second cursor is then simply iterated over exactly like a cursor for simple SELECT would be:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"with connection.cursor() as cursor:\n",
|
||||
" ref_cursor = connection.cursor()\n",
|
||||
"\n",
|
||||
" cursor.callproc(\"myrefcursorproc\", (2, 6, ref_cursor))\n",
|
||||
"\n",
|
||||
" print(\"Rows between 2 and 6:\")\n",
|
||||
" for row in ref_cursor:\n",
|
||||
" print(row)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Implicit Cursors\n",
|
||||
"\n",
|
||||
"Instead of binding a cursor to get a REF CURSOR, the `dbms_sql.return_result()` procedure can alternatively return a result set back which is fetched in python-oracledb using `getimplicitresults()`:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"with connection.cursor() as cursor:\n",
|
||||
"\n",
|
||||
" cursor.execute(\"\"\"\n",
|
||||
" declare\n",
|
||||
" c1 sys_refcursor;\n",
|
||||
" c2 sys_refcursor;\n",
|
||||
" begin\n",
|
||||
" open c1 for\n",
|
||||
" select * from ParentTable;\n",
|
||||
" dbms_sql.return_result(c1);\n",
|
||||
"\n",
|
||||
" open c2 for\n",
|
||||
" select * from ChildTable;\n",
|
||||
" dbms_sql.return_result(c2);\n",
|
||||
" end;\"\"\")\n",
|
||||
"\n",
|
||||
" for resultSet in cursor.getimplicitresults():\n",
|
||||
" print(\"Result Set:\")\n",
|
||||
" for row in resultSet:\n",
|
||||
" print(row)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.9.6"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 4
|
||||
}
|
|
@ -0,0 +1,392 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Oracle Database Objects and Collections\n",
|
||||
"\n",
|
||||
"Documentation reference link: [Fetching Oracle Database Objects and Collections](https://python-oracledb.readthedocs.io/en/latest/user_guide/sql_execution.html#fetching-oracle-database-objects-and-collections)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import oracledb"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"un = \"pythondemo\"\n",
|
||||
"pw = \"welcome\"\n",
|
||||
"cs = \"localhost/orclpdb1\"\n",
|
||||
"\n",
|
||||
"connection = oracledb.connect(user=un, password=pw, dsn=cs)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Binding Named Objects\n",
|
||||
"\n",
|
||||
"Create a demonstration table. This table uses the predefined SDO_GEOMETRY object which stores spatial information:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"with connection.cursor() as cursor:\n",
|
||||
" try:\n",
|
||||
" cursor.execute(\"drop table TestGeometry\")\n",
|
||||
" except:\n",
|
||||
" ;\n",
|
||||
" \n",
|
||||
" cursor.execute(\"\"\"create table TestGeometry (\n",
|
||||
" IntCol number(9) not null,\n",
|
||||
" Geometry sdo_geometry not null)\"\"\")\n",
|
||||
" \n",
|
||||
"print(\"Done\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Using python-oracledb functions like `gettype()` and `extend()` you can create a Python representation of the database object:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"with connection.cursor() as cursor:\n",
|
||||
" \n",
|
||||
" typeObj = connection.gettype(\"SDO_GEOMETRY\")\n",
|
||||
" elementInfoTypeObj = connection.gettype(\"SDO_ELEM_INFO_ARRAY\")\n",
|
||||
" ordinateTypeObj = connection.gettype(\"SDO_ORDINATE_ARRAY\")\n",
|
||||
"\n",
|
||||
" obj = typeObj() # Alternatively use 'obj = typeObj.newobject()''\n",
|
||||
" obj.SDO_GTYPE = 2003\n",
|
||||
" obj.SDO_ELEM_INFO = elementInfoTypeObj()\n",
|
||||
" obj.SDO_ELEM_INFO.extend([1, 1003, 3])\n",
|
||||
" obj.SDO_ORDINATES = ordinateTypeObj()\n",
|
||||
" obj.SDO_ORDINATES.extend([1, 1, 5, 7])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Calling `gettype()` requires multiple round-trips to the database, so avoid calling it unnecessarily."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"The new object can be bound directly for insertion:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"with connection.cursor() as cursor:\n",
|
||||
" cursor.execute(\"insert into TestGeometry values (1, :objbv)\", {\"objbv\": obj})\n",
|
||||
" \n",
|
||||
"print(\"Done\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"And then fetched back:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"with connection.cursor() as cursor:\n",
|
||||
" for (id, obj) in cursor.execute(\"select IntCol, Geometry from testgeometry\"):\n",
|
||||
" print(id, obj)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Simple attribute access is easy:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"with connection.cursor() as cursor:\n",
|
||||
" for (id, obj) in cursor.execute(\"select IntCol, Geometry from testgeometry\"):\n",
|
||||
" print(\"SDO_GTYPE is\", obj.SDO_GTYPE)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
" To display all attributes, create a helper function:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Oracle Database object dumper\n",
|
||||
"\n",
|
||||
"def dumpobject(obj, prefix = \" \"):\n",
|
||||
" if obj.type.iscollection:\n",
|
||||
" print(prefix, \"[\")\n",
|
||||
" for value in obj.aslist():\n",
|
||||
" if isinstance(value, oracledb.Object):\n",
|
||||
" dumpobject(value, prefix + \" \")\n",
|
||||
" else:\n",
|
||||
" print(prefix + \" \", repr(value))\n",
|
||||
" print(prefix, \"]\")\n",
|
||||
" else:\n",
|
||||
" print(prefix, \"{\")\n",
|
||||
" for attr in obj.type.attributes:\n",
|
||||
" value = getattr(obj, attr.name)\n",
|
||||
" if isinstance(value, oracledb.Object):\n",
|
||||
" print(prefix + \" \" + attr.name + \" :\")\n",
|
||||
" dumpobject(value, prefix + \" \")\n",
|
||||
" else:\n",
|
||||
" print(prefix + \" \" + attr.name + \" :\", repr(value))\n",
|
||||
" print(prefix, \"}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Using the helper function shows the full object structure:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"with connection.cursor() as cursor:\n",
|
||||
" for (id, obj) in cursor.execute(\"select IntCol, Geometry from testgeometry\"):\n",
|
||||
" print(\"Id: \", id)\n",
|
||||
" dumpobject(obj)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# PL/SQL Collections\n",
|
||||
"\n",
|
||||
"The sample schema uses PL/SQL collections"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"cursor = connection.cursor()\n",
|
||||
"\n",
|
||||
"cursor.execute(\"select dbms_metadata.get_ddl('PACKAGE', 'PKG_DEMO') from dual\")\n",
|
||||
"ddl, = cursor.fetchone()\n",
|
||||
"print(ddl.read())"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"To get a collection, create a Python variable with the database object type:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"typeObj = connection.gettype(\"PKG_DEMO.UDT_STRINGLIST\")\n",
|
||||
"obj = typeObj()\n",
|
||||
"\n",
|
||||
"# call the stored procedure which will populate the object\n",
|
||||
"cursor = connection.cursor()\n",
|
||||
"cursor.callproc(\"pkg_Demo.DemoCollectionOut\", (obj,))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"To show the collection indexes and values:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"ix = obj.first()\n",
|
||||
"while ix is not None:\n",
|
||||
" print(ix, \"->\", obj.getelement(ix))\n",
|
||||
" ix = obj.next(ix)\n",
|
||||
"print()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Show the values as a simple list:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print(obj.aslist())"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Show the values as a simple dictionary:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print(obj.asdict())"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Binding PL/SQL Records\n",
|
||||
"\n",
|
||||
"Create a new Python object of the correct type and set attribute values:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import datetime\n",
|
||||
"\n",
|
||||
"typeObj = connection.gettype(\"PKG_DEMO.UDT_DEMORECORD\")\n",
|
||||
"obj = typeObj()\n",
|
||||
"\n",
|
||||
"obj.NUMBERVALUE = 6\n",
|
||||
"obj.STRINGVALUE = \"Test String\"\n",
|
||||
"obj.DATEVALUE = datetime.datetime(2016, 5, 28)\n",
|
||||
"obj.BOOLEANVALUE = False"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Call the stored procedure which will modify the object:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"with connection.cursor() as cursor:\n",
|
||||
" cursor.callproc(\"pkg_Demo.DemoRecordsInOut\", (obj,))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Show the modified values:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print(\"NUMBERVALUE ->\", obj.NUMBERVALUE)\n",
|
||||
"print(\"STRINGVALUE ->\", obj.STRINGVALUE)\n",
|
||||
"print(\"DATEVALUE ->\", obj.DATEVALUE)\n",
|
||||
"print(\"BOOLEANVALUE ->\", obj.BOOLEANVALUE)"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.9.6"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 4
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
# Python python-oracledb Notebooks
|
||||
|
||||
This directory contains Jupyter notebooks showing best practices for using
|
||||
python-oracledb. The notebooks cover:
|
||||
|
||||
- Connecting
|
||||
- Queries
|
||||
- DML
|
||||
- Data loading and unloading (CSV Files)
|
||||
- JSON
|
||||
- PL/SQL
|
||||
- Objects
|
||||
|
||||
Python-oracledb's default 'Thin' mode is used.
|
||||
|
||||
Jupyter notebooks let you easily step through, modify, and execute Python code:
|
||||
|
||||

|
||||
|
||||
# Setup
|
||||
|
||||
An existing Oracle Database is required. The JSON demo assumes that Oracle
|
||||
Database 21c or later is being used.
|
||||
|
||||
### Install Python 3
|
||||
|
||||
See https://www.python.org/downloads/
|
||||
|
||||
### Install Jupyter
|
||||
|
||||
See https://jupyter.org/install:
|
||||
|
||||
python3 -m pip install notebook
|
||||
|
||||
### Install the python-oracledb driver
|
||||
|
||||
python3 -m pip install oracledb
|
||||
|
||||
### Install some libraries used by the examples
|
||||
|
||||
python3 -m pip install numpy matplotlib
|
||||
|
||||
### Create the python-oracledb sample schema
|
||||
|
||||
Clone the python-oracledb repository, for example in a terminal window:
|
||||
|
||||
git clone https://github.com/oracle/python-oracledb.git
|
||||
|
||||
cd python-oracledb/samples
|
||||
|
||||
Review README.md and sample_env.py
|
||||
|
||||
In the terminal, set desired credentials, for example:
|
||||
|
||||
export PYO_SAMPLES_ADMIN_USER=system
|
||||
export PYO_SAMPLES_ADMIN_PASSWORD=oracle
|
||||
export PYO_SAMPLES_CONNECT_STRING=localhost/orclpdb1
|
||||
export PYO_SAMPLES_MAIN_USER=pythondemo
|
||||
export PYO_SAMPLES_MAIN_PASSWORD=welcome
|
||||
export PYO_SAMPLES_EDITION_USER=pythoneditions
|
||||
export PYO_SAMPLES_EDITION_PASSWORD=welcome
|
||||
export PYO_SAMPLES_EDITION_NAME=python_e1
|
||||
|
||||
Install the schema:
|
||||
|
||||
python3 create_schema.py
|
||||
|
||||
### Start Jupyter
|
||||
|
||||
cd sample_notebooks
|
||||
jupyter notebook
|
||||
|
||||
If Jupyter is not in your path, you may need to find it on your computer and
|
||||
invoke it with an absolute path, for example on macOS:
|
||||
|
||||
$HOME/Library/Python/3.9/bin/jupyter notebook
|
||||
|
||||
Load each notebook *.ipynb file and step through the cells.
|
||||
|
||||
Before running the notebooks cells, edit the credentials and connect string
|
||||
near the top of each notebook to match those used when installing the sample
|
||||
schema.
|
|
@ -0,0 +1,2 @@
|
|||
1,Fred,Nurke,UK
|
||||
2,Henry,Crun,UK
|
|
After Width: | Height: | Size: 261 KiB |
After Width: | Height: | Size: 37 KiB |
After Width: | Height: | Size: 184 KiB |
After Width: | Height: | Size: 239 KiB |
After Width: | Height: | Size: 372 KiB |
After Width: | Height: | Size: 109 KiB |
After Width: | Height: | Size: 56 KiB |
After Width: | Height: | Size: 130 KiB |
After Width: | Height: | Size: 47 KiB |
|
@ -58,16 +58,16 @@ STMT_TYPE_SQLPLUS = 3 # Like SET or DESC
|
|||
|
||||
# Simple regexps for statement type identification
|
||||
SQL_PATTERN = re.compile(
|
||||
r"^(administer|alter|analyze|associate|audit|call|comment|commit|create"
|
||||
"^(administer|alter|analyze|associate|audit|call|comment|commit|create"
|
||||
"|delete|disassociate|drop|explain|flashback|grant|insert|lock|merge"
|
||||
"|noaudit|purge|rename|revoke|rollback|savepoint|select|truncate|update"
|
||||
"|with|set\s+constraint[s*]|set\s+role|set\s+transaction)(\s|$|;)",
|
||||
r"|with|set\s+constraint[s*]|set\s+role|set\s+transaction)(\s|$|;)",
|
||||
re.IGNORECASE,
|
||||
)
|
||||
|
||||
PLSQL_PATTERN = re.compile(
|
||||
r"^(begin|declare|create\s+or\s+replace|create\s+function"
|
||||
"|create\s+procedure|create\s+package|create\s+type)(\s|$)",
|
||||
r"|create\s+procedure|create\s+package|create\s+type)(\s|$)",
|
||||
re.IGNORECASE,
|
||||
)
|
||||
|
||||
|
@ -83,7 +83,7 @@ SQLPLUS_PATTERN = re.compile(
|
|||
"|(repf(o?|oo?|oot?|oote?|ooter?))|(reph(e?|ea?|ead?|eade?|eader?))"
|
||||
"|(r(u?|un?))|(sav(e?))|set|(sho(w?))|shutdown|(spo(o?|ol?))|(sta(r?|rt?))"
|
||||
"|startup|store|(timi(n?|ng?))|(tti(t?|tl?|tle?))|(undef(i?|in?|ine?))"
|
||||
"|(var(i?|ia?|iab?|iabl?|iable?))|whenever|xquery|--.*)(\s|$)",
|
||||
r"|(var(i?|ia?|iab?|iabl?|iable?))|whenever|xquery|--.*)(\s|$)",
|
||||
re.IGNORECASE,
|
||||
)
|
||||
|
||||
|
@ -161,10 +161,13 @@ def execute_db_statement(connection, statement, statement_type):
|
|||
with connection.cursor() as cursor:
|
||||
try:
|
||||
cursor.execute(statement)
|
||||
if cursor.warning:
|
||||
print(cursor.warning)
|
||||
if statement_type == STMT_TYPE_SQL and QUERY_PATTERN.match(
|
||||
statement
|
||||
):
|
||||
fetch_rows(cursor)
|
||||
|
||||
except oracledb.Error as e:
|
||||
(error,) = e.args
|
||||
print(statement)
|
||||
|
|