Skip to content

Commit

Permalink
Added support for getting/setting attributes of objects or element va…
Browse files Browse the repository at this point in the history
…lues in

collections that contain LOBs, BINARY_FLOAT values, BINARY_DOUBLE values and
NCHAR and NVARCHAR2 values; improve error message for any other types that are
not supported.
  • Loading branch information
anthony-tuininga committed May 9, 2017
1 parent e5a8885 commit 51f1815
Show file tree
Hide file tree
Showing 9 changed files with 153 additions and 51 deletions.
1 change: 1 addition & 0 deletions src/Connection.c
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,7 @@ static PyObject *Connection_ChangePassword(udt_Connection *self,
}


#include "LOB.c"
#include "Cursor.c"
#include "Subscription.c"
#include "DeqOptions.c"
Expand Down
55 changes: 29 additions & 26 deletions src/LOB.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,14 @@
//-----------------------------------------------------------------------------
typedef struct {
PyObject_HEAD
udt_Variable *var;
udt_Connection *connection;
dpiOracleTypeNum oracleTypeNum;
dpiLob *handle;
} udt_LOB;


//-----------------------------------------------------------------------------
// Declaration of external LOB variable functions.
// Declaration of external LOB functions.
//-----------------------------------------------------------------------------
static void LOB_Free(udt_LOB*);
static PyObject *LOB_Str(udt_LOB*);
Expand All @@ -42,7 +43,7 @@ static PyObject *LOB_Reduce(udt_LOB*);


//-----------------------------------------------------------------------------
// declaration of methods for Python type "ExternalLOBVar"
// declaration of methods for Python type "LOB"
//-----------------------------------------------------------------------------
static PyMethodDef g_LOBMethods[] = {
{ "size", (PyCFunction) LOB_Size, METH_NOARGS },
Expand Down Expand Up @@ -111,9 +112,10 @@ static PyTypeObject g_LOBType = {

//-----------------------------------------------------------------------------
// LOB_New()
// Create a new external LOB variable.
// Create a new LOB.
//-----------------------------------------------------------------------------
PyObject *LOB_New(udt_Variable *var, dpiLob *handle)
PyObject *LOB_New(udt_Connection *connection, dpiOracleTypeNum oracleTypeNum,
dpiLob *handle)
{
udt_LOB *self;

Expand All @@ -125,23 +127,24 @@ PyObject *LOB_New(udt_Variable *var, dpiLob *handle)
return NULL;
}
self->handle = handle;
Py_INCREF(var);
self->var = var;
self->oracleTypeNum = oracleTypeNum;
Py_INCREF(connection);
self->connection = connection;
return (PyObject*) self;
}


//-----------------------------------------------------------------------------
// LOB_Free()
// Free an external LOB variable.
// Free a LOB.
//-----------------------------------------------------------------------------
static void LOB_Free(udt_LOB *self)
{
if (self->handle) {
dpiLob_release(self->handle);
self->handle = NULL;
}
Py_CLEAR(self->var);
Py_CLEAR(self->connection);
Py_TYPE(self)->tp_free((PyObject*) self);
}

Expand Down Expand Up @@ -185,12 +188,12 @@ static PyObject *LOB_InternalRead(udt_LOB *self, uint64_t offset,
}

// return the result
if (self->var->type == &vt_CLOB)
if (self->oracleTypeNum == DPI_ORACLE_TYPE_CLOB)
result = PyUnicode_Decode(buffer, bufferSize,
self->var->connection->encodingInfo.encoding, NULL);
else if (self->var->type == &vt_NCLOB)
self->connection->encodingInfo.encoding, NULL);
else if (self->oracleTypeNum == DPI_ORACLE_TYPE_NCLOB)
result = cxString_FromEncodedString(buffer, bufferSize,
self->var->connection->encodingInfo.nencoding);
self->connection->encodingInfo.nencoding);
else result = PyBytes_FromStringAndSize(buffer, bufferSize);
PyMem_Free(buffer);
return result;
Expand All @@ -207,9 +210,9 @@ static int LOB_InternalWrite(udt_LOB *self, PyObject *dataObj, uint64_t offset)
udt_Buffer buffer;
int status;

