python-cx_Oracle/Callback.c

329 lines
10 KiB
C

//-----------------------------------------------------------------------------
// Callback.c
// Definition of OCI callback functions.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Callback_NewVariable()
// Return a new variable from a callback.
//-----------------------------------------------------------------------------
static udt_Variable *Callback_NewVariable(
udt_Connection *connection, // connection to use
ub2 oracleType, // Oracle type of data
ub4 maxLength, // maximum length of elements
void *data, // data pointer
void *indicator, // indicator pointer
ub2 *returnCode, // return code pointer
ub2 *actualLength) // actual length pointer
{
udt_VariableType *type;
udt_Variable *var;
// determine the type to use
type = Variable_TypeByOracleDataType(oracleType, SQLCS_IMPLICIT);
if (!type)
return NULL;
// attempt to allocate the object
var = PyObject_NEW(udt_Variable, type->pythonType);
if (!var)
return NULL;
// perform basic initialization
// note that the number of allocated elements is set arbitrarily high
// because the OCI doesn't give information about how many elements are
// actually allocated; that has to be implied by the number of rows
// passed to OCIStmtFetch and OCIStmtExecute
Py_INCREF(connection->environment);
var->environment = connection->environment;
var->boundCursorHandle = NULL;
var->bindHandle = NULL;
var->defineHandle = NULL;
var->boundName = NULL;
var->allocatedElements = 2147483647;
var->actualElements = 0;
var->isArray = 0;
var->isAllocatedInternally = 0;
var->type = type;
var->indicator = indicator;
var->data = data;
var->actualLength = actualLength;
var->returnCode = returnCode;
var->maxLength = type->elementLength;
if (type->isVariableLength)
var->maxLength = maxLength;
return var;
}
//-----------------------------------------------------------------------------
// Callback_BindByNameArgs()
// Return the arguments to be passed when OCIBindByName is called.
//-----------------------------------------------------------------------------
static PyObject *Callback_BindByNameArgs(
udt_Connection *connection, // connection to use
va_list args) // arguments to OCI function
{
ub4 nameLength, allocatedElements, *actualElements;
ub2 dataType, *actualLength, *returnCode;
dvoid *indicator, *value;
OCIBind **bindHandlePtr;
OCIError *errorHandle;
udt_Variable *var;
PyObject *result;
sb4 valueLength;
OCIStmt *handle;
text *name;
handle = va_arg(args, OCIStmt*);
bindHandlePtr = va_arg(args, OCIBind**);
errorHandle = va_arg(args, OCIError*);
name = va_arg(args, text*);
nameLength = va_arg(args, ub4);
value = va_arg(args, dvoid*);
valueLength = va_arg(args, sb4);
dataType = va_arg(args, int);
indicator = va_arg(args, dvoid*);
actualLength = va_arg(args, ub2*);
returnCode = va_arg(args, ub2*);
allocatedElements = va_arg(args, ub4);
actualElements = va_arg(args, ub4*);
var = Callback_NewVariable(connection, dataType, valueLength, value,
indicator, returnCode, actualLength);
if (!var)
return NULL;
if (allocatedElements > 0) {
var->isArray = 1;
var->actualElements = *actualElements;
}
result = Py_BuildValue("ls#O", handle, name, nameLength, var);
Py_DECREF(var);
return result;
}
//-----------------------------------------------------------------------------
// Callback_DefineByPosArgs()
// Return the arguments to be passed when OCIDefineByPos is called.
//-----------------------------------------------------------------------------
static PyObject *Callback_DefineByPosArgs(
udt_Connection *connection, // connection to use
va_list args) // arguments to OCI function
{
ub2 dataType, *actualLength, *returnCode;
OCIDefine **defineHandle;
dvoid *indicator, *value;
OCIError *errorHandle;
udt_Variable *var;
PyObject *result;
OCIStmt *handle;
sb4 valueLength;
ub4 position;
handle = va_arg(args, OCIStmt*);
defineHandle = va_arg(args, OCIDefine**);
errorHandle = va_arg(args, OCIError*);
position = va_arg(args, ub4);
value = va_arg(args, dvoid*);
valueLength = va_arg(args, sb4);
dataType = va_arg(args, int);
indicator = va_arg(args, dvoid*);
actualLength = va_arg(args, ub2*);
returnCode = va_arg(args, ub2*);
// create a variable
var = Callback_NewVariable(connection, dataType, valueLength, value,
indicator, returnCode, actualLength);
if (!var)
return NULL;
result = Py_BuildValue("liO", handle, position, var);
Py_DECREF(var);
return result;
}
//-----------------------------------------------------------------------------
// Callback_ExecuteArgs()
// Return the arguments to be passed when OCIStmtExecute is called.
//-----------------------------------------------------------------------------
static PyObject *Callback_ExecuteArgs(
va_list args) // arguments to OCI function
{
OCISvcCtx* serviceContextHandle;
OCIError *errorHandle;
ub4 iters, rowoff;
OCIStmt *handle;
serviceContextHandle = va_arg(args, OCISvcCtx*);
handle = va_arg(args, OCIStmt*);
errorHandle = va_arg(args, OCIError*);
iters = va_arg(args, ub4);
rowoff = va_arg(args, ub4);
return Py_BuildValue("lii", handle, iters, rowoff);
}
//-----------------------------------------------------------------------------
// Callback_FetchArgs()
// Return the arguments to be passed when OCIStmtFetch is called.
//-----------------------------------------------------------------------------
static PyObject *Callback_FetchArgs(
udt_Connection *connection, // connection to use
va_list args) // arguments to OCI function
{
ub4 numRows, rowCount;
OCIError *errorHandle;
OCIStmt *handle;
sword status;
handle = va_arg(args, OCIStmt*);
errorHandle = va_arg(args, OCIError*);
numRows = va_arg(args, ub4);
status = OCIAttrGet(handle, OCI_HTYPE_STMT, &rowCount, 0,
OCI_ATTR_ROW_COUNT, connection->environment->errorHandle);
if (Environment_CheckForError(connection->environment, status,
"Callback_FetchArgs()") < 0)
return NULL;
return Py_BuildValue("lii", handle, numRows, rowCount);
}
//-----------------------------------------------------------------------------
// Callback_PrepareArgs()
// Return the arguments to be passed when OCIStmtPrepare is called.
//-----------------------------------------------------------------------------
static PyObject *Callback_PrepareArgs(
va_list args) // arguments to OCI function
{
OCIError *errorHandle;
ub4 statementLength;
OCIStmt *handle;
text *statement;
handle = va_arg(args, OCIStmt*);
errorHandle = va_arg(args, OCIError*);
statement = va_arg(args, text *);
statementLength = va_arg(args, ub4);
return Py_BuildValue("ls#", handle, statement, statementLength);
}
//-----------------------------------------------------------------------------
// Callback_GetArgs()
// Return the arguments to be passed to the Python callback method.
//-----------------------------------------------------------------------------
static PyObject *Callback_GetArgs(
udt_Connection *connection, // connection to use
ub4 functionCode, // function code
va_list args) // OCI function arguments
{
switch (functionCode) {
case OCI_FNCODE_BINDBYNAME:
return Callback_BindByNameArgs(connection, args);
case OCI_FNCODE_DEFINEBYPOS:
return Callback_DefineByPosArgs(connection, args);
case OCI_FNCODE_STMTEXECUTE:
return Callback_ExecuteArgs(args);
case OCI_FNCODE_STMTFETCH:
return Callback_FetchArgs(connection, args);
case OCI_FNCODE_STMTPREPARE:
return Callback_PrepareArgs(args);
}
return PyTuple_New(0);
}
//-----------------------------------------------------------------------------
// Callback_Call()
// Actually make the call to the Python function.
//-----------------------------------------------------------------------------
static sword Callback_Call(
PyObject *tuple, // tuple containing connection/callback
ub4 functionCode, // function code
va_list args) // arguments
{
PyObject *callback, *callbackArgs, *result;
udt_Connection *connection;
// determine the connection and callback
connection = (udt_Connection*) PyTuple_GET_ITEM(tuple, 0);
callback = PyTuple_GET_ITEM(tuple, 1);
// determine the arguments to pass to the function
callbackArgs = Callback_GetArgs(connection, functionCode, args);
if (!callbackArgs)
return OCI_ERROR;
// actually make the call to the method
result = PyEval_CallObject(callback, callbackArgs);
Py_DECREF(callbackArgs);
if (!result)
return OCI_ERROR;
Py_DECREF(result);
return OCI_SUCCESS;
}
//-----------------------------------------------------------------------------
// Callback_Handler()
// Callback handler for calling Python code within an OCI callback.
//-----------------------------------------------------------------------------
static sword Callback_Handler(
PyObject *tuple, // tuple containing connection/callback
dvoid *handle, // pointer to handle
ub4 handleType, // handle type
ub4 functionCode, // function code
ub1 when, // when being called
sword returnCode, // return code
ub4 *errorCode, // error code (IN/OUT)
va_list args) // arguments
{
#ifdef WITH_THREAD
PyThreadState *threadState;
#endif
sword result;
// create new thread state, if necessary
#ifdef WITH_THREAD
threadState = PyThreadState_Swap(NULL);
if (threadState) {
PyThreadState_Swap(threadState);
threadState = NULL;
} else {
threadState = PyThreadState_New(g_InterpreterState);
if (!threadState) {
PyErr_Print();
return OCI_ERROR;
}
PyEval_AcquireThread(threadState);
}
#endif
// perform the call
result = Callback_Call(tuple, functionCode, args);
if (result != OCI_CONTINUE)
PyErr_Print();
// restore thread state, if necessary
#ifdef WITH_THREAD
if (threadState) {
PyThreadState_Clear(threadState);
PyEval_ReleaseThread(threadState);
PyThreadState_Delete(threadState);
}
#endif
return result;
}