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 <errno.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include "gen/iberror.h"
|
|
|
|
#include "../common/classes/alloc.h"
|
2008-01-23 16:52:40 +01:00
|
|
|
#include "../common/classes/init.h"
|
2004-03-01 04:35:23 +01:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2008-04-19 13:11:10 +02:00
|
|
|
class InterlockedStringsBuffer : public CircularBuffer
|
|
|
|
{
|
2004-03-01 04:35:23 +01:00
|
|
|
public:
|
2008-02-02 17:57:15 +01:00
|
|
|
explicit InterlockedStringsBuffer(Firebird::MemoryPool&)
|
2009-01-03 10:14:29 +01:00
|
|
|
: CircularBuffer()
|
|
|
|
{ }
|
2008-12-05 02:20:14 +01:00
|
|
|
virtual const char* alloc(const char* string, size_t& length)
|
2005-12-25 05:01:49 +01:00
|
|
|
{
|
2008-01-23 16:52:40 +01:00
|
|
|
Firebird::MutexLockGuard guard(buffer_lock);
|
|
|
|
return CircularBuffer::alloc(string, length);
|
2004-03-01 04:35:23 +01:00
|
|
|
}
|
|
|
|
private:
|
|
|
|
Firebird::Mutex buffer_lock;
|
|
|
|
};
|
|
|
|
|
2008-08-27 14:20:47 +02:00
|
|
|
char* dupStringTemp2(const char* s)
|
2002-04-04 07:33:01 +02:00
|
|
|
{
|
2006-01-07 17:55:40 +01:00
|
|
|
const size_t len = strlen(s);
|
|
|
|
char *string = FB_NEW(*getDefaultMemoryPool()) char[len + 1];
|
|
|
|
memcpy(string, s, len + 1);
|
2008-08-27 14:20:47 +02:00
|
|
|
return string;
|
|
|
|
}
|
|
|
|
|
|
|
|
ISC_STATUS dupStringTemp(const char* s)
|
|
|
|
{
|
2008-08-29 04:18:50 +02:00
|
|
|
return (ISC_STATUS)(IPTR) dupStringTemp2(s);
|
2002-04-04 07:33:01 +02:00
|
|
|
}
|
2002-11-11 19:06:01 +01:00
|
|
|
|
2008-07-06 18:42:52 +02:00
|
|
|
void fill_status(ISC_STATUS* ptr, const ISC_STATUS* orig_status)
|
2004-03-01 04:35:23 +01:00
|
|
|
{
|
|
|
|
// Move in status and clone transient strings
|
2008-12-05 02:20:14 +01:00
|
|
|
while (true)
|
2006-04-06 10:18:53 +02:00
|
|
|
{
|
2008-07-03 14:02:54 +02:00
|
|
|
const ISC_STATUS type = *ptr++ = *orig_status++;
|
2008-12-05 02:20:14 +01:00
|
|
|
if (type == isc_arg_end)
|
2004-03-07 08:58:55 +01:00
|
|
|
break;
|
|
|
|
|
2004-10-04 10:15:00 +02:00
|
|
|
switch (type) {
|
2008-12-05 02:20:14 +01:00
|
|
|
case isc_arg_cstring:
|
|
|
|
{
|
2008-07-03 14:02:54 +02:00
|
|
|
const size_t len = *ptr++ = *orig_status++;
|
2004-03-01 04:35:23 +01:00
|
|
|
char *string = FB_NEW(*getDefaultMemoryPool()) char[len];
|
2008-07-03 14:02:54 +02:00
|
|
|
const char *temp = reinterpret_cast<char*>(*orig_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:
|
2008-02-24 16:02:04 +01:00
|
|
|
case isc_arg_sql_state:
|
2004-03-01 04:35:23 +01:00
|
|
|
{
|
2008-07-03 14:02:54 +02:00
|
|
|
*ptr++ = dupStringTemp(reinterpret_cast<char*>(*orig_status++));
|
2004-03-01 04:35:23 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
2008-07-03 14:02:54 +02:00
|
|
|
*ptr++ = *orig_status++;
|
2004-03-01 04:35:23 +01:00
|
|
|
break;
|
|
|
|
}
|
2008-12-05 02:20:14 +01:00
|
|
|
}
|
2002-11-11 19:06:01 +01:00
|
|
|
}
|
|
|
|
|
2008-01-23 16:52:40 +01:00
|
|
|
Firebird::GlobalPtr<InterlockedStringsBuffer> engine_failures;
|
2006-05-22 13:45:19 +02:00
|
|
|
|
2006-01-07 17:55:40 +01:00
|
|
|
} // namespace
|
|
|
|
|
|
|
|
namespace Firebird {
|
|
|
|
|
2007-09-26 19:50:31 +02:00
|
|
|
/********************************* StringsBuffer *******************************/
|
|
|
|
|
|
|
|
void StringsBuffer::makePermanentVector(ISC_STATUS* perm, const ISC_STATUS* trans)
|
|
|
|
{
|
2008-12-05 02:20:14 +01:00
|
|
|
while (true)
|
2007-09-26 19:50:31 +02:00
|
|
|
{
|
|
|
|
const ISC_STATUS type = *perm++ = *trans++;
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case isc_arg_end:
|
|
|
|
return;
|
2008-12-05 02:20:14 +01:00
|
|
|
case isc_arg_cstring:
|
|
|
|
{
|
2008-08-27 14:20:47 +02:00
|
|
|
size_t len = *perm++ = *trans++;
|
2007-10-02 12:41:19 +02:00
|
|
|
const char* temp = reinterpret_cast<char*>(*trans++);
|
2007-09-26 19:50:31 +02:00
|
|
|
*perm++ = (ISC_STATUS)(IPTR) (alloc(temp, len));
|
2008-08-27 14:20:47 +02:00
|
|
|
perm[-2] = len;
|
2007-09-26 19:50:31 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case isc_arg_string:
|
|
|
|
case isc_arg_interpreted:
|
2008-02-24 16:02:04 +01:00
|
|
|
case isc_arg_sql_state:
|
2007-09-26 19:50:31 +02:00
|
|
|
{
|
2007-10-02 12:41:19 +02:00
|
|
|
const char* temp = reinterpret_cast<char*>(*trans++);
|
2008-08-27 14:20:47 +02:00
|
|
|
size_t len = strlen(temp);
|
|
|
|
*perm++ = (ISC_STATUS)(IPTR) (alloc(temp, len));
|
2007-09-26 19:50:31 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
*perm++ = *trans++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-08-27 14:20:47 +02:00
|
|
|
|
|
|
|
void StringsBuffer::makeEnginePermanentVector(ISC_STATUS* v)
|
|
|
|
{
|
|
|
|
engine_failures->makePermanentVector(v, v);
|
|
|
|
}
|
|
|
|
|
2006-01-07 17:55:40 +01:00
|
|
|
/********************************* status_exception *******************************/
|
|
|
|
|
2008-12-05 02:20:14 +01:00
|
|
|
status_exception::status_exception() throw() :
|
2006-05-19 17:17:02 +02:00
|
|
|
m_strings_permanent(true)
|
2004-03-07 08:58:55 +01:00
|
|
|
{
|
2006-01-07 17:55:40 +01:00
|
|
|
memset(m_status_vector, 0, sizeof(m_status_vector));
|
2004-03-01 04:35:23 +01:00
|
|
|
}
|
|
|
|
|
2006-07-27 16:17:02 +02:00
|
|
|
status_exception::status_exception(const ISC_STATUS *status_vector, bool permanent) throw() :
|
|
|
|
m_strings_permanent(true)
|
2004-03-07 08:58:55 +01:00
|
|
|
{
|
2006-07-27 16:17:02 +02:00
|
|
|
m_status_vector[0] = isc_arg_end;
|
|
|
|
|
|
|
|
if (status_vector)
|
2006-05-23 15:03:34 +02:00
|
|
|
{
|
2008-12-05 02:20:14 +01:00
|
|
|
set_status(status_vector, permanent);
|
2006-01-07 17:55:40 +01:00
|
|
|
}
|
|
|
|
}
|
2008-12-05 02:20:14 +01:00
|
|
|
|
2006-01-08 02:11:06 +01:00
|
|
|
void status_exception::set_status(const ISC_STATUS *new_vector, bool permanent) throw()
|
2006-01-07 17:55:40 +01:00
|
|
|
{
|
2006-05-23 15:03:34 +02:00
|
|
|
fb_assert(new_vector != 0);
|
|
|
|
|
2006-01-07 17:55:40 +01:00
|
|
|
release_vector();
|
2006-05-23 15:03:34 +02:00
|
|
|
|
2006-01-07 17:55:40 +01:00
|
|
|
m_strings_permanent = permanent;
|
2006-05-23 15:03:34 +02:00
|
|
|
|
|
|
|
ISC_STATUS *ptr = m_status_vector;
|
2008-12-05 02:20:14 +01:00
|
|
|
while (true)
|
2006-05-23 15:03:34 +02:00
|
|
|
{
|
|
|
|
const ISC_STATUS type = *ptr++ = *new_vector++;
|
|
|
|
if (type == isc_arg_end)
|
|
|
|
break;
|
|
|
|
if (type == isc_arg_cstring)
|
|
|
|
*ptr++ = *new_vector++;
|
|
|
|
*ptr++ = *new_vector++;
|
|
|
|
}
|
2004-03-01 04:35:23 +01:00
|
|
|
}
|
|
|
|
|
2006-01-07 17:55:40 +01:00
|
|
|
void status_exception::release_vector() throw()
|
2005-12-25 05:01:49 +01:00
|
|
|
{
|
2006-05-19 17:17:02 +02:00
|
|
|
if (m_strings_permanent)
|
2004-03-07 08:58:55 +01:00
|
|
|
return;
|
2008-12-05 02:20:14 +01:00
|
|
|
|
2004-03-01 04:35:23 +01:00
|
|
|
// Free owned strings
|
|
|
|
ISC_STATUS *ptr = m_status_vector;
|
2008-12-05 02:20:14 +01:00
|
|
|
while (true)
|
2006-05-23 15:03:34 +02:00
|
|
|
{
|
2004-03-07 08:58:55 +01:00
|
|
|
const ISC_STATUS type = *ptr++;
|
|
|
|
if (type == isc_arg_end)
|
|
|
|
break;
|
|
|
|
|
2009-01-03 10:14:29 +01:00
|
|
|
switch (type)
|
|
|
|
{
|
2004-03-01 04:35:23 +01:00
|
|
|
case isc_arg_cstring:
|
|
|
|
ptr++;
|
|
|
|
delete[] reinterpret_cast<char*>(*ptr++);
|
|
|
|
break;
|
|
|
|
case isc_arg_string:
|
|
|
|
case isc_arg_interpreted:
|
2008-02-24 16:02:04 +01:00
|
|
|
case isc_arg_sql_state:
|
2004-03-01 04:35:23 +01:00
|
|
|
delete[] reinterpret_cast<char*>(*ptr++);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ptr++;
|
|
|
|
break;
|
2008-12-05 02:20:14 +01:00
|
|
|
}
|
2006-04-06 10:18:53 +02:00
|
|
|
}
|
2004-03-01 04:35:23 +01:00
|
|
|
}
|
|
|
|
|
2008-12-05 02:20:14 +01:00
|
|
|
status_exception::~status_exception() throw()
|
2006-01-07 17:55:40 +01:00
|
|
|
{
|
|
|
|
release_vector();
|
|
|
|
}
|
|
|
|
|
2008-07-06 12:59:03 +02:00
|
|
|
/********************************* fatal_exception *******************************/
|
|
|
|
|
2008-12-05 02:20:14 +01:00
|
|
|
void fatal_exception::raiseFmt(const char* format, ...)
|
2005-12-25 05:01:49 +01:00
|
|
|
{
|
2004-11-11 22:46:25 +01:00
|
|
|
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;
|
2004-11-11 22:46:25 +01:00
|
|
|
va_end(args);
|
|
|
|
throw fatal_exception(buffer);
|
|
|
|
}
|
|
|
|
|
2008-12-05 02:20:14 +01:00
|
|
|
void status_exception::raise(const ISC_STATUS *status_vector)
|
2004-03-07 08:58:55 +01:00
|
|
|
{
|
2006-01-07 17:55:40 +01:00
|
|
|
throw status_exception(status_vector, true);
|
2004-03-01 04:35:23 +01:00
|
|
|
}
|
2008-12-05 02:20:14 +01:00
|
|
|
|
2008-07-03 14:02:54 +02:00
|
|
|
void status_exception::raise(const Arg::StatusVector& statusVector)
|
2004-03-07 08:58:55 +01:00
|
|
|
{
|
2006-01-07 17:55:40 +01:00
|
|
|
ISC_STATUS_ARRAY temp;
|
2008-07-03 14:02:54 +02:00
|
|
|
fill_status(temp, statusVector.value());
|
2006-01-07 17:55:40 +01:00
|
|
|
throw status_exception(temp, false);
|
2004-03-01 04:35:23 +01:00
|
|
|
}
|
|
|
|
|
2006-05-22 13:45:19 +02:00
|
|
|
ISC_STATUS status_exception::stuff_exception(ISC_STATUS* const status_vector, StringsBuffer* sb) const throw()
|
|
|
|
{
|
|
|
|
const ISC_STATUS *ptr = value();
|
|
|
|
ISC_STATUS *sv = status_vector;
|
|
|
|
if (!sb)
|
|
|
|
{
|
|
|
|
sb = &engine_failures;
|
|
|
|
}
|
|
|
|
|
2008-12-05 02:20:14 +01:00
|
|
|
if (strings_permanent())
|
2006-05-22 13:45:19 +02:00
|
|
|
{
|
|
|
|
// Copy status vector
|
2008-12-05 02:20:14 +01:00
|
|
|
while (true)
|
2006-05-22 13:45:19 +02:00
|
|
|
{
|
|
|
|
const ISC_STATUS type = *sv++ = *ptr++;
|
|
|
|
if (type == isc_arg_end)
|
|
|
|
break;
|
|
|
|
if (type == isc_arg_cstring)
|
|
|
|
*sv++ = *ptr++;
|
|
|
|
*sv++ = *ptr++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Move in status and clone transient strings
|
2007-09-26 19:50:31 +02:00
|
|
|
sb->makePermanentVector(sv, ptr);
|
2006-05-22 13:45:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return status_vector[1];
|
|
|
|
}
|
|
|
|
|
2006-05-19 17:17:02 +02:00
|
|
|
/********************************* BadAlloc ****************************/
|
|
|
|
|
|
|
|
void BadAlloc::raise()
|
|
|
|
{
|
|
|
|
throw BadAlloc();
|
|
|
|
}
|
|
|
|
|
2006-05-22 13:45:19 +02:00
|
|
|
ISC_STATUS BadAlloc::stuff_exception(ISC_STATUS* const status_vector, StringsBuffer* sb) const throw()
|
|
|
|
{
|
|
|
|
ISC_STATUS *sv = status_vector;
|
|
|
|
|
|
|
|
*sv++ = isc_arg_gds;
|
|
|
|
*sv++ = isc_virmemexh;
|
|
|
|
*sv++ = isc_arg_end;
|
|
|
|
|
|
|
|
return status_vector[1];
|
|
|
|
}
|
|
|
|
|
2006-05-19 17:17:02 +02:00
|
|
|
/********************************* LongJump ****************************/
|
|
|
|
|
|
|
|
void LongJump::raise()
|
|
|
|
{
|
|
|
|
throw LongJump();
|
|
|
|
}
|
|
|
|
|
2006-05-22 13:45:19 +02:00
|
|
|
ISC_STATUS LongJump::stuff_exception(ISC_STATUS* const status_vector, StringsBuffer* sb) const throw()
|
|
|
|
{
|
|
|
|
/*
|
2008-12-05 02:20:14 +01:00
|
|
|
* Do nothing for a while - not all utilities are ready,
|
2006-05-22 13:45:19 +02:00
|
|
|
* status_vector is passed in them by other means.
|
|
|
|
* Ideally status_exception should be always used for it,
|
|
|
|
* and we should activate the following code:
|
|
|
|
|
|
|
|
ISC_STATUS *sv = status_vector;
|
|
|
|
if (!sb)
|
|
|
|
{
|
|
|
|
sb = &engine_failures;
|
|
|
|
}
|
2008-12-05 02:20:14 +01:00
|
|
|
|
2006-05-22 13:45:19 +02:00
|
|
|
const char *temp = "Unexpected Firebird::LongJump";
|
|
|
|
|
|
|
|
*sv++ = isc_arg_gds;
|
|
|
|
*sv++ = isc_random;
|
|
|
|
*sv++ = isc_arg_string;
|
|
|
|
*sv++ = (ISC_STATUS)(IPTR) (sb->alloc(temp, strlen(temp)));
|
|
|
|
*sv++ = isc_arg_end;
|
|
|
|
*/
|
2008-12-05 02:20:14 +01:00
|
|
|
|
2006-05-22 13:45:19 +02:00
|
|
|
return status_vector[1];
|
|
|
|
}
|
|
|
|
|
2008-11-27 21:16:46 +01:00
|
|
|
|
|
|
|
/********************************* system_error ****************************/
|
|
|
|
|
2008-12-05 02:20:14 +01:00
|
|
|
system_error::system_error(const char* syscall, int error_code) :
|
2008-11-27 21:16:46 +01:00
|
|
|
status_exception(0, false), errorCode(error_code)
|
|
|
|
{
|
|
|
|
Arg::Gds temp(isc_sys_request);
|
|
|
|
temp << Arg::Str(dupStringTemp2(syscall));
|
|
|
|
temp << SYS_ERR(errorCode);
|
|
|
|
set_status(temp.value(), false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void system_error::raise(const char* syscall, int error_code)
|
|
|
|
{
|
|
|
|
throw system_error(syscall, error_code);
|
|
|
|
}
|
|
|
|
|
|
|
|
void system_error::raise(const char* syscall)
|
|
|
|
{
|
|
|
|
throw system_error(syscall, getSystemError());
|
|
|
|
}
|
|
|
|
|
|
|
|
int system_error::getSystemError()
|
|
|
|
{
|
|
|
|
#ifdef WIN_NT
|
|
|
|
return GetLastError();
|
|
|
|
#else
|
|
|
|
return errno;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2004-03-01 04:35:23 +01:00
|
|
|
/********************************* system_call_failed ****************************/
|
|
|
|
|
2008-12-05 02:20:14 +01:00
|
|
|
system_call_failed::system_call_failed(const char* syscall, int error_code) :
|
2008-11-27 21:16:46 +01:00
|
|
|
system_error(syscall, error_code)
|
2006-01-07 17:55:40 +01:00
|
|
|
{
|
2008-12-01 08:28:13 +01:00
|
|
|
#ifdef DEV_BUILD
|
2008-12-05 02:20:14 +01:00
|
|
|
// raised failed system call exception in DEV_BUILD in 99.99% means
|
2008-09-04 12:00:35 +02:00
|
|
|
// problems with the code - let's create memory dump now
|
|
|
|
abort();
|
|
|
|
#endif
|
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
|
|
|
{
|
2008-11-27 21:16:46 +01:00
|
|
|
throw system_call_failed(syscall, getSystemError());
|
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) :
|
2006-01-07 17:55:40 +01:00
|
|
|
status_exception(0, false)
|
2002-11-11 19:06:01 +01:00
|
|
|
{
|
2009-01-03 10:14:29 +01:00
|
|
|
const ISC_STATUS temp[] =
|
|
|
|
{
|
|
|
|
isc_arg_gds,
|
|
|
|
isc_random,
|
|
|
|
isc_arg_string, dupStringTemp(message),
|
|
|
|
isc_arg_end
|
|
|
|
};
|
2006-01-07 17:55:40 +01:00
|
|
|
set_status(temp, false);
|
2002-11-11 19:06:01 +01:00
|
|
|
}
|
|
|
|
|
2004-10-07 11:27:34 +02: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
|
2006-01-07 17:55:40 +01:00
|
|
|
// after initialization of status vector.
|
2004-10-07 11:27:34 +02:00
|
|
|
//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);
|
|
|
|
}
|
|
|
|
|
2004-03-01 04:35:23 +01:00
|
|
|
/************************** exception handling routines ***************************/
|
|
|
|
|
2006-05-22 13:45:19 +02:00
|
|
|
// Serialize exception into status_vector, put transient strings from exception into given StringsBuffer
|
|
|
|
ISC_STATUS stuff_exception(ISC_STATUS *status_vector, const Firebird::Exception& ex, StringsBuffer* sb) throw()
|
|
|
|
{
|
|
|
|
return ex.stuff_exception(status_vector, sb);
|
|
|
|
}
|
|
|
|
|
2002-11-11 19:06:01 +01:00
|
|
|
} // namespace Firebird
|
2003-12-31 06:36:12 +01:00
|
|
|
|