765 lines
28 KiB
C
765 lines
28 KiB
C
//-----------------------------------------------------------------------------
|
|
// Copyright 2016-2018, Oracle and/or its affiliates. All rights reserved.
|
|
//
|
|
// Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
|
|
//
|
|
// Portions Copyright 2001-2007, Computronix (Canada) Ltd., Edmonton, Alberta,
|
|
// Canada. All rights reserved.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// cxoVar.c
|
|
// Defines Python types for Oracle variables.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include "cxoModule.h"
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Declaration of common variable functions.
|
|
//-----------------------------------------------------------------------------
|
|
static void cxoVar_free(cxoVar*);
|
|
static PyObject *cxoVar_repr(cxoVar*);
|
|
static PyObject *cxoVar_externalCopy(cxoVar*, PyObject*);
|
|
static PyObject *cxoVar_externalSetValue(cxoVar*, PyObject*);
|
|
static PyObject *cxoVar_externalGetValue(cxoVar*, PyObject*, PyObject*);
|
|
static PyObject *cxoVar_externalGetActualElements(cxoVar*, void*);
|
|
static PyObject *cxoVar_externalGetValues(cxoVar*, void*);
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// declaration of members for variables
|
|
//-----------------------------------------------------------------------------
|
|
static PyMemberDef cxoVarMembers[] = {
|
|
{ "bufferSize", T_INT, offsetof(cxoVar, bufferSize), READONLY },
|
|
{ "inconverter", T_OBJECT, offsetof(cxoVar, inConverter), 0 },
|
|
{ "numElements", T_INT, offsetof(cxoVar, allocatedElements),
|
|
READONLY },
|
|
{ "outconverter", T_OBJECT, offsetof(cxoVar, outConverter), 0 },
|
|
{ "size", T_INT, offsetof(cxoVar, size), READONLY },
|
|
{ "type", T_OBJECT, offsetof(cxoVar, objectType), READONLY },
|
|
{ NULL }
|
|
};
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// declaration of calculated members for variables
|
|
//-----------------------------------------------------------------------------
|
|
static PyGetSetDef cxoVarCalcMembers[] = {
|
|
{ "actualElements", (getter) cxoVar_externalGetActualElements, 0, 0, 0 },
|
|
{ "values", (getter) cxoVar_externalGetValues, 0, 0, 0 },
|
|
{ NULL }
|
|
};
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// declaration of methods for variables
|
|
//-----------------------------------------------------------------------------
|
|
static PyMethodDef cxoVarMethods[] = {
|
|
{ "copy", (PyCFunction) cxoVar_externalCopy, METH_VARARGS },
|
|
{ "setvalue", (PyCFunction) cxoVar_externalSetValue, METH_VARARGS },
|
|
{ "getvalue", (PyCFunction) cxoVar_externalGetValue,
|
|
METH_VARARGS | METH_KEYWORDS },
|
|
{ NULL }
|
|
};
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// declaration of all variable types
|
|
//-----------------------------------------------------------------------------
|
|
#define DECLARE_VARIABLE_TYPE(INTERNAL_NAME, EXTERNAL_NAME) \
|
|
PyTypeObject INTERNAL_NAME = { \
|
|
PyVarObject_HEAD_INIT(NULL, 0) \
|
|
"cx_Oracle." #EXTERNAL_NAME, /* tp_name */ \
|
|
sizeof(cxoVar), /* tp_basicsize */ \
|
|
0, /* tp_itemsize */ \
|
|
(destructor) cxoVar_free, /* tp_dealloc */ \
|
|
0, /* tp_print */ \
|
|
0, /* tp_getattr */ \
|
|
0, /* tp_setattr */ \
|
|
0, /* tp_compare */ \
|
|
(reprfunc) cxoVar_repr, /* tp_repr */ \
|
|
0, /* tp_as_number */ \
|
|
0, /* tp_as_sequence */ \
|
|
0, /* tp_as_mapping */ \
|
|
0, /* tp_hash */ \
|
|
0, /* tp_call */ \
|
|
0, /* tp_str */ \
|
|
0, /* tp_getattro */ \
|
|
0, /* 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 */ \
|
|
cxoVarMethods, /* tp_methods */ \
|
|
cxoVarMembers, /* tp_members */ \
|
|
cxoVarCalcMembers /* tp_getset */ \
|
|
};
|
|
|
|
DECLARE_VARIABLE_TYPE(cxoPyTypeBfileVar, BFILE)
|
|
DECLARE_VARIABLE_TYPE(cxoPyTypeBinaryVar, BINARY)
|
|
DECLARE_VARIABLE_TYPE(cxoPyTypeBlobVar, BLOB)
|
|
DECLARE_VARIABLE_TYPE(cxoPyTypeBooleanVar, BOOLEAN)
|
|
DECLARE_VARIABLE_TYPE(cxoPyTypeClobVar, CLOB)
|
|
DECLARE_VARIABLE_TYPE(cxoPyTypeCursorVar, CURSOR)
|
|
DECLARE_VARIABLE_TYPE(cxoPyTypeDateTimeVar, DATETIME)
|
|
DECLARE_VARIABLE_TYPE(cxoPyTypeFixedCharVar, FIXED_CHAR)
|
|
DECLARE_VARIABLE_TYPE(cxoPyTypeFixedNcharVar, FIXED_NCHAR)
|
|
DECLARE_VARIABLE_TYPE(cxoPyTypeIntervalVar, INTERVAL)
|
|
DECLARE_VARIABLE_TYPE(cxoPyTypeLongBinaryVar, LONG_BINARY)
|
|
DECLARE_VARIABLE_TYPE(cxoPyTypeLongStringVar, LONG_STRING)
|
|
DECLARE_VARIABLE_TYPE(cxoPyTypeNativeFloatVar, NATIVE_FLOAT)
|
|
DECLARE_VARIABLE_TYPE(cxoPyTypeNativeIntVar, NATIVE_INT)
|
|
DECLARE_VARIABLE_TYPE(cxoPyTypeNcharVar, NCHAR)
|
|
DECLARE_VARIABLE_TYPE(cxoPyTypeNclobVar, NCLOB)
|
|
DECLARE_VARIABLE_TYPE(cxoPyTypeNumberVar, NUMBER)
|
|
DECLARE_VARIABLE_TYPE(cxoPyTypeObjectVar, OBJECT)
|
|
DECLARE_VARIABLE_TYPE(cxoPyTypeRowidVar, ROWID)
|
|
DECLARE_VARIABLE_TYPE(cxoPyTypeStringVar, STRING)
|
|
DECLARE_VARIABLE_TYPE(cxoPyTypeTimestampVar, TIMESTAMP)
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// cxoVar_new()
|
|
// Allocate a new variable.
|
|
//-----------------------------------------------------------------------------
|
|
cxoVar *cxoVar_new(cxoCursor *cursor, Py_ssize_t numElements, cxoVarType *type,
|
|
Py_ssize_t size, int isArray, cxoObjectType *objType)
|
|
{
|
|
dpiObjectType *typeHandle = NULL;
|
|
dpiOracleTypeNum oracleTypeNum;
|
|
dpiNativeTypeNum nativeTypeNum;
|
|
cxoVar *var;
|
|
|
|
// attempt to allocate the object
|
|
var = (cxoVar*) type->pythonType->tp_alloc(type->pythonType, 0);
|
|
if (!var)
|
|
return NULL;
|
|
|
|
// perform basic initialization
|
|
Py_INCREF(cursor->connection);
|
|
var->connection = cursor->connection;
|
|
if (objType) {
|
|
Py_INCREF(objType);
|
|
var->objectType = objType;
|
|
typeHandle = objType->handle;
|
|
}
|
|
if (numElements == 0)
|
|
numElements = 1;
|
|
var->allocatedElements = (uint32_t) numElements;
|
|
var->type = type;
|
|
var->size = (size == 0) ? type->size : (uint32_t) size;
|
|
var->isArray = isArray;
|
|
|
|
// acquire and initialize DPI variable
|
|
cxoTransform_getTypeInfo(type->transformNum, &oracleTypeNum,
|
|
&nativeTypeNum);
|
|
if (dpiConn_newVar(cursor->connection->handle, oracleTypeNum,
|
|
nativeTypeNum, var->allocatedElements, var->size, 0, isArray,
|
|
typeHandle, &var->handle, &var->data) < 0) {
|
|
cxoError_raiseAndReturnNull();
|
|
Py_DECREF(var);
|
|
return NULL;
|
|
}
|
|
|
|
// get buffer size for information
|
|
if (dpiVar_getSizeInBytes(var->handle, &var->bufferSize) < 0) {
|
|
cxoError_raiseAndReturnNull();
|
|
Py_DECREF(var);
|
|
return NULL;
|
|
}
|
|
|
|
return var;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// cxoVar_free()
|
|
// Free an existing variable.
|
|
//-----------------------------------------------------------------------------
|
|
static void cxoVar_free(cxoVar *var)
|
|
{
|
|
if (var->handle) {
|
|
Py_BEGIN_ALLOW_THREADS
|
|
dpiVar_release(var->handle);
|
|
Py_END_ALLOW_THREADS
|
|
var->handle = NULL;
|
|
}
|
|
Py_CLEAR(var->connection);
|
|
Py_CLEAR(var->inConverter);
|
|
Py_CLEAR(var->outConverter);
|
|
Py_CLEAR(var->objectType);
|
|
Py_TYPE(var)->tp_free((PyObject*) var);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// cxoVar_check()
|
|
// Returns a boolean indicating if the object is a variable.
|
|
//-----------------------------------------------------------------------------
|
|
int cxoVar_check(PyObject *object)
|
|
{
|
|
PyTypeObject *objectType = Py_TYPE(object);
|
|
|
|
return (objectType == &cxoPyTypeBfileVar ||
|
|
objectType == &cxoPyTypeBinaryVar ||
|
|
objectType == &cxoPyTypeBlobVar ||
|
|
objectType == &cxoPyTypeBooleanVar ||
|
|
objectType == &cxoPyTypeClobVar ||
|
|
objectType == &cxoPyTypeCursorVar ||
|
|
objectType == &cxoPyTypeDateTimeVar ||
|
|
objectType == &cxoPyTypeFixedCharVar ||
|
|
objectType == &cxoPyTypeFixedNcharVar ||
|
|
objectType == &cxoPyTypeIntervalVar ||
|
|
objectType == &cxoPyTypeLongBinaryVar ||
|
|
objectType == &cxoPyTypeLongStringVar ||
|
|
objectType == &cxoPyTypeNativeFloatVar ||
|
|
objectType == &cxoPyTypeNativeIntVar ||
|
|
objectType == &cxoPyTypeNcharVar ||
|
|
objectType == &cxoPyTypeNclobVar ||
|
|
objectType == &cxoPyTypeNumberVar ||
|
|
objectType == &cxoPyTypeObjectVar ||
|
|
objectType == &cxoPyTypeRowidVar ||
|
|
objectType == &cxoPyTypeStringVar ||
|
|
objectType == &cxoPyTypeTimestampVar);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// cxoVar_newByValue()
|
|
// Allocate a new variable by looking at the type of the data.
|
|
//-----------------------------------------------------------------------------
|
|
cxoVar *cxoVar_newByValue(cxoCursor *cursor, PyObject *value,
|
|
Py_ssize_t numElements)
|
|
{
|
|
PyObject *result, *inputTypeHandler = NULL;
|
|
cxoObjectType *objType = NULL;
|
|
cxoVarType *varType;
|
|
Py_ssize_t size;
|
|
cxoObject *obj;
|
|
int isArray;
|
|
|
|
// determine if an input type handler should be used; an input type handler
|
|
// defined on the cursor takes precedence over one defined on the
|
|
// connection to which the cursor belongs; the input type handler should
|
|
// return a variable or None; the value None implies that the default
|
|
// processing should take place just as if no input type handler was
|
|
// defined
|
|
if (cursor->inputTypeHandler && cursor->inputTypeHandler != Py_None)
|
|
inputTypeHandler = cursor->inputTypeHandler;
|
|
else if (cursor->connection->inputTypeHandler &&
|
|
cursor->connection->inputTypeHandler != Py_None)
|
|
inputTypeHandler = cursor->connection->inputTypeHandler;
|
|
if (inputTypeHandler) {
|
|
result = PyObject_CallFunction(inputTypeHandler, "OOn", cursor, value,
|
|
numElements);
|
|
if (!result)
|
|
return NULL;
|
|
if (result != Py_None) {
|
|
if (!cxoVar_check(result)) {
|
|
Py_DECREF(result);
|
|
PyErr_SetString(PyExc_TypeError,
|
|
"expecting variable from input type handler");
|
|
return NULL;
|
|
}
|
|
return (cxoVar*) result;
|
|
}
|
|
Py_DECREF(result);
|
|
}
|
|
|
|
// default processing
|
|
varType = cxoVarType_fromPythonValue(value, &isArray, &size, &numElements);
|
|
if (!varType)
|
|
return NULL;
|
|
if (varType->transformNum == CXO_TRANSFORM_OBJECT) {
|
|
obj = (cxoObject*) value;
|
|
objType = obj->objectType;
|
|
}
|
|
return cxoVar_new(cursor, numElements, varType, size, isArray, objType);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// cxoVar_newArrayByType()
|
|
// Allocate a new PL/SQL array by looking at the Python data type.
|
|
//-----------------------------------------------------------------------------
|
|
static cxoVar *cxoVar_newArrayByType(cxoCursor *cursor,
|
|
PyObject *value)
|
|
{
|
|
PyObject *typeObj, *numElementsObj;
|
|
cxoVarType *varType;
|
|
uint32_t numElements;
|
|
|
|
if (PyList_GET_SIZE(value) != 2) {
|
|
PyErr_SetString(cxoProgrammingErrorException,
|
|
"expecting an array of two elements [type, numelems]");
|
|
return NULL;
|
|
}
|
|
|
|
typeObj = PyList_GET_ITEM(value, 0);
|
|
numElementsObj = PyList_GET_ITEM(value, 1);
|
|
if (!PyInt_Check(numElementsObj)) {
|
|
PyErr_SetString(cxoProgrammingErrorException,
|
|
"number of elements must be an integer");
|
|
return NULL;
|
|
}
|
|
|
|
varType = cxoVarType_fromPythonType((PyTypeObject*) typeObj);
|
|
if (!varType)
|
|
return NULL;
|
|
|
|
numElements = PyInt_AsLong(numElementsObj);
|
|
if (PyErr_Occurred())
|
|
return NULL;
|
|
return cxoVar_new(cursor, numElements, varType, varType->size, 1, NULL);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// cxoVar_newByType()
|
|
// Allocate a new variable by looking at the Python data type.
|
|
//-----------------------------------------------------------------------------
|
|
cxoVar *cxoVar_newByType(cxoCursor *cursor, PyObject *value,
|
|
uint32_t numElements)
|
|
{
|
|
cxoVarType *varType;
|
|
long size;
|
|
|
|
// passing an integer is assumed to be a string
|
|
if (PyInt_Check(value)) {
|
|
size = PyInt_AsLong(value);
|
|
if (PyErr_Occurred())
|
|
return NULL;
|
|
varType = cxoVarType_fromPythonType(&cxoPyTypeString);
|
|
return cxoVar_new(cursor, numElements, varType, size, 0, NULL);
|
|
}
|
|
|
|
// passing an array of two elements to define an array
|
|
if (PyList_Check(value))
|
|
return cxoVar_newArrayByType(cursor, value);
|
|
|
|
// handle directly bound variables
|
|
if (cxoVar_check(value)) {
|
|
Py_INCREF(value);
|
|
return (cxoVar*) value;
|
|
}
|
|
|
|
// everything else ought to be a Python type
|
|
varType = cxoVarType_fromPythonType((PyTypeObject*) value);
|
|
if (!varType)
|
|
return NULL;
|
|
return cxoVar_new(cursor, numElements, varType, varType->size, 0, NULL);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// cxoVar_bind()
|
|
// Allocate a variable and bind it to the given statement.
|
|
//-----------------------------------------------------------------------------
|
|
int cxoVar_bind(cxoVar *var, cxoCursor *cursor, PyObject *name, uint32_t pos)
|
|
{
|
|
cxoBuffer nameBuffer;
|
|
int status;
|
|
|
|
// perform the bind
|
|
if (name) {
|
|
if (cxoBuffer_fromObject(&nameBuffer, name,
|
|
cursor->connection->encodingInfo.encoding) < 0)
|
|
return -1;
|
|
status = dpiStmt_bindByName(cursor->handle, (char*) nameBuffer.ptr,
|
|
nameBuffer.size, var->handle);
|
|
cxoBuffer_clear(&nameBuffer);
|
|
} else {
|
|
status = dpiStmt_bindByPos(cursor->handle, pos, var->handle);
|
|
}
|
|
if (status < 0)
|
|
return cxoError_raiseAndReturnInt();
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// cxoVar_getSingleValue()
|
|
// Return the value of the variable at the given position.
|
|
//-----------------------------------------------------------------------------
|
|
PyObject *cxoVar_getSingleValue(cxoVar *var, uint32_t arrayPos)
|
|
{
|
|
PyObject *value, *result;
|
|
dpiData *data;
|
|
|
|
// ensure we do not exceed the number of allocated elements
|
|
if (arrayPos >= var->allocatedElements) {
|
|
PyErr_SetString(PyExc_IndexError,
|
|
"cxoVar_getSingleValue: array size exceeded");
|
|
return NULL;
|
|
}
|
|
|
|
// return the value
|
|
data = &var->data[arrayPos];
|
|
if (data->isNull)
|
|
Py_RETURN_NONE;
|
|
value = cxoTransform_toPython(var->type->transformNum, var->connection,
|
|
var->objectType, &data->value);
|
|
if (value && var->objectType)
|
|
dpiObject_addRef(data->value.asObject);
|
|
if (value && var->outConverter && var->outConverter != Py_None) {
|
|
result = PyObject_CallFunctionObjArgs(var->outConverter, value, NULL);
|
|
Py_DECREF(value);
|
|
return result;
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// cxoVar_getArrayValue()
|
|
// Return the value of the variable as an array.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *cxoVar_getArrayValue(cxoVar *var,
|
|
uint32_t numElements)
|
|
{
|
|
PyObject *value, *singleValue;
|
|
uint32_t i;
|
|
|
|
value = PyList_New(numElements);
|
|
if (!value)
|
|
return NULL;
|
|
|
|
for (i = 0; i < numElements; i++) {
|
|
singleValue = cxoVar_getSingleValue(var, i);
|
|
if (!singleValue) {
|
|
Py_DECREF(value);
|
|
return NULL;
|
|
}
|
|
PyList_SET_ITEM(value, i, singleValue);
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// cxoVar_getValue()
|
|
// Return the value of the variable.
|
|
//-----------------------------------------------------------------------------
|
|
PyObject *cxoVar_getValue(cxoVar *var, uint32_t arrayPos)
|
|
{
|
|
uint32_t numElements;
|
|
|
|
if (var->isArray) {
|
|
if (dpiVar_getNumElementsInArray(var->handle, &numElements) < 0)
|
|
return cxoError_raiseAndReturnNull();
|
|
return cxoVar_getArrayValue(var, numElements);
|
|
}
|
|
|
|
return cxoVar_getSingleValue(var, arrayPos);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// cxoVar_setValueBytes()
|
|
// Set a value in the variable from a byte string of some sort.
|
|
//-----------------------------------------------------------------------------
|
|
static int cxoVar_setValueBytes(cxoVar *var, uint32_t pos, dpiData *data,
|
|
cxoBuffer *buffer)
|
|
{
|
|
dpiData *tempVarData, *sourceData;
|
|
dpiOracleTypeNum oracleTypeNum;
|
|
dpiNativeTypeNum nativeTypeNum;
|
|
dpiVar *tempVarHandle;
|
|
uint32_t i;
|
|
int status;
|
|
|
|
if (buffer->size > var->bufferSize) {
|
|
cxoTransform_getTypeInfo(var->type->transformNum, &oracleTypeNum,
|
|
&nativeTypeNum);
|
|
if (dpiConn_newVar(var->connection->handle, oracleTypeNum,
|
|
nativeTypeNum, var->allocatedElements, buffer->size, 0,
|
|
var->isArray, NULL, &tempVarHandle, &tempVarData) < 0)
|
|
return cxoError_raiseAndReturnInt();
|
|
for (i = 0; i < var->allocatedElements; i++) {
|
|
sourceData = &var->data[i];
|
|
if (i == pos || sourceData->isNull)
|
|
continue;
|
|
if (dpiVar_setFromBytes(tempVarHandle, i,
|
|
sourceData->value.asBytes.ptr,
|
|
sourceData->value.asBytes.length) < 0) {
|
|
dpiVar_release(tempVarHandle);
|
|
return cxoError_raiseAndReturnInt();
|
|
}
|
|
}
|
|
dpiVar_release(var->handle);
|
|
var->handle = tempVarHandle;
|
|
var->data = tempVarData;
|
|
var->size = buffer->numCharacters;
|
|
var->bufferSize = buffer->size;
|
|
}
|
|
status = dpiVar_setFromBytes(var->handle, pos, buffer->ptr, buffer->size);
|
|
if (status < 0)
|
|
return cxoError_raiseAndReturnInt();
|
|
return 0;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// cxoVar_setValueCursor()
|
|
// Set the value of the variable (which is assumed to be a cursor).
|
|
//-----------------------------------------------------------------------------
|
|
static int cxoVar_setValueCursor(cxoVar *var, uint32_t pos, dpiData *data,
|
|
PyObject *value)
|
|
{
|
|
cxoCursor *cursor;
|
|
dpiStmtInfo info;
|
|
|
|
if (!PyObject_IsInstance(value, (PyObject*) &cxoPyTypeCursor)) {
|
|
PyErr_SetString(PyExc_TypeError, "expecting cursor");
|
|
return -1;
|
|
}
|
|
|
|
// if the cursor already has a handle, use it directly
|
|
cursor = (cxoCursor *) value;
|
|
if (cursor->handle) {
|
|
if (dpiVar_setFromStmt(var->handle, pos, cursor->handle) < 0)
|
|
return cxoError_raiseAndReturnInt();
|
|
|
|
// otherwise, make use of the statement handle allocated by the variable
|
|
// BUT, make sure the statement handle is still valid as it may have been
|
|
// closed by some other code; the call to dpiStmt_getInfo() will ensure the
|
|
// statement is still open; if an error occurs, this bind will be discarded
|
|
// and a second attempt will be made with a new cursor
|
|
} else {
|
|
if (dpiStmt_getInfo(data->value.asStmt, &info) < 0)
|
|
return cxoError_raiseAndReturnInt();
|
|
cursor->handle = data->value.asStmt;
|
|
dpiStmt_addRef(cursor->handle);
|
|
}
|
|
cursor->fixupRefCursor = 1;
|
|
return 0;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// cxoVar_setSingleValue()
|
|
// Set a single value in the variable.
|
|
//-----------------------------------------------------------------------------
|
|
static int cxoVar_setSingleValue(cxoVar *var, uint32_t arrayPos,
|
|
PyObject *value)
|
|
{
|
|
dpiDataBuffer tempDbValue, *dbValue;
|
|
PyObject *convertedValue = NULL;
|
|
cxoBuffer buffer;
|
|
int result = 0;
|
|
dpiData *data;
|
|
|
|
// ensure we do not exceed the number of allocated elements
|
|
if (arrayPos >= var->allocatedElements) {
|
|
PyErr_SetString(PyExc_IndexError,
|
|
"cxoVar_setSingleValue: array size exceeded");
|
|
return -1;
|
|
}
|
|
|
|
// convert value, if necessary
|
|
if (var->inConverter && var->inConverter != Py_None) {
|
|
convertedValue = PyObject_CallFunctionObjArgs(var->inConverter, value,
|
|
NULL);
|
|
if (!convertedValue)
|
|
return -1;
|
|
value = convertedValue;
|
|
}
|
|
|
|
// tranform value from Python to value expected by ODPI-C
|
|
data = &var->data[arrayPos];
|
|
data->isNull = (value == Py_None);
|
|
if (!data->isNull) {
|
|
if (var->type->transformNum == CXO_TRANSFORM_CURSOR)
|
|
result = cxoVar_setValueCursor(var, arrayPos, data, value);
|
|
else {
|
|
cxoBuffer_init(&buffer);
|
|
if (var->type->size > 0)
|
|
dbValue = &tempDbValue;
|
|
else dbValue = &data->value;
|
|
result = cxoTransform_fromPython(var->type->transformNum, 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);
|
|
cxoBuffer_clear(&buffer);
|
|
}
|
|
}
|
|
Py_CLEAR(convertedValue);
|
|
return result;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// cxoVar_setArrayValue()
|
|
// Set all of the array values for the variable.
|
|
//-----------------------------------------------------------------------------
|
|
static int cxoVar_setArrayValue(cxoVar *var, PyObject *value)
|
|
{
|
|
Py_ssize_t numElements, i;
|
|
|
|
// ensure we have an array to set
|
|
if (!PyList_Check(value)) {
|
|
PyErr_SetString(PyExc_TypeError, "expecting array data");
|
|
return -1;
|
|
}
|
|
|
|
// set the number of actual elements
|
|
numElements = PyList_GET_SIZE(value);
|
|
if (dpiVar_setNumElementsInArray(var->handle, (uint32_t) numElements) < 0)
|
|
return cxoError_raiseAndReturnInt();
|
|
|
|
// set all of the values
|
|
for (i = 0; i < numElements; i++) {
|
|
if (cxoVar_setSingleValue(var, i, PyList_GET_ITEM(value, i)) < 0)
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// cxoVar_setValue()
|
|
// Set the value of the variable.
|
|
//-----------------------------------------------------------------------------
|
|
int cxoVar_setValue(cxoVar *var, uint32_t arrayPos, PyObject *value)
|
|
{
|
|
if (var->isArray) {
|
|
if (arrayPos > 0) {
|
|
PyErr_SetString(cxoNotSupportedErrorException,
|
|
"arrays of arrays are not supported by the OCI");
|
|
return -1;
|
|
}
|
|
return cxoVar_setArrayValue(var, value);
|
|
}
|
|
return cxoVar_setSingleValue(var, arrayPos, value);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// cxoVar_externalCopy()
|
|
// Copy the contents of the source variable to the destination variable.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *cxoVar_externalCopy(cxoVar *targetVar, PyObject *args)
|
|
{
|
|
uint32_t sourcePos, targetPos;
|
|
cxoVar *sourceVar;
|
|
|
|
if (!PyArg_ParseTuple(args, "Oii", &sourceVar, &sourcePos, &targetPos))
|
|
return NULL;
|
|
if (Py_TYPE(targetVar) != Py_TYPE(sourceVar)) {
|
|
PyErr_SetString(cxoProgrammingErrorException,
|
|
"source and target variable type must match");
|
|
return NULL;
|
|
}
|
|
if (dpiVar_copyData(targetVar->handle, targetPos, sourceVar->handle,
|
|
sourcePos) < 0)
|
|
return cxoError_raiseAndReturnNull();
|
|
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// cxoVar_externalSetValue()
|
|
// Set the value of the variable at the given position.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *cxoVar_externalSetValue(cxoVar *var, PyObject *args)
|
|
{
|
|
PyObject *value;
|
|
uint32_t pos;
|
|
|
|
if (!PyArg_ParseTuple(args, "iO", &pos, &value))
|
|
return NULL;
|
|
if (cxoVar_setValue(var, pos, value) < 0)
|
|
return NULL;
|
|
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// cxoVar_externalGetValue()
|
|
// Return the value of the variable at the given position.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *cxoVar_externalGetValue(cxoVar *var, PyObject *args,
|
|
PyObject *keywordArgs)
|
|
{
|
|
static char *keywordList[] = { "pos", NULL };
|
|
uint32_t pos = 0;
|
|
|
|
if (!PyArg_ParseTupleAndKeywords(args, keywordArgs, "|i", keywordList,
|
|
&pos))
|
|
return NULL;
|
|
return cxoVar_getValue(var, pos);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// cxoVar_externalGetActualElements()
|
|
// Return the values of the variable at all positions as a list.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *cxoVar_externalGetActualElements(cxoVar *var,
|
|
void *unused)
|
|
{
|
|
uint32_t numElements;
|
|
|
|
if (dpiVar_getNumElementsInArray(var->handle, &numElements) < 0)
|
|
return cxoError_raiseAndReturnNull();
|
|
return PyInt_FromLong(numElements);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// cxoVar_externalGetValues()
|
|
// Return the values of the variable at all positions as a list.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *cxoVar_externalGetValues(cxoVar *var, void *unused)
|
|
{
|
|
uint32_t numElements;
|
|
|
|
if (dpiVar_getNumElementsInArray(var->handle, &numElements) < 0)
|
|
return cxoError_raiseAndReturnNull();
|
|
return cxoVar_getArrayValue(var, numElements);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// cxoVar_repr()
|
|
// Return a string representation of the variable.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *cxoVar_repr(cxoVar *var)
|
|
{
|
|
PyObject *value, *module, *name, *result;
|
|
uint32_t numElements;
|
|
|
|
if (var->isArray) {
|
|
if (dpiVar_getNumElementsInArray(var->handle, &numElements) < 0)
|
|
return cxoError_raiseAndReturnNull();
|
|
value = cxoVar_getArrayValue(var, numElements);
|
|
} else if (var->allocatedElements == 1)
|
|
value = cxoVar_getSingleValue(var, 0);
|
|
else value = cxoVar_getArrayValue(var, var->allocatedElements);
|
|
if (!value)
|
|
return NULL;
|
|
if (cxoUtils_getModuleAndName(Py_TYPE(var), &module, &name) < 0) {
|
|
Py_DECREF(value);
|
|
return NULL;
|
|
}
|
|
result = cxoUtils_formatString("<%s.%s with value %r>",
|
|
PyTuple_Pack(3, module, name, value));
|
|
Py_DECREF(module);
|
|
Py_DECREF(name);
|
|
Py_DECREF(value);
|
|
return result;
|
|
}
|
|
|