2003-02-17 14:28:17 +01:00
|
|
|
#include "firebird.h"
|
|
|
|
|
|
|
|
//#include "fb_exception.h"
|
2002-04-04 07:33:01 +02:00
|
|
|
|
2002-11-11 19:06:01 +01:00
|
|
|
#include <string.h>
|
2004-03-01 04:35:23 +01:00
|
|
|
#include <typeinfo>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include "gen/iberror.h"
|
|
|
|
#include "../common/classes/alloc.h"
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
// This logic taken from JRD is bad, bad, bad!
|
|
|
|
// Replace it with attachment-level buffers whenever possible
|
|
|
|
const size_t ENGINE_FAILURE_SPACE = 4096;
|
|
|
|
|
2004-03-07 08:58:55 +01:00
|
|
|
typedef Firebird::CircularStringsBuffer<ENGINE_FAILURE_SPACE> CircularBuffer;
|
|
|
|
|
|
|
|
class InterlockedStringsBuffer : public CircularBuffer {
|
2004-03-01 04:35:23 +01:00
|
|
|
public:
|
|
|
|
virtual char* alloc(const char* string, size_t length) {
|
|
|
|
buffer_lock.enter();
|
2004-03-07 08:58:55 +01:00
|
|
|
char* new_string = CircularBuffer::alloc(string, length);
|
2004-03-01 04:35:23 +01:00
|
|
|
buffer_lock.leave();
|
|
|
|
return new_string;
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
Firebird::Mutex buffer_lock;
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
2002-11-11 19:06:01 +01:00
|
|
|
|
|
|
|
namespace Firebird {
|
|
|
|
|
2004-03-01 04:35:23 +01:00
|
|
|
/********************************* status_exception *******************************/
|
|
|
|
|
|
|
|
status_exception::status_exception() throw() :
|
|
|
|
m_strings_permanent(true), m_status_known(false)
|
2002-04-04 07:33:01 +02:00
|
|
|
{
|
2004-03-01 04:35:23 +01:00
|
|
|
memset(m_status_vector, 0, sizeof(m_status_vector));
|
2002-04-04 07:33:01 +02:00
|
|
|
}
|
2002-11-11 19:06:01 +01:00
|
|
|
|
2004-03-01 04:35:23 +01:00
|
|
|
status_exception::status_exception(const ISC_STATUS *status_vector) throw() :
|
|
|
|
m_strings_permanent(true), m_status_known(status_vector != NULL)
|
|
|
|
{
|
|
|
|
if (m_status_known) {
|
|
|
|
ISC_STATUS *ptr = m_status_vector;
|
|
|
|
do {
|
2004-03-07 08:58:55 +01:00
|
|
|
const ISC_STATUS type = *ptr++ = *status_vector++;
|
|
|
|
if (type == isc_arg_end)
|
|
|
|
break;
|
|
|
|
if (type == isc_arg_cstring)
|
|
|
|
*ptr++ = *status_vector++;
|
2004-03-01 04:35:23 +01:00
|
|
|
*ptr++ = *status_vector++;
|
|
|
|
} while(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void status_exception::fill_status(ISC_STATUS status, va_list status_args)
|
2002-11-11 19:06:01 +01:00
|
|
|
{
|
2004-03-01 04:35:23 +01:00
|
|
|
m_strings_permanent = false;
|
|
|
|
m_status_known = true;
|
|
|
|
// Move in status and clone transient strings
|
|
|
|
ISC_STATUS *ptr = m_status_vector;
|
|
|
|
*ptr++ = isc_arg_gds;
|
|
|
|
*ptr++ = status;
|
|
|
|
do {
|
|
|
|
ISC_STATUS type = *ptr++ = va_arg(status_args, ISC_STATUS);
|
2004-03-07 08:58:55 +01:00
|
|
|
if (type == isc_arg_end)
|
|
|
|
break;
|
|
|
|
|
2004-03-01 04:35:23 +01:00
|
|
|
switch(type) {
|
|
|
|
case isc_arg_cstring:
|
|
|
|
{
|
2004-03-07 08:58:55 +01:00
|
|
|
const UCHAR len = *ptr++ = va_arg(status_args, ISC_STATUS);
|
2004-03-01 04:35:23 +01:00
|
|
|
char *string = FB_NEW(*getDefaultMemoryPool()) char[len];
|
2004-03-07 08:58:55 +01:00
|
|
|
const char *temp = reinterpret_cast<char*>(va_arg(status_args, ISC_STATUS));
|
2004-03-01 04:35:23 +01:00
|
|
|
memcpy(string, temp, len);
|
2004-03-07 08:58:55 +01:00
|
|
|
*ptr++ = (ISC_STATUS)(IPTR)(string);
|
2004-03-01 04:35:23 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case isc_arg_string:
|
|
|
|
case isc_arg_interpreted:
|
|
|
|
{
|
|
|
|
char *temp = reinterpret_cast<char*>(va_arg(status_args, ISC_STATUS));
|
2004-03-07 08:58:55 +01:00
|
|
|
const size_t len = strlen(temp);
|
|
|
|
char *string = FB_NEW(*getDefaultMemoryPool()) char[len + 1];
|
|
|
|
memcpy(string, temp, len + 1);
|
|
|
|
*ptr++ = (ISC_STATUS)(IPTR)(string);
|
2004-03-01 04:35:23 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
*ptr++ = va_arg(status_args, ISC_STATUS);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} while (true);
|
2002-11-11 19:06:01 +01:00
|
|
|
}
|
|
|
|
|
2004-03-07 08:58:55 +01:00
|
|
|
status_exception::status_exception(ISC_STATUS status, va_list status_args)
|
|
|
|
{
|
2004-03-01 04:35:23 +01:00
|
|
|
fill_status(status, status_args);
|
|
|
|
}
|
|
|
|
|
2004-03-07 08:58:55 +01:00
|
|
|
status_exception::status_exception(ISC_STATUS status, ...)
|
|
|
|
{
|
2004-03-01 04:35:23 +01:00
|
|
|
va_list args;
|
|
|
|
va_start(args, status);
|
|
|
|
fill_status(status, args);
|
|
|
|
va_end(args);
|
|
|
|
}
|
|
|
|
|
|
|
|
status_exception::~status_exception() throw() {
|
2004-03-07 08:58:55 +01:00
|
|
|
if (m_strings_permanent)
|
|
|
|
return;
|
2004-03-01 04:35:23 +01:00
|
|
|
|
|
|
|
// Free owned strings
|
|
|
|
ISC_STATUS *ptr = m_status_vector;
|
|
|
|
do {
|
2004-03-07 08:58:55 +01:00
|
|
|
const ISC_STATUS type = *ptr++;
|
|
|
|
if (type == isc_arg_end)
|
|
|
|
break;
|
|
|
|
|
2004-03-01 04:35:23 +01:00
|
|
|
switch(type) {
|
|
|
|
case isc_arg_cstring:
|
|
|
|
ptr++;
|
|
|
|
delete[] reinterpret_cast<char*>(*ptr++);
|
|
|
|
break;
|
|
|
|
case isc_arg_string:
|
|
|
|
case isc_arg_interpreted:
|
|
|
|
delete[] reinterpret_cast<char*>(*ptr++);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ptr++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} while(true);
|
|
|
|
}
|
|
|
|
|
2004-03-07 08:58:55 +01:00
|
|
|
void status_exception::raise()
|
|
|
|
{
|
2004-03-01 04:35:23 +01:00
|
|
|
throw status_exception();
|
|
|
|
}
|
|
|
|
|
2004-03-07 08:58:55 +01:00
|
|
|
void status_exception::raise(const ISC_STATUS *status_vector)
|
|
|
|
{
|
2004-03-01 04:35:23 +01:00
|
|
|
throw status_exception(status_vector);
|
|
|
|
}
|
|
|
|
|
2004-03-07 08:58:55 +01:00
|
|
|
void status_exception::raise(ISC_STATUS status, ...)
|
|
|
|
{
|
2004-03-01 04:35:23 +01:00
|
|
|
va_list args;
|
|
|
|
va_start(args, status);
|
|
|
|
status_exception ex(status, args);
|
|
|
|
va_end(args);
|
|
|
|
throw ex;
|
|
|
|
}
|
|
|
|
|
|
|
|
/********************************* system_call_failed ****************************/
|
|
|
|
|
2004-03-01 17:50:26 +01:00
|
|
|
system_call_failed::system_call_failed(const char* v_syscall, int v_error_code) :
|
|
|
|
status_exception(isc_sys_request, isc_arg_string, v_syscall, SYS_ARG, v_error_code, isc_arg_end)
|
2004-03-01 04:35:23 +01:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void system_call_failed::raise(const char* syscall, int error_code)
|
2002-11-11 19:06:01 +01:00
|
|
|
{
|
2004-03-01 04:35:23 +01:00
|
|
|
throw system_call_failed(syscall, error_code);
|
2002-11-11 19:06:01 +01:00
|
|
|
}
|
|
|
|
|
2004-03-01 04:35:23 +01:00
|
|
|
void system_call_failed::raise(const char* syscall)
|
2002-11-11 19:06:01 +01:00
|
|
|
{
|
2004-03-01 04:35:23 +01:00
|
|
|
#ifdef WIN_NT
|
|
|
|
int error_code = GetLastError();
|
|
|
|
#else
|
|
|
|
int error_code = errno;
|
|
|
|
#endif
|
|
|
|
throw system_call_failed(syscall, error_code);
|
2002-11-11 19:06:01 +01:00
|
|
|
}
|
|
|
|
|
2004-03-01 04:35:23 +01:00
|
|
|
/********************************* fatal_exception ********************************/
|
|
|
|
|
|
|
|
fatal_exception::fatal_exception(const char* message) :
|
|
|
|
status_exception(isc_random, message, isc_arg_end)
|
2002-11-11 19:06:01 +01:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
void fatal_exception::raise(const char* message)
|
2002-11-11 19:06:01 +01:00
|
|
|
{
|
|
|
|
throw fatal_exception(message);
|
|
|
|
}
|
|
|
|
|
2004-03-01 04:35:23 +01:00
|
|
|
/************************** exception handling routines ***************************/
|
|
|
|
|
|
|
|
static InterlockedStringsBuffer engine_failures;
|
|
|
|
|
|
|
|
ISC_STATUS stuff_exception(ISC_STATUS *status_vector, const std::exception& ex, StringsBuffer *sb) throw()
|
|
|
|
{
|
|
|
|
// Note that this function will call unexpected() that will terminate process
|
|
|
|
// if exception appears during status vector serialization
|
|
|
|
|
2004-03-07 08:58:55 +01:00
|
|
|
if (!sb)
|
|
|
|
sb = &engine_failures;
|
2004-03-01 04:35:23 +01:00
|
|
|
|
|
|
|
const std::type_info& ex_type = typeid(ex);
|
|
|
|
|
|
|
|
if (ex_type == typeid(std::bad_alloc)) {
|
|
|
|
*status_vector++ = isc_arg_gds;
|
|
|
|
*status_vector++ = isc_virmemexh;
|
|
|
|
*status_vector++ = isc_arg_end;
|
|
|
|
return isc_virmemexh;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
const status_exception& c_ex = dynamic_cast<const status_exception&>(ex);
|
|
|
|
if (c_ex.status_known()) {
|
|
|
|
const ISC_STATUS *ptr = c_ex.value();
|
|
|
|
if (c_ex.strings_permanent())
|
|
|
|
{
|
|
|
|
// Copy status vector
|
|
|
|
do {
|
2004-03-07 08:58:55 +01:00
|
|
|
const ISC_STATUS type = *status_vector++ = *ptr++;
|
|
|
|
if (type == isc_arg_end)
|
|
|
|
break;
|
|
|
|
if (type == isc_arg_cstring)
|
|
|
|
*status_vector++ = *ptr++;
|
2004-03-01 04:35:23 +01:00
|
|
|
*status_vector++ = *ptr++;
|
|
|
|
} while(true);
|
2004-03-07 08:58:55 +01:00
|
|
|
}
|
|
|
|
else {
|
2004-03-01 04:35:23 +01:00
|
|
|
// Move in status and clone transient strings
|
|
|
|
do {
|
2004-03-07 08:58:55 +01:00
|
|
|
const ISC_STATUS type = *status_vector++ = *ptr++;
|
|
|
|
if (type == isc_arg_end)
|
|
|
|
break;
|
|
|
|
|
2004-03-01 04:35:23 +01:00
|
|
|
switch(type) {
|
|
|
|
case isc_arg_cstring:
|
|
|
|
{
|
2004-03-07 08:58:55 +01:00
|
|
|
const UCHAR len = *status_vector++ = *ptr++;
|
2004-03-01 04:35:23 +01:00
|
|
|
char *temp = reinterpret_cast<char*>(*ptr++);
|
2004-03-07 08:58:55 +01:00
|
|
|
*status_vector++ = (ISC_STATUS)(IPTR) (sb->alloc(temp, len));
|
2004-03-01 04:35:23 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case isc_arg_string:
|
|
|
|
case isc_arg_interpreted:
|
|
|
|
{
|
|
|
|
char *temp = reinterpret_cast<char*>(*ptr++);
|
2004-03-07 08:58:55 +01:00
|
|
|
*status_vector++ = (ISC_STATUS)(IPTR) (sb->alloc(temp, strlen(temp)));
|
2004-03-01 04:35:23 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
2004-03-07 08:58:55 +01:00
|
|
|
*status_vector++ = *ptr++;
|
2004-03-01 04:35:23 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
} while (true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return status_vector[1];
|
2004-03-07 08:58:55 +01:00
|
|
|
}
|
|
|
|
catch (const std::bad_cast&) {
|
2004-03-01 04:35:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Other random C++ exceptions
|
|
|
|
char temp[256];
|
2004-03-09 01:17:07 +01:00
|
|
|
SNPRINTF(temp, sizeof(temp)-1, "Unexpected C++ exception (class=\"%s\", what()=\"%s\")",
|
2004-03-01 04:35:23 +01:00
|
|
|
ex_type.name(), ex.what());
|
2004-03-07 08:58:55 +01:00
|
|
|
temp[sizeof(temp) - 1] = 0;
|
|
|
|
*status_vector++ = isc_arg_gds;
|
|
|
|
*status_vector++ = isc_random;
|
|
|
|
*status_vector++ = isc_arg_string;
|
|
|
|
*status_vector++ = (ISC_STATUS)(IPTR) (sb->alloc(temp, strlen(temp)));
|
|
|
|
*status_vector++ = isc_arg_end;
|
2004-03-01 04:35:23 +01:00
|
|
|
return isc_random;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-07 08:58:55 +01:00
|
|
|
const char* status_string(const char* string)
|
|
|
|
{
|
2004-03-01 04:35:23 +01:00
|
|
|
return status_nstring(string, strlen(string));
|
|
|
|
}
|
|
|
|
|
2004-03-07 08:58:55 +01:00
|
|
|
const char* status_nstring(const char* string, size_t length)
|
|
|
|
{
|
2004-03-01 04:35:23 +01:00
|
|
|
return engine_failures.alloc(string, length);
|
|
|
|
}
|
|
|
|
|
2002-11-11 19:06:01 +01:00
|
|
|
} // namespace Firebird
|
2003-12-31 06:36:12 +01:00
|
|
|
|