Added support for binding objects and setting attributes on objects of numbers,

strings and dates.
This commit is contained in:
Anthony Tuininga 2016-02-09 14:51:30 -07:00
parent 371717623b
commit cb3f833a63
21 changed files with 749 additions and 367 deletions

View File

@ -56,6 +56,7 @@ static udt_VariableType vt_Boolean = {
(FinalizeProc) NULL,
(PreDefineProc) NULL,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) NULL,
(IsNullProc) NULL,
(SetValueProc) BooleanVar_SetValue,

View File

@ -64,6 +64,7 @@ static PyObject *Connection_GetMaxBytesPerCharacter(udt_Connection*, void*);
static PyObject *Connection_ContextManagerEnter(udt_Connection*, PyObject*);
static PyObject *Connection_ContextManagerExit(udt_Connection*, PyObject*);
static PyObject *Connection_ChangePasswordExternal(udt_Connection*, PyObject*);
static PyObject *Connection_GetType(udt_Connection*, PyObject*);
static PyObject *Connection_GetStmtCacheSize(udt_Connection*, void*);
static int Connection_SetStmtCacheSize(udt_Connection*, PyObject*, void*);
#if ORACLE_VERSION_HEX >= ORACLE_VERSION(10, 2)
@ -112,6 +113,7 @@ static PyMethodDef g_ConnectionMethods[] = {
#endif
{ "changepassword", (PyCFunction) Connection_ChangePasswordExternal,
METH_VARARGS },
{ "gettype", (PyCFunction) Connection_GetType, METH_VARARGS },
{ NULL }
};
@ -1081,6 +1083,24 @@ static int Connection_SetStmtCacheSize(
}
//-----------------------------------------------------------------------------
// Connection_GetType()
// Return a type object given its name.
//-----------------------------------------------------------------------------
static PyObject *Connection_GetType(
udt_Connection *self, // connection
PyObject *args) // arguments
{
PyObject *nameObj = NULL;
// parse the arguments
if (!PyArg_ParseTuple(args, "O", &nameObj))
return NULL;
return (PyObject*) ObjectType_NewByName(self, nameObj);
}
//-----------------------------------------------------------------------------
// Connection_GetVersion()
// Retrieve the version of the database and return it. Note that this

View File

@ -59,6 +59,7 @@ static udt_VariableType vt_Cursor = {
(FinalizeProc) CursorVar_Finalize,
(PreDefineProc) NULL,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) NULL,
(IsNullProc) NULL,
(SetValueProc) CursorVar_SetValue,

View File

@ -55,6 +55,7 @@ static udt_VariableType vt_DateTime = {
(FinalizeProc) NULL,
(PreDefineProc) NULL,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) NULL,
(IsNullProc) NULL,
(SetValueProc) DateTimeVar_SetValue,
@ -76,6 +77,7 @@ static udt_VariableType vt_Date = {
(FinalizeProc) NULL,
(PreDefineProc) NULL,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) NULL,
(IsNullProc) NULL,
(SetValueProc) DateTimeVar_SetValue,
@ -101,31 +103,7 @@ static int DateTimeVar_SetValue(
unsigned pos, // array position to set
PyObject *value) // value to set
{
ub1 month, day, hour, minute, second;
short year;
if (PyDateTime_Check(value)) {
year = (short) PyDateTime_GET_YEAR(value);
month = PyDateTime_GET_MONTH(value);
day = PyDateTime_GET_DAY(value);
hour = PyDateTime_DATE_GET_HOUR(value);
minute = PyDateTime_DATE_GET_MINUTE(value);
second = PyDateTime_DATE_GET_SECOND(value);
} else if (PyDate_Check(value)) {
year = (short) PyDateTime_GET_YEAR(value);
month = PyDateTime_GET_MONTH(value);
day = PyDateTime_GET_DAY(value);
hour = minute = second = 0;
} else {
PyErr_SetString(PyExc_TypeError, "expecting date data");
return -1;
}
// store a copy of the value
OCIDateSetDate(&var->data[pos], year, month, day);
OCIDateSetTime(&var->data[pos], hour, minute, second);
return 0;
return PythonDateToOracleDate(value, &var->data[pos]);
}

View File

@ -18,6 +18,8 @@ typedef struct {
udt_Buffer numberToStringFormatBuffer;
udt_Buffer numberFromStringFormatBuffer;
udt_Buffer nlsNumericCharactersBuffer;
OCIString *tempStringValue;
OCIDateTime *tempTimestampValue;
} udt_Environment;
//-----------------------------------------------------------------------------
@ -72,6 +74,7 @@ static udt_Environment *Environment_New(
env = (udt_Environment*) g_EnvironmentType.tp_alloc(&g_EnvironmentType, 0);
if (!env)
return NULL;
env->handle = handle;
env->fixedWidth = 1;
env->maxBytesPerCharacter = 1;
cxBuffer_Init(&env->numberToStringFormatBuffer);
@ -94,7 +97,14 @@ static udt_Environment *Environment_New(
return NULL;
}
env->handle = handle;
// create the temp datetime handle (used for converting timestamps in
// objects)
status = OCIDescriptorAlloc(handle, (dvoid**) &env->tempTimestampValue,
OCI_DTYPE_TIMESTAMP, 0, 0);
if (Environment_CheckForError(env, status,
"Environment_New(): create timestamp descriptor") < 0)
return NULL;
return env;
}

View File

@ -57,6 +57,7 @@ static udt_VariableType vt_Interval = {
(FinalizeProc) IntervalVar_Finalize,
(PreDefineProc) NULL,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) NULL,
(IsNullProc) NULL,
(SetValueProc) IntervalVar_SetValue,

View File

@ -134,6 +134,7 @@ static udt_VariableType vt_CLOB = {
(FinalizeProc) LobVar_Finalize,
(PreDefineProc) NULL,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) LobVar_PreFetch,
(IsNullProc) NULL,
(SetValueProc) LobVar_SetValue,
@ -155,6 +156,7 @@ static udt_VariableType vt_NCLOB = {
(FinalizeProc) LobVar_Finalize,
(PreDefineProc) NULL,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) LobVar_PreFetch,
(IsNullProc) NULL,
(SetValueProc) LobVar_SetValue,
@ -176,6 +178,7 @@ static udt_VariableType vt_BLOB = {
(FinalizeProc) LobVar_Finalize,
(PreDefineProc) NULL,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) LobVar_PreFetch,
(IsNullProc) NULL,
(SetValueProc) LobVar_SetValue,
@ -197,6 +200,7 @@ static udt_VariableType vt_BFILE = {
(FinalizeProc) LobVar_Finalize,
(PreDefineProc) NULL,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) LobVar_PreFetch,
(IsNullProc) NULL,
(SetValueProc) LobVar_SetValue,

View File

@ -106,6 +106,7 @@ static udt_VariableType vt_LongString = {
(FinalizeProc) NULL,
(PreDefineProc) NULL,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) NULL,
(IsNullProc) NULL,
(SetValueProc) LongVar_SetValue,
@ -127,6 +128,7 @@ static udt_VariableType vt_LongNationalCharString = {
(FinalizeProc) NULL,
(PreDefineProc) NULL,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) NULL,
(IsNullProc) NULL,
(SetValueProc) LongVar_SetValue,
@ -148,6 +150,7 @@ static udt_VariableType vt_LongBinary = {
(FinalizeProc) NULL,
(PreDefineProc) NULL,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) NULL,
(IsNullProc) NULL,
(SetValueProc) LongVar_SetValue,

View File

