Skip to content

Commit 92ec239

Browse files
Added support for initializing a collection upon creation; provided a synonym
for newobject() in simply calling the type directly (as a convenience).
1 parent 9a7fb00 commit 92ec239

File tree

4 files changed

+126
-42
lines changed

4 files changed

+126
-42
lines changed

Object.c

Lines changed: 76 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,49 @@ PyObject *Object_New(
167167
}
168168

169169

170+
//-----------------------------------------------------------------------------
171+
// Object_Create()
172+
// Create a new object in the OCI.
173+
//-----------------------------------------------------------------------------
174+
static udt_Object *Object_Create(
175+
udt_ObjectType *self) // type of object to create
176+
{
177+
dvoid *instance;
178+
udt_Object *obj;
179+
sword status;
180+
181+
// create the object instance
182+
status = OCIObjectNew(self->connection->environment->handle,
183+
self->connection->environment->errorHandle,
184+
self->connection->handle, self->typeCode, self->tdo, NULL,
185+
OCI_DURATION_SESSION, TRUE, &instance);
186+
if (Environment_CheckForError(self->connection->environment, status,
187+
"Object_Create(): create object instance") < 0)
188+
return NULL;
189+
190+
// create the object
191+
obj = (udt_Object*) Object_New(self, instance, NULL, 1);
192+
if (!obj) {
193+
OCIObjectFree(self->connection->environment->handle,
194+
self->connection->environment->errorHandle, instance,
195+
OCI_DEFAULT);
196+
return NULL;
197+
}
198+
199+
// get the null indicator structure
200+
status = OCIObjectGetInd(self->connection->environment->handle,
201+
self->connection->environment->errorHandle, instance,
202+
&obj->indicator);
203+
if (Environment_CheckForError(self->connection->environment, status,
204+
"Object_Create(): get indicator structure") < 0) {
205+
Py_DECREF(obj);
206+
return NULL;
207+
}
208+
209+
return obj;
210+
}
211+
212+
170213
//-----------------------------------------------------------------------------
171214
// Object_Free()
172215
// Free an object.
@@ -578,6 +621,36 @@ static int Object_InternalAppend(
578621
}
579622

580623

