python-cx_Oracle/NumberVar.c
2016-02-24 12:02:04 -07:00

452 lines
17 KiB
C

//-----------------------------------------------------------------------------
// NumberVar.c
// Defines the routines for handling numeric variables.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Number types
//-----------------------------------------------------------------------------
typedef struct {
Variable_HEAD
OCINumber *data;
} udt_NumberVar;
typedef struct {
Variable_HEAD
double *data;
} udt_NativeFloatVar;
typedef struct {
Variable_HEAD
long *data;
} udt_NativeIntVar;
//-----------------------------------------------------------------------------
// Declaration of number variable functions.
//-----------------------------------------------------------------------------
static int NumberVar_PreDefine(udt_NumberVar*, OCIParam*);
static int NumberVar_SetValue(udt_NumberVar*, unsigned, PyObject*);
static PyObject *NumberVar_GetValue(udt_NumberVar*, unsigned);
static int NativeFloatVar_SetValue(udt_NativeFloatVar*, unsigned, PyObject*);
static PyObject *NativeFloatVar_GetValue(udt_NativeFloatVar*, unsigned);
static int NativeIntVar_SetValue(udt_NativeIntVar*, unsigned, PyObject*);
static PyObject *NativeIntVar_GetValue(udt_NativeIntVar*, unsigned);
//-----------------------------------------------------------------------------
// Python type declaration
//-----------------------------------------------------------------------------
static PyTypeObject g_NumberVarType = {
PyVarObject_HEAD_INIT(NULL, 0)
"cx_Oracle.NUMBER", // tp_name
sizeof(udt_NumberVar), // 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
};
static PyTypeObject g_NativeFloatVarType = {
PyVarObject_HEAD_INIT(NULL, 0)
"cx_Oracle.NATIVE_FLOAT", // tp_name
sizeof(udt_NativeFloatVar), // 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
};
static PyTypeObject g_NativeIntVarType = {
PyVarObject_HEAD_INIT(NULL, 0)
"cx_Oracle.NATIVE_INT", // tp_name
sizeof(udt_NativeIntVar), // 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_Float = {
(InitializeProc) NULL,
(FinalizeProc) NULL,
(PreDefineProc) NumberVar_PreDefine,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) NULL,
(IsNullProc) NULL,
(SetValueProc) NumberVar_SetValue,
(GetValueProc) NumberVar_GetValue,
(GetBufferSizeProc) NULL,
&g_NumberVarType, // Python type
SQLT_VNU, // Oracle type
SQLCS_IMPLICIT, // charset form
sizeof(OCINumber), // element length
0, // is character data
0, // is variable length
1, // can be copied
1 // can be in array
};
static udt_VariableType vt_NativeFloat = {
(InitializeProc) NULL,
(FinalizeProc) NULL,
(PreDefineProc) NULL,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) NULL,
(IsNullProc) NULL,
(SetValueProc) NativeFloatVar_SetValue,
(GetValueProc) NativeFloatVar_GetValue,
(GetBufferSizeProc) NULL,
&g_NativeFloatVarType, // Python type
SQLT_BDOUBLE, // Oracle type
SQLCS_IMPLICIT, // charset form
sizeof(double), // element length
0, // is character data
0, // is variable length
1, // can be copied
1 // can be in array
};
static udt_VariableType vt_NativeInteger = {
(InitializeProc) NULL,
(FinalizeProc) NULL,
(PreDefineProc) NULL,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) NULL,
(IsNullProc) NULL,
(SetValueProc) NativeIntVar_SetValue,
(GetValueProc) NativeIntVar_GetValue,
(GetBufferSizeProc) NULL,
&g_NativeIntVarType, // Python type
SQLT_INT, // Oracle type
SQLCS_IMPLICIT, // charset form
sizeof(long), // element length
0, // is character data
0, // is variable length
1, // can be copied
1 // can be in array
};
static udt_VariableType vt_Integer = {
(InitializeProc) NULL,
(FinalizeProc) NULL,
(PreDefineProc) NumberVar_PreDefine,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) NULL,
(IsNullProc) NULL,
(SetValueProc) NumberVar_SetValue,
(GetValueProc) NumberVar_GetValue,
(GetBufferSizeProc) NULL,
&g_NumberVarType, // Python type
SQLT_VNU, // Oracle type
SQLCS_IMPLICIT, // charset form
sizeof(OCINumber), // element length
0, // is character data
0, // is variable length
1, // can be copied
1 // can be in array
};
static udt_VariableType vt_LongInteger = {
(InitializeProc) NULL,
(FinalizeProc) NULL,
(PreDefineProc) NumberVar_PreDefine,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) NULL,
(IsNullProc) NULL,
(SetValueProc) NumberVar_SetValue,
(GetValueProc) NumberVar_GetValue,
(GetBufferSizeProc) NULL,
&g_NumberVarType, // Python type
SQLT_VNU, // Oracle type
SQLCS_IMPLICIT, // charset form
sizeof(OCINumber), // element length
0, // is character data
0, // is variable length
1, // can be copied
1 // can be in array
};
static udt_VariableType vt_NumberAsString = {
(InitializeProc) NULL,
(FinalizeProc) NULL,
(PreDefineProc) NumberVar_PreDefine,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) NULL,
(IsNullProc) NULL,
(SetValueProc) NumberVar_SetValue,
(GetValueProc) NumberVar_GetValue,
(GetBufferSizeProc) NULL,
&g_NumberVarType, // Python type
SQLT_VNU, // Oracle type
SQLCS_IMPLICIT, // charset form
sizeof(OCINumber), // element length
0, // is character data
0, // is variable length
1, // can be copied
1 // can be in array
};
#if ORACLE_VERSION_HEX < ORACLE_VERSION(12, 1)
static udt_VariableType vt_Boolean = {
(InitializeProc) NULL,
(FinalizeProc) NULL,
(PreDefineProc) NumberVar_PreDefine,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) NULL,
(IsNullProc) NULL,
(SetValueProc) NumberVar_SetValue,
(GetValueProc) NumberVar_GetValue,
(GetBufferSizeProc) NULL,
&g_NumberVarType, // Python type
SQLT_VNU, // Oracle type
SQLCS_IMPLICIT, // charset form
sizeof(OCINumber), // element length
0, // is character data
0, // is variable length
1, // can be copied
1 // can be in array
};
#endif
//-----------------------------------------------------------------------------
// NumberVar_PreDefine()
// Set the type of value (integer, float or string) that will be returned
// when values are fetched from this variable.
//-----------------------------------------------------------------------------
static int NumberVar_PreDefine(
udt_NumberVar *var, // variable to initialize
OCIParam *param) // parameter handle
{
static int maxLongSafeDigits = sizeof(long) >= 8 ? 18 : 9;
sb2 precision;
sword status;
sb1 scale;
// if the return type has not already been specified, check to see if the
// number can fit inside an integer by looking at the precision and scale
if (var->type == &vt_Float) {
scale = 0;
precision = 0;
status = OCIAttrGet(param, OCI_HTYPE_DESCRIBE, (dvoid*) &scale, 0,
OCI_ATTR_SCALE, var->environment->errorHandle);
if (Environment_CheckForError(var->environment, status,
"NumberVar_PreDefine(): scale") < 0)
return -1;
status = OCIAttrGet(param, OCI_HTYPE_DESCRIBE, (dvoid*) &precision, 0,
OCI_ATTR_PRECISION, var->environment->errorHandle);
if (Environment_CheckForError(var->environment, status,
"NumberVar_PreDefine(): precision") < 0)
return -1;
if (scale == 0 || (scale == -127 && precision == 0)) {
var->type = &vt_LongInteger;
if (precision > 0 && precision <= maxLongSafeDigits)
var->type = &vt_Integer;
}
}
return 0;
}
//-----------------------------------------------------------------------------
// NumberVar_SetValue()
// Set the value of the variable.
//-----------------------------------------------------------------------------
static int NumberVar_SetValue(
udt_NumberVar *var, // variable to set value for
unsigned pos, // array position to set
PyObject *value) // value to set
{
return PythonNumberToOracleNumber(var->environment, value,
&var->data[pos]);
}
//-----------------------------------------------------------------------------
// NumberVar_GetValue()
// Returns the value stored at the given array position.
//-----------------------------------------------------------------------------
static PyObject *NumberVar_GetValue(
udt_NumberVar *var, // variable to determine value for
unsigned pos) // array position
{
PyObject *result, *stringObj;
char stringValue[200];
long integerValue;
ub4 stringLength;
sword status;
if (var->type == &vt_Boolean || var->type == &vt_Integer) {
status = OCINumberToInt(var->environment->errorHandle, &var->data[pos],
sizeof(long), OCI_NUMBER_SIGNED, (dvoid*) &integerValue);
if (Environment_CheckForError(var->environment, status,
"NumberVar_GetValue(): as integer") < 0)
return NULL;
if (var->type == &vt_Boolean)
return PyBool_FromLong(integerValue);
#if PY_MAJOR_VERSION >= 3
return PyLong_FromLong(integerValue);
#else
return PyInt_FromLong(integerValue);
#endif
}
if (var->type == &vt_NumberAsString || var->type == &vt_LongInteger) {
stringLength = sizeof(stringValue);
status = OCINumberToText(var->environment->errorHandle,
&var->data[pos],
(text*) var->environment->numberToStringFormatBuffer.ptr,
var->environment->numberToStringFormatBuffer.size, NULL, 0,
&stringLength, (unsigned char*) stringValue);
if (Environment_CheckForError(var->environment, status,
"NumberVar_GetValue(): as string") < 0)
return NULL;
stringObj = cxString_FromEncodedString(stringValue, stringLength,
var->environment->encoding);
if (!stringObj)
return NULL;
if (var->type == &vt_NumberAsString)
return stringObj;
#if PY_MAJOR_VERSION >= 3
result = PyNumber_Long(stringObj);
#else
result = PyNumber_Int(stringObj);
#endif
Py_DECREF(stringObj);
if (result || !PyErr_ExceptionMatches(PyExc_ValueError))
return result;
PyErr_Clear();
}
return OracleNumberToPythonFloat(var->environment, &var->data[pos]);
}
//-----------------------------------------------------------------------------
// NativeFloatVar_GetValue()
// Returns the value stored at the given array position as a float.
//-----------------------------------------------------------------------------
static PyObject *NativeFloatVar_GetValue(
udt_NativeFloatVar *var, // variable to determine value for
unsigned pos) // array position
{
return PyFloat_FromDouble(var->data[pos]);
}
//-----------------------------------------------------------------------------
// NativeFloatVar_SetValue()
// Set the value of the variable which should be a native double.
//-----------------------------------------------------------------------------
static int NativeFloatVar_SetValue(
udt_NativeFloatVar *var, // variable to set value for
unsigned pos, // array position to set
PyObject *value) // value to set
{
if (!PyFloat_Check(value)) {
PyErr_SetString(PyExc_TypeError, "expecting float");
return -1;
}
var->data[pos] = PyFloat_AS_DOUBLE(value);
return 0;
}
//-----------------------------------------------------------------------------
// NativeIntVar_GetValue()
// Returns the value stored at the given array position as an integer.
//-----------------------------------------------------------------------------
static PyObject *NativeIntVar_GetValue(
udt_NativeIntVar *var, // variable to determine value for
unsigned pos) // array position
{
return PyInt_FromLong(var->data[pos]);
}
//-----------------------------------------------------------------------------
// NativeIntVar_SetValue()
// Set the value of the variable which should be a native integer.
//-----------------------------------------------------------------------------
static int NativeIntVar_SetValue(
udt_NativeIntVar *var, // variable to set value for
unsigned pos, // array position to set
PyObject *value) // value to set
{
if (!PyInt_Check(value)) {
PyErr_SetString(PyExc_TypeError, "expecting integer");
return -1;
}
var->data[pos] = PyInt_AsLong(value);
if (PyErr_Occurred())
return -1;
return 0;
}