@ -122,6 +122,7 @@ static udt_VariableType vt_Float = {
(FinalizeProc) NULL,
(PreDefineProc) NumberVar_PreDefine,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) NULL,
(IsNullProc) NULL,
(SetValueProc) NumberVar_SetValue,
@ -143,6 +144,7 @@ static udt_VariableType vt_NativeFloat = {
(FinalizeProc) NULL,
(PreDefineProc) NULL,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) NULL,
(IsNullProc) NULL,
(SetValueProc) NativeFloatVar_SetValue,
@ -164,6 +166,7 @@ static udt_VariableType vt_NativeInteger = {
(FinalizeProc) NULL,
(PreDefineProc) NULL,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) NULL,
(IsNullProc) NULL,
(SetValueProc) NativeIntVar_SetValue,
@ -185,6 +188,7 @@ static udt_VariableType vt_Integer = {
(FinalizeProc) NULL,
(PreDefineProc) NumberVar_PreDefine,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) NULL,
(IsNullProc) NULL,
(SetValueProc) NumberVar_SetValue,
@ -206,6 +210,7 @@ static udt_VariableType vt_LongInteger = {
(FinalizeProc) NULL,
(PreDefineProc) NumberVar_PreDefine,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) NULL,
(IsNullProc) NULL,
(SetValueProc) NumberVar_SetValue,
@ -227,6 +232,7 @@ static udt_VariableType vt_NumberAsString = {
(FinalizeProc) NULL,
(PreDefineProc) NumberVar_PreDefine,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) NULL,
(IsNullProc) NULL,
(SetValueProc) NumberVar_SetValue,
@ -249,6 +255,7 @@ static udt_VariableType vt_Boolean = {
(FinalizeProc) NULL,
(PreDefineProc) NumberVar_PreDefine,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) NULL,
(IsNullProc) NULL,
(SetValueProc) NumberVar_SetValue,
@ -306,232 +313,6 @@ static int NumberVar_PreDefine(
}
//-----------------------------------------------------------------------------
// NumberVar_SetValueFromBoolean()
// Set the value of the variable from a Python boolean.
//-----------------------------------------------------------------------------
static int NumberVar_SetValueFromBoolean(
udt_NumberVar *var, // variable to set value for
unsigned pos, // array position to set
PyObject *value) // value to set
{
long integerValue;
sword status;
integerValue = (value == Py_True);
status = OCINumberFromInt(var->environment->errorHandle, &integerValue,
sizeof(long), OCI_NUMBER_SIGNED, &var->data[pos]);
return Environment_CheckForError(var->environment, status,
"NumberVar_SetValueFromBoolean()");
}
#if PY_MAJOR_VERSION < 3
//-----------------------------------------------------------------------------
// NumberVar_SetValueFromInteger()
// Set the value of the variable from a Python integer.
//-----------------------------------------------------------------------------
static int NumberVar_SetValueFromInteger(
udt_NumberVar *var, // variable to set value for
unsigned pos, // array position to set
PyObject *value) // value to set
{
long integerValue;
sword status;
integerValue = PyInt_AS_LONG(value);
status = OCINumberFromInt(var->environment->errorHandle, &integerValue,
sizeof(long), OCI_NUMBER_SIGNED, &var->data[pos]);
return Environment_CheckForError(var->environment, status,
"NumberVar_SetValueFromInteger()");
}
#endif
//-----------------------------------------------------------------------------
// NumberVar_SetValueFromFloat()
// Set the value of the variable from a Python float.
//-----------------------------------------------------------------------------
static int NumberVar_SetValueFromFloat(
udt_NumberVar *var, // variable to set value for
unsigned pos, // array position to set
PyObject *value) // value to set
{
double doubleValue;
sword status;
doubleValue = PyFloat_AS_DOUBLE(value);
status = OCINumberFromReal(var->environment->errorHandle, &doubleValue,
sizeof(double), &var->data[pos]);
return Environment_CheckForError(var->environment, status,
"NumberVar_SetValueFromFloat()");
}
//-----------------------------------------------------------------------------
// NumberVar_SetValueFromLong()
// Set the value of the variable from a Python long.
//-----------------------------------------------------------------------------
static int NumberVar_SetValueFromLong(
udt_NumberVar *var, // variable to set value for
unsigned pos, // array position to set
PyObject *value) // value to set
{
udt_Buffer textBuffer;
PyObject *textValue;
sword status;
textValue = PyObject_Str(value);
if (!textValue)
return -1;
if (cxBuffer_FromObject(&textBuffer, textValue,
var->environment->encoding) < 0)
return -1;
status = OCINumberFromText(var->environment->errorHandle,
(text*) textBuffer.ptr, textBuffer.size,
(text*) var->environment->numberFromStringFormatBuffer.ptr,
var->environment->numberFromStringFormatBuffer.size, NULL, 0,
&var->data[pos]);
cxBuffer_Clear(&textBuffer);
Py_DECREF(textValue);
return Environment_CheckForError(var->environment, status,
"NumberVar_SetValueFromLong()");
}
//-----------------------------------------------------------------------------
// NumberVar_GetFormatAndTextFromDecimal()
// Return the number format and text to use for the Decimal object.
//-----------------------------------------------------------------------------
static int NumberVar_GetFormatAndTextFromDecimal(
PyObject *tupleValue, // decimal as_tuple() value
PyObject **textObj, // text string for conversion
PyObject **formatObj) // format for conversion
{
long numDigits, scale, i, sign, length, digit;
char *textValue, *format, *textPtr, *formatPtr;
PyObject *digits;
// acquire basic information from the value tuple
sign = PyInt_AsLong(PyTuple_GET_ITEM(tupleValue, 0));
if (PyErr_Occurred())
return -1;
digits = PyTuple_GET_ITEM(tupleValue, 1);
scale = PyInt_AsLong(PyTuple_GET_ITEM(tupleValue, 2));
if (PyErr_Occurred())
return -1;
numDigits = PyTuple_GET_SIZE(digits);
// allocate memory for the string and format to use in conversion
length = numDigits + abs(scale) + 3;
textValue = textPtr = PyMem_Malloc(length);
if (!textValue) {
PyErr_NoMemory();
return -1;
}
format = formatPtr = PyMem_Malloc(length);
if (!format) {
PyMem_Free(textValue);
PyErr_NoMemory();
return -1;
}
// populate the string and format
if (sign)
*textPtr++ = '-';
for (i = 0; i < numDigits + scale; i++) {
*formatPtr++ = '9';
if (i < numDigits) {
digit = PyInt_AsLong(PyTuple_GetItem(digits, i));
if (PyErr_Occurred()) {
PyMem_Free(textValue);
return -1;
}
}
else digit = 0;
*textPtr++ = '0' + (char) digit;
}
if (scale < 0) {
*formatPtr++ = 'D';
*textPtr++ = '.';
for (i = scale; i < 0; i++) {
*formatPtr++ = '9';
if (numDigits + i < 0)
digit = 0;
else {
digit = PyInt_AsLong(PyTuple_GetItem(digits, numDigits + i));
if (PyErr_Occurred()) {
PyMem_Free(textValue);
return -1;
}
}
*textPtr++ = '0' + (char) digit;
}
}
*formatPtr = '\0';
*textPtr = '\0';
*textObj = cxString_FromAscii(textValue);
PyMem_Free(textValue);
if (!*textObj) {
PyMem_Free(format);
return -1;
}
*formatObj = cxString_FromAscii(format);
PyMem_Free(format);
if (!*formatObj) {
Py_DECREF(*textObj);
return -1;
}
return 0;
}
//-----------------------------------------------------------------------------
// NumberVar_SetValueFromDecimal()
// Set the value of the variable from a Python decimal.Decimal object.
//-----------------------------------------------------------------------------
static int NumberVar_SetValueFromDecimal(
udt_NumberVar *var, // variable to set value for
unsigned pos, // array position to set
PyObject *value) // value to set
{
PyObject *textValue, *format, *tupleValue;
udt_Buffer textBuffer, formatBuffer;
sword status;
tupleValue = PyObject_CallMethod(value, "as_tuple", NULL);
if (!tupleValue)
return -1;
if (NumberVar_GetFormatAndTextFromDecimal(tupleValue, &textValue,
&format) < 0) {
Py_DECREF(tupleValue);
return -1;
}
Py_DECREF(tupleValue);
if (cxBuffer_FromObject(&textBuffer, textValue,
var->environment->encoding) < 0)
return -1;
if (cxBuffer_FromObject(&formatBuffer, format,
var->environment->encoding) < 0) {
cxBuffer_Clear(&textBuffer);
return -1;
}
status = OCINumberFromText(var->environment->errorHandle,
(text*) textBuffer.ptr, textBuffer.size, (text*) formatBuffer.ptr,
formatBuffer.size,
var->environment->nlsNumericCharactersBuffer.ptr,
var->environment->nlsNumericCharactersBuffer.size,
&var->data[pos]);
cxBuffer_Clear(&textBuffer);
cxBuffer_Clear(&formatBuffer);
Py_DECREF(textValue);
Py_DECREF(format);
return Environment_CheckForError(var->environment, status,
"NumberVar_SetValueFromDecimal()");
}
//-----------------------------------------------------------------------------
// NumberVar_SetValue()
// Set the value of the variable.
@ -541,20 +322,8 @@ static int NumberVar_SetValue(
unsigned pos, // array position to set
PyObject *value) // value to set
{
#if PY_MAJOR_VERSION < 3
if (PyInt_Check(value))
return NumberVar_SetValueFromInteger(var, pos, value);
#endif
if (PyBool_Check(value))
return NumberVar_SetValueFromBoolean(var, pos, value);
if (PyLong_Check(value))
return NumberVar_SetValueFromLong(var, pos, value);
if (PyFloat_Check(value))
return NumberVar_SetValueFromFloat(var, pos, value);
if (Py_TYPE(value) == g_DecimalType)
return NumberVar_SetValueFromDecimal(var, pos, value);
PyErr_SetString(PyExc_TypeError, "expecting numeric data");
return -1;
return PythonNumberToOracleNumber(var->environment, value,
&var->data[pos]);
}

