From 82097891b3ab66c2b7e734e8a0b62eea669c8f0c Mon Sep 17 00:00:00 2001 From: Anthony Tuininga Date: Mon, 29 Apr 2019 11:41:28 -0600 Subject: [PATCH] Add support for setting a CLOB attribute on a SQL object, as requested (https://github.com/oracle/python-cx_Oracle/issues/299). --- odpi | 2 +- src/cxoConnection.c | 6 ++++-- src/cxoModule.h | 3 ++- src/cxoObject.c | 3 ++- src/cxoTransform.c | 21 ++++++++++++++------- src/cxoVar.c | 6 ++++-- test/ObjectVar.py | 18 ++++++++++++++++++ 7 files changed, 45 insertions(+), 14 deletions(-) diff --git a/odpi b/odpi index e0c1f03..0fe226c 160000 --- a/odpi +++ b/odpi @@ -1 +1 @@ -Subproject commit e0c1f03eaea9954863cff77ac26bbcde4bd29807 +Subproject commit 0fe226c8b5b15b0cc42ab8e638f4bb875c78d479 diff --git a/src/cxoConnection.c b/src/cxoConnection.c index 20a5b57..78d115e 100644 --- a/src/cxoConnection.c +++ b/src/cxoConnection.c @@ -371,11 +371,13 @@ static int cxoConnectionParams_processShardingKeyValue( cxoConnectionParams *params, PyObject *value, dpiShardingKeyColumn *column, cxoBuffer *buffer) { + dpiNativeTypeNum nativeTypeNum; cxoTransformNum transformNum; transformNum = cxoTransform_getNumFromValue(value, 0); - if (cxoTransform_fromPython(transformNum, value, &column->value, buffer, - params->encoding, params->nencoding, NULL, 0) < 0) + if (cxoTransform_fromPython(transformNum, &nativeTypeNum, value, + &column->value, buffer, params->encoding, params->nencoding, NULL, + 0) < 0) return -1; cxoTransform_getTypeInfo(transformNum, &column->oracleTypeNum, &column->nativeTypeNum); diff --git a/src/cxoModule.h b/src/cxoModule.h index efb3808..6de88ec 100644 --- a/src/cxoModule.h +++ b/src/cxoModule.h @@ -504,7 +504,8 @@ cxoSodaOperation *cxoSodaOperation_new(cxoSodaCollection *collection); void cxoSubscr_callback(cxoSubscr *subscr, dpiSubscrMessage *message); PyObject *cxoTransform_dateFromTicks(PyObject *args); -int cxoTransform_fromPython(cxoTransformNum transformNum, PyObject *pyValue, +int cxoTransform_fromPython(cxoTransformNum transformNum, + dpiNativeTypeNum *nativeTypeNum, PyObject *pyValue, dpiDataBuffer *dbValue, cxoBuffer *buffer, const char *encoding, const char *nencoding, cxoVar *var, uint32_t arrayPos); cxoTransformNum cxoTransform_getNumFromDataTypeInfo(dpiDataTypeInfo *info); diff --git a/src/cxoObject.c b/src/cxoObject.c index d955cb2..e3d9be9 100644 --- a/src/cxoObject.c +++ b/src/cxoObject.c @@ -176,7 +176,8 @@ static int cxoObject_convertFromPython(cxoObject *obj, PyObject *value, // convert the different Python types cxoTransform_getTypeInfo(transformNum, &oracleTypeNum, nativeTypeNum); - if (cxoTransform_fromPython(transformNum, value, &data->value, buffer, + if (cxoTransform_fromPython(transformNum, nativeTypeNum, value, + &data->value, buffer, obj->objectType->connection->encodingInfo.encoding, obj->objectType->connection->encodingInfo.nencoding, NULL, 0) < 0) return -1; diff --git a/src/cxoTransform.c b/src/cxoTransform.c index ddc190e..0dc2c81 100644 --- a/src/cxoTransform.c +++ b/src/cxoTransform.c @@ -193,7 +193,8 @@ PyObject *cxoTransform_dateFromTicks(PyObject *args) // cxoTransform_fromPython() // Transforms a Python object into its corresponding database value. //----------------------------------------------------------------------------- -int cxoTransform_fromPython(cxoTransformNum transformNum, PyObject *pyValue, +int cxoTransform_fromPython(cxoTransformNum transformNum, + dpiNativeTypeNum *nativeTypeNum, PyObject *pyValue, dpiDataBuffer *dbValue, cxoBuffer *buffer, const char *encoding, const char *nencoding, cxoVar *var, uint32_t arrayPos) { @@ -242,12 +243,18 @@ int cxoTransform_fromPython(cxoTransformNum transformNum, PyObject *pyValue, encoding = nencoding; if (cxoBuffer_fromObject(buffer, pyValue, encoding) < 0) return -1; - Py_BEGIN_ALLOW_THREADS - status = dpiLob_setFromBytes(dbValue->asLOB, buffer->ptr, - buffer->size); - Py_END_ALLOW_THREADS - if (status < 0) - return cxoError_raiseAndReturnInt(); + if (var) { + Py_BEGIN_ALLOW_THREADS + status = dpiLob_setFromBytes(dbValue->asLOB, buffer->ptr, + buffer->size); + Py_END_ALLOW_THREADS + if (status < 0) + return cxoError_raiseAndReturnInt(); + } else { + *nativeTypeNum = DPI_NATIVE_TYPE_BYTES; + dbValue->asBytes.ptr = (char*) buffer->ptr; + dbValue->asBytes.length = buffer->size; + } return 0; case CXO_TRANSFORM_NATIVE_INT: #if PY_MAJOR_VERSION < 3 diff --git a/src/cxoVar.c b/src/cxoVar.c index 5bbe482..38836fc 100644 --- a/src/cxoVar.c +++ b/src/cxoVar.c @@ -601,6 +601,7 @@ static int cxoVar_setSingleValue(cxoVar *var, uint32_t arrayPos, { dpiDataBuffer tempDbValue, *dbValue; PyObject *convertedValue = NULL; + dpiNativeTypeNum nativeTypeNum; cxoBuffer buffer; int result = 0; dpiData *data; @@ -632,8 +633,9 @@ static int cxoVar_setSingleValue(cxoVar *var, uint32_t arrayPos, if (var->type->size > 0) dbValue = &tempDbValue; else dbValue = &data->value; - result = cxoTransform_fromPython(var->type->transformNum, value, - dbValue, &buffer, var->connection->encodingInfo.encoding, + result = cxoTransform_fromPython(var->type->transformNum, + &nativeTypeNum, value, dbValue, &buffer, + var->connection->encodingInfo.encoding, var->connection->encodingInfo.nencoding, var, arrayPos); if (result == 0 && var->type->size > 0) result = cxoVar_setValueBytes(var, arrayPos, data, &buffer); diff --git a/test/ObjectVar.py b/test/ObjectVar.py index 122670e..cc4e5e4 100644 --- a/test/ObjectVar.py +++ b/test/ObjectVar.py @@ -238,6 +238,24 @@ class TestCase(TestEnv.BaseTestCase): cx_Oracle.Timestamp(1999, 11, 12, 23, 5, 2), 'A short CLOB', 'A short NCLOB', b'A short BLOB', (23, 'Substring value'), None), None) + obj.CLOBVALUE = "A short CLOB (modified)" + obj.NCLOBVALUE = "A short NCLOB (modified)" + obj.BLOBVALUE = "A short BLOB (modified)" + self.cursor.execute("insert into TestObjects (IntCol, ObjectCol) " \ + "values (5, :obj)", obj = obj) + self.cursor.execute(""" + select IntCol, ObjectCol, ArrayCol + from TestObjects + where IntCol = 5""") + self.__TestData(5, (5, 'A string', 'Fixed str ', 'A NCHAR string', + 'Fixed N ', b'Raw Value', 27, 13, 184.875, 1.375, 23.75, + 14.25, 29.1625, cx_Oracle.Timestamp(2017, 5, 9, 0, 0, 0), + cx_Oracle.Timestamp(2017, 5, 9, 9, 41, 13), + cx_Oracle.Timestamp(1986, 8, 2, 15, 27, 38), + cx_Oracle.Timestamp(1999, 11, 12, 23, 5, 2), + 'A short CLOB (modified)', 'A short NCLOB (modified)', + b'A short BLOB (modified)', + (23, 'Substring value'), None), None) self.connection.rollback() def testInvalidTypeObject(self):