1113 lines
41 KiB
C
1113 lines
41 KiB
C
//-----------------------------------------------------------------------------
|
|
// Object.c
|
|
// Defines the routines for handling objects in Oracle.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// object type
|
|
//-----------------------------------------------------------------------------
|
|
typedef struct {
|
|
PyObject_HEAD
|
|
udt_ObjectType *objectType;
|
|
dvoid *instance;
|
|
dvoid *indicator;
|
|
int isIndependent;
|
|
} udt_Object;
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// functions for the Python type "Object"
|
|
//-----------------------------------------------------------------------------
|
|
static void Object_Free(udt_Object*);
|
|
static PyObject *Object_GetAttr(udt_Object*, PyObject*);
|
|
static PyObject *Object_Repr(udt_Object*);
|
|
static int Object_SetAttr(udt_Object*, PyObject*, PyObject*);
|
|
static PyObject *Object_ConvertToPython(udt_Environment*, OCITypeCode, dvoid*,
|
|
dvoid*, udt_ObjectType*);
|
|
static PyObject *Object_Append(udt_Object*, PyObject*);
|
|
static PyObject *Object_AsList(udt_Object*, PyObject*);
|
|
static PyObject *Object_Copy(udt_Object*, PyObject*);
|
|
static PyObject *Object_Delete(udt_Object*, PyObject*);
|
|
static PyObject *Object_Exists(udt_Object*, PyObject*);
|
|
static PyObject *Object_Extend(udt_Object*, PyObject*);
|
|
static PyObject *Object_GetElement(udt_Object*, PyObject*);
|
|
static PyObject *Object_GetFirstIndex(udt_Object*, PyObject*);
|
|
static PyObject *Object_GetLastIndex(udt_Object*, PyObject*);
|
|
static PyObject *Object_GetNextIndex(udt_Object*, PyObject*);
|
|
static PyObject *Object_GetPrevIndex(udt_Object*, PyObject*);
|
|
static PyObject *Object_GetSize(udt_Object*, PyObject*);
|
|
static PyObject *Object_SetElement(udt_Object*, PyObject*);
|
|
static PyObject *Object_Trim(udt_Object*, PyObject*);
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// declaration of methods for Python type "Object"
|
|
//-----------------------------------------------------------------------------
|
|
static PyMethodDef g_ObjectMethods[] = {
|
|
{ "append", (PyCFunction) Object_Append, METH_VARARGS },
|
|
{ "aslist", (PyCFunction) Object_AsList, METH_NOARGS },
|
|
{ "copy", (PyCFunction) Object_Copy, METH_NOARGS },
|
|
{ "delete", (PyCFunction) Object_Delete, METH_VARARGS },
|
|
{ "exists", (PyCFunction) Object_Exists, METH_VARARGS },
|
|
{ "extend", (PyCFunction) Object_Extend, METH_VARARGS },
|
|
{ "first", (PyCFunction) Object_GetFirstIndex, METH_NOARGS },
|
|
{ "getelement", (PyCFunction) Object_GetElement, METH_VARARGS },
|
|
{ "last", (PyCFunction) Object_GetLastIndex, METH_NOARGS },
|
|
{ "next", (PyCFunction) Object_GetNextIndex, METH_VARARGS },
|
|
{ "prev", (PyCFunction) Object_GetPrevIndex, METH_VARARGS },
|
|
{ "setelement", (PyCFunction) Object_SetElement, METH_VARARGS },
|
|
{ "size", (PyCFunction) Object_GetSize, METH_NOARGS },
|
|
{ "trim", (PyCFunction) Object_Trim, METH_VARARGS },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Declaration of members for Python type "Object".
|
|
//-----------------------------------------------------------------------------
|
|
static PyMemberDef g_ObjectMembers[] = {
|
|
{ "type", T_OBJECT, offsetof(udt_Object, objectType), READONLY },
|
|
{ NULL }
|
|
};
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Python type declaration
|
|
//-----------------------------------------------------------------------------
|
|
static PyTypeObject g_ObjectType = {
|
|
PyVarObject_HEAD_INIT(NULL, 0)
|
|
"cx_Oracle.Object", // tp_name
|
|
sizeof(udt_Object), // tp_basicsize
|
|
0, // tp_itemsize
|
|
(destructor) Object_Free, // tp_dealloc
|
|
0, // tp_print
|
|
0, // tp_getattr
|
|
0, // tp_setattr
|
|
0, // tp_compare
|
|
(reprfunc) Object_Repr, // tp_repr
|
|
0, // tp_as_number
|
|
0, // tp_as_sequence
|
|
0, // tp_as_mapping
|
|
0, // tp_hash
|
|
0, // tp_call
|
|
0, // tp_str
|
|
(getattrofunc) Object_GetAttr, // tp_getattro
|
|
(setattrofunc) Object_SetAttr, // 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_ObjectMethods, // tp_methods
|
|
g_ObjectMembers // tp_members
|
|
};
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Declaration of attribute data union
|
|
//-----------------------------------------------------------------------------
|
|
typedef union {
|
|
boolean booleanValue;
|
|
int integerValue;
|
|
OCINumber numberValue;
|
|
OCIDate dateValue;
|
|
OCIDateTime *timestampValue;
|
|
OCIString *stringValue;
|
|
} udt_AttributeData;
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// AttributeData_Initialize()
|
|
// Initialize any memory required for the convert from Python calls. All
|
|
// fields checked in the free routine should be initialized.
|
|
//-----------------------------------------------------------------------------
|
|
static void AttributeData_Initialize(
|
|
udt_AttributeData *data, // data structure to initialize
|
|
OCITypeCode typeCode) // type of Oracle data
|
|
{
|
|
switch (typeCode) {
|
|
case OCI_TYPECODE_CHAR:
|
|
case OCI_TYPECODE_VARCHAR:
|
|
case OCI_TYPECODE_VARCHAR2:
|
|
data->stringValue = NULL;
|
|
break;
|
|
case OCI_TYPECODE_TIMESTAMP:
|
|
data->timestampValue = NULL;
|
|
};
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// AttributeData_Free()
|
|
// Free any memory that was allocated by the convert from Python calls.
|
|
//-----------------------------------------------------------------------------
|
|
static void AttributeData_Free(
|
|
udt_Environment *environment, // environment object
|
|
udt_AttributeData *data, // data structure to initialize
|
|
OCITypeCode typeCode) // type of Oracle data
|
|
{
|
|
switch (typeCode) {
|
|
case OCI_TYPECODE_CHAR:
|
|
case OCI_TYPECODE_VARCHAR:
|
|
case OCI_TYPECODE_VARCHAR2:
|
|
if (data->stringValue)
|
|
OCIStringResize(environment->handle, environment->errorHandle,
|
|
0, &data->stringValue);
|
|
break;
|
|
case OCI_TYPECODE_TIMESTAMP:
|
|
if (data->timestampValue)
|
|
OCIDescriptorFree(data->timestampValue, OCI_DTYPE_TIMESTAMP);
|
|
};
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Object_New()
|
|
// Create a new object.
|
|
//-----------------------------------------------------------------------------
|
|
PyObject *Object_New(
|
|
udt_ObjectType *objectType, // type of object
|
|
dvoid *instance, // object instance data
|
|
dvoid *indicator, // indicator structure
|
|
int isIndependent) // is object independent?
|
|
{
|
|
udt_Object *self;
|
|
|
|
self = (udt_Object*) g_ObjectType.tp_alloc(&g_ObjectType, 0);
|
|
if (!self)
|
|
return NULL;
|
|
Py_INCREF(objectType);
|
|
self->objectType = objectType;
|
|
self->instance = instance;
|
|
self->indicator = indicator;
|
|
self->isIndependent = isIndependent;
|
|
return (PyObject*) self;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Object_Create()
|
|
// Create a new object in the OCI.
|
|
//-----------------------------------------------------------------------------
|
|
static udt_Object *Object_Create(
|
|
udt_ObjectType *self) // type of object to create
|
|
{
|
|
dvoid *instance;
|
|
udt_Object *obj;
|
|
sword status;
|
|
|
|
// create the object instance
|
|
status = OCIObjectNew(self->connection->environment->handle,
|
|
self->connection->environment->errorHandle,
|
|
self->connection->handle, self->typeCode, self->tdo, NULL,
|
|
OCI_DURATION_SESSION, TRUE, &instance);
|
|
if (Environment_CheckForError(self->connection->environment, status,
|
|
"Object_Create(): create object instance") < 0)
|
|
return NULL;
|
|
|
|
// create the object
|
|
obj = (udt_Object*) Object_New(self, instance, NULL, 1);
|
|
if (!obj) {
|
|
OCIObjectFree(self->connection->environment->handle,
|
|
self->connection->environment->errorHandle, instance,
|
|
OCI_DEFAULT);
|
|
return NULL;
|
|
}
|
|
|
|
// get the null indicator structure
|
|
status = OCIObjectGetInd(self->connection->environment->handle,
|
|
self->connection->environment->errorHandle, instance,
|
|
&obj->indicator);
|
|
if (Environment_CheckForError(self->connection->environment, status,
|
|
"Object_Create(): get indicator structure") < 0) {
|
|
Py_DECREF(obj);
|
|
return NULL;
|
|
}
|
|
|
|
return obj;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Object_Free()
|
|
// Free an object.
|
|
//-----------------------------------------------------------------------------
|
|
static void Object_Free(
|
|
udt_Object *self) // variable to free
|
|
{
|
|
if (self->isIndependent)
|
|
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);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Object_Repr()
|
|
// Return a string representation of the object.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Object_Repr(
|
|
udt_Object *self) // object type to return the string for
|
|
{
|
|
PyObject *module, *name, *result, *format, *formatArgs;
|
|
|
|
if (GetModuleAndName(Py_TYPE(self), &module, &name) < 0)
|
|
return NULL;
|
|
format = cxString_FromAscii("<%s.%s %s.%s at %#x>");
|
|
if (!format) {
|
|
Py_DECREF(module);
|
|
Py_DECREF(name);
|
|
return NULL;
|
|
}
|
|
formatArgs = Py_BuildValue("(OOOOl)", module, name,
|
|
self->objectType->schema, self->objectType->name, self);
|
|
Py_DECREF(module);
|
|
Py_DECREF(name);
|
|
if (!formatArgs) {
|
|
Py_DECREF(format);
|
|
return NULL;
|
|
}
|
|
result = cxString_Format(format, formatArgs);
|
|
Py_DECREF(format);
|
|
Py_DECREF(formatArgs);
|
|
return result;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Object_ConvertFromPython()
|
|
// Convert a Python value to an Oracle value.
|
|
//-----------------------------------------------------------------------------
|
|
static int Object_ConvertFromPython(
|
|
udt_Environment *environment, // environment to use
|
|
PyObject *pythonValue, // Python value to convert
|
|
OCITypeCode typeCode, // type of Oracle data
|
|
udt_AttributeData *oracleValue, // Oracle value
|
|
dvoid **ociValue, // OCI value
|
|
OCIInd *ociValueIndicator, // OCI value indicator
|
|
dvoid **ociObjectIndicator, // OCI object indicator
|
|
udt_ObjectType *subType) // sub type (for sub objects)
|
|
{
|
|
udt_Object *objectValue;
|
|
udt_Buffer buffer;
|
|
sword status;
|
|
|
|
// None is treated as null
|
|
if (pythonValue == Py_None) {
|
|
*ociValueIndicator = OCI_IND_NULL;
|
|
|
|
// all other values need to be converted
|
|
} else {
|
|
|
|
*ociValueIndicator = OCI_IND_NOTNULL;
|
|
switch (typeCode) {
|
|
case OCI_TYPECODE_CHAR:
|
|
case OCI_TYPECODE_VARCHAR:
|
|
case OCI_TYPECODE_VARCHAR2:
|
|
if (cxBuffer_FromObject(&buffer, pythonValue,
|
|
environment->encoding) < 0)
|
|
return -1;
|
|
status = OCIStringAssignText(environment->handle,
|
|
environment->errorHandle, buffer.ptr,
|
|
buffer.size, &oracleValue->stringValue);
|
|
cxBuffer_Clear(&buffer);
|
|
if (Environment_CheckForError(environment, status,
|
|
"Object_ConvertFromPython(): assigning string") < 0)
|
|
return -1;
|
|
*ociValue = oracleValue->stringValue;
|
|
break;
|
|
case OCI_TYPECODE_INTEGER:
|
|
case OCI_TYPECODE_NUMBER:
|
|
if (PythonNumberToOracleNumber(environment,
|
|
pythonValue, &oracleValue->numberValue) < 0)
|
|
return -1;
|
|
*ociValue = &oracleValue->numberValue;
|
|
break;
|
|
case OCI_TYPECODE_DATE:
|
|
if (PythonDateToOracleDate(pythonValue,
|
|
&oracleValue->dateValue) < 0)
|
|
return -1;
|
|
*ociValue = &oracleValue->dateValue;
|
|
break;
|
|
case OCI_TYPECODE_TIMESTAMP:
|
|
status = OCIDescriptorAlloc(environment->handle,
|
|
(dvoid**) &oracleValue->timestampValue,
|
|
OCI_DTYPE_TIMESTAMP, 0, 0);
|
|
if (Environment_CheckForError(environment, status,
|
|
"Object_ConvertFromPython(): "
|
|
"create timestamp descriptor") < 0)
|
|
return -1;
|
|
if (PythonDateToOracleTimestamp(environment,
|
|
pythonValue, oracleValue->timestampValue) < 0)
|
|
return -1;
|
|
*ociValue = oracleValue->timestampValue;
|
|
break;
|
|
case OCI_TYPECODE_NAMEDCOLLECTION:
|
|
case OCI_TYPECODE_OBJECT:
|
|
if (Py_TYPE(pythonValue) != &g_ObjectType) {
|
|
PyErr_SetString(PyExc_TypeError,
|
|
"expecting cx_Oracle.Object");
|
|
return -1;
|
|
}
|
|
objectValue = (udt_Object*) pythonValue;
|
|
if (objectValue->objectType->tdo != subType->tdo) {
|
|
PyErr_SetString(PyExc_TypeError,
|
|
"expecting an object of the correct type");
|
|
return -1;
|
|
}
|
|
*ociValue = objectValue->instance;
|
|
*ociObjectIndicator = objectValue->indicator;
|
|
break;
|
|
#if ORACLE_VERSION_HEX >= ORACLE_VERSION(12, 1)
|
|
case OCI_TYPECODE_BOOLEAN:
|
|
if (PythonBooleanToOracleBoolean(pythonValue,
|
|
&oracleValue->booleanValue) < 0)
|
|
return -1;
|
|
*ociValue = &oracleValue->booleanValue;
|
|
break;
|
|
#endif
|
|
default:
|
|
PyErr_Format(g_NotSupportedErrorException,
|
|
"Object_ConvertFromPython(): unhandled data type %d",
|
|
typeCode);
|
|
return -1;
|
|
};
|
|
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Object_ConvertToPython()
|
|
// Convert an Oracle value to a Python value.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Object_ConvertToPython(
|
|
udt_Environment *environment, // environment to use
|
|
OCITypeCode typeCode, // type of Oracle data
|
|
dvoid *value, // Oracle value
|
|
dvoid *indicator, // null indicator
|
|
udt_ObjectType *subType) // sub type (for sub objects)
|
|
{
|
|
text *stringValue;
|
|
ub4 stringSize;
|
|
|
|
// null values returned as None
|
|
if (* (OCIInd*) indicator == OCI_IND_NULL) {
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|
|
|
|
switch (typeCode) {
|
|
case OCI_TYPECODE_CHAR:
|
|
case OCI_TYPECODE_VARCHAR:
|
|
case OCI_TYPECODE_VARCHAR2:
|
|
stringValue = OCIStringPtr(environment->handle,
|
|
* (OCIString**) value);
|
|
stringSize = OCIStringSize(environment->handle,
|
|
* (OCIString**) value);
|
|
return cxString_FromEncodedString( (char*) stringValue,
|
|
stringSize, environment->encoding);
|
|
case OCI_TYPECODE_INTEGER:
|
|
return OracleNumberToPythonInteger(environment,
|
|
(OCINumber*) value);
|
|
case OCI_TYPECODE_NUMBER:
|
|
return OracleNumberToPythonFloat(environment, (OCINumber*) value);
|
|
case OCI_TYPECODE_DATE:
|
|
return OracleDateToPythonDate(&vt_DateTime, (OCIDate*) value);
|
|
case OCI_TYPECODE_TIMESTAMP:
|
|
return OracleTimestampToPythonDate(environment,
|
|
* (OCIDateTime**) value);
|
|
case OCI_TYPECODE_OBJECT:
|
|
return Object_New(subType, value, indicator, 0);
|
|
case OCI_TYPECODE_NAMEDCOLLECTION:
|
|
return Object_New(subType, * (OCIColl**) value, indicator, 0);
|
|
#if ORACLE_VERSION_HEX >= ORACLE_VERSION(12, 1)
|
|
case OCI_TYPECODE_BOOLEAN:
|
|
return OracleBooleanToPythonBoolean((boolean*) value);
|
|
#endif
|
|
};
|
|
|
|
return PyErr_Format(g_NotSupportedErrorException,
|
|
"Object_ConvertToPython(): unhandled data type %d", typeCode);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Object_GetAttributeValue()
|
|
// Retrieve an attribute on the object.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Object_GetAttributeValue(
|
|
udt_Object *self, // object
|
|
udt_ObjectAttribute *attribute) // attribute to get
|
|
{
|
|
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,
|
|
connection->environment->encoding) < 0)
|
|
return NULL;
|
|
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(connection->environment, status,
|
|
"Object_GetAttributeValue(): getting value") < 0)
|
|
return NULL;
|
|
|
|
// determine the proper null indicator
|
|
if (!valueIndicator)
|
|
valueIndicator = &scalarValueIndicator;
|
|
|
|
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 *ociObjectIndicator, *ociValue;
|
|
udt_AttributeData attributeData;
|
|
OCIInd ociValueIndicator;
|
|
udt_Connection *connection;
|
|
udt_Buffer buffer;
|
|
sword status;
|
|
|
|
// convert from Python
|
|
ociValue = ociObjectIndicator = NULL;
|
|
connection = self->objectType->connection;
|
|
AttributeData_Initialize(&attributeData, attribute->typeCode);
|
|
if (Object_ConvertFromPython(connection->environment, value,
|
|
attribute->typeCode, &attributeData, &ociValue, &ociValueIndicator,
|
|
&ociObjectIndicator, attribute->subType) < 0) {
|
|
AttributeData_Free(connection->environment, &attributeData,
|
|
attribute->typeCode);
|
|
return -1;
|
|
}
|
|
|
|
// set the value for the attribute
|
|
if (cxBuffer_FromObject(&buffer, attribute->name,
|
|
connection->environment->encoding) < 0) {
|
|
AttributeData_Free(connection->environment, &attributeData,
|
|
attribute->typeCode);
|
|
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,
|
|
ociValueIndicator, ociObjectIndicator, ociValue);
|
|
AttributeData_Free(connection->environment, &attributeData,
|
|
attribute->typeCode);
|
|
cxBuffer_Clear(&buffer);
|
|
if (Environment_CheckForError(connection->environment, status,
|
|
"Object_SetAttributeValue(): setting value") < 0)
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Object_GetAttr()
|
|
// Retrieve an attribute on an object.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Object_GetAttr(
|
|
udt_Object *self, // object
|
|
PyObject *nameObject) // name of attribute
|
|
{
|
|
udt_ObjectAttribute *attribute;
|
|
|
|
attribute = (udt_ObjectAttribute*)
|
|
PyDict_GetItem(self->objectType->attributesByName, nameObject);
|
|
if (attribute)
|
|
return Object_GetAttributeValue(self, attribute);
|
|
|
|
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);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Object_CheckIsCollection()
|
|
// Check if the object is a collection, and if not, raise an exception. This
|
|
// is used by the collection methods below.
|
|
//-----------------------------------------------------------------------------
|
|
static int Object_CheckIsCollection(
|
|
udt_Object *self) // object
|
|
{
|
|
if (!self->objectType->isCollection) {
|
|
PyErr_SetString(PyExc_TypeError, "object is not a collection");
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Object_PopulateList()
|
|
// Convert the collection elements to Python values.
|
|
//-----------------------------------------------------------------------------
|
|
static int Object_PopulateList(
|
|
udt_Object *self, // collection iterating
|
|
OCIIter *iter, // iterator
|
|
PyObject *list) // list result
|
|
{
|
|
dvoid *elementValue, *elementIndicator;
|
|
udt_Environment *environment;
|
|
PyObject *elementObject;
|
|
boolean endOfCollection;
|
|
sword status;
|
|
|
|
environment = self->objectType->connection->environment;
|
|
while (list) {
|
|
status = OCIIterNext(environment->handle, environment->errorHandle,
|
|
iter, &elementValue, &elementIndicator, &endOfCollection);
|
|
if (Environment_CheckForError(environment, status,
|
|
"Object_PopulateList(): get next") < 0)
|
|
return -1;
|
|
if (endOfCollection)
|
|
break;
|
|
elementObject = Object_ConvertToPython(environment,
|
|
self->objectType->elementTypeCode, elementValue,
|
|
elementIndicator,
|
|
(udt_ObjectType*) self->objectType->elementType);
|
|
if (!elementObject)
|
|
return -1;
|
|
if (PyList_Append(list, elementObject) < 0) {
|
|
Py_DECREF(elementObject);
|
|
return -1;
|
|
}
|
|
Py_DECREF(elementObject);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Object_InternalAppend()
|
|
// Append an item to the collection.
|
|
//-----------------------------------------------------------------------------
|
|
static int Object_InternalAppend(
|
|
udt_Object *self, // object
|
|
PyObject *value) // value to append
|
|
{
|
|
void *elementValue, *elementIndicator;
|
|
udt_AttributeData attributeData;
|
|
udt_Environment *environment;
|
|
OCIInd tempIndicator;
|
|
sword status;
|
|
|
|
// convert Python value to OCI value
|
|
elementValue = elementIndicator = NULL;
|
|
environment = self->objectType->connection->environment;
|
|
AttributeData_Initialize(&attributeData,
|
|
self->objectType->elementTypeCode);
|
|
if (Object_ConvertFromPython(environment, value,
|
|
self->objectType->elementTypeCode, &attributeData, &elementValue,
|
|
&tempIndicator, &elementIndicator,
|
|
(udt_ObjectType*) self->objectType->elementType) < 0) {
|
|
AttributeData_Free(environment, &attributeData,
|
|
self->objectType->elementTypeCode);
|
|
return -1;
|
|
}
|
|
if (!elementIndicator)
|
|
elementIndicator = &tempIndicator;
|
|
|
|
// append converted value to collection
|
|
status = OCICollAppend(environment->handle, environment->errorHandle,
|
|
elementValue, elementIndicator, (OCIColl*) self->instance);
|
|
if (Environment_CheckForError(environment, status,
|
|
"Object_Append()") < 0) {
|
|
AttributeData_Free(environment, &attributeData,
|
|
self->objectType->elementTypeCode);
|
|
return -1;
|
|
}
|
|
AttributeData_Free(environment, &attributeData,
|
|
self->objectType->elementTypeCode);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Object_InternalExtend()
|
|
// Extend the collection by appending each of the items in the sequence.
|
|
//-----------------------------------------------------------------------------
|
|
static int Object_InternalExtend(
|
|
udt_Object *self, // object
|
|
PyObject *sequence) // sequence to extend collection with
|
|
{
|
|
PyObject *fastSequence, *element;
|
|
Py_ssize_t size, i;
|
|
|
|
// make sure we are dealing with a collection
|
|
if (Object_CheckIsCollection(self) < 0)
|
|
return -1;
|
|
|
|
// append each of the items in the sequence to the collection
|
|
fastSequence = PySequence_Fast(sequence, "expecting sequence");
|
|
if (!fastSequence)
|
|
return -1;
|
|
size = PySequence_Fast_GET_SIZE(fastSequence);
|
|
for (i = 0; i < size; i++) {
|
|
element = PySequence_Fast_GET_ITEM(fastSequence, i);
|
|
if (Object_InternalAppend(self, element) < 0)
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Object_Append()
|
|
// Append an item to the collection.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Object_Append(
|
|
udt_Object *self, // object
|
|
PyObject *args) // arguments
|
|
{
|
|
PyObject *value;
|
|
|
|
if (Object_CheckIsCollection(self) < 0)
|
|
return NULL;
|
|
if (!PyArg_ParseTuple(args, "O", &value))
|
|
return NULL;
|
|
if (Object_InternalAppend(self, value) < 0)
|
|
return NULL;
|
|
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Object_AsList()
|
|
// Returns a collection as a list of elements. If the object is not a
|
|
// collection, an error is returned.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Object_AsList(
|
|
udt_Object *self, // object
|
|
PyObject *args) // arguments (none)
|
|
{
|
|
udt_Environment *environment;
|
|
PyObject *list;
|
|
OCIIter *iter;
|
|
sword status;
|
|
|
|
// make sure this is a collection
|
|
if (Object_CheckIsCollection(self) < 0)
|
|
return NULL;
|
|
|
|
// create the iterator
|
|
environment = self->objectType->connection->environment;
|
|
status = OCIIterCreate(environment->handle, environment->errorHandle,
|
|
self->instance, &iter);
|
|
if (Environment_CheckForError(environment, status,
|
|
"Object_AsList(): creating iterator") < 0)
|
|
return NULL;
|
|
|
|
// create the result list
|
|
list = PyList_New(0);
|
|
if (list) {
|
|
if (Object_PopulateList(self, iter, list) < 0) {
|
|
Py_DECREF(list);
|
|
list = NULL;
|
|
}
|
|
}
|
|
OCIIterDelete(environment->handle, environment->errorHandle, &iter);
|
|
|
|
return list;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Object_Copy()
|
|
// Return a copy of the object.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Object_Copy(
|
|
udt_Object *self, // object
|
|
PyObject *args) // arguments (none)
|
|
{
|
|
udt_Environment *environment;
|
|
udt_Object *copiedObject;
|
|
sword status;
|
|
|
|
copiedObject = Object_Create(self->objectType);
|
|
if (!copiedObject)
|
|
return NULL;
|
|
environment = self->objectType->connection->environment;
|
|
status = OCIObjectCopy(environment->handle, environment->errorHandle,
|
|
self->objectType->connection->handle, self->instance,
|
|
self->indicator, copiedObject->instance, copiedObject->indicator,
|
|
self->objectType->tdo, OCI_DURATION_SESSION, OCI_DEFAULT);
|
|
if (Environment_CheckForError(environment, status, "Object_Copy()") < 0) {
|
|
Py_DECREF(copiedObject);
|
|
return NULL;
|
|
}
|
|
|
|
return (PyObject*) copiedObject;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Object_Delete()
|
|
// Delete the element at the specified index in the collection.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Object_Delete(
|
|
udt_Object *self, // object
|
|
PyObject *args) // arguments
|
|
{
|
|
udt_Environment *environment;
|
|
sword status;
|
|
sb4 index;
|
|
|
|
if (Object_CheckIsCollection(self) < 0)
|
|
return NULL;
|
|
if (!PyArg_ParseTuple(args, "i", &index))
|
|
return NULL;
|
|
environment = self->objectType->connection->environment;
|
|
status = OCITableDelete(environment->handle, environment->errorHandle,
|
|
index, self->instance);
|
|
if (Environment_CheckForError(environment, status, "Object_Delete()") < 0)
|
|
return NULL;
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Object_Exists()
|
|
// Return true or false indicating if an element exists in the collection at
|
|
// the specified index.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Object_Exists(
|
|
udt_Object *self, // object
|
|
PyObject *args) // arguments
|
|
{
|
|
udt_Environment *environment;
|
|
boolean exists;
|
|
sword status;
|
|
sb4 index;
|
|
|
|
if (Object_CheckIsCollection(self) < 0)
|
|
return NULL;
|
|
if (!PyArg_ParseTuple(args, "i", &index))
|
|
return NULL;
|
|
environment = self->objectType->connection->environment;
|
|
status = OCITableExists(environment->handle, environment->errorHandle,
|
|
self->instance, index, &exists);
|
|
if (Environment_CheckForError(environment, status, "Object_Exists()") < 0)
|
|
return NULL;
|
|
if (exists)
|
|
Py_RETURN_TRUE;
|
|
Py_RETURN_FALSE;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Object_Extend()
|
|
// Extend the collection by appending each of the items in the sequence.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Object_Extend(
|
|
udt_Object *self, // object
|
|
PyObject *args) // arguments
|
|
{
|
|
PyObject *sequence;
|
|
|
|
if (!PyArg_ParseTuple(args, "O", &sequence))
|
|
return NULL;
|
|
if (Object_InternalExtend(self, sequence) < 0)
|
|
return NULL;
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Object_GetElement()
|
|
// Return the element at the given position in the collection.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Object_GetElement(
|
|
udt_Object *self, // object
|
|
PyObject *args) // arguments
|
|
{
|
|
void *elementValue, *elementIndicator;
|
|
udt_Environment *environment;
|
|
boolean exists;
|
|
sb4 position;
|
|
sword status;
|
|
|
|
if (Object_CheckIsCollection(self) < 0)
|
|
return NULL;
|
|
if (!PyArg_ParseTuple(args, "i", &position))
|
|
return NULL;
|
|
environment = self->objectType->connection->environment;
|
|
status = OCICollGetElem(environment->handle, environment->errorHandle,
|
|
(OCIColl*) self->instance, (sb4) position, &exists,
|
|
&elementValue, &elementIndicator);
|
|
if (Environment_CheckForError(environment, status,
|
|
"Object_GetItem(): get element") < 0)
|
|
return NULL;
|
|
if (!exists) {
|
|
PyErr_SetString(PyExc_IndexError, "element does not exist");
|
|
return NULL;
|
|
}
|
|
return Object_ConvertToPython(environment,
|
|
self->objectType->elementTypeCode, elementValue, elementIndicator,
|
|
(udt_ObjectType*) self->objectType->elementType);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Object_GetFirstIndex()
|
|
// Return the index of the first entry in the collection.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Object_GetFirstIndex(
|
|
udt_Object *self, // object
|
|
PyObject *args) // arguments (none)
|
|
{
|
|
udt_Environment *environment;
|
|
sword status;
|
|
sb4 index;
|
|
|
|
if (Object_CheckIsCollection(self) < 0)
|
|
return NULL;
|
|
environment = self->objectType->connection->environment;
|
|
status = OCITableFirst(environment->handle, environment->errorHandle,
|
|
self->instance, &index);
|
|
if (Environment_CheckForError(environment, status,
|
|
"Object_GetFirstIndex()") < 0)
|
|
return NULL;
|
|
return PyInt_FromLong(index);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Object_GetLastIndex()
|
|
// Return the index of the last entry in the collection.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Object_GetLastIndex(
|
|
udt_Object *self, // object
|
|
PyObject *args) // arguments (none)
|
|
{
|
|
udt_Environment *environment;
|
|
sword status;
|
|
sb4 index;
|
|
|
|
if (Object_CheckIsCollection(self) < 0)
|
|
return NULL;
|
|
environment = self->objectType->connection->environment;
|
|
status = OCITableLast(environment->handle, environment->errorHandle,
|
|
self->instance, &index);
|
|
if (Environment_CheckForError(environment, status,
|
|
"Object_GetLastIndex()") < 0)
|
|
return NULL;
|
|
return PyInt_FromLong(index);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Object_GetNextIndex()
|
|
// Return the index of the next entry in the collection following the index
|
|
// specified. If there is no next entry, None is returned.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Object_GetNextIndex(
|
|
udt_Object *self, // object
|
|
PyObject *args) // arguments
|
|
{
|
|
udt_Environment *environment;
|
|
sb4 index, nextIndex;
|
|
boolean exists;
|
|
sword status;
|
|
|
|
if (Object_CheckIsCollection(self) < 0)
|
|
return NULL;
|
|
if (!PyArg_ParseTuple(args, "i", &index))
|
|
return NULL;
|
|
environment = self->objectType->connection->environment;
|
|
status = OCITableNext(environment->handle, environment->errorHandle,
|
|
index, self->instance, &nextIndex, &exists);
|
|
if (Environment_CheckForError(environment, status,
|
|
"Object_GetNextIndex()") < 0)
|
|
return NULL;
|
|
if (exists)
|
|
return PyInt_FromLong(nextIndex);
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Object_GetPrevIndex()
|
|
// Return the index of the previous entry in the collection preceding the
|
|
// index specified. If there is no previous entry, None is returned.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Object_GetPrevIndex(
|
|
udt_Object *self, // object
|
|
PyObject *args) // arguments
|
|
{
|
|
udt_Environment *environment;
|
|
sb4 index, prevIndex;
|
|
boolean exists;
|
|
sword status;
|
|
|
|
if (Object_CheckIsCollection(self) < 0)
|
|
return NULL;
|
|
if (!PyArg_ParseTuple(args, "i", &index))
|
|
return NULL;
|
|
environment = self->objectType->connection->environment;
|
|
status = OCITablePrev(environment->handle, environment->errorHandle,
|
|
index, self->instance, &prevIndex, &exists);
|
|
if (Environment_CheckForError(environment, status,
|
|
"Object_GetPrevIndex()") < 0)
|
|
return NULL;
|
|
if (exists)
|
|
return PyInt_FromLong(prevIndex);
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Object_GetSize()
|
|
// Return the size of a collection. If the object is not a collection, an
|
|
// error is returned.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Object_GetSize(
|
|
udt_Object *self, // object
|
|
PyObject *args) // arguments (none)
|
|
{
|
|
udt_Environment *environment;
|
|
sword status;
|
|
sb4 size;
|
|
|
|
if (Object_CheckIsCollection(self) < 0)
|
|
return NULL;
|
|
environment = self->objectType->connection->environment;
|
|
status = OCICollSize(environment->handle, environment->errorHandle,
|
|
(const OCIColl*) self->instance, &size);
|
|
if (Environment_CheckForError(environment, status, "Object_Size()") < 0)
|
|
return NULL;
|
|
return PyInt_FromLong(size);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Object_SetElement()
|
|
// Set the element at the specified location to the given value.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Object_SetElement(
|
|
udt_Object *self, // object
|
|
PyObject *args) // arguments
|
|
{
|
|
void *elementValue, *elementIndicator;
|
|
udt_AttributeData attributeData;
|
|
udt_Environment *environment;
|
|
OCIInd tempIndicator;
|
|
PyObject *value;
|
|
sb4 position;
|
|
sword status;
|
|
|
|
// make sure we are dealing with a collection
|
|
if (Object_CheckIsCollection(self) < 0)
|
|
return NULL;
|
|
|
|
// parse arguments
|
|
if (!PyArg_ParseTuple(args, "iO", &position, &value))
|
|
return NULL;
|
|
|
|
// convert to OCI value
|
|
elementValue = elementIndicator = NULL;
|
|
environment = self->objectType->connection->environment;
|
|
AttributeData_Initialize(&attributeData,
|
|
self->objectType->elementTypeCode);
|
|
if (Object_ConvertFromPython(environment, value,
|
|
self->objectType->elementTypeCode, &attributeData, &elementValue,
|
|
&tempIndicator, &elementIndicator,
|
|
(udt_ObjectType*) self->objectType->elementType) < 0) {
|
|
AttributeData_Free(environment, &attributeData,
|
|
self->objectType->elementTypeCode);
|
|
return NULL;
|
|
}
|
|
if (!elementIndicator)
|
|
elementIndicator = &tempIndicator;
|
|
status = OCICollAssignElem(environment->handle, environment->errorHandle,
|
|
position, elementValue, elementIndicator,
|
|
(OCIColl*) self->instance);
|
|
if (Environment_CheckForError(environment, status,
|
|
"Object_SetItem(): assign element") < 0) {
|
|
AttributeData_Free(environment, &attributeData,
|
|
self->objectType->elementTypeCode);
|
|
return NULL;
|
|
}
|
|
AttributeData_Free(environment, &attributeData,
|
|
self->objectType->elementTypeCode);
|
|
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Object_Trim()
|
|
// Trim a number of elements from the end of the collection.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *Object_Trim(
|
|
udt_Object *self, // object
|
|
PyObject *args) // arguments
|
|
{
|
|
udt_Environment *environment;
|
|
sb4 numToTrim;
|
|
sword status;
|
|
|
|
if (Object_CheckIsCollection(self) < 0)
|
|
return NULL;
|
|
if (!PyArg_ParseTuple(args, "i", &numToTrim))
|
|
return NULL;
|
|
environment = self->objectType->connection->environment;
|
|
status = OCICollTrim(environment->handle, environment->errorHandle,
|
|
numToTrim, self->instance);
|
|
if (Environment_CheckForError(environment, status, "Object_Trim()") < 0)
|
|
return NULL;
|
|
Py_RETURN_NONE;
|
|
}
|
|
|