python-cx_Oracle/ObjectVar.c
2016-02-22 09:53:35 -07:00

364 lines
13 KiB
C

//-----------------------------------------------------------------------------
// ObjectVar.c
// Defines the routines for handling Oracle object variables.
//-----------------------------------------------------------------------------
#include "ObjectType.c"
//-----------------------------------------------------------------------------
// Object type
//-----------------------------------------------------------------------------
typedef struct {
Variable_HEAD
dvoid **data;
dvoid **objectIndicator;
PyObject **objects;
udt_Connection *connection;
udt_ObjectType *objectType;
} udt_ObjectVar;
//-----------------------------------------------------------------------------
// Declaration of object variable functions.
//-----------------------------------------------------------------------------
static int ObjectVar_Initialize(udt_ObjectVar*, udt_Cursor*);
static void ObjectVar_Finalize(udt_ObjectVar*);
static int ObjectVar_SetValue(udt_ObjectVar*, unsigned, PyObject*);
static PyObject *ObjectVar_GetValue(udt_ObjectVar*, unsigned);
static int ObjectVar_PreDefine(udt_ObjectVar*, OCIParam*);
static int ObjectVar_PostDefine(udt_ObjectVar*);
static int ObjectVar_PostBind(udt_ObjectVar*);
static int ObjectVar_PreFetch(udt_ObjectVar*);
static int ObjectVar_IsNull(udt_ObjectVar*, unsigned);
static int ObjectVar_SetType(udt_ObjectVar*, PyObject*);
//-----------------------------------------------------------------------------
// declaration of members for Oracle objects
//-----------------------------------------------------------------------------
static PyMemberDef g_ObjectVarMembers[] = {
{ "type", T_OBJECT, offsetof(udt_ObjectVar, objectType), READONLY },
{ NULL }
};
//-----------------------------------------------------------------------------
// Python type declarations
//-----------------------------------------------------------------------------
static PyTypeObject g_ObjectVarType = {
PyVarObject_HEAD_INIT(NULL, 0)
"cx_Oracle.OBJECT", // tp_name
sizeof(udt_ObjectVar), // tp_basicsize
0, // tp_itemsize
0, // tp_dealloc
0, // tp_print
0, // tp_getattr
0, // tp_setattr
0, // tp_compare
0, // 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, // tp_flags
0, // tp_doc
0, // tp_traverse
0, // tp_clear
0, // tp_richcompare
0, // tp_weaklistoffset
0, // tp_iter
0, // tp_iternext
0, // tp_methods
g_ObjectVarMembers // tp_members
};
//-----------------------------------------------------------------------------
// variable type declarations
//-----------------------------------------------------------------------------
static udt_VariableType vt_Object = {
(InitializeProc) ObjectVar_Initialize,
(FinalizeProc) ObjectVar_Finalize,
(PreDefineProc) ObjectVar_PreDefine,
(PostDefineProc) ObjectVar_PostDefine,
(PostBindProc) ObjectVar_PostBind,
(PreFetchProc) ObjectVar_PreFetch,
(IsNullProc) ObjectVar_IsNull,
(SetValueProc) ObjectVar_SetValue,
(GetValueProc) ObjectVar_GetValue,
(GetBufferSizeProc) NULL,
&g_ObjectVarType, // Python type
SQLT_NTY, // Oracle type
SQLCS_IMPLICIT, // charset form
sizeof(dvoid*), // element length
0, // is character data
0, // is variable length
0, // can be copied
0 // can be in array
};
//-----------------------------------------------------------------------------
// ObjectVar_Initialize()
// Initialize the variable.
//-----------------------------------------------------------------------------
static int ObjectVar_Initialize(
udt_ObjectVar *self, // variable to initialize
udt_Cursor *cursor) // cursor to use
{
ub4 i;
Py_INCREF(cursor->connection);
self->connection = cursor->connection;
self->objectType = NULL;
self->objectIndicator =
PyMem_Malloc(self->allocatedElements * sizeof(dvoid*));
if (!self->objectIndicator) {
PyErr_NoMemory();
return -1;
}
self->objects = PyMem_Malloc(self->allocatedElements * sizeof(PyObject*));
if (!self->objects) {
PyErr_NoMemory();
return -1;
}
for (i = 0; i < self->allocatedElements; i++) {
self->data[i] = NULL;
self->objectIndicator[i] = NULL;
self->objects[i] = NULL;
}
return 0;
}
//-----------------------------------------------------------------------------
// ObjectVar_Finalize()
// Prepare for variable destruction.
//-----------------------------------------------------------------------------
static void ObjectVar_Finalize(
udt_ObjectVar *self) // variable to free
{
ub4 i;
for (i = 0; i < self->allocatedElements; i++) {
if (self->objects[i])
Py_CLEAR(self->objects[i]);
else if (self->data[i])
OCIObjectFree(self->environment->handle,
self->environment->errorHandle, self->data[i],
OCI_DEFAULT);
}
Py_CLEAR(self->connection);
Py_CLEAR(self->objectType);
if (self->objectIndicator)
PyMem_Free(self->objectIndicator);
if (self->objects)
PyMem_Free(self->objects);
}
//-----------------------------------------------------------------------------
// ObjectVar_PreDefine()
// Performs additional steps required for defining objects.
//-----------------------------------------------------------------------------
static int ObjectVar_PreDefine(
udt_ObjectVar *self, // variable to set up
OCIParam *param) // parameter being defined
{
self->objectType = ObjectType_New(self->connection, param,
OCI_ATTR_TYPE_NAME);
if (!self->objectType)
return -1;
return 0;
}
//-----------------------------------------------------------------------------
// ObjectVar_PostDefine()
// Performs additional steps required for defining objects.
//-----------------------------------------------------------------------------
static int ObjectVar_PostDefine(
udt_ObjectVar *self) // variable to set up
{
sword status;
status = OCIDefineObject(self->defineHandle,
self->environment->errorHandle, self->objectType->tdo, self->data,
0, self->objectIndicator, 0);
return Environment_CheckForError(self->environment, status,
"ObjectVar_PostDefine(): define object");
}
//-----------------------------------------------------------------------------
// ObjectVar_PostBind()
// Performs additional steps required for binding objects.
//-----------------------------------------------------------------------------
static int ObjectVar_PostBind(
udt_ObjectVar *self) // variable to set up
{
sword status;
if (!self->objectType) {
PyErr_SetString(g_InterfaceErrorException,
"object type not associated with bind variable");
return -1;
}
status = OCIBindObject(self->bindHandle, self->environment->errorHandle,
self->objectType->tdo, self->data, 0, self->objectIndicator, 0);
return Environment_CheckForError(self->environment, status,
"ObjectVar_PostBind(): bind object");
}
//-----------------------------------------------------------------------------
// ObjectVar_PreFetch()
// Free objects prior to next fetch.
//-----------------------------------------------------------------------------
static int ObjectVar_PreFetch(
udt_ObjectVar *var) // variable to free
{
ub4 i;
for (i = 0; i < var->allocatedElements; i++) {
Py_CLEAR(var->objects[i]);
if (var->data[i])
OCIObjectFree(var->environment->handle,
var->environment->errorHandle, var->data[i], OCI_DEFAULT);
}
return 0;
}
//-----------------------------------------------------------------------------
// ObjectVar_IsNull()
// Returns a boolean indicating if the variable is null or not.
//-----------------------------------------------------------------------------
static int ObjectVar_IsNull(
udt_ObjectVar *self, // variable to set up
unsigned pos) // position to check
{
if (!self->objectIndicator[pos])
return 1;
return (*((OCIInd*) self->objectIndicator[pos]) == OCI_IND_NULL);
}
//-----------------------------------------------------------------------------
// ObjectVar_SetValue()
// Set the value of the variable.
//-----------------------------------------------------------------------------
static int ObjectVar_SetValue(
udt_ObjectVar *self, // variable to determine value for
unsigned pos, // array position
PyObject *value) // value to set
{
udt_Object *object;
// only cx_Oracle.Object values are permitted and the types must match
// if the variable doesn't have a type yet, assign it
if (Py_TYPE(value) != &g_ObjectType) {
PyErr_SetString(PyExc_TypeError, "expecting cx_Oracle.Object");
return -1;
}
object = (udt_Object*) value;
if (!self->objectType) {
Py_INCREF(object->objectType);
self->objectType = object->objectType;
} else if (object->objectType->tdo != self->objectType->tdo) {
PyErr_SetString(PyExc_TypeError,
"expecting same type as the variable itself");
return -1;
}
// eliminate prior value, if needed
if (self->objects[pos])
Py_CLEAR(self->objects[pos]);
else OCIObjectFree(self->environment->handle,
self->environment->errorHandle, self->data[pos], OCI_DEFAULT);
// set new value
Py_INCREF(value);
self->objects[pos] = value;
self->data[pos] = object->instance;
self->objectIndicator[pos] = object->indicator;
return 0;
}
//-----------------------------------------------------------------------------
// ObjectVar_GetValue()
// Returns the value stored at the given array position.
//-----------------------------------------------------------------------------
static PyObject *ObjectVar_GetValue(
udt_ObjectVar *self, // variable to determine value for
unsigned pos) // array position
{
PyObject *obj;
// create the object, if needed; for collections, return a list, not the
// object itself
if (!self->objects[pos]) {
obj = Object_New(self->objectType, self->data[pos],
self->objectIndicator[pos], 1);
if (!obj)
return NULL;
self->objects[pos] = obj;
}
Py_INCREF(self->objects[pos]);
return self->objects[pos];
}
//-----------------------------------------------------------------------------
// ObjectVar_SetType()
// Internal method used to set the type when creating an object variable.
// This will also create the object instances.
//-----------------------------------------------------------------------------
static int ObjectVar_SetType(
udt_ObjectVar *self, // variable to initialize the type
PyObject *typeNameObj) // value to set
{
dvoid *instance, *indicator;
sword status;
ub4 i;
// get the object type from the name
self->objectType = ObjectType_NewByName(self->connection, typeNameObj);
if (!self->objectType)
return -1;
// initialize the object instances
for (i = 0; i < self->allocatedElements; i++) {
// create the object instance
status = OCIObjectNew(self->connection->environment->handle,
self->connection->environment->errorHandle,
self->connection->handle, self->objectType->typeCode,
self->objectType->tdo, NULL, OCI_DURATION_SESSION, TRUE,
&instance);
if (Environment_CheckForError(self->connection->environment, status,
"ObjectVar_SetType(): create object instance") < 0)
return -1;
self->data[i] = instance;
// get the null indicator structure
status = OCIObjectGetInd(self->connection->environment->handle,
self->connection->environment->errorHandle, instance,
&indicator);
if (Environment_CheckForError(self->connection->environment, status,
"ObjectVar_SetType(): get indicator structure") < 0)
return -1;
*((OCIInd*) indicator) = OCI_IND_NULL;
self->objectIndicator[i] = indicator;
}
return 0;
}