202 lines
7.1 KiB
C
202 lines
7.1 KiB
C
//-----------------------------------------------------------------------------
|
|
// Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// cxoUtils.c
|
|
// Utility functions used in cx_Oracle.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include "cxoModule.h"
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// cxoUtils_formatString()
|
|
// Return a Python string formatted using the given format string and
|
|
// arguments. The arguments have a reference taken from them after they have
|
|
// been used (which should mean that they are destroyed).
|
|
//-----------------------------------------------------------------------------
|
|
PyObject *cxoUtils_formatString(const char *format, PyObject *args)
|
|
{
|
|
PyObject *formatObj, *result;
|
|
|
|
// assume that a NULL value for arguments implies building the arguments
|
|
// failed and a Python exception has already been raised
|
|
if (!args)
|
|
return NULL;
|
|
|
|
// convert string format to Python object
|
|
#if PY_MAJOR_VERSION >= 3
|
|
formatObj = PyUnicode_DecodeASCII(format, strlen(format), NULL);
|
|
#else
|
|
formatObj = PyString_FromString(format);
|
|
#endif
|
|
if (!formatObj) {
|
|
Py_DECREF(args);
|
|
return NULL;
|
|
}
|
|
|
|
// create formatted result
|
|
#if PY_MAJOR_VERSION >= 3
|
|
result = PyUnicode_Format(formatObj, args);
|
|
#else
|
|
result = PyString_Format(formatObj, args);
|
|
#endif
|
|
Py_DECREF(args);
|
|
Py_DECREF(formatObj);
|
|
return result;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// cxoUtils_getAdjustedEncoding()
|
|
// Return the adjusted encoding to use when encoding and decoding strings
|
|
// that are passed to and from the Oracle database. The Oracle client interface
|
|
// does not support the inclusion of a BOM in the encoded string but assumes
|
|
// native endian order for UTF-16. Python generates a BOM at the beginning of
|
|
// the encoded string if plain UTF-16 is specified. For this reason, the
|
|
// correct byte order must be determined and used inside Python so that the
|
|
// Oracle client receives the data it expects.
|
|
//-----------------------------------------------------------------------------
|
|
const char *cxoUtils_getAdjustedEncoding(const char *encoding)
|
|
{
|
|
static const union {
|
|
unsigned char bytes[4];
|
|
uint32_t value;
|
|
} hostOrder = { { 0, 1, 2, 3 } };
|
|
|
|
if (!encoding || strcmp(encoding, "UTF-16") != 0)
|
|
return encoding;
|
|
return (hostOrder.value == 0x03020100) ? "UTF-16LE" : "UTF-16BE";
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// cxoUtils_getBooleanValue()
|
|
// Get a boolean value from a Python object.
|
|
//-----------------------------------------------------------------------------
|
|
int cxoUtils_getBooleanValue(PyObject *obj, int defaultValue, int *value)
|
|
{
|
|
if (!obj)
|
|
*value = defaultValue;
|
|
else {
|
|
*value = PyObject_IsTrue(obj);
|
|
if (*value < 0)
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// cxoUtils_getModuleAndName()
|
|
// Return the module and name for the type.
|
|
//-----------------------------------------------------------------------------
|
|
int cxoUtils_getModuleAndName(PyTypeObject *type, PyObject **module,
|
|
PyObject **name)
|
|
{
|
|
*module = PyObject_GetAttrString( (PyObject*) type, "__module__");
|
|
if (!*module)
|
|
return -1;
|
|
*name = PyObject_GetAttrString( (PyObject*) type, "__name__");
|
|
if (!*name) {
|
|
Py_DECREF(*module);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// cxoUtils_initializeDPI()
|
|
// Initialize the ODPI-C library. This is done when the first standalone
|
|
// connection or session pool is created, rather than when the module is first
|
|
// imported so that manipulating environment variables such as NLS_LANG will
|
|
// work as expected. It also has the additional benefit of reducing the number
|
|
// of errors that can take place when the module is imported.
|
|
//-----------------------------------------------------------------------------
|
|
int cxoUtils_initializeDPI(void)
|
|
{
|
|
dpiErrorInfo errorInfo;
|
|
dpiContext *context;
|
|
|
|
if (!cxoDpiContext) {
|
|
if (dpiContext_create(DPI_MAJOR_VERSION, DPI_MINOR_VERSION,
|
|
&context, &errorInfo) < 0)
|
|
return cxoError_raiseFromInfo(&errorInfo);
|
|
if (dpiContext_getClientVersion(context, &cxoClientVersionInfo) < 0)
|
|
return cxoError_raiseAndReturnInt();
|
|
cxoDpiContext = context;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// cxoUtils_processJsonArg()
|
|
// Process the argument which is expected to be either a string or bytes, or
|
|
// a dictionary or list which is converted to a string via the json.dumps()
|
|
// method. All strings are encoded to UTF-8 which is what SODA expects.
|
|
//-----------------------------------------------------------------------------
|
|
int cxoUtils_processJsonArg(PyObject *arg, cxoBuffer *buffer)
|
|
{
|
|
int converted = 0;
|
|
|
|
if (arg && (PyDict_Check(arg) || PyList_Check(arg))) {
|
|
arg = PyObject_CallFunctionObjArgs(cxoJsonDumpFunction, arg, NULL);
|
|
if (!arg)
|
|
return -1;
|
|
converted = 1;
|
|
}
|
|
if (cxoBuffer_fromObject(buffer, arg, "UTF-8") < 0)
|
|
return -1;
|
|
if (converted)
|
|
Py_DECREF(arg);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// cxoUtils_processSodaDocArg()
|
|
// Process a SODA document argument. This is expectd to be an actual SODA
|
|
// document object or a dictionary. If the argument refers to a dictionary or
|
|
// list, a new SODA document will be created with the given content and without
|
|
// a key or media type specified.
|
|
//-----------------------------------------------------------------------------
|
|
int cxoUtils_processSodaDocArg(cxoSodaDatabase *db, PyObject *arg,
|
|
dpiSodaDoc **handle)
|
|
{
|
|
cxoBuffer buffer;
|
|
cxoSodaDoc *doc;
|
|
|
|
if (PyObject_TypeCheck(arg, &cxoPyTypeSodaDoc)) {
|
|
doc = (cxoSodaDoc*) arg;
|
|
if (dpiSodaDoc_addRef(doc->handle) < 0)
|
|
return cxoError_raiseAndReturnInt();
|
|
*handle = doc->handle;
|
|
} else if (PyDict_Check(arg) || PyList_Check(arg)) {
|
|
arg = PyObject_CallFunctionObjArgs(cxoJsonDumpFunction, arg, NULL);
|
|
if (!arg)
|
|
return -1;
|
|
if (cxoBuffer_fromObject(&buffer, arg, "UTF-8") < 0) {
|
|
Py_DECREF(arg);
|
|
return -1;
|
|
}
|
|
Py_DECREF(arg);
|
|
if (dpiSodaDb_createDocument(db->handle, NULL, 0, buffer.ptr,
|
|
buffer.size, NULL, 0, DPI_SODA_FLAGS_DEFAULT, handle) < 0) {
|
|
cxoBuffer_clear(&buffer);
|
|
return cxoError_raiseAndReturnInt();
|
|
}
|
|
cxoBuffer_clear(&buffer);
|
|
} else {
|
|
PyErr_SetString(PyExc_TypeError,
|
|
"value must be a SODA document or a dictionary or list");
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|