8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-27 06:03:02 +01:00
firebird-mirror/src/common/fb_exception.cpp

344 lines
7.8 KiB
C++
Raw Normal View History

2003-02-17 14:28:17 +01:00
#include "firebird.h"
//#include "fb_exception.h"
2002-11-11 19:06:01 +01:00
#include <string.h>
#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 {
public:
2005-12-25 05:01:49 +01:00
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);
buffer_lock.leave();
return new_string;
}
private:
Firebird::Mutex buffer_lock;
};
ISC_STATUS dupStringTemp(const char* s)
{
const size_t len = strlen(s);
char *string = FB_NEW(*getDefaultMemoryPool()) char[len + 1];
memcpy(string, s, len + 1);
return (ISC_STATUS)(IPTR)(string);
}
2002-11-11 19:06:01 +01:00
void fill_status(ISC_STATUS *ptr, ISC_STATUS status, va_list status_args)
{
// Move in status and clone transient strings
*ptr++ = isc_arg_gds;
*ptr++ = status;
2006-04-06 10:18:53 +02:00
while (true)
{
const ISC_STATUS type = *ptr++ = va_arg(status_args, ISC_STATUS);
2004-03-07 08:58:55 +01:00
if (type == isc_arg_end)
break;
switch (type) {
case isc_arg_cstring:
{
const size_t len = *ptr++ = va_arg(status_args, ISC_STATUS);
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));
memcpy(string, temp, len);
2004-03-07 08:58:55 +01:00
*ptr++ = (ISC_STATUS)(IPTR)(string);
break;
}
case isc_arg_string:
case isc_arg_interpreted:
{
*ptr++ = dupStringTemp(reinterpret_cast<char*>(va_arg(status_args, ISC_STATUS)));
break;
}
default:
*ptr++ = va_arg(status_args, ISC_STATUS);
break;
}
2006-04-06 10:18:53 +02:00
}
2002-11-11 19:06:01 +01:00
}
} // namespace
namespace Firebird {
/********************************* status_exception *******************************/
status_exception::status_exception() throw() :
m_strings_permanent(true)
2004-03-07 08:58:55 +01:00
{
memset(m_status_vector, 0, sizeof(m_status_vector));
}
status_exception::status_exception(const ISC_STATUS *status_vector, bool permanent) throw() :
m_strings_permanent(permanent)
2004-03-07 08:58:55 +01:00
{
ISC_STATUS *ptr = m_status_vector;
while (true)
{
const ISC_STATUS type = *ptr++ = *status_vector++;
if (type == isc_arg_end)
break;
if (type == isc_arg_cstring)
*ptr++ = *status_vector++;
*ptr++ = *status_vector++;
}
}
2006-01-08 02:11:06 +01:00
void status_exception::set_status(const ISC_STATUS *new_vector, bool permanent) throw()
{
release_vector();
m_strings_permanent = permanent;
fb_assert(new_vector != 0);
memcpy(m_status_vector, new_vector, sizeof(m_status_vector));
}
void status_exception::release_vector() throw()
2005-12-25 05:01:49 +01:00
{
if (m_strings_permanent)
2004-03-07 08:58:55 +01:00
return;
// Free owned strings
ISC_STATUS *ptr = m_status_vector;
2006-04-06 10:18:53 +02:00
while (true)
{
2004-03-07 08:58:55 +01:00
const ISC_STATUS type = *ptr++;
if (type == isc_arg_end)
break;
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;
}
2006-04-06 10:18:53 +02:00
}
}
status_exception::~status_exception() throw()
{
release_vector();
}
2005-12-25 05:01:49 +01:00
void fatal_exception::raiseFmt(const char* format, ...)
{
va_list args;
va_start(args, format);
char buffer[1024];
VSNPRINTF(buffer, sizeof(buffer), format, args);
2004-11-16 06:03:43 +01:00
buffer[sizeof(buffer) - 1] = 0;
va_end(args);
throw fatal_exception(buffer);
}
2004-03-07 08:58:55 +01:00
void status_exception::raise(const ISC_STATUS *status_vector)
{
throw status_exception(status_vector, true);
}
2004-03-07 08:58:55 +01:00
void status_exception::raise(ISC_STATUS status, ...)
{
va_list args;
va_start(args, status);
ISC_STATUS_ARRAY temp;
fill_status(temp, status, args);
va_end(args);
throw status_exception(temp, false);
}
/********************************* BadAlloc ****************************/
void BadAlloc::raise()
{
throw BadAlloc();
}
/********************************* LongJump ****************************/
void LongJump::raise()
{
throw LongJump();
}
/********************************* system_call_failed ****************************/
system_call_failed::system_call_failed(const char* v_syscall, int v_error_code) :
status_exception(0, false), errorCode(v_error_code)
{
ISC_STATUS temp[] = {isc_arg_gds,
isc_sys_request,
isc_arg_string, dupStringTemp(v_syscall),
SYS_ARG, errorCode,
isc_arg_end};
set_status(temp, false);
}
void system_call_failed::raise(const char* syscall, int error_code)
2002-11-11 19:06:01 +01:00
{
throw system_call_failed(syscall, error_code);
2002-11-11 19:06:01 +01:00
}
void system_call_failed::raise(const char* syscall)
2002-11-11 19:06:01 +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
}
/********************************* fatal_exception ********************************/
fatal_exception::fatal_exception(const char* message) :
status_exception(0, false)
2002-11-11 19:06:01 +01:00
{
ISC_STATUS temp[] = {isc_arg_gds,
isc_random,
isc_arg_string, dupStringTemp(message),
isc_arg_end};
set_status(temp, false);
2002-11-11 19:06:01 +01:00
}
// Moved to the header due to gpre. Gpre non-static can't receive it, but we
// want to avoid problems with picky compilers that can't find what().
// We can't link this file into normal gpre.
// Keep in sync with the constructor above, please; "message" becomes 4th element
// after initialization of status vector.
//const char* fatal_exception::what() const throw()
//{
// return reinterpret_cast<const char*>(value()[3]);
//}
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);
}
/************************** exception handling routines ***************************/
static InterlockedStringsBuffer engine_failures;
ISC_STATUS stuff_exception(ISC_STATUS* const status_vector, const 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;
ISC_STATUS *sv = status_vector;
switch (ex.kind())
{
case Exception::ExMemory:
*sv++ = isc_arg_gds;
*sv++ = isc_virmemexh;
*sv++ = isc_arg_end;
break;
case Exception::ExStatus:
{
const status_exception* c_ex = reinterpret_cast<const status_exception*>(&ex);
const ISC_STATUS *ptr = c_ex->value();
if (c_ex->strings_permanent())
{
// Copy status vector
2006-04-06 10:18:53 +02:00
while (true)
{
2006-01-06 12:21:57 +01:00
const ISC_STATUS type = *sv++ = *ptr++;
2004-03-07 08:58:55 +01:00
if (type == isc_arg_end)
break;
if (type == isc_arg_cstring)
2006-01-06 12:21:57 +01:00
*sv++ = *ptr++;
*sv++ = *ptr++;
2006-04-06 10:18:53 +02:00
}
2004-03-07 08:58:55 +01:00
}
else {
// Move in status and clone transient strings
2006-04-06 10:18:53 +02:00
while (true)
{
2006-01-07 01:34:42 +01:00
const ISC_STATUS type = *sv++ = *ptr++;
2004-03-07 08:58:55 +01:00
if (type == isc_arg_end)
break;
switch (type) {
case isc_arg_cstring:
{
2006-01-07 01:34:42 +01:00
const UCHAR len = *sv++ = *ptr++;
char *temp = reinterpret_cast<char*>(*ptr++);
2006-01-07 01:34:42 +01:00
*sv++ = (ISC_STATUS)(IPTR) (sb->alloc(temp, len));
break;
}
case isc_arg_string:
case isc_arg_interpreted:
{
char *temp = reinterpret_cast<char*>(*ptr++);
2006-01-07 01:34:42 +01:00
*sv++ = (ISC_STATUS)(IPTR) (sb->alloc(temp, strlen(temp)));
break;
}
default:
2006-01-07 01:34:42 +01:00
*sv++ = *ptr++;
break;
}
2006-04-06 10:18:53 +02:00
}
}
}
break;
case Exception::ExJump:
break; // keep SV 'as is'
default:
{
char temp[256];
SNPRINTF(temp, sizeof(temp) - 1,
"Unexpected Firebird::Exception (kind=%d what()=\"%s\")",
ex.kind(), ex.what());
temp[sizeof(temp) - 1] = 0;
*sv++ = isc_arg_gds;
*sv++ = isc_random;
*sv++ = isc_arg_string;
*sv++ = (ISC_STATUS)(IPTR) (sb->alloc(temp, strlen(temp)));
*sv++ = isc_arg_end;
}
break;
2004-03-07 08:58:55 +01:00
}
return status_vector[1];
}
2004-03-07 08:58:55 +01:00
const char* status_string(const char* string)
{
return status_nstring(string, strlen(string));
}
2004-03-07 08:58:55 +01:00
const char* status_nstring(const char* string, size_t length)
{
return engine_failures.alloc(string, length);
}
2002-11-11 19:06:01 +01:00
} // namespace Firebird
2003-12-31 06:36:12 +01:00