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() // Object_Free()
// Free an object. // 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() // Object_Append()
// Append an item to the collection. // Append an item to the collection.
@ -651,7 +724,7 @@ static PyObject *Object_Copy(
udt_Object *copiedObject; udt_Object *copiedObject;
sword status; sword status;
copiedObject = (udt_Object*) ObjectType_NewObject(self->objectType, args); copiedObject = Object_Create(self->objectType);
if (!copiedObject) if (!copiedObject)
return NULL; return NULL;
environment = self->objectType->connection->environment; environment = self->objectType->connection->environment;
@ -730,28 +803,12 @@ static PyObject *Object_Extend(
udt_Object *self, // object udt_Object *self, // object
PyObject *args) // arguments PyObject *args) // arguments
{ {
PyObject *sequence, *fastSequence, *element; PyObject *sequence;
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)) if (!PyArg_ParseTuple(args, "O", &sequence))
return NULL; return NULL;
fastSequence = PySequence_Fast(sequence, "expecting sequence"); if (Object_InternalExtend(self, sequence) < 0)
if (!fastSequence)
return NULL; 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; Py_RETURN_NONE;
} }

View File

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

View File

@ -11,6 +11,12 @@ Object Type Objects
:data:`~Variable.type` for variables containing Oracle 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 .. attribute:: ObjectType.attributes
This read-only attribute returns a list of the attributes that make up the 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. 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 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 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 .. attribute:: ObjectType.schema

View File

@ -75,6 +75,20 @@ class TestObjectVar(BaseTestCase):
"udt_Object(null, 'Test With Dates', null, null, null, " \ "udt_Object(null, 'Test With Dates', null, null, null, " \
"udt_SubObject(15, 'Sub String'), 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): def testFetchData(self):
"test fetching objects" "test fetching objects"
self.cursor.execute(""" self.cursor.execute("""