Added support for manipluating PL/SQL collections (both ordered and unordered).
This commit is contained in:
parent
e9d5a70e25
commit
6f52f6ce39
293
Object.c
293
Object.c
@ -26,8 +26,17 @@ static PyObject *Object_ConvertToPython(udt_Environment*, OCITypeCode, dvoid*,
|
||||
static PyObject *Object_Append(udt_Object*, PyObject*);
|
||||
static PyObject *Object_AsList(udt_Object*, PyObject*);
|
||||
static PyObject *Object_Copy(udt_Object*, PyObject*);
|
||||
static PyObject *Object_Delete(udt_Object*, PyObject*);
|
||||
static PyObject *Object_Exists(udt_Object*, PyObject*);
|
||||
static PyObject *Object_Extend(udt_Object*, PyObject*);
|
||||
static PyObject *Object_GetElement(udt_Object*, PyObject*);
|
||||
static PyObject *Object_GetFirstIndex(udt_Object*, PyObject*);
|
||||
static PyObject *Object_GetLastIndex(udt_Object*, PyObject*);
|
||||
static PyObject *Object_GetNextIndex(udt_Object*, PyObject*);
|
||||
static PyObject *Object_GetPrevIndex(udt_Object*, PyObject*);
|
||||
static PyObject *Object_GetSize(udt_Object*, PyObject*);
|
||||
static PyObject *Object_SetElement(udt_Object*, PyObject*);
|
||||
static PyObject *Object_Trim(udt_Object*, PyObject*);
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -37,8 +46,17 @@ static PyMethodDef g_ObjectMethods[] = {
|
||||
{ "append", (PyCFunction) Object_Append, METH_VARARGS },
|
||||
{ "aslist", (PyCFunction) Object_AsList, METH_NOARGS },
|
||||
{ "copy", (PyCFunction) Object_Copy, METH_NOARGS },
|
||||
{ "delete", (PyCFunction) Object_Delete, METH_VARARGS },
|
||||
{ "exists", (PyCFunction) Object_Exists, METH_VARARGS },
|
||||
{ "extend", (PyCFunction) Object_Extend, METH_VARARGS },
|
||||
{ "first", (PyCFunction) Object_GetFirstIndex, METH_NOARGS },
|
||||
{ "getelement", (PyCFunction) Object_GetElement, METH_VARARGS },
|
||||
{ "last", (PyCFunction) Object_GetLastIndex, METH_NOARGS },
|
||||
{ "next", (PyCFunction) Object_GetNextIndex, METH_VARARGS },
|
||||
{ "prev", (PyCFunction) Object_GetPrevIndex, METH_VARARGS },
|
||||
{ "setelement", (PyCFunction) Object_SetElement, METH_VARARGS },
|
||||
{ "size", (PyCFunction) Object_GetSize, METH_NOARGS },
|
||||
{ "trim", (PyCFunction) Object_Trim, METH_VARARGS },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
@ -628,6 +646,60 @@ static PyObject *Object_Copy(
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Object_Delete()
|
||||
// Delete the element at the specified index in the collection.
|
||||
//-----------------------------------------------------------------------------
|
||||
static PyObject *Object_Delete(
|
||||
udt_Object *self, // object
|
||||
PyObject *args) // arguments
|
||||
{
|
||||
udt_Environment *environment;
|
||||
sword status;
|
||||
sb4 index;
|
||||
|
||||
if (Object_CheckIsCollection(self) < 0)
|
||||
return NULL;
|
||||
if (!PyArg_ParseTuple(args, "i", &index))
|
||||
return NULL;
|
||||
environment = self->objectType->connection->environment;
|
||||
status = OCITableDelete(environment->handle, environment->errorHandle,
|
||||
index, self->instance);
|
||||
if (Environment_CheckForError(environment, status, "Object_Delete()") < 0)
|
||||
return NULL;
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Object_Exists()
|
||||
// Return true or false indicating if an element exists in the collection at
|
||||
// the specified index.
|
||||
//-----------------------------------------------------------------------------
|
||||
static PyObject *Object_Exists(
|
||||
udt_Object *self, // object
|
||||
PyObject *args) // arguments
|
||||
{
|
||||
udt_Environment *environment;
|
||||
boolean exists;
|
||||
sword status;
|
||||
sb4 index;
|
||||
|
||||
if (Object_CheckIsCollection(self) < 0)
|
||||
return NULL;
|
||||
if (!PyArg_ParseTuple(args, "i", &index))
|
||||
return NULL;
|
||||
environment = self->objectType->connection->environment;
|
||||
status = OCITableExists(environment->handle, environment->errorHandle,
|
||||
self->instance, index, &exists);
|
||||
if (Environment_CheckForError(environment, status, "Object_Exists()") < 0)
|
||||
return NULL;
|
||||
if (exists)
|
||||
Py_RETURN_TRUE;
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Object_Extend()
|
||||
// Extend the collection by appending each of the items in the sequence.
|
||||
@ -662,6 +734,149 @@ static PyObject *Object_Extend(
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Object_GetElement()
|
||||
// Return the element at the given position in the collection.
|
||||
//-----------------------------------------------------------------------------
|
||||
static PyObject *Object_GetElement(
|
||||
udt_Object *self, // object
|
||||
PyObject *args) // arguments
|
||||
{
|
||||
void *elementValue, *elementIndicator;
|
||||
udt_Environment *environment;
|
||||
boolean exists;
|
||||
sb4 position;
|
||||
sword status;
|
||||
|
||||
if (Object_CheckIsCollection(self) < 0)
|
||||
return NULL;
|
||||
if (!PyArg_ParseTuple(args, "i", &position))
|
||||
return NULL;
|
||||
environment = self->objectType->connection->environment;
|
||||
status = OCICollGetElem(environment->handle, environment->errorHandle,
|
||||
(OCIColl*) self->instance, (sb4) position, &exists,
|
||||
&elementValue, &elementIndicator);
|
||||
if (Environment_CheckForError(environment, status,
|
||||
"Object_GetItem(): get element") < 0)
|
||||
return NULL;
|
||||
if (!exists) {
|
||||
PyErr_SetString(PyExc_IndexError, "element does not exist");
|
||||
return NULL;
|
||||
}
|
||||
return Object_ConvertToPython(environment,
|
||||
self->objectType->elementTypeCode, elementValue, elementIndicator,
|
||||
(udt_ObjectType*) self->objectType->elementType);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Object_GetFirstIndex()
|
||||
// Return the index of the first entry in the collection.
|
||||
//-----------------------------------------------------------------------------
|
||||
static PyObject *Object_GetFirstIndex(
|
||||
udt_Object *self, // object
|
||||
PyObject *args) // arguments (none)
|
||||
{
|
||||
udt_Environment *environment;
|
||||
sword status;
|
||||
sb4 index;
|
||||
|
||||
if (Object_CheckIsCollection(self) < 0)
|
||||
return NULL;
|
||||
environment = self->objectType->connection->environment;
|
||||
status = OCITableFirst(environment->handle, environment->errorHandle,
|
||||
self->instance, &index);
|
||||
if (Environment_CheckForError(environment, status,
|
||||
"Object_GetFirstIndex()") < 0)
|
||||
return NULL;
|
||||
return PyInt_FromLong(index);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Object_GetLastIndex()
|
||||
// Return the index of the last entry in the collection.
|
||||
//-----------------------------------------------------------------------------
|
||||
static PyObject *Object_GetLastIndex(
|
||||
udt_Object *self, // object
|
||||
PyObject *args) // arguments (none)
|
||||
{
|
||||
udt_Environment *environment;
|
||||
sword status;
|
||||
sb4 index;
|
||||
|
||||
if (Object_CheckIsCollection(self) < 0)
|
||||
return NULL;
|
||||
environment = self->objectType->connection->environment;
|
||||
status = OCITableLast(environment->handle, environment->errorHandle,
|
||||
self->instance, &index);
|
||||
if (Environment_CheckForError(environment, status,
|
||||
"Object_GetLastIndex()") < 0)
|
||||
return NULL;
|
||||
return PyInt_FromLong(index);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Object_GetNextIndex()
|
||||
// Return the index of the next entry in the collection following the index
|
||||
// specified. If there is no next entry, None is returned.
|
||||
//-----------------------------------------------------------------------------
|
||||
static PyObject *Object_GetNextIndex(
|
||||
udt_Object *self, // object
|
||||
PyObject *args) // arguments
|
||||
{
|
||||
udt_Environment *environment;
|
||||
sb4 index, nextIndex;
|
||||
boolean exists;
|
||||
sword status;
|
||||
|
||||
if (Object_CheckIsCollection(self) < 0)
|
||||
return NULL;
|
||||
if (!PyArg_ParseTuple(args, "i", &index))
|
||||
return NULL;
|
||||
environment = self->objectType->connection->environment;
|
||||
status = OCITableNext(environment->handle, environment->errorHandle,
|
||||
index, self->instance, &nextIndex, &exists);
|
||||
if (Environment_CheckForError(environment, status,
|
||||
"Object_GetNextIndex()") < 0)
|
||||
return NULL;
|
||||
if (exists)
|
||||
return PyInt_FromLong(nextIndex);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Object_GetPrevIndex()
|
||||
// Return the index of the previous entry in the collection preceding the
|
||||
// index specified. If there is no previous entry, None is returned.
|
||||
//-----------------------------------------------------------------------------
|
||||
static PyObject *Object_GetPrevIndex(
|
||||
udt_Object *self, // object
|
||||
PyObject *args) // arguments
|
||||
{
|
||||
udt_Environment *environment;
|
||||
sb4 index, prevIndex;
|
||||
boolean exists;
|
||||
sword status;
|
||||
|
||||
if (Object_CheckIsCollection(self) < 0)
|
||||
return NULL;
|
||||
if (!PyArg_ParseTuple(args, "i", &index))
|
||||
return NULL;
|
||||
environment = self->objectType->connection->environment;
|
||||
status = OCITablePrev(environment->handle, environment->errorHandle,
|
||||
index, self->instance, &prevIndex, &exists);
|
||||
if (Environment_CheckForError(environment, status,
|
||||
"Object_GetPrevIndex()") < 0)
|
||||
return NULL;
|
||||
if (exists)
|
||||
return PyInt_FromLong(prevIndex);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Object_GetSize()
|
||||
// Return the size of a collection. If the object is not a collection, an
|
||||
@ -685,3 +900,81 @@ static PyObject *Object_GetSize(
|
||||
return PyInt_FromLong(size);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Object_SetElement()
|
||||
// Set the element at the specified location to the given value.
|
||||
//-----------------------------------------------------------------------------
|
||||
static PyObject *Object_SetElement(
|
||||
udt_Object *self, // object
|
||||
PyObject *args) // arguments
|
||||
{
|
||||
void *elementValue, *elementIndicator;
|
||||
udt_AttributeData attributeData;
|
||||
udt_Environment *environment;
|
||||
OCIInd tempIndicator;
|
||||
PyObject *value;
|
||||
sb4 position;
|
||||
sword status;
|
||||
|
||||
// make sure we are dealing with a collection
|
||||
if (Object_CheckIsCollection(self) < 0)
|
||||
return NULL;
|
||||
|
||||
// parse arguments
|
||||
if (!PyArg_ParseTuple(args, "iO", &position, &value))
|
||||
return NULL;
|
||||
|
||||
// convert 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 NULL;
|
||||
}
|
||||
if (!elementIndicator)
|
||||
elementIndicator = &tempIndicator;
|
||||
status = OCICollAssignElem(environment->handle, environment->errorHandle,
|
||||
position, elementValue, elementIndicator,
|
||||
(OCIColl*) self->instance);
|
||||
if (Environment_CheckForError(environment, status,
|
||||
"Object_SetItem(): assign element") < 0) {
|
||||
AttributeData_Free(environment, &attributeData,
|
||||
self->objectType->elementTypeCode);
|
||||
return NULL;
|
||||
}
|
||||
AttributeData_Free(environment, &attributeData,
|
||||
self->objectType->elementTypeCode);
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Object_Trim()
|
||||
// Trim a number of elements from the end of the collection.
|
||||
//-----------------------------------------------------------------------------
|
||||
static PyObject *Object_Trim(
|
||||
udt_Object *self, // object
|
||||
PyObject *args) // arguments
|
||||
{
|
||||
udt_Environment *environment;
|
||||
sb4 numToTrim;
|
||||
sword status;
|
||||
|
||||
if (Object_CheckIsCollection(self) < 0)
|
||||
return NULL;
|
||||
if (!PyArg_ParseTuple(args, "i", &numToTrim))
|
||||
return NULL;
|
||||
environment = self->objectType->connection->environment;
|
||||
status = OCICollTrim(environment->handle, environment->errorHandle,
|
||||
numToTrim, self->instance);
|
||||
if (Environment_CheckForError(environment, status, "Object_Trim()") < 0)
|
||||
return NULL;
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
@ -17,6 +17,12 @@ Object Type Objects
|
||||
object type. Each attribute has a name attribute on it.
|
||||
|
||||
|
||||
.. attribute:: ObjectType.iscollection
|
||||
|
||||
This read-only attribute returns a boolean indicating if the object type
|
||||
refers to a collection or not.
|
||||
|
||||
|
||||
.. attribute:: ObjectType.name
|
||||
|
||||
This read-only attribute returns the name of the type.
|
||||
@ -33,3 +39,98 @@ Object Type Objects
|
||||
|
||||
This read-only attribute returns the name of the schema that owns the type.
|
||||
|
||||
|
||||
Object Objects
|
||||
==============
|
||||
|
||||
.. note::
|
||||
|
||||
This object is an extension to the DB API. It is returned by the
|
||||
:meth:`~ObjectType.newobject()` call and can be bound to variables of
|
||||
type cx_Oracle.OBJECT. Attributes can be retrieved and set directly.
|
||||
|
||||
.. method:: Object.append(element)
|
||||
|
||||
Append an element to the collection object. If no elements exist in the
|
||||
collection, this creates an element at index 0; otherwise, it creates an
|
||||
element immediately following the highest index available in the collection.
|
||||
|
||||
|
||||
.. method:: Object.aslist()
|
||||
|
||||
Return a list of each of the collection's elements in index order.
|
||||
|
||||
|
||||
.. method:: Object.copy()
|
||||
|
||||
Create a copy of the object and return it.
|
||||
|
||||
|
||||
.. method:: Object.delete(index)
|
||||
|
||||
Delete the element at the specified index of the collection. If the
|
||||
element does not exist or is otherwise invalid, an error is raised. Note
|
||||
that the indices of the remaining elements in the collection are not
|
||||
changed. In other words, the delete operation creates holes in the
|
||||
collection.
|
||||
|
||||
|
||||
.. method:: Object.exists(index)
|
||||
|
||||
Return True or False indicating if an element exists in the collection at
|
||||
the specified index.
|
||||
|
||||
|
||||
.. method:: Object.extend(sequence)
|
||||
|
||||
Append all of the elements in the sequence to the collection. This is
|
||||
the equivalent of performing append() for each element found in the
|
||||
sequence.
|
||||
|
||||
|
||||
.. method:: Object.first()
|
||||
|
||||
Return the index of the first element in the collection. If the collection
|
||||
is empty, an error is raised.
|
||||
|
||||
|
||||
.. method:: Object.getelement(index)
|
||||
|
||||
Return the element at the specified index of the collection. If no element
|
||||
exists at that index, IndexError is raised.
|
||||
|
||||
|
||||
.. method:: Object.last()
|
||||
|
||||
Return the index of the last element in the collection. If the collection
|
||||
is empty, an error is raised.
|
||||
|
||||
|
||||
.. method:: Object.next(index)
|
||||
|
||||
Return the index of the next element in the collection following the
|
||||
specified index. If there are no elements in the collection following the
|
||||
specified index, None is returned.
|
||||
|
||||
|
||||
.. method:: Object.prev(index)
|
||||
|
||||
Return the index of the element in the collection preceding the specified
|
||||
index. If there are no elements in the collection preceding the
|
||||
specified index, None is returned.
|
||||
|
||||
|
||||
.. method:: Object.setelement(index, value)
|
||||
|
||||
Set the value in the collection at the specified index to the given value.
|
||||
|
||||
|
||||
.. method:: Object.size()
|
||||
|
||||
Return the number of elements in the collection.
|
||||
|
||||
|
||||
.. method:: Object.trim(num)
|
||||
|
||||
Remove the specified number of elements from the end of the collection.
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
"""Module for testing features introduced in 12.1"""
|
||||
|
||||
import datetime
|
||||
import sys
|
||||
|
||||
if sys.version_info > (3,):
|
||||
@ -40,6 +41,123 @@ class TestFeatures12_1(BaseTestCase):
|
||||
count, = self.cursor.fetchone()
|
||||
self.assertEqual(count, len(rows))
|
||||
|
||||
def testBindPLSQLDateCollectionIn(self):
|
||||
"test binding a PL/SQL date collection (in)"
|
||||
typeObj = self.connection.gettype("PKG_TESTDATEARRAYS.UDT_DATELIST")
|
||||
obj = typeObj.newobject()
|
||||
obj.setelement(1, datetime.datetime(2016, 2, 5))
|
||||
obj.append(datetime.datetime(2016, 2, 8, 12, 15, 30))
|
||||
obj.append(datetime.datetime(2016, 2, 12, 5, 44, 30))
|
||||
result = self.cursor.callfunc("pkg_TestDateArrays.TestInArrays", int,
|
||||
(2, datetime.datetime(2016, 2, 1), obj))
|
||||
self.assertEqual(result, 24.75)
|
||||
|
||||
def testBindPLSQLDateCollectionInOut(self):
|
||||
"test binding a PL/SQL date collection (in/out)"
|
||||
typeObj = self.connection.gettype("PKG_TESTDATEARRAYS.UDT_DATELIST")
|
||||
obj = typeObj.newobject()
|
||||
obj.setelement(1, datetime.datetime(2016, 1, 1))
|
||||
obj.append(datetime.datetime(2016, 1, 7))
|
||||
obj.append(datetime.datetime(2016, 1, 13))
|
||||
obj.append(datetime.datetime(2016, 1, 19))
|
||||
self.cursor.callproc("pkg_TestDateArrays.TestInOutArrays", (4, obj))
|
||||
self.assertEqual(obj.aslist(),
|
||||
[datetime.datetime(2016, 1, 8),
|
||||
datetime.datetime(2016, 1, 14),
|
||||
datetime.datetime(2016, 1, 20),
|
||||
datetime.datetime(2016, 1, 26)])
|
||||
|
||||
def testBindPLSQLDateCollectionOut(self):
|
||||
"test binding a PL/SQL date collection (out)"
|
||||
typeObj = self.connection.gettype("PKG_TESTDATEARRAYS.UDT_DATELIST")
|
||||
obj = typeObj.newobject()
|
||||
self.cursor.callproc("pkg_TestDateArrays.TestOutArrays", (3, obj))
|
||||
self.assertEqual(obj.aslist(),
|
||||
[datetime.datetime(2002, 12, 13, 4, 48),
|
||||
datetime.datetime(2002, 12, 14, 9, 36),
|
||||
datetime.datetime(2002, 12, 15, 14, 24)])
|
||||
|
||||
def testBindPLSQLNumberCollectionIn(self):
|
||||
"test binding a PL/SQL number collection (in)"
|
||||
typeObj = self.connection.gettype("PKG_TESTNUMBERARRAYS.UDT_NUMBERLIST")
|
||||
obj = typeObj.newobject()
|
||||
obj.setelement(1, 10)
|
||||
obj.extend([20, 30, 40, 50])
|
||||
result = self.cursor.callfunc("pkg_TestNumberArrays.TestInArrays", int,
|
||||
(5, obj))
|
||||
self.assertEqual(result, 155)
|
||||
|
||||
def testBindPLSQLNumberCollectionInOut(self):
|
||||
"test binding a PL/SQL number collection (in/out)"
|
||||
typeObj = self.connection.gettype("PKG_TESTNUMBERARRAYS.UDT_NUMBERLIST")
|
||||
obj = typeObj.newobject()
|
||||
obj.setelement(1, 5)
|
||||
obj.extend([8, 3, 2])
|
||||
self.cursor.callproc("pkg_TestNumberArrays.TestInOutArrays", (4, obj))
|
||||
self.assertEqual(obj.aslist(), [50, 80, 30, 20])
|
||||
|
||||
def testBindPLSQLNumberCollectionOut(self):
|
||||
"test binding a PL/SQL number collection (out)"
|
||||
typeObj = self.connection.gettype("PKG_TESTNUMBERARRAYS.UDT_NUMBERLIST")
|
||||
obj = typeObj.newobject()
|
||||
self.cursor.callproc("pkg_TestNumberArrays.TestOutArrays", (3, obj))
|
||||
self.assertEqual(obj.aslist(), [100, 200, 300])
|
||||
|
||||
def testBindPLSQLStringCollectionIn(self):
|
||||
"test binding a PL/SQL string collection (in)"
|
||||
typeObj = self.connection.gettype("PKG_TESTSTRINGARRAYS.UDT_STRINGLIST")
|
||||
obj = typeObj.newobject()
|
||||
obj.setelement(1, "First element")
|
||||
obj.setelement(2, "Second element")
|
||||
obj.setelement(3, "Third element")
|
||||
result = self.cursor.callfunc("pkg_TestStringArrays.TestInArrays", int,
|
||||
(5, obj))
|
||||
self.assertEqual(result, 45)
|
||||
|
||||
def testBindPLSQLStringCollectionInOut(self):
|
||||
"test binding a PL/SQL string collection (in/out)"
|
||||
typeObj = self.connection.gettype("PKG_TESTSTRINGARRAYS.UDT_STRINGLIST")
|
||||
obj = typeObj.newobject()
|
||||
obj.setelement(1, "The first element")
|
||||
obj.append("The second element")
|
||||
obj.append("The third and final element")
|
||||
self.cursor.callproc("pkg_TestStringArrays.TestInOutArrays", (3, obj))
|
||||
self.assertEqual(obj.aslist(),
|
||||
['Converted element # 1 originally had length 17',
|
||||
'Converted element # 2 originally had length 18',
|
||||
'Converted element # 3 originally had length 27'])
|
||||
|
||||
def testBindPLSQLStringCollectionOut(self):
|
||||
"test binding a PL/SQL string collection (out)"
|
||||
typeObj = self.connection.gettype("PKG_TESTSTRINGARRAYS.UDT_STRINGLIST")
|
||||
obj = typeObj.newobject()
|
||||
self.cursor.callproc("pkg_TestStringArrays.TestOutArrays", (4, obj))
|
||||
self.assertEqual(obj.aslist(),
|
||||
['Test out element # 1',
|
||||
'Test out element # 2',
|
||||
'Test out element # 3',
|
||||
'Test out element # 4'])
|
||||
|
||||
def testBindPLSQLStringCollectionOutWithHoles(self):
|
||||
"test binding a PL/SQL string collection (out with holes)"
|
||||
typeObj = self.connection.gettype("PKG_TESTSTRINGARRAYS.UDT_STRINGLIST")
|
||||
obj = typeObj.newobject()
|
||||
self.cursor.callproc("pkg_TestStringArrays.TestIndexBy", (obj,))
|
||||
self.assertEqual(obj.first(), -1048576)
|
||||
self.assertEqual(obj.last(), 8388608)
|
||||
self.assertEqual(obj.next(-576), 284)
|
||||
self.assertEqual(obj.prev(284), -576)
|
||||
self.assertEqual(obj.size(), 4)
|
||||
self.assertEqual(obj.exists(-576), True)
|
||||
self.assertEqual(obj.exists(-577), False)
|
||||
self.assertEqual(obj.getelement(284), 'Third element')
|
||||
self.assertEqual(obj.aslist(),
|
||||
["First element", "Second element", "Third element",
|
||||
"Fourth element"])
|
||||
obj.delete(-576)
|
||||
obj.delete(284)
|
||||
self.assertEqual(obj.aslist(), ["First element", "Fourth element"])
|
||||
|
||||
def testExceptionInIteration(self):
|
||||
"test executing with arraydmlrowcounts with exception"
|
||||
self.cursor.execute("truncate table TestArrayDML")
|
||||
|
||||
@ -322,6 +322,10 @@ create or replace package cx_Oracle.pkg_TestStringArrays as
|
||||
a_Array out nocopy udt_StringList
|
||||
);
|
||||
|
||||
procedure TestIndexBy (
|
||||
a_Array out nocopy udt_StringList
|
||||
);
|
||||
|
||||
end;
|
||||
/
|
||||
|
||||
@ -362,6 +366,16 @@ create or replace package body cx_Oracle.pkg_TestStringArrays as
|
||||
end loop;
|
||||
end;
|
||||
|
||||
procedure TestIndexBy (
|
||||
a_Array out nocopy udt_StringList
|
||||
) is
|
||||
begin
|
||||
a_Array(-1048576) := 'First element';
|
||||
a_Array(-576) := 'Second element';
|
||||
a_Array(284) := 'Third element';
|
||||
a_Array(8388608) := 'Fourth element';
|
||||
end;
|
||||
|
||||
end;
|
||||
/
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user