/*
* This file is part of rasdaman community.
*
* Rasdaman community is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Rasdaman community is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with rasdaman community. If not, see .
*
* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
rasdaman GmbH.
*
* For more information please see
* or contact Peter Baumann via .
*/
// This is -*- C++ -*-
/*************************************************************************
*
*
* PURPOSE:
* process base DBMS errors (PostgreSQL) by printing messages and throwing exceptions.
*
*
* COMMENTS:
* - different from other implementations in that no distinction between
* error and warning
* - the whole module should be redesigned for all DBMSs - very unconcise
* - no function printSQLError() as eg in Informix
* - FIXME: generateException() should be declared r_Ebase_dbms instead of r_Error
*
***********************************************************************/
static const char rcsid[] = "@(#)reladminif,SQLError: $Id: sqlerror.ec,v 1.4 2003/12/27 23:11:43 rasdev Exp $";
// #define SQLCA_STORAGE_CLASS extern
#include
#include
#include
#include "sqlerror.hh"
#include "externs.h"
#include "raslib/rmdebug.hh"
#include "raslib/error.hh"
#include "debug-srv.hh"
// general embedded SQL related definitions
EXEC SQL include "sqlglobals.h";
// SQLSTATE not available in PGSQL (SQLCODE is, funny enough)
#define SQLSTATE sqlca.sqlstate
// error codes
EXEC SQL define SUCCESS 0;
EXEC SQL define WARNING 1;
EXEC SQL define NODATA 100;
EXEC SQL define RTERROR -1;
// general message buffer size
#define BUFFER_SIZE 4000
// SQL error message max size
// FIXME: is this really enough?
const int MSG_MAXLEN=BUFFER_SIZE;
// length of buffer for remembering last message
#define LASTERRORMSGLEN BUFFER_SIZE
char lastErrorMsg[LASTERRORMSGLEN];
/*
* The sqlstate_err() function checks the SQLSTATE status variable to see
* if an error or warning has occurred following an SQL statement.
*/
int sqlstate_err()
{
int err_code = RTERROR;
if (SQLSTATE[0] == '0') /* trap '00', '01', '02' */
{
switch(SQLSTATE[1])
{
case '0': /* success - return 0 */
err_code = SUCCESS;
break;
case '1': /* warning - return 1 */
err_code = WARNING;
break;
case '2': /* end of data - return 100 */
err_code = NODATA;
break;
default: /* error - return SQLCODE */
break;
}
}
return err_code;
} // sqlstate_err()
/*
* The disp_sqlstate_err() function prints details into msgbuf.
*/
void disp_sqlstate_err(char* msgbuf, size_t length)
{
char error_buffer[BUFFER_SIZE];
size_t characters_written = 0;
snprintf(error_buffer, BUFFER_SIZE, "SQLSTATE: %5s SQLCODE: %ld\n", SQLSTATE, SQLCODE);
characters_written = strlen(error_buffer);
if (characters_written > length)
{
RMInit::logOut << "error message didn't fit into buffer: " << error_buffer << endl;
}
else
{
strcat(msgbuf, error_buffer);
}
} // disp_sqlstate_err()
/*
* disp_error(): print statement and error/warning text into buffer
*/
void disp_error(const char* stmt, char* msgbuf, size_t length)
{
char error_buffer[BUFFER_SIZE];
snprintf(error_buffer, BUFFER_SIZE, "Warning/error in %s:\n", stmt);
size_t error_len = strlen(error_buffer);
if (error_len > length)
RMInit::logOut << "error message didn't fit into buffer: " << error_buffer << endl;
else
{
strcat(msgbuf, error_buffer);
length = length - error_len;
}
disp_sqlstate_err(msgbuf, length);
} // disp_error()
/*
* disp_exception(): if sql_errcode says there was an error,
* allocate msg buffer and copy error msg
*/
char* disp_exception(const char* stmt, int sqlerr_code)
{
char* msgbuf = NULL;
switch (sqlerr_code)
{
case SUCCESS:
case NODATA:
break;
case WARNING:
case RTERROR:
msgbuf = new char[BUFFER_SIZE];
memset(msgbuf, 0, BUFFER_SIZE);
disp_error(stmt, msgbuf, BUFFER_SIZE);
break;
default:
RMInit::logOut << "Invalid exception state for " << stmt << " " << sqlerr_code << endl;
break;
}
return msgbuf;
} // disp_exception()
/*
* check(): check base DBMS for any error occurred during last
* database access and print message into log if so.
*/
int
check(const char* stmt) throw (r_Error)
{
char* msg = disp_exception(stmt, sqlstate_err());
if (msg != NULL)
{
RMInit::logOut << msg << endl;
snprintf(lastErrorMsg, LASTERRORMSGLEN,"%s\n" , msg);
delete [] msg;
msg = NULL;
}
return SQLCODE;
}
// generate r_Ebase_dbms exception using SQL error code and message
void
generateException() throw (r_Error)
{
TALK( "Throwing Exception (SQLCODE=" << SQLCODE << "): " << lastErrorMsg );
RMInit::dbgOut << "Throwing Exception (SQLCODE=" << SQLCODE << "): " << lastErrorMsg << endl;
throw r_Ebase_dbms( SQLCODE, lastErrorMsg );
} // generateException()