624+
//-----------------------------------------------------------------------------
625+
// Object_InternalExtend()
626+
// Extend the collection by appending each of the items in the sequence.
627+
//-----------------------------------------------------------------------------
628+
static int Object_InternalExtend(
629+
udt_Object *self, // object
630+
PyObject *sequence) // sequence to extend collection with
631+
{
632+
PyObject *fastSequence, *element;
633+
Py_ssize_t size, i;
634+
635+
// make sure we are dealing with a collection
636+
if (Object_CheckIsCollection(self) < 0)
637+
return -1;
638+
639+
// append each of the items in the sequence to the collection
640+
fastSequence = PySequence_Fast(sequence, "expecting sequence");
641+
if (!fastSequence)
642+
return -1;
643+
size = PySequence_Fast_GET_SIZE(fastSequence);
644+
for (i = 0; i < size; i++) {
645+
element = PySequence_Fast_GET_ITEM(fastSequence, i);
646+
if (Object_InternalAppend(self, element) < 0)
647+
return -1;
648+
}
649+
650+
return 0;
651+
}
652+
653+
581654
//-----------------------------------------------------------------------------
582655
// Object_Append()
583656
// Append an item to the collection.
@@ -651,7 +724,7 @@ static PyObject *Object_Copy(
651724
udt_Object *copiedObject;
652725
sword status;
653726

654-
copiedObject = (udt_Object*) ObjectType_NewObject(self->objectType, args);
727+
copiedObject = Object_Create(self->objectType);
655728
if (!copiedObject)
656729
return NULL;
657730
environment = self->objectType->connection->environment;
@@ -730,28 +803,12 @@ static PyObject *Object_Extend(
730803
udt_Object *self, // object
731804
PyObject *args) // arguments
732805
{
733-
PyObject *sequence, *fastSequence, *element;
734-
Py_ssize_t size, i;
806+
PyObject *sequence;
735807

736-
// make sure we are dealing with a collection
737-
if (Object_CheckIsCollection(self) < 0)
738-
return NULL;
739-
740-
// parse arguments
741808
if (!PyArg_ParseTuple(args, "O", &sequence))
742809
return NULL;
743-
fastSequence = PySequence_Fast(sequence, "expecting sequence");
744-
if (!fastSequence)
810+
if (Object_InternalExtend(self, sequence) < 0)
745811
return NULL;
746-
747-
// append each of the items in the sequence to the collection
748-
size = PySequence_Fast_GET_SIZE(fastSequence);
749-
for (i = 0; i < size; i++) {
750-
element = PySequence_Fast_GET_ITEM(fastSequence, i);
751-
if (Object_InternalAppend(self, element) < 0)
752-
return NULL;
753-
}
754-
755812
Py_RETURN_NONE;
756813
}
757814

ObjectType.c

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ typedef struct {
3434
static udt_ObjectType *ObjectType_New(udt_Connection*, OCIParam*, ub4);
3535
static void ObjectType_Free(udt_ObjectType*);
3636
static PyObject *ObjectType_Repr(udt_ObjectType*);
37-
static PyObject *ObjectType_NewObject(udt_ObjectType*, PyObject*);
37+
static PyObject *ObjectType_NewObject(udt_ObjectType*, PyObject*, PyObject*);
3838
static udt_ObjectAttribute *ObjectAttribute_New(udt_Connection*, OCIParam*);
3939
static void ObjectAttribute_Free(udt_ObjectAttribute*);
4040
static PyObject *ObjectAttribute_Repr(udt_ObjectAttribute*);
@@ -45,7 +45,8 @@ static PyObject *ObjectAttribute_Repr(udt_ObjectAttribute*);
4545
// declaration of methods for Python type "ObjectType"
4646
//-----------------------------------------------------------------------------
4747
static PyMethodDef g_ObjectTypeMethods[] = {
48-
{ "newobject", (PyCFunction) ObjectType_NewObject, METH_NOARGS },
48+
{ "newobject", (PyCFunction) ObjectType_NewObject,
49+
METH_VARARGS | METH_KEYWORDS },
4950
{ NULL, NULL }
5051
};
5152

@@ -92,7 +93,7 @@ static PyTypeObject g_ObjectTypeType = {
9293
0, // tp_as_sequence
9394
0, // tp_as_mapping
9495
0, // tp_hash
95-
0, // tp_call
96+
(ternaryfunc) ObjectType_NewObject, // tp_call
9697
0, // tp_str
9798
0, // tp_getattro
9899
0, // tp_setattro
@@ -529,32 +530,36 @@ static PyObject *ObjectType_Repr(
529530
//-----------------------------------------------------------------------------
530531
static PyObject *ObjectType_NewObject(
531532
udt_ObjectType *self, // object type to return the string for
532-
PyObject *args) // arguments (none, ignored)
533+
PyObject *args, // arguments
534+
PyObject *keywordArgs) // keyword arguments
533535
{
534-
dvoid *instance, *indicator;
535-
sword status;
536-
537-
// create the object instance
538-
status = OCIObjectNew(self->connection->environment->handle,
539-
self->connection->environment->errorHandle,
540-
self->connection->handle, self->typeCode, self->tdo, NULL,
541-
OCI_DURATION_SESSION, TRUE, &instance);
542-
if (Environment_CheckForError(self->connection->environment, status,
543-
"ObjectType_NewObject(): create object instance") < 0)
536+
static char *keywordList[] = { "value", NULL };
537+
PyObject *initialValue;
538+
udt_Object *obj;
539+
540+
// parse arguments
541+
initialValue = NULL;
542+
if (!PyArg_ParseTupleAndKeywords(args, keywordArgs, "|O", keywordList,
543+
&initialValue))
544544
return NULL;
545545

546-
// get the null indicator structure
547-
status = OCIObjectGetInd(self->connection->environment->handle,
548-
self->connection->environment->errorHandle, instance, &indicator);
549-
if (Environment_CheckForError(self->connection->environment, status,
550-
"ObjectType_NewObject(): get indicator structure") < 0)
546+
// create the object
547+
obj = Object_Create(self);
548+
if (!obj)
551549
return NULL;
552550

553-
return Object_New(self, instance, indicator, 1);
551+
// populate collection, if applicable
552+
if (initialValue) {
553+
if (Object_InternalExtend(obj, initialValue) < 0) {
554+
Py_DECREF(obj);
555+
return NULL;
556+
}
557+
}
558+
559+
return (PyObject*) obj;
554560
}
555561

556562

557-
static PyObject *ObjectType_NewObject(udt_ObjectType*, PyObject*);
558563
//-----------------------------------------------------------------------------
559564
// ObjectAttribute_Initialize()
560565
// Initialize the new object attribute.

doc/objecttype.rst

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@ Object Type Objects
1111
:data:`~Variable.type` for variables containing Oracle objects.
1212

1313

14+
.. method:: ObjectType([sequence])
15+
16+
The object type may be called directly and serves as an alternative way of
17+
calling newobject().
18+
19+
1420
.. attribute:: ObjectType.attributes
1521

1622
This read-only attribute returns a list of the attributes that make up the
@@ -28,11 +34,13 @@ Object Type Objects
2834
This read-only attribute returns the name of the type.
2935

3036

31-
.. method:: ObjectType.newobject()
37+
.. method:: ObjectType.newobject([sequence])
3238

3339
Return a new Oracle object of the given type. This object can then be
3440
modified by setting its attributes and then bound to a cursor for
35-
interaction with Oracle.
41+
interaction with Oracle. If the object type refers to a collection, a
42+
sequence may be passed and the collection will be initialized with the
43+
items in that sequnce.
3644

3745

3846
.. attribute:: ObjectType.schema

test/ObjectVar.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,20 @@ def testBindObjectIn(self):
7575
"udt_Object(null, 'Test With Dates', null, null, null, " \
7676
"udt_SubObject(15, 'Sub String'), null)")
7777

78+
def testCopyObject(self):
79+
"test copying an object"
80+
typeObj = self.connection.gettype("UDT_OBJECT")
81+
obj = typeObj()
82+
obj.NUMBERVALUE = 5124
83+
obj.STRINGVALUE = "A test string"
84+
obj.DATEVALUE = datetime.datetime(2016, 2, 24)
85+
obj.TIMESTAMPVALUE = datetime.datetime(2016, 2, 24, 13, 39, 10)
86+
copiedObj = obj.copy()
87+
self.assertEqual(obj.NUMBERVALUE, copiedObj.NUMBERVALUE)
88+
self.assertEqual(obj.STRINGVALUE, copiedObj.STRINGVALUE)
89+
self.assertEqual(obj.DATEVALUE, copiedObj.DATEVALUE)
90+
self.assertEqual(obj.TIMESTAMPVALUE, copiedObj.TIMESTAMPVALUE)
91+
7892
def testFetchData(self):
7993
"test fetching objects"
8094
self.cursor.execute("""

0 commit comments

Comments
 (0)