Added support for initializing a collection upon creation; provided a synonym

for newobject() in simply calling the type directly (as a convenience).
This commit is contained in:
Anthony Tuininga 2016-02-24 14:16:40 -07:00
parent 9a7fb0065f
commit 92ec23930b
4 changed files with 125 additions and 41 deletions

View File

@ -167,6 +167,49 @@ PyObject *Object_New(
}
//-----------------------------------------------------------------------------
// Object_Create()
// Create a new object in the OCI.
//-----------------------------------------------------------------------------
static udt_Object *Object_Create(
udt_ObjectType *self) // type of object to create
{
dvoid *instance;
udt_Object *obj;
sword status;
// create the object instance
status = OCIObjectNew(self->connection->environment->handle,
self->connection->environment->errorHandle,
self->connection->handle, self->typeCode, self->tdo, NULL,
OCI_DURATION_SESSION, TRUE, &instance);
if (Environment_CheckForError(self->connection->environment, status,
"Object_Create(): create object instance") < 0)
return NULL;
// create the object
obj = (udt_Object*) Object_New(self, instance, NULL, 1);
if (!obj) {
OCIObjectFree(self->connection->environment->handle,
self->connection->environment->errorHandle, instance,
OCI_DEFAULT);
return NULL;
}
// get the null indicator structure
status = OCIObjectGetInd(self->connection->environment->handle,
self->connection->environment->errorHandle, instance,
&obj->indicator);
if (Environment_CheckForError(self->connection->environment, status,
"Object_Create(): get indicator structure") < 0) {
Py_DECREF(obj);
return NULL;
}
return obj;
}
//-----------------------------------------------------------------------------
// Object_Free()
// Free an object.
@ -578,6 +621,36 @@ static int Object_InternalAppend(
}
//-----------------------------------------------------------------------------
// Object_InternalExtend()
// Extend the collection by appending each of the items in the sequence.
//-----------------------------------------------------------------------------
static int Object_InternalExtend(
udt_Object *self, // object
PyObject *sequence) // sequence to extend collection with
{
PyObject *fastSequence, *element;
Py_ssize_t size, i;
// make sure we are dealing with a collection
if (Object_CheckIsCollection(self) < 0)
return -1;
// append each of the items in the sequence to the collection
fastSequence = PySequence_Fast(sequence, "expecting sequence");
if (!fastSequence)
return -1;
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 -1;
}
return 0;
}
//-----------------------------------------------------------------------------
// Object_Append()
// Append an item to the collection.
@ -651,7 +724,7 @@ static PyObject *Object_Copy(
udt_Object *copiedObject;
sword status;
copiedObject = (udt_Object*) ObjectType_NewObject(self->objectType, args);
copiedObject = Object_Create(self->objectType);
if (!copiedObject)
return NULL;
environment = self->objectType->connection->environment;
@ -730,28 +803,12 @@ static PyObject *Object_Extend(
udt_Object *self, // object
PyObject *args) // arguments
{
PyObject *sequence, *fastSequence, *element;
Py_ssize_t size, i;
PyObject *sequence;
// 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)
if (Object_InternalExtend(self, sequence) < 0)
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;
}

View File

@ -34,7 +34,7 @@ typedef struct {
static udt_ObjectType *ObjectType_New(udt_Connection*, OCIParam*, ub4);
static void ObjectType_Free(udt_ObjectType*);
static PyObject *ObjectType_Repr(udt_ObjectType*);
static PyObject *ObjectType_NewObject(udt_ObjectType*, PyObject*);
static PyObject *ObjectType_NewObject(udt_ObjectType*, PyObject*, PyObject*);
static udt_ObjectAttribute *ObjectAttribute_New(udt_Connection*, OCIParam*);
static void ObjectAttribute_Free(udt_ObjectAttribute*);
static PyObject *ObjectAttribute_Repr(udt_ObjectAttribute*);
@ -45,7 +45,8 @@ static PyObject *ObjectAttribute_Repr(udt_ObjectAttribute*);
// declaration of methods for Python type "ObjectType"
//-----------------------------------------------------------------------------
static PyMethodDef g_ObjectTypeMethods[] = {
{ "newobject", (PyCFunction) ObjectType_NewObject, METH_NOARGS },
{ "newobject", (PyCFunction) ObjectType_NewObject,
METH_VARARGS | METH_KEYWORDS },
{ NULL, NULL }
};
@ -92,7 +93,7 @@ static PyTypeObject g_ObjectTypeType = {
0, // tp_as_sequence
0, // tp_as_mapping
0, // tp_hash
0, // tp_call
(ternaryfunc) ObjectType_NewObject, // tp_call
0, // tp_str
0, // tp_getattro
0, // tp_setattro
@ -529,32 +530,36 @@ static PyObject *ObjectType_Repr(
//-----------------------------------------------------------------------------
static PyObject *ObjectType_NewObject(
udt_ObjectType *self, // object type to return the string for
PyObject *args) // arguments (none, ignored)
PyObject *args, // arguments
PyObject *keywordArgs) // keyword arguments
{
dvoid *instance, *indicator;
sword status;
static char *keywordList[] = { "value", NULL };
PyObject *initialValue;
udt_Object *obj;
// create the object instance
status = OCIObjectNew(self->connection->environment->handle,
self->connection->environment->errorHandle,
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)
// parse arguments
initialValue = NULL;
if (!PyArg_ParseTupleAndKeywords(args, keywordArgs, "|O", keywordList,
&initialValue))
return NULL;
// get the null indicator structure
status = OCIObjectGetInd(self->connection->environment->handle,
self->connection->environment->errorHandle, instance, &indicator);
if (Environment_CheckForError(self->connection->environment, status,
"ObjectType_NewObject(): get indicator structure") < 0)
// create the object
obj = Object_Create(self);
if (!obj)
return NULL;
return Object_New(self, instance, indicator, 1);
// populate collection, if applicable
if (initialValue) {
if (Object_InternalExtend(obj, initialValue) < 0) {
Py_DECREF(obj);
return NULL;
}
}
return (PyObject*) obj;
}
static PyObject *ObjectType_NewObject(udt_ObjectType*, PyObject*);
//-----------------------------------------------------------------------------
// ObjectAttribute_Initialize()
// Initialize the new object attribute.

View File

@ -11,6 +11,12 @@ Object Type Objects
:data:`~Variable.type` for variables containing Oracle objects.
.. method:: ObjectType([sequence])
The object type may be called directly and serves as an alternative way of
calling newobject().
.. attribute:: ObjectType.attributes
This read-only attribute returns a list of the attributes that make up the
@ -28,11 +34,13 @@ Object Type Objects
This read-only attribute returns the name of the type.
.. method:: ObjectType.newobject()
.. method:: ObjectType.newobject([sequence])
Return a new Oracle object of the given type. This object can then be
modified by setting its attributes and then bound to a cursor for
interaction with Oracle.
interaction with Oracle. If the object type refers to a collection, a
sequence may be passed and the collection will be initialized with the
items in that sequnce.
.. attribute:: ObjectType.schema

View File

@ -75,6 +75,20 @@ class TestObjectVar(BaseTestCase):
"udt_Object(null, 'Test With Dates', null, null, null, " \
"udt_SubObject(15, 'Sub String'), null)")
def testCopyObject(self):
"test copying an object"
typeObj = self.connection.gettype("UDT_OBJECT")
obj = typeObj()
obj.NUMBERVALUE = 5124
obj.STRINGVALUE = "A test string"
obj.DATEVALUE = datetime.datetime(2016, 2, 24)
obj.TIMESTAMPVALUE = datetime.datetime(2016, 2, 24, 13, 39, 10)
copiedObj = obj.copy()
self.assertEqual(obj.NUMBERVALUE, copiedObj.NUMBERVALUE)
self.assertEqual(obj.STRINGVALUE, copiedObj.STRINGVALUE)
self.assertEqual(obj.DATEVALUE, copiedObj.DATEVALUE)
self.assertEqual(obj.TIMESTAMPVALUE, copiedObj.TIMESTAMPVALUE)
def testFetchData(self):
"test fetching objects"
self.cursor.execute("""