Renamed ExternalObjectVar to Object since it will be independent of variables;

removed limitation for retrieving the object from the variable only once.
This commit is contained in:
Anthony Tuininga 2016-02-08 12:16:28 -07:00
parent 4e1c26a3dc
commit 371717623b
4 changed files with 110 additions and 97 deletions

View File

@ -1,49 +1,45 @@
//-----------------------------------------------------------------------------
// ExternalObjectVar.c
// Defines the routines for handling object variables external to this
// module.
// Object.c
// Defines the routines for handling objects in Oracle.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// external Object type
// object type
//-----------------------------------------------------------------------------
typedef struct {
PyObject_HEAD
PyObject *referencedObject;
udt_ObjectType *objectType;
dvoid *instance;
dvoid *indicator;
int isIndependent;
} udt_ExternalObjectVar;
} udt_Object;
//-----------------------------------------------------------------------------
// Declaration of external object variable functions.
//-----------------------------------------------------------------------------
static void ExternalObjectVar_Free(udt_ExternalObjectVar*);
static PyObject *ExternalObjectVar_GetAttr(udt_ExternalObjectVar*, PyObject*);
static PyObject *ExternalObjectVar_ConvertToPython(udt_Environment*,
OCITypeCode, dvoid*, dvoid*, PyObject*, udt_ObjectType*);
static void Object_Free(udt_Object*);
static PyObject *Object_GetAttr(udt_Object*, PyObject*);
static PyObject *Object_ConvertToPython(udt_Environment*, OCITypeCode, dvoid*,
dvoid*, udt_ObjectType*);
//-----------------------------------------------------------------------------
// Declaration of external object variable members.
//-----------------------------------------------------------------------------
static PyMemberDef g_ExternalObjectVarMembers[] = {
{ "type", T_OBJECT, offsetof(udt_ExternalObjectVar, objectType),
READONLY },
static PyMemberDef g_ObjectMembers[] = {
{ "type", T_OBJECT, offsetof(udt_Object, objectType), READONLY },
{ NULL }
};
//-----------------------------------------------------------------------------
// Python type declaration
//-----------------------------------------------------------------------------
static PyTypeObject g_ExternalObjectVarType = {
static PyTypeObject g_ObjectType = {
PyVarObject_HEAD_INIT(NULL, 0)
"cx_Oracle.Object", // tp_name
sizeof(udt_ExternalObjectVar), // tp_basicsize
sizeof(udt_Object), // tp_basicsize
0, // tp_itemsize
(destructor) ExternalObjectVar_Free,
// tp_dealloc
(destructor) Object_Free, // tp_dealloc
0, // tp_print
0, // tp_getattr
0, // tp_setattr
@ -55,8 +51,7 @@ static PyTypeObject g_ExternalObjectVarType = {
0, // tp_hash
0, // tp_call
0, // tp_str
(getattrofunc) ExternalObjectVar_GetAttr,
// tp_getattro
(getattrofunc) Object_GetAttr, // tp_getattro
0, // tp_setattro
0, // tp_as_buffer
Py_TPFLAGS_DEFAULT, // tp_flags
@ -68,29 +63,25 @@ static PyTypeObject g_ExternalObjectVarType = {
0, // tp_iter
0, // tp_iternext
0, // tp_methods
g_ExternalObjectVarMembers // tp_members
g_ObjectMembers // tp_members
};
//-----------------------------------------------------------------------------
// ExternalObjectVar_New()
// Create a new external LOB variable.
// Object_New()
// Create a new object.
//-----------------------------------------------------------------------------
PyObject *ExternalObjectVar_New(
PyObject *referencedObject, // referenced 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_ExternalObjectVar *self;
udt_Object *self;
self = (udt_ExternalObjectVar*)
g_ExternalObjectVarType.tp_alloc(&g_ExternalObjectVarType, 0);
self = (udt_Object*) g_ObjectType.tp_alloc(&g_ObjectType, 0);
if (!self)
return NULL;
Py_INCREF(referencedObject);
self->referencedObject = referencedObject;
Py_INCREF(objectType);
self->objectType = objectType;
self->instance = instance;
@ -101,31 +92,29 @@ PyObject *ExternalObjectVar_New(
//-----------------------------------------------------------------------------
// ExternalObjectVar_Free()
// Free an external LOB variable.
// Object_Free()
// Free an object.
//-----------------------------------------------------------------------------
static void ExternalObjectVar_Free(
udt_ExternalObjectVar *self) // variable to free
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);
Py_CLEAR(self->objectType);
Py_CLEAR(self->referencedObject);
Py_TYPE(self)->tp_free((PyObject*) self);
}
//-----------------------------------------------------------------------------
// ExternalObjectVar_ConvertCollectionElements()
// Object_ConvertCollectionElements()
// Convert the collection elements to Python values.
//-----------------------------------------------------------------------------
static int ExternalObjectVar_ConvertCollectionElements(
static int Object_ConvertCollectionElements(
udt_Environment *environment, // environment to use
OCIIter *iter, // iterator
PyObject *list, // list result
PyObject *referencedObject, // referenced object
udt_ObjectType *objectType) // collection type information
{
dvoid *elementValue, *elementIndicator;
@ -137,13 +126,13 @@ static int ExternalObjectVar_ConvertCollectionElements(
status = OCIIterNext(environment->handle, environment->errorHandle,
iter, &elementValue, &elementIndicator, &endOfCollection);
if (Environment_CheckForError(environment, status,
"ExternalObjectVar_ConvertCollection(): get next") < 0)
"Object_ConvertCollection(): get next") < 0)
return -1;
if (endOfCollection)
break;
elementObject = ExternalObjectVar_ConvertToPython(environment,
elementObject = Object_ConvertToPython(environment,
objectType->elementTypeCode, elementValue, elementIndicator,
referencedObject, (udt_ObjectType*) objectType->elementType);
(udt_ObjectType*) objectType->elementType);
if (!elementObject)
return -1;
if (PyList_Append(list, elementObject) < 0) {
@ -158,13 +147,12 @@ static int ExternalObjectVar_ConvertCollectionElements(
//-----------------------------------------------------------------------------
// ExternalObjectVar_ConvertCollection()
// Object_ConvertCollection()
// Convert a collection to a Python list.
//-----------------------------------------------------------------------------
static PyObject *ExternalObjectVar_ConvertCollection(
static PyObject *Object_ConvertCollection(
udt_Environment *environment, // environment to use
OCIColl *collectionValue, // collection value
PyObject *referencedObject, // referenced object
udt_ObjectType *objectType) // collection type information
{
PyObject *list;
@ -176,14 +164,14 @@ static PyObject *ExternalObjectVar_ConvertCollection(
status = OCIIterCreate(environment->handle, environment->errorHandle,
collectionValue, &iter);
if (Environment_CheckForError(environment, status,
"ExternalObjectVar_ConvertCollection(): creating iterator") < 0)
"Object_ConvertCollection(): creating iterator") < 0)
return NULL;
// create the result list
list = PyList_New(0);
if (list) {
result = ExternalObjectVar_ConvertCollectionElements(environment, iter,
list, referencedObject, objectType);
result = Object_ConvertCollectionElements(environment, iter,
list, objectType);
if (result < 0) {
Py_DECREF(list);
list = NULL;
@ -196,15 +184,14 @@ static PyObject *ExternalObjectVar_ConvertCollection(
//-----------------------------------------------------------------------------
// ExternalObjectVar_ConvertToPython()
// Object_ConvertToPython()
// Convert an Oracle value to a Python value.
//-----------------------------------------------------------------------------
static PyObject *ExternalObjectVar_ConvertToPython(
static PyObject *Object_ConvertToPython(
udt_Environment *environment, // environment to use
OCITypeCode typeCode, // type of Oracle data
dvoid *value, // Oracle value
dvoid *indicator, // null indicator
PyObject *referencedObject, // referenced object (for sub objects)
udt_ObjectType *subType) // sub type (for sub objects)
{
text *stringValue;
@ -234,25 +221,24 @@ static PyObject *ExternalObjectVar_ConvertToPython(
return OracleTimestampToPythonDate(environment,
* (OCIDateTime**) value);
case OCI_TYPECODE_OBJECT:
return ExternalObjectVar_New(referencedObject, subType, value,
indicator, 0);
return Object_New(subType, value, indicator, 0);
case OCI_TYPECODE_NAMEDCOLLECTION:
return ExternalObjectVar_ConvertCollection(environment,
* (OCIColl**) value, referencedObject, subType);
return Object_ConvertCollection(environment,
* (OCIColl**) value, subType);
};
return PyErr_Format(g_NotSupportedErrorException,
"ExternalObjectVar_GetAttributeValue(): unhandled data type %d",
"Object_GetAttributeValue(): unhandled data type %d",
typeCode);
}
//-----------------------------------------------------------------------------
// ExternalObjectVar_GetAttributeValue()
// Retrieve an attribute on the external LOB variable object.
// Object_GetAttributeValue()
// Retrieve an attribute on the object.
//-----------------------------------------------------------------------------
static PyObject *ExternalObjectVar_GetAttributeValue(
udt_ExternalObjectVar *self, // object
static PyObject *Object_GetAttributeValue(
udt_Object *self, // object
udt_ObjectAttribute *attribute) // attribute to get
{
dvoid *valueIndicator, *value;
@ -272,25 +258,24 @@ static PyObject *ExternalObjectVar_GetAttributeValue(
&scalarValueIndicator, &valueIndicator, &value, &tdo);
cxBuffer_Clear(&buffer);
if (Environment_CheckForError(self->objectType->environment, status,
"ExternalObjectVar_GetAttributeValue(): getting value") < 0)
"Object_GetAttributeValue(): getting value") < 0)
return NULL;
// determine the proper null indicator
if (!valueIndicator)
valueIndicator = &scalarValueIndicator;
return ExternalObjectVar_ConvertToPython(self->objectType->environment,
attribute->typeCode, value, valueIndicator, (PyObject*) self,
attribute->subType);
return Object_ConvertToPython(self->objectType->environment,
attribute->typeCode, value, valueIndicator, attribute->subType);
}
//-----------------------------------------------------------------------------
// ExternalObjectVar_GetAttr()
// Retrieve an attribute on the external LOB variable object.
// Object_GetAttr()
// Retrieve an attribute on object.
//-----------------------------------------------------------------------------
static PyObject *ExternalObjectVar_GetAttr(
udt_ExternalObjectVar *self, // object
static PyObject *Object_GetAttr(
udt_Object *self, // object
PyObject *nameObject) // name of attribute
{
udt_ObjectAttribute *attribute;
@ -298,7 +283,7 @@ static PyObject *ExternalObjectVar_GetAttr(
attribute = (udt_ObjectAttribute*)
PyDict_GetItem(self->objectType->attributesByName, nameObject);
if (attribute)
return ExternalObjectVar_GetAttributeValue(self, attribute);
return Object_GetAttributeValue(self, attribute);
return PyObject_GenericGetAttr( (PyObject*) self, nameObject);
}

View File

@ -4,7 +4,7 @@
//-----------------------------------------------------------------------------
#include "ObjectType.c"
#include "ExternalObjectVar.c"
#include "Object.c"
//-----------------------------------------------------------------------------
// Object type
@ -13,6 +13,7 @@ typedef struct {
Variable_HEAD
dvoid **data;
dvoid **objectIndicator;
PyObject **objects;
udt_Connection *connection;
udt_ObjectType *objectType;
} udt_ObjectVar;
@ -25,6 +26,7 @@ static void ObjectVar_Finalize(udt_ObjectVar*);
static PyObject *ObjectVar_GetValue(udt_ObjectVar*, unsigned);
static int ObjectVar_PreDefine(udt_ObjectVar*, OCIParam*);
static int ObjectVar_PostDefine(udt_ObjectVar*);
static int ObjectVar_PreFetch(udt_ObjectVar*);
static int ObjectVar_IsNull(udt_ObjectVar*, unsigned);
//-----------------------------------------------------------------------------
@ -80,7 +82,7 @@ static udt_VariableType vt_Object = {
(FinalizeProc) ObjectVar_Finalize,
(PreDefineProc) ObjectVar_PreDefine,
(PostDefineProc) ObjectVar_PostDefine,
(PreFetchProc) NULL,
(PreFetchProc) ObjectVar_PreFetch,
(IsNullProc) ObjectVar_IsNull,
(SetValueProc) NULL,
(GetValueProc) ObjectVar_GetValue,
@ -115,9 +117,16 @@ static int ObjectVar_Initialize(
PyErr_NoMemory();
return -1;
}
self->objects = PyMem_Malloc(self->allocatedElements * sizeof(PyObject*));
if (!self->objects) {
PyErr_NoMemory();
return -1;
}
for (i = 0; i < self->allocatedElements; i++) {
self->data[i] = NULL;
self->objectIndicator[i] = NULL;
self->objects[i] = NULL;
}
return 0;
}
@ -133,15 +142,18 @@ static void ObjectVar_Finalize(
ub4 i;
for (i = 0; i < self->allocatedElements; i++) {
Py_CLEAR(self->objects[i]);
if (self->data[i])
OCIObjectFree(self->environment->handle,
self->environment->errorHandle, self->data[i],
OCI_OBJECTFREE_FORCE);
OCI_DEFAULT);
}
Py_DECREF(self->connection);
Py_XDECREF(self->objectType);
Py_CLEAR(self->connection);
Py_CLEAR(self->objectType);
if (self->objectIndicator)
PyMem_Free(self->objectIndicator);
if (self->objects)
PyMem_Free(self->objects);
}
@ -178,6 +190,26 @@ static int ObjectVar_PostDefine(
}
//-----------------------------------------------------------------------------
// ObjectVar_PreFetch()
// Free objects prior to next fetch.
//-----------------------------------------------------------------------------
static int ObjectVar_PreFetch(
udt_ObjectVar *var) // variable to free
{
ub4 i;
for (i = 0; i < var->allocatedElements; i++) {
Py_CLEAR(var->objects[i]);
if (var->data[i])
OCIObjectFree(var->environment->handle,
var->environment->errorHandle, var->data[i], OCI_DEFAULT);
}
return 0;
}
//-----------------------------------------------------------------------------
// ObjectVar_IsNull()
// Returns a boolean indicating if the variable is null or not.
@ -200,27 +232,24 @@ static PyObject *ObjectVar_GetValue(
udt_ObjectVar *self, // variable to determine value for
unsigned pos) // array position
{
PyObject *var;
PyObject *obj;
// only allowed to get the value once (for now)
if (!self->data[pos]) {
PyErr_SetString(g_ProgrammingErrorException,
"variable value can only be acquired once");
return NULL;
// create the object, if needed; for collections, return a list, not the
// object itself
if (!self->objects[pos]) {
if (self->objectType->isCollection)
obj = Object_ConvertCollection(self->environment, self->data[pos],
self->objectType);
else obj = Object_New(self->objectType, self->data[pos],
self->objectIndicator[pos], 1);
if (!obj)
return NULL;
self->objects[pos] = obj;
self->data[pos] = NULL;
self->objectIndicator[pos] = NULL;
}
// for collections, return the list rather than the object
if (self->objectType->isCollection)
return ExternalObjectVar_ConvertCollection(self->environment,
self->data[pos], (PyObject*) self, self->objectType);
// for objects, return a representation of the object
var = ExternalObjectVar_New((PyObject*) self, self->objectType,
self->data[pos], self->objectIndicator[pos], 1);
if (!var)
return NULL;
self->data[pos] = NULL;
self->objectIndicator[pos] = NULL;
return var;
Py_INCREF(self->objects[pos]);
return self->objects[pos];
}

View File

@ -357,7 +357,7 @@ static PyObject *Module_Initialize(void)
MAKE_TYPE_READY(&g_ObjectTypeType);
MAKE_TYPE_READY(&g_ObjectAttributeType);
MAKE_TYPE_READY(&g_ExternalLobVarType);
MAKE_TYPE_READY(&g_ExternalObjectVarType);
MAKE_TYPE_READY(&g_ObjectType);
#if ORACLE_VERSION_HEX >= ORACLE_VERSION(10, 2)
MAKE_TYPE_READY(&g_SubscriptionType);
MAKE_TYPE_READY(&g_MessageType);

View File

@ -364,11 +364,10 @@ extension = Extension(
sources = ["cx_Oracle.c"],
depends = ["Buffer.c", "Callback.c", "Connection.c", "Cursor.c",
"CursorVar.c", "DateTimeVar.c", "Environment.c", "Error.c",
"ExternalLobVar.c", "ExternalObjectVar.c", "IntervalVar.c",
"LobVar.c", "LongVar.c", "NumberVar.c", "ObjectType.c",
"ObjectVar.c", "SessionPool.c", "StringVar.c",
"Subscription.c", "TimestampVar.c", "Transforms.c",
"Variable.c"])
"ExternalLobVar.c", "IntervalVar.c", "LobVar.c", "LongVar.c",
"NumberVar.c", "Object.c", "ObjectType.c", "ObjectVar.c",
"SessionPool.c", "StringVar.c", "Subscription.c",
"TimestampVar.c", "Transforms.c", "Variable.c"])
# perform the setup
setup(