/* * 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); }