python-cx_Oracle/Connection.c

1709 lines
62 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 *password;
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;
#ifdef ORACLE_10G
static ub4 gc_ModuleAttribute = OCI_ATTR_MODULE;
static ub4 gc_ActionAttribute = OCI_ATTR_ACTION;
static ub4 gc_ClientInfoAttribute = OCI_ATTR_CLIENT_INFO;
#endif
#ifdef ORACLE_10GR2
static ub4 gc_CurrentSchemaAttribute = OCI_ATTR_CURRENT_SCHEMA;
#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*);
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_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*);
#ifndef WITH_UNICODE
static PyObject *Connection_GetEncoding(udt_Connection*, void*);
static PyObject *Connection_GetNationalEncoding(udt_Connection*, void*);
#endif
static PyObject *Connection_GetStmtCacheSize(udt_Connection*, void*);
static int Connection_SetStmtCacheSize(udt_Connection*, PyObject*, void*);
#ifdef ORACLE_10G
static PyObject *Connection_GetOCIAttr(udt_Connection*, ub4*);
#endif
static int Connection_SetOCIAttr(udt_Connection*, PyObject*, ub4*);
#ifdef ORACLE_10GR2
#if !defined(AIX5) || defined(ORACLE_11g)
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
//-----------------------------------------------------------------------------
// declaration of methods for Python type "Connection"
//-----------------------------------------------------------------------------
static PyMethodDef g_ConnectionMethods[] = {
{ "cursor", (PyCFunction) Connection_NewCursor, METH_NOARGS },
{ "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 },
#ifdef ORACLE_10GR2
#if !defined(AIX5) || defined(ORACLE_11g)
{ "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 },
{ NULL }
};
//-----------------------------------------------------------------------------
// declaration of members for Python type "Connection"
//-----------------------------------------------------------------------------
static PyMemberDef g_ConnectionMembers[] = {
{ "username", T_OBJECT, offsetof(udt_Connection, username), READONLY },
{ "password", T_OBJECT, offsetof(udt_Connection, password), 0 },
{ "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[] = {
#ifndef WITH_UNICODE
{ "encoding", (getter) Connection_GetEncoding, 0, 0, 0 },
{ "nencoding", (getter) Connection_GetNationalEncoding, 0, 0, 0 },
#endif
{ "version", (getter) Connection_GetVersion, 0, 0, 0 },
{ "maxBytesPerCharacter", (getter) Connection_GetMaxBytesPerCharacter,
0, 0, 0 },
{ "stmtcachesize", (getter) Connection_GetStmtCacheSize,
(setter) Connection_SetStmtCacheSize, 0, 0 },
#ifdef ORACLE_10G
{ "module", 0, (setter) Connection_SetOCIAttr, 0, &gc_ModuleAttribute },
{ "action", 0, (setter) Connection_SetOCIAttr, 0, &gc_ActionAttribute },
{ "clientinfo", 0, (setter) Connection_SetOCIAttr, 0,
&gc_ClientInfoAttribute },
#endif
{ "client_identifier", 0, (setter) Connection_SetOCIAttr, 0,
&gc_ClientIdentifierAttribute },
#ifdef ORACLE_10GR2
{ "current_schema", (getter) Connection_GetOCIAttr,
(setter) Connection_SetOCIAttr, 0, &gc_CurrentSchemaAttribute },
#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 *cclassObj, // connection class (DRCP)
ub4 purity) // purity (DRCP)
{
int externalCredentials, proxyCredentials;
udt_Environment *environment;
udt_StringBuffer buffer;
OCIAuthInfo *authInfo;
PyObject *dbNameObj;
boolean found;
sword status;
ub4 mode;
// set things up for the call to acquire a session
authInfo = NULL;
proxyCredentials = 0;
if (pool) {
environment = pool->environment;
dbNameObj = pool->name;
mode = OCI_SESSGET_SPOOL;
if (!pool->homogeneous && pool->username && self->username) {
proxyCredentials = PyObject_RichCompareBool(self->username,
pool->username, Py_NE);
if (proxyCredentials < 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 || proxyCredentials) {
// 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
externalCredentials = 1;
if (StringBuffer_Fill(&buffer, self->username) < 0)
return -1;
if (buffer.size > 0) {
externalCredentials = 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) {
StringBuffer_Clear(&buffer);
return -1;
}
}
StringBuffer_Clear(&buffer);
// set the password, if applicable
if (StringBuffer_Fill(&buffer, self->password) < 0)
return -1;
if (buffer.size > 0) {
externalCredentials = 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) {
StringBuffer_Clear(&buffer);
return -1;
}
}
StringBuffer_Clear(&buffer);
// if no user name or password are set, using external credentials
if (!pool && externalCredentials)
mode |= OCI_SESSGET_CREDEXT;
#ifdef ORACLE_11G
// set the connection class, if applicable
if (StringBuffer_Fill(&buffer, cclassObj) < 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) {
StringBuffer_Clear(&buffer);
return -1;
}
}
StringBuffer_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
}
// acquire the new session
if (StringBuffer_Fill(&buffer, dbNameObj) < 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
StringBuffer_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 (!proxyCredentials) {
Py_INCREF(pool->username);
self->username = pool->username;
Py_INCREF(pool->password);
self->password = pool->password;
}
Py_INCREF(pool->dsn);
self->dsn = pool->dsn;
Py_INCREF(pool);
self->sessionPool = pool;
}
self->release = 1;
return 0;
}
#ifdef ORACLE_10G
//-----------------------------------------------------------------------------
// 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_StringBuffer buffer;
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, (ub4*) &buffer.size, *attribute,
self->environment->errorHandle);
if (Environment_CheckForError(self->environment, status,
"Connection_GetOCIAttr()") < 0)
return NULL;
return cxString_FromEncodedString(buffer.ptr, buffer.size);
}
#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_StringBuffer buffer;
sword status;
// verify arguments
if (!cxString_Check(value)) {
PyErr_SetString(PyExc_TypeError, "value must be a string");
return -1;
}
// 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 (StringBuffer_Fill(&buffer, value))
return -1;
status = OCIAttrSet(sessionHandle, OCI_HTYPE_SESSION, (text*) buffer.ptr,
buffer.size, *attribute, self->environment->errorHandle);
StringBuffer_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_StringBuffer usernameBuffer, oldPasswordBuffer, newPasswordBuffer;
sword status;
if (StringBuffer_Fill(&usernameBuffer, self->username) < 0)
return -1;
if (StringBuffer_Fill(&oldPasswordBuffer, oldPasswordObj) < 0) {
StringBuffer_Clear(&usernameBuffer);
return -1;
}
if (StringBuffer_Fill(&newPasswordBuffer, newPasswordObj) < 0) {
StringBuffer_Clear(&usernameBuffer);
StringBuffer_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
StringBuffer_Clear(&usernameBuffer);
StringBuffer_Clear(&oldPasswordBuffer);
StringBuffer_Clear(&newPasswordBuffer);
if (Environment_CheckForError(self->environment, status,
"Connection_ChangePassword(): change password") < 0)
return -1;
Py_XDECREF(self->password);
Py_INCREF(newPasswordObj);
self->password = newPasswordObj;
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 *newPasswordObj) // new password (if desired)
{
ub4 credentialType = OCI_CRED_EXT;
udt_StringBuffer 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 (StringBuffer_Fill(&buffer, self->dsn) < 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
StringBuffer_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 (StringBuffer_Fill(&buffer, self->username) < 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) {
StringBuffer_Clear(&buffer);
return -1;
}
}
StringBuffer_Clear(&buffer);
// set password in session handle
if (StringBuffer_Fill(&buffer, self->password) < 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) {
StringBuffer_Clear(&buffer);
return -1;
}
}
StringBuffer_Clear(&buffer);
#ifdef OCI_ATTR_DRIVER_NAME
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 a new password has been specified, change it which will also
// establish the session
if (newPasswordObj)
return Connection_ChangePassword(self, self->password, 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"
#ifdef ORACLE_10GR2
#include "Subscription.c"
#endif
//-----------------------------------------------------------------------------
// 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;
self->environment = NULL;
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 *threadedObj, *twophaseObj, *eventsObj, *newPasswordObj;
PyObject *usernameObj, *passwordObj, *dsnObj, *cclassObj;
int threaded, twophase, events;
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", NULL };
// parse arguments
pool = NULL;
handle = NULL;
connectMode = OCI_DEFAULT;
usernameObj = passwordObj = dsnObj = cclassObj = NULL;
threadedObj = twophaseObj = eventsObj = newPasswordObj = NULL;
threaded = twophase = events = purity = 0;
#ifdef ORACLE_11G
purity = OCI_ATTR_PURITY_DEFAULT;
#endif
if (!PyArg_ParseTupleAndKeywords(args, keywordArgs, "|O!O!O!iiO!OOOO!iO!",
keywordList, cxString_Type, &usernameObj, cxString_Type,
&passwordObj, cxString_Type, &dsnObj, &connectMode, &handle,
&g_SessionPoolType, &pool, &threadedObj, &twophaseObj, &eventsObj,
cxString_Type, &cclassObj, &purity, cxString_Type,
&newPasswordObj))
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);
if (!self->environment)
return -1;
// keep a copy of the credentials
Py_XINCREF(usernameObj);
self->username = usernameObj;
Py_XINCREF(passwordObj);
self->password = passwordObj;
Py_XINCREF(dsnObj);
self->dsn = dsnObj;
// perform some parsing, if necessary
if (Connection_SplitComponent(&self->username, &self->password, "/") < 0)
return -1;
if (Connection_SplitComponent(&self->password, &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, cclassObj, purity);
return Connection_Connect(self, connectMode, twophase, newPasswordObj);
}
//-----------------------------------------------------------------------------
// 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->password);
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;
}
#ifndef WITH_UNICODE
//-----------------------------------------------------------------------------
// Connection_GetCharacterSetName()
// Retrieve the IANA character set name for the attribute.
//-----------------------------------------------------------------------------
static PyObject *Connection_GetCharacterSetName(
udt_Connection *self, // connection object
ub2 attribute) // attribute to fetch
{
char charsetName[OCI_NLS_MAXBUFSZ], ianaCharsetName[OCI_NLS_MAXBUFSZ];
ub2 charsetId;
sword status;
// get character set id
status = OCIAttrGet(self->environment->handle, OCI_HTYPE_ENV, &charsetId,
NULL, attribute, self->environment->errorHandle);
if (Environment_CheckForError(self->environment, status,
"Connection_GetCharacterSetName(): get charset id") < 0)
return NULL;
// get character set name
status = OCINlsCharSetIdToName(self->environment->handle,
(text*) charsetName, OCI_NLS_MAXBUFSZ, charsetId);
if (Environment_CheckForError(self->environment, status,
"Connection_GetCharacterSetName(): get Oracle charset name") < 0)
return NULL;
// get IANA character set name
status = OCINlsNameMap(self->environment->handle,
(oratext*) ianaCharsetName, OCI_NLS_MAXBUFSZ,
(oratext*) charsetName, OCI_NLS_CS_ORA_TO_IANA);
if (Environment_CheckForError(self->environment, status,
"Connection_GetCharacterSetName(): translate NLS charset") < 0)
return NULL;
return PyBytes_FromString(ianaCharsetName);
}
//-----------------------------------------------------------------------------
// Connection_GetEncoding()
// Retrieve the IANA encoding used by the client.
//-----------------------------------------------------------------------------
static PyObject *Connection_GetEncoding(
udt_Connection *self, // connection object
void *arg) // optional argument (ignored)
{
return Connection_GetCharacterSetName(self, OCI_ATTR_ENV_CHARSET_ID);
}
//-----------------------------------------------------------------------------
// Connection_GetNationalEncoding()
// Retrieve the IANA national encoding used by the client.
//-----------------------------------------------------------------------------
static PyObject *Connection_GetNationalEncoding(
udt_Connection *self, // connection object
void *arg) // optional argument (ignored)
{
return Connection_GetCharacterSetName(self, OCI_ATTR_ENV_NCHARSET_ID);
}
#endif
//-----------------------------------------------------------------------------
// 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_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);
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_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->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->handle, OCI_HTYPE_SVCCTX);
}
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 *createArgs, *result;
createArgs = PyTuple_New(1);
if (!createArgs)
return NULL;
Py_INCREF(self);
PyTuple_SET_ITEM(createArgs, 0, (PyObject*) self);
result = PyObject_Call( (PyObject*) &g_CursorType, createArgs, NULL);
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_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;
}
#ifdef ORACLE_10GR2
#if !defined(AIX5) || defined(ORACLE_11g)
//-----------------------------------------------------------------------------
// 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", NULL };
ub4 namespace, protocol, port, timeout, rowids, operations;
PyObject *rowidsObj, *callback;
int temp;
// parse arguments
timeout = rowids = port = 0;
rowidsObj = callback = NULL;
namespace = OCI_SUBSCR_NAMESPACE_DBCHANGE;
protocol = OCI_SUBSCR_PROTO_OCI;
operations = OCI_OPCODE_ALLOPS;
if (!PyArg_ParseTupleAndKeywords(args, keywordArgs, "|iiOiiOi", keywordList,
&namespace, &protocol, &callback, &timeout, &operations,
&rowidsObj, &port))
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, rowids);
}
#endif