/* KInterbasDB Python Package - Implementation of "Exception-Raising" Functions ** ** Version 3.1 ** ** The following contributors hold Copyright (C) over their respective ** portions of code (see license.txt for details): ** ** [Original Author (maintained through version 2.0-0.3.1):] ** 1998-2001 [alex] Alexander Kuznetsov ** [Maintainers (after version 2.0-0.3.1):] ** 2001-2002 [maz] Marek Isalski ** 2002-2004 [dsr] David Rushby ** [Contributors:] ** 2001 [eac] Evgeny A. Cherkashin ** 2001-2002 [janez] Janez Jere */ /******************** EXCEPTION FUNCTIONS:BEGIN ********************/ #if (defined(FIREBIRD_2_0_OR_LATER) && !defined(COMPILER_IS_MINGW_WIN32)) #define USE_MODERN_INTERP_FUNC #endif void raise_sql_exception( PyObject *excType, const char *preamble, ISC_STATUS *status_vector ) { /* Given the type of exception to raise ($excType), an introductory message ** ($preamble), and the status vector into which a Firebird API function has ** stored numeric error codes ($status_vector), ** set a Python exception bearing the following payload: ** (numeric database API error code, error message) */ char buf[MAX_ISC_ERROR_MESSAGE_BUFFER_SIZE]; /* DSR: Buffer overflow potential here is low, since only values supplied ** by the database library's interpret function are placed in the ** fixed-size buffer, and presumably it checks the size of the input buffer ** (a parameter for this purpose was added in FB 2.0). ** ** The only exception is the strcat that adds a period and a space, which ** is compensated for by the code. ** ** The variable-length parameter $preamble is handled dynamically (with ** PyString_FromString), so it poses no risk. */ ISC_LONG db_error_code; #ifdef USE_MODERN_INTERP_FUNC const #endif ISC_STATUS *ptr_status_vector = #ifdef USE_MODERN_INTERP_FUNC (const ISC_STATUS *) #endif status_vector ; PyObject *message = NULL; PyObject *next_message_segment = NULL; /* Not strictly necessary, but this code is far from performance-critical: */ memset(buf, '\0', MAX_ISC_ERROR_MESSAGE_BUFFER_SIZE); message = PyString_FromString( (preamble != NULL ? preamble : "") ); if (message == NULL) { goto LOW_MEMORY; } ENTER_DB_WITHOUT_LEAVING_PYTHON db_error_code = isc_sqlcode(status_vector); #ifdef USE_MODERN_INTERP_FUNC while (fb_interpret(buf, MAX_ISC_ERROR_MESSAGE_BUFFER_SIZE - 3, &ptr_status_vector)) { #else while (isc_interprete(buf, &ptr_status_vector)) { #endif /* This strcat compensated for by '- 3' passed to fb_interpret: */ strcat(buf, ". "); next_message_segment = PyString_FromString(buf); if (next_message_segment == NULL) { LEAVE_DB_WITHOUT_ENTERING_PYTHON goto LOW_MEMORY; } PyString_ConcatAndDel(&message, next_message_segment); /* PyString_ConcatAndDel has already DECREFed next_message_segment. */ next_message_segment = NULL; if (message == NULL) { LEAVE_DB_WITHOUT_ENTERING_PYTHON goto LOW_MEMORY; } } LEAVE_DB_WITHOUT_ENTERING_PYTHON { /* Raise an exception whose payload consists of a tuple of the form ** (error_code, error_message): */ PyObject *exceptionTuple = Py_BuildValue("(iO)", (long) db_error_code, message); if (exceptionTuple == NULL) { goto LOW_MEMORY; } PyErr_SetObject(excType, exceptionTuple); Py_DECREF(exceptionTuple); } /* Release the last Python string object stored in $message by ** PyString_ConcatAndDel: */ Py_DECREF(message); return; LOW_MEMORY: PyErr_NoMemory(); Py_XDECREF(message); } /* raise_sql_exception */ static void raise_exception_with_numeric_error_code( PyObject *excType, int error_code, const char *description ) { /* raise_exception_with_numeric_error_code allows the database API error code ** to be set directly, rather than having it extracted from a status vector. ** Thus, raise_exception_with_numeric_error_code might be said to "fall ** midway between raise_sql_exception and raise_exception". */ PyObject *exceptionTuple = Py_BuildValue("(is)", error_code, description); if (exceptionTuple == NULL) { PyErr_NoMemory(); return; } PyErr_SetObject(excType, exceptionTuple); Py_DECREF(exceptionTuple); } /* raise_exception_with_numeric_error_code */ void raise_exception(PyObject *excType, const char *description) { raise_exception_with_numeric_error_code(excType, 0, description); } /* raise_exception */ /******************** EXCEPTION FUNCTIONS:END ********************/