Rework to use the ODPI-C library instead of direct OCI calls.

This commit is contained in:
Anthony Tuininga 2017-03-07 13:21:49 -07:00
parent 856608e49c
commit b28e04e901
50 changed files with 5084 additions and 10102 deletions

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "odpi"]
path = odpi
url = ../odpi.git

View File

@ -1,54 +1,58 @@
Open Source Python/Oracle Utility - cx_Oracle
---------------------------------------------
cx_Oracle is a Python extension module that allows access to Oracle and
conforms to the Python database API 2.0 specifications with a number of
additions. The time data type is not supported by Oracle and is therefore not
implemented. The method cursor.nextset() is not implemented either as the DB
API specification assumes an implementation of cursors that does not fit well
with Oracle's implementation of cursors and implicit results. See the method
cx_Oracle is a Python extension module that enables access to Oracle databases
and conforms to the Python database API 2.0 specifications with a considerable
number of additions and a couple of exclusions. The time data type is not
supported by Oracle and is therefore not implemented. The method
cursor.nextset() is not implemented either as the DB API specification assumes
an implementation of cursors that does not fit well with Oracle's
implementation of cursors and implicit results. See the method
cursor.getimplicitresults() for more information.
See http://www.python.org/topics/database/DatabaseAPI-2.0.html for more
information on the Python database API specification. See the included
documentation for additional information.
information on the Python database API specification. See the documentation at
http://cx-oracle.readthedocs.io for a complete description of the module's
capabilities.
cx_Oracle is licensed under a BSD license which you can find at
http://cx-oracle.readthedocs.io/en/latest/license.html.
Please note that an Oracle client (or server) installation is required in order
to use cx_Oracle. If you do not require the tools that come with a full client
installation, it is recommended to install the Instant Client
(http://www.oracle.com/technetwork/database/features/instant-client/index.html)
which is far easier to install.
For feedback or patches, contact Anthony Tuininga at
anthony.tuininga@gmail.com. For help or to ask questions, please use the
mailing list at http://lists.sourceforge.net/lists/listinfo/cx-oracle-users.
Please note that an Oracle client (or server) installation is required in order
to use cx_Oracle. If you do not require the tools that come with a full client
installation, it is recommended to install the Instant Client which is far
easier to install.
Binary Install
--------------
Place the file cx_Oracle.pyd or cx_Oracle.so anywhere on your Python path.
Source Install
--------------
This module has been built with Oracle 11g and 12c on Linux, Windows and macOS.
Others have reported success with other platforms.
For simplified installation use pip
Installation
------------
Binaries for some platforms and Oracle versions are available at
https://pypi.python.org/pypi/cx_Oracle. If you prefer to build your own you
can use this command
pip install cx_Oracle
Otherwise, you can use the provided setup.py to build and install the module
which will download the source package, build and install it. Otherwise, you
can download the source package directly from PyPI, extract it and run these
commands instead
python setup.py build
python setup.py install
This module has been built with Oracle 10g, 11g and 12c on Linux and Windows.
Others have reported success with other platforms such as Mac OS X.
See BUILD.txt for additional information.
Usage Example
-------------
from __future__ import print_function
from __future__ import print_function # needed for Python 2.x
import cx_Oracle
@ -74,7 +78,3 @@ samples in the samples directory. You can also look at the scripts in the
cx_OracleTools (http://cx-oracletools.sourceforge.net) and the modules in the
cx_PyOracleLib (http://cx-pyoraclelib.sourceforge.net) projects.
For further information see
http://cx-oracle.readthedocs.io

View File

@ -40,9 +40,9 @@ author = 'Oracle'
# other places throughout the built documents.
#
# The short X.Y version.
version = '5.3'
version = '6.0'
# The full version, including alpha/beta/rc tags.
release = '5.3'
release = '6.0'
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:

View File

@ -135,6 +135,17 @@ Connection Object
Return a new :ref:`cursor object <cursorobj>` using the connection.
.. attribute:: Connection.dbop
This write-only attribute sets the database operation that is to be
monitored. This can be viewed in the DBOP_NAME column of the V$SQL_MONITOR
table.
.. note::
This attribute is an extension to the DB API definition.
.. method:: Connection.deq(name, options, msgproperties, payload)
Returns a message id after successfully dequeuing a message. The options
@ -247,6 +258,17 @@ Connection Object
This method is an extension to the DB API definition.
.. attribute:: Connection.handle
This read-only attribute returns the OCI service context handle for the
connection. It is primarily provided to facilitate testing the creation of a
connection using the OCI service context handle.
.. note::
This attribute is an extension to the DB API definition.
.. attribute:: Connection.inputtypehandler
This read-write attribute specifies a method called for each value that is
@ -430,7 +452,7 @@ Connection Object
This attribute is an extension to the DB API definition.
.. method:: Connection.subscribe(namespace=cx_Oracle.SUBSCR_NAMESPACE_DBCHANGE, protocol=cx_Oracle.SUBSCR_PROTO_OCI, callback=None, timeout=0, operations=OPCODE_ALLOPS, rowids=False, port=0, qos=0, cqqos=0)
.. method:: Connection.subscribe(namespace=cx_Oracle.SUBSCR_NAMESPACE_DBCHANGE, protocol=cx_Oracle.SUBSCR_PROTO_OCI, callback=None, timeout=0, operations=OPCODE_ALLOPS, port=0, qos=0)
Return a new :ref:`subscription object <subscrobj>` using the connection.
Currently the namespace and protocol arguments cannot have any other
@ -448,11 +470,6 @@ Connection Object
(insert, update, delete). The default value will send notifications for all
operations.
The rowids flag specifies whether the rowids of affected rows should be
included in the messages that are sent. This argument is deprecated and
will be removed in a future version of cx_Oracle. Use the value
:data:`~cx_Oracle.SUBSCR_QOS_ROWIDS` for the qos argument instead.
The port specifies the listening port for callback notifications from the
database server. If not specified, an unused port will be selected by the
database.
@ -465,9 +482,6 @@ Connection Object
:data:`cx_Oracle.SUBSCR_QOS_QUERY`,
:data:`cx_Oracle.SUBSCR_QOS_BEST_EFFORT`.
The cqqos argument is deprecated and will be removed in a future version of
cx_Oracle. The qos argument should be used instead.
.. note::
This method is an extension to the DB API definition.

View File

@ -337,24 +337,6 @@ Cursor Object
mentioned in PEP 249 as an optional extension.
.. attribute:: Cursor.numbersAsStrings
This integer attribute defines whether or not numbers should be returned as
strings rather than integers or floating point numbers. This is useful to
get around the fact that Oracle floating point numbers have considerably
greater precision than C floating point numbers and not require a change to
the SQL being executed.
.. deprecated:: 5.3
Use one of the attributes :attr:`Connection.outputtypehandler` or
:attr:`~Cursor.outputtypehandler` instead.
.. note::
The DB API definition does not define this attribute.
.. attribute:: Cursor.outputtypehandler
This read-write attribute specifies a method called for each column that is

View File

@ -8,12 +8,12 @@ License
.. centered:: **LICENSE AGREEMENT FOR CX_ORACLE**
Copyright |copy| 2016, 2017, Oracle and/or its affiliates. All rights reserved.
Copyright |copy| 2016-2017, Oracle and/or its affiliates. All rights reserved.
Portions Copyright |copy| 2007-2015, Anthony Tuininga. All rights reserved.
Copyright |copy| 2007-2015, Anthony Tuininga. All rights reserved.
Portions Copyright |copy| 2001-2007, Computronix (Canada) Ltd., Edmonton,
Alberta, Canada. All rights reserved.
Copyright |copy| 2001-2007, Computronix (Canada) Ltd., Edmonton, Alberta,
Canada. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

View File

@ -10,17 +10,6 @@ LOB Objects
:data:`CLOB`, :data:`BLOB` and :data:`BFILE` columns are fetched.
.. note::
Internally, Oracle uses LOB locators which are allocated based on the
cursor array size. Thus, it is important that the data in the LOB object be
manipulated before another internal fetch takes place. The safest way to do
this is to use the cursor as an iterator. In particular, do not use the
:meth:`Cursor.fetchall()` method. The exception "LOB variable no longer
valid after subsequent fetch" will be raised if an attempt to access a LOB
variable after a subsequent fetch is detected.
.. method:: LOB.close()
Close the LOB. Call this when writing is completed so that the indexes

View File

@ -22,18 +22,18 @@ Module Interface
This method is an extension to the DB API definition.
.. function:: Connection([user, password, dsn, mode, handle, pool, threaded, twophase, events, cclass, purity, newpassword, encoding, nencoding, module, action, clientinfo, edition, appcontext])
connect([user, password, dsn, mode, handle, pool, threaded, twophase, events, cclass, purity, newpassword, encoding, nencoding, module, action, clientinfo, edition, appcontext])
.. function:: Connection([user, password, dsn, mode, handle, pool, threaded, events, cclass, purity, newpassword, encoding, nencoding, edition, appcontext, tag, matchanytag])
connect([user, password, dsn, mode, handle, pool, threaded, events, cclass, purity, newpassword, encoding, nencoding, edition, appcontext, tag, matchanytag])
Constructor for creating a connection to the database. Return a
:ref:`connection object <connobj>`. All arguments are optional and can be
specified as keyword parameters.
The dsn (data source name) is the TNS entry (from the Oracle names server or
tnsnames.ora file) or is a string like the one returned from makedsn(). If
only one parameter is passed, a connect string is assumed which is to be of
the format ``user/password@dsn``, the same format accepted by Oracle
applications such as SQL\*Plus.
tnsnames.ora file) or is a string like the one returned from
:meth:`~cx_Oracle.makedsn()`. If only one parameter is passed, a connect
string is assumed which is to be of the format ``user/password@dsn``, the
same format accepted by Oracle applications such as SQL\*Plus.
If the mode is specified, it must be one of :data:`~cx_Oracle.SYSDBA`,
:data:`~cx_Oracle.SYSASM` or :data:`~cx_Oracle.SYSOPER` which are defined at
@ -51,13 +51,6 @@ Module Interface
mutex. Doing so in single threaded applications imposes a performance
penalty of about 10-15% which is why the default is False.
The twophase argument is expected to be a boolean expression which
indicates whether or not the external_name and internal_name attributes
should be set on the connection object to allow for two phase commit. The
default for this value is False. Use of this argument is deprecated and will
be removed in a future release of cx_Oracle. Instead, the application should
set these attributes itself to an appropriate value for the application.
The events argument is expected to be a boolean expression which indicates
whether or not to initialize Oracle in events mode.
@ -77,13 +70,6 @@ Module Interface
The nencoding argument is expected to be a string if specified and sets the
national encoding to use for national character set database strings.
The module, action and clientinfo arguments are expected to be strings, if
specified, and set the module, action and client_info attributes on the
connection respectively. These arguments are deprecated and will be removed
in a future version of cx_Oracle since Oracle does not support their use
during the creation of a connection. Instead, application context (see
below) should be used.
The edition argument is expected to be a string if specified and sets the
edition to use for the session. It is only relevant if both the client and
the server are at least Oracle Database 11.2.
@ -95,6 +81,15 @@ Module Interface
Each entry in the list is expected to contain three strings: the namespace,
the name and the value.
The tag argument, if specified, is expected to be a string and will limit
the sessions that can be returned from a session pool unless the matchanytag
argument is set to True. In that case sessions with the specified tag will
be preferred over others, but if no such sessions are available a session
with a different tag may be returned instead. In any case, untagged sessions
will always be returned if no sessions with the specified tag are available.
Sessions are tagged when they are :meth:`released <SessionPool.release>`
back to the pool.
.. function:: Cursor(connection)
@ -118,21 +113,18 @@ Module Interface
time module for details).
.. function:: makedsn(host, port, sid, [service_name])
.. function:: makedsn(host, port, sid=None, service_name=None, region=None, sharding_key=None, super_sharding_key=None)
Return a string suitable for use as the dsn argument for
:meth:`~cx_Oracle.connect()`. This string is identical to the strings that
are defined by the Oracle names server or defined in the tnsnames.ora file.
If you wish to use the service name instead of the sid, do not include a
value for the parameter sid and use the keyword parameter service_name
instead.
.. note::
This method is an extension to the DB API definition.
.. function:: SessionPool(user, password, database, min, max, increment, [connectiontype, threaded, getmode=cx_Oracle.SPOOL_ATTRVAL_NOWAIT, homogeneous=True, externalauth=True, encoding=None, nencoding=None])
.. function:: SessionPool(user, password, database, min, max, increment, [connectiontype, threaded, getmode=cx_Oracle.SPOOL_ATTRVAL_NOWAIT, homogeneous=True, externalauth=True, encoding=None, nencoding=None, edition=None])
Create and return a :ref:`session pool object <sesspool>`. This
allows for very fast connections to the database and is of primary use in a
@ -151,6 +143,10 @@ Module Interface
The nencoding argument is expected to be a string if specified and sets the
national encoding to use for national character set database strings.
The edition argument is expected to be a string, if specified, and sets the
edition to use for the sessions in the pool. It is only relevant if both the
client and the server are at least Oracle Database 11.2.
.. note::
This method is an extension to the DB API definition.

View File

@ -1,12 +1,45 @@
Release notes
=============
5.x releases
6.x releases
############
Version 5.next
--------------
Version 6.0 (TBD)
-----------------
1) Added attribute :attr:`SessionPool.stmtcachesize` to support getting and
setting the default statement cache size for connections in the pool.
2) Added attribute :attr:`Connection.dbop` to support setting the database
operation that is to be monitored.
3) Added attribute :attr:`Connection.handle` to facilitate testing the
creation of a connection using a OCI service context handle.
4) Added parameters tag and matchanytag to the :meth:`cx_Oracle.connect`
and :meth:`SessionPool.acquire` methods and added parameters tag and retag
to the :meth:`SessionPool.release` method in order to support session
tagging.
5) Added parameter edition to the :meth:`cx_Oracle.SessionPool` method.
6) Added support for universal rowids.
7) Added support for DML returning of multiple rows.
8) Added sharding parameters region, sharding_key and super_sharding_key to
the :meth:`cx_Oracle.makedsn()` method.
9) Removed restriction on fetching LOBs across round trips to the database
(LOB variable no longer valid after subsequent fetch).
10) Removed requirement for specifying a maximum size when fetching LONG or
LONG raw columns. This also allows CLOB, NCLOB, BLOB and BFILE columns to
be fetched without needing to specify a maximum size.
11) Dropped deprecated parameters twophase, action, module and clientinfo from
the :meth:`cx_Oracle.connect` method.
12) Dropped deprecated attribute numbersAsString from
:ref:`cursor objects <cursorobj>`. Use an output type handler instead.
13) Dropped deprecated attributes cqqos and rowids from
:ref:`subscription objects <subscrobj>`. Use the qos attribute instead.
14) Dropped deprecated parameters cqqos and rowids from the
:meth:`Connection.subscribe()` method.
5.x releases
############
Version 5.3 (March 2017)

View File

@ -9,11 +9,30 @@ SessionPool Object
This object is an extension to the DB API.
.. method:: SessionPool.acquire()
.. method:: SessionPool.acquire(user=None, password=None, cclass=None, purity=cx_Oracle.ATTR_PURITY_DEFAULT, tag=None, matchanytag=False)
Acquire a connection from the session pool and return a
:ref:`connection object <connobj>`.
The user and password arguments may not be specified if the pool is
homogeneous. In that case an exception will be raised.
The cclass argument, if specified, should be a string corresponding to the
connection class for database resident connection pooling (DRCP).
The purity argument is expected to be one of
:data:`~cx_Oracle.ATTR_PURITY_NEW`, :data:`~cx_Oracle.ATTR_PURITY_SELF`, or
:data:`~cx_Oracle.ATTR_PURITY_DEFAULT`.
The tag argument, if specified, is expected to be a string and will limit
the sessions that can be returned from a session pool unless the matchanytag
argument is set to True. In that case sessions with the specified tag will
be preferred over others, but if no such sessions are available a session
with a different tag may be returned instead. In any case, untagged sessions
will always be returned if no sessions with the specified tag are available.
Sessions are tagged when they are :meth:`released <SessionPool.release>`
back to the pool.
.. attribute:: SessionPool.busy
@ -81,11 +100,25 @@ SessionPool Object
the session pool.
.. method:: SessionPool.release(connection)
.. method:: SessionPool.release(connection, tag=None)
Release the connection back to the pool. This will be done automatically as
well if the connection object is garbage collected.
If a tag is specified, the session will be tagged (or retagged) with the
specified value before being returned to the pool.
.. attribute:: SessionPool.stmtcachesize
This read-write attribute specifies the size of the statement cache that
will be used as the starting point for any connections that are created by
the session pool. Once created, the connection's statement cache size can
only be changed by setting the stmtcachesize attribute on the connection
itself.
.. versionadded:: 6.0
.. attribute:: SessionPool.timeout

View File

@ -21,15 +21,6 @@ Subscription Object
the subscription when it was created.
.. attribute:: Subscription.cqqos
This read-only attribute returns the quality of service flags used to
register the subscription when it was created.
.. deprecated:: 5.3
Use the qos attribute instead.
.. attribute:: Subscription.id
This read-only attribute returns the registration ID returned by the
@ -77,16 +68,6 @@ Subscription Object
returned; otherwise, None is returned.
.. attribute:: Subscription.rowids
This read-only attribute returns True or False specifying if rowids will be
included in notifications sent using this subscription.
.. deprecated:: 5.3
Use :data:`~cx_Oracle.SUBSCR_QOS_ROWIDS` masked with the qos attribute
instead.
.. attribute:: Subscription.timeout
This read-only attribute returns the timeout (in seconds) that was specified

1
odpi Submodule

@ -0,0 +1 @@
Subproject commit 88f9cdc6508304ff02744b44f17f4088354f8677

View File

@ -38,7 +38,7 @@ except:
from distutils.extension import Extension
# define build constants
BUILD_VERSION = "5.3"
BUILD_VERSION = "6.0"
# define the list of files to be included as documentation for Windows
dataFiles = None
@ -224,6 +224,10 @@ else:
if not includeDirs:
raise DistutilsSetupError("cannot locate Oracle include files")
# include the ODPI-C header and source file locations
includeDirs.append("odpi/include")
includeDirs.append("odpi/src")
# NOTE: on HP-UX Itanium with Oracle 10g you need to add the library "ttsh10"
# to the list of libraries along with "clntsh"; since I am unable to test, I'll
# leave this as a comment until someone can verify when this is required
@ -361,13 +365,13 @@ extension = Extension(
extra_compile_args = extraCompileArgs,
extra_link_args = extraLinkArgs,
sources = ["src/cx_Oracle.c"],
depends = ["src/AQ.c", "src/Buffer.c", "src/Connection.c",
depends = ["src/BooleanVar.c", "src/Buffer.c", "src/Connection.c",
"src/Cursor.c", "src/CursorVar.c", "src/DateTimeVar.c",
"src/Environment.c", "src/Error.c", "src/ExternalLobVar.c",
"src/IntervalVar.c", "src/LobVar.c", "src/LongVar.c",
"src/NumberVar.c", "src/Object.c", "src/ObjectType.c",
"src/ObjectVar.c", "src/SessionPool.c", "src/StringVar.c",
"src/Subscription.c", "src/TimestampVar.c", "src/Transforms.c",
"src/DeqOptions.c", "src/EnqOptions.c", "src/Error.c",
"src/IntervalVar.c", "src/LOB.c", "src/LobVar.c",
"src/LongVar.c", "src/MsgProps.c", "src/NumberVar.c",
"src/Object.c", "src/ObjectType.c", "src/ObjectVar.c",
"src/SessionPool.c", "src/StringVar.c", "src/Subscription.c",
"src/Variable.c"])
# perform the setup

771
src/AQ.c
View File

@ -1,771 +0,0 @@
//-----------------------------------------------------------------------------
// Copyright 2016, 2017, Oracle and/or its affiliates. All rights reserved.
//
// Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
//
// Portions Copyright 2001-2007, Computronix (Canada) Ltd., Edmonton, Alberta,
// Canada. All rights reserved.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// AQ.c
// Implements the enqueue and dequeue options and message properties objects
// used in Advanced Queuing.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// structures used for handling AQ options and message properties
//-----------------------------------------------------------------------------
typedef struct {
PyObject_HEAD
udt_Environment *environment;
OCIAQEnqOptions *handle;
} udt_EnqOptions;
typedef struct {
PyObject_HEAD
udt_Environment *environment;
OCIAQDeqOptions *handle;
} udt_DeqOptions;
typedef struct {
PyObject_HEAD
udt_Environment *environment;
OCIAQMsgProperties *handle;
} udt_MessageProperties;
//-----------------------------------------------------------------------------
// Declaration of methods used for enqueue options
//-----------------------------------------------------------------------------
static udt_EnqOptions *EnqOptions_New(udt_Environment*);
static void EnqOptions_Free(udt_EnqOptions*);
static PyObject *EnqOptions_GetOCIAttr(udt_EnqOptions*, ub4*);
static int EnqOptions_SetOCIAttr(udt_EnqOptions*, PyObject*, ub4*);
//-----------------------------------------------------------------------------
// Declaration of methods used for dequeue options
//-----------------------------------------------------------------------------
static udt_DeqOptions *DeqOptions_New(udt_Environment*);
static void DeqOptions_Free(udt_DeqOptions*);
static PyObject *DeqOptions_GetOCIAttr(udt_DeqOptions*, ub4*);
static int DeqOptions_SetOCIAttr(udt_DeqOptions*, PyObject*, ub4*);
//-----------------------------------------------------------------------------
// Declaration of methods used for message properties
//-----------------------------------------------------------------------------
static udt_MessageProperties *MessageProperties_New(udt_Environment*);
static void MessageProperties_Free(udt_MessageProperties*);
static PyObject *MessageProperties_GetOCIAttr(udt_MessageProperties*, ub4*);
static int MessageProperties_SetOCIAttr(udt_MessageProperties*, PyObject*,
ub4*);
//-----------------------------------------------------------------------------
// constants for OCI attributes
//-----------------------------------------------------------------------------
static ub4 gc_AQAttempts = OCI_ATTR_ATTEMPTS;
static ub4 gc_AQConsumerName = OCI_ATTR_CONSUMER_NAME;
static ub4 gc_AQCorrelation = OCI_ATTR_CORRELATION;
static ub4 gc_AQDelay = OCI_ATTR_DELAY;
static ub4 gc_AQDeliveryMode = OCI_ATTR_MSG_DELIVERY_MODE;
static ub4 gc_AQDeqCondition = OCI_ATTR_DEQCOND;
static ub4 gc_AQDeqMode = OCI_ATTR_DEQ_MODE;
static ub4 gc_AQDeqMsgId = OCI_ATTR_DEQ_MSGID;
static ub4 gc_AQEnqTime = OCI_ATTR_ENQ_TIME;
static ub4 gc_AQExceptionQ = OCI_ATTR_EXCEPTION_QUEUE;
static ub4 gc_AQExpiration = OCI_ATTR_EXPIRATION;
static ub4 gc_AQNavigation = OCI_ATTR_NAVIGATION;
static ub4 gc_AQOriginalMsgId = OCI_ATTR_ORIGINAL_MSGID;
static ub4 gc_AQPriority = OCI_ATTR_PRIORITY;
static ub4 gc_AQState = OCI_ATTR_MSG_STATE;
static ub4 gc_AQTransformation = OCI_ATTR_TRANSFORMATION;
static ub4 gc_AQVisibility = OCI_ATTR_VISIBILITY;
static ub4 gc_AQWait = OCI_ATTR_WAIT;
//-----------------------------------------------------------------------------
// declaration of calculated members for Python type "EnqOptions"
//-----------------------------------------------------------------------------
static PyGetSetDef g_EnqOptionsCalcMembers[] = {
{ "deliverymode", 0, (setter) EnqOptions_SetOCIAttr, 0,
&gc_AQDeliveryMode },
{ "transformation", (getter) EnqOptions_GetOCIAttr,
(setter) EnqOptions_SetOCIAttr, 0, &gc_AQTransformation },
{ "visibility", (getter) EnqOptions_GetOCIAttr,
(setter) EnqOptions_SetOCIAttr, 0, &gc_AQVisibility },
{ NULL }
};
//-----------------------------------------------------------------------------
// declaration of calculated members for Python type "DeqOptions"
//-----------------------------------------------------------------------------
static PyGetSetDef g_DeqOptionsCalcMembers[] = {
{ "condition", (getter) DeqOptions_GetOCIAttr,
(setter) DeqOptions_SetOCIAttr, 0, &gc_AQDeqCondition },
{ "consumername", (getter) DeqOptions_GetOCIAttr,
(setter) DeqOptions_SetOCIAttr, 0, &gc_AQConsumerName },
{ "correlation", (getter) DeqOptions_GetOCIAttr,
(setter) DeqOptions_SetOCIAttr, 0, &gc_AQCorrelation },
{ "deliverymode", 0, (setter) EnqOptions_SetOCIAttr, 0,
&gc_AQDeliveryMode },
{ "mode", (getter) DeqOptions_GetOCIAttr,
(setter) DeqOptions_SetOCIAttr, 0, &gc_AQDeqMode },
{ "msgid", (getter) DeqOptions_GetOCIAttr,
(setter) DeqOptions_SetOCIAttr, 0, &gc_AQDeqMsgId },
{ "navigation", (getter) DeqOptions_GetOCIAttr,
(setter) DeqOptions_SetOCIAttr, 0, &gc_AQNavigation },
{ "transformation", (getter) EnqOptions_GetOCIAttr,
(setter) EnqOptions_SetOCIAttr, 0, &gc_AQTransformation },
{ "visibility", (getter) DeqOptions_GetOCIAttr,
(setter) DeqOptions_SetOCIAttr, 0, &gc_AQVisibility },
{ "wait", (getter) DeqOptions_GetOCIAttr,
(setter) DeqOptions_SetOCIAttr, 0, &gc_AQWait },
{ NULL }
};
//-----------------------------------------------------------------------------
// declaration of calculated members for Python type "MessageProperties"
//-----------------------------------------------------------------------------
static PyGetSetDef g_MessagePropertiesCalcMembers[] = {
{ "attempts", (getter) MessageProperties_GetOCIAttr, 0, 0,
&gc_AQAttempts },
{ "correlation", (getter) MessageProperties_GetOCIAttr,
(setter) MessageProperties_SetOCIAttr, 0, &gc_AQCorrelation },
{ "delay", (getter) MessageProperties_GetOCIAttr,
(setter) MessageProperties_SetOCIAttr, 0, &gc_AQDelay },
{ "deliverymode", (getter) MessageProperties_GetOCIAttr, 0, 0,
&gc_AQDeliveryMode },
{ "enqtime", (getter) MessageProperties_GetOCIAttr, 0, 0, &gc_AQEnqTime },
{ "exceptionq", (getter) MessageProperties_GetOCIAttr,
(setter) MessageProperties_SetOCIAttr, 0, &gc_AQExceptionQ },
{ "expiration", (getter) MessageProperties_GetOCIAttr,
(setter) MessageProperties_SetOCIAttr, 0, &gc_AQExpiration },
{ "msgid", (getter) MessageProperties_GetOCIAttr,
(setter) MessageProperties_SetOCIAttr, 0, &gc_AQOriginalMsgId },
{ "priority", (getter) MessageProperties_GetOCIAttr,
(setter) MessageProperties_SetOCIAttr, 0, &gc_AQPriority },
{ "state", (getter) MessageProperties_GetOCIAttr, 0, 0, &gc_AQState },
{ NULL }
};
//-----------------------------------------------------------------------------
// Python type declarations
//-----------------------------------------------------------------------------
static PyTypeObject g_EnqOptionsType = {
PyVarObject_HEAD_INIT(NULL, 0)
"cx_Oracle.EnqOptions", // tp_name
sizeof(udt_EnqOptions), // tp_basicsize
0, // tp_itemsize
(destructor) EnqOptions_Free, // tp_dealloc
0, // tp_print
0, // tp_getattr
0, // tp_setattr
0, // tp_compare
0, // tp_repr
0, // tp_as_number
0, // tp_as_sequence
0, // tp_as_mapping
0, // tp_hash
0, // tp_call
0, // tp_str
0, // tp_getattro
0, // tp_setattro
0, // tp_as_buffer
Py_TPFLAGS_DEFAULT, // tp_flags
0, // tp_doc
0, // tp_traverse
0, // tp_clear
0, // tp_richcompare
0, // tp_weaklistoffset
0, // tp_iter
0, // tp_iternext
0, // tp_methods
0, // tp_members
g_EnqOptionsCalcMembers, // tp_getset
0, // tp_base
0, // tp_dict
0, // tp_descr_get
0, // tp_descr_set
0, // tp_dictoffset
0, // tp_init
0, // tp_alloc
0, // tp_new
0, // tp_free
0, // tp_is_gc
0 // tp_bases
};
static PyTypeObject g_DeqOptionsType = {
PyVarObject_HEAD_INIT(NULL, 0)
"cx_Oracle.DeqOptions", // tp_name
sizeof(udt_DeqOptions), // tp_basicsize
0, // tp_itemsize
(destructor) DeqOptions_Free, // tp_dealloc
0, // tp_print
0, // tp_getattr
0, // tp_setattr
0, // tp_compare
0, // tp_repr
0, // tp_as_number
0, // tp_as_sequence
0, // tp_as_mapping
0, // tp_hash
0, // tp_call
0, // tp_str
0, // tp_getattro
0, // tp_setattro
0, // tp_as_buffer
Py_TPFLAGS_DEFAULT, // tp_flags
0, // tp_doc
0, // tp_traverse
0, // tp_clear
0, // tp_richcompare
0, // tp_weaklistoffset
0, // tp_iter
0, // tp_iternext
0, // tp_methods
0, // tp_members
g_DeqOptionsCalcMembers, // tp_getset
0, // tp_base
0, // tp_dict
0, // tp_descr_get
0, // tp_descr_set
0, // tp_dictoffset
0, // tp_init
0, // tp_alloc
0, // tp_new
0, // tp_free
0, // tp_is_gc
0 // tp_bases
};
static PyTypeObject g_MessagePropertiesType = {
PyVarObject_HEAD_INIT(NULL, 0)
"cx_Oracle.MessageProperties", // tp_name
sizeof(udt_MessageProperties), // tp_basicsize
0, // tp_itemsize
(destructor) MessageProperties_Free,// tp_dealloc
0, // tp_print
0, // tp_getattr
0, // tp_setattr
0, // tp_compare
0, // tp_repr
0, // tp_as_number
0, // tp_as_sequence
0, // tp_as_mapping
0, // tp_hash
0, // tp_call
0, // tp_str
0, // tp_getattro
0, // tp_setattro
0, // tp_as_buffer
Py_TPFLAGS_DEFAULT, // tp_flags
0, // tp_doc
0, // tp_traverse
0, // tp_clear
0, // tp_richcompare
0, // tp_weaklistoffset
0, // tp_iter
0, // tp_iternext
0, // tp_methods
0, // tp_members
g_MessagePropertiesCalcMembers, // tp_getset
0, // tp_base
0, // tp_dict
0, // tp_descr_get
0, // tp_descr_set
0, // tp_dictoffset
0, // tp_init
0, // tp_alloc
0, // tp_new
0, // tp_free
0, // tp_is_gc
0 // tp_bases
};
//-----------------------------------------------------------------------------
// EnqOptions_New()
// Create a new enqueue options object.
//-----------------------------------------------------------------------------
static udt_EnqOptions *EnqOptions_New(
udt_Environment *env) // environment in which to create
{
udt_EnqOptions *self;
sword status;
self = (udt_EnqOptions*) g_EnqOptionsType.tp_alloc(&g_EnqOptionsType, 0);
if (!self)
return NULL;
Py_INCREF(env);
self->environment = env;
status = OCIDescriptorAlloc(env->handle, (dvoid**) &self->handle,
OCI_DTYPE_AQENQ_OPTIONS, 0, 0);
if (Environment_CheckForError(env, status, "EnqOptions_New()") < 0) {
Py_DECREF(self);
return NULL;
}
return self;
}
//-----------------------------------------------------------------------------
// EnqOptions_Free()
// Free the memory associated with the enqueue options object.
//-----------------------------------------------------------------------------
static void EnqOptions_Free(
udt_EnqOptions *self) // object to free
{
if (self->handle)
OCIDescriptorFree(self->handle, OCI_DTYPE_AQENQ_OPTIONS);
Py_CLEAR(self->environment);
Py_TYPE(self)->tp_free((PyObject*) self);
}
//-----------------------------------------------------------------------------
// EnqOptions_GetOCIAttr()
// Get the value of the OCI attribute.
//-----------------------------------------------------------------------------
static PyObject *EnqOptions_GetOCIAttr(
udt_EnqOptions *self, // options object
ub4 *attribute) // OCI attribute type
{
ub4 valueLength, ub4Value;
dvoid *ociValue = NULL;
char *textValue;
sword status;
// get the value from the OCI
switch (*attribute) {
case OCI_ATTR_VISIBILITY:
ociValue = &ub4Value;
break;
case OCI_ATTR_TRANSFORMATION:
ociValue = &textValue;
break;
};
status = OCIAttrGet(self->handle, OCI_DTYPE_AQENQ_OPTIONS, ociValue,
&valueLength, *attribute, self->environment->errorHandle);
if (Environment_CheckForError(self->environment, status,
"EnqOptions_GetOCIAttr()") < 0)
return NULL;
if (*attribute == gc_AQTransformation) {
if (!textValue)
Py_RETURN_NONE;
return cxString_FromEncodedString(textValue, valueLength,
self->environment->encoding);
}
return PyInt_FromLong(ub4Value);
}
//-----------------------------------------------------------------------------
// EnqOptions_SetOCIAttr()
// Set the value of the OCI attribute.
//-----------------------------------------------------------------------------
static int EnqOptions_SetOCIAttr(
udt_EnqOptions *self, // options object
PyObject *value, // value to set
ub4 *attribute) // OCI attribute type
{
dvoid *ociValue = NULL;
ub4 valueLength = 0;
udt_Buffer buffer;
ub4 ub4Value;
ub2 ub2Value;
sword status;
switch (*attribute) {
case OCI_ATTR_MSG_DELIVERY_MODE:
ub2Value = (ub2) PyInt_AsLong(value);
if (PyErr_Occurred())
return -1;
ociValue = &ub2Value;
break;
case OCI_ATTR_VISIBILITY:
ub4Value = (ub4) PyInt_AsLong(value);
if (PyErr_Occurred())
return -1;
ociValue = &ub4Value;
break;
case OCI_ATTR_TRANSFORMATION:
if (cxBuffer_FromObject(&buffer, value,
self->environment->encoding) < 0)
return -1;
ociValue = (dvoid*) buffer.ptr;
valueLength = (ub4) buffer.size;
break;
};
status = OCIAttrSet(self->handle, OCI_DTYPE_AQENQ_OPTIONS,
ociValue, valueLength, *attribute, self->environment->errorHandle);
if (*attribute == gc_AQTransformation)
cxBuffer_Clear(&buffer);
if (Environment_CheckForError(self->environment, status,
"EnqOptions_SetOCIAttr()") < 0)
return -1;
return 0;
}
//-----------------------------------------------------------------------------
// DeqOptions_New()
// Create a new dequeue options object.
//-----------------------------------------------------------------------------
static udt_DeqOptions *DeqOptions_New(
udt_Environment *env) // environment in which to create
{
udt_DeqOptions *self;
sword status;
self = (udt_DeqOptions*) g_DeqOptionsType.tp_alloc(&g_DeqOptionsType, 0);
if (!self)
return NULL;
Py_INCREF(env);
self->environment = env;
status = OCIDescriptorAlloc(env->handle, (dvoid**) &self->handle,
OCI_DTYPE_AQDEQ_OPTIONS, 0, 0);
if (Environment_CheckForError(env, status, "DeqOptions_New()") < 0) {
Py_DECREF(self);
return NULL;
}
return self;
}
//-----------------------------------------------------------------------------
// DeqOptions_Free()
// Free the memory associated with the dequeue options object.
//-----------------------------------------------------------------------------
static void DeqOptions_Free(
udt_DeqOptions *self) // object to free
{
if (self->handle)
OCIDescriptorFree(self->handle, OCI_DTYPE_AQDEQ_OPTIONS);
Py_CLEAR(self->environment);
Py_TYPE(self)->tp_free((PyObject*) self);
}
//-----------------------------------------------------------------------------
// DeqOptions_GetOCIAttr()
// Get the value of the OCI attribute.
//-----------------------------------------------------------------------------
static PyObject *DeqOptions_GetOCIAttr(
udt_DeqOptions *self, // options object
ub4 *attribute) // OCI attribute type
{
ub4 valueLength, ub4Value;
dvoid *ociValue = NULL;
char *rawValuePtr;
OCIRaw *rawValue;
char *textValue;
sword status;
// get the value from the OCI
switch (*attribute) {
case OCI_ATTR_DEQ_MODE:
case OCI_ATTR_NAVIGATION:
case OCI_ATTR_VISIBILITY:
case OCI_ATTR_WAIT:
ociValue = &ub4Value;
break;
case OCI_ATTR_CONSUMER_NAME:
case OCI_ATTR_CORRELATION:
case OCI_ATTR_DEQCOND:
case OCI_ATTR_TRANSFORMATION:
ociValue = &textValue;
break;
case OCI_ATTR_DEQ_MSGID:
rawValue = NULL;
ociValue = &rawValue;
break;
};
status = OCIAttrGet(self->handle, OCI_DTYPE_AQDEQ_OPTIONS, ociValue,
&valueLength, *attribute, self->environment->errorHandle);
if (Environment_CheckForError(self->environment, status,
"DeqOptions_GetOCIAttr()") < 0)
return NULL;
if (ociValue == &textValue) {
if (!textValue)
Py_RETURN_NONE;
return cxString_FromEncodedString(textValue, valueLength,
self->environment->encoding);
} else if (ociValue == &rawValue) {
if (!rawValue)
Py_RETURN_NONE;
rawValuePtr = (char*) OCIRawPtr(self->environment->handle, rawValue);
valueLength = OCIRawSize(self->environment->handle, rawValue);
return PyBytes_FromStringAndSize(rawValuePtr, valueLength);
}
return PyInt_FromLong(ub4Value);
}
//-----------------------------------------------------------------------------
// DeqOptions_SetOCIAttr()
// Set the value of the OCI attribute.
//-----------------------------------------------------------------------------
static int DeqOptions_SetOCIAttr(
udt_DeqOptions *self, // options object
PyObject *value, // value to set
ub4 *attribute) // OCI attribute type
{
Py_ssize_t rawValueLength;
OCIRaw *rawValue = NULL;
dvoid *ociValue = NULL;
ub4 valueLength = 0;
udt_Buffer buffer;
char *rawValuePtr;
ub4 ub4Value;
ub2 ub2Value;
sword status;
cxBuffer_Init(&buffer);
switch (*attribute) {
case OCI_ATTR_MSG_DELIVERY_MODE:
ub2Value = (ub2) PyInt_AsLong(value);
if (PyErr_Occurred())
return -1;
ociValue = &ub2Value;
break;
case OCI_ATTR_DEQ_MODE:
case OCI_ATTR_NAVIGATION:
case OCI_ATTR_VISIBILITY:
case OCI_ATTR_WAIT:
ub4Value = (ub4) PyInt_AsLong(value);
if (PyErr_Occurred())
return -1;
ociValue = &ub4Value;
break;
case OCI_ATTR_CONSUMER_NAME:
case OCI_ATTR_CORRELATION:
case OCI_ATTR_DEQCOND:
case OCI_ATTR_TRANSFORMATION:
if (cxBuffer_FromObject(&buffer, value,
self->environment->encoding) < 0)
return -1;
ociValue = (dvoid*) buffer.ptr;
valueLength = (ub4) buffer.size;
break;
case OCI_ATTR_DEQ_MSGID:
if (PyBytes_AsStringAndSize(value, &rawValuePtr,
&rawValueLength) < 0)
return -1;
status = OCIRawAssignBytes(self->environment->handle,
self->environment->errorHandle, (const ub1*) rawValuePtr,
(ub4) rawValueLength, &rawValue);
if (Environment_CheckForError(self->environment, status,
"DeqOptions_SetOCIAttr(): assign raw value") < 0)
return -1;
ociValue = (dvoid*) &rawValue;
valueLength = OCIRawSize(self->environment->handle, rawValue);
break;
};
status = OCIAttrSet(self->handle, OCI_DTYPE_AQDEQ_OPTIONS,
ociValue, valueLength, *attribute, self->environment->errorHandle);
cxBuffer_Clear(&buffer);
if (rawValue)
OCIRawResize(self->environment->handle, self->environment->errorHandle,
0, &rawValue);
if (Environment_CheckForError(self->environment, status,
"DeqOptions_SetOCIAttr(): set value") < 0)
return -1;
return 0;
}
//-----------------------------------------------------------------------------
// MessageProperties_New()
// Create a new dequeue options object.
//-----------------------------------------------------------------------------
static udt_MessageProperties *MessageProperties_New(
udt_Environment *env) // environment in which to create
{
udt_MessageProperties *self;
sword status;
self = (udt_MessageProperties*)
g_MessagePropertiesType.tp_alloc(&g_MessagePropertiesType, 0);
if (!self)
return NULL;
Py_INCREF(env);
self->environment = env;
status = OCIDescriptorAlloc(env->handle, (dvoid**) &self->handle,
OCI_DTYPE_AQMSG_PROPERTIES, 0, 0);
if (Environment_CheckForError(env, status,
"MessageProperties_New()") < 0) {
Py_DECREF(self);
return NULL;
}
return self;
}
//-----------------------------------------------------------------------------
// MessageProperties_Free()
// Free the memory associated with the message properties object.
//-----------------------------------------------------------------------------
static void MessageProperties_Free(
udt_MessageProperties *self) // object to free
{
if (self->handle)
OCIDescriptorFree(self->handle, OCI_DTYPE_AQMSG_PROPERTIES);
Py_CLEAR(self->environment);
Py_TYPE(self)->tp_free((PyObject*) self);
}
//-----------------------------------------------------------------------------
// MessageProperties_GetOCIAttr()
// Get the value of the OCI attribute.
//-----------------------------------------------------------------------------
static PyObject *MessageProperties_GetOCIAttr(
udt_MessageProperties *self, // options object
ub4 *attribute) // OCI attribute type
{
ub4 valueLength, ub4Value;
dvoid *ociValue = NULL;
char *rawValuePtr;
OCIDate dateValue;
OCIRaw *rawValue;
char *textValue;
sb4 sb4Value;
ub2 ub2Value;
sword status;
// get the value from the OCI
switch (*attribute) {
case OCI_ATTR_MSG_DELIVERY_MODE:
ociValue = &ub2Value;
break;
case OCI_ATTR_ATTEMPTS:
case OCI_ATTR_DELAY:
case OCI_ATTR_EXPIRATION:
case OCI_ATTR_PRIORITY:
ociValue = &sb4Value;
break;
case OCI_ATTR_MSG_STATE:
ociValue = &ub4Value;
break;
case OCI_ATTR_CORRELATION:
case OCI_ATTR_EXCEPTION_QUEUE:
ociValue = &textValue;
break;
case OCI_ATTR_ENQ_TIME:
ociValue = &dateValue;
break;
case OCI_ATTR_ORIGINAL_MSGID:
rawValue = NULL;
ociValue = &rawValue;
break;
};
status = OCIAttrGet(self->handle, OCI_DTYPE_AQMSG_PROPERTIES, ociValue,
&valueLength, *attribute, self->environment->errorHandle);
if (Environment_CheckForError(self->environment, status,
"MessageProperties_GetOCIAttr()") < 0)
return NULL;
if (ociValue == &textValue) {
if (!textValue)
Py_RETURN_NONE;
return cxString_FromEncodedString(textValue, valueLength,
self->environment->encoding);
} else if (ociValue == &rawValue) {
if (!rawValue)
Py_RETURN_NONE;
rawValuePtr = (char*) OCIRawPtr(self->environment->handle, rawValue);
valueLength = OCIRawSize(self->environment->handle, rawValue);
return PyBytes_FromStringAndSize(rawValuePtr, valueLength);
} else if (ociValue == &dateValue)
return OracleDateToPythonDate(&vt_DateTime, &dateValue);
else if (ociValue == &ub2Value)
return PyInt_FromLong(ub2Value);
else if (ociValue == &sb4Value)
return PyInt_FromLong(sb4Value);
return PyInt_FromLong(ub4Value);
}
//-----------------------------------------------------------------------------
// MessageProperties_SetOCIAttr()
// Set the value of the OCI attribute.
//-----------------------------------------------------------------------------
static int MessageProperties_SetOCIAttr(
udt_MessageProperties *self, // options object
PyObject *value, // value to set
ub4 *attribute) // OCI attribute type
{
Py_ssize_t rawValueLength;
OCIRaw *rawValue = NULL;
dvoid *ociValue = NULL;
ub4 valueLength = 0;
udt_Buffer buffer;
char *rawValuePtr;
ub4 ub4Value;
ub2 ub2Value;
sword status;
cxBuffer_Init(&buffer);
switch (*attribute) {
case OCI_ATTR_MSG_DELIVERY_MODE:
ub2Value = (ub2) PyInt_AsLong(value);
if (PyErr_Occurred())
return -1;
ociValue = &ub2Value;
break;
case OCI_ATTR_DEQ_MODE:
case OCI_ATTR_NAVIGATION:
case OCI_ATTR_VISIBILITY:
case OCI_ATTR_WAIT:
ub4Value = (ub4) PyInt_AsLong(value);
if (PyErr_Occurred())
return -1;
ociValue = &ub4Value;
break;
case OCI_ATTR_CONSUMER_NAME:
case OCI_ATTR_CORRELATION:
case OCI_ATTR_DEQCOND:
case OCI_ATTR_TRANSFORMATION:
if (cxBuffer_FromObject(&buffer, value,
self->environment->encoding) < 0)
return -1;
ociValue = (dvoid*) buffer.ptr;
valueLength = (ub4) buffer.size;
break;
case OCI_ATTR_DEQ_MSGID:
if (PyBytes_AsStringAndSize(value, &rawValuePtr,
&rawValueLength) < 0)
return -1;
status = OCIRawAssignBytes(self->environment->handle,
self->environment->errorHandle, (const ub1*) rawValuePtr,
(ub4) rawValueLength, &rawValue);
if (Environment_CheckForError(self->environment, status,
"MessageProperties_SetOCIAttr(): assign raw value") < 0)
return -1;
ociValue = (dvoid*) &rawValue;
valueLength = OCIRawSize(self->environment->handle, rawValue);
break;
};
status = OCIAttrSet(self->handle, OCI_DTYPE_AQMSG_PROPERTIES,
ociValue, valueLength, *attribute, self->environment->errorHandle);
cxBuffer_Clear(&buffer);
if (rawValue)
OCIRawResize(self->environment->handle, self->environment->errorHandle,
0, &rawValue);
if (Environment_CheckForError(self->environment, status,
"MessageProperties_SetOCIAttr(): set value") < 0)
return -1;
return 0;
}

View File

@ -13,72 +13,29 @@
// Oracle 12.1).
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Data types
//-----------------------------------------------------------------------------
typedef struct {
Variable_HEAD
boolean *data;
} udt_BooleanVar;
//-----------------------------------------------------------------------------
// Declaration of variable functions.
//-----------------------------------------------------------------------------
static int BooleanVar_SetValue(udt_BooleanVar*, unsigned, PyObject*);
static PyObject *BooleanVar_GetValue(udt_BooleanVar*, unsigned);
static int BooleanVar_SetValue(udt_Variable*, uint32_t, dpiData*, PyObject*);
static PyObject *BooleanVar_GetValue(udt_Variable*, dpiData*);
//-----------------------------------------------------------------------------
// Python type declaration
//-----------------------------------------------------------------------------
static PyTypeObject g_BooleanVarType = {
PyVarObject_HEAD_INIT(NULL, 0)
"cx_Oracle.BOOLEAN", // tp_name
sizeof(udt_BooleanVar), // tp_basicsize
0, // tp_itemsize
0, // tp_dealloc
0, // tp_print
0, // tp_getattr
0, // tp_setattr
0, // tp_compare
0, // tp_repr
0, // tp_as_number
0, // tp_as_sequence
0, // tp_as_mapping
0, // tp_hash
0, // tp_call
0, // tp_str
0, // tp_getattro
0, // tp_setattro
0, // tp_as_buffer
Py_TPFLAGS_DEFAULT, // tp_flags
0 // tp_doc
};
DECLARE_VARIABLE_TYPE(g_BooleanVarType, BOOLEAN)
//-----------------------------------------------------------------------------
// variable type declarations
//-----------------------------------------------------------------------------
static udt_VariableType vt_Boolean = {
(InitializeProc) NULL,
(FinalizeProc) NULL,
(PreDefineProc) NULL,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) NULL,
(IsNullProc) NULL,
(SetValueProc) BooleanVar_SetValue,
(GetValueProc) BooleanVar_GetValue,
(GetBufferSizeProc) NULL,
&g_BooleanVarType, // Python type
SQLT_BOL, // Oracle type
SQLCS_IMPLICIT, // charset form
sizeof(boolean), // element length
0, // is character data
0, // is variable length
1, // can be copied
0 // can be in array
DPI_ORACLE_TYPE_BOOLEAN, // Oracle type
DPI_NATIVE_TYPE_BOOLEAN, // native type
0 // element length
};
@ -86,11 +43,11 @@ static udt_VariableType vt_Boolean = {
// BooleanVar_GetValue()
// Returns the value stored at the given array position.
//-----------------------------------------------------------------------------
static PyObject *BooleanVar_GetValue(
udt_BooleanVar *var, // variable to determine value for
unsigned pos) // array position
static PyObject *BooleanVar_GetValue(udt_Variable *var, dpiData *data)
{
return OracleBooleanToPythonBoolean(&var->data[pos]);
if (data->value.asBoolean)
Py_RETURN_TRUE;
Py_RETURN_FALSE;
}
@ -98,11 +55,10 @@ static PyObject *BooleanVar_GetValue(
// BooleanVar_SetValue()
// Set the value of the variable at the given array position.
//-----------------------------------------------------------------------------
static int BooleanVar_SetValue(
udt_BooleanVar *var, // variable to set value for
unsigned pos, // array position to set
PyObject *value) // value to set
static int BooleanVar_SetValue(udt_Variable *var, uint32_t pos, dpiData *data,
PyObject *value)
{
return PythonBooleanToOracleBoolean(value, &var->data[pos]);
data->value.asBoolean = (value == Py_True);
return 0;
}

View File

@ -16,7 +16,7 @@
// define structure for abstracting string buffers
typedef struct {
const void *ptr;
const char *ptr;
Py_ssize_t numCharacters;
Py_ssize_t size;
PyObject *obj;
@ -28,8 +28,7 @@ typedef struct {
// Initialize the buffer with an empty string. Returns 0 as a convenience to
// the caller.
//-----------------------------------------------------------------------------
static int cxBuffer_Init(
udt_Buffer *buf) // buffer to initialize
static int cxBuffer_Init(udt_Buffer *buf)
{
buf->ptr = NULL;
buf->size = 0;
@ -39,41 +38,26 @@ static int cxBuffer_Init(
}
//-----------------------------------------------------------------------------
// cxBuffer_Copy()
// Copy the contents of the buffer.
//-----------------------------------------------------------------------------
static int cxBuffer_Copy(
udt_Buffer *buf, // buffer to copy into
udt_Buffer *copyFromBuf) // buffer to copy from
{
buf->ptr = copyFromBuf->ptr;
buf->size = copyFromBuf->size;
buf->numCharacters = copyFromBuf->numCharacters;
Py_XINCREF(copyFromBuf->obj);
buf->obj = copyFromBuf->obj;
return 0;
}
//-----------------------------------------------------------------------------
// cxBuffer_FromObject()
// Populate the string buffer from a unicode object.
//-----------------------------------------------------------------------------
static int cxBuffer_FromObject(
udt_Buffer *buf, // buffer to fill
PyObject *obj, // object (string or Unicode object)
const char *encoding) // encoding to use, if applicable
static int cxBuffer_FromObject(udt_Buffer *buf, PyObject *obj,
const char *encoding)
{
if (!obj)
return cxBuffer_Init(buf);
if (encoding && PyUnicode_Check(obj)) {
if (PyUnicode_Check(obj)) {
buf->obj = PyUnicode_AsEncodedString(obj, encoding, NULL);
if (!buf->obj)
return -1;
buf->ptr = PyBytes_AS_STRING(buf->obj);
buf->size = PyBytes_GET_SIZE(buf->obj);
#if PY_MAJOR_VERSION < 3
buf->numCharacters = PyUnicode_GET_SIZE(obj);
#else
buf->numCharacters = PyUnicode_GET_LENGTH(obj);
#endif
} else if (PyBytes_Check(obj)) {
Py_INCREF(obj);
buf->obj = obj;
@ -81,7 +65,7 @@ static int cxBuffer_FromObject(
buf->size = buf->numCharacters = PyBytes_GET_SIZE(buf->obj);
#if PY_MAJOR_VERSION < 3
} else if (PyBuffer_Check(obj)) {
if (PyObject_AsReadBuffer(obj, &buf->ptr, &buf->size) < 0)
if (PyObject_AsReadBuffer(obj, (void*) &buf->ptr, &buf->size) < 0)
return -1;
Py_INCREF(obj);
buf->obj = obj;
@ -94,5 +78,5 @@ static int cxBuffer_FromObject(
return 0;
}
#define cxBuffer_Clear(buf) Py_XDECREF((buf)->obj)
#define cxBuffer_Clear(buf) Py_CLEAR((buf)->obj)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -12,134 +12,38 @@
// Defines the routines specific to the cursor type.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Cursor variable type
//-----------------------------------------------------------------------------
typedef struct {
Variable_HEAD
OCIStmt **data;
udt_Connection *connection;
PyObject *cursors;
} udt_CursorVar;
//-----------------------------------------------------------------------------
// Declaration of cursor variable functions.
//-----------------------------------------------------------------------------
static int CursorVar_Initialize(udt_CursorVar*, udt_Cursor*);
static void CursorVar_Finalize(udt_CursorVar*);
static int CursorVar_SetValue(udt_CursorVar*, unsigned, PyObject*);
static PyObject *CursorVar_GetValue(udt_CursorVar*, unsigned);
static int CursorVar_SetValue(udt_Variable*, uint32_t, dpiData*, PyObject*);
static PyObject *CursorVar_GetValue(udt_Variable*, dpiData*);
//-----------------------------------------------------------------------------
// Python type declarations
//-----------------------------------------------------------------------------
static PyTypeObject g_CursorVarType = {
PyVarObject_HEAD_INIT(NULL, 0)
"cx_Oracle.CURSOR", // tp_name
sizeof(udt_CursorVar), // tp_basicsize
0, // tp_itemsize
0, // tp_dealloc
0, // tp_print
0, // tp_getattr
0, // tp_setattr
0, // tp_compare
0, // tp_repr
0, // tp_as_number
0, // tp_as_sequence
0, // tp_as_mapping
0, // tp_hash
0, // tp_call
0, // tp_str
0, // tp_getattro
0, // tp_setattro
0, // tp_as_buffer
Py_TPFLAGS_DEFAULT, // tp_flags
0 // tp_doc
};
DECLARE_VARIABLE_TYPE(g_CursorVarType, CURSOR)
//-----------------------------------------------------------------------------
// variable type declarations
//-----------------------------------------------------------------------------
static udt_VariableType vt_Cursor = {
(InitializeProc) CursorVar_Initialize,
(FinalizeProc) CursorVar_Finalize,
(PreDefineProc) NULL,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) NULL,
(IsNullProc) NULL,
(SetValueProc) CursorVar_SetValue,
(GetValueProc) CursorVar_GetValue,
(GetBufferSizeProc) NULL,
&g_CursorVarType, // Python type
SQLT_RSET, // Oracle type
SQLCS_IMPLICIT, // charset form
sizeof(OCIStmt*), // element length
0, // is character data
0, // is variable length
0, // can be copied
0 // can be in array
DPI_ORACLE_TYPE_STMT, // Oracle type
DPI_NATIVE_TYPE_STMT, // native type
0 // element length
};
//-----------------------------------------------------------------------------
// CursorVar_Initialize()
// Initialize the variable.
//-----------------------------------------------------------------------------
static int CursorVar_Initialize(
udt_CursorVar *var, // variable to initialize
udt_Cursor *cursor) // cursor created by
{
udt_Cursor *tempCursor;
ub4 i;
Py_INCREF(cursor->connection);
var->connection = cursor->connection;
var->cursors = PyList_New(var->allocatedElements);
if (!var->cursors)
return -1;
for (i = 0; i < var->allocatedElements; i++) {
tempCursor = (udt_Cursor*) Connection_NewCursor(var->connection, NULL,
NULL);
if (!tempCursor) {
Py_DECREF(var);
return -1;
}
PyList_SET_ITEM(var->cursors, i, (PyObject*) tempCursor);
if (Cursor_AllocateHandle(tempCursor) < 0) {
Py_DECREF(var);
return -1;
}
var->data[i] = tempCursor->handle;
}
return 0;
}
//-----------------------------------------------------------------------------
// CursorVar_Finalize()
// Prepare for variable destruction.
//-----------------------------------------------------------------------------
static void CursorVar_Finalize(
udt_CursorVar *var) // variable to free
{
Py_DECREF(var->connection);
Py_XDECREF(var->cursors);
}
//-----------------------------------------------------------------------------
// CursorVar_SetValue()
// Set the value of the variable.
//-----------------------------------------------------------------------------
static int CursorVar_SetValue(
udt_CursorVar *var, // variable to set value for
unsigned pos, // array position to set
PyObject *value) // value to set
static int CursorVar_SetValue(udt_Variable *var, uint32_t pos, dpiData *data,
PyObject *value)
{
udt_Cursor *cursor;
@ -147,20 +51,15 @@ static int CursorVar_SetValue(
PyErr_SetString(PyExc_TypeError, "expecting cursor");
return -1;
}
Py_XDECREF(PyList_GET_ITEM(var->cursors, pos));
Py_INCREF(value);
PyList_SET_ITEM(var->cursors, pos, value);
cursor = (udt_Cursor *) value;
if (!cursor->isOwned) {
if (Cursor_FreeHandle(cursor, 1) < 0)
return -1;
cursor->isOwned = 1;
if (Cursor_AllocateHandle(cursor) < 0)
return -1;
if (cursor->handle) {
if (dpiVar_setFromStmt(var->handle, pos, cursor->handle) < 0)
return Error_RaiseAndReturnInt();
} else {
cursor->handle = data->value.asStmt;
dpiStmt_addRef(cursor->handle);
}
var->data[pos] = cursor->handle;
cursor->statementType = -1;
cursor->fixupRefCursor = 1;
return 0;
}
@ -169,15 +68,17 @@ static int CursorVar_SetValue(
// CursorVar_GetValue()
// Set the value of the variable.
//-----------------------------------------------------------------------------
static PyObject *CursorVar_GetValue(
udt_CursorVar *var, // variable to set value for
unsigned pos) // array position to set
static PyObject *CursorVar_GetValue(udt_Variable *var, dpiData *data)
{
PyObject *cursor;
udt_Cursor *cursor;
cursor = PyList_GET_ITEM(var->cursors, pos);
((udt_Cursor*) cursor)->statementType = -1;
Py_INCREF(cursor);
return cursor;
cursor = (udt_Cursor*) PyObject_CallMethod((PyObject*) var->connection,
"cursor", NULL);
if (!cursor)
return NULL;
cursor->handle = data->value.asStmt;
dpiStmt_addRef(cursor->handle);
cursor->fixupRefCursor = 1;
return (PyObject*) cursor;
}

View File

@ -12,94 +12,60 @@
// Defines the routines for handling date (time) variables.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// DateTime type
//-----------------------------------------------------------------------------
typedef struct {
Variable_HEAD
OCIDate *data;
} udt_DateTimeVar;
//-----------------------------------------------------------------------------
// Declaration of date/time variable functions.
//-----------------------------------------------------------------------------
static int DateTimeVar_SetValue(udt_DateTimeVar*, unsigned, PyObject*);
static PyObject *DateTimeVar_GetValue(udt_DateTimeVar*, unsigned);
static int DateTimeVar_SetValue(udt_Variable*, uint32_t, dpiData*, PyObject*);
static PyObject *DateTimeVar_GetValue(udt_Variable*, dpiData*);
//-----------------------------------------------------------------------------
// Python type declarations
//-----------------------------------------------------------------------------
static PyTypeObject g_DateTimeVarType = {
PyVarObject_HEAD_INIT(NULL, 0)
"cx_Oracle.DATETIME", // tp_name
sizeof(udt_DateTimeVar), // tp_basicsize
0, // tp_itemsize
0, // tp_dealloc
0, // tp_print
0, // tp_getattr
0, // tp_setattr
0, // tp_compare
0, // tp_repr
0, // tp_as_number
0, // tp_as_sequence
0, // tp_as_mapping
0, // tp_hash
0, // tp_call
0, // tp_str
0, // tp_getattro
0, // tp_setattro
0, // tp_as_buffer
Py_TPFLAGS_DEFAULT, // tp_flags
0 // tp_doc
};
DECLARE_VARIABLE_TYPE(g_DateTimeVarType, DATETIME)
DECLARE_VARIABLE_TYPE(g_TimestampVarType, TIMESTAMP)
//-----------------------------------------------------------------------------
// variable type declarations
//-----------------------------------------------------------------------------
static udt_VariableType vt_DateTime = {
(InitializeProc) NULL,
(FinalizeProc) NULL,
(PreDefineProc) NULL,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) NULL,
(IsNullProc) NULL,
(SetValueProc) DateTimeVar_SetValue,
(GetValueProc) DateTimeVar_GetValue,
(GetBufferSizeProc) NULL,
&g_DateTimeVarType, // Python type
SQLT_ODT, // Oracle type
SQLCS_IMPLICIT, // charset form
sizeof(OCIDate), // element length (default)
0, // is character data
0, // is variable length
1, // can be copied
1 // can be in array
DPI_ORACLE_TYPE_DATE, // Oracle type
DPI_NATIVE_TYPE_TIMESTAMP, // native type
0 // element length
};
static udt_VariableType vt_Date = {
(InitializeProc) NULL,
(FinalizeProc) NULL,
(PreDefineProc) NULL,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) NULL,
(IsNullProc) NULL,
(SetValueProc) DateTimeVar_SetValue,
(GetValueProc) DateTimeVar_GetValue,
(GetBufferSizeProc) NULL,
&g_DateTimeVarType, // Python type
SQLT_ODT, // Oracle type
SQLCS_IMPLICIT, // charset form
sizeof(OCIDate), // element length (default)
0, // is character data
0, // is variable length
1, // can be copied
1 // can be in array
DPI_ORACLE_TYPE_DATE, // Oracle type
DPI_NATIVE_TYPE_TIMESTAMP, // native type
0 // element length
};
static udt_VariableType vt_Timestamp = {
(SetValueProc) DateTimeVar_SetValue,
(GetValueProc) DateTimeVar_GetValue,
&g_TimestampVarType, // Python type
DPI_ORACLE_TYPE_TIMESTAMP, // Oracle type
DPI_NATIVE_TYPE_TIMESTAMP, // native type
0 // element length
};
static udt_VariableType vt_TimestampLTZ = {
(SetValueProc) DateTimeVar_SetValue,
(GetValueProc) DateTimeVar_GetValue,
&g_TimestampVarType, // Python type
DPI_ORACLE_TYPE_TIMESTAMP_LTZ, // Oracle type
DPI_NATIVE_TYPE_TIMESTAMP, // native type
0 // element length
};
@ -107,12 +73,33 @@ static udt_VariableType vt_Date = {
// DateTimeVar_SetValue()
// Set the value of the variable.
//-----------------------------------------------------------------------------
static int DateTimeVar_SetValue(
udt_DateTimeVar *var, // variable to set value for
unsigned pos, // array position to set
PyObject *value) // value to set
static int DateTimeVar_SetValue(udt_Variable *var, uint32_t pos, dpiData *data,
PyObject *value)
{
return PythonDateToOracleDate(value, &var->data[pos]);
dpiTimestamp *timestamp;
timestamp = &data->value.asTimestamp;
if (PyDateTime_Check(value)) {
timestamp->year = PyDateTime_GET_YEAR(value);
timestamp->month = PyDateTime_GET_MONTH(value);
timestamp->day = PyDateTime_GET_DAY(value);
timestamp->hour = PyDateTime_DATE_GET_HOUR(value);
timestamp->minute = PyDateTime_DATE_GET_MINUTE(value);
timestamp->second = PyDateTime_DATE_GET_SECOND(value);
timestamp->fsecond = PyDateTime_DATE_GET_MICROSECOND(value) * 1000;
} else if (PyDate_Check(value)) {
timestamp->year = PyDateTime_GET_YEAR(value);
timestamp->month = PyDateTime_GET_MONTH(value);
timestamp->day = PyDateTime_GET_DAY(value);
timestamp->hour = 0;
timestamp->minute = 0;
timestamp->second = 0;
timestamp->fsecond = 0;
} else {
PyErr_SetString(PyExc_TypeError, "expecting date data");
return -1;
}
return 0;
}
@ -120,10 +107,16 @@ static int DateTimeVar_SetValue(
// DateTimeVar_GetValue()
// Returns the value stored at the given array position.
//-----------------------------------------------------------------------------
static PyObject *DateTimeVar_GetValue(
udt_DateTimeVar *var, // variable to determine value for
unsigned pos) // array position
static PyObject *DateTimeVar_GetValue(udt_Variable *var, dpiData *data)
{
return OracleDateToPythonDate(var->type, &var->data[pos]);
dpiTimestamp *timestamp;
timestamp = &data->value.asTimestamp;
if (var->type == &vt_Date)
return PyDate_FromDate(timestamp->year, timestamp->month,
timestamp->day);
return PyDateTime_FromDateAndTime(timestamp->year, timestamp->month,
timestamp->day, timestamp->hour, timestamp->minute,
timestamp->second, timestamp->fsecond / 1000);
}

466
src/DeqOptions.c Normal file
View File

@ -0,0 +1,466 @@
//-----------------------------------------------------------------------------
// Copyright 2016, 2017, Oracle and/or its affiliates. All rights reserved.
//
// Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
//
// Portions Copyright 2001-2007, Computronix (Canada) Ltd., Edmonton, Alberta,
// Canada. All rights reserved.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// DeqOptions.c
// Implements the dequeue options objects used in Advanced Queuing.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// structure used for implementing dequeue options
//-----------------------------------------------------------------------------
typedef struct {
PyObject_HEAD
dpiDeqOptions *handle;
const char *encoding;
} udt_DeqOptions;
//-----------------------------------------------------------------------------
// Declaration of methods used for dequeue options
//-----------------------------------------------------------------------------
static udt_DeqOptions *DeqOptions_New(udt_Connection*);
static void DeqOptions_Free(udt_DeqOptions*);
static PyObject *DeqOptions_GetCondition(udt_DeqOptions*, void*);
static PyObject *DeqOptions_GetConsumerName(udt_DeqOptions*, void*);
static PyObject *DeqOptions_GetCorrelation(udt_DeqOptions*, void*);
static PyObject *DeqOptions_GetMode(udt_DeqOptions*, void*);
static PyObject *DeqOptions_GetMsgId(udt_DeqOptions*, void*);
static PyObject *DeqOptions_GetNavigation(udt_DeqOptions*, void*);
static PyObject *DeqOptions_GetTransformation(udt_DeqOptions*, void*);
static PyObject *DeqOptions_GetVisibility(udt_DeqOptions*, void*);
static PyObject *DeqOptions_GetWait(udt_DeqOptions*, void*);
static int DeqOptions_SetCondition(udt_DeqOptions*, PyObject*, void*);
static int DeqOptions_SetConsumerName(udt_DeqOptions*, PyObject*, void*);
static int DeqOptions_SetCorrelation(udt_DeqOptions*, PyObject*, void*);
static int DeqOptions_SetDeliveryMode(udt_DeqOptions*, PyObject*, void*);
static int DeqOptions_SetMode(udt_DeqOptions*, PyObject*, void*);
static int DeqOptions_SetMsgId(udt_DeqOptions*, PyObject*, void*);
static int DeqOptions_SetNavigation(udt_DeqOptions*, PyObject*, void*);
static int DeqOptions_SetTransformation(udt_DeqOptions*, PyObject*, void*);
static int DeqOptions_SetVisibility(udt_DeqOptions*, PyObject*, void*);
static int DeqOptions_SetWait(udt_DeqOptions*, PyObject*, void*);
//-----------------------------------------------------------------------------
// declaration of calculated members for Python type "DeqOptions"
//-----------------------------------------------------------------------------
static PyGetSetDef g_DeqOptionsCalcMembers[] = {
{ "condition", (getter) DeqOptions_GetCondition,
(setter) DeqOptions_SetCondition, 0, 0 },
{ "consumername", (getter) DeqOptions_GetConsumerName,
(setter) DeqOptions_SetConsumerName, 0, 0 },
{ "correlation", (getter) DeqOptions_GetCorrelation,
(setter) DeqOptions_SetCorrelation, 0, 0 },
{ "deliverymode", 0, (setter) DeqOptions_SetDeliveryMode, 0, 0 },
{ "mode", (getter) DeqOptions_GetMode, (setter) DeqOptions_SetMode, 0, 0 },
{ "msgid", (getter) DeqOptions_GetMsgId,
(setter) DeqOptions_SetMsgId, 0, 0 },
{ "navigation", (getter) DeqOptions_GetNavigation,
(setter) DeqOptions_SetNavigation, 0, 0 },
{ "transformation", (getter) DeqOptions_GetTransformation,
(setter) DeqOptions_SetTransformation, 0, 0 },
{ "visibility", (getter) DeqOptions_GetVisibility,
(setter) DeqOptions_SetVisibility, 0, 0 },
{ "wait", (getter) DeqOptions_GetWait, (setter) DeqOptions_SetWait, 0, 0 },
{ NULL }
};
//-----------------------------------------------------------------------------
// Python type declarations
//-----------------------------------------------------------------------------
static PyTypeObject g_DeqOptionsType = {
PyVarObject_HEAD_INIT(NULL, 0)
"cx_Oracle.DeqOptions", // tp_name
sizeof(udt_DeqOptions), // tp_basicsize
0, // tp_itemsize
(destructor) DeqOptions_Free, // tp_dealloc
0, // tp_print
0, // tp_getattr
0, // tp_setattr
0, // tp_compare
0, // tp_repr
0, // tp_as_number
0, // tp_as_sequence
0, // tp_as_mapping
0, // tp_hash
0, // tp_call
0, // tp_str
0, // tp_getattro
0, // tp_setattro
0, // tp_as_buffer
Py_TPFLAGS_DEFAULT, // tp_flags
0, // tp_doc
0, // tp_traverse
0, // tp_clear
0, // tp_richcompare
0, // tp_weaklistoffset
0, // tp_iter
0, // tp_iternext
0, // tp_methods
0, // tp_members
g_DeqOptionsCalcMembers, // tp_getset
0, // tp_base
0, // tp_dict
0, // tp_descr_get
0, // tp_descr_set
0, // tp_dictoffset
0, // tp_init
0, // tp_alloc
0, // tp_new
0, // tp_free
0, // tp_is_gc
0 // tp_bases
};
//-----------------------------------------------------------------------------
// DeqOptions_New()
// Create a new dequeue options object.
//-----------------------------------------------------------------------------
static udt_DeqOptions *DeqOptions_New(udt_Connection *connection)
{
udt_DeqOptions *self;
self = (udt_DeqOptions*) g_DeqOptionsType.tp_alloc(&g_DeqOptionsType, 0);
if (!self)
return NULL;
if (dpiConn_newDeqOptions(connection->handle, &self->handle) < 0) {
Py_DECREF(self);
Error_RaiseAndReturnNull();
return NULL;
}
self->encoding = connection->encodingInfo.encoding;
return self;
}
//-----------------------------------------------------------------------------
// DeqOptions_Free()
// Free the memory associated with the dequeue options object.
//-----------------------------------------------------------------------------
static void DeqOptions_Free(
udt_DeqOptions *self) // object to free
{
if (self->handle) {
dpiDeqOptions_release(self->handle);
self->handle = NULL;
}
Py_TYPE(self)->tp_free((PyObject*) self);
}
//-----------------------------------------------------------------------------
// DeqOptions_GetAttrText()
// Get the value of the attribute as text.
//-----------------------------------------------------------------------------
static PyObject *DeqOptions_GetAttrText(udt_DeqOptions *self,
int (*func)(dpiDeqOptions*, const char**, uint32_t*))
{
uint32_t valueLength;
const char *value;
if ((*func)(self->handle, &value, &valueLength) < 0)
return Error_RaiseAndReturnNull();
if (!value)
Py_RETURN_NONE;
return cxString_FromEncodedString(value, valueLength, self->encoding);
}
//-----------------------------------------------------------------------------
// DeqOptions_SetAttrText()
// Set the value of the attribute as text.
//-----------------------------------------------------------------------------
static int DeqOptions_SetAttrText(udt_DeqOptions *self, PyObject *value,
int (*func)(dpiDeqOptions*, const char*, uint32_t))
{
udt_Buffer buffer;
int status;
if (cxBuffer_FromObject(&buffer, value, self->encoding))
return -1;
status = (*func)(self->handle, buffer.ptr, buffer.size);
cxBuffer_Clear(&buffer);
if (status < 0)
return Error_RaiseAndReturnInt();
return 0;
}
//-----------------------------------------------------------------------------
// DeqOptions_GetCondition()
// Get the value of the condition option.
//-----------------------------------------------------------------------------
static PyObject *DeqOptions_GetCondition(udt_DeqOptions *self, void *unused)
{
return DeqOptions_GetAttrText(self, dpiDeqOptions_getCondition);
}
//-----------------------------------------------------------------------------
// DeqOptions_GetConsumerName()
// Get the value of the consumer name option.
//-----------------------------------------------------------------------------
static PyObject *DeqOptions_GetConsumerName(udt_DeqOptions *self, void *unused)
{
return DeqOptions_GetAttrText(self, dpiDeqOptions_getConsumerName);
}
//-----------------------------------------------------------------------------
// DeqOptions_GetCorrelation()
// Get the value of the correlation option.
//-----------------------------------------------------------------------------
static PyObject *DeqOptions_GetCorrelation(udt_DeqOptions *self, void *unused)
{
return DeqOptions_GetAttrText(self, dpiDeqOptions_getCorrelation);
}
//-----------------------------------------------------------------------------
// DeqOptions_GetMode()
// Get the value of the mode option.
//-----------------------------------------------------------------------------
static PyObject *DeqOptions_GetMode(udt_DeqOptions *self, void *unused)
{
dpiDeqMode value;
if (dpiDeqOptions_getMode(self->handle, &value) < 0)
return Error_RaiseAndReturnNull();
return PyInt_FromLong(value);
}
//-----------------------------------------------------------------------------
// DeqOptions_GetMsgId()
// Get the value of the message id option.
//-----------------------------------------------------------------------------
static PyObject *DeqOptions_GetMsgId(udt_DeqOptions *self, void *unused)
{
uint32_t valueLength;
const char *value;
if (dpiDeqOptions_getMsgId(self->handle, &value, &valueLength) < 0)
return Error_RaiseAndReturnNull();
if (!value)
Py_RETURN_NONE;
return PyBytes_FromStringAndSize(value, valueLength);
}
//-----------------------------------------------------------------------------
// DeqOptions_GetNavigation()
// Get the value of the navigation option.
//-----------------------------------------------------------------------------
static PyObject *DeqOptions_GetNavigation(udt_DeqOptions *self, void *unused)
{
dpiDeqNavigation value;
if (dpiDeqOptions_getNavigation(self->handle, &value) < 0)
return Error_RaiseAndReturnNull();
return PyInt_FromLong(value);
}
//-----------------------------------------------------------------------------
// DeqOptions_GetTransformation()
// Get the value of the transformation option.
//-----------------------------------------------------------------------------
static PyObject *DeqOptions_GetTransformation(udt_DeqOptions *self,
void *unused)
{
return DeqOptions_GetAttrText(self, dpiDeqOptions_getTransformation);
}
//-----------------------------------------------------------------------------
// DeqOptions_GetVisibility()
// Get the value of the visibility option.
//-----------------------------------------------------------------------------
static PyObject *DeqOptions_GetVisibility(udt_DeqOptions *self, void *unused)
{
dpiVisibility value;
if (dpiDeqOptions_getVisibility(self->handle, &value) < 0)
return Error_RaiseAndReturnNull();
return PyInt_FromLong(value);
}
//-----------------------------------------------------------------------------
// DeqOptions_GetWait()
// Get the value of the wait option.
//-----------------------------------------------------------------------------
static PyObject *DeqOptions_GetWait(udt_DeqOptions *self, void *unused)
{
uint32_t value;
if (dpiDeqOptions_getWait(self->handle, &value) < 0)
return Error_RaiseAndReturnNull();
return PyInt_FromLong(value);
}
//-----------------------------------------------------------------------------
// DeqOptions_SetCondition()
// Set the value of the condition option.
//-----------------------------------------------------------------------------
static int DeqOptions_SetCondition(udt_DeqOptions *self, PyObject *valueObj,
void *unused)
{
return DeqOptions_SetAttrText(self, valueObj, dpiDeqOptions_setCondition);
}
//-----------------------------------------------------------------------------
// DeqOptions_SetConsumerName()
// Set the value of the consumer name option.
//-----------------------------------------------------------------------------
static int DeqOptions_SetConsumerName(udt_DeqOptions *self, PyObject *valueObj,
void *unused)
{
return DeqOptions_SetAttrText(self, valueObj,
dpiDeqOptions_setConsumerName);
}
//-----------------------------------------------------------------------------
// DeqOptions_SetCorrelation()
// Set the value of the correlation option.
//-----------------------------------------------------------------------------
static int DeqOptions_SetCorrelation(udt_DeqOptions *self, PyObject *valueObj,
void *unused)
{
return DeqOptions_SetAttrText(self, valueObj,
dpiDeqOptions_setCorrelation);
}
//-----------------------------------------------------------------------------
// DeqOptions_SetDeliveryMode()
// Set the value of the delivery mode option.
//-----------------------------------------------------------------------------
static int DeqOptions_SetDeliveryMode(udt_DeqOptions *self, PyObject *valueObj,
void *unused)
{
dpiMessageDeliveryMode value;
value = PyInt_AsLong(valueObj);
if (PyErr_Occurred())
return -1;
if (dpiDeqOptions_setDeliveryMode(self->handle, value) < 0)
return Error_RaiseAndReturnInt();
return 0;
}
//-----------------------------------------------------------------------------
// DeqOptions_SetMode()
// Set the value of the mode option.
//-----------------------------------------------------------------------------
static int DeqOptions_SetMode(udt_DeqOptions *self, PyObject *valueObj,
void *unused)
{
dpiDeqMode value;
value = PyInt_AsLong(valueObj);
if (PyErr_Occurred())
return -1;
if (dpiDeqOptions_setMode(self->handle, value) < 0)
return Error_RaiseAndReturnInt();
return 0;
}
//-----------------------------------------------------------------------------
// DeqOptions_SetMsgId()
// Set the value of the message id option.
//-----------------------------------------------------------------------------
static int DeqOptions_SetMsgId(udt_DeqOptions *self, PyObject *valueObj,
void *unused)
{
Py_ssize_t valueLength;
char *value;
if (PyBytes_AsStringAndSize(valueObj, &value, &valueLength) < 0)
return -1;
if (dpiDeqOptions_setMsgId(self->handle, value, valueLength) < 0)
return Error_RaiseAndReturnInt();
return 0;
}
//-----------------------------------------------------------------------------
// DeqOptions_SetNavigation()
// Set the value of the navigation option.
//-----------------------------------------------------------------------------
static int DeqOptions_SetNavigation(udt_DeqOptions *self, PyObject *valueObj,
void *unused)
{
dpiDeqNavigation value;
value = PyInt_AsLong(valueObj);
if (PyErr_Occurred())
return -1;
if (dpiDeqOptions_setNavigation(self->handle, value) < 0)
return Error_RaiseAndReturnInt();
return 0;
}
//-----------------------------------------------------------------------------
// DeqOptions_SetTransformation()
// Set the value of the correlation option.
//-----------------------------------------------------------------------------
static int DeqOptions_SetTransformation(udt_DeqOptions *self,
PyObject *valueObj, void *unused)
{
return DeqOptions_SetAttrText(self, valueObj,
dpiDeqOptions_setTransformation);
}
//-----------------------------------------------------------------------------
// DeqOptions_SetVisibility()
// Set the value of the visibility option.
//-----------------------------------------------------------------------------
static int DeqOptions_SetVisibility(udt_DeqOptions *self, PyObject *valueObj,
void *unused)
{
dpiVisibility value;
value = PyInt_AsLong(valueObj);
if (PyErr_Occurred())
return -1;
if (dpiDeqOptions_setVisibility(self->handle, value) < 0)
return Error_RaiseAndReturnInt();
return 0;
}
//-----------------------------------------------------------------------------
// DeqOptions_SetWait()
// Set the value of the wait option.
//-----------------------------------------------------------------------------
static int DeqOptions_SetWait(udt_DeqOptions *self, PyObject *valueObj,
void *unused)
{
uint32_t value;
value = PyInt_AsLong(valueObj);
if (PyErr_Occurred())
return -1;
if (dpiDeqOptions_setWait(self->handle, value) < 0)
return Error_RaiseAndReturnInt();
return 0;
}

222
src/EnqOptions.c Normal file
View File

@ -0,0 +1,222 @@
//-----------------------------------------------------------------------------
// Copyright 2016, 2017, Oracle and/or its affiliates. All rights reserved.
//
// Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
//
// Portions Copyright 2001-2007, Computronix (Canada) Ltd., Edmonton, Alberta,
// Canada. All rights reserved.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// EnqOptions.c
// Implements the enqueue options objects used in Advanced Queuing.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// structure used for implementing enqueue options
//-----------------------------------------------------------------------------
typedef struct {
PyObject_HEAD
dpiEnqOptions *handle;
const char *encoding;
} udt_EnqOptions;
//-----------------------------------------------------------------------------
// Declaration of methods used for enqueue options
//-----------------------------------------------------------------------------
static udt_EnqOptions *EnqOptions_New(udt_Connection*);
static void EnqOptions_Free(udt_EnqOptions*);
static PyObject *EnqOptions_GetTransformation(udt_EnqOptions*, void*);
static PyObject *EnqOptions_GetVisibility(udt_EnqOptions*, void*);
static int EnqOptions_SetDeliveryMode(udt_EnqOptions*, PyObject*, void*);
static int EnqOptions_SetTransformation(udt_EnqOptions*, PyObject*, void*);
static int EnqOptions_SetVisibility(udt_EnqOptions*, PyObject*, void*);
//-----------------------------------------------------------------------------
// declaration of calculated members for Python type "EnqOptions"
//-----------------------------------------------------------------------------
static PyGetSetDef g_EnqOptionsCalcMembers[] = {
{ "deliverymode", 0, (setter) EnqOptions_SetDeliveryMode, 0, 0 },
{ "transformation", (getter) EnqOptions_GetTransformation,
(setter) EnqOptions_SetTransformation, 0, 0 },
{ "visibility", (getter) EnqOptions_GetVisibility,
(setter) EnqOptions_SetVisibility, 0, 0 },
{ NULL }
};
//-----------------------------------------------------------------------------
// Python type declarations
//-----------------------------------------------------------------------------
static PyTypeObject g_EnqOptionsType = {
PyVarObject_HEAD_INIT(NULL, 0)
"cx_Oracle.EnqOptions", // tp_name
sizeof(udt_EnqOptions), // tp_basicsize
0, // tp_itemsize
(destructor) EnqOptions_Free, // tp_dealloc
0, // tp_print
0, // tp_getattr
0, // tp_setattr
0, // tp_compare
0, // tp_repr
0, // tp_as_number
0, // tp_as_sequence
0, // tp_as_mapping
0, // tp_hash
0, // tp_call
0, // tp_str
0, // tp_getattro
0, // tp_setattro
0, // tp_as_buffer
Py_TPFLAGS_DEFAULT, // tp_flags
0, // tp_doc
0, // tp_traverse
0, // tp_clear
0, // tp_richcompare
0, // tp_weaklistoffset
0, // tp_iter
0, // tp_iternext
0, // tp_methods
0, // tp_members
g_EnqOptionsCalcMembers, // tp_getset
0, // tp_base
0, // tp_dict
0, // tp_descr_get
0, // tp_descr_set
0, // tp_dictoffset
0, // tp_init
0, // tp_alloc
0, // tp_new
0, // tp_free
0, // tp_is_gc
0 // tp_bases
};
//-----------------------------------------------------------------------------
// EnqOptions_New()
// Create a new enqueue options object.
//-----------------------------------------------------------------------------
static udt_EnqOptions *EnqOptions_New(udt_Connection *connection)
{
udt_EnqOptions *self;
self = (udt_EnqOptions*) g_EnqOptionsType.tp_alloc(&g_EnqOptionsType, 0);
if (!self)
return NULL;
if (dpiConn_newEnqOptions(connection->handle, &self->handle) < 0) {
Py_DECREF(self);
Error_RaiseAndReturnNull();
return NULL;
}
self->encoding = connection->encodingInfo.encoding;
return self;
}
//-----------------------------------------------------------------------------
// EnqOptions_Free()
// Free the memory associated with the enqueue options object.
//-----------------------------------------------------------------------------
static void EnqOptions_Free(udt_EnqOptions *self)
{
if (self->handle) {
dpiEnqOptions_release(self->handle);
self->handle = NULL;
}
Py_TYPE(self)->tp_free((PyObject*) self);
}
//-----------------------------------------------------------------------------
// EnqOptions_GetTransformation()
// Get the value of the transformation option.
//-----------------------------------------------------------------------------
static PyObject *EnqOptions_GetTransformation(udt_EnqOptions *self,
void *unused)
{
uint32_t valueLength;
const char *value;
if (dpiEnqOptions_getTransformation(self->handle, &value,
&valueLength) < 0)
return Error_RaiseAndReturnNull();
if (!value)
Py_RETURN_NONE;
return cxString_FromEncodedString(value, valueLength, self->encoding);
}
//-----------------------------------------------------------------------------
// EnqOptions_GetVisibility()
// Get the value of the visibility option.
//-----------------------------------------------------------------------------
static PyObject *EnqOptions_GetVisibility(udt_EnqOptions *self, void *unused)
{
dpiVisibility value;
if (dpiEnqOptions_getVisibility(self->handle, &value) < 0)
return Error_RaiseAndReturnNull();
return PyInt_FromLong(value);
}
//-----------------------------------------------------------------------------
// EnqOptions_SetDeliveryMode()
// Set the value of the delivery mode option.
//-----------------------------------------------------------------------------
static int EnqOptions_SetDeliveryMode(udt_EnqOptions *self, PyObject *valueObj,
void *unused)
{
dpiMessageDeliveryMode value;
value = PyInt_AsLong(valueObj);
if (PyErr_Occurred())
return -1;
if (dpiEnqOptions_setDeliveryMode(self->handle, value) < 0)
return Error_RaiseAndReturnInt();
return 0;
}
//-----------------------------------------------------------------------------
// EnqOptions_SetTransformation()
// Set the value of the transformation option.
//-----------------------------------------------------------------------------
static int EnqOptions_SetTransformation(udt_EnqOptions *self,
PyObject *valueObj, void *unused)
{
udt_Buffer buffer;
int status;
if (cxBuffer_FromObject(&buffer, valueObj, self->encoding) < 0)
return -1;
status = dpiEnqOptions_setTransformation(self->handle, buffer.ptr,
buffer.size);
cxBuffer_Clear(&buffer);
if (status < 0)
return Error_RaiseAndReturnInt();
return 0;
}
//-----------------------------------------------------------------------------
// EnqOptions_SetVisibility()
// Set the value of the visibility option.
//-----------------------------------------------------------------------------
static int EnqOptions_SetVisibility(udt_EnqOptions *self,
PyObject *valueObj, void *unused)
{
dpiVisibility value;
value = PyInt_AsLong(valueObj);
if (PyErr_Occurred())
return -1;
if (dpiEnqOptions_setVisibility(self->handle, value) < 0)
return Error_RaiseAndReturnInt();
return 0;
}

View File

@ -1,404 +0,0 @@
//-----------------------------------------------------------------------------
// Copyright 2016, 2017, Oracle and/or its affiliates. All rights reserved.
//
// Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
//
// Portions Copyright 2001-2007, Computronix (Canada) Ltd., Edmonton, Alberta,
// Canada. All rights reserved.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Environment.c
// Environment handling.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// structure for the Python type
//-----------------------------------------------------------------------------
typedef struct {
PyObject_HEAD
OCIEnv *handle;
OCIError *errorHandle;
int maxBytesPerCharacter;
int nmaxBytesPerCharacter;
char *encoding;
char *nencoding;
ub2 charsetId;
ub2 ncharsetId;
PyObject *cloneEnv;
udt_Buffer numberToStringFormatBuffer;
udt_Buffer numberFromStringFormatBuffer;
udt_Buffer nlsNumericCharactersBuffer;
} udt_Environment;
//-----------------------------------------------------------------------------
// forward declarations
//-----------------------------------------------------------------------------
static void Environment_Free(udt_Environment*);
static int Environment_CheckForError(udt_Environment*, sword, const char*);
//-----------------------------------------------------------------------------
// declaration of Python type
//-----------------------------------------------------------------------------
static PyTypeObject g_EnvironmentType = {
PyVarObject_HEAD_INIT(NULL, 0)
"OracleEnvironment", // tp_name
sizeof(udt_Environment), // tp_basicsize
0, // tp_itemsize
(destructor) Environment_Free, // tp_dealloc
0, // tp_print
0, // tp_getattr
0, // tp_setattr
0, // tp_compare
0, // tp_repr
0, // tp_as_number
0, // tp_as_sequence
0, // tp_as_mapping
0, // tp_hash
0, // tp_call
0, // tp_str
0, // tp_getattro
0, // tp_setattro
0, // tp_as_buffer
Py_TPFLAGS_DEFAULT, // tp_flags
0 // tp_doc
};
#include "Error.c"
//-----------------------------------------------------------------------------
// Environment_New()
// Create a new environment object.
//-----------------------------------------------------------------------------
static udt_Environment *Environment_New(
OCIEnv *handle) // handle to use
{
udt_Environment *env;
udt_Error *errorObj;
sword status;
// create a new object for the Oracle environment
env = (udt_Environment*) g_EnvironmentType.tp_alloc(&g_EnvironmentType, 0);
if (!env)
return NULL;
env->handle = handle;
env->maxBytesPerCharacter = 1;
env->nmaxBytesPerCharacter = 4;
cxBuffer_Init(&env->numberToStringFormatBuffer);
cxBuffer_Init(&env->numberFromStringFormatBuffer);
cxBuffer_Init(&env->nlsNumericCharactersBuffer);
// create the error handle
status = OCIHandleAlloc(handle, (dvoid**) &env->errorHandle,
OCI_HTYPE_ERROR, 0, 0);
if (status != OCI_SUCCESS) {
errorObj = Error_InternalNew(env,
"Environment_New(): create error handle", OCI_HTYPE_ENV,
handle);
if (!errorObj) {
Py_DECREF(env);
return NULL;
}
PyErr_SetObject(g_DatabaseErrorException, (PyObject*) errorObj);
Py_DECREF(env);
return NULL;
}
return env;
}
//-----------------------------------------------------------------------------
// Environment_GetCharacterSetName()
// Retrieve and store the IANA character set name for the attribute.
//-----------------------------------------------------------------------------
static int Environment_GetCharacterSetName(
udt_Environment *self, // environment object
ub2 attribute, // attribute to fetch
const char *overrideValue, // override value, if specified
char **result, // place to store result
ub2 *charsetId) // character set ID (OUT)
{
char charsetName[OCI_NLS_MAXBUFSZ], ianaCharsetName[OCI_NLS_MAXBUFSZ];
sword status;
// get character set id
status = OCIAttrGet(self->handle, OCI_HTYPE_ENV, charsetId, NULL,
attribute, self->errorHandle);
if (Environment_CheckForError(self, status,
"Environment_GetCharacterSetName(): get charset id") < 0)
return -1;
// if override value specified, use it
if (overrideValue) {
*result = PyMem_Malloc(strlen(overrideValue) + 1);
if (!*result)
return -1;
strcpy(*result, overrideValue);
return 0;
}
// get character set name
status = OCINlsCharSetIdToName(self->handle, (text*) charsetName,
OCI_NLS_MAXBUFSZ, *charsetId);
if (Environment_CheckForError(self, status,
"Environment_GetCharacterSetName(): get Oracle charset name") < 0)
return -1;
// get IANA character set name
status = OCINlsNameMap(self->handle, (oratext*) ianaCharsetName,
OCI_NLS_MAXBUFSZ, (oratext*) charsetName, OCI_NLS_CS_ORA_TO_IANA);
if (Environment_CheckForError(self, status,
"Environment_GetCharacterSetName(): translate NLS charset") < 0)
return -1;
// store results
*result = PyMem_Malloc(strlen(ianaCharsetName) + 1);
if (!*result)
return -1;
strcpy(*result, ianaCharsetName);
return 0;
}
//-----------------------------------------------------------------------------
// Environment_SetBuffer()
// Set the buffer in the environment from the specified string.
//-----------------------------------------------------------------------------
static int Environment_SetBuffer(
udt_Buffer *buf, // buffer to set
const char *value, // ASCII value to use
const char *encoding) // encoding to use
{
PyObject *obj;
obj = cxString_FromAscii(value);
if (!obj)
return -1;
if (cxBuffer_FromObject(buf, obj, encoding) < 0) {
Py_DECREF(obj);
return -1;
}
Py_CLEAR(obj);
return 0;
}
//-----------------------------------------------------------------------------
// Environment_LookupCharSet()
// Look up an Oracle character set given the name. This can be either the
// Oracle character set name or the IANA encoding name. A pointer to an
// environment handle is passed and an environment created if needed in
// order to perform the lookup.
//-----------------------------------------------------------------------------
static int Environment_LookupCharSet(
const char *name, // IANA or Oracle character set name
OCIEnv **envHandle, // environment handle (IN/OUT)
ub2 *charsetId) // Oracle character set id (OUT)
{
char oraCharsetName[OCI_NLS_MAXBUFSZ];
sword status;
// if IANA name is null, use the charset 0 which tells Oracle to make use
// of the NLS_LANG and NLS_NCHAR environment variables
if (!name) {
*charsetId = 0;
return 0;
}
// create environment, if needed
if (!*envHandle) {
status = OCIEnvCreate(envHandle, OCI_DEFAULT, NULL, NULL, NULL, NULL,
0, NULL);
if (status != OCI_SUCCESS) {
PyErr_SetString(g_InterfaceErrorException,
"Unable to acquire Oracle environment handle");
return -1;
}
}
// check for the Oracle character set name first
// if that fails, lookup using the IANA character set name
*charsetId = OCINlsCharSetNameToId(*envHandle, (oratext*) name);
if (!*charsetId) {
status = OCINlsNameMap(*envHandle, (oratext*) oraCharsetName,
sizeof(oraCharsetName), (oratext*) name,
OCI_NLS_CS_IANA_TO_ORA);
if (status == OCI_ERROR) {
PyErr_SetString(g_InterfaceErrorException,
"Invalid character set name");
return -1;
}
*charsetId = OCINlsCharSetNameToId(*envHandle,
(oratext*) oraCharsetName);
}
return 0;
}
//-----------------------------------------------------------------------------
// Environment_NewFromScratch()
// Create a new environment object from scratch.
//-----------------------------------------------------------------------------
static udt_Environment *Environment_NewFromScratch(
int threaded, // use threaded mode?
int events, // use events mode?
char *encoding, // override value for encoding
char *nencoding) // override value for nencoding
{
ub2 charsetId, ncharsetId;
udt_Environment *env;
OCIEnv *handle;
sword status;
ub4 mode;
// turn threading mode on, if desired
mode = OCI_OBJECT;
if (threaded)
mode |= OCI_THREADED;
if (events)
mode |= OCI_EVENTS;
// perform lookup of character sets to use
// keep track of any environment that needs to be created in order to
// perform this lookup
handle = NULL;
status = Environment_LookupCharSet(encoding, &handle, &charsetId);
if (status == 0)
status = Environment_LookupCharSet(nencoding, &handle, &ncharsetId);
if (handle) {
OCIHandleFree(handle, OCI_HTYPE_ENV);
handle = NULL;
}
if (status < 0)
return NULL;
// create the new environment handle
status = OCIEnvNlsCreate(&handle, mode, NULL, NULL, NULL, NULL, 0, NULL,
charsetId, ncharsetId);
if (!handle ||
(status != OCI_SUCCESS && status != OCI_SUCCESS_WITH_INFO)) {
PyErr_SetString(g_InterfaceErrorException,
"Unable to acquire Oracle environment handle");
return NULL;
}
// create the environment object
env = Environment_New(handle);
if (!env) {
OCIHandleFree(handle, OCI_HTYPE_ENV);
return NULL;
}
// acquire max bytes per character
status = OCINlsNumericInfoGet(env->handle, env->errorHandle,
&env->maxBytesPerCharacter, OCI_NLS_CHARSET_MAXBYTESZ);
if (Environment_CheckForError(env, status,
"Environment_New(): get max bytes per character") < 0) {
Py_DECREF(env);
return NULL;
}
// determine encodings to use for Unicode values
if (Environment_GetCharacterSetName(env, OCI_ATTR_ENV_CHARSET_ID,
encoding, &env->encoding, &env->charsetId) < 0)
return NULL;
if (Environment_GetCharacterSetName(env, OCI_ATTR_ENV_NCHARSET_ID,
nencoding, &env->nencoding, &env->ncharsetId) < 0)
return NULL;
// max bytes per character for NCHAR can be assigned only if it matches the
// character set used for CHAR data; OCI does not provide a way of
// determining it otherwise
if (env->ncharsetId == env->charsetId)
env->nmaxBytesPerCharacter = env->maxBytesPerCharacter;
// fill buffers for number formats
if (Environment_SetBuffer(&env->numberToStringFormatBuffer, "TM9",
env->encoding) < 0)
return NULL;
if (Environment_SetBuffer(&env->numberFromStringFormatBuffer,
"999999999999999999999999999999999999999999999999999999999999999",
env->encoding) < 0)
return NULL;
if (Environment_SetBuffer(&env->nlsNumericCharactersBuffer,
"NLS_NUMERIC_CHARACTERS='.,'", env->encoding) < 0)
return NULL;
return env;
}
//-----------------------------------------------------------------------------
// Environment_Clone()
// Clone an existing environment which is used when acquiring a connection
// from a session pool, for example.
//-----------------------------------------------------------------------------
static udt_Environment *Environment_Clone(
udt_Environment *cloneEnv) // environment to clone
{
udt_Environment *env;
env = Environment_New(cloneEnv->handle);
if (!env)
return NULL;
env->maxBytesPerCharacter = cloneEnv->maxBytesPerCharacter;
Py_INCREF(cloneEnv);
env->cloneEnv = (PyObject*) cloneEnv;
env->encoding = cloneEnv->encoding;
env->nencoding = cloneEnv->nencoding;
env->charsetId = cloneEnv->charsetId;
env->ncharsetId = cloneEnv->ncharsetId;
cxBuffer_Copy(&env->numberToStringFormatBuffer,
&cloneEnv->numberToStringFormatBuffer);
cxBuffer_Copy(&env->numberFromStringFormatBuffer,
&cloneEnv->numberFromStringFormatBuffer);
cxBuffer_Copy(&env->nlsNumericCharactersBuffer,
&cloneEnv->nlsNumericCharactersBuffer);
return env;
}
//-----------------------------------------------------------------------------
// Environment_Free()
// Deallocate the environment. Note that destroying the environment handle
// will automatically destroy any child handles that were created.
//-----------------------------------------------------------------------------
static void Environment_Free(
udt_Environment *self) // environment object
{
if (self->errorHandle)
OCIHandleFree(self->errorHandle, OCI_HTYPE_ERROR);
if (self->handle && !self->cloneEnv)
OCIHandleFree(self->handle, OCI_HTYPE_ENV);
if (!self->cloneEnv) {
if (self->encoding)
PyMem_Free(self->encoding);
if (self->nencoding)
PyMem_Free(self->nencoding);
}
cxBuffer_Clear(&self->numberToStringFormatBuffer);
cxBuffer_Clear(&self->numberFromStringFormatBuffer);
cxBuffer_Clear(&self->nlsNumericCharactersBuffer);
Py_CLEAR(self->cloneEnv);
Py_TYPE(self)->tp_free((PyObject*) self);
}
//-----------------------------------------------------------------------------
// Environment_CheckForError()
// Check for an error in the last call and if an error has occurred, raise a
// Python exception.
//-----------------------------------------------------------------------------
static int Environment_CheckForError(
udt_Environment *environment, // environment to raise error in
sword status, // status of last call
const char *context) // context
{
return Error_Check(environment, status, context, environment->errorHandle);
}

View File

@ -17,24 +17,14 @@
//-----------------------------------------------------------------------------
typedef struct {
PyObject_HEAD
sb4 code;
ub2 offset;
long code;
unsigned offset;
PyObject *message;
const char *context;
boolean isRecoverable;
PyObject *context;
char isRecoverable;
} udt_Error;
//-----------------------------------------------------------------------------
// maximum size of error message string in bytes
//-----------------------------------------------------------------------------
#ifdef OCI_ERROR_MAXMSG_SIZE2
#define ERROR_BUF_SIZE OCI_ERROR_MAXMSG_SIZE2
#else
#define ERROR_BUF_SIZE OCI_ERROR_MAXMSG_SIZE
#endif
//-----------------------------------------------------------------------------
// forward declarations
//-----------------------------------------------------------------------------
@ -57,10 +47,10 @@ static PyMethodDef g_ErrorMethods[] = {
// declaration of members
//-----------------------------------------------------------------------------
static PyMemberDef g_ErrorMembers[] = {
{ "code", T_INT, offsetof(udt_Error, code), READONLY },
{ "offset", T_INT, offsetof(udt_Error, offset), READONLY },
{ "code", T_LONG, offsetof(udt_Error, code), READONLY },
{ "offset", T_UINT, offsetof(udt_Error, offset), READONLY },
{ "message", T_OBJECT, offsetof(udt_Error, message), READONLY },
{ "context", T_STRING, offsetof(udt_Error, context), READONLY },
{ "context", T_OBJECT, offsetof(udt_Error, context), READONLY },
{ "isrecoverable", T_BOOL, offsetof(udt_Error, isRecoverable), READONLY },
{ NULL }
};
@ -116,12 +106,12 @@ static PyTypeObject g_ErrorType = {
//-----------------------------------------------------------------------------
// Error_Free()
// Deallocate the environment, disconnecting from the database if necessary.
// Deallocate the error.
//-----------------------------------------------------------------------------
static void Error_Free(
udt_Error *self) // error object
static void Error_Free(udt_Error *self)
{
Py_CLEAR(self->message);
Py_CLEAR(self->context);
PyObject_Del(self);
}
@ -131,32 +121,29 @@ static void Error_Free(
// Create a new error object. This is intended to only be used by the
// unpickling routine, and not by direct creation!
//-----------------------------------------------------------------------------
static PyObject *Error_New(
PyTypeObject *type, // type object
PyObject *args, // arguments
PyObject *keywordArgs) // keyword arguments
static PyObject *Error_New(PyTypeObject *type, PyObject *args,
PyObject *keywordArgs)
{
boolean isRecoverable;
PyObject *message;
PyObject *message, *context;
int isRecoverable, code;
udt_Error *self;
unsigned offset;
char *context;
int code;
isRecoverable = 0;
if (!PyArg_ParseTuple(args, "OiIs|i", &message, &code, &offset, &context,
if (!PyArg_ParseTuple(args, "OiIO|i", &message, &code, &offset, &context,
&isRecoverable))
return NULL;
self = (udt_Error*) type->tp_alloc(type, 0);
if (!self)
return NULL;
self->context = context;
self->code = code;
self->offset = offset;
self->isRecoverable = isRecoverable;
self->isRecoverable = (char) isRecoverable;
Py_INCREF(message);
self->message = message;
Py_INCREF(context);
self->context = context;
return (PyObject*) self;
}
@ -166,8 +153,7 @@ static PyObject *Error_New(
// Error_Str()
// Return a string representation of the error variable.
//-----------------------------------------------------------------------------
static PyObject *Error_Str(
udt_Error *self) // variable to return the string for
static PyObject *Error_Str(udt_Error *self)
{
Py_INCREF(self->message);
return self->message;
@ -176,57 +162,61 @@ static PyObject *Error_Str(
//-----------------------------------------------------------------------------
// Error_InternalNew()
// Internal method for creating an error object.
// Internal method for creating an error object from the DPI error
// information.
//-----------------------------------------------------------------------------
static udt_Error *Error_InternalNew(
udt_Environment *environment, // environment object
const char *context, // context in which error occurred
ub4 handleType, // handle type
dvoid* handle) // handle
static udt_Error *Error_InternalNew(dpiErrorInfo *errorInfo)
{
char errorText[ERROR_BUF_SIZE];
PyObject *format, *args, *fnName, *action;
udt_Error *self;
sword status;
#if PY_MAJOR_VERSION >= 3
Py_ssize_t len;
#endif
// create error object and initialize it
self = (udt_Error*) g_ErrorType.tp_alloc(&g_ErrorType, 0);
if (!self)
return NULL;
self->context = context;
self->code = errorInfo->code;
self->offset = errorInfo->offset;
self->isRecoverable = (char) errorInfo->isRecoverable;
if (handle) {
status = OCIErrorGet(handle, 1, 0, &self->code,
(unsigned char*) errorText, sizeof(errorText), handleType);
if (status != OCI_SUCCESS) {
Py_DECREF(self);
PyErr_SetString(g_InternalErrorException, "No Oracle error?");
return NULL;
}
#if PY_MAJOR_VERSION < 3
self->message = PyBytes_FromString(errorText);
#else
len = strlen(errorText);
self->message = PyUnicode_Decode(errorText, len, environment->encoding,
NULL);
#endif
if (!self->message) {
Py_DECREF(self);
return NULL;
}
#if ORACLE_VERSION_HEX >= ORACLE_VERSION(12, 1)
// determine if error is recoverable (Transaction Guard)
// if the attribute cannot be read properly, simply set it to false;
// otherwise, that error will mask the one that we really want to see
if (handleType == OCI_HTYPE_ERROR) {
status = OCIAttrGet(handle, handleType,
(dvoid*) &self->isRecoverable, 0,
OCI_ATTR_ERROR_IS_RECOVERABLE, handle);
if (status != OCI_SUCCESS)
self->isRecoverable = 0;
}
#endif
// create message
self->message = cxString_FromEncodedString(errorInfo->message,
errorInfo->messageLength, errorInfo->encoding);
if (!self->message) {
Py_DECREF(self);
return NULL;
}
// create context composed of function name and action
fnName = cxString_FromAscii(errorInfo->fnName);
if (!fnName) {
Py_DECREF(self);
return NULL;
}
action = cxString_FromAscii(errorInfo->action);
if (!action) {
Py_DECREF(fnName);
Py_DECREF(self);
return NULL;
}
args = PyTuple_Pack(2, fnName, action);
Py_DECREF(fnName);
Py_DECREF(action);
if (!args) {
Py_DECREF(self);
return NULL;
}
format = cxString_FromAscii("%s: %s");
if (!format) {
Py_DECREF(self);
Py_DECREF(args);
return NULL;
}
self->context = cxString_Format(format, args);
Py_DECREF(format);
Py_DECREF(args);
if (!self->context) {
Py_DECREF(self);
return NULL;
}
return self;
@ -234,94 +224,84 @@ static udt_Error *Error_InternalNew(
//-----------------------------------------------------------------------------
// Error_Raise()
// Reads the error that was caused by the last Oracle statement and raise an
// exception for Python. Return -1 as a convenience to the caller.
// Error_RaiseFromInfo()
// Internal method for raising an exception given an error information
// structure from DPI. Return -1 as a convenience to the caller.
//-----------------------------------------------------------------------------
static int Error_Raise(
udt_Environment *environment, // environment object
const char *context, // context in which error occurred
OCIError* errorHandle) // handle
static int Error_RaiseFromInfo(dpiErrorInfo *errorInfo)
{
PyObject *exceptionType;
udt_Error *error;
udt_Error *self;
error = Error_InternalNew(environment, context, OCI_HTYPE_ERROR,
errorHandle);
if (error) {
switch (error->code) {
case 1:
case 1400:
case 2290:
case 2291:
case 2292:
exceptionType = g_IntegrityErrorException;
break;
case 22:
case 378:
case 602:
case 603:
case 604:
case 609:
case 1012:
case 1013:
case 1033:
case 1034:
case 1041:
case 1043:
case 1089:
case 1090:
case 1092:
case 3113:
case 3114:
case 3122:
case 3135:
case 12153:
case 12203:
case 12500:
case 12571:
case 27146:
case 28511:
exceptionType = g_OperationalErrorException;
break;
default:
exceptionType = g_DatabaseErrorException;
break;
}
PyErr_SetObject(exceptionType, (PyObject*) error);
Py_DECREF(error);
self = Error_InternalNew(errorInfo);
switch (errorInfo->code) {
case 1:
case 1400:
case 2290:
case 2291:
case 2292:
exceptionType = g_IntegrityErrorException;
break;
case 22:
case 378:
case 602:
case 603:
case 604:
case 609:
case 1012:
case 1013:
case 1033:
case 1034:
case 1041:
case 1043:
case 1089:
case 1090:
case 1092:
case 3113:
case 3114:
case 3122:
case 3135:
case 12153:
case 12203:
case 12500:
case 12571:
case 27146:
case 28511:
exceptionType = g_OperationalErrorException;
break;
default:
exceptionType = g_DatabaseErrorException;
break;
}
PyErr_SetObject(exceptionType, (PyObject*) self);
Py_DECREF(self);
return -1;
}
//-----------------------------------------------------------------------------
// Error_Check()
// Check for an error in the last call and if an error has occurred, raise a
// Python exception.
// Error_RaiseAndReturnInt()
// Internal method for raising an exception from an error generated from DPI.
// Return -1 as a convenience to the caller.
//-----------------------------------------------------------------------------
static int Error_Check(
udt_Environment *environment, // environment to raise error in
sword status, // status of last call
const char *context, // context
OCIError *errorHandle) // error handle to use
static int Error_RaiseAndReturnInt(void)
{
udt_Error *error;
dpiErrorInfo errorInfo;
if (status != OCI_SUCCESS && status != OCI_SUCCESS_WITH_INFO) {
if (status != OCI_INVALID_HANDLE)
return Error_Raise(environment, context, errorHandle);
error = Error_InternalNew(environment, context, 0, NULL);
if (!error)
return -1;
error->code = 0;
error->message = cxString_FromAscii("Invalid handle!");
if (!error->message)
Py_DECREF(error);
else PyErr_SetObject(g_DatabaseErrorException, (PyObject*) error);
return -1;
}
return 0;
dpiContext_getError(g_DpiContext, &errorInfo);
return Error_RaiseFromInfo(&errorInfo);
}
//-----------------------------------------------------------------------------
// Error_RaiseAndReturnNull()
// Internal method for raising an exception from an error generated from DPI.
// Return NULL as a convenience to the caller.
//-----------------------------------------------------------------------------
static PyObject *Error_RaiseAndReturnNull(void)
{
Error_RaiseAndReturnInt();
return NULL;
}
@ -329,10 +309,9 @@ static int Error_Check(
// Error_Reduce()
// Method provided for pickling/unpickling of Error objects.
//-----------------------------------------------------------------------------
static PyObject *Error_Reduce(
udt_Error *self) // error object
static PyObject *Error_Reduce(udt_Error *self)
{
return Py_BuildValue("(O(OiIs))", Py_TYPE(self), self->message,
return Py_BuildValue("(O(OiIO))", Py_TYPE(self), self->message,
self->code, self->offset, self->context);
}

View File

@ -1,666 +0,0 @@
//-----------------------------------------------------------------------------
// Copyright 2016, 2017, Oracle and/or its affiliates. All rights reserved.
//
// Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
//
// Portions Copyright 2001-2007, Computronix (Canada) Ltd., Edmonton, Alberta,
// Canada. All rights reserved.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// ExternalLobVar.c
// Defines the routines for handling LOB variables external to this module.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// external LOB type
//-----------------------------------------------------------------------------
typedef struct {
PyObject_HEAD
udt_LobVar *lobVar;
unsigned pos;
unsigned internalFetchNum;
} udt_ExternalLobVar;
//-----------------------------------------------------------------------------
// Declaration of external LOB variable functions.
//-----------------------------------------------------------------------------
static void ExternalLobVar_Free(udt_ExternalLobVar*);
static PyObject *ExternalLobVar_Str(udt_ExternalLobVar*);
static PyObject *ExternalLobVar_Size(udt_ExternalLobVar*, PyObject*);
static PyObject *ExternalLobVar_Open(udt_ExternalLobVar*, PyObject*);
static PyObject *ExternalLobVar_Close(udt_ExternalLobVar*, PyObject*);
static PyObject *ExternalLobVar_Read(udt_ExternalLobVar*, PyObject*,
PyObject*);
static PyObject *ExternalLobVar_Write(udt_ExternalLobVar*, PyObject*,
PyObject*);
static PyObject *ExternalLobVar_Trim(udt_ExternalLobVar*, PyObject*,
PyObject*);
static PyObject *ExternalLobVar_GetChunkSize(udt_ExternalLobVar*, PyObject*);
static PyObject *ExternalLobVar_IsOpen(udt_ExternalLobVar*, PyObject*);
static PyObject *ExternalLobVar_GetFileName(udt_ExternalLobVar*, PyObject*);
static PyObject *ExternalLobVar_SetFileName(udt_ExternalLobVar*, PyObject*);
static PyObject *ExternalLobVar_FileExists(udt_ExternalLobVar*, PyObject*);
static PyObject *ExternalLobVar_Reduce(udt_ExternalLobVar*);
//-----------------------------------------------------------------------------
// declaration of methods for Python type "ExternalLOBVar"
//-----------------------------------------------------------------------------
static PyMethodDef g_ExternalLobVarMethods[] = {
{ "size", (PyCFunction) ExternalLobVar_Size, METH_NOARGS },
{ "open", (PyCFunction) ExternalLobVar_Open, METH_NOARGS },
{ "close", (PyCFunction) ExternalLobVar_Close, METH_NOARGS },
{ "read", (PyCFunction) ExternalLobVar_Read,
METH_VARARGS | METH_KEYWORDS },
{ "write", (PyCFunction) ExternalLobVar_Write,
METH_VARARGS | METH_KEYWORDS },
{ "trim", (PyCFunction) ExternalLobVar_Trim,
METH_VARARGS | METH_KEYWORDS },
{ "getchunksize", (PyCFunction) ExternalLobVar_GetChunkSize, METH_NOARGS },
{ "isopen", (PyCFunction) ExternalLobVar_IsOpen, METH_NOARGS },
{ "getfilename", (PyCFunction) ExternalLobVar_GetFileName, METH_NOARGS },
{ "setfilename", (PyCFunction) ExternalLobVar_SetFileName, METH_VARARGS },
{ "fileexists", (PyCFunction) ExternalLobVar_FileExists, METH_NOARGS },
{ "__reduce__", (PyCFunction) ExternalLobVar_Reduce, METH_NOARGS },
{ NULL, NULL }
};
//-----------------------------------------------------------------------------
// Python type declaration
//-----------------------------------------------------------------------------
static PyTypeObject g_ExternalLobVarType = {
PyVarObject_HEAD_INIT(NULL, 0)
"cx_Oracle.LOB", // tp_name
sizeof(udt_ExternalLobVar), // tp_basicsize
0, // tp_itemsize
(destructor) ExternalLobVar_Free, // tp_dealloc
0, // tp_print
0, // tp_getattr
0, // tp_setattr
0, // tp_compare
0, // tp_repr
0, // tp_as_number
0, // tp_as_sequence
0, // tp_as_mapping
0, // tp_hash
0, // tp_call
(reprfunc) ExternalLobVar_Str, // tp_str
0, // tp_getattro
0, // tp_setattro
0, // tp_as_buffer
Py_TPFLAGS_DEFAULT, // tp_flags
0, // tp_doc
0, // tp_traverse
0, // tp_clear
0, // tp_richcompare
0, // tp_weaklistoffset
0, // tp_iter
0, // tp_iternext
g_ExternalLobVarMethods, // tp_methods
0, // tp_members
0, // tp_getset
0, // tp_base
0, // tp_dict
0, // tp_descr_get
0, // tp_descr_set
0, // tp_dictoffset
0, // tp_init
0, // tp_alloc
0, // tp_new
0, // tp_free
0, // tp_is_gc
0 // tp_bases
};
//-----------------------------------------------------------------------------
// ExternalLobVar_New()
// Create a new external LOB variable.
//-----------------------------------------------------------------------------
PyObject *ExternalLobVar_New(
udt_LobVar *var, // variable to encapsulate
unsigned pos) // position in array to encapsulate
{
udt_ExternalLobVar *self;
self = (udt_ExternalLobVar*)
g_ExternalLobVarType.tp_alloc(&g_ExternalLobVarType, 0);
if (!self)
return NULL;
self->pos = pos;
self->internalFetchNum = var->internalFetchNum;
Py_INCREF(var);
self->lobVar = var;
return (PyObject*) self;
}
//-----------------------------------------------------------------------------
// ExternalLobVar_Free()
// Free an external LOB variable.
//-----------------------------------------------------------------------------
static void ExternalLobVar_Free(
udt_ExternalLobVar *self) // variable to free
{
Py_CLEAR(self->lobVar);
Py_TYPE(self)->tp_free((PyObject*) self);
}
//-----------------------------------------------------------------------------
// ExternalLobVar_Verify()
// Verify that the external LOB var is still valid.
//-----------------------------------------------------------------------------
static int ExternalLobVar_Verify(
udt_ExternalLobVar *var) // variable to verify
{
if (var->internalFetchNum != var->lobVar->internalFetchNum) {
PyErr_SetString(g_ProgrammingErrorException,
"LOB variable no longer valid after subsequent fetch");
return -1;
}
return 0;
}
//-----------------------------------------------------------------------------
// ExternalLobVar_InternalRead()
// Return the size of the LOB variable for internal comsumption.
//-----------------------------------------------------------------------------
static int ExternalLobVar_InternalRead(
udt_ExternalLobVar *var, // variable to return the size of
char *buffer, // buffer in which to put data
oraub8 bufferSize, // size of buffer
oraub8 *length, // length of data (IN/OUT)
oraub8 offset) // offset
{
oraub8 lengthInBytes = 0, lengthInChars = 0;
ub2 charsetId;
sword status;
if (var->lobVar->type == &vt_NCLOB || var->lobVar->type == &vt_CLOB)
lengthInChars = *length;
else lengthInBytes = *length;
if (var->lobVar->isFile) {
Py_BEGIN_ALLOW_THREADS
status = OCILobFileOpen(var->lobVar->connection->handle,
var->lobVar->environment->errorHandle,
var->lobVar->data[var->pos], OCI_FILE_READONLY);
Py_END_ALLOW_THREADS
if (Environment_CheckForError(var->lobVar->environment, status,
"ExternalLobVar_FileOpen()") < 0)
return -1;
}
Py_BEGIN_ALLOW_THREADS
charsetId = (var->lobVar->type->charsetForm == SQLCS_NCHAR) ?
var->lobVar->environment->ncharsetId :
var->lobVar->environment->charsetId;
status = OCILobRead2(var->lobVar->connection->handle,
var->lobVar->environment->errorHandle, var->lobVar->data[var->pos],
&lengthInBytes, &lengthInChars, offset, buffer, bufferSize,
OCI_ONE_PIECE, NULL, NULL, charsetId,
var->lobVar->type->charsetForm);
Py_END_ALLOW_THREADS
if (Environment_CheckForError(var->lobVar->environment, status,
"ExternalLobVar_LobRead()") < 0) {
if (var->lobVar->isFile) {
Py_BEGIN_ALLOW_THREADS
OCILobFileClose(var->lobVar->connection->handle,
var->lobVar->environment->errorHandle,
var->lobVar->data[var->pos]);
Py_END_ALLOW_THREADS
}
return -1;
}
*length = lengthInBytes;
if (var->lobVar->isFile) {
Py_BEGIN_ALLOW_THREADS
status = OCILobFileClose(var->lobVar->connection->handle,
var->lobVar->environment->errorHandle,
var->lobVar->data[var->pos]);
Py_END_ALLOW_THREADS
if (Environment_CheckForError(var->lobVar->environment, status,
"ExternalLobVar_FileClose()") < 0)
return -1;
}
return 0;
}
//-----------------------------------------------------------------------------
// ExternalLobVar_InternalSize()
// Return the size of the LOB variable for internal comsumption.
//-----------------------------------------------------------------------------
static int ExternalLobVar_InternalSize(
udt_ExternalLobVar *var, // variable to return the size of
oraub8 *length) // length to return
{
sword status;
Py_BEGIN_ALLOW_THREADS
status = OCILobGetLength2(var->lobVar->connection->handle,
var->lobVar->environment->errorHandle,
var->lobVar->data[var->pos], length);
Py_END_ALLOW_THREADS
if (Environment_CheckForError(var->lobVar->environment, status,
"ExternalLobVar_InternalSize()") < 0)
return -1;
return 0;
}
//-----------------------------------------------------------------------------
// ExternalLobVar_Value()
// Return a portion (or all) of the data in the external LOB variable.
//-----------------------------------------------------------------------------
static PyObject *ExternalLobVar_Value(
udt_ExternalLobVar *var, // variable to return the size of
oraub8 offset, // offset into LOB
oraub8 amount) // amount to read from LOB
{
oraub8 length, bufferSize;
PyObject *result;
char *buffer;
// modify the arguments
if (amount == (oraub8)(-1)) {
if (ExternalLobVar_InternalSize(var, &amount) < 0)
return NULL;
if (amount >= offset)
amount = amount - offset + 1;
else amount = 1;
}
length = amount;
if (var->lobVar->type == &vt_CLOB)
bufferSize = amount * var->lobVar->environment->maxBytesPerCharacter;
else if (var->lobVar->type == &vt_NCLOB)
bufferSize = amount * var->lobVar->environment->nmaxBytesPerCharacter;
else bufferSize = amount;
// create a string for retrieving the value
buffer = (char*) PyMem_Malloc(bufferSize);
if (!buffer)
return PyErr_NoMemory();
if (ExternalLobVar_InternalRead(var, buffer, bufferSize, &length,
offset) < 0) {
PyMem_Free(buffer);
return NULL;
}
// return the result
if (var->lobVar->type == &vt_CLOB) {
result = cxString_FromEncodedString(buffer, length,
var->lobVar->environment->encoding);
} else if (var->lobVar->type == &vt_NCLOB) {
result = PyUnicode_Decode(buffer, length,
var->lobVar->environment->encoding, NULL);
} else {
result = PyBytes_FromStringAndSize(buffer, length);
}
PyMem_Free(buffer);
return result;
}
//-----------------------------------------------------------------------------
// ExternalLobVar_Size()
// Return the size of the data in the LOB variable.
//-----------------------------------------------------------------------------
static PyObject *ExternalLobVar_Size(
udt_ExternalLobVar *var, // variable to return the size of
PyObject *args) // arguments
{
oraub8 length;
if (ExternalLobVar_Verify(var) < 0)
return NULL;
if (ExternalLobVar_InternalSize(var, &length) < 0)
return NULL;
return PyLong_FromUnsignedLong( (unsigned long) length);
}
//-----------------------------------------------------------------------------
// ExternalLobVar_Open()
// Open the LOB to speed further accesses.
//-----------------------------------------------------------------------------
static PyObject *ExternalLobVar_Open(
udt_ExternalLobVar *var, // variable to return the size of
PyObject *args) // arguments
{
sword status;
if (ExternalLobVar_Verify(var) < 0)
return NULL;
Py_BEGIN_ALLOW_THREADS
status = OCILobOpen(var->lobVar->connection->handle,
var->lobVar->environment->errorHandle,
var->lobVar->data[var->pos], OCI_LOB_READWRITE);
Py_END_ALLOW_THREADS
if (Environment_CheckForError(var->lobVar->environment, status,
"ExternalLobVar_Open()") < 0)
return NULL;
Py_INCREF(Py_None);
return Py_None;
}
//-----------------------------------------------------------------------------
// ExternalLobVar_Close()
// Close the LOB.
//-----------------------------------------------------------------------------
static PyObject *ExternalLobVar_Close(
udt_ExternalLobVar *var, // variable to return the size of
PyObject *args) // arguments
{
sword status;
if (ExternalLobVar_Verify(var) < 0)
return NULL;
Py_BEGIN_ALLOW_THREADS
status = OCILobClose(var->lobVar->connection->handle,
var->lobVar->environment->errorHandle,
var->lobVar->data[var->pos]);
Py_END_ALLOW_THREADS
if (Environment_CheckForError(var->lobVar->environment, status,
"ExternalLobVar_Close()") < 0)
return NULL;
Py_INCREF(Py_None);
return Py_None;
}
//-----------------------------------------------------------------------------
// ExternalLobVar_Read()
// Return a portion (or all) of the data in the external LOB variable.
//-----------------------------------------------------------------------------
static PyObject *ExternalLobVar_Read(
udt_ExternalLobVar *var, // variable to return the size of
PyObject *args, // arguments
PyObject *keywordArgs) // keyword arguments
{
static char *keywordList[] = { "offset", "amount", NULL };
oraub8 offset, amount;
// offset and amount are expected, both optional
offset = 1;
amount = (oraub8)(-1);
if (!PyArg_ParseTupleAndKeywords(args, keywordArgs, "|KK", keywordList,
&offset, &amount))
return NULL;
if (ExternalLobVar_Verify(var) < 0)
return NULL;
return ExternalLobVar_Value(var, offset, amount);
}
//-----------------------------------------------------------------------------
// ExternalLobVar_Str()
// Return all of the data in the external LOB variable.
//-----------------------------------------------------------------------------
static PyObject *ExternalLobVar_Str(
udt_ExternalLobVar *var) // variable to return the string for
{
if (ExternalLobVar_Verify(var) < 0)
return NULL;
return ExternalLobVar_Value(var, 1, (oraub8)(-1));
}
//-----------------------------------------------------------------------------
// ExternalLobVar_Write()
// Write a value to the LOB at the specified offset.
//-----------------------------------------------------------------------------
static PyObject *ExternalLobVar_Write(
udt_ExternalLobVar *var, // variable to perform write against
PyObject *args, // arguments
PyObject *keywordArgs) // keyword arguments
{
static char *keywordList[] = { "data", "offset", NULL };
PyObject *dataObj;
oraub8 offset;
// buffer is expected, offset is optional
offset = 1;
if (!PyArg_ParseTupleAndKeywords(args, keywordArgs, "O|K", keywordList,
&dataObj, &offset))
return NULL;
// perform the write, if possible
if (ExternalLobVar_Verify(var) < 0)
return NULL;
if (LobVar_Write(var->lobVar, var->pos, dataObj, offset) < 0)
return NULL;
Py_RETURN_NONE;
}
//-----------------------------------------------------------------------------
// ExternalLobVar_Trim()
// Trim the LOB variable to the specified length.
//-----------------------------------------------------------------------------
static PyObject *ExternalLobVar_Trim(
udt_ExternalLobVar *var, // variable to perform write against
PyObject *args, // arguments
PyObject *keywordArgs) // keyword arguments
{
static char *keywordList[] = { "newSize", NULL };
oraub8 newSize;
sword status;
// buffer and offset are expected, offset is optional
newSize = 0;
if (!PyArg_ParseTupleAndKeywords(args, keywordArgs, "|K", keywordList,
&newSize))
return NULL;
// create a string for retrieving the value
if (ExternalLobVar_Verify(var) < 0)
return NULL;
Py_BEGIN_ALLOW_THREADS
status = OCILobTrim2(var->lobVar->connection->handle,
var->lobVar->environment->errorHandle, var->lobVar->data[var->pos],
newSize);
Py_END_ALLOW_THREADS
if (Environment_CheckForError(var->lobVar->environment, status,
"ExternalLobVar_Trim()") < 0)
return NULL;
// return the result
Py_INCREF(Py_None);
return Py_None;
}
//-----------------------------------------------------------------------------
// ExternalLobVar_Reduce()
// Method provided for pickling/unpickling of LOB variables.
//-----------------------------------------------------------------------------
static PyObject *ExternalLobVar_Reduce(
udt_ExternalLobVar *self) // variable to dump
{
PyObject *result, *value;
value = ExternalLobVar_Str(self);
if (!value)
return NULL;
result = Py_BuildValue("(O(O))", Py_TYPE(value), value);
Py_DECREF(value);
return result;
}
//-----------------------------------------------------------------------------
// ExternalLobVar_GetChunkSize()
// Return the chunk size that should be used when reading/writing the LOB in
// chunks.
//-----------------------------------------------------------------------------
static PyObject *ExternalLobVar_GetChunkSize(
udt_ExternalLobVar *var, // variable to get chunk size for
PyObject *args) // arguments
{
ub4 chunkSize;
sword status;
if (ExternalLobVar_Verify(var) < 0)
return NULL;
status = OCILobGetChunkSize(var->lobVar->connection->handle,
var->lobVar->environment->errorHandle, var->lobVar->data[var->pos],
&chunkSize);
if (Environment_CheckForError(var->lobVar->environment, status,
"ExternalLobVar_GetChunkSize()") < 0)
return NULL;
return PyInt_FromLong(chunkSize);
}
//-----------------------------------------------------------------------------
// ExternalLobVar_IsOpen()
// Return a boolean indicating if the lob is open or not.
//-----------------------------------------------------------------------------
static PyObject *ExternalLobVar_IsOpen(
udt_ExternalLobVar *var, // variable to get chunk size for
PyObject *args) // arguments
{
boolean isOpen;
sword status;
if (ExternalLobVar_Verify(var) < 0)
return NULL;
Py_BEGIN_ALLOW_THREADS
status = OCILobIsOpen(var->lobVar->connection->handle,
var->lobVar->environment->errorHandle, var->lobVar->data[var->pos],
&isOpen);
Py_END_ALLOW_THREADS
if (Environment_CheckForError(var->lobVar->environment, status,
"ExternalLobVar_IsOpen()") < 0)
return NULL;
return PyBool_FromLong(isOpen);
}
//-----------------------------------------------------------------------------
// ExternalLobVar_GetFileName()
// Return the directory alias and file name for the BFILE lob.
//-----------------------------------------------------------------------------
static PyObject *ExternalLobVar_GetFileName(
udt_ExternalLobVar *var, // variable to get file name for
PyObject *args) // arguments
{
char dirAlias[120], name[1020];
ub2 dirAliasLength, nameLength;
PyObject *result, *temp;
sword status;
// determine the directory alias and name
if (ExternalLobVar_Verify(var) < 0)
return NULL;
nameLength = sizeof(name);
dirAliasLength = sizeof(dirAlias);
status = OCILobFileGetName(var->lobVar->environment->handle,
var->lobVar->environment->errorHandle, var->lobVar->data[var->pos],
(text*) dirAlias, &dirAliasLength, (text*) name, &nameLength);
if (Environment_CheckForError(var->lobVar->environment, status,
"ExternalLobVar_GetFileName()") < 0)
return NULL;
// create the two-tuple for returning
result = PyTuple_New(2);
if (!result)
return NULL;
temp = cxString_FromEncodedString(dirAlias, dirAliasLength,
var->lobVar->environment->encoding);
if (!temp) {
Py_DECREF(result);
return NULL;
}
PyTuple_SET_ITEM(result, 0, temp);
temp = cxString_FromEncodedString(name, nameLength,
var->lobVar->environment->encoding);
if (!temp) {
Py_DECREF(result);
return NULL;
}
PyTuple_SET_ITEM(result, 1, temp);
return result;
}
//-----------------------------------------------------------------------------
// ExternalLobVar_SetFileName()
// Set the directory alias and file name for the BFILE lob.
//-----------------------------------------------------------------------------
static PyObject *ExternalLobVar_SetFileName(
udt_ExternalLobVar *var, // variable to set file name for
PyObject *args) // arguments
{
int dirAliasLength, nameLength;
char *dirAlias, *name;
sword status;
// get the directory alias and name as strings
if (!PyArg_ParseTuple(args, "s#s#", &dirAlias, &dirAliasLength, &name,
&nameLength))
return NULL;
// create a string for retrieving the value
if (ExternalLobVar_Verify(var) < 0)
return NULL;
status = OCILobFileSetName(var->lobVar->environment->handle,
var->lobVar->environment->errorHandle,
&var->lobVar->data[var->pos], (text*) dirAlias,
(ub2) dirAliasLength, (text*) name, (ub2) nameLength);
if (Environment_CheckForError(var->lobVar->environment, status,
"ExternalLobVar_SetFileName()") < 0)
return NULL;
// return the result
Py_INCREF(Py_None);
return Py_None;
}
//-----------------------------------------------------------------------------
// ExternalLobVar_FileExists()
// Return a boolean indicating if the BFIILE lob exists.
//-----------------------------------------------------------------------------
static PyObject *ExternalLobVar_FileExists(
udt_ExternalLobVar *var, // variable to perform write against
PyObject *args) // arguments
{
PyObject *result;
sword status;
boolean flag;
if (ExternalLobVar_Verify(var) < 0)
return NULL;
Py_BEGIN_ALLOW_THREADS
status = OCILobFileExists(var->lobVar->connection->handle,
var->lobVar->environment->errorHandle, var->lobVar->data[var->pos],
&flag);
Py_END_ALLOW_THREADS
if (Environment_CheckForError(var->lobVar->environment, status,
"ExternalLobVar_FileExists()") < 0)
return NULL;
// return the result
if (flag)
result = Py_True;
else result = Py_False;
Py_INCREF(result);
return result;
}

View File

@ -12,147 +12,54 @@
// Defines the routines for handling interval variables.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Interval type
//-----------------------------------------------------------------------------
typedef struct {
Variable_HEAD
OCIInterval **data;
} udt_IntervalVar;
//-----------------------------------------------------------------------------
// Declaration of interval variable functions.
//-----------------------------------------------------------------------------
static int IntervalVar_Initialize(udt_IntervalVar*, udt_Cursor*);
static void IntervalVar_Finalize(udt_IntervalVar*);
static int IntervalVar_SetValue(udt_IntervalVar*, unsigned, PyObject*);
static PyObject *IntervalVar_GetValue(udt_IntervalVar*, unsigned);
static int IntervalVar_SetValue(udt_Variable*, uint32_t, dpiData*, PyObject*);
static PyObject *IntervalVar_GetValue(udt_Variable*, dpiData*);
//-----------------------------------------------------------------------------
// Python type declarations
//-----------------------------------------------------------------------------
static PyTypeObject g_IntervalVarType = {
PyVarObject_HEAD_INIT(NULL, 0)
"cx_Oracle.INTERVAL", // tp_name
sizeof(udt_IntervalVar), // tp_basicsize
0, // tp_itemsize
0, // tp_dealloc
0, // tp_print
0, // tp_getattr
0, // tp_setattr
0, // tp_compare
0, // tp_repr
0, // tp_as_number
0, // tp_as_sequence
0, // tp_as_mapping
0, // tp_hash
0, // tp_call
0, // tp_str
0, // tp_getattro
0, // tp_setattro
0, // tp_as_buffer
Py_TPFLAGS_DEFAULT, // tp_flags
0 // tp_doc
};
DECLARE_VARIABLE_TYPE(g_IntervalVarType, INTERVAL)
//-----------------------------------------------------------------------------
// variable type declarations
//-----------------------------------------------------------------------------
static udt_VariableType vt_Interval = {
(InitializeProc) IntervalVar_Initialize,
(FinalizeProc) IntervalVar_Finalize,
(PreDefineProc) NULL,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) NULL,
(IsNullProc) NULL,
(SetValueProc) IntervalVar_SetValue,
(GetValueProc) IntervalVar_GetValue,
(GetBufferSizeProc) NULL,
&g_IntervalVarType, // Python type
SQLT_INTERVAL_DS, // Oracle type
SQLCS_IMPLICIT, // charset form
sizeof(OCIInterval*), // element length (default)
0, // is character data
0, // is variable length
1, // can be copied
1 // can be in array
DPI_ORACLE_TYPE_INTERVAL_DS, // Oracle type
DPI_NATIVE_TYPE_INTERVAL_DS, // native type
0 // element length
};
//-----------------------------------------------------------------------------
// IntervalVar_Initialize()
// Initialize the variable.
//-----------------------------------------------------------------------------
static int IntervalVar_Initialize(
udt_IntervalVar *var, // variable to initialize
udt_Cursor *cursor) // cursor created by
{
sword status;
ub4 i;
// initialize the interval locators
for (i = 0; i < var->allocatedElements; i++) {
status = OCIDescriptorAlloc(var->environment->handle,
(dvoid**) &var->data[i], OCI_DTYPE_INTERVAL_DS, 0, 0);
if (Environment_CheckForError(var->environment, status,
"IntervalVar_Initialize()") < 0)
return -1;
}
return 0;
}
//-----------------------------------------------------------------------------
// IntervalVar_Finalize()
// Prepare for variable destruction.
//-----------------------------------------------------------------------------
static void IntervalVar_Finalize(
udt_IntervalVar *var) // variable to free
{
ub4 i;
for (i = 0; i < var->allocatedElements; i++) {
if (var->data[i])
OCIDescriptorFree(var->data[i], OCI_DTYPE_INTERVAL_DS);
}
}
//-----------------------------------------------------------------------------
// IntervalVar_SetValue()
// Set the value of the variable.
//-----------------------------------------------------------------------------
static int IntervalVar_SetValue(
udt_IntervalVar *var, // variable to set value for
unsigned pos, // array position to set
PyObject *value) // value to set
static int IntervalVar_SetValue(udt_Variable *var, uint32_t pos, dpiData *data,
PyObject *value)
{
sb4 hours, minutes, seconds;
dpiIntervalDS *interval;
PyDateTime_Delta *delta;
sword status;
if (!PyDelta_Check(value)) {
PyErr_SetString(PyExc_TypeError, "expecting timedelta data");
return -1;
}
delta = (PyDateTime_Delta*) value;
hours = (sb4) delta->seconds / 3600;
seconds = delta->seconds - hours * 3600;
minutes = (sb4) seconds / 60;
seconds -= minutes * 60;
status = OCIIntervalSetDaySecond(var->environment->handle,
var->environment->errorHandle, delta->days, hours, minutes,
seconds, delta->microseconds*1000, var->data[pos]);
if (Environment_CheckForError(var->environment, status,
"IntervalVar_SetValue()") < 0)
return -1;
interval = &data->value.asIntervalDS;
interval->days = delta->days;
interval->hours = (int32_t) delta->seconds / 3600;
interval->seconds = delta->seconds - interval->hours * 3600;
interval->minutes = (int32_t) interval->seconds / 60;
interval->seconds -= interval->minutes * 60;
interval->fseconds = delta->microseconds * 1000;
return 0;
}
@ -161,10 +68,14 @@ static int IntervalVar_SetValue(
// IntervalVar_GetValue()
// Returns the value stored at the given array position.
//-----------------------------------------------------------------------------
static PyObject *IntervalVar_GetValue(
udt_IntervalVar *var, // variable to determine value for
unsigned pos) // array position
static PyObject *IntervalVar_GetValue(udt_Variable *var, dpiData *data)
{
return OracleIntervalToPythonDelta(var->environment, var->data[pos]);
dpiIntervalDS *interval;
int32_t seconds;
interval = &data->value.asIntervalDS;
seconds = interval->hours * 60 * 60 + interval->minutes * 60 +
interval->seconds;
return PyDelta_FromDSU(interval->days, seconds, interval->fseconds / 1000);
}

492
src/LOB.c Normal file
View File

@ -0,0 +1,492 @@
//-----------------------------------------------------------------------------
// Copyright 2016, 2017, Oracle and/or its affiliates. All rights reserved.
//
// Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
//
// Portions Copyright 2001-2007, Computronix (Canada) Ltd., Edmonton, Alberta,
// Canada. All rights reserved.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// LOB.c
// Defines the routines for handling LOB values.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// LOB type
//-----------------------------------------------------------------------------
typedef struct {
PyObject_HEAD
udt_Variable *var;
dpiLob *handle;
} udt_LOB;
//-----------------------------------------------------------------------------
// Declaration of external LOB variable functions.
//-----------------------------------------------------------------------------
static void LOB_Free(udt_LOB*);
static PyObject *LOB_Str(udt_LOB*);
static PyObject *LOB_Size(udt_LOB*, PyObject*);
static PyObject *LOB_Open(udt_LOB*, PyObject*);
static PyObject *LOB_Close(udt_LOB*, PyObject*);
static PyObject *LOB_Read(udt_LOB*, PyObject*, PyObject*);
static PyObject *LOB_Write(udt_LOB*, PyObject*, PyObject*);
static PyObject *LOB_Trim(udt_LOB*, PyObject*, PyObject*);
static PyObject *LOB_GetChunkSize(udt_LOB*, PyObject*);
static PyObject *LOB_IsOpen(udt_LOB*, PyObject*);
static PyObject *LOB_GetFileName(udt_LOB*, PyObject*);
static PyObject *LOB_SetFileName(udt_LOB*, PyObject*);
static PyObject *LOB_FileExists(udt_LOB*, PyObject*);
static PyObject *LOB_Reduce(udt_LOB*);
//-----------------------------------------------------------------------------
// declaration of methods for Python type "ExternalLOBVar"
//-----------------------------------------------------------------------------
static PyMethodDef g_LOBMethods[] = {
{ "size", (PyCFunction) LOB_Size, METH_NOARGS },
{ "open", (PyCFunction) LOB_Open, METH_NOARGS },
{ "close", (PyCFunction) LOB_Close, METH_NOARGS },
{ "read", (PyCFunction) LOB_Read, METH_VARARGS | METH_KEYWORDS },
{ "write", (PyCFunction) LOB_Write, METH_VARARGS | METH_KEYWORDS },
{ "trim", (PyCFunction) LOB_Trim, METH_VARARGS | METH_KEYWORDS },
{ "getchunksize", (PyCFunction) LOB_GetChunkSize, METH_NOARGS },
{ "isopen", (PyCFunction) LOB_IsOpen, METH_NOARGS },
{ "getfilename", (PyCFunction) LOB_GetFileName, METH_NOARGS },
{ "setfilename", (PyCFunction) LOB_SetFileName, METH_VARARGS },
{ "fileexists", (PyCFunction) LOB_FileExists, METH_NOARGS },
{ "__reduce__", (PyCFunction) LOB_Reduce, METH_NOARGS },
{ NULL, NULL }
};
//-----------------------------------------------------------------------------
// Python type declaration
//-----------------------------------------------------------------------------
static PyTypeObject g_LOBType = {
PyVarObject_HEAD_INIT(NULL, 0)
"cx_Oracle.LOB", // tp_name
sizeof(udt_LOB), // tp_basicsize
0, // tp_itemsize
(destructor) LOB_Free, // tp_dealloc
0, // tp_print
0, // tp_getattr
0, // tp_setattr
0, // tp_compare
0, // tp_repr
0, // tp_as_number
0, // tp_as_sequence
0, // tp_as_mapping
0, // tp_hash
0, // tp_call
(reprfunc) LOB_Str, // tp_str
0, // tp_getattro
0, // tp_setattro
0, // tp_as_buffer
Py_TPFLAGS_DEFAULT, // tp_flags
0, // tp_doc
0, // tp_traverse
0, // tp_clear
0, // tp_richcompare
0, // tp_weaklistoffset
0, // tp_iter
0, // tp_iternext
g_LOBMethods, // tp_methods
0, // tp_members
0, // tp_getset
0, // tp_base
0, // tp_dict
0, // tp_descr_get
0, // tp_descr_set
0, // tp_dictoffset
0, // tp_init
0, // tp_alloc
0, // tp_new
0, // tp_free
0, // tp_is_gc
0 // tp_bases
};
//-----------------------------------------------------------------------------
// LOB_New()
// Create a new external LOB variable.
//-----------------------------------------------------------------------------
PyObject *LOB_New(udt_Variable *var, dpiLob *handle)
{
udt_LOB *self;
self = (udt_LOB*) g_LOBType.tp_alloc(&g_LOBType, 0);
if (!self)
return NULL;
if (dpiLob_addRef(handle) < 0) {
Py_DECREF(self);
return NULL;
}
self->handle = handle;
Py_INCREF(var);
self->var = var;
return (PyObject*) self;
}
//-----------------------------------------------------------------------------
// LOB_Free()
// Free an external LOB variable.
//-----------------------------------------------------------------------------
static void LOB_Free(udt_LOB *self)
{
if (self->handle) {
dpiLob_release(self->handle);
self->handle = NULL;
}
Py_CLEAR(self->var);
Py_TYPE(self)->tp_free((PyObject*) self);
}
//-----------------------------------------------------------------------------
// LOB_InternalRead()
// Return a portion (or all) of the data in the LOB.
//-----------------------------------------------------------------------------
static PyObject *LOB_InternalRead(udt_LOB *self, uint64_t offset,
uint64_t amount)
{
uint64_t bufferSize;
PyObject *result;
char *buffer;
int status;
// modify the arguments
if (amount == (uint64_t)(-1)) {
if (dpiLob_getSize(self->handle, &amount) < 0)
return Error_RaiseAndReturnNull();
if (amount >= offset)
amount = amount - offset + 1;
else amount = 1;
}
// create a buffer of the correct size
if (dpiLob_getBufferSize(self->handle, amount, &bufferSize) < 0)
return Error_RaiseAndReturnNull();
buffer = (char*) PyMem_Malloc(bufferSize);
if (!buffer)
return PyErr_NoMemory();
// read the LOB
Py_BEGIN_ALLOW_THREADS
status = dpiLob_readBytes(self->handle, offset, amount, buffer,
&bufferSize);
Py_END_ALLOW_THREADS
if (status < 0) {
PyMem_Free(buffer);
return Error_RaiseAndReturnNull();
}
// return the result
if (self->var->type == &vt_CLOB)
result = PyUnicode_Decode(buffer, bufferSize,
self->var->connection->encodingInfo.encoding, NULL);
else if (self->var->type == &vt_NCLOB)
result = cxString_FromEncodedString(buffer, bufferSize,
self->var->connection->encodingInfo.nencoding);
else result = PyBytes_FromStringAndSize(buffer, bufferSize);
PyMem_Free(buffer);
return result;
}
//-----------------------------------------------------------------------------
// LOB_InternalWrite()
// Write the data in the Python object to the LOB.
//-----------------------------------------------------------------------------
static int LOB_InternalWrite(udt_LOB *self, PyObject *dataObj, uint64_t offset)
{
const char *encoding;
udt_Buffer buffer;
int status;
if (self->var->type == &vt_NCLOB)
encoding = self->var->connection->encodingInfo.nencoding;
else encoding = self->var->connection->encodingInfo.encoding;
if (cxBuffer_FromObject(&buffer, dataObj, encoding) < 0)
return -1;
Py_BEGIN_ALLOW_THREADS
status = dpiLob_writeBytes(self->handle, offset,
(char*) buffer.ptr, buffer.size);
Py_END_ALLOW_THREADS
cxBuffer_Clear(&buffer);
if (status < 0)
return Error_RaiseAndReturnInt();
return 0;
}
//-----------------------------------------------------------------------------
// LOB_Size()
// Return the size of the data in the LOB variable.
//-----------------------------------------------------------------------------
static PyObject *LOB_Size(udt_LOB *self, PyObject *args)
{
uint64_t length;
if (dpiLob_getSize(self->handle, &length) < 0)
return Error_RaiseAndReturnNull();
return PyLong_FromUnsignedLongLong(length);
}
//-----------------------------------------------------------------------------
// LOB_Open()
// Open the LOB to speed further accesses.
//-----------------------------------------------------------------------------
static PyObject *LOB_Open(udt_LOB *self, PyObject *args)
{
int status;
Py_BEGIN_ALLOW_THREADS
status = dpiLob_openResource(self->handle);
Py_END_ALLOW_THREADS
if (status < 0)
return Error_RaiseAndReturnNull();
Py_RETURN_NONE;
}
//-----------------------------------------------------------------------------
// LOB_Close()
// Close the LOB.
//-----------------------------------------------------------------------------
static PyObject *LOB_Close(udt_LOB *self, PyObject *args)
{
int status;
Py_BEGIN_ALLOW_THREADS
status = dpiLob_closeResource(self->handle);
Py_END_ALLOW_THREADS
if (status < 0)
return Error_RaiseAndReturnNull();
Py_RETURN_NONE;
}
//-----------------------------------------------------------------------------
// LOB_Read()
// Return a portion (or all) of the data in the external LOB variable.
//-----------------------------------------------------------------------------
static PyObject *LOB_Read(udt_LOB *self, PyObject *args, PyObject *keywordArgs)
{
static char *keywordList[] = { "offset", "amount", NULL };
unsigned PY_LONG_LONG offset, amount;
// offset and amount are expected, both optional
offset = 1;
amount = (unsigned PY_LONG_LONG)(-1);
if (!PyArg_ParseTupleAndKeywords(args, keywordArgs, "|KK", keywordList,
&offset, &amount))
return NULL;
return LOB_InternalRead(self, (uint64_t) offset, (uint64_t) amount);
}
//-----------------------------------------------------------------------------
// LOB_Str()
// Return all of the data in the external LOB variable.
//-----------------------------------------------------------------------------
static PyObject *LOB_Str(udt_LOB *self)
{
return LOB_InternalRead(self, 1, (uint64_t)(-1));
}
//-----------------------------------------------------------------------------
// LOB_Write()
// Write a value to the LOB variable; return the number of bytes written.
//-----------------------------------------------------------------------------
static PyObject *LOB_Write(udt_LOB *self, PyObject *args,
PyObject *keywordArgs)
{
static char *keywordList[] = { "data", "offset", NULL };
unsigned PY_LONG_LONG offset;
PyObject *dataObj;
offset = 1;
if (!PyArg_ParseTupleAndKeywords(args, keywordArgs, "O|K", keywordList,
&dataObj, &offset))
return NULL;
if (LOB_InternalWrite(self, dataObj, (uint64_t) offset) < 0)
return NULL;
Py_RETURN_NONE;
}
//-----------------------------------------------------------------------------
// LOB_Trim()
// Trim the LOB variable to the specified length.
//-----------------------------------------------------------------------------
static PyObject *LOB_Trim(udt_LOB *self, PyObject *args, PyObject *keywordArgs)
{
static char *keywordList[] = { "newSize", NULL };
unsigned PY_LONG_LONG newSize;
int status;
newSize = 0;
if (!PyArg_ParseTupleAndKeywords(args, keywordArgs, "|K", keywordList,
&newSize))
return NULL;
Py_BEGIN_ALLOW_THREADS
status = dpiLob_trim(self->handle, (uint64_t) newSize);
Py_END_ALLOW_THREADS
if (status < 0)
return Error_RaiseAndReturnNull();
Py_RETURN_NONE;
}
//-----------------------------------------------------------------------------
// LOB_Reduce()
// Method provided for pickling/unpickling of LOB variables.
//-----------------------------------------------------------------------------
static PyObject *LOB_Reduce(udt_LOB *self)
{
PyObject *result, *value;
value = LOB_Str(self);
if (!value)
return NULL;
result = Py_BuildValue("(O(O))", Py_TYPE(value), value);
Py_DECREF(value);
return result;
}
//-----------------------------------------------------------------------------
// LOB_GetChunkSize()
// Return the chunk size that should be used when reading/writing the LOB in
// chunks.
//-----------------------------------------------------------------------------
static PyObject *LOB_GetChunkSize(udt_LOB *self, PyObject *args)
{
uint32_t size;
if (dpiLob_getChunkSize(self->handle, &size) < 0)
return Error_RaiseAndReturnNull();
return PyInt_FromLong(size);
}
//-----------------------------------------------------------------------------
// LOB_IsOpen()
// Return a boolean indicating if the lob is open or not.
//-----------------------------------------------------------------------------
static PyObject *LOB_IsOpen(udt_LOB *self, PyObject *args)
{
int isOpen, status;
Py_BEGIN_ALLOW_THREADS
status = dpiLob_getIsResourceOpen(self->handle, &isOpen);
Py_END_ALLOW_THREADS
if (status < 0)
return Error_RaiseAndReturnNull();
return PyBool_FromLong(isOpen);
}
//-----------------------------------------------------------------------------
// LOB_GetFileName()
// Return the directory alias and file name for the BFILE lob.
//-----------------------------------------------------------------------------
static PyObject *LOB_GetFileName(udt_LOB *self, PyObject *args)
{
uint32_t directoryAliasLength, fileNameLength;
const char *directoryAlias, *fileName;
PyObject *result, *temp;
int status;
// get the information from the LOB
Py_BEGIN_ALLOW_THREADS
status = dpiLob_getDirectoryAndFileName(self->handle, &directoryAlias,
&directoryAliasLength, &fileName, &fileNameLength);
Py_END_ALLOW_THREADS
if (status < 0)
return Error_RaiseAndReturnNull();
// create the two-tuple for returning
result = PyTuple_New(2);
if (!result)
return NULL;
temp = cxString_FromEncodedString(directoryAlias, directoryAliasLength,
self->var->connection->encodingInfo.encoding);
if (!temp) {
Py_DECREF(result);
return NULL;
}
PyTuple_SET_ITEM(result, 0, temp);
temp = cxString_FromEncodedString(fileName, fileNameLength,
self->var->connection->encodingInfo.encoding);
if (!temp) {
Py_DECREF(result);
return NULL;
}
PyTuple_SET_ITEM(result, 1, temp);
return result;
}
//-----------------------------------------------------------------------------
// LOB_SetFileName()
// Set the directory alias and file name for the BFILE lob.
//-----------------------------------------------------------------------------
static PyObject *LOB_SetFileName(udt_LOB *self, PyObject *args)
{
udt_Buffer directoryAliasBuffer, fileNameBuffer;
PyObject *directoryAliasObj, *fileNameObj;
int status;
// get the directory alias and file name
if (!PyArg_ParseTuple(args, "OO", &directoryAliasObj, &fileNameObj))
return NULL;
if (cxBuffer_FromObject(&directoryAliasBuffer, directoryAliasObj,
self->var->connection->encodingInfo.encoding) < 0)
return NULL;
if (cxBuffer_FromObject(&fileNameBuffer, fileNameObj,
self->var->connection->encodingInfo.encoding) < 0) {
cxBuffer_Clear(&directoryAliasBuffer);
return NULL;
}
// perform the work
Py_BEGIN_ALLOW_THREADS
status = dpiLob_setDirectoryAndFileName(self->handle,
(char*) directoryAliasBuffer.ptr, directoryAliasBuffer.size,
(char*) fileNameBuffer.ptr, fileNameBuffer.size);
Py_END_ALLOW_THREADS
cxBuffer_Clear(&directoryAliasBuffer);
cxBuffer_Clear(&fileNameBuffer);
if (status < 0)
return Error_RaiseAndReturnNull();
Py_RETURN_NONE;
}
//-----------------------------------------------------------------------------
// LOB_FileExists()
// Return a boolean indicating if the BFIILE lob exists.
//-----------------------------------------------------------------------------
static PyObject *LOB_FileExists(udt_LOB *self, PyObject *args)
{
int status, exists;
Py_BEGIN_ALLOW_THREADS
status = dpiLob_getFileExists(self->handle, &exists);
Py_END_ALLOW_THREADS
if (status < 0)
return Error_RaiseAndReturnNull();
if (exists)
Py_RETURN_TRUE;
Py_RETURN_FALSE;
}

View File

@ -12,364 +12,89 @@
// Defines the routines for handling LOB variables.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// LOB type
//-----------------------------------------------------------------------------
typedef struct {
Variable_HEAD
OCILobLocator **data;
udt_Connection *connection;
int isFile;
} udt_LobVar;
//-----------------------------------------------------------------------------
// Declaration of LOB variable functions.
//-----------------------------------------------------------------------------
static int LobVar_Initialize(udt_LobVar*, udt_Cursor*);
static int LobVar_PreFetch(udt_LobVar*);
static void LobVar_Finalize(udt_LobVar*);
static PyObject *LobVar_GetValue(udt_LobVar*, unsigned);
static int LobVar_SetValue(udt_LobVar*, unsigned, PyObject*);
static int LobVar_Write(udt_LobVar*, unsigned, PyObject*, oraub8);
static int LobVar_SetValue(udt_Variable*, uint32_t, dpiData*, PyObject*);
static PyObject *LobVar_GetValue(udt_Variable*, dpiData*);
//-----------------------------------------------------------------------------
// Python type declarations
//-----------------------------------------------------------------------------
static PyTypeObject g_CLOBVarType = {
PyVarObject_HEAD_INIT(NULL, 0)
"cx_Oracle.CLOB", // tp_name
sizeof(udt_LobVar), // tp_basicsize
0, // tp_itemsize
0, // tp_dealloc
0, // tp_print
0, // tp_getattr
0, // tp_setattr
0, // tp_compare
0, // tp_repr
0, // tp_as_number
0, // tp_as_sequence
0, // tp_as_mapping
0, // tp_hash
0, // tp_call
0, // tp_str
0, // tp_getattro
0, // tp_setattro
0, // tp_as_buffer
Py_TPFLAGS_DEFAULT, // tp_flags
0 // tp_doc
};
static PyTypeObject g_NCLOBVarType = {
PyVarObject_HEAD_INIT(NULL, 0)
"cx_Oracle.NCLOB", // tp_name
sizeof(udt_LobVar), // tp_basicsize
0, // tp_itemsize
0, // tp_dealloc
0, // tp_print
0, // tp_getattr
0, // tp_setattr
0, // tp_compare
0, // tp_repr
0, // tp_as_number
0, // tp_as_sequence
0, // tp_as_mapping
0, // tp_hash
0, // tp_call
0, // tp_str
0, // tp_getattro
0, // tp_setattro
0, // tp_as_buffer
Py_TPFLAGS_DEFAULT, // tp_flags
0 // tp_doc
};
static PyTypeObject g_BLOBVarType = {
PyVarObject_HEAD_INIT(NULL, 0)
"cx_Oracle.BLOB", // tp_name
sizeof(udt_LobVar), // tp_basicsize
0, // tp_itemsize
0, // tp_dealloc
0, // tp_print
0, // tp_getattr
0, // tp_setattr
0, // tp_compare
0, // tp_repr
0, // tp_as_number
0, // tp_as_sequence
0, // tp_as_mapping
0, // tp_hash
0, // tp_call
0, // tp_str
0, // tp_getattro
0, // tp_setattro
0, // tp_as_buffer
Py_TPFLAGS_DEFAULT, // tp_flags
0 // tp_doc
};
static PyTypeObject g_BFILEVarType = {
PyVarObject_HEAD_INIT(NULL, 0)
"cx_Oracle.BFILE", // tp_name
sizeof(udt_LobVar), // tp_basicsize
0, // tp_itemsize
0, // tp_dealloc
0, // tp_print
0, // tp_getattr
0, // tp_setattr
0, // tp_compare
0, // tp_repr
0, // tp_as_number
0, // tp_as_sequence
0, // tp_as_mapping
0, // tp_hash
0, // tp_call
0, // tp_str
0, // tp_getattro
0, // tp_setattro
0, // tp_as_buffer
Py_TPFLAGS_DEFAULT, // tp_flags
0 // tp_doc
};
DECLARE_VARIABLE_TYPE(g_CLOBVarType, CLOB)
DECLARE_VARIABLE_TYPE(g_NCLOBVarType, NCLOB)
DECLARE_VARIABLE_TYPE(g_BLOBVarType, BLOB)
DECLARE_VARIABLE_TYPE(g_BFILEVarType, BFILE)
//-----------------------------------------------------------------------------
// variable type declarations
//-----------------------------------------------------------------------------
static udt_VariableType vt_CLOB = {
(InitializeProc) LobVar_Initialize,
(FinalizeProc) LobVar_Finalize,
(PreDefineProc) NULL,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) LobVar_PreFetch,
(IsNullProc) NULL,
(SetValueProc) LobVar_SetValue,
(GetValueProc) LobVar_GetValue,
(GetBufferSizeProc) NULL,
&g_CLOBVarType, // Python type
SQLT_CLOB, // Oracle type
SQLCS_IMPLICIT, // charset form
sizeof(OCILobLocator*), // element length
1, // is character data
0, // is variable length
0, // can be copied
0 // can be in array
DPI_ORACLE_TYPE_CLOB, // Oracle type
DPI_NATIVE_TYPE_LOB, // native type
0 // element length
};
static udt_VariableType vt_NCLOB = {
(InitializeProc) LobVar_Initialize,
(FinalizeProc) LobVar_Finalize,
(PreDefineProc) NULL,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) LobVar_PreFetch,
(IsNullProc) NULL,
(SetValueProc) LobVar_SetValue,
(GetValueProc) LobVar_GetValue,
(GetBufferSizeProc) NULL,
&g_NCLOBVarType, // Python type
SQLT_CLOB, // Oracle type
SQLCS_NCHAR, // charset form
sizeof(OCILobLocator*), // element length
1, // is character data
0, // is variable length
0, // can be copied
0 // can be in array
DPI_ORACLE_TYPE_NCLOB, // Oracle type
DPI_NATIVE_TYPE_LOB, // native type
0 // element length
};
static udt_VariableType vt_BLOB = {
(InitializeProc) LobVar_Initialize,
(FinalizeProc) LobVar_Finalize,
(PreDefineProc) NULL,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) LobVar_PreFetch,
(IsNullProc) NULL,
(SetValueProc) LobVar_SetValue,
(GetValueProc) LobVar_GetValue,
(GetBufferSizeProc) NULL,
&g_BLOBVarType, // Python type
SQLT_BLOB, // Oracle type
SQLCS_IMPLICIT, // charset form
sizeof(OCILobLocator*), // element length
0, // is character data
0, // is variable length
0, // can be copied
0 // can be in array
DPI_ORACLE_TYPE_BLOB, // Oracle type
DPI_NATIVE_TYPE_LOB, // native type
0 // element length
};
static udt_VariableType vt_BFILE = {
(InitializeProc) LobVar_Initialize,
(FinalizeProc) LobVar_Finalize,
(PreDefineProc) NULL,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) LobVar_PreFetch,
(IsNullProc) NULL,
(SetValueProc) LobVar_SetValue,
(GetValueProc) LobVar_GetValue,
(GetBufferSizeProc) NULL,
&g_BFILEVarType, // Python type
SQLT_BFILE, // Oracle type
SQLCS_IMPLICIT, // charset form
sizeof(OCILobLocator*), // element length
0, // is character data
0, // is variable length
0, // can be copied
0 // can be in array
DPI_ORACLE_TYPE_BFILE, // Oracle type
DPI_NATIVE_TYPE_LOB, // native type
0 // element length
};
#include "ExternalLobVar.c"
#include "LOB.c"
//-----------------------------------------------------------------------------
// LobVar_Initialize()
// Initialize the variable.
// LobVar_SetValue()
// Set the value of the variable.
//-----------------------------------------------------------------------------
static int LobVar_Initialize(
udt_LobVar *var, // variable to initialize
udt_Cursor *cursor) // cursor created by
static int LobVar_SetValue(udt_Variable *var, uint32_t pos, dpiData *data,
PyObject *value)
{
sword status;
ub4 i;
// initialize members
Py_INCREF(cursor->connection);
var->connection = cursor->connection;
var->isFile = (var->type == &vt_BFILE);
// initialize the LOB locators
for (i = 0; i < var->allocatedElements; i++) {
status = OCIDescriptorAlloc(var->environment->handle,
(dvoid**) &var->data[i], OCI_DTYPE_LOB, 0, 0);
if (Environment_CheckForError(var->environment, status,
"LobVar_Initialize()") < 0)
return -1;
}
return 0;
}
//-----------------------------------------------------------------------------
// LobVar_PreFetch()
// Free temporary LOBs prior to fetch.
//-----------------------------------------------------------------------------
static int LobVar_PreFetch(
udt_LobVar *var) // variable to free
{
boolean isTemporary;
sword status;
ub4 i;
for (i = 0; i < var->allocatedElements; i++) {
if (var->data[i]) {
status = OCILobIsTemporary(var->environment->handle,
var->environment->errorHandle, var->data[i], &isTemporary);
if (Environment_CheckForError(var->environment, status,
"LobVar_PreFetch(): is temporary LOB?") < 0)
return -1;
if (isTemporary) {
Py_BEGIN_ALLOW_THREADS
status = OCILobFreeTemporary(var->connection->handle,
var->environment->errorHandle, var->data[i]);
Py_END_ALLOW_THREADS
if (Environment_CheckForError(var->environment, status,
"LobVar_PreFetch(): free temporary LOB") < 0)
return -1;
}
}
}
return 0;
}
//-----------------------------------------------------------------------------
// LobVar_Finalize()
// Prepare for variable destruction.
//-----------------------------------------------------------------------------
static void LobVar_Finalize(
udt_LobVar *var) // variable to free
{
boolean isTemporary;
ub4 i;
for (i = 0; i < var->allocatedElements; i++) {
if (var->data[i]) {
OCILobIsTemporary(var->environment->handle,
var->environment->errorHandle, var->data[i], &isTemporary);
if (isTemporary) {
Py_BEGIN_ALLOW_THREADS
OCILobFreeTemporary(var->connection->handle,
var->environment->errorHandle, var->data[i]);
Py_END_ALLOW_THREADS
}
OCIDescriptorFree(var->data[i], OCI_DTYPE_LOB);
}
}
Py_DECREF(var->connection);
}
//-----------------------------------------------------------------------------
// LobVar_Write()
// Write data to the LOB variable.
//-----------------------------------------------------------------------------
static int LobVar_Write(
udt_LobVar *var, // variable to perform write against
unsigned position, // position to perform write against
PyObject *dataObj, // data object to write into LOB
oraub8 offset) // offset into variable
{
oraub8 lengthInBytes, lengthInChars = 0;
const char *encoding;
udt_Buffer buffer;
ub2 charsetId;
sword status;
int status;
// verify the data type
if (var->type == &vt_BFILE) {
PyErr_SetString(PyExc_TypeError, "BFILEs are read only");
if (var->type == &vt_NCLOB)
encoding = var->connection->encodingInfo.nencoding;
else encoding = var->connection->encodingInfo.encoding;
if (cxBuffer_FromObject(&buffer, value, encoding) < 0)
return -1;
}
// determine the buffer to write
if (var->type->charsetForm == SQLCS_NCHAR) {
charsetId = var->environment->ncharsetId;
encoding = var->environment->nencoding;
} else {
charsetId = var->environment->charsetId;
encoding = var->environment->encoding;
}
if (cxBuffer_FromObject(&buffer, dataObj, encoding) < 0)
return -1;
lengthInBytes = buffer.size;
// nothing to do if no data to write
if (lengthInBytes == 0) {
cxBuffer_Clear(&buffer);
return 0;
}
// write the data with the correct character set
Py_BEGIN_ALLOW_THREADS
status = OCILobWrite2(var->connection->handle,
var->environment->errorHandle, var->data[position], &lengthInBytes,
&lengthInChars, offset, (void*) buffer.ptr, buffer.size,
OCI_ONE_PIECE, NULL, NULL, charsetId, var->type->charsetForm);
status = dpiLob_setFromBytes(data->value.asLOB, buffer.ptr, buffer.size);
Py_END_ALLOW_THREADS
cxBuffer_Clear(&buffer);
if (Environment_CheckForError(var->environment, status,
"LobVar_Write()") < 0)
return -1;
if (status < 0)
return Error_RaiseAndReturnInt();
return 0;
}
@ -379,58 +104,8 @@ static int LobVar_Write(
// LobVar_GetValue()
// Returns the value stored at the given array position.
//-----------------------------------------------------------------------------
static PyObject *LobVar_GetValue(
udt_LobVar *var, // variable to determine value for
unsigned pos) // array position
static PyObject *LobVar_GetValue(udt_Variable *var, dpiData *data)
{
return ExternalLobVar_New(var, pos);
}
//-----------------------------------------------------------------------------
// LobVar_SetValue()
// Sets the value stored at the given array position.
//-----------------------------------------------------------------------------
static int LobVar_SetValue(
udt_LobVar *var, // variable to determine value for
unsigned position, // array position
PyObject *value) // value to set
{
boolean isTemporary;
sword status;
ub1 lobType;
// make sure have temporary LOBs set up
status = OCILobIsTemporary(var->environment->handle,
var->environment->errorHandle, var->data[position], &isTemporary);
if (Environment_CheckForError(var->environment, status,
"LobVar_SetValue(): is temporary?") < 0)
return -1;
if (!isTemporary) {
if (var->type->oracleType == SQLT_BLOB)
lobType = OCI_TEMP_BLOB;
else lobType = OCI_TEMP_CLOB;
Py_BEGIN_ALLOW_THREADS
status = OCILobCreateTemporary(var->connection->handle,
var->environment->errorHandle, var->data[position],
OCI_DEFAULT, var->type->charsetForm, lobType, FALSE,
OCI_DURATION_SESSION);
Py_END_ALLOW_THREADS
if (Environment_CheckForError(var->environment, status,
"LobVar_SetValue(): create temporary") < 0)
return -1;
}
// trim the current value
Py_BEGIN_ALLOW_THREADS
status = OCILobTrim(var->connection->handle,
var->environment->errorHandle, var->data[position], 0);
Py_END_ALLOW_THREADS
if (Environment_CheckForError(var->environment, status,
"LobVar_SetValue(): trim") < 0)
return -1;
// set the current value
return LobVar_Write(var, position, value, 1);
return LOB_New(var, data->value.asLOB);
}

View File

@ -12,235 +12,54 @@
// Defines the routines specific to the long type.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// long type
//-----------------------------------------------------------------------------
typedef struct {
Variable_HEAD
char *data;
} udt_LongVar;
//-----------------------------------------------------------------------------
// declaration of long variable functions.
//-----------------------------------------------------------------------------
static int LongVar_SetValue(udt_LongVar*, unsigned, PyObject*);
static PyObject *LongVar_GetValue(udt_LongVar*, unsigned);
static ub4 LongVar_GetBufferSize(udt_LongVar*);
static PyObject *LongVar_GetValue(udt_Variable*, dpiData*);
//-----------------------------------------------------------------------------
// Python type declarations
//-----------------------------------------------------------------------------
static PyTypeObject g_LongStringVarType = {
PyVarObject_HEAD_INIT(NULL, 0)
"cx_Oracle.LONG_STRING", // tp_name
sizeof(udt_LongVar), // tp_basicsize
0, // tp_itemsize
0, // tp_dealloc
0, // tp_print
0, // tp_getattr
0, // tp_setattr
0, // tp_compare
0, // tp_repr
0, // tp_as_number
0, // tp_as_sequence
0, // tp_as_mapping
0, // tp_hash
0, // tp_call
0, // tp_str
0, // tp_getattro
0, // tp_setattro
0, // tp_as_buffer
Py_TPFLAGS_DEFAULT, // tp_flags
0 // tp_doc
};
static PyTypeObject g_LongNCharVarType = {
PyVarObject_HEAD_INIT(NULL, 0)
"cx_Oracle.LONG_NCHAR", // tp_name
sizeof(udt_LongVar), // tp_basicsize
0, // tp_itemsize
0, // tp_dealloc
0, // tp_print
0, // tp_getattr
0, // tp_setattr
0, // tp_compare
0, // tp_repr
0, // tp_as_number
0, // tp_as_sequence
0, // tp_as_mapping
0, // tp_hash
0, // tp_call
0, // tp_str
0, // tp_getattro
0, // tp_setattro
0, // tp_as_buffer
Py_TPFLAGS_DEFAULT, // tp_flags
0 // tp_doc
};
static PyTypeObject g_LongBinaryVarType = {
PyVarObject_HEAD_INIT(NULL, 0)
"cx_Oracle.LONG_BINARY", // tp_name
sizeof(udt_LongVar), // tp_basicsize
0, // tp_itemsize
0, // tp_dealloc
0, // tp_print
0, // tp_getattr
0, // tp_setattr
0, // tp_compare
0, // tp_repr
0, // tp_as_number
0, // tp_as_sequence
0, // tp_as_mapping
0, // tp_hash
0, // tp_call
0, // tp_str
0, // tp_getattro
0, // tp_setattro
0, // tp_as_buffer
Py_TPFLAGS_DEFAULT, // tp_flags
0 // tp_doc
};
DECLARE_VARIABLE_TYPE(g_LongStringVarType, LONG_STRING)
DECLARE_VARIABLE_TYPE(g_LongBinaryVarType, LONG_BINARY)
//-----------------------------------------------------------------------------
// variable type declarations
//-----------------------------------------------------------------------------
static udt_VariableType vt_LongString = {
(InitializeProc) NULL,
(FinalizeProc) NULL,
(PreDefineProc) NULL,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) NULL,
(IsNullProc) NULL,
(SetValueProc) LongVar_SetValue,
(SetValueProc) Variable_SetValueBytes,
(GetValueProc) LongVar_GetValue,
(GetBufferSizeProc) LongVar_GetBufferSize,
&g_LongStringVarType, // Python type
SQLT_LVC, // Oracle type
SQLCS_IMPLICIT, // charset form
128 * 1024, // element length (default)
1, // is character data
1, // is variable length
1, // can be copied
0 // can be in array
};
static udt_VariableType vt_LongNationalCharString = {
(InitializeProc) NULL,
(FinalizeProc) NULL,
(PreDefineProc) NULL,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) NULL,
(IsNullProc) NULL,
(SetValueProc) LongVar_SetValue,
(GetValueProc) LongVar_GetValue,
(GetBufferSizeProc) LongVar_GetBufferSize,
&g_LongNCharVarType, // Python type
SQLT_LVC, // Oracle type
SQLCS_NCHAR, // charset form
128 * 1024, // element length (default)
1, // is character data
1, // is variable length
1, // can be copied
0 // can be in array
DPI_ORACLE_TYPE_LONG_VARCHAR, // Oracle type
DPI_NATIVE_TYPE_BYTES, // native type
128 * 1024 // element length (default)
};
static udt_VariableType vt_LongBinary = {
(InitializeProc) NULL,
(FinalizeProc) NULL,
(PreDefineProc) NULL,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) NULL,
(IsNullProc) NULL,
(SetValueProc) LongVar_SetValue,
(SetValueProc) Variable_SetValueBytes,
(GetValueProc) LongVar_GetValue,
(GetBufferSizeProc) LongVar_GetBufferSize,
&g_LongBinaryVarType, // Python type
SQLT_LVB, // Oracle type
SQLCS_IMPLICIT, // charset form
128 * 1024, // element length (default)
0, // is character data
1, // is variable length
1, // can be copied
0 // can be in array
DPI_ORACLE_TYPE_LONG_RAW, // Oracle type
DPI_NATIVE_TYPE_BYTES, // native type
128 * 1024 // element length (default)
};
//-----------------------------------------------------------------------------
// LongVar_SetValue()
// Set the value of the variable.
//-----------------------------------------------------------------------------
static int LongVar_SetValue(
udt_LongVar *var, // variable to set value for
unsigned pos, // array position to set
PyObject *value) // value to set
{
udt_Buffer buffer;
char *ptr;
// get the buffer data and size for binding
if (cxBuffer_FromObject(&buffer, value, var->environment->encoding) < 0)
return -1;
// verify there is enough space to store the value
if (buffer.numCharacters > var->size) {
if (Variable_Resize((udt_Variable*) var,
(unsigned) buffer.numCharacters) < 0) {
cxBuffer_Clear(&buffer);
return -1;
}
}
// copy the string to the Oracle buffer
ptr = var->data + var->bufferSize * pos;
*((ub4 *) ptr) = (ub4) buffer.size;
if (buffer.size)
memcpy(ptr + sizeof(ub4), buffer.ptr, buffer.size);
cxBuffer_Clear(&buffer);
return 0;
}
//-----------------------------------------------------------------------------
// LongVar_GetValue()
// Returns the value stored at the given array position.
//-----------------------------------------------------------------------------
static PyObject *LongVar_GetValue(
udt_LongVar *var, // variable to determine value for
unsigned pos) // array position
static PyObject *LongVar_GetValue(udt_Variable *var, dpiData *data)
{
char *ptr;
ub4 size;
dpiBytes *bytes;
ptr = var->data + var->bufferSize * pos;
size = *((ub4 *) ptr);
ptr += sizeof(ub4);
bytes = &data->value.asBytes;
if (var->type == &vt_LongBinary)
return PyBytes_FromStringAndSize(ptr, size);
return cxString_FromEncodedString(ptr, size, var->environment->encoding);
}
//-----------------------------------------------------------------------------
// LongVar_GetBufferSize()
// Returns the size of the buffer to use for data of the given size.
//-----------------------------------------------------------------------------
static ub4 LongVar_GetBufferSize(
udt_LongVar *self) // variable to get buffer size
{
if (!self->type->isCharacterData)
return self->size + sizeof(ub4);
return sizeof(ub4) + self->size * self->environment->maxBytesPerCharacter;
return PyBytes_FromStringAndSize(bytes->ptr, bytes->length);
return cxString_FromEncodedString(bytes->ptr, bytes->length,
bytes->encoding);
}

412
src/MsgProps.c Normal file
View File

@ -0,0 +1,412 @@
//-----------------------------------------------------------------------------
// Copyright 2016, 2017, Oracle and/or its affiliates. All rights reserved.
//
// Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
//
// Portions Copyright 2001-2007, Computronix (Canada) Ltd., Edmonton, Alberta,
// Canada. All rights reserved.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// MsgProps.c
// Implements the message properties object used in Advanced Queuing.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// structures used for handling AQ options and message properties
//-----------------------------------------------------------------------------
typedef struct {
PyObject_HEAD
dpiMsgProps *handle;
const char *encoding;
} udt_MsgProps;
//-----------------------------------------------------------------------------
// Declaration of methods used for message properties
//-----------------------------------------------------------------------------
static udt_MsgProps *MsgProps_New(udt_Connection*);
static void MsgProps_Free(udt_MsgProps*);
static PyObject *MsgProps_GetNumAttempts(udt_MsgProps*, void*);
static PyObject *MsgProps_GetCorrelation(udt_MsgProps*, void*);
static PyObject *MsgProps_GetDelay(udt_MsgProps*, void*);
static PyObject *MsgProps_GetDeliveryMode(udt_MsgProps*, void*);
static PyObject *MsgProps_GetEnqTime(udt_MsgProps*, void*);
static PyObject *MsgProps_GetExceptionQ(udt_MsgProps*, void*);
static PyObject *MsgProps_GetExpiration(udt_MsgProps*, void*);
static PyObject *MsgProps_GetOriginalMsgId(udt_MsgProps*, void*);
static PyObject *MsgProps_GetPriority(udt_MsgProps*, void*);
static PyObject *MsgProps_GetState(udt_MsgProps*, void*);
static int MsgProps_SetCorrelation(udt_MsgProps*, PyObject*, void*);
static int MsgProps_SetDelay(udt_MsgProps*, PyObject*, void*);
static int MsgProps_SetExceptionQ(udt_MsgProps*, PyObject*, void*);
static int MsgProps_SetExpiration(udt_MsgProps*, PyObject*, void*);
static int MsgProps_SetOriginalMsgId(udt_MsgProps*, PyObject*, void*);
static int MsgProps_SetPriority(udt_MsgProps*, PyObject*, void*);
//-----------------------------------------------------------------------------
// declaration of calculated members for Python type "MessageProperties"
//-----------------------------------------------------------------------------
static PyGetSetDef g_MessagePropertiesCalcMembers[] = {
{ "attempts", (getter) MsgProps_GetNumAttempts, 0, 0, 0 },
{ "correlation", (getter) MsgProps_GetCorrelation,
(setter) MsgProps_SetCorrelation, 0, 0 },
{ "delay", (getter) MsgProps_GetDelay, (setter) MsgProps_SetDelay, 0, 0 },
{ "deliverymode", (getter) MsgProps_GetDeliveryMode, 0, 0, 0 },
{ "enqtime", (getter) MsgProps_GetEnqTime, 0, 0, 0 },
{ "exceptionq", (getter) MsgProps_GetExceptionQ,
(setter) MsgProps_SetExceptionQ, 0, 0 },
{ "expiration", (getter) MsgProps_GetExpiration,
(setter) MsgProps_SetExpiration, 0, 0 },
{ "msgid", (getter) MsgProps_GetOriginalMsgId,
(setter) MsgProps_SetOriginalMsgId, 0, 0 },
{ "priority", (getter) MsgProps_GetPriority,
(setter) MsgProps_SetPriority, 0, 0 },
{ "state", (getter) MsgProps_GetState, 0, 0, 0 },
{ NULL }
};
//-----------------------------------------------------------------------------
// Python type declarations
//-----------------------------------------------------------------------------
static PyTypeObject g_MessagePropertiesType = {
PyVarObject_HEAD_INIT(NULL, 0)
"cx_Oracle.MessageProperties", // tp_name
sizeof(udt_MsgProps), // tp_basicsize
0, // tp_itemsize
(destructor) MsgProps_Free, // tp_dealloc
0, // tp_print
0, // tp_getattr
0, // tp_setattr
0, // tp_compare
0, // tp_repr
0, // tp_as_number
0, // tp_as_sequence
0, // tp_as_mapping
0, // tp_hash
0, // tp_call
0, // tp_str
0, // tp_getattro
0, // tp_setattro
0, // tp_as_buffer
Py_TPFLAGS_DEFAULT, // tp_flags
0, // tp_doc
0, // tp_traverse
0, // tp_clear
0, // tp_richcompare
0, // tp_weaklistoffset
0, // tp_iter
0, // tp_iternext
0, // tp_methods
0, // tp_members
g_MessagePropertiesCalcMembers, // tp_getset
0, // tp_base
0, // tp_dict
0, // tp_descr_get
0, // tp_descr_set
0, // tp_dictoffset
0, // tp_init
0, // tp_alloc
0, // tp_new
0, // tp_free
0, // tp_is_gc
0 // tp_bases
};
//-----------------------------------------------------------------------------
// MsgProps_New()
// Create a new message properties object.
//-----------------------------------------------------------------------------
static udt_MsgProps *MsgProps_New(udt_Connection *connection)
{
udt_MsgProps *self;
self = (udt_MsgProps*)
g_MessagePropertiesType.tp_alloc(&g_MessagePropertiesType, 0);
if (!self)
return NULL;
if (dpiConn_newMsgProps(connection->handle, &self->handle) < 0) {
Py_DECREF(self);
Error_RaiseAndReturnNull();
return NULL;
}
self->encoding = connection->encodingInfo.encoding;
return self;
}
//-----------------------------------------------------------------------------
// MsgProps_Free()
// Free the memory associated with the message properties object.
//-----------------------------------------------------------------------------
static void MsgProps_Free(udt_MsgProps *self)
{
if (self->handle) {
dpiMsgProps_release(self->handle);
self->handle = NULL;
}
Py_TYPE(self)->tp_free((PyObject*) self);
}
//-----------------------------------------------------------------------------
// MsgProps_GetAttrInt32()
// Get the value of the attribute as a 32-bit integer.
//-----------------------------------------------------------------------------
static PyObject *MsgProps_GetAttrInt32(udt_MsgProps *self,
int (*func)(dpiMsgProps *props, int32_t *value))
{
int32_t value;
if ((*func)(self->handle, &value) < 0)
return Error_RaiseAndReturnNull();
return PyInt_FromLong(value);
}
//-----------------------------------------------------------------------------
// MsgProps_SetAttrInt32()
// Set the value of the attribute as a 32-bit integer.
//-----------------------------------------------------------------------------
static int MsgProps_SetAttrInt32(udt_MsgProps *self, PyObject *valueObj,
int (*func)(dpiMsgProps *props, int32_t value))
{
int32_t value;
value = PyInt_AsLong(valueObj);
if (PyErr_Occurred())
return -1;
if ((*func)(self->handle, value) < 0)
return Error_RaiseAndReturnInt();
return 0;
}
//-----------------------------------------------------------------------------
// MsgProps_GetNumAttempts()
// Get the value of the attempts property.
//-----------------------------------------------------------------------------
static PyObject *MsgProps_GetNumAttempts(udt_MsgProps *self, void *unused)
{
return MsgProps_GetAttrInt32(self, dpiMsgProps_getNumAttempts);
}
//-----------------------------------------------------------------------------
// MsgProps_GetCorrelation()
// Get the value of the correlation property.
//-----------------------------------------------------------------------------
static PyObject *MsgProps_GetCorrelation(udt_MsgProps *self, void *unused)
{
uint32_t valueLength;
const char *value;
if (dpiMsgProps_getCorrelation(self->handle, &value, &valueLength) < 0)
return Error_RaiseAndReturnNull();
if (!value)
Py_RETURN_NONE;
return cxString_FromEncodedString(value, valueLength, self->encoding);
}
//-----------------------------------------------------------------------------
// MsgProps_GetDelay()
// Get the value of the delay property.
//-----------------------------------------------------------------------------
static PyObject *MsgProps_GetDelay(udt_MsgProps *self, void *unused)
{
return MsgProps_GetAttrInt32(self, dpiMsgProps_getDelay);
}
//-----------------------------------------------------------------------------
// MsgProps_GetDeliveryMode()
// Get the value of the delivery mode property.
//-----------------------------------------------------------------------------
static PyObject *MsgProps_GetDeliveryMode(udt_MsgProps *self, void *unused)
{
dpiMessageDeliveryMode value;
if (dpiMsgProps_getDeliveryMode(self->handle, &value) < 0)
return Error_RaiseAndReturnNull();
return PyInt_FromLong(value);
}
//-----------------------------------------------------------------------------
// MsgProps_GetEnqTime()
// Get the value of the enqueue time property.
//-----------------------------------------------------------------------------
static PyObject *MsgProps_GetEnqTime(udt_MsgProps *self, void *unused)
{
dpiTimestamp value;
if (dpiMsgProps_getEnqTime(self->handle, &value) < 0)
return Error_RaiseAndReturnNull();
return PyDateTime_FromDateAndTime(value.year, value.month, value.day,
value.hour, value.minute, value.second, 0);
}
//-----------------------------------------------------------------------------
// MsgProps_GetExceptionQ()
// Get the value of the exception queue property.
//-----------------------------------------------------------------------------
static PyObject *MsgProps_GetExceptionQ(udt_MsgProps *self, void *unused)
{
uint32_t valueLength;
const char *value;
if (dpiMsgProps_getExceptionQ(self->handle, &value, &valueLength) < 0)
return Error_RaiseAndReturnNull();
if (!value)
Py_RETURN_NONE;
return cxString_FromEncodedString(value, valueLength, self->encoding);
}
//-----------------------------------------------------------------------------
// MsgProps_GetExpiration()
// Get the value of the expiration property.
//-----------------------------------------------------------------------------
static PyObject *MsgProps_GetExpiration(udt_MsgProps *self, void *unused)
{
return MsgProps_GetAttrInt32(self, dpiMsgProps_getExpiration);
}
//-----------------------------------------------------------------------------
// MsgProps_GetOriginalMsgId()
// Get the value of the expiration property.
//-----------------------------------------------------------------------------
static PyObject *MsgProps_GetOriginalMsgId(udt_MsgProps *self, void *unused)
{
uint32_t valueLength;
const char *value;
if (dpiMsgProps_getOriginalMsgId(self->handle, &value, &valueLength) < 0)
return Error_RaiseAndReturnNull();
if (!value)
Py_RETURN_NONE;
return PyBytes_FromStringAndSize(value, valueLength);
}
//-----------------------------------------------------------------------------
// MsgProps_GetPriority()
// Get the value of the priority property.
//-----------------------------------------------------------------------------
static PyObject *MsgProps_GetPriority(udt_MsgProps *self, void *unused)
{
return MsgProps_GetAttrInt32(self, dpiMsgProps_getPriority);
}
//-----------------------------------------------------------------------------
// MsgProps_GetState()
// Get the value of the state property.
//-----------------------------------------------------------------------------
static PyObject *MsgProps_GetState(udt_MsgProps *self, void *unused)
{
dpiMessageState value;
if (dpiMsgProps_getState(self->handle, &value) < 0)
return Error_RaiseAndReturnNull();
return PyInt_FromLong(value);
}
//-----------------------------------------------------------------------------
// MsgProps_SetCorrelation()
// Set the value of the correlation property.
//-----------------------------------------------------------------------------
static int MsgProps_SetCorrelation(udt_MsgProps *self, PyObject *valueObj,
void *unused)
{
udt_Buffer buffer;
int status;
if (cxBuffer_FromObject(&buffer, valueObj, self->encoding))
return -1;
status = dpiMsgProps_setCorrelation(self->handle, buffer.ptr, buffer.size);
cxBuffer_Clear(&buffer);
if (status < 0)
return Error_RaiseAndReturnInt();
return 0;
}
//-----------------------------------------------------------------------------
// MsgProps_SetDelay()
// Set the value of the delay property.
//-----------------------------------------------------------------------------
static int MsgProps_SetDelay(udt_MsgProps *self, PyObject *valueObj,
void *unused)
{
return MsgProps_SetAttrInt32(self, valueObj, dpiMsgProps_setDelay);
}
//-----------------------------------------------------------------------------
// MsgProps_SetExceptionQ()
// Set the value of the exception queue property.
//-----------------------------------------------------------------------------
static int MsgProps_SetExceptionQ(udt_MsgProps *self, PyObject *valueObj,
void *unused)
{
udt_Buffer buffer;
int status;
if (cxBuffer_FromObject(&buffer, valueObj, self->encoding))
return -1;
status = dpiMsgProps_setExceptionQ(self->handle, buffer.ptr, buffer.size);
cxBuffer_Clear(&buffer);
if (status < 0)
return Error_RaiseAndReturnInt();
return 0;
}
//-----------------------------------------------------------------------------
// MsgProps_SetExpiration()
// Set the value of the expiration property.
//-----------------------------------------------------------------------------
static int MsgProps_SetExpiration(udt_MsgProps *self, PyObject *valueObj,
void *unused)
{
return MsgProps_SetAttrInt32(self, valueObj, dpiMsgProps_setExpiration);
}
//-----------------------------------------------------------------------------
// MsgProps_SetOriginalMsgId()
// Set the value of the original message id property.
//-----------------------------------------------------------------------------
static int MsgProps_SetOriginalMsgId(udt_MsgProps *self, PyObject *valueObj,
void *unused)
{
Py_ssize_t valueLength;
char *value;
if (PyBytes_AsStringAndSize(valueObj, &value, &valueLength) < 0)
return -1;
if (dpiMsgProps_setOriginalMsgId(self->handle, value, valueLength) < 0)
return Error_RaiseAndReturnInt();
return 0;
}
//-----------------------------------------------------------------------------
// MsgProps_SetPriority()
// Set the value of the expiration property.
//-----------------------------------------------------------------------------
static int MsgProps_SetPriority(udt_MsgProps *self, PyObject *valueObj,
void *unused)
{
return MsgProps_SetAttrInt32(self, valueObj, dpiMsgProps_setPriority);
}

View File

@ -12,449 +12,242 @@
// Defines the routines for handling numeric variables.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Number types
//-----------------------------------------------------------------------------
typedef struct {
Variable_HEAD
OCINumber *data;
} udt_NumberVar;
typedef struct {
Variable_HEAD
double *data;
} udt_NativeFloatVar;
typedef struct {
Variable_HEAD
long *data;
} udt_NativeIntVar;
//-----------------------------------------------------------------------------
// Declaration of number variable functions.
//-----------------------------------------------------------------------------
static int NumberVar_PreDefine(udt_NumberVar*, OCIParam*);
static int NumberVar_SetValue(udt_NumberVar*, unsigned, PyObject*);
static PyObject *NumberVar_GetValue(udt_NumberVar*, unsigned);
static int NativeFloatVar_SetValue(udt_NativeFloatVar*, unsigned, PyObject*);
static PyObject *NativeFloatVar_GetValue(udt_NativeFloatVar*, unsigned);
static int NativeIntVar_SetValue(udt_NativeIntVar*, unsigned, PyObject*);
static PyObject *NativeIntVar_GetValue(udt_NativeIntVar*, unsigned);
static PyObject *NumberVar_GetValueDecimal(udt_Variable*, dpiData*);
static PyObject *NumberVar_GetValueFloat(udt_Variable*, dpiData*);
static PyObject *NumberVar_GetValueInteger(udt_Variable*, dpiData*);
static PyObject *NumberVar_GetValueLongInteger(udt_Variable*, dpiData*);
static int NumberVar_SetValueDecimal(udt_Variable*, uint32_t, dpiData*,
PyObject*);
static int NumberVar_SetValueFloat(udt_Variable*, uint32_t, dpiData*,
PyObject*);
static int NumberVar_SetValueInteger(udt_Variable*, uint32_t, dpiData*,
PyObject*);
static int NumberVar_SetValueLongInteger(udt_Variable*, uint32_t, dpiData*,
PyObject*);
//-----------------------------------------------------------------------------
// Python type declaration
// Python type declarations
//-----------------------------------------------------------------------------
static PyTypeObject g_NumberVarType = {
PyVarObject_HEAD_INIT(NULL, 0)
"cx_Oracle.NUMBER", // tp_name
sizeof(udt_NumberVar), // tp_basicsize
0, // tp_itemsize
0, // tp_dealloc
0, // tp_print
0, // tp_getattr
0, // tp_setattr
0, // tp_compare
0, // tp_repr
0, // tp_as_number
0, // tp_as_sequence
0, // tp_as_mapping
0, // tp_hash
0, // tp_call
0, // tp_str
0, // tp_getattro
0, // tp_setattro
0, // tp_as_buffer
Py_TPFLAGS_DEFAULT, // tp_flags
0 // tp_doc
};
static PyTypeObject g_NativeFloatVarType = {
PyVarObject_HEAD_INIT(NULL, 0)
"cx_Oracle.NATIVE_FLOAT", // tp_name
sizeof(udt_NativeFloatVar), // tp_basicsize
0, // tp_itemsize
0, // tp_dealloc
0, // tp_print
0, // tp_getattr
0, // tp_setattr
0, // tp_compare
0, // tp_repr
0, // tp_as_number
0, // tp_as_sequence
0, // tp_as_mapping
0, // tp_hash
0, // tp_call
0, // tp_str
0, // tp_getattro
0, // tp_setattro
0, // tp_as_buffer
Py_TPFLAGS_DEFAULT, // tp_flags
0 // tp_doc
};
static PyTypeObject g_NativeIntVarType = {
PyVarObject_HEAD_INIT(NULL, 0)
"cx_Oracle.NATIVE_INT", // tp_name
sizeof(udt_NativeIntVar), // tp_basicsize
0, // tp_itemsize
0, // tp_dealloc
0, // tp_print
0, // tp_getattr
0, // tp_setattr
0, // tp_compare
0, // tp_repr
0, // tp_as_number
0, // tp_as_sequence
0, // tp_as_mapping
0, // tp_hash
0, // tp_call
0, // tp_str
0, // tp_getattro
0, // tp_setattro
0, // tp_as_buffer
Py_TPFLAGS_DEFAULT, // tp_flags
0 // tp_doc
};
DECLARE_VARIABLE_TYPE(g_NumberVarType, NUMBER)
DECLARE_VARIABLE_TYPE(g_NativeFloatVarType, NATIVE_FLOAT)
DECLARE_VARIABLE_TYPE(g_NativeIntVarType, NATIVE_INT)
//-----------------------------------------------------------------------------
// variable type declarations
//-----------------------------------------------------------------------------
static udt_VariableType vt_Float = {
(InitializeProc) NULL,
(FinalizeProc) NULL,
(PreDefineProc) NumberVar_PreDefine,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) NULL,
(IsNullProc) NULL,
(SetValueProc) NumberVar_SetValue,
(GetValueProc) NumberVar_GetValue,
(GetBufferSizeProc) NULL,
static udt_VariableType vt_NumberAsDecimal = {
(SetValueProc) NumberVar_SetValueDecimal,
(GetValueProc) NumberVar_GetValueDecimal,
&g_NumberVarType, // Python type
SQLT_VNU, // Oracle type
SQLCS_IMPLICIT, // charset form
sizeof(OCINumber), // element length
0, // is character data
0, // is variable length
1, // can be copied
1 // can be in array
DPI_ORACLE_TYPE_NUMBER, // Oracle type
DPI_NATIVE_TYPE_BYTES, // native type
1000 // element length
};
static udt_VariableType vt_NumberAsFloat = {
(SetValueProc) NumberVar_SetValueFloat,
(GetValueProc) NumberVar_GetValueFloat,
&g_NumberVarType, // Python type
DPI_ORACLE_TYPE_NUMBER, // Oracle type
DPI_NATIVE_TYPE_DOUBLE, // native type
0 // element length
};
static udt_VariableType vt_NumberAsInteger = {
(SetValueProc) NumberVar_SetValueInteger,
(GetValueProc) NumberVar_GetValueInteger,
&g_NumberVarType, // Python type
DPI_ORACLE_TYPE_NUMBER, // Oracle type
DPI_NATIVE_TYPE_INT64, // native type
0 // element length
};
static udt_VariableType vt_NumberAsLongInteger = {
(SetValueProc) NumberVar_SetValueLongInteger,
(GetValueProc) NumberVar_GetValueLongInteger,
&g_NumberVarType, // Python type
DPI_ORACLE_TYPE_NUMBER, // Oracle type
DPI_NATIVE_TYPE_BYTES, // native type
40 // element length
};
static udt_VariableType vt_NativeFloat = {
(InitializeProc) NULL,
(FinalizeProc) NULL,
(PreDefineProc) NULL,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) NULL,
(IsNullProc) NULL,
(SetValueProc) NativeFloatVar_SetValue,
(GetValueProc) NativeFloatVar_GetValue,
(GetBufferSizeProc) NULL,
(SetValueProc) NumberVar_SetValueFloat,
(GetValueProc) NumberVar_GetValueFloat,
&g_NativeFloatVarType, // Python type
SQLT_BDOUBLE, // Oracle type
SQLCS_IMPLICIT, // charset form
sizeof(double), // element length
0, // is character data
0, // is variable length
1, // can be copied
1 // can be in array
DPI_ORACLE_TYPE_NATIVE_DOUBLE, // Oracle type
DPI_NATIVE_TYPE_DOUBLE, // native type
0 // element length
};
static udt_VariableType vt_NativeInteger = {
(InitializeProc) NULL,
(FinalizeProc) NULL,
(PreDefineProc) NULL,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) NULL,
(IsNullProc) NULL,
(SetValueProc) NativeIntVar_SetValue,
(GetValueProc) NativeIntVar_GetValue,
(GetBufferSizeProc) NULL,
(SetValueProc) NumberVar_SetValueInteger,
(GetValueProc) NumberVar_GetValueInteger,
&g_NativeIntVarType, // Python type
SQLT_INT, // Oracle type
SQLCS_IMPLICIT, // charset form
sizeof(long), // element length
0, // is character data
0, // is variable length
1, // can be copied
1 // can be in array
DPI_ORACLE_TYPE_NATIVE_INT, // Oracle type
DPI_NATIVE_TYPE_INT64, // native type
0 // element length
};
static udt_VariableType vt_Integer = {
(InitializeProc) NULL,
(FinalizeProc) NULL,
(PreDefineProc) NumberVar_PreDefine,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) NULL,
(IsNullProc) NULL,
(SetValueProc) NumberVar_SetValue,
(GetValueProc) NumberVar_GetValue,
(GetBufferSizeProc) NULL,
&g_NumberVarType, // Python type
SQLT_VNU, // Oracle type
SQLCS_IMPLICIT, // charset form
sizeof(OCINumber), // element length
0, // is character data
0, // is variable length
1, // can be copied
1 // can be in array
};
static udt_VariableType vt_LongInteger = {
(InitializeProc) NULL,
(FinalizeProc) NULL,
(PreDefineProc) NumberVar_PreDefine,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) NULL,
(IsNullProc) NULL,
(SetValueProc) NumberVar_SetValue,
(GetValueProc) NumberVar_GetValue,
(GetBufferSizeProc) NULL,
&g_NumberVarType, // Python type
SQLT_VNU, // Oracle type
SQLCS_IMPLICIT, // charset form
sizeof(OCINumber), // element length
0, // is character data
0, // is variable length
1, // can be copied
1 // can be in array
};
static udt_VariableType vt_NumberAsString = {
(InitializeProc) NULL,
(FinalizeProc) NULL,
(PreDefineProc) NumberVar_PreDefine,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) NULL,
(IsNullProc) NULL,
(SetValueProc) NumberVar_SetValue,
(GetValueProc) NumberVar_GetValue,
(GetBufferSizeProc) NULL,
&g_NumberVarType, // Python type
SQLT_VNU, // Oracle type
SQLCS_IMPLICIT, // charset form
sizeof(OCINumber), // element length
0, // is character data
0, // is variable length
1, // can be copied
1 // can be in array
};
#if ORACLE_VERSION_HEX < ORACLE_VERSION(12, 1)
static udt_VariableType vt_Boolean = {
(InitializeProc) NULL,
(FinalizeProc) NULL,
(PreDefineProc) NumberVar_PreDefine,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) NULL,
(IsNullProc) NULL,
(SetValueProc) NumberVar_SetValue,
(GetValueProc) NumberVar_GetValue,
(GetBufferSizeProc) NULL,
&g_NumberVarType, // Python type
SQLT_VNU, // Oracle type
SQLCS_IMPLICIT, // charset form
sizeof(OCINumber), // element length
0, // is character data
0, // is variable length
1, // can be copied
1 // can be in array
};
#endif
//-----------------------------------------------------------------------------
// NumberVar_PreDefine()
// Set the type of value (integer, float or string) that will be returned
// when values are fetched from this variable.
// NumberVar_GetValueDecimal()
// Returns the value of the variable as a decimal object.
//-----------------------------------------------------------------------------
static int NumberVar_PreDefine(
udt_NumberVar *var, // variable to initialize
OCIParam *param) // parameter handle
static PyObject *NumberVar_GetValueDecimal(udt_Variable *var, dpiData *data)
{
static int maxLongSafeDigits = sizeof(long) >= 8 ? 18 : 9;
sb2 precision;
sword status;
sb1 scale;
PyObject *stringObj, *result;
dpiBytes *bytes;
// if the return type has not already been specified, check to see if the
// number can fit inside an integer by looking at the precision and scale
if (var->type == &vt_Float) {
scale = 0;
precision = 0;
status = OCIAttrGet(param, OCI_HTYPE_DESCRIBE, (dvoid*) &scale, 0,
OCI_ATTR_SCALE, var->environment->errorHandle);
if (Environment_CheckForError(var->environment, status,
"NumberVar_PreDefine(): scale") < 0)
return -1;
status = OCIAttrGet(param, OCI_HTYPE_DESCRIBE, (dvoid*) &precision, 0,
OCI_ATTR_PRECISION, var->environment->errorHandle);
if (Environment_CheckForError(var->environment, status,
"NumberVar_PreDefine(): precision") < 0)
return -1;
if (scale == 0 || (scale == -127 && precision == 0)) {
var->type = &vt_LongInteger;
if (precision > 0 && precision <= maxLongSafeDigits)
var->type = &vt_Integer;
}
}
return 0;
bytes = &data->value.asBytes;
stringObj = cxString_FromEncodedString(bytes->ptr, bytes->length,
bytes->encoding);
if (!stringObj)
return NULL;
result = PyObject_CallFunctionObjArgs( (PyObject*) g_DecimalType,
stringObj, NULL);
Py_DECREF(stringObj);
return result;
}
//-----------------------------------------------------------------------------
// NumberVar_SetValue()
// Set the value of the variable.
// NumberVar_GetValueFloat()
// Returns the value of the variable as a float.
//-----------------------------------------------------------------------------
static int NumberVar_SetValue(
udt_NumberVar *var, // variable to set value for
unsigned pos, // array position to set
PyObject *value) // value to set
static PyObject *NumberVar_GetValueFloat(udt_Variable *var, dpiData *data)
{
return PythonNumberToOracleNumber(var->environment, value,
&var->data[pos]);
return PyFloat_FromDouble(data->value.asDouble);
}
//-----------------------------------------------------------------------------
// NumberVar_GetValue()
// Returns the value stored at the given array position.
// NumberVar_GetValueInteger()
// Returns the value of the variable as an integer.
//-----------------------------------------------------------------------------
static PyObject *NumberVar_GetValue(
udt_NumberVar *var, // variable to determine value for
unsigned pos) // array position
static PyObject *NumberVar_GetValueInteger(udt_Variable *var, dpiData *data)
{
PyObject *result, *stringObj;
char stringValue[200];
long integerValue;
ub4 stringLength;
sword status;
if (var->type == &vt_Boolean || var->type == &vt_Integer) {
status = OCINumberToInt(var->environment->errorHandle, &var->data[pos],
sizeof(long), OCI_NUMBER_SIGNED, (dvoid*) &integerValue);
if (Environment_CheckForError(var->environment, status,
"NumberVar_GetValue(): as integer") < 0)
return NULL;
if (var->type == &vt_Boolean)
return PyBool_FromLong(integerValue);
#if PY_MAJOR_VERSION >= 3
return PyLong_FromLong(integerValue);
#else
return PyInt_FromLong(integerValue);
#endif
}
if (var->type == &vt_NumberAsString || var->type == &vt_LongInteger) {
stringLength = sizeof(stringValue);
status = OCINumberToText(var->environment->errorHandle,
&var->data[pos],
(text*) var->environment->numberToStringFormatBuffer.ptr,
(ub4) var->environment->numberToStringFormatBuffer.size, NULL,
0, &stringLength, (unsigned char*) stringValue);
if (Environment_CheckForError(var->environment, status,
"NumberVar_GetValue(): as string") < 0)
return NULL;
stringObj = cxString_FromEncodedString(stringValue, stringLength,
var->environment->encoding);
if (!stringObj)
return NULL;
if (var->type == &vt_NumberAsString)
return stringObj;
#if PY_MAJOR_VERSION >= 3
result = PyNumber_Long(stringObj);
#else
result = PyNumber_Int(stringObj);
#endif
Py_DECREF(stringObj);
if (result || !PyErr_ExceptionMatches(PyExc_ValueError))
return result;
PyErr_Clear();
}
return OracleNumberToPythonFloat(var->environment, &var->data[pos]);
return PyInt_FromLong(data->value.asInt64);
}
//-----------------------------------------------------------------------------
// NativeFloatVar_GetValue()
// Returns the value stored at the given array position as a float.
// NumberVar_GetValueLongInteger()
// Returns the value of the variable as a long integer (one that may not fit
// in a native integer).
//-----------------------------------------------------------------------------
static PyObject *NativeFloatVar_GetValue(
udt_NativeFloatVar *var, // variable to determine value for
unsigned pos) // array position
static PyObject *NumberVar_GetValueLongInteger(udt_Variable *var,
dpiData *data)
{
return PyFloat_FromDouble(var->data[pos]);
PyObject *stringObj, *result;
dpiBytes *bytes;
bytes = &data->value.asBytes;
stringObj = cxString_FromEncodedString(bytes->ptr, bytes->length,
bytes->encoding);
if (!stringObj)
return NULL;
result = PyNumber_Int(stringObj);
Py_DECREF(stringObj);
return result;
}
//-----------------------------------------------------------------------------
// NativeFloatVar_SetValue()
// Set the value of the variable which should be a native double.
// NumberVar_SetValueDecimal()
// Sets the value of the variable from a decimal object.
//-----------------------------------------------------------------------------
static int NativeFloatVar_SetValue(
udt_NativeFloatVar *var, // variable to set value for
unsigned pos, // array position to set
PyObject *value) // value to set
static int NumberVar_SetValueDecimal(udt_Variable *var, uint32_t pos,
dpiData *data, PyObject *value)
{
if (!PyFloat_Check(value)) {
PyErr_SetString(PyExc_TypeError, "expecting float");
PyObject *textValue;
int status;
if (Py_TYPE(value) != g_DecimalType) {
PyErr_SetString(PyExc_TypeError, "expecting decimal");
return -1;
}
var->data[pos] = PyFloat_AS_DOUBLE(value);
return 0;
}
//-----------------------------------------------------------------------------
// NativeIntVar_GetValue()
// Returns the value stored at the given array position as an integer.
//-----------------------------------------------------------------------------
static PyObject *NativeIntVar_GetValue(
udt_NativeIntVar *var, // variable to determine value for
unsigned pos) // array position
{
return PyInt_FromLong(var->data[pos]);
}
//-----------------------------------------------------------------------------
// NativeIntVar_SetValue()
// Set the value of the variable which should be a native integer.
//-----------------------------------------------------------------------------
static int NativeIntVar_SetValue(
udt_NativeIntVar *var, // variable to set value for
unsigned pos, // array position to set
PyObject *value) // value to set
{
if (!PyInt_Check(value)) {
PyErr_SetString(PyExc_TypeError, "expecting integer");
textValue = PyObject_Str(value);
if (!textValue)
return -1;
}
var->data[pos] = PyInt_AsLong(value);
status = Variable_SetValueBytes(var, pos, data, textValue);
Py_DECREF(textValue);
return status;
}
//-----------------------------------------------------------------------------
// NumberVar_SetValueFloat()
// Sets the value of the variable from a float.
//-----------------------------------------------------------------------------
static int NumberVar_SetValueFloat(udt_Variable *var, uint32_t pos,
dpiData *data, PyObject *value)
{
data->value.asDouble = PyFloat_AsDouble(value);
if (PyErr_Occurred())
return -1;
return 0;
}
//-----------------------------------------------------------------------------
// NumberVar_SetValueInteger()
// Sets the value of the variable from an integer.
//-----------------------------------------------------------------------------
static int NumberVar_SetValueInteger(udt_Variable *var, uint32_t pos,
dpiData *data, PyObject *value)
{
#if PY_MAJOR_VERSION < 3
if (PyInt_Check(value)) {
data->value.asInt64 = PyInt_AS_LONG(value);
return 0;
}
#endif
if (!PyLong_Check(value)) {
PyErr_SetString(PyExc_TypeError, "expecting integer");
return -1;
}
data->value.asInt64 = PyLong_AsLong(value);
if (PyErr_Occurred())
return -1;
return 0;
}
//-----------------------------------------------------------------------------
// NumberVar_SetValueLongInteger()
// Sets the value of the variable from a long integer.
//-----------------------------------------------------------------------------
static int NumberVar_SetValueLongInteger(udt_Variable *var, uint32_t pos,
dpiData *data, PyObject *value)
{
PyObject *textValue;
int status;
#if PY_MAJOR_VERSION < 3
if (!PyInt_Check(value) && !PyLong_Check(value)) {
#else
if (!PyLong_Check(value)) {
#endif
PyErr_SetString(PyExc_TypeError, "expecting integer");
return -1;
}
textValue = PyObject_Str(value);
if (!textValue)
return -1;
status = Variable_SetValueBytes(var, pos, data, textValue);
Py_DECREF(textValue);
return status;
}

File diff suppressed because it is too large Load Diff

View File

@ -17,34 +17,34 @@
//-----------------------------------------------------------------------------
typedef struct {
PyObject_HEAD
udt_Connection *connection;
OCIType *tdo;
dpiObjectType *handle;
PyObject *schema;
PyObject *name;
PyObject *attributes;
PyObject *attributesByName;
OCITypeCode typeCode;
OCITypeCode collectionTypeCode;
OCITypeCode elementTypeCode;
const char *encoding;
dpiNativeTypeNum elementNativeTypeNum;
PyObject *elementType;
boolean isCollection;
char isCollection;
} udt_ObjectType;
typedef struct {
PyObject_HEAD
PyObject *name;
OCITypeCode typeCode;
udt_ObjectType *subType;
dpiObjectAttr *handle;
dpiNativeTypeNum nativeTypeNum;
udt_ObjectType *type;
} udt_ObjectAttribute;
//-----------------------------------------------------------------------------
// Declaration of type variable functions.
// Declaration of functions
//-----------------------------------------------------------------------------
static udt_ObjectType *ObjectType_New(udt_Connection*, OCIParam*, ub4);
static udt_ObjectType *ObjectType_New(udt_Connection*, dpiObjectType*);
static void ObjectType_Free(udt_ObjectType*);
static PyObject *ObjectType_Repr(udt_ObjectType*);
static PyObject *ObjectType_NewObject(udt_ObjectType*, PyObject*, PyObject*);
static udt_ObjectAttribute *ObjectAttribute_New(udt_Connection*, OCIParam*);
static udt_ObjectAttribute *ObjectAttribute_New(udt_Connection*,
dpiObjectAttr*);
static void ObjectAttribute_Free(udt_ObjectAttribute*);
static PyObject *ObjectAttribute_Repr(udt_ObjectAttribute*);
@ -178,194 +178,71 @@ static PyTypeObject g_ObjectAttributeType = {
//-----------------------------------------------------------------------------
// ObjectType_Describe()
// Describe the type and store information about it as needed.
// ObjectType_Initialize()
// Initialize the object type with the information that is required.
//-----------------------------------------------------------------------------
static int ObjectType_Describe(
udt_ObjectType *self, // type to populate
OCIDescribe *describeHandle) // describe handle
static int ObjectType_Initialize(udt_ObjectType *self,
udt_Connection *connection)
{
OCIParam *topLevelParam, *attributeListParam, *attributeParam;
udt_ObjectAttribute *attribute;
OCIParam *collectionParam;
ub2 numAttributes;
sword status;
int i;
dpiObjectAttr **attributes;
udt_ObjectAttribute *attr;
dpiObjectTypeInfo info;
uint16_t i;
// describe the type
status = OCIDescribeAny(self->connection->handle,
self->connection->environment->errorHandle, (dvoid*) self->tdo, 0,
OCI_OTYPE_PTR, OCI_DEFAULT, OCI_PTYPE_TYPE, describeHandle);
if (Environment_CheckForError(self->connection->environment, status,
"ObjectType_Describe(): describe type") < 0)
// get object type information
self->encoding = connection->encodingInfo.encoding;
if (dpiObjectType_getInfo(self->handle, &info) < 0)
return Error_RaiseAndReturnInt();
self->schema = cxString_FromEncodedString(info.schema, info.schemaLength,
self->encoding);
if (!self->schema)
return -1;
// get top level parameter descriptor
status = OCIAttrGet(describeHandle, OCI_HTYPE_DESCRIBE, &topLevelParam, 0,
OCI_ATTR_PARAM, self->connection->environment->errorHandle);
if (Environment_CheckForError(self->connection->environment, status,
"ObjectType_Describe(): get top level parameter descriptor") < 0)
self->name = cxString_FromEncodedString(info.name, info.nameLength,
self->encoding);
if (!self->name)
return -1;
// determine type of type
status = OCIAttrGet(topLevelParam, OCI_DTYPE_PARAM, &self->typeCode, 0,
OCI_ATTR_TYPECODE, self->connection->environment->errorHandle);
if (Environment_CheckForError(self->connection->environment, status,
"ObjectType_Describe(): get type code") < 0)
return -1;
// if a collection, need to determine the sub type
if (self->typeCode == OCI_TYPECODE_NAMEDCOLLECTION) {
self->isCollection = 1;
// determine type of collection
status = OCIAttrGet(topLevelParam, OCI_DTYPE_PARAM,
&self->collectionTypeCode, 0, OCI_ATTR_COLLECTION_TYPECODE,
self->connection->environment->errorHandle);
if (Environment_CheckForError(self->connection->environment, status,
"ObjectType_Describe(): get collection type code") < 0)
self->isCollection = info.isCollection;
self->elementNativeTypeNum = info.elementDefaultNativeTypeNum;
if (info.elementObjectType) {
self->elementType = (PyObject*) ObjectType_New(connection,
info.elementObjectType);
if (!self->elementType)
return -1;
// acquire collection parameter descriptor
status = OCIAttrGet(topLevelParam, OCI_DTYPE_PARAM, &collectionParam,
0, OCI_ATTR_COLLECTION_ELEMENT,
self->connection->environment->errorHandle);
if (Environment_CheckForError(self->connection->environment, status,
"ObjectType_Describe(): get collection descriptor") < 0)
return -1;
// determine type of element
status = OCIAttrGet(collectionParam, OCI_DTYPE_PARAM,
&self->elementTypeCode, 0, OCI_ATTR_TYPECODE,
self->connection->environment->errorHandle);
if (Environment_CheckForError(self->connection->environment, status,
"ObjectType_Describe(): get element type code") < 0)
return -1;
// if element type is an object type get its type
if (self->elementTypeCode == OCI_TYPECODE_OBJECT) {
self->elementType = (PyObject*)
ObjectType_New(self->connection, collectionParam,
OCI_ATTR_TYPE_NAME);
if (!self->elementType)
return -1;
}
}
// determine the number of attributes
status = OCIAttrGet(topLevelParam, OCI_DTYPE_PARAM,
(dvoid*) &numAttributes, 0, OCI_ATTR_NUM_TYPE_ATTRS,
self->connection->environment->errorHandle);
if (Environment_CheckForError(self->connection->environment, status,
"ObjectType_Describe(): get number of attributes") < 0)
return -1;
// allocate the attribute list and dictionary
self->attributes = PyList_New(numAttributes);
// allocate the attribute list (temporary and permanent) and dictionary
self->attributes = PyList_New(info.numAttributes);
if (!self->attributes)
return -1;
self->attributesByName = PyDict_New();
if (!self->attributesByName)
return -1;
// acquire the list parameter descriptor
status = OCIAttrGet(topLevelParam, OCI_DTYPE_PARAM,
(dvoid*) &attributeListParam, 0, OCI_ATTR_LIST_TYPE_ATTRS,
self->connection->environment->errorHandle);
if (Environment_CheckForError(self->connection->environment, status,
"ObjectType_Describe(): get list parameter descriptor") < 0)
// get the list of attributes from DPI
attributes = PyMem_Malloc(sizeof(dpiObjectAttr*) * info.numAttributes);
if (!attributes) {
PyErr_NoMemory();
return -1;
// create attribute information for each attribute
for (i = 0; i < numAttributes; i++) {
status = OCIParamGet(attributeListParam, OCI_DTYPE_PARAM,
self->connection->environment->errorHandle,
(dvoid**) &attributeParam, (ub4) i + 1);
if (Environment_CheckForError(self->connection->environment, status,
"ObjectType_Describe(): get attribute param descriptor") < 0)
return -1;
attribute = ObjectAttribute_New(self->connection, attributeParam);
if (!attribute)
return -1;
PyList_SET_ITEM(self->attributes, i, (PyObject*) attribute);
if (PyDict_SetItem(self->attributesByName, attribute->name,
(PyObject*) attribute) < 0)
return -1;
}
if (dpiObjectType_getAttributes(self->handle, info.numAttributes,
attributes) < 0) {
PyMem_Free(attributes);
return Error_RaiseAndReturnInt();
}
return 0;
}
//-----------------------------------------------------------------------------
// ObjectType_Initialize()
// Initialize the object type with the information that is required.
//-----------------------------------------------------------------------------
static int ObjectType_Initialize(
udt_ObjectType *self, // type to initialize
OCIParam *param, // parameter descriptor
ub4 nameAttribute) // value for the name attribute
{
OCIDescribe *describeHandle;
OCIRef *tdoReference;
sword status;
char *name;
ub4 size;
// determine the schema of the type
status = OCIAttrGet(param, OCI_HTYPE_DESCRIBE, (dvoid*) &name, &size,
OCI_ATTR_SCHEMA_NAME, self->connection->environment->errorHandle);
if (Environment_CheckForError(self->connection->environment, status,
"ObjectType_Initialize(): get schema name") < 0)
return -1;
self->schema = cxString_FromEncodedString(name, size,
self->connection->environment->encoding);
if (!self->schema)
return -1;
// determine the name of the type
status = OCIAttrGet(param, OCI_HTYPE_DESCRIBE, (dvoid*) &name, &size,
nameAttribute, self->connection->environment->errorHandle);
if (Environment_CheckForError(self->connection->environment, status,
"ObjectType_Initialize(): get name") < 0)
return -1;
self->name = cxString_FromEncodedString(name, size,
self->connection->environment->encoding);
if (!self->name)
return -1;
// retrieve TDO of the parameter
status = OCIAttrGet(param, OCI_HTYPE_DESCRIBE, (dvoid*) &tdoReference, 0,
OCI_ATTR_REF_TDO, self->connection->environment->errorHandle);
if (Environment_CheckForError(self->connection->environment, status,
"ObjectType_Initialize(): get TDO reference") < 0)
return -1;
status = OCIObjectPin(self->connection->environment->handle,
self->connection->environment->errorHandle, tdoReference, NULL,
OCI_PIN_ANY, OCI_DURATION_SESSION, OCI_LOCK_NONE,
(dvoid**) &self->tdo);
if (Environment_CheckForError(self->connection->environment, status,
"ObjectType_Initialize(): pin TDO reference") < 0)
return -1;
// acquire a describe handle
status = OCIHandleAlloc(self->connection->environment->handle,
(dvoid**) &describeHandle, OCI_HTYPE_DESCRIBE, 0, 0);
if (Environment_CheckForError(self->connection->environment, status,
"ObjectType_Initialize(): allocate describe handle") < 0)
return -1;
// describe the type
if (ObjectType_Describe(self, describeHandle) < 0)
return -1;
// free the describe handle
status = OCIHandleFree(describeHandle, OCI_HTYPE_DESCRIBE);
if (Environment_CheckForError(self->connection->environment, status,
"ObjectType_Initialize(): free describe handle") < 0)
return -1;
// create attribute information for each attribute
for (i = 0; i < info.numAttributes; i++) {
attr = ObjectAttribute_New(connection, attributes[i]);
if (!attr) {
PyMem_Free(attributes);
return -1;
}
PyList_SET_ITEM(self->attributes, i, (PyObject*) attr);
if (PyDict_SetItem(self->attributesByName, attr->name,
(PyObject*) attr) < 0)
return -1;
}
PyMem_Free(attributes);
return 0;
}
@ -374,19 +251,21 @@ static int ObjectType_Initialize(
// ObjectType_New()
// Allocate a new object type.
//-----------------------------------------------------------------------------
static udt_ObjectType *ObjectType_New(
udt_Connection *connection, // connection for type information
OCIParam *param, // parameter descriptor
ub4 nameAttribute) // value for the name attribute
static udt_ObjectType *ObjectType_New(udt_Connection *connection,
dpiObjectType *handle)
{
udt_ObjectType *self;
self = (udt_ObjectType*) g_ObjectTypeType.tp_alloc(&g_ObjectTypeType, 0);
if (!self)
return NULL;
Py_INCREF(connection);
self->connection = connection;
if (ObjectType_Initialize(self, param, nameAttribute) < 0) {
if (dpiObjectType_addRef(handle) < 0) {
Py_DECREF(self);
Error_RaiseAndReturnNull();
return NULL;
}
self->handle = handle;
if (ObjectType_Initialize(self, connection) < 0) {
Py_DECREF(self);
return NULL;
}
@ -399,87 +278,25 @@ static udt_ObjectType *ObjectType_New(
// ObjectType_NewByName()
// Create a new object type given its name.
//-----------------------------------------------------------------------------
static udt_ObjectType *ObjectType_NewByName(
udt_Connection *connection, // connection for type information
PyObject *name) // name of object type to describe
static udt_ObjectType *ObjectType_NewByName(udt_Connection *connection,
PyObject *name)
{
OCIDescribe *describeHandle;
udt_ObjectType *result;
udt_ObjectType *objType;
dpiObjectType *handle;
udt_Buffer buffer;
OCIParam *param;
#if ORACLE_VERSION_HEX >= ORACLE_VERSION(12, 1)
OCIType *tdo;
#endif
sword status;
int status;
// allocate describe handle
status = OCIHandleAlloc(connection->environment->handle,
(dvoid**) &describeHandle, OCI_HTYPE_DESCRIBE, 0, 0);
if (Environment_CheckForError(connection->environment, status,
"ObjectType_NewByName(): allocate describe handle") < 0)
return NULL;
// describe the object
if (cxBuffer_FromObject(&buffer, name,
connection->environment->encoding) < 0) {
OCIHandleFree(describeHandle, OCI_HTYPE_DESCRIBE);
connection->encodingInfo.encoding) < 0)
return NULL;
}
#if ORACLE_VERSION_HEX >= ORACLE_VERSION(12, 1)
status = OCITypeByFullName(connection->environment->handle,
connection->environment->errorHandle, connection->handle,
buffer.ptr, (ub4) buffer.size, NULL, 0, OCI_DURATION_SESSION,
OCI_TYPEGET_ALL, &tdo);
status = dpiConn_getObjectType(connection->handle, buffer.ptr,
buffer.size, &handle);
cxBuffer_Clear(&buffer);
if (Environment_CheckForError(connection->environment, status,
"ObjectType_NewByName(): get type by full name") < 0) {
OCIHandleFree(describeHandle, OCI_HTYPE_DESCRIBE);
return NULL;
}
status = OCIDescribeAny(connection->handle,
connection->environment->errorHandle, (dvoid*) tdo, 0,
OCI_OTYPE_PTR, 0, OCI_PTYPE_TYPE, describeHandle);
if (Environment_CheckForError(connection->environment, status,
"ObjectType_NewByName(): describe type") < 0) {
OCIHandleFree(describeHandle, OCI_HTYPE_DESCRIBE);
return NULL;
}
#else
status = OCIDescribeAny(connection->handle,
connection->environment->errorHandle, (dvoid*) buffer.ptr,
(ub4) buffer.size, OCI_OTYPE_NAME, 0, OCI_PTYPE_TYPE,
describeHandle);
cxBuffer_Clear(&buffer);
if (Environment_CheckForError(connection->environment, status,
"ObjectType_NewByName(): describe type") < 0) {
OCIHandleFree(describeHandle, OCI_HTYPE_DESCRIBE);
return NULL;
}
#endif
// get the parameter handle
status = OCIAttrGet(describeHandle, OCI_HTYPE_DESCRIBE, &param, 0,
OCI_ATTR_PARAM, connection->environment->errorHandle);
if (Environment_CheckForError(connection->environment, status,
"ObjectType_NewByName(): get parameter handle") < 0) {
OCIHandleFree(describeHandle, OCI_HTYPE_DESCRIBE);
return NULL;
}
// get object type
result = ObjectType_New(connection, param, OCI_ATTR_NAME);
if (!result) {
OCIHandleFree(describeHandle, OCI_HTYPE_DESCRIBE);
return NULL;
}
// free the describe handle
status = OCIHandleFree(describeHandle, OCI_HTYPE_DESCRIBE);
if (Environment_CheckForError(connection->environment, status,
"ObjectType_NewByName(): free describe handle") < 0)
return NULL;
return result;
if (status < 0)
return (udt_ObjectType*) Error_RaiseAndReturnNull();
objType = ObjectType_New(connection, handle);
dpiObjectType_release(handle);
return objType;
}
@ -487,13 +304,12 @@ static udt_ObjectType *ObjectType_NewByName(
// ObjectType_Free()
// Free the memory associated with an object type.
//-----------------------------------------------------------------------------
static void ObjectType_Free(
udt_ObjectType *self) // object type to free
static void ObjectType_Free(udt_ObjectType *self)
{
if (self->tdo)
OCIObjectUnpin(self->connection->environment->handle,
self->connection->environment->errorHandle, self->tdo);
Py_CLEAR(self->connection);
if (self->handle) {
dpiObjectType_release(self->handle);
self->handle = NULL;
}
Py_CLEAR(self->schema);
Py_CLEAR(self->name);
Py_CLEAR(self->attributes);
@ -507,8 +323,7 @@ static void ObjectType_Free(
// ObjectType_Repr()
// Return a string representation of the object type.
//-----------------------------------------------------------------------------
static PyObject *ObjectType_Repr(
udt_ObjectType *self) // object type to return the string for
static PyObject *ObjectType_Repr(udt_ObjectType *self)
{
PyObject *module, *name, *result, *format, *formatArgs;
@ -538,13 +353,12 @@ static PyObject *ObjectType_Repr(
// ObjectType_NewObject()
// Factory function for creating objects of the type which can be bound.
//-----------------------------------------------------------------------------
static PyObject *ObjectType_NewObject(
udt_ObjectType *self, // object type to return the string for
PyObject *args, // arguments
PyObject *keywordArgs) // keyword arguments
static PyObject *ObjectType_NewObject(udt_ObjectType *self, PyObject *args,
PyObject *keywordArgs)
{
static char *keywordList[] = { "value", NULL };
PyObject *initialValue;
dpiObject *handle;
udt_Object *obj;
// parse arguments
@ -553,8 +367,12 @@ static PyObject *ObjectType_NewObject(
&initialValue))
return NULL;
// get handle to newly created object
if (dpiObjectType_createObject(self->handle, &handle) < 0)
return Error_RaiseAndReturnNull();
// create the object
obj = Object_Create(self);
obj = (udt_Object*) Object_New(self, handle, 0);
if (!obj)
return NULL;
@ -574,43 +392,23 @@ static PyObject *ObjectType_NewObject(
// ObjectAttribute_Initialize()
// Initialize the new object attribute.
//-----------------------------------------------------------------------------
static int ObjectAttribute_Initialize(
udt_ObjectAttribute *self, // object attribute to initialize
udt_Connection *connection, // connection in use
OCIParam *param) // parameter descriptor
static int ObjectAttribute_Initialize(udt_ObjectAttribute *self,
udt_Connection *connection)
{
sword status;
char *name;
ub4 size;
dpiObjectAttrInfo info;
// determine the name of the attribute
status = OCIAttrGet(param, OCI_DTYPE_PARAM, (dvoid*) &name, &size,
OCI_ATTR_NAME, connection->environment->errorHandle);
if (Environment_CheckForError(connection->environment, status,
"ObjectAttribute_Initialize(): get name") < 0)
return -1;
self->name = cxString_FromEncodedString(name, size,
connection->environment->encoding);
if (dpiObjectAttr_getInfo(self->handle, &info) < 0)
return Error_RaiseAndReturnInt();
self->nativeTypeNum = info.defaultNativeTypeNum;
self->name = cxString_FromEncodedString(info.name, info.nameLength,
connection->encodingInfo.encoding);
if (!self->name)
return -1;
// determine the type of the attribute
status = OCIAttrGet(param, OCI_DTYPE_PARAM, (dvoid*) &self->typeCode, 0,
OCI_ATTR_TYPECODE, connection->environment->errorHandle);
if (Environment_CheckForError(connection->environment, status,
"ObjectAttribute_Initialize(): get type code") < 0)
return -1;
// if the type of the attribute is object, recurse
switch (self->typeCode) {
case OCI_TYPECODE_NAMEDCOLLECTION:
case OCI_TYPECODE_OBJECT:
self->subType = ObjectType_New(connection, param,
OCI_ATTR_TYPE_NAME);
if (!self->subType)
return -1;
break;
};
if (info.objectType) {
self->type = ObjectType_New(connection, info.objectType);
if (!self->type)
return -1;
}
return 0;
}
@ -620,17 +418,19 @@ static int ObjectAttribute_Initialize(
// ObjectAttribute_New()
// Allocate a new object attribute.
//-----------------------------------------------------------------------------
static udt_ObjectAttribute *ObjectAttribute_New(
udt_Connection *connection, // connection information
OCIParam *param) // parameter descriptor
static udt_ObjectAttribute *ObjectAttribute_New(udt_Connection *connection,
dpiObjectAttr *handle)
{
udt_ObjectAttribute *self;
self = (udt_ObjectAttribute*)
g_ObjectAttributeType.tp_alloc(&g_ObjectAttributeType, 0);
if (!self)
if (!self) {
dpiObjectAttr_release(handle);
return NULL;
if (ObjectAttribute_Initialize(self, connection, param) < 0) {
}
self->handle = handle;
if (ObjectAttribute_Initialize(self, connection) < 0) {
Py_DECREF(self);
return NULL;
}
@ -643,11 +443,14 @@ static udt_ObjectAttribute *ObjectAttribute_New(
// ObjectAttribute_Free()
// Free the memory associated with an object attribute.
//-----------------------------------------------------------------------------
static void ObjectAttribute_Free(
udt_ObjectAttribute *self) // object attribute to free
static void ObjectAttribute_Free(udt_ObjectAttribute *self)
{
if (self->handle) {
dpiObjectAttr_release(self->handle);
self->handle = NULL;
}
Py_CLEAR(self->name);
Py_CLEAR(self->subType);
Py_CLEAR(self->type);
Py_TYPE(self)->tp_free((PyObject*) self);
}
@ -656,8 +459,7 @@ static void ObjectAttribute_Free(
// ObjectAttribute_Repr()
// Return a string representation of the object attribute.
//-----------------------------------------------------------------------------
static PyObject *ObjectAttribute_Repr(
udt_ObjectAttribute *self) // attribute to return the string for
static PyObject *ObjectAttribute_Repr(udt_ObjectAttribute *self)
{
PyObject *module, *name, *result, *format, *formatArgs;

View File

@ -12,364 +12,58 @@
// Defines the routines for handling Oracle object variables.
//-----------------------------------------------------------------------------
#include "ObjectType.c"
//-----------------------------------------------------------------------------
// Object type
//-----------------------------------------------------------------------------
typedef struct {
Variable_HEAD
dvoid **data;
dvoid **objectIndicator;
PyObject **objects;
udt_Connection *connection;
udt_ObjectType *objectType;
} udt_ObjectVar;
//-----------------------------------------------------------------------------
// Declaration of object variable functions.
//-----------------------------------------------------------------------------
static int ObjectVar_Initialize(udt_ObjectVar*, udt_Cursor*);
static void ObjectVar_Finalize(udt_ObjectVar*);
static int ObjectVar_SetValue(udt_ObjectVar*, unsigned, PyObject*);
static PyObject *ObjectVar_GetValue(udt_ObjectVar*, unsigned);
static int ObjectVar_PreDefine(udt_ObjectVar*, OCIParam*);
static int ObjectVar_PostDefine(udt_ObjectVar*);
static int ObjectVar_PostBind(udt_ObjectVar*);
static int ObjectVar_PreFetch(udt_ObjectVar*);
static int ObjectVar_IsNull(udt_ObjectVar*, unsigned);
static int ObjectVar_SetType(udt_ObjectVar*, PyObject*);
//-----------------------------------------------------------------------------
// declaration of members for Oracle objects
//-----------------------------------------------------------------------------
static PyMemberDef g_ObjectVarMembers[] = {
{ "type", T_OBJECT, offsetof(udt_ObjectVar, objectType), READONLY },
{ NULL }
};
static int ObjectVar_SetValue(udt_Variable*, uint32_t, dpiData*, PyObject*);
static PyObject *ObjectVar_GetValue(udt_Variable*, dpiData*);
//-----------------------------------------------------------------------------
// Python type declarations
//-----------------------------------------------------------------------------
static PyTypeObject g_ObjectVarType = {
PyVarObject_HEAD_INIT(NULL, 0)
"cx_Oracle.OBJECT", // tp_name
sizeof(udt_ObjectVar), // tp_basicsize
0, // tp_itemsize
0, // tp_dealloc
0, // tp_print
0, // tp_getattr
0, // tp_setattr
0, // tp_compare
0, // tp_repr
0, // tp_as_number
0, // tp_as_sequence
0, // tp_as_mapping
0, // tp_hash
0, // tp_call
0, // tp_str
0, // tp_getattro
0, // tp_setattro
0, // tp_as_buffer
Py_TPFLAGS_DEFAULT, // tp_flags
0, // tp_doc
0, // tp_traverse
0, // tp_clear
0, // tp_richcompare
0, // tp_weaklistoffset
0, // tp_iter
0, // tp_iternext
0, // tp_methods
g_ObjectVarMembers // tp_members
};
DECLARE_VARIABLE_TYPE(g_ObjectVarType, OBJECT)
//-----------------------------------------------------------------------------
// variable type declarations
//-----------------------------------------------------------------------------
static udt_VariableType vt_Object = {
(InitializeProc) ObjectVar_Initialize,
(FinalizeProc) ObjectVar_Finalize,
(PreDefineProc) ObjectVar_PreDefine,
(PostDefineProc) ObjectVar_PostDefine,
(PostBindProc) ObjectVar_PostBind,
(PreFetchProc) ObjectVar_PreFetch,
(IsNullProc) ObjectVar_IsNull,
(SetValueProc) ObjectVar_SetValue,
(GetValueProc) ObjectVar_GetValue,
(GetBufferSizeProc) NULL,
&g_ObjectVarType, // Python type
SQLT_NTY, // Oracle type
SQLCS_IMPLICIT, // charset form
sizeof(dvoid*), // element length
0, // is character data
0, // is variable length
0, // can be copied
0 // can be in array
DPI_ORACLE_TYPE_OBJECT, // Oracle type
DPI_NATIVE_TYPE_OBJECT, // native type
0 // element length
};
//-----------------------------------------------------------------------------
// ObjectVar_Initialize()
// Initialize the variable.
//-----------------------------------------------------------------------------
static int ObjectVar_Initialize(
udt_ObjectVar *self, // variable to initialize
udt_Cursor *cursor) // cursor to use
{
ub4 i;
Py_INCREF(cursor->connection);
self->connection = cursor->connection;
self->objectType = NULL;
self->objectIndicator =
PyMem_Malloc(self->allocatedElements * sizeof(dvoid*));
if (!self->objectIndicator) {
PyErr_NoMemory();
return -1;
}
self->objects = PyMem_Malloc(self->allocatedElements * sizeof(PyObject*));
if (!self->objects) {
PyErr_NoMemory();
return -1;
}
for (i = 0; i < self->allocatedElements; i++) {
self->data[i] = NULL;
self->objectIndicator[i] = NULL;
self->objects[i] = NULL;
}
return 0;
}
//-----------------------------------------------------------------------------
// ObjectVar_Finalize()
// Prepare for variable destruction.
//-----------------------------------------------------------------------------
static void ObjectVar_Finalize(
udt_ObjectVar *self) // variable to free
{
ub4 i;
for (i = 0; i < self->allocatedElements; i++) {
if (self->objects[i])
Py_CLEAR(self->objects[i]);
else if (self->data[i])
OCIObjectFree(self->environment->handle,
self->environment->errorHandle, self->data[i],
OCI_DEFAULT);
}
Py_CLEAR(self->connection);
Py_CLEAR(self->objectType);
if (self->objectIndicator)
PyMem_Free(self->objectIndicator);
if (self->objects)
PyMem_Free(self->objects);
}
//-----------------------------------------------------------------------------
// ObjectVar_PreDefine()
// Performs additional steps required for defining objects.
//-----------------------------------------------------------------------------
static int ObjectVar_PreDefine(
udt_ObjectVar *self, // variable to set up
OCIParam *param) // parameter being defined
{
self->objectType = ObjectType_New(self->connection, param,
OCI_ATTR_TYPE_NAME);
if (!self->objectType)
return -1;
return 0;
}
//-----------------------------------------------------------------------------
// ObjectVar_PostDefine()
// Performs additional steps required for defining objects.
//-----------------------------------------------------------------------------
static int ObjectVar_PostDefine(
udt_ObjectVar *self) // variable to set up
{
sword status;
status = OCIDefineObject(self->defineHandle,
self->environment->errorHandle, self->objectType->tdo, self->data,
0, self->objectIndicator, 0);
return Environment_CheckForError(self->environment, status,
"ObjectVar_PostDefine(): define object");
}
//-----------------------------------------------------------------------------
// ObjectVar_PostBind()
// Performs additional steps required for binding objects.
//-----------------------------------------------------------------------------
static int ObjectVar_PostBind(
udt_ObjectVar *self) // variable to set up
{
sword status;
if (!self->objectType) {
PyErr_SetString(g_InterfaceErrorException,
"object type not associated with bind variable");
return -1;
}
status = OCIBindObject(self->bindHandle, self->environment->errorHandle,
self->objectType->tdo, self->data, 0, self->objectIndicator, 0);
return Environment_CheckForError(self->environment, status,
"ObjectVar_PostBind(): bind object");
}
//-----------------------------------------------------------------------------
// ObjectVar_PreFetch()
// Free objects prior to next fetch.
//-----------------------------------------------------------------------------
static int ObjectVar_PreFetch(
udt_ObjectVar *var) // variable to free
{
ub4 i;
for (i = 0; i < var->allocatedElements; i++) {
if (var->objects[i])
Py_CLEAR(var->objects[i]);
else if (var->data[i])
OCIObjectFree(var->environment->handle,
var->environment->errorHandle, var->data[i], OCI_DEFAULT);
var->data[i] = NULL;
var->objectIndicator[i] = NULL;
}
return 0;
}
//-----------------------------------------------------------------------------
// ObjectVar_IsNull()
// Returns a boolean indicating if the variable is null or not.
//-----------------------------------------------------------------------------
static int ObjectVar_IsNull(
udt_ObjectVar *self, // variable to set up
unsigned pos) // position to check
{
if (!self->objectIndicator[pos])
return 1;
return (*((OCIInd*) self->objectIndicator[pos]) == OCI_IND_NULL);
}
//-----------------------------------------------------------------------------
// ObjectVar_SetValue()
// Set the value of the variable.
// Set the value of the variable. Only cx_Oracle.Object values are permitted.
//-----------------------------------------------------------------------------
static int ObjectVar_SetValue(
udt_ObjectVar *self, // variable to determine value for
unsigned pos, // array position
PyObject *value) // value to set
static int ObjectVar_SetValue(udt_Variable *self, uint32_t pos, dpiData *data,
PyObject *value)
{
udt_Object *object;
udt_Object *obj;
// only cx_Oracle.Object values are permitted and the types must match
// if the variable doesn't have a type yet, assign it
if (Py_TYPE(value) != &g_ObjectType) {
PyErr_SetString(PyExc_TypeError, "expecting cx_Oracle.Object");
return -1;
}
object = (udt_Object*) value;
if (!self->objectType) {
Py_INCREF(object->objectType);
self->objectType = object->objectType;
} else if (object->objectType->tdo != self->objectType->tdo) {
PyErr_SetString(PyExc_TypeError,
"expecting same type as the variable itself");
return -1;
}
// eliminate prior value, if needed
if (self->objects[pos])
Py_CLEAR(self->objects[pos]);
else OCIObjectFree(self->environment->handle,
self->environment->errorHandle, self->data[pos], OCI_DEFAULT);
// set new value
Py_INCREF(value);
self->objects[pos] = value;
self->data[pos] = object->instance;
self->objectIndicator[pos] = object->indicator;
obj = (udt_Object*) value;
if (dpiVar_setFromObject(self->handle, pos, obj->handle) < 0)
return Error_RaiseAndReturnInt();
return 0;
}
//-----------------------------------------------------------------------------
// ObjectVar_GetValue()
// Returns the value stored at the given array position.
//-----------------------------------------------------------------------------
static PyObject *ObjectVar_GetValue(
udt_ObjectVar *self, // variable to determine value for
unsigned pos) // array position
static PyObject *ObjectVar_GetValue(udt_Variable *self, dpiData *data)
{
PyObject *obj;
// create the object, if needed; for collections, return a list, not the
// object itself
if (!self->objects[pos]) {
obj = Object_New(self->objectType, self->data[pos],
self->objectIndicator[pos], 1);
if (!obj)
return NULL;
self->objects[pos] = obj;
}
Py_INCREF(self->objects[pos]);
return self->objects[pos];
}
//-----------------------------------------------------------------------------
// ObjectVar_SetType()
// Internal method used to set the type when creating an object variable.
// This will also create the object instances.
//-----------------------------------------------------------------------------
static int ObjectVar_SetType(
udt_ObjectVar *self, // variable to initialize the type
PyObject *typeNameObj) // value to set
{
dvoid *instance, *indicator;
sword status;
ub4 i;
// get the object type from the name
self->objectType = ObjectType_NewByName(self->connection, typeNameObj);
if (!self->objectType)
return -1;
// initialize the object instances
for (i = 0; i < self->allocatedElements; i++) {
// create the object instance
status = OCIObjectNew(self->connection->environment->handle,
self->connection->environment->errorHandle,
self->connection->handle, self->objectType->typeCode,
self->objectType->tdo, NULL, OCI_DURATION_SESSION, TRUE,
&instance);
if (Environment_CheckForError(self->connection->environment, status,
"ObjectVar_SetType(): create object instance") < 0)
return -1;
self->data[i] = instance;
// get the null indicator structure
status = OCIObjectGetInd(self->connection->environment->handle,
self->connection->environment->errorHandle, instance,
&indicator);
if (Environment_CheckForError(self->connection->environment, status,
"ObjectVar_SetType(): get indicator structure") < 0)
return -1;
*((OCIInd*) indicator) = OCI_IND_NULL;
self->objectIndicator[i] = indicator;
}
return 0;
return Object_New(self->objectType, data->value.asObject, 1);
}

View File

@ -17,31 +17,20 @@
//-----------------------------------------------------------------------------
typedef struct {
PyObject_HEAD
OCISPool *handle;
ub4 minSessions;
ub4 maxSessions;
ub4 sessionIncrement;
ub4 cacheSize;
dpiPool *handle;
uint32_t minSessions;
uint32_t maxSessions;
uint32_t sessionIncrement;
uint32_t cacheSize;
dpiEncodingInfo encodingInfo;
int homogeneous;
int externalAuth;
PyObject *name;
PyObject *username;
PyObject *dsn;
udt_Environment *environment;
PyObject *name;
PyTypeObject *connectionType;
} udt_SessionPool;
//-----------------------------------------------------------------------------
// constants for the OCI attributes
//-----------------------------------------------------------------------------
static ub4 gc_OpenAttribute = OCI_ATTR_SPOOL_OPEN_COUNT;
static ub4 gc_BusyAttribute = OCI_ATTR_SPOOL_BUSY_COUNT;
static ub4 gc_TimeoutAttribute = OCI_ATTR_SPOOL_TIMEOUT;
static ub4 gc_GetModeAttribute = OCI_ATTR_SPOOL_GETMODE;
#if ORACLE_VERSION_HEX >= ORACLE_VERSION(12, 1)
static ub4 gc_MaxLifetimeAttribute = OCI_ATTR_SPOOL_MAX_LIFETIME_SESSION;
#endif
//-----------------------------------------------------------------------------
// functions for the Python type "SessionPool"
//-----------------------------------------------------------------------------
@ -50,9 +39,18 @@ static int SessionPool_Init(udt_SessionPool*, PyObject*, PyObject*);
static void SessionPool_Free(udt_SessionPool*);
static PyObject *SessionPool_Acquire(udt_SessionPool*, PyObject*, PyObject*);
static PyObject *SessionPool_Drop(udt_SessionPool*, PyObject*);
static PyObject *SessionPool_Release(udt_SessionPool*, PyObject*);
static PyObject *SessionPool_GetOCIAttr(udt_SessionPool*, ub4*);
static int SessionPool_SetOCIAttr(udt_SessionPool*, PyObject*, ub4*);
static PyObject *SessionPool_Release(udt_SessionPool*, PyObject*, PyObject*);
static PyObject *SessionPool_GetBusyCount(udt_SessionPool*, void*);
static PyObject *SessionPool_GetGetMode(udt_SessionPool*, void*);
static PyObject *SessionPool_GetMaxLifetimeSession(udt_SessionPool*, void*);
static PyObject *SessionPool_GetOpenCount(udt_SessionPool*, void*);
static PyObject *SessionPool_GetStmtCacheSize(udt_SessionPool*, void*);
static PyObject *SessionPool_GetTimeout(udt_SessionPool*, void*);
static int SessionPool_SetGetMode(udt_SessionPool*, PyObject*, void*);
static int SessionPool_SetMaxLifetimeSession(udt_SessionPool*, PyObject*,
void*);
static int SessionPool_SetStmtCacheSize(udt_SessionPool*, PyObject*, void*);
static int SessionPool_SetTimeout(udt_SessionPool*, PyObject*, void*);
//-----------------------------------------------------------------------------
@ -62,7 +60,8 @@ static PyMethodDef g_SessionPoolMethods[] = {
{ "acquire", (PyCFunction) SessionPool_Acquire,
METH_VARARGS | METH_KEYWORDS },
{ "drop", (PyCFunction) SessionPool_Drop, METH_VARARGS },
{ "release", (PyCFunction) SessionPool_Release, METH_VARARGS },
{ "release", (PyCFunction) SessionPool_Release,
METH_VARARGS | METH_KEYWORDS },
{ NULL }
};
@ -88,16 +87,16 @@ static PyMemberDef g_SessionPoolMembers[] = {
// declaration of calculated members for Python type "SessionPool"
//-----------------------------------------------------------------------------
static PyGetSetDef g_SessionPoolCalcMembers[] = {
{ "opened", (getter) SessionPool_GetOCIAttr, 0, 0, &gc_OpenAttribute },
{ "busy", (getter) SessionPool_GetOCIAttr, 0, 0, &gc_BusyAttribute },
{ "timeout", (getter) SessionPool_GetOCIAttr,
(setter) SessionPool_SetOCIAttr, 0, &gc_TimeoutAttribute },
{ "getmode", (getter) SessionPool_GetOCIAttr,
(setter) SessionPool_SetOCIAttr, 0, &gc_GetModeAttribute },
#if ORACLE_VERSION_HEX >= ORACLE_VERSION(12, 1)
{ "max_lifetime_session", (getter) SessionPool_GetOCIAttr,
(setter) SessionPool_SetOCIAttr, 0, &gc_MaxLifetimeAttribute },
#endif
{ "opened", (getter) SessionPool_GetOpenCount, 0, 0, 0 },
{ "busy", (getter) SessionPool_GetBusyCount, 0, 0, 0 },
{ "timeout", (getter) SessionPool_GetTimeout,
(setter) SessionPool_SetTimeout, 0, 0 },
{ "getmode", (getter) SessionPool_GetGetMode,
(setter) SessionPool_SetGetMode, 0, 0 },
{ "max_lifetime_session", (getter) SessionPool_GetMaxLifetimeSession,
(setter) SessionPool_SetMaxLifetimeSession, 0, 0 },
{ "stmtcachesize", (getter) SessionPool_GetStmtCacheSize,
(setter) SessionPool_SetStmtCacheSize, 0, 0 },
{ NULL }
};
@ -158,10 +157,8 @@ static PyTypeObject g_SessionPoolType = {
// SessionPool_New()
// Create a new session pool object.
//-----------------------------------------------------------------------------
static PyObject *SessionPool_New(
PyTypeObject *type, // type object
PyObject *args, // arguments
PyObject *keywordArgs) // keyword arguments
static PyObject *SessionPool_New(PyTypeObject *type, PyObject *args,
PyObject *keywordArgs)
{
udt_SessionPool *newObject;
@ -178,43 +175,42 @@ static PyObject *SessionPool_New(
// SessionPool_Init()
// Initialize the session pool object.
//-----------------------------------------------------------------------------
static int SessionPool_Init(
udt_SessionPool *self, // session pool object
PyObject *args, // arguments
PyObject *keywordArgs) // keyword arguments
static int SessionPool_Init(udt_SessionPool *self, PyObject *args,
PyObject *keywordArgs)
{
udt_Buffer userNameBuffer, passwordBuffer, dsnBuffer, editionBuffer;
PyObject *threadedObj, *eventsObj, *homogeneousObj, *passwordObj;
unsigned minSessions, maxSessions, sessionIncrement;
int threaded, events, homogeneous, externalAuth;
udt_Buffer username, password, dsn;
uint32_t minSessions, maxSessions, sessionIncrement;
PyObject *externalAuthObj, *editionObj;
dpiCommonCreateParams dpiCommonParams;
dpiPoolCreateParams dpiCreateParams;
PyTypeObject *connectionType;
char *encoding, *nencoding;
PyObject *externalAuthObj;
unsigned poolNameLength;
const char *poolName;
sword status;
ub4 poolMode;
ub1 getMode;
const char *encoding;
int status, temp;
// define keyword arguments
static char *keywordList[] = { "user", "password", "dsn", "min", "max",
"increment", "connectiontype", "threaded", "getmode", "events",
"homogeneous", "externalauth", "encoding", "nencoding", NULL };
"homogeneous", "externalauth", "encoding", "nencoding", "edition",
NULL };
// parse arguments and keywords
homogeneous = 1;
externalAuthObj = NULL;
encoding = nencoding = NULL;
threaded = events = externalAuth = 0;
externalAuthObj = editionObj = NULL;
threadedObj = eventsObj = homogeneousObj = passwordObj = NULL;
connectionType = &g_ConnectionType;
getMode = OCI_SPOOL_ATTRVAL_NOWAIT;
if (!PyArg_ParseTupleAndKeywords(args, keywordArgs, "O!O!O!iii|OObOOOss",
if (dpiContext_initCommonCreateParams(g_DpiContext, &dpiCommonParams) < 0)
return Error_RaiseAndReturnInt();
dpiCommonParams.driverName = DRIVER_NAME;
dpiCommonParams.driverNameLength = strlen(dpiCommonParams.driverName);
if (dpiContext_initPoolCreateParams(g_DpiContext, &dpiCreateParams) < 0)
return Error_RaiseAndReturnInt();
if (!PyArg_ParseTupleAndKeywords(args, keywordArgs, "O!O!O!iii|OObOOOssO",
keywordList, cxString_Type, &self->username,
cxString_Type, &passwordObj, cxString_Type, &self->dsn,
&minSessions, &maxSessions, &sessionIncrement, &connectionType,
&threadedObj, &getMode, &eventsObj, &homogeneousObj,
&externalAuthObj, &encoding, &nencoding))
&threadedObj, &dpiCreateParams.getMode, &eventsObj,
&homogeneousObj, &externalAuthObj, &dpiCommonParams.encoding,
&dpiCommonParams.nencoding, &editionObj))
return -1;
if (!PyType_Check(connectionType)) {
PyErr_SetString(g_ProgrammingErrorException,
@ -226,27 +222,18 @@ static int SessionPool_Init(
"connectiontype must be a subclass of Connection");
return -1;
}
if (threadedObj) {
threaded = PyObject_IsTrue(threadedObj);
if (threaded < 0)
return -1;
}
if (eventsObj) {
events = PyObject_IsTrue(eventsObj);
if (events < 0)
return -1;
}
if (externalAuthObj) {
externalAuth = PyObject_IsTrue(externalAuthObj);
if (externalAuth < 0)
return -1;
homogeneous = 0;
}
if (homogeneousObj) {
homogeneous = PyObject_IsTrue(homogeneousObj);
if (homogeneous < 0)
return -1;
}
if (GetBooleanValue(threadedObj, 0, &temp) < 0)
return -1;
if (temp)
dpiCommonParams.createMode |= DPI_MODE_CREATE_THREADED;
if (GetBooleanValue(eventsObj, 0, &temp) < 0)
return -1;
if (temp)
dpiCommonParams.createMode |= DPI_MODE_CREATE_EVENTS;
if (GetBooleanValue(externalAuthObj, 0, &dpiCreateParams.externalAuth) < 0)
return -1;
if (GetBooleanValue(homogeneousObj, 1, &dpiCreateParams.homogeneous) < 0)
return -1;
// initialize the object's members
Py_INCREF(connectionType);
@ -256,70 +243,58 @@ static int SessionPool_Init(
self->minSessions = minSessions;
self->maxSessions = maxSessions;
self->sessionIncrement = sessionIncrement;
self->homogeneous = homogeneous;
self->externalAuth = externalAuth;
self->homogeneous = dpiCreateParams.homogeneous;
self->externalAuth = dpiCreateParams.externalAuth;
// set up the environment
self->environment = Environment_NewFromScratch(threaded, events, encoding,
nencoding);
if (!self->environment)
// populate parameters
encoding = GetAdjustedEncoding(dpiCommonParams.encoding);
if (cxBuffer_FromObject(&userNameBuffer, self->username, encoding) < 0)
return -1;
// create the session pool handle
status = OCIHandleAlloc(self->environment->handle, (dvoid**) &self->handle,
OCI_HTYPE_SPOOL, 0, 0);
if (Environment_CheckForError(self->environment, status,
"SessionPool_New(): allocate handle") < 0)
return -1;
// prepare pool mode
poolMode = OCI_SPC_STMTCACHE;
if (self->homogeneous)
poolMode |= OCI_SPC_HOMOGENEOUS;
// create the session pool
if (cxBuffer_FromObject(&username, self->username,
self->environment->encoding) < 0)
return -1;
if (cxBuffer_FromObject(&password, passwordObj,
self->environment->encoding) < 0) {
cxBuffer_Clear(&username);
if (cxBuffer_FromObject(&passwordBuffer, passwordObj, encoding) < 0) {
cxBuffer_Clear(&userNameBuffer);
return -1;
}
if (cxBuffer_FromObject(&dsn, self->dsn,
self->environment->encoding) < 0) {
cxBuffer_Clear(&username);
cxBuffer_Clear(&password);
if (cxBuffer_FromObject(&dsnBuffer, self->dsn, encoding) < 0) {
cxBuffer_Clear(&userNameBuffer);
cxBuffer_Clear(&passwordBuffer);
return -1;
}
if (cxBuffer_FromObject(&editionBuffer, editionObj, encoding) < 0) {
cxBuffer_Clear(&userNameBuffer);
cxBuffer_Clear(&passwordBuffer);
cxBuffer_Clear(&dsnBuffer);
return -1;
}
dpiCreateParams.minSessions = minSessions;
dpiCreateParams.maxSessions = maxSessions;
dpiCreateParams.sessionIncrement = sessionIncrement;
// create pool
Py_BEGIN_ALLOW_THREADS
status = OCISessionPoolCreate(self->environment->handle,
self->environment->errorHandle, self->handle,
(OraText**) &poolName, &poolNameLength, (OraText*) dsn.ptr,
(ub4) dsn.size, minSessions, maxSessions, sessionIncrement,
(OraText*) username.ptr, (ub4) username.size,
(OraText*) password.ptr, (ub4) password.size, poolMode);
status = dpiPool_create(g_DpiContext, userNameBuffer.ptr,
userNameBuffer.size, passwordBuffer.ptr, passwordBuffer.size,
dsnBuffer.ptr, dsnBuffer.size, &dpiCommonParams, &dpiCreateParams,
&self->handle);
Py_END_ALLOW_THREADS
cxBuffer_Clear(&username);
cxBuffer_Clear(&password);
cxBuffer_Clear(&dsn);
if (Environment_CheckForError(self->environment, status,
"SessionPool_New(): create pool") < 0)
return -1;
cxBuffer_Clear(&userNameBuffer);
cxBuffer_Clear(&passwordBuffer);
cxBuffer_Clear(&dsnBuffer);
cxBuffer_Clear(&editionBuffer);
if (status < 0)
return Error_RaiseAndReturnInt();
// create the string for the pool name
self->name = cxString_FromEncodedString(poolName, poolNameLength,
self->environment->encoding);
// get encodings and name
if (dpiPool_getEncodingInfo(self->handle, &self->encodingInfo) < 0)
return Error_RaiseAndReturnInt();
self->encodingInfo.encoding =
GetAdjustedEncoding(self->encodingInfo.encoding);
self->encodingInfo.nencoding =
GetAdjustedEncoding(self->encodingInfo.nencoding);
self->name = cxString_FromEncodedString(dpiCreateParams.outPoolName,
dpiCreateParams.outPoolNameLength, self->encodingInfo.encoding);
if (!self->name)
return -1;
// set the mode on the pool
status = OCIAttrSet(self->handle, OCI_HTYPE_SPOOL, (dvoid*) &getMode, 0,
OCI_ATTR_SPOOL_GETMODE, self->environment->errorHandle);
if (Environment_CheckForError(self->environment, status,
"SessionPool_New(): set wait mode") < 0)
return -1;
return 0;
}
@ -328,70 +303,45 @@ static int SessionPool_Init(
// SessionPool_Free()
// Deallocate the session pool.
//-----------------------------------------------------------------------------
static void SessionPool_Free(
udt_SessionPool *self) // session pool
static void SessionPool_Free(udt_SessionPool *self)
{
if (self->handle) {
OCISessionPoolDestroy(self->handle, self->environment->errorHandle,
OCI_SPD_FORCE);
OCIHandleFree(self->handle, OCI_HTYPE_SPOOL);
dpiPool_release(self->handle);
self->handle = NULL;
}
Py_XDECREF(self->name);
Py_XDECREF(self->environment);
Py_XDECREF(self->username);
Py_XDECREF(self->dsn);
Py_CLEAR(self->username);
Py_CLEAR(self->dsn);
Py_CLEAR(self->name);
Py_TYPE(self)->tp_free((PyObject*) self);
}
//-----------------------------------------------------------------------------
// SessionPool_IsConnected()
// Determines if the session pool object is connected to the database. If
// not, a Python exception is raised.
//-----------------------------------------------------------------------------
static int SessionPool_IsConnected(
udt_SessionPool *self) // session pool
{
if (!self->handle) {
PyErr_SetString(g_InterfaceErrorException, "not connected");
return -1;
}
return 0;
}
//-----------------------------------------------------------------------------
// SessionPool_Acquire()
// Create a new connection within the session pool.
//-----------------------------------------------------------------------------
static PyObject *SessionPool_Acquire(
udt_SessionPool *self, // session pool
PyObject *args, // arguments
PyObject *keywordArgs) // keyword arguments
static PyObject *SessionPool_Acquire(udt_SessionPool *self, PyObject *args,
PyObject *keywordArgs)
{
static char *keywordList[] = { "user", "password", "cclass", "purity",
NULL };
PyObject *createKeywordArgs, *result, *cclassObj, *purityObj;
"tag", "matchanytag", NULL };
PyObject *createKeywordArgs, *result, *cclassObj, *purityObj, *tagObj;
unsigned usernameLength, passwordLength;
char *username, *password;
PyObject *matchAnyTagObj;
// parse arguments
username = NULL;
password = NULL;
if (!PyArg_ParseTupleAndKeywords(args, keywordArgs, "|s#s#OO", keywordList,
&username, &usernameLength, &password, &passwordLength, &cclassObj,
&purityObj))
if (!PyArg_ParseTupleAndKeywords(args, keywordArgs, "|s#s#OOOO",
keywordList, &username, &usernameLength, &password,
&passwordLength, &cclassObj, &purityObj, &tagObj, &matchAnyTagObj))
return NULL;
if (self->homogeneous && (username || password)) {
if (self->homogeneous && username) {
PyErr_SetString(g_ProgrammingErrorException,
"pool is homogeneous. Proxy authentication is not possible.");
return NULL;
}
// make sure session pool is connected
if (SessionPool_IsConnected(self) < 0)
return NULL;
// create arguments
if (keywordArgs)
createKeywordArgs = PyDict_Copy(keywordArgs);
@ -414,74 +364,32 @@ static PyObject *SessionPool_Acquire(
//-----------------------------------------------------------------------------
// SessionPool_InternalRelease()
// Internal method used to release a connection back to the pool in order to
// allow for the possibility of dropping the connection.
// SessionPool_Drop()
// Release a connection back to the session pool, dropping it so that a new
// connection will be created if needed.
//-----------------------------------------------------------------------------
static PyObject *SessionPool_InternalRelease(
udt_SessionPool *self, // session pool
PyObject *args, // arguments
ub4 mode) // OCI mode to use
static PyObject *SessionPool_Drop(udt_SessionPool *self, PyObject *args)
{
udt_Connection *connection;
sword status;
int status;
// connection is expected
if (!PyArg_ParseTuple(args, "O!", &g_ConnectionType, &connection))
return NULL;
// make sure session pool is connected
if (SessionPool_IsConnected(self) < 0)
return NULL;
if (connection->sessionPool != self) {
PyErr_SetString(g_ProgrammingErrorException,
"connection not acquired with this session pool");
return NULL;
}
// attempt a rollback but if dropping the connection from the pool
// ignore the error
Py_BEGIN_ALLOW_THREADS
status = OCITransRollback(connection->handle,
connection->environment->errorHandle, OCI_DEFAULT);
Py_END_ALLOW_THREADS
if (Environment_CheckForError(connection->environment, status,
"SessionPool_Release(): rollback") < 0) {
if (mode != OCI_SESSRLS_DROPSESS)
return NULL;
PyErr_Clear();
}
// release the connection
Py_BEGIN_ALLOW_THREADS
status = OCISessionRelease(connection->handle,
connection->environment->errorHandle, NULL, 0, mode);
status = dpiConn_close(connection->handle, DPI_MODE_CONN_CLOSE_DROP, NULL,
0);
Py_END_ALLOW_THREADS
if (Environment_CheckForError(connection->environment, status,
"SessionPool_Release(): release session") < 0)
return NULL;
if (status < 0)
return Error_RaiseAndReturnNull();
// ensure that the connection behaves as closed
Py_DECREF(connection->sessionPool);
connection->sessionPool = NULL;
// mark connection as closed
Py_CLEAR(connection->sessionPool);
dpiConn_release(connection->handle);
connection->handle = NULL;
connection->release = 0;
Py_INCREF(Py_None);
return Py_None;
}
//-----------------------------------------------------------------------------
// SessionPool_Drop()
// Release a connection back to the session pool, dropping it so that a new
// connection will be created if needed.
//-----------------------------------------------------------------------------
static PyObject *SessionPool_Drop(
udt_SessionPool *self, // session pool
PyObject *args) // arguments
{
return SessionPool_InternalRelease(self, args, OCI_SESSRLS_DROPSESS);
Py_RETURN_NONE;
}
@ -489,70 +397,205 @@ static PyObject *SessionPool_Drop(
// SessionPool_Release()
// Release a connection back to the session pool.
//-----------------------------------------------------------------------------
static PyObject *SessionPool_Release(
udt_SessionPool *self, // session pool
PyObject *args) // arguments
static PyObject *SessionPool_Release(udt_SessionPool *self, PyObject *args,
PyObject *keywordArgs)
{
return SessionPool_InternalRelease(self, args, OCI_DEFAULT);
static char *keywordList[] = { "connection", "tag", NULL };
udt_Connection *connection;
dpiConnCloseMode mode;
udt_Buffer tagBuffer;
PyObject *tagObj;
int status;
// parse arguments
tagObj = NULL;
if (!PyArg_ParseTupleAndKeywords(args, keywordArgs, "O!|O",
keywordList, &g_ConnectionType, &connection, &tagObj))
return NULL;
if (cxBuffer_FromObject(&tagBuffer, tagObj,
self->encodingInfo.encoding) < 0)
return NULL;
mode = (tagBuffer.size > 0) ? DPI_MODE_CONN_CLOSE_RETAG :
DPI_MODE_CONN_CLOSE_DEFAULT;
Py_BEGIN_ALLOW_THREADS
status = dpiConn_close(connection->handle, mode, (char*) tagBuffer.ptr,
tagBuffer.size);
Py_END_ALLOW_THREADS
cxBuffer_Clear(&tagBuffer);
if (status < 0)
return Error_RaiseAndReturnNull();
// mark connection as closed
Py_CLEAR(connection->sessionPool);
dpiConn_release(connection->handle);
connection->handle = NULL;
Py_RETURN_NONE;
}
//-----------------------------------------------------------------------------
// SessionPool_GetOCIAttr()
// Return the value for the OCI attribute.
// SessionPool_GetAttribute()
// Return the value for the attribute.
//-----------------------------------------------------------------------------
static PyObject *SessionPool_GetOCIAttr(
udt_SessionPool *self, // session pool
ub4 *attribute) // OCI attribute type
static PyObject *SessionPool_GetAttribute(udt_SessionPool *self,
int (*func)(dpiPool *pool, uint32_t *value))
{
sword status;
ub4 value;
uint32_t value;
// make sure session pool is connected
if (SessionPool_IsConnected(self) < 0)
return NULL;
if ((*func)(self->handle, &value) < 0)
return Error_RaiseAndReturnNull();
#if PY_MAJOR_VERSION >= 3
return PyInt_FromUnsignedLong(value);
#else
return PyInt_FromLong(value);
#endif
}
// get the value from the OCI
status = OCIAttrGet(self->handle, OCI_HTYPE_SPOOL, &value, 0, *attribute,
self->environment->errorHandle);
if (Environment_CheckForError(self->environment, status,
"SessionPool_GetOCIAttr()") < 0)
return NULL;
if (*attribute == OCI_ATTR_SPOOL_GETMODE)
return PyInt_FromLong((ub1) value);
//-----------------------------------------------------------------------------
// SessionPool_SetAttribute()
// Set the value of the OCI attribute.
//-----------------------------------------------------------------------------
static int SessionPool_SetAttribute(udt_SessionPool *self, PyObject *value,
int (*func)(dpiPool *pool, uint32_t value))
{
uint32_t cValue;
if (!PyInt_Check(value)) {
PyErr_SetString(PyExc_TypeError, "value must be an integer");
return -1;
}
#if PY_MAJOR_VERSION >= 3
cValue = PyInt_AsUnsignedLong(value);
#else
cValue = PyInt_AsLong(value);
#endif
if (PyErr_Occurred())
return -1;
if ((*func)(self->handle, cValue) < 0)
return Error_RaiseAndReturnInt();
return 0;
}
//-----------------------------------------------------------------------------
// SessionPool_GetBusyCount()
// Return the number of busy connections in the session pool.
//-----------------------------------------------------------------------------
static PyObject *SessionPool_GetBusyCount(udt_SessionPool *pool, void *unused)
{
return SessionPool_GetAttribute(pool, dpiPool_getBusyCount);
}
//-----------------------------------------------------------------------------
// SessionPool_GetGetMode()
// Return the "get" mode for connections in the session pool.
//-----------------------------------------------------------------------------
static PyObject *SessionPool_GetGetMode(udt_SessionPool *pool, void *unused)
{
dpiPoolGetMode value;
if (dpiPool_getGetMode(pool->handle, &value) < 0)
return Error_RaiseAndReturnNull();
return PyInt_FromLong(value);
}
//-----------------------------------------------------------------------------
// SessionPool_SetOCIAttr()
// Set the value of the OCI attribute.
// SessionPool_GetMaxLifetimeSession()
// Return the maximum lifetime session of connections in the session pool.
//-----------------------------------------------------------------------------
static int SessionPool_SetOCIAttr(
udt_SessionPool *self, // session pool
PyObject *value, // value to set
ub4 *attribute) // OCI attribute type
static PyObject *SessionPool_GetMaxLifetimeSession(udt_SessionPool *pool,
void *unused)
{
ub4 ociValue;
sword status;
return SessionPool_GetAttribute(pool, dpiPool_getMaxLifetimeSession);
}
// make sure session pool is connected
if (SessionPool_IsConnected(self) < 0)
return -1;
// set the value in the OCI
if (!PyInt_Check(value)) {
PyErr_SetString(PyExc_TypeError, "value must be an integer");
return -1;
}
ociValue = PyInt_AsLong(value);
//-----------------------------------------------------------------------------
// SessionPool_GetOpenCount()
// Return the number of open connections in the session pool.
//-----------------------------------------------------------------------------
static PyObject *SessionPool_GetOpenCount(udt_SessionPool *pool, void *unused)
{
return SessionPool_GetAttribute(pool, dpiPool_getOpenCount);
}
//-----------------------------------------------------------------------------
// SessionPool_GetStmtCacheSize()
// Return the size of the statement cache to use in connections that are
// acquired from the pool.
//-----------------------------------------------------------------------------
static PyObject *SessionPool_GetStmtCacheSize(udt_SessionPool *pool,
void *unused)
{
return SessionPool_GetAttribute(pool, dpiPool_getStmtCacheSize);
}
//-----------------------------------------------------------------------------
// SessionPool_GetTimeout()
// Return the timeout for connections in the session pool.
//-----------------------------------------------------------------------------
static PyObject *SessionPool_GetTimeout(udt_SessionPool *pool, void *unused)
{
return SessionPool_GetAttribute(pool, dpiPool_getTimeout);
}
//-----------------------------------------------------------------------------
// SessionPool_SetGetMode()
// Set the "get" mode for connections in the session pool.
//-----------------------------------------------------------------------------
static int SessionPool_SetGetMode(udt_SessionPool *pool, PyObject *value,
void *unused)
{
dpiPoolGetMode cValue;
cValue = PyInt_AsLong(value);
if (PyErr_Occurred())
return -1;
status = OCIAttrSet(self->handle, OCI_HTYPE_SPOOL, &ociValue, 0,
*attribute, self->environment->errorHandle);
if (Environment_CheckForError(self->environment, status,
"SessionPool_SetOCIAttr()") < 0)
return -1;
if (dpiPool_setGetMode(pool->handle, cValue) < 0)
return Error_RaiseAndReturnInt();
return 0;
}
//-----------------------------------------------------------------------------
// SessionPool_SetMaxLifetimeSession()
// Set the maximum lifetime for connections in the session pool.
//-----------------------------------------------------------------------------
static int SessionPool_SetMaxLifetimeSession(udt_SessionPool *pool,
PyObject *value, void *unused)
{
return SessionPool_SetAttribute(pool, value,
dpiPool_setMaxLifetimeSession);
}
//-----------------------------------------------------------------------------
// SessionPool_SetStmtCacheSize()
// Set the default size of the statement cache used for connections that are
// acquired from the pool.
//-----------------------------------------------------------------------------
static int SessionPool_SetStmtCacheSize(udt_SessionPool *pool,
PyObject *value, void *unused)
{
return SessionPool_SetAttribute(pool, value, dpiPool_setStmtCacheSize);
}
//-----------------------------------------------------------------------------
// SessionPool_SetTimeout()
// Set the timeout for connections in the session pool.
//-----------------------------------------------------------------------------
static int SessionPool_SetTimeout(udt_SessionPool *pool, PyObject *value,
void *unused)
{
return SessionPool_SetAttribute(pool, value, dpiPool_setTimeout);
}

View File

@ -12,373 +12,113 @@
// Defines the routines specific to the string type.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// String type
//-----------------------------------------------------------------------------
typedef struct {
Variable_HEAD
char *data;
} udt_StringVar;
//-----------------------------------------------------------------------------
// Declaration of string variable functions.
//-----------------------------------------------------------------------------
static int StringVar_Initialize(udt_StringVar*, udt_Cursor*);
static int StringVar_SetValue(udt_StringVar*, unsigned, PyObject*);
static PyObject *StringVar_GetValue(udt_StringVar*, unsigned);
static int StringVar_PostDefine(udt_StringVar*);
static ub4 StringVar_GetBufferSize(udt_StringVar*);
static PyObject *RowidVar_GetValue(udt_Variable*, dpiData*);
static PyObject *StringVar_GetValue(udt_Variable*, dpiData*);
static int RowidVar_SetValue(udt_Variable*, uint32_t, dpiData*, PyObject*);
//-----------------------------------------------------------------------------
// Python type declarations
//-----------------------------------------------------------------------------
static PyTypeObject g_StringVarType = {
PyVarObject_HEAD_INIT(NULL, 0)
"cx_Oracle.STRING", // tp_name
sizeof(udt_StringVar), // tp_basicsize
0, // tp_itemsize
0, // tp_dealloc
0, // tp_print
0, // tp_getattr
0, // tp_setattr
0, // tp_compare
0, // tp_repr
0, // tp_as_number
0, // tp_as_sequence
0, // tp_as_mapping
0, // tp_hash
0, // tp_call
0, // tp_str
0, // tp_getattro
0, // tp_setattro
0, // tp_as_buffer
Py_TPFLAGS_DEFAULT, // tp_flags
0 // tp_doc
};
static PyTypeObject g_NCharVarType = {
PyVarObject_HEAD_INIT(NULL, 0)
"cx_Oracle.NCHAR", // tp_name
sizeof(udt_StringVar), // tp_basicsize
0, // tp_itemsize
0, // tp_dealloc
0, // tp_print
0, // tp_getattr
0, // tp_setattr
0, // tp_compare
0, // tp_repr
0, // tp_as_number
0, // tp_as_sequence
0, // tp_as_mapping
0, // tp_hash
0, // tp_call
0, // tp_str
0, // tp_getattro
0, // tp_setattro
0, // tp_as_buffer
Py_TPFLAGS_DEFAULT, // tp_flags
0 // tp_doc
};
static PyTypeObject g_FixedCharVarType = {
PyVarObject_HEAD_INIT(NULL, 0)
"cx_Oracle.FIXED_CHAR", // tp_name
sizeof(udt_StringVar), // tp_basicsize
0, // tp_itemsize
0, // tp_dealloc
0, // tp_print
0, // tp_getattr
0, // tp_setattr
0, // tp_compare
0, // tp_repr
0, // tp_as_number
0, // tp_as_sequence
0, // tp_as_mapping
0, // tp_hash
0, // tp_call
0, // tp_str
0, // tp_getattro
0, // tp_setattro
0, // tp_as_buffer
Py_TPFLAGS_DEFAULT, // tp_flags
0 // tp_doc
};
static PyTypeObject g_FixedNCharVarType = {
PyVarObject_HEAD_INIT(NULL, 0)
"cx_Oracle.FIXED_NCHAR", // tp_name
sizeof(udt_StringVar), // tp_basicsize
0, // tp_itemsize
0, // tp_dealloc
0, // tp_print
0, // tp_getattr
0, // tp_setattr
0, // tp_compare
0, // tp_repr
0, // tp_as_number
0, // tp_as_sequence
0, // tp_as_mapping
0, // tp_hash
0, // tp_call
0, // tp_str
0, // tp_getattro
0, // tp_setattro
0, // tp_as_buffer
Py_TPFLAGS_DEFAULT, // tp_flags
0 // tp_doc
};
static PyTypeObject g_RowidVarType = {
PyVarObject_HEAD_INIT(NULL, 0)
"cx_Oracle.ROWID", // tp_name
sizeof(udt_StringVar), // tp_basicsize
0, // tp_itemsize
0, // tp_dealloc
0, // tp_print
0, // tp_getattr
0, // tp_setattr
0, // tp_compare
0, // tp_repr
0, // tp_as_number
0, // tp_as_sequence
0, // tp_as_mapping
0, // tp_hash
0, // tp_call
0, // tp_str
0, // tp_getattro
0, // tp_setattro
0, // tp_as_buffer
Py_TPFLAGS_DEFAULT, // tp_flags
0 // tp_doc
};
static PyTypeObject g_BinaryVarType = {
PyVarObject_HEAD_INIT(NULL, 0)
"cx_Oracle.BINARY", // tp_name
sizeof(udt_StringVar), // tp_basicsize
0, // tp_itemsize
0, // tp_dealloc
0, // tp_print
0, // tp_getattr
0, // tp_setattr
0, // tp_compare
0, // tp_repr
0, // tp_as_number
0, // tp_as_sequence
0, // tp_as_mapping
0, // tp_hash
0, // tp_call
0, // tp_str
0, // tp_getattro
0, // tp_setattro
0, // tp_as_buffer
Py_TPFLAGS_DEFAULT, // tp_flags
0 // tp_doc
};
DECLARE_VARIABLE_TYPE(g_StringVarType, STRING)
DECLARE_VARIABLE_TYPE(g_NCharVarType, NCHAR)
DECLARE_VARIABLE_TYPE(g_FixedCharVarType, FIXED_CHAR)
DECLARE_VARIABLE_TYPE(g_FixedNCharVarType, FIXED_NCHAR)
DECLARE_VARIABLE_TYPE(g_RowidVarType, ROWID)
DECLARE_VARIABLE_TYPE(g_BinaryVarType, BINARY)
//-----------------------------------------------------------------------------
// variable type declarations
//-----------------------------------------------------------------------------
static udt_VariableType vt_String = {
(InitializeProc) StringVar_Initialize,
(FinalizeProc) NULL,
(PreDefineProc) NULL,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) NULL,
(IsNullProc) NULL,
(SetValueProc) StringVar_SetValue,
(SetValueProc) Variable_SetValueBytes,
(GetValueProc) StringVar_GetValue,
(GetBufferSizeProc) StringVar_GetBufferSize,
&g_StringVarType, // Python type
SQLT_CHR, // Oracle type
SQLCS_IMPLICIT, // charset form
4000, // element length (default)
1, // is character data
1, // is variable length
1, // can be copied
1 // can be in array
DPI_ORACLE_TYPE_VARCHAR, // Oracle type
DPI_NATIVE_TYPE_BYTES, // native type
4000 // element length (default)
};
static udt_VariableType vt_NationalCharString = {
(InitializeProc) StringVar_Initialize,
(FinalizeProc) NULL,
(PreDefineProc) NULL,
(PostDefineProc) StringVar_PostDefine,
(PostBindProc) NULL,
(PreFetchProc) NULL,
(IsNullProc) NULL,
(SetValueProc) StringVar_SetValue,
(SetValueProc) Variable_SetValueBytes,
(GetValueProc) StringVar_GetValue,
(GetBufferSizeProc) StringVar_GetBufferSize,
&g_NCharVarType, // Python type
SQLT_CHR, // Oracle type
SQLCS_NCHAR, // charset form
4000, // element length (default)
1, // is character data
1, // is variable length
1, // can be copied
1 // can be in array
DPI_ORACLE_TYPE_NVARCHAR, // Oracle type
DPI_NATIVE_TYPE_BYTES, // native type
4000 // element length (default)
};
static udt_VariableType vt_FixedChar = {
(InitializeProc) StringVar_Initialize,
(FinalizeProc) NULL,
(PreDefineProc) NULL,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) NULL,
(IsNullProc) NULL,
(SetValueProc) StringVar_SetValue,
(SetValueProc) Variable_SetValueBytes,
(GetValueProc) StringVar_GetValue,
(GetBufferSizeProc) StringVar_GetBufferSize,
&g_FixedCharVarType, // Python type
SQLT_AFC, // Oracle type
SQLCS_IMPLICIT, // charset form
2000, // element length (default)
1, // is character data
1, // is variable length
1, // can be copied
1 // can be in array
DPI_ORACLE_TYPE_CHAR, // Oracle type
DPI_NATIVE_TYPE_BYTES, // native type
2000 // element length (default)
};
static udt_VariableType vt_FixedNationalChar = {
(InitializeProc) StringVar_Initialize,
(FinalizeProc) NULL,
(PreDefineProc) NULL,
(PostDefineProc) StringVar_PostDefine,
(PostBindProc) NULL,
(PreFetchProc) NULL,
(IsNullProc) NULL,
(SetValueProc) StringVar_SetValue,
(SetValueProc) Variable_SetValueBytes,
(GetValueProc) StringVar_GetValue,
(GetBufferSizeProc) StringVar_GetBufferSize,
&g_FixedNCharVarType, // Python type
SQLT_AFC, // Oracle type
SQLCS_NCHAR, // charset form
2000, // element length (default)
1, // is character data
1, // is variable length
1, // can be copied
1 // can be in array
DPI_ORACLE_TYPE_NCHAR, // Oracle type
DPI_NATIVE_TYPE_BYTES, // native type
2000 // element length (default)
};
static udt_VariableType vt_Rowid = {
(InitializeProc) StringVar_Initialize,
(FinalizeProc) NULL,
(PreDefineProc) NULL,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) NULL,
(IsNullProc) NULL,
(SetValueProc) StringVar_SetValue,
(GetValueProc) StringVar_GetValue,
(GetBufferSizeProc) StringVar_GetBufferSize,
(SetValueProc) RowidVar_SetValue,
(GetValueProc) RowidVar_GetValue,
&g_RowidVarType, // Python type
SQLT_CHR, // Oracle type
SQLCS_IMPLICIT, // charset form
18, // element length (default)
1, // is character data
0, // is variable length
1, // can be copied
1 // can be in array
DPI_ORACLE_TYPE_ROWID, // Oracle type
DPI_NATIVE_TYPE_ROWID, // native type
18 // element length (default)
};
static udt_VariableType vt_Binary = {
(InitializeProc) StringVar_Initialize,
(FinalizeProc) NULL,
(PreDefineProc) NULL,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) NULL,
(IsNullProc) NULL,
(SetValueProc) StringVar_SetValue,
(SetValueProc) Variable_SetValueBytes,
(GetValueProc) StringVar_GetValue,
(GetBufferSizeProc) NULL,
&g_BinaryVarType, // Python type
SQLT_BIN, // Oracle type
SQLCS_IMPLICIT, // charset form
4000, // element length (default)
0, // is character data
1, // is variable length
1, // can be copied
1 // can be in array
DPI_ORACLE_TYPE_RAW, // Oracle type
DPI_NATIVE_TYPE_BYTES, // native type
4000 // element length (default)
};
//-----------------------------------------------------------------------------
// StringVar_Initialize()
// Initialize the variable.
// RowidVar_GetValue()
// Returns the value stored at the given array position.
//-----------------------------------------------------------------------------
static int StringVar_Initialize(
udt_StringVar *var, // variable to initialize
udt_Cursor *cursor) // cursor to use
static PyObject *RowidVar_GetValue(udt_Variable *var, dpiData *data)
{
ub4 i;
uint32_t rowidLength;
const char *rowid;
var->actualLength = (ACTUAL_LENGTH_TYPE *)
PyMem_Malloc(var->allocatedElements * sizeof(ACTUAL_LENGTH_TYPE));
if (!var->actualLength) {
PyErr_NoMemory();
return -1;
}
for (i = 0; i < var->allocatedElements; i++)
var->actualLength[i] = 0;
return 0;
if (dpiRowid_getStringValue(data->value.asRowid, &rowid, &rowidLength) < 0)
return Error_RaiseAndReturnNull();
return cxString_FromEncodedString(rowid, rowidLength,
var->connection->encodingInfo.encoding);
}
//-----------------------------------------------------------------------------
// StringVar_SetValue()
// Set the value of the variable.
// RowidVar_SetValue()
// Rowid values cannot be set.
//-----------------------------------------------------------------------------
static int StringVar_SetValue(
udt_StringVar *var, // variable to set value for
unsigned pos, // array position to set
PyObject *value) // value to set
static int RowidVar_SetValue(udt_Variable *var, uint32_t pos, dpiData *data,
PyObject *value)
{
udt_Buffer buffer;
char *encoding;
// determine which encoding should be used
if (var->type->charsetForm == SQLCS_NCHAR)
encoding = var->environment->nencoding;
else encoding = var->environment->encoding;
// populate the buffer and confirm the maximum size is not exceeded
if (cxBuffer_FromObject(&buffer, value, encoding) < 0)
return -1;
// ensure that the buffer is large enough
if (buffer.size > var->bufferSize) {
if (Variable_Resize( (udt_Variable*) var,
(unsigned) buffer.numCharacters) < 0) {
cxBuffer_Clear(&buffer);
return -1;
}
}
// keep a copy of the string
var->actualLength[pos] = (ACTUAL_LENGTH_TYPE) buffer.size;
if (buffer.size)
memcpy(var->data + var->bufferSize * pos, buffer.ptr, buffer.size);
cxBuffer_Clear(&buffer);
return 0;
PyErr_SetString(g_NotSupportedErrorException,
"setting rowid variables, use a string variable instead");
return -1;
}
@ -386,54 +126,18 @@ static int StringVar_SetValue(
// StringVar_GetValue()
// Returns the value stored at the given array position.
//-----------------------------------------------------------------------------
static PyObject *StringVar_GetValue(
udt_StringVar *var, // variable to determine value for
unsigned pos) // array position
static PyObject *StringVar_GetValue(udt_Variable *var, dpiData *data)
{
char *data;
dpiBytes *bytes;
data = var->data + pos * var->bufferSize;
bytes = &data->value.asBytes;
if (var->type == &vt_Binary)
return PyBytes_FromStringAndSize(data, var->actualLength[pos]);
if (var->type == &vt_FixedNationalChar
|| var->type == &vt_NationalCharString)
return PyUnicode_Decode(data, var->actualLength[pos],
var->environment->nencoding, NULL);
return cxString_FromEncodedString(data, var->actualLength[pos],
var->environment->encoding);
}
//-----------------------------------------------------------------------------
// StringVar_PostDefine()
// Set the character set information when values are fetched from this
// variable.
//-----------------------------------------------------------------------------
static int StringVar_PostDefine(
udt_StringVar *var) // variable to initialize
{
sword status;
status = OCIAttrSet(var->defineHandle, OCI_HTYPE_DEFINE,
&var->type->charsetForm, 0, OCI_ATTR_CHARSET_FORM,
var->environment->errorHandle);
if (Environment_CheckForError(var->environment, status,
"StringVar_PostDefine(): setting charset form") < 0)
return -1;
return 0;
}
//-----------------------------------------------------------------------------
// StringVar_GetBufferSize()
// Returns the buffer size to use for the variable.
//-----------------------------------------------------------------------------
static ub4 StringVar_GetBufferSize(
udt_StringVar* self) // variable to get buffer size for
{
if (self->type->isCharacterData)
return self->size * self->environment->maxBytesPerCharacter;
return self->size;
return PyBytes_FromStringAndSize(bytes->ptr, bytes->length);
else if (var->type == &vt_FixedNationalChar ||
var->type == &vt_NationalCharString)
return PyUnicode_Decode(bytes->ptr, bytes->length, bytes->encoding,
NULL);
return cxString_FromEncodedString(bytes->ptr, bytes->length,
bytes->encoding);
}

View File

@ -17,24 +17,22 @@
//-----------------------------------------------------------------------------
typedef struct {
PyObject_HEAD
OCISubscription *handle;
dpiSubscr *handle;
udt_Connection *connection;
PyObject *callback;
ub4 namespace;
ub4 protocol;
ub4 port;
ub4 timeout;
ub4 operations;
ub4 qos;
ub4 cqqos;
ub4 rowids;
ub4 id;
uint32_t namespace;
uint32_t protocol;
uint32_t port;
uint32_t timeout;
uint32_t operations;
uint32_t qos;
uint32_t id;
} udt_Subscription;
typedef struct {
PyObject_HEAD
udt_Subscription *subscription;
ub4 type;
dpiEventType type;
PyObject *dbname;
PyObject *tables;
PyObject *queries;
@ -44,19 +42,19 @@ typedef struct {
PyObject_HEAD
PyObject *name;
PyObject *rows;
ub4 operation;
dpiOpCode operation;
} udt_MessageTable;
typedef struct {
PyObject_HEAD
PyObject *rowid;
ub4 operation;
dpiOpCode operation;
} udt_MessageRow;
typedef struct {
PyObject_HEAD
ub8 id;
ub4 operation;
uint64_t id;
dpiOpCode operation;
PyObject *tables;
} udt_MessageQuery;
@ -85,8 +83,6 @@ static PyMemberDef g_SubscriptionTypeMembers[] = {
{ "timeout", T_INT, offsetof(udt_Subscription, timeout), READONLY },
{ "operations", T_INT, offsetof(udt_Subscription, operations), READONLY },
{ "qos", T_INT, offsetof(udt_Subscription, qos), READONLY },
{ "cqqos", T_INT, offsetof(udt_Subscription, cqqos), READONLY },
{ "rowids", T_BOOL, offsetof(udt_Subscription, rowids), READONLY },
{ "id", T_INT, offsetof(udt_Subscription, id), READONLY },
{ NULL }
};
@ -362,30 +358,12 @@ static PyTypeObject g_MessageQueryType = {
// MessageRow_Initialize()
// Initialize a new message row with the information from the descriptor.
//-----------------------------------------------------------------------------
static int MessageRow_Initialize(
udt_MessageRow *self, // object to initialize
udt_Environment *env, // environment to use
dvoid *descriptor) // descriptor to get information from
static int MessageRow_Initialize(udt_MessageRow *self, const char *encoding,
dpiSubscrMessageRow *row)
{
ub4 rowidLength;
sword status;
char *rowid;
// determine operation
status = OCIAttrGet(descriptor, OCI_DTYPE_ROW_CHDES, &self->operation,
NULL, OCI_ATTR_CHDES_ROW_OPFLAGS, env->errorHandle);
if (Environment_CheckForError(env, status,
"MessageRow_Initialize(): get operation") < 0)
return -1;
// determine table name
status = OCIAttrGet(descriptor, OCI_DTYPE_ROW_CHDES, &rowid, &rowidLength,
OCI_ATTR_CHDES_ROW_ROWID, env->errorHandle);
if (Environment_CheckForError(env, status,
"MessageRow_Initialize(): get rowid") < 0)
return -1;
self->rowid = cxString_FromEncodedString(rowid, rowidLength,
env->encoding);
self->operation = row->operation;
self->rowid = cxString_FromEncodedString(row->rowid, row->rowidLength,
encoding);
if (!self->rowid)
return -1;
@ -397,70 +375,25 @@ static int MessageRow_Initialize(
// MessageTable_Initialize()
// Initialize a new message table with the information from the descriptor.
//-----------------------------------------------------------------------------
static int MessageTable_Initialize(
udt_MessageTable *self, // object to initialize
udt_Environment *env, // environment to use
dvoid *descriptor) // descriptor to get information from
static int MessageTable_Initialize(udt_MessageTable *self,
const char *encoding, dpiSubscrMessageTable *table)
{
dvoid **rowDescriptor, *indicator;
udt_MessageRow *row;
ub4 nameLength;
boolean exists;
sb4 numRows, i;
OCIColl *rows;
sword status;
char *name;
uint32_t i;
// determine operation
status = OCIAttrGet(descriptor, OCI_DTYPE_TABLE_CHDES, &self->operation,
NULL, OCI_ATTR_CHDES_TABLE_OPFLAGS, env->errorHandle);
if (Environment_CheckForError(env, status,
"MessageTable_Initialize(): get operation") < 0)
return -1;
// determine table name
status = OCIAttrGet(descriptor, OCI_DTYPE_TABLE_CHDES, &name, &nameLength,
OCI_ATTR_CHDES_TABLE_NAME, env->errorHandle);
if (Environment_CheckForError(env, status,
"MessageTable_Initialize(): get table name") < 0)
return -1;
self->name = cxString_FromEncodedString(name, nameLength, env->encoding);
if (!self->name)
return -1;
// if change invalidated all rows, nothing to do
if (self->operation & OCI_OPCODE_ALLROWS)
return 0;
// determine rows collection
status = OCIAttrGet(descriptor, OCI_DTYPE_TABLE_CHDES, &rows, NULL,
OCI_ATTR_CHDES_TABLE_ROW_CHANGES, env->errorHandle);
if (Environment_CheckForError(env, status,
"MessageTable_Initialize(): get rows collection") < 0)
return -1;
// determine number of rows in collection
status = OCICollSize(env->handle, env->errorHandle, rows, &numRows);
if (Environment_CheckForError(env, status,
"MessageTable_Initialize(): get size of rows collection") < 0)
return -1;
// populate the rows attribute
self->rows = PyList_New(numRows);
self->operation = table->operation;
self->name = cxString_FromEncodedString(table->name, table->nameLength,
encoding);
self->rows = PyList_New(table->numRows);
if (!self->rows)
return -1;
for (i = 0; i < numRows; i++) {
status = OCICollGetElem(env->handle, env->errorHandle, rows, i,
&exists, (dvoid*) &rowDescriptor, &indicator);
if (Environment_CheckForError(env, status,
"MessageTable_Initialize(): get element from collection") < 0)
return -1;
for (i = 0; i < table->numRows; i++) {
row = (udt_MessageRow*)
g_MessageRowType.tp_alloc(&g_MessageRowType, 0);
if (!row)
return -1;
PyList_SET_ITEM(self->rows, i, (PyObject*) row);
if (MessageRow_Initialize(row, env, *rowDescriptor) < 0)
if (MessageRow_Initialize(row, encoding, &table->rows[i]) < 0)
return -1;
}
@ -472,68 +405,24 @@ static int MessageTable_Initialize(
// MessageQuery_Initialize()
// Initialize a new message query with the information from the descriptor.
//-----------------------------------------------------------------------------
static int MessageQuery_Initialize(
udt_MessageQuery *self, // object to initialize
udt_Environment *env, // environment to use
dvoid *descriptor) // descriptor to get information from
static int MessageQuery_Initialize(udt_MessageQuery *self,
const char *encoding, dpiSubscrMessageQuery *query)
{
dvoid **tableDescriptor, *indicator;
udt_MessageTable *table;
sb4 numTables, i;
OCIColl *tables;
boolean exists;
sword status;
uint32_t i;
// determine query id
status = OCIAttrGet(descriptor, OCI_DTYPE_CQDES, &self->id,
NULL, OCI_ATTR_CQDES_QUERYID, env->errorHandle);
if (Environment_CheckForError(env, status,
"MessageQuery_Initialize(): get query id") < 0)
return -1;
// determine operation
status = OCIAttrGet(descriptor, OCI_DTYPE_CQDES, &self->operation,
NULL, OCI_ATTR_CQDES_OPERATION, env->errorHandle);
if (Environment_CheckForError(env, status,
"MessageQuery_Initialize(): get operation") < 0)
return -1;
// determine table collection
status = OCIAttrGet(descriptor, OCI_DTYPE_CQDES, &tables, NULL,
OCI_ATTR_CQDES_TABLE_CHANGES, env->errorHandle);
if (Environment_CheckForError(env, status,
"MessageQuery_Initialize(): get tables collection") < 0)
return -1;
// determine number of tables
if (!tables)
numTables = 0;
else {
status = OCICollSize(env->handle, env->errorHandle, tables,
&numTables);
if (Environment_CheckForError(env, status,
"MessageQuery_Initialize(): get size of collection") < 0)
return -1;
}
// create list to hold results
self->tables = PyList_New(numTables);
self->id = query->id;
self->operation = query->operation;
self->tables = PyList_New(query->numTables);
if (!self->tables)
return -1;
// populate each entry with a message table instance
for (i = 0; i < numTables; i++) {
status = OCICollGetElem(env->handle, env->errorHandle, tables, i,
&exists, (dvoid*) &tableDescriptor, &indicator);
if (Environment_CheckForError(env, status,
"MessageQuery_Initialize(): get element from collection") < 0)
return -1;
for (i = 0; i < query->numTables; i++) {
table = (udt_MessageTable*)
g_MessageTableType.tp_alloc(&g_MessageTableType, 0);
if (!table)
return -1;
PyList_SET_ITEM(self->tables, i, (PyObject*) table);
if (MessageTable_Initialize(table, env, *tableDescriptor) < 0)
if (MessageTable_Initialize(table, encoding, &query->tables[i]) < 0)
return -1;
}
@ -545,124 +434,55 @@ static int MessageQuery_Initialize(
// Message_Initialize()
// Initialize a new message with the information from the descriptor.
//-----------------------------------------------------------------------------
static int Message_Initialize(
udt_Message *self, // object to initialize
udt_Environment *env, // environment to use
udt_Subscription *subscription, // associated subscription for message
dvoid *descriptor) // descriptor to get information from
static int Message_Initialize(udt_Message *self,
udt_Subscription *subscription, dpiSubscrMessage *message)
{
dvoid **tableDescriptor, *indicator, **queryDescriptor;
sb4 numTables, numQueries, i;
OCIColl *tables, *queries;
udt_MessageTable *table;
udt_MessageQuery *query;
ub4 dbnameLength;
boolean exists;
char *dbname;
sword status;
const char *encoding;
uint32_t i;
// assign reference to associated subscription
Py_INCREF(subscription);
self->subscription = subscription;
// determine type
status = OCIAttrGet(descriptor, OCI_DTYPE_CHDES, &self->type, NULL,
OCI_ATTR_CHDES_NFYTYPE, env->errorHandle);
if (Environment_CheckForError(env, status,
"Message_Initialize(): get type") < 0)
return -1;
// determine database name
status = OCIAttrGet(descriptor, OCI_DTYPE_CHDES, &dbname, &dbnameLength,
OCI_ATTR_CHDES_DBNAME, env->errorHandle);
if (Environment_CheckForError(env, status,
"Message_Initialize(): get database name") < 0)
return -1;
self->dbname = cxString_FromEncodedString(dbname, dbnameLength,
env->encoding);
encoding = subscription->connection->encodingInfo.encoding;
self->type = message->eventType;
self->dbname = cxString_FromEncodedString(message->dbName,
message->dbNameLength, encoding);
if (!self->dbname)
return -1;
if (self->type == OCI_EVENT_OBJCHANGE) {
// determine table collection
status = OCIAttrGet(descriptor, OCI_DTYPE_CHDES, &tables, NULL,
OCI_ATTR_CHDES_TABLE_CHANGES, env->errorHandle);
if (Environment_CheckForError(env, status,
"Message_Initialize(): get tables collection") < 0)
return -1;
// determine number of tables
if (!tables)
numTables = 0;
else {
status = OCICollSize(env->handle, env->errorHandle, tables,
&numTables);
if (Environment_CheckForError(env, status,
"Message_Initialize(): get size of collection") < 0)
switch (message->eventType) {
case DPI_EVENT_OBJCHANGE:
self->tables = PyList_New(message->numTables);
if (!self->tables)
return -1;
}
// create list to hold results
self->tables = PyList_New(numTables);
if (!self->tables)
return -1;
// populate each entry with a message table instance
for (i = 0; i < numTables; i++) {
status = OCICollGetElem(env->handle, env->errorHandle, tables, i,
&exists, (dvoid*) &tableDescriptor, &indicator);
if (Environment_CheckForError(env, status,
"Message_Initialize(): get element from collection") < 0)
for (i = 0; i < message->numTables; i++) {
table = (udt_MessageTable*)
g_MessageTableType.tp_alloc(&g_MessageTableType, 0);
if (!table)
return -1;
PyList_SET_ITEM(self->tables, i, (PyObject*) table);
if (MessageTable_Initialize(table, encoding,
&message->tables[i]) < 0)
return -1;
}
break;
case DPI_EVENT_QUERYCHANGE:
self->queries = PyList_New(message->numQueries);
if (!self->queries)
return -1;
table = (udt_MessageTable*)
g_MessageTableType.tp_alloc(&g_MessageTableType, 0);
if (!table)
return -1;
PyList_SET_ITEM(self->tables, i, (PyObject*) table);
if (MessageTable_Initialize(table, env, *tableDescriptor) < 0)
return -1;
}
}
if (self->type == OCI_EVENT_QUERYCHANGE) {
// determine query collection
status = OCIAttrGet(descriptor, OCI_DTYPE_CHDES, &queries, NULL,
OCI_ATTR_CHDES_QUERIES, env->errorHandle);
if (Environment_CheckForError(env, status,
"Message_Initialize(): get queries collection") < 0)
return -1;
// determine number of queries
if (!queries)
numQueries = 0;
else {
status = OCICollSize(env->handle, env->errorHandle, queries,
&numQueries);
if (Environment_CheckForError(env, status,
"Message_Initialize(): get size of collection") < 0)
return -1;
}
// create list to hold results
self->queries = PyList_New(numQueries);
if (!self->queries)
return -1;
// populate each entry with a message query instance
for (i = 0; i < numQueries; i++) {
status = OCICollGetElem(env->handle, env->errorHandle, queries, i,
&exists, (dvoid*) &queryDescriptor, &indicator);
if (Environment_CheckForError(env, status,
"Message_Initialize(): get element from collection") < 0)
return -1;
query = (udt_MessageQuery*)
g_MessageQueryType.tp_alloc(&g_MessageQueryType, 0);
if (!query)
return -1;
PyList_SET_ITEM(self->queries, i, (PyObject*) query);
if (MessageQuery_Initialize(query, env, *queryDescriptor) < 0)
return -1;
}
for (i = 0; i < message->numQueries; i++) {
query = (udt_MessageQuery*)
g_MessageQueryType.tp_alloc(&g_MessageQueryType, 0);
if (!query)
return -1;
PyList_SET_ITEM(self->queries, i, (PyObject*) query);
if (MessageQuery_Initialize(query, encoding,
&message->queries[i]) < 0)
return -1;
}
break;
default:
break;
}
return 0;
@ -673,26 +493,24 @@ static int Message_Initialize(
// Subscription_CallbackHandler()
// Routine that performs the actual call.
//-----------------------------------------------------------------------------
static int Subscription_CallbackHandler(
udt_Subscription *self, // subscription object
udt_Environment *env, // environment to use
dvoid *descriptor) // descriptor to get information from
static int Subscription_CallbackHandler(udt_Subscription *self,
dpiSubscrMessage *message)
{
PyObject *result, *args;
udt_Message *message;
udt_Message *messageObj;
// create the message
message = (udt_Message*) g_MessageType.tp_alloc(&g_MessageType, 0);
if (!message)
messageObj = (udt_Message*) g_MessageType.tp_alloc(&g_MessageType, 0);
if (!messageObj)
return -1;
if (Message_Initialize(message, env, self, descriptor) < 0) {
Py_DECREF(message);
if (Message_Initialize(messageObj, self, message) < 0) {
Py_DECREF(messageObj);
return -1;
}
// create the arguments for the call
args = PyTuple_Pack(1, message);
Py_DECREF(message);
args = PyTuple_Pack(1, messageObj);
Py_DECREF(messageObj);
if (!args)
return -1;
@ -711,192 +529,35 @@ static int Subscription_CallbackHandler(
// Subscription_Callback()
// Routine that is called when a callback needs to be invoked.
//-----------------------------------------------------------------------------
static void Subscription_Callback(
udt_Subscription *self, // subscription object
OCISubscription *handle, // subscription handle
dvoid *payload, // payload
ub4 *payloadLength, // payload length
dvoid *descriptor, // descriptor
ub4 mode) // mode used
static void Subscription_Callback(udt_Subscription *self,
dpiSubscrMessage *message)
{
#ifdef WITH_THREAD
PyGILState_STATE gstate = PyGILState_Ensure();
#endif
udt_Environment *env;
// perform the call
env = Environment_NewFromScratch(0, 0, NULL, NULL);
if (!env)
if (message->errorInfo) {
Error_RaiseFromInfo(message->errorInfo);
PyErr_Print();
} else if (Subscription_CallbackHandler(self, message) < 0)
PyErr_Print();
else {
if (Subscription_CallbackHandler(self, env, descriptor) < 0)
PyErr_Print();
Py_DECREF(env);
}
// restore thread state, if necessary
#ifdef WITH_THREAD
PyGILState_Release(gstate);
#endif
}
//-----------------------------------------------------------------------------
// Subscription_Register()
// Register the subscription.
//-----------------------------------------------------------------------------
static int Subscription_Register(
udt_Subscription *self) // subscription to register
{
udt_Environment *env;
ub4 qosFlags;
sword status;
// create the subscription handle
env = self->connection->environment;
status = OCIHandleAlloc(env->handle, (dvoid**) &self->handle,
OCI_HTYPE_SUBSCRIPTION, 0, 0);
if (Environment_CheckForError(env, status,
"Subscription_Register(): allocate handle") < 0)
return -1;
// set the namespace
status = OCIAttrSet(self->handle, OCI_HTYPE_SUBSCRIPTION,
(dvoid*) &self->namespace, sizeof(ub4), OCI_ATTR_SUBSCR_NAMESPACE,
env->errorHandle);
if (Environment_CheckForError(env, status,
"Subscription_Register(): set namespace") < 0)
return -1;
// set the protocol
status = OCIAttrSet(self->handle, OCI_HTYPE_SUBSCRIPTION,
(dvoid*) &self->protocol, sizeof(ub4), OCI_ATTR_SUBSCR_RECPTPROTO,
env->errorHandle);
if (Environment_CheckForError(env, status,
"Subscription_Register(): set protocol") < 0)
return -1;
// set the timeout
status = OCIAttrSet(self->handle, OCI_HTYPE_SUBSCRIPTION,
(dvoid*) &self->timeout, sizeof(ub4), OCI_ATTR_SUBSCR_TIMEOUT,
env->errorHandle);
if (Environment_CheckForError(env, status,
"Subscription_Register(): set timeout") < 0)
return -1;
// set the TCP port used on client to listen for callback from DB server
if (self->port > 0) {
status = OCIAttrSet(env->handle, OCI_HTYPE_ENV,
(dvoid*) &(self->port), (ub4) 0, OCI_ATTR_SUBSCR_PORTNO,
env->errorHandle);
if (Environment_CheckForError(env, status,
"Subscription_Register(): set port") < 0)
return -1;
}
// set the context for the callback
status = OCIAttrSet(self->handle, OCI_HTYPE_SUBSCRIPTION,
(dvoid*) self, 0, OCI_ATTR_SUBSCR_CTX, env->errorHandle);
if (Environment_CheckForError(env, status,
"Subscription_Register(): set context") < 0)
return -1;
// set the callback, if applicable
if (self->callback) {
status = OCIAttrSet(self->handle, OCI_HTYPE_SUBSCRIPTION,
(dvoid*) Subscription_Callback, 0, OCI_ATTR_SUBSCR_CALLBACK,
env->errorHandle);
if (Environment_CheckForError(env, status,
"Subscription_Register(): set callback") < 0)
return -1;
}
// set suscription QOS
qosFlags = 0;
if (self->qos & CX_SUBSCR_QOS_RELIABLE)
qosFlags |= OCI_SUBSCR_QOS_RELIABLE;
if (self->qos & CX_SUBSCR_QOS_DEREG_NFY)
qosFlags |= OCI_SUBSCR_QOS_PURGE_ON_NTFN;
if (qosFlags) {
status = OCIAttrSet(self->handle, OCI_HTYPE_SUBSCRIPTION,
(dvoid*) &qosFlags, sizeof(ub4), OCI_ATTR_SUBSCR_QOSFLAGS,
env->errorHandle);
if (Environment_CheckForError(env, status,
"Subscription_Register(): set qos flags") < 0)
return -1;
}
// set subscription change notification QOS flags
qosFlags = 0;
if (self->qos & CX_SUBSCR_QOS_QUERY)
qosFlags |= OCI_SUBSCR_CQ_QOS_QUERY;
if (self->qos & CX_SUBSCR_QOS_BEST_EFFORT)
qosFlags |= OCI_SUBSCR_CQ_QOS_BEST_EFFORT;
if (qosFlags) {
status = OCIAttrSet(self->handle, OCI_HTYPE_SUBSCRIPTION,
(dvoid*) &qosFlags, sizeof(ub4), OCI_ATTR_SUBSCR_CQ_QOSFLAGS,
env->errorHandle);
if (Environment_CheckForError(env, status,
"Subscription_Register(): set cq qos flags") < 0)
return -1;
}
// set whether or not rowids are desired
if (self->qos & CX_SUBSCR_QOS_ROWIDS) {
self->rowids = 1;
status = OCIAttrSet(self->handle, OCI_HTYPE_SUBSCRIPTION,
(dvoid*) &self->rowids, sizeof(ub4), OCI_ATTR_CHNF_ROWIDS,
env->errorHandle);
if (Environment_CheckForError(env, status,
"Subscription_Register(): set rowids") < 0)
return -1;
}
// set which operations are desired
status = OCIAttrSet(self->handle, OCI_HTYPE_SUBSCRIPTION,
(dvoid*) &self->operations, sizeof(ub4), OCI_ATTR_CHNF_OPERATIONS,
env->errorHandle);
if (Environment_CheckForError(env, status,
"Subscription_Register(): set operations") < 0)
return -1;
// register the subscription
Py_BEGIN_ALLOW_THREADS
status = OCISubscriptionRegister(self->connection->handle,
&self->handle, 1, env->errorHandle, OCI_DEFAULT);
Py_END_ALLOW_THREADS
if (Environment_CheckForError(env, status,
"Subscription_Register(): register") < 0)
return -1;
// get the registration id
status = OCIAttrGet(self->handle, OCI_HTYPE_SUBSCRIPTION, &self->id,
NULL, OCI_ATTR_SUBSCR_CQ_REGID, env->errorHandle);
if (Environment_CheckForError(env, status,
"Subscription_Register(): get registration id") < 0) {
return -1;
}
return 0;
}
//-----------------------------------------------------------------------------
// Subscription_New()
// Allocate a new subscription object.
//-----------------------------------------------------------------------------
static udt_Subscription *Subscription_New(
udt_Connection *connection, // connection object
ub4 namespace, // namespace to use
ub4 protocol, // protocol to use
ub4 port, // client port for callbacks
PyObject *callback, // callback routine
ub4 timeout, // timeout (in seconds)
ub4 operations, // operations to notify
ub4 qos, // QOS flags
ub4 cqqos, // change notification QOS flags
int rowids) // retrieve rowids?
static udt_Subscription *Subscription_New(udt_Connection *connection,
uint32_t namespace, uint32_t protocol, uint32_t port,
PyObject *callback, uint32_t timeout, uint32_t operations,
uint32_t qos)
{
dpiSubscrCreateParams params;
udt_Subscription *self;
self = (udt_Subscription*)
@ -911,15 +572,26 @@ static udt_Subscription *Subscription_New(
self->protocol = protocol;
self->port = port;
self->timeout = timeout;
self->rowids = rowids;
self->operations = operations;
self->qos = qos | cqqos;
if (rowids)
self->qos |= CX_SUBSCR_QOS_ROWIDS;
else if (qos & CX_SUBSCR_QOS_ROWIDS)
self->rowids = 1;
self->cqqos = cqqos;
if (Subscription_Register(self) < 0) {
self->qos = qos;
if (dpiContext_initSubscrCreateParams(g_DpiContext, &params) < 0) {
Error_RaiseAndReturnNull();
return NULL;
}
params.subscrNamespace = namespace;
params.protocol = protocol;
params.portNumber = port;
if (callback) {
params.callback = (dpiSubscrCallback) Subscription_Callback;
params.callbackContext = self;
}
params.timeout = timeout;
params.operations = operations;
params.qos = qos;
if (dpiConn_newSubscription(connection->handle, &params, &self->handle,
&self->id) < 0) {
Error_RaiseAndReturnNull();
Py_DECREF(self);
return NULL;
}
@ -932,13 +604,12 @@ static udt_Subscription *Subscription_New(
// Subscription_Free()
// Free the memory associated with a subscription.
//-----------------------------------------------------------------------------
static void Subscription_Free(
udt_Subscription *self) // subscription to free
static void Subscription_Free(udt_Subscription *self)
{
if (self->handle)
OCISubscriptionUnRegister(self->connection->handle,
self->handle, self->connection->environment->errorHandle,
OCI_DEFAULT);
if (self->handle) {
dpiSubscr_release(self->handle);
self->handle = NULL;
}
Py_CLEAR(self->connection);
Py_CLEAR(self->callback);
Py_TYPE(self)->tp_free((PyObject*) self);
@ -949,8 +620,7 @@ static void Subscription_Free(
// Subscription_Repr()
// Return a string representation of the subscription.
//-----------------------------------------------------------------------------
static PyObject *Subscription_Repr(
udt_Subscription *subscription) // subscription to repr
static PyObject *Subscription_Repr(udt_Subscription *subscription)
{
PyObject *connectionRepr, *module, *name, *result, *format, *formatArgs;
@ -986,16 +656,15 @@ static PyObject *Subscription_Repr(
// Subscription_RegisterQuery()
// Register a query for database change notification.
//-----------------------------------------------------------------------------
static PyObject *Subscription_RegisterQuery(
udt_Subscription *self, // subscription to use
PyObject *args) // arguments
static PyObject *Subscription_RegisterQuery(udt_Subscription *self,
PyObject *args)
{
PyObject *statement, *executeArgs;
udt_Buffer statementBuffer;
udt_Environment *env;
uint32_t numQueryColumns;
udt_Cursor *cursor;
sword status;
ub8 queryid;
uint64_t queryId;
int status;
// parse arguments
executeArgs = NULL;
@ -1011,29 +680,22 @@ static PyObject *Subscription_RegisterQuery(
}
// create cursor to perform query
env = self->connection->environment;
cursor = (udt_Cursor*) Connection_NewCursor(self->connection, NULL, NULL);
cursor = (udt_Cursor*) PyObject_CallMethod((PyObject*) self->connection,
"cursor", NULL);
if (!cursor)
return NULL;
// allocate the handle so the subscription handle can be set
if (Cursor_AllocateHandle(cursor) < 0) {
Py_DECREF(cursor);
return NULL;
}
// prepare the statement for execution
if (cxBuffer_FromObject(&statementBuffer, statement,
env->encoding) < 0) {
self->connection->encodingInfo.encoding) < 0) {
Py_DECREF(cursor);
return NULL;
}
status = OCIStmtPrepare(cursor->handle, env->errorHandle,
(text*) statementBuffer.ptr, (ub4) statementBuffer.size,
OCI_NTV_SYNTAX, OCI_DEFAULT);
status = dpiSubscr_prepareStmt(self->handle, statementBuffer.ptr,
statementBuffer.size, &cursor->handle);
cxBuffer_Clear(&statementBuffer);
if (Environment_CheckForError(env, status,
"Subscription_RegisterQuery(): prepare statement") < 0) {
if (status < 0) {
Error_RaiseAndReturnNull();
Py_DECREF(cursor);
return NULL;
}
@ -1049,56 +711,30 @@ static PyObject *Subscription_RegisterQuery(
return NULL;
}
// parse the query in order to get the defined variables
// perform the execute (which registers the query)
Py_BEGIN_ALLOW_THREADS
status = OCIStmtExecute(self->connection->handle, cursor->handle,
env->errorHandle, 0, 0, 0, 0, OCI_DESCRIBE_ONLY);
status = dpiStmt_execute(cursor->handle, DPI_MODE_EXEC_DEFAULT,
&numQueryColumns);
Py_END_ALLOW_THREADS
if (Environment_CheckForError(env, status,
"Subscription_RegisterQuery(): parse statement") < 0) {
if (status < 0) {
Error_RaiseAndReturnNull();
Py_DECREF(cursor);
return NULL;
}
// perform define as needed
if (Cursor_PerformDefine(cursor) < 0) {
Py_DECREF(cursor);
return NULL;
}
// set the subscription handle
status = OCIAttrSet(cursor->handle, OCI_HTYPE_STMT, self->handle, 0,
OCI_ATTR_CHNF_REGHANDLE, env->errorHandle);
if (Environment_CheckForError(env, status,
"Subscription_RegisterQuery(): set subscription handle") < 0) {
Py_DECREF(cursor);
return NULL;
}
// execute the query which registers it
if (Cursor_InternalExecute(cursor, 0, 0) < 0) {
Py_DECREF(cursor);
return NULL;
}
if (self->cqqos & OCI_SUBSCR_CQ_QOS_QUERY) {
// get the query id
status = OCIAttrGet(cursor->handle, OCI_HTYPE_STMT, &queryid, NULL,
OCI_ATTR_CQ_QUERYID, env->errorHandle);
if (Environment_CheckForError(env, status,
"Subscription_RegisterQuery(): get query id") < 0) {
// return the query id, if applicable
if (self->qos & DPI_SUBSCR_QOS_QUERY) {
if (dpiStmt_getSubscrQueryId(cursor->handle, &queryId) < 0) {
Error_RaiseAndReturnNull();
Py_DECREF(cursor);
return NULL;
}
Py_DECREF(cursor);
return PyInt_FromLong(queryId);
}
Py_DECREF(cursor);
if (self->cqqos & OCI_SUBSCR_CQ_QOS_QUERY)
return PyInt_FromLong( (long) queryid);
Py_INCREF(Py_None);
return Py_None;
Py_RETURN_NONE;
}
@ -1106,8 +742,7 @@ static PyObject *Subscription_RegisterQuery(
// Message_Free()
// Free the memory associated with a message.
//-----------------------------------------------------------------------------
static void Message_Free(
udt_Message *self) // object to free
static void Message_Free(udt_Message *self)
{
Py_CLEAR(self->subscription);
Py_CLEAR(self->dbname);
@ -1121,8 +756,7 @@ static void Message_Free(
// MessageTable_Free()
// Free the memory associated with a table in a message.
//-----------------------------------------------------------------------------
static void MessageTable_Free(
udt_MessageTable *self) // object to free
static void MessageTable_Free(udt_MessageTable *self)
{
Py_CLEAR(self->name);
Py_CLEAR(self->rows);
@ -1134,8 +768,7 @@ static void MessageTable_Free(
// MessageRow_Free()
// Free the memory associated with a row in a message.
//-----------------------------------------------------------------------------
static void MessageRow_Free(
udt_MessageRow *self) // object to free
static void MessageRow_Free(udt_MessageRow *self)
{
Py_CLEAR(self->rowid);
Py_TYPE(self)->tp_free((PyObject*) self);
@ -1146,8 +779,7 @@ static void MessageRow_Free(
// MessageQuery_Free()
// Free the memory associated with a query in a message.
//-----------------------------------------------------------------------------
static void MessageQuery_Free(
udt_MessageQuery *self) // object to free
static void MessageQuery_Free(udt_MessageQuery *self)
{
Py_CLEAR(self->tables);
Py_TYPE(self)->tp_free((PyObject*) self);

View File

@ -1,150 +0,0 @@
//-----------------------------------------------------------------------------
// Copyright 2016, 2017, Oracle and/or its affiliates. All rights reserved.
//
// Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
//
// Portions Copyright 2001-2007, Computronix (Canada) Ltd., Edmonton, Alberta,
// Canada. All rights reserved.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// TimestampVar.c
// Defines the routines for handling timestamp variables.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Timestamp type
//-----------------------------------------------------------------------------
typedef struct {
Variable_HEAD
OCIDateTime **data;
} udt_TimestampVar;
//-----------------------------------------------------------------------------
// Declaration of date/time variable functions.
//-----------------------------------------------------------------------------
static int TimestampVar_Initialize(udt_TimestampVar*, udt_Cursor*);
static void TimestampVar_Finalize(udt_TimestampVar*);
static int TimestampVar_SetValue(udt_TimestampVar*, unsigned, PyObject*);
static PyObject *TimestampVar_GetValue(udt_TimestampVar*, unsigned);
//-----------------------------------------------------------------------------
// Python type declarations
//-----------------------------------------------------------------------------
static PyTypeObject g_TimestampVarType = {
PyVarObject_HEAD_INIT(NULL, 0)
"cx_Oracle.TIMESTAMP", // tp_name
sizeof(udt_TimestampVar), // tp_basicsize
0, // tp_itemsize
0, // tp_dealloc
0, // tp_print
0, // tp_getattr
0, // tp_setattr
0, // tp_compare
0, // tp_repr
0, // tp_as_number
0, // tp_as_sequence
0, // tp_as_mapping
0, // tp_hash
0, // tp_call
0, // tp_str
0, // tp_getattro
0, // tp_setattro
0, // tp_as_buffer
Py_TPFLAGS_DEFAULT, // tp_flags
0 // tp_doc
};
//-----------------------------------------------------------------------------
// variable type declarations
//-----------------------------------------------------------------------------
static udt_VariableType vt_Timestamp = {
(InitializeProc) TimestampVar_Initialize,
(FinalizeProc) TimestampVar_Finalize,
(PreDefineProc) NULL,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) NULL,
(IsNullProc) NULL,
(SetValueProc) TimestampVar_SetValue,
(GetValueProc) TimestampVar_GetValue,
(GetBufferSizeProc) NULL,
&g_TimestampVarType, // Python type
SQLT_TIMESTAMP, // Oracle type
SQLCS_IMPLICIT, // charset form
sizeof(OCIDateTime*), // element length (default)
0, // is character data
0, // is variable length
1, // can be copied
1 // can be in array
};
//-----------------------------------------------------------------------------
// TimestampVar_Initialize()
// Initialize the variable.
//-----------------------------------------------------------------------------
static int TimestampVar_Initialize(
udt_TimestampVar *var, // variable to initialize
udt_Cursor *cursor) // cursor variable associated with
{
sword status;
ub4 i;
// initialize the LOB locators
for (i = 0; i < var->allocatedElements; i++) {
status = OCIDescriptorAlloc(var->environment->handle,
(dvoid**) &var->data[i], OCI_DTYPE_TIMESTAMP, 0, 0);
if (Environment_CheckForError(var->environment, status,
"TimestampVar_Initialize()") < 0)
return -1;
}
return 0;
}
//-----------------------------------------------------------------------------
// TimestampVar_Finalize()
// Prepare for variable destruction.
//-----------------------------------------------------------------------------
static void TimestampVar_Finalize(
udt_TimestampVar *var) // variable to free
{
ub4 i;
for (i = 0; i < var->allocatedElements; i++) {
if (var->data[i])
OCIDescriptorFree(var->data[i], OCI_DTYPE_TIMESTAMP);
}
}
//-----------------------------------------------------------------------------
// TimestampVar_SetValue()
// Set the value of the variable.
//-----------------------------------------------------------------------------
static int TimestampVar_SetValue(
udt_TimestampVar *var, // variable to set value for
unsigned pos, // array position to set
PyObject *value) // value to set
{
return PythonDateToOracleTimestamp(var->environment, value,
var->data[pos]);
}
//-----------------------------------------------------------------------------
// TimestampVar_GetValue()
// Returns the value stored at the given array position.
//-----------------------------------------------------------------------------
static PyObject *TimestampVar_GetValue(
udt_TimestampVar *var, // variable to determine value for
unsigned pos) // array position
{
return OracleTimestampToPythonDate(var->environment, var->data[pos]);
}

View File

@ -1,492 +0,0 @@
//-----------------------------------------------------------------------------
// Copyright 2016, 2017, Oracle and/or its affiliates. All rights reserved.
//
// Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
//
// Portions Copyright 2001-2007, Computronix (Canada) Ltd., Edmonton, Alberta,
// Canada. All rights reserved.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Transforms.c
// Provides methods for transforming Oracle data to Python objects or for
// setting Oracle data from Python objects.
//-----------------------------------------------------------------------------
static udt_VariableType vt_Date;
#if ORACLE_VERSION_HEX >= ORACLE_VERSION(12, 1)
//-----------------------------------------------------------------------------
// OracleBooleanToPythonBoolean()
// Return a Python boolean object given an Oracle boolean.
//-----------------------------------------------------------------------------
static PyObject *OracleBooleanToPythonBoolean(
boolean *value) // value to convert
{
PyObject *pythonValue;
pythonValue = (*value) ? Py_True : Py_False;
Py_INCREF(pythonValue);
return pythonValue;
}
#endif
//-----------------------------------------------------------------------------
// OracleDateToPythonDate()
// Return a Python date object given an Oracle date.
//-----------------------------------------------------------------------------
static PyObject *OracleDateToPythonDate(
udt_VariableType *varType, // variable type
OCIDate* value) // value to convert
{
ub1 hour, minute, second, month, day;
sb2 year;
OCIDateGetDate(value, &year, &month, &day);
OCIDateGetTime(value, &hour, &minute, &second);
if (varType == &vt_Date)
return PyDate_FromDate(year, month, day);
return PyDateTime_FromDateAndTime(year, month, day, hour, minute, second,
0);
}
//-----------------------------------------------------------------------------
// OracleIntervalToPythonDelta()
// Return a Python delta object given an Oracle interval.
//-----------------------------------------------------------------------------
static PyObject *OracleIntervalToPythonDelta(
udt_Environment *environment, // environment
OCIInterval *value) // value to convert
{
sb4 days, hours, minutes, seconds, fseconds;
sword status;
status = OCIIntervalGetDaySecond(environment->handle,
environment->errorHandle, &days, &hours, &minutes, &seconds,
&fseconds, value);
if (Environment_CheckForError(environment, status,
"OracleIntervalToPythonDelta()") < 0)
return NULL;
seconds = hours * 60 * 60 + minutes * 60 + seconds;
return PyDelta_FromDSU(days, seconds, fseconds / 1000);
}
//-----------------------------------------------------------------------------
// OracleTimestampToPythonDate()
// Return a Python date object given an Oracle timestamp.
//-----------------------------------------------------------------------------
static PyObject *OracleTimestampToPythonDate(
udt_Environment *environment, // environment
OCIDateTime* value) // value to convert
{
ub1 hour, minute, second, month, day;
sword status;
ub4 fsecond;
sb2 year;
status = OCIDateTimeGetDate(environment->handle, environment->errorHandle,
value, &year, &month, &day);
if (Environment_CheckForError(environment, status,
"OracleTimestampToPythonDate(): date portion") < 0)
return NULL;
status = OCIDateTimeGetTime(environment->handle, environment->errorHandle,
value, &hour, &minute, &second, &fsecond);
if (Environment_CheckForError(environment, status,
"OracleTimestampToPythonDate(): time portion") < 0)
return NULL;
return PyDateTime_FromDateAndTime(year, month, day, hour, minute, second,
fsecond / 1000);
}
//-----------------------------------------------------------------------------
// OracleNumberToPythonFloat()
// Return a Python float given an Oracle number.
//-----------------------------------------------------------------------------
static PyObject *OracleNumberToPythonFloat(
udt_Environment *environment, // environment
OCINumber* value) // value to convert
{
double doubleValue;
sword status;
status = OCINumberToReal(environment->errorHandle,
value, sizeof(double), (dvoid*) &doubleValue);
if (Environment_CheckForError(environment, status,
"OracleNumberToPythonFloat()") < 0)
return NULL;
return PyFloat_FromDouble(doubleValue);
}
//-----------------------------------------------------------------------------
// OracleNumberToPythonInteger()
// Return a Python integer given an Oracle number.
//-----------------------------------------------------------------------------
static PyObject *OracleNumberToPythonInteger(
udt_Environment *environment, // environment
OCINumber* value) // value to convert
{
long integerValue;
sword status;
status = OCINumberToInt(environment->errorHandle, value,
sizeof(long), OCI_NUMBER_SIGNED, (dvoid*) &integerValue);
if (Environment_CheckForError(environment, status,
"OracleNumberToPythonInteger()") < 0)
return NULL;
return PyInt_FromLong(integerValue);
}
#if ORACLE_VERSION_HEX >= ORACLE_VERSION(12, 1)
//-----------------------------------------------------------------------------
// PythonBooleanToOracleBoolean()
// Transform a Python boolean into an Oracle boolean.
//-----------------------------------------------------------------------------
static int PythonBooleanToOracleBoolean(
PyObject *pythonValue, // Python value to convert
boolean *oracleValue) // value to convert
{
*oracleValue = (pythonValue == Py_True);
return 0;
}
#endif
//-----------------------------------------------------------------------------
// PythonBooleanToOracleNumber()
// Transform a Python boolean into an Oracle number.
//-----------------------------------------------------------------------------
static int PythonBooleanToOracleNumber(
udt_Environment *environment, // environment
PyObject *pythonValue, // Python value to convert
OCINumber *oracleValue) // Oracle value to set
{
long integerValue;
sword status;
integerValue = (pythonValue == Py_True);
status = OCINumberFromInt(environment->errorHandle, &integerValue,
sizeof(long), OCI_NUMBER_SIGNED, oracleValue);
return Environment_CheckForError(environment, status,
"PythonBooleanToOracleNumber()");
}
//-----------------------------------------------------------------------------
// PythonDateToOracleDate()
// Transform a Python date into an Oracle date.
//-----------------------------------------------------------------------------
static int PythonDateToOracleDate(
PyObject *pythonValue, // Python value to convert
OCIDate *oracleValue) // Oracle value to set
{
ub1 month, day, hour, minute, second;
sb2 year;
if (PyDateTime_Check(pythonValue)) {
year = (short) PyDateTime_GET_YEAR(pythonValue);
month = PyDateTime_GET_MONTH(pythonValue);
day = PyDateTime_GET_DAY(pythonValue);
hour = PyDateTime_DATE_GET_HOUR(pythonValue);
minute = PyDateTime_DATE_GET_MINUTE(pythonValue);
second = PyDateTime_DATE_GET_SECOND(pythonValue);
} else if (PyDate_Check(pythonValue)) {
year = (short) PyDateTime_GET_YEAR(pythonValue);
month = PyDateTime_GET_MONTH(pythonValue);
day = PyDateTime_GET_DAY(pythonValue);
hour = minute = second = 0;
} else {
PyErr_SetString(PyExc_TypeError, "expecting date data");
return -1;
}
OCIDateSetDate(oracleValue, year, month, day);
OCIDateSetTime(oracleValue, hour, minute, second);
return 0;
}
#if PY_MAJOR_VERSION < 3
//-----------------------------------------------------------------------------
// PythonIntegerToOracleNumber()
// Transform a Python integer into an Oracle number.
//-----------------------------------------------------------------------------
static int PythonIntegerToOracleNumber(
udt_Environment *environment, // environment
PyObject *pythonValue, // Python value to convert
OCINumber *oracleValue) // Oracle value to set
{
long integerValue;
sword status;
integerValue = PyInt_AS_LONG(pythonValue);
status = OCINumberFromInt(environment->errorHandle, &integerValue,
sizeof(long), OCI_NUMBER_SIGNED, oracleValue);
return Environment_CheckForError(environment, status,
"PythonIntegerToOracleNumber()");
}
#endif
//-----------------------------------------------------------------------------
// PythonFloatToOracleNumber()
// Transform a Python float into an Oracle number.
//-----------------------------------------------------------------------------
static int PythonFloatToOracleNumber(
udt_Environment *environment, // environment
PyObject *pythonValue, // Python value to convert
OCINumber *oracleValue) // Oracle value to set
{
double doubleValue;
sword status;
doubleValue = PyFloat_AS_DOUBLE(pythonValue);
status = OCINumberFromReal(environment->errorHandle, &doubleValue,
sizeof(double), oracleValue);
return Environment_CheckForError(environment, status,
"PythonFloatToOracleNumber()");
}
//-----------------------------------------------------------------------------
// PythonLongToOracleNumber()
// Set the value of the variable from a Python long.
//-----------------------------------------------------------------------------
static int PythonLongToOracleNumber(
udt_Environment *environment, // environment
PyObject *pythonValue, // Python value to convert
OCINumber *oracleValue) // Oracle value to set
{
udt_Buffer textBuffer;
PyObject *textValue;
sword status;
textValue = PyObject_Str(pythonValue);
if (!textValue)
return -1;
if (cxBuffer_FromObject(&textBuffer, textValue, environment->encoding) < 0)
return -1;
status = OCINumberFromText(environment->errorHandle,
(text*) textBuffer.ptr, (ub4) textBuffer.size,
(text*) environment->numberFromStringFormatBuffer.ptr,
(ub4) environment->numberFromStringFormatBuffer.size, NULL, 0,
oracleValue);
cxBuffer_Clear(&textBuffer);
Py_DECREF(textValue);
return Environment_CheckForError(environment, status,
"PythonLongToOracleNumber()");
}
//-----------------------------------------------------------------------------
// GetFormatAndTextFromPythonDecimal()
// Return the number format and text to use for the Decimal object.
//-----------------------------------------------------------------------------
static int GetFormatAndTextFromPythonDecimal(
PyObject *tupleValue, // decimal as_tuple() value
PyObject **textObj, // text string for conversion
PyObject **formatObj) // format for conversion
{
Py_ssize_t numDigits, scale, i, sign, length, digit;
char *textValue, *format, *textPtr, *formatPtr;
PyObject *digits;
// acquire basic information from the value tuple
sign = PyInt_AsLong(PyTuple_GET_ITEM(tupleValue, 0));
if (PyErr_Occurred())
return -1;
digits = PyTuple_GET_ITEM(tupleValue, 1);
scale = PyInt_AsLong(PyTuple_GET_ITEM(tupleValue, 2));
if (PyErr_Occurred())
return -1;
numDigits = PyTuple_GET_SIZE(digits);
// allocate memory for the string and format to use in conversion
length = numDigits + abs( (long) scale) + 3;
textValue = textPtr = PyMem_Malloc(length);
if (!textValue) {
PyErr_NoMemory();
return -1;
}
format = formatPtr = PyMem_Malloc(length);
if (!format) {
PyMem_Free(textValue);
PyErr_NoMemory();
return -1;
}
// populate the string and format
if (sign)
*textPtr++ = '-';
for (i = 0; i < numDigits + scale; i++) {
*formatPtr++ = '9';
if (i < numDigits) {
digit = PyInt_AsLong(PyTuple_GetItem(digits, i));
if (PyErr_Occurred()) {
PyMem_Free(textValue);
return -1;
}
}
else digit = 0;
*textPtr++ = '0' + (char) digit;
}
if (scale < 0) {
*formatPtr++ = 'D';
*textPtr++ = '.';
for (i = scale; i < 0; i++) {
*formatPtr++ = '9';
if (numDigits + i < 0)
digit = 0;
else {
digit = PyInt_AsLong(PyTuple_GetItem(digits, numDigits + i));
if (PyErr_Occurred()) {
PyMem_Free(textValue);
return -1;
}
}
*textPtr++ = '0' + (char) digit;
}
}
*formatPtr = '\0';
*textPtr = '\0';
*textObj = cxString_FromAscii(textValue);
PyMem_Free(textValue);
if (!*textObj) {
PyMem_Free(format);
return -1;
}
*formatObj = cxString_FromAscii(format);
PyMem_Free(format);
if (!*formatObj) {
Py_DECREF(*textObj);
return -1;
}
return 0;
}
//-----------------------------------------------------------------------------
// PythonDecimalToOracleNumber()
// Transform a Python decimal object into an Oracle number.
//-----------------------------------------------------------------------------
static int PythonDecimalToOracleNumber(
udt_Environment *environment, // environment
PyObject *pythonValue, // Python value to convert
OCINumber *oracleValue) // Oracle value to set
{
PyObject *textValue, *format, *tupleValue;
udt_Buffer textBuffer, formatBuffer;
sword status;
tupleValue = PyObject_CallMethod(pythonValue, "as_tuple", NULL);
if (!tupleValue)
return -1;
if (GetFormatAndTextFromPythonDecimal(tupleValue, &textValue,
&format) < 0) {
Py_DECREF(tupleValue);
return -1;
}
Py_DECREF(tupleValue);
if (cxBuffer_FromObject(&textBuffer, textValue, environment->encoding) < 0)
return -1;
if (cxBuffer_FromObject(&formatBuffer, format,
environment->encoding) < 0) {
cxBuffer_Clear(&textBuffer);
return -1;
}
status = OCINumberFromText(environment->errorHandle,
(text*) textBuffer.ptr, (ub4) textBuffer.size,
(text*) formatBuffer.ptr, (ub4) formatBuffer.size,
environment->nlsNumericCharactersBuffer.ptr,
(ub4) environment->nlsNumericCharactersBuffer.size, oracleValue);
cxBuffer_Clear(&textBuffer);
cxBuffer_Clear(&formatBuffer);
Py_DECREF(textValue);
Py_DECREF(format);
return Environment_CheckForError(environment, status,
"PythonDecimalToOracleNumber()");
}
//-----------------------------------------------------------------------------
// PythonNumberToOracleNumber()
// Convert a Python number to an Oracle number.
//-----------------------------------------------------------------------------
static int PythonNumberToOracleNumber(
udt_Environment *environment, // environment
PyObject *pythonValue, // Python value
OCINumber* oracleValue) // Oracle value
{
#if PY_MAJOR_VERSION < 3
if (PyInt_Check(pythonValue))
return PythonIntegerToOracleNumber(environment, pythonValue,
oracleValue);
#endif
if (PyBool_Check(pythonValue))
return PythonBooleanToOracleNumber(environment, pythonValue,
oracleValue);
if (PyLong_Check(pythonValue))
return PythonLongToOracleNumber(environment, pythonValue, oracleValue);
if (PyFloat_Check(pythonValue))
return PythonFloatToOracleNumber(environment, pythonValue,
oracleValue);
if (Py_TYPE(pythonValue) == g_DecimalType)
return PythonDecimalToOracleNumber(environment, pythonValue,
oracleValue);
PyErr_SetString(PyExc_TypeError, "expecting numeric data");
return -1;
}
//-----------------------------------------------------------------------------
// PythonDateToOracleTimestamp()
// Convert a Python date to an Oracle timestamp.
//-----------------------------------------------------------------------------
static int PythonDateToOracleTimestamp(
udt_Environment *environment, // environment
PyObject *pythonValue, // Python value
OCIDateTime* oracleValue) // Oracle value
{
sword status;
uword valid;
// make sure a timestamp is being bound
if (!PyDateTime_Check(pythonValue)) {
PyErr_SetString(PyExc_TypeError, "expecting timestamp data");
return -1;
}
// store a copy of the value
status = OCIDateTimeConstruct(environment->handle,
environment->errorHandle, oracleValue,
(sb2) PyDateTime_GET_YEAR(pythonValue),
PyDateTime_GET_MONTH(pythonValue),
PyDateTime_GET_DAY(pythonValue),
PyDateTime_DATE_GET_HOUR(pythonValue),
PyDateTime_DATE_GET_MINUTE(pythonValue),
PyDateTime_DATE_GET_SECOND(pythonValue),
PyDateTime_DATE_GET_MICROSECOND(pythonValue) * 1000, NULL, 0);
if (Environment_CheckForError(environment, status,
"PythonDateToOracleTimestamp(): create structure") < 0)
return -1;
status = OCIDateTimeCheck(environment->handle, environment->errorHandle,
oracleValue, &valid);
if (Environment_CheckForError(environment, status,
"PythonDateToOracleTimestamp(): check validity") < 0)
return -1;
if (valid != 0) {
PyErr_SetString(g_DataErrorException, "invalid date");
return -1;
}
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -18,28 +18,17 @@
#include <datetime.h>
#include <structmember.h>
#include <time.h>
#include <oci.h>
#include <orid.h>
#include <xa.h>
#include <dpi.h>
// validate OCI library
#if !defined(OCI_MAJOR_VERSION) || (OCI_MAJOR_VERSION < 11) || \
((OCI_MAJOR_VERSION == 11) && (OCI_MINOR_VERSION < 2))
#error Oracle 11.2 or later client libraries are required for building
#endif
// define simple way to respresent Oracle version
#define ORACLE_VERSION(major, minor) \
((major << 8) | minor)
#define ORACLE_VERSION_HEX \
ORACLE_VERSION(OCI_MAJOR_VERSION, OCI_MINOR_VERSION)
// define PyInt_* macros for Python 3.x
// define integer macros/methods for Python 3.x
#ifndef PyInt_Check
#define PyInt_Check PyLong_Check
#define PyInt_FromLong PyLong_FromLong
#define PyInt_FromUnsignedLong PyLong_FromUnsignedLong
#define PyInt_AsLong PyLong_AsLong
#define PyInt_AsUnsignedLong PyLong_AsUnsignedLong
#define PyInt_Type PyLong_Type
#define PyNumber_Int PyNumber_Long
#endif
// use the bytes methods in cx_Oracle and define them as the equivalent string
@ -61,7 +50,7 @@
#define cxString_Type &PyUnicode_Type
#define cxString_Format PyUnicode_Format
#define cxString_Check PyUnicode_Check
#define cxString_GetSize PyUnicode_GET_SIZE
#define cxString_GetSize PyUnicode_GET_LENGTH
#else
#define cxBinary_Type PyBuffer_Type
#define cxBinary_Check PyBuffer_Check
@ -104,13 +93,43 @@
if (PyModule_AddObject(module, name, (PyObject*) type) < 0) \
return NULL;
// define macros for making types ready
// define macros for defining and making variable types ready
#define DECLARE_VARIABLE_TYPE(INTERNAL_NAME, EXTERNAL_NAME) \
static PyTypeObject INTERNAL_NAME = { \
PyVarObject_HEAD_INIT(NULL, 0) \
"cx_Oracle." #EXTERNAL_NAME, /* tp_name */ \
sizeof(udt_Variable), /* tp_basicsize */ \
0, /* tp_itemsize */ \
(destructor) Variable_Free, /* tp_dealloc */ \
0, /* tp_print */ \
0, /* tp_getattr */ \
0, /* tp_setattr */ \
0, /* tp_compare */ \
(reprfunc) Variable_Repr, /* tp_repr */ \
0, /* tp_as_number */ \
0, /* tp_as_sequence */ \
0, /* tp_as_mapping */ \
0, /* tp_hash */ \
0, /* tp_call */ \
0, /* tp_str */ \
0, /* tp_getattro */ \
0, /* tp_setattro */ \
0, /* tp_as_buffer */ \
Py_TPFLAGS_DEFAULT, /* tp_flags */ \
0, /* tp_doc */ \
0, /* tp_traverse */ \
0, /* tp_clear */ \
0, /* tp_richcompare */ \
0, /* tp_weaklistoffset */ \
0, /* tp_iter */ \
0, /* tp_iternext */ \
g_VariableMethods, /* tp_methods */ \
g_VariableMembers /* tp_members */ \
};
#define MAKE_TYPE_READY(type) \
if (PyType_Ready(type) < 0) \
return NULL;
#define MAKE_VARIABLE_TYPE_READY(type) \
(type)->tp_base = &g_BaseVarType; \
MAKE_TYPE_READY(type)
// define macros to get the build version as a string and the driver name
#define xstr(s) str(s)
@ -118,15 +137,6 @@
#define BUILD_VERSION_STRING xstr(BUILD_VERSION)
#define DRIVER_NAME "cx_Oracle : "BUILD_VERSION_STRING
// define constants used for subscription quality of service
// these are intended to more closely follow the PL/SQL implementation and
// merge the SUBSCR_QOS and SUBSCR_CQ_QOS constants
#define CX_SUBSCR_QOS_RELIABLE 0x01
#define CX_SUBSCR_QOS_DEREG_NFY 0x02
#define CX_SUBSCR_QOS_ROWIDS 0x04
#define CX_SUBSCR_QOS_QUERY 0x08
#define CX_SUBSCR_QOS_BEST_EFFORT 0x10
#include "Buffer.c"
//-----------------------------------------------------------------------------
@ -144,17 +154,15 @@ static PyObject *g_ProgrammingErrorException = NULL;
static PyObject *g_NotSupportedErrorException = NULL;
static PyTypeObject *g_DateTimeType = NULL;
static PyTypeObject *g_DecimalType = NULL;
static dpiContext *g_DpiContext = NULL;
//-----------------------------------------------------------------------------
// SetException()
// Create an exception and set it in the provided dictionary.
//-----------------------------------------------------------------------------
static int SetException(
PyObject *module, // module object
PyObject **exception, // exception to create
char *name, // name of the exception
PyObject *baseException) // exception to base exception on
static int SetException(PyObject *module, PyObject **exception, char *name,
PyObject *baseException)
{
char buffer[100];
@ -170,10 +178,8 @@ static int SetException(
// GetModuleAndName()
// Return the module and name for the type.
//-----------------------------------------------------------------------------
static int GetModuleAndName(
PyTypeObject *type, // type to get module/name for
PyObject **module, // name of module
PyObject **name) // name of type
static int GetModuleAndName(PyTypeObject *type, PyObject **module,
PyObject **name)
{
*module = PyObject_GetAttrString( (PyObject*) type, "__module__");
if (!*module)
@ -187,7 +193,47 @@ static int GetModuleAndName(
}
#include "Environment.c"
//-----------------------------------------------------------------------------
// GetBooleanValue()
// Get a boolean value from a Python object.
//-----------------------------------------------------------------------------
static int GetBooleanValue(PyObject *obj, int defaultValue, int *value)
{
if (!obj)
*value = defaultValue;
else {
*value = PyObject_IsTrue(obj);
if (*value < 0)
return -1;
}
return 0;
}
//-----------------------------------------------------------------------------
// GetAdjustedEncoding()
// Return the adjusted encoding to use when encoding and decoding strings
// that are passed to and from the Oracle database. The Oracle client interface
// does not support the inclusion of a BOM in the encoded string but assumes
// native endian order for UTF-16. Python generates a BOM at the beginning of
// the encoded string if plain UTF-16 is specified. For this reason, the
// correct byte order must be determined and used inside Python so that the
// Oracle client receives the data it expects.
//-----------------------------------------------------------------------------
static const char *GetAdjustedEncoding(const char *encoding)
{
static const union {
unsigned char bytes[4];
uint32_t value;
} hostOrder = { { 0, 1, 2, 3 } };
if (!encoding || strcmp(encoding, "UTF-16") != 0)
return encoding;
return (hostOrder.value == 0x03020100) ? "UTF-16LE" : "UTF-16BE";
}
#include "Error.c"
#include "SessionPool.c"
@ -195,34 +241,78 @@ static int GetModuleAndName(
// MakeDSN()
// Make a data source name given the host port and SID.
//-----------------------------------------------------------------------------
static PyObject* MakeDSN(
PyObject* self, // passthrough argument
PyObject* args, // arguments to function
PyObject* keywordArgs) // keyword arguments
static PyObject* MakeDSN(PyObject* self, PyObject* args, PyObject* keywordArgs)
{
static unsigned int numConnectDataArgs = 5;
static char *keywordList[] = { "host", "port", "sid", "service_name",
NULL };
PyObject *hostObj, *portObj, *sidObj, *serviceNameObj, *connectDataObj;
PyObject *format, *result, *formatArgs;
"region", "sharding_key", "super_sharding_key", NULL };
PyObject *format, *formatArgs, *result, *connectData, *hostObj, *portObj;
char connectDataFormat[72], *sourcePtr, *targetPtr;
PyObject *connectDataArgs[5], *formatArgsArray;
unsigned int i;
// parse arguments
sidObj = serviceNameObj = NULL;
if (!PyArg_ParseTupleAndKeywords(args, keywordArgs, "OO|OO", keywordList,
&hostObj, &portObj, &sidObj, &serviceNameObj))
for (i = 0; i < numConnectDataArgs; i++)
connectDataArgs[i] = NULL;
if (!PyArg_ParseTupleAndKeywords(args, keywordArgs, "OO|OOOO0",
keywordList, &hostObj, &portObj, &connectDataArgs[0],
&connectDataArgs[1], &connectDataArgs[2], &connectDataArgs[3],
&connectDataArgs[4]))
return NULL;
if (sidObj) {
connectDataObj = sidObj;
format = cxString_FromAscii("(DESCRIPTION=(ADDRESS="
"(PROTOCOL=TCP)(HOST=%s)(PORT=%s))(CONNECT_DATA=(SID=%s)))");
} else {
connectDataObj = serviceNameObj;
format = cxString_FromAscii("(DESCRIPTION=(ADDRESS="
"(PROTOCOL=TCP)(HOST=%s)(PORT=%s))(CONNECT_DATA="
"(SERVICE_NAME=%s)))");
// create list for connect data format arguments
formatArgsArray = PyList_New(0);
if (!formatArgsArray)
return NULL;
// process each of the connect data arguments
// build up a format string and a list of format arguments
targetPtr = connectDataFormat;
*targetPtr = '\0';
for (i = 0; i < numConnectDataArgs; i++) {
if (connectDataArgs[i]) {
if (PyList_Append(formatArgsArray, connectDataArgs[i]) < 0) {
Py_DECREF(formatArgsArray);
return NULL;
}
sourcePtr = keywordList[i + 2];
*targetPtr++ = '(';
while (*sourcePtr)
*targetPtr++ = toupper(*sourcePtr++);
*targetPtr++ = '=';
*targetPtr++ = '%';
*targetPtr++ = 's';
*targetPtr++ = ')';
*targetPtr = '\0';
}
}
if (!format)
formatArgs = PyList_AsTuple(formatArgsArray);
Py_DECREF(formatArgsArray);
if (!formatArgs)
return NULL;
formatArgs = PyTuple_Pack(3, hostObj, portObj, connectDataObj);
// determine connect data
format = cxString_FromAscii(connectDataFormat);
if (!format) {
Py_DECREF(formatArgs);
return NULL;
}
connectData = cxString_Format(format, formatArgs);
Py_DECREF(format);
Py_DECREF(formatArgs);
if (!connectData)
return NULL;
// perform overall format
format = cxString_FromAscii("(DESCRIPTION=(ADDRESS="
"(PROTOCOL=TCP)(HOST=%s)(PORT=%s))(CONNECT_DATA=%s))");
if (!format) {
Py_DECREF(connectData);
return NULL;
}
formatArgs = PyTuple_Pack(3, hostObj, portObj, connectData);
Py_DECREF(connectData);
if (!formatArgs) {
Py_DECREF(format);
return NULL;
@ -238,16 +328,15 @@ static PyObject* MakeDSN(
// ClientVersion()
// Return the version of the Oracle client being used as a 5-tuple.
//-----------------------------------------------------------------------------
static PyObject* ClientVersion(
PyObject* self, // passthrough argument
PyObject* args) // arguments to function
static PyObject* ClientVersion(PyObject* self, PyObject* args)
{
sword majorVersion, minorVersion, updateNum, patchNum, portUpdateNum;
int versionNum, releaseNum, updateNum, portReleaseNum, portUpdateNum;
OCIClientVersion(&majorVersion, &minorVersion, &updateNum,
&patchNum, &portUpdateNum);
return Py_BuildValue("(iiiii)", majorVersion, minorVersion, updateNum,
patchNum, portUpdateNum);
if (dpiContext_getClientVersion(g_DpiContext, &versionNum, &releaseNum,
&updateNum, &portReleaseNum, &portUpdateNum) < 0)
return Error_RaiseAndReturnNull();
return Py_BuildValue("(iiiii)", versionNum, releaseNum, updateNum,
portReleaseNum, portUpdateNum);
}
@ -255,9 +344,7 @@ static PyObject* ClientVersion(
// Time()
// Returns a time value suitable for binding.
//-----------------------------------------------------------------------------
static PyObject* Time(
PyObject* self, // passthrough argument
PyObject* args) // arguments to function
static PyObject* Time(PyObject* self, PyObject* args)
{
PyErr_SetString(g_NotSupportedErrorException,
"Oracle does not support time only variables");
@ -269,9 +356,7 @@ static PyObject* Time(
// TimeFromTicks()
// Returns a time value suitable for binding.
//-----------------------------------------------------------------------------
static PyObject* TimeFromTicks(
PyObject* self, // passthrough argument
PyObject* args) // arguments to function
static PyObject* TimeFromTicks(PyObject* self, PyObject* args)
{
PyErr_SetString(g_NotSupportedErrorException,
"Oracle does not support time only variables");
@ -283,9 +368,7 @@ static PyObject* TimeFromTicks(
// DateFromTicks()
// Returns a date value suitable for binding.
//-----------------------------------------------------------------------------
static PyObject* DateFromTicks(
PyObject* self, // passthrough argument
PyObject* args) // arguments to function
static PyObject* DateFromTicks(PyObject* self, PyObject* args)
{
return PyDate_FromTimestamp(args);
}
@ -295,9 +378,7 @@ static PyObject* DateFromTicks(
// TimestampFromTicks()
// Returns a date value suitable for binding.
//-----------------------------------------------------------------------------
static PyObject* TimestampFromTicks(
PyObject* self, // passthrough argument
PyObject* args) // arguments to function
static PyObject* TimestampFromTicks(PyObject* self, PyObject* args)
{
return PyDateTime_FromTimestamp(args);
}
@ -341,6 +422,7 @@ static struct PyModuleDef g_ModuleDef = {
//-----------------------------------------------------------------------------
static PyObject *Module_Initialize(void)
{
dpiErrorInfo errorInfo;
PyObject *module;
#ifdef WITH_THREAD
@ -365,10 +447,9 @@ static PyObject *Module_Initialize(void)
MAKE_TYPE_READY(&g_CursorType);
MAKE_TYPE_READY(&g_ErrorType);
MAKE_TYPE_READY(&g_SessionPoolType);
MAKE_TYPE_READY(&g_EnvironmentType);
MAKE_TYPE_READY(&g_ObjectTypeType);
MAKE_TYPE_READY(&g_ObjectAttributeType);
MAKE_TYPE_READY(&g_ExternalLobVarType);
MAKE_TYPE_READY(&g_LOBType);
MAKE_TYPE_READY(&g_ObjectType);
MAKE_TYPE_READY(&g_EnqOptionsType);
MAKE_TYPE_READY(&g_DeqOptionsType);
@ -378,30 +459,27 @@ static PyObject *Module_Initialize(void)
MAKE_TYPE_READY(&g_MessageTableType);
MAKE_TYPE_READY(&g_MessageRowType);
MAKE_TYPE_READY(&g_MessageQueryType);
MAKE_VARIABLE_TYPE_READY(&g_StringVarType);
MAKE_VARIABLE_TYPE_READY(&g_FixedCharVarType);
MAKE_VARIABLE_TYPE_READY(&g_RowidVarType);
MAKE_VARIABLE_TYPE_READY(&g_BinaryVarType);
MAKE_VARIABLE_TYPE_READY(&g_LongStringVarType);
MAKE_VARIABLE_TYPE_READY(&g_LongBinaryVarType);
MAKE_VARIABLE_TYPE_READY(&g_NumberVarType);
MAKE_VARIABLE_TYPE_READY(&g_DateTimeVarType);
MAKE_VARIABLE_TYPE_READY(&g_TimestampVarType);
MAKE_VARIABLE_TYPE_READY(&g_CLOBVarType);
MAKE_VARIABLE_TYPE_READY(&g_BLOBVarType);
MAKE_VARIABLE_TYPE_READY(&g_BFILEVarType);
MAKE_VARIABLE_TYPE_READY(&g_CursorVarType);
MAKE_VARIABLE_TYPE_READY(&g_ObjectVarType);
MAKE_VARIABLE_TYPE_READY(&g_NCharVarType);
MAKE_VARIABLE_TYPE_READY(&g_FixedNCharVarType);
MAKE_VARIABLE_TYPE_READY(&g_LongNCharVarType);
MAKE_VARIABLE_TYPE_READY(&g_NCLOBVarType);
MAKE_VARIABLE_TYPE_READY(&g_NativeFloatVarType);
MAKE_VARIABLE_TYPE_READY(&g_NativeIntVarType);
MAKE_VARIABLE_TYPE_READY(&g_IntervalVarType);
#if ORACLE_VERSION_HEX >= ORACLE_VERSION(12, 1)
MAKE_VARIABLE_TYPE_READY(&g_BooleanVarType);
#endif
MAKE_TYPE_READY(&g_StringVarType);
MAKE_TYPE_READY(&g_FixedCharVarType);
MAKE_TYPE_READY(&g_RowidVarType);
MAKE_TYPE_READY(&g_BinaryVarType);
MAKE_TYPE_READY(&g_LongStringVarType);
MAKE_TYPE_READY(&g_LongBinaryVarType);
MAKE_TYPE_READY(&g_NumberVarType);
MAKE_TYPE_READY(&g_DateTimeVarType);
MAKE_TYPE_READY(&g_TimestampVarType);
MAKE_TYPE_READY(&g_CLOBVarType);
MAKE_TYPE_READY(&g_BLOBVarType);
MAKE_TYPE_READY(&g_BFILEVarType);
MAKE_TYPE_READY(&g_CursorVarType);
MAKE_TYPE_READY(&g_ObjectVarType);
MAKE_TYPE_READY(&g_NCharVarType);
MAKE_TYPE_READY(&g_FixedNCharVarType);
MAKE_TYPE_READY(&g_NCLOBVarType);
MAKE_TYPE_READY(&g_NativeFloatVarType);
MAKE_TYPE_READY(&g_NativeIntVarType);
MAKE_TYPE_READY(&g_IntervalVarType);
MAKE_TYPE_READY(&g_BooleanVarType);
// initialize module and retrieve the dictionary
#if PY_MAJOR_VERSION >= 3
@ -444,6 +522,13 @@ static PyObject *Module_Initialize(void)
"NotSupportedError", g_DatabaseErrorException) < 0)
return NULL;
// initialize DPI library and create DPI context
if (dpiContext_create(DPI_MAJOR_VERSION, DPI_MINOR_VERSION, &g_DpiContext,
&errorInfo) < 0) {
Error_RaiseFromInfo(&errorInfo);
return NULL;
}
// set up the types that are available
ADD_TYPE_OBJECT("Binary", &cxBinary_Type)
ADD_TYPE_OBJECT("Connection", &g_ConnectionType)
@ -472,9 +557,8 @@ static PyObject *Module_Initialize(void)
ADD_TYPE_OBJECT("FIXED_CHAR", &g_FixedCharVarType)
ADD_TYPE_OBJECT("FIXED_NCHAR", &g_FixedNCharVarType)
ADD_TYPE_OBJECT("NCHAR", &g_NCharVarType)
ADD_TYPE_OBJECT("LONG_NCHAR", &g_LongNCharVarType)
ADD_TYPE_OBJECT("INTERVAL", &g_IntervalVarType)
ADD_TYPE_OBJECT("LOB", &g_ExternalLobVarType)
ADD_TYPE_OBJECT("LOB", &g_LOBType)
ADD_TYPE_OBJECT("LONG_BINARY", &g_LongBinaryVarType)
ADD_TYPE_OBJECT("LONG_STRING", &g_LongStringVarType)
ADD_TYPE_OBJECT("NCLOB", &g_NCLOBVarType)
@ -484,9 +568,7 @@ static PyObject *Module_Initialize(void)
ADD_TYPE_OBJECT("TIMESTAMP", &g_TimestampVarType)
ADD_TYPE_OBJECT("NATIVE_INT", &g_NativeIntVarType)
ADD_TYPE_OBJECT("NATIVE_FLOAT", &g_NativeFloatVarType)
#if ORACLE_VERSION_HEX >= ORACLE_VERSION(12, 1)
ADD_TYPE_OBJECT("BOOLEAN", &g_BooleanVarType)
#endif
// create constants required by Python DB API 2.0
if (PyModule_AddStringConstant(module, "apilevel", "2.0") < 0)
@ -508,108 +590,103 @@ static PyObject *Module_Initialize(void)
return NULL;
// add constants for authorization modes
ADD_INT_CONSTANT("SYSASM", OCI_SYSASM)
ADD_INT_CONSTANT("SYSDBA", OCI_SYSDBA)
ADD_INT_CONSTANT("SYSOPER", OCI_SYSOPER)
ADD_INT_CONSTANT("PRELIM_AUTH", OCI_PRELIM_AUTH)
ADD_INT_CONSTANT("SYSASM", DPI_MODE_AUTH_SYSASM)
ADD_INT_CONSTANT("SYSDBA", DPI_MODE_AUTH_SYSDBA)
ADD_INT_CONSTANT("SYSOPER", DPI_MODE_AUTH_SYSOPER)
ADD_INT_CONSTANT("PRELIM_AUTH", DPI_MODE_AUTH_PRELIM)
// add constants for session pool get modes
ADD_INT_CONSTANT("SPOOL_ATTRVAL_WAIT", OCI_SPOOL_ATTRVAL_WAIT)
ADD_INT_CONSTANT("SPOOL_ATTRVAL_NOWAIT", OCI_SPOOL_ATTRVAL_NOWAIT)
ADD_INT_CONSTANT("SPOOL_ATTRVAL_FORCEGET", OCI_SPOOL_ATTRVAL_FORCEGET)
ADD_INT_CONSTANT("SPOOL_ATTRVAL_WAIT", DPI_MODE_POOL_GET_WAIT)
ADD_INT_CONSTANT("SPOOL_ATTRVAL_NOWAIT", DPI_MODE_POOL_GET_NOWAIT)
ADD_INT_CONSTANT("SPOOL_ATTRVAL_FORCEGET", DPI_MODE_POOL_GET_FORCEGET)
// add constants for database shutdown modes
ADD_INT_CONSTANT("DBSHUTDOWN_ABORT", OCI_DBSHUTDOWN_ABORT)
ADD_INT_CONSTANT("DBSHUTDOWN_FINAL", OCI_DBSHUTDOWN_FINAL)
ADD_INT_CONSTANT("DBSHUTDOWN_IMMEDIATE", OCI_DBSHUTDOWN_IMMEDIATE)
ADD_INT_CONSTANT("DBSHUTDOWN_TRANSACTIONAL", OCI_DBSHUTDOWN_TRANSACTIONAL)
ADD_INT_CONSTANT("DBSHUTDOWN_ABORT", DPI_MODE_SHUTDOWN_ABORT)
ADD_INT_CONSTANT("DBSHUTDOWN_FINAL", DPI_MODE_SHUTDOWN_FINAL)
ADD_INT_CONSTANT("DBSHUTDOWN_IMMEDIATE", DPI_MODE_SHUTDOWN_IMMEDIATE)
ADD_INT_CONSTANT("DBSHUTDOWN_TRANSACTIONAL",
DPI_MODE_SHUTDOWN_TRANSACTIONAL)
ADD_INT_CONSTANT("DBSHUTDOWN_TRANSACTIONAL_LOCAL",
OCI_DBSHUTDOWN_TRANSACTIONAL_LOCAL)
DPI_MODE_SHUTDOWN_TRANSACTIONAL_LOCAL)
// add constants for purity
ADD_INT_CONSTANT("ATTR_PURITY_DEFAULT", OCI_ATTR_PURITY_DEFAULT)
ADD_INT_CONSTANT("ATTR_PURITY_NEW", OCI_ATTR_PURITY_NEW)
ADD_INT_CONSTANT("ATTR_PURITY_SELF", OCI_ATTR_PURITY_SELF)
ADD_INT_CONSTANT("ATTR_PURITY_DEFAULT", DPI_PURITY_DEFAULT)
ADD_INT_CONSTANT("ATTR_PURITY_NEW", DPI_PURITY_NEW)
ADD_INT_CONSTANT("ATTR_PURITY_SELF", DPI_PURITY_SELF)
// add constants for subscription protocols
ADD_INT_CONSTANT("SUBSCR_PROTO_OCI", OCI_SUBSCR_PROTO_OCI)
ADD_INT_CONSTANT("SUBSCR_PROTO_MAIL", OCI_SUBSCR_PROTO_MAIL)
ADD_INT_CONSTANT("SUBSCR_PROTO_SERVER", OCI_SUBSCR_PROTO_SERVER)
ADD_INT_CONSTANT("SUBSCR_PROTO_HTTP", OCI_SUBSCR_PROTO_HTTP)
ADD_INT_CONSTANT("SUBSCR_PROTO_OCI", DPI_SUBSCR_PROTO_CALLBACK)
ADD_INT_CONSTANT("SUBSCR_PROTO_MAIL", DPI_SUBSCR_PROTO_MAIL)
ADD_INT_CONSTANT("SUBSCR_PROTO_SERVER", DPI_SUBSCR_PROTO_PLSQL)
ADD_INT_CONSTANT("SUBSCR_PROTO_HTTP", DPI_SUBSCR_PROTO_HTTP)
// add constants for subscription quality of service
ADD_INT_CONSTANT("SUBSCR_QOS_RELIABLE", CX_SUBSCR_QOS_RELIABLE)
ADD_INT_CONSTANT("SUBSCR_QOS_DEREG_NFY", CX_SUBSCR_QOS_DEREG_NFY)
ADD_INT_CONSTANT("SUBSCR_QOS_ROWIDS", CX_SUBSCR_QOS_ROWIDS)
ADD_INT_CONSTANT("SUBSCR_QOS_QUERY", CX_SUBSCR_QOS_QUERY)
ADD_INT_CONSTANT("SUBSCR_QOS_BEST_EFFORT", CX_SUBSCR_QOS_BEST_EFFORT)
// add constants for deprecated subscription quality of service
ADD_INT_CONSTANT("SUBSCR_CQ_QOS_PURGE_ON_NTFN", CX_SUBSCR_QOS_DEREG_NFY)
ADD_INT_CONSTANT("SUBSCR_CQ_QOS_QUERY", CX_SUBSCR_QOS_QUERY)
ADD_INT_CONSTANT("SUBSCR_CQ_QOS_BEST_EFFORT",
OCI_SUBSCR_CQ_QOS_BEST_EFFORT)
ADD_INT_CONSTANT("SUBSCR_QOS_RELIABLE", DPI_SUBSCR_QOS_RELIABLE)
ADD_INT_CONSTANT("SUBSCR_QOS_DEREG_NFY", DPI_SUBSCR_QOS_DEREG_NFY)
ADD_INT_CONSTANT("SUBSCR_QOS_ROWIDS", DPI_SUBSCR_QOS_ROWIDS)
ADD_INT_CONSTANT("SUBSCR_QOS_QUERY", DPI_SUBSCR_QOS_QUERY)
ADD_INT_CONSTANT("SUBSCR_QOS_BEST_EFFORT", DPI_SUBSCR_QOS_BEST_EFFORT)
// add constants for subscription namespaces
ADD_INT_CONSTANT("SUBSCR_NAMESPACE_DBCHANGE",
OCI_SUBSCR_NAMESPACE_DBCHANGE)
DPI_SUBSCR_NAMESPACE_DBCHANGE)
// add constants for event types
ADD_INT_CONSTANT("EVENT_NONE", OCI_EVENT_NONE)
ADD_INT_CONSTANT("EVENT_STARTUP", OCI_EVENT_STARTUP)
ADD_INT_CONSTANT("EVENT_SHUTDOWN", OCI_EVENT_SHUTDOWN)
ADD_INT_CONSTANT("EVENT_SHUTDOWN_ANY", OCI_EVENT_SHUTDOWN_ANY)
ADD_INT_CONSTANT("EVENT_DEREG", OCI_EVENT_DEREG)
ADD_INT_CONSTANT("EVENT_OBJCHANGE", OCI_EVENT_OBJCHANGE)
ADD_INT_CONSTANT("EVENT_QUERYCHANGE", OCI_EVENT_QUERYCHANGE)
ADD_INT_CONSTANT("EVENT_NONE", DPI_EVENT_NONE)
ADD_INT_CONSTANT("EVENT_STARTUP", DPI_EVENT_STARTUP)
ADD_INT_CONSTANT("EVENT_SHUTDOWN", DPI_EVENT_SHUTDOWN)
ADD_INT_CONSTANT("EVENT_SHUTDOWN_ANY", DPI_EVENT_SHUTDOWN_ANY)
ADD_INT_CONSTANT("EVENT_DEREG", DPI_EVENT_DEREG)
ADD_INT_CONSTANT("EVENT_OBJCHANGE", DPI_EVENT_OBJCHANGE)
ADD_INT_CONSTANT("EVENT_QUERYCHANGE", DPI_EVENT_QUERYCHANGE)
// add constants for opcodes
ADD_INT_CONSTANT("OPCODE_ALLOPS", OCI_OPCODE_ALLOPS)
ADD_INT_CONSTANT("OPCODE_ALLROWS", OCI_OPCODE_ALLROWS)
ADD_INT_CONSTANT("OPCODE_INSERT", OCI_OPCODE_INSERT)
ADD_INT_CONSTANT("OPCODE_UPDATE", OCI_OPCODE_UPDATE)
ADD_INT_CONSTANT("OPCODE_DELETE", OCI_OPCODE_DELETE)
ADD_INT_CONSTANT("OPCODE_ALTER", OCI_OPCODE_ALTER)
ADD_INT_CONSTANT("OPCODE_DROP", OCI_OPCODE_DROP)
ADD_INT_CONSTANT("OPCODE_ALLOPS", DPI_OPCODE_ALL_OPS)
ADD_INT_CONSTANT("OPCODE_ALLROWS", DPI_OPCODE_ALL_ROWS)
ADD_INT_CONSTANT("OPCODE_INSERT", DPI_OPCODE_INSERT)
ADD_INT_CONSTANT("OPCODE_UPDATE", DPI_OPCODE_UPDATE)
ADD_INT_CONSTANT("OPCODE_DELETE", DPI_OPCODE_DELETE)
ADD_INT_CONSTANT("OPCODE_ALTER", DPI_OPCODE_ALTER)
ADD_INT_CONSTANT("OPCODE_DROP", DPI_OPCODE_DROP)
// add constants for AQ dequeue modes
ADD_INT_CONSTANT("DEQ_BROWSE", OCI_DEQ_BROWSE)
ADD_INT_CONSTANT("DEQ_LOCKED", OCI_DEQ_LOCKED)
ADD_INT_CONSTANT("DEQ_REMOVE", OCI_DEQ_REMOVE)
ADD_INT_CONSTANT("DEQ_REMOVE_NODATA", OCI_DEQ_REMOVE_NODATA)
ADD_INT_CONSTANT("DEQ_BROWSE", DPI_MODE_DEQ_BROWSE)
ADD_INT_CONSTANT("DEQ_LOCKED", DPI_MODE_DEQ_LOCKED)
ADD_INT_CONSTANT("DEQ_REMOVE", DPI_MODE_DEQ_REMOVE)
ADD_INT_CONSTANT("DEQ_REMOVE_NODATA", DPI_MODE_DEQ_REMOVE_NO_DATA)
// add constants for AQ dequeue navigation
ADD_INT_CONSTANT("DEQ_FIRST_MSG", OCI_DEQ_FIRST_MSG)
ADD_INT_CONSTANT("DEQ_NEXT_TRANSACTION", OCI_DEQ_NEXT_TRANSACTION)
ADD_INT_CONSTANT("DEQ_NEXT_MSG", OCI_DEQ_NEXT_MSG)
ADD_INT_CONSTANT("DEQ_FIRST_MSG", DPI_DEQ_NAV_FIRST_MSG)
ADD_INT_CONSTANT("DEQ_NEXT_TRANSACTION", DPI_DEQ_NAV_NEXT_TRANSACTION)
ADD_INT_CONSTANT("DEQ_NEXT_MSG", DPI_DEQ_NAV_NEXT_MSG)
// add constants for AQ dequeue visibility
ADD_INT_CONSTANT("DEQ_IMMEDIATE", OCI_DEQ_IMMEDIATE)
ADD_INT_CONSTANT("DEQ_ON_COMMIT", OCI_DEQ_ON_COMMIT)
ADD_INT_CONSTANT("DEQ_IMMEDIATE", DPI_VISIBILITY_IMMEDIATE)
ADD_INT_CONSTANT("DEQ_ON_COMMIT", DPI_VISIBILITY_ON_COMMIT)
// add constants for AQ dequeue wait
ADD_INT_CONSTANT("DEQ_NO_WAIT", OCI_DEQ_NO_WAIT)
ADD_INT_CONSTANT("DEQ_WAIT_FOREVER", OCI_DEQ_WAIT_FOREVER)
ADD_INT_CONSTANT("DEQ_NO_WAIT", DPI_DEQ_WAIT_NO_WAIT)
ADD_INT_CONSTANT("DEQ_WAIT_FOREVER", DPI_DEQ_WAIT_FOREVER)
// add constants for AQ enqueue visibility
ADD_INT_CONSTANT("ENQ_IMMEDIATE", OCI_ENQ_IMMEDIATE)
ADD_INT_CONSTANT("ENQ_ON_COMMIT", OCI_ENQ_ON_COMMIT)
ADD_INT_CONSTANT("ENQ_IMMEDIATE", DPI_VISIBILITY_IMMEDIATE)
ADD_INT_CONSTANT("ENQ_ON_COMMIT", DPI_VISIBILITY_ON_COMMIT)
// add constants for AQ table purge mode (message)
ADD_INT_CONSTANT("MSG_PERSISTENT", OCI_MSG_PERSISTENT)
ADD_INT_CONSTANT("MSG_BUFFERED", OCI_MSG_BUFFERED)
ADD_INT_CONSTANT("MSG_PERSISTENT", DPI_MODE_MSG_PERSISTENT)
ADD_INT_CONSTANT("MSG_BUFFERED", DPI_MODE_MSG_BUFFERED)
ADD_INT_CONSTANT("MSG_PERSISTENT_OR_BUFFERED",
OCI_MSG_PERSISTENT_OR_BUFFERED)
DPI_MODE_MSG_PERSISTENT_OR_BUFFERED)
// add constants for AQ message state
ADD_INT_CONSTANT("MSG_EXPIRED", OCI_MSG_EXPIRED)
ADD_INT_CONSTANT("MSG_READY", OCI_MSG_READY)
ADD_INT_CONSTANT("MSG_PROCESSED", OCI_MSG_PROCESSED)
ADD_INT_CONSTANT("MSG_WAITING", OCI_MSG_WAITING)
ADD_INT_CONSTANT("MSG_EXPIRED", DPI_MSG_STATE_EXPIRED)
ADD_INT_CONSTANT("MSG_READY", DPI_MSG_STATE_READY)
ADD_INT_CONSTANT("MSG_PROCESSED", DPI_MSG_STATE_PROCESSED)
ADD_INT_CONSTANT("MSG_WAITING", DPI_MSG_STATE_WAITING)
// add special constants for AQ delay/expiration
ADD_INT_CONSTANT("MSG_NO_DELAY", OCI_MSG_NO_DELAY)
ADD_INT_CONSTANT("MSG_NO_EXPIRATION", OCI_MSG_NO_EXPIRATION)
ADD_INT_CONSTANT("MSG_NO_DELAY", 0)
ADD_INT_CONSTANT("MSG_NO_EXPIRATION", -1)
return module;
}
@ -630,3 +707,30 @@ void initcx_Oracle(void)
}
#endif
//-----------------------------------------------------------------------------
// include all DPI files
//-----------------------------------------------------------------------------
#include "dpiConn.c"
#include "dpiContext.c"
#include "dpiData.c"
#include "dpiDeqOptions.c"
#include "dpiEnqOptions.c"
#include "dpiEnv.c"
#include "dpiError.c"
#include "dpiGen.c"
#include "dpiGlobal.c"
#include "dpiLob.c"
#include "dpiMsgProps.c"
#include "dpiObject.c"
#include "dpiObjectAttr.c"
#include "dpiObjectType.c"
#include "dpiOracleType.c"
#include "dpiPool.c"
#include "dpiRowid.c"
#include "dpiStmt.c"
#include "dpiSubscr.c"
#include "dpiUtils.c"
#include "dpiVar.c"

View File

@ -49,7 +49,7 @@ class TestConnection(TestCase):
connection = cx_Oracle.connect(self.username, self.password,
self.tnsentry)
connection.close()
self.assertRaises(cx_Oracle.InterfaceError, connection.rollback)
self.assertRaises(cx_Oracle.DatabaseError, connection.rollback)
def testMakeDSN(self):
"test making a data source name from host, port and sid"

View File

@ -19,7 +19,6 @@ class TestError(BaseTestCase):
self.assertTrue("Test!" in errorObj.message)
self.assertEqual(errorObj.code, 20101)
self.assertEqual(errorObj.offset, 0)
self.assertEqual(errorObj.context, "Cursor_InternalExecute()")
self.assertTrue(isinstance(errorObj.isrecoverable, bool))
pickledData = pickle.dumps(errorObj)
newErrorObj = pickle.loads(pickledData)

View File

@ -120,6 +120,35 @@ class TestFeatures12_1(BaseTestCase):
self.cursor.callproc("pkg_TestNumberArrays.TestOutArrays", (3, obj))
self.assertEqual(obj.aslist(), [100, 200, 300])
def testBindPLSQLRecordArray(self):
"test binding an array of PL/SQL records (in)"
recType = self.connection.gettype("PKG_TESTRECORDS.UDT_RECORD")
arrayType = self.connection.gettype("PKG_TESTRECORDS.UDT_RECORDARRAY")
arrayObj = arrayType.newobject()
for i in range(3):
obj = recType.newobject()
obj.NUMBERVALUE = i + 1
obj.STRINGVALUE = "String in record #%d" % (i + 1)
obj.DATEVALUE = datetime.datetime(2017, i + 1, 1)
obj.TIMESTAMPVALUE = datetime.datetime(2017, 1, i + 1)
obj.BOOLEANVALUE = (i % 2) == 1
arrayObj.append(obj)
result = self.cursor.callfunc("pkg_TestRecords.TestInArrays", str,
(arrayObj,))
self.assertEqual(result,
"udt_Record(1, 'String in record #1', " \
"to_date('2017-01-01', 'YYYY-MM-DD'), " \
"to_timestamp('2017-01-01 00:00:00', " \
"'YYYY-MM-DD HH24:MI:SS'), false); " \
"udt_Record(2, 'String in record #2', " \
"to_date('2017-02-01', 'YYYY-MM-DD'), " \
"to_timestamp('2017-01-02 00:00:00', " \
"'YYYY-MM-DD HH24:MI:SS'), true); " \
"udt_Record(3, 'String in record #3', " \
"to_date('2017-03-01', 'YYYY-MM-DD'), " \
"to_timestamp('2017-01-03 00:00:00', " \
"'YYYY-MM-DD HH24:MI:SS'), false)")
def testBindPLSQLRecordIn(self):
"test binding a PL/SQL record (in)"
typeObj = self.connection.gettype("PKG_TESTRECORDS.UDT_RECORD")
@ -312,9 +341,9 @@ class TestFeatures12_1(BaseTestCase):
arraydmlrowcounts = True)
expectedErrors = [
( 4, 1438, "ORA-01438: value larger than specified " \
"precision allowed for this column\n" ),
"precision allowed for this column" ),
( 2, 1, "ORA-00001: unique constraint " \
"(CX_ORACLE.TESTARRAYDML_PK) violated\n")
"(CX_ORACLE.TESTARRAYDML_PK) violated")
]
actualErrors = [(e.offset, e.code, e.message) \
for e in self.cursor.getbatcherrors()]
@ -349,7 +378,7 @@ class TestFeatures12_1(BaseTestCase):
self.cursor.executemany(sql, rows, batcherrors = True)
expectedErrors = [
( 6, 1, "ORA-00001: unique constraint " \
"(CX_ORACLE.TESTARRAYDML_PK) violated\n")
"(CX_ORACLE.TESTARRAYDML_PK) violated")
]
actualErrors = [(e.offset, e.code, e.message) \
for e in self.cursor.getbatcherrors()]
@ -364,7 +393,7 @@ class TestFeatures12_1(BaseTestCase):
batcherrors = True)
expectedErrors = [
( 2, 1438, "ORA-01438: value larger than specified " \
"precision allowed for this column\n" )
"precision allowed for this column" )
]
actualErrors = [(e.offset, e.code, e.message) \
for e in self.cursor.getbatcherrors()]

View File

@ -76,7 +76,7 @@ class TestLobVar(BaseTestCase):
def __ValidateQuery(self, rows, lobType):
longString = ""
for row in self.cursor:
for row in rows:
integerValue, lob = row
if integerValue == 0:
self.assertEqual(lob.size(), 0)

View File

@ -26,7 +26,6 @@ class TestLongVar(BaseTestCase):
integerValue = i,
longString = bindValue)
self.connection.commit()
self.cursor.setoutputsize(250000, 2)
self.cursor.execute("""
select *
from Test%ss
@ -76,7 +75,6 @@ class TestLongVar(BaseTestCase):
self.cursor.execute("select * from TestLongRaws")
longVar = self.cursor.fetchvars[1]
self.assertEqual(longVar.size, 25000)
self.assertEqual(longVar.bufferSize, 25004)
def testSetOutputSizesWrongColumn(self):
"test setoutputsizes is valid (wrong column)"
@ -84,8 +82,6 @@ class TestLongVar(BaseTestCase):
self.cursor.execute("select * from TestLongs")
longVar = self.cursor.fetchvars[1]
self.assertEqual(longVar.size, 131072)
self.assertEqual(longVar.bufferSize,
131072 * self.connection.maxBytesPerCharacter + 4)
def testSetOutputSizesRightColumn(self):
"test setoutputsizes is valid (right column)"
@ -93,11 +89,10 @@ class TestLongVar(BaseTestCase):
self.cursor.execute("select * from TestLongRaws")
longVar = self.cursor.fetchvars[1]
self.assertEqual(longVar.size, 35000)
self.assertEqual(longVar.bufferSize, 35004)
def testArraySizeTooLarge(self):
"test array size too large generates an exception"
self.cursor.arraysize = 65536
self.assertRaises(ValueError, self.cursor.execute,
self.cursor.arraysize = 268435456
self.assertRaises(cx_Oracle.DatabaseError, self.cursor.execute,
"select * from TestLongRaws")

View File

@ -49,7 +49,7 @@ class TestConnection(TestCase):
connection = cx_Oracle.connect(self.username, self.password,
self.tnsentry)
connection.close()
self.assertRaises(cx_Oracle.InterfaceError, connection.rollback)
self.assertRaises(cx_Oracle.DatabaseError, connection.rollback)
def testMakeDSN(self):
"test making a data source name from host, port and sid"

View File

@ -103,9 +103,9 @@ class TestArrayDMLBatchError(BaseTestCase):
arraydmlrowcounts = True)
expectedErrors = [
( 4, 1438, u"ORA-01438: value larger than specified " \
u"precision allowed for this column\n" ),
u"precision allowed for this column" ),
( 2, 1, u"ORA-00001: unique constraint " \
u"(CX_ORACLE.TESTARRAYDML_PK) violated\n")
u"(CX_ORACLE.TESTARRAYDML_PK) violated")
]
actualErrors = [(e.offset, e.code, e.message) \
for e in self.cursor.getbatcherrors()]
@ -140,7 +140,7 @@ class TestArrayDMLBatchError(BaseTestCase):
self.cursor.executemany(sql, rows, batcherrors = True)
expectedErrors = [
( 6, 1, u"ORA-00001: unique constraint " \
u"(CX_ORACLE.TESTARRAYDML_PK) violated\n")
u"(CX_ORACLE.TESTARRAYDML_PK) violated")
]
actualErrors = [(e.offset, e.code, e.message) \
for e in self.cursor.getbatcherrors()]
@ -155,7 +155,7 @@ class TestArrayDMLBatchError(BaseTestCase):
batcherrors = True)
expectedErrors = [
( 2, 1438, u"ORA-01438: value larger than specified " \
u"precision allowed for this column\n" )
u"precision allowed for this column" )
]
actualErrors = [(e.offset, e.code, e.message) \
for e in self.cursor.getbatcherrors()]

View File

@ -124,13 +124,6 @@ class TestLobVar(BaseTestCase):
"test trimming a CLOB"
self.__TestTrim("CLOB")
def testMultipleFetch(self):
"test retrieving data from a CLOB after multiple fetches"
self.cursor.arraysize = 1
self.cursor.execute(u"select CLOBCol from TestCLOBS")
rows = self.cursor.fetchall()
self.assertRaises(cx_Oracle.ProgrammingError, rows[1][0].read)
def testNCLOBCursorDescription(self):
"test cursor description is accurate for NCLOBs"
self.cursor.execute(u"select * from TestNCLOBs")

View File

@ -72,7 +72,6 @@ class TestLongVar(BaseTestCase):
self.cursor.execute(u"select * from TestLongRaws")
longVar = self.cursor.fetchvars[1]
self.assertEqual(longVar.size, 25000)
self.assertEqual(longVar.bufferSize, 25004)
def testSetOutputSizesWrongColumn(self):
"test setoutputsizes is valid (wrong column)"
@ -80,11 +79,10 @@ class TestLongVar(BaseTestCase):
self.cursor.execute(u"select * from TestLongRaws")
longVar = self.cursor.fetchvars[1]
self.assertEqual(longVar.size, 131072)
self.assertEqual(longVar.bufferSize, 131076)
def testArraySizeTooLarge(self):
"test array size too large generates an exception"
self.cursor.arraysize = 65536
self.assertRaises(ValueError, self.cursor.execute,
self.cursor.arraysize = 268435456
self.assertRaises(cx_Oracle.DatabaseError, self.cursor.execute,
u"select * from TestLongRaws")