config updation
This commit is contained in:
1275
.venv/lib/python3.9/site-packages/oracledb/__init__.py
Normal file
1275
.venv/lib/python3.9/site-packages/oracledb/__init__.py
Normal file
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
659
.venv/lib/python3.9/site-packages/oracledb/aq.py
Normal file
659
.venv/lib/python3.9/site-packages/oracledb/aq.py
Normal file
@@ -0,0 +1,659 @@
|
||||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2021, 2025, 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
|
||||
from . import errors
|
||||
from .base import BaseMetaClass
|
||||
from .dbobject import DbObject, DbObjectType
|
||||
|
||||
|
||||
class BaseQueue(metaclass=BaseMetaClass):
|
||||
@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)
|
||||
if isinstance(self.payload_type, DbObjectType):
|
||||
if (
|
||||
not isinstance(message.payload, DbObject)
|
||||
or message.payload.type != self.payload_type
|
||||
):
|
||||
errors._raise_err(errors.ERR_PAYLOAD_CANNOT_BE_ENQUEUED)
|
||||
elif self.payload_type == "JSON":
|
||||
if not isinstance(message.payload, (dict, list)):
|
||||
errors._raise_err(errors.ERR_PAYLOAD_CANNOT_BE_ENQUEUED)
|
||||
else:
|
||||
if not isinstance(message.payload, (str, bytes)):
|
||||
errors._raise_err(errors.ERR_PAYLOAD_CANNOT_BE_ENQUEUED)
|
||||
|
||||
@property
|
||||
def connection(self) -> "connection_module.Connection":
|
||||
"""
|
||||
This read-only attribute returns a reference to the connection object
|
||||
on which the queue was created.
|
||||
"""
|
||||
return self._connection
|
||||
|
||||
@property
|
||||
def deqoptions(self) -> "DeqOptions":
|
||||
"""
|
||||
This read-only attribute returns a reference to 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
|
||||
|
||||
@property
|
||||
def enqoptions(self) -> "EnqOptions":
|
||||
"""
|
||||
This read-only attribute returns a reference to 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:
|
||||
"""
|
||||
This read-only attribute returns the name of the queue.
|
||||
"""
|
||||
return self._impl.name
|
||||
|
||||
@property
|
||||
def payload_type(self) -> Union[DbObjectType, None]:
|
||||
"""
|
||||
This read-only attribute returns the object type for payloads that can
|
||||
be enqueued and dequeued. If using a JSON queue, this returns the value
|
||||
"JSON". 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 Queue(BaseQueue):
|
||||
|
||||
def deqmany(self, max_num_messages: int) -> list["MessageProperties"]:
|
||||
"""
|
||||
Dequeues up to the specified number of messages from the queue and
|
||||
returns a list of these messages.
|
||||
"""
|
||||
if self._impl._supports_deq_many(self._connection._impl):
|
||||
message_impls = self._impl.deq_many(max_num_messages)
|
||||
else:
|
||||
message_impls = []
|
||||
while len(message_impls) < max_num_messages:
|
||||
message_impl = self._impl.deq_one()
|
||||
if message_impl is None:
|
||||
break
|
||||
message_impls.append(message_impl)
|
||||
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()
|
||||
|
||||
def enqmany(self, messages: list["MessageProperties"]) -> 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: In python-oracledb Thick mode using Oracle Client libraries
|
||||
prior to 21c, calling :meth:`Queue.enqmany()` in parallel on different
|
||||
connections acquired from the same connection pool may fail due to
|
||||
Oracle bug 29928074. To avoid this, do one of: upgrade the client
|
||||
libraries, ensure that :meth:`Queue.enqmany()` is not run in parallel,
|
||||
use standalone connections or connections from different pools, or make
|
||||
multiple calls to :meth:`Queue.enqone()`. The function
|
||||
:meth:`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["MessageProperties"]) -> 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)
|
||||
|
||||
|
||||
class AsyncQueue(BaseQueue):
|
||||
|
||||
async def deqmany(
|
||||
self, max_num_messages: int
|
||||
) -> list["MessageProperties"]:
|
||||
"""
|
||||
Dequeues up to the specified number of messages from the queue and
|
||||
returns a list of these messages.
|
||||
"""
|
||||
message_impls = await self._impl.deq_many(max_num_messages)
|
||||
return [MessageProperties._from_impl(impl) for impl in message_impls]
|
||||
|
||||
async 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 = await self._impl.deq_one()
|
||||
if message_impl is not None:
|
||||
return MessageProperties._from_impl(message_impl)
|
||||
|
||||
async def enqmany(self, messages: list["MessageProperties"]) -> 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]
|
||||
await self._impl.enq_many(message_impls)
|
||||
|
||||
async 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)
|
||||
await self._impl.enq_one(message._impl)
|
||||
|
||||
|
||||
class DeqOptions(metaclass=BaseMetaClass):
|
||||
@classmethod
|
||||
def _from_impl(cls, impl):
|
||||
options = cls.__new__(cls)
|
||||
options._impl = impl
|
||||
return options
|
||||
|
||||
@property
|
||||
def condition(self) -> str:
|
||||
"""
|
||||
This read-write attribute 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:
|
||||
"""
|
||||
This read-write attribute 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:
|
||||
"""
|
||||
This read-write attribute 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) -> int:
|
||||
"""
|
||||
This write-only attribute specifies what types of messages should be
|
||||
dequeued. It should be one of the values
|
||||
:data:`~oracledb.MSG_PERSISTENT` (default),
|
||||
:data:`~oracledb.MSG_BUFFERED`, or
|
||||
:data:`~oracledb.MSG_PERSISTENT_OR_BUFFERED`.
|
||||
|
||||
Note that :data:`~oracledb.MSG_BUFFERED` is not supported for JSON
|
||||
payloads.
|
||||
"""
|
||||
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:
|
||||
"""
|
||||
This read-write attribute specifies the locking behaviour associated
|
||||
with the dequeue operation. It should be one of the values
|
||||
:data:`~oracledb.DEQ_BROWSE`, :data:`~oracledb.DEQ_LOCKED`,
|
||||
:data:`~oracledb.DEQ_REMOVE` (default), or
|
||||
:data:`~oracledb.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:
|
||||
"""
|
||||
This read-write attribute 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:
|
||||
"""
|
||||
This read-write attribute specifies the position of the message that is
|
||||
retrieved. It should be one of the values
|
||||
:data:`~oracledb.DEQ_FIRST_MSG`, :data:`~oracledb.DEQ_NEXT_MSG`
|
||||
(default), or :data:`~oracledb.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:
|
||||
"""
|
||||
This read-write attribute 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:
|
||||
"""
|
||||
This read-write attribute specifies the transactional behavior of the
|
||||
dequeue request. It should be one of the values
|
||||
:data:`~oracledb.DEQ_ON_COMMIT` (default) or
|
||||
:data:`~oracledb.DEQ_IMMEDIATE`. This attribute is ignored when using
|
||||
the :data:`~oracledb.DEQ_BROWSE` mode. Note the value of
|
||||
:attr:`~Connection.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:
|
||||
"""
|
||||
This read-write attribute specifies the time to wait, in seconds, for a
|
||||
message matching the search criteria to become available for dequeuing.
|
||||
One of the values :data:`~oracledb.DEQ_NO_WAIT` or
|
||||
:data:`~oracledb.DEQ_WAIT_FOREVER` can also be used. The default is
|
||||
:data:`~oracledb.DEQ_WAIT_FOREVER`.
|
||||
"""
|
||||
return self._impl.get_wait()
|
||||
|
||||
@wait.setter
|
||||
def wait(self, value: int) -> None:
|
||||
self._impl.set_wait(value)
|
||||
|
||||
|
||||
class EnqOptions(metaclass=BaseMetaClass):
|
||||
@classmethod
|
||||
def _from_impl(cls, impl):
|
||||
options = cls.__new__(cls)
|
||||
options._impl = impl
|
||||
return options
|
||||
|
||||
@property
|
||||
def deliverymode(self) -> int:
|
||||
"""
|
||||
This write-only attribute specifies what type of messages should be
|
||||
enqueued. It should be one of the values
|
||||
:data:`~oracledb.MSG_PERSISTENT` (default) or
|
||||
:data:`~oracledb.MSG_BUFFERED`.
|
||||
|
||||
Note that :data:`~oracledb.MSG_BUFFERED` is not supported for JSON
|
||||
payloads.
|
||||
"""
|
||||
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:
|
||||
"""
|
||||
This read-write attribute 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:
|
||||
"""
|
||||
This read-write attribute specifies the transactional behavior of the
|
||||
enqueue request. It should be one of the values
|
||||
:data:`~oracledb.ENQ_ON_COMMIT` (default) or
|
||||
:data:`~oracledb.ENQ_IMMEDIATE`. Note the value of
|
||||
:attr:`~Connection.autocommit` is ignored.
|
||||
"""
|
||||
return self._impl.get_visibility()
|
||||
|
||||
@visibility.setter
|
||||
def visibility(self, value: int) -> None:
|
||||
self._impl.set_visibility(value)
|
||||
|
||||
|
||||
class MessageProperties(metaclass=BaseMetaClass):
|
||||
_recipients = []
|
||||
|
||||
@classmethod
|
||||
def _from_impl(cls, impl):
|
||||
props = cls.__new__(cls)
|
||||
props._impl = impl
|
||||
return props
|
||||
|
||||
@property
|
||||
def attempts(self) -> int:
|
||||
"""
|
||||
This read-only attribute specifies the number of attempts that have
|
||||
been made to dequeue the message.
|
||||
"""
|
||||
return self._impl.get_num_attempts()
|
||||
|
||||
@property
|
||||
def correlation(self) -> str:
|
||||
"""
|
||||
This read-write attribute 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:
|
||||
"""
|
||||
This read-write attribute specifies the number of seconds to delay an
|
||||
enqueued message. Any integer is acceptable but the constant
|
||||
:data:`~oracledb.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:
|
||||
"""
|
||||
This read-only attribute specifies the type of message that was
|
||||
dequeued. It will be one of the values
|
||||
:data:`~oracledb.MSG_PERSISTENT` or
|
||||
:data:`~oracledb.MSG_BUFFERED`.
|
||||
"""
|
||||
return self._impl.get_delivery_mode()
|
||||
|
||||
@property
|
||||
def enqtime(self) -> datetime.datetime:
|
||||
"""
|
||||
This read-only attribute specifies the time that the message was
|
||||
enqueued.
|
||||
"""
|
||||
return self._impl.get_enq_time()
|
||||
|
||||
@property
|
||||
def exceptionq(self) -> str:
|
||||
"""
|
||||
This read-write attribute 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 :data:`~oracledb.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:
|
||||
"""
|
||||
This read-write attribute 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
|
||||
:data:`~oracledb.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:
|
||||
"""
|
||||
This read-only attribute 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]:
|
||||
"""
|
||||
This read-write attribute 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:
|
||||
"""
|
||||
This read-write attribute 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 0.
|
||||
"""
|
||||
return self._impl.get_priority()
|
||||
|
||||
@priority.setter
|
||||
def priority(self, value: int) -> None:
|
||||
self._impl.set_priority(value)
|
||||
|
||||
@property
|
||||
def recipients(self) -> list[str]:
|
||||
"""
|
||||
This read-write attribute specifies a list of recipient names that 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:
|
||||
"""
|
||||
This read-only attribute specifies the state of the message at the time
|
||||
of the dequeue. It will be one of the values
|
||||
:data:`~oracledb.MSG_WAITING`, :data:`~oracledb.MSG_READY`,
|
||||
:data:`~oracledb.MSG_PROCESSED`, or :data:`~oracledb.MSG_EXPIRED`.
|
||||
"""
|
||||
return self._impl.get_state()
|
||||
112
.venv/lib/python3.9/site-packages/oracledb/arrow_array.py
Normal file
112
.venv/lib/python3.9/site-packages/oracledb/arrow_array.py
Normal file
@@ -0,0 +1,112 @@
|
||||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2025, 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.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# arrow_array.py
|
||||
#
|
||||
# Implement an ArrowArray that is used for efficiently transferring Arrow
|
||||
# array data to other data frame libraries.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
from .arrow_impl import ArrowArrayImpl
|
||||
from .base import BaseMetaClass
|
||||
|
||||
from . import errors
|
||||
|
||||
|
||||
class ArrowArray(metaclass=BaseMetaClass):
|
||||
_impl = None
|
||||
|
||||
def __init__(self):
|
||||
errors._raise_err(errors.ERR_INTERNAL_CREATION_REQUIRED)
|
||||
|
||||
def __len__(self):
|
||||
return self.num_rows
|
||||
|
||||
def __repr__(self):
|
||||
return (
|
||||
f"ArrowArray(name={self.name}, "
|
||||
f"len={self.num_rows}, "
|
||||
f"type={self.dtype})"
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return self.__repr__()
|
||||
|
||||
@classmethod
|
||||
def _from_arrow(cls, obj):
|
||||
array = cls.__new__(cls)
|
||||
array._impl = ArrowArrayImpl.from_arrow_array(obj)
|
||||
return array
|
||||
|
||||
@classmethod
|
||||
def _from_impl(cls, impl):
|
||||
array = cls.__new__(cls)
|
||||
array._impl = impl
|
||||
return array
|
||||
|
||||
def __arrow_c_array__(self, requested_schema=None):
|
||||
"""
|
||||
Returns a tuple containing an ArrowSchema and ArrowArray PyCapsules.
|
||||
"""
|
||||
if requested_schema is not None:
|
||||
raise NotImplementedError("requested_schema")
|
||||
return (
|
||||
self._impl.get_schema_capsule(),
|
||||
self._impl.get_array_capsule(),
|
||||
)
|
||||
|
||||
def __arrow_c_schema__(self):
|
||||
"""
|
||||
Returns an ArrowSchema PyCapsule.
|
||||
"""
|
||||
return self._impl.get_schema_capsule()
|
||||
|
||||
@property
|
||||
def dtype(self) -> str:
|
||||
"""
|
||||
Returns the data type associated with the array.
|
||||
"""
|
||||
return self._impl.get_data_type()
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
"""
|
||||
Returns the name associated with the array.
|
||||
"""
|
||||
return self._impl.get_name()
|
||||
|
||||
@property
|
||||
def null_count(self) -> int:
|
||||
"""
|
||||
Returns the number of rows that contain null values.
|
||||
"""
|
||||
return self._impl.get_null_count()
|
||||
|
||||
@property
|
||||
def num_rows(self) -> int:
|
||||
"""
|
||||
Returns the number of rows in the array.
|
||||
"""
|
||||
return self._impl.get_num_rows()
|
||||
Binary file not shown.
48
.venv/lib/python3.9/site-packages/oracledb/base.py
Normal file
48
.venv/lib/python3.9/site-packages/oracledb/base.py
Normal file
@@ -0,0 +1,48 @@
|
||||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2025, 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.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# base.py
|
||||
#
|
||||
# Contains base classes and methods that have no internal dependencies.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
from . import __name__ as MODULE_NAME
|
||||
|
||||
|
||||
# metaclass used by all oracledb classes; currently this only ensures that when
|
||||
# the class is displayed it only shows the overall module name instead of any
|
||||
# subpackage names
|
||||
class BaseMetaClass(type):
|
||||
|
||||
def __new__(cls, name, bases, attrs):
|
||||
module_name = attrs["__module__"]
|
||||
qual_name = attrs["__qualname__"]
|
||||
if module_name.startswith(MODULE_NAME):
|
||||
module_name = MODULE_NAME
|
||||
attrs["_public_name"] = f"{module_name}.{qual_name}"
|
||||
return super().__new__(cls, name, bases, attrs)
|
||||
|
||||
def __repr__(cls):
|
||||
return f"<class '{cls._public_name}'>"
|
||||
Binary file not shown.
102
.venv/lib/python3.9/site-packages/oracledb/builtin_hooks.py
Normal file
102
.venv/lib/python3.9/site-packages/oracledb/builtin_hooks.py
Normal file
@@ -0,0 +1,102 @@
|
||||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2024, 2025, 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.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# config_provider.py
|
||||
#
|
||||
# Contains the built-in config providers.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
import base64
|
||||
import json
|
||||
import os
|
||||
import urllib.parse
|
||||
import warnings
|
||||
|
||||
from . import errors
|
||||
from .utils import register_password_type, register_protocol
|
||||
|
||||
|
||||
def config_provider_file_hook(protocol, protocol_arg, connect_params):
|
||||
"""
|
||||
Hook for "config-file://". The protocol_arg is expected to be the name of a
|
||||
file containing one or more configurations. An optional "key" parameter is
|
||||
allowed which will choose a configuration from a set of configurations
|
||||
stored in the file.
|
||||
"""
|
||||
pos = protocol_arg.find("?")
|
||||
if pos < 0:
|
||||
file_name = protocol_arg
|
||||
key = None
|
||||
else:
|
||||
file_name = protocol_arg[:pos]
|
||||
args = urllib.parse.parse_qs(protocol_arg[pos + 1 :])
|
||||
key = args.get("key")
|
||||
if key is not None:
|
||||
key = key[0]
|
||||
if not os.path.isabs(file_name):
|
||||
if connect_params.config_dir is None:
|
||||
errors._raise_err(errors.ERR_NO_CONFIG_DIR)
|
||||
file_name = os.path.join(connect_params.config_dir, file_name)
|
||||
config = json.load(open(file_name))
|
||||
if key is not None:
|
||||
config = config[key]
|
||||
connect_params.set_from_config(config)
|
||||
|
||||
|
||||
register_protocol("config-file", config_provider_file_hook)
|
||||
|
||||
|
||||
def ldap_hook(protocol, arg, params):
|
||||
"""
|
||||
Default hook for LDAP which simply points the user to the documentation
|
||||
which explains how they can write their own hook for LDAP.
|
||||
This hook is needed for python-oracledb Thin mode,or when
|
||||
defaults.thick_mode_dsn_passthrough is False in Thick mode.
|
||||
"""
|
||||
doc_url = (
|
||||
"https://python-oracledb.readthedocs.io/en/latest"
|
||||
"/user_guide/connection_handling.html#ldap-directory-naming"
|
||||
)
|
||||
message = (
|
||||
f"To use an LDAP URL in python-oracledb, "
|
||||
f"register an LDAP resolution function as shown in {doc_url}"
|
||||
)
|
||||
raise Exception(message)
|
||||
|
||||
|
||||
register_protocol("ldap", ldap_hook)
|
||||
register_protocol("ldaps", ldap_hook)
|
||||
|
||||
|
||||
def password_type_base64_hook(args):
|
||||
"""
|
||||
Hook for password type "base64". The key "value" in the supplied args is
|
||||
expected to be a base64-encoded string.
|
||||
"""
|
||||
warnings.warn("base64 encoded passwords are insecure")
|
||||
return base64.b64decode(args["value"].encode()).decode()
|
||||
|
||||
|
||||
register_password_type("base64", password_type_base64_hook)
|
||||
1266
.venv/lib/python3.9/site-packages/oracledb/connect_params.py
Normal file
1266
.venv/lib/python3.9/site-packages/oracledb/connect_params.py
Normal file
File diff suppressed because it is too large
Load Diff
3320
.venv/lib/python3.9/site-packages/oracledb/connection.py
Normal file
3320
.venv/lib/python3.9/site-packages/oracledb/connection.py
Normal file
File diff suppressed because it is too large
Load Diff
127
.venv/lib/python3.9/site-packages/oracledb/constants.py
Normal file
127
.venv/lib/python3.9/site-packages/oracledb/constants.py
Normal file
@@ -0,0 +1,127 @@
|
||||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2020, 2025, 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.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# 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_end()
|
||||
TPC_END_NORMAL = 0
|
||||
TPC_END_SUSPEND = 0x00100000
|
||||
|
||||
# vector metadata flags
|
||||
VECTOR_META_FLAG_FLEXIBLE_DIM = 0x01
|
||||
VECTOR_META_FLAG_SPARSE_VECTOR = 0x02
|
||||
100
.venv/lib/python3.9/site-packages/oracledb/constructors.py
Normal file
100
.venv/lib/python3.9/site-packages/oracledb/constructors.py
Normal file
@@ -0,0 +1,100 @@
|
||||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2020, 2025, 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 typing import Any
|
||||
|
||||
from . import errors
|
||||
|
||||
|
||||
def Binary(value: Any) -> bytes:
|
||||
"""
|
||||
Constructs an object holding a binary (long) string value.
|
||||
"""
|
||||
return bytes(value)
|
||||
|
||||
|
||||
def Date(year: int, month: int, day: int) -> datetime.date:
|
||||
"""
|
||||
Constructs an object holding a date value.
|
||||
"""
|
||||
return datetime.date(year, month, day)
|
||||
|
||||
|
||||
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 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 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 Timestamp(
|
||||
year: int,
|
||||
month: int,
|
||||
day: int,
|
||||
hour: int = 0,
|
||||
minute: int = 0,
|
||||
second: int = 0,
|
||||
) -> datetime.datetime:
|
||||
"""
|
||||
Constructs an object holding a time stamp value.
|
||||
"""
|
||||
return datetime.datetime(year, month, day, hour, minute, second)
|
||||
|
||||
|
||||
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)
|
||||
1373
.venv/lib/python3.9/site-packages/oracledb/cursor.py
Normal file
1373
.venv/lib/python3.9/site-packages/oracledb/cursor.py
Normal file
File diff suppressed because it is too large
Load Diff
122
.venv/lib/python3.9/site-packages/oracledb/dataframe.py
Normal file
122
.venv/lib/python3.9/site-packages/oracledb/dataframe.py
Normal file
@@ -0,0 +1,122 @@
|
||||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2025, 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.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# dataframe.py
|
||||
#
|
||||
# Implement a data frame that can be used for efficiently transferring Arrow
|
||||
# array data to other data frame libraries.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
from .arrow_array import ArrowArray
|
||||
from .arrow_impl import DataFrameImpl
|
||||
from .base import BaseMetaClass
|
||||
from . import errors
|
||||
|
||||
|
||||
class DataFrame(metaclass=BaseMetaClass):
|
||||
_impl = None
|
||||
|
||||
def __init__(self):
|
||||
errors._raise_err(errors.ERR_INTERNAL_CREATION_REQUIRED)
|
||||
|
||||
@classmethod
|
||||
def _from_arrow(cls, obj):
|
||||
df = cls.__new__(cls)
|
||||
df._initialize(DataFrameImpl.from_arrow_stream(obj))
|
||||
return df
|
||||
|
||||
@classmethod
|
||||
def _from_impl(cls, impl):
|
||||
df = cls.__new__(cls)
|
||||
df._initialize(impl)
|
||||
return df
|
||||
|
||||
def _initialize(self, impl):
|
||||
"""
|
||||
Initializes the object given the implementation.
|
||||
"""
|
||||
self._impl = impl
|
||||
self._arrays = [ArrowArray._from_impl(a) for a in impl.get_arrays()]
|
||||
self._arrays_by_name = {}
|
||||
for array in self._arrays:
|
||||
self._arrays_by_name[array.name] = array
|
||||
|
||||
def __arrow_c_stream__(self, requested_schema=None):
|
||||
"""
|
||||
Returns the ArrowArrayStream PyCapsule which allows direct conversion
|
||||
to foreign data frames that support this interface.
|
||||
"""
|
||||
if requested_schema is not None:
|
||||
raise NotImplementedError("requested_schema")
|
||||
return self._impl.get_stream_capsule()
|
||||
|
||||
def column_arrays(self) -> list[ArrowArray]:
|
||||
"""
|
||||
Returns a list of ArrowArray objects, each containing a select list
|
||||
column.
|
||||
"""
|
||||
return self._arrays
|
||||
|
||||
def column_names(self) -> list[str]:
|
||||
"""
|
||||
Returns a list of the column names in the data frame.
|
||||
"""
|
||||
return [a.name for a in self._arrays]
|
||||
|
||||
def get_column(self, i: int) -> ArrowArray:
|
||||
"""
|
||||
Returns an :ref:`ArrowArray <oraclearrowarrayobj>` object for the
|
||||
column at the given index ``i``. If the index is out of range, an
|
||||
IndexError exception is raised.
|
||||
"""
|
||||
if i < 0 or i >= self.num_columns():
|
||||
raise IndexError(
|
||||
f"Column index {i} is out of bounds for "
|
||||
f"DataFrame with {self.num_columns()} columns"
|
||||
)
|
||||
return self._arrays[i]
|
||||
|
||||
def get_column_by_name(self, name: str) -> ArrowArray:
|
||||
"""
|
||||
Returns an :ref:`ArrowArray <oraclearrowarrayobj>` object for the
|
||||
column with the given name ``name``. If the column name is not found,
|
||||
a KeyError exception is raised.
|
||||
"""
|
||||
try:
|
||||
return self._arrays_by_name[name]
|
||||
except KeyError:
|
||||
raise KeyError(f"Column {name} not found in DataFrame")
|
||||
|
||||
def num_columns(self) -> int:
|
||||
"""
|
||||
Returns the number of columns in the data frame.
|
||||
"""
|
||||
return len(self._arrays)
|
||||
|
||||
def num_rows(self) -> int:
|
||||
"""
|
||||
Returns the number of rows in the data frame.
|
||||
"""
|
||||
return len(self._arrays[0])
|
||||
392
.venv/lib/python3.9/site-packages/oracledb/dbobject.py
Normal file
392
.venv/lib/python3.9/site-packages/oracledb/dbobject.py
Normal file
@@ -0,0 +1,392 @@
|
||||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2021, 2025, 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 .base import BaseMetaClass
|
||||
from .base_impl import DbType
|
||||
|
||||
|
||||
class DbObject(metaclass=BaseMetaClass):
|
||||
|
||||
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 __iter__(self):
|
||||
self._ensure_is_collection()
|
||||
ix = self._impl.get_first_index()
|
||||
while ix is not None:
|
||||
yield self._impl.get_element_by_index(ix)
|
||||
ix = self._impl.get_next_index(ix)
|
||||
|
||||
def __repr__(self):
|
||||
cls_name = self.__class__._public_name
|
||||
return f"<{cls_name} {self.type._get_full_name()} at {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:
|
||||
"""
|
||||
Appends 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._ensure_is_collection()
|
||||
self._impl.append(element)
|
||||
|
||||
def asdict(self) -> dict:
|
||||
"""
|
||||
Returns a dictionary where the collection’s 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:
|
||||
"""
|
||||
Returns a list of each of the collection’s elements in index order.
|
||||
"""
|
||||
return list(self)
|
||||
|
||||
def copy(self) -> "DbObject":
|
||||
"""
|
||||
Creates a copy of the object and returns 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:
|
||||
"""
|
||||
Appends 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:
|
||||
"""
|
||||
Returns 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:
|
||||
"""
|
||||
Returns 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:
|
||||
"""
|
||||
Returns 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:
|
||||
"""
|
||||
Returns 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:
|
||||
"""
|
||||
Returns 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:
|
||||
"""
|
||||
Sets 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:
|
||||
"""
|
||||
Returns the number of elements in the collection.
|
||||
"""
|
||||
self._ensure_is_collection()
|
||||
return self._impl.get_size()
|
||||
|
||||
def trim(self, num: int) -> None:
|
||||
"""
|
||||
Removes the specified number of elements from the end of the
|
||||
collection.
|
||||
"""
|
||||
self._ensure_is_collection()
|
||||
self._impl.trim(num)
|
||||
|
||||
@property
|
||||
def type(self) -> "DbObjectType":
|
||||
"""
|
||||
This read-only attribute arturns 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(metaclass=BaseMetaClass):
|
||||
|
||||
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 max_size(self) -> Union[int, None]:
|
||||
"""
|
||||
This read-only attribute returns the maximum size (in bytes) of the
|
||||
attribute when the attribute's type is one of
|
||||
DB_TYPE_RAW, DB_TYPE_CHAR, DB_TYPE_NCHAR, DB_TYPE_VARCHAR and
|
||||
DB_TYPE_NVARCHAR. For all other types, the value returned is None.
|
||||
"""
|
||||
if self._impl.max_size:
|
||||
return self._impl.max_size
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
"""
|
||||
This read-only attribute returns the name of the attribute.
|
||||
"""
|
||||
return self._impl.name
|
||||
|
||||
@property
|
||||
def precision(self) -> Union[int, None]:
|
||||
"""
|
||||
This read-only attribute returns the precision of the attribute when
|
||||
the attribute's type is DB_TYPE_NUMBER. For all other types, the value
|
||||
returned is None.
|
||||
"""
|
||||
if self._impl.precision or self._impl.scale:
|
||||
return self._impl.precision
|
||||
|
||||
@property
|
||||
def scale(self) -> Union[int, None]:
|
||||
"""
|
||||
This read-only attribute returns the scale of the attribute when the
|
||||
attribute's type is DB_TYPE_NUMBER. For all other types, the value
|
||||
returned is None.
|
||||
"""
|
||||
if self._impl.precision or self._impl.scale:
|
||||
return self._impl.scale
|
||||
|
||||
@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(metaclass=BaseMetaClass):
|
||||
|
||||
def __call__(self, value: Sequence = None) -> DbObject:
|
||||
"""
|
||||
The object type may be called directly and serves as an alternative way
|
||||
of calling :meth:`~DbObjectType.newobject()`.
|
||||
"""
|
||||
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["DbObjectAttr"]:
|
||||
"""
|
||||
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_metadata.objtype is not None:
|
||||
typ_impl = self._impl.element_metadata.objtype
|
||||
self._element_type = DbObjectType._from_impl(typ_impl)
|
||||
else:
|
||||
self._element_type = self._impl.element_metadata.dbtype
|
||||
return self._element_type
|
||||
|
||||
def newobject(self, value: Sequence = None) -> DbObject:
|
||||
"""
|
||||
Returns 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
|
||||
329
.venv/lib/python3.9/site-packages/oracledb/defaults.py
Normal file
329
.venv/lib/python3.9/site-packages/oracledb/defaults.py
Normal file
@@ -0,0 +1,329 @@
|
||||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2021, 2025, 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.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
from . import base_impl
|
||||
from . import errors
|
||||
from .base import BaseMetaClass
|
||||
|
||||
|
||||
class Defaults(metaclass=BaseMetaClass):
|
||||
"""
|
||||
A singleton Defaults object contains attributes to adjust default
|
||||
behaviors of python-oracledb. It is accessed using the :data:`defaults`
|
||||
attribute of the imported module.
|
||||
"""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self._impl = base_impl.DEFAULTS
|
||||
|
||||
@property
|
||||
def arraysize(self) -> int:
|
||||
"""
|
||||
This read-write attribute specifies the default arraysize to use when
|
||||
cursors are created.
|
||||
|
||||
It is an attribute for tuning the performance of fetching rows from
|
||||
Oracle Database. It does not affect data insertion.
|
||||
|
||||
This value is the default for :attr:`Cursor.arraysize` and
|
||||
:attr:`AsyncCursor.arraysize`.
|
||||
|
||||
This attribute has an initial value of *100*.
|
||||
"""
|
||||
return self._impl.arraysize
|
||||
|
||||
@arraysize.setter
|
||||
def arraysize(self, value: int):
|
||||
self._impl.arraysize = value
|
||||
|
||||
@property
|
||||
def config_dir(self) -> str:
|
||||
"""
|
||||
This read-write attribute specifies the directory in which the optional
|
||||
configuration file ``tnsnames.ora`` will be read in python-oracledb
|
||||
Thin mode. It is also used in Thick mode if
|
||||
:attr:`Defaults.thick_mode_dsn_passthrough` is *False*.
|
||||
|
||||
At time of ``import oracledb`` the value of
|
||||
``oracledb.defaults.config_dir`` will be set to (first one wins):
|
||||
|
||||
- the value of ``$TNS_ADMIN``, if ``TNS_ADMIN`` is set.
|
||||
|
||||
- ``$ORACLE_HOME/network/admin``, if ``$ORACLE_HOME`` is set.
|
||||
|
||||
Otherwise, ``oracledb.defaults.config_dir`` will not be set.
|
||||
|
||||
At completion of a call to :meth:`oracledb.init_oracle_client()` in
|
||||
python-oracledb Thick mode, the value of ``config_dir`` may get
|
||||
changed.
|
||||
"""
|
||||
return self._impl.config_dir
|
||||
|
||||
@config_dir.setter
|
||||
def config_dir(self, value: str):
|
||||
self._impl.config_dir = value
|
||||
|
||||
@property
|
||||
def fetch_lobs(self) -> bool:
|
||||
"""
|
||||
This read-write attribute specifies whether queries that contain LOBs
|
||||
should return LOB objects or their contents instead.
|
||||
|
||||
When the value of this attribute is *True*, then queries to LOB columns
|
||||
return LOB locators. When the value of this attribute is *False*, then
|
||||
CLOBs and NCLOBs are fetched as strings, and BLOBs are fetched as
|
||||
bytes. If LOBs are larger than 1 GB, then this attribute should be set
|
||||
to *True* and the LOBs should be streamed.
|
||||
|
||||
The value of ``oracledb.defaults.fetch_lobs`` does not affect LOBs
|
||||
returned as OUT binds.
|
||||
|
||||
The value of ``fetch_lobs`` can be overridden at statement execution by
|
||||
passing an equivalent parameter.
|
||||
|
||||
An output type handler such as the one previously required in the
|
||||
obsolete cx_Oracle driver can alternatively be used to adjust the
|
||||
returned type. If a type handler exists and returns a variable (that
|
||||
is, `cursor.var(...)`), then that return variable is used. If the type
|
||||
handler returns *None*, then the value of
|
||||
``oracledb.defaults.fetch_lobs`` is used.
|
||||
|
||||
This attribute has an initial value of *True*.
|
||||
"""
|
||||
return self._impl.fetch_lobs
|
||||
|
||||
@fetch_lobs.setter
|
||||
def fetch_lobs(self, value: bool):
|
||||
self._impl.fetch_lobs = value
|
||||
|
||||
@property
|
||||
def fetch_decimals(self) -> bool:
|
||||
"""
|
||||
This read-write attribute specifies whether queries that contain
|
||||
numbers should be fetched as Python decimal.Decimal objects or floating
|
||||
point numbers. This can help avoid issues with converting numbers from
|
||||
Oracle Database's decimal format to Python's binary format.
|
||||
|
||||
The value of ``fetch_decimals`` can be overridden at statement
|
||||
execution by passing an equivalent parameter.
|
||||
|
||||
An output type handler such as previously required in the obsolete
|
||||
cx_Oracle driver can alternatively be used to adjust the returned type.
|
||||
If a type handler exists and returns a variable (that is,
|
||||
``cursor.var(...)``), then that return variable is used. If the type
|
||||
handler returns *None*, then the value of
|
||||
``oracledb.defaults.fetch_decimals`` is used to determine whether to
|
||||
return ``decimal.Decimal`` values.
|
||||
|
||||
This attribute has an initial value of *False*.
|
||||
"""
|
||||
return self._impl.fetch_decimals
|
||||
|
||||
@fetch_decimals.setter
|
||||
def fetch_decimals(self, value: bool):
|
||||
self._impl.fetch_decimals = value
|
||||
|
||||
@property
|
||||
def prefetchrows(self) -> int:
|
||||
"""
|
||||
This read-write attribute specifies the default number of rows to
|
||||
prefetch when cursors are executed.
|
||||
|
||||
This is an attribute for tuning the performance of fetching rows from
|
||||
Oracle Database. It does not affect data insertion.
|
||||
|
||||
This value is the default for :attr:`Cursor.prefetchrows` and
|
||||
:attr:`AsyncCursor.prefetchrows`.
|
||||
|
||||
This attribute is ignored when using :meth:`Connection.fetch_df_all()`
|
||||
or :meth:`Connection.fetch_df_batches()` since these methods always set
|
||||
the internal prefetch size to their relevant ``arraysize`` or ``size``
|
||||
parameter value.
|
||||
|
||||
This attribute has an initial value of *2*.
|
||||
"""
|
||||
return self._impl.prefetchrows
|
||||
|
||||
@prefetchrows.setter
|
||||
def prefetchrows(self, value: int):
|
||||
self._impl.prefetchrows = value
|
||||
|
||||
@property
|
||||
def stmtcachesize(self) -> int:
|
||||
"""
|
||||
This read-write attribute specifies the default size of the statement
|
||||
cache.
|
||||
|
||||
This is an attribute for tuning statement execution performance when a
|
||||
statement is executed more than once.
|
||||
|
||||
This value is the default for :attr:`Connection.stmtcachesize`,
|
||||
:attr:`ConnectionPool.stmtcachesize`,
|
||||
:attr:`AsyncConnection.stmtcachesize`, and
|
||||
:attr:`AsyncConnectionPool.stmtcachesize`.
|
||||
|
||||
This attribute has an initial value of *20*.
|
||||
"""
|
||||
return self._impl.stmtcachesize
|
||||
|
||||
@stmtcachesize.setter
|
||||
def stmtcachesize(self, value: int):
|
||||
self._impl.stmtcachesize = value
|
||||
|
||||
@property
|
||||
def program(self) -> str:
|
||||
"""
|
||||
This read-write attribute is a string recorded by Oracle Database
|
||||
as the program from which the connection originates. This is the value
|
||||
used in the PROGRAM column of the V$SESSION view.
|
||||
|
||||
This attribute has an initial value that is populated by
|
||||
`sys.executable <https://docs.python.org/3/library/sys.html#
|
||||
sys.executable>`__.
|
||||
|
||||
This attribute is only used in python-oracledb Thin mode.
|
||||
"""
|
||||
return self._impl.program
|
||||
|
||||
@program.setter
|
||||
def program(self, value: str):
|
||||
if base_impl.sanitize(value) != value:
|
||||
errors._raise_err(errors.ERR_INVALID_NETWORK_NAME, name="program")
|
||||
self._impl.program = value
|
||||
|
||||
@property
|
||||
def machine(self) -> str:
|
||||
"""
|
||||
This read-write attribute is a string recorded by Oracle Database as
|
||||
the name of machine from which the connection originates. This is the
|
||||
value used in the MACHINE column of the V$SESSION view.
|
||||
|
||||
This attribute takes the host name where the application is running as
|
||||
its initial value.
|
||||
|
||||
This attribute is only used in python-oracledb Thin mode.
|
||||
"""
|
||||
return self._impl.machine
|
||||
|
||||
@machine.setter
|
||||
def machine(self, value: str):
|
||||
if base_impl.sanitize(value) != value:
|
||||
errors._raise_err(errors.ERR_INVALID_NETWORK_NAME, name="machine")
|
||||
self._impl.machine = value
|
||||
|
||||
@property
|
||||
def terminal(self) -> str:
|
||||
"""
|
||||
This read-write attribute specifies the terminal identifier from which
|
||||
the connection originates. This is the value used in the TERMINAL
|
||||
column of the V$SESSION view.
|
||||
|
||||
This attribute has an initial value of "unknown".
|
||||
|
||||
This attribute is only used in python-oracledb Thin mode.
|
||||
"""
|
||||
return self._impl.terminal
|
||||
|
||||
@terminal.setter
|
||||
def terminal(self, value: str):
|
||||
self._impl.terminal = value
|
||||
|
||||
@property
|
||||
def osuser(self) -> str:
|
||||
"""
|
||||
This read-write attribute is a string recorded by Oracle Database
|
||||
as the operating system user who originated the connection. This is the
|
||||
value used in the OSUSER column of the V$SESSION view.
|
||||
|
||||
This attribute takes the login name of the user as its initial value.
|
||||
|
||||
This attribute is only used in python-oracledb Thin mode.
|
||||
"""
|
||||
return self._impl.osuser
|
||||
|
||||
@osuser.setter
|
||||
def osuser(self, value: str):
|
||||
if base_impl.sanitize(value) != value:
|
||||
errors._raise_err(errors.ERR_INVALID_NETWORK_NAME, name="osuser")
|
||||
self._impl.osuser = value
|
||||
|
||||
@property
|
||||
def driver_name(self) -> str:
|
||||
"""
|
||||
This read-write attribute is a string recorded by Oracle Database
|
||||
as the name of the driver which originated the connection. This is the
|
||||
value used in the CLIENT_DRIVER column of the V$SESSION_CONNECT_INFO
|
||||
view.
|
||||
|
||||
This attribute has an initial value of *None*. It is used as required
|
||||
in python-oracledb Thick and Thin mode.
|
||||
|
||||
In python-oracledb Thick mode, this attribute is used if the
|
||||
``driver_name`` parameter is not specified in
|
||||
:meth:`oracledb.init_oracle_client()`. In Thin mode, this attribute is
|
||||
used if the ``driver_name`` parameter is not specified in
|
||||
:meth:`oracledb.connect()`, :meth:`oracledb.connect_async()`,
|
||||
:meth:`oracledb.create_pool()`, or
|
||||
:meth:`oracledb.create_pool_async()`. If the value of this attribute is
|
||||
*None*, the value set when connecting in python-oracledb Thick mode is
|
||||
like "python-oracledb thk : <version>" and in Thin mode is like
|
||||
"python-oracledb thn : <version>".
|
||||
"""
|
||||
return self._impl.driver_name
|
||||
|
||||
@driver_name.setter
|
||||
def driver_name(self, value: str):
|
||||
self._impl.driver_name = value
|
||||
|
||||
@property
|
||||
def thick_mode_dsn_passthrough(self) -> bool:
|
||||
"""
|
||||
This read-write attribute determines whether
|
||||
connection strings passed as the ``dsn`` parameter to
|
||||
:meth:`oracledb.connect()`, :meth:`oracledb.create_pool()`,
|
||||
:meth:`oracledb.connect_async()`, and
|
||||
:meth:`oracledb.create_pool_async()` in python-oracledb Thick mode will
|
||||
be parsed by Oracle Client libraries or by python-oracledb itself.
|
||||
|
||||
The value of ``thick_mode_dsn_passthrough`` is ignored in
|
||||
python-oracledb Thin mode, which always parses all connect strings
|
||||
(including reading a tnsnames.ora file, if required).
|
||||
|
||||
This attribute has an initial value of *True*.
|
||||
"""
|
||||
return self._impl.thick_mode_dsn_passthrough
|
||||
|
||||
@thick_mode_dsn_passthrough.setter
|
||||
def thick_mode_dsn_passthrough(self, value: str):
|
||||
self._impl.thick_mode_dsn_passthrough = value
|
||||
|
||||
|
||||
defaults = Defaults()
|
||||
140
.venv/lib/python3.9/site-packages/oracledb/driver_mode.py
Normal file
140
.venv/lib/python3.9/site-packages/oracledb/driver_mode.py
Normal file
@@ -0,0 +1,140 @@
|
||||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2021, 2025 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.
|
||||
"""
|
||||
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
|
||||
):
|
||||
if requested_thin_mode:
|
||||
errors._raise_err(errors.ERR_THICK_MODE_ENABLED)
|
||||
else:
|
||||
errors._raise_err(errors.ERR_THIN_CONNECTION_ALREADY_CREATED)
|
||||
return manager
|
||||
|
||||
|
||||
def is_thin_mode() -> bool:
|
||||
"""
|
||||
Returns a boolean indicating if python-oracledb is in Thin mode.
|
||||
|
||||
Immediately after python-oracledb is imported, this function will return
|
||||
*True* indicating that python-oracledb defaults to Thin mode. If a call to
|
||||
:func:`oracledb.init_oracle_client()` returns 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, or a successful call to ``oracledb.init_oracle_client()``
|
||||
is made, or :meth:`oracledb.enable_thin_mode()` is called, then
|
||||
python-oracledb’s mode is fixed and the value returned by
|
||||
``is_thin_mode()`` will never change for the lifetime of the process.
|
||||
|
||||
The attribute :attr:`Connection.thin` can be used to check a connection's
|
||||
mode. The attribute :attr:`ConnectionPool.thin` can be used to check a
|
||||
pool's mode.
|
||||
"""
|
||||
if manager.thin_mode is not None:
|
||||
return manager.thin_mode
|
||||
return True
|
||||
81
.venv/lib/python3.9/site-packages/oracledb/dsn.py
Normal file
81
.venv/lib/python3.9/site-packages/oracledb/dsn.py
Normal file
@@ -0,0 +1,81 @@
|
||||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2021, 2025, 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:
|
||||
"""
|
||||
Returns a string suitable for use as the ``dsn`` parameter for
|
||||
:meth:`~oracledb.connect()`. This string is identical to the strings that
|
||||
are defined by the Oracle names server or defined in the ``tnsnames.ora``
|
||||
file.
|
||||
"""
|
||||
connect_data_parts = []
|
||||
_check_arg("host", host)
|
||||
if service_name is not None:
|
||||
_check_arg("service_name", service_name)
|
||||
connect_data_parts.append(f"(SERVICE_NAME={service_name})")
|
||||
elif sid is not None:
|
||||
_check_arg("sid", sid)
|
||||
connect_data_parts.append(f"(SID={sid})")
|
||||
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}))"
|
||||
)
|
||||
76
.venv/lib/python3.9/site-packages/oracledb/enums.py
Normal file
76
.venv/lib/python3.9/site-packages/oracledb/enums.py
Normal file
@@ -0,0 +1,76 @@
|
||||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2024, 2025, 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.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# enums.py
|
||||
#
|
||||
# Contains the enumerations of various constants used throughout the package.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
import enum
|
||||
|
||||
from . import base_impl
|
||||
|
||||
|
||||
class AuthMode(enum.IntFlag):
|
||||
DEFAULT = base_impl.AUTH_MODE_DEFAULT
|
||||
PRELIM = base_impl.AUTH_MODE_PRELIM
|
||||
SYSASM = base_impl.AUTH_MODE_SYSASM
|
||||
SYSBKP = base_impl.AUTH_MODE_SYSBKP
|
||||
SYSDBA = base_impl.AUTH_MODE_SYSDBA
|
||||
SYSDGD = base_impl.AUTH_MODE_SYSDGD
|
||||
SYSKMT = base_impl.AUTH_MODE_SYSKMT
|
||||
SYSOPER = base_impl.AUTH_MODE_SYSOPER
|
||||
SYSRAC = base_impl.AUTH_MODE_SYSRAC
|
||||
|
||||
|
||||
class PipelineOpType(enum.IntFlag):
|
||||
CALL_FUNC = base_impl.PIPELINE_OP_TYPE_CALL_FUNC
|
||||
CALL_PROC = base_impl.PIPELINE_OP_TYPE_CALL_PROC
|
||||
COMMIT = base_impl.PIPELINE_OP_TYPE_COMMIT
|
||||
EXECUTE = base_impl.PIPELINE_OP_TYPE_EXECUTE
|
||||
EXECUTE_MANY = base_impl.PIPELINE_OP_TYPE_EXECUTE_MANY
|
||||
FETCH_ALL = base_impl.PIPELINE_OP_TYPE_FETCH_ALL
|
||||
FETCH_MANY = base_impl.PIPELINE_OP_TYPE_FETCH_MANY
|
||||
FETCH_ONE = base_impl.PIPELINE_OP_TYPE_FETCH_ONE
|
||||
|
||||
|
||||
class PoolGetMode(enum.IntEnum):
|
||||
FORCEGET = base_impl.POOL_GETMODE_FORCEGET
|
||||
NOWAIT = base_impl.POOL_GETMODE_NOWAIT
|
||||
TIMEDWAIT = base_impl.POOL_GETMODE_TIMEDWAIT
|
||||
WAIT = base_impl.POOL_GETMODE_WAIT
|
||||
|
||||
|
||||
class Purity(enum.IntEnum):
|
||||
DEFAULT = base_impl.PURITY_DEFAULT
|
||||
NEW = base_impl.PURITY_NEW
|
||||
SELF = base_impl.PURITY_SELF
|
||||
|
||||
|
||||
class VectorFormat(enum.IntEnum):
|
||||
BINARY = base_impl.VECTOR_FORMAT_BINARY
|
||||
FLOAT32 = base_impl.VECTOR_FORMAT_FLOAT32
|
||||
FLOAT64 = base_impl.VECTOR_FORMAT_FLOAT64
|
||||
INT8 = base_impl.VECTOR_FORMAT_INT8
|
||||
1019
.venv/lib/python3.9/site-packages/oracledb/errors.py
Normal file
1019
.venv/lib/python3.9/site-packages/oracledb/errors.py
Normal file
File diff suppressed because it is too large
Load Diff
125
.venv/lib/python3.9/site-packages/oracledb/exceptions.py
Normal file
125
.venv/lib/python3.9/site-packages/oracledb/exceptions.py
Normal file
@@ -0,0 +1,125 @@
|
||||
# -----------------------------------------------------------------------------
|
||||
# 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):
|
||||
"""
|
||||
Exception raised for warnings.
|
||||
|
||||
Exception messages of this class will have the prefix DPY and an error
|
||||
number in the range 9000 - 9999.
|
||||
"""
|
||||
|
||||
|
||||
class Error(Exception):
|
||||
"""
|
||||
Exception that is the base class of all other exceptions defined by
|
||||
python-oracledb.
|
||||
"""
|
||||
|
||||
|
||||
class DatabaseError(Error):
|
||||
"""
|
||||
Exception raised for errors that are related to the database. It is a
|
||||
subclass of Error.
|
||||
|
||||
Exception messages of this class will have the prefix DPY and an error
|
||||
number in the range 4000 - 4999.
|
||||
"""
|
||||
|
||||
|
||||
class DataError(DatabaseError):
|
||||
"""
|
||||
Exception raised for errors that are due to problems with the processed
|
||||
data. It is a subclass of DatabaseError.
|
||||
|
||||
Exception messages of this class are generated by the database and will
|
||||
have a prefix such as ORA.
|
||||
"""
|
||||
|
||||
|
||||
class IntegrityError(DatabaseError):
|
||||
"""
|
||||
Exception raised when the relational integrity of the database is affected.
|
||||
It is a subclass of DatabaseError.
|
||||
|
||||
Exception messages of this class are generated by the database and will
|
||||
have a prefix such as ORA.
|
||||
"""
|
||||
|
||||
|
||||
class InterfaceError(Error):
|
||||
"""
|
||||
Exception raised for errors that are related to the database interface
|
||||
rather than the database itself. It is a subclass of Error.
|
||||
|
||||
Exception messages of this class will have the prefix DPY and an error
|
||||
number in the range 1000 - 1999.
|
||||
"""
|
||||
|
||||
|
||||
class InternalError(DatabaseError):
|
||||
"""
|
||||
Exception raised when the database encounters an internal error. It is a
|
||||
subclass of DatabaseError.
|
||||
|
||||
Exception messages of this class will have the prefix DPY and an error
|
||||
number in the range 5000 - 5999.
|
||||
"""
|
||||
|
||||
|
||||
class NotSupportedError(DatabaseError):
|
||||
"""
|
||||
Exception raised when a method or database API was used which is not
|
||||
supported by the database. It is a subclass of DatabaseError.
|
||||
|
||||
Exception messages of this class will have the prefix DPY and an error
|
||||
number in the range 3000 - 3999.
|
||||
"""
|
||||
|
||||
|
||||
class OperationalError(DatabaseError):
|
||||
"""
|
||||
Exception raised for errors that are related to the operation of the
|
||||
database but are not necessarily under the control of the programmer. It is
|
||||
a subclass of DatabaseError.
|
||||
|
||||
Exception messages of this class will have the prefix DPY and an error
|
||||
number in the range 6000 - 6999.
|
||||
"""
|
||||
|
||||
|
||||
class ProgrammingError(DatabaseError):
|
||||
"""
|
||||
Exception raised for programming errors. It is a subclass of DatabaseError.
|
||||
|
||||
Exception messages of this class will have the prefix DPY and an error
|
||||
number in the range 2000 - 2999.
|
||||
"""
|
||||
310
.venv/lib/python3.9/site-packages/oracledb/fetch_info.py
Normal file
310
.venv/lib/python3.9/site-packages/oracledb/fetch_info.py
Normal file
@@ -0,0 +1,310 @@
|
||||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2023, 2025, 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
|
||||
|
||||
import oracledb
|
||||
|
||||
from . import constants
|
||||
from .base import BaseMetaClass
|
||||
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,
|
||||
DB_TYPE_VECTOR,
|
||||
)
|
||||
from .dbobject import DbObjectType
|
||||
|
||||
|
||||
class FetchInfo(metaclass=BaseMetaClass):
|
||||
"""
|
||||
Identifies metadata of columns that are being fetched.
|
||||
"""
|
||||
|
||||
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]:
|
||||
"""
|
||||
This read-only attribute returns a dictionary containing the
|
||||
`annotations <https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=
|
||||
GUID-1AC16117-BBB6-4435-8794-2B99F8F68052>`__ associated with the
|
||||
fetched column. If there are no annotations, the value *None* is
|
||||
returned. Annotations require Oracle Database version 23, or later. If
|
||||
using python-oracledb Thick mode, Oracle Client version 23 or later is
|
||||
also required.
|
||||
"""
|
||||
return self._impl.annotations
|
||||
|
||||
@property
|
||||
def display_size(self) -> Union[int, None]:
|
||||
"""
|
||||
This read-only attribute returns the display size of the column.
|
||||
"""
|
||||
if self._impl.max_size > 0:
|
||||
return self._impl.max_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]:
|
||||
"""
|
||||
This read-only attribute returns the name of the `data use case
|
||||
domain
|
||||
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-17D3A9C6
|
||||
-D993-4E94-BF6B-CACA56581F41>`__ associated with the fetched column. If
|
||||
there is no data use case domain, the value *None* is returned. `Data
|
||||
use case domains <https://www.oracle.com/pls/topic/lookup?ctx=dblatest
|
||||
&id=GUID-4743FDE1-7C6E-471B-BC9D-442383CCA2F9>`__ require Oracle
|
||||
Database version 23, or later. If using python-oracledb Thick mode,
|
||||
Oracle Client version 23 or later is also required.
|
||||
"""
|
||||
return self._impl.domain_name
|
||||
|
||||
@property
|
||||
def domain_schema(self) -> Union[str, None]:
|
||||
"""
|
||||
This read-only attribute returns the schema of the `data use case
|
||||
domain <https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-
|
||||
17D3A9C6-D993-4E94-BF6B-CACA56581F41>`__ associated with the fetched
|
||||
column. If there is no data use case domain, the value *None* is
|
||||
returned. `Data use case domains <https://www.oracle.com/pls/topic/
|
||||
lookup?ctx=dblatest&id=GUID-4743FDE1-7C6E-471B-BC9D-442383CCA2F9>`__
|
||||
require Oracle Database version 23, or later. If using python-oracledb
|
||||
Thick mode, Oracle Client version 23 or later is also required.
|
||||
"""
|
||||
return self._impl.domain_schema
|
||||
|
||||
@property
|
||||
def internal_size(self) -> Union[int, None]:
|
||||
"""
|
||||
This read-only attribute returns the internal size of the column as
|
||||
mandated by the Python Database API.
|
||||
"""
|
||||
if self._impl.max_size > 0:
|
||||
return self._impl.buffer_size
|
||||
|
||||
@property
|
||||
def is_json(self) -> bool:
|
||||
"""
|
||||
This read-only attribute returns whether the column is known to contain
|
||||
JSON data. This will be *True* when the type code is
|
||||
:data:`oracledb.DB_TYPE_JSON` as well as when an "IS JSON" constraint
|
||||
is enabled on LOB and VARCHAR2 columns.
|
||||
"""
|
||||
return self._impl.is_json
|
||||
|
||||
@property
|
||||
def is_oson(self) -> bool:
|
||||
"""
|
||||
This read-only attribute returns whether the column is known to contain
|
||||
binary encoded `OSON <https://www.oracle.com/pls/topic/lookup?ctx=
|
||||
dblatest&id=GUID-911D302C-CFAF-406B-B6A5-4E99DD38ABAD>`__ data. This
|
||||
will be *True* when an "IS JSON FORMAT OSON" check constraint is
|
||||
enabled on BLOB columns.
|
||||
"""
|
||||
return self._impl.is_oson
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
"""
|
||||
This read-only attribute returns the name of the column as mandated by
|
||||
the Python Database API.
|
||||
"""
|
||||
return self._impl.name
|
||||
|
||||
@property
|
||||
def null_ok(self) -> bool:
|
||||
"""
|
||||
This read-only attribute returns whether nulls are allowed in the
|
||||
column as mandated by the Python Database API.
|
||||
"""
|
||||
return self._impl.nulls_allowed
|
||||
|
||||
@property
|
||||
def precision(self) -> Union[int, None]:
|
||||
"""
|
||||
This read-only attribute returns the precision of the column as
|
||||
mandated by the Python Database API.
|
||||
"""
|
||||
if self._impl.precision or self._impl.scale:
|
||||
return self._impl.precision
|
||||
|
||||
@property
|
||||
def scale(self) -> Union[int, None]:
|
||||
"""
|
||||
This read-only attribute returns the scale of the column as mandated by
|
||||
the Python Database API.
|
||||
"""
|
||||
if self._impl.precision or self._impl.scale:
|
||||
return self._impl.scale
|
||||
|
||||
@property
|
||||
def type(self) -> Union[DbType, DbObjectType]:
|
||||
"""
|
||||
This read-only attribute returns the type of the column. This will be
|
||||
an :ref:`Oracle Object Type <dbobjecttype>` if the column contains
|
||||
Oracle objects; otherwise, it will be one of the
|
||||
:ref:`database type constants <dbtypes>` defined at the module level.
|
||||
"""
|
||||
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:
|
||||
"""
|
||||
This read-only attribute returns the type of the column as mandated by
|
||||
the Python Database API. The type will be one of the
|
||||
:ref:`database type constants <dbtypes>` defined at the module level.
|
||||
"""
|
||||
return self._impl.dbtype
|
||||
|
||||
@property
|
||||
def vector_dimensions(self) -> Union[int, None]:
|
||||
"""
|
||||
This read-only attribute returns the number of dimensions required by
|
||||
VECTOR columns. If the column is not a VECTOR column or allows for any
|
||||
number of dimensions, the value returned is *None*.
|
||||
"""
|
||||
if self._impl.dbtype is DB_TYPE_VECTOR:
|
||||
flags = self._impl.vector_flags
|
||||
if not (flags & constants.VECTOR_META_FLAG_FLEXIBLE_DIM):
|
||||
return self._impl.vector_dimensions
|
||||
|
||||
@property
|
||||
def vector_format(self) -> Union[oracledb.VectorFormat, None]:
|
||||
"""
|
||||
This read-only attribute returns the storage type used by VECTOR
|
||||
columns. The value of this attribute can be:
|
||||
|
||||
- :data:`oracledb.VECTOR_FORMAT_BINARY` which represents 8-bit unsigned
|
||||
integers
|
||||
- :data:`oracledb.VECTOR_FORMAT_INT8` which represents 8-bit signed
|
||||
integers
|
||||
- :data:`oracledb.VECTOR_FORMAT_FLOAT32` which represents 32-bit
|
||||
floating-point numbers
|
||||
- :data:`oracledb.VECTOR_FORMAT_FLOAT64` which represents 64-bit
|
||||
floating-point numbers
|
||||
|
||||
If the column is not a VECTOR column or allows for any type of storage,
|
||||
the value returned is *None*.
|
||||
"""
|
||||
if (
|
||||
self._impl.dbtype is DB_TYPE_VECTOR
|
||||
and self._impl.vector_format != 0
|
||||
):
|
||||
return oracledb.VectorFormat(self._impl.vector_format)
|
||||
|
||||
@property
|
||||
def vector_is_sparse(self) -> Union[bool, None]:
|
||||
"""
|
||||
This read-only attribute returns a boolean indicating if the vector is
|
||||
sparse or not.
|
||||
|
||||
If the column contains vectors that are SPARSE, the value returned is
|
||||
*True*. If the column contains vectors that are DENSE, the value
|
||||
returned is *False*. If the column is not a VECTOR column, the value
|
||||
returned is *None*.
|
||||
"""
|
||||
if self._impl.dbtype is DB_TYPE_VECTOR:
|
||||
flags = self._impl.vector_flags
|
||||
return bool(flags & constants.VECTOR_META_FLAG_SPARSE_VECTOR)
|
||||
46
.venv/lib/python3.9/site-packages/oracledb/future.py
Normal file
46
.venv/lib/python3.9/site-packages/oracledb/future.py
Normal file
@@ -0,0 +1,46 @@
|
||||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2020, 2025, 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()
|
||||
318
.venv/lib/python3.9/site-packages/oracledb/lob.py
Normal file
318
.venv/lib/python3.9/site-packages/oracledb/lob.py
Normal file
@@ -0,0 +1,318 @@
|
||||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2021, 2025, 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 Optional, Union
|
||||
|
||||
from .base import BaseMetaClass
|
||||
from .base_impl import DbType, DB_TYPE_BFILE, DB_TYPE_BLOB
|
||||
from . import errors
|
||||
|
||||
|
||||
class BaseLOB(metaclass=BaseMetaClass):
|
||||
|
||||
def __del__(self):
|
||||
self._impl.free_lob()
|
||||
|
||||
def _check_is_bfile(self):
|
||||
if self._impl.dbtype is not DB_TYPE_BFILE:
|
||||
errors._raise_err(errors.ERR_OPERATION_ONLY_SUPPORTED_ON_BFILE)
|
||||
|
||||
def _check_not_bfile(self):
|
||||
if self._impl.dbtype is DB_TYPE_BFILE:
|
||||
errors._raise_err(errors.ERR_OPERATION_NOT_SUPPORTED_ON_BFILE)
|
||||
|
||||
def _check_value_to_write(self, value):
|
||||
"""
|
||||
Checks the value to write and returns the actual value to write.
|
||||
Character LOBs must write strings but can accept UTF-8 encoded bytes
|
||||
(which will be decoded to strings). Binary LOBs must write bytes but
|
||||
can accept strings (which will be encoded in UTF-8).
|
||||
"""
|
||||
if self.type is DB_TYPE_BLOB:
|
||||
if isinstance(value, str):
|
||||
return value.encode()
|
||||
elif isinstance(value, bytes):
|
||||
return value
|
||||
else:
|
||||
if isinstance(value, str):
|
||||
return value
|
||||
elif isinstance(value, bytes):
|
||||
return value.decode()
|
||||
raise TypeError("expecting string or bytes")
|
||||
|
||||
@classmethod
|
||||
def _from_impl(cls, impl):
|
||||
if isinstance(impl, BaseLOB):
|
||||
return impl
|
||||
lob = cls.__new__(cls)
|
||||
lob._impl = impl
|
||||
return lob
|
||||
|
||||
def getfilename(self) -> tuple:
|
||||
"""
|
||||
Returns a two-tuple consisting of the directory alias and file name for
|
||||
a BFILE type LOB.
|
||||
"""
|
||||
self._check_is_bfile()
|
||||
return self._impl.get_file_name()
|
||||
|
||||
def setfilename(self, dir_alias: str, name: str) -> None:
|
||||
"""
|
||||
Sets the directory alias and name of a BFILE type LOB.
|
||||
"""
|
||||
self._check_is_bfile()
|
||||
self._impl.set_file_name(dir_alias, name)
|
||||
|
||||
@property
|
||||
def type(self) -> DbType:
|
||||
"""
|
||||
This read-only attribute returns the type of the LOB as one of the
|
||||
database type constants.
|
||||
"""
|
||||
return self._impl.dbtype
|
||||
|
||||
|
||||
class LOB(BaseLOB):
|
||||
|
||||
def __reduce__(self):
|
||||
value = self.read()
|
||||
return (type(value), (value,))
|
||||
|
||||
def __str__(self):
|
||||
return self.read()
|
||||
|
||||
def close(self) -> None:
|
||||
"""
|
||||
Closes 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:
|
||||
"""
|
||||
Returns a boolean indicating if the file referenced by a BFILE type LOB
|
||||
exists.
|
||||
"""
|
||||
self._check_is_bfile()
|
||||
return self._impl.file_exists()
|
||||
|
||||
def getchunksize(self) -> int:
|
||||
"""
|
||||
Returns the chunk size for the LOB. Reading and writing to the LOB in
|
||||
chunks of multiples of this size will improve performance.
|
||||
"""
|
||||
self._check_not_bfile()
|
||||
return self._impl.get_chunk_size()
|
||||
|
||||
def isopen(self) -> bool:
|
||||
"""
|
||||
Returns a boolean indicating if the LOB has been opened using the
|
||||
method open().
|
||||
"""
|
||||
return self._impl.get_is_open()
|
||||
|
||||
def open(self) -> None:
|
||||
"""
|
||||
Opens 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: Optional[int] = None
|
||||
) -> Union[str, bytes]:
|
||||
"""
|
||||
Returns 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
|
||||
elif amount <= 0:
|
||||
errors._raise_err(errors.ERR_INVALID_LOB_AMOUNT)
|
||||
if offset <= 0:
|
||||
errors._raise_err(errors.ERR_INVALID_LOB_OFFSET)
|
||||
return self._impl.read(offset, amount)
|
||||
|
||||
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: Optional[int] = None
|
||||
) -> None:
|
||||
"""
|
||||
Trims the LOB to the new size (the second parameter is deprecated and
|
||||
should not be used).
|
||||
"""
|
||||
self._check_not_bfile()
|
||||
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:
|
||||
"""
|
||||
Writes 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._check_not_bfile()
|
||||
self._impl.write(self._check_value_to_write(data), offset)
|
||||
|
||||
|
||||
class AsyncLOB(BaseLOB):
|
||||
|
||||
async def close(self) -> None:
|
||||
"""
|
||||
Closes 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:
|
||||
"""
|
||||
Returns a boolean indicating if the file referenced by a BFILE type LOB
|
||||
exists.
|
||||
"""
|
||||
self._check_is_bfile()
|
||||
return await self._impl.file_exists()
|
||||
|
||||
async def getchunksize(self) -> int:
|
||||
"""
|
||||
Returns the chunk size for the LOB. Reading and writing to the LOB in
|
||||
chunks of multiples of this size will improve performance.
|
||||
"""
|
||||
self._check_not_bfile()
|
||||
return await self._impl.get_chunk_size()
|
||||
|
||||
async def isopen(self) -> bool:
|
||||
"""
|
||||
Returns 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:
|
||||
"""
|
||||
Opens 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: Optional[int] = None
|
||||
) -> Union[str, bytes]:
|
||||
"""
|
||||
Returns 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 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: Optional[int] = None
|
||||
) -> None:
|
||||
"""
|
||||
Trims the LOB to the new size (the second parameter is deprecated and
|
||||
should not be used).
|
||||
"""
|
||||
self._check_not_bfile()
|
||||
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:
|
||||
"""
|
||||
Writes 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._check_not_bfile()
|
||||
await self._impl.write(self._check_value_to_write(data), offset)
|
||||
491
.venv/lib/python3.9/site-packages/oracledb/pipeline.py
Normal file
491
.venv/lib/python3.9/site-packages/oracledb/pipeline.py
Normal file
@@ -0,0 +1,491 @@
|
||||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2024, 2025, 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.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# pipeline.py
|
||||
#
|
||||
# Contains the Pipeline class used for executing multiple operations.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
from typing import Any, Callable, Optional, Union
|
||||
|
||||
from . import utils
|
||||
from .base import BaseMetaClass
|
||||
from .base_impl import PipelineImpl, PipelineOpImpl, PipelineOpResultImpl
|
||||
from .defaults import defaults
|
||||
from .enums import PipelineOpType
|
||||
from .errors import _Error
|
||||
from .fetch_info import FetchInfo
|
||||
|
||||
|
||||
class PipelineOp(metaclass=BaseMetaClass):
|
||||
|
||||
def __repr__(self):
|
||||
cls_name = self.__class__._public_name
|
||||
return f"<{cls_name} of type {self.op_type.name}>"
|
||||
|
||||
def _create_result(self):
|
||||
"""
|
||||
Internal method used for creating a result object that is returned when
|
||||
running a pipeline.
|
||||
"""
|
||||
impl = PipelineOpResultImpl(self._impl)
|
||||
result = PipelineOpResult.__new__(PipelineOpResult)
|
||||
result._operation = self
|
||||
result._impl = impl
|
||||
return result
|
||||
|
||||
@property
|
||||
def arraysize(self) -> int:
|
||||
"""
|
||||
This read-only attribute returns the array size that will be used when
|
||||
fetching query rows with :meth:`Pipeline.add_fetchall()`. For all other
|
||||
operations, the value returned is *0*.
|
||||
"""
|
||||
return self._impl.arraysize
|
||||
|
||||
@property
|
||||
def fetch_decimals(self) -> bool:
|
||||
"""
|
||||
Returns whether or not to fetch columns of type ``NUMBER`` as
|
||||
``decimal.Decimal`` values for a query.
|
||||
"""
|
||||
return self._impl.fetch_decimals
|
||||
|
||||
@property
|
||||
def fetch_lobs(self) -> bool:
|
||||
"""
|
||||
Returns whether or not to fetch LOB locators for a query.
|
||||
"""
|
||||
return self._impl.fetch_lobs
|
||||
|
||||
@property
|
||||
def keyword_parameters(self) -> Any:
|
||||
"""
|
||||
This read-only attribute returns the keyword parameters to the stored
|
||||
procedure or function being called by the operation, if applicable.
|
||||
"""
|
||||
return self._impl.keyword_parameters
|
||||
|
||||
@property
|
||||
def name(self) -> Union[str, None]:
|
||||
"""
|
||||
This read-only attribute returns the name of the stored procedure or
|
||||
function being called by the operation, if applicable.
|
||||
"""
|
||||
return self._impl.name
|
||||
|
||||
@property
|
||||
def num_rows(self) -> int:
|
||||
"""
|
||||
This read-only attribute returns the number of rows to fetch when
|
||||
performing a query of a specific number of rows. For all other
|
||||
operations, the value returned is *0*.
|
||||
"""
|
||||
return self._impl.num_rows
|
||||
|
||||
@property
|
||||
def op_type(self) -> PipelineOpType:
|
||||
"""
|
||||
This read-only attribute returns the type of operation that is taking
|
||||
place.
|
||||
"""
|
||||
return PipelineOpType(self._impl.op_type)
|
||||
|
||||
@property
|
||||
def parameters(self) -> Any:
|
||||
"""
|
||||
This read-only attribute returns the parameters to the stored procedure
|
||||
or function or the parameters bound to the statement being executed by
|
||||
the operation, if applicable.
|
||||
"""
|
||||
return self._impl.parameters
|
||||
|
||||
@property
|
||||
def return_type(self) -> Any:
|
||||
"""
|
||||
This read-only attribute returns the return type of the stored function
|
||||
being called by the operation, if applicable.
|
||||
"""
|
||||
return self._impl.return_type
|
||||
|
||||
@property
|
||||
def rowfactory(self) -> Union[Callable, None]:
|
||||
"""
|
||||
This read-only attribute returns the row factory callable function to
|
||||
be used in a query executed by the operation, if applicable.
|
||||
"""
|
||||
return self._impl.rowfactory
|
||||
|
||||
@property
|
||||
def statement(self) -> Union[str, None]:
|
||||
"""
|
||||
This read-only attribute returns the statement being executed by the
|
||||
operation, if applicable.
|
||||
"""
|
||||
return self._impl.statement
|
||||
|
||||
|
||||
class PipelineOpResult(metaclass=BaseMetaClass):
|
||||
|
||||
def __repr__(self):
|
||||
cls_name = self.__class__._public_name
|
||||
return (
|
||||
f"<{cls_name} for operation of type {self.operation.op_type.name}>"
|
||||
)
|
||||
|
||||
@property
|
||||
def columns(self) -> Union[list[FetchInfo], None]:
|
||||
"""
|
||||
This read-only attribute is a list of FetchInfo objects. This
|
||||
attribute will be *None* for operations that do not return rows.
|
||||
"""
|
||||
if self._impl.fetch_metadata is not None:
|
||||
return [FetchInfo._from_impl(i) for i in self._impl.fetch_metadata]
|
||||
|
||||
@property
|
||||
def error(self) -> Union[_Error, None]:
|
||||
"""
|
||||
This read-only attribute returns the error that occurred when running
|
||||
this operation. If no error occurred, then the value *None* is
|
||||
returned.
|
||||
"""
|
||||
return self._impl.error
|
||||
|
||||
@property
|
||||
def operation(self) -> PipelineOp:
|
||||
"""
|
||||
This read-only attribute returns the PipelineOp operation object that
|
||||
generated the result.
|
||||
"""
|
||||
return self._operation
|
||||
|
||||
@property
|
||||
def return_value(self) -> Any:
|
||||
"""
|
||||
This read-only attribute returns the return value of the called PL/SQL
|
||||
function, if a function was called for the operation.
|
||||
"""
|
||||
return self._impl.return_value
|
||||
|
||||
@property
|
||||
def rows(self) -> Union[list, None]:
|
||||
"""
|
||||
This read-only attribute returns the rows that were fetched by the
|
||||
operation, if a query was executed.
|
||||
"""
|
||||
return self._impl.rows
|
||||
|
||||
@property
|
||||
def warning(self) -> Union[_Error, None]:
|
||||
"""
|
||||
This read-only attribute returns any warning that was encountered when
|
||||
running this operation. If no warning was encountered, then the value
|
||||
*None* is returned.
|
||||
"""
|
||||
return self._impl.warning
|
||||
|
||||
|
||||
class Pipeline(metaclass=BaseMetaClass):
|
||||
|
||||
def __repr__(self):
|
||||
cls_name = self.__class__._public_name
|
||||
return f"<{cls_name} with {len(self._impl.operations)} operations>"
|
||||
|
||||
def _add_op(self, op_impl):
|
||||
"""
|
||||
Internal method for adding an PipelineOpImpl instance to the list of
|
||||
operations, creating an associated PipelineOp instance to correspond to
|
||||
it.
|
||||
"""
|
||||
self._impl.operations.append(op_impl)
|
||||
op = PipelineOp.__new__(PipelineOp)
|
||||
op._impl = op_impl
|
||||
self._operations.append(op)
|
||||
return op
|
||||
|
||||
def add_callfunc(
|
||||
self,
|
||||
name: str,
|
||||
return_type: Any,
|
||||
parameters: Optional[Union[list, tuple]] = None,
|
||||
keyword_parameters: Optional[dict] = None,
|
||||
) -> PipelineOp:
|
||||
"""
|
||||
Adds an operation to the pipeline that calls a stored PL/SQL function
|
||||
with the given parameters and return type. The created PipelineOp
|
||||
object is also returned from this function.
|
||||
|
||||
When the Pipeline is executed, the PipelineOpResult object that is
|
||||
returned for this operation will have the
|
||||
:attr:`~PipelineOpResult.return_value` attribute populated with the
|
||||
return value of the PL/SQL function if the call completes
|
||||
successfully.
|
||||
"""
|
||||
utils.verify_stored_proc_args(parameters, keyword_parameters)
|
||||
op_impl = PipelineOpImpl(
|
||||
op_type=PipelineOpType.CALL_FUNC,
|
||||
name=name,
|
||||
return_type=return_type,
|
||||
parameters=parameters,
|
||||
keyword_parameters=keyword_parameters,
|
||||
)
|
||||
return self._add_op(op_impl)
|
||||
|
||||
def add_callproc(
|
||||
self,
|
||||
name: str,
|
||||
parameters: Optional[Union[list, tuple]] = None,
|
||||
keyword_parameters: Optional[dict] = None,
|
||||
) -> PipelineOp:
|
||||
"""
|
||||
Adds an operation that calls a stored procedure with the given
|
||||
parameters. The created PipelineOp object is also returned from
|
||||
this function.
|
||||
"""
|
||||
utils.verify_stored_proc_args(parameters, keyword_parameters)
|
||||
op_impl = PipelineOpImpl(
|
||||
op_type=PipelineOpType.CALL_PROC,
|
||||
name=name,
|
||||
parameters=parameters,
|
||||
keyword_parameters=keyword_parameters,
|
||||
)
|
||||
return self._add_op(op_impl)
|
||||
|
||||
def add_commit(self) -> PipelineOp:
|
||||
"""
|
||||
Adds an operation that performs a commit.
|
||||
"""
|
||||
op_impl = PipelineOpImpl(op_type=PipelineOpType.COMMIT)
|
||||
return self._add_op(op_impl)
|
||||
|
||||
def add_execute(
|
||||
self,
|
||||
statement: str,
|
||||
parameters: Optional[Union[list, tuple, dict]] = None,
|
||||
) -> PipelineOp:
|
||||
"""
|
||||
Adds an operation that executes a statement with the given parameters.
|
||||
The created PipelineOp object is also returned from this function.
|
||||
|
||||
Do not use this for queries that return rows. Instead use
|
||||
:meth:`Pipeline.add_fetchall()`, :meth:`Pipeline.add_fetchmany()`, or
|
||||
:meth:`Pipeline.add_fetchone()`.
|
||||
"""
|
||||
op_impl = PipelineOpImpl(
|
||||
op_type=PipelineOpType.EXECUTE,
|
||||
statement=statement,
|
||||
parameters=parameters,
|
||||
)
|
||||
return self._add_op(op_impl)
|
||||
|
||||
def add_executemany(
|
||||
self,
|
||||
statement: str,
|
||||
parameters: Union[list, int],
|
||||
) -> PipelineOp:
|
||||
"""
|
||||
Adds an operation that executes a SQL statement once using all bind
|
||||
value mappings or sequences found in the sequence parameters. This can
|
||||
be used to insert, update, or delete multiple rows in a table. It can
|
||||
also invoke a PL/SQL procedure multiple times.
|
||||
|
||||
The created PipelineOp object is also returned from this function.
|
||||
|
||||
The ``parameters`` parameter can be a list of tuples, where each tuple
|
||||
item maps to one bind variable placeholder in ``statement``. It can
|
||||
also be a list of dictionaries, where the keys match the bind variable
|
||||
placeholder names in ``statement``. If there are no bind values, or
|
||||
values have previously been bound, the ``parameters`` value can be an
|
||||
integer specifying the number of iterations.
|
||||
"""
|
||||
op_impl = PipelineOpImpl(
|
||||
op_type=PipelineOpType.EXECUTE_MANY,
|
||||
statement=statement,
|
||||
parameters=parameters,
|
||||
)
|
||||
return self._add_op(op_impl)
|
||||
|
||||
def add_fetchall(
|
||||
self,
|
||||
statement: str,
|
||||
parameters: Optional[Union[list, tuple, dict]] = None,
|
||||
arraysize: Optional[int] = None,
|
||||
rowfactory: Optional[Callable] = None,
|
||||
fetch_lobs: Optional[bool] = None,
|
||||
fetch_decimals: Optional[bool] = None,
|
||||
) -> PipelineOp:
|
||||
"""
|
||||
Adds an operation that executes a query and returns all of the rows
|
||||
from the result set. The created PipelineOp object is also returned
|
||||
from this function.
|
||||
|
||||
When the Pipeline is executed, the PipelineOpResult object that is
|
||||
returned for this operation will have the
|
||||
:attr:`~PipelineOpResult.rows` attribute populated with the list of
|
||||
rows returned by the query.
|
||||
|
||||
The default value for ``arraysize`` is
|
||||
:attr:`oracledb.defaults.arraysize <Defaults.arraysize>`.
|
||||
|
||||
Internally, this operation's :attr:`Cursor.prefetchrows` size is set
|
||||
to the value of the explicit or default ``arraysize`` parameter value.
|
||||
|
||||
The ``fetch_lobs`` parameter specifies whether to return LOB locators
|
||||
or ``str``/``bytes`` values when fetching LOB columns. The default
|
||||
value is :data:`oracledb.defaults.fetch_lobs <Defaults.fetch_lobs>`.
|
||||
|
||||
The ``fetch_decimals`` parameter specifies whether to return
|
||||
``decimal.Decimal`` values when fetching columns of type ``NUMBER``.
|
||||
The default value is
|
||||
:data:`oracledb.defaults.fetch_decimals <Defaults.fetch_decimals>`.
|
||||
"""
|
||||
if arraysize is None:
|
||||
arraysize = defaults.arraysize
|
||||
op_impl = PipelineOpImpl(
|
||||
op_type=PipelineOpType.FETCH_ALL,
|
||||
statement=statement,
|
||||
parameters=parameters,
|
||||
arraysize=arraysize,
|
||||
rowfactory=rowfactory,
|
||||
fetch_lobs=fetch_lobs,
|
||||
fetch_decimals=fetch_decimals,
|
||||
)
|
||||
return self._add_op(op_impl)
|
||||
|
||||
def add_fetchmany(
|
||||
self,
|
||||
statement: str,
|
||||
parameters: Optional[Union[list, tuple, dict]] = None,
|
||||
num_rows: Optional[int] = None,
|
||||
rowfactory: Optional[Callable] = None,
|
||||
fetch_lobs: Optional[bool] = None,
|
||||
fetch_decimals: Optional[bool] = None,
|
||||
) -> PipelineOp:
|
||||
"""
|
||||
Adds an operation that executes a query and returns up to the specified
|
||||
number of rows from the result set. The created PipelineOp object is
|
||||
also returned from this function.
|
||||
|
||||
When the Pipeline is executed, the PipelineOpResult object that is
|
||||
returned for this operation will have the
|
||||
:attr:`~PipelineOpResult.rows` attribute populated with the list of
|
||||
rows returned by the query.
|
||||
|
||||
The default value for ``num_rows`` is the value of
|
||||
:attr:`oracledb.defaults.arraysize <Defaults.arraysize>`.
|
||||
|
||||
Internally, this operation's :attr:`Cursor.prefetchrows` size is set to
|
||||
the value of the explicit or default ``num_rows`` parameter, allowing
|
||||
all rows to be fetched in one round-trip.
|
||||
|
||||
Since only one fetch is performed for a query operation, consider
|
||||
adding a ``FETCH NEXT`` clause to the statement to prevent the
|
||||
database processing rows that will never be fetched.
|
||||
|
||||
The ``fetch_lobs`` parameter specifies whether to return LOB locators
|
||||
or ``str``/``bytes`` values when fetching LOB columns. The default
|
||||
value is :data:`oracledb.defaults.fetch_lobs <Defaults.fetch_lobs>`.
|
||||
|
||||
The ``fetch_decimals`` parameter specifies whether to return
|
||||
``decimal.Decimal`` values when fetching columns of type ``NUMBER``.
|
||||
The default value is
|
||||
:data:`oracledb.defaults.fetch_decimals <Defaults.fetch_decimals>`.
|
||||
"""
|
||||
if num_rows is None:
|
||||
num_rows = defaults.arraysize
|
||||
op_impl = PipelineOpImpl(
|
||||
op_type=PipelineOpType.FETCH_MANY,
|
||||
statement=statement,
|
||||
parameters=parameters,
|
||||
num_rows=num_rows,
|
||||
rowfactory=rowfactory,
|
||||
fetch_lobs=fetch_lobs,
|
||||
fetch_decimals=fetch_decimals,
|
||||
)
|
||||
return self._add_op(op_impl)
|
||||
|
||||
def add_fetchone(
|
||||
self,
|
||||
statement: str,
|
||||
parameters: Optional[Union[list, tuple, dict]] = None,
|
||||
rowfactory: Optional[Callable] = None,
|
||||
fetch_lobs: Optional[bool] = None,
|
||||
fetch_decimals: Optional[bool] = None,
|
||||
) -> PipelineOp:
|
||||
"""
|
||||
Adds an operation that executes a query and returns the first row of
|
||||
the result set if one exists (or *None*, if no rows exist). The
|
||||
created PipelineOp object is also returned from this function.
|
||||
|
||||
When the Pipeline is executed, the PipelineOpResult object that is
|
||||
returned for this operation will have the
|
||||
:attr:`~PipelineOpResult.rows` attribute populated with this row if the
|
||||
query is performed successfully.
|
||||
|
||||
Internally, this operation's :attr:`Cursor.prefetchrows` and
|
||||
:attr:`Cursor.arraysize` sizes will be set to *1*.
|
||||
|
||||
Since only one fetch is performed for a query operation, consider
|
||||
adding a ``WHERE`` condition or using a ``FETCH NEXT`` clause in the
|
||||
statement to prevent the database processing rows that will never be
|
||||
fetched.
|
||||
|
||||
The ``fetch_lobs`` parameter specifies whether to return LOB locators
|
||||
or ``str``/``bytes`` values when fetching LOB columns. The default
|
||||
value is :data:`oracledb.defaults.fetch_lobs <Defaults.fetch_lobs>`.
|
||||
|
||||
The ``fetch_decimals`` parameter specifies whether to return
|
||||
``decimal.Decimal`` values when fetching columns of type ``NUMBER``.
|
||||
The default value is
|
||||
:data:`oracledb.defaults.fetch_decimals <Defaults.fetch_decimals>`.
|
||||
"""
|
||||
op_impl = PipelineOpImpl(
|
||||
op_type=PipelineOpType.FETCH_ONE,
|
||||
statement=statement,
|
||||
parameters=parameters,
|
||||
rowfactory=rowfactory,
|
||||
fetch_lobs=fetch_lobs,
|
||||
fetch_decimals=fetch_decimals,
|
||||
)
|
||||
return self._add_op(op_impl)
|
||||
|
||||
@property
|
||||
def operations(self) -> list[PipelineOp]:
|
||||
"""
|
||||
This read-only attribute returns the list of operations associated with
|
||||
the pipeline.
|
||||
"""
|
||||
return self._operations
|
||||
|
||||
|
||||
def create_pipeline() -> Pipeline:
|
||||
"""
|
||||
Creates a pipeline object which can be used to process a set of operations
|
||||
against a database.
|
||||
"""
|
||||
pipeline = Pipeline.__new__(Pipeline)
|
||||
pipeline._impl = PipelineImpl()
|
||||
pipeline._operations = []
|
||||
return pipeline
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,274 @@
|
||||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2024, 2025, 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.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# azure_config_provider.py
|
||||
#
|
||||
# Python file contains the hook method config_azure_hook() that fetches config
|
||||
# store from Azure App Configuration.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
import json
|
||||
import re
|
||||
|
||||
import oracledb
|
||||
|
||||
from urllib.parse import urlparse, parse_qs
|
||||
from azure.appconfiguration import AzureAppConfigurationClient
|
||||
from azure.keyvault.secrets import SecretClient
|
||||
from azure.core.exceptions import ResourceNotFoundError
|
||||
from azure.identity import (
|
||||
ClientSecretCredential,
|
||||
CertificateCredential,
|
||||
ManagedIdentityCredential,
|
||||
ChainedTokenCredential,
|
||||
EnvironmentCredential,
|
||||
)
|
||||
|
||||
|
||||
def _get_authentication_method(parameters):
|
||||
auth_method = parameters.get("authentication", parameters.get("method"))
|
||||
if auth_method is not None:
|
||||
auth_method = auth_method.upper()
|
||||
if auth_method == "AZURE_DEFAULT":
|
||||
auth_method = None
|
||||
return auth_method
|
||||
|
||||
|
||||
def _get_credential(parameters):
|
||||
"""
|
||||
Returns the appropriate credential given the input supplied by the original
|
||||
connect string.
|
||||
"""
|
||||
|
||||
tokens = []
|
||||
auth_method = _get_authentication_method(parameters)
|
||||
|
||||
if auth_method is None or auth_method == "AZURE_SERVICE_PRINCIPAL":
|
||||
if "azure_client_secret" in parameters:
|
||||
tokens.append(
|
||||
ClientSecretCredential(
|
||||
_get_required_parameter(parameters, "azure_tenant_id"),
|
||||
_get_required_parameter(parameters, "azure_client_id"),
|
||||
_get_required_parameter(parameters, "azure_client_secret"),
|
||||
)
|
||||
)
|
||||
elif "azure_client_certificate_path" in parameters:
|
||||
tokens.append(
|
||||
CertificateCredential(
|
||||
_get_required_parameter(parameters, "azure_tenant_id"),
|
||||
_get_required_parameter(parameters, "azure_client_id"),
|
||||
_get_required_parameter(
|
||||
parameters, "azure_client_certificate_path"
|
||||
),
|
||||
)
|
||||
)
|
||||
if auth_method is None or auth_method == "AZURE_MANAGED_IDENTITY":
|
||||
client_id = parameters.get("azure_managed_identity_client_id")
|
||||
if client_id is not None:
|
||||
tokens.append(ManagedIdentityCredential(client_id=client_id))
|
||||
|
||||
if len(tokens) == 0:
|
||||
message = (
|
||||
"Authentication options were not available in Connection String"
|
||||
)
|
||||
raise Exception(message)
|
||||
elif len(tokens) == 1:
|
||||
return tokens[0]
|
||||
tokens.append(EnvironmentCredential())
|
||||
return ChainedTokenCredential(*tokens)
|
||||
|
||||
|
||||
def _get_password(pwd_string, parameters):
|
||||
try:
|
||||
pwd = json.loads(pwd_string)
|
||||
except json.JSONDecodeError:
|
||||
message = (
|
||||
"Password is expected to be JSON"
|
||||
" containing Azure Vault details."
|
||||
)
|
||||
raise Exception(message)
|
||||
|
||||
pwd["value"] = pwd.pop("uri")
|
||||
pwd["type"] = "azurevault"
|
||||
|
||||
# make authentication section
|
||||
pwd["authentication"] = authentication = {}
|
||||
|
||||
authentication["method"] = auth_method = _get_authentication_method(
|
||||
parameters
|
||||
)
|
||||
|
||||
if auth_method is None or auth_method == "AZURE_SERVICE_PRINCIPAL":
|
||||
if "azure_client_secret" in parameters:
|
||||
authentication["azure_tenant_id"] = _get_required_parameter(
|
||||
parameters, "azure_tenant_id"
|
||||
)
|
||||
authentication["azure_client_id"] = _get_required_parameter(
|
||||
parameters, "azure_client_id"
|
||||
)
|
||||
authentication["azure_client_secret"] = _get_required_parameter(
|
||||
parameters, "azure_client_secret"
|
||||
)
|
||||
|
||||
elif "azure_client_certificate_path" in parameters:
|
||||
authentication["azure_tenant_id"] = (
|
||||
_get_required_parameter(parameters, "azure_tenant_id"),
|
||||
)
|
||||
authentication["azure_client_id"] = (
|
||||
_get_required_parameter(parameters, "azure_client_id"),
|
||||
)
|
||||
authentication["azure_client_certificate_path"] = (
|
||||
_get_required_parameter(
|
||||
parameters, "azure_client_certificate_path"
|
||||
)
|
||||
)
|
||||
|
||||
if auth_method is None or auth_method == "AZURE_MANAGED_IDENTITY":
|
||||
authentication["azure_managed_identity_client_id"] = parameters.get(
|
||||
"azure_managed_identity_client_id"
|
||||
)
|
||||
return pwd
|
||||
|
||||
|
||||
def _get_required_parameter(parameters, name, location="connection string"):
|
||||
try:
|
||||
return parameters[name]
|
||||
except KeyError:
|
||||
message = f'Parameter named "{name}" is missing from {location}'
|
||||
raise Exception(message) from None
|
||||
|
||||
|
||||
def _get_setting(client, key, sub_key, label, required=True):
|
||||
"""
|
||||
Returns the configuration setting given the client, key and label.
|
||||
"""
|
||||
try:
|
||||
if key.endswith("/"):
|
||||
actual_key = f"{key}{sub_key}"
|
||||
else:
|
||||
actual_key = f"{key}/{sub_key}"
|
||||
obj = client.get_configuration_setting(key=actual_key, label=label)
|
||||
except ResourceNotFoundError:
|
||||
if required:
|
||||
message = f"Missing required configuration key: {actual_key}"
|
||||
raise Exception(message)
|
||||
return None
|
||||
return obj.value
|
||||
|
||||
|
||||
def _parse_parameters(protocol_arg: str) -> dict:
|
||||
"""
|
||||
Parse the parameters from the protocol argument string.
|
||||
"""
|
||||
pos = protocol_arg.find("?")
|
||||
parsed_url = urlparse(protocol_arg[pos + 1 :])
|
||||
parsed_values = parse_qs(parsed_url.path)
|
||||
parameters = {
|
||||
key.lower(): value[0] for key, value in parsed_values.items()
|
||||
}
|
||||
config_name = protocol_arg[:pos].rstrip("/")
|
||||
if not config_name.endswith(".azconfig.io"):
|
||||
config_name += ".azconfig.io"
|
||||
parameters["appconfigname"] = config_name
|
||||
return parameters
|
||||
|
||||
|
||||
def password_type_azure_vault_hook(args):
|
||||
uri = _get_required_parameter(args, "value", '"password" key section')
|
||||
credential = args.get("credential")
|
||||
|
||||
if credential is None:
|
||||
# if credential not present, this might be coming
|
||||
# from oci config provider, so create credential
|
||||
# for azure key vault.
|
||||
auth = args.get("authentication")
|
||||
if auth is None:
|
||||
raise Exception(
|
||||
"Azure Vault authentication details were not provided."
|
||||
)
|
||||
credential = _get_credential(auth)
|
||||
|
||||
pattern = re.compile(
|
||||
r"(?P<vault_url>https://[A-Za-z0-9._-]+)/"
|
||||
r"secrets/(?P<secretKey>[A-Za-z][A-Za-z0-9-]*)$"
|
||||
)
|
||||
match = pattern.match(uri)
|
||||
if match is None:
|
||||
raise Exception("Invalid Azure Vault details")
|
||||
vault_url = match.group("vault_url")
|
||||
secret_key = match.group("secretKey")
|
||||
secret_client = SecretClient(vault_url, credential)
|
||||
return secret_client.get_secret(secret_key).value
|
||||
|
||||
|
||||
def _process_config(parameters, connect_params):
|
||||
"""
|
||||
Processes the configuration stored in the Azure App configuration store.
|
||||
"""
|
||||
|
||||
credential = _get_credential(parameters)
|
||||
client = AzureAppConfigurationClient(
|
||||
"https://" + _get_required_parameter(parameters, "appconfigname"),
|
||||
credential,
|
||||
)
|
||||
key = _get_required_parameter(parameters, "key")
|
||||
label = parameters.get("label")
|
||||
|
||||
# get the common parameters
|
||||
config = {}
|
||||
config["connect_descriptor"] = _get_setting(
|
||||
client, key, "connect_descriptor", label
|
||||
)
|
||||
config["user"] = _get_setting(client, key, "user", label, required=False)
|
||||
pwd = _get_setting(client, key, "password", label, required=False)
|
||||
if pwd is not None:
|
||||
config["password"] = _get_password(pwd, parameters)
|
||||
|
||||
config["config_time_to_live"] = _get_setting(
|
||||
client, key, "config_time_to_live", label, required=False
|
||||
)
|
||||
config["config_time_to_live_grace_period"] = _get_setting(
|
||||
client, key, "config_time_to_live_grace_period", label, required=False
|
||||
)
|
||||
|
||||
# get the python-oracledb specific parameters
|
||||
settings = _get_setting(client, key, "pyo", label, required=False)
|
||||
if settings is not None:
|
||||
config["pyo"] = json.loads(settings)
|
||||
|
||||
# set the configuration
|
||||
connect_params.set_from_config(config)
|
||||
|
||||
|
||||
def config_azure_hook(protocol, protocol_arg, connect_params):
|
||||
"""
|
||||
Hook for handling parameters stored in an Azure configuration store.
|
||||
"""
|
||||
parameters = _parse_parameters(protocol_arg)
|
||||
_process_config(parameters, connect_params)
|
||||
|
||||
|
||||
oracledb.register_password_type("azurevault", password_type_azure_vault_hook)
|
||||
oracledb.register_protocol("config-azure", config_azure_hook)
|
||||
@@ -0,0 +1,81 @@
|
||||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2024, 2025, 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.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# azure_tokens.py
|
||||
#
|
||||
# Methods that generates an OAuth2 access token using the MSAL SDK
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
import msal
|
||||
import oracledb
|
||||
|
||||
|
||||
def generate_token(token_auth_config, refresh=False):
|
||||
"""
|
||||
Generates an Azure access token based on provided credentials.
|
||||
"""
|
||||
user_auth_type = token_auth_config.get("auth_type") or ""
|
||||
auth_type = user_auth_type.lower()
|
||||
if auth_type == "azureserviceprincipal":
|
||||
return _service_principal_credentials(token_auth_config)
|
||||
else:
|
||||
raise ValueError(
|
||||
f"Unrecognized auth_type authentication method: {user_auth_type}"
|
||||
)
|
||||
|
||||
|
||||
def _service_principal_credentials(token_auth_config):
|
||||
"""
|
||||
Returns the access token for authentication as a service principal.
|
||||
"""
|
||||
msal_config = {
|
||||
"authority": token_auth_config["authority"],
|
||||
"client_id": token_auth_config["client_id"],
|
||||
"client_credential": token_auth_config["client_credential"],
|
||||
}
|
||||
# Initialize the Confidential Client Application
|
||||
cca = msal.ConfidentialClientApplication(**msal_config)
|
||||
auth_response = cca.acquire_token_for_client(
|
||||
scopes=[token_auth_config["scopes"]]
|
||||
)
|
||||
|
||||
if "access_token" in auth_response:
|
||||
return auth_response["access_token"]
|
||||
|
||||
|
||||
def azure_token_hook(params: oracledb.ConnectParams):
|
||||
"""
|
||||
Azure-specific hook for generating a token.
|
||||
"""
|
||||
if params.extra_auth_params is not None:
|
||||
|
||||
def token_callback(refresh):
|
||||
return generate_token(params.extra_auth_params, refresh)
|
||||
|
||||
params.set(access_token=token_callback)
|
||||
|
||||
|
||||
# Register the token hook for Azure
|
||||
oracledb.register_params_hook(azure_token_hook)
|
||||
@@ -0,0 +1,253 @@
|
||||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2024, 2025, 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.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# oci_config_provider.py
|
||||
#
|
||||
# Python file contains the hook method config_oci_hook() that fetches config
|
||||
# store from OCI Object Storage.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
import base64
|
||||
import json
|
||||
import oci
|
||||
import oracledb
|
||||
import re
|
||||
|
||||
from urllib.parse import urlparse, parse_qs
|
||||
|
||||
oci_from_file = oci.config.from_file
|
||||
oci_client_error = oci.exceptions.ClientError
|
||||
oci_object_storage_client = oci.object_storage.ObjectStorageClient
|
||||
oci_secrets_client = oci.secrets.SecretsClient
|
||||
|
||||
|
||||
"""
|
||||
Pattern to parse OCI Object Connect String
|
||||
"""
|
||||
cloud_net_naming_pattern_oci = re.compile(
|
||||
r"(?P<objservername>[^/]+)/n/(?P<namespace>[^/]+)/b/(?P<bucketname>[^/]+)/o/(?P<filename>[^/]+)(/c/(?P<alias>[^/]+))?"
|
||||
)
|
||||
|
||||
|
||||
def _get_config(parameters, connect_params):
|
||||
config = {}
|
||||
|
||||
credential, signer = _get_credential(parameters)
|
||||
auth_method = parameters.get("authentication")
|
||||
if auth_method is not None:
|
||||
auth_method = auth_method.upper()
|
||||
|
||||
if auth_method is None or auth_method == "OCI_DEFAULT":
|
||||
client_oci = oci_object_storage_client(credential)
|
||||
elif (
|
||||
auth_method == "OCI_INSTANCE_PRINCIPAL"
|
||||
or auth_method == "OCI_RESOURCE_PRINCIPAL"
|
||||
):
|
||||
client_oci = oci_object_storage_client(
|
||||
config=credential, signer=signer
|
||||
)
|
||||
get_object_request = {
|
||||
"object_name": _get_required_parameter(parameters, "filename"),
|
||||
"bucket_name": _get_required_parameter(parameters, "bucketname"),
|
||||
"namespace_name": _get_required_parameter(parameters, "namespace"),
|
||||
}
|
||||
|
||||
get_object_response = client_oci.get_object(**get_object_request)
|
||||
resp = _stream_to_string(get_object_response.data)
|
||||
settings = json.loads(resp)
|
||||
user_alias = parameters.get("alias")
|
||||
if user_alias:
|
||||
settings = settings[user_alias]
|
||||
|
||||
# Connect Descriptor
|
||||
config["connect_descriptor"] = _get_required_parameter(
|
||||
settings, "connect_descriptor"
|
||||
)
|
||||
|
||||
# user and password
|
||||
if connect_params.user is None:
|
||||
config["user"] = settings.get("user")
|
||||
if "password" in settings:
|
||||
config["password"] = pwd = settings["password"]
|
||||
if pwd["type"] == "ocivault":
|
||||
authentication = pwd.setdefault("authentication", {})
|
||||
authentication.setdefault("method", auth_method)
|
||||
authentication["credential"] = credential
|
||||
|
||||
# config cache settings
|
||||
config["config_time_to_live"] = settings.get("config_time_to_live")
|
||||
config["config_time_to_live_grace_period"] = settings.get(
|
||||
"config_time_to_live_grace_period"
|
||||
)
|
||||
|
||||
# pyo parameters settings
|
||||
config["pyo"] = settings.get("pyo", None)
|
||||
|
||||
# set the configuration
|
||||
connect_params.set_from_config(config)
|
||||
|
||||
|
||||
def _get_credential(parameters):
|
||||
"""
|
||||
Returns the appropriate credential given the input supplied by the original
|
||||
connect string.
|
||||
"""
|
||||
auth_method = parameters.get("authentication", parameters.get("method"))
|
||||
|
||||
if auth_method is not None:
|
||||
auth_method = auth_method.upper()
|
||||
|
||||
# if region is not in connection string, retrieve from object server name.
|
||||
region = parameters.get(
|
||||
"oci_region", _retrieve_region(parameters.get("objservername"))
|
||||
)
|
||||
|
||||
try:
|
||||
if auth_method is None or auth_method == "OCI_DEFAULT":
|
||||
# Default Authentication
|
||||
# default path ~/.oci/config
|
||||
return oci_from_file(), None
|
||||
except oci.exceptions.ClientError:
|
||||
# try to create config with connection string parameters.
|
||||
if "oci_tenancy" in parameters and "oci_user" in parameters:
|
||||
with open(parameters["oci_key_file"], "r") as file_content:
|
||||
public_key = file_content.read()
|
||||
provider = dict(
|
||||
tenancy=parameters["oci_tenancy"],
|
||||
user=parameters["oci_user"],
|
||||
fingerprint=parameters["oci_fingerprint"],
|
||||
key_file=parameters["oci_key_file"],
|
||||
private_key_content=public_key,
|
||||
region=region,
|
||||
)
|
||||
return provider, None
|
||||
|
||||
if auth_method == "OCI_INSTANCE_PRINCIPAL":
|
||||
signer = oci.auth.signers.InstancePrincipalsSecurityTokenSigner()
|
||||
return (
|
||||
dict(region=region),
|
||||
signer,
|
||||
)
|
||||
|
||||
elif auth_method == "OCI_RESOURCE_PRINCIPAL":
|
||||
signer = oci.auth.signers.get_resource_principals_signer()
|
||||
return {}, signer
|
||||
else:
|
||||
msg = "Authentication options were not available in Connection String"
|
||||
raise Exception(msg)
|
||||
|
||||
|
||||
def _get_required_parameter(parameters, name, location="connection string"):
|
||||
try:
|
||||
return parameters[name]
|
||||
except KeyError:
|
||||
message = f'Parameter named "{name}" is missing from {location}'
|
||||
raise Exception(message) from None
|
||||
|
||||
|
||||
def _parse_parameters(protocol_arg: str) -> dict:
|
||||
"""
|
||||
Parse the parameters from the protocol argument string.
|
||||
"""
|
||||
pos = protocol_arg.find("?")
|
||||
parsed_url = urlparse(protocol_arg[pos + 1 :])
|
||||
parsed_values = parse_qs(parsed_url.path)
|
||||
parameters = {
|
||||
key.lower(): value[0] for key, value in parsed_values.items()
|
||||
}
|
||||
|
||||
match = cloud_net_naming_pattern_oci.match(protocol_arg[:pos])
|
||||
if match:
|
||||
parameters["objservername"] = match.group("objservername")
|
||||
parameters["namespace"] = match.group("namespace")
|
||||
parameters["bucketname"] = match.group("bucketname")
|
||||
parameters["filename"] = match.group("filename")
|
||||
if match.group("alias"):
|
||||
parameters["alias"] = match.group("alias")
|
||||
return parameters
|
||||
|
||||
|
||||
def password_type_oci_vault_hook(args):
|
||||
secret_id = _get_required_parameter(
|
||||
args, "value", '"password" key section'
|
||||
)
|
||||
authentication = args.get("authentication")
|
||||
if authentication is None:
|
||||
raise Exception(
|
||||
"OCI Key Vault authentication details were not provided."
|
||||
)
|
||||
|
||||
# if credentials are not present, create credentials with given
|
||||
# authentication details.
|
||||
credential = authentication.get("credential")
|
||||
if credential is None:
|
||||
credential, signer = _get_credential(authentication)
|
||||
|
||||
auth_method = authentication.get("method")
|
||||
if auth_method is not None:
|
||||
auth_method = auth_method.upper()
|
||||
if auth_method is None or auth_method == "OCI_DEFAULT":
|
||||
secret_client_oci = oci_secrets_client(credential)
|
||||
elif auth_method == "OCI_INSTANCE_PRINCIPAL":
|
||||
signer = oci.auth.signers.InstancePrincipalsSecurityTokenSigner()
|
||||
secret_client_oci = oci_secrets_client(
|
||||
config=credential, signer=signer
|
||||
)
|
||||
elif auth_method == "OCI_RESOURCE_PRINCIPAL":
|
||||
signer = oci.auth.signers.get_resource_principals_signer()
|
||||
secret_client_oci = oci_secrets_client(
|
||||
config=credential, signer=signer
|
||||
)
|
||||
|
||||
get_secret_bundle_response = secret_client_oci.get_secret_bundle(
|
||||
secret_id=secret_id
|
||||
)
|
||||
# decoding the vault content
|
||||
b64content = get_secret_bundle_response.data.secret_bundle_content.content
|
||||
return base64.b64decode(b64content).decode()
|
||||
|
||||
|
||||
def _retrieve_region(objservername):
|
||||
if objservername is not None:
|
||||
arr = objservername.split(".")
|
||||
return arr[1].lower().replace("_", "-")
|
||||
|
||||
|
||||
def _stream_to_string(stream):
|
||||
return b"".join(stream).decode()
|
||||
|
||||
|
||||
def config_oci_hook(
|
||||
protocol: str, protocol_arg: str, connect_params: oracledb.ConnectParams
|
||||
):
|
||||
"""
|
||||
Hook for handling parameters stored in an OCI Object store.
|
||||
"""
|
||||
parameters = _parse_parameters(protocol_arg)
|
||||
_get_config(parameters, connect_params)
|
||||
|
||||
|
||||
oracledb.register_password_type("ocivault", password_type_oci_vault_hook)
|
||||
oracledb.register_protocol("config-ociobject", config_oci_hook)
|
||||
169
.venv/lib/python3.9/site-packages/oracledb/plugins/oci_tokens.py
Normal file
169
.venv/lib/python3.9/site-packages/oracledb/plugins/oci_tokens.py
Normal file
@@ -0,0 +1,169 @@
|
||||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2024, 2025, 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.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# oci_tokens.py
|
||||
#
|
||||
# Methods that generates an OCI access token using the OCI SDK
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
import oci
|
||||
import oracledb
|
||||
from cryptography.hazmat.primitives.asymmetric import rsa
|
||||
from cryptography.hazmat.primitives import serialization
|
||||
|
||||
|
||||
def generate_token(token_auth_config, refresh=False):
|
||||
"""
|
||||
Generates an OCI access token based on provided credentials.
|
||||
"""
|
||||
user_auth_type = token_auth_config.get("auth_type") or ""
|
||||
auth_type = user_auth_type.lower()
|
||||
if auth_type == "configfileauthentication":
|
||||
return _config_file_based_authentication(token_auth_config)
|
||||
elif auth_type == "simpleauthentication":
|
||||
return _simple_authentication(token_auth_config)
|
||||
elif auth_type == "instanceprincipal":
|
||||
return _instance_principal_authentication(token_auth_config)
|
||||
else:
|
||||
raise ValueError(
|
||||
f"Unrecognized auth_type authentication method {user_auth_type}"
|
||||
)
|
||||
|
||||
|
||||
def _get_key_pair():
|
||||
"""
|
||||
Generates a public-private key pair for proof of possession.
|
||||
"""
|
||||
private_key = rsa.generate_private_key(
|
||||
public_exponent=65537,
|
||||
key_size=4096,
|
||||
)
|
||||
private_key_pem = private_key.private_bytes(
|
||||
encoding=serialization.Encoding.PEM,
|
||||
format=serialization.PrivateFormat.PKCS8,
|
||||
encryption_algorithm=serialization.NoEncryption(),
|
||||
).decode("utf-8")
|
||||
|
||||
public_key_pem = (
|
||||
private_key.public_key()
|
||||
.public_bytes(
|
||||
encoding=serialization.Encoding.PEM,
|
||||
format=serialization.PublicFormat.SubjectPublicKeyInfo,
|
||||
)
|
||||
.decode("utf-8")
|
||||
)
|
||||
|
||||
if not oracledb.is_thin_mode():
|
||||
p_key = "".join(
|
||||
line.strip()
|
||||
for line in private_key_pem.splitlines()
|
||||
if not (
|
||||
line.startswith("-----BEGIN") or line.startswith("-----END")
|
||||
)
|
||||
)
|
||||
private_key_pem = p_key
|
||||
|
||||
return {"private_key": private_key_pem, "public_key": public_key_pem}
|
||||
|
||||
|
||||
def _generate_access_token(client, token_auth_config):
|
||||
"""
|
||||
Token generation logic used by authentication methods.
|
||||
"""
|
||||
key_pair = _get_key_pair()
|
||||
scope = token_auth_config.get("scope", "urn:oracle:db::id::*")
|
||||
|
||||
details = oci.identity_data_plane.models.GenerateScopedAccessTokenDetails(
|
||||
scope=scope, public_key=key_pair["public_key"]
|
||||
)
|
||||
response = client.generate_scoped_access_token(
|
||||
generate_scoped_access_token_details=details
|
||||
)
|
||||
|
||||
return (response.data.token, key_pair["private_key"])
|
||||
|
||||
|
||||
def _config_file_based_authentication(token_auth_config):
|
||||
"""
|
||||
Config file base authentication implementation: config parameters
|
||||
are provided in a file.
|
||||
"""
|
||||
file_location = token_auth_config.get(
|
||||
"file_location", oci.config.DEFAULT_LOCATION
|
||||
)
|
||||
profile = token_auth_config.get("profile", oci.config.DEFAULT_PROFILE)
|
||||
|
||||
# Load OCI config
|
||||
config = oci.config.from_file(file_location, profile)
|
||||
oci.config.validate_config(config)
|
||||
|
||||
# Initialize service client with default config file
|
||||
client = oci.identity_data_plane.DataplaneClient(config)
|
||||
|
||||
return _generate_access_token(client, token_auth_config)
|
||||
|
||||
|
||||
def _simple_authentication(token_auth_config):
|
||||
"""
|
||||
Simple authentication: config parameters are passed as parameters
|
||||
"""
|
||||
config = {
|
||||
"user": token_auth_config["user"],
|
||||
"key_file": token_auth_config["key_file"],
|
||||
"fingerprint": token_auth_config["fingerprint"],
|
||||
"tenancy": token_auth_config["tenancy"],
|
||||
"region": token_auth_config["region"],
|
||||
"profile": token_auth_config["profile"],
|
||||
}
|
||||
oci.config.validate_config(config)
|
||||
|
||||
client = oci.identity_data_plane.DataplaneClient(config)
|
||||
return _generate_access_token(client, token_auth_config)
|
||||
|
||||
|
||||
def _instance_principal_authentication(token_auth_config):
|
||||
"""
|
||||
Instance principal authentication: for compute instances
|
||||
with dynamic group access.
|
||||
"""
|
||||
signer = oci.auth.signers.InstancePrincipalsSecurityTokenSigner()
|
||||
client = oci.identity_data_plane.DataplaneClient(config={}, signer=signer)
|
||||
return _generate_access_token(client, token_auth_config)
|
||||
|
||||
|
||||
def oci_token_hook(params: oracledb.ConnectParams):
|
||||
"""
|
||||
OCI-specific hook for generating a token.
|
||||
"""
|
||||
if params.extra_auth_params is not None:
|
||||
|
||||
def token_callback(refresh):
|
||||
return generate_token(params.extra_auth_params, refresh)
|
||||
|
||||
params.set(access_token=token_callback)
|
||||
|
||||
|
||||
# Register the token hook for OCI
|
||||
oracledb.register_params_hook(oci_token_hook)
|
||||
1704
.venv/lib/python3.9/site-packages/oracledb/pool.py
Normal file
1704
.venv/lib/python3.9/site-packages/oracledb/pool.py
Normal file
File diff suppressed because it is too large
Load Diff
1017
.venv/lib/python3.9/site-packages/oracledb/pool_params.py
Normal file
1017
.venv/lib/python3.9/site-packages/oracledb/pool_params.py
Normal file
File diff suppressed because it is too large
Load Diff
0
.venv/lib/python3.9/site-packages/oracledb/py.typed
Normal file
0
.venv/lib/python3.9/site-packages/oracledb/py.typed
Normal file
746
.venv/lib/python3.9/site-packages/oracledb/soda.py
Normal file
746
.venv/lib/python3.9/site-packages/oracledb/soda.py
Normal file
@@ -0,0 +1,746 @@
|
||||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2021, 2025, 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, Optional, Union
|
||||
from typing_extensions import Self
|
||||
import json
|
||||
|
||||
from .base import BaseMetaClass
|
||||
from . import errors
|
||||
|
||||
|
||||
class SodaDatabase(metaclass=BaseMetaClass):
|
||||
def __repr__(self):
|
||||
cls_name = self.__class__._public_name
|
||||
return f"<{cls_name} on {self._conn!r}>"
|
||||
|
||||
@classmethod
|
||||
def _from_impl(cls, conn, impl):
|
||||
db = cls.__new__(cls)
|
||||
db._conn = conn
|
||||
db._impl = impl
|
||||
return db
|
||||
|
||||
def _create_doc_impl(
|
||||
self, content: Any, key: str = None, media_type: str = None
|
||||
) -> "SodaDocument":
|
||||
"""
|
||||
Internal method used for creating a document implementation object with
|
||||
the given content, key and media type.
|
||||
"""
|
||||
if isinstance(content, str):
|
||||
content_bytes = content.encode()
|
||||
elif isinstance(content, bytes):
|
||||
content_bytes = content
|
||||
elif self._impl.supports_json:
|
||||
return self._impl.create_json_document(content, key)
|
||||
else:
|
||||
content_bytes = json.dumps(content).encode()
|
||||
return self._impl.create_document(content_bytes, key, media_type)
|
||||
|
||||
def createCollection(
|
||||
self,
|
||||
name: str,
|
||||
metadata: Optional[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: Optional[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
|
||||
:attr:`~SodaDoc.createdOn`, :attr:`~SodaDoc.lastModified`, and
|
||||
:attr:`~SodaDoc.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.
|
||||
"""
|
||||
doc_impl = self._create_doc_impl(content, key, mediaType)
|
||||
return SodaDocument._from_impl(doc_impl)
|
||||
|
||||
def getCollectionNames(
|
||||
self, startName: Optional[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(metaclass=BaseMetaClass):
|
||||
@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
|
||||
return self._db._create_doc_impl(arg)
|
||||
|
||||
def createIndex(self, spec: Union[dict, str]) -> None:
|
||||
"""
|
||||
Creates an index on a SODA collection.
|
||||
|
||||
The ``spec`` parameter 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
|
||||
does not normally permit. This is only applicable to spatial and JSON
|
||||
search indexes.
|
||||
|
||||
A boolean value is returned indicating if the index was actually
|
||||
dropped.
|
||||
"""
|
||||
return self._impl.drop_index(name, force)
|
||||
|
||||
def find(self) -> "SodaOperation":
|
||||
"""
|
||||
Begins 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.
|
||||
|
||||
This method requires Oracle Client 18.5 (or later) and is available
|
||||
only as a preview.
|
||||
"""
|
||||
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: Optional[str] = None
|
||||
) -> list["SodaDocument"]:
|
||||
"""
|
||||
Similar to :meth:`SodaCollection.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 later (or Oracle Client 19 from 19.11).
|
||||
|
||||
This method requires Oracle Client 18.5 (or later).
|
||||
"""
|
||||
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: Optional[str] = None
|
||||
) -> "SodaDocument":
|
||||
"""
|
||||
Similar to :meth:`~SodaCollection.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 later (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:
|
||||
"""
|
||||
Returns a list of specifications for the indexes found on the
|
||||
collection.
|
||||
|
||||
This method requires Oracle Client 21.3 or later (or Oracle Client 19
|
||||
from 19.13).
|
||||
"""
|
||||
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
|
||||
:meth:`~SodaCollection.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.
|
||||
|
||||
This method requires Oracle Client 19.9 (or later) in addition to the
|
||||
usual SODA requirements.
|
||||
"""
|
||||
doc_impl = self._process_doc_arg(doc)
|
||||
self._impl.save(doc_impl, hint=None, return_doc=False)
|
||||
|
||||
def saveAndGet(
|
||||
self, doc: Any, hint: Optional[str] = None
|
||||
) -> "SodaDocument":
|
||||
"""
|
||||
Saves a document into the collection. This method is equivalent to
|
||||
:meth:`~SodaCollection.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 later (or Oracle Client 19 from 19.11).
|
||||
|
||||
This method requires Oracle Client 19.9 (or later) in addition to the
|
||||
usual SODA requirements.
|
||||
"""
|
||||
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(metaclass=BaseMetaClass):
|
||||
@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
|
||||
:meth:`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.
|
||||
"""
|
||||
content, encoding = self._impl.get_content()
|
||||
if isinstance(content, bytes) and self.mediaType == "application/json":
|
||||
return json.loads(content.decode(encoding))
|
||||
return content
|
||||
|
||||
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, encoding = self._impl.get_content()
|
||||
if isinstance(content, bytes):
|
||||
return content
|
||||
elif content is not None:
|
||||
return str(content).encode()
|
||||
|
||||
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, encoding = self._impl.get_content()
|
||||
if isinstance(content, bytes):
|
||||
return content.decode(encoding)
|
||||
elif content is not None:
|
||||
return str(content)
|
||||
|
||||
@property
|
||||
def key(self) -> str:
|
||||
"""
|
||||
This read-only attribute returns the unique key assigned to this
|
||||
document. Documents created by :meth:`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
|
||||
:meth:`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 :meth:`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 :meth:`SodaDatabase.createDocument()` or fetched
|
||||
from collections where this attribute is not stored will return *None*.
|
||||
"""
|
||||
return self._impl.get_version()
|
||||
|
||||
|
||||
class SodaDocCursor(metaclass=BaseMetaClass):
|
||||
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:
|
||||
"""
|
||||
Closes the cursor now, rather than whenever __del__ is called. The
|
||||
cursor will be unusable from this point forward; an Error exception
|
||||
will be raised if any operation is attempted with the cursor.
|
||||
"""
|
||||
if self._impl is None:
|
||||
errors._raise_err(errors.ERR_CURSOR_NOT_OPEN)
|
||||
self._impl.close()
|
||||
self._impl = None
|
||||
|
||||
|
||||
class SodaOperation(metaclass=BaseMetaClass):
|
||||
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 :meth:`~SodaOperation.skip()` or
|
||||
:meth:`~SodaOperation.limit()` were called on this object, an
|
||||
exception is raised.
|
||||
"""
|
||||
return self._collection._impl.get_count(self)
|
||||
|
||||
def fetchArraySize(self, value: int) -> Self:
|
||||
"""
|
||||
This is a tuning method to specify the number of documents that are
|
||||
internally fetched in batches by calls to
|
||||
:meth:`~SodaOperation.getCursor()` and
|
||||
:meth:`~SodaOperation.getDocuments()`. It does not affect how many
|
||||
documents are returned to the application.
|
||||
|
||||
If ``fetchArraySize()`` is not used, or the ``value`` parameter is *0*,
|
||||
the array size will default to *100*.
|
||||
|
||||
As a convenience, the SodaOperation object is returned so that further
|
||||
criteria can be specified by chaining methods together.
|
||||
|
||||
This method is only available when using Oracle Client 19.5, or later.
|
||||
"""
|
||||
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]) -> Self:
|
||||
"""
|
||||
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.
|
||||
|
||||
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["SodaDocument"]:
|
||||
"""
|
||||
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) -> Self:
|
||||
"""
|
||||
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 later (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) -> Self:
|
||||
"""
|
||||
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 later (or Oracle Client 19 from 19.11).
|
||||
|
||||
The next commit or rollback on the connection made after the operation
|
||||
is performed will "unlock" the documents. Ensure that the connection is
|
||||
not in autocommit mode or the documents will be unlocked immediately
|
||||
after the operation is complete.
|
||||
|
||||
This method should only be used with read operations (other than
|
||||
:func:`~SodaOperation.count()`) and should not be used in conjunction
|
||||
with non-terminal methods :meth:`~SodaOperation.skip()` and
|
||||
:meth:`~SodaOperation.limit()`.
|
||||
|
||||
If this method is specified in conjunction with a write operation, this
|
||||
method is ignored.
|
||||
|
||||
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) -> Self:
|
||||
"""
|
||||
Specifies that the document with the specified key should be returned.
|
||||
This causes any previous calls made to this method and
|
||||
:meth:`~SodaOperation.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) -> Self:
|
||||
"""
|
||||
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 :meth:`~SodaOperation.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) -> Self:
|
||||
"""
|
||||
Specifies that only the specified number of documents should be
|
||||
returned. This method is only usable for read operations such as
|
||||
:meth:`~SodaOperation.getCursor()` and
|
||||
:meth:`~SodaOperation.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 :meth:`~SodaOperation.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":
|
||||
"""
|
||||
Similar to :meth:`~SodaOperation.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) -> Self:
|
||||
"""
|
||||
Specifies the number of documents that match the other criteria that
|
||||
will be skipped. This method is only usable for read operations such as
|
||||
:meth:`~SodaOperation.getOne()`, :meth:`~SodaOperation.getCursor()`,
|
||||
and :meth:`~SodaOperation.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) -> Self:
|
||||
"""
|
||||
Specifies that documents with the specified version should be returned.
|
||||
Typically this is used with :meth:`~SodaOperation.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
|
||||
114
.venv/lib/python3.9/site-packages/oracledb/sparse_vector.py
Normal file
114
.venv/lib/python3.9/site-packages/oracledb/sparse_vector.py
Normal file
@@ -0,0 +1,114 @@
|
||||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2024, 2025, 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.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# sparse_vector.py
|
||||
#
|
||||
# Contains the SparseVector class which stores information about a sparse
|
||||
# vector. Sparse vectors are available in Oracle Database 23.6 and higher.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
import array
|
||||
from typing import Union
|
||||
|
||||
from .base import BaseMetaClass
|
||||
from .base_impl import get_array_type_code_uint32, SparseVectorImpl
|
||||
|
||||
ARRAY_TYPE_CODE_UINT32 = get_array_type_code_uint32()
|
||||
|
||||
|
||||
class SparseVector(metaclass=BaseMetaClass):
|
||||
"""
|
||||
Provides information about sparse vectors.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
num_dimensions: int,
|
||||
indices: Union[list, array.array],
|
||||
values: Union[list, array.array],
|
||||
):
|
||||
"""
|
||||
Creates and returns a :ref:`SparseVector object <sparsevectorsobj>`.
|
||||
|
||||
The ``num_dimensions`` parameter is the number of dimensions contained
|
||||
in the vector.
|
||||
|
||||
The ``indices`` parameter is the indices (zero-based) of non-zero
|
||||
values in the vector.
|
||||
|
||||
The ``values`` parameter is the non-zero values stored in the vector.
|
||||
"""
|
||||
if (
|
||||
not isinstance(indices, array.array)
|
||||
or indices.typecode != ARRAY_TYPE_CODE_UINT32
|
||||
):
|
||||
indices = array.array(ARRAY_TYPE_CODE_UINT32, indices)
|
||||
if not isinstance(values, array.array):
|
||||
values = array.array("d", values)
|
||||
if len(indices) != len(values):
|
||||
raise TypeError("indices and values must be of the same length!")
|
||||
self._impl = SparseVectorImpl.from_values(
|
||||
num_dimensions, indices, values
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
cls_name = self.__class__._public_name
|
||||
return (
|
||||
f"{cls_name}({self.num_dimensions}, "
|
||||
f"{self.indices}, {self.values})"
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return (
|
||||
f"[{self.num_dimensions}, {list(self.indices)}, "
|
||||
f"{list(self.values)}]"
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def _from_impl(cls, impl):
|
||||
vector = cls.__new__(cls)
|
||||
vector._impl = impl
|
||||
return vector
|
||||
|
||||
@property
|
||||
def indices(self) -> array.array:
|
||||
"""
|
||||
Returns the indices (zero-based) of non-zero values in the vector.
|
||||
"""
|
||||
return self._impl.indices
|
||||
|
||||
@property
|
||||
def num_dimensions(self) -> int:
|
||||
"""
|
||||
Returns the number of dimensions contained in the vector.
|
||||
"""
|
||||
return self._impl.num_dimensions
|
||||
|
||||
@property
|
||||
def values(self) -> array.array:
|
||||
"""
|
||||
Returns the non-zero values stored in the vector.
|
||||
"""
|
||||
return self._impl.values
|
||||
378
.venv/lib/python3.9/site-packages/oracledb/subscr.py
Normal file
378
.venv/lib/python3.9/site-packages/oracledb/subscr.py
Normal file
@@ -0,0 +1,378 @@
|
||||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2021, 2025, 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, Optional, Union
|
||||
from .base import BaseMetaClass
|
||||
from . import connection
|
||||
|
||||
|
||||
class Subscription(metaclass=BaseMetaClass):
|
||||
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:
|
||||
"""
|
||||
This read-only attribute returns the callback that was registered when
|
||||
the subscription was created.
|
||||
"""
|
||||
return self._impl.callback
|
||||
|
||||
@property
|
||||
def connection(self) -> "connection.Connection":
|
||||
"""
|
||||
This read-only attribute returns the connection that was used to
|
||||
register the subscription when it was created.
|
||||
"""
|
||||
return self._impl.connection
|
||||
|
||||
@property
|
||||
def id(self) -> int:
|
||||
"""
|
||||
This read-only attribute 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:
|
||||
"""
|
||||
This read-only attribute 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:
|
||||
"""
|
||||
This read-only attribute returns the name used to register the
|
||||
subscription when it was created.
|
||||
"""
|
||||
return self._impl.name
|
||||
|
||||
@property
|
||||
def namespace(self) -> int:
|
||||
"""
|
||||
This read-only attribute returns the namespace used to register the
|
||||
subscription when it was created.
|
||||
"""
|
||||
return self._impl.namespace
|
||||
|
||||
@property
|
||||
def operations(self) -> int:
|
||||
"""
|
||||
This read-only attribute 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:
|
||||
"""
|
||||
This read-only attribute returns the port used for callback
|
||||
notifications from the database server. If not set during
|
||||
construction, this value is *0*.
|
||||
"""
|
||||
return self._impl.port
|
||||
|
||||
@property
|
||||
def protocol(self) -> int:
|
||||
"""
|
||||
This read-only attribute returns the protocol used to register the
|
||||
subscription when it was created.
|
||||
"""
|
||||
return self._impl.protocol
|
||||
|
||||
@property
|
||||
def qos(self) -> int:
|
||||
"""
|
||||
This read-only attribute 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: Optional[Union[list, dict]] = None
|
||||
) -> int:
|
||||
"""
|
||||
Registers the query for subsequent notification when tables referenced
|
||||
by the query are changed. This behaves similarly to
|
||||
:meth:`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
|
||||
:data:`oracledb.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:
|
||||
"""
|
||||
This read-only attribute 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(metaclass=BaseMetaClass):
|
||||
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]:
|
||||
"""
|
||||
This read-only attribute returns the name of the consumer which
|
||||
generated the notification. It will be populated if the
|
||||
subscription was created with the namespace
|
||||
:data:`oracledb.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]:
|
||||
"""
|
||||
This read-only attribute returns the name of the database that
|
||||
generated the notification.
|
||||
"""
|
||||
return self._dbname
|
||||
|
||||
@property
|
||||
def msgid(self) -> Union[bytes, None]:
|
||||
"""
|
||||
This read-only attribute returns the message id of the AQ message that
|
||||
generated the notification. It will only be populated if the
|
||||
subscription was created with the namespace
|
||||
:data:`oracledb.SUBSCR_NAMESPACE_AQ`.
|
||||
"""
|
||||
return self._msgid
|
||||
|
||||
@property
|
||||
def queries(self) -> list["MessageQuery"]:
|
||||
"""
|
||||
This read-only attribute 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 :data:`~oracledb.SUBSCR_QOS_QUERY` when the
|
||||
subscription was created.
|
||||
"""
|
||||
return self._queries
|
||||
|
||||
@property
|
||||
def queue_name(self) -> Union[str, None]:
|
||||
"""
|
||||
This read-only attribute returns the name of the queue which generated
|
||||
the notification. It will only be populated if the subscription was
|
||||
created with the namespace :data:`oracledb.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:
|
||||
"""
|
||||
This read-only attribute 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
|
||||
:data:`oracledb.SUBSCR_QOS_DEREG_NFY` is used).
|
||||
"""
|
||||
return self._registered
|
||||
|
||||
@property
|
||||
def subscription(self) -> Subscription:
|
||||
"""
|
||||
This read-only attribute returns the subscription object for which this
|
||||
notification was generated.
|
||||
"""
|
||||
return self._subscription
|
||||
|
||||
@property
|
||||
def tables(self) -> list["MessageTable"]:
|
||||
"""
|
||||
This read-only attribute 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 :data:`~oracledb.SUBSCR_QOS_QUERY` when the subscription was
|
||||
created.
|
||||
"""
|
||||
return self._tables
|
||||
|
||||
@property
|
||||
def txid(self) -> Union[bytes, None]:
|
||||
"""
|
||||
This read-only attribute returns the id of the transaction that
|
||||
generated the notification.
|
||||
"""
|
||||
return self._txid
|
||||
|
||||
@property
|
||||
def type(self) -> int:
|
||||
"""
|
||||
This read-only attribute returns the type of message that has been
|
||||
sent.
|
||||
"""
|
||||
return self._type
|
||||
|
||||
|
||||
class MessageQuery(metaclass=BaseMetaClass):
|
||||
def __init__(self) -> None:
|
||||
self._id = 0
|
||||
self._operation = 0
|
||||
self._tables = []
|
||||
|
||||
@property
|
||||
def id(self) -> int:
|
||||
"""
|
||||
This read-only attribute returns the query id of the query for which
|
||||
the result set changed. The value will match the value returned by
|
||||
:meth:`Subscription.registerquery()` when the related query was
|
||||
registered.
|
||||
"""
|
||||
return self._id
|
||||
|
||||
@property
|
||||
def operation(self) -> int:
|
||||
"""
|
||||
This read-only attribute returns the operation that took place on the
|
||||
query result set that was changed. Valid values for this attribute are
|
||||
:data:`~oracledb.EVENT_DEREG` and :data:`~oracledb.EVENT_QUERYCHANGE`.
|
||||
"""
|
||||
return self._operation
|
||||
|
||||
@property
|
||||
def tables(self) -> list["MessageTable"]:
|
||||
"""
|
||||
This read-only attribute 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(metaclass=BaseMetaClass):
|
||||
def __init__(self) -> None:
|
||||
self._operation = 0
|
||||
self._rowid = None
|
||||
|
||||
@property
|
||||
def operation(self) -> int:
|
||||
"""
|
||||
This read-only attribute returns the operation that took place on the
|
||||
row that was changed.
|
||||
"""
|
||||
return self._operation
|
||||
|
||||
@property
|
||||
def rowid(self) -> Union[str, None]:
|
||||
"""
|
||||
This read-only attribute returns the rowid of the row that was changed.
|
||||
"""
|
||||
return self._rowid
|
||||
|
||||
|
||||
class MessageTable(metaclass=BaseMetaClass):
|
||||
def __init__(self) -> None:
|
||||
self._name = None
|
||||
self._operation = 0
|
||||
self._rows = []
|
||||
|
||||
@property
|
||||
def name(self) -> Union[str, None]:
|
||||
"""
|
||||
This read-only attribute returns the name of the table that was
|
||||
changed.
|
||||
"""
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def operation(self) -> int:
|
||||
"""
|
||||
This read-only attribute returns the operation that took place on the
|
||||
table that was changed.
|
||||
"""
|
||||
return self._operation
|
||||
|
||||
@property
|
||||
def rows(self) -> list["MessageRow"]:
|
||||
"""
|
||||
This read-only attribute 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
|
||||
:meth:`Connection.subscribe()` method included the flag
|
||||
:data:`~oracledb.SUBSCR_QOS_ROWIDS`.
|
||||
"""
|
||||
return self._rows
|
||||
Binary file not shown.
Binary file not shown.
392
.venv/lib/python3.9/site-packages/oracledb/utils.py
Normal file
392
.venv/lib/python3.9/site-packages/oracledb/utils.py
Normal file
@@ -0,0 +1,392 @@
|
||||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2020, 2025, 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.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
import functools
|
||||
from typing import Any, Callable, Optional, Union
|
||||
import uuid
|
||||
|
||||
from .arrow_array import ArrowArray
|
||||
from .dataframe import DataFrame
|
||||
|
||||
from . import base_impl
|
||||
from . import driver_mode
|
||||
from . import errors
|
||||
from . import thick_impl
|
||||
|
||||
|
||||
def clientversion() -> tuple:
|
||||
"""
|
||||
This function can only be called when python-oracledb is in Thick mode.
|
||||
Using it in Thin mode will throw an exception.
|
||||
"""
|
||||
return thick_impl.clientversion()
|
||||
|
||||
|
||||
def enable_thin_mode():
|
||||
"""
|
||||
Makes python-oracledb be in Thin mode. After this method is called, Thick
|
||||
mode cannot be enabled. If python-oracledb is already in Thick mode, then
|
||||
calling ``enable_thin_mode()`` will fail. If Thin mode connections have
|
||||
already been opened, or a connection pool created in Thin mode, then
|
||||
calling ``enable_thin_mode()`` is a no-op.
|
||||
|
||||
Since python-oracledb defaults to Thin mode, almost all applications do not
|
||||
need to call this method. However, because it bypasses python-oracledb's
|
||||
internal mode-determination heuristic, it may be useful for applications
|
||||
with multiple threads that concurrently create :ref:`standalone connections
|
||||
<standaloneconnection>` when the application starts.
|
||||
"""
|
||||
with driver_mode.get_manager(requested_thin_mode=True):
|
||||
pass
|
||||
|
||||
|
||||
def from_arrow(obj: Any) -> Union[DataFrame, ArrowArray]:
|
||||
"""
|
||||
This method converts a data frame to a
|
||||
:ref:`DataFrame <oracledataframeobj>` or
|
||||
:ref:`ArrowArray <oraclearrowarrayobj>` instance.
|
||||
|
||||
If ``obj`` supports the Arrow PyCapsule interface ``__arrow_c_stream__``
|
||||
method, then ``from_arrow()`` returns the instance as a :ref:`DataFrame
|
||||
<oracledataframeobj>`. If ``obj`` does not support that method, but does
|
||||
support ``__arrow_c_array__``, then an :ref:`ArrowArray
|
||||
<oraclearrowarrayobj>` is returned.
|
||||
"""
|
||||
if hasattr(obj, "__arrow_c_stream__"):
|
||||
return DataFrame._from_arrow(obj)
|
||||
elif hasattr(obj, "__arrow_c_array__"):
|
||||
return ArrowArray._from_arrow(obj)
|
||||
msg = "object must implement the PyCapsule stream or array interfaces"
|
||||
raise ValueError(msg)
|
||||
|
||||
|
||||
def init_oracle_client(
|
||||
lib_dir: Optional[Union[str, bytes]] = None,
|
||||
config_dir: Optional[Union[str, bytes]] = None,
|
||||
error_url: Optional[str] = None,
|
||||
driver_name: Optional[str] = None,
|
||||
):
|
||||
"""
|
||||
Enables python-oracledb Thick mode by initializing the Oracle Client
|
||||
library, see :ref:`enablingthick`. If a standalone connection or pool has
|
||||
already been created in Thin mode, ``init_oracle_client()`` will raise an
|
||||
exception and python-oracledb will remain in Thin mode.
|
||||
|
||||
If a standalone connection or pool has *not* already been created in Thin
|
||||
mode, but ``init_oracle_client()`` raises an exception, python-oracledb
|
||||
will remain in Thin mode but further calls to ``init_oracle_client()`` can
|
||||
be made, if desired.
|
||||
|
||||
The ``init_oracle_client()`` method can be called multiple times in each
|
||||
Python process as long as the arguments are the same each time.
|
||||
|
||||
The ``lib_dir`` parameter is a string or a bytes object that specifies the
|
||||
directory containing Oracle Client libraries. If the ``lib_dir`` parameter
|
||||
is set, then the specified directory is the only one searched for the
|
||||
Oracle Client libraries; otherwise, the operating system library search
|
||||
path is used to locate the Oracle Client library. If you are using Python
|
||||
3.11 and later, then the value specified in this parameter is encoded
|
||||
using `locale.getencoding() <https://docs.python.org/3/library/locale.html
|
||||
#locale.getencoding>`__. For all other Python versions, the encoding
|
||||
"utf-8" is used. If a bytes object is specified in this parameter, then
|
||||
this value will be used as is without any encoding.
|
||||
|
||||
The ``config_dir`` parameter is a string or a bytes object that specifies
|
||||
the directory in which the
|
||||
:ref:`Optional Oracle Net Configuration <optnetfiles>` and
|
||||
:ref:`Optional Oracle Client Configuration <optclientfiles>` files reside.
|
||||
If the ``config_dir`` parameter is set, then the specified directory is
|
||||
used to find Oracle Client library configuration files. This is
|
||||
equivalent to setting the environment variable ``TNS_ADMIN`` and overrides
|
||||
any value already set in ``TNS_ADMIN``. If this parameter is not set, the
|
||||
:ref:`Oracle standard <usingconfigfiles>` way of locating Oracle Client
|
||||
library configuration files is used. If you are using Python 3.11 and
|
||||
later, then the value specified in this parameter is encoded using
|
||||
`locale.getencoding() <https://docs.python.org/3/library/locale.html#
|
||||
locale.getencoding>`__. For all other Python versions, the encoding
|
||||
"utf-8" is used. If a bytes object is specified in this parameter, then
|
||||
this value will be used as is without any encoding.
|
||||
|
||||
The ``error_url`` parameter is a string that specifies the URL which is
|
||||
included in the python-oracledb exception message if the Oracle Client
|
||||
libraries cannot be loaded. If the ``error_url`` parameter is set, then
|
||||
the specified value is included in the message of the exception raised
|
||||
when the Oracle Client library cannot be loaded; otherwise, the
|
||||
:ref:`installation` URL is included. This parameter lets your application
|
||||
display custom installation instructions.
|
||||
|
||||
The ``driver_name`` parameter is a string that specifies the driver name
|
||||
value. If the ``driver_name`` parameter is set, then the specified value
|
||||
can be found in database views that give information about connections.
|
||||
For example, it is in the CLIENT_DRIVER column of the
|
||||
V$SESSION_CONNECT_INFO view. From Oracle Database 12.2, the name displayed
|
||||
can be 30 characters. The standard is to set this value to ``"<name> :
|
||||
version>"``, where <name> is the name of the driver and <version> is its
|
||||
version. There should be a single space character before and after the
|
||||
colon. If this parameter is not set, then the value specified in
|
||||
:attr:`oracledb.defaults.driver_name <defaults.driver_name>` is used. If
|
||||
the value of this attribute is *None*, then the default value in
|
||||
python-oracledb Thick mode is like "python-oracledb thk : <version>". See
|
||||
:ref:`otherinit`.
|
||||
|
||||
At successful completion of a call to ``oracledb.init_oracle_client()``,
|
||||
the attribute :attr:`oracledb.defaults.config_dir <Defaults.config_dir>`
|
||||
will be set as determined below (first one wins):
|
||||
|
||||
- the value of the ``oracledb.init_oracle_client()`` parameter
|
||||
``config_dir``, if one was passed.
|
||||
|
||||
- the value of :attr:`oracledb.defaults.config_dir <Defaults.config_dir>`
|
||||
if it has one. i.e.
|
||||
:attr:`oracledb.defaults.config_dir <Defaults.config_dir>` remains
|
||||
unchanged after ``oracledb.init_oracle_client()`` completes.
|
||||
|
||||
- the value of the environment variable ``$TNS_ADMIN``, if it is set.
|
||||
|
||||
- the value of ``$ORACLE_HOME/network/admin`` if the environment variable
|
||||
``$ORACLE_HOME`` is set.
|
||||
|
||||
- the directory of the loaded Oracle Client library, appended with
|
||||
``network/admin``. Note this directory is not determinable on AIX.
|
||||
|
||||
- otherwise the value *None* is used. (Leaving
|
||||
:attr:`oracledb.defaults.config_dir <Defaults.config_dir>` unchanged).
|
||||
"""
|
||||
thick_impl.init_oracle_client(lib_dir, config_dir, error_url, driver_name)
|
||||
|
||||
|
||||
def normalize_sessionless_transaction_id(
|
||||
value: Optional[Union[bytes, str]] = None,
|
||||
) -> bytes:
|
||||
"""
|
||||
Normalize and validate the transaction_id.
|
||||
|
||||
- If `value` is a string, it's UTF-8 encoded.
|
||||
- If `value` is None, a UUID4-based transaction_id is generated.
|
||||
- If `value` is not str/bytes/None, raises TypeError.
|
||||
- If transaction_id exceeds 64 bytes, raises ValueError.
|
||||
|
||||
Returns:
|
||||
bytes: Normalized transaction_id
|
||||
"""
|
||||
if value is None:
|
||||
value = uuid.uuid4().bytes
|
||||
elif isinstance(value, str):
|
||||
value = value.encode("utf-8")
|
||||
elif not isinstance(value, bytes):
|
||||
raise TypeError("invalid transaction_id: must be str, bytes, or None")
|
||||
|
||||
if len(value) > 64:
|
||||
raise ValueError(
|
||||
f"transaction_id size exceeds 64 bytes (got {len(value)})"
|
||||
)
|
||||
|
||||
return value
|
||||
|
||||
|
||||
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).
|
||||
"""
|
||||
|
||||
@functools.wraps(f)
|
||||
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).
|
||||
"""
|
||||
|
||||
@functools.wraps(f)
|
||||
def wrapped_f(self, *args, **kwargs):
|
||||
f(self, *args, **kwargs)
|
||||
self._impl.set(kwargs)
|
||||
|
||||
return wrapped_f
|
||||
|
||||
|
||||
def register_params_hook(hook_function: Callable) -> None:
|
||||
"""
|
||||
Registers a user parameter hook function that will be called internally by
|
||||
python-oracledb prior to connection or pool creation. The hook function
|
||||
accepts a copy of the parameters that will be used to create the pool or
|
||||
standalone connection and may modify them. For example, the cloud native
|
||||
authentication plugins modify the "access_token" parameter with a function
|
||||
that will acquire the token using information found in the
|
||||
"extra_auth_parms" parameter.
|
||||
|
||||
Multiple hooks may be registered. They will be invoked in order of
|
||||
registration.
|
||||
"""
|
||||
if hook_function is None or not callable(hook_function):
|
||||
raise TypeError("hook_function must be a callable and cannot be None")
|
||||
base_impl.REGISTERED_PARAMS_HOOKS.append(hook_function)
|
||||
|
||||
|
||||
def register_password_type(
|
||||
password_type: str, hook_function: Callable
|
||||
) -> None:
|
||||
"""
|
||||
Registers a user password hook function that will be called internally by
|
||||
python-oracledb when a password is supplied as a dictionary containing the
|
||||
given ``password_type`` as the key "type". The hook function is called for
|
||||
passwords specified as the ``password``, ``newpassword`` and
|
||||
``wallet_parameter`` parameters in calls to :meth:`oracledb.connect()`,
|
||||
:meth:`oracledb.create_pool()`, :meth:`oracledb.connect_async()`, and
|
||||
:meth:`oracledb.create_pool_async()`.
|
||||
|
||||
Your hook function is expected to accept the dictionary supplied by the
|
||||
application and return the valid password.
|
||||
|
||||
Calling :meth:`~oracledb.register_password_type()` with the
|
||||
``hook_function`` parameter set to *None* will result in a previously
|
||||
registered user function being removed and the default behavior restored.
|
||||
"""
|
||||
if not isinstance(password_type, str):
|
||||
raise TypeError("password_type must be a string")
|
||||
if hook_function is not None and not callable(hook_function):
|
||||
raise TypeError("hook_function must be a callable")
|
||||
password_type = password_type.lower()
|
||||
if hook_function is None:
|
||||
base_impl.REGISTERED_PASSWORD_TYPES.pop(password_type)
|
||||
else:
|
||||
base_impl.REGISTERED_PASSWORD_TYPES[password_type] = hook_function
|
||||
|
||||
|
||||
def register_protocol(protocol: str, hook_function: Callable) -> None:
|
||||
"""
|
||||
Registers a user protocol hook function that will be called internally by
|
||||
python-oracledb Thin mode prior to connection or pool creation. The hook
|
||||
function will be invoked when :func:`oracledb.connect`,
|
||||
:func:`oracledb.create_pool`, :meth:`oracledb.connect_async()`, or
|
||||
:meth:`oracledb.create_pool_async()` are called with a ``dsn`` parameter
|
||||
value prefixed with the specified protocol. The user function will also be
|
||||
invoked when :meth:`ConnectParams.parse_connect_string()` is called in Thin
|
||||
or Thick modes with a similar ``connect_string`` parameter value.
|
||||
|
||||
Your hook function is expected to construct valid connection details. For
|
||||
example, if a hook function is registered for the "ldaps" protocol, then
|
||||
calling :func:`oracledb.connect` with a connection string prefixed with
|
||||
"ldaps://" will invoke the function. The function can then perform LDAP
|
||||
lookup to retrieve and set the actual database information that will be
|
||||
used internally by python-oracledb to complete the connection creation.
|
||||
|
||||
The ``protocol`` parameter is a string that will be matched against the
|
||||
prefix appearing before "://" in connection strings.
|
||||
|
||||
The ``hook_function`` parameter should be a function with the signature::
|
||||
|
||||
hook_function(protocol, protocol_arg, params)
|
||||
|
||||
The hook function will be called with the following arguments:
|
||||
|
||||
- The ``protocol`` parameter is the value that was registered.
|
||||
|
||||
- The ``protocol_arg`` parameter is the section after "://" in the
|
||||
connection string used in the connection or pool creation call, or passed
|
||||
to :meth:`~ConnectParams.parse_connect_string()`.
|
||||
|
||||
- The ``params`` parameter is an instance of :ref:`ConnectParams
|
||||
<connparam>`.
|
||||
|
||||
When your hook function is invoked internally prior to connection or pool
|
||||
creation, ``params`` will be the ConnectParams instance originally passed
|
||||
to the :func:`oracledb.connect`, :func:`oracledb.create_pool`,
|
||||
:meth:`oracledb.connect_async()`, or :meth:`oracledb.create_pool_async()`
|
||||
call, if such an instance was passed. Otherwise it will be a new
|
||||
ConnectParams instance. The hook function should parse ``protocol`` and
|
||||
``protocol_arg`` and take any desired action to update ``params``
|
||||
:ref:`attributes <connparamsattr>` with appropriate connection
|
||||
parameters. Attributes can be set using :meth:`ConnectParams.set()` or
|
||||
:meth:`ConnectParams.parse_connect_string()`. The ConnectParams instance
|
||||
will then be used to complete the connection or pool creation.
|
||||
|
||||
When your hook function is invoked by
|
||||
:meth:`ConnectParams.parse_connect_string()`, then ``params`` will be the
|
||||
invoking ConnectParams instance that you can update using
|
||||
:meth:`ConnectParams.set()` or
|
||||
:meth:`ConnectParams.parse_connect_string()`.
|
||||
|
||||
Internal hook functions for the "tcp" and "tcps" protocols are
|
||||
pre-registered but can be overridden if needed. If any other protocol has
|
||||
not been registered, then connecting will result in the error ``DPY-4021:
|
||||
invalid protocol``.
|
||||
|
||||
Calling :meth:`~oracledb.register_protocol()` with the ``hook_function``
|
||||
parameter set to *None* will result in a previously registered user
|
||||
function being removed and the default behavior restored.
|
||||
"""
|
||||
if not isinstance(protocol, str):
|
||||
raise TypeError("protocol must be a string")
|
||||
if hook_function is not None and not callable(hook_function):
|
||||
raise TypeError("hook_function must be a callable")
|
||||
protocol = protocol.lower()
|
||||
if hook_function is None:
|
||||
base_impl.REGISTERED_PROTOCOLS.pop(protocol)
|
||||
else:
|
||||
base_impl.REGISTERED_PROTOCOLS[protocol] = hook_function
|
||||
|
||||
|
||||
def unregister_params_hook(hook_function: Callable) -> None:
|
||||
"""
|
||||
Unregisters a user parameter function that was earlier registered with a
|
||||
call to :meth:`oracledb.register_params_hook()`.
|
||||
"""
|
||||
base_impl.REGISTERED_PARAMS_HOOKS.remove(hook_function)
|
||||
|
||||
|
||||
def verify_stored_proc_args(
|
||||
parameters: Union[list, tuple], keyword_parameters: dict
|
||||
) -> None:
|
||||
"""
|
||||
Verifies that the arguments to a call to a stored procedure or function
|
||||
are acceptable.
|
||||
"""
|
||||
if parameters is not None and not isinstance(parameters, (list, tuple)):
|
||||
errors._raise_err(errors.ERR_ARGS_MUST_BE_LIST_OR_TUPLE)
|
||||
if keyword_parameters is not None and not isinstance(
|
||||
keyword_parameters, dict
|
||||
):
|
||||
errors._raise_err(errors.ERR_KEYWORD_ARGS_MUST_BE_DICT)
|
||||
186
.venv/lib/python3.9/site-packages/oracledb/var.py
Normal file
186
.venv/lib/python3.9/site-packages/oracledb/var.py
Normal file
@@ -0,0 +1,186 @@
|
||||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2021, 2025, 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, Optional, Union
|
||||
from .dbobject import DbObjectType
|
||||
from .base import BaseMetaClass
|
||||
from .base_impl import DbType
|
||||
|
||||
|
||||
class Var(metaclass=BaseMetaClass):
|
||||
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.metadata.objtype is not None:
|
||||
var._type = DbObjectType._from_impl(impl.metadata.objtype)
|
||||
else:
|
||||
var._type = impl.metadata.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
|
||||
:meth:`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.metadata.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:
|
||||
"""
|
||||
Returns the value at the given position in the variable. For variables
|
||||
created using the method :meth:`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) -> Optional[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) -> Optional[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:
|
||||
"""
|
||||
Sets 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 the same
|
||||
value as the attribute buffer_size.
|
||||
"""
|
||||
return self._impl.metadata.max_size
|
||||
|
||||
@property
|
||||
def type(self) -> Union[DbType, DbObjectType]:
|
||||
"""
|
||||
This read-only attribute returns the type of the variable. This will be
|
||||
an :ref:`Oracle Object Type <dbobjecttype>` if the variable binds
|
||||
Oracle objects; otherwise, it will be one of the
|
||||
:ref:`database type constants <dbtypes>`.
|
||||
|
||||
Database type constants are now used when the variable is not used for
|
||||
binding Oracle objects.
|
||||
"""
|
||||
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()
|
||||
33
.venv/lib/python3.9/site-packages/oracledb/version.py
Normal file
33
.venv/lib/python3.9/site-packages/oracledb/version.py
Normal file
@@ -0,0 +1,33 @@
|
||||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2021, 2026, 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__ = "3.4.2"
|
||||
Reference in New Issue
Block a user