Compare commits
13 Commits
Author | SHA1 | Date |
---|---|---|
![]() |
ec62806c18 | |
![]() |
33f4093ad1 | |
![]() |
cd70b4474b | |
![]() |
104ec0331b | |
![]() |
23af6a748e | |
![]() |
7076712234 | |
![]() |
ecd8956d42 | |
![]() |
d73e43acad | |
![]() |
cc52daf97b | |
![]() |
cebde524d0 | |
![]() |
b07a524373 | |
![]() |
1d1e17144d | |
![]() |
ace0d52ce7 |
|
@ -2387,7 +2387,7 @@ version of python-oracledb.
|
||||||
|
|
||||||
.. data:: NCHAR
|
.. data:: NCHAR
|
||||||
|
|
||||||
A synonym for :data:`DB_TYPE_NVARCHAR`.
|
A synonym for :data:`DB_TYPE_NCHAR`.
|
||||||
|
|
||||||
.. deprecated:: cx_Oracle 8.0
|
.. deprecated:: cx_Oracle 8.0
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ root_doc = master_doc = 'index'
|
||||||
|
|
||||||
# General substitutions.
|
# General substitutions.
|
||||||
project = 'python-oracledb'
|
project = 'python-oracledb'
|
||||||
copyright = u'2016, 2022, Oracle and/or its affiliates. All rights reserved. Portions Copyright © 2007-2015, Anthony Tuininga. All rights reserved. Portions Copyright © 2001-2007, Computronix (Canada) Ltd., Edmonton, Alberta, Canada. All rights reserved'
|
copyright = u'2016, 2023, Oracle and/or its affiliates. All rights reserved. Portions Copyright © 2007-2015, Anthony Tuininga. All rights reserved. Portions Copyright © 2001-2007, Computronix (Canada) Ltd., Edmonton, Alberta, Canada. All rights reserved'
|
||||||
author = 'Oracle'
|
author = 'Oracle'
|
||||||
|
|
||||||
# The default replacements for |version| and |release|, also used in various
|
# The default replacements for |version| and |release|, also used in various
|
||||||
|
|
|
@ -10,7 +10,7 @@ License
|
||||||
|
|
||||||
.. centered:: **LICENSE AGREEMENT FOR python-oracledb**
|
.. centered:: **LICENSE AGREEMENT FOR python-oracledb**
|
||||||
|
|
||||||
Copyright |copy| 2016, 2022 Oracle and/or its affiliates.
|
Copyright |copy| 2016, 2023 Oracle and/or its affiliates.
|
||||||
|
|
||||||
This software is dual-licensed to you under the Universal Permissive License
|
This software is dual-licensed to you under the Universal Permissive License
|
||||||
(UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
(UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
||||||
|
|
|
@ -7,6 +7,37 @@ python-oracledb Release Notes
|
||||||
|
|
||||||
For deprecations, see :ref:`Deprecations <deprecations>`.
|
For deprecations, see :ref:`Deprecations <deprecations>`.
|
||||||
|
|
||||||
|
oracledb 1.2.2 (January 2023)
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
Thin Mode Changes
|
||||||
|
+++++++++++++++++
|
||||||
|
|
||||||
|
#) Any exception raised while finding the operating system user for database
|
||||||
|
logging is now ignored (`issue 112
|
||||||
|
<https://github.com/oracle/python-oracledb/issues/112>`__).
|
||||||
|
#) Fixed bug when binding OUT a NULL boolean value.
|
||||||
|
(`issue 119 <https://github.com/oracle/python-oracledb/issues/119>`__).
|
||||||
|
#) Fixed bug when getting a record type based on a table (%ROWTYPE)
|
||||||
|
(`issue 123 <https://github.com/oracle/python-oracledb/issues/123>`__).
|
||||||
|
#) Fixed bug when using a `select * from table` query and columns are added to
|
||||||
|
the table
|
||||||
|
(`issue 125 <https://github.com/oracle/python-oracledb/issues/125>`__).
|
||||||
|
|
||||||
|
Thick Mode Changes
|
||||||
|
++++++++++++++++++
|
||||||
|
|
||||||
|
#) Fixed bug when attempting to create bequeath connections to a local
|
||||||
|
database
|
||||||
|
(`issue 114 <https://github.com/oracle/python-oracledb/issues/114>`__).
|
||||||
|
|
||||||
|
Common Changes
|
||||||
|
++++++++++++++
|
||||||
|
|
||||||
|
#) Fixed bug when attempting to populate an array variable with too many
|
||||||
|
elements.
|
||||||
|
|
||||||
|
|
||||||
oracledb 1.2.1 (December 2022)
|
oracledb 1.2.1 (December 2022)
|
||||||
------------------------------
|
------------------------------
|
||||||
|
|
||||||
|
|
|
@ -215,3 +215,22 @@ To convert dates:
|
||||||
for row in cursor:
|
for row in cursor:
|
||||||
print(row) # gives 'Mi 15 Dez 19:57:56 2021'
|
print(row) # gives 'Mi 15 Dez 19:57:56 2021'
|
||||||
print()
|
print()
|
||||||
|
|
||||||
|
Inserting NVARCHAR2 and NCHAR Data
|
||||||
|
----------------------------------
|
||||||
|
|
||||||
|
To bind NVARCHAR2 data, use :func:`Cursor.setinputsizes()` or create a bind
|
||||||
|
variable with the correct type by calling :func:`Cursor.var()`. This removes
|
||||||
|
an internal character set conversion to the standard `Database Character Set`_
|
||||||
|
that may corrupt data. By binding as :data:`oracledb.DB_TYPE_NVARCHAR`, the
|
||||||
|
data is inserted directly as the `Database National Character Set`_. For
|
||||||
|
example, to insert into a table containing two NVARCHAR2 columns:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
sql = "insert into mytable values (:1, :2)"
|
||||||
|
bv = ['data1', 'data2']
|
||||||
|
cursor.setinputsizes(oracledb.DB_TYPE_NVARCHAR, oracledb.DB_TYPE_NVARCHAR)
|
||||||
|
cursor.execute(sql, bv)
|
||||||
|
|
||||||
|
For NCHAR data, bind as :data:`oracledb.DB_TYPE_NCHAR`.
|
||||||
|
|
|
@ -32,7 +32,8 @@ upgrading a cx_Oracle application to python-oracledb, then refer to
|
||||||
|
|
||||||
All connections in an application use the same mode.
|
All connections in an application use the same mode.
|
||||||
|
|
||||||
Once the Thick mode is enabled, you cannot go back to Thin mode.
|
Once the Thick mode is enabled, you cannot go back to Thin mode except by
|
||||||
|
restarting the application.
|
||||||
|
|
||||||
Enabling the python-oracledb Thick mode loads Oracle Client libraries which
|
Enabling the python-oracledb Thick mode loads Oracle Client libraries which
|
||||||
handle communication to your database. The Oracle Client libraries need to be
|
handle communication to your database. The Oracle Client libraries need to be
|
||||||
|
@ -43,9 +44,9 @@ installed separately. See :ref:`installation`.
|
||||||
|
|
||||||
Architecture of the python-oracledb driver in Thick mode
|
Architecture of the python-oracledb driver in Thick mode
|
||||||
|
|
||||||
You can validate the python-oracledb mode by querying the ``CLIENT_DRIVER``
|
You can validate python-oracledb is running in Thick mode by querying the
|
||||||
column of ``V$SESSION_CONNECT_INFO`` and verifying the value of the column
|
``CLIENT_DRIVER`` column of ``V$SESSION_CONNECT_INFO`` and verifying the value
|
||||||
begins with ``python-oracledb thk``. See :ref:`vsessconinfo`.
|
of the column begins with ``python-oracledb thk``. See :ref:`vsessconinfo`.
|
||||||
|
|
||||||
|
|
||||||
.. _libinit:
|
.. _libinit:
|
||||||
|
@ -54,26 +55,35 @@ Setting the Oracle Client Library Directory
|
||||||
-------------------------------------------
|
-------------------------------------------
|
||||||
|
|
||||||
When :meth:`~oracledb.init_oracle_client()` is called, python-oracledb
|
When :meth:`~oracledb.init_oracle_client()` is called, python-oracledb
|
||||||
dynamically loads Oracle Client libraries using a search heuristic. Only the
|
dynamically loads Oracle Client libraries using a search heuristic. The
|
||||||
first set of libraries found are loaded. The libraries can be:
|
libraries can be:
|
||||||
|
|
||||||
- in an installation of Oracle Instant Client
|
- in an installation of Oracle Instant Client
|
||||||
- or in a full Oracle Client installation
|
- or in a full Oracle Client installation
|
||||||
- or in an Oracle Database installation (if Python is running on the same
|
- or in an Oracle Database installation (if Python is running on the same
|
||||||
machine as the database).
|
machine as the database).
|
||||||
|
|
||||||
The versions of Oracle Client and Oracle Database do not have
|
|
||||||
to be the same. For certified configurations see Oracle Support's `Doc ID
|
|
||||||
207303.1
|
|
||||||
<https://support.oracle.com/epmos/faces/DocumentDisplay?id=207303.1>`__.
|
|
||||||
|
|
||||||
See :ref:`installation` for information about installing Oracle Client
|
See :ref:`installation` for information about installing Oracle Client
|
||||||
libraries.
|
libraries.
|
||||||
|
|
||||||
|
The versions of Oracle Client libraries and Oracle Database do not have to be
|
||||||
|
the same. For certified configurations see Oracle Support's `Doc ID 207303.1
|
||||||
|
<https://support.oracle.com/epmos/faces/DocumentDisplay?id=207303.1>`__.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
If Oracle Client libraries cannot be loaded then
|
||||||
|
:meth:`~oracledb.init_oracle_client()` will raise an error ``DPI-1047:
|
||||||
|
Oracle Client library cannot be loaded``. To resolve this, review the
|
||||||
|
platform-specific instructions below or see :ref:`runtimetroubleshooting`.
|
||||||
|
Alternatively remove the call to :meth:`~oracledb.init_oracle_client()` and
|
||||||
|
use Thin mode. The features supported by Thin mode can be found in
|
||||||
|
:ref:`driverdiff`.
|
||||||
|
|
||||||
.. _wininit:
|
.. _wininit:
|
||||||
|
|
||||||
Setting the Oracle Client Directory on Windows
|
Setting the Oracle Client Library Directory on Windows
|
||||||
++++++++++++++++++++++++++++++++++++++++++++++
|
++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
|
||||||
On Windows, python-oracledb Thick mode can be enabled as follows:
|
On Windows, python-oracledb Thick mode can be enabled as follows:
|
||||||
|
|
||||||
|
@ -121,8 +131,8 @@ On Windows, python-oracledb Thick mode can be enabled as follows:
|
||||||
|
|
||||||
.. _macinit:
|
.. _macinit:
|
||||||
|
|
||||||
Setting the Oracle Client Directory on macOS
|
Setting the Oracle Client Library Directory on macOS
|
||||||
++++++++++++++++++++++++++++++++++++++++++++
|
++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
|
||||||
On macOS, python-oracledb Thick mode can be enabled as follows:
|
On macOS, python-oracledb Thick mode can be enabled as follows:
|
||||||
|
|
||||||
|
@ -154,14 +164,33 @@ On macOS, python-oracledb Thick mode can be enabled as follows:
|
||||||
'Basic' or 'Basic Light' package, or a symbolic link to the main Oracle
|
'Basic' or 'Basic Light' package, or a symbolic link to the main Oracle
|
||||||
Client library if Instant Client is in a different directory.
|
Client library if Instant Client is in a different directory.
|
||||||
|
|
||||||
You can find the directory containing the Thick mode binary module by
|
You can find the directory containing the Thick mode binary module by calling
|
||||||
calling the python CLI without specifying a Python script, executing
|
the python CLI without specifying a Python script, executing ``import
|
||||||
``import oracledb``, and then typing ``oracledb`` at the prompt. For
|
oracledb``, and then typing ``oracledb`` at the prompt. For example this
|
||||||
example if
|
might show
|
||||||
``/Users/yourname/Library/3.9.6/lib/python3.9/site-packages/oracledb-1.0.0-py3.9-macosx-11.5-x86_64.egg/oracledb``
|
``/Users/yourname/.pyenv/versions/3.9.6/lib/python3.9/site-packages/oracledb/__init__.py``.
|
||||||
contains ``thick_impl.cpython-39-darwin.so``, then you could run ``ln -s
|
After checking that
|
||||||
~/Downloads/instantclient_19_8/libclntsh.dylib
|
``/Users/yourname/.pyenv/versions/3.9.6/lib/python3.9/site-packages/oracledb``
|
||||||
~/Library/3.9.6/lib/python3.9/site-packages/oracledb-1.0.0-py3.9-macosx-11.5-x86_64.egg/oracledb/``.
|
contains the binary module ``thick_impl.cpython-39-darwin.so`` you could then
|
||||||
|
run these commands in a terminal window::
|
||||||
|
|
||||||
|
CLIENT_DIR=~/Downloads/instantclient_19_8
|
||||||
|
DPY_DIR=~/.pyenv/versions/3.9.6/lib/python3.9/site-packages/oracledb
|
||||||
|
ln -s $CLIENT_DIR/libclntsh.dylib $DPY_DIR
|
||||||
|
|
||||||
|
This can be automated in Python with:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
CLIENT_DIR = "~/Downloads/instantclient_19_8"
|
||||||
|
LIB_NAME = "libclntsh.dylib"
|
||||||
|
|
||||||
|
import os
|
||||||
|
import oracledb
|
||||||
|
|
||||||
|
target_dir = oracledb.__path__[0]
|
||||||
|
os.symlink(os.path.join(CLIENT_DIR, LIB_NAME),
|
||||||
|
os.path.join(target_dir, LIB_NAME))
|
||||||
|
|
||||||
If python-oracledb does not find the Oracle Client library in that
|
If python-oracledb does not find the Oracle Client library in that
|
||||||
directory, the directories on the system library search path may be used,
|
directory, the directories on the system library search path may be used,
|
||||||
|
@ -174,8 +203,8 @@ On macOS, python-oracledb Thick mode can be enabled as follows:
|
||||||
|
|
||||||
.. _linuxinit:
|
.. _linuxinit:
|
||||||
|
|
||||||
Setting the Oracle Client Directory on Linux and Related Platforms
|
Setting the Oracle Client Library Directory on Linux and Related Platforms
|
||||||
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
|
||||||
On Linux and related platforms, python-oracledb Thick mode can be enabled as
|
On Linux and related platforms, python-oracledb Thick mode can be enabled as
|
||||||
follows:
|
follows:
|
||||||
|
@ -207,16 +236,18 @@ follows:
|
||||||
raised.
|
raised.
|
||||||
|
|
||||||
Ensure that the Python process has directory and file access permissions for
|
Ensure that the Python process has directory and file access permissions for
|
||||||
the Oracle Client libraries. On Linux ensure a ``libclntsh.so`` file exists.
|
the Oracle Client libraries. On some platforms OS restrictions may prevent the
|
||||||
On macOS ensure a ``libclntsh.dylib`` file exists. python-oracledb Thick will
|
opening of Oracle Client libraries installed in unsafe paths, such as from a
|
||||||
not directly load ``libclntsh.*.XX.1`` files in ``lib_dir`` or from the directory
|
user directory. On Linux ensure a ``libclntsh.so`` file exists. On macOS
|
||||||
where the python-oracledb binary module is available. Note that other libraries
|
ensure a ``libclntsh.dylib`` file exists. Python-oracledb Thick mode will not
|
||||||
used by ``libclntsh*`` are also required.
|
directly load ``libclntsh.*.XX.1`` files in ``lib_dir`` or from the directory
|
||||||
|
where the python-oracledb binary module is available. Note that other
|
||||||
|
libraries used by ``libclntsh*`` are also required.
|
||||||
|
|
||||||
.. _usinginitoracleclient:
|
.. _usinginitoracleclient:
|
||||||
|
|
||||||
Calling oracledb.init_oracle_client() to Set the Oracle Client Directory
|
Example Calling oracledb.init_oracle_client()
|
||||||
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
+++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
|
||||||
Oracle Client Libraries are loaded when :meth:`oracledb.init_oracle_client()`
|
Oracle Client Libraries are loaded when :meth:`oracledb.init_oracle_client()`
|
||||||
is called. In some environments, applications can use the ``lib_dir``
|
is called. In some environments, applications can use the ``lib_dir``
|
||||||
|
@ -225,7 +256,7 @@ Otherwise, the system library search path should contain the relevant library
|
||||||
directory before Python is invoked.
|
directory before Python is invoked.
|
||||||
|
|
||||||
For example, if the Oracle Instant Client Libraries are in
|
For example, if the Oracle Instant Client Libraries are in
|
||||||
``C:\oracle\instantclient_19_9`` on Windows or
|
``C:\oracle\instantclient_19_17`` on Windows or
|
||||||
``$HOME/Downloads/instantclient_19_8`` on macOS (Intel x86), then you can use:
|
``$HOME/Downloads/instantclient_19_8`` on macOS (Intel x86), then you can use:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
@ -238,10 +269,10 @@ For example, if the Oracle Instant Client Libraries are in
|
||||||
if platform.system() == "Darwin" and platform.machine() == "x86_64":
|
if platform.system() == "Darwin" and platform.machine() == "x86_64":
|
||||||
d = os.environ.get("HOME")+"/Downloads/instantclient_19_8")
|
d = os.environ.get("HOME")+"/Downloads/instantclient_19_8")
|
||||||
elif platform.system() == "Windows":
|
elif platform.system() == "Windows":
|
||||||
d = r"C:\oracle\instantclient_19_14"
|
d = r"C:\oracle\instantclient_19_17"
|
||||||
oracledb.init_oracle_client(lib_dir=d)
|
oracledb.init_oracle_client(lib_dir=d)
|
||||||
|
|
||||||
Note the use of a 'raw' string ``r"..."`` on Windows so that backslashes are
|
The use of a 'raw' string ``r"..."`` on Windows means that backslashes are
|
||||||
treated as directory separators.
|
treated as directory separators.
|
||||||
|
|
||||||
**Note that if you set** ``lib_dir`` **on Linux and related platforms, you must
|
**Note that if you set** ``lib_dir`` **on Linux and related platforms, you must
|
||||||
|
@ -258,12 +289,16 @@ shown in :ref:`envset`.
|
||||||
**Tracing Oracle Client Libraries Loading**
|
**Tracing Oracle Client Libraries Loading**
|
||||||
|
|
||||||
To trace the loading of Oracle Client libraries, the environment variable
|
To trace the loading of Oracle Client libraries, the environment variable
|
||||||
``DPI_DEBUG_LEVEL`` can be set to 64 before starting Python. For example, on
|
``DPI_DEBUG_LEVEL`` can be set to 64 before starting Python. At a Windows
|
||||||
Linux, you might use::
|
command prompt, this could be done with::
|
||||||
|
|
||||||
$ export DPI_DEBUG_LEVEL=64
|
set DPI_DEBUG_LEVEL=64
|
||||||
$ python myapp.py 2> log.txt
|
|
||||||
|
|
||||||
|
On Linux and macOS, you might use::
|
||||||
|
|
||||||
|
export DPI_DEBUG_LEVEL=64
|
||||||
|
|
||||||
|
When your python-oracledb application is run, logging output is shown.
|
||||||
|
|
||||||
.. _optnetfiles:
|
.. _optnetfiles:
|
||||||
|
|
||||||
|
|
|
@ -271,6 +271,10 @@ To use python-oracledb Thick mode with Oracle Instant Client zip files:
|
||||||
cd /opt/oracle
|
cd /opt/oracle
|
||||||
unzip instantclient-basic-linux.x64-21.6.0.0.0.zip
|
unzip instantclient-basic-linux.x64-21.6.0.0.0.zip
|
||||||
|
|
||||||
|
Note OS restrictions may prevent the opening of Oracle Client libraries
|
||||||
|
installed in unsafe paths, such as from a user directory. You may need to
|
||||||
|
install under a directory like ``/opt`` or ``/usr/local``.
|
||||||
|
|
||||||
3. Install the ``libaio`` package with sudo or as the root user. For example::
|
3. Install the ``libaio`` package with sudo or as the root user. For example::
|
||||||
|
|
||||||
sudo yum install libaio
|
sudo yum install libaio
|
||||||
|
@ -827,9 +831,14 @@ used to install into a local directory::
|
||||||
|
|
||||||
python setup.py install --user
|
python setup.py install --user
|
||||||
|
|
||||||
|
.. _troubleshooting:
|
||||||
|
|
||||||
Troubleshooting
|
Troubleshooting
|
||||||
===============
|
===============
|
||||||
|
|
||||||
|
Installation Troubleshooting
|
||||||
|
----------------------------
|
||||||
|
|
||||||
If installation fails:
|
If installation fails:
|
||||||
|
|
||||||
- An error such as ``not a supported wheel on this platform.`` indicates that
|
- An error such as ``not a supported wheel on this platform.`` indicates that
|
||||||
|
@ -866,6 +875,11 @@ If installation fails:
|
||||||
a subdirectory called "odpi" containing files. If this is missing, review the
|
a subdirectory called "odpi" containing files. If this is missing, review the
|
||||||
section on `Install Using GitHub`_.
|
section on `Install Using GitHub`_.
|
||||||
|
|
||||||
|
.. _runtimetroubleshooting:
|
||||||
|
|
||||||
|
Runtime Error Troubleshooting
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
If using python-oracledb fails:
|
If using python-oracledb fails:
|
||||||
|
|
||||||
- If you have multiple versions of Python installed, ensure that you are
|
- If you have multiple versions of Python installed, ensure that you are
|
||||||
|
@ -884,14 +898,19 @@ If using python-oracledb fails:
|
||||||
should be the location of your Oracle Client libraries. Do not pass
|
should be the location of your Oracle Client libraries. Do not pass
|
||||||
this parameter on Linux.
|
this parameter on Linux.
|
||||||
|
|
||||||
|
- Check that the Python process has permission to open the Oracle Client
|
||||||
|
libraries. OS restrictions may prevent the opening of libraries installed
|
||||||
|
in unsafe paths, such as from a user directory. On Linux you may need to
|
||||||
|
install the Oracle Client libraries under a directory like ``/opt`` or
|
||||||
|
``/usr/local``.
|
||||||
|
|
||||||
- Check if Python and your Oracle Client libraries are both 64-bit or
|
- Check if Python and your Oracle Client libraries are both 64-bit or
|
||||||
both 32-bit. The ``DPI-1047`` message will tell you whether the 64-bit
|
both 32-bit. The ``DPI-1047`` message will tell you whether the 64-bit
|
||||||
or 32-bit Oracle Client is needed for your Python.
|
or 32-bit Oracle Client is needed for your Python.
|
||||||
|
|
||||||
- For Thick mode connections, set the environment variable
|
- Set the environment variable ``DPI_DEBUG_LEVEL`` to 64 and restart
|
||||||
``DPI_DEBUG_LEVEL`` to 64 and restart python-oracledb. The trace
|
python-oracledb. The trace messages will show how and where
|
||||||
messages will show how and where python-oracledb is looking for the
|
python-oracledb is looking for the Oracle Client libraries.
|
||||||
Oracle Client libraries.
|
|
||||||
|
|
||||||
At a Windows command prompt, this could be done with::
|
At a Windows command prompt, this could be done with::
|
||||||
|
|
||||||
|
@ -919,9 +938,10 @@ If using python-oracledb fails:
|
||||||
been installed.
|
been installed.
|
||||||
|
|
||||||
- On Linux, check if the ``LD_LIBRARY_PATH`` environment variable contains
|
- On Linux, check if the ``LD_LIBRARY_PATH`` environment variable contains
|
||||||
the Oracle Client library directory. Or, if you are using Oracle
|
the Oracle Client library directory. Some environments such as web servers
|
||||||
Instant Client, a preferred alternative is to ensure that a file in the
|
reset environment variables. If you are using Oracle Instant Client, a
|
||||||
``/etc/ld.so.conf.d`` directory contains the path to the Instant Client
|
preferred alternative to ``LD_LIBRARY_PATH`` is to ensure that a file in
|
||||||
|
the ``/etc/ld.so.conf.d`` directory contains the path to the Instant Client
|
||||||
directory, and then run ``ldconfig``.
|
directory, and then run ``ldconfig``.
|
||||||
|
|
||||||
- If you get the error ``DPY-3010: connections to this database server
|
- If you get the error ``DPY-3010: connections to this database server
|
||||||
|
@ -931,8 +951,8 @@ If using python-oracledb fails:
|
||||||
:meth:`oracledb.init_oracle_client()` in your code. Alternatively,
|
:meth:`oracledb.init_oracle_client()` in your code. Alternatively,
|
||||||
upgrade your database.
|
upgrade your database.
|
||||||
|
|
||||||
- If you get the error "``DPI-1072: the Oracle Client library version is
|
- If you get the error ``DPI-1072: the Oracle Client library version is
|
||||||
unsupported``", then review the installation requirements. The Thick
|
unsupported``, then review the installation requirements. The Thick
|
||||||
mode of python-oracledb needs Oracle Client libraries 11.2 or later.
|
mode of python-oracledb needs Oracle Client libraries 11.2 or later.
|
||||||
Note that version 19 is not supported on Windows 7. Similar steps shown
|
Note that version 19 is not supported on Windows 7. Similar steps shown
|
||||||
above for ``DPI-1047`` may help. You may be able to use Thin mode which
|
above for ``DPI-1047`` may help. You may be able to use Thin mode which
|
||||||
|
|
|
@ -248,10 +248,10 @@ Python.
|
||||||
Tuning Fetching from REF CURSORS
|
Tuning Fetching from REF CURSORS
|
||||||
--------------------------------
|
--------------------------------
|
||||||
|
|
||||||
In python-oracledb, REF CURSORS can also be tuned by setting the values of
|
In python-oracledb, fetching data from REF CURSORS can be tuned by setting the
|
||||||
``arraysize`` and ``prefetchrows``. The ``prefetchrows`` value must be set
|
values of ``arraysize`` and ``prefetchrows``. The ``prefetchrows`` value must
|
||||||
before calling the PL/SQL procedure as the REF CURSOR is executed on the
|
be set before calling the PL/SQL procedure because the REF CURSOR is executed
|
||||||
server.
|
on the server.
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
|
@ -272,6 +272,8 @@ For example:
|
||||||
|
|
||||||
.. _roundtrips:
|
.. _roundtrips:
|
||||||
|
|
||||||
|
Also see `Avoiding Premature Prefetching`_.
|
||||||
|
|
||||||
Database Round-trips
|
Database Round-trips
|
||||||
====================
|
====================
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
# Copyright (c) 2020, 2022, Oracle and/or its affiliates.
|
# Copyright (c) 2020, 2023, Oracle and/or its affiliates.
|
||||||
#
|
#
|
||||||
# This software is dual-licensed to you under the Universal Permissive License
|
# This software is dual-licensed to you under the Universal Permissive License
|
||||||
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
||||||
|
@ -115,6 +115,7 @@ cdef class AddressList:
|
||||||
bint load_balance
|
bint load_balance
|
||||||
int lru_index
|
int lru_index
|
||||||
|
|
||||||
|
cdef bint _uses_tcps(self)
|
||||||
cdef str build_connect_string(self)
|
cdef str build_connect_string(self)
|
||||||
|
|
||||||
|
|
||||||
|
@ -191,7 +192,6 @@ cdef class ConnectParamsImpl:
|
||||||
bytearray _token_obfuscator
|
bytearray _token_obfuscator
|
||||||
bytearray _private_key
|
bytearray _private_key
|
||||||
bytearray _private_key_obfuscator
|
bytearray _private_key_obfuscator
|
||||||
bint _has_components
|
|
||||||
|
|
||||||
cdef int _check_credentials(self) except -1
|
cdef int _check_credentials(self) except -1
|
||||||
cdef int _copy(self, ConnectParamsImpl other_params) except -1
|
cdef int _copy(self, ConnectParamsImpl other_params) except -1
|
||||||
|
|
|
@ -158,5 +158,6 @@ TPC_END_SUSPEND = 0x00100000
|
||||||
# basic configuration constants
|
# basic configuration constants
|
||||||
DRIVER_NAME = "python-oracledb"
|
DRIVER_NAME = "python-oracledb"
|
||||||
INSTALLATION_URL = "https://python-oracledb.readthedocs.io/en/" \
|
INSTALLATION_URL = "https://python-oracledb.readthedocs.io/en/" \
|
||||||
"latest/user_guide/installation.html"
|
"/latest/user_guide/initialization.html" \
|
||||||
|
"#setting-the-oracle-client-library-directory"
|
||||||
ENCODING = "UTF-8"
|
ENCODING = "UTF-8"
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
# Copyright (c) 2022, Oracle and/or its affiliates.
|
# Copyright (c) 2022, 2023, Oracle and/or its affiliates.
|
||||||
#
|
#
|
||||||
# This software is dual-licensed to you under the Universal Permissive License
|
# This software is dual-licensed to you under the Universal Permissive License
|
||||||
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
||||||
|
@ -169,8 +169,6 @@ cdef class ConnectParamsImpl:
|
||||||
self._default_address.set_from_args(args)
|
self._default_address.set_from_args(args)
|
||||||
_set_bool_param(args, "externalauth", &self.externalauth)
|
_set_bool_param(args, "externalauth", &self.externalauth)
|
||||||
self._set_access_token_param(args.get("access_token"))
|
self._set_access_token_param(args.get("access_token"))
|
||||||
if args:
|
|
||||||
self._has_components = True
|
|
||||||
|
|
||||||
cdef int _check_credentials(self) except -1:
|
cdef int _check_credentials(self) except -1:
|
||||||
"""
|
"""
|
||||||
|
@ -344,7 +342,6 @@ cdef class ConnectParamsImpl:
|
||||||
# to be a full connect descriptor
|
# to be a full connect descriptor
|
||||||
if connect_string.startswith("("):
|
if connect_string.startswith("("):
|
||||||
_parse_connect_descriptor(connect_string, args)
|
_parse_connect_descriptor(connect_string, args)
|
||||||
self._has_components = True
|
|
||||||
return self._process_connect_descriptor(args)
|
return self._process_connect_descriptor(args)
|
||||||
|
|
||||||
# otherwise, see if the connect string is an EasyConnect string
|
# otherwise, see if the connect string is an EasyConnect string
|
||||||
|
@ -389,9 +386,6 @@ cdef class ConnectParamsImpl:
|
||||||
_parse_connect_descriptor(connect_string, args)
|
_parse_connect_descriptor(connect_string, args)
|
||||||
self._process_connect_descriptor(args)
|
self._process_connect_descriptor(args)
|
||||||
|
|
||||||
# mark that object has components
|
|
||||||
self._has_components = True
|
|
||||||
|
|
||||||
cdef int _process_connect_descriptor(self, dict args) except -1:
|
cdef int _process_connect_descriptor(self, dict args) except -1:
|
||||||
"""
|
"""
|
||||||
Internal method used for processing the parsed connect descriptor into
|
Internal method used for processing the parsed connect descriptor into
|
||||||
|
@ -538,8 +532,7 @@ cdef class ConnectParamsImpl:
|
||||||
will be a connect string built up from the components supplied when the
|
will be a connect string built up from the components supplied when the
|
||||||
object was built.
|
object was built.
|
||||||
"""
|
"""
|
||||||
if self._has_components:
|
return self.description_list.build_connect_string()
|
||||||
return self.description_list.build_connect_string()
|
|
||||||
|
|
||||||
def get_full_user(self):
|
def get_full_user(self):
|
||||||
"""
|
"""
|
||||||
|
@ -613,16 +606,18 @@ cdef class Address:
|
||||||
|
|
||||||
cdef str build_connect_string(self):
|
cdef str build_connect_string(self):
|
||||||
"""
|
"""
|
||||||
Build a connect string from the components.
|
Build a connect string from the components. If no host is specified,
|
||||||
|
None is returned (used for bequeath connections).
|
||||||
"""
|
"""
|
||||||
parts = [f"(PROTOCOL={self.protocol})",
|
if self.host is not None:
|
||||||
f"(HOST={self.host})",
|
parts = [f"(PROTOCOL={self.protocol})",
|
||||||
f"(PORT={self.port})"]
|
f"(HOST={self.host})",
|
||||||
if self.https_proxy is not None:
|
f"(PORT={self.port})"]
|
||||||
parts.append(f"(HTTPS_PROXY={self.https_proxy})")
|
if self.https_proxy is not None:
|
||||||
if self.https_proxy_port != 0:
|
parts.append(f"(HTTPS_PROXY={self.https_proxy})")
|
||||||
parts.append(f"(HTTPS_PROXY_PORT={self.https_proxy_port})")
|
if self.https_proxy_port != 0:
|
||||||
return f'(ADDRESS={"".join(parts)})'
|
parts.append(f"(HTTPS_PROXY_PORT={self.https_proxy_port})")
|
||||||
|
return f'(ADDRESS={"".join(parts)})'
|
||||||
|
|
||||||
def copy(self):
|
def copy(self):
|
||||||
"""
|
"""
|
||||||
|
@ -667,12 +662,25 @@ cdef class AddressList:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.addresses = []
|
self.addresses = []
|
||||||
|
|
||||||
|
cdef bint _uses_tcps(self):
|
||||||
|
"""
|
||||||
|
Returns a boolean indicating if any of the addresses in the address
|
||||||
|
list use the protocol TCPS.
|
||||||
|
"""
|
||||||
|
cdef Address address
|
||||||
|
for address in self.addresses:
|
||||||
|
if address.protocol == "tcps":
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
cdef str build_connect_string(self):
|
cdef str build_connect_string(self):
|
||||||
"""
|
"""
|
||||||
Build a connect string from the components.
|
Build a connect string from the components.
|
||||||
"""
|
"""
|
||||||
cdef Address a
|
cdef Address a
|
||||||
parts = [a.build_connect_string() for a in self.addresses]
|
parts = [a.build_connect_string() for a in self.addresses]
|
||||||
|
if len(parts) == 1:
|
||||||
|
return parts[0]
|
||||||
return f'(ADDRESS_LIST={"".join(parts)})'
|
return f'(ADDRESS_LIST={"".join(parts)})'
|
||||||
|
|
||||||
def set_from_args(self, dict args):
|
def set_from_args(self, dict args):
|
||||||
|
@ -713,37 +721,12 @@ cdef class Description:
|
||||||
Build a connect string from the components.
|
Build a connect string from the components.
|
||||||
"""
|
"""
|
||||||
cdef:
|
cdef:
|
||||||
str connect_data, security, temp
|
AddressList address_list
|
||||||
list parts, address_lists
|
list parts, temp_parts
|
||||||
AddressList a
|
bint uses_tcps = False
|
||||||
|
str temp
|
||||||
|
|
||||||
# build connect data segment
|
# build top-level description parts
|
||||||
parts = []
|
|
||||||
if self.service_name is not None:
|
|
||||||
parts.append(f"(SERVICE_NAME={self.service_name})")
|
|
||||||
elif self.sid is not None:
|
|
||||||
parts.append(f"(SID={self.sid})")
|
|
||||||
if self.server_type is not None:
|
|
||||||
parts.append(f"(SERVER={self.server_type})")
|
|
||||||
if self.cclass is not None:
|
|
||||||
parts.append(f"(POOL_CONNECTION_CLASS={self.cclass})")
|
|
||||||
if self.purity != 0:
|
|
||||||
parts.append(f"(POOL_PURITY={self.purity})")
|
|
||||||
if cid is not None:
|
|
||||||
parts.append(f"(CID={cid})")
|
|
||||||
connect_data = f'(CONNECT_DATA={"".join(parts)})'
|
|
||||||
|
|
||||||
# build security segment, if applicable
|
|
||||||
parts = []
|
|
||||||
if self.ssl_server_dn_match:
|
|
||||||
parts.append("(SSL_SERVER_DN_MATCH=ON)")
|
|
||||||
if self.ssl_server_cert_dn is not None:
|
|
||||||
parts.append(f"(SSL_SERVER_CERT_DN={self.ssl_server_cert_dn})")
|
|
||||||
if self.wallet_location is not None:
|
|
||||||
parts.append(f"(MY_WALLET_DIRECTORY={self.wallet_location})")
|
|
||||||
security = f'(SECURITY={"".join(parts)})'
|
|
||||||
|
|
||||||
# build connect string
|
|
||||||
parts = []
|
parts = []
|
||||||
if self.load_balance:
|
if self.load_balance:
|
||||||
parts.append("(LOAD_BALANCE=ON)")
|
parts.append("(LOAD_BALANCE=ON)")
|
||||||
|
@ -758,10 +741,48 @@ cdef class Description:
|
||||||
if self.tcp_connect_timeout != DEFAULT_TCP_CONNECT_TIMEOUT:
|
if self.tcp_connect_timeout != DEFAULT_TCP_CONNECT_TIMEOUT:
|
||||||
temp = self._build_duration_str(self.tcp_connect_timeout)
|
temp = self._build_duration_str(self.tcp_connect_timeout)
|
||||||
parts.append(f"(TRANSPORT_CONNECT_TIMEOUT={temp})")
|
parts.append(f"(TRANSPORT_CONNECT_TIMEOUT={temp})")
|
||||||
address_lists = [a.build_connect_string() for a in self.address_lists]
|
|
||||||
parts.extend(address_lists)
|
# add address lists, but if the address list contains only a single
|
||||||
parts.append(connect_data)
|
# entry and that entry does not have a host, the other parts aren't
|
||||||
parts.append(security)
|
# relevant anyway!
|
||||||
|
for address_list in self.address_lists:
|
||||||
|
temp = address_list.build_connect_string()
|
||||||
|
if temp is None:
|
||||||
|
return None
|
||||||
|
parts.append(temp)
|
||||||
|
if not uses_tcps:
|
||||||
|
uses_tcps = address_list._uses_tcps()
|
||||||
|
|
||||||
|
# build connect data segment
|
||||||
|
temp_parts = []
|
||||||
|
if self.service_name is not None:
|
||||||
|
temp_parts.append(f"(SERVICE_NAME={self.service_name})")
|
||||||
|
elif self.sid is not None:
|
||||||
|
temp_parts.append(f"(SID={self.sid})")
|
||||||
|
if self.server_type is not None:
|
||||||
|
temp_parts.append(f"(SERVER={self.server_type})")
|
||||||
|
if self.cclass is not None:
|
||||||
|
temp_parts.append(f"(POOL_CONNECTION_CLASS={self.cclass})")
|
||||||
|
if self.purity != 0:
|
||||||
|
temp_parts.append(f"(POOL_PURITY={self.purity})")
|
||||||
|
if cid is not None:
|
||||||
|
temp_parts.append(f"(CID={cid})")
|
||||||
|
if temp_parts:
|
||||||
|
parts.append(f'(CONNECT_DATA={"".join(temp_parts)})')
|
||||||
|
|
||||||
|
# build security segment, if applicable
|
||||||
|
if uses_tcps:
|
||||||
|
temp_parts = []
|
||||||
|
if self.ssl_server_dn_match:
|
||||||
|
temp_parts.append("(SSL_SERVER_DN_MATCH=ON)")
|
||||||
|
if self.ssl_server_cert_dn is not None:
|
||||||
|
temp = f"(SSL_SERVER_CERT_DN={self.ssl_server_cert_dn})"
|
||||||
|
temp_parts.append(temp)
|
||||||
|
if self.wallet_location is not None:
|
||||||
|
temp = f"(MY_WALLET_DIRECTORY={self.wallet_location})"
|
||||||
|
temp_parts.append(temp)
|
||||||
|
parts.append(f'(SECURITY={"".join(temp_parts)})')
|
||||||
|
|
||||||
return f'(DESCRIPTION={"".join(parts)})'
|
return f'(DESCRIPTION={"".join(parts)})'
|
||||||
|
|
||||||
def copy(self):
|
def copy(self):
|
||||||
|
|
|
@ -99,7 +99,7 @@ cdef class BaseVarImpl:
|
||||||
if was_set != NULL:
|
if was_set != NULL:
|
||||||
was_set[0] = False
|
was_set[0] = False
|
||||||
return 0
|
return 0
|
||||||
errors._raise_err(errors.ERR_INCORRECT_VAR_ARRAY_SIZE,
|
errors._raise_err(errors.ERR_INCORRECT_VAR_ARRAYSIZE,
|
||||||
var_arraysize=self.num_elements,
|
var_arraysize=self.num_elements,
|
||||||
required_arraysize=num_elements_in_array)
|
required_arraysize=num_elements_in_array)
|
||||||
|
|
||||||
|
|
|
@ -368,13 +368,15 @@ cdef class Buffer:
|
||||||
|
|
||||||
cdef object read_bool(self):
|
cdef object read_bool(self):
|
||||||
"""
|
"""
|
||||||
Read a boolean from the buffer and return True, False or None.
|
Read a boolean from the buffer and return True, False or None. A zero
|
||||||
|
length or a negative length (indicated by the value 0x81 in the first
|
||||||
|
byte) implies a null value.
|
||||||
"""
|
"""
|
||||||
cdef:
|
cdef:
|
||||||
const char_type *ptr
|
const char_type *ptr
|
||||||
ssize_t num_bytes
|
ssize_t num_bytes
|
||||||
self.read_raw_bytes_and_length(&ptr, &num_bytes)
|
self.read_raw_bytes_and_length(&ptr, &num_bytes)
|
||||||
if ptr != NULL:
|
if ptr != NULL and ptr[0] != 0x81:
|
||||||
return ptr[num_bytes - 1] == 1
|
return ptr[num_bytes - 1] == 1
|
||||||
|
|
||||||
cdef object read_bytes(self):
|
cdef object read_bytes(self):
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
# Copyright (c) 2022, Oracle and/or its affiliates.
|
# Copyright (c) 2022, 2023, Oracle and/or its affiliates.
|
||||||
#
|
#
|
||||||
# This software is dual-licensed to you under the Universal Permissive License
|
# This software is dual-licensed to you under the Universal Permissive License
|
||||||
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
||||||
|
@ -719,23 +719,35 @@ cdef class ThinDbObjectTypeCache:
|
||||||
t_SuperTypeOwner varchar2(128);
|
t_SuperTypeOwner varchar2(128);
|
||||||
t_SuperTypeName varchar2(128);
|
t_SuperTypeName varchar2(128);
|
||||||
t_SubTypeRefCursor sys_refcursor;
|
t_SubTypeRefCursor sys_refcursor;
|
||||||
|
t_Pos pls_integer;
|
||||||
begin
|
begin
|
||||||
:ret_val := dbms_pickler.get_type_shape(:full_name, :oid,
|
:ret_val := dbms_pickler.get_type_shape(:full_name, :oid,
|
||||||
:version, :tds, t_Instantiable, t_SuperTypeOwner,
|
:version, :tds, t_Instantiable, t_SuperTypeOwner,
|
||||||
t_SuperTypeName, :attrs_rc, t_SubTypeRefCursor);
|
t_SuperTypeName, :attrs_rc, t_SubTypeRefCursor);
|
||||||
:package_name := null;
|
:package_name := null;
|
||||||
begin
|
if substr(:full_name, length(:full_name) - 7) = '%ROWTYPE' then
|
||||||
select owner, type_name
|
t_Pos := instr(:full_name, '.');
|
||||||
into :schema, :name
|
:schema := substr(:full_name, 1, t_Pos - 1);
|
||||||
from all_types
|
:name := substr(:full_name, t_Pos + 1);
|
||||||
where type_oid = :oid;
|
else
|
||||||
exception
|
begin
|
||||||
when no_data_found then
|
select owner, type_name
|
||||||
select owner, package_name, type_name
|
into :schema, :name
|
||||||
into :schema, :package_name, :name
|
from all_types
|
||||||
from all_plsql_types
|
where type_oid = :oid;
|
||||||
where type_oid = :oid;
|
exception
|
||||||
end;
|
when no_data_found then
|
||||||
|
begin
|
||||||
|
select owner, package_name, type_name
|
||||||
|
into :schema, :package_name, :name
|
||||||
|
from all_plsql_types
|
||||||
|
where type_oid = :oid;
|
||||||
|
exception
|
||||||
|
when no_data_found then
|
||||||
|
null;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end if;
|
||||||
end;""")
|
end;""")
|
||||||
self.meta_cursor = cursor
|
self.meta_cursor = cursor
|
||||||
|
|
||||||
|
@ -939,17 +951,23 @@ cdef class ThinDbObjectTypeCache:
|
||||||
"""
|
"""
|
||||||
cdef:
|
cdef:
|
||||||
ThinDbObjectTypeImpl typ_impl
|
ThinDbObjectTypeImpl typ_impl
|
||||||
str full_name
|
str full_name, name, suffix
|
||||||
while self.partial_types:
|
while self.partial_types:
|
||||||
typ_impl = self.partial_types.pop()
|
typ_impl = self.partial_types.pop()
|
||||||
if self.meta_cursor is None:
|
if self.meta_cursor is None:
|
||||||
self._init_meta_cursor(conn)
|
self._init_meta_cursor(conn)
|
||||||
|
suffix = "%ROWTYPE"
|
||||||
|
if typ_impl.name.endswith(suffix):
|
||||||
|
name = typ_impl.name[:-len(suffix)]
|
||||||
|
else:
|
||||||
|
name = typ_impl.name
|
||||||
|
suffix = ""
|
||||||
if typ_impl.package_name is not None:
|
if typ_impl.package_name is not None:
|
||||||
full_name = f'"{typ_impl.schema}".' + \
|
full_name = f'"{typ_impl.schema}".' + \
|
||||||
f'"{typ_impl.package_name}".' + \
|
f'"{typ_impl.package_name}".' + \
|
||||||
f'"{typ_impl.name}"'
|
f'"{name}"{suffix}'
|
||||||
else:
|
else:
|
||||||
full_name = f'"{typ_impl.schema}"."{typ_impl.name}"'
|
full_name = f'"{typ_impl.schema}"."{name}"{suffix}'
|
||||||
self._populate_type_info(full_name, typ_impl)
|
self._populate_type_info(full_name, typ_impl)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
# Copyright (c) 2020, 2022, Oracle and/or its affiliates.
|
# Copyright (c) 2020, 2023, Oracle and/or its affiliates.
|
||||||
#
|
#
|
||||||
# This software is dual-licensed to you under the Universal Permissive License
|
# This software is dual-licensed to you under the Universal Permissive License
|
||||||
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
||||||
|
@ -615,7 +615,9 @@ cdef class MessageWithData(Message):
|
||||||
name=var_impl.dbtype.name)
|
name=var_impl.dbtype.name)
|
||||||
if not self.in_fetch:
|
if not self.in_fetch:
|
||||||
buf.read_sb4(&actual_num_bytes)
|
buf.read_sb4(&actual_num_bytes)
|
||||||
if actual_num_bytes != 0 and column_value is not None:
|
if actual_num_bytes < 0 and column_value is False:
|
||||||
|
column_value = None
|
||||||
|
elif actual_num_bytes != 0 and column_value is not None:
|
||||||
unit_type = "bytes" if isinstance(column_value, bytes) \
|
unit_type = "bytes" if isinstance(column_value, bytes) \
|
||||||
else "characters"
|
else "characters"
|
||||||
errors._raise_err(errors.ERR_COLUMN_TRUNCATED,
|
errors._raise_err(errors.ERR_COLUMN_TRUNCATED,
|
||||||
|
@ -714,7 +716,8 @@ cdef class MessageWithData(Message):
|
||||||
conn = self.cursor.connection
|
conn = self.cursor.connection
|
||||||
for i in range(cursor_impl._num_columns):
|
for i in range(cursor_impl._num_columns):
|
||||||
fetch_info = self._process_column_info(buf, cursor_impl)
|
fetch_info = self._process_column_info(buf, cursor_impl)
|
||||||
if prev_fetch_var_impls is not None:
|
if prev_fetch_var_impls is not None \
|
||||||
|
and i < len(prev_fetch_var_impls):
|
||||||
self._adjust_fetch_info(prev_fetch_var_impls[i], fetch_info)
|
self._adjust_fetch_info(prev_fetch_var_impls[i], fetch_info)
|
||||||
cursor_impl._create_fetch_var(conn, self.cursor, type_handler, i,
|
cursor_impl._create_fetch_var(conn, self.cursor, type_handler, i,
|
||||||
fetch_info)
|
fetch_info)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
# Copyright (c) 2020, 2022, Oracle and/or its affiliates.
|
# Copyright (c) 2020, 2023, Oracle and/or its affiliates.
|
||||||
#
|
#
|
||||||
# This software is dual-licensed to you under the Universal Permissive License
|
# This software is dual-licensed to you under the Universal Permissive License
|
||||||
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
||||||
|
@ -36,7 +36,10 @@ class ConnectConstants:
|
||||||
self.program_name = sys.executable
|
self.program_name = sys.executable
|
||||||
self.machine_name = socket.gethostname()
|
self.machine_name = socket.gethostname()
|
||||||
self.pid = str(os.getpid())
|
self.pid = str(os.getpid())
|
||||||
self.user_name = getpass.getuser()
|
try:
|
||||||
|
self.user_name = getpass.getuser()
|
||||||
|
except:
|
||||||
|
self.user_name = ""
|
||||||
self.terminal_name = "unknown"
|
self.terminal_name = "unknown"
|
||||||
self.sanitized_program_name = self._sanitize(self.program_name)
|
self.sanitized_program_name = self._sanitize(self.program_name)
|
||||||
self.sanitized_machine_name = self._sanitize(self.machine_name)
|
self.sanitized_machine_name = self._sanitize(self.machine_name)
|
||||||
|
|
|
@ -30,4 +30,4 @@
|
||||||
# file doc/src/conf.py both reference this file directly.
|
# file doc/src/conf.py both reference this file directly.
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
__version__ = "1.2.1"
|
__version__ = "1.2.2"
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*-----------------------------------------------------------------------------
|
/*-----------------------------------------------------------------------------
|
||||||
* Copyright (c) 2020, 2022, Oracle and/or its affiliates.
|
* Copyright (c) 2020, 2023, Oracle and/or its affiliates.
|
||||||
*
|
*
|
||||||
* This software is dual-licensed to you under the Universal Permissive License
|
* This software is dual-licensed to you under the Universal Permissive License
|
||||||
* (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
* (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
||||||
|
@ -968,6 +968,9 @@ create or replace package &main_user..pkg_TestBooleans as
|
||||||
a_Value udt_BooleanList
|
a_Value udt_BooleanList
|
||||||
) return number;
|
) return number;
|
||||||
|
|
||||||
|
function TestOutValueNull
|
||||||
|
return boolean;
|
||||||
|
|
||||||
procedure TestOutArrays (
|
procedure TestOutArrays (
|
||||||
a_NumElements number,
|
a_NumElements number,
|
||||||
a_Value out nocopy udt_BooleanList
|
a_Value out nocopy udt_BooleanList
|
||||||
|
@ -1011,6 +1014,12 @@ create or replace package body &main_user..pkg_TestBooleans as
|
||||||
return t_Result;
|
return t_Result;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TestOutValueNull
|
||||||
|
return boolean is
|
||||||
|
begin
|
||||||
|
return null;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TestOutArrays (
|
procedure TestOutArrays (
|
||||||
a_NumElements number,
|
a_NumElements number,
|
||||||
a_Value out nocopy udt_BooleanList
|
a_Value out nocopy udt_BooleanList
|
||||||
|
@ -1026,6 +1035,10 @@ end;
|
||||||
|
|
||||||
create or replace package &main_user..pkg_TestBindObject as
|
create or replace package &main_user..pkg_TestBindObject as
|
||||||
|
|
||||||
|
subtype udt_RowType is TestTempTable%rowtype;
|
||||||
|
|
||||||
|
type udt_CollectionRowType is table of udt_RowType index by binary_integer;
|
||||||
|
|
||||||
function GetStringRep (
|
function GetStringRep (
|
||||||
a_Object udt_Object
|
a_Object udt_Object
|
||||||
) return varchar2;
|
) return varchar2;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
# Copyright (c) 2020, 2022, Oracle and/or its affiliates.
|
# Copyright (c) 2020, 2023, Oracle and/or its affiliates.
|
||||||
#
|
#
|
||||||
# This software is dual-licensed to you under the Universal Permissive License
|
# This software is dual-licensed to you under the Universal Permissive License
|
||||||
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
||||||
|
@ -89,5 +89,11 @@ class TestCase(test_env.BaseTestCase):
|
||||||
(True,))
|
(True,))
|
||||||
self.assertEqual(result, "TRUE")
|
self.assertEqual(result, "TRUE")
|
||||||
|
|
||||||
|
def test_3108_bind_out_null(self):
|
||||||
|
"3108 - test binding out a boolean value (None)"
|
||||||
|
result = self.cursor.callfunc("pkg_TestBooleans.TestOutValueNull",
|
||||||
|
bool)
|
||||||
|
self.assertEqual(result, None)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
test_env.run_test_cases()
|
test_env.run_test_cases()
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
# Copyright (c) 2020, 2022, Oracle and/or its affiliates.
|
# Copyright (c) 2020, 2023, Oracle and/or its affiliates.
|
||||||
#
|
#
|
||||||
# This software is dual-licensed to you under the Universal Permissive License
|
# This software is dual-licensed to you under the Universal Permissive License
|
||||||
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
||||||
|
@ -539,5 +539,16 @@ class TestCase(test_env.BaseTestCase):
|
||||||
for e in self.cursor.getbatcherrors()]
|
for e in self.cursor.getbatcherrors()]
|
||||||
self.assertEqual(actual_errors, expected_errors)
|
self.assertEqual(actual_errors, expected_errors)
|
||||||
|
|
||||||
|
def test_3228_record_based_on_table_type(self):
|
||||||
|
"3228 - test %ROWTYPE record type"
|
||||||
|
type_obj = self.connection.gettype("TESTTEMPTABLE%ROWTYPE")
|
||||||
|
self.assertEqual(type_obj.attributes[3].name, "NUMBERCOL")
|
||||||
|
|
||||||
|
def test_3229_collection_of_records_based_on_table_type(self):
|
||||||
|
"3229 - test collection of %ROWTYPE record type"
|
||||||
|
type_name = "PKG_TESTBINDOBJECT.UDT_COLLECTIONROWTYPE"
|
||||||
|
type_obj = self.connection.gettype(type_name)
|
||||||
|
self.assertEqual(type_obj.element_type.attributes[3].name, "NUMBERCOL")
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
test_env.run_test_cases()
|
test_env.run_test_cases()
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
# Copyright (c) 2020, 2022, Oracle and/or its affiliates.
|
# Copyright (c) 2020, 2023, Oracle and/or its affiliates.
|
||||||
#
|
#
|
||||||
# This software is dual-licensed to you under the Universal Permissive License
|
# This software is dual-licensed to you under the Universal Permissive License
|
||||||
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
||||||
|
@ -826,5 +826,30 @@ class TestCase(test_env.BaseTestCase):
|
||||||
from dual""")
|
from dual""")
|
||||||
self.assertEqual(self.cursor.bindnames(), ["A", "B"])
|
self.assertEqual(self.cursor.bindnames(), ["A", "B"])
|
||||||
|
|
||||||
|
def test_4365_add_column_to_cached_query(self):
|
||||||
|
"4365 - test addition of column to cached query"
|
||||||
|
table_name = "test_4365"
|
||||||
|
try:
|
||||||
|
self.cursor.execute(f"drop table {table_name}")
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
data = ('val 1', 'val 2')
|
||||||
|
self.cursor.execute(f"create table {table_name} (col1 varchar2(10))")
|
||||||
|
self.cursor.execute(f"insert into {table_name} values (:1)", [data[0]])
|
||||||
|
self.connection.commit()
|
||||||
|
self.cursor.execute(f"select * from {table_name}")
|
||||||
|
self.assertEqual(self.cursor.fetchall(), [(data[0],)])
|
||||||
|
self.cursor.execute(f"alter table {table_name} add col2 varchar2(10)")
|
||||||
|
self.cursor.execute(f"update {table_name} set col2 = :1", [data[1]])
|
||||||
|
self.connection.commit()
|
||||||
|
self.cursor.execute(f"select * from {table_name}")
|
||||||
|
self.assertEqual(self.cursor.fetchall(), [data])
|
||||||
|
|
||||||
|
def test_4366_populate_array_var_with_too_many_elements(self):
|
||||||
|
"4366 - test population of array var with too many elements"
|
||||||
|
var = self.cursor.arrayvar(int, 3)
|
||||||
|
self.assertRaisesRegex(oracledb.ProgrammingError, "^DPY-2016:",
|
||||||
|
var.setvalue, 0, [1, 2, 3, 4])
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
test_env.run_test_cases()
|
test_env.run_test_cases()
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
# Copyright (c) 2021, 2022, Oracle and/or its affiliates.
|
# Copyright (c) 2021, 2023, Oracle and/or its affiliates.
|
||||||
#
|
#
|
||||||
# This software is dual-licensed to you under the Universal Permissive License
|
# This software is dual-licensed to you under the Universal Permissive License
|
||||||
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
||||||
|
@ -478,10 +478,9 @@ class TestCase(test_env.BaseTestCase):
|
||||||
tcp_connect_timeout=in_val)
|
tcp_connect_timeout=in_val)
|
||||||
tcp_timeout_val = f"(TRANSPORT_CONNECT_TIMEOUT={out_val})"
|
tcp_timeout_val = f"(TRANSPORT_CONNECT_TIMEOUT={out_val})"
|
||||||
connect_string = f"(DESCRIPTION={tcp_timeout_val}" + \
|
connect_string = f"(DESCRIPTION={tcp_timeout_val}" + \
|
||||||
f"(ADDRESS_LIST=(ADDRESS=(PROTOCOL=tcp)" + \
|
f"(ADDRESS=(PROTOCOL=tcp)" + \
|
||||||
f"(HOST={host})(PORT=1521)))(CONNECT_DATA=" + \
|
f"(HOST={host})(PORT=1521))(CONNECT_DATA=" + \
|
||||||
f"(SERVICE_NAME={service_name}))" + \
|
f"(SERVICE_NAME={service_name})))"
|
||||||
f"(SECURITY=(SSL_SERVER_DN_MATCH=ON)))"
|
|
||||||
self.assertEqual(params.get_connect_string(), connect_string)
|
self.assertEqual(params.get_connect_string(), connect_string)
|
||||||
|
|
||||||
def test_4532_multiple_alias_entry_tnsnames(self):
|
def test_4532_multiple_alias_entry_tnsnames(self):
|
||||||
|
@ -582,9 +581,15 @@ class TestCase(test_env.BaseTestCase):
|
||||||
f"(ADDRESS_LIST=" + \
|
f"(ADDRESS_LIST=" + \
|
||||||
f"(ADDRESS=(PROTOCOL=tcp)(HOST=host1)(PORT=1521))" + \
|
f"(ADDRESS=(PROTOCOL=tcp)(HOST=host1)(PORT=1521))" + \
|
||||||
f"(ADDRESS=(PROTOCOL=tcp)(HOST=host2)(PORT=1522)))" + \
|
f"(ADDRESS=(PROTOCOL=tcp)(HOST=host2)(PORT=1522)))" + \
|
||||||
f"(CONNECT_DATA=(SERVICE_NAME=my_service_35))" + \
|
f"(CONNECT_DATA=(SERVICE_NAME=my_service_35)))"
|
||||||
f"(SECURITY=(SSL_SERVER_DN_MATCH=ON)))"
|
|
||||||
self.assertEqual(params.get_connect_string(), connect_string)
|
self.assertEqual(params.get_connect_string(), connect_string)
|
||||||
|
|
||||||
|
def test_4537_no_connect_string(self):
|
||||||
|
"4537 - test connect parameters which generate no connect string"
|
||||||
|
params = oracledb.ConnectParams()
|
||||||
|
self.assertEqual(params.get_connect_string(), None)
|
||||||
|
params.set(mode=oracledb.SYSDBA)
|
||||||
|
self.assertEqual(params.get_connect_string(), None)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
test_env.run_test_cases()
|
test_env.run_test_cases()
|
||||||
|
|
Loading…
Reference in New Issue