Added support for PL/SQL collections of booleans (available only in 12.1).

This commit is contained in:
Anthony Tuininga 2016-02-16 16:32:00 -07:00
parent 6f52f6ce39
commit f4a24f3930
6 changed files with 102 additions and 12 deletions

View File

@ -9,7 +9,7 @@
//-----------------------------------------------------------------------------
typedef struct {
Variable_HEAD
int *data;
boolean *data;
} udt_BooleanVar;
@ -65,7 +65,7 @@ static udt_VariableType vt_Boolean = {
&g_BooleanVarType, // Python type
SQLT_BOL, // Oracle type
SQLCS_IMPLICIT, // charset form
sizeof(int), // element length
sizeof(boolean), // element length
0, // is character data
0, // is variable length
1, // can be copied
@ -81,13 +81,7 @@ static PyObject *BooleanVar_GetValue(
udt_BooleanVar *var, // variable to determine value for
unsigned pos) // array position
{
int integerValue;
PyObject *value;
integerValue = var->data[pos];
value = (integerValue) ? Py_True : Py_False;
Py_INCREF(value);
return value;
return OracleBooleanToPythonBoolean(&var->data[pos]);
}
@ -100,7 +94,6 @@ static int BooleanVar_SetValue(
unsigned pos, // array position to set
PyObject *value) // value to set
{
var->data[pos] = (value == Py_True);
return 0;
return PythonBooleanToOracleBoolean(value, &var->data[pos]);
}

View File

@ -110,6 +110,7 @@ static PyTypeObject g_ObjectType = {
// Declaration of attribute data union
//-----------------------------------------------------------------------------
typedef union {
boolean booleanValue;
OCINumber numberValue;
OCIDate dateValue;
OCIDateTime *timestampValue;
@ -265,6 +266,14 @@ static int Object_ConvertFromPython(
*ociValue = objectValue->instance;
*ociObjectIndicator = objectValue->indicator;
break;
#if ORACLE_VERSION_HEX >= ORACLE_VERSION(12, 1)
case OCI_TYPECODE_BOOLEAN:
if (PythonBooleanToOracleBoolean(pythonValue,
&oracleValue->booleanValue) < 0)
return -1;
*ociValue = &oracleValue->booleanValue;
break;
#endif
default:
PyErr_Format(g_NotSupportedErrorException,
"Object_ConvertFromPython(): unhandled data type %d",
@ -319,6 +328,10 @@ static PyObject *Object_ConvertToPython(
return Object_New(subType, value, indicator, 0);
case OCI_TYPECODE_NAMEDCOLLECTION:
return Object_New(subType, * (OCIColl**) value, indicator, 0);
#if ORACLE_VERSION_HEX >= ORACLE_VERSION(12, 1)
case OCI_TYPECODE_BOOLEAN:
return OracleBooleanToPythonBoolean((boolean*) value);
#endif
};
return PyErr_Format(g_NotSupportedErrorException,

View File

@ -6,6 +6,23 @@
static udt_VariableType vt_Date;
#if ORACLE_VERSION_HEX >= ORACLE_VERSION(12, 1)
//-----------------------------------------------------------------------------
// OracleBooleanToPythonBoolean()
// Return a Python boolean object given an Oracle boolean.
//-----------------------------------------------------------------------------
static PyObject *OracleBooleanToPythonBoolean(
boolean *value) // value to convert
{
PyObject *pythonValue;
pythonValue = (*value) ? Py_True : Py_False;
Py_INCREF(pythonValue);
return pythonValue;
}
#endif
//-----------------------------------------------------------------------------
// OracleDateToPythonDate()
// Return a Python date object given an Oracle date.
@ -97,6 +114,21 @@ static PyObject *OracleNumberToPythonFloat(
}
#if ORACLE_VERSION_HEX >= ORACLE_VERSION(12, 1)
//-----------------------------------------------------------------------------
// PythonBooleanToOracleBoolean()
// Transform a Python boolean into an Oracle boolean.
//-----------------------------------------------------------------------------
static int PythonBooleanToOracleBoolean(
PyObject *pythonValue, // Python value to convert
boolean *oracleValue) // value to convert
{
*oracleValue = (pythonValue == Py_True);
return 0;
}
#endif
//-----------------------------------------------------------------------------
// PythonBooleanToOracleNumber()
// Transform a Python boolean into an Oracle number.

View File

@ -161,10 +161,10 @@ static PyTypeObject g_BaseVarType = {
};
#include "Transforms.c"
#if ORACLE_VERSION_HEX >= ORACLE_VERSION(12, 1)
#include "BooleanVar.c"
#endif
#include "Transforms.c"
#include "StringVar.c"
#include "LongVar.c"
#include "NumberVar.c"

View File

@ -41,6 +41,23 @@ class TestFeatures12_1(BaseTestCase):
count, = self.cursor.fetchone()
self.assertEqual(count, len(rows))
def testBindPLSQLBooleanCollectionIn(self):
"test binding a boolean collection (in)"
typeObj = self.connection.gettype("PKG_TESTBOOLEANS.UDT_BOOLEANLIST")
obj = typeObj.newobject()
obj.setelement(1, True)
obj.extend([True, False, True, True, False, True])
result = self.cursor.callfunc("pkg_TestBooleans.TestInArrays", int,
(obj,))
self.assertEqual(result, 5)
def testBindPLSQLBooleanCollectionOut(self):
"test binding a boolean collection (out)"
typeObj = self.connection.gettype("PKG_TESTBOOLEANS.UDT_BOOLEANLIST")
obj = typeObj.newobject()
self.cursor.callproc("pkg_TestBooleans.TestOutArrays", (6, obj))
self.assertEqual(obj.aslist(), [True, False, True, False, True, False])
def testBindPLSQLDateCollectionIn(self):
"test binding a PL/SQL date collection (in)"
typeObj = self.connection.gettype("PKG_TESTDATEARRAYS.UDT_DATELIST")

View File

@ -597,6 +597,8 @@ end;
create or replace package cx_Oracle.pkg_TestBooleans as
type udt_BooleanList is table of boolean index by binary_integer;
function GetStringRep (
a_Value boolean
) return varchar2;
@ -605,6 +607,15 @@ create or replace package cx_Oracle.pkg_TestBooleans as
a_Value number
) return boolean;
function TestInArrays (
a_Value udt_BooleanList
) return number;
procedure TestOutArrays (
a_NumElements number,
a_Value out nocopy udt_BooleanList
);
end;
/
@ -629,6 +640,30 @@ create or replace package body cx_Oracle.pkg_TestBooleans as
return a_Value < 10;
end;
function TestInArrays (
a_Value udt_BooleanList
) return number is
t_Result pls_integer;
begin
t_Result := 0;
for i in 1..a_Value.count loop
if a_Value(i) then
t_Result := t_Result + 1;
end if;
end loop;
return t_Result;
end;
procedure TestOutArrays (
a_NumElements number,
a_Value out nocopy udt_BooleanList
) is
begin
for i in 1..a_NumElements loop
a_Value(i) := (mod(i, 2) = 1);
end loop;
end;
end;
/