if (self->var->type == &vt_NCLOB)
encoding = self->var->connection->encodingInfo.nencoding;
else encoding = self->var->connection->encodingInfo.encoding;
if (self->oracleTypeNum == DPI_ORACLE_TYPE_NCLOB)
encoding = self->connection->encodingInfo.nencoding;
else encoding = self->connection->encodingInfo.encoding;
if (cxBuffer_FromObject(&buffer, dataObj, encoding) < 0)
return -1;
Py_BEGIN_ALLOW_THREADS
Expand All @@ -225,7 +228,7 @@ static int LOB_InternalWrite(udt_LOB *self, PyObject *dataObj, uint64_t offset)

//-----------------------------------------------------------------------------
// LOB_Size()
// Return the size of the data in the LOB variable.
// Return the size of the data in the LOB.
//-----------------------------------------------------------------------------
static PyObject *LOB_Size(udt_LOB *self, PyObject *args)
{
Expand Down Expand Up @@ -273,7 +276,7 @@ static PyObject *LOB_Close(udt_LOB *self, PyObject *args)

//-----------------------------------------------------------------------------
// LOB_Read()
// Return a portion (or all) of the data in the external LOB variable.
// Return a portion (or all) of the data in the LOB.
//-----------------------------------------------------------------------------
static PyObject *LOB_Read(udt_LOB *self, PyObject *args, PyObject *keywordArgs)
{
Expand All @@ -292,7 +295,7 @@ static PyObject *LOB_Read(udt_LOB *self, PyObject *args, PyObject *keywordArgs)

//-----------------------------------------------------------------------------
// LOB_Str()
// Return all of the data in the external LOB variable.
// Return all of the data in the LOB.
//-----------------------------------------------------------------------------
static PyObject *LOB_Str(udt_LOB *self)
{
Expand All @@ -302,7 +305,7 @@ static PyObject *LOB_Str(udt_LOB *self)

//-----------------------------------------------------------------------------
// LOB_Write()
// Write a value to the LOB variable; return the number of bytes written.
// Write a value to the LOB.
//-----------------------------------------------------------------------------
static PyObject *LOB_Write(udt_LOB *self, PyObject *args,
PyObject *keywordArgs)
Expand All @@ -323,7 +326,7 @@ static PyObject *LOB_Write(udt_LOB *self, PyObject *args,

//-----------------------------------------------------------------------------
// LOB_Trim()
// Trim the LOB variable to the specified length.
// Trim the LOB to the specified length.
//-----------------------------------------------------------------------------
static PyObject *LOB_Trim(udt_LOB *self, PyObject *args, PyObject *keywordArgs)
{
Expand All @@ -346,7 +349,7 @@ static PyObject *LOB_Trim(udt_LOB *self, PyObject *args, PyObject *keywordArgs)

//-----------------------------------------------------------------------------
// LOB_Reduce()
// Method provided for pickling/unpickling of LOB variables.
// Method provided for pickling/unpickling of LOBs.
//-----------------------------------------------------------------------------
static PyObject *LOB_Reduce(udt_LOB *self)
{
Expand Down Expand Up @@ -417,14 +420,14 @@ static PyObject *LOB_GetFileName(udt_LOB *self, PyObject *args)
if (!result)
return NULL;
temp = cxString_FromEncodedString(directoryAlias, directoryAliasLength,
self->var->connection->encodingInfo.encoding);
self->connection->encodingInfo.encoding);
if (!temp) {
Py_DECREF(result);
return NULL;
}
PyTuple_SET_ITEM(result, 0, temp);
temp = cxString_FromEncodedString(fileName, fileNameLength,
self->var->connection->encodingInfo.encoding);
self->connection->encodingInfo.encoding);
if (!temp) {
Py_DECREF(result);
return NULL;
Expand All @@ -449,10 +452,10 @@ static PyObject *LOB_SetFileName(udt_LOB *self, PyObject *args)
if (!PyArg_ParseTuple(args, "OO", &directoryAliasObj, &fileNameObj))
return NULL;
if (cxBuffer_FromObject(&directoryAliasBuffer, directoryAliasObj,
self->var->connection->encodingInfo.encoding) < 0)
self->connection->encodingInfo.encoding) < 0)
return NULL;
if (cxBuffer_FromObject(&fileNameBuffer, fileNameObj,
self->var->connection->encodingInfo.encoding) < 0) {
self->connection->encodingInfo.encoding) < 0) {
cxBuffer_Clear(&directoryAliasBuffer);
return NULL;
}
Expand Down
6 changes: 2 additions & 4 deletions src/LobVar.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,6 @@ static udt_VariableType vt_BFILE = {
};


#include "LOB.c"


//-----------------------------------------------------------------------------
// LobVar_SetValue()
// Set the value of the variable.
Expand Down Expand Up @@ -106,6 +103,7 @@ static int LobVar_SetValue(udt_Variable *var, uint32_t pos, dpiData *data,
//-----------------------------------------------------------------------------
static PyObject *LobVar_GetValue(udt_Variable *var, dpiData *data)
{
return LOB_New(var, data->value.asLOB);
return LOB_New(var->connection, var->type->oracleTypeNum,
data->value.asLOB);
}

25 changes: 19 additions & 6 deletions src/Object.c
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ static int Object_ConvertFromPython(udt_Object *obj, PyObject *value,
dpiTimestamp *timestamp;
udt_Object *otherObj;
dpiBytes *bytes;
udt_LOB *lob;

// None is treated as null
if (value == Py_None) {
Expand All @@ -201,7 +202,8 @@ static int Object_ConvertFromPython(udt_Object *obj, PyObject *value,
// convert the different Python types
data->isNull = 0;
if (PyUnicode_Check(value) || PyBytes_Check(value)) {
if (cxBuffer_FromObject(buffer, value, obj->objectType->encoding) < 0)
if (cxBuffer_FromObject(buffer, value,
obj->objectType->connection->encodingInfo.encoding) < 0)
return -1;
*nativeTypeNum = DPI_NATIVE_TYPE_BYTES;
bytes = &data->value.asBytes;
Expand Down Expand Up @@ -245,6 +247,10 @@ static int Object_ConvertFromPython(udt_Object *obj, PyObject *value,
*nativeTypeNum = DPI_NATIVE_TYPE_OBJECT;
otherObj = (udt_Object*) value;
data->value.asObject = otherObj->handle;
} else if (Py_TYPE(value) == &g_LOBType) {
*nativeTypeNum = DPI_NATIVE_TYPE_LOB;
lob = (udt_LOB*) value;
data->value.asLOB = lob->handle;
} else {
PyErr_Format(g_NotSupportedErrorException,
"Object_ConvertFromPython(): unhandled value type");
Expand All @@ -260,7 +266,8 @@ static int Object_ConvertFromPython(udt_Object *obj, PyObject *value,
// Convert an Oracle value to a Python value.
//-----------------------------------------------------------------------------
static PyObject *Object_ConvertToPython(udt_Object *obj,
dpiNativeTypeNum nativeTypeNum, dpiData *data, udt_ObjectType *objType)
dpiOracleTypeNum oracleTypeNum, dpiNativeTypeNum nativeTypeNum,
dpiData *data, udt_ObjectType *objType)
{
dpiIntervalDS *intervalDS;
dpiTimestamp *timestamp;
Expand All @@ -281,6 +288,7 @@ static PyObject *Object_ConvertToPython(udt_Object *obj,
(unsigned long) data->value.asUint64);
#endif
case DPI_NATIVE_TYPE_FLOAT:
return PyFloat_FromDouble(data->value.asFloat);
case DPI_NATIVE_TYPE_DOUBLE:
return PyFloat_FromDouble(data->value.asDouble);
case DPI_NATIVE_TYPE_BYTES:
Expand All @@ -305,6 +313,9 @@ static PyObject *Object_ConvertToPython(udt_Object *obj,
if (data->value.asBoolean)
Py_RETURN_TRUE;
Py_RETURN_FALSE;
case DPI_NATIVE_TYPE_LOB:
return LOB_New(obj->objectType->connection, oracleTypeNum,
data->value.asLOB);
default:
break;
}
Expand All @@ -326,8 +337,8 @@ static PyObject *Object_GetAttributeValue(udt_Object *self,
if (dpiObject_getAttributeValue(self->handle, attribute->handle,
attribute->nativeTypeNum, &data) < 0)
return Error_RaiseAndReturnNull();
return Object_ConvertToPython(self, attribute->nativeTypeNum, &data,
attribute->type);
return Object_ConvertToPython(self, attribute->oracleTypeNum,
attribute->nativeTypeNum, &data, attribute->type);
}


Expand Down Expand Up @@ -484,6 +495,7 @@ static PyObject *Object_AsList(udt_Object *self, PyObject *args)
return Error_RaiseAndReturnNull();
}
elementValue = Object_ConvertToPython(self,
self->objectType->elementOracleTypeNum,
self->objectType->elementNativeTypeNum, &data,
(udt_ObjectType*) self->objectType->elementType);
if (!elementValue) {
Expand Down Expand Up @@ -588,8 +600,9 @@ static PyObject *Object_GetElement(udt_Object *self, PyObject *args)
if (dpiObject_getElementValueByIndex(self->handle, index,
self->objectType->elementNativeTypeNum, &data) < 0)
return Error_RaiseAndReturnNull();
return Object_ConvertToPython(self, self->objectType->elementNativeTypeNum,
&data, (udt_ObjectType*) self->objectType->elementType);
return Object_ConvertToPython(self, self->objectType->elementOracleTypeNum,
self->objectType->elementNativeTypeNum, &data,
(udt_ObjectType*) self->objectType->elementType);
}


Expand Down
14 changes: 10 additions & 4 deletions src/ObjectType.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ typedef struct {
PyObject *name;
PyObject *attributes;
PyObject *attributesByName;
const char *encoding;
udt_Connection *connection;
dpiOracleTypeNum elementOracleTypeNum;
dpiNativeTypeNum elementNativeTypeNum;
PyObject *elementType;
char isCollection;
Expand All @@ -32,6 +33,7 @@ typedef struct {
PyObject_HEAD
PyObject *name;
dpiObjectAttr *handle;
dpiOracleTypeNum oracleTypeNum;
dpiNativeTypeNum nativeTypeNum;
udt_ObjectType *type;
} udt_ObjectAttribute;
Expand Down Expand Up @@ -190,18 +192,20 @@ static int ObjectType_Initialize(udt_ObjectType *self,
uint16_t i;

// get object type information
self->encoding = connection->encodingInfo.encoding;
if (dpiObjectType_getInfo(self->handle, &info) < 0)
return Error_RaiseAndReturnInt();
Py_INCREF(connection);
self->connection = connection;
self->schema = cxString_FromEncodedString(info.schema, info.schemaLength,
self->encoding);
connection->encodingInfo.encoding);
if (!self->schema)
return -1;
self->name = cxString_FromEncodedString(info.name, info.nameLength,
self->encoding);
connection->encodingInfo.encoding);
if (!self->name)
return -1;
self->isCollection = info.isCollection;
self->elementOracleTypeNum = info.elementOracleTypeNum;
self->elementNativeTypeNum = info.elementDefaultNativeTypeNum;
if (info.elementObjectType) {
self->elementType = (PyObject*) ObjectType_New(connection,
Expand Down Expand Up @@ -310,6 +314,7 @@ static void ObjectType_Free(udt_ObjectType *self)
dpiObjectType_release(self->handle);
self->handle = NULL;
}
Py_CLEAR(self->connection);
Py_CLEAR(self->schema);
Py_CLEAR(self->name);
Py_CLEAR(self->attributes);
Expand Down Expand Up @@ -399,6 +404,7 @@ static int ObjectAttribute_Initialize(udt_ObjectAttribute *self,

if (dpiObjectAttr_getInfo(self->handle, &info) < 0)
return Error_RaiseAndReturnInt();
self->oracleTypeNum = info.oracleTypeNum;
self->nativeTypeNum = info.defaultNativeTypeNum;
self->name = cxString_FromEncodedString(info.name, info.nameLength,
connection->encodingInfo.encoding);
Expand Down
Loading

0 comments on commit 51f1815

Please sign in to comment.