1997 lines
74 KiB
C
1997 lines
74 KiB
C
//-----------------------------------------------------------------------------
|
|
// Connection.c
|
|
// Definition of the Python type OracleConnection.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// structure for the Python type "Connection"
|
|
//-----------------------------------------------------------------------------
|
|
typedef struct {
|
|
PyObject_HEAD
|
|
OCISvcCtx *handle;
|
|
OCIServer *serverHandle;
|
|
OCISession *sessionHandle;
|
|
udt_Environment *environment;
|
|
udt_SessionPool *sessionPool;
|
|
PyObject *inputTypeHandler;
|
|
PyObject *outputTypeHandler;
|
|
PyObject *username;
|
|
PyObject *dsn;
|
|
PyObject *version;
|
|
ub4 commitMode;
|
|
int autocommit;
|
|
int release;
|
|
int attached;
|
|
} udt_Connection;
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// constants for the OCI attributes
|
|
//-----------------------------------------------------------------------------
|
|
static ub4 gc_ClientIdentifierAttribute = OCI_ATTR_CLIENT_IDENTIFIER;
|
|
static ub4 gc_ModuleAttribute = OCI_ATTR_MODULE;
|
|
static ub4 gc_ActionAttribute = OCI_ATTR_ACTION;
|
|
static ub4 gc_ClientInfoAttribute = OCI_ATTR_CLIENT_INFO;
|
|
|
|
#if ORACLE_VERSION_HEX >= ORACLE_VERSION(10, 2)
|
|
static ub4 gc_CurrentSchemaAttribute = OCI_ATTR_CURRENT_SCHEMA;
|
|
#endif
|
|
|
|
#if ORACLE_VERSION_HEX >= ORACLE_VERSION(11, 2)
|
|
static ub4 gc_EditionAttribute = OCI_ATTR_EDITION;
|
|
#endif
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// functions for the Python type "Connection"
|
|
//-----------------------------------------------------------------------------
|
|
static void Connection_Free(udt_Connection*);
|
|
static PyObject *Connection_New(PyTypeObject*, PyObject*, PyObject*);
|
|
static int Connection_Init(udt_Connection*, PyObject*, PyObject*);
|
|
static PyObject *Connection_Repr(udt_Connection*);
|
|
static PyObject *Connection_Close(udt_Connection*, PyObject*);
|
|
static PyObject *Connection_Commit(udt_Connection*, PyObject*);
|
|
static PyObject *Connection_Begin(udt_Connection*, PyObject*);
|
|
static PyObject *Connection_Prepare(udt_Connection*, PyObject*);
|
|
static PyObject *Connection_Rollback(udt_Connection*, PyObject*);
|
|
static PyObject *Connection_NewCursor(udt_Connection*, PyObject*, PyObject*);
|
|
static PyObject *Connection_Cancel(udt_Connection*, PyObject*);
|
|
static PyObject *Connection_RegisterCallback(udt_Connection*, PyObject*);
|
|
static PyObject *Connection_UnregisterCallback(udt_Connection*, PyObject*);
|
|
static PyObject *Connection_GetVersion(udt_Connection*, void*);
|
|
static PyObject *Connection_GetEncoding(udt_Connection*, void*);
|
|
static PyObject *Connection_GetNationalEncoding(udt_Connection*, void*);
|
|
static PyObject *Connection_GetMaxBytesPerCharacter(udt_Connection*, void*);
|
|
static PyObject *Connection_ContextManagerEnter(udt_Connection*, PyObject*);
|
|
static PyObject *Connection_ContextManagerExit(udt_Connection*, PyObject*);
|
|
static PyObject *Connection_ChangePasswordExternal(udt_Connection*, PyObject*);
|
|
static PyObject *Connection_GetType(udt_Connection*, PyObject*);
|
|
static PyObject *Connection_GetStmtCacheSize(udt_Connection*, void*);
|
|
static PyObject *Connection_NewEnqueueOptions(udt_Connection*, PyObject*);
|
|
static PyObject *Connection_NewDequeueOptions(udt_Connection*, PyObject*);
|
|
static PyObject *Connection_NewMessageProperties(udt_Connection*, PyObject*);
|
|
static PyObject *Connection_Dequeue(udt_Connection*, PyObject*, PyObject*);
|
|
static PyObject *Connection_Enqueue(udt_Connection*, PyObject*, PyObject*);
|
|
static int Connection_SetStmtCacheSize(udt_Connection*, PyObject*, void*);
|
|
#if ORACLE_VERSION_HEX >= ORACLE_VERSION(10, 2)
|
|
static PyObject *Connection_GetOCIAttr(udt_Connection*, ub4*);
|
|
#endif
|
|
static int Connection_SetOCIAttr(udt_Connection*, PyObject*, ub4*);
|
|
#if ORACLE_VERSION_HEX >= ORACLE_VERSION(10, 2)
|
|
#if !defined(AIX5) || ORACLE_VERSION_HEX >= ORACLE_VERSION(11, 1)
|
|
static PyObject *Connection_Ping(udt_Connection*, PyObject*);
|
|
#endif
|
|
static PyObject *Connection_Shutdown(udt_Connection*, PyObject*, PyObject*);
|
|
static PyObject *Connection_Startup(udt_Connection*, PyObject*, PyObject*);
|
|
static PyObject *Connection_Subscribe(udt_Connection*, PyObject*, PyObject*);
|
|
#endif
|
|
#if ORACLE_VERSION_HEX >= ORACLE_VERSION(12, 1)
|
|
static PyObject *Connection_GetLTXID(udt_Connection*, void*);
|
|
#endif
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// declaration of methods for Python type "Connection"
|
|
//-----------------------------------------------------------------------------
|
|
static PyMethodDef g_ConnectionMethods[] = {
|
|
{ "cursor", (PyCFunction) Connection_NewCursor,
|
|
METH_VARARGS | METH_KEYWORDS },
|
|
{ "commit", (PyCFunction) Connection_Commit, METH_NOARGS },
|
|
{ "rollback", (PyCFunction) Connection_Rollback, METH_NOARGS },
|
|
{ "begin", (PyCFunction) Connection_Begin, METH_VARARGS },
|
|
{ "prepare", (PyCFunction) Connection_Prepare, METH_NOARGS },
|
|
{ "close", (PyCFunction) Connection_Close, METH_NOARGS },
|
|
{ "cancel", (PyCFunction) Connection_Cancel, METH_NOARGS },
|
|
{ "register", (PyCFunction) Connection_RegisterCallback, METH_VARARGS },
|
|
{ "unregister", (PyCFunction) Connection_UnregisterCallback, METH_VARARGS },
|
|
{ "__enter__", (PyCFunction) Connection_ContextManagerEnter, METH_NOARGS },
|
|
{ "__exit__", (PyCFunction) Connection_ContextManagerExit, METH_VARARGS },
|
|
#if ORACLE_VERSION_HEX >= ORACLE_VERSION(10, 2)
|
|
#if !defined(AIX5) || ORACLE_VERSION_HEX >= ORACLE_VERSION(11, 1)
|
|
{ "ping", (PyCFunction) Connection_Ping, METH_NOARGS },
|
|
#endif
|
|
{ "shutdown", (PyCFunction) Connection_Shutdown,
|
|
METH_VARARGS | METH_KEYWORDS},
|
|
{ "startup", (PyCFunction) Connection_Startup,
|
|
METH_VARARGS | METH_KEYWORDS},
|
|
{ "subscribe", (PyCFunction) Connection_Subscribe,
|
|
METH_VARARGS | METH_KEYWORDS},
|
|
#endif
|
|
{ "changepassword", (PyCFunction) Connection_ChangePasswordExternal,
|
|
METH_VARARGS },
|
|
{ "gettype", (PyCFunction) Connection_GetType, METH_VARARGS },
|
|
{ "deqoptions", (PyCFunction) Connection_NewDequeueOptions, METH_NOARGS },
|
|
{ "enqoptions", (PyCFunction) Connection_NewEnqueueOptions, METH_NOARGS },
|
|
{ "msgproperties", (PyCFunction) Connection_NewMessageProperties,
|
|
METH_NOARGS },
|
|
{ "deq", (PyCFunction) Connection_Dequeue, METH_VARARGS | METH_KEYWORDS },
|
|
{ "enq", (PyCFunction) Connection_Enqueue, METH_VARARGS | METH_KEYWORDS },
|
|
{ NULL }
|
|
};
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// declaration of members for Python type "Connection"
|
|
//-----------------------------------------------------------------------------
|
|
static PyMemberDef g_ConnectionMembers[] = {
|
|
{ "username", T_OBJECT, offsetof(udt_Connection, username), READONLY },
|
|
{ "dsn", T_OBJECT, offsetof(udt_Connection, dsn), READONLY },
|
|
{ "tnsentry", T_OBJECT, offsetof(udt_Connection, dsn), READONLY },
|
|
{ "autocommit", T_INT, offsetof(udt_Connection, autocommit), 0 },
|
|
{ "inputtypehandler", T_OBJECT,
|
|
offsetof(udt_Connection, inputTypeHandler), 0 },
|
|
{ "outputtypehandler", T_OBJECT,
|
|
offsetof(udt_Connection, outputTypeHandler), 0 },
|
|
{ NULL }
|
|
};
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// declaration of calculated members for Python type "Connection"
|
|
//-----------------------------------------------------------------------------
|
|
static PyGetSetDef g_ConnectionCalcMembers[] = {
|
|
{ "version", (getter) Connection_GetVersion, 0, 0, 0 },
|
|
{ "encoding", (getter) Connection_GetEncoding, 0, 0, 0 },
|
|
{ "nencoding", (getter) Connection_GetNationalEncoding, 0, 0, 0 },
|
|
{ "maxBytesPerCharacter", (getter) Connection_GetMaxBytesPerCharacter,
|
|
0, 0, 0 },
|
|
{ "stmtcachesize", (getter) Connection_GetStmtCacheSize,
|
|
(setter) Connection_SetStmtCacheSize, 0, 0 },
|
|
{ "module", 0, (setter) Connection_SetOCIAttr, 0, &gc_ModuleAttribute },
|
|
{ "action", 0, (setter) Connection_SetOCIAttr, 0, &gc_ActionAttribute },
|
|
{ "clientinfo", 0, (setter) Connection_SetOCIAttr, 0,
|
|
&gc_ClientInfoAttribute },
|
|
{ "client_identifier", 0, (setter) Connection_SetOCIAttr, 0,
|
|
&gc_ClientIdentifierAttribute },
|
|
#if ORACLE_VERSION_HEX >= ORACLE_VERSION(10, 2)
|
|
{ "current_schema", (getter) Connection_GetOCIAttr,
|
|
(setter) Connection_SetOCIAttr, 0, &gc_CurrentSchemaAttribute },
|
|
#endif
|
|
#if ORACLE_VERSION_HEX >= ORACLE_VERSION(11, 2)
|
|
{ "edition", (getter) Connection_GetOCIAttr, 0, 0, &gc_EditionAttribute },
|
|
#endif
|
|
#if ORACLE_VERSION_HEX >= ORACLE_VERSION(12, 1)
|
|
{ "ltxid", (getter) Connection_GetLTXID, 0, 0, 0 },
|
|
#endif
|
|
{ NULL }
|
|
};
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// declaration of Python type "Connection"
|
|
//-----------------------------------------------------------------------------
|
|
static PyTypeObject g_ConnectionType = {
|
|
PyVarObject_HEAD_INIT(NULL, 0)
|
|
"cx_Oracle.Connection", // tp_name
|
|
sizeof(udt_Connection), // tp_basicsize
|
|
0, // tp_itemsize
|
|
(destructor) Connection_Free, // tp_dealloc
|
|
0, // tp_print
|
|
0, // tp_getattr
|
|
0, // tp_setattr
|
|
0, // tp_compare
|
|
(reprfunc) Connection_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 | Py_TPFLAGS_BASETYPE,
|
|
// tp_flags
|
|
0, // tp_doc
|
|
0, // tp_traverse
|
|
0, // tp_clear
|
|
0, // tp_richcompare
|
|
0, // tp_weaklistoffset
|
|
0, // tp_iter
|
|
0, // tp_iternext
|
|
g_ConnectionMethods, // tp_methods
|
|
g_ConnectionMembers, // tp_members
|
|
g_ConnectionCalcMembers, // tp_getset
|
|
0, // tp_base
|
|
0, // tp_dict
|
|
0, // tp_descr_get
|
|
0, // tp_descr_set
|
|
0, // tp_dictoffset
|
|
(initproc) Connection_Init, // tp_init
|
|
0, // tp_alloc
|
|
(newfunc) Connection_New, // tp_new
|
|
0, // tp_free
|
|
0, // tp_is_gc
|
|
0 // tp_bases
|
|
};
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Connection_IsConnected()
|
|
// Determines if the connection object is connected to the database. If not,
|
|
// a Python exception is raised.
|
|
//-----------------------------------------------------------------------------
|
|
static int Connection_IsConnected(
|
|
udt_Connection *self) // connection to check
|
|
{
|
|
if (!self->handle) {
|
|
PyErr_SetString(g_InterfaceErrorException, "not connected");
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Connection_GetConnection()
|
|
// Get a connection using the OCISessionGet() interface rather than using
|
|
// the low level interface for connecting.
|
|
//-----------------------------------------------------------------------------
|
|
static int Connection_GetConnection(
|
|
udt_Connection *self, // connection
|
|
udt_SessionPool *pool, // pool to acquire connection from
|
|
PyObject *passwordObj, // password
|
|
PyObject *cclassObj, // connection class (DRCP)
|
|
ub4 purity) // purity (DRCP)
|
|
{
|
|
udt_Environment *environment;
|
|
int externalAuth, proxyAuth;
|
|
udt_Buffer buffer;
|
|
OCIAuthInfo *authInfo;
|
|
PyObject *dbNameObj;
|
|
boolean found;
|
|
sword status;
|
|
ub4 mode;
|
|
|
|
// set things up for the call to acquire a session
|
|
authInfo = NULL;
|
|
externalAuth = proxyAuth = 0;
|
|
if (pool) {
|
|
environment = pool->environment;
|
|
dbNameObj = pool->name;
|
|
mode = OCI_SESSGET_SPOOL;
|
|
externalAuth = pool->externalAuth;
|
|
if (!pool->homogeneous && pool->username && self->username) {
|
|
proxyAuth = PyObject_RichCompareBool(self->username,
|
|
pool->username, Py_NE);
|
|
if (proxyAuth < 0)
|
|
return -1;
|
|
mode = mode | OCI_SESSGET_CREDPROXY;
|
|
}
|
|
} else {
|
|
environment = self->environment;
|
|
dbNameObj = self->dsn;
|
|
mode = OCI_SESSGET_STMTCACHE;
|
|
}
|
|
|
|
// set up authorization handle, if needed
|
|
if (!pool || cclassObj || proxyAuth) {
|
|
|
|
// create authorization handle
|
|
status = OCIHandleAlloc(environment->handle, (dvoid*) &authInfo,
|
|
OCI_HTYPE_AUTHINFO, 0, NULL);
|
|
if (Environment_CheckForError(environment, status,
|
|
"Connection_GetConnection(): allocate handle") < 0)
|
|
return -1;
|
|
|
|
// set the user name, if applicable
|
|
externalAuth = 1;
|
|
if (cxBuffer_FromObject(&buffer, self->username,
|
|
self->environment->encoding) < 0)
|
|
return -1;
|
|
if (buffer.size > 0) {
|
|
externalAuth = 0;
|
|
status = OCIAttrSet(authInfo, OCI_HTYPE_AUTHINFO,
|
|
(text*) buffer.ptr, buffer.size, OCI_ATTR_USERNAME,
|
|
environment->errorHandle);
|
|
if (Environment_CheckForError(environment, status,
|
|
"Connection_GetConnection(): set user name") < 0) {
|
|
cxBuffer_Clear(&buffer);
|
|
return -1;
|
|
}
|
|
}
|
|
cxBuffer_Clear(&buffer);
|
|
|
|
// set the password, if applicable
|
|
if (cxBuffer_FromObject(&buffer, passwordObj,
|
|
self->environment->encoding) < 0)
|
|
return -1;
|
|
if (buffer.size > 0) {
|
|
externalAuth = 0;
|
|
status = OCIAttrSet(authInfo, OCI_HTYPE_AUTHINFO,
|
|
(text*) buffer.ptr, buffer.size, OCI_ATTR_PASSWORD,
|
|
environment->errorHandle);
|
|
if (Environment_CheckForError(environment, status,
|
|
"Connection_GetConnection(): set password") < 0) {
|
|
cxBuffer_Clear(&buffer);
|
|
return -1;
|
|
}
|
|
}
|
|
cxBuffer_Clear(&buffer);
|
|
|
|
#if ORACLE_VERSION_HEX >= ORACLE_VERSION(11, 1)
|
|
// set the connection class, if applicable
|
|
if (cxBuffer_FromObject(&buffer, cclassObj,
|
|
self->environment->encoding) < 0)
|
|
return -1;
|
|
if (buffer.size > 0) {
|
|
status = OCIAttrSet(authInfo, OCI_HTYPE_AUTHINFO,
|
|
(text*) buffer.ptr, buffer.size, OCI_ATTR_CONNECTION_CLASS,
|
|
environment->errorHandle);
|
|
if (Environment_CheckForError(environment, status,
|
|
"Connection_GetConnection(): set connection class") < 0) {
|
|
cxBuffer_Clear(&buffer);
|
|
return -1;
|
|
}
|
|
}
|
|
cxBuffer_Clear(&buffer);
|
|
|
|
// set the purity, if applicable
|
|
if (purity != OCI_ATTR_PURITY_DEFAULT) {
|
|
status = OCIAttrSet(authInfo, OCI_HTYPE_AUTHINFO, &purity,
|
|
sizeof(purity), OCI_ATTR_PURITY,
|
|
environment->errorHandle);
|
|
if (Environment_CheckForError(environment, status,
|
|
"Connection_GetConnection(): set purity") < 0)
|
|
return -1;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// external auth requested (no username/password or specified via pool)
|
|
if (externalAuth)
|
|
mode |= OCI_SESSGET_CREDEXT;
|
|
|
|
// acquire the new session
|
|
if (cxBuffer_FromObject(&buffer, dbNameObj,
|
|
self->environment->encoding) < 0)
|
|
return -1;
|
|
Py_BEGIN_ALLOW_THREADS
|
|
status = OCISessionGet(environment->handle, environment->errorHandle,
|
|
&self->handle, authInfo, (text*) buffer.ptr, buffer.size, NULL, 0,
|
|
NULL, NULL, &found, mode);
|
|
Py_END_ALLOW_THREADS
|
|
cxBuffer_Clear(&buffer);
|
|
if (Environment_CheckForError(environment, status,
|
|
"Connection_GetConnection(): get connection") < 0)
|
|
return -1;
|
|
|
|
// eliminate the authorization handle immediately, if applicable
|
|
if (authInfo)
|
|
OCIHandleFree(authInfo, OCI_HTYPE_AUTHINFO);
|
|
|
|
// copy members in the case where a pool is being used
|
|
if (pool) {
|
|
if (!proxyAuth) {
|
|
Py_INCREF(pool->username);
|
|
self->username = pool->username;
|
|
}
|
|
Py_INCREF(pool->dsn);
|
|
self->dsn = pool->dsn;
|
|
Py_INCREF(pool);
|
|
self->sessionPool = pool;
|
|
}
|
|
|
|
self->release = 1;
|
|
return 0;
|
|
}
|
|
|
|
|
|
#if ORACLE_VERSION_HEX >= ORACLE_VERSION(10, 2)
|
|
//-----------------------------------------------------------------------------
|
|
// Connection_GetOCIAttr()
|
|
// Get the value of the OCI attribute.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Connection_GetOCIAttr(
|
|
udt_Connection *self, // connection to set
|
|
ub4 *attribute) // OCI attribute type
|
|
{
|
|
OCISession *sessionHandle;
|
|
udt_Buffer buffer;
|
|
ub4 bufferSize;
|
|
sword status;
|
|
|
|
// make sure connection is connected
|
|
if (Connection_IsConnected(self) < 0)
|
|
return NULL;
|
|
|
|
// acquire the session handle
|
|
status = OCIAttrGet(self->handle, OCI_HTYPE_SVCCTX,
|
|
(dvoid**) &sessionHandle, 0, OCI_ATTR_SESSION,
|
|
self->environment->errorHandle);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"Connection_GetOCIAttr(): determine session handle") < 0)
|
|
return NULL;
|
|
|
|
// get the value from the OCI
|
|
status = OCIAttrGet(sessionHandle, OCI_HTYPE_SESSION,
|
|
(text**) &buffer.ptr, &bufferSize, *attribute,
|
|
self->environment->errorHandle);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"Connection_GetOCIAttr()") < 0)
|
|
return NULL;
|
|
if (!buffer.ptr) {
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|
|
|
|
buffer.size = bufferSize;
|
|
return cxString_FromEncodedString(buffer.ptr, buffer.size,
|
|
self->environment->encoding);
|
|
}
|
|
#endif
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Connection_SetOCIAttr()
|
|
// Set the value of the OCI attribute.
|
|
//-----------------------------------------------------------------------------
|
|
static int Connection_SetOCIAttr(
|
|
udt_Connection *self, // connection to set
|
|
PyObject *value, // value to set
|
|
ub4 *attribute) // OCI attribute type
|
|
{
|
|
OCISession *sessionHandle;
|
|
udt_Buffer buffer;
|
|
sword status;
|
|
|
|
// make sure connection is connected
|
|
if (Connection_IsConnected(self) < 0)
|
|
return -1;
|
|
|
|
// acquire the session handle
|
|
status = OCIAttrGet(self->handle, OCI_HTYPE_SVCCTX,
|
|
(dvoid**) &sessionHandle, 0, OCI_ATTR_SESSION,
|
|
self->environment->errorHandle);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"Connection_SetOCIAttr(): determine session handle") < 0)
|
|
return -1;
|
|
|
|
// set the value in the OCI
|
|
if (cxBuffer_FromObject(&buffer, value, self->environment->encoding))
|
|
return -1;
|
|
status = OCIAttrSet(sessionHandle, OCI_HTYPE_SESSION, (text*) buffer.ptr,
|
|
buffer.size, *attribute, self->environment->errorHandle);
|
|
cxBuffer_Clear(&buffer);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"Connection_SetOCIAttr(): set value") < 0)
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Connection_Attach()
|
|
// Attach to an existing connection.
|
|
//-----------------------------------------------------------------------------
|
|
static int Connection_Attach(
|
|
udt_Connection *self, // connection
|
|
OCISvcCtx *handle) // handle of connection to attach to
|
|
{
|
|
OCISession *sessionHandle;
|
|
OCIServer *serverHandle;
|
|
sword status;
|
|
|
|
// acquire the server handle
|
|
status = OCIAttrGet(handle, OCI_HTYPE_SVCCTX, (dvoid**) &serverHandle, 0,
|
|
OCI_ATTR_SERVER, self->environment->errorHandle);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"Connection_Attach(): determine server handle") < 0)
|
|
return -1;
|
|
|
|
// acquire the session handle
|
|
status = OCIAttrGet(handle, OCI_HTYPE_SVCCTX, (dvoid**) &sessionHandle, 0,
|
|
OCI_ATTR_SESSION, self->environment->errorHandle);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"Connection_Attach(): determine session handle") < 0)
|
|
return -1;
|
|
|
|
// allocate the service context handle
|
|
status = OCIHandleAlloc(self->environment->handle,
|
|
(dvoid*) &self->handle, OCI_HTYPE_SVCCTX, 0, 0);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"Connection_Attach(): allocate service context handle") < 0)
|
|
return -1;
|
|
|
|
// set attribute for server handle
|
|
status = OCIAttrSet(self->handle, OCI_HTYPE_SVCCTX, serverHandle, 0,
|
|
OCI_ATTR_SERVER, self->environment->errorHandle);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"Connection_Attach(): set server handle") < 0)
|
|
return -1;
|
|
|
|
// set attribute for session handle
|
|
status = OCIAttrSet(self->handle, OCI_HTYPE_SVCCTX, sessionHandle, 0,
|
|
OCI_ATTR_SESSION, self->environment->errorHandle);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"Connection_Attach(): set session handle") < 0)
|
|
return -1;
|
|
|
|
self->attached = 1;
|
|
return 0;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Connection_ChangePassword()
|
|
// Change the password for the given connection.
|
|
//-----------------------------------------------------------------------------
|
|
static int Connection_ChangePassword(
|
|
udt_Connection *self, // connection
|
|
PyObject *oldPasswordObj, // old password
|
|
PyObject *newPasswordObj) // new password
|
|
{
|
|
udt_Buffer usernameBuffer, oldPasswordBuffer, newPasswordBuffer;
|
|
sword status;
|
|
|
|
if (cxBuffer_FromObject(&usernameBuffer, self->username,
|
|
self->environment->encoding) < 0)
|
|
return -1;
|
|
if (cxBuffer_FromObject(&oldPasswordBuffer, oldPasswordObj,
|
|
self->environment->encoding) < 0) {
|
|
cxBuffer_Clear(&usernameBuffer);
|
|
return -1;
|
|
}
|
|
if (cxBuffer_FromObject(&newPasswordBuffer, newPasswordObj,
|
|
self->environment->encoding) < 0) {
|
|
cxBuffer_Clear(&usernameBuffer);
|
|
cxBuffer_Clear(&oldPasswordBuffer);
|
|
return -1;
|
|
}
|
|
|
|
// begin the session
|
|
Py_BEGIN_ALLOW_THREADS
|
|
status = OCIPasswordChange(self->handle, self->environment->errorHandle,
|
|
(text*) usernameBuffer.ptr, usernameBuffer.size,
|
|
(text*) oldPasswordBuffer.ptr, oldPasswordBuffer.size,
|
|
(text*) newPasswordBuffer.ptr, newPasswordBuffer.size,
|
|
OCI_AUTH);
|
|
Py_END_ALLOW_THREADS
|
|
cxBuffer_Clear(&usernameBuffer);
|
|
cxBuffer_Clear(&oldPasswordBuffer);
|
|
cxBuffer_Clear(&newPasswordBuffer);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"Connection_ChangePassword(): change password") < 0)
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Connection_ChangePasswordExternal()
|
|
// Change the password for the given connection.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Connection_ChangePasswordExternal(
|
|
udt_Connection *self, // connection
|
|
PyObject *args) // arguments
|
|
{
|
|
PyObject *oldPasswordObj, *newPasswordObj;
|
|
|
|
// parse the arguments
|
|
if (!PyArg_ParseTuple(args, "O!O!", cxString_Type, &oldPasswordObj,
|
|
cxString_Type, &newPasswordObj))
|
|
return NULL;
|
|
|
|
if (Connection_ChangePassword(self, oldPasswordObj, newPasswordObj) < 0)
|
|
return NULL;
|
|
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Connection_Connect()
|
|
// Create a new connection object by connecting to the database.
|
|
//-----------------------------------------------------------------------------
|
|
static int Connection_Connect(
|
|
udt_Connection *self, // connection
|
|
ub4 mode, // mode to connect as
|
|
int twophase, // allow two phase commit?
|
|
PyObject *passwordObj, // password
|
|
PyObject *newPasswordObj, // new password (if desired)
|
|
PyObject *moduleObj, // session "module" value
|
|
PyObject *actionObj, // session "action" value
|
|
PyObject *clientinfoObj, // session "clientinfo" value
|
|
PyObject *editionObj) // session "edition" value
|
|
{
|
|
ub4 credentialType = OCI_CRED_EXT;
|
|
udt_Buffer buffer;
|
|
sword status;
|
|
|
|
// allocate the server handle
|
|
status = OCIHandleAlloc(self->environment->handle,
|
|
(dvoid**) &self->serverHandle, OCI_HTYPE_SERVER, 0, 0);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"Connection_Connect(): allocate server handle") < 0)
|
|
return -1;
|
|
|
|
// attach to the server
|
|
if (cxBuffer_FromObject(&buffer, self->dsn,
|
|
self->environment->encoding) < 0)
|
|
return -1;
|
|
Py_BEGIN_ALLOW_THREADS
|
|
status = OCIServerAttach(self->serverHandle,
|
|
self->environment->errorHandle, (text*) buffer.ptr, buffer.size,
|
|
OCI_DEFAULT);
|
|
Py_END_ALLOW_THREADS
|
|
cxBuffer_Clear(&buffer);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"Connection_Connect(): server attach") < 0)
|
|
return -1;
|
|
|
|
// allocate the service context handle
|
|
status = OCIHandleAlloc(self->environment->handle,
|
|
(dvoid**) &self->handle, OCI_HTYPE_SVCCTX, 0, 0);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"Connection_Connect(): allocate service context handle") < 0)
|
|
return -1;
|
|
|
|
// set attribute for server handle
|
|
status = OCIAttrSet(self->handle, OCI_HTYPE_SVCCTX, self->serverHandle, 0,
|
|
OCI_ATTR_SERVER, self->environment->errorHandle);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"Connection_Connect(): set server handle") < 0)
|
|
return -1;
|
|
|
|
// set the internal and external names; these are needed for global
|
|
// transactions but are limited in terms of the lengths of the strings
|
|
if (twophase) {
|
|
status = OCIAttrSet(self->serverHandle, OCI_HTYPE_SERVER,
|
|
(dvoid*) "cx_Oracle", 0, OCI_ATTR_INTERNAL_NAME,
|
|
self->environment->errorHandle);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"Connection_Connect(): set internal name") < 0)
|
|
return -1;
|
|
status = OCIAttrSet(self->serverHandle, OCI_HTYPE_SERVER,
|
|
(dvoid*) "cx_Oracle", 0, OCI_ATTR_EXTERNAL_NAME,
|
|
self->environment->errorHandle);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"Connection_Connect(): set external name") < 0)
|
|
return -1;
|
|
}
|
|
|
|
// allocate the session handle
|
|
status = OCIHandleAlloc(self->environment->handle,
|
|
(dvoid**) &self->sessionHandle, OCI_HTYPE_SESSION, 0, 0);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"Connection_Connect(): allocate session handle") < 0)
|
|
return -1;
|
|
|
|
// set user name in session handle
|
|
if (cxBuffer_FromObject(&buffer, self->username,
|
|
self->environment->encoding) < 0)
|
|
return -1;
|
|
if (buffer.size > 0) {
|
|
credentialType = OCI_CRED_RDBMS;
|
|
status = OCIAttrSet(self->sessionHandle, OCI_HTYPE_SESSION,
|
|
(text*) buffer.ptr, buffer.size, OCI_ATTR_USERNAME,
|
|
self->environment->errorHandle);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"Connection_Connect(): set user name") < 0) {
|
|
cxBuffer_Clear(&buffer);
|
|
return -1;
|
|
}
|
|
}
|
|
cxBuffer_Clear(&buffer);
|
|
|
|
// set password in session handle
|
|
if (cxBuffer_FromObject(&buffer, passwordObj,
|
|
self->environment->encoding) < 0)
|
|
return -1;
|
|
if (buffer.size > 0) {
|
|
credentialType = OCI_CRED_RDBMS;
|
|
status = OCIAttrSet(self->sessionHandle, OCI_HTYPE_SESSION,
|
|
(text*) buffer.ptr, buffer.size, OCI_ATTR_PASSWORD,
|
|
self->environment->errorHandle);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"Connection_Connect(): set password") < 0) {
|
|
cxBuffer_Clear(&buffer);
|
|
return -1;
|
|
}
|
|
}
|
|
cxBuffer_Clear(&buffer);
|
|
|
|
#if ORACLE_VERSION_HEX >= ORACLE_VERSION(11,1)
|
|
status = OCIAttrSet(self->sessionHandle, OCI_HTYPE_SESSION,
|
|
(text*) DRIVER_NAME, strlen(DRIVER_NAME), OCI_ATTR_DRIVER_NAME,
|
|
self->environment->errorHandle);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"Connection_Connect(): set driver name") < 0)
|
|
return -1;
|
|
|
|
#endif
|
|
|
|
// set the session handle on the service context handle
|
|
status = OCIAttrSet(self->handle, OCI_HTYPE_SVCCTX,
|
|
self->sessionHandle, 0, OCI_ATTR_SESSION,
|
|
self->environment->errorHandle);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"Connection_Connect(): set session handle") < 0)
|
|
return -1;
|
|
|
|
if (moduleObj) {
|
|
if (cxBuffer_FromObject(&buffer, moduleObj,
|
|
self->environment->encoding))
|
|
return -1;
|
|
status = OCIAttrSet(self->sessionHandle, OCI_HTYPE_SESSION,
|
|
(text*) buffer.ptr, buffer.size, OCI_ATTR_MODULE,
|
|
self->environment->errorHandle);
|
|
cxBuffer_Clear(&buffer);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"Connection_Connect(): set module") < 0)
|
|
return -1;
|
|
}
|
|
|
|
if (actionObj) {
|
|
if (cxBuffer_FromObject(&buffer, actionObj,
|
|
self->environment->encoding))
|
|
return -1;
|
|
status = OCIAttrSet(self->sessionHandle, OCI_HTYPE_SESSION,
|
|
(text*) buffer.ptr, buffer.size, OCI_ATTR_ACTION,
|
|
self->environment->errorHandle);
|
|
cxBuffer_Clear(&buffer);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"Connection_Connect(): set action") < 0)
|
|
return -1;
|
|
}
|
|
|
|
if (clientinfoObj) {
|
|
if (cxBuffer_FromObject(&buffer, clientinfoObj,
|
|
self->environment->encoding))
|
|
return -1;
|
|
status = OCIAttrSet(self->sessionHandle, OCI_HTYPE_SESSION,
|
|
(text*) buffer.ptr, buffer.size, OCI_ATTR_CLIENT_INFO,
|
|
self->environment->errorHandle);
|
|
cxBuffer_Clear(&buffer);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"Connection_Connect(): set clientinfo") < 0)
|
|
return -1;
|
|
}
|
|
|
|
#if ORACLE_VERSION_HEX >= ORACLE_VERSION(11, 2)
|
|
if (editionObj) {
|
|
if (cxBuffer_FromObject(&buffer, editionObj,
|
|
self->environment->encoding))
|
|
return -1;
|
|
status = OCIAttrSet(self->sessionHandle, OCI_HTYPE_SESSION,
|
|
(text*) buffer.ptr, buffer.size, OCI_ATTR_EDITION,
|
|
self->environment->errorHandle);
|
|
cxBuffer_Clear(&buffer);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"Connection_Connect(): set edition") < 0)
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
// if a new password has been specified, change it which will also
|
|
// establish the session
|
|
if (newPasswordObj)
|
|
return Connection_ChangePassword(self, passwordObj, newPasswordObj);
|
|
|
|
// begin the session
|
|
Py_BEGIN_ALLOW_THREADS
|
|
status = OCISessionBegin(self->handle, self->environment->errorHandle,
|
|
self->sessionHandle, credentialType, mode);
|
|
Py_END_ALLOW_THREADS
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"Connection_Connect(): begin session") < 0) {
|
|
self->sessionHandle = NULL;
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
#include "Cursor.c"
|
|
#include "Callback.c"
|
|
#if ORACLE_VERSION_HEX >= ORACLE_VERSION(10, 2)
|
|
#include "Subscription.c"
|
|
#endif
|
|
#include "AQ.c"
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Connection_New()
|
|
// Create a new connection object and return it.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject* Connection_New(
|
|
PyTypeObject *type, // type object
|
|
PyObject *args, // arguments
|
|
PyObject *keywordArgs) // keyword arguments
|
|
{
|
|
udt_Connection *self;
|
|
|
|
// create the object
|
|
self = (udt_Connection*) type->tp_alloc(type, 0);
|
|
if (!self)
|
|
return NULL;
|
|
self->commitMode = OCI_DEFAULT;
|
|
|
|
return (PyObject*) self;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Connection_SplitComponent()
|
|
// Split the component out of the source and replace the source with the
|
|
// characters up to the split string and put the characters after the split
|
|
// string in to the target.
|
|
//-----------------------------------------------------------------------------
|
|
static int Connection_SplitComponent(
|
|
PyObject **sourceObj, // source object to split
|
|
PyObject **targetObj, // target object (for component)
|
|
const char *splitString) // split string (assume one character)
|
|
{
|
|
PyObject *temp, *posObj;
|
|
Py_ssize_t size, pos;
|
|
|
|
if (!*sourceObj || *targetObj)
|
|
return 0;
|
|
posObj = PyObject_CallMethod(*sourceObj, "find", "s", splitString);
|
|
if (!posObj)
|
|
return -1;
|
|
pos = PyInt_AsLong(posObj);
|
|
Py_DECREF(posObj);
|
|
if (PyErr_Occurred())
|
|
return -1;
|
|
if (pos >= 0) {
|
|
size = PySequence_Size(*sourceObj);
|
|
if (PyErr_Occurred())
|
|
return -1;
|
|
*targetObj = PySequence_GetSlice(*sourceObj, pos + 1, size);
|
|
if (!*targetObj)
|
|
return -1;
|
|
temp = PySequence_GetSlice(*sourceObj, 0, pos);
|
|
if (!temp)
|
|
return -1;
|
|
*sourceObj = temp;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Connection_Init()
|
|
// Initialize the connection members.
|
|
//-----------------------------------------------------------------------------
|
|
static int Connection_Init(
|
|
udt_Connection *self, // connection
|
|
PyObject *args, // arguments
|
|
PyObject *keywordArgs) // keyword arguments
|
|
{
|
|
PyObject *usernameObj, *passwordObj, *dsnObj, *cclassObj, *editionObj;
|
|
PyObject *threadedObj, *twophaseObj, *eventsObj, *newPasswordObj;
|
|
PyObject *moduleObj, *actionObj, *clientinfoObj;
|
|
int threaded, twophase, events;
|
|
char *encoding, *nencoding;
|
|
ub4 connectMode, purity;
|
|
udt_SessionPool *pool;
|
|
OCISvcCtx *handle;
|
|
|
|
// define keyword arguments
|
|
static char *keywordList[] = { "user", "password", "dsn", "mode",
|
|
"handle", "pool", "threaded", "twophase", "events", "cclass",
|
|
"purity", "newpassword", "encoding", "nencoding", "module",
|
|
"action", "clientinfo", "edition", NULL };
|
|
|
|
// parse arguments
|
|
pool = NULL;
|
|
handle = NULL;
|
|
connectMode = OCI_DEFAULT;
|
|
threadedObj = twophaseObj = eventsObj = newPasswordObj = NULL;
|
|
usernameObj = passwordObj = dsnObj = cclassObj = editionObj = NULL;
|
|
moduleObj = actionObj = clientinfoObj = NULL;
|
|
threaded = twophase = events = purity = 0;
|
|
encoding = nencoding = NULL;
|
|
#if ORACLE_VERSION_HEX >= ORACLE_VERSION(11, 1)
|
|
purity = OCI_ATTR_PURITY_DEFAULT;
|
|
#endif
|
|
if (!PyArg_ParseTupleAndKeywords(args, keywordArgs,
|
|
"|OOOiiO!OOOOiOssOOOO", keywordList, &usernameObj, &passwordObj,
|
|
&dsnObj, &connectMode, &handle, &g_SessionPoolType, &pool,
|
|
&threadedObj, &twophaseObj, &eventsObj, &cclassObj, &purity,
|
|
&newPasswordObj, &encoding, &nencoding, &moduleObj, &actionObj,
|
|
&clientinfoObj, &editionObj))
|
|
return -1;
|
|
if (threadedObj) {
|
|
threaded = PyObject_IsTrue(threadedObj);
|
|
if (threaded < 0)
|
|
return -1;
|
|
}
|
|
if (twophaseObj) {
|
|
twophase = PyObject_IsTrue(twophaseObj);
|
|
if (twophase < 0)
|
|
return -1;
|
|
}
|
|
if (eventsObj) {
|
|
events = PyObject_IsTrue(eventsObj);
|
|
if (events < 0)
|
|
return -1;
|
|
}
|
|
|
|
// set up the environment
|
|
if (pool)
|
|
self->environment = Environment_Clone(pool->environment);
|
|
else self->environment = Environment_NewFromScratch(threaded, events,
|
|
encoding, nencoding);
|
|
if (!self->environment)
|
|
return -1;
|
|
|
|
// keep a copy of the credentials
|
|
Py_XINCREF(usernameObj);
|
|
self->username = usernameObj;
|
|
Py_XINCREF(dsnObj);
|
|
self->dsn = dsnObj;
|
|
|
|
// perform some parsing, if necessary
|
|
if (Connection_SplitComponent(&self->username, &passwordObj, "/") < 0)
|
|
return -1;
|
|
if (Connection_SplitComponent(&passwordObj, &self->dsn, "@") < 0)
|
|
return -1;
|
|
|
|
// handle the different ways of initializing the connection
|
|
if (handle)
|
|
return Connection_Attach(self, handle);
|
|
if (pool || cclassObj)
|
|
return Connection_GetConnection(self, pool, passwordObj, cclassObj,
|
|
purity);
|
|
return Connection_Connect(self, connectMode, twophase, passwordObj,
|
|
newPasswordObj, moduleObj, actionObj, clientinfoObj,
|
|
editionObj);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Connection_Free()
|
|
// Deallocate the connection, disconnecting from the database if necessary.
|
|
//-----------------------------------------------------------------------------
|
|
static void Connection_Free(
|
|
udt_Connection *self) // connection object
|
|
{
|
|
if (self->release) {
|
|
Py_BEGIN_ALLOW_THREADS
|
|
OCITransRollback(self->handle, self->environment->errorHandle,
|
|
OCI_DEFAULT);
|
|
OCISessionRelease(self->handle, self->environment->errorHandle, NULL,
|
|
0, OCI_DEFAULT);
|
|
Py_END_ALLOW_THREADS
|
|
} else if (!self->attached) {
|
|
if (self->sessionHandle) {
|
|
Py_BEGIN_ALLOW_THREADS
|
|
OCITransRollback(self->handle, self->environment->errorHandle,
|
|
OCI_DEFAULT);
|
|
OCISessionEnd(self->handle, self->environment->errorHandle,
|
|
self->sessionHandle, OCI_DEFAULT);
|
|
Py_END_ALLOW_THREADS
|
|
}
|
|
if (self->serverHandle)
|
|
OCIServerDetach(self->serverHandle,
|
|
self->environment->errorHandle, OCI_DEFAULT);
|
|
}
|
|
Py_CLEAR(self->environment);
|
|
Py_CLEAR(self->sessionPool);
|
|
Py_CLEAR(self->username);
|
|
Py_CLEAR(self->dsn);
|
|
Py_CLEAR(self->version);
|
|
Py_CLEAR(self->inputTypeHandler);
|
|
Py_CLEAR(self->outputTypeHandler);
|
|
Py_TYPE(self)->tp_free((PyObject*) self);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Connection_Repr()
|
|
// Return a string representation of the connection.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Connection_Repr(
|
|
udt_Connection *connection) // connection to return the string for
|
|
{
|
|
PyObject *module, *name, *result, *format, *formatArgs = NULL;
|
|
|
|
if (GetModuleAndName(Py_TYPE(connection), &module, &name) < 0)
|
|
return NULL;
|
|
if (connection->username && connection->username != Py_None &&
|
|
connection->dsn && connection->dsn != Py_None) {
|
|
format = cxString_FromAscii("<%s.%s to %s@%s>");
|
|
if (format)
|
|
formatArgs = PyTuple_Pack(4, module, name, connection->username,
|
|
connection->dsn);
|
|
} else if (connection->username && connection->username != Py_None) {
|
|
format = cxString_FromAscii("<%s.%s to user %s@local>");
|
|
if (format)
|
|
formatArgs = PyTuple_Pack(3, module, name, connection->username);
|
|
} else {
|
|
format = cxString_FromAscii("<%s.%s to externally identified user>");
|
|
if (format)
|
|
formatArgs = PyTuple_Pack(2, module, name);
|
|
}
|
|
Py_DECREF(module);
|
|
Py_DECREF(name);
|
|
if (!format)
|
|
return NULL;
|
|
if (!formatArgs) {
|
|
Py_DECREF(format);
|
|
return NULL;
|
|
}
|
|
result = cxString_Format(format, formatArgs);
|
|
Py_DECREF(format);
|
|
Py_DECREF(formatArgs);
|
|
return result;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Connection_GetStmtCacheSize()
|
|
// Return the Oracle statement cache size.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Connection_GetStmtCacheSize(
|
|
udt_Connection* self, // connection object
|
|
void* arg) // optional argument (ignored)
|
|
{
|
|
ub4 cacheSize;
|
|
sword status;
|
|
|
|
if (Connection_IsConnected(self) < 0)
|
|
return NULL;
|
|
status = OCIAttrGet(self->handle, OCI_HTYPE_SVCCTX,
|
|
(dvoid**) &cacheSize, 0, OCI_ATTR_STMTCACHESIZE,
|
|
self->environment->errorHandle);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"Connection_GetStmtCacheSize()") < 0)
|
|
return NULL;
|
|
return PyInt_FromLong(cacheSize);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Connection_SetStmtCacheSize()
|
|
// Set the Oracle statement cache size.
|
|
//-----------------------------------------------------------------------------
|
|
static int Connection_SetStmtCacheSize(
|
|
udt_Connection* self, // connection object
|
|
PyObject *value, // value to set it to
|
|
void* arg) // optional argument (ignored)
|
|
{
|
|
ub4 valueToSet;
|
|
sword status;
|
|
|
|
if (Connection_IsConnected(self) < 0)
|
|
return -1;
|
|
if (!PyInt_Check(value)) {
|
|
PyErr_SetString(PyExc_TypeError, "value must be an integer");
|
|
return -1;
|
|
}
|
|
valueToSet = (ub4) PyInt_AsLong(value);
|
|
if (PyErr_Occurred())
|
|
return -1;
|
|
status = OCIAttrSet(self->handle, OCI_HTYPE_SVCCTX, (dvoid*) &valueToSet,
|
|
0, OCI_ATTR_STMTCACHESIZE, self->environment->errorHandle);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"Connection_SetStmtCacheSize()") < 0)
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Connection_GetType()
|
|
// Return a type object given its name.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Connection_GetType(
|
|
udt_Connection *self, // connection
|
|
PyObject *args) // arguments
|
|
{
|
|
PyObject *nameObj = NULL;
|
|
|
|
// parse the arguments
|
|
if (!PyArg_ParseTuple(args, "O", &nameObj))
|
|
return NULL;
|
|
|
|
return (PyObject*) ObjectType_NewByName(self, nameObj);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Connection_GetVersion()
|
|
// Retrieve the version of the database and return it. Note that this
|
|
// function also places the result in the associated dictionary so it is only
|
|
// calculated once.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Connection_GetVersion(
|
|
udt_Connection *self, // connection object
|
|
void *arg) // optional argument (ignored)
|
|
{
|
|
PyObject *procName, *listOfArguments;
|
|
udt_Variable *versionVar, *compatVar;
|
|
udt_Cursor *cursor;
|
|
|
|
// if version has already been determined, no need to determine again
|
|
if (self->version) {
|
|
Py_INCREF(self->version);
|
|
return self->version;
|
|
}
|
|
|
|
// allocate a cursor to retrieve the version
|
|
cursor = (udt_Cursor*) Connection_NewCursor(self, NULL, NULL);
|
|
if (!cursor)
|
|
return NULL;
|
|
|
|
// allocate version variable
|
|
versionVar = Variable_New(cursor, cursor->arraySize, &vt_String,
|
|
vt_String.size);
|
|
if (!versionVar) {
|
|
Py_DECREF(cursor);
|
|
return NULL;
|
|
}
|
|
|
|
// allocate compatibility variable
|
|
compatVar = Variable_New(cursor, cursor->arraySize, &vt_String,
|
|
vt_String.size);
|
|
if (!compatVar) {
|
|
Py_DECREF(versionVar);
|
|
Py_DECREF(cursor);
|
|
return NULL;
|
|
}
|
|
|
|
// create the list of arguments
|
|
listOfArguments = PyList_New(2);
|
|
if (!listOfArguments) {
|
|
Py_DECREF(versionVar);
|
|
Py_DECREF(compatVar);
|
|
Py_DECREF(cursor);
|
|
return NULL;
|
|
}
|
|
PyList_SET_ITEM(listOfArguments, 0, (PyObject*) versionVar);
|
|
PyList_SET_ITEM(listOfArguments, 1, (PyObject*) compatVar);
|
|
|
|
// create the string variable
|
|
procName = cxString_FromAscii("dbms_utility.db_version");
|
|
if (!procName) {
|
|
Py_DECREF(listOfArguments);
|
|
Py_DECREF(cursor);
|
|
return NULL;
|
|
}
|
|
|
|
// call stored procedure
|
|
if (Cursor_Call(cursor, NULL, procName, listOfArguments, NULL) < 0) {
|
|
Py_DECREF(procName);
|
|
Py_DECREF(listOfArguments);
|
|
Py_DECREF(cursor);
|
|
return NULL;
|
|
}
|
|
Py_DECREF(procName);
|
|
|
|
// retrieve value
|
|
self->version = Variable_GetValue(versionVar, 0);
|
|
Py_DECREF(listOfArguments);
|
|
Py_DECREF(cursor);
|
|
Py_XINCREF(self->version);
|
|
return self->version;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Connection_GetEncoding()
|
|
// Return the encoding associated with the environment of the connection.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Connection_GetEncoding(
|
|
udt_Connection *self, // connection object
|
|
void *arg) // optional argument (ignored)
|
|
{
|
|
return cxString_FromAscii(self->environment->encoding);
|
|
}
|
|
|
|
|
|
#if ORACLE_VERSION_HEX >= ORACLE_VERSION(12, 1)
|
|
//-----------------------------------------------------------------------------
|
|
// Connection_GetLTXID()
|
|
// Return the logical transaction id used with Transaction Guard.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Connection_GetLTXID(
|
|
udt_Connection *self, // connection object
|
|
void *arg) // optional argument (ignored)
|
|
{
|
|
OCISession *sessionHandle;
|
|
ub4 ltxidLength;
|
|
sword status;
|
|
ub1 *ltxid;
|
|
|
|
// make sure connection is connected
|
|
if (Connection_IsConnected(self) < 0)
|
|
return NULL;
|
|
|
|
// acquire the session handle
|
|
status = OCIAttrGet(self->handle, OCI_HTYPE_SVCCTX,
|
|
(dvoid**) &sessionHandle, 0, OCI_ATTR_SESSION,
|
|
self->environment->errorHandle);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"Connection_GetLTXID(): determine session handle") < 0)
|
|
return NULL;
|
|
|
|
// get the value from the OCI
|
|
status = OCIAttrGet(sessionHandle, OCI_HTYPE_SESSION,
|
|
<xid, <xidLength, OCI_ATTR_LTXID,
|
|
self->environment->errorHandle);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"Connection_GetLTXID()") < 0)
|
|
return NULL;
|
|
|
|
return PyBytes_FromStringAndSize( (char*) ltxid, (Py_ssize_t) ltxidLength);
|
|
}
|
|
#endif
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Connection_GetNationalEncoding()
|
|
// Return the national encoding associated with the environment of the
|
|
// connection.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Connection_GetNationalEncoding(
|
|
udt_Connection *self, // connection object
|
|
void *arg) // optional argument (ignored)
|
|
{
|
|
return cxString_FromAscii(self->environment->nencoding);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Connection_GetMaxBytesPerCharacter()
|
|
// Return the maximum number of bytes per character.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Connection_GetMaxBytesPerCharacter(
|
|
udt_Connection *self, // connection object
|
|
void *arg) // optional argument (ignored)
|
|
{
|
|
return PyInt_FromLong(self->environment->maxBytesPerCharacter);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Connection_Close()
|
|
// Close the connection, disconnecting from the database.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Connection_Close(
|
|
udt_Connection *self, // connection to close
|
|
PyObject *args) // arguments
|
|
{
|
|
sword status;
|
|
|
|
// make sure we are actually connected
|
|
if (Connection_IsConnected(self) < 0)
|
|
return NULL;
|
|
|
|
// perform a rollback
|
|
Py_BEGIN_ALLOW_THREADS
|
|
status = OCITransRollback(self->handle, self->environment->errorHandle,
|
|
OCI_DEFAULT);
|
|
Py_END_ALLOW_THREADS
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"Connection_Close(): rollback") < 0)
|
|
return NULL;
|
|
|
|
// logoff of the server
|
|
if (self->release) {
|
|
Py_BEGIN_ALLOW_THREADS
|
|
status = OCISessionRelease(self->handle,
|
|
self->environment->errorHandle, NULL, 0, OCI_DEFAULT);
|
|
Py_END_ALLOW_THREADS
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"Connection_Close(): release session") < 0)
|
|
return NULL;
|
|
self->release = 0;
|
|
}
|
|
else {
|
|
if (self->sessionHandle) {
|
|
Py_BEGIN_ALLOW_THREADS
|
|
status = OCISessionEnd(self->handle,
|
|
self->environment->errorHandle, self->sessionHandle,
|
|
OCI_DEFAULT);
|
|
Py_END_ALLOW_THREADS
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"Connection_Close(): end session") < 0)
|
|
return NULL;
|
|
OCIHandleFree(self->sessionHandle, OCI_HTYPE_SESSION);
|
|
self->sessionHandle = NULL;
|
|
OCIHandleFree(self->handle, OCI_HTYPE_SVCCTX);
|
|
}
|
|
|
|
if (self->serverHandle) {
|
|
status = OCIServerDetach(self->serverHandle,
|
|
self->environment->errorHandle, OCI_DEFAULT);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"Connection_Close(): server detach") < 0)
|
|
return NULL;
|
|
OCIHandleFree(self->serverHandle, OCI_HTYPE_SERVER);
|
|
self->serverHandle = NULL;
|
|
}
|
|
}
|
|
self->handle = NULL;
|
|
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Connection_Commit()
|
|
// Commit the transaction on the connection.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Connection_Commit(
|
|
udt_Connection *self, // connection to commit
|
|
PyObject *args) // arguments
|
|
{
|
|
sword status;
|
|
|
|
// make sure we are actually connected
|
|
if (Connection_IsConnected(self) < 0)
|
|
return NULL;
|
|
|
|
// perform the commit
|
|
Py_BEGIN_ALLOW_THREADS
|
|
status = OCITransCommit(self->handle, self->environment->errorHandle,
|
|
self->commitMode);
|
|
Py_END_ALLOW_THREADS
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"Connection_Commit()") < 0)
|
|
return NULL;
|
|
self->commitMode = OCI_DEFAULT;
|
|
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Connection_Begin()
|
|
// Begin a new transaction on the connection.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Connection_Begin(
|
|
udt_Connection *self, // connection to commit
|
|
PyObject *args) // arguments
|
|
{
|
|
unsigned transactionIdLength, branchIdLength;
|
|
const char *transactionId, *branchId;
|
|
OCITrans *transactionHandle;
|
|
int formatId;
|
|
sword status;
|
|
XID xid;
|
|
|
|
// parse the arguments
|
|
formatId = -1;
|
|
transactionIdLength = branchIdLength = 0;
|
|
if (!PyArg_ParseTuple(args, "|is#s#", &formatId, &transactionId,
|
|
&transactionIdLength, &branchId, &branchIdLength))
|
|
return NULL;
|
|
if (transactionIdLength > MAXGTRIDSIZE) {
|
|
PyErr_SetString(PyExc_ValueError, "transaction id too large");
|
|
return NULL;
|
|
}
|
|
if (branchIdLength > MAXBQUALSIZE) {
|
|
PyErr_SetString(PyExc_ValueError, "branch id too large");
|
|
return NULL;
|
|
}
|
|
|
|
// make sure we are actually connected
|
|
if (Connection_IsConnected(self) < 0)
|
|
return NULL;
|
|
|
|
// determine if a transaction handle was previously allocated
|
|
status = OCIAttrGet(self->handle, OCI_HTYPE_SVCCTX,
|
|
(dvoid**) &transactionHandle, 0, OCI_ATTR_TRANS,
|
|
self->environment->errorHandle);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"Connection_Begin(): find existing transaction handle") < 0)
|
|
return NULL;
|
|
|
|
// create a new transaction handle, if necessary
|
|
if (!transactionHandle) {
|
|
status = OCIHandleAlloc(self->environment->handle,
|
|
(dvoid**) &transactionHandle, OCI_HTYPE_TRANS, 0, 0);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"Connection_Begin(): allocate transaction handle") < 0)
|
|
return NULL;
|
|
}
|
|
|
|
// set the XID for the transaction, if applicable
|
|
if (formatId != -1) {
|
|
xid.formatID = formatId;
|
|
xid.gtrid_length = transactionIdLength;
|
|
xid.bqual_length = branchIdLength;
|
|
if (transactionIdLength > 0)
|
|
strncpy(xid.data, transactionId, transactionIdLength);
|
|
if (branchIdLength > 0)
|
|
strncpy(&xid.data[transactionIdLength], branchId, branchIdLength);
|
|
OCIAttrSet(transactionHandle, OCI_HTYPE_TRANS, &xid, sizeof(XID),
|
|
OCI_ATTR_XID, self->environment->errorHandle);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"Connection_Begin(): set XID") < 0)
|
|
return NULL;
|
|
}
|
|
|
|
// associate the transaction with the connection
|
|
OCIAttrSet(self->handle, OCI_HTYPE_SVCCTX, transactionHandle, 0,
|
|
OCI_ATTR_TRANS, self->environment->errorHandle);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"Connection_Begin(): associate transaction") < 0)
|
|
return NULL;
|
|
|
|
// start the transaction
|
|
Py_BEGIN_ALLOW_THREADS
|
|
status = OCITransStart(self->handle, self->environment->errorHandle, 0,
|
|
OCI_TRANS_NEW);
|
|
Py_END_ALLOW_THREADS
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"Connection_Begin(): start transaction") < 0)
|
|
return NULL;
|
|
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Connection_Prepare()
|
|
// Commit the transaction on the connection.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Connection_Prepare(
|
|
udt_Connection *self, // connection to commit
|
|
PyObject *args) // arguments
|
|
{
|
|
sword status;
|
|
|
|
// make sure we are actually connected
|
|
if (Connection_IsConnected(self) < 0)
|
|
return NULL;
|
|
|
|
// perform the prepare
|
|
Py_BEGIN_ALLOW_THREADS
|
|
status = OCITransPrepare(self->handle, self->environment->errorHandle,
|
|
OCI_DEFAULT);
|
|
Py_END_ALLOW_THREADS
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"Connection_Prepare()") < 0)
|
|
return NULL;
|
|
|
|
// if nothing available to prepare, return False in order to allow for
|
|
// avoiding the call to commit() which will fail with ORA-24756
|
|
// (transaction does not exist)
|
|
if (status == OCI_SUCCESS_WITH_INFO) {
|
|
Py_INCREF(Py_False);
|
|
return Py_False;
|
|
}
|
|
self->commitMode = OCI_TRANS_TWOPHASE;
|
|
Py_INCREF(Py_True);
|
|
return Py_True;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Connection_Rollback()
|
|
// Rollback the transaction on the connection.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Connection_Rollback(
|
|
udt_Connection *self, // connection to rollback
|
|
PyObject *args) // arguments
|
|
{
|
|
sword status;
|
|
|
|
// make sure we are actually connected
|
|
if (Connection_IsConnected(self) < 0)
|
|
return NULL;
|
|
|
|
// perform the rollback
|
|
Py_BEGIN_ALLOW_THREADS
|
|
status = OCITransRollback(self->handle, self->environment->errorHandle,
|
|
OCI_DEFAULT);
|
|
Py_END_ALLOW_THREADS
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"Connection_Rollback()") < 0)
|
|
return NULL;
|
|
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Connection_NewCursor()
|
|
// Create a new cursor (statement) referencing the connection.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Connection_NewCursor(
|
|
udt_Connection *self, // connection to create cursor on
|
|
PyObject *args, // arguments
|
|
PyObject *keywordArgs) // keyword arguments
|
|
{
|
|
PyObject *createArgs, *result;
|
|
Py_ssize_t numArgs = 0, i;
|
|
|
|
if (args)
|
|
numArgs = PyTuple_GET_SIZE(args);
|
|
createArgs = PyTuple_New(1 + numArgs);
|
|
if (!createArgs)
|
|
return NULL;
|
|
Py_INCREF(self);
|
|
PyTuple_SET_ITEM(createArgs, 0, (PyObject*) self);
|
|
for (i = 0; i < numArgs; i++)
|
|
PyTuple_SET_ITEM(createArgs, i + 1, PyTuple_GET_ITEM(args, i));
|
|
result = PyObject_Call( (PyObject*) &g_CursorType, createArgs,
|
|
keywordArgs);
|
|
Py_DECREF(createArgs);
|
|
return result;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Connection_Cancel()
|
|
// Execute an OCIBreak() to cause an immediate (asynchronous) abort of any
|
|
// currently executing OCI function.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Connection_Cancel(
|
|
udt_Connection *self, // connection to cancel
|
|
PyObject *args) // arguments
|
|
{
|
|
sword status;
|
|
|
|
// make sure we are actually connected
|
|
if (Connection_IsConnected(self) < 0)
|
|
return NULL;
|
|
|
|
// perform the break
|
|
status = OCIBreak(self->handle, self->environment->errorHandle);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"Connection_Cancel()") < 0)
|
|
return NULL;
|
|
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Connection_NewEnqueueOptions()
|
|
// Creates a new enqueue options object and returns it.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Connection_NewEnqueueOptions(
|
|
udt_Connection *self, // connection
|
|
PyObject *args) // none
|
|
{
|
|
return (PyObject*) EnqOptions_New(self->environment);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Connection_NewDequeueOptions()
|
|
// Creates a new dequeue options object and returns it.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Connection_NewDequeueOptions(
|
|
udt_Connection *self, // connection
|
|
PyObject *args) // none
|
|
{
|
|
return (PyObject*) DeqOptions_New(self->environment);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Connection_NewMessageProperties()
|
|
// Creates a new message properties object and returns it.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Connection_NewMessageProperties(
|
|
udt_Connection *self, // connection
|
|
PyObject *args) // none
|
|
{
|
|
return (PyObject*) MessageProperties_New(self->environment);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Connection_Dequeue()
|
|
// Dequeues a message using Advanced Queuing capabilities. The message ID is
|
|
// returned if a message is available or None if no message is available.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Connection_Dequeue(
|
|
udt_Connection *self, // connection
|
|
PyObject* args, // arguments
|
|
PyObject* keywordArgs) // keyword arguments
|
|
{
|
|
static char *keywordList[] = { "name", "options", "msgproperties",
|
|
"payload", NULL };
|
|
PyObject *nameObj, *excType, *excValue, *traceback;
|
|
udt_MessageProperties *propertiesObj;
|
|
udt_DeqOptions *optionsObj;
|
|
udt_Object *payloadObj;
|
|
udt_Buffer nameBuffer;
|
|
char *messageIdValue;
|
|
OCIRaw *messageId;
|
|
ub4 messageIdSize;
|
|
udt_Error *error;
|
|
sword status;
|
|
|
|
// parse arguments
|
|
if (!PyArg_ParseTupleAndKeywords(args, keywordArgs, "OO!O!O!", keywordList,
|
|
&nameObj, &g_DeqOptionsType, &optionsObj, &g_MessagePropertiesType,
|
|
&propertiesObj, &g_ObjectType, &payloadObj))
|
|
return NULL;
|
|
if (cxBuffer_FromObject(&nameBuffer, nameObj,
|
|
self->environment->encoding) < 0)
|
|
return NULL;
|
|
|
|
// enqueue payload
|
|
messageId = NULL;
|
|
status = OCIAQDeq(self->handle, self->environment->errorHandle,
|
|
(oratext*) nameBuffer.ptr, optionsObj->handle,
|
|
propertiesObj->handle, payloadObj->objectType->tdo,
|
|
&payloadObj->instance, &payloadObj->indicator, &messageId,
|
|
OCI_DEFAULT);
|
|
cxBuffer_Clear(&nameBuffer);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"Connection_Dequeue()") < 0) {
|
|
PyErr_Fetch(&excType, &excValue, &traceback);
|
|
if (excValue) {
|
|
error = (udt_Error*) excValue;
|
|
if (error->code == 25228) {
|
|
Py_XDECREF(excType);
|
|
Py_XDECREF(excValue);
|
|
Py_XDECREF(traceback);
|
|
Py_RETURN_NONE;
|
|
}
|
|
}
|
|
PyErr_Restore(excType, excValue, traceback);
|
|
return NULL;
|
|
}
|
|
|
|
// determine the message id
|
|
messageIdValue = (char*) OCIRawPtr(self->environment->handle, messageId);
|
|
messageIdSize = OCIRawSize(self->environment->handle, messageId);
|
|
return PyBytes_FromStringAndSize(messageIdValue, messageIdSize);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Connection_Enqueue()
|
|
// Enqueues a message using Advanced Queuing capabilities. The message ID is
|
|
// returned.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Connection_Enqueue(
|
|
udt_Connection *self, // connection
|
|
PyObject* args, // arguments
|
|
PyObject* keywordArgs) // keyword arguments
|
|
{
|
|
static char *keywordList[] = { "name", "options", "msgproperties",
|
|
"payload", NULL };
|
|
udt_MessageProperties *propertiesObj;
|
|
udt_EnqOptions *optionsObj;
|
|
udt_Object *payloadObj;
|
|
udt_Buffer nameBuffer;
|
|
char *messageIdValue;
|
|
PyObject *nameObj;
|
|
OCIRaw *messageId;
|
|
ub4 messageIdSize;
|
|
sword status;
|
|
|
|
// parse arguments
|
|
if (!PyArg_ParseTupleAndKeywords(args, keywordArgs, "OO!O!O!", keywordList,
|
|
&nameObj, &g_EnqOptionsType, &optionsObj, &g_MessagePropertiesType,
|
|
&propertiesObj, &g_ObjectType, &payloadObj))
|
|
return NULL;
|
|
if (cxBuffer_FromObject(&nameBuffer, nameObj,
|
|
self->environment->encoding) < 0)
|
|
return NULL;
|
|
|
|
// enqueue payload
|
|
messageId = NULL;
|
|
status = OCIAQEnq(self->handle, self->environment->errorHandle,
|
|
(oratext*) nameBuffer.ptr, optionsObj->handle,
|
|
propertiesObj->handle, payloadObj->objectType->tdo,
|
|
&payloadObj->instance, &payloadObj->indicator, &messageId,
|
|
OCI_DEFAULT);
|
|
cxBuffer_Clear(&nameBuffer);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"Connection_Enqueue()") < 0)
|
|
return NULL;
|
|
|
|
// determine the message id
|
|
messageIdValue = (char*) OCIRawPtr(self->environment->handle, messageId);
|
|
messageIdSize = OCIRawSize(self->environment->handle, messageId);
|
|
return PyBytes_FromStringAndSize(messageIdValue, messageIdSize);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Connection_RegisterCallback()
|
|
// Register a callback for the OCI function.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Connection_RegisterCallback(
|
|
udt_Connection *self, // connection to register callback on
|
|
PyObject *args) // arguments
|
|
{
|
|
PyObject *callback, *tuple;
|
|
int functionCode, when;
|
|
sword status;
|
|
|
|
// parse the arguments
|
|
if (!PyArg_ParseTuple(args, "iiO", &functionCode, &when, &callback))
|
|
return NULL;
|
|
|
|
// create a tuple for passing through to the callback handler
|
|
tuple = Py_BuildValue("OO", self, callback);
|
|
if (!tuple)
|
|
return NULL;
|
|
|
|
// make sure we are actually connected
|
|
if (Connection_IsConnected(self) < 0)
|
|
return NULL;
|
|
|
|
// register the callback with the OCI
|
|
status = OCIUserCallbackRegister(self->environment->handle, OCI_HTYPE_ENV,
|
|
self->environment->errorHandle, (OCIUserCallback) Callback_Handler,
|
|
tuple, functionCode, when, NULL);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"Connection_RegisterCallback()") < 0)
|
|
return NULL;
|
|
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Connection_UnregisterCallback()
|
|
// Unregister a callback for the OCI function, if one has been registered.
|
|
// No error is raised if a callback has not been registered.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Connection_UnregisterCallback(
|
|
udt_Connection *self, // connection to unregister callback on
|
|
PyObject *args) // arguments
|
|
{
|
|
OCIUserCallback callback;
|
|
int functionCode, when;
|
|
PyObject *tuple;
|
|
sword status;
|
|
|
|
// parse the arguments
|
|
if (!PyArg_ParseTuple(args, "ii", &functionCode, &when))
|
|
return NULL;
|
|
|
|
// make sure we are actually connected
|
|
if (Connection_IsConnected(self) < 0)
|
|
return NULL;
|
|
|
|
// find out if a callback has been registered
|
|
status = OCIUserCallbackGet(self->environment->handle, OCI_HTYPE_ENV,
|
|
self->environment->errorHandle, functionCode, when, &callback,
|
|
(dvoid**) &tuple, NULL);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"Connection_UnregisterCallback(): get") < 0)
|
|
return NULL;
|
|
|
|
// if a callback was registered, clear it
|
|
if (callback) {
|
|
Py_DECREF(tuple);
|
|
status = OCIUserCallbackRegister(self->environment->handle,
|
|
OCI_HTYPE_ENV, self->environment->errorHandle, NULL,
|
|
NULL, functionCode, when, NULL);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"Connection_UnregisterCallback(): clear") < 0)
|
|
return NULL;
|
|
}
|
|
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Connection_ContextManagerEnter()
|
|
// Called when the connection is used as a context manager and simply returns
|
|
// itself as a convenience to the caller.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Connection_ContextManagerEnter(
|
|
udt_Connection *self, // connection
|
|
PyObject* args) // arguments
|
|
{
|
|
Py_INCREF(self);
|
|
return (PyObject*) self;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Connection_ContextManagerExit()
|
|
// Called when the connection is used as a context manager and if any
|
|
// exception a rollback takes place; otherwise, a commit takes place.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Connection_ContextManagerExit(
|
|
udt_Connection *self, // connection
|
|
PyObject* args) // arguments
|
|
{
|
|
PyObject *excType, *excValue, *excTraceback, *result;
|
|
char *methodName;
|
|
|
|
if (!PyArg_ParseTuple(args, "OOO", &excType, &excValue, &excTraceback))
|
|
return NULL;
|
|
if (excType == Py_None && excValue == Py_None && excTraceback == Py_None)
|
|
methodName = "commit";
|
|
else methodName = "rollback";
|
|
result = PyObject_CallMethod((PyObject*) self, methodName, "");
|
|
if (!result)
|
|
return NULL;
|
|
Py_DECREF(result);
|
|
|
|
Py_INCREF(Py_False);
|
|
return Py_False;
|
|
}
|
|
|
|
|
|
#if ORACLE_VERSION_HEX >= ORACLE_VERSION(10, 2)
|
|
#if !defined(AIX5) || ORACLE_VERSION_HEX >= ORACLE_VERSION(11, 1)
|
|
//-----------------------------------------------------------------------------
|
|
// Connection_Ping()
|
|
// Makes a round trip call to the server to confirm that the connection and
|
|
// server are active.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Connection_Ping(
|
|
udt_Connection *self, // connection
|
|
PyObject* args) // arguments
|
|
{
|
|
sword status;
|
|
|
|
if (Connection_IsConnected(self) < 0)
|
|
return NULL;
|
|
status = OCIPing(self->handle, self->environment->errorHandle,
|
|
OCI_DEFAULT);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"Connection_Ping()") < 0)
|
|
return NULL;
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|
|
#endif
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Connection_Shutdown()
|
|
// Shuts down the database. Note that this must be done in two phases except
|
|
// in the situation where the instance is aborted.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Connection_Shutdown(
|
|
udt_Connection *self, // connection
|
|
PyObject* args, // arguments
|
|
PyObject* keywordArgs) // keyword arguments
|
|
{
|
|
static char *keywordList[] = { "mode", NULL };
|
|
sword status;
|
|
ub4 mode;
|
|
|
|
// parse arguments
|
|
mode = OCI_DEFAULT;
|
|
if (!PyArg_ParseTupleAndKeywords(args, keywordArgs, "|i", keywordList,
|
|
&mode))
|
|
return NULL;
|
|
|
|
// perform the work
|
|
if (Connection_IsConnected(self) < 0)
|
|
return NULL;
|
|
status = OCIDBShutdown(self->handle, self->environment->errorHandle, NULL,
|
|
mode);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"Connection_Shutdown()") < 0)
|
|
return NULL;
|
|
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Connection_Startup()
|
|
// Starts up the database, equivalent to "startup nomount" in SQL*Plus.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Connection_Startup(
|
|
udt_Connection *self, // connection
|
|
PyObject* args, // arguments
|
|
PyObject* keywordArgs) // keyword arguments
|
|
{
|
|
static char *keywordList[] = { "force", "restrict", NULL };
|
|
PyObject *forceObj, *restrictObj;
|
|
int flagTemp;
|
|
sword status;
|
|
ub4 flags;
|
|
|
|
// parse arguments
|
|
forceObj = restrictObj = NULL;
|
|
if (!PyArg_ParseTupleAndKeywords(args, keywordArgs, "|OO", keywordList,
|
|
&forceObj, &restrictObj))
|
|
return NULL;
|
|
|
|
// set the flags to use during startup
|
|
flags = 0;
|
|
if (forceObj) {
|
|
flagTemp = PyObject_IsTrue(forceObj);
|
|
if (flagTemp < 0)
|
|
return NULL;
|
|
if (flagTemp)
|
|
flags |= OCI_DBSTARTUPFLAG_FORCE;
|
|
}
|
|
if (restrictObj) {
|
|
flagTemp = PyObject_IsTrue(restrictObj);
|
|
if (flagTemp < 0)
|
|
return NULL;
|
|
if (flagTemp)
|
|
flags |= OCI_DBSTARTUPFLAG_RESTRICT;
|
|
}
|
|
|
|
// perform the work
|
|
if (Connection_IsConnected(self) < 0)
|
|
return NULL;
|
|
status = OCIDBStartup(self->handle, self->environment->errorHandle, NULL,
|
|
OCI_DEFAULT, flags);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"Connection_Startup()") < 0)
|
|
return NULL;
|
|
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Connection_Subscribe()
|
|
// Create a subscription to events that take place in the database.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Connection_Subscribe(
|
|
udt_Connection *self, // connection
|
|
PyObject* args, // arguments
|
|
PyObject* keywordArgs) // keyword arguments
|
|
{
|
|
static char *keywordList[] = { "namespace", "protocol", "callback",
|
|
"timeout", "operations", "rowids", "port", "qos", "cqqos", NULL };
|
|
ub4 namespace, protocol, port, timeout, rowids, operations, qos, cqqos;
|
|
PyObject *rowidsObj, *callback;
|
|
int temp;
|
|
|
|
// parse arguments
|
|
timeout = rowids = port = qos = cqqos = 0;
|
|
rowidsObj = callback = NULL;
|
|
namespace = OCI_SUBSCR_NAMESPACE_DBCHANGE;
|
|
protocol = OCI_SUBSCR_PROTO_OCI;
|
|
operations = OCI_OPCODE_ALLOPS;
|
|
if (!PyArg_ParseTupleAndKeywords(args, keywordArgs, "|iiOiiOiii", keywordList,
|
|
&namespace, &protocol, &callback, &timeout, &operations,
|
|
&rowidsObj, &port, &qos, &cqqos))
|
|
return NULL;
|
|
|
|
// set the value for rowids
|
|
if (rowidsObj) {
|
|
temp = PyObject_IsTrue(rowidsObj);
|
|
if (temp < 0)
|
|
return NULL;
|
|
if (temp)
|
|
rowids = 1;
|
|
}
|
|
|
|
return (PyObject*) Subscription_New(self, namespace, protocol, port,
|
|
callback, timeout, operations, qos, cqqos, rowids);
|
|
}
|
|
#endif
|
|
|