Compare commits
12 Commits
Author | SHA1 | Date |
---|---|---|
![]() |
f2f2ed9fd5 | |
![]() |
065d8ba81a | |
![]() |
790ee29d3c | |
![]() |
1674d8ce8f | |
![]() |
6dda5b597c | |
![]() |
0a59085f64 | |
![]() |
512826e028 | |
![]() |
d3e14f6b87 | |
![]() |
aa9b1daa65 | |
![]() |
b0f0c671b2 | |
![]() |
6f37dec1d9 | |
![]() |
25fb52b6b2 |
|
@ -1,4 +1,4 @@
|
|||
# python-oracledb 1.0
|
||||
# python-oracledb 1.1
|
||||
|
||||
python-oracledb is a [Python programming language][python] extension module
|
||||
allowing Python programs to connect to [Oracle Database][oracledb]. It is the
|
||||
|
|
|
@ -2066,9 +2066,9 @@ DB API Types
|
|||
.. data:: ROWID
|
||||
|
||||
This type object is used to describe the pseudo column "rowid". The
|
||||
database type :data:`DB_TYPE_ROWID` will compare equal to this value. If a
|
||||
variable is created with this type, the database type
|
||||
:data:`DB_TYPE_VARCHAR` will be used.
|
||||
database types :data:`DB_TYPE_ROWID` and :data:`DB_TYPE_UROWID` will
|
||||
compare equal to this value. If a variable is created with this type, the
|
||||
database type :data:`DB_TYPE_VARCHAR` will be used.
|
||||
|
||||
|
||||
.. data:: STRING
|
||||
|
@ -2281,6 +2281,17 @@ when binding data.
|
|||
:data:`DATETIME`.
|
||||
|
||||
|
||||
.. data:: DB_TYPE_UROWID
|
||||
|
||||
Describes columns, attributes or array elements in a database that are of
|
||||
type UROWID. It will compare equal to the DB API type :data:`ROWID`.
|
||||
|
||||
.. note::
|
||||
|
||||
This type is not supported in python-oracledb Thick mode.
|
||||
See :ref:`querymetadatadiff`.
|
||||
|
||||
|
||||
.. data:: DB_TYPE_VARCHAR
|
||||
|
||||
Describes columns, attributes or array elements in a database that are of
|
||||
|
|
|
@ -7,6 +7,40 @@ python-oracledb Release Notes
|
|||
|
||||
For deprecations, see :ref:`Deprecations <deprecations>`.
|
||||
|
||||
oracledb 1.1.1 (September 2022)
|
||||
-------------------------------
|
||||
|
||||
Thin Mode Changes
|
||||
+++++++++++++++++
|
||||
|
||||
#) Fixed bug that prevented binding data of types
|
||||
:data:`~oracledb.DB_TYPE_ROWID` and :data:`~oracledb.DB_TYPE_UROWID`.
|
||||
#) Fixed bug that caused :meth:`Connection.is_healthy()` to return `True`
|
||||
after a connection has been killed.
|
||||
#) Internally, before a connection is returned from a pool, perform additional
|
||||
checks in order to avoid returning a dead connection from the pool.
|
||||
|
||||
Thick Mode Changes
|
||||
++++++++++++++++++
|
||||
|
||||
#) Fixed bug returning metadata of SODA documents inserted into a collection
|
||||
using :meth:`SodaCollection.saveAndGet()`.
|
||||
|
||||
Common Changes
|
||||
++++++++++++++
|
||||
|
||||
#) Fixed type checking errors
|
||||
(`issue 52 <https://github.com/oracle/python-oracledb/issues/52>`__).
|
||||
#) Enhanced type checking
|
||||
(`issue 54 <https://github.com/oracle/python-oracledb/issues/54>`__),
|
||||
(`issue 60 <https://github.com/oracle/python-oracledb/issues/60>`__).
|
||||
#) The mode of python-oracledb is now fixed only after a call to
|
||||
:meth:`oracledb.init_oracle_client()`, :meth:`oracledb.connect()` or
|
||||
:meth:`oracledb.create_pool()` has completed successfully
|
||||
(`issue 44 <https://github.com/oracle/python-oracledb/issues/44>`__).
|
||||
#) Improved test suite and documentation.
|
||||
|
||||
|
||||
oracledb 1.1.0 (September 2022)
|
||||
-------------------------------
|
||||
|
||||
|
|
|
@ -463,11 +463,11 @@ values.
|
|||
* - ROWID
|
||||
- DB_TYPE_ROWID
|
||||
- Yes
|
||||
- cannot be set
|
||||
- bytes, str
|
||||
* - UROWID
|
||||
- DB_TYPE_ROWID
|
||||
- DB_TYPE_ROWID, DB_TYPE_UROWID (only supported in python-oracledb Thin mode)
|
||||
- Yes. May show DB_TYPE_UROWID in metadata. See :ref:`Query Metadata Differences <querymetadatadiff>`.
|
||||
- cannot be set
|
||||
- bytes, str
|
||||
* - CHAR
|
||||
- DB_TYPE_CHAR
|
||||
- Yes
|
||||
|
@ -578,7 +578,7 @@ these arrays.
|
|||
* - DB_TYPE_RAW
|
||||
- bytes, str
|
||||
* - DB_TYPE_ROWID
|
||||
- cannot be set
|
||||
- bytes, str
|
||||
* - DB_TYPE_TIMESTAMP
|
||||
- datetime.date, datetime.datetime
|
||||
* - DB_TYPE_TIMESTAMP_LTZ
|
||||
|
@ -586,6 +586,6 @@ these arrays.
|
|||
* - DB_TYPE_TIMESTAMP_TZ
|
||||
- datetime.date, datetime.datetime
|
||||
* - DB_TYPE_UROWID
|
||||
- cannot be set
|
||||
- bytes, str
|
||||
* - DB_TYPE_VARCHAR
|
||||
- bytes, str
|
||||
|
|
|
@ -183,6 +183,48 @@ fetching a row and then updating that row by binding its rowid:
|
|||
where rowid = :rid""", manager_id=205, rid=rowid)
|
||||
|
||||
|
||||
Binding UROWID Values
|
||||
=====================
|
||||
|
||||
Universal rowids (UROWID) are used to uniquely identify rows in index
|
||||
organized tables. In python-oracledb, UROWID values are represented as strings.
|
||||
The example below shows fetching a row from index organized table
|
||||
``universal_rowids`` and then updating that row by binding its urowid:
|
||||
|
||||
.. code-block:: sql
|
||||
|
||||
CREATE TABLE universal_rowids (
|
||||
int_col number(9) not null,
|
||||
str_col varchar2(250) not null,
|
||||
date_col date not null,
|
||||
CONSTRAINT universal_rowids_pk PRIMARY KEY(int_col, str_col, date_col)
|
||||
) ORGANIZATION INDEX
|
||||
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
ridvar = cursor.var(oracledb.DB_TYPE_UROWID)
|
||||
|
||||
# fetch the row
|
||||
cursor.execute("""
|
||||
begin
|
||||
select rowid into :rid from universal_rowids
|
||||
where int_col = 3;
|
||||
end;""", rid=ridvar)
|
||||
|
||||
# update the row by binding UROWID
|
||||
cursor.execute("""
|
||||
update universal_rowids set
|
||||
str_col = :str_val
|
||||
where rowid = :rowid_val""",
|
||||
str_val="String #33", rowid_val=ridvar)
|
||||
|
||||
Note that the type :attr:`oracledb.DB_TYPE_UROWID` is only supported in
|
||||
python-oracledb Thin mode. For python-oracledb Thick mode, the database type
|
||||
UROWID can be bound with type :attr:`oracledb.DB_TYPE_ROWID`.
|
||||
See :ref:`querymetadatadiff`.
|
||||
|
||||
|
||||
DML RETURNING Bind Variables
|
||||
============================
|
||||
|
||||
|
|
|
@ -795,13 +795,13 @@ In order to install using the source on GitHub, use the following commands::
|
|||
|
||||
Note that if you download a source zip file directly from GitHub then you will
|
||||
also need to download an `ODPI-C <https://github.com/oracle/odpi>`__ source zip
|
||||
file and put the extracted contents inside the subdirectory
|
||||
"python-oracledb-*/src/oracledb/impl/thick/odpi".
|
||||
file and put the extracted contents inside the "odpi" subdirectory, for example
|
||||
in "python-oracledb-main/src/oracledb/impl/thick/odpi".
|
||||
|
||||
Python-oracledb source code is also available from opensource.oracle.com. This
|
||||
can be installed with::
|
||||
|
||||
git clone --recurse-submodules git://opensource.oracle.com/git/oracle/python-oracledb.git
|
||||
git clone --recurse-submodules https://opensource.oracle.com/git/oracle/python-oracledb.git
|
||||
cd python-oracledb
|
||||
python setup.py build
|
||||
python setup.py install
|
||||
|
|
|
@ -239,7 +239,7 @@ Python object that is returned by default. Python types can be changed with
|
|||
- :attr:`oracledb.DB_TYPE_TIMESTAMP_TZ`
|
||||
- datetime.datetime [2]_
|
||||
* - UROWID
|
||||
- :attr:`oracledb.DB_TYPE_ROWID`
|
||||
- :attr:`oracledb.DB_TYPE_ROWID`, :attr:`oracledb.DB_TYPE_UROWID`
|
||||
- str
|
||||
* - VARCHAR2
|
||||
- :attr:`oracledb.DB_TYPE_VARCHAR`
|
||||
|
@ -744,15 +744,10 @@ Querying Corrupt Data
|
|||
If queries fail with the error "codec can't decode byte" when you select data,
|
||||
then:
|
||||
|
||||
* Check your :ref:`character set <globalization>` is correct. Review the
|
||||
* Check if your :ref:`character set <globalization>` is correct. Review the
|
||||
:ref:`database character sets <findingcharset>`. Check with
|
||||
:ref:`fetching-raw-data`. Consider using UTF-8, if this is appropriate:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
connection = oracledb.connect(user="hr", password=userpwd,
|
||||
dsn="dbhost.example.com/orclpdb",
|
||||
encoding="UTF-8", nencoding="UTF-8")
|
||||
:ref:`fetching-raw-data`. Note that the encoding used for all character
|
||||
data in python-oracledb is "UTF-8".
|
||||
|
||||
* Check for corrupt data in the database.
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ classifiers =
|
|||
zip_safe = false
|
||||
python_requires = >=3.6
|
||||
setup_requires = cython
|
||||
install_requires = cryptography>=3.4
|
||||
install_requires = cryptography>=3.2.1
|
||||
test_suite = tests
|
||||
packages = find:
|
||||
package_dir =
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
import datetime
|
||||
|
||||
from . import connection as connection_module
|
||||
from typing import Type, Union
|
||||
from typing import Union, List
|
||||
from . import errors, exceptions
|
||||
from .dbobject import DbObject, DbObjectType
|
||||
|
||||
|
@ -48,7 +48,7 @@ class Queue:
|
|||
queue._impl = impl
|
||||
return queue
|
||||
|
||||
def _verify_message(self, message: Type["MessageProperties"]) -> None:
|
||||
def _verify_message(self, message: "MessageProperties") -> None:
|
||||
"""
|
||||
Internal method used for verifying a message.
|
||||
"""
|
||||
|
@ -58,7 +58,7 @@ class Queue:
|
|||
errors._raise_err(errors.ERR_MESSAGE_HAS_NO_PAYLOAD)
|
||||
|
||||
@property
|
||||
def connection(self) -> Type["connection_module.Connection"]:
|
||||
def connection(self) -> "connection_module.Connection":
|
||||
"""
|
||||
Returns the connection on which the queue was created.
|
||||
"""
|
||||
|
@ -72,13 +72,13 @@ class Queue:
|
|||
message_impls = self._impl.deq_many(max_num_messages)
|
||||
return [MessageProperties._from_impl(impl) for impl in message_impls]
|
||||
|
||||
def deqMany(self, max_num_messages: int) -> list:
|
||||
def deqMany(self, max_num_messages: int) -> List["MessageProperties"]:
|
||||
"""
|
||||
Deprecated: use deqmany() instead.
|
||||
"""
|
||||
return self.deqmany(max_num_messages)
|
||||
|
||||
def deqone(self) -> Union[Type["MessageProperties"], None]:
|
||||
def deqone(self) -> Union["MessageProperties", None]:
|
||||
"""
|
||||
Dequeues at most one message from the queue and returns it. If no
|
||||
message is dequeued, None is returned.
|
||||
|
@ -87,14 +87,14 @@ class Queue:
|
|||
if message_impl is not None:
|
||||
return MessageProperties._from_impl(message_impl)
|
||||
|
||||
def deqOne(self) -> Union[Type["MessageProperties"], None]:
|
||||
def deqOne(self) -> Union["MessageProperties", None]:
|
||||
"""
|
||||
Deprecated: use deqone() instead.
|
||||
"""
|
||||
return self.deqone()
|
||||
|
||||
@property
|
||||
def deqoptions(self) -> Type["DeqOptions"]:
|
||||
def deqoptions(self) -> "DeqOptions":
|
||||
"""
|
||||
Returns the options that will be used when dequeuing messages from the
|
||||
queue.
|
||||
|
@ -102,7 +102,7 @@ class Queue:
|
|||
return self._deq_options
|
||||
|
||||
@property
|
||||
def deqOptions(self) -> Type["DeqOptions"]:
|
||||
def deqOptions(self) -> "DeqOptions":
|
||||
"""
|
||||
Deprecated: use deqoptions instead.
|
||||
"""
|
||||
|
@ -131,7 +131,7 @@ class Queue:
|
|||
"""
|
||||
return self.enqmany(messages)
|
||||
|
||||
def enqone(self, message: Type["MessageProperties"]) -> None:
|
||||
def enqone(self, message: "MessageProperties") -> None:
|
||||
"""
|
||||
Enqueues a single message into the queue. The message must be a message
|
||||
property object which has had its payload attribute set to a value that
|
||||
|
@ -140,14 +140,14 @@ class Queue:
|
|||
self._verify_message(message)
|
||||
self._impl.enq_one(message._impl)
|
||||
|
||||
def enqOne(self, message: Type["MessageProperties"]) -> None:
|
||||
def enqOne(self, message: "MessageProperties") -> None:
|
||||
"""
|
||||
Deprecated: use enqone() instead.
|
||||
"""
|
||||
return self.enqone(message)
|
||||
|
||||
@property
|
||||
def enqoptions(self) -> Type["EnqOptions"]:
|
||||
def enqoptions(self) -> "EnqOptions":
|
||||
"""
|
||||
Returns the options that will be used when enqueuing messages into the
|
||||
queue.
|
||||
|
@ -155,7 +155,7 @@ class Queue:
|
|||
return self._enq_options
|
||||
|
||||
@property
|
||||
def enqOptions(self) -> Type["EnqOptions"]:
|
||||
def enqOptions(self) -> "EnqOptions":
|
||||
"""
|
||||
Deprecated: use enqoptions() instead.
|
||||
"""
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
#------------------------------------------------------------------------------
|
||||
|
||||
import functools
|
||||
from typing import Type, Union, Callable
|
||||
from typing import Union, Callable
|
||||
|
||||
import oracledb
|
||||
|
||||
|
@ -575,7 +575,7 @@ class ConnectParams:
|
|||
"""
|
||||
return self._impl.wallet_location
|
||||
|
||||
def copy(self) -> Type["ConnectParams"]:
|
||||
def copy(self) -> "ConnectParams":
|
||||
"""
|
||||
Creates a copy of the parameters and returns it.
|
||||
"""
|
||||
|
|
|
@ -64,7 +64,7 @@ class Connection:
|
|||
|
||||
def __init__(self,
|
||||
dsn: str=None, *,
|
||||
pool: Type["pool_module.ConnectionPool"]=None,
|
||||
pool: "pool_module.ConnectionPool"=None,
|
||||
params: ConnectParams=None,
|
||||
**kwargs) -> None:
|
||||
"""
|
||||
|
@ -99,51 +99,52 @@ class Connection:
|
|||
self._impl = None
|
||||
|
||||
# determine if thin mode is being used
|
||||
thin = driver_mode.check_and_return_mode()
|
||||
with driver_mode.get_manager() as mode_mgr:
|
||||
thin = mode_mgr.thin
|
||||
|
||||
# determine which connection parameters to use
|
||||
if params is None:
|
||||
params_impl = base_impl.ConnectParamsImpl()
|
||||
elif not isinstance(params, ConnectParams):
|
||||
errors._raise_err(errors.ERR_INVALID_CONNECT_PARAMS)
|
||||
else:
|
||||
params_impl = params._impl.copy()
|
||||
if kwargs:
|
||||
params_impl.set(kwargs)
|
||||
if dsn is not None:
|
||||
dsn = params_impl.parse_dsn(dsn, thin)
|
||||
if dsn is None:
|
||||
dsn = params_impl.get_connect_string()
|
||||
|
||||
# see if connection is being acquired from a pool
|
||||
if pool is None:
|
||||
pool_impl = None
|
||||
elif not isinstance(pool, pool_module.ConnectionPool):
|
||||
message = "pool must be an instance of oracledb.ConnectionPool"
|
||||
raise TypeError(message)
|
||||
else:
|
||||
pool._verify_open()
|
||||
pool_impl = pool._impl
|
||||
|
||||
# create thin or thick implementation object
|
||||
if thin:
|
||||
if pool is not None:
|
||||
impl = pool_impl.acquire(params_impl)
|
||||
# determine which connection parameters to use
|
||||
if params is None:
|
||||
params_impl = base_impl.ConnectParamsImpl()
|
||||
elif not isinstance(params, ConnectParams):
|
||||
errors._raise_err(errors.ERR_INVALID_CONNECT_PARAMS)
|
||||
else:
|
||||
impl = thin_impl.ThinConnImpl(dsn, params_impl)
|
||||
impl.connect(params_impl)
|
||||
else:
|
||||
impl = thick_impl.ThickConnImpl(dsn, params_impl)
|
||||
impl.connect(params_impl, pool_impl)
|
||||
self._impl = impl
|
||||
self._version = None
|
||||
params_impl = params._impl.copy()
|
||||
if kwargs:
|
||||
params_impl.set(kwargs)
|
||||
if dsn is not None:
|
||||
dsn = params_impl.parse_dsn(dsn, thin)
|
||||
if dsn is None:
|
||||
dsn = params_impl.get_connect_string()
|
||||
|
||||
# invoke callback, if applicable
|
||||
if impl.invoke_session_callback and pool is not None \
|
||||
and pool.session_callback is not None \
|
||||
and callable(pool.session_callback):
|
||||
pool.session_callback(self, params_impl.tag)
|
||||
impl.invoke_session_callback = False
|
||||
# see if connection is being acquired from a pool
|
||||
if pool is None:
|
||||
pool_impl = None
|
||||
elif not isinstance(pool, pool_module.ConnectionPool):
|
||||
message = "pool must be an instance of oracledb.ConnectionPool"
|
||||
raise TypeError(message)
|
||||
else:
|
||||
pool._verify_open()
|
||||
pool_impl = pool._impl
|
||||
|
||||
# create thin or thick implementation object
|
||||
if thin:
|
||||
if pool is not None:
|
||||
impl = pool_impl.acquire(params_impl)
|
||||
else:
|
||||
impl = thin_impl.ThinConnImpl(dsn, params_impl)
|
||||
impl.connect(params_impl)
|
||||
else:
|
||||
impl = thick_impl.ThickConnImpl(dsn, params_impl)
|
||||
impl.connect(params_impl, pool_impl)
|
||||
self._impl = impl
|
||||
self._version = None
|
||||
|
||||
# invoke callback, if applicable
|
||||
if impl.invoke_session_callback and pool is not None \
|
||||
and pool.session_callback is not None \
|
||||
and callable(pool.session_callback):
|
||||
pool.session_callback(self, params_impl.tag)
|
||||
impl.invoke_session_callback = False
|
||||
|
||||
def __del__(self):
|
||||
if self._impl is not None:
|
||||
|
@ -502,7 +503,7 @@ class Connection:
|
|||
This function performs a local check. To fully check a connection's
|
||||
health, use ping() which performs a round-trip to the database.
|
||||
"""
|
||||
return self._impl.get_is_healthy()
|
||||
return self._impl is not None and self._impl.get_is_healthy()
|
||||
|
||||
@property
|
||||
def ltxid(self) -> bytes:
|
||||
|
@ -603,7 +604,7 @@ class Connection:
|
|||
"""
|
||||
return self.tpc_prepare()
|
||||
|
||||
def queue(self, name: str, payload_type: [DbObjectType, str]=None, *,
|
||||
def queue(self, name: str, payload_type: Union[DbObjectType, str]=None, *,
|
||||
payloadType: DbObjectType=None) -> Queue:
|
||||
"""
|
||||
Creates and returns a queue which is used to enqueue and dequeue
|
||||
|
@ -1001,7 +1002,7 @@ def _connection_factory(f):
|
|||
"""
|
||||
@functools.wraps(f)
|
||||
def connect(dsn: str=None, *,
|
||||
pool: Type["pool_module.ConnectionPool"]=None,
|
||||
pool: "pool_module.ConnectionPool"=None,
|
||||
conn_class: Type[Connection]=Connection,
|
||||
params: ConnectParams=None,
|
||||
**kwargs) -> Connection:
|
||||
|
@ -1014,7 +1015,7 @@ def _connection_factory(f):
|
|||
|
||||
@_connection_factory
|
||||
def connect(dsn: str=None, *,
|
||||
pool: Type["pool_module.ConnectionPool"]=None,
|
||||
pool: "pool_module.ConnectionPool"=None,
|
||||
conn_class: Type[Connection]=Connection,
|
||||
params: ConnectParams=None,
|
||||
user: str=None,
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
# fetching results from queries.
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
from typing import Any, Type, Union, Callable
|
||||
from typing import Any, Union, Callable
|
||||
|
||||
from . import __name__ as MODULE_NAME
|
||||
from . import errors, exceptions
|
||||
|
@ -42,7 +42,7 @@ from .dbobject import DbObjectType
|
|||
class Cursor:
|
||||
__module__ = MODULE_NAME
|
||||
|
||||
def __init__(self, connection: Type["connection_module.Connection"],
|
||||
def __init__(self, connection: "connection_module.Connection",
|
||||
scrollable: bool = False) -> None:
|
||||
self._impl = None
|
||||
self.connection = connection
|
||||
|
@ -309,7 +309,7 @@ class Cursor:
|
|||
|
||||
def execute(self, statement: Union[str, None],
|
||||
parameters: Union[list, tuple, dict]=None,
|
||||
**keyword_parameters: dict) -> Union[Type["Cursor"], None]:
|
||||
**keyword_parameters: dict) -> Union["Cursor", None]:
|
||||
"""
|
||||
Execute a statement against the database.
|
||||
|
||||
|
@ -739,7 +739,7 @@ class Cursor:
|
|||
encoding_errors: str=None,
|
||||
bypass_decode: bool=False,
|
||||
*,
|
||||
encodingErrors: str=None) -> Type["Var"]:
|
||||
encodingErrors: str=None) -> "Var":
|
||||
"""
|
||||
Create a variable with the specified characteristics. This method was
|
||||
designed for use with PL/SQL in/out variables where the length or type
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
# object type metadata: DbObject, DbObjectType and DbObjectAttr.
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
from typing import Sequence, Type, Union
|
||||
from typing import Sequence, Union
|
||||
|
||||
from . import __name__ as MODULE_NAME
|
||||
from .base_impl import DbType
|
||||
|
@ -91,7 +91,7 @@ class DbObject:
|
|||
ix = self._impl.get_next_index(ix)
|
||||
return result
|
||||
|
||||
def copy(self) -> Type["DbObject"]:
|
||||
def copy(self) -> "DbObject":
|
||||
"""
|
||||
Create a copy of the object and return it.
|
||||
"""
|
||||
|
@ -181,7 +181,7 @@ class DbObject:
|
|||
self._impl.trim(num)
|
||||
|
||||
@property
|
||||
def type(self) -> Type["DbObjectType"]:
|
||||
def type(self) -> "DbObjectType":
|
||||
"""
|
||||
Returns an ObjectType corresponding to the type of the object.
|
||||
"""
|
||||
|
@ -211,7 +211,7 @@ class DbObjectAttr:
|
|||
return self._impl.name
|
||||
|
||||
@property
|
||||
def type(self) -> Union[Type["DbObjectType"], DbType]:
|
||||
def type(self) -> Union["DbObjectType", DbType]:
|
||||
"""
|
||||
This read-only attribute returns the type of the attribute. This will
|
||||
be an Oracle Object Type if the variable binds Oracle objects;
|
||||
|
@ -274,7 +274,7 @@ class DbObjectType:
|
|||
return self._impl.name
|
||||
|
||||
@property
|
||||
def element_type(self) -> Union[Type["DbObjectType"], DbType]:
|
||||
def element_type(self) -> Union["DbObjectType", DbType]:
|
||||
"""
|
||||
This read-only attribute returns the type of elements found in
|
||||
collections of this type, if iscollection is True; otherwise, it
|
||||
|
|
|
@ -31,27 +31,63 @@
|
|||
# simultaneously.
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
import threading
|
||||
|
||||
from . import errors
|
||||
|
||||
# this flag is used to indicate which mode is currently being used:
|
||||
# None: neither thick nor thin implementation has been used yet
|
||||
# False: thick implementation is being used
|
||||
# True: thin implementation is being used
|
||||
thin_mode = None
|
||||
|
||||
def check_and_return_mode(requested_thin_mode=None):
|
||||
# The DriverModeHandler class is used to manage which mode the driver is using.
|
||||
#
|
||||
# The "thin_mode" flag contains the current state:
|
||||
# None: neither thick nor thin implementation has been used yet
|
||||
# False: thick implementation is being used
|
||||
# True: thin implementation is being used
|
||||
#
|
||||
# The "requested_thin_mode" flag is set to the mode that is being requested:
|
||||
# False: thick implementation is being initialized
|
||||
# True: thin implementation is being initialized
|
||||
class DriverModeManager:
|
||||
"""
|
||||
Internal function to return the current mode of python-oracledb.
|
||||
Manages the mode the driver is using. The "thin_mode" flag contains the
|
||||
current state:
|
||||
None: neither thick nor thin implementation has been used yet
|
||||
False: thick implementation is being used
|
||||
True: thin implementation is being used
|
||||
The "requested_thin_mode" is set to the mode that is being requested, but
|
||||
only while initialization is taking place (otherwise, it contains the value
|
||||
None):
|
||||
False: thick implementation is being initialized
|
||||
True: thin implementation is being initialized
|
||||
The condition is used to ensure that only one thread is performing
|
||||
initialization.
|
||||
"""
|
||||
def __init__(self):
|
||||
self.thin_mode = None
|
||||
self.requested_thin_mode = None
|
||||
self.condition = threading.Condition()
|
||||
|
||||
If neither the thick nor the thin implementation have been used yet (the
|
||||
value of thin_mode is None), then:
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
- the mode is set to the requested mode, or
|
||||
def __exit__(self, exc_type, exc_value, exc_tb):
|
||||
with self.condition:
|
||||
if exc_type is None and exc_value is None and exc_tb is None \
|
||||
and self.requested_thin_mode is not None:
|
||||
self.thin_mode = self.requested_thin_mode
|
||||
self.requested_thin_mode = None
|
||||
self.condition.notify()
|
||||
|
||||
- the mode is set to thin, if no mode is requested.
|
||||
@property
|
||||
def thin(self):
|
||||
if self.requested_thin_mode is not None:
|
||||
return self.requested_thin_mode
|
||||
return self.thin_mode
|
||||
|
||||
Otherwise, if requested_thin_mode is used and the mode requested
|
||||
does not match the current mode, an error is raised.
|
||||
manager = DriverModeManager()
|
||||
|
||||
def get_manager(requested_thin_mode=None):
|
||||
"""
|
||||
Returns the manager, but only after ensuring that no other threads are
|
||||
attempting to initialize the mode.
|
||||
|
||||
NOTE: the current implementation of the driver only requires
|
||||
requested_thin_mode to be set when initializing the thick mode; for this
|
||||
|
@ -59,15 +95,19 @@ def check_and_return_mode(requested_thin_mode=None):
|
|||
being created. If this assumption changes, a new error message will be
|
||||
required.
|
||||
"""
|
||||
global thin_mode
|
||||
if thin_mode is None:
|
||||
if requested_thin_mode is None:
|
||||
thin_mode = True
|
||||
else:
|
||||
thin_mode = requested_thin_mode
|
||||
elif requested_thin_mode is not None and requested_thin_mode != thin_mode:
|
||||
errors._raise_err(errors.ERR_THIN_CONNECTION_ALREADY_CREATED)
|
||||
return thin_mode
|
||||
with manager.condition:
|
||||
if manager.thin_mode is None:
|
||||
if manager.requested_thin_mode is not None:
|
||||
manager.condition.wait()
|
||||
if manager.thin_mode is None:
|
||||
if requested_thin_mode is None:
|
||||
manager.requested_thin_mode = True
|
||||
else:
|
||||
manager.requested_thin_mode = requested_thin_mode
|
||||
elif requested_thin_mode is not None \
|
||||
and requested_thin_mode != manager.thin_mode:
|
||||
errors._raise_err(errors.ERR_THIN_CONNECTION_ALREADY_CREATED)
|
||||
return manager
|
||||
|
||||
|
||||
def is_thin_mode() -> bool:
|
||||
|
@ -77,14 +117,14 @@ def is_thin_mode() -> bool:
|
|||
|
||||
Immediately after python-oracledb is imported, this function will return
|
||||
True indicating that python-oracledb defaults to Thin mode. If
|
||||
oracledb.init_oracle_client() is called, then a subsequent call to
|
||||
is_thin_mode() will return False indicating that Thick mode is enabled.
|
||||
Once the first standalone connection or connection pool is created, or a
|
||||
call to oracledb.init_oracle_client() is made, then python-oracledb's mode
|
||||
is fixed and the value returned by is_thin_mode() will never change for the
|
||||
lifetime of the process.
|
||||
oracledb.init_oracle_client() is called successfully, then a subsequent
|
||||
call to is_thin_mode() will return False indicating that Thick mode is
|
||||
enabled. Once the first standalone connection or connection pool is
|
||||
created succesfully, or a call to oracledb.init_oracle_client() is made
|
||||
successfully, then python-oracledb's mode is fixed and the value returned
|
||||
by is_thin_mode() will never change for the lifetime of the process.
|
||||
|
||||
"""
|
||||
if thin_mode is not None:
|
||||
return thin_mode
|
||||
if manager.thin_mode is not None:
|
||||
return manager.thin_mode
|
||||
return True
|
||||
|
|
|
@ -452,31 +452,32 @@ def init_oracle_client(lib_dir=None, config_dir=None, error_url=None,
|
|||
if params_tuple != driver_context_params:
|
||||
errors._raise_err(errors.ERR_LIBRARY_ALREADY_INITIALIZED)
|
||||
return
|
||||
driver_mode.check_and_return_mode(requested_thin_mode=False)
|
||||
memset(¶ms, 0, sizeof(dpiContextCreateParams))
|
||||
encoding_bytes = constants.ENCODING.encode()
|
||||
params.defaultEncoding = encoding_bytes
|
||||
if config_dir is None:
|
||||
config_dir = defaults.config_dir
|
||||
if lib_dir is not None:
|
||||
lib_dir_bytes = lib_dir.encode()
|
||||
params.oracleClientLibDir = lib_dir_bytes
|
||||
if config_dir is not None:
|
||||
config_dir_bytes = config_dir.encode()
|
||||
params.oracleClientConfigDir = config_dir_bytes
|
||||
if driver_name is None:
|
||||
driver_name = f"{constants.DRIVER_NAME} thk : {VERSION}"
|
||||
driver_name_bytes = driver_name.encode()
|
||||
params.defaultDriverName = driver_name_bytes
|
||||
if error_url is not None:
|
||||
error_url_bytes = error_url.encode()
|
||||
else:
|
||||
error_url_bytes = constants.INSTALLATION_URL.encode()
|
||||
params.loadErrorUrl = error_url_bytes
|
||||
if dpiContext_createWithParams(DPI_MAJOR_VERSION, DPI_MINOR_VERSION,
|
||||
¶ms, &driver_context, &error_info) < 0:
|
||||
_raise_from_info(&error_info)
|
||||
driver_context_params = params_tuple
|
||||
with driver_mode.get_manager(requested_thin_mode=False) as mode_mgr:
|
||||
memset(¶ms, 0, sizeof(dpiContextCreateParams))
|
||||
encoding_bytes = constants.ENCODING.encode()
|
||||
params.defaultEncoding = encoding_bytes
|
||||
if config_dir is None:
|
||||
config_dir = defaults.config_dir
|
||||
if lib_dir is not None:
|
||||
lib_dir_bytes = lib_dir.encode()
|
||||
params.oracleClientLibDir = lib_dir_bytes
|
||||
if config_dir is not None:
|
||||
config_dir_bytes = config_dir.encode()
|
||||
params.oracleClientConfigDir = config_dir_bytes
|
||||
if driver_name is None:
|
||||
driver_name = f"{constants.DRIVER_NAME} thk : {VERSION}"
|
||||
driver_name_bytes = driver_name.encode()
|
||||
params.defaultDriverName = driver_name_bytes
|
||||
if error_url is not None:
|
||||
error_url_bytes = error_url.encode()
|
||||
else:
|
||||
error_url_bytes = constants.INSTALLATION_URL.encode()
|
||||
params.loadErrorUrl = error_url_bytes
|
||||
if dpiContext_createWithParams(DPI_MAJOR_VERSION, DPI_MINOR_VERSION,
|
||||
¶ms, &driver_context,
|
||||
&error_info) < 0:
|
||||
_raise_from_info(&error_info)
|
||||
driver_context_params = params_tuple
|
||||
|
||||
|
||||
def init_thick_impl(package):
|
||||
|
|
|
@ -1016,15 +1016,22 @@ cdef class ReadBuffer:
|
|||
const char_type *input_ptr
|
||||
bytearray output_value
|
||||
uint32_t num_bytes
|
||||
uint8_t length
|
||||
Rowid rowid
|
||||
|
||||
# check for null
|
||||
self.read_ub4(&num_bytes)
|
||||
if num_bytes == 0:
|
||||
self.read_ub1(&length)
|
||||
if _is_null_length(length):
|
||||
return None
|
||||
|
||||
# handle physical rowid
|
||||
if length == 1:
|
||||
self.skip_ub1()
|
||||
else:
|
||||
self.read_ub4(&num_bytes)
|
||||
|
||||
self.read_raw_bytes_chunked(&input_ptr, &input_len)
|
||||
|
||||
# handle physical rowid
|
||||
if input_ptr[0] == 1:
|
||||
rowid.rba = unpack_uint32(&input_ptr[1], BYTE_ORDER_MSB)
|
||||
rowid.partition_id = unpack_uint16(&input_ptr[5], BYTE_ORDER_MSB)
|
||||
|
|
|
@ -325,7 +325,8 @@ cdef class ThinConnImpl(BaseConnImpl):
|
|||
return self._internal_name
|
||||
|
||||
def get_is_healthy(self):
|
||||
return not self._protocol._read_buf._session_needs_to_be_closed
|
||||
return self._protocol._socket is not None \
|
||||
and not self._protocol._read_buf._session_needs_to_be_closed
|
||||
|
||||
def get_ltxid(self):
|
||||
return self._ltxid or b''
|
||||
|
|
|
@ -621,6 +621,7 @@ DEF TNS_MAX_CURSORS_TO_CLOSE = 500
|
|||
DEF TNS_TXN_IN_PROGRESS = 0x00000002
|
||||
DEF TNS_MAX_CONNECT_DATA = 230
|
||||
DEF TNS_CHUNK_SIZE = 32767
|
||||
DEF TNS_MAX_UROWID_LENGTH = 3950
|
||||
|
||||
# base 64 encoding alphabet
|
||||
DEF TNS_BASE64_ALPHABET = \
|
||||
|
|
|
@ -537,7 +537,8 @@ cdef class MessageWithData(Message):
|
|||
if var_impl.bypass_decode:
|
||||
ora_type_num = TNS_DATA_TYPE_RAW
|
||||
if buffer_size == 0 and ora_type_num != TNS_DATA_TYPE_LONG \
|
||||
and ora_type_num != TNS_DATA_TYPE_LONG_RAW:
|
||||
and ora_type_num != TNS_DATA_TYPE_LONG_RAW \
|
||||
and ora_type_num != TNS_DATA_TYPE_UROWID:
|
||||
column_value = None # column is null by describe
|
||||
elif ora_type_num == TNS_DATA_TYPE_VARCHAR \
|
||||
or ora_type_num == TNS_DATA_TYPE_CHAR \
|
||||
|
@ -557,7 +558,7 @@ cdef class MessageWithData(Message):
|
|||
column_value = buf.read_date()
|
||||
elif ora_type_num == TNS_DATA_TYPE_ROWID:
|
||||
if not self.in_fetch:
|
||||
column_value = buf.read_urowid()
|
||||
column_value = buf.read_str(TNS_CS_IMPLICIT)
|
||||
else:
|
||||
buf.read_ub1(&num_bytes)
|
||||
if _is_null_length(num_bytes):
|
||||
|
@ -566,7 +567,10 @@ cdef class MessageWithData(Message):
|
|||
buf.read_rowid(&rowid)
|
||||
column_value = _encode_rowid(&rowid)
|
||||
elif ora_type_num == TNS_DATA_TYPE_UROWID:
|
||||
column_value = buf.read_urowid()
|
||||
if not self.in_fetch:
|
||||
column_value = buf.read_str(TNS_CS_IMPLICIT)
|
||||
else:
|
||||
column_value = buf.read_urowid()
|
||||
elif ora_type_num == TNS_DATA_TYPE_BINARY_DOUBLE:
|
||||
column_value = buf.read_binary_double()
|
||||
elif ora_type_num == TNS_DATA_TYPE_BINARY_FLOAT:
|
||||
|
@ -895,11 +899,14 @@ cdef class MessageWithData(Message):
|
|||
list bind_var_impls) except -1:
|
||||
cdef:
|
||||
uint8_t ora_type_num, flag
|
||||
uint32_t buffer_size
|
||||
ThinVarImpl var_impl
|
||||
for var_impl in bind_var_impls:
|
||||
ora_type_num = var_impl.dbtype._ora_type_num
|
||||
if ora_type_num == TNS_DATA_TYPE_ROWID:
|
||||
ora_type_num = TNS_DATA_TYPE_UROWID
|
||||
buffer_size = var_impl.buffer_size
|
||||
if ora_type_num in (TNS_DATA_TYPE_ROWID, TNS_DATA_TYPE_UROWID):
|
||||
ora_type_num = TNS_DATA_TYPE_VARCHAR
|
||||
buffer_size = TNS_MAX_UROWID_LENGTH
|
||||
flag = TNS_BIND_USE_INDICATORS
|
||||
if var_impl.is_array:
|
||||
flag |= TNS_BIND_ARRAY
|
||||
|
@ -909,10 +916,10 @@ cdef class MessageWithData(Message):
|
|||
# expects that and complains if any other value is sent!
|
||||
buf.write_uint8(0)
|
||||
buf.write_uint8(0)
|
||||
if var_impl.buffer_size >= TNS_MIN_LONG_LENGTH:
|
||||
if buffer_size >= TNS_MIN_LONG_LENGTH:
|
||||
buf.write_ub4(TNS_MAX_LONG_LENGTH)
|
||||
else:
|
||||
buf.write_ub4(var_impl.buffer_size)
|
||||
buf.write_ub4(buffer_size)
|
||||
if var_impl.is_array:
|
||||
buf.write_ub4(var_impl.num_elements)
|
||||
else:
|
||||
|
@ -996,6 +1003,9 @@ cdef class MessageWithData(Message):
|
|||
num_bytes = <uint32_t> len(lob_impl._locator)
|
||||
buf.write_ub4(num_bytes)
|
||||
buf.write_bytes_chunked(lob_impl._locator)
|
||||
elif ora_type_num in (TNS_DATA_TYPE_ROWID, TNS_DATA_TYPE_UROWID):
|
||||
temp_bytes = (<str> value).encode()
|
||||
buf.write_bytes_chunked(temp_bytes)
|
||||
else:
|
||||
errors._raise_err(errors.ERR_DB_TYPE_NOT_SUPPORTED,
|
||||
name=var_impl.dbtype.name)
|
||||
|
|
|
@ -331,8 +331,10 @@ cdef class ThinPoolImpl(BasePoolImpl):
|
|||
read_buf = conn_impl._protocol._read_buf
|
||||
if not read_buf._session_needs_to_be_closed:
|
||||
socket_list = [conn_impl._protocol._socket]
|
||||
read_socks, _, _ = select.select(socket_list, [], [], 0)
|
||||
if read_socks:
|
||||
while not read_buf._session_needs_to_be_closed:
|
||||
read_socks, _, _ = select.select(socket_list, [], [], 0)
|
||||
if not read_socks:
|
||||
break
|
||||
read_buf.check_control_packet()
|
||||
if read_buf._session_needs_to_be_closed:
|
||||
with self._condition:
|
||||
|
|
|
@ -88,17 +88,18 @@ class ConnectionPool:
|
|||
params_impl.set(kwargs)
|
||||
self._connection_type = \
|
||||
params_impl.connectiontype or connection_module.Connection
|
||||
thin = driver_mode.check_and_return_mode()
|
||||
if dsn is not None:
|
||||
dsn = params_impl.parse_dsn(dsn, thin)
|
||||
if dsn is None:
|
||||
dsn = params_impl.get_connect_string()
|
||||
if thin:
|
||||
impl = thin_impl.ThinPoolImpl(dsn, params_impl)
|
||||
else:
|
||||
impl = thick_impl.ThickPoolImpl(dsn, params_impl)
|
||||
self._impl = impl
|
||||
self.session_callback = params_impl.session_callback
|
||||
with driver_mode.get_manager() as mode_mgr:
|
||||
thin = mode_mgr.thin
|
||||
if dsn is not None:
|
||||
dsn = params_impl.parse_dsn(dsn, thin)
|
||||
if dsn is None:
|
||||
dsn = params_impl.get_connect_string()
|
||||
if thin:
|
||||
impl = thin_impl.ThinPoolImpl(dsn, params_impl)
|
||||
else:
|
||||
impl = thick_impl.ThickPoolImpl(dsn, params_impl)
|
||||
self._impl = impl
|
||||
self.session_callback = params_impl.session_callback
|
||||
|
||||
def __del__(self):
|
||||
if self._impl is not None:
|
||||
|
@ -120,7 +121,7 @@ class ConnectionPool:
|
|||
tag: str=None,
|
||||
matchanytag: bool=False,
|
||||
shardingkey: list=None,
|
||||
supershardingkey: list=None) -> Type["connection_module.Connection"]:
|
||||
supershardingkey: list=None) -> "connection_module.Connection":
|
||||
"""
|
||||
Acquire a connection from the pool and return it.
|
||||
|
||||
|
@ -177,7 +178,7 @@ class ConnectionPool:
|
|||
self._impl.close(force)
|
||||
self._impl = None
|
||||
|
||||
def drop(self, connection: Type["connection_module.Connection"]) -> None:
|
||||
def drop(self, connection: "connection_module.Connection") -> None:
|
||||
"""
|
||||
Drop the connection from the pool, which is useful if the connection is
|
||||
no longer usable (such as when the database session is killed).
|
||||
|
@ -322,7 +323,7 @@ class ConnectionPool:
|
|||
def ping_interval(self, value: int) -> None:
|
||||
self._impl.set_ping_interval(value)
|
||||
|
||||
def release(self, connection: Type["connection_module.Connection"],
|
||||
def release(self, connection: "connection_module.Connection",
|
||||
tag: str=None) -> None:
|
||||
"""
|
||||
Release the connection back to the pool now, rather than whenever
|
||||
|
|
|
@ -468,7 +468,7 @@ class PoolParams(ConnectParams):
|
|||
"""
|
||||
return self._impl.wait_timeout
|
||||
|
||||
def copy(self) -> Type["PoolParams"]:
|
||||
def copy(self) -> "PoolParams":
|
||||
"""
|
||||
Creates a copy of the parameters and returns it.
|
||||
"""
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
# SodaDatabase, SodaCollection, SodaDocument, SodaDocCursor and SodaOperation.
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
from typing import Type, Union
|
||||
from typing import Union, List
|
||||
import json
|
||||
|
||||
from . import connection
|
||||
|
@ -58,7 +58,7 @@ class SodaDatabase:
|
|||
return json.dumps(content).encode()
|
||||
|
||||
def createCollection(self, name: str, metadata: Union[str, dict]=None,
|
||||
mapMode: bool=False) -> Type["SodaCollection"]:
|
||||
mapMode: bool=False) -> "SodaCollection":
|
||||
"""
|
||||
Creates a SODA collection with the given name and returns a new SODA
|
||||
collection object. If you try to create a collection, and a collection
|
||||
|
@ -85,7 +85,7 @@ class SodaDatabase:
|
|||
return SodaCollection._from_impl(self, collection_impl)
|
||||
|
||||
def createDocument(self, content: object, key: str=None,
|
||||
mediaType: str="application/json") -> Type["SodaDocument"]:
|
||||
mediaType: str="application/json") -> "SodaDocument":
|
||||
"""
|
||||
Creates a SODA document usable for SODA write operations. You only need
|
||||
to use this method if your collection requires client-assigned keys or
|
||||
|
@ -112,7 +112,8 @@ class SodaDatabase:
|
|||
doc_impl = self._impl.create_document(content_bytes, key, mediaType)
|
||||
return SodaDocument._from_impl(doc_impl)
|
||||
|
||||
def getCollectionNames(self, startName: str=None, limit: int=0) -> list:
|
||||
def getCollectionNames(self, startName: str=None,
|
||||
limit: int=0) -> List[str]:
|
||||
"""
|
||||
Returns a list of the names of collections in the database that match
|
||||
the criteria, in alphabetical order.
|
||||
|
@ -126,7 +127,7 @@ class SodaDatabase:
|
|||
"""
|
||||
return self._impl.get_collection_names(startName, limit)
|
||||
|
||||
def openCollection(self, name: str) -> Type["SodaCollection"]:
|
||||
def openCollection(self, name: str) -> "SodaCollection":
|
||||
"""
|
||||
Opens an existing collection with the given name and returns a new SODA
|
||||
collection object. If a collection with that name does not exist, None
|
||||
|
@ -191,7 +192,7 @@ class SodaCollection:
|
|||
"""
|
||||
return self._impl.drop_index(name, force)
|
||||
|
||||
def find(self) -> Type["SodaOperation"]:
|
||||
def find(self) -> "SodaOperation":
|
||||
"""
|
||||
This method is used to begin an operation that will act upon documents
|
||||
in the collection. It creates and returns a SodaOperation object which
|
||||
|
@ -200,7 +201,7 @@ class SodaCollection:
|
|||
"""
|
||||
return SodaOperation(self)
|
||||
|
||||
def getDataGuide(self) -> Type["SodaDocument"]:
|
||||
def getDataGuide(self) -> "SodaDocument":
|
||||
"""
|
||||
Returns a SODA document object containing property names, data types
|
||||
and lengths inferred from the JSON documents in the collection. It can
|
||||
|
@ -253,7 +254,7 @@ class SodaCollection:
|
|||
self._impl.insert_one(doc_impl, hint=None, return_doc=False)
|
||||
|
||||
def insertOneAndGet(self, doc: object,
|
||||
hint: str=None) -> Type["SodaDocument"]:
|
||||
hint: str=None) -> "SodaDocument":
|
||||
"""
|
||||
Similarly to insertOne() this method inserts a given document into the
|
||||
collection. The only difference is that it returns a SODA Document
|
||||
|
@ -300,7 +301,7 @@ class SodaCollection:
|
|||
doc_impl = self._process_doc_arg(doc)
|
||||
self._impl.save(doc_impl, hint=None, return_doc=False)
|
||||
|
||||
def saveAndGet(self, doc: object, hint: str=None) -> Type["SodaDocument"]:
|
||||
def saveAndGet(self, doc: object, hint: str=None) -> "SodaDocument":
|
||||
"""
|
||||
Saves a document into the collection. This method is equivalent to
|
||||
insertOneAndGet() except that if client-assigned keys are used, and the
|
||||
|
@ -318,7 +319,7 @@ class SodaCollection:
|
|||
doc_impl = self._process_doc_arg(doc)
|
||||
if hint is not None and not isinstance(hint, str):
|
||||
raise TypeError("expecting a string")
|
||||
return_doc_impl = self._impl.save(doc_impl, hint, return_doc=False)
|
||||
return_doc_impl = self._impl.save(doc_impl, hint, return_doc=True)
|
||||
return SodaDocument._from_impl(return_doc_impl)
|
||||
|
||||
def truncate(self) -> None:
|
||||
|
@ -461,7 +462,7 @@ class SodaOperation:
|
|||
"""
|
||||
return self._collection._impl.get_count(self)
|
||||
|
||||
def fetchArraySize(self, value: int) -> Type["SodaOperation"]:
|
||||
def fetchArraySize(self, value: int) -> "SodaOperation":
|
||||
"""
|
||||
This is a tuning method to specify the number of documents that are
|
||||
internally fetched in batches by calls to getCursor() and
|
||||
|
@ -480,7 +481,7 @@ class SodaOperation:
|
|||
self._fetch_array_size = value
|
||||
return self
|
||||
|
||||
def filter(self, value: Union[dict, str]) -> Type["SodaOperation"]:
|
||||
def filter(self, value: Union[dict, str]) -> "SodaOperation":
|
||||
"""
|
||||
Sets a filter specification for complex document queries and ordering
|
||||
of JSON documents. Filter specifications must be provided as a
|
||||
|
@ -499,7 +500,7 @@ class SodaOperation:
|
|||
raise TypeError("expecting string or dictionary")
|
||||
return self
|
||||
|
||||
def getCursor(self) -> Type["SodaDocCursor"]:
|
||||
def getCursor(self) -> "SodaDocCursor":
|
||||
"""
|
||||
Returns a SodaDocCursor object that can be used to iterate over the
|
||||
documents that match the criteria.
|
||||
|
@ -513,7 +514,7 @@ class SodaOperation:
|
|||
"""
|
||||
return [d for d in self.getCursor()]
|
||||
|
||||
def getOne(self) -> Union[Type["SodaDocument"], None]:
|
||||
def getOne(self) -> Union["SodaDocument", None]:
|
||||
"""
|
||||
Returns a single SodaDocument object that matches the criteria. Note
|
||||
that if multiple documents match the criteria only the first one is
|
||||
|
@ -523,7 +524,7 @@ class SodaOperation:
|
|||
if doc_impl is not None:
|
||||
return SodaDocument._from_impl(doc_impl)
|
||||
|
||||
def hint(self, value: str) -> Type["SodaOperation"]:
|
||||
def hint(self, value: str) -> "SodaOperation":
|
||||
"""
|
||||
Specifies a hint that will be provided to the SODA operation when it is
|
||||
performed. This is expected to be a string in the same format as SQL
|
||||
|
@ -541,7 +542,7 @@ class SodaOperation:
|
|||
self._hint = value
|
||||
return self
|
||||
|
||||
def key(self, value: str) -> Type["SodaOperation"]:
|
||||
def key(self, value: str) -> "SodaOperation":
|
||||
"""
|
||||
Specifies that the document with the specified key should be returned.
|
||||
This causes any previous calls made to this method and keys() to be
|
||||
|
@ -556,7 +557,7 @@ class SodaOperation:
|
|||
self._keys = None
|
||||
return self
|
||||
|
||||
def keys(self, value: list) -> Type["SodaOperation"]:
|
||||
def keys(self, value: list) -> "SodaOperation":
|
||||
"""
|
||||
Specifies that documents that match the keys found in the supplied
|
||||
sequence should be returned. This causes any previous calls made to
|
||||
|
@ -573,7 +574,7 @@ class SodaOperation:
|
|||
self._key = None
|
||||
return self
|
||||
|
||||
def limit(self, value: int) -> Type["SodaOperation"]:
|
||||
def limit(self, value: int) -> "SodaOperation":
|
||||
"""
|
||||
Specifies that only the specified number of documents should be
|
||||
returned. This method is only usable for read operations such as
|
||||
|
@ -609,7 +610,7 @@ class SodaOperation:
|
|||
return self._collection._impl.replace_one(self, doc_impl,
|
||||
return_doc=False)
|
||||
|
||||
def replaceOneAndGet(self, doc: object) -> Type["SodaDocument"]:
|
||||
def replaceOneAndGet(self, doc: object) -> "SodaDocument":
|
||||
"""
|
||||
Similarly to replaceOne(), this method replaces a single document in
|
||||
the collection with the specified document. The only difference is that
|
||||
|
@ -621,7 +622,7 @@ class SodaOperation:
|
|||
return_doc=True)
|
||||
return SodaDocument._from_impl(return_doc_impl)
|
||||
|
||||
def skip(self, value: int) -> Type["SodaOperation"]:
|
||||
def skip(self, value: int) -> "SodaOperation":
|
||||
"""
|
||||
Specifies the number of documents that match the other criteria that
|
||||
will be skipped. This method is only usable for read operations such as
|
||||
|
@ -636,7 +637,7 @@ class SodaOperation:
|
|||
self._skip = value
|
||||
return self
|
||||
|
||||
def version(self, value: str) -> Type["SodaOperation"]:
|
||||
def version(self, value: str) -> "SodaOperation":
|
||||
"""
|
||||
Specifies that documents with the specified version should be returned.
|
||||
Typically this is used with key() to implement optimistic locking, so
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
# events are detected.
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
from typing import Callable, Type, Union
|
||||
from typing import Callable, Union, List
|
||||
from . import connection
|
||||
|
||||
class Subscription:
|
||||
|
@ -53,7 +53,7 @@ class Subscription:
|
|||
return self._impl.callback
|
||||
|
||||
@property
|
||||
def connection(self) -> Type["connection.Connection"]:
|
||||
def connection(self) -> "connection.Connection":
|
||||
"""
|
||||
Returns the connection that was used to register the subscription when
|
||||
it was created.
|
||||
|
@ -172,7 +172,7 @@ class Message:
|
|||
|
||||
|
||||
@property
|
||||
def consumer_name(self) -> str:
|
||||
def consumer_name(self) -> Union[str, None]:
|
||||
"""
|
||||
Returns the name of the consumer which generated the notification. It
|
||||
will be populated if the subscription was created with the namespace
|
||||
|
@ -181,28 +181,29 @@ class Message:
|
|||
return self._consumer_name
|
||||
|
||||
@property
|
||||
def consumerName(self) -> str:
|
||||
def consumerName(self) -> Union[str, None]:
|
||||
"""
|
||||
Deprecated. Use property consumer_name instead.
|
||||
"""
|
||||
return self.consumer_name
|
||||
|
||||
@property
|
||||
def dbname(self) -> str:
|
||||
def dbname(self) -> Union[str, None]:
|
||||
"""
|
||||
Returns the name of the database that generated the notification.
|
||||
"""
|
||||
return self._db_name
|
||||
|
||||
@property
|
||||
def msgid(self) -> bytes:
|
||||
def msgid(self) -> Union[bytes, None]:
|
||||
"""
|
||||
Returns the message id of the AQ message that generated the notification.
|
||||
Returns the message id of the AQ message that generated the
|
||||
notification.
|
||||
"""
|
||||
return self._msgid
|
||||
|
||||
@property
|
||||
def queries(self) -> list:
|
||||
def queries(self) -> List["MessageQuery"]:
|
||||
"""
|
||||
Returns a list of message query objects that give information about
|
||||
query result sets changed for this notification. This attribute will be
|
||||
|
@ -212,7 +213,7 @@ class Message:
|
|||
return self._queries
|
||||
|
||||
@property
|
||||
def queue_name(self) -> str:
|
||||
def queue_name(self) -> Union[str, None]:
|
||||
"""
|
||||
Returns the name of the queue which generated the notification. It will
|
||||
only be populated if the subscription was created with the namespace
|
||||
|
@ -221,7 +222,7 @@ class Message:
|
|||
return self._queue_name
|
||||
|
||||
@property
|
||||
def queueName(self) -> str:
|
||||
def queueName(self) -> Union[str, None]:
|
||||
"""
|
||||
Deprecated. Use property queue_name instead.
|
||||
"""
|
||||
|
@ -247,7 +248,7 @@ class Message:
|
|||
return self._subscription
|
||||
|
||||
@property
|
||||
def tables(self) -> list:
|
||||
def tables(self) -> List["MessageTable"]:
|
||||
"""
|
||||
Returns a list of message table objects that give information about the
|
||||
tables changed for this notification. This attribute will be an empty
|
||||
|
@ -257,14 +258,14 @@ class Message:
|
|||
return self._tables
|
||||
|
||||
@property
|
||||
def txid(self) -> bytes:
|
||||
def txid(self) -> Union[bytes, None]:
|
||||
"""
|
||||
Returns the id of the transaction that generated the notification.
|
||||
"""
|
||||
return self._txid
|
||||
|
||||
@property
|
||||
def type(self) -> str:
|
||||
def type(self) -> int:
|
||||
"""
|
||||
Returns the type of message that has been sent.
|
||||
"""
|
||||
|
@ -297,7 +298,7 @@ class MessageQuery:
|
|||
return self._operation
|
||||
|
||||
@property
|
||||
def tables(self) -> list:
|
||||
def tables(self) -> List["MessageTable"]:
|
||||
"""
|
||||
Returns a list of message table objects that give information about the
|
||||
table changes that caused the query result set to change for this
|
||||
|
@ -320,7 +321,7 @@ class MessageRow:
|
|||
return self._operation
|
||||
|
||||
@property
|
||||
def rowid(self) -> str:
|
||||
def rowid(self) -> Union[str, None]:
|
||||
"""
|
||||
Returns the rowid of the row that was changed.
|
||||
"""
|
||||
|
@ -335,7 +336,7 @@ class MessageTable:
|
|||
self._rows = []
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
def name(self) -> Union[str, None]:
|
||||
"""
|
||||
Returns the name of the table that was changed.
|
||||
"""
|
||||
|
@ -349,7 +350,7 @@ class MessageTable:
|
|||
return self._operation
|
||||
|
||||
@property
|
||||
def rows(self) -> list:
|
||||
def rows(self) -> List["MessageRow"]:
|
||||
"""
|
||||
Returns a list of message row objects that give information about the
|
||||
rows changed on the table. This value is only filled in if the qos
|
||||
|
|
|
@ -30,4 +30,4 @@
|
|||
# file doc/src/conf.py both reference this file directly.
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
__version__ = "1.1.0"
|
||||
__version__ = "1.1.1"
|
||||
|
|
|
@ -194,5 +194,10 @@ class TestCase(test_env.BaseTestCase):
|
|||
"1528 - test oracledb.ROWID pickling"
|
||||
self.__test_pickle(oracledb.ROWID)
|
||||
|
||||
def test_1529_DB_TYPE_UROWID(self):
|
||||
"1529 - test oracledb.DB_TYPE_UROWID comparisons and pickling"
|
||||
self.__test_compare(oracledb.DB_TYPE_UROWID, oracledb.ROWID)
|
||||
self.__test_pickle(oracledb.DB_TYPE_UROWID)
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_env.run_test_cases()
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
"""
|
||||
|
||||
import datetime
|
||||
import unittest
|
||||
|
||||
import oracledb
|
||||
import test_env
|
||||
|
@ -84,5 +85,90 @@ class TestCase(test_env.BaseTestCase):
|
|||
val=rowid)
|
||||
self.assertEqual(self.cursor.fetchall(), [(int_val,)])
|
||||
|
||||
def test_2904_select_rowids_as_rowids(self):
|
||||
"2904 - test selecting regular rowids stored in a rowid column"
|
||||
self.cursor.execute("truncate table TestRowids")
|
||||
self.cursor.execute("""
|
||||
insert into TestRowids (IntCol, RowidCol)
|
||||
select IntCol, rowid from TestNumbers""")
|
||||
self.connection.commit()
|
||||
self.cursor.execute("select IntCol, RowidCol from TestRowids")
|
||||
for int_val, rowid in self.cursor.fetchall():
|
||||
self.cursor.execute("""
|
||||
select IntCol
|
||||
from TestNumbers
|
||||
where rowid = :val""",
|
||||
val=rowid)
|
||||
self.assertEqual(self.cursor.fetchall(), [(int_val,)])
|
||||
|
||||
def test_2905_test_bind_and_insert_rowid(self):
|
||||
"2905 - binding and inserting a rowid"
|
||||
self.cursor.execute("truncate table TestRowids")
|
||||
insert_data = [
|
||||
(1, "String #1"), (2, "String #2"),
|
||||
(3, "String #3"),(4, "String #4")
|
||||
]
|
||||
self.cursor.execute("truncate table TestTempTable")
|
||||
sql = "insert into TestTempTable (IntCol, StringCol1) values (:1, :2)"
|
||||
self.cursor.executemany(sql, insert_data)
|
||||
self.connection.commit()
|
||||
ridvar = self.cursor.var(oracledb.ROWID)
|
||||
self.cursor.execute("""
|
||||
begin
|
||||
select rowid into :rid from TestTempTable
|
||||
where IntCol = 3;
|
||||
end;""",
|
||||
rid=ridvar)
|
||||
self.cursor.setinputsizes(r1=oracledb.ROWID)
|
||||
self.cursor.execute("""
|
||||
insert into TestRowids (IntCol, RowidCol)
|
||||
values(1, :r1)""",
|
||||
r1=ridvar)
|
||||
self.connection.commit()
|
||||
self.cursor.execute("select IntCol, RowidCol from TestRowids")
|
||||
int_val, rowid = self.cursor.fetchone()
|
||||
self.cursor.execute("""
|
||||
select IntCol, StringCol1 from TestTempTable
|
||||
where rowid = :val""",
|
||||
val=rowid)
|
||||
self.assertEqual(self.cursor.fetchone(), (3, "String #3"))
|
||||
|
||||
@unittest.skipIf(not test_env.get_is_thin(),
|
||||
"thick mode doesn't support DB_TYPE_UROWID")
|
||||
def test_2906_test_bind_and_insert_rowid_as_urowid(self):
|
||||
"2906 - binding and inserting a rowid as urowid"
|
||||
self.cursor.execute("truncate table TestRowids")
|
||||
insert_data = [
|
||||
(1, "String #1", datetime.datetime(2017, 4, 4)),
|
||||
(2, "String #2", datetime.datetime(2017, 4, 5)),
|
||||
(3, "String #3", datetime.datetime(2017, 4, 6)),
|
||||
(4, "A" * 250, datetime.datetime(2017, 4, 7))
|
||||
]
|
||||
self.cursor.execute("truncate table TestUniversalRowids")
|
||||
sql = "insert into TestUniversalRowids values (:1, :2, :3)"
|
||||
self.cursor.executemany(sql, insert_data)
|
||||
self.connection.commit()
|
||||
ridvar = self.cursor.var(oracledb.DB_TYPE_UROWID)
|
||||
self.cursor.execute("""
|
||||
begin
|
||||
select rowid into :rid from TestUniversalRowids
|
||||
where IntCol = 3;
|
||||
end;""",
|
||||
rid=ridvar)
|
||||
self.cursor.setinputsizes(r1=oracledb.DB_TYPE_UROWID)
|
||||
self.cursor.execute("""
|
||||
insert into TestRowids (IntCol, UrowidCol)
|
||||
values(1, :r1)""",
|
||||
r1=ridvar)
|
||||
self.connection.commit()
|
||||
self.cursor.execute("select IntCol, UrowidCol from TestRowids")
|
||||
int_val, rowid = self.cursor.fetchone()
|
||||
self.cursor.execute("""
|
||||
select IntCol, StringCol, DateCol from TestUniversalRowids
|
||||
where rowid = :val""",
|
||||
val=rowid)
|
||||
self.assertEqual(self.cursor.fetchone(),
|
||||
(3, "String #3", datetime.datetime(2017, 4, 6)))
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_env.run_test_cases()
|
||||
|
|
|
@ -446,5 +446,46 @@ class TestCase(test_env.BaseTestCase):
|
|||
result, = cursor.fetchone()
|
||||
self.assertTrue(hint in result.read())
|
||||
|
||||
def test_3420_save_and_get(self):
|
||||
"3420 - test saveAndGet"
|
||||
soda_db = self.get_soda_database(minclient=(19, 9))
|
||||
coll = soda_db.createCollection("TestSodaSaveAndGet")
|
||||
coll.find().remove()
|
||||
values_to_save = [
|
||||
dict(name="John", age=50),
|
||||
soda_db.createDocument(dict(name="Mark", age=45)),
|
||||
soda_db.createDocument(dict(name="Jill", age=32))
|
||||
]
|
||||
inserted_keys = []
|
||||
for value in values_to_save:
|
||||
doc = coll.saveAndGet(value)
|
||||
inserted_keys.append(doc.key)
|
||||
fetched_docs = coll.find().getDocuments()
|
||||
self.connection.commit()
|
||||
self.assertEqual(coll.find().count(), len(values_to_save))
|
||||
for key, fetched_doc in zip(inserted_keys, fetched_docs):
|
||||
doc = coll.find().key(key).getOne()
|
||||
self.assertEqual(doc.getContent(), fetched_doc.getContent())
|
||||
coll.drop()
|
||||
|
||||
def test_3421_insert_many_and_get(self):
|
||||
"3421 - test insert many and get"
|
||||
soda_db = self.get_soda_database(minclient=(18, 5))
|
||||
coll = soda_db.createCollection("TestInsertManyAndGet")
|
||||
values_to_insert = [
|
||||
dict(name="George", age=25),
|
||||
soda_db.createDocument(dict(name="Lucas", age=47))
|
||||
]
|
||||
docs = coll.insertManyAndGet(values_to_insert)
|
||||
inserted_keys = [i.key for i in docs]
|
||||
self.connection.commit()
|
||||
self.assertEqual(coll.find().count(), len(values_to_insert))
|
||||
for key, expected_doc in zip(inserted_keys, values_to_insert):
|
||||
if isinstance(expected_doc, dict):
|
||||
expected_doc = soda_db.createDocument(expected_doc)
|
||||
doc = coll.find().key(key).getOne()
|
||||
self.assertEqual(doc.getContent(), expected_doc.getContent())
|
||||
coll.drop()
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_env.run_test_cases()
|
||||
|
|
|
@ -395,5 +395,12 @@ class TestCase(test_env.BaseTestCase):
|
|||
results = self.cursor.fetchall()
|
||||
self.assertEqual(results, [(None, None, None, None, None, None, None)])
|
||||
|
||||
@unittest.skipIf(not test_env.get_is_thin(),
|
||||
"thick mode doesn't support DB_TYPE_UROWID")
|
||||
def test_3725_DB_TYPE_UROWID(self):
|
||||
"3725 - setting values on variables of type DB_TYPE_UROWID"
|
||||
self._test_negative_set_and_get(oracledb.DB_TYPE_UROWID, 12345)
|
||||
self._test_negative_set_and_get(oracledb.DB_TYPE_UROWID, "523lkhlf")
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_env.run_test_cases()
|
||||
|
|
|
@ -739,6 +739,7 @@ class TestCase(test_env.BaseTestCase):
|
|||
admin_cursor.execute(sql)
|
||||
self.assertRaisesRegex(oracledb.DatabaseError, "^DPY-4011:",
|
||||
cursor.execute, "select user from dual")
|
||||
self.assertFalse(conn.is_healthy())
|
||||
|
||||
def test_4359_kill_conn_in_context_manager(self):
|
||||
"4359 - kill connection in cursor context manager"
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
#------------------------------------------------------------------------------
|
||||
|
||||
import functools
|
||||
from typing import Type, Union, Callable
|
||||
from typing import Union, Callable
|
||||
|
||||
import oracledb
|
||||
|
||||
|
@ -88,7 +88,7 @@ class ConnectParams:
|
|||
|
||||
#{{ params_properties }}
|
||||
|
||||
def copy(self) -> Type["ConnectParams"]:
|
||||
def copy(self) -> "ConnectParams":
|
||||
"""
|
||||
Creates a copy of the parameters and returns it.
|
||||
"""
|
||||
|
|
|
@ -62,7 +62,7 @@ class Connection:
|
|||
|
||||
def __init__(self,
|
||||
dsn: str=None, *,
|
||||
pool: Type["pool_module.ConnectionPool"]=None,
|
||||
pool: "pool_module.ConnectionPool"=None,
|
||||
params: ConnectParams=None,
|
||||
**kwargs) -> None:
|
||||
"""
|
||||
|
@ -97,51 +97,52 @@ class Connection:
|
|||
self._impl = None
|
||||
|
||||
# determine if thin mode is being used
|
||||
thin = driver_mode.check_and_return_mode()
|
||||
with driver_mode.get_manager() as mode_mgr:
|
||||
thin = mode_mgr.thin
|
||||
|
||||
# determine which connection parameters to use
|
||||
if params is None:
|
||||
params_impl = base_impl.ConnectParamsImpl()
|
||||
elif not isinstance(params, ConnectParams):
|
||||
errors._raise_err(errors.ERR_INVALID_CONNECT_PARAMS)
|
||||
else:
|
||||
params_impl = params._impl.copy()
|
||||
if kwargs:
|
||||
params_impl.set(kwargs)
|
||||
if dsn is not None:
|
||||
dsn = params_impl.parse_dsn(dsn, thin)
|
||||
if dsn is None:
|
||||
dsn = params_impl.get_connect_string()
|
||||
|
||||
# see if connection is being acquired from a pool
|
||||
if pool is None:
|
||||
pool_impl = None
|
||||
elif not isinstance(pool, pool_module.ConnectionPool):
|
||||
message = "pool must be an instance of oracledb.ConnectionPool"
|
||||
raise TypeError(message)
|
||||
else:
|
||||
pool._verify_open()
|
||||
pool_impl = pool._impl
|
||||
|
||||
# create thin or thick implementation object
|
||||
if thin:
|
||||
if pool is not None:
|
||||
impl = pool_impl.acquire(params_impl)
|
||||
# determine which connection parameters to use
|
||||
if params is None:
|
||||
params_impl = base_impl.ConnectParamsImpl()
|
||||
elif not isinstance(params, ConnectParams):
|
||||
errors._raise_err(errors.ERR_INVALID_CONNECT_PARAMS)
|
||||
else:
|
||||
impl = thin_impl.ThinConnImpl(dsn, params_impl)
|
||||
impl.connect(params_impl)
|
||||
else:
|
||||
impl = thick_impl.ThickConnImpl(dsn, params_impl)
|
||||
impl.connect(params_impl, pool_impl)
|
||||
self._impl = impl
|
||||
self._version = None
|
||||
params_impl = params._impl.copy()
|
||||
if kwargs:
|
||||
params_impl.set(kwargs)
|
||||
if dsn is not None:
|
||||
dsn = params_impl.parse_dsn(dsn, thin)
|
||||
if dsn is None:
|
||||
dsn = params_impl.get_connect_string()
|
||||
|
||||
# invoke callback, if applicable
|
||||
if impl.invoke_session_callback and pool is not None \
|
||||
and pool.session_callback is not None \
|
||||
and callable(pool.session_callback):
|
||||
pool.session_callback(self, params_impl.tag)
|
||||
impl.invoke_session_callback = False
|
||||
# see if connection is being acquired from a pool
|
||||
if pool is None:
|
||||
pool_impl = None
|
||||
elif not isinstance(pool, pool_module.ConnectionPool):
|
||||
message = "pool must be an instance of oracledb.ConnectionPool"
|
||||
raise TypeError(message)
|
||||
else:
|
||||
pool._verify_open()
|
||||
pool_impl = pool._impl
|
||||
|
||||
# create thin or thick implementation object
|
||||
if thin:
|
||||
if pool is not None:
|
||||
impl = pool_impl.acquire(params_impl)
|
||||
else:
|
||||
impl = thin_impl.ThinConnImpl(dsn, params_impl)
|
||||
impl.connect(params_impl)
|
||||
else:
|
||||
impl = thick_impl.ThickConnImpl(dsn, params_impl)
|
||||
impl.connect(params_impl, pool_impl)
|
||||
self._impl = impl
|
||||
self._version = None
|
||||
|
||||
# invoke callback, if applicable
|
||||
if impl.invoke_session_callback and pool is not None \
|
||||
and pool.session_callback is not None \
|
||||
and callable(pool.session_callback):
|
||||
pool.session_callback(self, params_impl.tag)
|
||||
impl.invoke_session_callback = False
|
||||
|
||||
def __del__(self):
|
||||
if self._impl is not None:
|
||||
|
@ -500,7 +501,7 @@ class Connection:
|
|||
This function performs a local check. To fully check a connection's
|
||||
health, use ping() which performs a round-trip to the database.
|
||||
"""
|
||||
return self._impl.get_is_healthy()
|
||||
return self._impl is not None and self._impl.get_is_healthy()
|
||||
|
||||
@property
|
||||
def ltxid(self) -> bytes:
|
||||
|
@ -601,7 +602,7 @@ class Connection:
|
|||
"""
|
||||
return self.tpc_prepare()
|
||||
|
||||
def queue(self, name: str, payload_type: [DbObjectType, str]=None, *,
|
||||
def queue(self, name: str, payload_type: Union[DbObjectType, str]=None, *,
|
||||
payloadType: DbObjectType=None) -> Queue:
|
||||
"""
|
||||
Creates and returns a queue which is used to enqueue and dequeue
|
||||
|
@ -999,7 +1000,7 @@ def _connection_factory(f):
|
|||
"""
|
||||
@functools.wraps(f)
|
||||
def connect(dsn: str=None, *,
|
||||
pool: Type["pool_module.ConnectionPool"]=None,
|
||||
pool: "pool_module.ConnectionPool"=None,
|
||||
conn_class: Type[Connection]=Connection,
|
||||
params: ConnectParams=None,
|
||||
**kwargs) -> Connection:
|
||||
|
@ -1012,7 +1013,7 @@ def _connection_factory(f):
|
|||
|
||||
@_connection_factory
|
||||
def connect(dsn: str=None, *,
|
||||
pool: Type["pool_module.ConnectionPool"]=None,
|
||||
pool: "pool_module.ConnectionPool"=None,
|
||||
conn_class: Type[Connection]=Connection,
|
||||
params: ConnectParams=None,
|
||||
#{{ args_with_defaults }}
|
||||
|
|
|
@ -86,17 +86,18 @@ class ConnectionPool:
|
|||
params_impl.set(kwargs)
|
||||
self._connection_type = \
|
||||
params_impl.connectiontype or connection_module.Connection
|
||||
thin = driver_mode.check_and_return_mode()
|
||||
if dsn is not None:
|
||||
dsn = params_impl.parse_dsn(dsn, thin)
|
||||
if dsn is None:
|
||||
dsn = params_impl.get_connect_string()
|
||||
if thin:
|
||||
impl = thin_impl.ThinPoolImpl(dsn, params_impl)
|
||||
else:
|
||||
impl = thick_impl.ThickPoolImpl(dsn, params_impl)
|
||||
self._impl = impl
|
||||
self.session_callback = params_impl.session_callback
|
||||
with driver_mode.get_manager() as mode_mgr:
|
||||
thin = mode_mgr.thin
|
||||
if dsn is not None:
|
||||
dsn = params_impl.parse_dsn(dsn, thin)
|
||||
if dsn is None:
|
||||
dsn = params_impl.get_connect_string()
|
||||
if thin:
|
||||
impl = thin_impl.ThinPoolImpl(dsn, params_impl)
|
||||
else:
|
||||
impl = thick_impl.ThickPoolImpl(dsn, params_impl)
|
||||
self._impl = impl
|
||||
self.session_callback = params_impl.session_callback
|
||||
|
||||
def __del__(self):
|
||||
if self._impl is not None:
|
||||
|
@ -118,7 +119,7 @@ class ConnectionPool:
|
|||
tag: str=None,
|
||||
matchanytag: bool=False,
|
||||
shardingkey: list=None,
|
||||
supershardingkey: list=None) -> Type["connection_module.Connection"]:
|
||||
supershardingkey: list=None) -> "connection_module.Connection":
|
||||
"""
|
||||
Acquire a connection from the pool and return it.
|
||||
|
||||
|
@ -175,7 +176,7 @@ class ConnectionPool:
|
|||
self._impl.close(force)
|
||||
self._impl = None
|
||||
|
||||
def drop(self, connection: Type["connection_module.Connection"]) -> None:
|
||||
def drop(self, connection: "connection_module.Connection") -> None:
|
||||
"""
|
||||
Drop the connection from the pool, which is useful if the connection is
|
||||
no longer usable (such as when the database session is killed).
|
||||
|
@ -320,7 +321,7 @@ class ConnectionPool:
|
|||
def ping_interval(self, value: int) -> None:
|
||||
self._impl.set_ping_interval(value)
|
||||
|
||||
def release(self, connection: Type["connection_module.Connection"],
|
||||
def release(self, connection: "connection_module.Connection",
|
||||
tag: str=None) -> None:
|
||||
"""
|
||||
Release the connection back to the pool now, rather than whenever
|
||||
|
|
|
@ -66,7 +66,7 @@ class PoolParams(ConnectParams):
|
|||
|
||||
#{{ params_properties }}
|
||||
|
||||
def copy(self) -> Type["PoolParams"]:
|
||||
def copy(self) -> "PoolParams":
|
||||
"""
|
||||
Creates a copy of the parameters and returns it.
|
||||
"""
|
||||
|
|
Loading…
Reference in New Issue