From bab41ac5440f9ec9f99dfdb38d24e007397b4a00 Mon Sep 17 00:00:00 2001 From: Anthony Tuininga Date: Wed, 16 May 2018 14:08:28 -0600 Subject: [PATCH] Added support for specifying the IP address the subscription should use instead of having the Oracle Client library determine the IP address on its own. --- doc/src/connection.rst | 6 +++++- doc/src/subscription.rst | 7 +++++++ src/cxoConnection.c | 14 +++++++------- src/cxoModule.h | 6 ++++-- src/cxoSubscr.c | 19 +++++++++++++++++-- 5 files changed, 40 insertions(+), 12 deletions(-) diff --git a/doc/src/connection.rst b/doc/src/connection.rst index da6d785..b6f6002 100644 --- a/doc/src/connection.rst +++ b/doc/src/connection.rst @@ -480,7 +480,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, port=0, qos=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, ipAddress=None) Return a new :ref:`subscription object ` using the connection. Currently the namespace and protocol parameters cannot have any other @@ -510,6 +510,10 @@ Connection Object :data:`cx_Oracle.SUBSCR_QOS_QUERY`, :data:`cx_Oracle.SUBSCR_QOS_BEST_EFFORT`. + The ipAddress specifies the IP address (IPv4 or IPv6) to bind for callback + notifications from the database server. If not specified, the client IP + address will be determined by the Oracle Client libraries. + .. note:: This method is an extension to the DB API definition. diff --git a/doc/src/subscription.rst b/doc/src/subscription.rst index e3e7426..ca837f9 100644 --- a/doc/src/subscription.rst +++ b/doc/src/subscription.rst @@ -43,6 +43,13 @@ Subscription Object subscription. +.. attribute:: Subscription.ipAddress + + This read-only attribute returns the IP address used for callback + notifications from the database server. If not set during construction, + this value is None. + + .. attribute:: Subscription.port This read-only attribute returns the port used for callback notifications diff --git a/src/cxoConnection.c b/src/cxoConnection.c index f152fb1..aaa8906 100644 --- a/src/cxoConnection.c +++ b/src/cxoConnection.c @@ -1456,21 +1456,21 @@ static PyObject *cxoConnection_subscribe(cxoConnection *conn, PyObject* args, PyObject* keywordArgs) { static char *keywordList[] = { "namespace", "protocol", "callback", - "timeout", "operations", "port", "qos", NULL }; + "timeout", "operations", "port", "qos", "ipAddress", NULL }; uint32_t namespace, protocol, port, timeout, operations, qos; - PyObject *callback; + PyObject *callback, *ipAddress; - callback = NULL; timeout = port = qos = 0; + callback = ipAddress = NULL; namespace = DPI_SUBSCR_NAMESPACE_DBCHANGE; protocol = DPI_SUBSCR_PROTO_CALLBACK; operations = DPI_OPCODE_ALL_OPS; - if (!PyArg_ParseTupleAndKeywords(args, keywordArgs, "|iiOiiii", + if (!PyArg_ParseTupleAndKeywords(args, keywordArgs, "|iiOiiiiO", keywordList, &namespace, &protocol, &callback, &timeout, - &operations, &port, &qos)) + &operations, &port, &qos, &ipAddress)) return NULL; - return (PyObject*) cxoSubscr_new(conn, namespace, protocol, port, callback, - timeout, operations, qos); + return (PyObject*) cxoSubscr_new(conn, namespace, protocol, ipAddress, + port, callback, timeout, operations, qos); } diff --git a/src/cxoModule.h b/src/cxoModule.h index f4b8a4d..e4bff23 100644 --- a/src/cxoModule.h +++ b/src/cxoModule.h @@ -359,6 +359,7 @@ struct cxoSubscr { PyObject *callback; uint32_t namespace; uint32_t protocol; + PyObject *ipAddress; uint32_t port; uint32_t timeout; uint32_t operations; @@ -430,8 +431,9 @@ cxoObjectType *cxoObjectType_newByName(cxoConnection *connection, PyObject *name); cxoSubscr *cxoSubscr_new(cxoConnection *connection, uint32_t namespace, - uint32_t protocol, uint32_t port, PyObject *callback, uint32_t timeout, - uint32_t operations, uint32_t qos); + uint32_t protocol, PyObject *ipAddress, uint32_t port, + PyObject *callback, uint32_t timeout, uint32_t operations, + uint32_t qos); PyObject *cxoTransform_dateFromTicks(PyObject *args); int cxoTransform_fromPython(cxoTransformNum transformNum, PyObject *pyValue, diff --git a/src/cxoSubscr.c b/src/cxoSubscr.c index c96dd86..8c8bf51 100644 --- a/src/cxoSubscr.c +++ b/src/cxoSubscr.c @@ -34,6 +34,7 @@ static PyMemberDef cxoSubscrTypeMembers[] = { READONLY }, { "namespace", T_INT, offsetof(cxoSubscr, namespace), READONLY }, { "protocol", T_INT, offsetof(cxoSubscr, protocol), READONLY }, + { "ipAddress", T_OBJECT, offsetof(cxoSubscr, ipAddress), READONLY }, { "port", T_INT, offsetof(cxoSubscr, port), READONLY }, { "timeout", T_INT, offsetof(cxoSubscr, timeout), READONLY }, { "operations", T_INT, offsetof(cxoSubscr, operations), READONLY }, @@ -517,11 +518,13 @@ static void cxoSubscr_callback(cxoSubscr *subscr, // Allocate a new subscription object. //----------------------------------------------------------------------------- cxoSubscr *cxoSubscr_new(cxoConnection *connection, uint32_t namespace, - uint32_t protocol, uint32_t port, PyObject *callback, uint32_t timeout, - uint32_t operations, uint32_t qos) + uint32_t protocol, PyObject *ipAddress, uint32_t port, + PyObject *callback, uint32_t timeout, uint32_t operations, + uint32_t qos) { dpiSubscrCreateParams params; cxoSubscr *subscr; + cxoBuffer buffer; subscr = (cxoSubscr*) cxoPyTypeSubscr.tp_alloc(&cxoPyTypeSubscr, 0); if (!subscr) @@ -532,6 +535,8 @@ cxoSubscr *cxoSubscr_new(cxoConnection *connection, uint32_t namespace, subscr->callback = callback; subscr->namespace = namespace; subscr->protocol = protocol; + Py_XINCREF(ipAddress); + subscr->ipAddress = ipAddress; subscr->port = port; subscr->timeout = timeout; subscr->operations = operations; @@ -539,10 +544,20 @@ cxoSubscr *cxoSubscr_new(cxoConnection *connection, uint32_t namespace, if (dpiContext_initSubscrCreateParams(cxoDpiContext, ¶ms) < 0) { cxoError_raiseAndReturnNull(); + Py_DECREF(subscr); return NULL; } params.subscrNamespace = namespace; params.protocol = protocol; + if (ipAddress) { + if (cxoBuffer_fromObject(&buffer, ipAddress, + connection->encodingInfo.encoding) < 0) { + Py_DECREF(subscr); + return NULL; + } + params.ipAddress = buffer.ptr; + params.ipAddressLength = buffer.size; + } params.portNumber = port; if (callback) { params.callback = (dpiSubscrCallback) cxoSubscr_callback;