//----------------------------------------------------------------------------- // 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; }