2003-02-17 14:28:17 +01:00
|
|
|
#include "firebird.h"
|
2011-06-02 17:57:08 +02:00
|
|
|
#include "firebird/Provider.h"
|
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"
|
2009-09-01 11:20:24 +02:00
|
|
|
#include "../common/classes/array.h"
|
|
|
|
#include "../common/thd.h"
|
2010-10-12 10:02:57 +02:00
|
|
|
#include "../common/utils_proto.h"
|
2011-01-14 18:31:40 +01:00
|
|
|
#include "../common/StatusHolder.h"
|
2009-09-01 11:20:24 +02:00
|
|
|
|
2006-01-07 17:55:40 +01:00
|
|
|
namespace Firebird {
|
|
|
|
|
2009-11-30 13:10:47 +01:00
|
|
|
// Before using thr parameter, make sure that thread is not going to work with
|
|
|
|
// this functions itself.
|
2009-04-26 12:24:44 +02:00
|
|
|
// CVC: Do not let "perm" be incremented before "trans", because it may lead to serious memory errors,
|
|
|
|
// since several places in our code blindly pass the same vector twice.
|
2012-03-01 09:55:43 +01:00
|
|
|
void makePermanentVector(ISC_STATUS* perm, const ISC_STATUS* trans, ThreadId thr) throw()
|
2007-09-26 19:50:31 +02:00
|
|
|
{
|
2009-09-01 11:20:24 +02:00
|
|
|
try
|
2007-09-26 19:50:31 +02:00
|
|
|
{
|
2009-09-01 11:20:24 +02:00
|
|
|
while (true)
|
2009-02-03 12:02:00 +01:00
|
|
|
{
|
2009-09-01 11:20:24 +02:00
|
|
|
const ISC_STATUS type = *perm++ = *trans++;
|
|
|
|
|
|
|
|
switch (type)
|
2007-09-26 19:50:31 +02:00
|
|
|
{
|
2009-09-01 11:20:24 +02:00
|
|
|
case isc_arg_end:
|
|
|
|
return;
|
|
|
|
case isc_arg_cstring:
|
|
|
|
{
|
2010-02-07 14:17:41 +01:00
|
|
|
perm [-1] = isc_arg_string;
|
|
|
|
const size_t len = *trans++;
|
2009-09-01 11:20:24 +02:00
|
|
|
const char* temp = reinterpret_cast<char*>(*trans++);
|
2011-04-08 17:18:50 +02:00
|
|
|
*perm++ = (ISC_STATUS)(IPTR) (MasterInterfacePtr()->circularAlloc(temp, len, thr));
|
2009-09-01 11:20:24 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case isc_arg_string:
|
|
|
|
case isc_arg_interpreted:
|
|
|
|
case isc_arg_sql_state:
|
|
|
|
{
|
|
|
|
const char* temp = reinterpret_cast<char*>(*trans++);
|
2010-02-08 14:39:37 +01:00
|
|
|
const size_t len = strlen(temp);
|
2011-04-08 17:18:50 +02:00
|
|
|
*perm++ = (ISC_STATUS)(IPTR) (MasterInterfacePtr()->circularAlloc(temp, len, thr));
|
2009-09-01 11:20:24 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
*perm++ = *trans++;
|
|
|
|
break;
|
2007-09-26 19:50:31 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-09-01 11:20:24 +02:00
|
|
|
catch (const system_call_failed& ex)
|
|
|
|
{
|
|
|
|
memcpy(perm, ex.value(), sizeof(ISC_STATUS_ARRAY));
|
|
|
|
}
|
2010-10-22 03:24:31 +02:00
|
|
|
catch (const BadAlloc&)
|
2009-09-01 11:20:24 +02:00
|
|
|
{
|
2010-10-12 10:02:57 +02:00
|
|
|
*perm++ = isc_arg_gds;
|
|
|
|
*perm++ = isc_virmemexh;
|
|
|
|
*perm++ = isc_arg_end;
|
2009-09-01 11:20:24 +02:00
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
|
|
|
*perm++ = isc_arg_gds;
|
|
|
|
*perm++ = isc_random;
|
|
|
|
*perm++ = isc_arg_string;
|
|
|
|
*perm++ = (ISC_STATUS)(IPTR) "Unexpected exception in makePermanentVector()";
|
|
|
|
*perm++ = isc_arg_end;
|
|
|
|
}
|
2007-09-26 19:50:31 +02:00
|
|
|
}
|
2008-08-27 14:20:47 +02:00
|
|
|
|
2012-03-01 09:55:43 +01:00
|
|
|
void makePermanentVector(ISC_STATUS* v, ThreadId thr) throw()
|
2008-08-27 14:20:47 +02:00
|
|
|
{
|
2009-11-30 13:10:47 +01:00
|
|
|
makePermanentVector(v, v, thr);
|
2008-08-27 14:20:47 +02:00
|
|
|
}
|
|
|
|
|
2009-07-21 15:59:45 +02:00
|
|
|
// ********************************* Exception *******************************
|
|
|
|
|
|
|
|
Exception::~Exception() throw() { }
|
|
|
|
|
2010-10-12 10:02:57 +02:00
|
|
|
ISC_STATUS Exception::stuff_exception(ISC_STATUS* const status_vector) const throw()
|
|
|
|
{
|
2011-01-14 18:31:40 +01:00
|
|
|
LocalStatus status;
|
|
|
|
stuffException(&status);
|
|
|
|
const ISC_STATUS* s = status.get();
|
2010-10-12 10:02:57 +02:00
|
|
|
fb_utils::copyStatus(status_vector, ISC_STATUS_LENGTH, s, fb_utils::statusLength(s));
|
|
|
|
|
|
|
|
return status_vector[1];
|
|
|
|
}
|
|
|
|
|
2009-04-17 16:10:11 +02:00
|
|
|
// ********************************* status_exception *******************************
|
2006-01-07 17:55:40 +01:00
|
|
|
|
2009-09-01 11:20:24 +02:00
|
|
|
status_exception::status_exception() throw()
|
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
|
|
|
}
|
|
|
|
|
2009-09-01 11:20:24 +02:00
|
|
|
status_exception::status_exception(const ISC_STATUS *status_vector) throw()
|
2004-03-07 08:58:55 +01:00
|
|
|
{
|
2009-09-01 11:20:24 +02:00
|
|
|
memset(m_status_vector, 0, sizeof(m_status_vector));
|
2006-07-27 16:17:02 +02:00
|
|
|
|
|
|
|
if (status_vector)
|
2006-05-23 15:03:34 +02:00
|
|
|
{
|
2009-09-01 11:20:24 +02:00
|
|
|
set_status(status_vector);
|
2006-01-07 17:55:40 +01:00
|
|
|
}
|
|
|
|
}
|
2008-12-05 02:20:14 +01:00
|
|
|
|
2009-09-01 11:20:24 +02:00
|
|
|
void status_exception::set_status(const ISC_STATUS *new_vector) throw()
|
2005-12-25 05:01:49 +01:00
|
|
|
{
|
2009-09-01 11:20:24 +02:00
|
|
|
fb_assert(new_vector != 0);
|
2004-03-07 08:58:55 +01:00
|
|
|
|
2009-09-01 11:20:24 +02:00
|
|
|
makePermanentVector(m_status_vector, new_vector);
|
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
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2009-07-21 15:59:45 +02:00
|
|
|
const char* status_exception::what() const throw()
|
2005-12-25 05:01:49 +01:00
|
|
|
{
|
2009-07-21 15:59:45 +02:00
|
|
|
return "Firebird::status_exception";
|
2004-11-11 22:46:25 +01:00
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
2009-09-01 11:20:24 +02:00
|
|
|
throw status_exception(status_vector);
|
|
|
|
}
|
|
|
|
|
2008-07-03 14:02:54 +02:00
|
|
|
void status_exception::raise(const Arg::StatusVector& statusVector)
|
2004-03-07 08:58:55 +01:00
|
|
|
{
|
2009-09-01 11:20:24 +02:00
|
|
|
throw status_exception(statusVector.value());
|
2004-03-01 04:35:23 +01:00
|
|
|
}
|
|
|
|
|
2011-04-07 19:16:00 +02:00
|
|
|
ISC_STATUS status_exception::stuffException(IStatus* status) const throw()
|
2006-05-22 13:45:19 +02:00
|
|
|
{
|
2010-10-12 10:02:57 +02:00
|
|
|
if (status)
|
2006-05-22 13:45:19 +02:00
|
|
|
{
|
2010-10-12 10:02:57 +02:00
|
|
|
status->set(value());
|
2006-05-22 13:45:19 +02:00
|
|
|
}
|
|
|
|
|
2010-10-12 10:02:57 +02:00
|
|
|
return value()[1];
|
2006-05-22 13:45:19 +02:00
|
|
|
}
|
|
|
|
|
2009-04-17 16:10:11 +02:00
|
|
|
// ********************************* BadAlloc ****************************
|
2006-05-19 17:17:02 +02:00
|
|
|
|
|
|
|
void BadAlloc::raise()
|
|
|
|
{
|
|
|
|
throw BadAlloc();
|
|
|
|
}
|
|
|
|
|
2011-04-07 19:16:00 +02:00
|
|
|
ISC_STATUS BadAlloc::stuffException(IStatus* status) const throw()
|
2006-05-22 13:45:19 +02:00
|
|
|
{
|
2010-10-12 10:02:57 +02:00
|
|
|
const ISC_STATUS sv[] = {isc_arg_gds, isc_virmemexh};
|
2006-05-22 13:45:19 +02:00
|
|
|
|
2010-10-12 10:02:57 +02:00
|
|
|
if (status)
|
|
|
|
{
|
|
|
|
status->set(FB_NELEM(sv), sv);
|
|
|
|
}
|
2006-05-22 13:45:19 +02:00
|
|
|
|
2010-10-12 10:02:57 +02:00
|
|
|
return sv[1];
|
2006-05-22 13:45:19 +02:00
|
|
|
}
|
|
|
|
|
2009-07-21 15:59:45 +02:00
|
|
|
const char* BadAlloc::what() const throw()
|
|
|
|
{
|
|
|
|
return "Firebird::BadAlloc";
|
|
|
|
}
|
|
|
|
|
2009-04-17 16:10:11 +02:00
|
|
|
// ********************************* LongJump ***************************
|
2006-05-19 17:17:02 +02:00
|
|
|
|
|
|
|
void LongJump::raise()
|
|
|
|
{
|
|
|
|
throw LongJump();
|
|
|
|
}
|
|
|
|
|
2011-04-07 19:16:00 +02:00
|
|
|
ISC_STATUS LongJump::stuffException(IStatus* status) const throw()
|
2006-05-22 13:45:19 +02:00
|
|
|
{
|
2011-04-02 06:16:48 +02:00
|
|
|
ISC_STATUS sv[] = {isc_arg_gds, isc_random, isc_arg_string, (ISC_STATUS)(IPTR) "Unexpected Firebird::LongJump"};
|
2006-05-22 13:45:19 +02:00
|
|
|
|
2010-10-12 10:02:57 +02:00
|
|
|
if (status)
|
|
|
|
{
|
|
|
|
status->set(FB_NELEM(sv), sv);
|
|
|
|
}
|
2008-12-05 02:20:14 +01:00
|
|
|
|
2010-10-12 10:02:57 +02:00
|
|
|
return sv[1];
|
2006-05-22 13:45:19 +02:00
|
|
|
}
|
|
|
|
|
2009-07-23 02:56:28 +02:00
|
|
|
const char* LongJump::what() const throw()
|
2009-07-21 15:59:45 +02:00
|
|
|
{
|
|
|
|
return "Firebird::LongJump";
|
|
|
|
}
|
|
|
|
|
2008-11-27 21:16:46 +01:00
|
|
|
|
2009-04-17 16:10:11 +02:00
|
|
|
// ********************************* system_error ***************************
|
2008-11-27 21:16:46 +01:00
|
|
|
|
2008-12-05 02:20:14 +01:00
|
|
|
system_error::system_error(const char* syscall, int error_code) :
|
2009-09-01 11:20:24 +02:00
|
|
|
status_exception(), errorCode(error_code)
|
2008-11-27 21:16:46 +01:00
|
|
|
{
|
|
|
|
Arg::Gds temp(isc_sys_request);
|
2009-08-26 15:08:54 +02:00
|
|
|
temp << Arg::Str(syscall);
|
2008-11-27 21:16:46 +01:00
|
|
|
temp << SYS_ERR(errorCode);
|
2009-09-01 11:20:24 +02:00
|
|
|
set_status(temp.value());
|
2008-11-27 21:16:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2009-04-17 16:10:11 +02:00
|
|
|
// ********************************* system_call_failed ***************************
|
2004-03-01 04:35:23 +01:00
|
|
|
|
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
|
|
|
{
|
2009-08-30 21:00:46 +02:00
|
|
|
// NS: something unexpected has happened. Log the error to log file
|
|
|
|
// In the future we may consider terminating the process even in PROD_BUILD
|
2009-11-15 19:38:34 +01:00
|
|
|
gds__log("Operating system call %s failed. Error code %d", syscall, error_code);
|
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
|
|
|
}
|
|
|
|
|
2009-04-17 16:10:11 +02:00
|
|
|
// ********************************* fatal_exception *******************************
|
2004-03-01 04:35:23 +01:00
|
|
|
|
|
|
|
fatal_exception::fatal_exception(const char* message) :
|
2009-09-01 11:20:24 +02:00
|
|
|
status_exception()
|
2002-11-11 19:06:01 +01:00
|
|
|
{
|
2009-02-03 12:02:00 +01:00
|
|
|
const ISC_STATUS temp[] =
|
|
|
|
{
|
2009-01-03 20:02:04 +01:00
|
|
|
isc_arg_gds,
|
|
|
|
isc_random,
|
2009-09-03 03:28:54 +02:00
|
|
|
isc_arg_string,
|
2009-09-01 11:20:24 +02:00
|
|
|
(ISC_STATUS)(IPTR) message,
|
2009-01-03 20:02:04 +01:00
|
|
|
isc_arg_end
|
|
|
|
};
|
2009-09-01 11:20:24 +02:00
|
|
|
set_status(temp);
|
2002-11-11 19:06:01 +01:00
|
|
|
}
|
|
|
|
|
2004-10-07 11:27:34 +02:00
|
|
|
// Keep in sync with the constructor above, please; "message" becomes 4th element
|
2009-07-21 16:18:34 +02:00
|
|
|
// after initialization of status vector in constructor.
|
|
|
|
const char* fatal_exception::what() const throw()
|
|
|
|
{
|
|
|
|
return reinterpret_cast<const char*>(value()[3]);
|
|
|
|
}
|
2004-10-07 11:27:34 +02: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);
|
|
|
|
}
|
|
|
|
|
2009-07-21 15:59:45 +02:00
|
|
|
void fatal_exception::raiseFmt(const char* format, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
va_start(args, format);
|
|
|
|
char buffer[1024];
|
|
|
|
VSNPRINTF(buffer, sizeof(buffer), format, args);
|
|
|
|
buffer[sizeof(buffer) - 1] = 0;
|
|
|
|
va_end(args);
|
|
|
|
throw fatal_exception(buffer);
|
|
|
|
}
|
|
|
|
|
2009-04-17 16:10:11 +02:00
|
|
|
// ************************** exception handling routines **************************
|
2004-03-01 04:35:23 +01:00
|
|
|
|
2009-09-01 11:20:24 +02:00
|
|
|
// Serialize exception into status_vector
|
|
|
|
ISC_STATUS stuff_exception(ISC_STATUS *status_vector, const Firebird::Exception& ex) throw()
|
2006-05-22 13:45:19 +02:00
|
|
|
{
|
2009-09-01 11:20:24 +02:00
|
|
|
return ex.stuff_exception(status_vector);
|
2006-05-22 13:45:19 +02:00
|
|
|
}
|
|
|
|
|
2011-04-07 19:16:00 +02:00
|
|
|
ISC_STATUS stuff_exception(IStatus* status, const Firebird::Exception& ex) throw()
|
2010-10-12 10:02:57 +02:00
|
|
|
{
|
|
|
|
return ex.stuffException(status);
|
|
|
|
}
|
|
|
|
|
2002-11-11 19:06:01 +01:00
|
|
|
} // namespace Firebird
|