summaryrefslogtreecommitdiffstats
path: root/relblobif/blobtile.pgc
diff options
context:
space:
mode:
authorConstantin Jucovschi <cj@ubuntu.localdomain>2009-04-24 07:20:22 -0400
committerConstantin Jucovschi <cj@ubuntu.localdomain>2009-04-24 07:20:22 -0400
commit8f27e65bddd7d4b8515ce620fb485fdd78fcdf89 (patch)
treebd328a4dd4f92d32202241b5e3a7f36177792c5f /relblobif/blobtile.pgc
downloadrasdaman-upstream-8f27e65bddd7d4b8515ce620fb485fdd78fcdf89.tar.gz
rasdaman-upstream-8f27e65bddd7d4b8515ce620fb485fdd78fcdf89.tar.xz
rasdaman-upstream-8f27e65bddd7d4b8515ce620fb485fdd78fcdf89.zip
Initial commitv8.0
Diffstat (limited to 'relblobif/blobtile.pgc')
-rw-r--r--relblobif/blobtile.pgc765
1 files changed, 765 insertions, 0 deletions
diff --git a/relblobif/blobtile.pgc b/relblobif/blobtile.pgc
new file mode 100644
index 0000000..7f3aef4
--- /dev/null
+++ b/relblobif/blobtile.pgc
@@ -0,0 +1,765 @@
+/*
+* 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 <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include "mymalloc/mymalloc.h"
+// This is -*- C++ -*-
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * implements blobtile interface using the PostgreSQL DBMS.
+ *
+ *
+ * COMMENTS:
+ * - uses LO blob method, this has been tested to be faster than bytea
+ * - RMDBG macros generate so weird output that I added DEBUG macros
+ * although this is very ugly (2 trace facilities in parallel)
+ * - exceptions thrown are r_Error, either directly or through common
+ * function generateException() (reladminif) which throws r_Ebase_dbms
+ *
+ ************************************************************/
+
+using namespace std;
+
+static const char rcsid[] = "@(#)blobif,BLOBTile: $Id: blobtile.ec,v 1.8 2003/12/27 23:19:03 rasdev Exp $";
+
+#include <stdio.h>
+#include <stdlib.h> /* atoi */
+
+// PG stuff:
+#include "libpq-fe.h" /* C interface to PgSQL */
+#include "libpq/libpq-fs.h" /* large object (lo) api */
+
+// simple trace facility
+// trace macros are activated through externally defined compile variable DEBUG
+#include "debug-srv.hh"
+
+// general embedded SQL related definitions
+EXEC SQL include "../reladminif/sqlglobals.h";
+
+// libpg connection maintenance
+// must have been initiated before use (see databasif.pgc)
+extern PGconn *pgConn;
+
+// all the DBMS independent code is factored out and
+// will be included in the resulting .c file
+//#include "blobtile.cc"
+#include "blobtile.hh"
+#include "raslib/rmdebug.hh"
+#include "reladminif/objectbroker.hh"
+#include "reladminif/dbref.hh"
+#include "reladminif/sqlerror.hh"
+#include "inlinetile.hh"
+
+// update blob in ras_tiles table, identified by variable myOId (from blobtile.cc), update map ref
+void
+BLOBTile::updateInDb() throw (r_Error)
+{
+ RMDBGENTER(3, RMDebug::module_blobif, "BLOBTile", "updateInDb() " << myOId);
+ ENTER( "BLOBTile::updateInDb" );
+
+#ifdef NOTYET // should be in future
+/*
+ EXEC SQL BEGIN DECLARE SECTION;
+ Oid tile;
+ long indbmyoId;
+ long indbmyoid = 0;
+ short dataformat = 0;
+ EXEC SQL END DECLARE SECTION;
+
+ dataformat = dataFormat;
+ indbmyoid = myOId.getCounter();
+
+ // (1) --- get tuple
+ TALK( "EXEC SQL SELECT Tile INTO :tile FROM RAS_TILES WHERE BlobId = " << indbmyoid );
+ EXEC SQL SELECT TILE
+ INTO :tile
+ FROM RAS_TILES
+ WHERE BlobId = :indbmyoid;
+ if (SQLCODE < 0)
+ {
+ RMInit::logOut << "BLOBTile::updateInDb(): error: cannot get blob, SQLCODE " << SQLCODE << endl;
+ LEAVE( "BLOBTile::updateInDb(): error: cannot get blob, SQLCODE " << SQLCODE );
+ check("Select blob oid");
+ generateException();
+ }
+ else if (SQLCODE == SQLNODATAFOUND)
+ {
+ RMInit::logOut << "BLOBTile::updateInDb(): error: object not in database" << endl;
+ LEAVE( "BLOBTile::updateInDb(): error: object not in database" );
+ throw r_Error(r_Error::r_Error_ObjectUnknown);
+ }
+*/
+#endif //NOTYET
+ // alternative solution for now:
+ Oid tile;
+ long indbmyoId = 0;
+ long indbmyoid = 0;
+ short dataformat = 0;
+ char pgQuery[SQL_QUERY_BUFFER_SIZE];
+ PGresult *pgResult = NULL;
+
+ // (1) --- get tuple
+ dataformat = dataFormat;
+ indbmyoid = myOId.getCounter();
+
+ (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "SELECT Tile FROM RAS_TILES WHERE BlobId = %d", indbmyoid );
+ TALK( pgQuery );
+ pgResult = PQexec( pgConn, pgQuery );
+ if (PQresultStatus(pgResult) != PGRES_TUPLES_OK)
+ {
+ LEAVE( "BLOBTile::updateInDb() libpq 'select tile' error: " << PQerrorMessage(pgConn) );
+ PQclear( pgResult );
+ generateException();
+ }
+ else if (PQntuples(pgResult) != 1)
+ {
+ LEAVE( "BLOBTile::updateInDb() libpq 'select' did not yield 1 result but " << PQntuples(pgResult) );
+ PQclear( pgResult );
+ generateException();
+ }
+ tile = atoi( PQgetvalue( pgResult, 0, 0 ) ); // extract value from result
+ PQclear( pgResult );
+
+ // (2) --- open, write, close blob
+ TALK( "lo_open()" );
+ int fd = lo_open( pgConn, tile, INV_WRITE ); // no error code mentioned in manual
+ TALK( "lo_write() for fd " << fd << " and " << size << " bytes" );
+ int loResult = lo_write( pgConn, fd, cells, size );
+ if (loResult < 0)
+ {
+ RMInit::logOut << "BLOBTile::updateInDb() cannot write blob, error: " << loResult << endl;
+ LEAVE( "BLOBTile::updateInDb: cannot write blob, error " << loResult );
+ generateException();
+ }
+ else if (loResult != size) // did not get all
+ {
+ RMInit::dbgOut << "BLOB (" << myOId << ") insert: wrote " << loResult << " instead of " << size << " bytes" << endl;
+ LEAVE( "BLOBTile::updateInDb: wrote " << loResult << " instead of " << size << " bytes" );
+ generateException();
+ }
+ TALK( "lo_close()" );
+ loResult = lo_close( pgConn, fd );
+ if (loResult < 0) // can't close, don't know if data are written
+ {
+ RMInit::logOut << "BLOBTile::updateInDb() ignoring lo_close() error: " << PQerrorMessage(pgConn) << endl;
+ LEAVE( "BLOBTile::updateInDb: cannot lo_close(): " << PQerrorMessage(pgConn) );
+ generateException();
+ }
+
+#ifdef NOTYET // should be in future
+/*
+ // (3) --- update data format
+ // NOTE: we assume the blob already exists and do not change the oid
+ TALK( "EXEC SQL UPDATE RAS_TILES SET DataFormat = " << dataformat << " WHERE BlobId = " << indbmyoid );
+ EXEC SQL UPDATE RAS_TILES
+ SET DataFormat = :dataformat
+ WHERE BlobId = :indbmyoid;
+ if (check("Update Dataformat"))
+ generateException();
+*/
+#endif //NOTYET
+ // alternative solution for now:
+ (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "UPDATE RAS_TILES SET DataFormat = %d WHERE BlobId = %d", dataformat, indbmyoid );
+ TALK( pgQuery );
+ pgResult = PQexec( pgConn, pgQuery );
+ if (PQresultStatus(pgResult) != PGRES_COMMAND_OK)
+ {
+ LEAVE( "BLOBTile::updateInDb() libpq 'update dataformat' error: " << PQerrorMessage(pgConn) );
+ PQclear( pgResult );
+ generateException();
+ }
+
+ // (4) --- update map ref
+ DBObject::updateInDb();
+
+ LEAVE( "BLOBTile::updateInDb, myOId=" << myOId );
+ RMDBGEXIT(3, RMDebug::module_blobif, "BLOBTile", "updateInDb() " << myOId);
+} // updateInDb()
+
+// insert new blob into ras_tiles table, update map ref
+// tuple is identified by blobtile.cc var myOId
+// data is taken from buffer 'cells' containing 'size' bytes
+void
+BLOBTile::insertInDb() throw (r_Error)
+{
+ RMDBGENTER(3, RMDebug::module_blobif, "BLOBTile", "insertInDb() " << myOId);
+ ENTER( "BLOBTile::insertInDb" );
+
+/*
+#ifdef NOTYET
+ EXEC SQL BEGIN DECLARE SECTION;
+#endif NOTYET
+*/
+ Oid blobOid;
+ long indbmyOId2;
+ short dataformat2;
+ Oid tile2;
+/*
+#ifdef NOTYET
+ EXEC SQL END DECLARE SECTION;
+#endif NOTYET
+*/
+ dataformat2 = dataFormat;
+
+ // prelim:
+ char pgQuery[SQL_QUERY_BUFFER_SIZE];
+ PGresult *pgResult = NULL;
+
+ indbmyOId2 = myOId.getCounter();
+ TALK( "myOId.getCounter = " << indbmyOId2 );
+
+ // (1) --- open, write, close blob; generates new 'oid' for subsequent storage in tuple
+ TALK( "lo_creat()" );
+ blobOid = lo_creat( pgConn, INV_READ|INV_WRITE ); // create -- not clear what INV_* here means so indicate all
+ if (blobOid == 0)
+ {
+ RMInit::logOut << "BLOBTile::insertInDb() cannot create blob, error: " << PQerrorMessage(pgConn) << endl;
+ LEAVE( "BLOBTile::insertInDb(): cannot create blob, error " << PQerrorMessage(pgConn) );
+ generateException();
+ }
+ TALK( "lo_open() for oid " << blobOid );
+ int fd = lo_open( pgConn, blobOid, INV_WRITE ); // no error code indicated, 0 seems to be no error
+ TALK( "lo_write() for fd " << fd << " and " << size << " bytes" );
+ int loResult = lo_write( pgConn, fd, cells, size );
+ if (loResult < 0)
+ {
+ RMInit::logOut << "BLOBTile::insertInDb() cannot write blob, error: " << PQerrorMessage(pgConn) << endl;
+ LEAVE( "BLOBTile::insertInDb(): cannot write blob, error " << PQerrorMessage(pgConn) );
+ generateException();
+ }
+ else if (loResult != size) // did not get all
+ {
+ RMInit::dbgOut << "BLOB (" << myOId << ") insert: wrote " << loResult << " instead of " << size << " bytes" << endl;
+ LEAVE( "BLOBTile::insertInDb(): wrote " << loResult << " instead of " << size << " bytes" );
+ generateException();
+ }
+ TALK( "lo_close()" );
+ loResult = lo_close( pgConn, fd );
+ if (loResult < 0) // cannot close, don't know if data are there
+ {
+ RMInit::logOut << "BLOBTile::insertInDb() ignoring lo_close() error: " << PQerrorMessage(pgConn) << endl;
+ LEAVE( "BLOBTile::insertInDb(): ignoring lo_close() error: " << PQerrorMessage(pgConn) );
+ generateException();
+ }
+
+/*
+#ifdef NOTYET
+ // (2) --- insert tuple into db
+ TALK( "EXEC SQL INSERT INTO RAS_TILES ( BlobId, DataFormat, Tile ) VALUES (" << indbmyOId2 << "," << dataformat2 << ", " << blobOid << ")" );
+ EXEC SQL INSERT INTO RAS_TILES ( BlobId, DataFormat, Tile)
+ VALUES ( :indbmyOId2, :dataformat2, :blobOid );
+#endif NOTYET
+*/
+ // alternative solution for now:
+ // (2) --- insert tuple into db
+ (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "INSERT INTO RAS_TILES ( BlobId, DataFormat, Tile) VALUES ( %d, %d, %d )", indbmyOId2, dataformat2, blobOid );
+ TALK( pgQuery );
+ pgResult = PQexec( pgConn, pgQuery );
+ if (PQresultStatus(pgResult) != PGRES_COMMAND_OK)
+ {
+ LEAVE( "BLOBTile::insertInDb() libpq 'insert' error: " << PQerrorMessage(pgConn) );
+ PQclear( pgResult );
+ generateException();
+ }
+ PQclear( pgResult );
+
+ // FIXME: other sources have here an updateInDb();
+
+ // (3) --- update map ref
+ DBObject::insertInDb();
+
+ LEAVE( "BLOBTile::insertInDb(), myOId=" << myOId );
+ RMDBGEXIT(3, RMDebug::module_blobif, "BLOBTile", "insertInDb() " << myOId);
+} // insertInDb()
+
+// delete one tuple from ras_tiles table, update map ref
+// tuple is identified by blobtile.cc var myOId
+void
+BLOBTile::deleteFromDb() throw (r_Error)
+{
+ RMDBGENTER(3, RMDebug::module_blobif, "BLOBTile", "deleteFromDb() " << myOId);
+ ENTER( "BLOBTile::deleteFromDb" );
+
+/*
+#ifdef NOTYET
+ EXEC SQL BEGIN DECLARE SECTION;
+#endif NOTYET
+*/
+ long blobId; // blob tuple primary key
+ Oid blobOid; // blob oid "ptr"
+/*
+#ifdef NOTYET
+ EXEC SQL END DECLARE SECTION;
+#endif NOTYET
+*/
+
+ // get counter value (primary key) from oid
+ blobId = myOId.getCounter();
+
+/*
+#ifdef NOTYET
+ // (1) --- get tile tuple
+ TALK( "EXEC SQL SELECT Tile INTO :blobOid FROM RAS_TILES WHERE BlobId = " << blobId );
+ EXEC SQL SELECT Tile INTO :blobOid FROM RAS_TILES WHERE BlobId = :blobId;
+ if (SQLCODE < 0)
+ {
+ LEAVE( "BLOBTile::deleteFromDb(): Fatal error: cannot find tuple for oid " << blobId );
+ check("BLOBTile::deleteFromDb() - find tuple\0");
+ generateException();
+ }
+#endif NOTYET
+*/
+ char pgQuery[SQL_QUERY_BUFFER_SIZE];
+ (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "SELECT Tile FROM RAS_TILES WHERE BlobId = %d", blobId );
+ TALK( pgQuery );
+ PGresult *pgResult = PQexec( pgConn, pgQuery );
+ if (PQresultStatus(pgResult))
+ {
+ LEAVE( "BLOBTile::deleteFromDb() libpq 'select tile' error: " << PQerrorMessage(pgConn) );
+ PQclear( pgResult );
+ generateException();
+ }
+ else if (PQntuples(pgResult) != 1)
+ {
+ LEAVE( "BLOBTile::deleteFromDb() libpq 'select' did not yield 1 result but " << PQntuples(pgResult) );
+ PQclear( pgResult );
+ generateException();
+ }
+ blobOid = atoi( PQgetvalue( pgResult, 0, 0 ) ); // extract value from result
+ PQclear( pgResult );
+
+ // FIXME: other sources have here an updateInDb();
+
+ // (2) --- delete blob identified by blobOid
+ TALK( "lo_unlink()" );
+ int loResult = lo_unlink( pgConn, blobOid );
+ if (loResult < 0)
+ {
+ LEAVE( "BLOBTile::deleteFromDb(): cannot unlink blob with id '" << blobOid << "' for oid " << blobId << PQerrorMessage(pgConn) );
+ generateException();
+ }
+
+/*
+#ifdef NOTYET
+ // (3) --- delete tuple from table
+ TALK( "EXEC SQL DELETE FROM RAS_TILES WHERE BlobId = " << blobId );
+ EXEC SQL DELETE FROM RAS_TILES WHERE BlobId = :blobId;
+ if (SQLCODE < 0)
+ {
+ LEAVE( "BLOBTile::deleteFromDb: Fatal error: cannot delete tuple for oid " << blobId << ", error: " << SQLCODE );
+ check("BLOBTile::deleteFromDb() - delete tuple\0");
+ generateException();
+ }
+#endif NOTYET
+*/
+ (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "DELETE FROM RAS_TILES WHERE BlobId = ", blobOid );
+ TALK( pgQuery );
+ pgResult = PQexec( pgConn, pgQuery );
+ if (PQresultStatus(pgResult) != PGRES_COMMAND_OK)
+ {
+ LEAVE( "BLOBTile::deleteFromDb() libpq 'delete tuple' error: " << PQerrorMessage(pgConn) );
+ PQclear( pgResult );
+ generateException();
+ }
+ PQclear( pgResult );
+
+ // FIXME: other sources have here an updateInDb();
+
+ // update map ref
+ DBObject::deleteFromDb();
+
+ LEAVE( "BLOBTile::deleteFromDb, myOId=" << myOId );
+ RMDBGEXIT(3, RMDebug::module_blobif, "BLOBTile", "deleteFromDb() " << myOId);
+}
+
+// delete a range of tuple(s) from ras_tiles table, update map ref
+// tuples are identified by target and a range
+void
+BLOBTile::kill(const OId& target, unsigned int range)
+{
+ RMDBGENTER(0, RMDebug::module_blobif, "BLOBTile", "kill(" << target << ", " << range <<")");
+ ENTER( "BLOBTile::kill, target=" << target << ", range=" << range );
+
+/*
+#ifdef NOTYET
+ EXEC SQL BEGIN DECLARE SECTION;
+#endif NOTYET
+*/
+ long indbmyOId5;
+ long indbmyOId6;
+ long blobId; // blob tuple primary key
+ Oid blobOid; // blob oid "ptr"
+/*
+#ifdef NOTYET
+ EXEC SQL END DECLARE SECTION;
+#endif NOTYET
+*/
+ char pgQuery[SQL_QUERY_BUFFER_SIZE];
+ PGresult *pgResult = NULL; // query result
+
+ DBObject* targetobj = NULL;
+
+ if (range == 0) // single tuple
+ {
+ // (1) --- delete form cache
+ targetobj = ObjectBroker::isInMemory(target);
+ if (targetobj)
+ {
+ targetobj->setPersistent(false);
+ }
+
+ // (2) --- free blob
+ indbmyOId5 = target.getCounter();
+/*
+#ifdef NOTYET
+ TALK( "EXEC SQL SELECT Tile INTO :blobOid FROM RAS_TILES WHERE BlobId = " << indbmyOId5 );
+ EXEC SQL SELECT Tile INTO :blobOid FROM RAS_TILES WHERE BlobId = :indbmyOId5;
+ if (SQLCODE < 0)
+ {
+ LEAVE( "BLOBTile::kill(): Fatal error: cannot find tuple for oid " << blobId );
+ check("BLOBTile::kill() - find tuple\0");
+ generateException();
+ }
+ else if (SQLCODE != SQLNODATAFOUND) // we've got a tuple
+ {
+ // delete blob identified by blobOid
+ }
+ // else there is no tuple - this is inconsistent, but nothing to delete
+#endif NOTYET
+*/
+ (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "SELECT Tile FROM RAS_TILES WHERE BlobId = %d", indbmyOId5 );
+ TALK( pgQuery );
+ pgResult = PQexec( pgConn, pgQuery );
+ if (PQresultStatus(pgResult) != PGRES_TUPLES_OK)
+ {
+ LEAVE( "BLOBTile::kill() libpq 'select tile' error: " << PQerrorMessage(pgConn) );
+ PQclear( pgResult );
+ generateException();
+ }
+ else if (PQntuples(pgResult) != 1)
+ {
+ LEAVE( "BLOBTile::kill() libpq 'select' did not yield 1 result but " << PQntuples(pgResult) );
+ PQclear( pgResult );
+ generateException();
+ }
+ blobOid = atoi( PQgetvalue( pgResult, 0, 0 ) ); // extract value from result
+ PQclear( pgResult );
+
+ // delete blob identified by blobOid
+ int loResult = lo_unlink( pgConn, blobOid );
+ if (loResult < 0)
+ {
+ LEAVE( "BLOBTile::kill(): cannot unlink blob with id '" << blobOid << "' for oid " << blobId << ": " << PQerrorMessage(pgConn) );
+ check("BLOBTile::kill() - unlink blob\0");
+ generateException();
+ }
+
+/*
+#ifdef NOTYET
+ // (3) --- delete tuple
+ TALK( "EXEC SQL DELETE FROM RAS_TILES WHERE BlobId = " << indbmyOId5 );
+ EXEC SQL DELETE FROM RAS_TILES WHERE BlobId = :indbmyOId5;
+ if (SQLCODE != SQLOK)
+ {
+ if (SQLCODE == SQLNODATAFOUND) // was: NODATA -- PB 2005-feb-13
+ {
+ if (target.getType() == OId::INLINETILEOID)
+ {
+ InlineTileId t(target);
+ if (!t.is_null())
+ t->setPersistent(false);
+ }
+ //else: this tile has been deleted before
+ }
+ else
+ {
+ check("BLOBTile::kill()\0");
+ generateException();
+ }
+ }
+#endif NOTYET
+*/
+ (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "DELETE FROM RAS_TILES WHERE BlobId = %d", indbmyOId5 );
+ TALK( pgQuery );
+ pgResult = PQexec( pgConn, pgQuery );
+ if (PQresultStatus(pgResult) != PGRES_COMMAND_OK)
+ {
+ LEAVE( "BLOBTile::kill() libpq 'delete single' error: " << PQerrorMessage(pgConn) );
+ PQclear( pgResult );
+ generateException();
+ }
+ else if (PQntuples(pgResult) == 0)
+ {
+ if (target.getType() == OId::INLINETILEOID)
+ {
+ InlineTileId t(target);
+ if (!t.is_null())
+ t->setPersistent(false);
+ }
+ //else: this tile has been deleted before
+ }
+ PQclear( pgResult );
+ }
+ else
+ {
+ // (1) --- iterate over cache and remove
+ DBObjectPMap& mapRef = ObjectBroker::getMap(target.getType());
+ DBObjectPMap::iterator it = mapRef.begin();
+ DBObjectPMap::iterator theEnd = mapRef.end();
+ OId end(target.getCounter() + range, target.getType());
+ while (it != theEnd)
+ {
+ if (target <= (const OId&)(*it).first && (*it).first <= (const OId&)end)
+ {
+ (*it).second->setPersistent(false);
+ }
+ }
+
+ // (2) --- iterate over db and remove
+/*
+#ifdef NOTYET
+ TALK( "EXEC SQL DECLARE DeleteLoop CURSOR FOR SELECT Tile FROM RAS_TILES WHERE " << indbmyOId5 << " <= BlobId AND BlobId <= " << indbmyOId6 );
+ EXEC SQL DECLARE DeleteLoop CURSOR FOR SELECT Tile FROM RAS_TILES WHERE :indbmyOId5 <= BlobId AND BlobId <= :indbmyOId6;
+ if (SQLCODE < 0)
+ {
+ LEAVE( "BLOBTile::kill: Fatal error: cannot prepare cursor for oid " << blobId << " to " << indbmyOId6 );
+ check("BLOBTile::kill() - prepare cursor\0");
+ generateException();
+ }
+#endif NOTYET
+*/
+ (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "DECLARE DeleteLoop CURSOR FOR SELECT Tile FROM RAS_TILES WHERE %d <= BlobId AND BlobId <= %d", indbmyOId5, indbmyOId6 );
+ TALK( pgQuery );
+ pgResult = PQexec( pgConn, pgQuery );
+ if (PQresultStatus(pgResult) != PGRES_TUPLES_OK)
+ {
+ LEAVE( "BLOBTile::kill() libpq 'select for deleteLoop' error: " << PQerrorMessage(pgConn) );
+ PQclear( pgResult );
+ generateException();
+ }
+
+ // loop over elements & delete each one
+ do
+ {
+/*
+#ifdef NOTYET
+ TALK( "EXEC SQL FETCH NEXT FROM DeleteLoop INTO :blobOid" );
+ EXEC SQL FETCH NEXT FROM DeleteLoop INTO :blobOid;
+ if (SQLCODE < 0)
+ {
+ LEAVE( "BLOBTile::kill: Fatal error: cannot fetch next tuple" );
+ check("BLOBTile::kill() - fetch next tuple\0");
+ generateException();
+ }
+#endif NOTYET
+*/
+ (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "FETCH NEXT FROM DeleteLoop" );
+ TALK( pgQuery );
+ pgResult = PQexec( pgConn, pgQuery );
+ if (PQresultStatus(pgResult) != PGRES_TUPLES_OK)
+ {
+ LEAVE( "BLOBTile::kill() libpq 'fetch next' error: " << PQerrorMessage(pgConn) );
+ PQclear( pgResult );
+ generateException();
+ }
+ else if (PQntuples(pgResult) != 1)
+ {
+ LEAVE( "BLOBTile::kill() libpq 'fetch' did not yield 1 result but " << PQntuples(pgResult) );
+ PQclear( pgResult );
+ generateException();
+ }
+ blobOid = atoi( PQgetvalue( pgResult, 0, 0 ) ); // extract value from result
+
+ // delete blob identified by blobOid
+ int loResult = lo_unlink( pgConn, blobOid );
+ if (loResult < 0)
+ {
+ LEAVE( "BLOBTile::kill: Fatal error: cannot unlink blob with id '" << blobOid << "' for oid " << blobId );
+ check("BLOBTile::kill() - unlink blob\0");
+ generateException();
+ }
+/*
+#ifdef NOTYET
+ } while (SQLCODE == SQLOK || SQLCODE < 0);
+#endif NOTYET
+*/
+ // FIXME: what about errors? continue??
+ } while (PQresultStatus(pgResult) != PGRES_TUPLES_OK);
+ PQclear( pgResult );
+
+ // (3) --- delete tuples in db
+ indbmyOId5 = target.getCounter();
+ indbmyOId6 = end.getCounter();
+/*
+#ifdef NOTYET
+ TALK( "EXEC SQL DELETE FROM RAS_TILES WHERE " << indbmyOId5 << " <= BlobId AND BlobId <= " << indbmyOId6 );
+ EXEC SQL DELETE FROM RAS_TILES WHERE :indbmyOId5 <= BlobId AND BlobId <= :indbmyOId6;
+ if ((SQLCODE != SQLOK) && (SQLCODE != SQLNODATAFOUND))
+ {
+ check("BLOBTile::kill()\0");
+ generateException();
+ }
+#endif NOTYET
+*/
+ (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "DELETE FROM RAS_TILES WHERE %d <= BlobId AND BlobId <= %d", indbmyOId5, indbmyOId6 );
+ TALK( pgQuery );
+ pgResult = PQexec( pgConn, pgQuery );
+ if (PQresultStatus(pgResult) != PGRES_COMMAND_OK)
+ {
+ LEAVE( "BLOBTile::kill() libpq 'delete range' error: " << PQerrorMessage(pgConn) );
+ PQclear( pgResult );
+ generateException();
+ }
+ PQclear( pgResult );
+
+ }
+
+ LEAVE( "BLOBTile::kill" );
+ RMDBGEXIT(0, RMDebug::module_blobif, "BLOBTile", "kill(" << target << " " << target.getType() << ")");
+}
+
+// read tuple from ras_tiles, identified by blobtile.cc var myOId
+// allocates necessary mem into ptr 'cells' and fills it; must be freed elsewhere
+// external var 'size' is set to the number of bytes read
+void
+BLOBTile::readFromDb() throw (r_Error)
+{
+ RMDBGENTER(3, RMDebug::module_blobif, "BLOBTile", "readFromDb() " << myOId);
+ ENTER( "BLOBTile::readFromDb" );
+
+#ifdef RMANBENCHMARK
+ DBObject::readTimer.resume();
+#endif
+
+/*
+#ifdef NOTYET
+ EXEC SQL BEGIN DECLARE SECTION;
+#endif NOTYET
+*/
+ Oid blobOid;
+ long indbmyOId3;
+ short dataformat3;
+ short indicatorr3;
+/*
+#ifdef NOTYET
+ EXEC SQL END DECLARE SECTION;
+#endif NOTYET
+*/
+ PGresult *pgResult = NULL; // PostgreSQL call return values
+
+ indbmyOId3 = myOId.getCounter();
+
+ // (1) --- access tuple
+/*
+#ifdef NOTYET
+ TALK( "EXEC SQL SELECT Tile, DataFormat INTO :blobOid, :dataformat3 FROM RAS_TILES WHERE BlobId = " << indbmyOId3 );
+ EXEC SQL SELECT Tile, DataFormat INTO :blobOid, :dataformat3 FROM RAS_TILES WHERE BlobId = :indbmyOId3;
+ if (SQLCODE < 0)
+ {
+ RMInit::logOut << "BLOBTile::readFromDb() Fatal error during RAS_TILES read: got SQLCODE " << SQLCODE << " for oid " << indbmyOId3 << endl;
+ LEAVE( "BLOBTile::readFromDb: Fatal error during RAS_TILES read: got SQLCODE " << SQLCODE << " for oid " << indbmyOId3 );
+ check("BLOBTile::readFromDb() - find tuple\0");
+ generateException();
+ }
+ else if (SQLCODE == SQLNODATAFOUND) // we've got no tuple
+ {
+ RMInit::logOut << "BLOBTile::readFromDb() error: object unknown for oid " << indbmyOId3 << endl;
+ LEAVE( "BLOBTile::readFromDb: Error: object unknown for oid " << indbmyOId3 );
+ throw r_Error(r_Error::r_Error_ObjectUnknown);
+ }
+#endif NOTYET
+*/
+ char pgQuery[SQL_QUERY_BUFFER_SIZE];
+ (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "SELECT Tile, DataFormat FROM RAS_TILES WHERE BlobId = %d", indbmyOId3 );
+ TALK( pgQuery );
+ pgResult = PQexec( pgConn, pgQuery );
+ if (PQresultStatus(pgResult) != PGRES_TUPLES_OK)
+ {
+ LEAVE( "BLOBTile::readFromDb() libpq 'select' error: " << PQerrorMessage(pgConn) );
+ PQclear( pgResult );
+ generateException();
+ }
+ else if (PQntuples(pgResult) != 1)
+ {
+ LEAVE( "BLOBTile::readFromDb() libpq 'select' did not yield 1 result but " << PQntuples(pgResult) );
+ PQclear( pgResult );
+ throw r_Error(r_Error::r_Error_ObjectUnknown);
+ }
+ blobOid = atoi( PQgetvalue( pgResult, 0, 0 ) ); // extract 1st value from result
+ dataformat3 = atoi( PQgetvalue( pgResult, 0, 1 ) ); // extract 2nd value from result
+ PQclear( pgResult );
+
+ // we have a tuple, extract data format
+ dataFormat = (r_Data_Format)dataformat3;
+ currentFormat = (r_Data_Format)dataformat3;
+ TALK( "got dataFormat " << dataFormat );
+
+ // (2) --- open, read, close blob
+ TALK( "lo_open()" );
+ int fd = lo_open( pgConn, blobOid, INV_READ ); // open; manual tells no error indication
+ TALK( "lo_lseek() end" );
+ size = lo_lseek( pgConn, fd, 0, SEEK_END ); // determine blob size; FIXME: more efficient method??
+ TALK( "lo_lseek() start" );
+ (void) lo_lseek( pgConn, fd, 0, SEEK_SET ); // rewind for reading
+ cells = (char*) mymalloc( size * sizeof(char) ); // allocate buffer for blob
+ if (cells == NULL)
+ {
+ RMInit::logOut << "BLOBTile::readFromDb() error: cannot allocate " << size << " bytes " << endl;
+ LEAVE( "BLOBTile::readFromDb: error: cannot allocate " << size << " bytes" );
+ generateException();
+ }
+
+ TALK( "lo_read()" ); // read blob
+ int loResult = lo_read( pgConn, fd, cells, size );
+ if (loResult < 0)
+ {
+ RMInit::logOut << "BLOBTile::readFromDb() cannot read blob, error: " << PQerrorMessage(pgConn) << endl;
+ LEAVE( "BLOBTile::readFromDb: cannot read blob, error " << PQerrorMessage(pgConn) );
+ generateException();
+ }
+ else if (loResult != size) // did not get all
+ {
+ RMInit::dbgOut << "BLOB (" << myOId << ") read: want to read (" << size << " bytes, but got " << loResult << " bytes" << endl;
+ LEAVE( "BLOBTile::readFromDb: want to read " << size << " bytes, but got " << loResult << " bytes" );
+ generateException();
+ }
+ TALK( "lo_close()" );
+ int ignoredPgResult = lo_close( pgConn, fd ); // close blob
+ if (ignoredPgResult < 0) // we note, but ignore errors, as we have the data
+ {
+ RMInit::logOut << "BLOBTile::readFromDb() ignoring lo_close() error: " << ignoredPgResult << endl;
+ TALK( "BLOBTile::readFromDb: ignoring lo_close() error: " << ignoredPgResult );
+ }
+ RMDBGIF(20, RMDebug::module_blobif, "BLOBTileOutput", for (int a = 0; a < size; a++)\
+ RMInit::dbgOut << " " << hex << (int)(cells[a]); RMInit::dbgOut << dec << endl;)
+
+ DBObject::readFromDb();
+
+#ifdef RMANBENCHMARK
+ DBObject::readTimer.pause();
+#endif
+
+ LEAVE( "BLOBTile::readFromDb" );
+ RMDBGEXIT(3, RMDebug::module_blobif, "BLOBTile", "readFromDb() " << myOId);
+}
+