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
|
||||
|
||||
A synonym for :data:`DB_TYPE_NVARCHAR`.
|
||||
A synonym for :data:`DB_TYPE_NCHAR`.
|
||||
|
||||
.. deprecated:: cx_Oracle 8.0
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ root_doc = master_doc = 'index'
|
|||
|
||||
# General substitutions.
|
||||
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'
|
||||
|
||||
# The default replacements for |version| and |release|, also used in various
|
||||
|
|
|
@ -10,7 +10,7 @@ License
|
|||
|
||||
.. 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
|
||||
(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>`.
|
||||
|
||||
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)
|
||||
------------------------------
|
||||
|
||||
|
|
|
@ -215,3 +215,22 @@ To convert dates:
|
|||
for row in cursor:
|
||||
print(row) # gives 'Mi 15 Dez 19:57:56 2021'
|
||||
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.
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
You can validate the python-oracledb mode by querying the ``CLIENT_DRIVER``
|
||||
column of ``V$SESSION_CONNECT_INFO`` and verifying the value of the column
|
||||
begins with ``python-oracledb thk``. See :ref:`vsessconinfo`.
|
||||
You can validate python-oracledb is running in Thick mode by querying the
|
||||
``CLIENT_DRIVER`` column of ``V$SESSION_CONNECT_INFO`` and verifying the value
|
||||
of the column begins with ``python-oracledb thk``. See :ref:`vsessconinfo`.
|
||||
|
||||
|
||||
.. _libinit:
|
||||
|
@ -54,26 +55,35 @@ Setting the Oracle Client Library Directory
|
|||
-------------------------------------------
|
||||
|
||||
When :meth:`~oracledb.init_oracle_client()` is called, python-oracledb
|
||||
dynamically loads Oracle Client libraries using a search heuristic. Only the
|
||||
first set of libraries found are loaded. The libraries can be:
|
||||
dynamically loads Oracle Client libraries using a search heuristic. The
|
||||
libraries can be:
|
||||
|
||||
- in an installation of Oracle Instant Client
|
||||
- or in a full Oracle Client installation
|
||||
- or in an Oracle Database installation (if Python is running on the same
|
||||
machine as the database).
|
||||
|
||||
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
|
||||
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:
|
||||
|
||||
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:
|
||||
|
||||
|
@ -121,8 +131,8 @@ On Windows, python-oracledb Thick mode can be enabled as follows:
|
|||
|
||||
.. _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:
|
||||
|
||||
|
@ -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
|
||||
Client library if Instant Client is in a different directory.
|
||||
|
||||
You can find the directory containing the Thick mode binary module by
|
||||
calling the python CLI without specifying a Python script, executing
|
||||
``import oracledb``, and then typing ``oracledb`` at the prompt. For
|
||||
example if
|
||||
``/Users/yourname/Library/3.9.6/lib/python3.9/site-packages/oracledb-1.0.0-py3.9-macosx-11.5-x86_64.egg/oracledb``
|
||||
contains ``thick_impl.cpython-39-darwin.so``, then you could run ``ln -s
|
||||
~/Downloads/instantclient_19_8/libclntsh.dylib
|
||||
~/Library/3.9.6/lib/python3.9/site-packages/oracledb-1.0.0-py3.9-macosx-11.5-x86_64.egg/oracledb/``.
|
||||
You can find the directory containing the Thick mode binary module by calling
|
||||
the python CLI without specifying a Python script, executing ``import
|
||||
oracledb``, and then typing ``oracledb`` at the prompt. For example this
|
||||
might show
|
||||
``/Users/yourname/.pyenv/versions/3.9.6/lib/python3.9/site-packages/oracledb/__init__.py``.
|
||||
After checking that
|
||||
``/Users/yourname/.pyenv/versions/3.9.6/lib/python3.9/site-packages/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
|
||||
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:
|
||||
|
||||
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
|
||||
follows:
|
||||
|
@ -207,16 +236,18 @@ follows:
|
|||
raised.
|
||||
|
||||
Ensure that the Python process has directory and file access permissions for
|
||||
the Oracle Client libraries. On Linux ensure a ``libclntsh.so`` file exists.
|
||||
On macOS ensure a ``libclntsh.dylib`` file exists. python-oracledb Thick will
|
||||
not directly load ``libclntsh.*.XX.1`` files in ``lib_dir`` or from the directory
|
||||
where the python-oracledb binary module is available. Note that other libraries
|
||||
used by ``libclntsh*`` are also required.
|
||||
the Oracle Client libraries. On some platforms OS restrictions may prevent the
|
||||
opening of Oracle Client libraries installed in unsafe paths, such as from a
|
||||
user directory. On Linux ensure a ``libclntsh.so`` file exists. On macOS
|
||||
ensure a ``libclntsh.dylib`` file exists. Python-oracledb Thick mode will not
|
||||
directly load ``libclntsh.*.XX.1`` files in ``lib_dir`` or from the directory
|
||||
where the python-oracledb binary module is available. Note that other
|
||||
libraries used by ``libclntsh*`` are also required.
|
||||
|
||||
.. _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()`
|
||||
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.
|
||||
|
||||
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:
|
||||
|
||||
.. 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":
|
||||
d = os.environ.get("HOME")+"/Downloads/instantclient_19_8")
|
||||
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)
|
||||
|
||||
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.
|
||||
|
||||
**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**
|
||||
|
||||
To trace the loading of Oracle Client libraries, the environment variable
|
||||
``DPI_DEBUG_LEVEL`` can be set to 64 before starting Python. For example, on
|
||||
Linux, you might use::
|
||||
``DPI_DEBUG_LEVEL`` can be set to 64 before starting Python. At a Windows
|
||||
command prompt, this could be done with::
|
||||
|
||||
$ export DPI_DEBUG_LEVEL=64
|
||||
$ python myapp.py 2> log.txt
|
||||
set DPI_DEBUG_LEVEL=64
|
||||
|
||||
On Linux and macOS, you might use::
|
||||
|
||||
export DPI_DEBUG_LEVEL=64
|
||||
|
||||
When your python-oracledb application is run, logging output is shown.
|
||||
|
||||
.. _optnetfiles:
|
||||
|
||||
|
|
|
@ -271,6 +271,10 @@ To use python-oracledb Thick mode with Oracle Instant Client zip files:
|
|||
cd /opt/oracle
|
||||
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::
|
||||
|
||||
sudo yum install libaio
|
||||
|
@ -827,9 +831,14 @@ used to install into a local directory::
|
|||
|
||||
python setup.py install --user
|
||||
|
||||
.. _troubleshooting:
|
||||
|
||||
Troubleshooting
|
||||
===============
|
||||
|
||||
Installation Troubleshooting
|
||||
----------------------------
|
||||
|
||||
If installation fails:
|
||||
|
||||
- An error such as ``not a supported wheel on this platform.`` indicates that
|
||||
|
@ -866,6 +875,11 @@ If installation fails:
|
|||
a subdirectory called "odpi" containing files. If this is missing, review the
|
||||
section on `Install Using GitHub`_.
|
||||
|
||||
.. _runtimetroubleshooting:
|
||||
|
||||
Runtime Error Troubleshooting
|
||||
-----------------------------
|
||||
|
||||
If using python-oracledb fails:
|
||||
|
||||
- If you have multiple versions of Python installed, ensure that you are
|
||||
|
@ -884,14 +898,19 @@ If using python-oracledb fails:
|
|||
should be the location of your Oracle Client libraries. Do not pass
|
||||
this parameter on Linux.
|
||||
|
||||
- Check that the Python process has permission to open the Oracle Client
|
||||
libraries. OS restrictions may prevent the opening of libraries installed
|
||||
in unsafe paths, such as from a user directory. On Linux you may need to
|
||||
install the Oracle Client libraries under a directory like ``/opt`` or
|
||||
``/usr/local``.
|
||||
|
||||
- Check if Python and your Oracle Client libraries are both 64-bit or
|
||||
both 32-bit. The ``DPI-1047`` message will tell you whether the 64-bit
|
||||
or 32-bit Oracle Client is needed for your Python.
|
||||
|
||||
- For Thick mode connections, set the environment variable
|
||||
``DPI_DEBUG_LEVEL`` to 64 and restart python-oracledb. The trace
|
||||
messages will show how and where python-oracledb is looking for the
|
||||
Oracle Client libraries.
|
||||
- Set the environment variable ``DPI_DEBUG_LEVEL`` to 64 and restart
|
||||
python-oracledb. The trace messages will show how and where
|
||||
python-oracledb is looking for the Oracle Client libraries.
|
||||
|
||||
At a Windows command prompt, this could be done with::
|
||||
|
||||
|
@ -919,9 +938,10 @@ If using python-oracledb fails:
|
|||
been installed.
|
||||
|
||||
- On Linux, check if the ``LD_LIBRARY_PATH`` environment variable contains
|
||||
the Oracle Client library directory. Or, if you are using Oracle
|
||||
Instant Client, a preferred alternative is to ensure that a file in the
|
||||
``/etc/ld.so.conf.d`` directory contains the path to the Instant Client
|
||||
the Oracle Client library directory. Some environments such as web servers
|
||||
reset environment variables. If you are using Oracle Instant Client, a
|
||||
preferred alternative to ``LD_LIBRARY_PATH`` is to ensure that a file in
|
||||
the ``/etc/ld.so.conf.d`` directory contains the path to the Instant Client
|
||||
directory, and then run ``ldconfig``.
|
||||
|
||||
- If you get the error ``DPY-3010: connections to this database server
|
||||
|
@ -931,8 +951,8 @@ If using python-oracledb fails:
|
|||
:meth:`oracledb.init_oracle_client()` in your code. Alternatively,
|
||||
upgrade your database.
|
||||
|
||||
- If you get the error "``DPI-1072: the Oracle Client library version is
|
||||
unsupported``", then review the installation requirements. The Thick
|
||||
- If you get the error ``DPI-1072: the Oracle Client library version is
|
||||
unsupported``, then review the installation requirements. The Thick
|
||||
mode of python-oracledb needs Oracle Client libraries 11.2 or later.
|
||||
Note that version 19 is not supported on Windows 7. Similar steps shown
|
||||
above for ``DPI-1047`` may help. You may be able to use Thin mode which
|
||||
|
|
|
@ -248,10 +248,10 @@ Python.
|
|||
Tuning Fetching from REF CURSORS
|
||||
--------------------------------
|
||||
|
||||
In python-oracledb, REF CURSORS can also be tuned by setting the values of
|
||||
``arraysize`` and ``prefetchrows``. The ``prefetchrows`` value must be set
|
||||
before calling the PL/SQL procedure as the REF CURSOR is executed on the
|
||||
server.
|
||||
In python-oracledb, fetching data from REF CURSORS can be tuned by setting the
|
||||
values of ``arraysize`` and ``prefetchrows``. The ``prefetchrows`` value must
|
||||
be set before calling the PL/SQL procedure because the REF CURSOR is executed
|
||||
on the server.
|
||||
|
||||
For example:
|
||||
|
||||
|
@ -272,6 +272,8 @@ For example:
|
|||
|
||||
.. _roundtrips:
|
||||
|
||||
Also see `Avoiding Premature Prefetching`_.
|
||||
|
||||
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
|
||||
# (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
|
||||
int lru_index
|
||||
|
||||
cdef bint _uses_tcps(self)
|
||||
cdef str build_connect_string(self)
|
||||
|
||||
|
||||
|
@ -191,7 +192,6 @@ cdef class ConnectParamsImpl:
|
|||
bytearray _token_obfuscator
|
||||
bytearray _private_key
|
||||
bytearray _private_key_obfuscator
|
||||
bint _has_components
|
||||
|
||||
cdef int _check_credentials(self) except -1
|
||||
cdef int _copy(self, ConnectParamsImpl other_params) except -1
|
||||
|
|
|
@ -158,5 +158,6 @@ TPC_END_SUSPEND = 0x00100000
|
|||
# basic configuration constants
|
||||
DRIVER_NAME = "python-oracledb"
|
||||
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"
|
||||
|
|
|
@ -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
|
||||
# (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)
|
||||
_set_bool_param(args, "externalauth", &self.externalauth)
|
||||
self._set_access_token_param(args.get("access_token"))
|
||||
if args:
|
||||
self._has_components = True
|
||||
|
||||
cdef int _check_credentials(self) except -1:
|
||||
"""
|
||||
|
@ -344,7 +342,6 @@ cdef class ConnectParamsImpl:
|
|||
# to be a full connect descriptor
|
||||
if connect_string.startswith("("):
|
||||
_parse_connect_descriptor(connect_string, args)
|
||||
self._has_components = True
|
||||
return self._process_connect_descriptor(args)
|
||||
|
||||
# otherwise, see if the connect string is an EasyConnect string
|
||||
|
@ -389,9 +386,6 @@ cdef class ConnectParamsImpl:
|
|||
_parse_connect_descriptor(connect_string, 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:
|
||||
"""
|
||||
Internal method used for processing the parsed connect descriptor into
|
||||
|
@ -538,7 +532,6 @@ cdef class ConnectParamsImpl:
|
|||
will be a connect string built up from the components supplied when the
|
||||
object was built.
|
||||
"""
|
||||
if self._has_components:
|
||||
return self.description_list.build_connect_string()
|
||||
|
||||
def get_full_user(self):
|
||||
|
@ -613,8 +606,10 @@ cdef class Address:
|
|||
|
||||
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).
|
||||
"""
|
||||
if self.host is not None:
|
||||
parts = [f"(PROTOCOL={self.protocol})",
|
||||
f"(HOST={self.host})",
|
||||
f"(PORT={self.port})"]
|
||||
|
@ -667,12 +662,25 @@ cdef class AddressList:
|
|||
def __init__(self):
|
||||
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):
|
||||
"""
|
||||
Build a connect string from the components.
|
||||
"""
|
||||
cdef Address a
|
||||
parts = [a.build_connect_string() for a in self.addresses]
|
||||
if len(parts) == 1:
|
||||
return parts[0]
|
||||
return f'(ADDRESS_LIST={"".join(parts)})'
|
||||
|
||||
def set_from_args(self, dict args):
|
||||
|
@ -713,37 +721,12 @@ cdef class Description:
|
|||
Build a connect string from the components.
|
||||
"""
|
||||
cdef:
|
||||
str connect_data, security, temp
|
||||
list parts, address_lists
|
||||
AddressList a
|
||||
AddressList address_list
|
||||
list parts, temp_parts
|
||||
bint uses_tcps = False
|
||||
str temp
|
||||
|
||||
# build connect data segment
|
||||
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
|
||||
# build top-level description parts
|
||||
parts = []
|
||||
if self.load_balance:
|
||||
parts.append("(LOAD_BALANCE=ON)")
|
||||
|
@ -758,10 +741,48 @@ cdef class Description:
|
|||
if self.tcp_connect_timeout != DEFAULT_TCP_CONNECT_TIMEOUT:
|
||||
temp = self._build_duration_str(self.tcp_connect_timeout)
|
||||
parts.append(f"(TRANSPORT_CONNECT_TIMEOUT={temp})")
|
||||
address_lists = [a.build_connect_string() for a in self.address_lists]
|
||||
parts.extend(address_lists)
|
||||
parts.append(connect_data)
|
||||
parts.append(security)
|
||||
|
||||
# add address lists, but if the address list contains only a single
|
||||
# entry and that entry does not have a host, the other parts aren't
|
||||
# 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)})'
|
||||
|
||||
def copy(self):
|
||||
|
|
|
@ -99,7 +99,7 @@ cdef class BaseVarImpl:
|
|||
if was_set != NULL:
|
||||
was_set[0] = False
|
||||
return 0
|
||||
errors._raise_err(errors.ERR_INCORRECT_VAR_ARRAY_SIZE,
|
||||
errors._raise_err(errors.ERR_INCORRECT_VAR_ARRAYSIZE,
|
||||
var_arraysize=self.num_elements,
|
||||
required_arraysize=num_elements_in_array)
|
||||
|
||||
|
|
|
@ -368,13 +368,15 @@ cdef class Buffer:
|
|||
|
||||
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:
|
||||
const char_type *ptr
|
||||
ssize_t 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
|
||||
|
||||
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
|
||||
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
||||
|
@ -719,11 +719,17 @@ cdef class ThinDbObjectTypeCache:
|
|||
t_SuperTypeOwner varchar2(128);
|
||||
t_SuperTypeName varchar2(128);
|
||||
t_SubTypeRefCursor sys_refcursor;
|
||||
t_Pos pls_integer;
|
||||
begin
|
||||
:ret_val := dbms_pickler.get_type_shape(:full_name, :oid,
|
||||
:version, :tds, t_Instantiable, t_SuperTypeOwner,
|
||||
t_SuperTypeName, :attrs_rc, t_SubTypeRefCursor);
|
||||
:package_name := null;
|
||||
if substr(:full_name, length(:full_name) - 7) = '%ROWTYPE' then
|
||||
t_Pos := instr(:full_name, '.');
|
||||
:schema := substr(:full_name, 1, t_Pos - 1);
|
||||
:name := substr(:full_name, t_Pos + 1);
|
||||
else
|
||||
begin
|
||||
select owner, type_name
|
||||
into :schema, :name
|
||||
|
@ -731,11 +737,17 @@ cdef class ThinDbObjectTypeCache:
|
|||
where type_oid = :oid;
|
||||
exception
|
||||
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;""")
|
||||
self.meta_cursor = cursor
|
||||
|
||||
|
@ -939,17 +951,23 @@ cdef class ThinDbObjectTypeCache:
|
|||
"""
|
||||
cdef:
|
||||
ThinDbObjectTypeImpl typ_impl
|
||||
str full_name
|
||||
str full_name, name, suffix
|
||||
while self.partial_types:
|
||||
typ_impl = self.partial_types.pop()
|
||||
if self.meta_cursor is None:
|
||||
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:
|
||||
full_name = f'"{typ_impl.schema}".' + \
|
||||
f'"{typ_impl.package_name}".' + \
|
||||
f'"{typ_impl.name}"'
|
||||
f'"{name}"{suffix}'
|
||||
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)
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
# (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)
|
||||
if not self.in_fetch:
|
||||
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) \
|
||||
else "characters"
|
||||
errors._raise_err(errors.ERR_COLUMN_TRUNCATED,
|
||||
|
@ -714,7 +716,8 @@ cdef class MessageWithData(Message):
|
|||
conn = self.cursor.connection
|
||||
for i in range(cursor_impl._num_columns):
|
||||
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)
|
||||
cursor_impl._create_fetch_var(conn, self.cursor, type_handler, i,
|
||||
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
|
||||
# (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.machine_name = socket.gethostname()
|
||||
self.pid = str(os.getpid())
|
||||
try:
|
||||
self.user_name = getpass.getuser()
|
||||
except:
|
||||
self.user_name = ""
|
||||
self.terminal_name = "unknown"
|
||||
self.sanitized_program_name = self._sanitize(self.program_name)
|
||||
self.sanitized_machine_name = self._sanitize(self.machine_name)
|
||||
|
|
|
@ -30,4 +30,4 @@
|
|||
# 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
|
||||
* (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
|
||||
) return number;
|
||||
|
||||
function TestOutValueNull
|
||||
return boolean;
|
||||
|
||||
procedure TestOutArrays (
|
||||
a_NumElements number,
|
||||
a_Value out nocopy udt_BooleanList
|
||||
|
@ -1011,6 +1014,12 @@ create or replace package body &main_user..pkg_TestBooleans as
|
|||
return t_Result;
|
||||
end;
|
||||
|
||||
function TestOutValueNull
|
||||
return boolean is
|
||||
begin
|
||||
return null;
|
||||
end;
|
||||
|
||||
procedure TestOutArrays (
|
||||
a_NumElements number,
|
||||
a_Value out nocopy udt_BooleanList
|
||||
|
@ -1026,6 +1035,10 @@ end;
|
|||
|
||||
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 (
|
||||
a_Object udt_Object
|
||||
) 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
|
||||
# (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,))
|
||||
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__":
|
||||
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
|
||||
# (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()]
|
||||
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__":
|
||||
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
|
||||
# (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""")
|
||||
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__":
|
||||
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
|
||||
# (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_timeout_val = f"(TRANSPORT_CONNECT_TIMEOUT={out_val})"
|
||||
connect_string = f"(DESCRIPTION={tcp_timeout_val}" + \
|
||||
f"(ADDRESS_LIST=(ADDRESS=(PROTOCOL=tcp)" + \
|
||||
f"(HOST={host})(PORT=1521)))(CONNECT_DATA=" + \
|
||||
f"(SERVICE_NAME={service_name}))" + \
|
||||
f"(SECURITY=(SSL_SERVER_DN_MATCH=ON)))"
|
||||
f"(ADDRESS=(PROTOCOL=tcp)" + \
|
||||
f"(HOST={host})(PORT=1521))(CONNECT_DATA=" + \
|
||||
f"(SERVICE_NAME={service_name})))"
|
||||
self.assertEqual(params.get_connect_string(), connect_string)
|
||||
|
||||
def test_4532_multiple_alias_entry_tnsnames(self):
|
||||
|
@ -582,9 +581,15 @@ class TestCase(test_env.BaseTestCase):
|
|||
f"(ADDRESS_LIST=" + \
|
||||
f"(ADDRESS=(PROTOCOL=tcp)(HOST=host1)(PORT=1521))" + \
|
||||
f"(ADDRESS=(PROTOCOL=tcp)(HOST=host2)(PORT=1522)))" + \
|
||||
f"(CONNECT_DATA=(SERVICE_NAME=my_service_35))" + \
|
||||
f"(SECURITY=(SSL_SERVER_DN_MATCH=ON)))"
|
||||
f"(CONNECT_DATA=(SERVICE_NAME=my_service_35)))"
|
||||
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__":
|
||||
test_env.run_test_cases()
|
||||
|
|
Loading…
Reference in New Issue