140
Object.c
View File

@ -20,6 +20,7 @@ typedef struct {
//-----------------------------------------------------------------------------
static void Object_Free(udt_Object*);
static PyObject *Object_GetAttr(udt_Object*, PyObject*);
static int Object_SetAttr(udt_Object*, PyObject*, PyObject*);
static PyObject *Object_ConvertToPython(udt_Environment*, OCITypeCode, dvoid*,
dvoid*, udt_ObjectType*);
@ -52,7 +53,7 @@ static PyTypeObject g_ObjectType = {
0, // tp_call
0, // tp_str
(getattrofunc) Object_GetAttr, // tp_getattro
0, // tp_setattro
(setattrofunc) Object_SetAttr, // tp_setattro
0, // tp_as_buffer
Py_TPFLAGS_DEFAULT, // tp_flags
0, // tp_doc
@ -99,9 +100,9 @@ static void Object_Free(
udt_Object *self) // variable to free
{
if (self->isIndependent)
OCIObjectFree(self->objectType->environment->handle,
self->objectType->environment->errorHandle,
self->instance, OCI_OBJECTFREE_FORCE);
OCIObjectFree(self->objectType->connection->environment->handle,
self->objectType->connection->environment->errorHandle,
self->instance, OCI_DEFAULT);
Py_CLEAR(self->objectType);
Py_TYPE(self)->tp_free((PyObject*) self);
}
@ -243,21 +244,23 @@ static PyObject *Object_GetAttributeValue(
{
dvoid *valueIndicator, *value;
OCIInd scalarValueIndicator;
udt_Connection *connection;
udt_Buffer buffer;
sword status;
OCIType *tdo;
// get the value for the attribute
connection = self->objectType->connection;
if (cxBuffer_FromObject(&buffer, attribute->name,
self->objectType->environment->encoding) < 0)
connection->environment->encoding) < 0)
return NULL;
status = OCIObjectGetAttr(self->objectType->environment->handle,
self->objectType->environment->errorHandle, self->instance,
status = OCIObjectGetAttr(connection->environment->handle,
connection->environment->errorHandle, self->instance,
self->indicator, self->objectType->tdo,
(const OraText**) &buffer.ptr, (ub4*) &buffer.size, 1, 0, 0,
&scalarValueIndicator, &valueIndicator, &value, &tdo);
cxBuffer_Clear(&buffer);
if (Environment_CheckForError(self->objectType->environment, status,
if (Environment_CheckForError(connection->environment, status,
"Object_GetAttributeValue(): getting value") < 0)
return NULL;
@ -265,14 +268,111 @@ static PyObject *Object_GetAttributeValue(
if (!valueIndicator)
valueIndicator = &scalarValueIndicator;
return Object_ConvertToPython(self->objectType->environment,
return Object_ConvertToPython(connection->environment,
attribute->typeCode, value, valueIndicator, attribute->subType);
}
//-----------------------------------------------------------------------------
// Object_SetAttributeValue()
// Set an attribute on the object.
//-----------------------------------------------------------------------------
static int Object_SetAttributeValue(
udt_Object *self, // object
udt_ObjectAttribute *attribute, // attribute to set
PyObject *value) // value to set
{
dvoid *ociValueIndicator, *ociValue;
OCIInd ociScalarValueIndicator;
udt_Connection *connection;
OCINumber numericValue;
udt_Buffer buffer;
OCIDate dateValue;
sword status;
// initialization
ociValue = NULL;
ociValueIndicator = NULL;
connection = self->objectType->connection;
// None is treated as null
if (value == Py_None) {
ociScalarValueIndicator = OCI_IND_NULL;
// all other values need to be converted
} else {
ociScalarValueIndicator = OCI_IND_NOTNULL;
switch (attribute->typeCode) {
case OCI_TYPECODE_CHAR:
case OCI_TYPECODE_VARCHAR:
case OCI_TYPECODE_VARCHAR2:
if (cxBuffer_FromObject(&buffer, value,
connection->environment->encoding) < 0)
return -1;
status = OCIStringAssignText(connection->environment->handle,
connection->environment->errorHandle, buffer.ptr,
buffer.size,
&connection->environment->tempStringValue);
cxBuffer_Clear(&buffer);
if (Environment_CheckForError(connection->environment, status,
"Object_SetAttributeValue(): assigning string") < 0)
return -1;
ociValue = connection->environment->tempStringValue;
break;
case OCI_TYPECODE_NUMBER:
ociValue = &numericValue;
if (PythonNumberToOracleNumber(connection->environment, value,
ociValue) < 0)
return -1;
break;
case OCI_TYPECODE_DATE:
ociValue = &dateValue;
if (PythonDateToOracleDate(value, ociValue) < 0)
return -1;
break;
case OCI_TYPECODE_TIMESTAMP:
ociValue = connection->environment->tempTimestampValue;
if (PythonDateToOracleTimestamp(connection->environment, value,
ociValue) < 0)
return -1;
break;
case OCI_TYPECODE_OBJECT:
break;
case OCI_TYPECODE_NAMEDCOLLECTION:
break;
};
if (!ociValue) {
PyErr_Format(g_NotSupportedErrorException,
"Object_SetAttributeValue(): unhandled data type %d",
attribute->typeCode);
return -1;
}
}
// set the value for the attribute
if (cxBuffer_FromObject(&buffer, attribute->name,
connection->environment->encoding) < 0)
return -1;
status = OCIObjectSetAttr(connection->environment->handle,
connection->environment->errorHandle, self->instance,
self->indicator, self->objectType->tdo,
(const OraText**) &buffer.ptr, (ub4*) &buffer.size, 1, 0, 0,
ociScalarValueIndicator, ociValueIndicator, ociValue);
cxBuffer_Clear(&buffer);
if (Environment_CheckForError(connection->environment, status,
"Object_SetAttributeValue(): setting value") < 0)
return -1;
return 0;
}
//-----------------------------------------------------------------------------
// Object_GetAttr()
// Retrieve an attribute on object.
// Retrieve an attribute on an object.
//-----------------------------------------------------------------------------
static PyObject *Object_GetAttr(
udt_Object *self, // object
@ -288,3 +388,23 @@ static PyObject *Object_GetAttr(
return PyObject_GenericGetAttr( (PyObject*) self, nameObject);
}
//-----------------------------------------------------------------------------
// Object_SetAttr()
// Set an attribute on an object.
//-----------------------------------------------------------------------------
static int Object_SetAttr(
udt_Object *self, // object
PyObject *nameObject, // name of attribute
PyObject *value) // value to set
{
udt_ObjectAttribute *attribute;
attribute = (udt_ObjectAttribute*)
PyDict_GetItem(self->objectType->attributesByName, nameObject);
if (attribute)
return Object_SetAttributeValue(self, attribute, value);
return PyObject_GenericSetAttr( (PyObject*) self, nameObject, value);
}

View File

@ -8,7 +8,7 @@
//-----------------------------------------------------------------------------
typedef struct {
PyObject_HEAD
udt_Environment *environment;
udt_Connection *connection;
OCIType *tdo;
PyObject *schema;
PyObject *name;
@ -27,6 +27,7 @@ typedef struct {
udt_ObjectType *subType;
} udt_ObjectAttribute;
#include "Object.c"
//-----------------------------------------------------------------------------
// Declaration of type variable functions.
@ -34,11 +35,21 @@ typedef struct {
static udt_ObjectType *ObjectType_New(udt_Connection*, OCIParam*, ub4);
static void ObjectType_Free(udt_ObjectType*);
static PyObject *ObjectType_Repr(udt_ObjectType*);
static PyObject *ObjectType_NewObject(udt_ObjectType*, PyObject*);
static udt_ObjectAttribute *ObjectAttribute_New(udt_Connection*, OCIParam*);
static void ObjectAttribute_Free(udt_ObjectAttribute*);
static PyObject *ObjectAttribute_Repr(udt_ObjectAttribute*);
//-----------------------------------------------------------------------------
// declaration of methods for Python type "ObjectType"
//-----------------------------------------------------------------------------
static PyMethodDef g_ObjectTypeMethods[] = {
{ "newobject", (PyCFunction) ObjectType_NewObject, METH_NOARGS },
{ NULL, NULL }
};
//-----------------------------------------------------------------------------
// declaration of members for Python type "ObjectType"
//-----------------------------------------------------------------------------
@ -90,7 +101,7 @@ static PyTypeObject g_ObjectTypeType = {
0, // tp_weaklistoffset
0, // tp_iter
0, // tp_iternext
0, // tp_methods
g_ObjectTypeMethods, // tp_methods
g_ObjectTypeMembers, // tp_members
0, // tp_getset
0, // tp_base
@ -158,7 +169,6 @@ static PyTypeObject g_ObjectAttributeType = {
//-----------------------------------------------------------------------------
static int ObjectType_Describe(
udt_ObjectType *self, // type to populate
udt_Connection *connection, // connection for type information
OCIDescribe *describeHandle) // describe handle
{
OCIParam *topLevelParam, *attributeListParam, *attributeParam;
@ -170,24 +180,24 @@ static int ObjectType_Describe(
int i;
// describe the type
status = OCIDescribeAny(connection->handle, self->environment->errorHandle,
(dvoid*) self->tdo, 0, OCI_OTYPE_PTR, OCI_DEFAULT, OCI_PTYPE_TYPE,
describeHandle);
if (Environment_CheckForError(self->environment, status,
status = OCIDescribeAny(self->connection->handle,
self->connection->environment->errorHandle, (dvoid*) self->tdo, 0,
OCI_OTYPE_PTR, OCI_DEFAULT, OCI_PTYPE_TYPE, describeHandle);
if (Environment_CheckForError(self->connection->environment, status,
"ObjectType_Describe(): describe type") < 0)
return -1;
// get top level parameter descriptor
status = OCIAttrGet(describeHandle, OCI_HTYPE_DESCRIBE, &topLevelParam, 0,
OCI_ATTR_PARAM, self->environment->errorHandle);
if (Environment_CheckForError(self->environment, status,
OCI_ATTR_PARAM, self->connection->environment->errorHandle);
if (Environment_CheckForError(self->connection->environment, status,
"ObjectType_Describe(): get top level parameter descriptor") < 0)
return -1;
// determine type of type
status = OCIAttrGet(topLevelParam, OCI_DTYPE_PARAM, &typeCode, 0,
OCI_ATTR_TYPECODE, self->environment->errorHandle);
if (Environment_CheckForError(self->environment, status,
OCI_ATTR_TYPECODE, self->connection->environment->errorHandle);
if (Environment_CheckForError(self->connection->environment, status,
"ObjectType_Describe(): get type code") < 0)
return -1;
@ -198,31 +208,31 @@ static int ObjectType_Describe(
// determine type of collection
status = OCIAttrGet(topLevelParam, OCI_DTYPE_PARAM,
&self->collectionTypeCode, 0, OCI_ATTR_COLLECTION_TYPECODE,
self->environment->errorHandle);
if (Environment_CheckForError(self->environment, status,
self->connection->environment->errorHandle);
if (Environment_CheckForError(self->connection->environment, status,
"ObjectType_Describe(): get collection type code") < 0)
return -1;
// acquire collection parameter descriptor
status = OCIAttrGet(topLevelParam, OCI_DTYPE_PARAM, &collectionParam,
0, OCI_ATTR_COLLECTION_ELEMENT,
self->environment->errorHandle);
if (Environment_CheckForError(self->environment, status,
self->connection->environment->errorHandle);
if (Environment_CheckForError(self->connection->environment, status,
"ObjectType_Describe(): get collection descriptor") < 0)
return -1;
// determine type of element
status = OCIAttrGet(collectionParam, OCI_DTYPE_PARAM,
&self->elementTypeCode, 0, OCI_ATTR_TYPECODE,
self->environment->errorHandle);
if (Environment_CheckForError(self->environment, status,
self->connection->environment->errorHandle);
if (Environment_CheckForError(self->connection->environment, status,
"ObjectType_Describe(): get element type code") < 0)
return -1;
// if element type is an object type get its type
if (self->elementTypeCode == OCI_TYPECODE_OBJECT) {
self->elementType = (PyObject*)
ObjectType_New(connection, collectionParam,
ObjectType_New(self->connection, collectionParam,
OCI_ATTR_TYPE_NAME);
if (!self->elementType)
return -1;
@ -233,8 +243,8 @@ static int ObjectType_Describe(
// determine the number of attributes
status = OCIAttrGet(topLevelParam, OCI_DTYPE_PARAM,
(dvoid*) &numAttributes, 0, OCI_ATTR_NUM_TYPE_ATTRS,
self->environment->errorHandle);
if (Environment_CheckForError(self->environment, status,
self->connection->environment->errorHandle);
if (Environment_CheckForError(self->connection->environment, status,
"ObjectType_Describe(): get number of attributes") < 0)
return -1;
@ -249,20 +259,20 @@ static int ObjectType_Describe(
// acquire the list parameter descriptor
status = OCIAttrGet(topLevelParam, OCI_DTYPE_PARAM,
(dvoid*) &attributeListParam, 0, OCI_ATTR_LIST_TYPE_ATTRS,
self->environment->errorHandle);
if (Environment_CheckForError(self->environment, status,
self->connection->environment->errorHandle);
if (Environment_CheckForError(self->connection->environment, status,
"ObjectType_Describe(): get list parameter descriptor") < 0)
return -1;
// create attribute information for each attribute
for (i = 0; i < numAttributes; i++) {
status = OCIParamGet(attributeListParam, OCI_DTYPE_PARAM,
self->environment->errorHandle, (dvoid**) &attributeParam,
(ub4) i + 1);
if (Environment_CheckForError(self->environment, status,
self->connection->environment->errorHandle,
(dvoid**) &attributeParam, (ub4) i + 1);
if (Environment_CheckForError(self->connection->environment, status,
"ObjectType_Describe(): get attribute param descriptor") < 0)
return -1;
attribute = ObjectAttribute_New(connection, attributeParam);
attribute = ObjectAttribute_New(self->connection, attributeParam);
if (!attribute)
return -1;
PyList_SET_ITEM(self->attributes, i, (PyObject*) attribute);
@ -281,7 +291,6 @@ static int ObjectType_Describe(
//-----------------------------------------------------------------------------
static int ObjectType_Initialize(
udt_ObjectType *self, // type to initialize
udt_Connection *connection, // connection for type information
OCIParam *param, // parameter descriptor
ub4 nameAttribute) // value for the name attribute
{
@ -293,53 +302,54 @@ static int ObjectType_Initialize(
// determine the schema of the type
status = OCIAttrGet(param, OCI_HTYPE_DESCRIBE, (dvoid*) &name, &size,
OCI_ATTR_SCHEMA_NAME, self->environment->errorHandle);
if (Environment_CheckForError(self->environment, status,
OCI_ATTR_SCHEMA_NAME, self->connection->environment->errorHandle);
if (Environment_CheckForError(self->connection->environment, status,
"ObjectType_Initialize(): get schema name") < 0)
return -1;
self->schema = cxString_FromEncodedString(name, size,
self->environment->encoding);
self->connection->environment->encoding);
if (!self->schema)
return -1;
// determine the name of the type
status = OCIAttrGet(param, OCI_HTYPE_DESCRIBE, (dvoid*) &name, &size,
nameAttribute, self->environment->errorHandle);
if (Environment_CheckForError(self->environment, status,
nameAttribute, self->connection->environment->errorHandle);
if (Environment_CheckForError(self->connection->environment, status,
"ObjectType_Initialize(): get name") < 0)
return -1;
self->name = cxString_FromEncodedString(name, size,
self->environment->encoding);
self->connection->environment->encoding);
if (!self->name)
return -1;
// retrieve TDO of the parameter
status = OCIAttrGet(param, OCI_HTYPE_DESCRIBE, (dvoid*) &tdoReference, 0,
OCI_ATTR_REF_TDO, self->environment->errorHandle);
if (Environment_CheckForError(self->environment, status,
OCI_ATTR_REF_TDO, self->connection->environment->errorHandle);
if (Environment_CheckForError(self->connection->environment, status,
"ObjectType_Initialize(): get TDO reference") < 0)
return -1;
status = OCIObjectPin(self->environment->handle,
self->environment->errorHandle, tdoReference, NULL, OCI_PIN_ANY,
OCI_DURATION_SESSION, OCI_LOCK_NONE, (dvoid**) &self->tdo);
if (Environment_CheckForError(self->environment, status,
status = OCIObjectPin(self->connection->environment->handle,
self->connection->environment->errorHandle, tdoReference, NULL,
OCI_PIN_ANY, OCI_DURATION_SESSION, OCI_LOCK_NONE,
(dvoid**) &self->tdo);
if (Environment_CheckForError(self->connection->environment, status,
"ObjectType_Initialize(): pin TDO reference") < 0)
return -1;
// acquire a describe handle
status = OCIHandleAlloc(self->environment->handle,
status = OCIHandleAlloc(self->connection->environment->handle,
(dvoid**) &describeHandle, OCI_HTYPE_DESCRIBE, 0, 0);
if (Environment_CheckForError(self->environment, status,
if (Environment_CheckForError(self->connection->environment, status,
"ObjectType_Initialize(): allocate describe handle") < 0)
return -1;
// describe the type
if (ObjectType_Describe(self, connection, describeHandle) < 0)
if (ObjectType_Describe(self, describeHandle) < 0)
return -1;
// free the describe handle
status = OCIHandleFree(describeHandle, OCI_HTYPE_DESCRIBE);
if (Environment_CheckForError(self->environment, status,
if (Environment_CheckForError(self->connection->environment, status,
"ObjectType_Initialize(): free describe handle") < 0)
return -1;
@ -361,9 +371,9 @@ static udt_ObjectType *ObjectType_New(
self = (udt_ObjectType*) g_ObjectTypeType.tp_alloc(&g_ObjectTypeType, 0);
if (!self)
return NULL;
Py_INCREF(connection->environment);
self->environment = connection->environment;
if (ObjectType_Initialize(self, connection, param, nameAttribute) < 0) {
Py_INCREF(connection);
self->connection = connection;
if (ObjectType_Initialize(self, param, nameAttribute) < 0) {
Py_DECREF(self);
return NULL;
}
@ -443,9 +453,9 @@ static void ObjectType_Free(
udt_ObjectType *self) // object type to free
{
if (self->tdo)
OCIObjectUnpin(self->environment->handle,
self->environment->errorHandle, self->tdo);
Py_CLEAR(self->environment);
OCIObjectUnpin(self->connection->environment->handle,
self->connection->environment->errorHandle, self->tdo);
Py_CLEAR(self->connection);
Py_CLEAR(self->schema);
Py_CLEAR(self->name);
Py_CLEAR(self->attributes);
@ -486,6 +496,38 @@ static PyObject *ObjectType_Repr(
}
//-----------------------------------------------------------------------------
// ObjectType_NewObject()
// Factory function for creating objects of the type which can be bound.
//-----------------------------------------------------------------------------
static PyObject *ObjectType_NewObject(
udt_ObjectType *self, // object type to return the string for
PyObject *args) // arguments (none, ignored)
{
dvoid *instance, *indicator;
sword status;
// create the object instance
status = OCIObjectNew(self->connection->environment->handle,
self->connection->environment->errorHandle,
self->connection->handle, OCI_TYPECODE_OBJECT, self->tdo, NULL,
OCI_DURATION_SESSION, TRUE, &instance);
if (Environment_CheckForError(self->connection->environment, status,
"ObjectType_NewObject(): create object instance") < 0)
return NULL;
// get the null indicator structure
status = OCIObjectGetInd(self->connection->environment->handle,
self->connection->environment->errorHandle, instance, &indicator);
if (Environment_CheckForError(self->connection->environment, status,
"ObjectType_NewObject(): get indicator structure") < 0)
return NULL;
return Object_New(self, instance, indicator, 1);
}
static PyObject *ObjectType_NewObject(udt_ObjectType*, PyObject*);
//-----------------------------------------------------------------------------
// ObjectAttribute_Initialize()
// Initialize the new object attribute.

View File

@ -4,7 +4,6 @@
//-----------------------------------------------------------------------------
#include "ObjectType.c"
#include "Object.c"
//-----------------------------------------------------------------------------
// Object type
@ -23,9 +22,11 @@ typedef struct {
//-----------------------------------------------------------------------------
static int ObjectVar_Initialize(udt_ObjectVar*, udt_Cursor*);
static void ObjectVar_Finalize(udt_ObjectVar*);
static int ObjectVar_SetValue(udt_ObjectVar*, unsigned, PyObject*);
static PyObject *ObjectVar_GetValue(udt_ObjectVar*, unsigned);
static int ObjectVar_PreDefine(udt_ObjectVar*, OCIParam*);
static int ObjectVar_PostDefine(udt_ObjectVar*);
static int ObjectVar_PostBind(udt_ObjectVar*);
static int ObjectVar_PreFetch(udt_ObjectVar*);
static int ObjectVar_IsNull(udt_ObjectVar*, unsigned);
@ -82,9 +83,10 @@ static udt_VariableType vt_Object = {
(FinalizeProc) ObjectVar_Finalize,
(PreDefineProc) ObjectVar_PreDefine,
(PostDefineProc) ObjectVar_PostDefine,
(PostBindProc) ObjectVar_PostBind,
(PreFetchProc) ObjectVar_PreFetch,
(IsNullProc) ObjectVar_IsNull,
(SetValueProc) NULL,
(SetValueProc) ObjectVar_SetValue,
(GetValueProc) ObjectVar_GetValue,
(GetBufferSizeProc) NULL,
&g_ObjectVarType, // Python type
@ -142,8 +144,9 @@ static void ObjectVar_Finalize(
ub4 i;
for (i = 0; i < self->allocatedElements; i++) {
Py_CLEAR(self->objects[i]);
if (self->data[i])
if (self->objects[i])
Py_CLEAR(self->objects[i]);
else if (self->data[i])
OCIObjectFree(self->environment->handle,
self->environment->errorHandle, self->data[i],
OCI_DEFAULT);
@ -190,6 +193,22 @@ static int ObjectVar_PostDefine(
}
//-----------------------------------------------------------------------------
// ObjectVar_PostBind()
// Performs additional steps required for binding objects.
//-----------------------------------------------------------------------------
static int ObjectVar_PostBind(
udt_ObjectVar *self) // variable to set up
{
sword status;
status = OCIBindObject(self->bindHandle, self->environment->errorHandle,
self->objectType->tdo, self->data, 0, self->objectIndicator, 0);
return Environment_CheckForError(self->environment, status,
"ObjectVar_PostBind(): bind object");
}
//-----------------------------------------------------------------------------
// ObjectVar_PreFetch()
// Free objects prior to next fetch.
@ -224,6 +243,47 @@ static int ObjectVar_IsNull(
}
//-----------------------------------------------------------------------------
// ObjectVar_SetValue()
// Set the value of the variable.
//-----------------------------------------------------------------------------
static int ObjectVar_SetValue(
udt_ObjectVar *self, // variable to determine value for
unsigned pos, // array position
PyObject *value) // value to set
{
udt_Object *object;
// only cx_Oracle.Object values are permitted and the types must match
// if the variable doesn't have a type yet, assign it
if (Py_TYPE(value) != &g_ObjectType) {
PyErr_SetString(PyExc_TypeError, "expecting cx_Oracle.Object");
return -1;
}
object = (udt_Object*) value;
if (!self->objectType) {
Py_INCREF(object->objectType);
self->objectType = object->objectType;
} else if (object->objectType != self->objectType) {
PyErr_SetString(PyExc_TypeError,
"expecting same type as the variable itself");
return -1;
}
// eliminate prior value, if needed
if (self->objects[pos])
Py_CLEAR(self->objects[pos]);
else OCIObjectFree(self->environment->handle,
self->environment->errorHandle, self->data[pos], OCI_DEFAULT);
// set new value
Py_INCREF(value);
self->objects[pos] = value;
self->data[pos] = object->instance;
self->objectIndicator[pos] = object->indicator;
return 0;
}
//-----------------------------------------------------------------------------
// ObjectVar_GetValue()
// Returns the value stored at the given array position.
@ -245,8 +305,6 @@ static PyObject *ObjectVar_GetValue(
if (!obj)
return NULL;
self->objects[pos] = obj;
self->data[pos] = NULL;
self->objectIndicator[pos] = NULL;
}
Py_INCREF(self->objects[pos]);

View File

@ -182,6 +182,7 @@ static udt_VariableType vt_String = {
(FinalizeProc) NULL,
(PreDefineProc) NULL,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) NULL,
(IsNullProc) NULL,
(SetValueProc) StringVar_SetValue,
@ -203,6 +204,7 @@ static udt_VariableType vt_NationalCharString = {
(FinalizeProc) NULL,
(PreDefineProc) NULL,
(PostDefineProc) StringVar_PostDefine,
(PostBindProc) NULL,
(PreFetchProc) NULL,
(IsNullProc) NULL,
(SetValueProc) StringVar_SetValue,
@ -224,6 +226,7 @@ static udt_VariableType vt_FixedChar = {
(FinalizeProc) NULL,
(PreDefineProc) NULL,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) NULL,
(IsNullProc) NULL,
(SetValueProc) StringVar_SetValue,
@ -245,6 +248,7 @@ static udt_VariableType vt_FixedNationalChar = {
(FinalizeProc) NULL,
(PreDefineProc) NULL,
(PostDefineProc) StringVar_PostDefine,
(PostBindProc) NULL,
(PreFetchProc) NULL,
(IsNullProc) NULL,
(SetValueProc) StringVar_SetValue,
@ -266,6 +270,7 @@ static udt_VariableType vt_Rowid = {
(FinalizeProc) NULL,
(PreDefineProc) NULL,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) NULL,
(IsNullProc) NULL,
(SetValueProc) StringVar_SetValue,
@ -287,6 +292,7 @@ static udt_VariableType vt_Binary = {
(FinalizeProc) NULL,
(PreDefineProc) NULL,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) NULL,
(IsNullProc) NULL,
(SetValueProc) StringVar_SetValue,

View File

@ -57,6 +57,7 @@ static udt_VariableType vt_Timestamp = {
(FinalizeProc) TimestampVar_Finalize,
(PreDefineProc) NULL,
(PostDefineProc) NULL,
(PostBindProc) NULL,
(PreFetchProc) NULL,
(IsNullProc) NULL,
(SetValueProc) TimestampVar_SetValue,
@ -122,39 +123,8 @@ static int TimestampVar_SetValue(
unsigned pos, // array position to set
PyObject *value) // value to set
{
sword status;
uword valid;
// make sure a timestamp is being bound
if (!PyDateTime_Check(value)) {
PyErr_SetString(PyExc_TypeError, "expecting timestamp data");
return -1;
}
// store a copy of the value
status = OCIDateTimeConstruct(var->environment->handle,
var->environment->errorHandle, var->data[pos],
(sb2) PyDateTime_GET_YEAR(value),
PyDateTime_GET_MONTH(value),
PyDateTime_GET_DAY(value),
PyDateTime_DATE_GET_HOUR(value),
PyDateTime_DATE_GET_MINUTE(value),
PyDateTime_DATE_GET_SECOND(value),
PyDateTime_DATE_GET_MICROSECOND(value) * 1000, NULL, 0);
if (Environment_CheckForError(var->environment, status,
"TimestampVar_SetValue(): create structure") < 0)
return -1;
status = OCIDateTimeCheck(var->environment->handle,
var->environment->errorHandle, var->data[pos], &valid);
if (Environment_CheckForError(var->environment, status,
"TimestampVar_SetValue()") < 0)
return -1;
if (valid != 0) {
PyErr_SetString(g_DataErrorException, "invalid date");
return -1;
}
return 0;
return PythonDateToOracleTimestamp(var->environment, value,
var->data[pos]);
}

View File

@ -96,3 +96,335 @@ static PyObject *OracleNumberToPythonFloat(
return PyFloat_FromDouble(doubleValue);
}
//-----------------------------------------------------------------------------
// PythonBooleanToOracleNumber()
// Transform a Python boolean into an Oracle number.
//-----------------------------------------------------------------------------
static int PythonBooleanToOracleNumber(
udt_Environment *environment, // environment
PyObject *pythonValue, // Python value to convert
OCINumber *oracleValue) // Oracle value to set
{
long integerValue;
sword status;
integerValue = (pythonValue == Py_True);
status = OCINumberFromInt(environment->errorHandle, &integerValue,
sizeof(long), OCI_NUMBER_SIGNED, oracleValue);
return Environment_CheckForError(environment, status,
"PythonBooleanToOracleNumber()");
}
//-----------------------------------------------------------------------------
// PythonDateToOracleDate()
// Transform a Python date into an Oracle date.
//-----------------------------------------------------------------------------
static int PythonDateToOracleDate(
PyObject *pythonValue, // Python value to convert
OCIDate *oracleValue) // Oracle value to set
{
ub1 month, day, hour, minute, second;
sb2 year;
if (PyDateTime_Check(pythonValue)) {
year = (short) PyDateTime_GET_YEAR(pythonValue);
month = PyDateTime_GET_MONTH(pythonValue);
day = PyDateTime_GET_DAY(pythonValue);
hour = PyDateTime_DATE_GET_HOUR(pythonValue);
minute = PyDateTime_DATE_GET_MINUTE(pythonValue);
second = PyDateTime_DATE_GET_SECOND(pythonValue);
} else if (PyDate_Check(pythonValue)) {
year = (short) PyDateTime_GET_YEAR(pythonValue);
month = PyDateTime_GET_MONTH(pythonValue);
day = PyDateTime_GET_DAY(pythonValue);
hour = minute = second = 0;
} else {
PyErr_SetString(PyExc_TypeError, "expecting date data");
return -1;
}
OCIDateSetDate(oracleValue, year, month, day);
OCIDateSetTime(oracleValue, hour, minute, second);
return 0;
}
#if PY_MAJOR_VERSION < 3
//-----------------------------------------------------------------------------
// PythonIntegerToOracleNumber()
// Transform a Python integer into an Oracle number.
//-----------------------------------------------------------------------------
static int PythonIntegerToOracleNumber(
udt_Environment *environment, // environment
PyObject *pythonValue, // Python value to convert
OCINumber *oracleValue) // Oracle value to set
{
long integerValue;
sword status;
integerValue = PyInt_AS_LONG(pythonValue);
status = OCINumberFromInt(environment->errorHandle, &integerValue,
sizeof(long), OCI_NUMBER_SIGNED, oracleValue);
return Environment_CheckForError(environment, status,
"PythonIntegerToOracleNumber()");
}
#endif
//-----------------------------------------------------------------------------
// PythonFloatToOracleNumber()
// Transform a Python float into an Oracle number.
//-----------------------------------------------------------------------------
static int PythonFloatToOracleNumber(
udt_Environment *environment, // environment
PyObject *pythonValue, // Python value to convert
OCINumber *oracleValue) // Oracle value to set
{
double doubleValue;
sword status;
doubleValue = PyFloat_AS_DOUBLE(pythonValue);
status = OCINumberFromReal(environment->errorHandle, &doubleValue,
sizeof(double), oracleValue);
return Environment_CheckForError(environment, status,
"PythonFloatToOracleNumber()");
}
//-----------------------------------------------------------------------------
// PythonLongToOracleNumber()
// Set the value of the variable from a Python long.
//-----------------------------------------------------------------------------
static int PythonLongToOracleNumber(
udt_Environment *environment, // environment
PyObject *pythonValue, // Python value to convert
OCINumber *oracleValue) // Oracle value to set
{
udt_Buffer textBuffer;
PyObject *textValue;
sword status;
textValue = PyObject_Str(pythonValue);
if (!textValue)
return -1;
if (cxBuffer_FromObject(&textBuffer, textValue, environment->encoding) < 0)
return -1;
status = OCINumberFromText(environment->errorHandle,
(text*) textBuffer.ptr, textBuffer.size,
(text*) environment->numberFromStringFormatBuffer.ptr,
environment->numberFromStringFormatBuffer.size, NULL, 0,
oracleValue);
cxBuffer_Clear(&textBuffer);
Py_DECREF(textValue);
return Environment_CheckForError(environment, status,
"PythonLongToOracleNumber()");
}
//-----------------------------------------------------------------------------
// GetFormatAndTextFromPythonDecimal()
// Return the number format and text to use for the Decimal object.
//-----------------------------------------------------------------------------
static int GetFormatAndTextFromPythonDecimal(
PyObject *tupleValue, // decimal as_tuple() value
PyObject **textObj, // text string for conversion
PyObject **formatObj) // format for conversion
{
long numDigits, scale, i, sign, length, digit;
char *textValue, *format, *textPtr, *formatPtr;
PyObject *digits;
// acquire basic information from the value tuple
sign = PyInt_AsLong(PyTuple_GET_ITEM(tupleValue, 0));
if (PyErr_Occurred())
return -1;
digits = PyTuple_GET_ITEM(tupleValue, 1);
scale = PyInt_AsLong(PyTuple_GET_ITEM(tupleValue, 2));
if (PyErr_Occurred())
return -1;
numDigits = PyTuple_GET_SIZE(digits);
// allocate memory for the string and format to use in conversion
length = numDigits + abs(scale) + 3;
textValue = textPtr = PyMem_Malloc(length);
if (!textValue) {
PyErr_NoMemory();
return -1;
}
format = formatPtr = PyMem_Malloc(length);
if (!format) {
PyMem_Free(textValue);
PyErr_NoMemory();
return -1;
}
// populate the string and format
if (sign)
*textPtr++ = '-';
for (i = 0; i < numDigits + scale; i++) {
*formatPtr++ = '9';
if (i < numDigits) {
digit = PyInt_AsLong(PyTuple_GetItem(digits, i));
if (PyErr_Occurred()) {
PyMem_Free(textValue);
return -1;
}
}
else digit = 0;
*textPtr++ = '0' + (char) digit;
}
if (scale < 0) {
*formatPtr++ = 'D';
*textPtr++ = '.';
for (i = scale; i < 0; i++) {
*formatPtr++ = '9';
if (numDigits + i < 0)
digit = 0;
else {
digit = PyInt_AsLong(PyTuple_GetItem(digits, numDigits + i));
if (PyErr_Occurred()) {
PyMem_Free(textValue);
return -1;
}
}
*textPtr++ = '0' + (char) digit;
}
}
*formatPtr = '\0';
*textPtr = '\0';
*textObj = cxString_FromAscii(textValue);
PyMem_Free(textValue);
if (!*textObj) {
PyMem_Free(format);
return -1;
}
*formatObj = cxString_FromAscii(format);
PyMem_Free(format);
if (!*formatObj) {
Py_DECREF(*textObj);
return -1;
}
return 0;
}
//-----------------------------------------------------------------------------
// PythonDecimalToOracleNumber()
// Transform a Python decimal object into an Oracle number.
//-----------------------------------------------------------------------------
static int PythonDecimalToOracleNumber(
udt_Environment *environment, // environment
PyObject *pythonValue, // Python value to convert
OCINumber *oracleValue) // Oracle value to set
{
PyObject *textValue, *format, *tupleValue;
udt_Buffer textBuffer, formatBuffer;
sword status;
tupleValue = PyObject_CallMethod(pythonValue, "as_tuple", NULL);
if (!tupleValue)
return -1;
if (GetFormatAndTextFromPythonDecimal(tupleValue, &textValue,
&format) < 0) {
Py_DECREF(tupleValue);
return -1;
}
Py_DECREF(tupleValue);
if (cxBuffer_FromObject(&textBuffer, textValue, environment->encoding) < 0)
return -1;
if (cxBuffer_FromObject(&formatBuffer, format,
environment->encoding) < 0) {
cxBuffer_Clear(&textBuffer);
return -1;
}
status = OCINumberFromText(environment->errorHandle,
(text*) textBuffer.ptr, textBuffer.size, (text*) formatBuffer.ptr,
formatBuffer.size, environment->nlsNumericCharactersBuffer.ptr,
environment->nlsNumericCharactersBuffer.size, oracleValue);
cxBuffer_Clear(&textBuffer);
cxBuffer_Clear(&formatBuffer);
Py_DECREF(textValue);
Py_DECREF(format);
return Environment_CheckForError(environment, status,
"PythonDecimalToOracleNumber()");
}
//-----------------------------------------------------------------------------
// PythonNumberToOracleNumber()
// Convert a Python number to an Oracle number.
//-----------------------------------------------------------------------------
static int PythonNumberToOracleNumber(
udt_Environment *environment, // environment
PyObject *pythonValue, // Python value
OCINumber* oracleValue) // Oracle value
{
#if PY_MAJOR_VERSION < 3
if (PyInt_Check(pythonValue))
return PythonIntegerToOracleNumber(environment, pythonValue,
oracleValue);
#endif
if (PyBool_Check(pythonValue))
return PythonBooleanToOracleNumber(environment, pythonValue,
oracleValue);
if (PyLong_Check(pythonValue))
return PythonLongToOracleNumber(environment, pythonValue, oracleValue);
if (PyFloat_Check(pythonValue))
return PythonFloatToOracleNumber(environment, pythonValue,
oracleValue);
if (Py_TYPE(pythonValue) == g_DecimalType)
return PythonDecimalToOracleNumber(environment, pythonValue,
oracleValue);
PyErr_SetString(PyExc_TypeError, "expecting numeric data");
return -1;
}
//-----------------------------------------------------------------------------
// PythonDateToOracleTimestamp()
// Convert a Python date to an Oracle timestamp.
//-----------------------------------------------------------------------------
static int PythonDateToOracleTimestamp(
udt_Environment *environment, // environment
PyObject *pythonValue, // Python value
OCIDateTime* oracleValue) // Oracle value
{
sword status;
uword valid;
// make sure a timestamp is being bound
if (!PyDateTime_Check(pythonValue)) {
PyErr_SetString(PyExc_TypeError, "expecting timestamp data");
return -1;
}
// store a copy of the value
status = OCIDateTimeConstruct(environment->handle,
environment->errorHandle, oracleValue,
(sb2) PyDateTime_GET_YEAR(pythonValue),
PyDateTime_GET_MONTH(pythonValue),
PyDateTime_GET_DAY(pythonValue),
PyDateTime_DATE_GET_HOUR(pythonValue),
PyDateTime_DATE_GET_MINUTE(pythonValue),
PyDateTime_DATE_GET_SECOND(pythonValue),
PyDateTime_DATE_GET_MICROSECOND(pythonValue) * 1000, NULL, 0);
if (Environment_CheckForError(environment, status,
"PythonDateToOracleTimestamp(): create structure") < 0)
return -1;
status = OCIDateTimeCheck(environment->handle, environment->errorHandle,
oracleValue, &valid);
if (Environment_CheckForError(environment, status,
"PythonDateToOracleTimestamp(): check validity") < 0)
return -1;
if (valid != 0) {
PyErr_SetString(g_DataErrorException, "invalid date");
return -1;
}
return 0;
}

View File

@ -53,6 +53,7 @@ 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 (*PostBindProc)(udt_Variable*);
typedef int (*PreFetchProc)(udt_Variable*);
typedef int (*IsNullProc)(udt_Variable*, unsigned);
typedef int (*SetValueProc)(udt_Variable*, unsigned, PyObject*);
@ -68,6 +69,7 @@ typedef struct _udt_VariableType {
FinalizeProc finalizeProc;
PreDefineProc preDefineProc;
PostDefineProc postDefineProc;
PostBindProc postBindProc;
PreFetchProc preFetchProc;
IsNullProc isNullProc;
SetValueProc setValueProc;
@ -371,6 +373,7 @@ static int Variable_Check(
Py_TYPE(object) == &g_BinaryVarType ||
Py_TYPE(object) == &g_TimestampVarType ||
Py_TYPE(object) == &g_IntervalVarType ||
Py_TYPE(object) == &g_ObjectVarType ||
#if ORACLE_VERSION_HEX >= ORACLE_VERSION(12,1)
Py_TYPE(object) == &g_BooleanVarType ||
#endif
@ -461,6 +464,8 @@ static udt_VariableType *Variable_TypeByPythonType(
return &vt_NativeInteger;
if (type == (PyObject*) &g_ObjectVarType)
return &vt_Object;
if (type == (PyObject*) &g_ObjectType)
return &vt_Object;
PyErr_SetString(g_NotSupportedErrorException,
"Variable_TypeByPythonType(): unhandled data type");
@ -538,6 +543,8 @@ static udt_VariableType *Variable_TypeByValue(
return &vt_DateTime;
if (Py_TYPE(value) == g_DecimalType)
return &vt_NumberAsString;
if (Py_TYPE(value) == &g_ObjectType)
return &vt_Object;
// handle arrays
if (PyList_Check(value)) {
@ -1119,6 +1126,12 @@ static int Variable_InternalBind(
return -1;
}
// call the procedure to set values after define
if (var->type->postBindProc) {
if ((*var->type->postBindProc)(var) < 0)
return -1;
}
return 0;
}

View File

@ -169,6 +169,19 @@ Connection Object
available in Python 2.x when not built in unicode mode.
.. method:: Connection.gettype(name)
Return a type object (:ref:`objecttype`) given its name. This can then be
used to create objects which can be bound to cursors created by this
connection.
.. versionadded:: development
.. note::
This method is an extension to the DB API definition.
.. attribute:: Connection.inputtypehandler
This read-write attribute specifies a method called for each value that is

View File

@ -490,9 +490,7 @@ Cursor Object
outconverter specify methods used for converting values to/from the
database. More information can be found in the section on variable objects.
To create an empty SQL object variable, specify the typename. Additional
support for editing the attributes of this object is not yet available but
will be forthcoming in a future release.
To create an empty SQL object variable, specify the typename.
This method was designed for use with PL/SQL in/out variables where the
length or type cannot be determined automatically from the Python object

View File

@ -21,6 +21,7 @@ Contents:
session_pool.rst
subscription.rst
lob.rst
objecttype.rst
releasenotes.rst
license.rst

35
doc/objecttype.rst Normal file
View File

@ -0,0 +1,35 @@
.. _objecttype:
*******************
Object Type Objects
*******************
.. note::
This object is an extension to the DB API. It is returned by the
:meth:`~Connection.gettype()` call and is available as the
:data:`~Variable.type` for variables containing Oracle objects.
.. attribute:: ObjectType.attributes
This read-only attribute returns a list of the attributes that make up the
object type. Each attribute has a name attribute on it.
.. attribute:: ObjectType.name
This read-only attribute returns the name of the type.
.. method:: ObjectType.newobject()
Return a new Oracle object of the given type. This object can then be
modified by setting its attributes and then bound to a cursor for
interaction with Oracle.
.. attribute:: ObjectType.schema
This read-only attribute returns the name of the schema that owns the type.

View File

@ -73,3 +73,10 @@ Variable Objects
value is the size in characters. For all others, this is same value as the
attribute bufferSize.
.. attribute:: Variable.type
This read-only attribute returns the type of the variable for those
variables that bind Oracle objects (it is not present for any other type of
variable).