As requested by Helge Tesdal, allow an output type handler to be specified

at the connection and cursor levels. This handler will be called for each
variable being defined with the parameters cursor, name, defaultType, size,
precision and scale and expects to have a variable of the correct type
returned or None to indicate that default processing should take place.
This commit is contained in:
Anthony Tuininga 2008-08-05 03:32:19 +00:00
parent 64eeeabda7
commit 780423a59e
3 changed files with 80 additions and 1 deletions

View File

@ -13,6 +13,7 @@ typedef struct {
OCISession *sessionHandle;
udt_Environment *environment;
udt_SessionPool *sessionPool;
PyObject *outputTypeHandler;
PyObject *username;
PyObject *password;
PyObject *dsn;
@ -105,6 +106,8 @@ static PyMemberDef g_ConnectionMembers[] = {
{ "dsn", T_OBJECT, offsetof(udt_Connection, dsn), READONLY },
{ "tnsentry", T_OBJECT, offsetof(udt_Connection, dsn), READONLY },
{ "autocommit", T_INT, offsetof(udt_Connection, autocommit), 0 },
{ "outputtypehandler", T_OBJECT,
offsetof(udt_Connection, outputTypeHandler), 0 },
{ NULL }
};

View File

@ -16,6 +16,7 @@ typedef struct {
PyObject *bindVariables;
PyObject *fetchVariables;
PyObject *rowFactory;
PyObject *outputTypeHandler;
int arraySize;
int bindArraySize;
int fetchArraySize;
@ -109,6 +110,8 @@ static PyMemberDef g_CursorMembers[] = {
{ "connection", T_OBJECT_EX, offsetof(udt_Cursor, connection), READONLY },
{ "numbersAsStrings", T_INT, offsetof(udt_Cursor, numbersAsStrings), 0 },
{ "rowfactory", T_OBJECT, offsetof(udt_Cursor, rowFactory), 0 },
{ "outputtypehandler", T_OBJECT, offsetof(udt_Cursor, outputTypeHandler),
0 },
{ NULL }
};

View File

@ -637,6 +637,71 @@ static udt_Variable *Variable_NewByType(
}
//-----------------------------------------------------------------------------
// Variable_NewByOutputTypeHandler()
// Create a new variable by calling the output type handler.
//-----------------------------------------------------------------------------
static udt_Variable *Variable_NewByOutputTypeHandler(
udt_Cursor *cursor, // cursor to associate variable with
OCIParam *param, // parameter descriptor
PyObject *outputTypeHandler, // method to call to get type
udt_VariableType *varType, // variable type already chosen
ub4 maxLength, // maximum length of variable
unsigned numElements) // number of elements
{
PyObject *result;
ub4 nameLength;
sb2 precision;
sword status;
char *name;
sb1 scale;
// determine name of variable
status = OCIAttrGet(param, OCI_HTYPE_DESCRIBE, (dvoid*) &name,
&nameLength, OCI_ATTR_NAME, cursor->environment->errorHandle);
if (Environment_CheckForError(cursor->environment, status,
"Variable_NewByOutputTypeHandler(): get name") < 0)
return NULL;
// retrieve scale and precision of the parameter, if applicable
scale = precision = 0;
if (varType->pythonType == &g_NumberVarType) {
status = OCIAttrGet(param, OCI_HTYPE_DESCRIBE, (dvoid*) &scale, 0,
OCI_ATTR_SCALE, cursor->environment->errorHandle);
if (Environment_CheckForError(cursor->environment, status,
"Variable_NewByOutputTypeHandler(): get scale") < 0)
return NULL;
status = OCIAttrGet(param, OCI_HTYPE_DESCRIBE, (dvoid*) &precision, 0,
OCI_ATTR_PRECISION, cursor->environment->errorHandle);
if (Environment_CheckForError(cursor->environment, status,
"Variable_NewByOutputTypeHandler(): get precision") < 0)
return NULL;
}
// call method, passing parameters
result = PyObject_CallFunction(outputTypeHandler, "Os#Oiii",
cursor, name, nameLength, varType->pythonType, maxLength,
precision, scale);
if (!result)
return NULL;
// if result is None, assume default behavior
if (result == Py_None) {
Py_DECREF(result);
return Variable_New(cursor, numElements, varType, maxLength);
}
// otherwise, return the result, ensuring it is a variable first
if (!Variable_Check(result)) {
Py_DECREF(result);
PyErr_SetString(PyExc_TypeError,
"expecting variable from output type handler");
return NULL;
}
return (udt_Variable*) result;
}
//-----------------------------------------------------------------------------
// Variable_DefineHelper()
// Helper routine for Variable_Define() used so that constant calls to
@ -707,7 +772,15 @@ static udt_Variable *Variable_DefineHelper(
}
// create a variable of the correct type
var = Variable_New(cursor, numElements, varType, maxLength);
if (cursor->outputTypeHandler && cursor->outputTypeHandler != Py_None)
var = Variable_NewByOutputTypeHandler(cursor, param,
cursor->outputTypeHandler, varType, maxLength, numElements);
else if (cursor->connection->outputTypeHandler &&
cursor->connection->outputTypeHandler != Py_None)
var = Variable_NewByOutputTypeHandler(cursor, param,
cursor->connection->outputTypeHandler, varType, maxLength,
numElements);
else var = Variable_New(cursor, numElements, varType, maxLength);
if (!var)
return NULL;