1519 lines
53 KiB
C
1519 lines
53 KiB
C
//-----------------------------------------------------------------------------
|
|
// Variable.c
|
|
// Defines Python types for Oracle variables.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// define structure common to all variables
|
|
//-----------------------------------------------------------------------------
|
|
#if ORACLE_VERSION_HEX >= ORACLE_VERSION(12,1)
|
|
#define OCIBINDBYNAME OCIBindByName2
|
|
#define OCIBINDBYPOS OCIBindByPos2
|
|
#define OCIDEFINEBYPOS OCIDefineByPos2
|
|
#define ACTUAL_LENGTH_TYPE ub4
|
|
#else
|
|
#define OCIBINDBYNAME OCIBindByName
|
|
#define OCIBINDBYPOS OCIBindByPos
|
|
#define OCIDEFINEBYPOS OCIDefineByPos
|
|
#define ACTUAL_LENGTH_TYPE ub2
|
|
#endif
|
|
|
|
struct _udt_VariableType;
|
|
#define Variable_HEAD \
|
|
PyObject_HEAD \
|
|
OCIBind *bindHandle; \
|
|
OCIDefine *defineHandle; \
|
|
OCIStmt *boundCursorHandle; \
|
|
PyObject *boundName; \
|
|
PyObject *inConverter; \
|
|
PyObject *outConverter; \
|
|
ub4 boundPos; \
|
|
udt_Environment *environment; \
|
|
ub4 allocatedElements; \
|
|
ub4 actualElements; \
|
|
unsigned internalFetchNum; \
|
|
int isArray; \
|
|
int isAllocatedInternally; \
|
|
sb2 *indicator; \
|
|
ub2 *returnCode; \
|
|
ACTUAL_LENGTH_TYPE *actualLength; \
|
|
ub4 size; \
|
|
ub4 bufferSize; \
|
|
struct _udt_VariableType *type;
|
|
typedef struct {
|
|
Variable_HEAD
|
|
void *data;
|
|
} udt_Variable;
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// define function types for the common actions that take place on a variable
|
|
//-----------------------------------------------------------------------------
|
|
typedef int (*InitializeProc)(udt_Variable*, udt_Cursor*);
|
|
typedef void (*FinalizeProc)(udt_Variable*);
|
|
typedef int (*PreDefineProc)(udt_Variable*, OCIParam*);
|
|
typedef int (*PostDefineProc)(udt_Variable*);
|
|
typedef int (*PreFetchProc)(udt_Variable*);
|
|
typedef int (*IsNullProc)(udt_Variable*, unsigned);
|
|
typedef int (*SetValueProc)(udt_Variable*, unsigned, PyObject*);
|
|
typedef PyObject * (*GetValueProc)(udt_Variable*, unsigned);
|
|
typedef ub4 (*GetBufferSizeProc)(udt_Variable*);
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// define structure for the common actions that take place on a variable
|
|
//-----------------------------------------------------------------------------
|
|
typedef struct _udt_VariableType {
|
|
InitializeProc initializeProc;
|
|
FinalizeProc finalizeProc;
|
|
PreDefineProc preDefineProc;
|
|
PostDefineProc postDefineProc;
|
|
PreFetchProc preFetchProc;
|
|
IsNullProc isNullProc;
|
|
SetValueProc setValueProc;
|
|
GetValueProc getValueProc;
|
|
GetBufferSizeProc getBufferSizeProc;
|
|
PyTypeObject *pythonType;
|
|
ub2 oracleType;
|
|
ub1 charsetForm;
|
|
ub4 size;
|
|
int isCharacterData;
|
|
int isVariableLength;
|
|
int canBeCopied;
|
|
int canBeInArray;
|
|
} udt_VariableType;
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Declaration of common variable functions.
|
|
//-----------------------------------------------------------------------------
|
|
static void Variable_Free(udt_Variable *);
|
|
static PyObject *Variable_Repr(udt_Variable *);
|
|
static PyObject *Variable_ExternalCopy(udt_Variable *, PyObject *);
|
|
static PyObject *Variable_ExternalSetValue(udt_Variable *, PyObject *);
|
|
static PyObject *Variable_ExternalGetValue(udt_Variable *, PyObject *,
|
|
PyObject *);
|
|
static int Variable_InternalBind(udt_Variable *);
|
|
static int Variable_Resize(udt_Variable *, unsigned);
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// declaration of members for variables
|
|
//-----------------------------------------------------------------------------
|
|
static PyMemberDef g_VariableMembers[] = {
|
|
{ "bufferSize", T_INT, offsetof(udt_Variable, bufferSize), READONLY },
|
|
{ "inconverter", T_OBJECT, offsetof(udt_Variable, inConverter), 0 },
|
|
{ "numElements", T_INT, offsetof(udt_Variable, allocatedElements),
|
|
READONLY },
|
|
{ "outconverter", T_OBJECT, offsetof(udt_Variable, outConverter), 0 },
|
|
{ "size", T_INT, offsetof(udt_Variable, size), READONLY },
|
|
{ "maxlength", T_INT, offsetof(udt_Variable, bufferSize), READONLY },
|
|
{ "allocelems", T_INT, offsetof(udt_Variable, allocatedElements),
|
|
READONLY },
|
|
{ NULL }
|
|
};
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// declaration of methods for variables
|
|
//-----------------------------------------------------------------------------
|
|
static PyMethodDef g_VariableMethods[] = {
|
|
{ "copy", (PyCFunction) Variable_ExternalCopy, METH_VARARGS },
|
|
{ "setvalue", (PyCFunction) Variable_ExternalSetValue, METH_VARARGS },
|
|
{ "getvalue", (PyCFunction) Variable_ExternalGetValue,
|
|
METH_VARARGS | METH_KEYWORDS },
|
|
{ NULL }
|
|
};
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// The base variable type
|
|
//-----------------------------------------------------------------------------
|
|
static PyTypeObject g_BaseVarType = {
|
|
PyVarObject_HEAD_INIT(NULL, 0)
|
|
"cx_Oracle._BASEVARTYPE", // tp_name
|
|
sizeof(udt_Variable), // tp_basicsize
|
|
0, // tp_itemsize
|
|
(destructor) Variable_Free, // tp_dealloc
|
|
0, // tp_print
|
|
0, // tp_getattr
|
|
0, // tp_setattr
|
|
0, // tp_compare
|
|
(reprfunc) Variable_Repr, // 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
|
|
0, // tp_traverse
|
|
0, // tp_clear
|
|
0, // tp_richcompare
|
|
0, // tp_weaklistoffset
|
|
0, // tp_iter
|
|
0, // tp_iternext
|
|
g_VariableMethods, // tp_methods
|
|
g_VariableMembers // tp_members
|
|
};
|
|
|
|
|
|
#include "Transforms.c"
|
|
#include "StringVar.c"
|
|
#include "LongVar.c"
|
|
#include "NumberVar.c"
|
|
#include "DateTimeVar.c"
|
|
#include "TimestampVar.c"
|
|
#include "LobVar.c"
|
|
#include "CursorVar.c"
|
|
#include "ObjectVar.c"
|
|
#include "IntervalVar.c"
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Variable_AllocateData()
|
|
// Allocate the data for the variable.
|
|
//-----------------------------------------------------------------------------
|
|
static int Variable_AllocateData(
|
|
udt_Variable *self) // variable to allocate data for
|
|
{
|
|
unsigned PY_LONG_LONG dataLength;
|
|
|
|
// set the buffer size for the variable
|
|
if (self->type->getBufferSizeProc)
|
|
self->bufferSize = (*self->type->getBufferSizeProc)(self);
|
|
else self->bufferSize = self->size;
|
|
|
|
// allocate the data as long as it is small enough
|
|
dataLength = (unsigned PY_LONG_LONG) self->allocatedElements *
|
|
(unsigned PY_LONG_LONG) self->bufferSize;
|
|
if (dataLength > INT_MAX) {
|
|
PyErr_SetString(PyExc_ValueError, "array size too large");
|
|
return -1;
|
|
}
|
|
self->data = PyMem_Malloc((size_t) dataLength);
|
|
if (!self->data) {
|
|
PyErr_NoMemory();
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Variable_New()
|
|
// Allocate a new variable.
|
|
//-----------------------------------------------------------------------------
|
|
static udt_Variable *Variable_New(
|
|
udt_Cursor *cursor, // cursor to associate variable with
|
|
unsigned numElements, // number of elements to allocate
|
|
udt_VariableType *type, // variable type
|
|
ub4 size) // used only for variable length types
|
|
{
|
|
udt_Variable *self;
|
|
ub4 i;
|
|
|
|
// attempt to allocate the object
|
|
self = (udt_Variable*) type->pythonType->tp_alloc(type->pythonType, 0);
|
|
if (!self)
|
|
return NULL;
|
|
|
|
// perform basic initialization
|
|
Py_INCREF(cursor->connection->environment);
|
|
self->environment = cursor->connection->environment;
|
|
self->boundCursorHandle = NULL;
|
|
self->bindHandle = NULL;
|
|
self->defineHandle = NULL;
|
|
self->boundName = NULL;
|
|
self->inConverter = NULL;
|
|
self->outConverter = NULL;
|
|
self->boundPos = 0;
|
|
if (numElements < 1)
|
|
self->allocatedElements = 1;
|
|
else self->allocatedElements = numElements;
|
|
self->actualElements = 0;
|
|
self->internalFetchNum = 0;
|
|
self->isArray = 0;
|
|
self->isAllocatedInternally = 1;
|
|
self->type = type;
|
|
self->indicator = NULL;
|
|
self->data = NULL;
|
|
self->actualLength = NULL;
|
|
self->returnCode = NULL;
|
|
|
|
// set the maximum length of the variable, ensure that a minimum of
|
|
// 2 bytes is allocated to ensure that the array size check works
|
|
self->size = type->size;
|
|
if (type->isVariableLength) {
|
|
if (size < sizeof(ub2))
|
|
size = sizeof(ub2);
|
|
self->size = size;
|
|
}
|
|
|
|
// allocate the data for the variable
|
|
if (Variable_AllocateData(self) < 0) {
|
|
Py_DECREF(self);
|
|
return NULL;
|
|
}
|
|
|
|
// allocate the indicator for the variable
|
|
self->indicator = PyMem_Malloc(self->allocatedElements * sizeof(sb2));
|
|
if (!self->indicator) {
|
|
PyErr_NoMemory();
|
|
Py_DECREF(self);
|
|
return NULL;
|
|
}
|
|
|
|
// ensure that all variable values start out NULL
|
|
for (i = 0; i < self->allocatedElements; i++)
|
|
self->indicator[i] = OCI_IND_NULL;
|
|
|
|
// for variable length data, also allocate the return code
|
|
if (type->isVariableLength) {
|
|
self->returnCode = PyMem_Malloc(self->allocatedElements * sizeof(ub2));
|
|
if (!self->returnCode) {
|
|
PyErr_NoMemory();
|
|
Py_DECREF(self);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
// perform extended initialization
|
|
if (self->type->initializeProc) {
|
|
if ((*self->type->initializeProc)(self, cursor) < 0) {
|
|
Py_DECREF(self);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Variable_Free()
|
|
// Free an existing variable.
|
|
//-----------------------------------------------------------------------------
|
|
static void Variable_Free(
|
|
udt_Variable *self) // variable to free
|
|
{
|
|
if (self->isAllocatedInternally) {
|
|
if (self->type->finalizeProc)
|
|
(*self->type->finalizeProc)(self);
|
|
if (self->indicator)
|
|
PyMem_Free(self->indicator);
|
|
if (self->data)
|
|
PyMem_Free(self->data);
|
|
if (self->actualLength)
|
|
PyMem_Free(self->actualLength);
|
|
if (self->returnCode)
|
|
PyMem_Free(self->returnCode);
|
|
}
|
|
Py_CLEAR(self->environment);
|
|
Py_CLEAR(self->boundName);
|
|
Py_CLEAR(self->inConverter);
|
|
Py_CLEAR(self->outConverter);
|
|
Py_TYPE(self)->tp_free((PyObject*) self);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Variable_Resize()
|
|
// Resize the variable.
|
|
//-----------------------------------------------------------------------------
|
|
static int Variable_Resize(
|
|
udt_Variable *self, // variable to resize
|
|
unsigned size) // new size to use
|
|
{
|
|
ub4 origBufferSize, i;
|
|
char *origData;
|
|
|
|
// allocate the data for the new array
|
|
origData = self->data;
|
|
origBufferSize = self->bufferSize;
|
|
self->size = size;
|
|
if (Variable_AllocateData(self) < 0)
|
|
return -1;
|
|
|
|
// copy the data from the original array to the new array
|
|
for (i = 0; i < self->allocatedElements; i++)
|
|
memcpy( (char*) self->data + self->bufferSize * i,
|
|
(void*) ( (char*) origData + origBufferSize * i ),
|
|
origBufferSize);
|
|
PyMem_Free(origData);
|
|
|
|
// force rebinding
|
|
if (self->boundName || self->boundPos > 0) {
|
|
if (Variable_InternalBind(self) < 0)
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Variable_Check()
|
|
// Returns a boolean indicating if the object is a variable.
|
|
//-----------------------------------------------------------------------------
|
|
static int Variable_Check(
|
|
PyObject *object) // Python object to check
|
|
{
|
|
return (Py_TYPE(object) == &g_CursorVarType ||
|
|
Py_TYPE(object) == &g_DateTimeVarType ||
|
|
Py_TYPE(object) == &g_BFILEVarType ||
|
|
Py_TYPE(object) == &g_BLOBVarType ||
|
|
Py_TYPE(object) == &g_CLOBVarType ||
|
|
Py_TYPE(object) == &g_LongStringVarType ||
|
|
Py_TYPE(object) == &g_LongBinaryVarType ||
|
|
Py_TYPE(object) == &g_NumberVarType ||
|
|
Py_TYPE(object) == &g_StringVarType ||
|
|
Py_TYPE(object) == &g_FixedCharVarType ||
|
|
Py_TYPE(object) == &g_NCLOBVarType ||
|
|
Py_TYPE(object) == &g_UnicodeVarType ||
|
|
Py_TYPE(object) == &g_FixedUnicodeVarType ||
|
|
Py_TYPE(object) == &g_LongUnicodeVarType ||
|
|
Py_TYPE(object) == &g_RowidVarType ||
|
|
Py_TYPE(object) == &g_BinaryVarType ||
|
|
Py_TYPE(object) == &g_TimestampVarType ||
|
|
Py_TYPE(object) == &g_IntervalVarType
|
|
#ifdef SQLT_BFLOAT
|
|
|| Py_TYPE(object) == &g_NativeFloatVarType
|
|
#endif
|
|
);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Variable_TypeByPythonType()
|
|
// Return a variable type given a Python type object or NULL if the Python
|
|
// type does not have a corresponding variable type.
|
|
//-----------------------------------------------------------------------------
|
|
static udt_VariableType *Variable_TypeByPythonType(
|
|
udt_Cursor* cursor, // cursor variable created for
|
|
PyObject* type) // Python type
|
|
{
|
|
if (type == (PyObject*) &g_StringVarType)
|
|
return &vt_String;
|
|
if (type == (PyObject*) cxString_Type)
|
|
return &vt_String;
|
|
if (type == (PyObject*) &g_FixedCharVarType)
|
|
return &vt_FixedChar;
|
|
if (type == (PyObject*) &g_UnicodeVarType)
|
|
return &vt_NationalCharString;
|
|
#if PY_MAJOR_VERSION < 3
|
|
if (type == (PyObject*) &PyUnicode_Type)
|
|
return &vt_NationalCharString;
|
|
#endif
|
|
if (type == (PyObject*) &g_FixedUnicodeVarType)
|
|
return &vt_FixedNationalChar;
|
|
if (type == (PyObject*) &g_LongUnicodeVarType)
|
|
return &vt_LongNationalCharString;
|
|
if (type == (PyObject*) &g_NCLOBVarType)
|
|
return &vt_NCLOB;
|
|
if (type == (PyObject*) &g_RowidVarType)
|
|
return &vt_Rowid;
|
|
if (type == (PyObject*) &g_BinaryVarType)
|
|
return &vt_Binary;
|
|
if (type == (PyObject*) &cxBinary_Type)
|
|
return &vt_Binary;
|
|
if (type == (PyObject*) &g_LongStringVarType)
|
|
return &vt_LongString;
|
|
if (type == (PyObject*) &g_LongBinaryVarType)
|
|
return &vt_LongBinary;
|
|
if (type == (PyObject*) &g_BFILEVarType)
|
|
return &vt_BFILE;
|
|
if (type == (PyObject*) &g_BLOBVarType)
|
|
return &vt_BLOB;
|
|
if (type == (PyObject*) &g_CLOBVarType)
|
|
return &vt_CLOB;
|
|
if (type == (PyObject*) &g_NumberVarType) {
|
|
if (cursor->numbersAsStrings)
|
|
return &vt_NumberAsString;
|
|
return &vt_Float;
|
|
}
|
|
if (type == (PyObject*) &PyFloat_Type)
|
|
return &vt_Float;
|
|
#if PY_MAJOR_VERSION < 3
|
|
if (type == (PyObject*) &PyInt_Type)
|
|
return &vt_Integer;
|
|
#endif
|
|
if (type == (PyObject*) &PyLong_Type)
|
|
return &vt_LongInteger;
|
|
if (type == (PyObject*) &PyBool_Type)
|
|
return &vt_Boolean;
|
|
if (type == (PyObject*) &g_DateTimeVarType)
|
|
return &vt_DateTime;
|
|
if (type == (PyObject*) PyDateTimeAPI->DateType)
|
|
return &vt_Date;
|
|
if (type == (PyObject*) PyDateTimeAPI->DateTimeType)
|
|
return &vt_DateTime;
|
|
if (type == (PyObject*) &g_IntervalVarType)
|
|
return &vt_Interval;
|
|
if (type == (PyObject*) PyDateTimeAPI->DeltaType)
|
|
return &vt_Interval;
|
|
if (type == (PyObject*) &g_TimestampVarType)
|
|
return &vt_Timestamp;
|
|
if (type == (PyObject*) &g_CursorVarType)
|
|
return &vt_Cursor;
|
|
#ifdef SQLT_BFLOAT
|
|
if (type == (PyObject*) &g_NativeFloatVarType)
|
|
return &vt_NativeFloat;
|
|
#endif
|
|
if (type == (PyObject*) &g_ObjectVarType)
|
|
return &vt_Object;
|
|
|
|
PyErr_SetString(g_NotSupportedErrorException,
|
|
"Variable_TypeByPythonType(): unhandled data type");
|
|
return NULL;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Variable_TypeByValue()
|
|
// Return a variable type given a Python object or NULL if the Python
|
|
// object does not have a corresponding variable type.
|
|
//-----------------------------------------------------------------------------
|
|
static udt_VariableType *Variable_TypeByValue(
|
|
PyObject* value, // Python type
|
|
ub4* size, // size to use (OUT)
|
|
unsigned *numElements) // number of elements (OUT)
|
|
{
|
|
udt_VariableType *varType;
|
|
PyObject *elementValue;
|
|
char buffer[200];
|
|
int i, result;
|
|
|
|
// handle scalars
|
|
if (value == Py_None) {
|
|
*size = 1;
|
|
return &vt_String;
|
|
}
|
|
if (cxString_Check(value)) {
|
|
*size = cxString_GetSize(value);
|
|
return &vt_String;
|
|
}
|
|
#if PY_MAJOR_VERSION < 3
|
|
if (PyUnicode_Check(value)) {
|
|
*size = PyUnicode_GET_SIZE(value);
|
|
return &vt_NationalCharString;
|
|
}
|
|
if (PyInt_Check(value))
|
|
return &vt_Integer;
|
|
#else
|
|
if (PyBytes_Check(value)) {
|
|
*size = PyBytes_GET_SIZE(value);
|
|
return &vt_Binary;
|
|
}
|
|
#endif
|
|
if (PyBool_Check(value))
|
|
return &vt_Boolean;
|
|
if (PyLong_Check(value))
|
|
return &vt_LongInteger;
|
|
if (PyFloat_Check(value))
|
|
return &vt_Float;
|
|
if (cxBinary_Check(value)) {
|
|
udt_Buffer temp;
|
|
if (cxBuffer_FromObject(&temp, value, NULL) < 0)
|
|
return NULL;
|
|
*size = temp.size;
|
|
cxBuffer_Clear(&temp);
|
|
return &vt_Binary;
|
|
}
|
|
if (PyDateTime_Check(value))
|
|
return &vt_DateTime;
|
|
if (PyDate_Check(value))
|
|
return &vt_DateTime;
|
|
if (PyDelta_Check(value))
|
|
return &vt_Interval;
|
|
result = PyObject_IsInstance(value, (PyObject*) &g_CursorType);
|
|
if (result < 0)
|
|
return NULL;
|
|
if (result)
|
|
return &vt_Cursor;
|
|
if (Py_TYPE(value) == g_DateTimeType)
|
|
return &vt_DateTime;
|
|
if (Py_TYPE(value) == g_DecimalType)
|
|
return &vt_NumberAsString;
|
|
|
|
// handle arrays
|
|
if (PyList_Check(value)) {
|
|
elementValue = Py_None;
|
|
for (i = 0; i < PyList_GET_SIZE(value); i++) {
|
|
elementValue = PyList_GET_ITEM(value, i);
|
|
if (elementValue != Py_None)
|
|
break;
|
|
}
|
|
varType = Variable_TypeByValue(elementValue, size, numElements);
|
|
if (!varType)
|
|
return NULL;
|
|
*numElements = PyList_GET_SIZE(value);
|
|
*size = varType->size;
|
|
return varType;
|
|
}
|
|
|
|
sprintf(buffer, "Variable_TypeByValue(): unhandled data type %.*s", 150,
|
|
Py_TYPE(value)->tp_name);
|
|
PyErr_SetString(g_NotSupportedErrorException, buffer);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Variable_TypeByOracleDataType()
|
|
// Return a variable type given an Oracle data type or NULL if the Oracle
|
|
// data type does not have a corresponding variable type.
|
|
//-----------------------------------------------------------------------------
|
|
static udt_VariableType *Variable_TypeByOracleDataType (
|
|
ub2 oracleDataType, // Oracle data type
|
|
ub1 charsetForm) // character set form
|
|
{
|
|
char buffer[100];
|
|
|
|
switch(oracleDataType) {
|
|
case SQLT_LNG:
|
|
return &vt_LongString;
|
|
case SQLT_AFC:
|
|
if (charsetForm == SQLCS_NCHAR)
|
|
return &vt_FixedNationalChar;
|
|
return &vt_FixedChar;
|
|
case SQLT_CHR:
|
|
if (charsetForm == SQLCS_NCHAR)
|
|
return &vt_NationalCharString;
|
|
return &vt_String;
|
|
case SQLT_RDD:
|
|
return &vt_Rowid;
|
|
case SQLT_BIN:
|
|
return &vt_Binary;
|
|
case SQLT_LBI:
|
|
return &vt_LongBinary;
|
|
#ifdef SQLT_BFLOAT
|
|
case SQLT_BFLOAT:
|
|
case SQLT_IBFLOAT:
|
|
case SQLT_BDOUBLE:
|
|
case SQLT_IBDOUBLE:
|
|
return &vt_NativeFloat;
|
|
#endif
|
|
case SQLT_NUM:
|
|
case SQLT_VNU:
|
|
return &vt_Float;
|
|
case SQLT_DAT:
|
|
case SQLT_ODT:
|
|
return &vt_DateTime;
|
|
case SQLT_DATE:
|
|
case SQLT_TIMESTAMP:
|
|
case SQLT_TIMESTAMP_TZ:
|
|
case SQLT_TIMESTAMP_LTZ:
|
|
return &vt_Timestamp;
|
|
case SQLT_INTERVAL_DS:
|
|
return &vt_Interval;
|
|
case SQLT_CLOB:
|
|
if (charsetForm == SQLCS_NCHAR)
|
|
return &vt_NCLOB;
|
|
return &vt_CLOB;
|
|
case SQLT_BLOB:
|
|
return &vt_BLOB;
|
|
case SQLT_BFILE:
|
|
return &vt_BFILE;
|
|
case SQLT_RSET:
|
|
return &vt_Cursor;
|
|
case SQLT_NTY:
|
|
return &vt_Object;
|
|
}
|
|
|
|
sprintf(buffer, "Variable_TypeByOracleDataType: unhandled data type %d",
|
|
oracleDataType);
|
|
PyErr_SetString(g_NotSupportedErrorException, buffer);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Variable_TypeByOracleDescriptor()
|
|
// Return a variable type given an Oracle descriptor.
|
|
//-----------------------------------------------------------------------------
|
|
static udt_VariableType *Variable_TypeByOracleDescriptor(
|
|
OCIParam *param, // parameter to get type from
|
|
udt_Environment *environment) // environment to use
|
|
{
|
|
ub1 charsetForm;
|
|
ub2 dataType;
|
|
sword status;
|
|
|
|
// retrieve datatype of the parameter
|
|
status = OCIAttrGet(param, OCI_HTYPE_DESCRIBE, (dvoid*) &dataType, 0,
|
|
OCI_ATTR_DATA_TYPE, environment->errorHandle);
|
|
if (Environment_CheckForError(environment, status,
|
|
"Variable_TypeByOracleDescriptor(): data type") < 0)
|
|
return NULL;
|
|
|
|
// retrieve character set form of the parameter
|
|
if (dataType != SQLT_CHR && dataType != SQLT_AFC &&
|
|
dataType != SQLT_CLOB) {
|
|
charsetForm = SQLCS_IMPLICIT;
|
|
} else {
|
|
status = OCIAttrGet(param, OCI_HTYPE_DESCRIBE, (dvoid*) &charsetForm,
|
|
0, OCI_ATTR_CHARSET_FORM, environment->errorHandle);
|
|
if (Environment_CheckForError(environment, status,
|
|
"Variable_TypeByOracleDescriptor(): charset form") < 0)
|
|
return NULL;
|
|
}
|
|
|
|
return Variable_TypeByOracleDataType(dataType, charsetForm);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Variable_MakeArray()
|
|
// Make the variable an array, ensuring that the type supports arrays.
|
|
//-----------------------------------------------------------------------------
|
|
static int Variable_MakeArray(
|
|
udt_Variable *var) // variable to make an array
|
|
{
|
|
if (!var->type->canBeInArray) {
|
|
PyErr_SetString(g_NotSupportedErrorException,
|
|
"Variable_MakeArray(): type does not support arrays");
|
|
return -1;
|
|
}
|
|
var->isArray = 1;
|
|
return 0;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Variable_DefaultNewByValue()
|
|
// Default method for determining the type of variable to use for the data.
|
|
//-----------------------------------------------------------------------------
|
|
static udt_Variable *Variable_DefaultNewByValue(
|
|
udt_Cursor *cursor, // cursor to associate variable with
|
|
PyObject *value, // Python value to associate
|
|
unsigned numElements) // number of elements to allocate
|
|
{
|
|
udt_VariableType *varType;
|
|
udt_Variable *var;
|
|
ub4 size = 0;
|
|
|
|
varType = Variable_TypeByValue(value, &size, &numElements);
|
|
if (!varType)
|
|
return NULL;
|
|
var = Variable_New(cursor, numElements, varType, size);
|
|
if (!var)
|
|
return NULL;
|
|
if (PyList_Check(value)) {
|
|
if (Variable_MakeArray(var) < 0) {
|
|
Py_DECREF(var);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
return var;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Variable_NewByInputTypeHandler()
|
|
// Allocate a new variable by looking at the type of the data.
|
|
//-----------------------------------------------------------------------------
|
|
static udt_Variable *Variable_NewByInputTypeHandler(
|
|
udt_Cursor *cursor, // cursor to associate variable with
|
|
PyObject *inputTypeHandler, // input type handler
|
|
PyObject *value, // Python value to associate
|
|
unsigned numElements) // number of elements to allocate
|
|
{
|
|
PyObject *var;
|
|
|
|
var = PyObject_CallFunction(inputTypeHandler, "OOi", cursor, value,
|
|
numElements);
|
|
if (!var)
|
|
return NULL;
|
|
if (var != Py_None) {
|
|
if (!Variable_Check(var)) {
|
|
Py_DECREF(var);
|
|
PyErr_SetString(PyExc_TypeError,
|
|
"expecting variable from input type handler");
|
|
return NULL;
|
|
}
|
|
return (udt_Variable*) var;
|
|
}
|
|
Py_DECREF(var);
|
|
return Variable_DefaultNewByValue(cursor, value, numElements);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Variable_NewByValue()
|
|
// Allocate a new variable by looking at the type of the data.
|
|
//-----------------------------------------------------------------------------
|
|
static udt_Variable *Variable_NewByValue(
|
|
udt_Cursor *cursor, // cursor to associate variable with
|
|
PyObject *value, // Python value to associate
|
|
unsigned numElements) // number of elements to allocate
|
|
{
|
|
if (cursor->inputTypeHandler && cursor->inputTypeHandler != Py_None)
|
|
return Variable_NewByInputTypeHandler(cursor, cursor->inputTypeHandler,
|
|
value, numElements);
|
|
if (cursor->connection->inputTypeHandler &&
|
|
cursor->connection->inputTypeHandler != Py_None)
|
|
return Variable_NewByInputTypeHandler(cursor,
|
|
cursor->connection->inputTypeHandler, value, numElements);
|
|
return Variable_DefaultNewByValue(cursor, value, numElements);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Variable_NewArrayByType()
|
|
// Allocate a new PL/SQL array by looking at the Python data type.
|
|
//-----------------------------------------------------------------------------
|
|
static udt_Variable *Variable_NewArrayByType(
|
|
udt_Cursor *cursor, // cursor to bind variable to
|
|
PyObject *value) // value to bind
|
|
{
|
|
PyObject *typeObj, *numElementsObj;
|
|
udt_VariableType *varType;
|
|
unsigned numElements;
|
|
udt_Variable *var;
|
|
|
|
if (PyList_GET_SIZE(value) != 2) {
|
|
PyErr_SetString(g_ProgrammingErrorException,
|
|
"expecting an array of two elements [type, numelems]");
|
|
return NULL;
|
|
}
|
|
|
|
typeObj = PyList_GET_ITEM(value, 0);
|
|
numElementsObj = PyList_GET_ITEM(value, 1);
|
|
if (!PyInt_Check(numElementsObj)) {
|
|
PyErr_SetString(g_ProgrammingErrorException,
|
|
"number of elements must be an integer");
|
|
return NULL;
|
|
}
|
|
|
|
varType = Variable_TypeByPythonType(cursor, typeObj);
|
|
if (!varType)
|
|
return NULL;
|
|
|
|
numElements = PyInt_AsLong(numElementsObj);
|
|
if (PyErr_Occurred())
|
|
return NULL;
|
|
var = Variable_New(cursor, numElements, varType, varType->size);
|
|
if (!var)
|
|
return NULL;
|
|
if (Variable_MakeArray(var) < 0) {
|
|
Py_DECREF(var);
|
|
return NULL;
|
|
}
|
|
|
|
return var;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Variable_NewByType()
|
|
// Allocate a new variable by looking at the Python data type.
|
|
//-----------------------------------------------------------------------------
|
|
static udt_Variable *Variable_NewByType(
|
|
udt_Cursor *cursor, // cursor to associate variable with
|
|
PyObject *value, // Python data type to associate
|
|
unsigned numElements) // number of elements to allocate
|
|
{
|
|
udt_VariableType *varType;
|
|
int size;
|
|
|
|
// passing an integer is assumed to be a string
|
|
if (PyInt_Check(value)) {
|
|
size = PyInt_AsLong(value);
|
|
if (PyErr_Occurred())
|
|
return NULL;
|
|
varType = &vt_String;
|
|
return Variable_New(cursor, numElements, varType, size);
|
|
}
|
|
|
|
// passing an array of two elements to define an array
|
|
if (PyList_Check(value))
|
|
return Variable_NewArrayByType(cursor, value);
|
|
|
|
// handle directly bound variables
|
|
if (Variable_Check(value)) {
|
|
Py_INCREF(value);
|
|
return (udt_Variable*) value;
|
|
}
|
|
|
|
// everything else ought to be a Python type
|
|
varType = Variable_TypeByPythonType(cursor, value);
|
|
if (!varType)
|
|
return NULL;
|
|
return Variable_New(cursor, numElements, varType, varType->size);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Variable_NewByOutputTypeHandler()
|
|
// Create a new variable by calling the output type handler.
|
|
//-----------------------------------------------------------------------------
|
|
static udt_Variable *Variable_NewByOutputTypeHandler(
|
|
udt_Cursor *cursor, // cursor to associate variable with
|
|
OCIParam *param, // parameter descriptor
|
|
PyObject *outputTypeHandler, // method to call to get type
|
|
udt_VariableType *varType, // variable type already chosen
|
|
ub4 size, // maximum size of variable
|
|
unsigned numElements) // number of elements
|
|
{
|
|
udt_Variable *var;
|
|
PyObject *result;
|
|
ub4 nameLength;
|
|
sb2 precision;
|
|
sword status;
|
|
char *name;
|
|
sb1 scale;
|
|
|
|
// determine name of variable
|
|
status = OCIAttrGet(param, OCI_HTYPE_DESCRIBE, (dvoid*) &name,
|
|
&nameLength, OCI_ATTR_NAME, cursor->environment->errorHandle);
|
|
if (Environment_CheckForError(cursor->environment, status,
|
|
"Variable_NewByOutputTypeHandler(): get name") < 0)
|
|
return NULL;
|
|
|
|
// retrieve scale and precision of the parameter, if applicable
|
|
precision = scale = 0;
|
|
if (varType->pythonType == &g_NumberVarType) {
|
|
status = OCIAttrGet(param, OCI_HTYPE_DESCRIBE, (dvoid*) &scale, 0,
|
|
OCI_ATTR_SCALE, cursor->environment->errorHandle);
|
|
if (Environment_CheckForError(cursor->environment, status,
|
|
"Variable_NewByOutputTypeHandler(): get scale") < 0)
|
|
return NULL;
|
|
status = OCIAttrGet(param, OCI_HTYPE_DESCRIBE, (dvoid*) &precision, 0,
|
|
OCI_ATTR_PRECISION, cursor->environment->errorHandle);
|
|
if (Environment_CheckForError(cursor->environment, status,
|
|
"Variable_NewByOutputTypeHandler(): get precision") < 0)
|
|
return NULL;
|
|
}
|
|
|
|
// call method, passing parameters
|
|
result = PyObject_CallFunction(outputTypeHandler, "Os#Oiii", cursor, name,
|
|
nameLength, varType->pythonType, size, precision, scale);
|
|
if (!result)
|
|
return NULL;
|
|
|
|
// if result is None, assume default behavior
|
|
if (result == Py_None) {
|
|
Py_DECREF(result);
|
|
return Variable_New(cursor, numElements, varType, size);
|
|
}
|
|
|
|
// otherwise, verify that the result is an actual variable
|
|
if (!Variable_Check(result)) {
|
|
Py_DECREF(result);
|
|
PyErr_SetString(PyExc_TypeError,
|
|
"expecting variable from output type handler");
|
|
return NULL;
|
|
}
|
|
|
|
// verify that the array size is sufficient to handle the fetch
|
|
var = (udt_Variable*) result;
|
|
if (var->allocatedElements < cursor->fetchArraySize) {
|
|
Py_DECREF(result);
|
|
PyErr_SetString(PyExc_TypeError,
|
|
"expecting variable with array size large enough for fetch");
|
|
return NULL;
|
|
}
|
|
|
|
return var;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Variable_DefineHelper()
|
|
// Helper routine for Variable_Define() used so that constant calls to
|
|
// OCIDescriptorFree() is not necessary.
|
|
//-----------------------------------------------------------------------------
|
|
static udt_Variable *Variable_DefineHelper(
|
|
udt_Cursor *cursor, // cursor in use
|
|
OCIParam *param, // parameter descriptor
|
|
unsigned position, // position in define list
|
|
unsigned numElements) // number of elements to create
|
|
{
|
|
udt_VariableType *varType;
|
|
ub2 sizeFromOracle;
|
|
udt_Variable *var;
|
|
sword status;
|
|
ub4 size;
|
|
|
|
// determine data type
|
|
varType = Variable_TypeByOracleDescriptor(param, cursor->environment);
|
|
if (!varType)
|
|
return NULL;
|
|
if (cursor->numbersAsStrings && varType == &vt_Float)
|
|
varType = &vt_NumberAsString;
|
|
|
|
// retrieve size of the parameter
|
|
size = varType->size;
|
|
if (varType->isVariableLength) {
|
|
|
|
// determine the maximum length from Oracle
|
|
status = OCIAttrGet(param, OCI_HTYPE_DESCRIBE,
|
|
(dvoid*) &sizeFromOracle, 0, OCI_ATTR_DATA_SIZE,
|
|
cursor->environment->errorHandle);
|
|
if (Environment_CheckForError(cursor->environment, status,
|
|
"Variable_Define(): data size") < 0)
|
|
return NULL;
|
|
|
|
// use the length from Oracle directly if available
|
|
if (sizeFromOracle)
|
|
size = sizeFromOracle;
|
|
|
|
// otherwise, use the value set with the setoutputsize() parameter
|
|
else if (cursor->outputSize >= 0) {
|
|
if (cursor->outputSizeColumn < 0 ||
|
|
(int) position == cursor->outputSizeColumn)
|
|
size = cursor->outputSize;
|
|
}
|
|
}
|
|
|
|
// create a variable of the correct type
|
|
if (cursor->outputTypeHandler && cursor->outputTypeHandler != Py_None)
|
|
var = Variable_NewByOutputTypeHandler(cursor, param,
|
|
cursor->outputTypeHandler, varType, size, numElements);
|
|
else if (cursor->connection->outputTypeHandler &&
|
|
cursor->connection->outputTypeHandler != Py_None)
|
|
var = Variable_NewByOutputTypeHandler(cursor, param,
|
|
cursor->connection->outputTypeHandler, varType, size,
|
|
numElements);
|
|
else var = Variable_New(cursor, numElements, varType, size);
|
|
if (!var)
|
|
return NULL;
|
|
|
|
// call the procedure to set values prior to define
|
|
if (var->type->preDefineProc) {
|
|
if ((*var->type->preDefineProc)(var, param) < 0) {
|
|
Py_DECREF(var);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
// perform the define
|
|
status = OCIDEFINEBYPOS(cursor->handle, &var->defineHandle,
|
|
var->environment->errorHandle, position, var->data,
|
|
var->bufferSize, var->type->oracleType, var->indicator,
|
|
var->actualLength, var->returnCode, OCI_DEFAULT);
|
|
if (Environment_CheckForError(var->environment, status,
|
|
"Variable_Define(): define") < 0) {
|
|
Py_DECREF(var);
|
|
return NULL;
|
|
}
|
|
|
|
// call the procedure to set values after define
|
|
if (var->type->postDefineProc) {
|
|
if ((*var->type->postDefineProc)(var) < 0) {
|
|
Py_DECREF(var);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
return var;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Variable_Define()
|
|
// Allocate a variable and define it for the given statement.
|
|
//-----------------------------------------------------------------------------
|
|
static udt_Variable *Variable_Define(
|
|
udt_Cursor *cursor, // cursor to define for
|
|
unsigned numElements, // number of elements to create
|
|
unsigned position) // position to define
|
|
{
|
|
udt_Variable *var;
|
|
OCIParam *param;
|
|
sword status;
|
|
|
|
// retrieve parameter descriptor
|
|
status = OCIParamGet(cursor->handle, OCI_HTYPE_STMT,
|
|
cursor->environment->errorHandle, (void**) ¶m, position);
|
|
if (Environment_CheckForError(cursor->environment, status,
|
|
"Variable_Define(): parameter") < 0)
|
|
return NULL;
|
|
|
|
// call the helper to do the actual work
|
|
var = Variable_DefineHelper(cursor, param, position, numElements);
|
|
OCIDescriptorFree(param, OCI_DTYPE_PARAM);
|
|
return var;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Variable_InternalBind()
|
|
// Allocate a variable and bind it to the given statement.
|
|
//-----------------------------------------------------------------------------
|
|
static int Variable_InternalBind(
|
|
udt_Variable *var) // variable to bind
|
|
{
|
|
sword status;
|
|
|
|
// perform the bind
|
|
if (var->boundName) {
|
|
udt_Buffer buffer;
|
|
if (cxBuffer_FromObject(&buffer, var->boundName,
|
|
var->environment->encoding) < 0)
|
|
return -1;
|
|
if (var->isArray) {
|
|
status = OCIBINDBYNAME(var->boundCursorHandle, &var->bindHandle,
|
|
var->environment->errorHandle, (text*) buffer.ptr,
|
|
buffer.size, var->data, var->bufferSize,
|
|
var->type->oracleType, var->indicator, var->actualLength,
|
|
var->returnCode, var->allocatedElements,
|
|
&var->actualElements, OCI_DEFAULT);
|
|
} else {
|
|
status = OCIBINDBYNAME(var->boundCursorHandle, &var->bindHandle,
|
|
var->environment->errorHandle, (text*) buffer.ptr,
|
|
buffer.size, var->data, var->bufferSize,
|
|
var->type->oracleType, var->indicator, var->actualLength,
|
|
var->returnCode, 0, 0, OCI_DEFAULT);
|
|
}
|
|
cxBuffer_Clear(&buffer);
|
|
} else {
|
|
if (var->isArray) {
|
|
status = OCIBINDBYPOS(var->boundCursorHandle, &var->bindHandle,
|
|
var->environment->errorHandle, var->boundPos, var->data,
|
|
var->bufferSize, var->type->oracleType, var->indicator,
|
|
var->actualLength, var->returnCode, var->allocatedElements,
|
|
&var->actualElements, OCI_DEFAULT);
|
|
} else {
|
|
status = OCIBINDBYPOS(var->boundCursorHandle, &var->bindHandle,
|
|
var->environment->errorHandle, var->boundPos, var->data,
|
|
var->bufferSize, var->type->oracleType, var->indicator,
|
|
var->actualLength, var->returnCode, 0, 0, OCI_DEFAULT);
|
|
}
|
|
}
|
|
if (Environment_CheckForError(var->environment, status,
|
|
"Variable_InternalBind()") < 0)
|
|
return -1;
|
|
|
|
// set the charset form and id if applicable
|
|
if (var->type->charsetForm != SQLCS_IMPLICIT) {
|
|
status = OCIAttrSet(var->bindHandle, OCI_HTYPE_BIND,
|
|
(dvoid*) &var->type->charsetForm, 0, OCI_ATTR_CHARSET_FORM,
|
|
var->environment->errorHandle);
|
|
if (Environment_CheckForError(var->environment, status,
|
|
"Variable_InternalBind(): set charset form") < 0)
|
|
return -1;
|
|
status = OCIAttrSet(var->bindHandle, OCI_HTYPE_BIND,
|
|
(dvoid*) &var->bufferSize, 0, OCI_ATTR_MAXDATA_SIZE,
|
|
var->environment->errorHandle);
|
|
if (Environment_CheckForError(var->environment, status,
|
|
"Variable_InternalBind(): set max data size") < 0)
|
|
return -1;
|
|
}
|
|
|
|
// set the max data size for strings
|
|
if ((var->type == &vt_String || var->type == &vt_FixedChar)
|
|
&& var->size > var->type->size) {
|
|
status = OCIAttrSet(var->bindHandle, OCI_HTYPE_BIND,
|
|
(dvoid*) &var->type->size, 0, OCI_ATTR_MAXDATA_SIZE,
|
|
var->environment->errorHandle);
|
|
if (Environment_CheckForError(var->environment, status,
|
|
"Variable_InternalBind(): set max data size") < 0)
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Variable_Bind()
|
|
// Allocate a variable and bind it to the given statement.
|
|
//-----------------------------------------------------------------------------
|
|
static int Variable_Bind(
|
|
udt_Variable *var, // variable to bind
|
|
udt_Cursor *cursor, // cursor to bind to
|
|
PyObject *name, // name to bind to
|
|
ub4 pos) // position to bind to
|
|
{
|
|
// nothing to do if already bound
|
|
if (var->bindHandle && name == var->boundName && pos == var->boundPos)
|
|
return 0;
|
|
|
|
// set the instance variables specific for binding
|
|
var->boundPos = pos;
|
|
var->boundCursorHandle = cursor->handle;
|
|
Py_XDECREF(var->boundName);
|
|
Py_XINCREF(name);
|
|
var->boundName = name;
|
|
|
|
// perform the bind
|
|
return Variable_InternalBind(var);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Variable_VerifyFetch()
|
|
// Verifies that truncation or other problems did not take place on retrieve.
|
|
//-----------------------------------------------------------------------------
|
|
static int Variable_VerifyFetch(
|
|
udt_Variable *var, // variable to check fetch for
|
|
unsigned arrayPos) // array position
|
|
{
|
|
char messageText[200];
|
|
udt_Error *error;
|
|
|
|
if (var->type->isVariableLength) {
|
|
if (var->returnCode[arrayPos] != 0) {
|
|
error = Error_New(var->environment, "Variable_VerifyFetch()", 0);
|
|
error->code = var->returnCode[arrayPos];
|
|
sprintf(messageText,
|
|
"column at array pos %d fetched with error: %d",
|
|
arrayPos, var->returnCode[arrayPos]);
|
|
error->message = cxString_FromAscii(messageText);
|
|
if (!error->message)
|
|
Py_DECREF(error);
|
|
else PyErr_SetObject(g_DatabaseErrorException, (PyObject*) error);
|
|
return -1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Variable_GetSingleValue()
|
|
// Return the value of the variable at the given position.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Variable_GetSingleValue(
|
|
udt_Variable *var, // variable to get the value for
|
|
unsigned arrayPos) // array position
|
|
{
|
|
PyObject *value, *result;
|
|
int isNull;
|
|
|
|
// ensure we do not exceed the number of allocated elements
|
|
if (arrayPos >= var->allocatedElements) {
|
|
PyErr_SetString(PyExc_IndexError,
|
|
"Variable_GetSingleValue: array size exceeded");
|
|
return NULL;
|
|
}
|
|
|
|
// check for a NULL value
|
|
if (var->type->isNullProc)
|
|
isNull = (*var->type->isNullProc)(var, arrayPos);
|
|
else isNull = (var->indicator[arrayPos] == OCI_IND_NULL);
|
|
if (isNull) {
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|
|
|
|
// check for truncation or other problems on retrieve
|
|
if (Variable_VerifyFetch(var, arrayPos) < 0)
|
|
return NULL;
|
|
|
|
// calculate value to return
|
|
value = (*var->type->getValueProc)(var, arrayPos);
|
|
if (value && var->outConverter && var->outConverter != Py_None) {
|
|
result = PyObject_CallFunctionObjArgs(var->outConverter, value, NULL);
|
|
Py_DECREF(value);
|
|
return result;
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Variable_GetArrayValue()
|
|
// Return the value of the variable as an array.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Variable_GetArrayValue(
|
|
udt_Variable *var, // variable to get the value for
|
|
ub4 numElements) // number of elements to include
|
|
{
|
|
PyObject *value, *singleValue;
|
|
ub4 i;
|
|
|
|
value = PyList_New(numElements);
|
|
if (!value)
|
|
return NULL;
|
|
|
|
for (i = 0; i < numElements; i++) {
|
|
singleValue = Variable_GetSingleValue(var, i);
|
|
if (!singleValue) {
|
|
Py_DECREF(value);
|
|
return NULL;
|
|
}
|
|
PyList_SET_ITEM(value, i, singleValue);
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Variable_GetValue()
|
|
// Return the value of the variable.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Variable_GetValue(
|
|
udt_Variable *var, // variable to get the value for
|
|
unsigned arrayPos) // array position
|
|
{
|
|
if (var->isArray)
|
|
return Variable_GetArrayValue(var, var->actualElements);
|
|
return Variable_GetSingleValue(var, arrayPos);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Variable_SetSingleValue()
|
|
// Set a single value in the variable.
|
|
//-----------------------------------------------------------------------------
|
|
static int Variable_SetSingleValue(
|
|
udt_Variable *var, // variable to set value for
|
|
unsigned arrayPos, // array position
|
|
PyObject *value) // value to set
|
|
{
|
|
PyObject *convertedValue = NULL;
|
|
int result;
|
|
|
|
// ensure we do not exceed the number of allocated elements
|
|
if (arrayPos >= var->allocatedElements) {
|
|
PyErr_SetString(PyExc_IndexError,
|
|
"Variable_SetSingleValue: array size exceeded");
|
|
return -1;
|
|
}
|
|
|
|
// convert value, if necessary
|
|
if (var->inConverter && var->inConverter != Py_None) {
|
|
convertedValue = PyObject_CallFunctionObjArgs(var->inConverter, value,
|
|
NULL);
|
|
if (!convertedValue)
|
|
return -1;
|
|
value = convertedValue;
|
|
}
|
|
|
|
// check for a NULL value
|
|
if (value == Py_None) {
|
|
var->indicator[arrayPos] = OCI_IND_NULL;
|
|
Py_XDECREF(convertedValue);
|
|
return 0;
|
|
}
|
|
|
|
var->indicator[arrayPos] = OCI_IND_NOTNULL;
|
|
if (var->type->isVariableLength)
|
|
var->returnCode[arrayPos] = 0;
|
|
result = (*var->type->setValueProc)(var, arrayPos, value);
|
|
Py_XDECREF(convertedValue);
|
|
return result;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Variable_SetArrayValue()
|
|
// Set all of the array values for the variable.
|
|
//-----------------------------------------------------------------------------
|
|
static int Variable_SetArrayValue(
|
|
udt_Variable *var, // variable to set value for
|
|
PyObject *value) // value to set
|
|
{
|
|
unsigned numElements;
|
|
ub4 i;
|
|
|
|
// ensure we have an array to set
|
|
if (!PyList_Check(value)) {
|
|
PyErr_SetString(PyExc_TypeError, "expecting array data");
|
|
return -1;
|
|
}
|
|
|
|
// ensure we haven't exceeded the number of allocated elements
|
|
numElements = PyList_GET_SIZE(value);
|
|
if (numElements > var->allocatedElements) {
|
|
PyErr_SetString(PyExc_IndexError,
|
|
"Variable_SetArrayValue: array size exceeded");
|
|
return -1;
|
|
}
|
|
|
|
// set all of the values
|
|
var->actualElements = numElements;
|
|
for (i = 0; i < var->actualElements; i++) {
|
|
if (Variable_SetSingleValue(var, i, PyList_GET_ITEM(value, i)) < 0)
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Variable_SetValue()
|
|
// Set the value of the variable.
|
|
//-----------------------------------------------------------------------------
|
|
static int Variable_SetValue(
|
|
udt_Variable *var, // variable to set
|
|
unsigned arrayPos, // array position
|
|
PyObject *value) // value to set
|
|
{
|
|
if (var->isArray) {
|
|
if (arrayPos > 0) {
|
|
PyErr_SetString(g_NotSupportedErrorException,
|
|
"arrays of arrays are not supported by the OCI");
|
|
return -1;
|
|
}
|
|
return Variable_SetArrayValue(var, value);
|
|
}
|
|
return Variable_SetSingleValue(var, arrayPos, value);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Variable_ExternalCopy()
|
|
// Copy the contents of the source variable to the destination variable.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Variable_ExternalCopy(
|
|
udt_Variable *targetVar, // variable to set
|
|
PyObject *args) // arguments
|
|
{
|
|
unsigned sourcePos, targetPos;
|
|
udt_Variable *sourceVar;
|
|
|
|
// parse arguments; verify that copy is possible
|
|
if (!PyArg_ParseTuple(args, "Oii", &sourceVar, &sourcePos, &targetPos))
|
|
return NULL;
|
|
if (Py_TYPE(targetVar) != Py_TYPE(sourceVar)) {
|
|
PyErr_SetString(g_ProgrammingErrorException,
|
|
"source and target variable type must match");
|
|
return NULL;
|
|
}
|
|
if (!sourceVar->type->canBeCopied) {
|
|
PyErr_SetString(g_ProgrammingErrorException,
|
|
"variable does not support copying");
|
|
return NULL;
|
|
}
|
|
|
|
// ensure array positions are not violated
|
|
if (sourcePos >= sourceVar->allocatedElements) {
|
|
PyErr_SetString(PyExc_IndexError,
|
|
"Variable_ExternalCopy: source array size exceeded");
|
|
return NULL;
|
|
}
|
|
if (targetPos >= targetVar->allocatedElements) {
|
|
PyErr_SetString(PyExc_IndexError,
|
|
"Variable_ExternalCopy: target array size exceeded");
|
|
return NULL;
|
|
}
|
|
|
|
// ensure target can support amount data from the source
|
|
if (targetVar->bufferSize < sourceVar->bufferSize) {
|
|
PyErr_SetString(g_ProgrammingErrorException,
|
|
"target variable has insufficient space to copy source data");
|
|
return NULL;
|
|
}
|
|
|
|
// handle null case directly
|
|
if (sourceVar->indicator[sourcePos] == OCI_IND_NULL)
|
|
targetVar->indicator[targetPos] = OCI_IND_NULL;
|
|
|
|
// otherwise, copy data
|
|
else {
|
|
targetVar->indicator[targetPos] = OCI_IND_NOTNULL;
|
|
if (Variable_VerifyFetch(sourceVar, sourcePos) < 0)
|
|
return NULL;
|
|
if (targetVar->actualLength)
|
|
targetVar->actualLength[targetPos] =
|
|
sourceVar->actualLength[sourcePos];
|
|
if (targetVar->returnCode)
|
|
targetVar->returnCode[targetPos] =
|
|
sourceVar->returnCode[sourcePos];
|
|
memcpy( (char*) targetVar->data + targetPos * targetVar->bufferSize,
|
|
(char*) sourceVar->data + sourcePos * sourceVar->bufferSize,
|
|
sourceVar->bufferSize);
|
|
}
|
|
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Variable_ExternalSetValue()
|
|
// Set the value of the variable at the given position.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Variable_ExternalSetValue(
|
|
udt_Variable *var, // variable to set
|
|
PyObject *args) // arguments
|
|
{
|
|
PyObject *value;
|
|
unsigned pos;
|
|
|
|
if (!PyArg_ParseTuple(args, "iO", &pos, &value))
|
|
return NULL;
|
|
if (Variable_SetValue(var, pos, value) < 0)
|
|
return NULL;
|
|
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Variable_ExternalGetValue()
|
|
// Return the value of the variable at the given position.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Variable_ExternalGetValue(
|
|
udt_Variable *var, // variable to set
|
|
PyObject *args, // arguments
|
|
PyObject *keywordArgs) // keyword arguments
|
|
{
|
|
static char *keywordList[] = { "pos", NULL };
|
|
unsigned pos = 0;
|
|
|
|
if (!PyArg_ParseTupleAndKeywords(args, keywordArgs, "|i", keywordList,
|
|
&pos))
|
|
return NULL;
|
|
return Variable_GetValue(var, pos);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Variable_Repr()
|
|
// Return a string representation of the variable.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Variable_Repr(
|
|
udt_Variable *var) // variable to return the string for
|
|
{
|
|
PyObject *valueRepr, *value, *module, *name, *result, *format, *formatArgs;
|
|
|
|
if (var->isArray)
|
|
value = Variable_GetArrayValue(var, var->actualElements);
|
|
else if (var->allocatedElements == 1)
|
|
value = Variable_GetSingleValue(var, 0);
|
|
else value = Variable_GetArrayValue(var, var->allocatedElements);
|
|
if (!value)
|
|
return NULL;
|
|
valueRepr = PyObject_Repr(value);
|
|
Py_DECREF(value);
|
|
if (!valueRepr)
|
|
return NULL;
|
|
format = cxString_FromAscii("<%s.%s with value %s>");
|
|
if (!format) {
|
|
Py_DECREF(valueRepr);
|
|
return NULL;
|
|
}
|
|
if (GetModuleAndName(Py_TYPE(var), &module, &name) < 0) {
|
|
Py_DECREF(valueRepr);
|
|
Py_DECREF(format);
|
|
return NULL;
|
|
}
|
|
formatArgs = PyTuple_Pack(3, module, name, valueRepr);
|
|
Py_DECREF(module);
|
|
Py_DECREF(name);
|
|
Py_DECREF(valueRepr);
|
|
if (!formatArgs) {
|
|
Py_DECREF(format);
|
|
return NULL;
|
|
}
|
|
result = cxString_Format(format, formatArgs);
|
|
Py_DECREF(format);
|
|
Py_DECREF(formatArgs);
|
|
return result;
|
|
}
|
|
|