place internally when fetching strings from the database (https://github.com/oracle/python-cx_Oracle/issues/162).
332 lines
11 KiB
C
332 lines
11 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.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// cxoError.c
|
|
// Error handling.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include "cxoModule.h"
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// forward declarations
|
|
//-----------------------------------------------------------------------------
|
|
static void cxoError_free(cxoError *error);
|
|
static PyObject *cxoError_str(cxoError *error);
|
|
static PyObject *cxoError_new(PyTypeObject *type, PyObject *args,
|
|
PyObject *keywordArgs);
|
|
static PyObject *cxoError_reduce(cxoError*);
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// declaration of methods
|
|
//-----------------------------------------------------------------------------
|
|
static PyMethodDef cxoErrorMethods[] = {
|
|
{ "__reduce__", (PyCFunction) cxoError_reduce, METH_NOARGS },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// declaration of members
|
|
//-----------------------------------------------------------------------------
|
|
static PyMemberDef cxoErrorMembers[] = {
|
|
{ "code", T_LONG, offsetof(cxoError, code), READONLY },
|
|
{ "offset", T_UINT, offsetof(cxoError, offset), READONLY },
|
|
{ "message", T_OBJECT, offsetof(cxoError, message), READONLY },
|
|
{ "context", T_OBJECT, offsetof(cxoError, context), READONLY },
|
|
{ "isrecoverable", T_BOOL, offsetof(cxoError, isRecoverable), READONLY },
|
|
{ NULL }
|
|
};
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// declaration of Python type
|
|
//-----------------------------------------------------------------------------
|
|
PyTypeObject cxoPyTypeError = {
|
|
PyVarObject_HEAD_INIT(NULL, 0)
|
|
"cx_Oracle._Error", // tp_name
|
|
sizeof(cxoError), // tp_basicsize
|
|
0, // tp_itemsize
|
|
(destructor) cxoError_free, // tp_dealloc
|
|
0, // tp_print
|
|
0, // tp_getattr
|
|
0, // tp_setattr
|
|
0, // tp_compare
|
|
0, // tp_repr
|
|
0, // tp_as_number
|
|
0, // tp_as_sequence
|
|
0, // tp_as_mapping
|
|
0, // tp_hash
|
|
0, // tp_call
|
|
(reprfunc) cxoError_str, // 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
|
|
cxoErrorMethods, // tp_methods
|
|
cxoErrorMembers, // tp_members
|
|
0, // tp_getset
|
|
0, // tp_base
|
|
0, // tp_dict
|
|
0, // tp_descr_get
|
|
0, // tp_descr_set
|
|
0, // tp_dictoffset
|
|
0, // tp_init
|
|
0, // tp_alloc
|
|
cxoError_new, // tp_new
|
|
0, // tp_free
|
|
0, // tp_is_gc
|
|
0 // tp_bases
|
|
};
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// cxoError_free()
|
|
// Deallocate the error.
|
|
//-----------------------------------------------------------------------------
|
|
static void cxoError_free(cxoError *error)
|
|
{
|
|
Py_CLEAR(error->message);
|
|
Py_CLEAR(error->context);
|
|
PyObject_Del(error);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// cxoError_new()
|
|
// Create a new error object. This is intended to only be used by the
|
|
// unpickling routine, and not by direct creation!
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *cxoError_new(PyTypeObject *type, PyObject *args,
|
|
PyObject *keywordArgs)
|
|
{
|
|
PyObject *message, *context;
|
|
int isRecoverable, code;
|
|
cxoError *error;
|
|
unsigned offset;
|
|
|
|
isRecoverable = 0;
|
|
if (!PyArg_ParseTuple(args, "OiIO|i", &message, &code, &offset, &context,
|
|
&isRecoverable))
|
|
return NULL;
|
|
error = (cxoError*) type->tp_alloc(type, 0);
|
|
if (!error)
|
|
return NULL;
|
|
|
|
error->code = code;
|
|
error->offset = offset;
|
|
error->isRecoverable = (char) isRecoverable;
|
|
Py_INCREF(message);
|
|
error->message = message;
|
|
Py_INCREF(context);
|
|
error->context = context;
|
|
|
|
return (PyObject*) error;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// cxoError_newFromInfo()
|
|
// Internal method for creating an error object from the DPI error
|
|
// information.
|
|
//-----------------------------------------------------------------------------
|
|
cxoError *cxoError_newFromInfo(dpiErrorInfo *errorInfo)
|
|
{
|
|
cxoError *error;
|
|
|
|
// create error object and initialize it
|
|
error = (cxoError*) cxoPyTypeError.tp_alloc(&cxoPyTypeError, 0);
|
|
if (!error)
|
|
return NULL;
|
|
error->code = errorInfo->code;
|
|
error->offset = errorInfo->offset;
|
|
error->isRecoverable = (char) errorInfo->isRecoverable;
|
|
|
|
// create message
|
|
error->message = cxoPyString_fromEncodedString(errorInfo->message,
|
|
errorInfo->messageLength, errorInfo->encoding, NULL);
|
|
if (!error->message) {
|
|
Py_DECREF(error);
|
|
return NULL;
|
|
}
|
|
|
|
// create context composed of function name and action
|
|
#if PY_MAJOR_VERSION >= 3
|
|
error->context = PyUnicode_FromFormat("%s: %s", errorInfo->fnName,
|
|
errorInfo->action);
|
|
#else
|
|
error->context = PyString_FromFormat("%s: %s", errorInfo->fnName,
|
|
errorInfo->action);
|
|
#endif
|
|
if (!error->context) {
|
|
Py_DECREF(error);
|
|
return NULL;
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// cxoError_newFromString()
|
|
// Internal method for creating an error object from the DPI error
|
|
// information.
|
|
//-----------------------------------------------------------------------------
|
|
static cxoError *cxoError_newFromString(const char *message)
|
|
{
|
|
cxoError *error;
|
|
|
|
error = (cxoError*) cxoPyTypeError.tp_alloc(&cxoPyTypeError, 0);
|
|
if (!error)
|
|
return NULL;
|
|
Py_INCREF(Py_None);
|
|
error->context = Py_None;
|
|
error->message = cxoPyString_fromAscii(message);
|
|
if (!error->message) {
|
|
Py_DECREF(error);
|
|
return NULL;
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// cxoError_raiseAndReturnInt()
|
|
// Internal method for raising an exception from an error generated from DPI.
|
|
// Return -1 as a convenience to the caller.
|
|
//-----------------------------------------------------------------------------
|
|
int cxoError_raiseAndReturnInt(void)
|
|
{
|
|
dpiErrorInfo errorInfo;
|
|
|
|
dpiContext_getError(cxoDpiContext, &errorInfo);
|
|
return cxoError_raiseFromInfo(&errorInfo);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// cxoError_raiseAndReturnNull()
|
|
// Internal method for raising an exception from an error generated from DPI.
|
|
// Return NULL as a convenience to the caller.
|
|
//-----------------------------------------------------------------------------
|
|
PyObject *cxoError_raiseAndReturnNull(void)
|
|
{
|
|
cxoError_raiseAndReturnInt();
|
|
return NULL;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// cxoError_raiseFromInfo()
|
|
// Internal method for raising an exception given an error information
|
|
// structure from DPI. Return -1 as a convenience to the caller.
|
|
//-----------------------------------------------------------------------------
|
|
int cxoError_raiseFromInfo(dpiErrorInfo *errorInfo)
|
|
{
|
|
PyObject *exceptionType;
|
|
cxoError *error;
|
|
|
|
error = cxoError_newFromInfo(errorInfo);
|
|
if (!error)
|
|
return -1;
|
|
switch (errorInfo->code) {
|
|
case 1:
|
|
case 1400:
|
|
case 2290:
|
|
case 2291:
|
|
case 2292:
|
|
exceptionType = cxoIntegrityErrorException;
|
|
break;
|
|
case 22:
|
|
case 378:
|
|
case 602:
|
|
case 603:
|
|
case 604:
|
|
case 609:
|
|
case 1012:
|
|
case 1013:
|
|
case 1033:
|
|
case 1034:
|
|
case 1041:
|
|
case 1043:
|
|
case 1089:
|
|
case 1090:
|
|
case 1092:
|
|
case 3113:
|
|
case 3114:
|
|
case 3122:
|
|
case 3135:
|
|
case 12153:
|
|
case 12203:
|
|
case 12500:
|
|
case 12571:
|
|
case 27146:
|
|
case 28511:
|
|
exceptionType = cxoOperationalErrorException;
|
|
break;
|
|
default:
|
|
exceptionType = cxoDatabaseErrorException;
|
|
break;
|
|
}
|
|
PyErr_SetObject(exceptionType, (PyObject*) error);
|
|
Py_DECREF(error);
|
|
return -1;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// cxoError_raiseFromString()
|
|
// Internal method for raising an exception given an error information
|
|
// structure from DPI. Return -1 as a convenience to the caller.
|
|
//-----------------------------------------------------------------------------
|
|
PyObject *cxoError_raiseFromString(PyObject *exceptionType,
|
|
const char *message)
|
|
{
|
|
cxoError *error;
|
|
|
|
error = cxoError_newFromString(message);
|
|
if (!error)
|
|
return NULL;
|
|
PyErr_SetObject(exceptionType, (PyObject*) error);
|
|
Py_DECREF(error);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// cxoError_reduce()
|
|
// Method provided for pickling/unpickling of Error objects.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *cxoError_reduce(cxoError *error)
|
|
{
|
|
return Py_BuildValue("(O(OiIO))", Py_TYPE(error), error->message,
|
|
error->code, error->offset, error->context);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// cxoError_str()
|
|
// Return a string representation of the error variable.
|
|
//-----------------------------------------------------------------------------
|
|
static PyObject *cxoError_str(cxoError *error)
|
|
{
|
|
Py_INCREF(error->message);
|
|
return error->message;
|
|
}
|
|
|