This commit is contained in:
2026-04-28 17:35:33 +05:30
parent 58d8329dbd
commit 043a49e6aa
1654 changed files with 303910 additions and 40 deletions
@@ -0,0 +1,328 @@
# -----------------------------------------------------------------------------
# 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
# 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
# either license.
#
# If you elect to accept the software under the Apache License, Version 2.0,
# the following applies:
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# __init__.py
#
# Package initialization module.
# -----------------------------------------------------------------------------
import sys
import warnings
if sys.version_info[:2] < (3, 8):
message = (
f"Python {sys.version_info[0]}.{sys.version_info[1]} is no longer "
"supported by the Python core team. Therefore, support for it is "
"deprecated in python-oracledb and will be removed in a future release"
)
warnings.warn(message)
from .version import __version__ as __version__
from .constants import (
# mandated DB API constants
apilevel as apilevel,
threadsafety as threadsafety,
paramstyle as paramstyle,
# authentication modes
AUTH_MODE_DEFAULT as AUTH_MODE_DEFAULT,
AUTH_MODE_PRELIM as AUTH_MODE_PRELIM,
AUTH_MODE_SYSASM as AUTH_MODE_SYSASM,
AUTH_MODE_SYSBKP as AUTH_MODE_SYSBKP,
AUTH_MODE_SYSDBA as AUTH_MODE_SYSDBA,
AUTH_MODE_SYSDGD as AUTH_MODE_SYSDGD,
AUTH_MODE_SYSKMT as AUTH_MODE_SYSKMT,
AUTH_MODE_SYSOPER as AUTH_MODE_SYSOPER,
AUTH_MODE_SYSRAC as AUTH_MODE_SYSRAC,
# pool "get" modes
POOL_GETMODE_WAIT as POOL_GETMODE_WAIT,
POOL_GETMODE_NOWAIT as POOL_GETMODE_NOWAIT,
POOL_GETMODE_FORCEGET as POOL_GETMODE_FORCEGET,
POOL_GETMODE_TIMEDWAIT as POOL_GETMODE_TIMEDWAIT,
# purity values
PURITY_DEFAULT as PURITY_DEFAULT,
PURITY_NEW as PURITY_NEW,
PURITY_SELF as PURITY_SELF,
# AQ delivery modes
MSG_BUFFERED as MSG_BUFFERED,
MSG_PERSISTENT as MSG_PERSISTENT,
MSG_PERSISTENT_OR_BUFFERED as MSG_PERSISTENT_OR_BUFFERED,
# AQ dequeue modes
DEQ_BROWSE as DEQ_BROWSE,
DEQ_LOCKED as DEQ_LOCKED,
DEQ_REMOVE as DEQ_REMOVE,
DEQ_REMOVE_NODATA as DEQ_REMOVE_NODATA,
# AQ dequeue navigation modes
DEQ_FIRST_MSG as DEQ_FIRST_MSG,
DEQ_NEXT_MSG as DEQ_NEXT_MSG,
DEQ_NEXT_TRANSACTION as DEQ_NEXT_TRANSACTION,
# AQ dequeue visibility modes
DEQ_IMMEDIATE as DEQ_IMMEDIATE,
DEQ_ON_COMMIT as DEQ_ON_COMMIT,
# AQ dequeue wait modes
DEQ_NO_WAIT as DEQ_NO_WAIT,
DEQ_WAIT_FOREVER as DEQ_WAIT_FOREVER,
# AQ enqueue visibility modes
ENQ_IMMEDIATE as ENQ_IMMEDIATE,
ENQ_ON_COMMIT as ENQ_ON_COMMIT,
# AQ message states
MSG_EXPIRED as MSG_EXPIRED,
MSG_PROCESSED as MSG_PROCESSED,
MSG_READY as MSG_READY,
MSG_WAITING as MSG_WAITING,
# AQ other constants
MSG_NO_DELAY as MSG_NO_DELAY,
MSG_NO_EXPIRATION as MSG_NO_EXPIRATION,
# shutdown modes
DBSHUTDOWN_ABORT as DBSHUTDOWN_ABORT,
DBSHUTDOWN_FINAL as DBSHUTDOWN_FINAL,
DBSHUTDOWN_IMMEDIATE as DBSHUTDOWN_IMMEDIATE,
DBSHUTDOWN_TRANSACTIONAL as DBSHUTDOWN_TRANSACTIONAL,
DBSHUTDOWN_TRANSACTIONAL_LOCAL as DBSHUTDOWN_TRANSACTIONAL_LOCAL,
# subscription grouping classes
SUBSCR_GROUPING_CLASS_NONE as SUBSCR_GROUPING_CLASS_NONE,
SUBSCR_GROUPING_CLASS_TIME as SUBSCR_GROUPING_CLASS_TIME,
# subscription grouping types
SUBSCR_GROUPING_TYPE_SUMMARY as SUBSCR_GROUPING_TYPE_SUMMARY,
SUBSCR_GROUPING_TYPE_LAST as SUBSCR_GROUPING_TYPE_LAST,
# subscription namespaces
SUBSCR_NAMESPACE_AQ as SUBSCR_NAMESPACE_AQ,
SUBSCR_NAMESPACE_DBCHANGE as SUBSCR_NAMESPACE_DBCHANGE,
# subscription protocols
SUBSCR_PROTO_HTTP as SUBSCR_PROTO_HTTP,
SUBSCR_PROTO_MAIL as SUBSCR_PROTO_MAIL,
SUBSCR_PROTO_CALLBACK as SUBSCR_PROTO_CALLBACK,
SUBSCR_PROTO_SERVER as SUBSCR_PROTO_SERVER,
# subscription quality of service
SUBSCR_QOS_BEST_EFFORT as SUBSCR_QOS_BEST_EFFORT,
SUBSCR_QOS_DEFAULT as SUBSCR_QOS_DEFAULT,
SUBSCR_QOS_DEREG_NFY as SUBSCR_QOS_DEREG_NFY,
SUBSCR_QOS_QUERY as SUBSCR_QOS_QUERY,
SUBSCR_QOS_RELIABLE as SUBSCR_QOS_RELIABLE,
SUBSCR_QOS_ROWIDS as SUBSCR_QOS_ROWIDS,
# event types
EVENT_AQ as EVENT_AQ,
EVENT_DEREG as EVENT_DEREG,
EVENT_NONE as EVENT_NONE,
EVENT_OBJCHANGE as EVENT_OBJCHANGE,
EVENT_QUERYCHANGE as EVENT_QUERYCHANGE,
EVENT_SHUTDOWN as EVENT_SHUTDOWN,
EVENT_SHUTDOWN_ANY as EVENT_SHUTDOWN_ANY,
EVENT_STARTUP as EVENT_STARTUP,
# operation codes
OPCODE_ALLOPS as OPCODE_ALLOPS,
OPCODE_ALLROWS as OPCODE_ALLROWS,
OPCODE_ALTER as OPCODE_ALTER,
OPCODE_DELETE as OPCODE_DELETE,
OPCODE_DROP as OPCODE_DROP,
OPCODE_INSERT as OPCODE_INSERT,
OPCODE_UPDATE as OPCODE_UPDATE,
# flags for tpc_begin()
TPC_BEGIN_JOIN as TPC_BEGIN_JOIN,
TPC_BEGIN_NEW as TPC_BEGIN_NEW,
TPC_BEGIN_PROMOTE as TPC_BEGIN_PROMOTE,
TPC_BEGIN_RESUME as TPC_BEGIN_RESUME,
# flags for tpc_end()
TPC_END_NORMAL as TPC_END_NORMAL,
TPC_END_SUSPEND as TPC_END_SUSPEND,
)
from .exceptions import (
Warning as Warning,
Error as Error,
DatabaseError as DatabaseError,
DataError as DataError,
IntegrityError as IntegrityError,
InterfaceError as InterfaceError,
InternalError as InternalError,
NotSupportedError as NotSupportedError,
OperationalError as OperationalError,
ProgrammingError as ProgrammingError,
)
from .errors import _Error as _Error
from .defaults import defaults as defaults
from .connection import (
AsyncConnection as AsyncConnection,
connect as connect,
connect_async as connect_async,
Connection as Connection,
)
from .cursor import (
AsyncCursor as AsyncCursor,
Cursor as Cursor,
)
from .pool import (
AsyncConnectionPool as AsyncConnectionPool,
ConnectionPool as ConnectionPool,
create_pool as create_pool,
create_pool_async as create_pool_async,
)
from .connect_params import ConnectParams as ConnectParams
from .pool_params import PoolParams as PoolParams
from .lob import (
LOB as LOB,
AsyncLOB as AsyncLOB,
)
from .dbobject import DbObject as DbObject, DbObjectType as DbObjectType
from .fetch_info import FetchInfo as FetchInfo
from .var import Var as Var
from .dsn import makedsn as makedsn
from .driver_mode import is_thin_mode as is_thin_mode
from . import base_impl, thick_impl, thin_impl
from .base_impl import (
# database types
DB_TYPE_BFILE as DB_TYPE_BFILE,
DB_TYPE_BINARY_DOUBLE as DB_TYPE_BINARY_DOUBLE,
DB_TYPE_BINARY_FLOAT as DB_TYPE_BINARY_FLOAT,
DB_TYPE_BINARY_INTEGER as DB_TYPE_BINARY_INTEGER,
DB_TYPE_BLOB as DB_TYPE_BLOB,
DB_TYPE_BOOLEAN as DB_TYPE_BOOLEAN,
DB_TYPE_CHAR as DB_TYPE_CHAR,
DB_TYPE_CLOB as DB_TYPE_CLOB,
DB_TYPE_CURSOR as DB_TYPE_CURSOR,
DB_TYPE_DATE as DB_TYPE_DATE,
DB_TYPE_INTERVAL_DS as DB_TYPE_INTERVAL_DS,
DB_TYPE_INTERVAL_YM as DB_TYPE_INTERVAL_YM,
DB_TYPE_JSON as DB_TYPE_JSON,
DB_TYPE_LONG as DB_TYPE_LONG,
DB_TYPE_LONG_NVARCHAR as DB_TYPE_LONG_NVARCHAR,
DB_TYPE_LONG_RAW as DB_TYPE_LONG_RAW,
DB_TYPE_NCHAR as DB_TYPE_NCHAR,
DB_TYPE_NCLOB as DB_TYPE_NCLOB,
DB_TYPE_NUMBER as DB_TYPE_NUMBER,
DB_TYPE_NVARCHAR as DB_TYPE_NVARCHAR,
DB_TYPE_OBJECT as DB_TYPE_OBJECT,
DB_TYPE_RAW as DB_TYPE_RAW,
DB_TYPE_ROWID as DB_TYPE_ROWID,
DB_TYPE_TIMESTAMP as DB_TYPE_TIMESTAMP,
DB_TYPE_TIMESTAMP_LTZ as DB_TYPE_TIMESTAMP_LTZ,
DB_TYPE_TIMESTAMP_TZ as DB_TYPE_TIMESTAMP_TZ,
DB_TYPE_UNKNOWN as DB_TYPE_UNKNOWN,
DB_TYPE_UROWID as DB_TYPE_UROWID,
DB_TYPE_VARCHAR as DB_TYPE_VARCHAR,
DB_TYPE_XMLTYPE as DB_TYPE_XMLTYPE,
# API types
BINARY as BINARY,
DATETIME as DATETIME,
NUMBER as NUMBER,
ROWID as ROWID,
STRING as STRING,
)
from .thick_impl import (
clientversion as clientversion,
init_oracle_client as init_oracle_client,
)
from .constructors import (
Binary as Binary,
Date as Date,
DateFromTicks as DateFromTicks,
Time as Time,
TimeFromTicks as TimeFromTicks,
Timestamp as Timestamp,
TimestampFromTicks as TimestampFromTicks,
)
from .future import (
future as __future__, # noqa: F401
)
package = sys.modules[__name__]
base_impl.init_base_impl(package)
thick_impl.init_thick_impl(package)
thin_impl.init_thin_impl(package)
del package
# remove unnecessary symbols
del sys, warnings
del aq, base_impl, connect_params, connection, constants, constructors # noqa
del cursor, dbobject, driver_mode, dsn, errors, exceptions, fetch_info # noqa
del future, lob, pool, pool_params, soda, subscr, thick_impl, thin_impl # noqa
del utils, var # noqa
# general aliases (for backwards compatibility)
ObjectType = DbObjectType
Object = DbObject
SessionPool = ConnectionPool
version = __version__
# aliases for database types (for backwards compatibility)
BFILE = DB_TYPE_BFILE
BLOB = DB_TYPE_BLOB
BOOLEAN = DB_TYPE_BOOLEAN
CLOB = DB_TYPE_CLOB
CURSOR = DB_TYPE_CURSOR
FIXED_CHAR = DB_TYPE_CHAR
FIXED_NCHAR = DB_TYPE_NCHAR
INTERVAL = DB_TYPE_INTERVAL_DS
LONG_BINARY = DB_TYPE_LONG_RAW
LONG_STRING = DB_TYPE_LONG
NATIVE_INT = DB_TYPE_BINARY_INTEGER
NATIVE_FLOAT = DB_TYPE_BINARY_DOUBLE
NCHAR = DB_TYPE_NVARCHAR
OBJECT = DB_TYPE_OBJECT
NCLOB = DB_TYPE_NCLOB
TIMESTAMP = DB_TYPE_TIMESTAMP
# aliases for authhentication modes (for backwards compatibility)
DEFAULT_AUTH = AUTH_MODE_DEFAULT
SYSASM = AUTH_MODE_SYSASM
SYSBKP = AUTH_MODE_SYSBKP
SYSDBA = AUTH_MODE_SYSDBA
SYSDGD = AUTH_MODE_SYSDGD
SYSKMT = AUTH_MODE_SYSKMT
SYSOPER = AUTH_MODE_SYSOPER
SYSRAC = AUTH_MODE_SYSRAC
PRELIM_AUTH = AUTH_MODE_PRELIM
# aliases for pool "get" modes (for backwards compatibility)
SPOOL_ATTRVAL_WAIT = POOL_GETMODE_WAIT
SPOOL_ATTRVAL_NOWAIT = POOL_GETMODE_NOWAIT
SPOOL_ATTRVAL_FORCEGET = POOL_GETMODE_FORCEGET
SPOOL_ATTRVAL_TIMEDWAIT = POOL_GETMODE_TIMEDWAIT
# aliases for purity (for backwards compatibility)
ATTR_PURITY_DEFAULT = PURITY_DEFAULT
ATTR_PURITY_NEW = PURITY_NEW
ATTR_PURITY_SELF = PURITY_SELF
# aliases for subscription protocols (for backwards compatibility)
SUBSCR_PROTO_OCI = SUBSCR_PROTO_CALLBACK
@@ -0,0 +1,553 @@
# -----------------------------------------------------------------------------
# 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
# 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
# either license.
#
# If you elect to accept the software under the Apache License, Version 2.0,
# the following applies:
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# aq.py
#
# Contains the classes used for handling Advanced Queuing (AQ): Queue,
# DeqOptions, EnqOptions and MessageProperties.
# -----------------------------------------------------------------------------
import datetime
from . import connection as connection_module
from typing import Any, Union, List
from . import errors
from .dbobject import DbObject, DbObjectType
class Queue:
@classmethod
def _from_impl(cls, connection, impl):
queue = cls.__new__(cls)
queue._connection = connection
queue._deq_options = DeqOptions._from_impl(impl.deq_options_impl)
queue._enq_options = EnqOptions._from_impl(impl.enq_options_impl)
queue._payload_type = None
queue._impl = impl
return queue
def _verify_message(self, message: "MessageProperties") -> None:
"""
Internal method used for verifying a message.
"""
if not isinstance(message, MessageProperties):
raise TypeError("expecting MessageProperties object")
if message.payload is None:
errors._raise_err(errors.ERR_MESSAGE_HAS_NO_PAYLOAD)
@property
def connection(self) -> "connection_module.Connection":
"""
Returns the connection on which the queue was created.
"""
return self._connection
def deqmany(self, max_num_messages: int) -> list:
"""
Dequeues up to the specified number of messages from the queue and
returns a list of these messages.
"""
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["MessageProperties"]:
"""
Deprecated: use deqmany() instead.
"""
return self.deqmany(max_num_messages)
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.
"""
message_impl = self._impl.deq_one()
if message_impl is not None:
return MessageProperties._from_impl(message_impl)
def deqOne(self) -> Union["MessageProperties", None]:
"""
Deprecated: use deqone() instead.
"""
return self.deqone()
@property
def deqoptions(self) -> "DeqOptions":
"""
Returns the options that will be used when dequeuing messages from the
queue.
"""
return self._deq_options
@property
def deqOptions(self) -> "DeqOptions":
"""
Deprecated: use deqoptions instead.
"""
return self.deqoptions
def enqmany(self, messages: list) -> None:
"""
Enqueues multiple messages into the queue. The messages parameter must
be a sequence containing message property objects which have all had
their payload attribute set to a value that the queue supports.
Warning: calling this function in parallel on different connections
acquired from the same pool may fail due to Oracle bug 29928074. Ensure
that this function is not run in parallel, use standalone connections
or connections from different pools, or make multiple calls to
enqOne() instead. The function Queue.deqMany() call is not affected.
"""
for message in messages:
self._verify_message(message)
message_impls = [m._impl for m in messages]
self._impl.enq_many(message_impls)
def enqMany(self, messages: list) -> None:
"""
Deprecated: use enqmany() instead.
"""
return self.enqmany(messages)
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
the queue supports.
"""
self._verify_message(message)
self._impl.enq_one(message._impl)
def enqOne(self, message: "MessageProperties") -> None:
"""
Deprecated: use enqone() instead.
"""
return self.enqone(message)
@property
def enqoptions(self) -> "EnqOptions":
"""
Returns the options that will be used when enqueuing messages into the
queue.
"""
return self._enq_options
@property
def enqOptions(self) -> "EnqOptions":
"""
Deprecated: use enqoptions() instead.
"""
return self.enqoptions
@property
def name(self) -> str:
"""
Returns the name of the queue.
"""
return self._impl.name
@property
def payload_type(self) -> Union[DbObjectType, None]:
"""
Returns the object type for payloads that can be enqueued and dequeued.
If using a raw queue, this returns the value None.
"""
if self._payload_type is None:
if self._impl.is_json:
self._payload_type = "JSON"
elif self._impl.payload_type is not None:
self._payload_type = DbObjectType._from_impl(
self._impl.payload_type
)
return self._payload_type
@property
def payloadType(self) -> Union[DbObjectType, None]:
"""
Deprecated: use payload_type instead.
"""
return self.payload_type
class DeqOptions:
@classmethod
def _from_impl(cls, impl):
options = cls.__new__(cls)
options._impl = impl
return options
@property
def condition(self) -> str:
"""
Specifies a boolean expression similar to the where clause of a SQL
query. The boolean expression can include conditions on message
properties, user data properties and PL/SQL or SQL functions. The
default is to have no condition specified.
"""
return self._impl.get_condition()
@condition.setter
def condition(self, value: str) -> None:
self._impl.set_condition(value)
@property
def consumername(self) -> str:
"""
Specifies the name of the consumer. Only messages matching the consumer
name will be accessed. If the queue is not set up for multiple
consumers this attribute should not be set. The default is to have no
consumer name specified.
"""
return self._impl.get_consumer_name()
@consumername.setter
def consumername(self, value: str) -> None:
self._impl.set_consumer_name(value)
@property
def correlation(self) -> str:
"""
Specifies the correlation identifier of the message to be dequeued.
Special pattern-matching characters, such as the percent sign (%) and
the underscore (_), can be used. If multiple messages satisfy the
pattern, the order of dequeuing is indeterminate. The default is to
have no correlation specified.
"""
return self._impl.get_correlation()
@correlation.setter
def correlation(self, value: str) -> None:
self._impl.set_correlation(value)
@property
def deliverymode(self) -> None:
"""
Specifies what types of messages should be dequeued. It should be one
of the values MSG_PERSISTENT (default), MSG_BUFFERED or
MSG_PERSISTENT_OR_BUFFERED.
"""
raise AttributeError("deliverymode can only be written")
@deliverymode.setter
def deliverymode(self, value: int) -> None:
self._impl.set_delivery_mode(value)
@property
def mode(self) -> int:
"""
Specifies the locking behaviour associated with the dequeue operation.
It should be one of the values DEQ_BROWSE, DEQ_LOCKED, DEQ_REMOVE
(default), or DEQ_REMOVE_NODATA.
"""
return self._impl.get_mode()
@mode.setter
def mode(self, value: int) -> None:
self._impl.set_mode(value)
@property
def msgid(self) -> bytes:
"""
Specifies the identifier of the message to be dequeued. The default is
to have no message identifier specified.
"""
return self._impl.get_message_id()
@msgid.setter
def msgid(self, value: bytes) -> None:
self._impl.set_message_id(value)
@property
def navigation(self) -> int:
"""
Specifies the position of the message that is retrieved. It should be
one of the values DEQ_FIRST_MSG, DEQ_NEXT_MSG (default), or
DEQ_NEXT_TRANSACTION.
"""
return self._impl.get_navigation()
@navigation.setter
def navigation(self, value: int) -> None:
self._impl.set_navigation(value)
@property
def transformation(self) -> str:
"""
Specifies the name of the transformation that must be applied after the
message is dequeued from the database but before it is returned to the
calling application. The transformation must be created using
dbms_transform. The default is to have no transformation specified.
"""
return self._impl.get_transformation()
@transformation.setter
def transformation(self, value: str) -> None:
self._impl.set_transformation(value)
@property
def visibility(self) -> int:
"""
Specifies the transactional behavior of the dequeue request. It should
be one of the values DEQ_ON_COMMIT (default) or DEQ_IMMEDIATE. This
attribute is ignored when using the DEQ_BROWSE mode. Note the value of
autocommit is always ignored.
"""
return self._impl.get_visibility()
@visibility.setter
def visibility(self, value: int) -> None:
self._impl.set_visibility(value)
@property
def wait(self) -> int:
"""
Specifies the time to wait, in seconds, for a message matching the
search criteria to become available for dequeuing. One of the values
DEQ_NO_WAIT or DEQ_WAIT_FOREVER can also be used. The default is
DEQ_WAIT_FOREVER.
"""
return self._impl.get_wait()
@wait.setter
def wait(self, value: int) -> None:
self._impl.set_wait(value)
class EnqOptions:
@classmethod
def _from_impl(cls, impl):
options = cls.__new__(cls)
options._impl = impl
return options
@property
def deliverymode(self) -> int:
"""
Specifies what type of messages should be enqueued. It should be one of
the values MSG_PERSISTENT (default) or MSG_BUFFERED.
"""
raise AttributeError("deliverymode can only be written")
@deliverymode.setter
def deliverymode(self, value: int) -> None:
self._impl.set_delivery_mode(value)
@property
def transformation(self) -> str:
"""
Specifies the name of the transformation that must be applied before
the message is enqueued into the database. The transformation must be
created using dbms_transform. The default is to have no transformation
specified.
"""
return self._impl.get_transformation()
@transformation.setter
def transformation(self, value: str) -> None:
self._impl.set_transformation(value)
@property
def visibility(self) -> int:
"""
Specifies the transactional behavior of the enqueue request. It should
be one of the values ENQ_ON_COMMIT (default) or ENQ_IMMEDIATE. Note the
value of autocommit is ignored.
"""
return self._impl.get_visibility()
@visibility.setter
def visibility(self, value: int) -> None:
self._impl.set_visibility(value)
class MessageProperties:
_recipients = []
@classmethod
def _from_impl(cls, impl):
props = cls.__new__(cls)
props._impl = impl
return props
@property
def attempts(self) -> int:
"""
Specifies the number of attempts that have been made to dequeue the
message.
"""
return self._impl.get_num_attempts()
@property
def correlation(self) -> str:
"""
Specifies the correlation used when the message was enqueued.
"""
return self._impl.get_correlation()
@correlation.setter
def correlation(self, value: str) -> None:
self._impl.set_correlation(value)
@property
def delay(self) -> int:
"""
Specifies the number of seconds to delay an enqueued message. Any
integer is acceptable but the constant MSG_NO_DELAY can also be used
indicating that the message is available for immediate dequeuing.
"""
return self._impl.get_delay()
@delay.setter
def delay(self, value: int) -> None:
self._impl.set_delay(value)
@property
def deliverymode(self) -> int:
"""
Specifies the type of message that was dequeued. It will be one of the
values MSG_PERSISTENT or MSG_BUFFERED.
"""
return self._impl.get_delivery_mode()
@property
def enqtime(self) -> datetime.datetime:
"""
Specifies the time that the message was enqueued.
"""
return self._impl.get_enq_time()
@property
def exceptionq(self) -> str:
"""
Specifies the name of the queue to which the message is moved if it
cannot be processed successfully. Messages are moved if the number of
unsuccessful dequeue attempts has exceeded the maximum number of
retries or if the message has expired. All messages in the exception
queue are in the MSG_EXPIRED state. The default value is the name of
the exception queue associated with the queue table.
"""
return self._impl.get_exception_queue()
@exceptionq.setter
def exceptionq(self, value: str) -> None:
self._impl.set_exception_queue(value)
@property
def expiration(self) -> int:
"""
Specifies, in seconds, how long the message is available for dequeuing.
This attribute is an offset from the delay attribute. Expiration
processing requires the queue monitor to be running. Any integer is
accepted but the constant MSG_NO_EXPIRATION can also be used indicating
that the message never expires.
"""
return self._impl.get_expiration()
@expiration.setter
def expiration(self, value: int) -> None:
self._impl.set_expiration(value)
@property
def msgid(self) -> bytes:
"""
Specifies the id of the message in the last queue that enqueued or
dequeued this message. If the message has never been dequeued or
enqueued, the value will be `None`.
"""
return self._impl.get_message_id()
@property
def payload(self) -> Union[bytes, DbObject]:
"""
Specifies the payload that will be enqueued or the payload that was
dequeued when using a queue. When enqueuing, the value is checked to
ensure that it conforms to the type expected by that queue. For RAW
queues, the value can be a bytes object or a string. If the value is a
string it will be converted to bytes in the encoding UTF-8.
"""
return self._impl.payload
@payload.setter
def payload(self, value: Any) -> None:
if isinstance(value, DbObject):
self._impl.set_payload_object(value._impl)
elif not isinstance(value, (str, bytes)):
self._impl.set_payload_json(value)
else:
if isinstance(value, str):
value_bytes = value.encode()
elif isinstance(value, bytes):
value_bytes = value
self._impl.set_payload_bytes(value_bytes)
self._impl.payload = value
@property
def priority(self) -> int:
"""
Specifies the priority of the message. A smaller number indicates a
higher priority. The priority can be any integer, including negative
numbers. The default value is zero.
"""
return self._impl.get_priority()
@priority.setter
def priority(self, value: int) -> None:
self._impl.set_priority(value)
@property
def recipients(self) -> list:
"""
A list of recipient names can be associated with a message at the time
a message is enqueued. This allows a limited set of recipients to
dequeue each message. The recipient list associated with the message
overrides the queue subscriber list, if there is one. The recipient
names need not be in the subscriber list but can be, if desired.
To dequeue a message, the consumername attribute can be set to one of
the recipient names. The original message recipient list is not
available on dequeued messages. All recipients have to dequeue a
message before it gets removed from the queue.
Subscribing to a queue is like subscribing to a magazine: each
subscriber can dequeue all the messages placed into a specific queue,
just as each magazine subscriber has access to all its articles. Being
a recipient, however, is like getting a letter: each recipient is a
designated target of a particular message.
"""
return self._recipients
@recipients.setter
def recipients(self, value: list) -> None:
self._impl.set_recipients(value)
self._recipients = value
@property
def state(self) -> int:
"""
Specifies the state of the message at the time of the dequeue. It will
be one of the values MSG_WAITING, MSG_READY, MSG_PROCESSED or
MSG_EXPIRED.
"""
return self._impl.get_state()
@@ -0,0 +1,878 @@
# -----------------------------------------------------------------------------
# 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
# 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
# either license.
#
# If you elect to accept the software under the Apache License, Version 2.0,
# the following applies:
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# connect_params.py
#
# Contains the ConnectParams class used for managing the parameters required to
# establish a connection to the database.
#
# *** NOTICE *** This file is generated from a template and should not be
# modified directly. See build_from_template.py in the utils subdirectory for
# more information.
# -----------------------------------------------------------------------------
import functools
from typing import Union, Callable, Any
import oracledb
from . import base_impl, utils
class ConnectParams:
"""
Contains all parameters used for establishing a connection to the
database.
"""
__module__ = oracledb.__name__
__slots__ = ["_impl"]
_impl_class = base_impl.ConnectParamsImpl
@utils.params_initer
def __init__(
self,
*,
user: str = None,
proxy_user: str = None,
password: str = None,
newpassword: str = None,
wallet_password: str = None,
access_token: Union[str, tuple, Callable] = None,
host: str = None,
port: int = 1521,
protocol: str = "tcp",
https_proxy: str = None,
https_proxy_port: int = 0,
service_name: str = None,
sid: str = None,
server_type: str = None,
cclass: str = None,
purity: int = oracledb.PURITY_DEFAULT,
expire_time: int = 0,
retry_count: int = 0,
retry_delay: int = 0,
tcp_connect_timeout: float = 60.0,
ssl_server_dn_match: bool = True,
ssl_server_cert_dn: str = None,
wallet_location: str = None,
events: bool = False,
externalauth: bool = False,
mode: int = oracledb.AUTH_MODE_DEFAULT,
disable_oob: bool = False,
stmtcachesize: int = oracledb.defaults.stmtcachesize,
edition: str = None,
tag: str = None,
matchanytag: bool = False,
config_dir: str = oracledb.defaults.config_dir,
appcontext: list = None,
shardingkey: list = None,
supershardingkey: list = None,
debug_jdwp: str = None,
connection_id_prefix: str = None,
ssl_context: Any = None,
sdu: int = 8192,
handle: int = 0,
):
"""
All parameters are optional. A brief description of each parameter
follows:
- user: the name of the user to connect to (default: None)
- proxy_user: the name of the proxy user to connect to. If this value
is not specified, it will be parsed out of user if user is in the
form "user[proxy_user]" (default: None)
- password: the password for the user (default: None)
- newpassword: the new password for the user. The new password will
take effect immediately upon a successful connection to the database
(default: None)
- wallet_password: the password to use to decrypt the wallet, if it is
encrypted. This value is only used in thin mode (default: None)
- access_token: expected to be a string or a 2-tuple or a callable. If
it is a string, it specifies an Azure AD OAuth2 token used for Open
Authorization (OAuth 2.0) token based authentication. If it is a
2-tuple, it specifies the token and private key strings used for
Oracle Cloud Infrastructure (OCI) Identity and Access Management
(IAM) token based authentication. If it is a callable, it returns
either a string or a 2-tuple used for OAuth 2.0 or OCI IAM token
based authentication and is useful when the pool needs to expand and
create new connections but the current authentication token has
expired (default: None)
- host: the name or IP address of the machine hosting the database or
the database listener (default: None)
- port: the port number on which the database listener is listening
(default: 1521)
- protocol: one of the strings "tcp" or "tcps" indicating whether to
use unencrypted network traffic or encrypted network traffic (TLS)
(default: "tcp")
- https_proxy: the name or IP address of a proxy host to use for
tunneling secure connections (default: None)
- https_proxy_port: the port on which to communicate with the proxy
host (default: 0)
- service_name: the service name of the database (default: None)
- sid: the system identifier (SID) of the database. Note using a
service_name instead is recommended (default: None)
- server_type: the type of server connection that should be
established. If specified, it should be one of "dedicated", "shared"
or "pooled" (default: None)
- cclass: connection class to use for Database Resident Connection
Pooling (DRCP) (default: None)
- purity: purity to use for Database Resident Connection Pooling (DRCP)
(default: oracledb.PURITY_DEFAULT)
- expire_time: an integer indicating the number of minutes between the
sending of keepalive probes. If this parameter is set to a value
greater than zero it enables keepalive (default: 0)
- retry_count: the number of times that a connection attempt should be
retried before the attempt is terminated (default: 0)
- retry_delay: the number of seconds to wait before making a new
connection attempt (default: 0)
- tcp_connect_timeout: a float indicating the maximum number of seconds
to wait for establishing a connection to the database host (default:
60.0)
- ssl_server_dn_match: boolean indicating whether the server
certificate distinguished name (DN) should be matched in addition to
the regular certificate verification that is performed. Note that if
the ssl_server_cert_dn parameter is not privided, host name matching
is performed instead (default: True)
- ssl_server_cert_dn: the distinguished name (DN) which should be
matched with the server. This value is ignored if the
ssl_server_dn_match parameter is not set to the value True. If
specified this value is used for any verfication. Otherwise the
hostname will be used. (default: None)
- wallet_location: the directory where the wallet can be found. In thin
mode this must be the directory containing the PEM-encoded wallet
file ewallet.pem. In thick mode this must be the directory containing
the file cwallet.sso (default: None)
- events: boolean specifying whether events mode should be enabled.
This value is only used in thick mode and is needed for continuous
query notification and high availability event notifications
(default: False)
- externalauth: a boolean indicating whether to use external
authentication (default: False)
- mode: authorization mode to use. For example
oracledb.AUTH_MODE_SYSDBA (default: oracledb.AUTH_MODE_DEFAULT)
- disable_oob: boolean indicating whether out-of-band breaks should be
disabled. This value is only used in thin mode. It has no effect on
Windows which does not support this functionality (default: False)
- stmtcachesize: identifies the initial size of the statement cache
(default: oracledb.defaults.stmtcachesize)
- edition: edition to use for the connection. This parameter cannot be
used simultaneously with the cclass parameter (default: None)
- tag: identifies the type of connection that should be returned from a
pool. This value is only used in thick mode (default: None)
- matchanytag: boolean specifying whether any tag can be used when
acquiring a connection from the pool. This value is only used in
thick mode. (default: False)
- config_dir: directory in which the optional tnsnames.ora
configuration file is located. This value is only used in thin mode.
For thick mode use the config_dir parameter of init_oracle_client()
(default: oracledb.defaults.config_dir)
- appcontext: application context used by the connection. It should be
a list of 3-tuples (namespace, name, value) and each entry in the
tuple should be a string. This value is only used in thick mode
(default: None)
- shardingkey: a list of strings, numbers, bytes or dates that identify
the database shard to connect to. This value is only used in thick
mode (default: None)
- supershardingkey: a list of strings, numbers, bytes or dates that
identify the database shard to connect to. This value is only used in
thick mode (default: None)
- debug_jdwp: a string with the format "host=<host>;port=<port>" that
specifies the host and port of the PL/SQL debugger. This value is
only used in thin mode. For thick mode set the ORA_DEBUG_JDWP
environment variable (default: None)
- connection_id_prefix: an application specific prefix that is added to
the connection identifier used for tracing (default: None)
- ssl_context: an SSLContext object used for connecting to the database
using TLS. This SSL context will be modified to include the private
key or any certificates found in a separately supplied wallet. This
parameter should only be specified if the default SSLContext object
cannot be used (default: None)
- sdu: the requested size of the Session Data Unit (SDU), in bytes. The
value tunes internal buffers used for communication to the database.
Bigger values can increase throughput for large queries or bulk data
loads, but at the cost of higher memory use. The SDU size that will
actually be used is negotiated down to the lower of this value and
the database network SDU configuration value (default: 8192)
- handle: an integer representing a pointer to a valid service context
handle. This value is only used in thick mode. It should be used with
extreme caution (default: 0)
"""
pass
def __repr__(self):
return (
self.__class__.__qualname__
+ "("
+ f"user={self.user!r}, "
+ f"proxy_user={self.proxy_user!r}, "
+ f"host={self.host!r}, "
+ f"port={self.port!r}, "
+ f"protocol={self.protocol!r}, "
+ f"https_proxy={self.https_proxy!r}, "
+ f"https_proxy_port={self.https_proxy_port!r}, "
+ f"service_name={self.service_name!r}, "
+ f"sid={self.sid!r}, "
+ f"server_type={self.server_type!r}, "
+ f"cclass={self.cclass!r}, "
+ f"purity={self.purity!r}, "
+ f"expire_time={self.expire_time!r}, "
+ f"retry_count={self.retry_count!r}, "
+ f"retry_delay={self.retry_delay!r}, "
+ f"tcp_connect_timeout={self.tcp_connect_timeout!r}, "
+ f"ssl_server_dn_match={self.ssl_server_dn_match!r}, "
+ f"ssl_server_cert_dn={self.ssl_server_cert_dn!r}, "
+ f"wallet_location={self.wallet_location!r}, "
+ f"events={self.events!r}, "
+ f"externalauth={self.externalauth!r}, "
+ f"mode={self.mode!r}, "
+ f"disable_oob={self.disable_oob!r}, "
+ f"stmtcachesize={self.stmtcachesize!r}, "
+ f"edition={self.edition!r}, "
+ f"tag={self.tag!r}, "
+ f"matchanytag={self.matchanytag!r}, "
+ f"config_dir={self.config_dir!r}, "
+ f"appcontext={self.appcontext!r}, "
+ f"shardingkey={self.shardingkey!r}, "
+ f"supershardingkey={self.supershardingkey!r}, "
+ f"debug_jdwp={self.debug_jdwp!r}, "
+ f"connection_id_prefix={self.connection_id_prefix!r}, "
+ f"ssl_context={self.ssl_context!r}, "
+ f"sdu={self.sdu!r}"
+ ")"
)
def _address_attr(f):
"""
Helper function used to get address level attributes.
"""
@functools.wraps(f)
def wrapped(self):
values = [
getattr(a, f.__name__) for a in self._impl._get_addresses()
]
return values if len(values) > 1 else values[0]
return wrapped
def _description_attr(f):
"""
Helper function used to get description level attributes.
"""
@functools.wraps(f)
def wrapped(self):
values = [
getattr(d, f.__name__)
for d in self._impl.description_list.children
]
return values if len(values) > 1 else values[0]
return wrapped
@property
def appcontext(self) -> list:
"""
Application context used by the connection. It should be a list of
3-tuples (namespace, name, value) and each entry in the tuple should be
a string. This value is only used in thick mode.
"""
return self._impl.appcontext
@property
@_description_attr
def cclass(self) -> Union[list, str]:
"""
Connection class to use for Database Resident Connection Pooling
(DRCP).
"""
return self._impl.cclass
@property
def config_dir(self) -> str:
"""
Directory in which the optional tnsnames.ora configuration file is
located. This value is only used in thin mode. For thick mode use the
config_dir parameter of init_oracle_client().
"""
return self._impl.config_dir
@property
@_description_attr
def connection_id_prefix(self) -> Union[list, str]:
"""
An application specific prefix that is added to the connection
identifier used for tracing.
"""
return self._impl.connection_id_prefix
@property
def debug_jdwp(self) -> str:
"""
A string with the format "host=<host>;port=<port>" that specifies the
host and port of the PL/SQL debugger. This value is only used in thin
mode. For thick mode set the ORA_DEBUG_JDWP environment variable.
"""
return self._impl.debug_jdwp
@property
def disable_oob(self) -> bool:
"""
Boolean indicating whether out-of-band breaks should be disabled. This
value is only used in thin mode. It has no effect on Windows which does
not support this functionality.
"""
return self._impl.disable_oob
@property
def edition(self) -> str:
"""
Edition to use for the connection. This parameter cannot be used
simultaneously with the cclass parameter.
"""
return self._impl.edition
@property
def events(self) -> bool:
"""
Boolean specifying whether events mode should be enabled. This value is
only used in thick mode and is needed for continuous query notification
and high availability event notifications.
"""
return self._impl.events
@property
@_description_attr
def expire_time(self) -> Union[list, int]:
"""
An integer indicating the number of minutes between the sending of
keepalive probes. If this parameter is set to a value greater than zero
it enables keepalive.
"""
return self._impl.expire_time
@property
def externalauth(self) -> bool:
"""
A boolean indicating whether to use external authentication.
"""
return self._impl.externalauth
@property
@_address_attr
def host(self) -> Union[list, str]:
"""
The name or IP address of the machine hosting the database or the
database listener.
"""
return self._impl.host
@property
@_address_attr
def https_proxy(self) -> Union[list, str]:
"""
The name or IP address of a proxy host to use for tunneling secure
connections.
"""
return self._impl.https_proxy
@property
@_address_attr
def https_proxy_port(self) -> Union[list, int]:
"""
The port on which to communicate with the proxy host.
"""
return self._impl.https_proxy_port
@property
def matchanytag(self) -> bool:
"""
Boolean specifying whether any tag can be used when acquiring a
connection from the pool. This value is only used in thick mode..
"""
return self._impl.matchanytag
@property
def mode(self) -> int:
"""
Authorization mode to use. For example oracledb.AUTH_MODE_SYSDBA.
"""
return self._impl.mode
@property
@_address_attr
def port(self) -> Union[list, int]:
"""
The port number on which the database listener is listening.
"""
return self._impl.port
@property
@_address_attr
def protocol(self) -> Union[list, str]:
"""
One of the strings "tcp" or "tcps" indicating whether to use
unencrypted network traffic or encrypted network traffic (TLS).
"""
return self._impl.protocol
@property
def proxy_user(self) -> str:
"""
The name of the proxy user to connect to. If this value is not
specified, it will be parsed out of user if user is in the form
"user[proxy_user]".
"""
return self._impl.proxy_user
@property
@_description_attr
def purity(self) -> Union[list, int]:
"""
Purity to use for Database Resident Connection Pooling (DRCP).
"""
return self._impl.purity
@property
@_description_attr
def retry_count(self) -> Union[list, int]:
"""
The number of times that a connection attempt should be retried before
the attempt is terminated.
"""
return self._impl.retry_count
@property
@_description_attr
def retry_delay(self) -> Union[list, int]:
"""
The number of seconds to wait before making a new connection attempt.
"""
return self._impl.retry_delay
@property
@_description_attr
def sdu(self) -> Union[list, int]:
"""
The requested size of the Session Data Unit (SDU), in bytes. The value
tunes internal buffers used for communication to the database. Bigger
values can increase throughput for large queries or bulk data loads,
but at the cost of higher memory use. The SDU size that will actually
be used is negotiated down to the lower of this value and the database
network SDU configuration value.
"""
return self._impl.sdu
@property
@_description_attr
def server_type(self) -> Union[list, str]:
"""
The type of server connection that should be established. If specified,
it should be one of "dedicated", "shared" or "pooled".
"""
return self._impl.server_type
@property
@_description_attr
def service_name(self) -> Union[list, str]:
"""
The service name of the database.
"""
return self._impl.service_name
@property
def shardingkey(self) -> list:
"""
A list of strings, numbers, bytes or dates that identify the database
shard to connect to. This value is only used in thick mode.
"""
return self._impl.shardingkey
@property
@_description_attr
def sid(self) -> Union[list, str]:
"""
The system identifier (SID) of the database. Note using a service_name
instead is recommended.
"""
return self._impl.sid
@property
def ssl_context(self) -> Any:
"""
An SSLContext object used for connecting to the database using TLS.
This SSL context will be modified to include the private key or any
certificates found in a separately supplied wallet. This parameter
should only be specified if the default SSLContext object cannot be
used.
"""
return self._impl.ssl_context
@property
@_description_attr
def ssl_server_cert_dn(self) -> Union[list, str]:
"""
The distinguished name (DN) which should be matched with the server.
This value is ignored if the ssl_server_dn_match parameter is not set
to the value True. If specified this value is used for any verfication.
Otherwise the hostname will be used..
"""
return self._impl.ssl_server_cert_dn
@property
@_description_attr
def ssl_server_dn_match(self) -> Union[list, bool]:
"""
Boolean indicating whether the server certificate distinguished name
(DN) should be matched in addition to the regular certificate
verification that is performed. Note that if the ssl_server_cert_dn
parameter is not privided, host name matching is performed instead.
"""
return self._impl.ssl_server_dn_match
@property
def stmtcachesize(self) -> int:
"""
Identifies the initial size of the statement cache.
"""
return self._impl.stmtcachesize
@property
def supershardingkey(self) -> list:
"""
A list of strings, numbers, bytes or dates that identify the database
shard to connect to. This value is only used in thick mode.
"""
return self._impl.supershardingkey
@property
def tag(self) -> str:
"""
Identifies the type of connection that should be returned from a pool.
This value is only used in thick mode.
"""
return self._impl.tag
@property
@_description_attr
def tcp_connect_timeout(self) -> Union[list, float]:
"""
A float indicating the maximum number of seconds to wait for
establishing a connection to the database host.
"""
return self._impl.tcp_connect_timeout
@property
def user(self) -> str:
"""
The name of the user to connect to.
"""
return self._impl.user
@property
@_description_attr
def wallet_location(self) -> Union[list, str]:
"""
The directory where the wallet can be found. In thin mode this must be
the directory containing the PEM-encoded wallet file ewallet.pem. In
thick mode this must be the directory containing the file cwallet.sso.
"""
return self._impl.wallet_location
def copy(self) -> "ConnectParams":
"""
Creates a copy of the parameters and returns it.
"""
params = ConnectParams.__new__(ConnectParams)
params._impl = self._impl.copy()
return params
def get_connect_string(self) -> str:
"""
Returns a connect string generated from the parameters.
"""
return self._impl.get_connect_string()
def parse_connect_string(self, connect_string: str) -> None:
"""
Parses the connect string into its components and stores the
parameters. The connect string could be an Easy Connect string,
name-value pairs or a simple alias which is looked up in tnsnames.ora.
Any parameters found in the connect string override any currently
stored values.
"""
self._impl.parse_connect_string(connect_string)
def parse_dsn_with_credentials(self, dsn: str) -> tuple:
"""
Parses a dsn in the form <user>/<password>@<connect_string> or in the
form <user>/<password> and returns a 3-tuple containing the parsed
user, password and connect string. Empty strings are returned as the
value None. This is done automatically when a value is passed to
the dsn parameter but no value is passed to the user password when
creating a standalone connection or connection pool.
"""
return self._impl.parse_dsn_with_credentials(dsn)
@utils.params_setter
def set(
self,
*,
user: str = None,
proxy_user: str = None,
password: str = None,
newpassword: str = None,
wallet_password: str = None,
access_token: Union[str, tuple, Callable] = None,
host: str = None,
port: int = None,
protocol: str = None,
https_proxy: str = None,
https_proxy_port: int = None,
service_name: str = None,
sid: str = None,
server_type: str = None,
cclass: str = None,
purity: int = None,
expire_time: int = None,
retry_count: int = None,
retry_delay: int = None,
tcp_connect_timeout: float = None,
ssl_server_dn_match: bool = None,
ssl_server_cert_dn: str = None,
wallet_location: str = None,
events: bool = None,
externalauth: bool = None,
mode: int = None,
disable_oob: bool = None,
stmtcachesize: int = None,
edition: str = None,
tag: str = None,
matchanytag: bool = None,
config_dir: str = None,
appcontext: list = None,
shardingkey: list = None,
supershardingkey: list = None,
debug_jdwp: str = None,
connection_id_prefix: str = None,
ssl_context: Any = None,
sdu: int = None,
handle: int = None,
):
"""
All parameters are optional. A brief description of each parameter
follows:
- user: the name of the user to connect to
- proxy_user: the name of the proxy user to connect to. If this value
is not specified, it will be parsed out of user if user is in the
form "user[proxy_user]"
- password: the password for the user
- newpassword: the new password for the user. The new password will
take effect immediately upon a successful connection to the database
- wallet_password: the password to use to decrypt the wallet, if it is
encrypted. This value is only used in thin mode
- access_token: expected to be a string or a 2-tuple or a callable. If
it is a string, it specifies an Azure AD OAuth2 token used for Open
Authorization (OAuth 2.0) token based authentication. If it is a
2-tuple, it specifies the token and private key strings used for
Oracle Cloud Infrastructure (OCI) Identity and Access Management
(IAM) token based authentication. If it is a callable, it returns
either a string or a 2-tuple used for OAuth 2.0 or OCI IAM token
based authentication and is useful when the pool needs to expand and
create new connections but the current authentication token has
expired
- host: the name or IP address of the machine hosting the database or
the database listener
- port: the port number on which the database listener is listening
- protocol: one of the strings "tcp" or "tcps" indicating whether to
use unencrypted network traffic or encrypted network traffic (TLS)
- https_proxy: the name or IP address of a proxy host to use for
tunneling secure connections
- https_proxy_port: the port on which to communicate with the proxy
host
- service_name: the service name of the database
- sid: the system identifier (SID) of the database. Note using a
service_name instead is recommended
- server_type: the type of server connection that should be
established. If specified, it should be one of "dedicated", "shared"
or "pooled"
- cclass: connection class to use for Database Resident Connection
Pooling (DRCP)
- purity: purity to use for Database Resident Connection Pooling (DRCP)
- expire_time: an integer indicating the number of minutes between the
sending of keepalive probes. If this parameter is set to a value
greater than zero it enables keepalive
- retry_count: the number of times that a connection attempt should be
retried before the attempt is terminated
- retry_delay: the number of seconds to wait before making a new
connection attempt
- tcp_connect_timeout: a float indicating the maximum number of seconds
to wait for establishing a connection to the database host
- ssl_server_dn_match: boolean indicating whether the server
certificate distinguished name (DN) should be matched in addition to
the regular certificate verification that is performed. Note that if
the ssl_server_cert_dn parameter is not privided, host name matching
is performed instead
- ssl_server_cert_dn: the distinguished name (DN) which should be
matched with the server. This value is ignored if the
ssl_server_dn_match parameter is not set to the value True. If
specified this value is used for any verfication. Otherwise the
hostname will be used.
- wallet_location: the directory where the wallet can be found. In thin
mode this must be the directory containing the PEM-encoded wallet
file ewallet.pem. In thick mode this must be the directory containing
the file cwallet.sso
- events: boolean specifying whether events mode should be enabled.
This value is only used in thick mode and is needed for continuous
query notification and high availability event notifications
- externalauth: a boolean indicating whether to use external
authentication
- mode: authorization mode to use. For example
oracledb.AUTH_MODE_SYSDBA
- disable_oob: boolean indicating whether out-of-band breaks should be
disabled. This value is only used in thin mode. It has no effect on
Windows which does not support this functionality
- stmtcachesize: identifies the initial size of the statement cache
- edition: edition to use for the connection. This parameter cannot be
used simultaneously with the cclass parameter
- tag: identifies the type of connection that should be returned from a
pool. This value is only used in thick mode
- matchanytag: boolean specifying whether any tag can be used when
acquiring a connection from the pool. This value is only used in
thick mode.
- config_dir: directory in which the optional tnsnames.ora
configuration file is located. This value is only used in thin mode.
For thick mode use the config_dir parameter of init_oracle_client()
- appcontext: application context used by the connection. It should be
a list of 3-tuples (namespace, name, value) and each entry in the
tuple should be a string. This value is only used in thick mode
- shardingkey: a list of strings, numbers, bytes or dates that identify
the database shard to connect to. This value is only used in thick
mode
- supershardingkey: a list of strings, numbers, bytes or dates that
identify the database shard to connect to. This value is only used in
thick mode
- debug_jdwp: a string with the format "host=<host>;port=<port>" that
specifies the host and port of the PL/SQL debugger. This value is
only used in thin mode. For thick mode set the ORA_DEBUG_JDWP
environment variable
- connection_id_prefix: an application specific prefix that is added to
the connection identifier used for tracing
- ssl_context: an SSLContext object used for connecting to the database
using TLS. This SSL context will be modified to include the private
key or any certificates found in a separately supplied wallet. This
parameter should only be specified if the default SSLContext object
cannot be used
- sdu: the requested size of the Session Data Unit (SDU), in bytes. The
value tunes internal buffers used for communication to the database.
Bigger values can increase throughput for large queries or bulk data
loads, but at the cost of higher memory use. The SDU size that will
actually be used is negotiated down to the lower of this value and
the database network SDU configuration value
- handle: an integer representing a pointer to a valid service context
handle. This value is only used in thick mode. It should be used with
extreme caution
"""
pass
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,164 @@
# -----------------------------------------------------------------------------
# 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
# 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
# either license.
#
# If you elect to accept the software under the Apache License, Version 2.0,
# the following applies:
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# constants.py
#
# Contains the constants defined by the package.
# -----------------------------------------------------------------------------
# mandated DB API constants
apilevel = "2.0"
threadsafety = 2
paramstyle = "named"
# authentication modes
AUTH_MODE_DEFAULT = 0
AUTH_MODE_PRELIM = 0x00000008
AUTH_MODE_SYSASM = 0x00008000
AUTH_MODE_SYSBKP = 0x00020000
AUTH_MODE_SYSDBA = 0x00000002
AUTH_MODE_SYSDGD = 0x00040000
AUTH_MODE_SYSKMT = 0x00080000
AUTH_MODE_SYSOPER = 0x00000004
AUTH_MODE_SYSRAC = 0x00100000
# pool "get" modes
POOL_GETMODE_WAIT = 0
POOL_GETMODE_NOWAIT = 1
POOL_GETMODE_FORCEGET = 2
POOL_GETMODE_TIMEDWAIT = 3
# purity values
PURITY_DEFAULT = 0
PURITY_NEW = 1
PURITY_SELF = 2
# AQ delivery modes
MSG_BUFFERED = 2
MSG_PERSISTENT = 1
MSG_PERSISTENT_OR_BUFFERED = 3
# AQ dequeue modes
DEQ_BROWSE = 1
DEQ_LOCKED = 2
DEQ_REMOVE = 3
DEQ_REMOVE_NODATA = 4
# AQ dequeue navigation modes
DEQ_FIRST_MSG = 1
DEQ_NEXT_MSG = 3
DEQ_NEXT_TRANSACTION = 2
# AQ dequeue visibility modes
DEQ_IMMEDIATE = 1
DEQ_ON_COMMIT = 2
# AQ dequeue wait modes
DEQ_NO_WAIT = 0
DEQ_WAIT_FOREVER = 2**32 - 1
# AQ enqueue visibility modes
ENQ_IMMEDIATE = 1
ENQ_ON_COMMIT = 2
# AQ message states
MSG_EXPIRED = 3
MSG_PROCESSED = 2
MSG_READY = 0
MSG_WAITING = 1
# AQ other constants
MSG_NO_DELAY = 0
MSG_NO_EXPIRATION = -1
# shutdown modes
DBSHUTDOWN_ABORT = 4
DBSHUTDOWN_FINAL = 5
DBSHUTDOWN_IMMEDIATE = 3
DBSHUTDOWN_TRANSACTIONAL = 1
DBSHUTDOWN_TRANSACTIONAL_LOCAL = 2
# subscription grouping classes
SUBSCR_GROUPING_CLASS_NONE = 0
SUBSCR_GROUPING_CLASS_TIME = 1
# subscription grouping types
SUBSCR_GROUPING_TYPE_SUMMARY = 1
SUBSCR_GROUPING_TYPE_LAST = 2
# subscription namespaces
SUBSCR_NAMESPACE_AQ = 1
SUBSCR_NAMESPACE_DBCHANGE = 2
# subscription protocols
SUBSCR_PROTO_HTTP = 3
SUBSCR_PROTO_MAIL = 1
SUBSCR_PROTO_CALLBACK = 0
SUBSCR_PROTO_SERVER = 2
# subscription quality of service
SUBSCR_QOS_BEST_EFFORT = 0x10
SUBSCR_QOS_DEFAULT = 0
SUBSCR_QOS_DEREG_NFY = 0x02
SUBSCR_QOS_QUERY = 0x08
SUBSCR_QOS_RELIABLE = 0x01
SUBSCR_QOS_ROWIDS = 0x04
# event types
EVENT_AQ = 100
EVENT_DEREG = 5
EVENT_NONE = 0
EVENT_OBJCHANGE = 6
EVENT_QUERYCHANGE = 7
EVENT_SHUTDOWN = 2
EVENT_SHUTDOWN_ANY = 3
EVENT_STARTUP = 1
# operation codes
OPCODE_ALLOPS = 0
OPCODE_ALLROWS = 0x01
OPCODE_ALTER = 0x10
OPCODE_DELETE = 0x08
OPCODE_DROP = 0x20
OPCODE_INSERT = 0x02
OPCODE_UPDATE = 0x04
# flags for tpc_begin()
TPC_BEGIN_JOIN = 0x00000002
TPC_BEGIN_NEW = 0x00000001
TPC_BEGIN_PROMOTE = 0x00000008
TPC_BEGIN_RESUME = 0x00000004
# flags for tpc_end()
TPC_END_NORMAL = 0
TPC_END_SUSPEND = 0x00100000
# basic configuration constants
DRIVER_NAME = "python-oracledb"
INSTALLATION_URL = (
"https://python-oracledb.readthedocs.io/en/"
"latest/user_guide/initialization.html"
)
ENCODING = "UTF-8"
@@ -0,0 +1,76 @@
# -----------------------------------------------------------------------------
# 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
# 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
# either license.
#
# If you elect to accept the software under the Apache License, Version 2.0,
# the following applies:
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# constructors.py
#
# Contains the constructors mandated by the Python Database API.
# -----------------------------------------------------------------------------
import datetime
from . import errors
# synonyms for the types mandated by the database API
Binary = bytes
Date = datetime.date
Timestamp = datetime.datetime
def Time(hour: int, minute: int, second: int) -> None:
"""
Constructor mandated by the database API for creating a time value. Since
Oracle doesn't support time only values, an exception is raised when this
method is called.
"""
errors._raise_err(errors.ERR_TIME_NOT_SUPPORTED)
def DateFromTicks(ticks: float) -> datetime.date:
"""
Constructor mandated by the database API for creating a date value given
the number of seconds since the epoch (January 1, 1970). This is equivalent
to using datetime.date.fromtimestamp() and that should be used instead.
"""
return datetime.date.fromtimestamp(ticks)
def TimeFromTicks(ticks: float) -> None:
"""
Constructor mandated by the database API for creating a time value given
the number of seconds since the epoch (January 1, 1970). Since Oracle
doesn't support time only values, an exception is raised when this method
is called.
"""
errors._raise_err(errors.ERR_TIME_NOT_SUPPORTED)
def TimestampFromTicks(ticks: float) -> datetime.datetime:
"""
Constructor mandated by the database API for creating a timestamp value
given the number of seconds since the epoch (January 1, 1970). This is
equivalent to using datetime.datetime.fromtimestamp() and that should be
used instead.
"""
return datetime.datetime.fromtimestamp(ticks)
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,358 @@
# -----------------------------------------------------------------------------
# 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
# 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
# either license.
#
# If you elect to accept the software under the Apache License, Version 2.0,
# the following applies:
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# dbobject.py
#
# Contains the classes used for managing database objects and the database
# object type metadata: DbObject, DbObjectType and DbObjectAttr.
# -----------------------------------------------------------------------------
from typing import Any, Sequence, Union
from . import errors
from . import __name__ as MODULE_NAME
from .base_impl import DbType
class DbObject:
__module__ = MODULE_NAME
def __getattr__(self, name):
try:
attr_impl = self._impl.type.attrs_by_name[name]
except KeyError:
return super().__getattribute__(name)
return self._impl.get_attr_value(attr_impl)
def __repr__(self):
return (
f"<oracledb.DbObject {self.type._get_full_name()} at "
f"{hex(id(self))}>"
)
def __setattr__(self, name, value):
if name == "_impl" or name == "_type":
super().__setattr__(name, value)
else:
attr_impl = self._impl.type.attrs_by_name[name]
self._impl.set_attr_value(attr_impl, value)
def _ensure_is_collection(self):
"""
Ensures that the object refers to a collection. If not, an exception is
raised.
"""
if not self.type.iscollection:
errors._raise_err(
errors.ERR_OBJECT_IS_NOT_A_COLLECTION,
name=self.type._get_full_name(),
)
@classmethod
def _from_impl(cls, impl):
obj = cls.__new__(cls)
obj._impl = impl
obj._type = None
return obj
def append(self, element: Any) -> None:
"""
Append an element to the collection object. If no elements exist in the
collection, this creates an element at index 0; otherwise, it creates
an element immediately following the highest index available in the
collection.
"""
self._impl.append(element)
def asdict(self) -> dict:
"""
Return a dictionary where the collections indexes are the keys and the
elements are its values.
"""
self._ensure_is_collection()
result = {}
ix = self._impl.get_first_index()
while ix is not None:
result[ix] = self._impl.get_element_by_index(ix)
ix = self._impl.get_next_index(ix)
return result
def aslist(self) -> list:
"""
Return a list of each of the collections elements in index order.
"""
self._ensure_is_collection()
result = []
ix = self._impl.get_first_index()
while ix is not None:
result.append(self._impl.get_element_by_index(ix))
ix = self._impl.get_next_index(ix)
return result
def copy(self) -> "DbObject":
"""
Create a copy of the object and return it.
"""
copied_impl = self._impl.copy()
return DbObject._from_impl(copied_impl)
def delete(self, index: int) -> None:
"""
Delete the element at the specified index of the collection. If the
element does not exist or is otherwise invalid, an error is raised.
Note that the indices of the remaining elements in the collection are
not changed. In other words, the delete operation creates holes in the
collection.
"""
self._ensure_is_collection()
self._impl.delete_by_index(index)
def exists(self, index: int) -> bool:
"""
Return True or False indicating if an element exists in the collection
at the specified index.
"""
self._ensure_is_collection()
return self._impl.exists_by_index(index)
def extend(self, seq: list) -> None:
"""
Append all of the elements in the sequence to the collection. This is
the equivalent of performing append() for each element found in the
sequence.
"""
self._ensure_is_collection()
for value in seq:
self.append(value)
def first(self) -> int:
"""
Return the index of the first element in the collection. If the
collection is empty, None is returned.
"""
self._ensure_is_collection()
return self._impl.get_first_index()
def getelement(self, index: int) -> Any:
"""
Return the element at the specified index of the collection. If no
element exists at that index, an exception is raised.
"""
self._ensure_is_collection()
return self._impl.get_element_by_index(index)
def last(self) -> int:
"""
Return the index of the last element in the collection. If the
collection is empty, None is returned.
"""
self._ensure_is_collection()
return self._impl.get_last_index()
def next(self, index: int) -> int:
"""
Return the index of the next element in the collection following the
specified index. If there are no elements in the collection following
the specified index, None is returned.
"""
self._ensure_is_collection()
return self._impl.get_next_index(index)
def prev(self, index: int) -> int:
"""
Return the index of the element in the collection preceding the
specified index. If there are no elements in the collection preceding
the specified index, None is returned.
"""
self._ensure_is_collection()
return self._impl.get_prev_index(index)
def setelement(self, index: int, value: Any) -> None:
"""
Set the value in the collection at the specified index to the given
value.
"""
self._ensure_is_collection()
self._impl.set_element_by_index(index, value)
def size(self) -> int:
"""
Return the number of elements in the collection.
"""
self._ensure_is_collection()
return self._impl.get_size()
def trim(self, num: int) -> None:
"""
Remove the specified number of elements from the end of the collection.
"""
self._ensure_is_collection()
self._impl.trim(num)
@property
def type(self) -> "DbObjectType":
"""
Returns an ObjectType corresponding to the type of the object.
"""
if self._type is None:
self._type = DbObjectType._from_impl(self._impl.type)
return self._type
class DbObjectAttr:
__module__ = MODULE_NAME
def __repr__(self):
return f"<oracledb.DbObjectAttr {self.name}>"
@classmethod
def _from_impl(cls, impl):
attr = cls.__new__(cls)
attr._impl = impl
attr._type = None
return attr
@property
def name(self) -> str:
"""
This read-only attribute returns the name of the attribute.
"""
return self._impl.name
@property
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;
otherwise, it will be one of the database type constants.
"""
if self._type is None:
if self._impl.objtype is not None:
self._type = DbObjectType._from_impl(self._impl.objtype)
else:
self._type = self._impl.dbtype
return self._type
class DbObjectType:
__module__ = MODULE_NAME
def __call__(self, value=None):
return self.newobject(value)
def __eq__(self, other):
if isinstance(other, DbObjectType):
return other._impl == self._impl
return NotImplemented
def __repr__(self):
return f"<oracledb.DbObjectType {self._get_full_name()}>"
@classmethod
def _from_impl(cls, impl):
typ = cls.__new__(cls)
typ._impl = impl
typ._attributes = None
typ._element_type = None
return typ
def _get_full_name(self):
"""
Returns the full name of the type.
"""
return self._impl._get_fqn()
@property
def attributes(self) -> list:
"""
This read-only attribute returns a list of the attributes that make up
the object type.
"""
if self._attributes is None:
self._attributes = [
DbObjectAttr._from_impl(i) for i in self._impl.attrs
]
return self._attributes
@property
def iscollection(self) -> bool:
"""
This read-only attribute returns a boolean indicating if the object
type refers to a collection or not.
"""
return self._impl.is_collection
@property
def name(self) -> str:
"""
This read-only attribute returns the name of the type.
"""
return self._impl.name
@property
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
returns None. If the collection contains objects, this will be another
object type; otherwise, it will be one of the database type constants.
"""
if self._element_type is None:
if self._impl.element_objtype is not None:
typ_impl = self._impl.element_objtype
self._element_type = DbObjectType._from_impl(typ_impl)
else:
self._element_type = self._impl.element_dbtype
return self._element_type
def newobject(self, value: Sequence = None) -> DbObject:
"""
Return a new Oracle object of the given type. This object can then be
modified by setting its attributes and then bound to a cursor for
interaction with Oracle. If the object type refers to a collection, a
sequence may be passed and the collection will be initialized with the
items in that sequence.
"""
obj_impl = self._impl.create_new_object()
obj = DbObject._from_impl(obj_impl)
if value is not None:
obj.extend(value)
return obj
@property
def package_name(self) -> str:
"""
This read-only attribute returns the name of the package containing the
PL/SQL type or None if the type is not a PL/SQL type.
"""
return self._impl.package_name
@property
def schema(self) -> str:
"""
This read-only attribute returns the name of the schema that owns the
type.
"""
return self._impl.schema
@@ -0,0 +1,53 @@
# -----------------------------------------------------------------------------
# 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
# 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
# either license.
#
# If you elect to accept the software under the Apache License, Version 2.0,
# the following applies:
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# defaults.py
#
# Contains the Defaults class used for managing default values used throughout
# the module.
# -----------------------------------------------------------------------------
import os
from . import __name__ as MODULE_NAME
class Defaults:
"""
Identifies the default values used by the driver.
"""
__module__ = MODULE_NAME
def __init__(self) -> None:
self.arraysize = 100
self.stmtcachesize = 20
self.config_dir = os.environ.get("TNS_ADMIN")
self.fetch_lobs = True
self.fetch_decimals = False
self.prefetchrows = 2
defaults = Defaults()
@@ -0,0 +1,140 @@
# -----------------------------------------------------------------------------
# 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
# 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
# either license.
#
# If you elect to accept the software under the Apache License, Version 2.0,
# the following applies:
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# driver_mode.py
#
# Contains a simple method for checking and returning which mode the driver is
# currently using. The driver only supports creating connections and pools with
# either the thin implementation or the thick implementation, not both
# simultaneously.
# -----------------------------------------------------------------------------
import threading
from . import errors
# 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:
"""
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()
def __enter__(self):
return self
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()
@property
def thin(self):
if self.requested_thin_mode is not None:
return self.requested_thin_mode
return self.thin_mode
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
reason the error raised is specified about a thin mode connection already
being created. If this assumption changes, a new error message will be
required.
"""
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:
"""
Return a boolean specifying whether the driver is using thin mode (True) or
thick mode (False).
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 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 manager.thin_mode is not None:
return manager.thin_mode
return True
@@ -0,0 +1,80 @@
# -----------------------------------------------------------------------------
# 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
# 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
# either license.
#
# If you elect to accept the software under the Apache License, Version 2.0,
# the following applies:
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# dsn.py
#
# Contains makedsn(), a method available for backwards compatibility with
# cx_Oracle. Use of the ConnectParams class or the keyword arguments to
# connect() and create_pool() is recommended instead.
# -----------------------------------------------------------------------------
from . import errors
def _check_arg(name: str, value: str) -> None:
"""
Checks the argument to ensure that it does not contain (, ) or = as these
characters are not permitted within connect strings.
"""
if "(" in value or ")" in value or "=" in value:
errors._raise_err(errors.ERR_INVALID_MAKEDSN_ARG, name=name)
def makedsn(
host: str,
port: int,
sid: str = None,
service_name: str = None,
region: str = None,
sharding_key: str = None,
super_sharding_key: str = None,
) -> str:
"""
Return a string suitable for use as the dsn parameter for connect(). This
string is identical to the strings that are defined in the tnsnames.ora
file.
"""
connect_data_parts = []
_check_arg("host", host)
if sid is not None:
_check_arg("sid", sid)
connect_data_parts.append(f"(SID={sid})")
if service_name is not None:
_check_arg("service_name", service_name)
connect_data_parts.append(f"(SERVICE_NAME={service_name})")
if region is not None:
_check_arg("region", region)
connect_data_parts.append(f"(REGION={region})")
if sharding_key is not None:
_check_arg("sharding_key", sharding_key)
connect_data_parts.append(f"(SHARDING_KEY={sharding_key})")
if super_sharding_key is not None:
_check_arg("super_sharding_key", super_sharding_key)
connect_data_parts.append(f"(SUPER_SHARDING_KEY={super_sharding_key})")
connect_data = "".join(connect_data_parts)
return (
f"(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST={host})"
f"(PORT={port}))(CONNECT_DATA={connect_data}))"
)
@@ -0,0 +1,638 @@
# -----------------------------------------------------------------------------
# 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
# 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
# either license.
#
# If you elect to accept the software under the Apache License, Version 2.0,
# the following applies:
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# errors.py
#
# Contains the _Error class and all of the errors that are raised explicitly by
# the package. Oracle Database errors and ODPI-C errors (when using thick mode)
# are only referenced here if they are transformed into package specific
# errors.
# -----------------------------------------------------------------------------
import re
from .driver_mode import is_thin_mode
from . import exceptions
class _Error:
"""
Error class which is used for all errors that are raised by the driver.
"""
def __init__(
self,
message: str = None,
context: str = None,
isrecoverable: bool = False,
iswarning: bool = False,
code: int = 0,
offset: int = 0,
) -> None:
self.message = message
self.context = context
self.isrecoverable = isrecoverable
self.iswarning = iswarning
self.code = code
self.offset = offset
self.is_session_dead = False
self.full_code = ""
self._make_adjustments()
def _make_adjustments(self):
"""
Make adjustments to the error, if needed, and calculate the full_code
attribute.
"""
if self.message is not None:
pos = self.message.find(":")
if pos > 0:
self.full_code = self.message[:pos]
# add Oracle Database Error Help Portal URL for database error
# messages, but only in thin mode since this is done
# automatically in thick mode with Oracle Client 23c and higher
if self.code != 0 and is_thin_mode():
self.message = (
self.message
+ "\n"
+ "Help: https://docs.oracle.com/error-help/db/ora-"
+ f"{self.code:05}/"
)
elif self.full_code in ERR_TROUBLESHOOTING_AVAILABLE:
self.message = (
self.message
+ "\n"
+ "Help: https://python-oracledb.readthedocs.io/en/"
+ "latest/user_guide/troubleshooting.html#"
+ self.full_code.lower()
)
if self.code != 0 or self.full_code.startswith("DPI-"):
args = {}
if self.code != 0:
driver_error_info = ERR_ORACLE_ERROR_XREF.get(self.code)
else:
error_num = int(self.full_code[4:])
driver_error_info = ERR_DPI_ERROR_XREF.get(error_num)
if driver_error_info is not None:
if isinstance(driver_error_info, tuple):
driver_error_num, pattern = driver_error_info
match = re.search(pattern, self.message)
args = {} if match is None else match.groupdict()
else:
driver_error_num = driver_error_info
if driver_error_num == ERR_CONNECTION_CLOSED:
self.is_session_dead = True
driver_error = _get_error_text(driver_error_num, **args)
self.message = f"{driver_error}\n{self.message}"
self.full_code = f"{ERR_PREFIX}-{driver_error_num:04}"
def __str__(self):
return self.message
def _get_error_text(error_num: int, **args) -> str:
"""
Return the error text for the driver specific error number.
"""
message_format = ERR_MESSAGE_FORMATS.get(error_num)
if message_format is None:
message_format = "missing error {error_num}"
args = dict(error_num=error_num)
error_num = ERR_MISSING_ERROR
try:
message = message_format.format(**args)
except KeyError:
message = (
message_format
+ "\nWrong arguments to message format:\n"
+ repr(args)
)
return f"{ERR_PREFIX}-{error_num:04}: {message}"
def _create_warning(error_num: int, **args) -> _Error:
"""
Returns a warning error object for the specified error number and supplied
arguments.
"""
message = _get_error_text(error_num, **args)
return _Error(message, iswarning=True)
def _raise_err(
error_num: int,
context_error_message: str = None,
cause: Exception = None,
**args,
) -> None:
"""
Raises a driver specific exception from the specified error number and
supplied arguments.
"""
message = _get_error_text(error_num, **args)
if context_error_message is None and cause is not None:
context_error_message = str(cause)
if context_error_message is not None:
message = f"{message}\n{context_error_message}"
exc_type = ERR_EXCEPTION_TYPES[error_num // 1000]
raise exc_type(_Error(message)) from cause
def _raise_from_string(exc_type: Exception, message: str) -> None:
"""
Raises an exception from a given string. This ensures that an _Error object
is created for all exceptions that are raised.
"""
raise exc_type(_Error(message)) from None
# prefix used for all error messages
ERR_PREFIX = "DPY"
# error numbers that result in InterfaceError
ERR_MISSING_ERROR = 1000
ERR_NOT_CONNECTED = 1001
ERR_POOL_NOT_OPEN = 1002
ERR_NOT_A_QUERY = 1003
ERR_NO_STATEMENT_EXECUTED = 1004
ERR_POOL_HAS_BUSY_CONNECTIONS = 1005
ERR_CURSOR_NOT_OPEN = 1006
# error numbers that result in ProgrammingError
ERR_MESSAGE_HAS_NO_PAYLOAD = 2000
ERR_NO_STATEMENT = 2001
ERR_NO_STATEMENT_PREPARED = 2002
ERR_WRONG_EXECUTE_PARAMETERS_TYPE = 2003
ERR_WRONG_EXECUTEMANY_PARAMETERS_TYPE = 2004
ERR_ARGS_AND_KEYWORD_ARGS = 2005
ERR_MIXED_POSITIONAL_AND_NAMED_BINDS = 2006
ERR_EXPECTING_TYPE = 2007
ERR_WRONG_OBJECT_TYPE = 2008
ERR_WRONG_SCROLL_MODE = 2009
ERR_MIXED_ELEMENT_TYPES = 2010
ERR_WRONG_ARRAY_DEFINITION = 2011
ERR_ARGS_MUST_BE_LIST_OR_TUPLE = 2012
ERR_KEYWORD_ARGS_MUST_BE_DICT = 2013
ERR_DUPLICATED_PARAMETER = 2014
ERR_EXPECTING_VAR = 2015
ERR_INCORRECT_VAR_ARRAYSIZE = 2016
ERR_LIBRARY_ALREADY_INITIALIZED = 2017
ERR_WALLET_FILE_MISSING = 2018
ERR_THIN_CONNECTION_ALREADY_CREATED = 2019
ERR_INVALID_MAKEDSN_ARG = 2020
ERR_INIT_ORACLE_CLIENT_NOT_CALLED = 2021
ERR_INVALID_OCI_ATTR_TYPE = 2022
ERR_INVALID_CONN_CLASS = 2023
ERR_INVALID_CONNECT_PARAMS = 2025
ERR_INVALID_POOL_CLASS = 2026
ERR_INVALID_POOL_PARAMS = 2027
ERR_EXPECTING_LIST_FOR_ARRAY_VAR = 2028
ERR_HTTPS_PROXY_REQUIRES_TCPS = 2029
ERR_INVALID_LOB_OFFSET = 2030
ERR_INVALID_ACCESS_TOKEN_PARAM = 2031
ERR_INVALID_ACCESS_TOKEN_RETURNED = 2032
ERR_EXPIRED_ACCESS_TOKEN = 2033
ERR_ACCESS_TOKEN_REQUIRES_TCPS = 2034
ERR_INVALID_OBJECT_TYPE_NAME = 2035
ERR_OBJECT_IS_NOT_A_COLLECTION = 2036
ERR_MISSING_TYPE_NAME_FOR_OBJECT_VAR = 2037
ERR_INVALID_COLL_INDEX_GET = 2038
ERR_INVALID_COLL_INDEX_SET = 2039
ERR_EXECUTE_MODE_ONLY_FOR_DML = 2040
ERR_MISSING_QUOTE_IN_STRING = 2041
ERR_MISSING_QUOTE_IN_IDENTIFIER = 2042
ERR_DBOBJECT_ATTR_MAX_SIZE_VIOLATED = 2043
ERR_DBOBJECT_ELEMENT_MAX_SIZE_VIOLATED = 2044
# error numbers that result in NotSupportedError
ERR_TIME_NOT_SUPPORTED = 3000
ERR_FEATURE_NOT_SUPPORTED = 3001
ERR_PYTHON_VALUE_NOT_SUPPORTED = 3002
ERR_PYTHON_TYPE_NOT_SUPPORTED = 3003
ERR_UNSUPPORTED_TYPE_SET = 3004
ERR_ARRAYS_OF_ARRAYS = 3005
ERR_ORACLE_TYPE_NOT_SUPPORTED = 3006
ERR_DB_TYPE_NOT_SUPPORTED = 3007
ERR_UNSUPPORTED_INBAND_NOTIFICATION = 3008
ERR_SELF_BIND_NOT_SUPPORTED = 3009
ERR_SERVER_VERSION_NOT_SUPPORTED = 3010
ERR_NCHAR_CS_NOT_SUPPORTED = 3012
ERR_UNSUPPORTED_PYTHON_TYPE_FOR_DB_TYPE = 3013
ERR_LOB_OF_WRONG_TYPE = 3014
ERR_UNSUPPORTED_VERIFIER_TYPE = 3015
ERR_NO_CRYPTOGRAPHY_PACKAGE = 3016
ERR_ORACLE_TYPE_NAME_NOT_SUPPORTED = 3017
ERR_TDS_TYPE_NOT_SUPPORTED = 3018
ERR_OSON_NODE_TYPE_NOT_SUPPORTED = 3019
ERR_OSON_FIELD_NAME_LIMITATION = 3020
ERR_OSON_VERSION_NOT_SUPPORTED = 3021
ERR_NAMED_TIMEZONE_NOT_SUPPORTED = 3022
# error numbers that result in DatabaseError
ERR_TNS_ENTRY_NOT_FOUND = 4000
ERR_NO_CREDENTIALS = 4001
ERR_COLUMN_TRUNCATED = 4002
ERR_ORACLE_NUMBER_NO_REPR = 4003
ERR_INVALID_NUMBER = 4004
ERR_POOL_NO_CONNECTION_AVAILABLE = 4005
ERR_ARRAY_DML_ROW_COUNTS_NOT_ENABLED = 4006
ERR_INCONSISTENT_DATATYPES = 4007
ERR_INVALID_BIND_NAME = 4008
ERR_WRONG_NUMBER_OF_POSITIONAL_BINDS = 4009
ERR_MISSING_BIND_VALUE = 4010
ERR_CONNECTION_CLOSED = 4011
ERR_NUMBER_WITH_INVALID_EXPONENT = 4012
ERR_NUMBER_STRING_OF_ZERO_LENGTH = 4013
ERR_NUMBER_STRING_TOO_LONG = 4014
ERR_NUMBER_WITH_EMPTY_EXPONENT = 4015
ERR_CONTENT_INVALID_AFTER_NUMBER = 4016
ERR_INVALID_CONNECT_DESCRIPTOR = 4017
ERR_CANNOT_PARSE_CONNECT_STRING = 4018
ERR_INVALID_REDIRECT_DATA = 4019
ERR_INVALID_PROTOCOL = 4021
ERR_INVALID_POOL_PURITY = 4022
ERR_CALL_TIMEOUT_EXCEEDED = 4024
ERR_INVALID_REF_CURSOR = 4025
ERR_TNS_NAMES_FILE_MISSING = 4026
ERR_NO_CONFIG_DIR = 4027
ERR_INVALID_SERVER_TYPE = 4028
ERR_TOO_MANY_BATCH_ERRORS = 4029
# error numbers that result in InternalError
ERR_MESSAGE_TYPE_UNKNOWN = 5000
ERR_BUFFER_LENGTH_INSUFFICIENT = 5001
ERR_INTEGER_TOO_LARGE = 5002
ERR_UNEXPECTED_NEGATIVE_INTEGER = 5003
ERR_UNEXPECTED_DATA = 5004
ERR_UNEXPECTED_REFUSE = 5005
ERR_UNEXPECTED_END_OF_DATA = 5006
ERR_UNEXPECTED_XML_TYPE = 5007
ERR_TOO_MANY_CURSORS_TO_CLOSE = 5008
ERR_UNKOWN_SERVER_SIDE_PIGGYBACK = 5009
# error numbers that result in OperationalError
ERR_LISTENER_REFUSED_CONNECTION = 6000
ERR_INVALID_SERVICE_NAME = 6001
ERR_INVALID_SERVER_CERT_DN = 6002
ERR_INVALID_SID = 6003
ERR_PROXY_FAILURE = 6004
ERR_CONNECTION_FAILED = 6005
# error numbers that result in Warning
WRN_COMPILATION_ERROR = 7000
# Oracle error number cross reference
ERR_ORACLE_ERROR_XREF = {
28: ERR_CONNECTION_CLOSED,
600: ERR_CONNECTION_CLOSED,
1005: ERR_NO_CREDENTIALS,
1740: ERR_MISSING_QUOTE_IN_IDENTIFIER,
1756: ERR_MISSING_QUOTE_IN_STRING,
22165: (
ERR_INVALID_COLL_INDEX_SET,
r"index \[(?P<index>\d+)\] must be in the range of "
r"\[(?P<min_index>\d+)\] to \[(?P<max_index>\d+)\]",
),
22303: (ERR_INVALID_OBJECT_TYPE_NAME, r'type "(?P<name>[^"]*"."[^"]*)"'),
24422: ERR_POOL_HAS_BUSY_CONNECTIONS,
24349: ERR_ARRAY_DML_ROW_COUNTS_NOT_ENABLED,
24459: ERR_POOL_NO_CONNECTION_AVAILABLE,
24496: ERR_POOL_NO_CONNECTION_AVAILABLE,
24338: ERR_INVALID_REF_CURSOR,
24344: WRN_COMPILATION_ERROR,
38902: ERR_TOO_MANY_BATCH_ERRORS,
}
# ODPI-C error number cross reference
ERR_DPI_ERROR_XREF = {
1010: ERR_CONNECTION_CLOSED,
1024: (ERR_INVALID_COLL_INDEX_GET, r"at index (?P<index>\d+) does"),
1043: ERR_INVALID_NUMBER,
1044: ERR_ORACLE_NUMBER_NO_REPR,
1063: ERR_EXECUTE_MODE_ONLY_FOR_DML,
1067: (ERR_CALL_TIMEOUT_EXCEEDED, r"call timeout of (?P<timeout>\d+) ms"),
1080: ERR_CONNECTION_CLOSED,
}
# error message exception types (multiples of 1000)
ERR_EXCEPTION_TYPES = {
1: exceptions.InterfaceError,
2: exceptions.ProgrammingError,
3: exceptions.NotSupportedError,
4: exceptions.DatabaseError,
5: exceptions.InternalError,
6: exceptions.OperationalError,
7: exceptions.Warning,
}
# error messages that have a troubleshooting section available
ERR_TROUBLESHOOTING_AVAILABLE = set(
[
"DPI-1047", # Oracle Client library cannot be loaded
"DPI-1072", # Oracle Client library version is unsupported
"DPY-3010", # connections to Oracle Database version not supported
"DPY-3015", # password verifier type is not supported
"DPY-4011", # the database or network closed the connection
]
)
# error message formats
ERR_MESSAGE_FORMATS = {
ERR_ACCESS_TOKEN_REQUIRES_TCPS: (
"access_token requires use of the tcps protocol"
),
ERR_ARGS_MUST_BE_LIST_OR_TUPLE: "arguments must be a list or tuple",
ERR_ARGS_AND_KEYWORD_ARGS: (
"expecting positional arguments or keyword arguments, not both"
),
ERR_ARRAY_DML_ROW_COUNTS_NOT_ENABLED: (
"array DML row counts mode is not enabled"
),
ERR_ARRAYS_OF_ARRAYS: "arrays of arrays are not supported",
ERR_BUFFER_LENGTH_INSUFFICIENT: (
"internal error: buffer of length {actual_buffer_len} "
"insufficient to hold {required_buffer_len} bytes"
),
ERR_CALL_TIMEOUT_EXCEEDED: "call timeout of {timeout} ms exceeded",
ERR_CANNOT_PARSE_CONNECT_STRING: 'cannot parse connect string "{data}"',
ERR_COLUMN_TRUNCATED: (
"column truncated to {col_value_len} {unit}. "
"Untruncated was {actual_len}"
),
ERR_CONNECTION_FAILED: (
"cannot connect to database (CONNECTION_ID={connection_id})."
),
ERR_CONTENT_INVALID_AFTER_NUMBER: "invalid number (content after number)",
ERR_CURSOR_NOT_OPEN: "cursor is not open",
ERR_DBOBJECT_ATTR_MAX_SIZE_VIOLATED: (
"attribute {attr_name} of type {type_name} exceeds its maximum size "
"(actual: {actual_size}, maximum: {max_size})"
),
ERR_DBOBJECT_ELEMENT_MAX_SIZE_VIOLATED: (
"element {index} of type {type_name} exceeds its maximum size "
"(actual: {actual_size}, maximum: {max_size})"
),
ERR_DB_TYPE_NOT_SUPPORTED: 'database type "{name}" is not supported',
ERR_DUPLICATED_PARAMETER: (
'"{deprecated_name}" and "{new_name}" cannot be specified together'
),
ERR_EXECUTE_MODE_ONLY_FOR_DML: (
'parameters "batcherrors" and "arraydmlrowcounts" may only be '
"true when used with insert, update, delete and merge statements"
),
ERR_EXPECTING_LIST_FOR_ARRAY_VAR: (
"expecting list when setting array variables"
),
ERR_EXPECTING_TYPE: "expected a type",
ERR_EXPECTING_VAR: (
"type handler should return None or the value returned by a call "
"to cursor.var()"
),
ERR_EXPIRED_ACCESS_TOKEN: "access token has expired",
ERR_FEATURE_NOT_SUPPORTED: (
"{feature} is only supported in python-oracledb {driver_type} mode"
),
ERR_HTTPS_PROXY_REQUIRES_TCPS: (
"https_proxy requires use of the tcps protocol"
),
ERR_INCONSISTENT_DATATYPES: (
"cannot convert from data type {input_type} to {output_type}"
),
ERR_INCORRECT_VAR_ARRAYSIZE: (
"variable array size of {var_arraysize} is "
"too small (should be at least {required_arraysize})"
),
ERR_INIT_ORACLE_CLIENT_NOT_CALLED: (
"init_oracle_client() must be called first"
),
ERR_INTEGER_TOO_LARGE: (
"internal error: read integer of length {length} when expecting "
"integer of no more than length {max_length}"
),
ERR_INVALID_ACCESS_TOKEN_PARAM: (
"invalid access token: value must be a string (for OAuth), a "
"2-tuple containing the token and private key strings (for IAM), "
"or a callable that returns a string or 2-tuple"
),
ERR_INVALID_ACCESS_TOKEN_RETURNED: (
"invalid access token returned from callable: value must be a "
"string (for OAuth) or a 2-tuple containing the token and private "
"key strings (for IAM)"
),
ERR_INVALID_BIND_NAME: (
'no bind placeholder named ":{name}" was found in the SQL text'
),
ERR_INVALID_CONN_CLASS: "invalid connection class",
ERR_INVALID_CONNECT_DESCRIPTOR: 'invalid connect descriptor "{data}"',
ERR_INVALID_CONNECT_PARAMS: "invalid connection params",
ERR_INVALID_COLL_INDEX_GET: "element at index {index} does not exist",
ERR_INVALID_COLL_INDEX_SET: (
"given index {index} must be in the range of {min_index} to "
"{max_index}"
),
ERR_INVALID_LOB_OFFSET: "LOB offset must be greater than zero",
ERR_INVALID_MAKEDSN_ARG: '"{name}" argument contains invalid values',
ERR_INVALID_NUMBER: "invalid number",
ERR_INVALID_OBJECT_TYPE_NAME: 'invalid object type name: "{name}"',
ERR_INVALID_OCI_ATTR_TYPE: "invalid OCI attribute type {attr_type}",
ERR_INVALID_POOL_CLASS: "invalid connection pool class",
ERR_INVALID_POOL_PARAMS: "invalid pool params",
ERR_INVALID_POOL_PURITY: "invalid DRCP purity {purity}",
ERR_INVALID_PROTOCOL: 'invalid protocol "{protocol}"',
ERR_INVALID_REDIRECT_DATA: "invalid redirect data {data}",
ERR_INVALID_REF_CURSOR: "invalid REF CURSOR: never opened in PL/SQL",
ERR_INVALID_SERVER_CERT_DN: (
"The distinguished name (DN) on the server certificate does not "
"match the expected value"
),
ERR_INVALID_SERVER_TYPE: "invalid server_type: {server_type}",
ERR_INVALID_SERVICE_NAME: (
'Service "{service_name}" is not registered with the listener at '
'host "{host}" port {port}. (Similar to ORA-12514)'
),
ERR_INVALID_SID: (
'SID "{sid}" is not registered with the listener at host "{host}" '
"port {port}. (Similar to ORA-12505)"
),
ERR_KEYWORD_ARGS_MUST_BE_DICT: (
'"keyword_parameters" argument must be a dict'
),
ERR_LIBRARY_ALREADY_INITIALIZED: (
"init_oracle_client() was already called with different arguments"
),
ERR_LISTENER_REFUSED_CONNECTION: (
"Listener refused connection. (Similar to ORA-{error_code})"
),
ERR_LOB_OF_WRONG_TYPE: (
"LOB is of type {actual_type_name} but must be of type "
"{expected_type_name}"
),
ERR_MESSAGE_HAS_NO_PAYLOAD: "message has no payload",
ERR_MESSAGE_TYPE_UNKNOWN: (
"internal error: unknown protocol message type {message_type} "
"at position {position}"
),
ERR_MISSING_BIND_VALUE: (
'a bind variable replacement value for placeholder ":{name}" was '
"not provided"
),
ERR_MISSING_QUOTE_IN_IDENTIFIER: 'missing ending quote (") in identifier',
ERR_MISSING_QUOTE_IN_STRING: "missing ending quote (') in string",
ERR_MISSING_TYPE_NAME_FOR_OBJECT_VAR: (
"no object type specified for object variable"
),
ERR_MIXED_ELEMENT_TYPES: (
"element {element} is not the same data type as previous elements"
),
ERR_MIXED_POSITIONAL_AND_NAMED_BINDS: (
"positional and named binds cannot be intermixed"
),
ERR_NAMED_TIMEZONE_NOT_SUPPORTED: (
"named time zones are not supported in thin mode"
),
ERR_NCHAR_CS_NOT_SUPPORTED: (
"national character set id {charset_id} is not supported by "
"python-oracledb in thin mode"
),
ERR_NO_CONFIG_DIR: "no configuration directory to search for tnsnames.ora",
ERR_NO_CREDENTIALS: "no credentials specified",
ERR_NO_CRYPTOGRAPHY_PACKAGE: (
"python-oracledb thin mode cannot be used because the "
"cryptography package is not installed"
),
ERR_NO_STATEMENT: "no statement specified and no prior statement prepared",
ERR_NO_STATEMENT_EXECUTED: "no statement executed",
ERR_NO_STATEMENT_PREPARED: "statement must be prepared first",
ERR_NOT_A_QUERY: "the executed statement does not return rows",
ERR_NOT_CONNECTED: "not connected to database",
ERR_NUMBER_STRING_OF_ZERO_LENGTH: "invalid number: zero length string",
ERR_NUMBER_STRING_TOO_LONG: "invalid number: string too long",
ERR_NUMBER_WITH_EMPTY_EXPONENT: "invalid number: empty exponent",
ERR_NUMBER_WITH_INVALID_EXPONENT: "invalid number: invalid exponent",
ERR_OBJECT_IS_NOT_A_COLLECTION: "object {name} is not a collection",
ERR_ORACLE_NUMBER_NO_REPR: (
"value cannot be represented as an Oracle number"
),
ERR_ORACLE_TYPE_NAME_NOT_SUPPORTED: (
'Oracle data type name "{name}" is not supported'
),
ERR_ORACLE_TYPE_NOT_SUPPORTED: "Oracle data type {num} is not supported",
ERR_OSON_FIELD_NAME_LIMITATION: (
"OSON field names may not exceed {max_fname_size} UTF-8 encoded bytes"
),
ERR_OSON_NODE_TYPE_NOT_SUPPORTED: (
"OSON node type 0x{node_type:x} is not supported"
),
ERR_OSON_VERSION_NOT_SUPPORTED: "OSON version {version} is not supported",
ERR_POOL_HAS_BUSY_CONNECTIONS: (
"connection pool cannot be closed because connections are busy"
),
ERR_POOL_NO_CONNECTION_AVAILABLE: (
"timed out waiting for the connection pool to return a connection"
),
ERR_POOL_NOT_OPEN: "connection pool is not open",
ERR_PROXY_FAILURE: "network proxy failed: response was {response}",
ERR_PYTHON_TYPE_NOT_SUPPORTED: "Python type {typ} is not supported",
ERR_PYTHON_VALUE_NOT_SUPPORTED: (
'Python value of type "{type_name}" is not supported'
),
ERR_SELF_BIND_NOT_SUPPORTED: "binding to self is not supported",
ERR_CONNECTION_CLOSED: "the database or network closed the connection",
ERR_SERVER_VERSION_NOT_SUPPORTED: (
"connections to this database server version are not supported "
"by python-oracledb in thin mode"
),
ERR_TDS_TYPE_NOT_SUPPORTED: "Oracle TDS data type {num} is not supported",
ERR_THIN_CONNECTION_ALREADY_CREATED: (
"python-oracledb thick mode cannot be used because a thin mode "
"connection has already been created"
),
ERR_TIME_NOT_SUPPORTED: (
"Oracle Database does not support time only variables"
),
ERR_TNS_ENTRY_NOT_FOUND: 'unable to find "{name}" in {file_name}',
ERR_TNS_NAMES_FILE_MISSING: "file tnsnames.ora not found in {config_dir}",
ERR_TOO_MANY_CURSORS_TO_CLOSE: (
"internal error: attempt to close more than {num_cursors} cursors"
),
ERR_TOO_MANY_BATCH_ERRORS: (
"the number of batch errors from executemany() exceeds 65535"
),
ERR_UNEXPECTED_DATA: "unexpected data received: {data}",
ERR_UNEXPECTED_END_OF_DATA: (
"unexpected end of data: want {num_bytes_wanted} bytes but "
"only {num_bytes_available} bytes are available"
),
ERR_UNEXPECTED_NEGATIVE_INTEGER: (
"internal error: read a negative integer when expecting a "
"positive integer"
),
ERR_UNEXPECTED_REFUSE: (
"the listener refused the connection but an unexpected error "
"format was returned"
),
ERR_UNEXPECTED_XML_TYPE: "unexpected XMLType with flag {flag}",
ERR_UNKOWN_SERVER_SIDE_PIGGYBACK: (
"internal error: unknown server side piggyback opcode {opcode}"
),
ERR_UNSUPPORTED_INBAND_NOTIFICATION: (
"unsupported in-band notification with error number {err_num}"
),
ERR_UNSUPPORTED_PYTHON_TYPE_FOR_DB_TYPE: (
"unsupported Python type {py_type_name} for database type "
"{db_type_name}"
),
ERR_UNSUPPORTED_TYPE_SET: "type {db_type_name} does not support being set",
ERR_UNSUPPORTED_VERIFIER_TYPE: (
"password verifier type 0x{verifier_type:x} is not supported by "
"python-oracledb in thin mode"
),
ERR_WALLET_FILE_MISSING: "wallet file {name} was not found",
ERR_WRONG_ARRAY_DEFINITION: (
"expecting a list of two elements [type, numelems]"
),
ERR_WRONG_EXECUTE_PARAMETERS_TYPE: (
"expecting a dictionary, list or tuple, or keyword args"
),
ERR_WRONG_EXECUTEMANY_PARAMETERS_TYPE: (
'"parameters" argument should be a list of sequences or '
"dictionaries, or an integer specifying the number of "
"times to execute the statement"
),
ERR_WRONG_NUMBER_OF_POSITIONAL_BINDS: (
"{expected_num} positional bind values are required but "
"{actual_num} were provided"
),
ERR_WRONG_OBJECT_TYPE: (
'found object of type "{actual_schema}.{actual_name}" when '
'expecting object of type "{expected_schema}.{expected_name}"'
),
ERR_WRONG_SCROLL_MODE: (
"scroll mode must be relative, absolute, first or last"
),
WRN_COMPILATION_ERROR: "creation succeeded with compilation errors",
}
@@ -0,0 +1,69 @@
# -----------------------------------------------------------------------------
# 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
# 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
# either license.
#
# If you elect to accept the software under the Apache License, Version 2.0,
# the following applies:
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# exceptions.py
#
# Contains the exception classes mandated by the Python Database API.
# -----------------------------------------------------------------------------
class Warning(Exception):
pass
class Error(Exception):
pass
class DatabaseError(Error):
pass
class DataError(DatabaseError):
pass
class IntegrityError(DatabaseError):
pass
class InterfaceError(Error):
pass
class InternalError(DatabaseError):
pass
class NotSupportedError(DatabaseError):
pass
class OperationalError(DatabaseError):
pass
class ProgrammingError(DatabaseError):
pass
@@ -0,0 +1,215 @@
# -----------------------------------------------------------------------------
# Copyright (c) 2023, Oracle and/or its affiliates.
#
# This software is dual-licensed to you under the Universal Permissive License
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
# 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
# either license.
#
# If you elect to accept the software under the Apache License, Version 2.0,
# the following applies:
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# fetch_info.py
#
# Contains the FetchInfo class which stores metadata about columns that are
# being fetched.
# -----------------------------------------------------------------------------
from typing import Union
from . import __name__ as MODULE_NAME
from .dbobject import DbObjectType
from .base_impl import (
DbType,
DB_TYPE_DATE,
DB_TYPE_TIMESTAMP,
DB_TYPE_TIMESTAMP_LTZ,
DB_TYPE_TIMESTAMP_TZ,
DB_TYPE_BINARY_FLOAT,
DB_TYPE_BINARY_DOUBLE,
DB_TYPE_BINARY_INTEGER,
DB_TYPE_NUMBER,
)
class FetchInfo:
"""
Identifies metadata of columns that are being fetched.
"""
__module__ = MODULE_NAME
def __eq__(self, other):
return tuple(self) == other
def __getitem__(self, index):
"""
Return the parts mandated by the Python Database API.
"""
if index == 0 or index == -7:
return self.name
elif index == 1 or index == -6:
return self.type_code
elif index == 2 or index == -5:
return self.display_size
elif index == 3 or index == -4:
return self.internal_size
elif index == 4 or index == -3:
return self.precision
elif index == 5 or index == -2:
return self.scale
elif index == 6 or index == -1:
return self.null_ok
elif isinstance(index, slice):
return tuple(self).__getitem__(index)
raise IndexError("list index out of range")
def __len__(self):
"""
Length mandated by the Python Database API.
"""
return 7
def __repr__(self):
return repr(tuple(self))
def __str__(self):
return str(tuple(self))
@classmethod
def _from_impl(cls, impl):
info = cls.__new__(cls)
info._impl = impl
info._type = None
return info
@property
def annotations(self) -> Union[dict, None]:
"""
Returns a dictionary of the annotations associated with the column, if
applicable.
"""
return self._impl.annotations
@property
def display_size(self) -> Union[int, None]:
"""
Returns the display size of the column.
"""
if self._impl.size > 0:
return self._impl.size
dbtype = self._impl.dbtype
if (
dbtype is DB_TYPE_DATE
or dbtype is DB_TYPE_TIMESTAMP
or dbtype is DB_TYPE_TIMESTAMP_LTZ
or dbtype is DB_TYPE_TIMESTAMP_TZ
):
return 23
elif (
dbtype is DB_TYPE_BINARY_FLOAT
or dbtype is DB_TYPE_BINARY_DOUBLE
or dbtype is DB_TYPE_BINARY_INTEGER
or dbtype is DB_TYPE_NUMBER
):
if self._impl.precision:
display_size = self._impl.precision + 1
if self._impl.scale > 0:
display_size += self._impl.scale + 1
else:
display_size = 127
return display_size
@property
def domain_name(self) -> Union[str, None]:
"""
Returns the name of the domain, if applicable.
"""
return self._impl.domain_name
@property
def domain_schema(self) -> Union[str, None]:
"""
Returns the name of the schema in which the domain is found, if
applicable.
"""
return self._impl.domain_schema
@property
def internal_size(self) -> Union[int, None]:
"""
Returns the size in bytes of the column.
"""
if self._impl.size > 0:
return self._impl.buffer_size
@property
def is_json(self) -> bool:
"""
Returns whether the column contains JSON.
"""
return self._impl.is_json
@property
def name(self) -> str:
"""
Returns the name of the column.
"""
return self._impl.name
@property
def null_ok(self) -> bool:
"""
Returns whether nulls or permitted or not in the column.
"""
return self._impl.nulls_allowed
@property
def precision(self) -> Union[int, None]:
"""
Returns the precision of the column.
"""
if self._impl.precision or self._impl.scale:
return self._impl.precision
@property
def scale(self) -> Union[int, None]:
"""
Returns the scale of the column.
"""
if self._impl.precision or self._impl.scale:
return self._impl.scale
@property
def type(self) -> Union[DbType, DbObjectType]:
"""
Returns the type of the column, as either a database object type or a
database type.
"""
if self._type is None:
if self._impl.objtype is not None:
self._type = DbObjectType._from_impl(self._impl.objtype)
else:
self._type = self._impl.dbtype
return self._type
@property
def type_code(self) -> DbType:
"""
Returns the type of the column.
"""
return self._impl.dbtype
@@ -0,0 +1,46 @@
# -----------------------------------------------------------------------------
# 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
# 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
# either license.
#
# If you elect to accept the software under the Apache License, Version 2.0,
# the following applies:
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# future.py
#
# Module for handling backwards incompatible changes.
# -----------------------------------------------------------------------------
FEATURES = []
# future object used for managing backwards incompatible changes
class Future:
def __getattr__(self, name):
if name in FEATURES:
return super().__getattr__(name)
return None
def __setattr__(self, name, value):
if name in FEATURES:
return super().__setattr__(name, value)
future = Future()
@@ -0,0 +1,285 @@
# -----------------------------------------------------------------------------
# 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
# 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
# either license.
#
# If you elect to accept the software under the Apache License, Version 2.0,
# the following applies:
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# lob.py
#
# Contains the LOB class for managing BLOB, CLOB, NCLOB and BFILE data.
# -----------------------------------------------------------------------------
from typing import Any, Union
from . import __name__ as MODULE_NAME
from . import errors
class BaseLOB:
__module__ = MODULE_NAME
def __del__(self):
self._impl.free_lob()
@classmethod
def _from_impl(cls, impl):
lob = cls.__new__(cls)
lob._impl = impl
return lob
@property
def type(self) -> Any:
"""
Returns the type of the LOB as one of the database type constants.
"""
return self._impl.dbtype
class LOB(BaseLOB):
__module__ = MODULE_NAME
def __reduce__(self):
value = self.read()
return (type(value), (value,))
def __str__(self):
return self.read()
def close(self) -> None:
"""
Close the LOB. Call this when writing is completed so that the indexes
associated with the LOB can be updated - but only if open() was called
first.
"""
self._impl.close()
def fileexists(self) -> bool:
"""
Return a boolean indicating if the file referenced by a BFILE type LOB
exists.
"""
return self._impl.file_exists()
def getchunksize(self) -> int:
"""
Return the chunk size for the LOB. Reading and writing to the LOB in
chunks of multiples of this size will improve performance.
"""
return self._impl.get_chunk_size()
def getfilename(self) -> tuple:
"""
Return a two-tuple consisting of the directory alias and file name for
a BFILE type LOB.
"""
return self._impl.get_file_name()
def isopen(self) -> bool:
"""
Return a boolean indicating if the LOB has been opened using the method
open().
"""
return self._impl.get_is_open()
def open(self) -> None:
"""
Open the LOB for writing. This will improve performance when writing to
the LOB in chunks and there are functional or extensible indexes
associated with the LOB. If this method is not called, each write will
perform an open internally followed by a close after the write has been
completed.
"""
self._impl.open()
def read(self, offset: int = 1, amount: int = None) -> Union[str, bytes]:
"""
Return a portion (or all) of the data in the LOB. Note that the amount
and offset are in bytes for BLOB and BFILE type LOBs and in UCS-2 code
points for CLOB and NCLOB type LOBs. UCS-2 code points are equivalent
to characters for all but supplemental characters. If supplemental
characters are in the LOB, the offset and amount will have to be chosen
carefully to avoid splitting a character.
"""
if amount is None:
amount = self._impl.get_max_amount()
if amount >= offset:
amount = amount - offset + 1
else:
amount = 1
if offset <= 0:
errors._raise_err(errors.ERR_INVALID_LOB_OFFSET)
return self._impl.read(offset, amount)
def setfilename(self, dir_alias: str, name: str) -> None:
"""
Set the directory alias and name of a BFILE type LOB.
"""
self._impl.set_file_name(dir_alias, name)
def size(self) -> int:
"""
Returns the size of the data in the LOB. For BLOB and BFILE type LOBs
this is the number of bytes. For CLOB and NCLOB type LOBs this is the
number of UCS-2 code points. UCS-2 code points are equivalent to
characters for all but supplemental characters.
"""
return self._impl.get_size()
def trim(self, new_size: int = 0, *, newSize: int = None) -> None:
"""
Trim the LOB to the new size (the second parameter is deprecated and
should not be used).
"""
if newSize is not None:
if new_size != 0:
errors._raise_err(
errors.ERR_DUPLICATED_PARAMETER,
deprecated_name="newSize",
new_name="new_size",
)
new_size = newSize
self._impl.trim(new_size)
def write(self, data: Union[str, bytes], offset: int = 1) -> None:
"""
Write the data to the LOB at the given offset. The offset is in bytes
for BLOB type LOBs and in UCS-2 code points for CLOB and NCLOB type
LOBs. UCS-2 code points are equivalent to characters for all but
supplemental characters. If supplemental characters are in the LOB, the
offset will have to be chosen carefully to avoid splitting a character.
Note that if you want to make the LOB value smaller, you must use the
trim() function.
"""
self._impl.write(data, offset)
class AsyncLOB(BaseLOB):
__module__ = MODULE_NAME
async def close(self) -> None:
"""
Close the LOB. Call this when writing is completed so that the indexes
associated with the LOB can be updated - but only if open() was called
first.
"""
await self._impl.close()
async def fileexists(self) -> bool:
"""
Return a boolean indicating if the file referenced by a BFILE type LOB
exists.
"""
return await self._impl.file_exists()
async def getchunksize(self) -> int:
"""
Return the chunk size for the LOB. Reading and writing to the LOB in
chunks of multiples of this size will improve performance.
"""
return await self._impl.get_chunk_size()
async def getfilename(self) -> tuple:
"""
Return a two-tuple consisting of the directory alias and file name for
a BFILE type LOB.
"""
return await self._impl.get_file_name()
async def isopen(self) -> bool:
"""
Return a boolean indicating if the LOB has been opened using the method
open().
"""
return await self._impl.get_is_open()
async def open(self) -> None:
"""
Open the LOB for writing. This will improve performance when writing to
the LOB in chunks and there are functional or extensible indexes
associated with the LOB. If this method is not called, each write will
perform an open internally followed by a close after the write has been
completed.
"""
await self._impl.open()
async def read(
self, offset: int = 1, amount: int = None
) -> Union[str, bytes]:
"""
Return a portion (or all) of the data in the LOB. Note that the amount
and offset are in bytes for BLOB and BFILE type LOBs and in UCS-2 code
points for CLOB and NCLOB type LOBs. UCS-2 code points are equivalent
to characters for all but supplemental characters. If supplemental
characters are in the LOB, the offset and amount will have to be chosen
carefully to avoid splitting a character.
"""
if amount is None:
amount = self._impl.get_max_amount()
if amount >= offset:
amount = amount - offset + 1
else:
amount = 1
if offset <= 0:
errors._raise_err(errors.ERR_INVALID_LOB_OFFSET)
return await self._impl.read(offset, amount)
async def setfilename(self, dir_alias: str, name: str) -> None:
"""
Set the directory alias and name of a BFILE type LOB.
"""
await self._impl.set_file_name(dir_alias, name)
async def size(self) -> int:
"""
Returns the size of the data in the LOB. For BLOB and BFILE type LOBs
this is the number of bytes. For CLOB and NCLOB type LOBs this is the
number of UCS-2 code points. UCS-2 code points are equivalent to
characters for all but supplemental characters.
"""
return await self._impl.get_size()
async def trim(self, new_size: int = 0, *, newSize: int = None) -> None:
"""
Trim the LOB to the new size (the second parameter is deprecated and
should not be used).
"""
if newSize is not None:
if new_size != 0:
errors._raise_err(
errors.ERR_DUPLICATED_PARAMETER,
deprecated_name="newSize",
new_name="new_size",
)
new_size = newSize
await self._impl.trim(new_size)
async def write(self, data: Union[str, bytes], offset: int = 1) -> None:
"""
Write the data to the LOB at the given offset. The offset is in bytes
for BLOB type LOBs and in UCS-2 code points for CLOB and NCLOB type
LOBs. UCS-2 code points are equivalent to characters for all but
supplemental characters. If supplemental characters are in the LOB, the
offset will have to be chosen carefully to avoid splitting a character.
Note that if you want to make the LOB value smaller, you must use the
trim() function.
"""
await self._impl.write(data, offset)
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,759 @@
# -----------------------------------------------------------------------------
# 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
# 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
# either license.
#
# If you elect to accept the software under the Apache License, Version 2.0,
# the following applies:
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# pool_params.py
#
# Contains the PoolParams class used for managing the parameters required to
# create a connection pool.
#
# *** NOTICE *** This file is generated from a template and should not be
# modified directly. See build_from_template.py in the utils subdirectory for
# more information.
# -----------------------------------------------------------------------------
from typing import Callable, Type, Union, Any
import oracledb
from . import base_impl, utils
from .connect_params import ConnectParams
class PoolParams(ConnectParams):
"""
Contains all parameters used for creating a connection pool.
"""
__module__ = oracledb.__name__
__slots__ = ["_impl"]
_impl_class = base_impl.PoolParamsImpl
@utils.params_initer
def __init__(
self,
*,
min: int = 1,
max: int = 2,
increment: int = 1,
connectiontype: Type["oracledb.Connection"] = None,
getmode: int = oracledb.POOL_GETMODE_WAIT,
homogeneous: bool = True,
timeout: int = 0,
wait_timeout: int = 0,
max_lifetime_session: int = 0,
session_callback: Callable = None,
max_sessions_per_shard: int = 0,
soda_metadata_cache: bool = False,
ping_interval: int = 60,
user: str = None,
proxy_user: str = None,
password: str = None,
newpassword: str = None,
wallet_password: str = None,
access_token: Union[str, tuple, Callable] = None,
host: str = None,
port: int = 1521,
protocol: str = "tcp",
https_proxy: str = None,
https_proxy_port: int = 0,
service_name: str = None,
sid: str = None,
server_type: str = None,
cclass: str = None,
purity: int = oracledb.PURITY_DEFAULT,
expire_time: int = 0,
retry_count: int = 0,
retry_delay: int = 0,
tcp_connect_timeout: float = 60.0,
ssl_server_dn_match: bool = True,
ssl_server_cert_dn: str = None,
wallet_location: str = None,
events: bool = False,
externalauth: bool = False,
mode: int = oracledb.AUTH_MODE_DEFAULT,
disable_oob: bool = False,
stmtcachesize: int = oracledb.defaults.stmtcachesize,
edition: str = None,
tag: str = None,
matchanytag: bool = False,
config_dir: str = oracledb.defaults.config_dir,
appcontext: list = None,
shardingkey: list = None,
supershardingkey: list = None,
debug_jdwp: str = None,
connection_id_prefix: str = None,
ssl_context: Any = None,
sdu: int = 8192,
handle: int = 0,
):
"""
All parameters are optional. A brief description of each parameter
follows:
- min: the minimum number of connections the pool should contain
(default: 1)
- max: the maximum number of connections the pool should contain
(default: 2)
- increment: the number of connections that should be added to the pool
whenever a new connection needs to be created (default: 1)
- connectiontype: the class of the connection that should be returned
during calls to pool.acquire(). It must be Connection or a subclass
of Connection (default: None)
- getmode: how pool.acquire() will behave. One of the constants
oracledb.POOL_GETMODE_WAIT, oracledb.POOL_GETMODE_NOWAIT,
oracledb.POOL_GETMODE_FORCEGET, or oracledb.POOL_GETMODE_TIMEDWAIT
(default: oracledb.POOL_GETMODE_WAIT)
- homogeneous: a boolean indicating whether the connections are
homogeneous (same user) or heterogeneous (multiple users) (default:
True)
- timeout: length of time (in seconds) that a connection may remain
idle in the pool before it is terminated. If it is 0 then connections
are never terminated (default: 0)
- wait_timeout: length of time (in milliseconds) that a caller should
wait when acquiring a connection from the pool with getmode set to
oracledb.POOL_GETMODE_TIMEDWAIT (default: 0)
- max_lifetime_session: length of time (in seconds) that connections
can remain in the pool. If it is 0 then connections may remain in the
pool indefinitely (default: 0)
- session_callback: a callable that is invoked when a connection is
returned from the pool for the first time, or when the connection tag
differs from the one requested (default: None)
- max_sessions_per_shard: the maximum number of connections that may be
associated with a particular shard (default: 0)
- soda_metadata_cache: boolean indicating whether or not the SODA
metadata cache should be enabled (default: False)
- ping_interval: length of time (in seconds) after which an unused
connection in the pool will be a candidate for pinging when
pool.acquire() is called. If the ping to the database indicates the
connection is not alive a replacement connection will be returned by
pool.acquire(). If ping_interval is a negative value the ping
functionality will be disabled (default: 60)
- user: the name of the user to connect to (default: None)
- proxy_user: the name of the proxy user to connect to. If this value
is not specified, it will be parsed out of user if user is in the
form "user[proxy_user]" (default: None)
- password: the password for the user (default: None)
- newpassword: the new password for the user. The new password will
take effect immediately upon a successful connection to the database
(default: None)
- wallet_password: the password to use to decrypt the wallet, if it is
encrypted. This value is only used in thin mode (default: None)
- access_token: expected to be a string or a 2-tuple or a callable. If
it is a string, it specifies an Azure AD OAuth2 token used for Open
Authorization (OAuth 2.0) token based authentication. If it is a
2-tuple, it specifies the token and private key strings used for
Oracle Cloud Infrastructure (OCI) Identity and Access Management
(IAM) token based authentication. If it is a callable, it returns
either a string or a 2-tuple used for OAuth 2.0 or OCI IAM token
based authentication and is useful when the pool needs to expand and
create new connections but the current authentication token has
expired (default: None)
- host: the name or IP address of the machine hosting the database or
the database listener (default: None)
- port: the port number on which the database listener is listening
(default: 1521)
- protocol: one of the strings "tcp" or "tcps" indicating whether to
use unencrypted network traffic or encrypted network traffic (TLS)
(default: "tcp")
- https_proxy: the name or IP address of a proxy host to use for
tunneling secure connections (default: None)
- https_proxy_port: the port on which to communicate with the proxy
host (default: 0)
- service_name: the service name of the database (default: None)
- sid: the system identifier (SID) of the database. Note using a
service_name instead is recommended (default: None)
- server_type: the type of server connection that should be
established. If specified, it should be one of "dedicated", "shared"
or "pooled" (default: None)
- cclass: connection class to use for Database Resident Connection
Pooling (DRCP) (default: None)
- purity: purity to use for Database Resident Connection Pooling (DRCP)
(default: oracledb.PURITY_DEFAULT)
- expire_time: an integer indicating the number of minutes between the
sending of keepalive probes. If this parameter is set to a value
greater than zero it enables keepalive (default: 0)
- retry_count: the number of times that a connection attempt should be
retried before the attempt is terminated (default: 0)
- retry_delay: the number of seconds to wait before making a new
connection attempt (default: 0)
- tcp_connect_timeout: a float indicating the maximum number of seconds
to wait for establishing a connection to the database host (default:
60.0)
- ssl_server_dn_match: boolean indicating whether the server
certificate distinguished name (DN) should be matched in addition to
the regular certificate verification that is performed. Note that if
the ssl_server_cert_dn parameter is not privided, host name matching
is performed instead (default: True)
- ssl_server_cert_dn: the distinguished name (DN) which should be
matched with the server. This value is ignored if the
ssl_server_dn_match parameter is not set to the value True. If
specified this value is used for any verfication. Otherwise the
hostname will be used. (default: None)
- wallet_location: the directory where the wallet can be found. In thin
mode this must be the directory containing the PEM-encoded wallet
file ewallet.pem. In thick mode this must be the directory containing
the file cwallet.sso (default: None)
- events: boolean specifying whether events mode should be enabled.
This value is only used in thick mode and is needed for continuous
query notification and high availability event notifications
(default: False)
- externalauth: a boolean indicating whether to use external
authentication (default: False)
- mode: authorization mode to use. For example
oracledb.AUTH_MODE_SYSDBA (default: oracledb.AUTH_MODE_DEFAULT)
- disable_oob: boolean indicating whether out-of-band breaks should be
disabled. This value is only used in thin mode. It has no effect on
Windows which does not support this functionality (default: False)
- stmtcachesize: identifies the initial size of the statement cache
(default: oracledb.defaults.stmtcachesize)
- edition: edition to use for the connection. This parameter cannot be
used simultaneously with the cclass parameter (default: None)
- tag: identifies the type of connection that should be returned from a
pool. This value is only used in thick mode (default: None)
- matchanytag: boolean specifying whether any tag can be used when
acquiring a connection from the pool. This value is only used in
thick mode. (default: False)
- config_dir: directory in which the optional tnsnames.ora
configuration file is located. This value is only used in thin mode.
For thick mode use the config_dir parameter of init_oracle_client()
(default: oracledb.defaults.config_dir)
- appcontext: application context used by the connection. It should be
a list of 3-tuples (namespace, name, value) and each entry in the
tuple should be a string. This value is only used in thick mode
(default: None)
- shardingkey: a list of strings, numbers, bytes or dates that identify
the database shard to connect to. This value is only used in thick
mode (default: None)
- supershardingkey: a list of strings, numbers, bytes or dates that
identify the database shard to connect to. This value is only used in
thick mode (default: None)
- debug_jdwp: a string with the format "host=<host>;port=<port>" that
specifies the host and port of the PL/SQL debugger. This value is
only used in thin mode. For thick mode set the ORA_DEBUG_JDWP
environment variable (default: None)
- connection_id_prefix: an application specific prefix that is added to
the connection identifier used for tracing (default: None)
- ssl_context: an SSLContext object used for connecting to the database
using TLS. This SSL context will be modified to include the private
key or any certificates found in a separately supplied wallet. This
parameter should only be specified if the default SSLContext object
cannot be used (default: None)
- sdu: the requested size of the Session Data Unit (SDU), in bytes. The
value tunes internal buffers used for communication to the database.
Bigger values can increase throughput for large queries or bulk data
loads, but at the cost of higher memory use. The SDU size that will
actually be used is negotiated down to the lower of this value and
the database network SDU configuration value (default: 8192)
- handle: an integer representing a pointer to a valid service context
handle. This value is only used in thick mode. It should be used with
extreme caution (default: 0)
"""
pass
def __repr__(self):
return (
self.__class__.__qualname__
+ "("
+ f"min={self.min!r}, "
+ f"max={self.max!r}, "
+ f"increment={self.increment!r}, "
+ f"connectiontype={self.connectiontype!r}, "
+ f"getmode={self.getmode!r}, "
+ f"homogeneous={self.homogeneous!r}, "
+ f"timeout={self.timeout!r}, "
+ f"wait_timeout={self.wait_timeout!r}, "
+ f"max_lifetime_session={self.max_lifetime_session!r}, "
+ f"session_callback={self.session_callback!r}, "
+ f"max_sessions_per_shard={self.max_sessions_per_shard!r}, "
+ f"soda_metadata_cache={self.soda_metadata_cache!r}, "
+ f"ping_interval={self.ping_interval!r}, "
+ f"user={self.user!r}, "
+ f"proxy_user={self.proxy_user!r}, "
+ f"host={self.host!r}, "
+ f"port={self.port!r}, "
+ f"protocol={self.protocol!r}, "
+ f"https_proxy={self.https_proxy!r}, "
+ f"https_proxy_port={self.https_proxy_port!r}, "
+ f"service_name={self.service_name!r}, "
+ f"sid={self.sid!r}, "
+ f"server_type={self.server_type!r}, "
+ f"cclass={self.cclass!r}, "
+ f"purity={self.purity!r}, "
+ f"expire_time={self.expire_time!r}, "
+ f"retry_count={self.retry_count!r}, "
+ f"retry_delay={self.retry_delay!r}, "
+ f"tcp_connect_timeout={self.tcp_connect_timeout!r}, "
+ f"ssl_server_dn_match={self.ssl_server_dn_match!r}, "
+ f"ssl_server_cert_dn={self.ssl_server_cert_dn!r}, "
+ f"wallet_location={self.wallet_location!r}, "
+ f"events={self.events!r}, "
+ f"externalauth={self.externalauth!r}, "
+ f"mode={self.mode!r}, "
+ f"disable_oob={self.disable_oob!r}, "
+ f"stmtcachesize={self.stmtcachesize!r}, "
+ f"edition={self.edition!r}, "
+ f"tag={self.tag!r}, "
+ f"matchanytag={self.matchanytag!r}, "
+ f"config_dir={self.config_dir!r}, "
+ f"appcontext={self.appcontext!r}, "
+ f"shardingkey={self.shardingkey!r}, "
+ f"supershardingkey={self.supershardingkey!r}, "
+ f"debug_jdwp={self.debug_jdwp!r}, "
+ f"connection_id_prefix={self.connection_id_prefix!r}, "
+ f"ssl_context={self.ssl_context!r}, "
+ f"sdu={self.sdu!r}"
+ ")"
)
@property
def connectiontype(self) -> Type["oracledb.Connection"]:
"""
The class of the connection that should be returned during calls to
pool.acquire(). It must be Connection or a subclass of Connection.
"""
return self._impl.connectiontype
@property
def getmode(self) -> int:
"""
How pool.acquire() will behave. One of the constants
oracledb.POOL_GETMODE_WAIT, oracledb.POOL_GETMODE_NOWAIT,
oracledb.POOL_GETMODE_FORCEGET, or oracledb.POOL_GETMODE_TIMEDWAIT.
"""
return self._impl.getmode
@property
def homogeneous(self) -> bool:
"""
A boolean indicating whether the connections are homogeneous (same
user) or heterogeneous (multiple users).
"""
return self._impl.homogeneous
@property
def increment(self) -> int:
"""
The number of connections that should be added to the pool whenever a
new connection needs to be created.
"""
return self._impl.increment
@property
def max(self) -> int:
"""
The maximum number of connections the pool should contain.
"""
return self._impl.max
@property
def max_lifetime_session(self) -> int:
"""
Length of time (in seconds) that connections can remain in the pool. If
it is 0 then connections may remain in the pool indefinitely.
"""
return self._impl.max_lifetime_session
@property
def max_sessions_per_shard(self) -> int:
"""
The maximum number of connections that may be associated with a
particular shard.
"""
return self._impl.max_sessions_per_shard
@property
def min(self) -> int:
"""
The minimum number of connections the pool should contain.
"""
return self._impl.min
@property
def ping_interval(self) -> int:
"""
Length of time (in seconds) after which an unused connection in the
pool will be a candidate for pinging when pool.acquire() is called. If
the ping to the database indicates the connection is not alive a
replacement connection will be returned by pool.acquire(). If
ping_interval is a negative value the ping functionality will be
disabled.
"""
return self._impl.ping_interval
@property
def session_callback(self) -> Callable:
"""
A callable that is invoked when a connection is returned from the pool
for the first time, or when the connection tag differs from the one
requested.
"""
return self._impl.session_callback
@property
def soda_metadata_cache(self) -> bool:
"""
Boolean indicating whether or not the SODA metadata cache should be
enabled.
"""
return self._impl.soda_metadata_cache
@property
def timeout(self) -> int:
"""
Length of time (in seconds) that a connection may remain idle in the
pool before it is terminated. If it is 0 then connections are never
terminated.
"""
return self._impl.timeout
@property
def wait_timeout(self) -> int:
"""
Length of time (in milliseconds) that a caller should wait when
acquiring a connection from the pool with getmode set to
oracledb.POOL_GETMODE_TIMEDWAIT.
"""
return self._impl.wait_timeout
def copy(self) -> "PoolParams":
"""
Creates a copy of the parameters and returns it.
"""
params = PoolParams.__new__(PoolParams)
params._impl = self._impl.copy()
return params
@utils.params_setter
def set(
self,
*,
min: int = None,
max: int = None,
increment: int = None,
connectiontype: Type["oracledb.Connection"] = None,
getmode: int = None,
homogeneous: bool = None,
timeout: int = None,
wait_timeout: int = None,
max_lifetime_session: int = None,
session_callback: Callable = None,
max_sessions_per_shard: int = None,
soda_metadata_cache: bool = None,
ping_interval: int = None,
user: str = None,
proxy_user: str = None,
password: str = None,
newpassword: str = None,
wallet_password: str = None,
access_token: Union[str, tuple, Callable] = None,
host: str = None,
port: int = None,
protocol: str = None,
https_proxy: str = None,
https_proxy_port: int = None,
service_name: str = None,
sid: str = None,
server_type: str = None,
cclass: str = None,
purity: int = None,
expire_time: int = None,
retry_count: int = None,
retry_delay: int = None,
tcp_connect_timeout: float = None,
ssl_server_dn_match: bool = None,
ssl_server_cert_dn: str = None,
wallet_location: str = None,
events: bool = None,
externalauth: bool = None,
mode: int = None,
disable_oob: bool = None,
stmtcachesize: int = None,
edition: str = None,
tag: str = None,
matchanytag: bool = None,
config_dir: str = None,
appcontext: list = None,
shardingkey: list = None,
supershardingkey: list = None,
debug_jdwp: str = None,
connection_id_prefix: str = None,
ssl_context: Any = None,
sdu: int = None,
handle: int = None,
):
"""
All parameters are optional. A brief description of each parameter
follows:
- min: the minimum number of connections the pool should contain
- max: the maximum number of connections the pool should contain
- increment: the number of connections that should be added to the pool
whenever a new connection needs to be created
- connectiontype: the class of the connection that should be returned
during calls to pool.acquire(). It must be Connection or a subclass
of Connection
- getmode: how pool.acquire() will behave. One of the constants
oracledb.POOL_GETMODE_WAIT, oracledb.POOL_GETMODE_NOWAIT,
oracledb.POOL_GETMODE_FORCEGET, or oracledb.POOL_GETMODE_TIMEDWAIT
- homogeneous: a boolean indicating whether the connections are
homogeneous (same user) or heterogeneous (multiple users)
- timeout: length of time (in seconds) that a connection may remain
idle in the pool before it is terminated. If it is 0 then connections
are never terminated
- wait_timeout: length of time (in milliseconds) that a caller should
wait when acquiring a connection from the pool with getmode set to
oracledb.POOL_GETMODE_TIMEDWAIT
- max_lifetime_session: length of time (in seconds) that connections
can remain in the pool. If it is 0 then connections may remain in the
pool indefinitely
- session_callback: a callable that is invoked when a connection is
returned from the pool for the first time, or when the connection tag
differs from the one requested
- max_sessions_per_shard: the maximum number of connections that may be
associated with a particular shard
- soda_metadata_cache: boolean indicating whether or not the SODA
metadata cache should be enabled
- ping_interval: length of time (in seconds) after which an unused
connection in the pool will be a candidate for pinging when
pool.acquire() is called. If the ping to the database indicates the
connection is not alive a replacement connection will be returned by
pool.acquire(). If ping_interval is a negative value the ping
functionality will be disabled
- user: the name of the user to connect to
- proxy_user: the name of the proxy user to connect to. If this value
is not specified, it will be parsed out of user if user is in the
form "user[proxy_user]"
- password: the password for the user
- newpassword: the new password for the user. The new password will
take effect immediately upon a successful connection to the database
- wallet_password: the password to use to decrypt the wallet, if it is
encrypted. This value is only used in thin mode
- access_token: expected to be a string or a 2-tuple or a callable. If
it is a string, it specifies an Azure AD OAuth2 token used for Open
Authorization (OAuth 2.0) token based authentication. If it is a
2-tuple, it specifies the token and private key strings used for
Oracle Cloud Infrastructure (OCI) Identity and Access Management
(IAM) token based authentication. If it is a callable, it returns
either a string or a 2-tuple used for OAuth 2.0 or OCI IAM token
based authentication and is useful when the pool needs to expand and
create new connections but the current authentication token has
expired
- host: the name or IP address of the machine hosting the database or
the database listener
- port: the port number on which the database listener is listening
- protocol: one of the strings "tcp" or "tcps" indicating whether to
use unencrypted network traffic or encrypted network traffic (TLS)
- https_proxy: the name or IP address of a proxy host to use for
tunneling secure connections
- https_proxy_port: the port on which to communicate with the proxy
host
- service_name: the service name of the database
- sid: the system identifier (SID) of the database. Note using a
service_name instead is recommended
- server_type: the type of server connection that should be
established. If specified, it should be one of "dedicated", "shared"
or "pooled"
- cclass: connection class to use for Database Resident Connection
Pooling (DRCP)
- purity: purity to use for Database Resident Connection Pooling (DRCP)
- expire_time: an integer indicating the number of minutes between the
sending of keepalive probes. If this parameter is set to a value
greater than zero it enables keepalive
- retry_count: the number of times that a connection attempt should be
retried before the attempt is terminated
- retry_delay: the number of seconds to wait before making a new
connection attempt
- tcp_connect_timeout: a float indicating the maximum number of seconds
to wait for establishing a connection to the database host
- ssl_server_dn_match: boolean indicating whether the server
certificate distinguished name (DN) should be matched in addition to
the regular certificate verification that is performed. Note that if
the ssl_server_cert_dn parameter is not privided, host name matching
is performed instead
- ssl_server_cert_dn: the distinguished name (DN) which should be
matched with the server. This value is ignored if the
ssl_server_dn_match parameter is not set to the value True. If
specified this value is used for any verfication. Otherwise the
hostname will be used.
- wallet_location: the directory where the wallet can be found. In thin
mode this must be the directory containing the PEM-encoded wallet
file ewallet.pem. In thick mode this must be the directory containing
the file cwallet.sso
- events: boolean specifying whether events mode should be enabled.
This value is only used in thick mode and is needed for continuous
query notification and high availability event notifications
- externalauth: a boolean indicating whether to use external
authentication
- mode: authorization mode to use. For example
oracledb.AUTH_MODE_SYSDBA
- disable_oob: boolean indicating whether out-of-band breaks should be
disabled. This value is only used in thin mode. It has no effect on
Windows which does not support this functionality
- stmtcachesize: identifies the initial size of the statement cache
- edition: edition to use for the connection. This parameter cannot be
used simultaneously with the cclass parameter
- tag: identifies the type of connection that should be returned from a
pool. This value is only used in thick mode
- matchanytag: boolean specifying whether any tag can be used when
acquiring a connection from the pool. This value is only used in
thick mode.
- config_dir: directory in which the optional tnsnames.ora
configuration file is located. This value is only used in thin mode.
For thick mode use the config_dir parameter of init_oracle_client()
- appcontext: application context used by the connection. It should be
a list of 3-tuples (namespace, name, value) and each entry in the
tuple should be a string. This value is only used in thick mode
- shardingkey: a list of strings, numbers, bytes or dates that identify
the database shard to connect to. This value is only used in thick
mode
- supershardingkey: a list of strings, numbers, bytes or dates that
identify the database shard to connect to. This value is only used in
thick mode
- debug_jdwp: a string with the format "host=<host>;port=<port>" that
specifies the host and port of the PL/SQL debugger. This value is
only used in thin mode. For thick mode set the ORA_DEBUG_JDWP
environment variable
- connection_id_prefix: an application specific prefix that is added to
the connection identifier used for tracing
- ssl_context: an SSLContext object used for connecting to the database
using TLS. This SSL context will be modified to include the private
key or any certificates found in a separately supplied wallet. This
parameter should only be specified if the default SSLContext object
cannot be used
- sdu: the requested size of the Session Data Unit (SDU), in bytes. The
value tunes internal buffers used for communication to the database.
Bigger values can increase throughput for large queries or bulk data
loads, but at the cost of higher memory use. The SDU size that will
actually be used is negotiated down to the lower of this value and
the database network SDU configuration value
- handle: an integer representing a pointer to a valid service context
handle. This value is only used in thick mode. It should be used with
extreme caution
"""
pass
@@ -0,0 +1,685 @@
# -----------------------------------------------------------------------------
# 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
# 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
# either license.
#
# If you elect to accept the software under the Apache License, Version 2.0,
# the following applies:
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# soda.py
#
# Contains the classes for managing Simple Oracle Document Access (SODA):
# SodaDatabase, SodaCollection, SodaDocument, SodaDocCursor and SodaOperation.
# -----------------------------------------------------------------------------
from typing import Any, Union, List
import json
from . import errors
class SodaDatabase:
def __repr__(self):
return f"<oracledb.SodaDatabase on {self._conn!r}>"
@classmethod
def _from_impl(cls, conn, impl):
db = cls.__new__(cls)
db._conn = conn
db._impl = impl
return db
def _get_content_bytes(self, content: Any) -> bytes:
"""
Internal method used for returning the bytes to store in document
content.
"""
if isinstance(content, str):
return content.encode()
elif isinstance(content, bytes):
return content
return json.dumps(content).encode()
def createCollection(
self,
name: str,
metadata: Union[str, dict] = None,
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
with the same name and metadata already exists, then that existing
collection is opened without error.
If metadata is specified, it is expected to be a string containing
valid JSON or a dictionary that will be transformed into a JSON string.
This JSON permits you to specify the configuration of the collection
including storage options; specifying the presence or absence of
columns for creation timestamp, last modified timestamp and version;
whether the collection can store only JSON documents; and methods of
key and version generation. The default metadata creates a collection
that only supports JSON documents and uses system generated keys.
If the mapMode parameter is set to True, the new collection is mapped
to an existing table instead of creating a table. If a collection is
created in this way, dropping the collection will not drop the existing
table either.
"""
if metadata is not None and not isinstance(metadata, str):
metadata = json.dumps(metadata)
collection_impl = self._impl.create_collection(name, metadata, mapMode)
return SodaCollection._from_impl(self, collection_impl)
def createDocument(
self,
content: Any,
key: str = None,
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
has non-JSON content; otherwise, you can pass your content directly to
SODA write operations. SodaDocument attributes "createdOn",
"lastModified" and "version" will be None.
The content parameter can be a dictionary or list which will be
transformed into a JSON string and then UTF-8 encoded. It can also be a
string which will be UTF-8 encoded or it can be a bytes object which
will be stored unchanged. If a bytes object is provided and the content
is expected to be JSON, note that SODA only supports UTF-8, UTF-16LE
and UTF-16BE encodings.
The key parameter should only be supplied if the collection in which
the document is to be placed requires client-assigned keys.
The mediaType parameter should only be supplied if the collection in
which the document is to be placed supports non-JSON documents and the
content for this document is non-JSON. Using a standard MIME type for
this value is recommended but any string will be accepted.
"""
content_bytes = self._get_content_bytes(content)
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[str]:
"""
Returns a list of the names of collections in the database that match
the criteria, in alphabetical order.
If the startName parameter is specified, the list of names returned
will start with this value and also contain any names that fall after
this value in alphabetical order.
If the limit parameter is specified and is non-zero, the number of
collection names returned will be limited to this value.
"""
return self._impl.get_collection_names(startName, limit)
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
is returned.
"""
collection_impl = self._impl.open_collection(name)
if collection_impl is not None:
return SodaCollection._from_impl(self, collection_impl)
class SodaCollection:
@classmethod
def _from_impl(cls, db, impl):
coll = cls.__new__(cls)
coll._db = db
coll._impl = impl
return coll
def _process_doc_arg(self, arg):
if isinstance(arg, SodaDocument):
return arg._impl
content_bytes = self._db._get_content_bytes(arg)
return self._db._impl.create_document(content_bytes, None, None)
def createIndex(self, spec: Union[dict, str]) -> None:
"""
Creates an index on a SODA collection. The spec is expected to be a
dictionary or a JSON-encoded string.
Note that a commit should be performed before attempting to create an
index.
"""
if isinstance(spec, dict):
spec = json.dumps(spec)
elif not isinstance(spec, str):
raise TypeError("expecting a dictionary or string")
self._impl.create_index(spec)
def drop(self) -> bool:
"""
Drops the collection from the database, if it exists. Note that if the
collection was created with mapMode set to True the underlying table
will not be dropped.
A boolean value is returned indicating if the collection was actually
dropped.
"""
return self._impl.drop()
def dropIndex(self, name: str, force: bool = False) -> bool:
"""
Drops the index with the specified name, if it exists.
The force parameter, if set to True, can be used to force the dropping
of an index that the underlying Oracle Database domain index doesnt
normally permit. This is only applicable to spatial and JSON search
indexes. See here for more information.
A boolean value is returned indicating if the index was actually
dropped.
"""
return self._impl.drop_index(name, force)
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
is used to specify the criteria and the operation that will be
performed on the documents that match that criteria.
"""
return SodaOperation(self)
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
be useful for exploring the schema of a collection. Note that this
method is only supported for JSON-only collections where a JSON search
index has been created with the dataguide option enabled. If there
are no documents in the collection, None is returned.
"""
doc_impl = self._impl.get_data_guide()
if doc_impl is not None:
return SodaDocument._from_impl(doc_impl)
def insertMany(self, docs: list) -> None:
"""
Inserts a list of documents into the collection at one time. Each of
the input documents can be a dictionary or list or an existing SODA
document object.
"""
doc_impls = [self._process_doc_arg(d) for d in docs]
self._impl.insert_many(doc_impls, hint=None, return_docs=False)
def insertManyAndGet(self, docs: list, hint: str = None) -> list:
"""
Similarly to insertMany() this method inserts a list of documents into
the collection at one time. The only difference is that it returns a
list of SODA Document objects. Note that for performance reasons the
returned documents do not contain the content.
The hint parameter, if specified, supplies a hint to the database when
processing the SODA operation. This is expected to be a string in the
same format as SQL hints but without any comment characters, for
example hint="MONITOR". While you could use this to pass any SQL hint,
the hints MONITOR (turn on monitoring) and NO_MONITOR (turn off
monitoring) are the most useful. Use of the hint parameter requires
Oracle Client 21.3 or higher (or Oracle Client 19 from 19.11).
"""
doc_impls = [self._process_doc_arg(d) for d in docs]
if hint is not None and not isinstance(hint, str):
raise TypeError("expecting a string")
return_doc_impls = self._impl.insert_many(
doc_impls, hint, return_docs=True
)
return [SodaDocument._from_impl(i) for i in return_doc_impls]
def insertOne(self, doc: Any) -> None:
"""
Inserts a given document into the collection. The input document can be
a dictionary or list or an existing SODA document object.
"""
doc_impl = self._process_doc_arg(doc)
self._impl.insert_one(doc_impl, hint=None, return_doc=False)
def insertOneAndGet(self, doc: Any, 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
object. Note that for performance reasons the returned document does
not contain the content.
The hint parameter, if specified, supplies a hint to the database when
processing the SODA operation. This is expected to be a string in the
same format as SQL hints but without any comment characters, for
example hint="MONITOR". While you could use this to pass any SQL hint,
the hints MONITOR (turn on monitoring) and NO_MONITOR (turn off
monitoring) are the most useful. Use of the hint parameter requires
Oracle Client 21.3 or higher (or Oracle Client 19 from 19.11).
"""
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.insert_one(
doc_impl, hint, return_doc=True
)
return SodaDocument._from_impl(return_doc_impl)
def listIndexes(self) -> list:
"""
Return a list of indexes associated with the collection.
"""
return [json.loads(s) for s in self._impl.list_indexes()]
@property
def metadata(self) -> dict:
"""
This read-only attribute returns a dictionary containing the metadata
that was used to create the collection.
"""
return json.loads(self._impl.get_metadata())
@property
def name(self) -> str:
"""
This read-only attribute returns the name of the collection.
"""
return self._impl.name
def save(self, doc: Any) -> None:
"""
Saves a document into the collection. This method is equivalent to
insertOne() except that if client-assigned keys are used, and the
document with the specified key already exists in the collection, it
will be replaced with the input document.
"""
doc_impl = self._process_doc_arg(doc)
self._impl.save(doc_impl, hint=None, return_doc=False)
def saveAndGet(self, doc: Any, 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
document with the specified key already exists in the collection, it
will be replaced with the input document.
The hint parameter, if specified, supplies a hint to the database when
processing the SODA operation. This is expected to be a string in the
same format as SQL hints but without any comment characters, for
example hint="MONITOR". While you could use this to pass any SQL hint,
the hints MONITOR (turn on monitoring) and NO_MONITOR (turn off
monitoring) are the most useful. Use of the hint parameter requires
Oracle Client 21.3 or higher (or Oracle Client 19 from 19.11).
"""
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=True)
return SodaDocument._from_impl(return_doc_impl)
def truncate(self) -> None:
"""
Removes all of the documents in the collection, similarly to what is
done for rows in a table by the TRUNCATE TABLE statement.
"""
self._impl.truncate()
class SodaDocument:
@classmethod
def _from_impl(cls, impl):
doc = cls.__new__(cls)
doc._impl = impl
return doc
@property
def createdOn(self) -> str:
"""
This read-only attribute returns the creation time of the document in
ISO 8601 format. Documents created by SodaDatabase.createDocument() or
fetched from collections where this attribute is not stored will return
None.
"""
return self._impl.get_created_on()
def getContent(self) -> Union[dict, list]:
"""
Returns the content of the document as a dictionary or list. This
method assumes that the content is application/json and will raise an
exception if this is not the case. If there is no content, however,
None will be returned.
"""
return json.loads(self.getContentAsString())
def getContentAsBytes(self) -> bytes:
"""
Returns the content of the document as a bytes object. If there is no
content, however, None will be returned.
"""
content_bytes, encoding = self._impl.get_content()
return content_bytes
def getContentAsString(self) -> str:
"""
Returns the content of the document as a string. If the document
encoding is not known, UTF-8 will be used. If there is no content,
however, None will be returned.
"""
content_bytes, encoding = self._impl.get_content()
return content_bytes.decode(encoding)
@property
def key(self) -> str:
"""
This read-only attribute returns the unique key assigned to this
document. Documents created by SodaDatabase.createDocument() may not
have a value assigned to them and return None.
"""
return self._impl.get_key()
@property
def lastModified(self) -> str:
"""
This read-only attribute returns the last modified time of the document
in ISO 8601 format. Documents created by SodaDatabase.createDocument()
or fetched from collections where this attribute is not stored will
return None.
"""
return self._impl.get_last_modified()
@property
def mediaType(self) -> str:
"""
This read-only attribute returns the media type assigned to the
document. By convention this is expected to be a MIME type but no
checks are performed on this value. If a value is not specified when
calling SodaDatabase.createDocument() or the document is fetched from a
collection where this component is not stored, the string
“application/json” is returned.
"""
return self._impl.get_media_type()
@property
def version(self) -> str:
"""
This read-only attribute returns the version assigned to this document.
Documents created by SodaDatabase.createDocument() or fetched from
collections where this attribute is not stored will return None.
"""
return self._impl.get_version()
class SodaDocCursor:
def __iter__(self):
return self
def __next__(self):
if self._impl is None:
errors._raise_err(errors.ERR_CURSOR_NOT_OPEN)
doc_impl = self._impl.get_next_doc()
if doc_impl is not None:
return SodaDocument._from_impl(doc_impl)
raise StopIteration
@classmethod
def _from_impl(cls, impl):
cursor = cls.__new__(cls)
cursor._impl = impl
return cursor
def close(self) -> None:
"""
Close the cursor now, rather than whenever __del__ is called. The
cursor will be unusable from this point forward; an Error exception
will be raised if any operation is attempted with the cursor.
"""
if self._impl is None:
errors._raise_err(errors.ERR_CURSOR_NOT_OPEN)
self._impl.close()
self._impl = None
class SodaOperation:
def __init__(self, collection: SodaCollection) -> None:
self._collection = collection
self._key = None
self._keys = None
self._version = None
self._filter = None
self._hint = None
self._skip = None
self._limit = None
self._fetch_array_size = None
self._lock = False
def count(self) -> int:
"""
Returns a count of the number of documents in the collection that match
the criteria. If skip() or limit() were called on this object, an
exception is raised.
"""
return self._collection._impl.get_count(self)
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
getDocuments(). It does not affect how many documents are returned to
the application. A value of 0 will use the default value (100). This
method is only available in Oracle Client 19.5 and higher.
As a convenience, the SodaOperation object is returned so that further
criteria can be specified by chaining methods together.
"""
if not isinstance(value, int) or value < 0:
raise TypeError("expecting integer >= 0")
if value == 0:
self._fetch_array_size = None
else:
self._fetch_array_size = value
return self
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
dictionary or JSON-encoded string and can include comparisons, regular
expressions, logical and spatial operators, among others. See the
overview of SODA filter specifications for more information.
As a convenience, the SodaOperation object is returned so that further
criteria can be specified by chaining methods together.
"""
if isinstance(value, dict):
self._filter = json.dumps(value)
elif isinstance(value, str):
self._filter = value
else:
raise TypeError("expecting string or dictionary")
return self
def getCursor(self) -> "SodaDocCursor":
"""
Returns a SodaDocCursor object that can be used to iterate over the
documents that match the criteria.
"""
impl = self._collection._impl.get_cursor(self)
return SodaDocCursor._from_impl(impl)
def getDocuments(self) -> list:
"""
Returns a list of SodaDocument objects that match the criteria.
"""
return [d for d in self.getCursor()]
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
returned.
"""
doc_impl = self._collection._impl.get_one(self)
if doc_impl is not None:
return SodaDocument._from_impl(doc_impl)
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
hints but without any comment characters. While you could use this to
pass any SQL hint, the hints MONITOR (turn on monitoring) and
NO_MONITOR (turn off monitoring) are the most useful. Use of this
method requires Oracle Client 21.3 or higher (or Oracle Client 19 from
19.11).
As a convenience, the SodaOperation object is returned so that further
criteria can be specified by chaining methods together.
"""
if not isinstance(value, str):
raise TypeError("expecting a string")
self._hint = value
return self
def lock(self) -> "SodaOperation":
"""
Specifies whether the documents fetched from the collection should be
locked (equivalent to SQL "select for update"). Use of this method
requires Oracle Client 21.3 or higher (or Oracle Client 19 from 19.11).
As a convenience, the SodaOperation object is returned so that further
criteria can be specified by chaining methods together.
"""
self._lock = True
return self
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
ignored.
As a convenience, the SodaOperation object is returned so that further
criteria can be specified by chaining methods together.
"""
if not isinstance(value, str):
raise TypeError("expecting string")
self._key = value
self._keys = None
return self
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
this method and key() to be ignored.
As a convenience, the SodaOperation object is returned so that further
criteria can be specified by chaining methods together.
"""
value_as_list = list(value)
for element in value_as_list:
if not isinstance(element, str):
raise TypeError("expecting sequence of strings")
self._keys = value_as_list
self._key = None
return self
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
getCursor() and getDocuments(). For write operations, any value set
using this method is ignored.
As a convenience, the SodaOperation object is returned so that further
criteria can be specified by chaining methods together.
"""
if not isinstance(value, int) or value <= 0:
raise TypeError("expecting positive integer")
self._limit = value
return self
def remove(self) -> int:
"""
Removes all of the documents in the collection that match the criteria.
The number of documents that have been removed is returned.
"""
return self._collection._impl.remove(self)
def replaceOne(self, doc: Any) -> bool:
"""
Replaces a single document in the collection with the specified
document. The input document can be a dictionary or list or an existing
SODA document object. A boolean indicating if a document was replaced
or not is returned.
Currently the method key() must be called before this method can be
called.
"""
doc_impl = self._collection._process_doc_arg(doc)
return self._collection._impl.replace_one(
self, doc_impl, return_doc=False
)
def replaceOneAndGet(self, doc: Any) -> "SodaDocument":
"""
Similarly to replaceOne(), this method replaces a single document in
the collection with the specified document. The only difference is that
it returns a SodaDocument object. Note that for performance reasons the
returned document does not contain the content.
"""
doc_impl = self._collection._process_doc_arg(doc)
return_doc_impl = self._collection._impl.replace_one(
self, doc_impl, return_doc=True
)
return SodaDocument._from_impl(return_doc_impl)
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
getCursor() and getDocuments(). For write operations, any value set
using this method is ignored.
As a convenience, the SodaOperation object is returned so that further
criteria can be specified by chaining methods together.
"""
if not isinstance(value, int) or value < 0:
raise TypeError("expecting integer >= 0")
self._skip = value
return self
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
that the write operation called later does not affect a document that
someone else has modified.
As a convenience, the SodaOperation object is returned so that further
criteria can be specified by chaining methods together.
"""
if not isinstance(value, str):
raise TypeError("expecting string")
self._version = value
return self
@@ -0,0 +1,356 @@
# -----------------------------------------------------------------------------
# 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
# 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
# either license.
#
# If you elect to accept the software under the Apache License, Version 2.0,
# the following applies:
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# subscr.py
#
# Contains the Subscription class and Message classes used for managing
# subscriptions to database events and the messages that are sent when those
# events are detected.
# -----------------------------------------------------------------------------
from typing import Callable, Union, List
from . import connection
class Subscription:
def __repr__(self):
return f"<oracledb.Subscription on {self.connection!r}>"
@classmethod
def _from_impl(cls, impl):
subscr = cls.__new__(cls)
subscr._impl = impl
return subscr
@property
def callback(self) -> Callable:
"""
Returns the callback that was registered when the subscription was
created.
"""
return self._impl.callback
@property
def connection(self) -> "connection.Connection":
"""
Returns the connection that was used to register the subscription when
it was created.
"""
return self._impl.connection
@property
def id(self) -> int:
"""
Returns the value of REGID found in the database view
USER_CHANGE_NOTIFICATION_REGS or the value of REG_ID found in the
database view USER_SUBSCR_REGISTRATIONS. For AQ subscriptions, this
value is 0.
"""
return self._impl.id
@property
def ip_address(self) -> str:
"""
Returns the IP address used for callback notifications from the
database server. If not set during construction, this value is None.
"""
return self._impl.ip_address
@property
def ipAddress(self) -> str:
"""
Deprecated. Use property ip_address instead.
"""
return self.ip_address
@property
def name(self) -> str:
"""
Returns the name used to register the subscription when it was created.
"""
return self._impl.name
@property
def namespace(self) -> int:
"""
Returns the namespace used to register the subscription when it was
created.
"""
return self._impl.namespace
@property
def operations(self) -> int:
"""
Returns the operations that will send notifications for each table or
query that is registered using this subscription.
"""
return self._impl.operations
@property
def port(self) -> int:
"""
Returns the port used for callback notifications from the database
server. If not set during construction, this value is zero.
"""
return self._impl.port
@property
def protocol(self) -> int:
"""
Returns the protocol used to register the subscription when it was
created.
"""
return self._impl.protocol
@property
def qos(self) -> int:
"""
Returns the quality of service flags used to register the subscription
when it was created.
"""
return self._impl.qos
def registerquery(
self, statement: str, args: Union[list, dict] = None
) -> int:
"""
Register the query for subsequent notification when tables referenced
by the query are changed. This behaves similarly to cursor.execute()
but only queries are permitted and the args parameter, if specified,
must be a sequence or dictionary. If the qos parameter included the
flag SUBSCR_QOS_QUERY when the subscription was created, then the ID
for the registered query is returned; otherwise, None is returned.
"""
if args is not None and not isinstance(args, (list, dict)):
raise TypeError("expecting args to be a dictionary or list")
return self._impl.register_query(statement, args)
@property
def timeout(self) -> int:
"""
Returns the timeout (in seconds) that was specified when the
subscription was created. A value of 0 indicates that there is no
timeout.
"""
return self._impl.timeout
class Message:
def __init__(self, subscription: Subscription) -> None:
self._subscription = subscription
self._consumer_name = None
self._dbname = None
self._queries = []
self._queue_name = None
self._registered = False
self._tables = []
self._txid = None
self._type = 0
self._msgid = None
@property
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
SUBSCR_NAMESPACE_AQ and the queue is a multiple consumer queue.
"""
return self._consumer_name
@property
def consumerName(self) -> Union[str, None]:
"""
Deprecated. Use property consumer_name instead.
"""
return self.consumer_name
@property
def dbname(self) -> Union[str, None]:
"""
Returns the name of the database that generated the notification.
"""
return self._dbname
@property
def msgid(self) -> Union[bytes, None]:
"""
Returns the message id of the AQ message that generated the
notification.
"""
return self._msgid
@property
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
an empty list if the qos parameter did not include the flag
SUBSCR_QOS_QUERY when the subscription was created.
"""
return self._queries
@property
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
SUBSCR_NAMESPACE_AQ.
"""
return self._queue_name
@property
def queueName(self) -> Union[str, None]:
"""
Deprecated. Use property queue_name instead.
"""
return self.queue_name
@property
def registered(self) -> bool:
"""
Returns whether the subscription which generated this notification is
still registered with the database. The subscription is automatically
deregistered with the database when the subscription timeout value is
reached or when the first notification is sent (when the quality of
service flag SUBSCR_QOS_DEREG_NFY is used).
"""
return self._registered
@property
def subscription(self) -> Subscription:
"""
Returns the subscription object for which this notification was
generated.
"""
return self._subscription
@property
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
list if the qos parameter included the flag SUBSCR_QOS_QUERY when the
subscription was created.
"""
return self._tables
@property
def txid(self) -> Union[bytes, None]:
"""
Returns the id of the transaction that generated the notification.
"""
return self._txid
@property
def type(self) -> int:
"""
Returns the type of message that has been sent.
"""
return self._type
class MessageQuery:
def __init__(self) -> None:
self._id = 0
self._operation = 0
self._tables = []
@property
def id(self) -> int:
"""
Returns the query id of the query for which the result set changed. The
value will match the value returned by Subscription.registerquery()
when the related query was registered.
"""
return self._id
@property
def operation(self) -> int:
"""
Returns the operation that took place on the query result set that was
changed. Valid values for this attribute are EVENT_DEREG and
EVENT_QUERYCHANGE.
"""
return self._operation
@property
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
notification.
"""
return self._tables
class MessageRow:
def __init__(self) -> None:
self._operation = 0
self._rowid = None
@property
def operation(self) -> int:
"""
Returns the operation that took place on the row that was changed.
"""
return self._operation
@property
def rowid(self) -> Union[str, None]:
"""
Returns the rowid of the row that was changed.
"""
return self._rowid
class MessageTable:
def __init__(self) -> None:
self._name = None
self._operation = 0
self._rows = []
@property
def name(self) -> Union[str, None]:
"""
Returns the name of the table that was changed.
"""
return self._name
@property
def operation(self) -> int:
"""
Returns the operation that took place on the table that was changed.
"""
return self._operation
@property
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
parameter to the Connection.subscribe() method included the flag
SUBSCR_QOS_ROWIDS.
"""
return self._rows
@@ -0,0 +1,93 @@
# -----------------------------------------------------------------------------
# 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
# 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
# either license.
#
# If you elect to accept the software under the Apache License, Version 2.0,
# the following applies:
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# utils.py
#
# Contains utility classes and methods.
# -----------------------------------------------------------------------------
from . import errors
class CheckImpls:
"""
Decorator class which is used on the base implementation method and checks
to see which implementation is currently being used (and therefore has no
support for the method). An exception is raised letting the user know which
implementation does support the method. Currently there are only two
implementations (thick and thin) so the assumption is made that the
implementation not currently running does support the method.
"""
def __init__(self, feature):
self.feature = feature
def __call__(self, f):
feature = self.feature
def wrapped_f(self, *args, **kwargs):
class_name = type(self).__name__
driver_type = "thin" if class_name.startswith("Thick") else "thick"
errors._raise_err(
errors.ERR_FEATURE_NOT_SUPPORTED,
feature=feature,
driver_type=driver_type,
)
return wrapped_f
def params_initer(f):
"""
Decorator function which is used on the ConnectParams and PoolParams
classes. It creates the implementation object using the implementation
class stored on the parameter class. It first, however, calls the original
method to ensure that the keyword parameters supplied are valid (the
original method itself does nothing).
"""
def wrapped_f(self, *args, **kwargs):
f(self, *args, **kwargs)
self._impl = self._impl_class()
if kwargs:
self._impl.set(kwargs)
return wrapped_f
def params_setter(f):
"""
Decorator function which is used on the ConnectParams and PoolParams
classes. It calls the set() method on the parameter implementation object
with the supplied keyword arguments. It first, however, calls the original
method to ensure that the keyword parameters supplied are valid (the
original method itself does nothing).
"""
def wrapped_f(self, *args, **kwargs):
f(self, *args, **kwargs)
self._impl.set(kwargs)
return wrapped_f
@@ -0,0 +1,181 @@
# -----------------------------------------------------------------------------
# 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
# 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
# either license.
#
# If you elect to accept the software under the Apache License, Version 2.0,
# the following applies:
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# var.py
#
# Contains the Var class used for managing variables used during bind and
# fetch. These hold the metadata as well as any necessary buffers.
# -----------------------------------------------------------------------------
from typing import Any, Callable, Union
from .dbobject import DbObjectType
from .base_impl import DbType
class Var:
def __repr__(self):
value = self._impl.get_all_values()
if not self._impl.is_array and len(value) == 1:
value = value[0]
typ = self._type
return f"<oracledb.Var of type {typ.name} with value {repr(value)}>"
@classmethod
def _from_impl(cls, impl, typ=None):
var = cls.__new__(cls)
var._impl = impl
if typ is not None:
var._type = typ
elif impl.objtype is not None:
var._type = DbObjectType._from_impl(impl.objtype)
else:
var._type = impl.dbtype
return var
@property
def actual_elements(self) -> int:
"""
This read-only attribute returns the actual number of elements in the
variable. This corresponds to the number of elements in a PL/SQL
index-by table for variables that are created using the method
Cursor.arrayvar(). For all other variables this value will be identical
to the attribute num_elements.
"""
if self._impl.is_array:
return self._impl.num_elements_in_array
return self._impl.num_elements
@property
def actualElements(self) -> int:
"""
Deprecated. Use property actual_elements instead.
"""
return self.actual_elements
@property
def buffer_size(self) -> int:
"""
This read-only attribute returns the size of the buffer allocated for
each element in bytes.
"""
return self._impl.buffer_size
@property
def bufferSize(self) -> int:
"""
Deprecated. Use property buffer_size intead().
"""
return self.buffer_size
@property
def convert_nulls(self) -> bool:
"""
This read-only attribute returns whether null values are converted
using the supplied ``outconverter``.
"""
return self._impl.convert_nulls
def getvalue(self, pos: int = 0) -> Any:
"""
Return the value at the given position in the variable. For variables
created using the method Cursor.arrayvar() the value returned will be a
list of each of the values in the PL/SQL index-by table. For variables
bound to DML returning statements, the value returned will also be a
list corresponding to the returned data for the given execution of the
statement (as identified by the pos parameter).
"""
return self._impl.get_value(pos)
@property
def inconverter(self) -> Callable:
"""
This read-only attribute specifies the method used to convert data from
Python to the Oracle database. The method signature is converter(value)
and the expected return value is the value to bind to the database. If
this attribute is None, the value is bound directly without any
conversion.
"""
return self._impl.inconverter
@property
def num_elements(self) -> int:
"""
This read-only attribute returns the number of elements allocated in an
array, or the number of scalar items that can be fetched into the
variable or bound to the variable.
"""
return self._impl.num_elements
@property
def numElements(self) -> int:
"""
Deprecated. Use property num_elements instead.
"""
return self.num_elements
@property
def outconverter(self) -> Callable:
"""
This read-only attribute specifies the method used to convert data from
the Oracle database to Python. The method signature is converter(value)
and the expected return value is the value to return to Python. If this
attribute is None, the value is returned directly without any
conversion.
"""
return self._impl.outconverter
def setvalue(self, pos: int, value: Any) -> None:
"""
Set the value at the given position in the variable.
"""
self._impl.set_value(pos, value)
@property
def size(self) -> int:
"""
This read-only attribute returns the size of the variable. For strings
this value is the size in characters. For all others, this is same
value as the attribute buffer_size.
"""
return self._impl.size
@property
def type(self) -> Union[DbType, DbObjectType]:
"""
This read-only attribute returns the type of the variable. This will be
an Oracle Object Type if the variable binds Oracle objects; otherwise,
it will be one of the database type constants.
"""
return self._type
@property
def values(self) -> list:
"""
This read-only attribute returns a copy of the value of all actual
positions in the variable as a list. This is the equivalent of calling
getvalue() for each valid position and the length will correspond to
the value of the actual_elements attribute.
"""
return self._impl.get_all_values()
@@ -0,0 +1,33 @@
# -----------------------------------------------------------------------------
# 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
# 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
# either license.
#
# If you elect to accept the software under the Apache License, Version 2.0,
# the following applies:
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# version.py
#
# Defines the version of the package. This is the only place where this is
# found. The setup.cfg configuration file and the documentation configuration
# file doc/src/conf.py both reference this file directly.
# -----------------------------------------------------------------------------
__version__ = "2.0.0"