/*
* 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 .
*/
/*************************************************************************
*
*
* PURPOSE:
* Code with embedded SQL for relational DBMS
*
*
* COMMENTS:
* - reconsider this 604 ignorance!
*
***********************************************************************/
static const char rcsid[] = "@(#)reladminif,TransactionIf: $Id: transactionif.ec,v 1.6 2003/12/27 23:11:43 rasdev Exp $";
#include "debug.hh"
// general embedded SQL related definitions
EXEC SQL include sqlglobals.h;
#include "transactionif.hh"
#include "raslib/rmdebug.hh"
#include "adminif.hh"
#include "oidif.hh"
#include "catalogmgr/typefactory.hh"
#include "sqlerror.hh"
#include "objectbroker.hh"
#include "databaseif.hh"
// PG stuff for libpg connection maintenance
#include "libpq-fe.h"
extern PGconn *pgConn;
void
TransactionIf::begin( bool readOnly ) throw ( r_Error )
{
RMDBGENTER(2, RMDebug::module_adminif, "TransactionIf", "begin(" << readOnly << ")");
ENTER( "TransactionIf::begin, readOnly=" << readOnly );
isReadOnly = readOnly;
AdminIf::setAborted(false);
AdminIf::setReadOnlyTA(readOnly);
TALK( "EXEC SQL BEGIN WORK" );
EXEC SQL BEGIN WORK;
if (sqlca.sqlwarn[2] == 'W') // real error, not just a warning
{
SQLCODE = 0; // FIXME: bad hack, as PG can't reset error state and SQLCODE is queried in many places -- PB 2005-jan-09
}
else
{
RMDBGMIDDLE(4, RMDebug::module_adminif, "TransactionIf", "error occured while issuing BEGIN");
LEAVE( "TransactionIf::begin(): error during BEGIN: " << SQLCODE );
generateException();
}
if (readOnly)
{
TALK( "EXEC SQL SET TRANSACTION READ ONLY" );
EXEC SQL SET TRANSACTION READ ONLY;
// no error check, as this doesn't inhibit work
}
// prelim.:have additional libpq TA -- PB 2005-jan-09
TALK( "PQexec( pgConn, BEGIN )" );
PGresult *pgResult = PQexec( pgConn, "BEGIN" );
if (PQresultStatus(pgResult) != PGRES_COMMAND_OK)
{
LEAVE( "TransactionIf::begin() Error: cannot open libpq TA: " << PQerrorMessage(pgConn) );
generateException();
}
#ifdef RMANBENCHMARK
DBObject::readTimer.start();
DBObject::readTimer.pause();
DBObject::updateTimer.start();
DBObject::updateTimer.pause();
DBObject::deleteTimer.start();
DBObject::deleteTimer.pause();
DBObject::insertTimer.start();
DBObject::insertTimer.pause();
OId::oidAlloc.start();
OId::oidAlloc.pause();
OId::oidResolve.start();
OId::oidResolve.pause();
#endif
OId::initialize();
TypeFactory::initialize();
LEAVE( "TransactionIf::begin, SQLCODE=" << SQLCODE );
RMDBGEXIT(2, RMDebug::module_adminif, "TransactionIf", "begin(" << readOnly << ") ");
}
void
TransactionIf::commit() throw ( r_Error )
{
RMDBGENTER(2, RMDebug::module_adminif, "TransactionIf", "commit()");
ENTER( "TransactionIf::commit" );
if (isReadOnly)
{
RMDBGMIDDLE(9, RMDebug::module_adminif, "TransactionIf", "read only: aborting");
TALK( "TA is readonly: aborting" );
abort();
}
else
{
AdminIf::setAborted(false);
RMDBGMIDDLE(9, RMDebug::module_adminif, "TransactionIf", "set aborted false");
TypeFactory::freeTempTypes();
RMDBGMIDDLE(9, RMDebug::module_adminif, "TransactionIf", "freed temp types");
ObjectBroker::clearBroker();
RMDBGMIDDLE(9, RMDebug::module_adminif, "TransactionIf", "cleared broker");
OId::deinitialize();
RMDBGMIDDLE(9, RMDebug::module_adminif, "TransactionIf", "wrote oid counters");
AdminIf::setReadOnlyTA(false);
RMDBGMIDDLE(9, RMDebug::module_adminif, "TransactionIf", "committing");
// prelim.:have additional libpq TA -- PB 2005-jan-09
TALK( "PQexec( pgConn, END )" );
PGresult *pgResult = PQexec( pgConn, "END" );
if (PQresultStatus(pgResult) != PGRES_COMMAND_OK)
{
LEAVE( "TransactionIf::commit() Error: cannot commit libpq TA: " << PQerrorMessage(pgConn) );
generateException();
}
TALK( "EXEC SQL COMMIT WORK" );
EXEC SQL COMMIT WORK;
if (SQLCODE == -604) // = "no TA open" - seems to be a hickup from our double transaction
// so we ignore it; FIXME: reinvestigate! -- PB 25-aug-2005
{
TALK( "TransactionIf::commit(): ignoring 'no TA open' error (SQLCODE -604) during COMMIT." );
}
else if (check("TransactionIf::begin() COMMIT\0"))
{
RMDBGMIDDLE(4, RMDebug::module_adminif, "TransactionIf", "error occured while issuing COMMIT");
LEAVE( "TransactionIf::commit(): error during COMMIT:" << SQLCODE );
generateException();
}
if (lastBase)
{
RMDBGMIDDLE(9, RMDebug::module_adminif, "TransactionIf", "closing dbms");
lastBase->baseDBMSClose();
}
}
#ifdef RMANBENCHMARK
DBObject::readTimer.stop();
DBObject::updateTimer.stop();
DBObject::deleteTimer.stop();
DBObject::insertTimer.stop();
OId::oidAlloc.stop();
OId::oidResolve.stop();
#endif
LEAVE( "TransactionIf::commit" );
RMDBGEXIT(2, RMDebug::module_adminif, "TransactionIf", "commit() " << endl << endl);
}
void
TransactionIf::abort()
{
RMDBGENTER(2, RMDebug::module_adminif, "TransactionIf", "abort()");
ENTER( "TransactionIf::abort" );
// prelim.:have additional libpq TA -- PB 2005-jan-09
TALK( "PQexec( pgConn, ABORT )" );
PGresult *pgResult = PQexec( pgConn, "ABORT" );
if (PQresultStatus(pgResult) != PGRES_COMMAND_OK)
{
LEAVE( "TransactionIf::abort() Error: cannot abort libpq TA: " << PQerrorMessage(pgConn) );
generateException();
}
AdminIf::setAborted(true);
TypeFactory::freeTempTypes();
ObjectBroker::clearBroker();
OId::deinitialize();
AdminIf::setReadOnlyTA(false);
TALK( "EXEC SQL ROLLBACK WORK" );
EXEC SQL ROLLBACK WORK;
if (check("TransactionIf::abort() ROLLBACK\0"))
{
RMDBGMIDDLE(4, RMDebug::module_adminif, "TransactionIf", "error occured while issuing ROLLBACK");
TALK( "TransactionIf::abort(): error during ROLLBACK, still continuing: " << SQLCODE );
}
if(lastBase)
lastBase->baseDBMSClose();
#ifdef RMANBENCHMARK
DBObject::readTimer.stop();
DBObject::updateTimer.stop();
DBObject::deleteTimer.stop();
DBObject::insertTimer.stop();
OId::oidAlloc.stop();
OId::oidResolve.stop();
#endif
LEAVE( "TransactionIf::abort, SQLCODE=" << SQLCODE );
RMDBGEXIT(2, RMDebug::module_adminif, "TransactionIf", "abort() " << endl << endl);
}