519 lines
20 KiB
C
519 lines
20 KiB
C
//-----------------------------------------------------------------------------
|
|
// ObjectType.c
|
|
// Defines the routines for handling Oracle type information.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// structures used for handling object types
|
|
//-----------------------------------------------------------------------------
|
|
typedef struct {
|
|
PyObject_HEAD
|
|
udt_Environment *environment;
|
|
OCIType *tdo;
|
|
PyObject *schema;
|
|
PyObject *name;
|
|
PyObject *attributes;
|
|
PyObject *attributesByName;
|
|
OCITypeCode collectionTypeCode;
|
|
OCITypeCode elementTypeCode;
|
|
PyObject *elementType;
|
|
int isCollection;
|
|
} udt_ObjectType;
|
|
|
|
typedef struct {
|
|
PyObject_HEAD
|
|
PyObject *name;
|
|
OCITypeCode typeCode;
|
|
udt_ObjectType *subType;
|
|
} udt_ObjectAttribute;
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Declaration of type variable functions.
|
|
//-----------------------------------------------------------------------------
|
|
static udt_ObjectType *ObjectType_New(udt_Connection*, OCIParam*);
|
|
static void ObjectType_Free(udt_ObjectType*);
|
|
static PyObject *ObjectType_Repr(udt_ObjectType*);
|
|
static udt_ObjectAttribute *ObjectAttribute_New(udt_Connection*, OCIParam*);
|
|
static void ObjectAttribute_Free(udt_ObjectAttribute*);
|
|
static PyObject *ObjectAttribute_Repr(udt_ObjectAttribute*);
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// declaration of members for Python type "ObjectType"
|
|
//-----------------------------------------------------------------------------
|
|
static PyMemberDef g_ObjectTypeMembers[] = {
|
|
{ "schema", T_OBJECT, offsetof(udt_ObjectType, schema), READONLY },
|
|
{ "name", T_OBJECT, offsetof(udt_ObjectType, name), READONLY },
|
|
{ "attributes", T_OBJECT, offsetof(udt_ObjectType, attributes), READONLY },
|
|
{ NULL }
|
|
};
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// declaration of members for Python type "ObjectAttribute"
|
|
//-----------------------------------------------------------------------------
|
|
static PyMemberDef g_ObjectAttributeMembers[] = {
|
|
{ "name", T_OBJECT, offsetof(udt_ObjectAttribute, name), READONLY },
|
|
{ NULL }
|
|
};
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Python type declarations
|
|
//-----------------------------------------------------------------------------
|
|
static PyTypeObject g_ObjectTypeType = {
|
|
PyObject_HEAD_INIT(NULL)
|
|
0, // ob_size
|
|
"cx_Oracle.ObjectType", // tp_name
|
|
sizeof(udt_ObjectType), // tp_basicsize
|
|
0, // tp_itemsize
|
|
(destructor) ObjectType_Free, // tp_dealloc
|
|
0, // tp_print
|
|
0, // tp_getattr
|
|
0, // tp_setattr
|
|
0, // tp_compare
|
|
(reprfunc) ObjectType_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, // 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_ObjectTypeMembers, // tp_members
|
|
0, // tp_getset
|
|
0, // tp_base
|
|
0, // tp_dict
|
|
0, // tp_descr_get
|
|
0, // tp_descr_set
|
|
0, // tp_dictoffset
|
|
0, // tp_init
|
|
0, // tp_alloc
|
|
0, // tp_new
|
|
0, // tp_free
|
|
0, // tp_is_gc
|
|
0 // tp_bases
|
|
};
|
|
|
|
|
|
static PyTypeObject g_ObjectAttributeType = {
|
|
PyObject_HEAD_INIT(NULL)
|
|
0, // ob_size
|
|
"cx_Oracle.ObjectAttribute", // tp_name
|
|
sizeof(udt_ObjectAttribute), // tp_basicsize
|
|
0, // tp_itemsize
|
|
(destructor) ObjectAttribute_Free, // tp_dealloc
|
|
0, // tp_print
|
|
0, // tp_getattr
|
|
0, // tp_setattr
|
|
0, // tp_compare
|
|
(reprfunc) ObjectAttribute_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, // 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_ObjectAttributeMembers, // tp_members
|
|
0, // tp_getset
|
|
0, // tp_base
|
|
0, // tp_dict
|
|
0, // tp_descr_get
|
|
0, // tp_descr_set
|
|
0, // tp_dictoffset
|
|
0, // tp_init
|
|
0, // tp_alloc
|
|
0, // tp_new
|
|
0, // tp_free
|
|
0, // tp_is_gc
|
|
0 // tp_bases
|
|
};
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// ObjectType_Describe()
|
|
// Describe the type and store information about it as needed.
|
|
//-----------------------------------------------------------------------------
|
|
static int ObjectType_Describe(
|
|
udt_ObjectType *self, // type to populate
|
|
udt_Connection *connection, // connection for type information
|
|
OCIDescribe *describeHandle) // describe handle
|
|
{
|
|
OCIParam *topLevelParam, *attributeListParam, *attributeParam;
|
|
udt_ObjectAttribute *attribute;
|
|
OCIParam *collectionParam;
|
|
OCITypeCode typeCode;
|
|
ub2 numAttributes;
|
|
sword status;
|
|
int i;
|
|
|
|
// describe the type
|
|
status = OCIDescribeAny(connection->handle, self->environment->errorHandle,
|
|
(dvoid*) self->tdo, 0, OCI_OTYPE_PTR, OCI_DEFAULT, OCI_PTYPE_TYPE,
|
|
describeHandle);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"ObjectType_Describe(): describe type") < 0)
|
|
return -1;
|
|
|
|
// get top level parameter descriptor
|
|
status = OCIAttrGet(describeHandle, OCI_HTYPE_DESCRIBE, &topLevelParam, 0,
|
|
OCI_ATTR_PARAM, self->environment->errorHandle);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"ObjectType_Describe(): get top level parameter descriptor") < 0)
|
|
return -1;
|
|
|
|
// determine type of type
|
|
status = OCIAttrGet(topLevelParam, OCI_DTYPE_PARAM, &typeCode, 0,
|
|
OCI_ATTR_TYPECODE, self->environment->errorHandle);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"ObjectType_Describe(): get type code") < 0)
|
|
return -1;
|
|
|
|
// if a collection, need to determine the sub type
|
|
if (typeCode == OCI_TYPECODE_NAMEDCOLLECTION) {
|
|
self->isCollection = 1;
|
|
|
|
// determine type of collection
|
|
status = OCIAttrGet(topLevelParam, OCI_DTYPE_PARAM,
|
|
&self->collectionTypeCode, 0, OCI_ATTR_COLLECTION_TYPECODE,
|
|
self->environment->errorHandle);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"ObjectType_Describe(): get collection type code") < 0)
|
|
return -1;
|
|
|
|
// acquire collection parameter descriptor
|
|
status = OCIAttrGet(topLevelParam, OCI_DTYPE_PARAM, &collectionParam,
|
|
0, OCI_ATTR_COLLECTION_ELEMENT,
|
|
self->environment->errorHandle);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"ObjectType_Describe(): get collection descriptor") < 0)
|
|
return -1;
|
|
|
|
// determine type of element
|
|
status = OCIAttrGet(collectionParam, OCI_DTYPE_PARAM,
|
|
&self->elementTypeCode, 0, OCI_ATTR_TYPECODE,
|
|
self->environment->errorHandle);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"ObjectType_Describe(): get element type code") < 0)
|
|
return -1;
|
|
|
|
// if element type is an object type get its type
|
|
if (self->elementTypeCode == OCI_TYPECODE_OBJECT) {
|
|
self->elementType = (PyObject*)
|
|
ObjectType_New(connection, collectionParam);
|
|
if (!self->elementType)
|
|
return -1;
|
|
}
|
|
|
|
}
|
|
|
|
// determine the number of attributes
|
|
status = OCIAttrGet(topLevelParam, OCI_DTYPE_PARAM,
|
|
(dvoid*) &numAttributes, 0, OCI_ATTR_NUM_TYPE_ATTRS,
|
|
self->environment->errorHandle);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"ObjectType_Describe(): get number of attributes") < 0)
|
|
return -1;
|
|
|
|
// allocate the attribute list and dictionary
|
|
self->attributes = PyList_New(numAttributes);
|
|
if (!self->attributes)
|
|
return -1;
|
|
self->attributesByName = PyDict_New();
|
|
if (!self->attributesByName)
|
|
return -1;
|
|
|
|
// acquire the list parameter descriptor
|
|
status = OCIAttrGet(topLevelParam, OCI_DTYPE_PARAM,
|
|
(dvoid*) &attributeListParam, 0, OCI_ATTR_LIST_TYPE_ATTRS,
|
|
self->environment->errorHandle);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"ObjectType_Describe(): get list parameter descriptor") < 0)
|
|
return -1;
|
|
|
|
// create attribute information for each attribute
|
|
for (i = 0; i < numAttributes; i++) {
|
|
status = OCIParamGet(attributeListParam, OCI_DTYPE_PARAM,
|
|
self->environment->errorHandle, (dvoid**) &attributeParam,
|
|
(ub4) i + 1);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"ObjectType_Describe(): get attribute param descriptor") < 0)
|
|
return -1;
|
|
attribute = ObjectAttribute_New(connection, attributeParam);
|
|
if (!attribute)
|
|
return -1;
|
|
PyList_SET_ITEM(self->attributes, i, (PyObject*) attribute);
|
|
if (PyDict_SetItem(self->attributesByName, attribute->name,
|
|
(PyObject*) attribute) < 0)
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// ObjectType_Initialize()
|
|
// Initialize the object type with the information that is required.
|
|
//-----------------------------------------------------------------------------
|
|
static int ObjectType_Initialize(
|
|
udt_ObjectType *self, // type to initialize
|
|
udt_Connection *connection, // connection for type information
|
|
OCIParam *param) // parameter descriptor
|
|
{
|
|
OCIDescribe *describeHandle;
|
|
OCIRef *tdoReference;
|
|
sword status;
|
|
char *name;
|
|
ub4 size;
|
|
|
|
// determine the schema of the type
|
|
status = OCIAttrGet(param, OCI_HTYPE_DESCRIBE, (dvoid*) &name, &size,
|
|
OCI_ATTR_SCHEMA_NAME, self->environment->errorHandle);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"ObjectType_Initialize(): get schema name") < 0)
|
|
return -1;
|
|
self->schema = PyString_FromStringAndSize(name, size);
|
|
if (!self->schema)
|
|
return -1;
|
|
|
|
// determine the name of the type
|
|
status = OCIAttrGet(param, OCI_HTYPE_DESCRIBE, (dvoid*) &name, &size,
|
|
OCI_ATTR_TYPE_NAME, self->environment->errorHandle);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"ObjectType_Initialize(): get name") < 0)
|
|
return -1;
|
|
self->name = PyString_FromStringAndSize(name, size);
|
|
if (!self->name)
|
|
return -1;
|
|
|
|
// retrieve TDO of the parameter
|
|
status = OCIAttrGet(param, OCI_HTYPE_DESCRIBE, (dvoid*) &tdoReference, 0,
|
|
OCI_ATTR_REF_TDO, self->environment->errorHandle);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"ObjectType_Initialize(): get TDO reference") < 0)
|
|
return -1;
|
|
status = OCIObjectPin(self->environment->handle,
|
|
self->environment->errorHandle, tdoReference, NULL, OCI_PIN_ANY,
|
|
OCI_DURATION_SESSION, OCI_LOCK_NONE, (dvoid**) &self->tdo);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"ObjectType_Initialize(): pin TDO reference") < 0)
|
|
return -1;
|
|
|
|
// acquire a describe handle
|
|
status = OCIHandleAlloc(self->environment->handle,
|
|
(dvoid**) &describeHandle, OCI_HTYPE_DESCRIBE, 0, 0);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"ObjectType_Initialize(): allocate describe handle") < 0)
|
|
return -1;
|
|
|
|
// describe the type
|
|
if (ObjectType_Describe(self, connection, describeHandle) < 0)
|
|
return -1;
|
|
|
|
// free the describe handle
|
|
status = OCIHandleFree(describeHandle, OCI_HTYPE_DESCRIBE);
|
|
if (Environment_CheckForError(self->environment, status,
|
|
"ObjectType_Initialize(): free describe handle") < 0)
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// ObjectType_New()
|
|
// Allocate a new object type.
|
|
//-----------------------------------------------------------------------------
|
|
static udt_ObjectType *ObjectType_New(
|
|
udt_Connection *connection, // connection for type information
|
|
OCIParam *param) // parameter descriptor
|
|
{
|
|
udt_ObjectType *self;
|
|
|
|
self = PyObject_NEW(udt_ObjectType, &g_ObjectTypeType);
|
|
if (!self)
|
|
return NULL;
|
|
Py_INCREF(connection->environment);
|
|
self->environment = connection->environment;
|
|
self->tdo = NULL;
|
|
self->schema = NULL;
|
|
self->name = NULL;
|
|
self->attributes = NULL;
|
|
self->attributesByName = NULL;
|
|
self->elementType = NULL;
|
|
self->isCollection = 0;
|
|
if (ObjectType_Initialize(self, connection, param) < 0) {
|
|
Py_DECREF(self);
|
|
return NULL;
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// ObjectType_Free()
|
|
// Free the memory associated with an object type.
|
|
//-----------------------------------------------------------------------------
|
|
static void ObjectType_Free(
|
|
udt_ObjectType *self) // object type to free
|
|
{
|
|
Py_DECREF(self->environment);
|
|
Py_XDECREF(self->schema);
|
|
Py_XDECREF(self->name);
|
|
Py_XDECREF(self->attributes);
|
|
Py_XDECREF(self->attributesByName);
|
|
Py_XDECREF(self->elementType);
|
|
if (self->tdo)
|
|
OCIObjectUnpin(self->environment->handle,
|
|
self->environment->errorHandle, self->tdo);
|
|
PyObject_DEL(self);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// ObjectType_Repr()
|
|
// Return a string representation of the object type.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *ObjectType_Repr(
|
|
udt_ObjectType *self) // object type to return the string for
|
|
{
|
|
PyObject *module, *name, *result;
|
|
|
|
if (GetModuleAndName(self->ob_type, &module, &name) < 0)
|
|
return NULL;
|
|
result = PyString_FromFormat("<%s.%s %s.%s>",
|
|
PyString_AS_STRING(module), PyString_AS_STRING(name),
|
|
PyString_AS_STRING(self->schema), PyString_AS_STRING(self->name));
|
|
Py_DECREF(module);
|
|
Py_DECREF(name);
|
|
return result;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// ObjectAttribute_Initialize()
|
|
// Initialize the new object attribute.
|
|
//-----------------------------------------------------------------------------
|
|
static int ObjectAttribute_Initialize(
|
|
udt_ObjectAttribute *self, // object attribute to initialize
|
|
udt_Connection *connection, // connection in use
|
|
OCIParam *param) // parameter descriptor
|
|
{
|
|
sword status;
|
|
char *name;
|
|
ub4 size;
|
|
|
|
// determine the name of the attribute
|
|
status = OCIAttrGet(param, OCI_DTYPE_PARAM, (dvoid*) &name, &size,
|
|
OCI_ATTR_NAME, connection->environment->errorHandle);
|
|
if (Environment_CheckForError(connection->environment, status,
|
|
"ObjectAttribute_Initialize(): get name") < 0)
|
|
return -1;
|
|
self->name = PyString_FromStringAndSize(name, size);
|
|
if (!self->name)
|
|
return -1;
|
|
|
|
// determine the type of the attribute
|
|
status = OCIAttrGet(param, OCI_DTYPE_PARAM, (dvoid*) &self->typeCode, 0,
|
|
OCI_ATTR_TYPECODE, connection->environment->errorHandle);
|
|
if (Environment_CheckForError(connection->environment, status,
|
|
"ObjectAttribute_Initialize(): get type code") < 0)
|
|
return -1;
|
|
|
|
// if the type of the attribute is object, recurse
|
|
switch (self->typeCode) {
|
|
case OCI_TYPECODE_NAMEDCOLLECTION:
|
|
case OCI_TYPECODE_OBJECT:
|
|
self->subType = ObjectType_New(connection, param);
|
|
if (!self->subType)
|
|
return -1;
|
|
break;
|
|
};
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// ObjectAttribute_New()
|
|
// Allocate a new object attribute.
|
|
//-----------------------------------------------------------------------------
|
|
static udt_ObjectAttribute *ObjectAttribute_New(
|
|
udt_Connection *connection, // connection information
|
|
OCIParam *param) // parameter descriptor
|
|
{
|
|
udt_ObjectAttribute *self;
|
|
|
|
self = PyObject_NEW(udt_ObjectAttribute, &g_ObjectAttributeType);
|
|
if (!self)
|
|
return NULL;
|
|
self->name = NULL;
|
|
self->subType = NULL;
|
|
if (ObjectAttribute_Initialize(self, connection, param) < 0) {
|
|
Py_DECREF(self);
|
|
return NULL;
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// ObjectAttribute_Free()
|
|
// Free the memory associated with an object attribute.
|
|
//-----------------------------------------------------------------------------
|
|
static void ObjectAttribute_Free(
|
|
udt_ObjectAttribute *self) // object attribute to free
|
|
{
|
|
Py_XDECREF(self->name);
|
|
Py_XDECREF(self->subType);
|
|
PyObject_DEL(self);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// ObjectAttribute_Repr()
|
|
// Return a string representation of the object attribute.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *ObjectAttribute_Repr(
|
|
udt_ObjectAttribute *self) // attribute to return the string for
|
|
{
|
|
PyObject *module, *name, *result;
|
|
|
|
if (GetModuleAndName(self->ob_type, &module, &name) < 0)
|
|
return NULL;
|
|
result = PyString_FromFormat("<%s.%s %s>",
|
|
PyString_AS_STRING(module), PyString_AS_STRING(name),
|
|
PyString_AS_STRING(self->name));
|
|
Py_DECREF(module);
|
|
Py_DECREF(name);
|
|
return result;
|
|
}
|
|
|