Added support for binding boolean values to PL/SQL booleans -- a feature that
is only available in Oracle 12.1 and higher.
This commit is contained in:
parent
2398ed617d
commit
8c1e6f68e4
|
@ -0,0 +1,105 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// BooleanVar.c
|
||||
// Defines the routines for handling boolean variables (only available after
|
||||
// Oracle 12.1).
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Data types
|
||||
//-----------------------------------------------------------------------------
|
||||
typedef struct {
|
||||
Variable_HEAD
|
||||
int *data;
|
||||
} udt_BooleanVar;
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Declaration of variable functions.
|
||||
//-----------------------------------------------------------------------------
|
||||
static int BooleanVar_SetValue(udt_BooleanVar*, unsigned, PyObject*);
|
||||
static PyObject *BooleanVar_GetValue(udt_BooleanVar*, unsigned);
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Python type declaration
|
||||
//-----------------------------------------------------------------------------
|
||||
static PyTypeObject g_BooleanVarType = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
"cx_Oracle.BOOLEAN", // tp_name
|
||||
sizeof(udt_BooleanVar), // tp_basicsize
|
||||
0, // tp_itemsize
|
||||
0, // tp_dealloc
|
||||
0, // tp_print
|
||||
0, // tp_getattr
|
||||
0, // tp_setattr
|
||||
0, // tp_compare
|
||||
0, // tp_repr
|
||||
0, // tp_as_number
|
||||
0, // tp_as_sequence
|
||||
0, // tp_as_mapping
|
||||
0, // tp_hash
|
||||
0, // tp_call
|
||||
0, // tp_str
|
||||
0, // tp_getattro
|
||||
0, // tp_setattro
|
||||
0, // tp_as_buffer
|
||||
Py_TPFLAGS_DEFAULT, // tp_flags
|
||||
0 // tp_doc
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// variable type declarations
|
||||
//-----------------------------------------------------------------------------
|
||||
static udt_VariableType vt_Boolean = {
|
||||
(InitializeProc) NULL,
|
||||
(FinalizeProc) NULL,
|
||||
(PreDefineProc) NULL,
|
||||
(PostDefineProc) NULL,
|
||||
(PreFetchProc) NULL,
|
||||
(IsNullProc) NULL,
|
||||
(SetValueProc) BooleanVar_SetValue,
|
||||
(GetValueProc) BooleanVar_GetValue,
|
||||
(GetBufferSizeProc) NULL,
|
||||
&g_BooleanVarType, // Python type
|
||||
SQLT_BOL, // Oracle type
|
||||
SQLCS_IMPLICIT, // charset form
|
||||
sizeof(int), // element length
|
||||
0, // is character data
|
||||
0, // is variable length
|
||||
1, // can be copied
|
||||
0 // can be in array
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// BooleanVar_GetValue()
|
||||
// Returns the value stored at the given array position.
|
||||
//-----------------------------------------------------------------------------
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// BooleanVar_SetValue()
|
||||
// Set the value of the variable at the given array position.
|
||||
//-----------------------------------------------------------------------------
|
||||
static int BooleanVar_SetValue(
|
||||
udt_BooleanVar *var, // variable to set value for
|
||||
unsigned pos, // array position to set
|
||||
PyObject *value) // value to set
|
||||
{
|
||||
var->data[pos] = (value == Py_True);
|
||||
return 0;
|
||||
}
|
||||
|
8
Cursor.c
8
Cursor.c
|
@ -1313,7 +1313,7 @@ static int Cursor_CallCalculateSize(
|
|||
|
||||
// assume up to 9 characters for each positional argument
|
||||
// this allows up to four digits for the placeholder if the bind variale
|
||||
// is a boolean value
|
||||
// is a boolean value (prior to Oracle 12.1)
|
||||
if (listOfArguments) {
|
||||
numPositionalArgs = PySequence_Size(listOfArguments);
|
||||
if (numPositionalArgs < 0)
|
||||
|
@ -1323,7 +1323,7 @@ static int Cursor_CallCalculateSize(
|
|||
|
||||
// assume up to 15 characters for each keyword argument
|
||||
// this allows up to four digits for the placeholder if the bind variable
|
||||
// is a boolean value
|
||||
// is a boolean value (prior to Oracle 12.1)
|
||||
if (keywordArguments) {
|
||||
numKeywordArgs = PyDict_Size(keywordArguments);
|
||||
if (numKeywordArgs < 0)
|
||||
|
@ -1400,8 +1400,10 @@ static int Cursor_CallBuildStatement(
|
|||
if (i > 0)
|
||||
*ptr++ = ',';
|
||||
ptr += sprintf(ptr, ":%d", argNum++);
|
||||
#if ORACLE_VERSION_HEX < ORACLE_VERSION(12, 1)
|
||||
if (PyBool_Check(PySequence_Fast_GET_ITEM(positionalArgs, i)))
|
||||
ptr += sprintf(ptr, " = 1");
|
||||
#endif
|
||||
}
|
||||
Py_DECREF(positionalArgs);
|
||||
}
|
||||
|
@ -1421,8 +1423,10 @@ static int Cursor_CallBuildStatement(
|
|||
if ((argNum > 1 && !returnValue) || (argNum > 2 && returnValue))
|
||||
*ptr++ = ',';
|
||||
ptr += sprintf(ptr, "%%s => :%d", argNum++);
|
||||
#if ORACLE_VERSION_HEX < ORACLE_VERSION(12, 1)
|
||||
if (PyBool_Check(value))
|
||||
ptr += sprintf(ptr, " = 1");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -189,6 +189,7 @@ static udt_VariableType vt_NumberAsString = {
|
|||
};
|
||||
|
||||
|
||||
#if ORACLE_VERSION_HEX < ORACLE_VERSION(12, 1)
|
||||
static udt_VariableType vt_Boolean = {
|
||||
(InitializeProc) NULL,
|
||||
(FinalizeProc) NULL,
|
||||
|
@ -208,6 +209,7 @@ static udt_VariableType vt_Boolean = {
|
|||
1, // can be copied
|
||||
1 // can be in array
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
14
Variable.c
14
Variable.c
|
@ -162,6 +162,9 @@ static PyTypeObject g_BaseVarType = {
|
|||
};
|
||||
|
||||
|
||||
#if ORACLE_VERSION_HEX >= ORACLE_VERSION(12, 1)
|
||||
#include "BooleanVar.c"
|
||||
#endif
|
||||
#include "Transforms.c"
|
||||
#include "StringVar.c"
|
||||
#include "LongVar.c"
|
||||
|
@ -382,6 +385,9 @@ static int Variable_Check(
|
|||
Py_TYPE(object) == &g_BinaryVarType ||
|
||||
Py_TYPE(object) == &g_TimestampVarType ||
|
||||
Py_TYPE(object) == &g_IntervalVarType ||
|
||||
#if ORACLE_VERSION_HEX >= ORACLE_VERSION(12,1)
|
||||
Py_TYPE(object) == &g_BooleanVarType ||
|
||||
#endif
|
||||
Py_TYPE(object) == &g_NativeFloatVarType);
|
||||
}
|
||||
|
||||
|
@ -442,6 +448,10 @@ static udt_VariableType *Variable_TypeByPythonType(
|
|||
#endif
|
||||
if (type == (PyObject*) &PyLong_Type)
|
||||
return &vt_LongInteger;
|
||||
#if ORACLE_VERSION_HEX >= ORACLE_VERSION(12,1)
|
||||
if (type == (PyObject*) &g_BooleanVarType)
|
||||
return &vt_Boolean;
|
||||
#endif
|
||||
if (type == (PyObject*) &PyBool_Type)
|
||||
return &vt_Boolean;
|
||||
if (type == (PyObject*) &g_DateTimeVarType)
|
||||
|
@ -495,6 +505,8 @@ static udt_VariableType *Variable_TypeByValue(
|
|||
return &vt_LongString;
|
||||
return &vt_String;
|
||||
}
|
||||
if (PyBool_Check(value))
|
||||
return &vt_Boolean;
|
||||
#if PY_MAJOR_VERSION < 3
|
||||
if (PyUnicode_Check(value)) {
|
||||
*size = PyUnicode_GET_SIZE(value);
|
||||
|
@ -510,8 +522,6 @@ static udt_VariableType *Variable_TypeByValue(
|
|||
return &vt_Binary;
|
||||
}
|
||||
#endif
|
||||
if (PyBool_Check(value))
|
||||
return &vt_Boolean;
|
||||
if (PyLong_Check(value))
|
||||
return &vt_LongInteger;
|
||||
if (PyFloat_Check(value))
|
||||
|
|
|
@ -415,6 +415,9 @@ static PyObject *Module_Initialize(void)
|
|||
MAKE_VARIABLE_TYPE_READY(&g_NCLOBVarType);
|
||||
MAKE_VARIABLE_TYPE_READY(&g_NativeFloatVarType);
|
||||
MAKE_VARIABLE_TYPE_READY(&g_IntervalVarType);
|
||||
#if ORACLE_VERSION_HEX >= ORACLE_VERSION(12, 1)
|
||||
MAKE_VARIABLE_TYPE_READY(&g_BooleanVarType);
|
||||
#endif
|
||||
|
||||
// initialize module and retrieve the dictionary
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
|
@ -494,6 +497,9 @@ static PyObject *Module_Initialize(void)
|
|||
ADD_TYPE_OBJECT("STRING", &g_StringVarType)
|
||||
ADD_TYPE_OBJECT("TIMESTAMP", &g_TimestampVarType)
|
||||
ADD_TYPE_OBJECT("NATIVE_FLOAT", &g_NativeFloatVarType)
|
||||
#if ORACLE_VERSION_HEX >= ORACLE_VERSION(12, 1)
|
||||
ADD_TYPE_OBJECT("BOOLEAN", &g_BooleanVarType)
|
||||
#endif
|
||||
|
||||
// create constants required by Python DB API 2.0
|
||||
if (PyModule_AddStringConstant(module, "apilevel", "2.0") < 0)
|
||||
|
|
|
@ -637,6 +637,17 @@ Types
|
|||
This type is an extension to the DB API definition.
|
||||
|
||||
|
||||
.. data:: BOOLEAN
|
||||
|
||||
This type object is used to represent PL/SQL booleans.
|
||||
|
||||
.. note::
|
||||
|
||||
This type is an extension to the DB API definition. It is only available
|
||||
in Oracle 12.1 and higher and within PL/SQL. It cannot be used in
|
||||
columns.
|
||||
|
||||
|
||||
.. data:: CLOB
|
||||
|
||||
This type object is used to describe columns in a database that are CLOBs.
|
||||
|
|
|
@ -21,6 +21,8 @@ Version 5.2.1
|
|||
4) Use the national character set encoding when required (when char set form is
|
||||
SQLCS_NCHAR); otherwise, the wrong encoding would be used if the environment
|
||||
variable NLS_NCHAR is set.
|
||||
5) Added support for binding boolean values to PL/SQL blocks and stored
|
||||
procedures (available in Oracle 12.1).
|
||||
|
||||
|
||||
Version 5.2
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
"""Module for testing boolean variables."""
|
||||
|
||||
class TestBooleanVar(BaseTestCase):
|
||||
|
||||
def testBindFalse(self):
|
||||
"test binding in a False value"
|
||||
result = self.cursor.callfunc("pkg_TestBooleans.GetStringRep", str,
|
||||
(False,))
|
||||
self.failUnlessEqual(result, "FALSE")
|
||||
|
||||
def testBindNull(self):
|
||||
"test binding in a null value"
|
||||
self.cursor.setinputsizes(None, bool)
|
||||
result = self.cursor.callfunc("pkg_TestBooleans.GetStringRep", str,
|
||||
(None,))
|
||||
self.failUnlessEqual(result, "NULL")
|
||||
|
||||
def testBindOutFalse(self):
|
||||
"test binding out a boolean value (False)"
|
||||
result = self.cursor.callfunc("pkg_TestBooleans.IsLessThan10",
|
||||
cx_Oracle.BOOLEAN, (15,))
|
||||
self.failUnlessEqual(result, False)
|
||||
|
||||
def testBindOutTrue(self):
|
||||
"test binding out a boolean value (True)"
|
||||
result = self.cursor.callfunc("pkg_TestBooleans.IsLessThan10", bool,
|
||||
(5,))
|
||||
self.failUnlessEqual(result, True)
|
||||
|
||||
def testBindTrue(self):
|
||||
"test binding in a True value"
|
||||
result = self.cursor.callfunc("pkg_TestBooleans.GetStringRep", str,
|
||||
(True,))
|
||||
self.failUnlessEqual(result, "TRUE")
|
||||
|
|
@ -560,5 +560,42 @@ create or replace package body cx_Oracle.pkg_TestOutCursors as
|
|||
end;
|
||||
/
|
||||
|
||||
create or replace package cx_Oracle.pkg_TestBooleans as
|
||||
|
||||
function GetStringRep (
|
||||
a_Value boolean
|
||||
) return varchar2;
|
||||
|
||||
function IsLessThan10 (
|
||||
a_Value number
|
||||
) return boolean;
|
||||
|
||||
end;
|
||||
/
|
||||
|
||||
create or replace package body cx_Oracle.pkg_TestBooleans as
|
||||
|
||||
function GetStringRep (
|
||||
a_Value boolean
|
||||
) return varchar2 is
|
||||
begin
|
||||
if a_Value is null then
|
||||
return 'NULL';
|
||||
elsif a_Value then
|
||||
return 'TRUE';
|
||||
end if;
|
||||
return 'FALSE';
|
||||
end;
|
||||
|
||||
function IsLessThan10 (
|
||||
a_Value number
|
||||
) return boolean is
|
||||
begin
|
||||
return a_Value < 10;
|
||||
end;
|
||||
|
||||
end;
|
||||
/
|
||||
|
||||
exit
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@ else:
|
|||
if cx_Oracle.clientversion()[0] >= 12:
|
||||
moduleNames.insert(0, "uArrayDMLBatchError")
|
||||
moduleNames.insert(0, "ArrayDMLBatchError")
|
||||
moduleNames.append("BooleanVar")
|
||||
|
||||
class BaseTestCase(unittest.TestCase):
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ else:
|
|||
]
|
||||
if cx_Oracle.clientversion()[0] >= 12:
|
||||
moduleNames.insert(0, "3kArrayDMLBatchError")
|
||||
moduleNames.append("BooleanVar")
|
||||
|
||||
class BaseTestCase(unittest.TestCase):
|
||||
|
||||
|
|
Loading…
Reference in New Issue