Added preliminary support for binding collections (both SQL typed and PL/SQL
typed in Oracle 12.1).
This commit is contained in:
parent
39805c66d7
commit
e9d5a70e25
352
Object.c
352
Object.c
@ -16,17 +16,35 @@ typedef struct {
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Declaration of external object variable functions.
|
||||
// functions for the Python type "Object"
|
||||
//-----------------------------------------------------------------------------
|
||||
static void Object_Free(udt_Object*);
|
||||
static PyObject *Object_GetAttr(udt_Object*, PyObject*);
|
||||
static int Object_SetAttr(udt_Object*, PyObject*, PyObject*);
|
||||
static PyObject *Object_ConvertToPython(udt_Environment*, OCITypeCode, dvoid*,
|
||||
dvoid*, udt_ObjectType*);
|
||||
static PyObject *Object_Append(udt_Object*, PyObject*);
|
||||
static PyObject *Object_AsList(udt_Object*, PyObject*);
|
||||
static PyObject *Object_Copy(udt_Object*, PyObject*);
|
||||
static PyObject *Object_Extend(udt_Object*, PyObject*);
|
||||
static PyObject *Object_GetSize(udt_Object*, PyObject*);
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Declaration of external object variable members.
|
||||
// declaration of methods for Python type "Object"
|
||||
//-----------------------------------------------------------------------------
|
||||
static PyMethodDef g_ObjectMethods[] = {
|
||||
{ "append", (PyCFunction) Object_Append, METH_VARARGS },
|
||||
{ "aslist", (PyCFunction) Object_AsList, METH_NOARGS },
|
||||
{ "copy", (PyCFunction) Object_Copy, METH_NOARGS },
|
||||
{ "extend", (PyCFunction) Object_Extend, METH_VARARGS },
|
||||
{ "size", (PyCFunction) Object_GetSize, METH_NOARGS },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Declaration of members for Python type "Object".
|
||||
//-----------------------------------------------------------------------------
|
||||
static PyMemberDef g_ObjectMembers[] = {
|
||||
{ "type", T_OBJECT, offsetof(udt_Object, objectType), READONLY },
|
||||
@ -65,7 +83,7 @@ static PyTypeObject g_ObjectType = {
|
||||
0, // tp_weaklistoffset
|
||||
0, // tp_iter
|
||||
0, // tp_iternext
|
||||
0, // tp_methods
|
||||
g_ObjectMethods, // tp_methods
|
||||
g_ObjectMembers // tp_members
|
||||
};
|
||||
|
||||
@ -145,82 +163,6 @@ static void Object_Free(
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Object_ConvertCollectionElements()
|
||||
// Convert the collection elements to Python values.
|
||||
//-----------------------------------------------------------------------------
|
||||
static int Object_ConvertCollectionElements(
|
||||
udt_Environment *environment, // environment to use
|
||||
OCIIter *iter, // iterator
|
||||
PyObject *list, // list result
|
||||
udt_ObjectType *objectType) // collection type information
|
||||
{
|
||||
dvoid *elementValue, *elementIndicator;
|
||||
PyObject *elementObject;
|
||||
boolean endOfCollection;
|
||||
sword status;
|
||||
|
||||
while (list) {
|
||||
status = OCIIterNext(environment->handle, environment->errorHandle,
|
||||
iter, &elementValue, &elementIndicator, &endOfCollection);
|
||||
if (Environment_CheckForError(environment, status,
|
||||
"Object_ConvertCollection(): get next") < 0)
|
||||
return -1;
|
||||
if (endOfCollection)
|
||||
break;
|
||||
elementObject = Object_ConvertToPython(environment,
|
||||
objectType->elementTypeCode, elementValue, elementIndicator,
|
||||
(udt_ObjectType*) objectType->elementType);
|
||||
if (!elementObject)
|
||||
return -1;
|
||||
if (PyList_Append(list, elementObject) < 0) {
|
||||
Py_DECREF(elementObject);
|
||||
return -1;
|
||||
}
|
||||
Py_DECREF(elementObject);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Object_ConvertCollection()
|
||||
// Convert a collection to a Python list.
|
||||
//-----------------------------------------------------------------------------
|
||||
static PyObject *Object_ConvertCollection(
|
||||
udt_Environment *environment, // environment to use
|
||||
OCIColl *collectionValue, // collection value
|
||||
udt_ObjectType *objectType) // collection type information
|
||||
{
|
||||
PyObject *list;
|
||||
OCIIter *iter;
|
||||
sword status;
|
||||
int result;
|
||||
|
||||
// create the iterator
|
||||
status = OCIIterCreate(environment->handle, environment->errorHandle,
|
||||
collectionValue, &iter);
|
||||
if (Environment_CheckForError(environment, status,
|
||||
"Object_ConvertCollection(): creating iterator") < 0)
|
||||
return NULL;
|
||||
|
||||
// create the result list
|
||||
list = PyList_New(0);
|
||||
if (list) {
|
||||
result = Object_ConvertCollectionElements(environment, iter,
|
||||
list, objectType);
|
||||
if (result < 0) {
|
||||
Py_DECREF(list);
|
||||
list = NULL;
|
||||
}
|
||||
}
|
||||
OCIIterDelete(environment->handle, environment->errorHandle, &iter);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Object_ConvertFromPython()
|
||||
// Convert a Python value to an Oracle value.
|
||||
@ -358,8 +300,7 @@ static PyObject *Object_ConvertToPython(
|
||||
case OCI_TYPECODE_OBJECT:
|
||||
return Object_New(subType, value, indicator, 0);
|
||||
case OCI_TYPECODE_NAMEDCOLLECTION:
|
||||
return Object_ConvertCollection(environment,
|
||||
* (OCIColl**) value, subType);
|
||||
return Object_New(subType, * (OCIColl**) value, indicator, 0);
|
||||
};
|
||||
|
||||
return PyErr_Format(g_NotSupportedErrorException,
|
||||
@ -495,3 +436,252 @@ static int Object_SetAttr(
|
||||
return PyObject_GenericSetAttr( (PyObject*) self, nameObject, value);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Object_CheckIsCollection()
|
||||
// Check if the object is a collection, and if not, raise an exception. This
|
||||
// is used by the collection methods below.
|
||||
//-----------------------------------------------------------------------------
|
||||
static int Object_CheckIsCollection(
|
||||
udt_Object *self) // object
|
||||
{
|
||||
if (!self->objectType->isCollection) {
|
||||
PyErr_SetString(PyExc_TypeError, "object is not a collection");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Object_PopulateList()
|
||||
// Convert the collection elements to Python values.
|
||||
//-----------------------------------------------------------------------------
|
||||
static int Object_PopulateList(
|
||||
udt_Object *self, // collection iterating
|
||||
OCIIter *iter, // iterator
|
||||
PyObject *list) // list result
|
||||
{
|
||||
dvoid *elementValue, *elementIndicator;
|
||||
udt_Environment *environment;
|
||||
PyObject *elementObject;
|
||||
boolean endOfCollection;
|
||||
sword status;
|
||||
|
||||
environment = self->objectType->connection->environment;
|
||||
while (list) {
|
||||
status = OCIIterNext(environment->handle, environment->errorHandle,
|
||||
iter, &elementValue, &elementIndicator, &endOfCollection);
|
||||
if (Environment_CheckForError(environment, status,
|
||||
"Object_PopulateList(): get next") < 0)
|
||||
return -1;
|
||||
if (endOfCollection)
|
||||
break;
|
||||
elementObject = Object_ConvertToPython(environment,
|
||||
self->objectType->elementTypeCode, elementValue,
|
||||
elementIndicator,
|
||||
(udt_ObjectType*) self->objectType->elementType);
|
||||
if (!elementObject)
|
||||
return -1;
|
||||
if (PyList_Append(list, elementObject) < 0) {
|
||||
Py_DECREF(elementObject);
|
||||
return -1;
|
||||
}
|
||||
Py_DECREF(elementObject);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Object_InternalAppend()
|
||||
// Append an item to the collection.
|
||||
//-----------------------------------------------------------------------------
|
||||
static int Object_InternalAppend(
|
||||
udt_Object *self, // object
|
||||
PyObject *value) // value to append
|
||||
{
|
||||
void *elementValue, *elementIndicator;
|
||||
udt_AttributeData attributeData;
|
||||
udt_Environment *environment;
|
||||
OCIInd tempIndicator;
|
||||
sword status;
|
||||
|
||||
// convert Python value to OCI value
|
||||
elementValue = elementIndicator = NULL;
|
||||
environment = self->objectType->connection->environment;
|
||||
if (Object_ConvertFromPython(environment, value,
|
||||
self->objectType->elementTypeCode, &attributeData, &elementValue,
|
||||
&tempIndicator, &elementIndicator,
|
||||
(udt_ObjectType*) self->objectType->elementType) < 0) {
|
||||
AttributeData_Free(environment, &attributeData,
|
||||
self->objectType->elementTypeCode);
|
||||
return -1;
|
||||
}
|
||||
if (!elementIndicator)
|
||||
elementIndicator = &tempIndicator;
|
||||
|
||||
// append converted value to collection
|
||||
status = OCICollAppend(environment->handle, environment->errorHandle,
|
||||
elementValue, elementIndicator, (OCIColl*) self->instance);
|
||||
if (Environment_CheckForError(environment, status,
|
||||
"Object_Append()") < 0) {
|
||||
AttributeData_Free(environment, &attributeData,
|
||||
self->objectType->elementTypeCode);
|
||||
return -1;
|
||||
}
|
||||
AttributeData_Free(environment, &attributeData,
|
||||
self->objectType->elementTypeCode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Object_Append()
|
||||
// Append an item to the collection.
|
||||
//-----------------------------------------------------------------------------
|
||||
static PyObject *Object_Append(
|
||||
udt_Object *self, // object
|
||||
PyObject *args) // arguments
|
||||
{
|
||||
PyObject *value;
|
||||
|
||||
if (Object_CheckIsCollection(self) < 0)
|
||||
return NULL;
|
||||
if (!PyArg_ParseTuple(args, "O", &value))
|
||||
return NULL;
|
||||
if (Object_InternalAppend(self, value) < 0)
|
||||
return NULL;
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Object_AsList()
|
||||
// Returns a collection as a list of elements. If the object is not a
|
||||
// collection, an error is returned.
|
||||
//-----------------------------------------------------------------------------
|
||||
static PyObject *Object_AsList(
|
||||
udt_Object *self, // object
|
||||
PyObject *args) // arguments (none)
|
||||
{
|
||||
udt_Environment *environment;
|
||||
PyObject *list;
|
||||
OCIIter *iter;
|
||||
sword status;
|
||||
|
||||
// make sure this is a collection
|
||||
if (Object_CheckIsCollection(self) < 0)
|
||||
return NULL;
|
||||
|
||||
// create the iterator
|
||||
environment = self->objectType->connection->environment;
|
||||
status = OCIIterCreate(environment->handle, environment->errorHandle,
|
||||
self->instance, &iter);
|
||||
if (Environment_CheckForError(environment, status,
|
||||
"Object_AsList(): creating iterator") < 0)
|
||||
return NULL;
|
||||
|
||||
// create the result list
|
||||
list = PyList_New(0);
|
||||
if (list) {
|
||||
if (Object_PopulateList(self, iter, list) < 0) {
|
||||
Py_DECREF(list);
|
||||
list = NULL;
|
||||
}
|
||||
}
|
||||
OCIIterDelete(environment->handle, environment->errorHandle, &iter);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Object_Copy()
|
||||
// Return a copy of the object.
|
||||
//-----------------------------------------------------------------------------
|
||||
static PyObject *Object_Copy(
|
||||
udt_Object *self, // object
|
||||
PyObject *args) // arguments (none)
|
||||
{
|
||||
udt_Environment *environment;
|
||||
udt_Object *copiedObject;
|
||||
sword status;
|
||||
|
||||
copiedObject = (udt_Object*) ObjectType_NewObject(self->objectType, args);
|
||||
if (!copiedObject)
|
||||
return NULL;
|
||||
environment = self->objectType->connection->environment;
|
||||
status = OCIObjectCopy(environment->handle, environment->errorHandle,
|
||||
self->objectType->connection->handle, self->instance,
|
||||
self->indicator, copiedObject->instance, copiedObject->indicator,
|
||||
self->objectType->tdo, OCI_DURATION_SESSION, OCI_DEFAULT);
|
||||
if (Environment_CheckForError(environment, status, "Object_Copy()") < 0) {
|
||||
Py_DECREF(copiedObject);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (PyObject*) copiedObject;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Object_Extend()
|
||||
// Extend the collection by appending each of the items in the sequence.
|
||||
//-----------------------------------------------------------------------------
|
||||
static PyObject *Object_Extend(
|
||||
udt_Object *self, // object
|
||||
PyObject *args) // arguments
|
||||
{
|
||||
PyObject *sequence, *fastSequence, *element;
|
||||
Py_ssize_t size, i;
|
||||
|
||||
// make sure we are dealing with a collection
|
||||
if (Object_CheckIsCollection(self) < 0)
|
||||
return NULL;
|
||||
|
||||
// parse arguments
|
||||
if (!PyArg_ParseTuple(args, "O", &sequence))
|
||||
return NULL;
|
||||
fastSequence = PySequence_Fast(sequence, "expecting sequence");
|
||||
if (!fastSequence)
|
||||
return NULL;
|
||||
|
||||
// append each of the items in the sequence to the collection
|
||||
size = PySequence_Fast_GET_SIZE(fastSequence);
|
||||
for (i = 0; i < size; i++) {
|
||||
element = PySequence_Fast_GET_ITEM(fastSequence, i);
|
||||
if (Object_InternalAppend(self, element) < 0)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Object_GetSize()
|
||||
// Return the size of a collection. If the object is not a collection, an
|
||||
// error is returned.
|
||||
//-----------------------------------------------------------------------------
|
||||
static PyObject *Object_GetSize(
|
||||
udt_Object *self, // object
|
||||
PyObject *args) // arguments (none)
|
||||
{
|
||||
udt_Environment *environment;
|
||||
sword status;
|
||||
sb4 size;
|
||||
|
||||
if (Object_CheckIsCollection(self) < 0)
|
||||
return NULL;
|
||||
environment = self->objectType->connection->environment;
|
||||
status = OCICollSize(environment->handle, environment->errorHandle,
|
||||
(const OCIColl*) self->instance, &size);
|
||||
if (Environment_CheckForError(environment, status, "Object_Size()") < 0)
|
||||
return NULL;
|
||||
return PyInt_FromLong(size);
|
||||
}
|
||||
|
||||
|
||||
41
ObjectType.c
41
ObjectType.c
@ -14,10 +14,11 @@ typedef struct {
|
||||
PyObject *name;
|
||||
PyObject *attributes;
|
||||
PyObject *attributesByName;
|
||||
OCITypeCode typeCode;
|
||||
OCITypeCode collectionTypeCode;
|
||||
OCITypeCode elementTypeCode;
|
||||
PyObject *elementType;
|
||||
int isCollection;
|
||||
boolean isCollection;
|
||||
} udt_ObjectType;
|
||||
|
||||
typedef struct {
|
||||
@ -27,8 +28,6 @@ typedef struct {
|
||||
udt_ObjectType *subType;
|
||||
} udt_ObjectAttribute;
|
||||
|
||||
#include "Object.c"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Declaration of type variable functions.
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -40,6 +39,7 @@ static udt_ObjectAttribute *ObjectAttribute_New(udt_Connection*, OCIParam*);
|
||||
static void ObjectAttribute_Free(udt_ObjectAttribute*);
|
||||
static PyObject *ObjectAttribute_Repr(udt_ObjectAttribute*);
|
||||
|
||||
#include "Object.c"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// declaration of methods for Python type "ObjectType"
|
||||
@ -57,6 +57,10 @@ 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 },
|
||||
{ "elementType", T_OBJECT, offsetof(udt_ObjectType, elementType),
|
||||
READONLY },
|
||||
{ "iscollection", T_BOOL, offsetof(udt_ObjectType, isCollection),
|
||||
READONLY },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
@ -174,7 +178,6 @@ static int ObjectType_Describe(
|
||||
OCIParam *topLevelParam, *attributeListParam, *attributeParam;
|
||||
udt_ObjectAttribute *attribute;
|
||||
OCIParam *collectionParam;
|
||||
OCITypeCode typeCode;
|
||||
ub2 numAttributes;
|
||||
sword status;
|
||||
int i;
|
||||
@ -195,14 +198,14 @@ static int ObjectType_Describe(
|
||||
return -1;
|
||||
|
||||
// determine type of type
|
||||
status = OCIAttrGet(topLevelParam, OCI_DTYPE_PARAM, &typeCode, 0,
|
||||
status = OCIAttrGet(topLevelParam, OCI_DTYPE_PARAM, &self->typeCode, 0,
|
||||
OCI_ATTR_TYPECODE, self->connection->environment->errorHandle);
|
||||
if (Environment_CheckForError(self->connection->environment, status,
|
||||
"ObjectType_Describe(): get type code") < 0)
|
||||
return -1;
|
||||
|
||||
// if a collection, need to determine the sub type
|
||||
if (typeCode == OCI_TYPECODE_NAMEDCOLLECTION) {
|
||||
if (self->typeCode == OCI_TYPECODE_NAMEDCOLLECTION) {
|
||||
self->isCollection = 1;
|
||||
|
||||
// determine type of collection
|
||||
@ -394,6 +397,9 @@ static udt_ObjectType *ObjectType_NewByName(
|
||||
udt_ObjectType *result;
|
||||
udt_Buffer buffer;
|
||||
OCIParam *param;
|
||||
#if ORACLE_VERSION_HEX >= ORACLE_VERSION(12, 1)
|
||||
OCIType *tdo;
|
||||
#endif
|
||||
sword status;
|
||||
|
||||
// allocate describe handle
|
||||
@ -409,6 +415,26 @@ static udt_ObjectType *ObjectType_NewByName(
|
||||
OCIHandleFree(describeHandle, OCI_HTYPE_DESCRIBE);
|
||||
return NULL;
|
||||
}
|
||||
#if ORACLE_VERSION_HEX >= ORACLE_VERSION(12, 1)
|
||||
status = OCITypeByFullName(connection->environment->handle,
|
||||
connection->environment->errorHandle, connection->handle,
|
||||
buffer.ptr, buffer.size, NULL, 0, OCI_DURATION_SESSION,
|
||||
OCI_TYPEGET_ALL, &tdo);
|
||||
cxBuffer_Clear(&buffer);
|
||||
if (Environment_CheckForError(connection->environment, status,
|
||||
"ObjectType_NewByName(): get type by full name") < 0) {
|
||||
OCIHandleFree(describeHandle, OCI_HTYPE_DESCRIBE);
|
||||
return NULL;
|
||||
}
|
||||
status = OCIDescribeAny(connection->handle,
|
||||
connection->environment->errorHandle, (dvoid*) tdo, 0,
|
||||
OCI_OTYPE_PTR, 0, OCI_PTYPE_TYPE, describeHandle);
|
||||
if (Environment_CheckForError(connection->environment, status,
|
||||
"ObjectType_NewByName(): describe type") < 0) {
|
||||
OCIHandleFree(describeHandle, OCI_HTYPE_DESCRIBE);
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
status = OCIDescribeAny(connection->handle,
|
||||
connection->environment->errorHandle, (dvoid*) buffer.ptr,
|
||||
buffer.size, OCI_OTYPE_NAME, 0, OCI_PTYPE_TYPE, describeHandle);
|
||||
@ -418,6 +444,7 @@ static udt_ObjectType *ObjectType_NewByName(
|
||||
OCIHandleFree(describeHandle, OCI_HTYPE_DESCRIBE);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
// get the parameter handle
|
||||
status = OCIAttrGet(describeHandle, OCI_HTYPE_DESCRIBE, ¶m, 0,
|
||||
@ -510,7 +537,7 @@ static PyObject *ObjectType_NewObject(
|
||||
// create the object instance
|
||||
status = OCIObjectNew(self->connection->environment->handle,
|
||||
self->connection->environment->errorHandle,
|
||||
self->connection->handle, OCI_TYPECODE_OBJECT, self->tdo, NULL,
|
||||
self->connection->handle, self->typeCode, self->tdo, NULL,
|
||||
OCI_DURATION_SESSION, TRUE, &instance);
|
||||
if (Environment_CheckForError(self->connection->environment, status,
|
||||
"ObjectType_NewObject(): create object instance") < 0)
|
||||
|
||||
@ -303,10 +303,7 @@ static PyObject *ObjectVar_GetValue(
|
||||
// create the object, if needed; for collections, return a list, not the
|
||||
// object itself
|
||||
if (!self->objects[pos]) {
|
||||
if (self->objectType->isCollection)
|
||||
obj = Object_ConvertCollection(self->environment, self->data[pos],
|
||||
self->objectType);
|
||||
else obj = Object_New(self->objectType, self->data[pos],
|
||||
obj = Object_New(self->objectType, self->data[pos],
|
||||
self->objectIndicator[pos], 1);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
|
||||
@ -10,14 +10,15 @@ class TestObjectVar(BaseTestCase):
|
||||
for attribute in obj.type.attributes:
|
||||
value = getattr(obj, attribute.name)
|
||||
if isinstance(value, cx_Oracle.Object):
|
||||
value = self.__GetObjectAsTuple(value)
|
||||
elif isinstance(value, list):
|
||||
subValue = []
|
||||
for v in value:
|
||||
if isinstance(v, cx_Oracle.Object):
|
||||
v = self.__GetObjectAsTuple(v)
|
||||
subValue.append(v)
|
||||
value = subValue
|
||||
if not value.type.iscollection:
|
||||
value = self.__GetObjectAsTuple(value)
|
||||
else:
|
||||
subValue = []
|
||||
for v in value.aslist():
|
||||
if isinstance(v, cx_Oracle.Object):
|
||||
v = self.__GetObjectAsTuple(v)
|
||||
subValue.append(v)
|
||||
value = subValue
|
||||
attributeValues.append(value)
|
||||
return tuple(attributeValues)
|
||||
|
||||
@ -26,6 +27,8 @@ class TestObjectVar(BaseTestCase):
|
||||
intValue, objectValue, arrayValue = self.cursor.fetchone()
|
||||
if objectValue is not None:
|
||||
objectValue = self.__GetObjectAsTuple(objectValue)
|
||||
if arrayValue is not None:
|
||||
arrayValue = arrayValue.aslist()
|
||||
self.assertEqual(intValue, expectedIntValue)
|
||||
self.assertEqual(objectValue, expectedObjectValue)
|
||||
self.assertEqual(arrayValue, expectedArrayValue)
|
||||
@ -102,13 +105,17 @@ class TestObjectVar(BaseTestCase):
|
||||
def testGetObjectType(self):
|
||||
"test getting object type"
|
||||
typeObj = self.connection.gettype("UDT_OBJECT")
|
||||
self.assertEqual(typeObj.schema, "CX_ORACLE")
|
||||
self.assertEqual(typeObj.iscollection, False)
|
||||
self.assertEqual(typeObj.schema, self.connection.username.upper())
|
||||
self.assertEqual(typeObj.name, "UDT_OBJECT")
|
||||
expectedAttributeNames = ["NUMBERVALUE", "STRINGVALUE",
|
||||
"FIXEDCHARVALUE", "DATEVALUE", "TIMESTAMPVALUE",
|
||||
"SUBOBJECTVALUE", "SUBOBJECTARRAY"]
|
||||
actualAttributeNames = [a.name for a in typeObj.attributes]
|
||||
self.assertEqual(actualAttributeNames, expectedAttributeNames)
|
||||
typeObj = self.connection.gettype("UDT_OBJECTARRAY")
|
||||
self.assertEqual(typeObj.iscollection, True)
|
||||
self.assertEqual(typeObj.attributes, [])
|
||||
|
||||
def testObjectType(self):
|
||||
"test object type data"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user