summaryrefslogtreecommitdiffstats
path: root/relindexif/hierindex.pgc
diff options
context:
space:
mode:
Diffstat (limited to 'relindexif/hierindex.pgc')
-rw-r--r--relindexif/hierindex.pgc745
1 files changed, 745 insertions, 0 deletions
diff --git a/relindexif/hierindex.pgc b/relindexif/hierindex.pgc
new file mode 100644
index 0000000..fa56b8b
--- /dev/null
+++ b/relindexif/hierindex.pgc
@@ -0,0 +1,745 @@
+#include "mymalloc/mymalloc.h"
+
+/*
+* 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>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * Code with embedded SQL for PostgreSQL DBMS
+ *
+ *
+ * COMMENTS:
+ * - blobs contain 13c as first byte; this is not required here,
+ * but kept for data compatibility with other base DBMSs.
+ *
+ ************************************************************/
+
+// PG stuff:
+#include "libpq-fe.h" /* C interface to PgSQL */
+#include "libpq/libpq-fs.h" /* large object (lo) api */
+
+#include "debug-srv.hh"
+
+// general embedded SQL related definitions
+EXEC SQL include "../reladminif/sqlglobals.h";
+
+#include "hierindex.hh"
+#include "raslib/rmdebug.hh"
+#include "reladminif/sqlerror.hh"
+#include "relblobif/blobtile.hh"
+#include "indexmgr/keyobject.hh"
+
+// libpg connection maintenance
+extern PGconn *pgConn;
+
+void
+DBHierIndex::insertInDb() throw (r_Error)
+{
+ RMDBGENTER(5, RMDebug::module_indexif, "DBHierIndex", "insertInDb() " << myOId);
+ ENTER( "DBHierIndex::insertInDb(), myOId=" << myOId );
+
+#ifdef NOTYET // should be in future
+/*
+ EXEC SQL BEGIN DECLARE SECTION;
+*/
+#endif // NOTYET
+ double id2;
+ long dimension2;
+ long size2;
+ double parentid2;
+ short indexsubtype2;
+ Oid blobOid;
+ char pgQuery[SQL_QUERY_BUFFER_SIZE]; // prelim
+ PGresult *pgResult = NULL; // prelim
+#ifdef NOTYET // should be in future
+/*
+ EXEC SQL END DECLARE SECTION;
+*/
+#endif // NOTYET
+
+ // (0) --- prepare variables
+ id2 = myOId;
+ dimension2 = myDomain.dimension();
+ // size2 = myKeyObjects.size();
+ size2 = getSize();
+ indexsubtype2 = _isNode;
+
+ if (parent.getType() == OId::INVALID)
+ parentid2 = 0;
+ else
+ parentid2 = parent;
+
+ // (1) -­- set all buffers
+ //number of bytes for bounds for "size" entries and mydomain
+ r_Bytes boundssize = sizeof(r_Range) * (size2 + 1) * dimension2;
+ //number of bytes for fixes for "size" entries and mydomain
+ r_Bytes fixessize = sizeof(char) * (size2 + 1) * dimension2;
+ //number of bytes for ids of entries
+ r_Bytes idssize = sizeof(OId::OIdCounter) * size2;
+ //number of bytes for types of entries
+ r_Bytes typessize = sizeof(char) * size2;
+ //number of bytes for the dynamic data, plus 1 starter byte (see below)
+ r_Bytes completesize = 1 + boundssize * 2 + fixessize * 2 + idssize + typessize;
+
+ char* completebuffer = (char*)mymalloc(completesize);
+ if (completebuffer == NULL)
+ {
+ RMInit::logOut << "DBHierIndex::insertInDb() cannot malloc buffer" << endl;
+ LEAVE( "DBHierIndex::insertInDb() cannot malloc buffer" );
+ throw r_Error( r_Error::r_Error_MemoryAllocation );
+ }
+ r_Range* upperboundsbuf = (r_Range*)mymalloc(boundssize);
+ if (upperboundsbuf == NULL)
+ {
+ RMInit::logOut << "DBHierIndex::insertInDb() cannot malloc buffer" << endl;
+ LEAVE( "DBHierIndex::insertInDb() cannot malloc buffer" );
+ throw r_Error( r_Error::r_Error_MemoryAllocation );
+ }
+ r_Range* lowerboundsbuf = (r_Range*)mymalloc(boundssize);
+ if (lowerboundsbuf == NULL)
+ {
+ RMInit::logOut << "DBHierIndex::insertInDb() cannot malloc buffer" << endl;
+ LEAVE( "DBHierIndex::insertInDb() cannot malloc buffer" );
+ throw r_Error( r_Error::r_Error_MemoryAllocation );
+ }
+ char* upperfixedbuf = (char*)mymalloc(fixessize);
+ if (upperfixedbuf == NULL)
+ {
+ RMInit::logOut << "DBHierIndex::insertInDb() cannot malloc buffer" << endl;
+ LEAVE( "DBHierIndex::insertInDb() cannot malloc buffer" );
+ throw r_Error( r_Error::r_Error_MemoryAllocation );
+ }
+ char* lowerfixedbuf = (char*)mymalloc(fixessize);
+ if (lowerfixedbuf == NULL)
+ {
+ RMInit::logOut << "DBHierIndex::insertInDb() cannot malloc buffer" << endl;
+ LEAVE( "DBHierIndex::insertInDb() cannot malloc buffer" );
+ throw r_Error( r_Error::r_Error_MemoryAllocation );
+ }
+ OId::OIdCounter* entryidsbuf = (OId::OIdCounter*)mymalloc(idssize);
+ if (entryidsbuf == NULL)
+ {
+ RMInit::logOut << "DBHierIndex::insertInDb() cannot malloc buffer" << endl;
+ LEAVE( "DBHierIndex::insertInDb() cannot malloc buffer" );
+ throw r_Error( r_Error::r_Error_MemoryAllocation );
+ }
+ char* entrytypesbuf = (char*)mymalloc(typessize);
+ if (entrytypesbuf == NULL)
+ {
+ RMInit::logOut << "DBHierIndex::insertInDb() cannot malloc buffer" << endl;
+ LEAVE( "DBHierIndex::insertInDb() cannot malloc buffer" );
+ throw r_Error( r_Error::r_Error_MemoryAllocation );
+ }
+
+ RMDBGMIDDLE(8, RMDebug::module_indexif, "DBHierIndex", "complete=" << completesize << " bounds=" << boundssize << " fixes=" << fixessize << " ids=" << idssize << " types=" << typessize << ", size=" << size2 << " dimension=" << dimension2 );
+
+ myDomain.insertInDb(&(lowerboundsbuf[0]), &(upperboundsbuf[0]), &(lowerfixedbuf[0]), &(upperfixedbuf[0]));
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBHierIndex", "domain " << myDomain << " stored as " << InlineMinterval(dimension2, &(lowerboundsbuf[0]), &(upperboundsbuf[0]), &(lowerfixedbuf[0]), &(upperfixedbuf[0])));
+ //populate the buffers with data
+ KeyObjectVector::iterator it = myKeyObjects.begin();
+ InlineMinterval indom;
+ for (unsigned int i = 0; i < size2; i++, it++)
+ {
+ indom = (*it).getDomain();
+ indom.insertInDb(&(lowerboundsbuf[(i+1)*dimension2]), &(upperboundsbuf[(i+1)*dimension2]), &(lowerfixedbuf[(i+1)*dimension2]), &(upperfixedbuf[(i+1)*dimension2]));
+ entryidsbuf[i] = (*it).getObject().getOId().getCounter();
+ entrytypesbuf[i] = (char)(*it).getObject().getOId().getType();
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBHierIndex", "entry " << entryidsbuf[i] << " " << (OId::OIdType)entrytypesbuf[i] << " at " << InlineMinterval(dimension2, &(lowerboundsbuf[(i+1)*dimension2]), &(upperboundsbuf[(i+1)*dimension2]), &(lowerfixedbuf[(i+1)*dimension2]), &(upperfixedbuf[(i+1)*dimension2])));
+ }
+
+ // write the buffers in the complete buffer, free all unnecessary buffers
+ // this indirection is neccessary because of memory alignement of longs...
+ completebuffer[0] = 13; //the first char must not be a \0
+ (void) memcpy( &completebuffer[1], lowerboundsbuf, boundssize);
+ free(lowerboundsbuf);
+ (void) memcpy( &completebuffer[boundssize + 1], upperboundsbuf, boundssize);
+ free(upperboundsbuf);
+ (void) memcpy( &completebuffer[boundssize * 2 + 1], lowerfixedbuf, fixessize);
+ free(lowerfixedbuf);
+ (void) memcpy( &completebuffer[boundssize * 2 + fixessize + 1], upperfixedbuf, fixessize);
+ free(upperfixedbuf);
+ (void) memcpy( &completebuffer[boundssize * 2 + fixessize * 2 + 1], entryidsbuf, idssize);
+ free(entryidsbuf);
+ (void) memcpy( &completebuffer[boundssize * 2 + fixessize * 2 + idssize + 1], entrytypesbuf, typessize);
+ free(entrytypesbuf);
+
+#ifdef RMANDEBUG // dump low-level blob byte string
+{
+ char printbuf[10000];
+ (void) sprintf( printbuf, "XXX DBHierIndex::insertInDb(): [%d]", completesize );
+ char bytebuf[3];
+ for (unsigned int i = 0; i < completesize; i++)
+ {
+ (void) sprintf( bytebuf, " %2X", (unsigned char) completebuffer[i] );
+ strcat( printbuf, bytebuf );
+ }
+ TALK( printbuf );
+}
+#endif // RMANDEBUG
+
+ // (2) --- create, 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 << "DBHierIndex::insertInDb() cannot create blob, error: " << PQerrorMessage(pgConn) << endl;
+ LEAVE( "DBHierIndex::insertInDb(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 << " with " << completesize << " bytes" );
+ int loResult = lo_write( pgConn, fd, completebuffer, completesize );
+ if (loResult < 0)
+ {
+ RMInit::logOut << "DBHierIndex::insertInDb() cannot write blob, error: " << PQerrorMessage(pgConn) << endl;
+ LEAVE( "DBHierIndex::insertInDb() cannot write blob, error " << PQerrorMessage(pgConn) );
+ generateException();
+ }
+ else if (loResult != completesize) // did not get all
+ {
+ RMInit::dbgOut << "BLOB (" << myOId << ") insert: wrote " << loResult << " instead of " << completesize << " bytes" << endl;
+ LEAVE( "DBHierIndex::insertInDb() wrote " << loResult << " instead of " << completesize << " 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 << "DBHierIndex::insertInDb() ignoring lo_close() error: " << PQerrorMessage(pgConn) << endl;
+ LEAVE( "DBHierIndex::insertInDb() cannot lo_close(): " << PQerrorMessage(pgConn) );
+ generateException();
+ }
+
+ free(completebuffer); // free main buffer
+
+ // (3) --- insert HIERIX tuple into db
+#ifdef NOTYET // should be in future
+/*
+ TALK( "EXEC SQL INSERT INTO RAS_HIERIX ( MDDObjIxOId, NumEntries, Dimension, ParentOId, IndexSubType, DynData ) VALUES ( " << id2 << "," << size2 << "," << dimension2 << "," << parentid2 << "," << indexsubtype2 << ", " << blobOid << " )" );
+ EXEC SQL INSERT INTO RAS_HIERIX ( MDDObjIxOId, NumEntries, Dimension, ParentOId, IndexSubType, DynData)
+ VALUES ( :id2, :size2, :dimension2, :parentid2, :indexsubtype2, :blobOid);
+ if (SQLCODE != SQLOK)
+ {
+ check("DBHierIndex::insertInDb() insert into RAS_HIERIX\0");
+ LEAVE( "DBHierIndex::insertInDb(): db access error: " << SQLCODE );
+ generateException();
+ }
+*/
+#endif // NOTYET
+ // alternative solution for now:
+ (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "INSERT INTO RAS_HIERIX ( MDDObjIxOId, NumEntries, Dimension, ParentOId, IndexSubType, DynData ) VALUES ( %f, %d, %d, %f, %d, %d )", id2, size2, dimension2, parentid2, indexsubtype2, blobOid );
+ TALK( pgQuery );
+ pgResult = PQexec( pgConn, pgQuery );
+ if (PQresultStatus(pgResult) != PGRES_COMMAND_OK)
+ {
+ LEAVE( "DBHierIndex::insertInDb() libpq 'insert RAS_HIERIX' error: " << PQerrorMessage(pgConn) );
+ PQclear( pgResult );
+ generateException();
+ }
+ PQclear( pgResult );
+
+ // (4) --- dbobject insert
+ DBObject::insertInDb();
+
+ RMDBGEXIT(5, RMDebug::module_indexif, "DBHierIndex", "insertInDb() " << myOId);
+ LEAVE( "DBHierIndex::insertInDb(), myOId=" << myOId );
+} // insertInDb()
+
+void
+DBHierIndex::readFromDb() throw (r_Error)
+{
+ RMDBGENTER(5, RMDebug::module_indexif, "DBHierIndex", "readFromDb() " << myOId);
+ ENTER( "DBHierIndex::readFromDb(), myOId=" << myOId );
+
+#ifdef RMANBENCHMARK
+ DBObject::readTimer.resume();
+#endif
+#ifdef NOTYET // should be in future
+/*
+ EXEC SQL BEGIN DECLARE SECTION;
+*/
+#endif // NOTYET
+ double id1;
+ double parentid1;
+ long dimension1;
+ long size1;
+ short indexsubtype1;
+ short lowerfind;
+ Oid blobOid;
+ char pgQuery[SQL_QUERY_BUFFER_SIZE]; // prelim
+ PGresult *pgResult = NULL; // prelim
+#ifdef NOTYET // should be in future
+/*
+ EXEC SQL END DECLARE SECTION;
+*/
+#endif // NOTYET
+
+ // (0) --- prepare variables
+ id1 = myOId;
+
+ // (1) --- fetch tuple from database
+#ifdef NOTYET // should be in future
+/*
+ TALK( "EXEC SQL SELECT NumEntries, Dimension, ParentOId, IndexSubType, DynData INTO :size1, :dimension1, :parentid1, :indexsubtype1, blobOid FROM RAS_HIERIX WHERE MDDObjIxOId = " << id1 );
+ EXEC SQL SELECT NumEntries, Dimension, ParentOId, IndexSubType, DynData
+ INTO :size1, :dimension1, :parentid1, :indexsubtype1, :blobOid
+ FROM RAS_HIERIX
+ WHERE MDDObjIxOId = :id1;
+ if (SQLCODE != SQLOK)
+ {
+ check("DBHierIndex::readFromDb() select from RAS_HIERIX");
+ LEAVE( "DBHierIndex::insertInDb() 'select from RAS_HIERIX' error: " << SQLCODE );
+ generateException();
+ }
+*/
+#endif // NOTYET
+ // alternative solution for now:
+ (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "SELECT NumEntries, Dimension, ParentOId, IndexSubType, DynData FROM RAS_HIERIX WHERE MDDObjIxOId = %f", id1 );
+ TALK( pgQuery );
+ pgResult = PQexec( pgConn, pgQuery );
+ if (PQresultStatus(pgResult) != PGRES_TUPLES_OK)
+ {
+ LEAVE( "DBHierIndex::insertInDb() libpq 'select RAS_HIERIX' error: " << PQerrorMessage(pgConn) );
+ PQclear( pgResult );
+ generateException();
+ }
+ size1 = atoi( PQgetvalue( pgResult, 0, 0 ) ); // extract value #1 from result
+ dimension1 = atoi( PQgetvalue( pgResult, 0, 1 ) ); // extract value #2 from result
+ parentid1 = atoi( PQgetvalue( pgResult, 0, 2 ) ); // extract value #3 from result
+ indexsubtype1 = atoi( PQgetvalue( pgResult, 0, 3 ) ); // extract value #4 from result
+ blobOid = atoi( PQgetvalue( pgResult, 0, 4 ) ); // extract value #5 from result
+ PQclear( pgResult );
+
+ // (2) --- fill variables and buffers
+
+ _isNode = indexsubtype1;
+
+ if (parentid1)
+ parent = OId(parentid1);
+ else
+ parent = OId(0, OId::INVALID);
+
+ //number of bytes for bounds for "size" entries and mydomain
+ r_Bytes boundssize = sizeof(r_Range) * (size1 + 1) * dimension1;
+ //number of bytes for fixes for "size" entries and mydomain
+ r_Bytes fixessize = sizeof(char) * (size1 + 1) * dimension1;
+ //number of bytes for ids of entries
+ r_Bytes idssize = sizeof(OId::OIdCounter) * size1;
+ //number of bytes for types of entries
+ r_Bytes typessize = sizeof(char) * size1;
+ //number of bytes for the dynamic data (1 starter byte!)
+ r_Bytes completesize = 1 + boundssize * 2 + fixessize * 2 + idssize + typessize;
+
+ RMDBGMIDDLE(8, RMDebug::module_indexif, "DBHierIndex", "complete=" << completesize << " bounds=" << boundssize << " fixes=" << fixessize << " ids=" << idssize << " types=" << typessize << ", size=" << size1 << " dimension=" << dimension1 );
+
+ char* completebuffer = (char*)mymalloc(completesize);
+ r_Range* upperboundsbuf = (r_Range*)mymalloc(boundssize);
+ r_Range* lowerboundsbuf = (r_Range*)mymalloc(boundssize);
+ char* upperfixedbuf = (char*)mymalloc(fixessize);
+ char* lowerfixedbuf = (char*)mymalloc(fixessize);
+ OId::OIdCounter* entryidsbuf = (OId::OIdCounter*)mymalloc(idssize);
+ char* entrytypesbuf = (char*)mymalloc(typessize);
+
+ // (3) --- 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" );
+ int bytesToDo = 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
+ TALK( "lo_read() for " << completesize << " bytes" ); // read blob
+ int loResult = lo_read( pgConn, fd, completebuffer, completesize );
+ if (loResult < 0)
+ {
+ RMInit::logOut << "DBHierIndex::readFromDb() cannot read blob, error: " << pgResult << endl;
+ LEAVE( "DBHierIndex::readFromDb: cannot read blob, error " << pgResult );
+ throw r_Error( r_Error::r_Error_BaseDBMSFailed );
+ }
+ else if (loResult != bytesToDo) // did not get all
+ {
+ RMInit::dbgOut << "BLOB (" << myOId << ") read: want to read (" << bytesToDo << " bytes, but got " << loResult << " bytes" << endl;
+ LEAVE( "DBHierIndex::readFromDb: want to read " << bytesToDo << " bytes, but got " << loResult << " bytes" );
+ throw r_Error( r_Error::r_Error_LimitsMismatch );
+ }
+ else if (completesize != bytesToDo) // this because I don't trust computations
+ {
+ RMInit::dbgOut << "BLOB (" << myOId << ") read: completesize=" << completesize << ", but bytesToDo=" << bytesToDo << endl;
+ LEAVE( "DBHierIndex::readFromDb: completesize=" << completesize << ", but bytesToDo=" << bytesToDo );
+ throw r_Error( r_Error::r_Error_LimitsMismatch );
+ }
+ 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 << "DBHierIndex::readFromDb() ignoring lo_close() error: " << ignoredPgResult << endl;
+ TALK( "DBHierIndex::readFromDb: ignoring lo_close() error: " << ignoredPgResult );
+ }
+
+#ifdef RMANDEBUG // dump low-level blob byte string
+{
+ char printbuf[10000];
+ (void) sprintf( printbuf, "XXX DBHierIndex::readFromDb(): [%d]", completesize );
+ char bytebuf[3];
+ for (unsigned int i = 0; i < completesize; i++)
+ {
+ (void) sprintf( bytebuf, " %2X", (unsigned char) completebuffer[i] );
+ strcat( printbuf, bytebuf );
+ }
+ TALK( printbuf );
+}
+#endif // RMANDEBUG
+
+ // (4) --- copy data into buffers
+ // all dynamic data ( plus starter byte) is in completebuffer, put that stuff in the correct buffers
+ memcpy(lowerboundsbuf, &completebuffer[1], boundssize);
+ memcpy(upperboundsbuf, &completebuffer[boundssize + 1], boundssize);
+ memcpy(lowerfixedbuf, &completebuffer[boundssize * 2 + 1], fixessize);
+ memcpy(upperfixedbuf, &completebuffer[boundssize * 2 + fixessize + 1], fixessize);
+ memcpy(entryidsbuf, &completebuffer[boundssize * 2 + fixessize * 2 + 1], idssize);
+ memcpy(entrytypesbuf, &completebuffer[boundssize * 2 + fixessize * 2 + idssize + 1], typessize);
+ // now all dynamic data is in its private buffer
+ free (completebuffer);
+ completebuffer = NULL;
+
+ // rebuild the attributes from the buffers
+ int i = 0;
+ myDomain = InlineMinterval(dimension1, &(lowerboundsbuf[0]), &(upperboundsbuf[0]), &(lowerfixedbuf[0]), &(upperfixedbuf[i*dimension1]));
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBHierIndex", "domain " << myDomain << " constructed from " << InlineMinterval(dimension1, &(lowerboundsbuf[0]), &(upperboundsbuf[0]), &(lowerfixedbuf[0]), &(upperfixedbuf[0])));
+ KeyObject theKey = KeyObject(DBObjectId(), myDomain);
+ for (i = 0; i < size1; i++)
+ {
+ theKey.setDomain(InlineMinterval(dimension1, &(lowerboundsbuf[(i+1)*dimension1]), &(upperboundsbuf[(i+1)*dimension1]), &(lowerfixedbuf[(i+1)*dimension1]), &(upperfixedbuf[(i+1)*dimension1])));
+ theKey.setObject(OId(entryidsbuf[i], (OId::OIdType)entrytypesbuf[i]));
+ myKeyObjects.push_back(theKey);
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBHierIndex", "entry " << entryidsbuf[i] << " " << (OId::OIdType)entrytypesbuf[i] << " at " << InlineMinterval(dimension1, &(lowerboundsbuf[(i+1)*dimension1]), &(upperboundsbuf[(i+1)*dimension1]), &(lowerfixedbuf[(i+1)*dimension1]), &(upperfixedbuf[(i+1)*dimension1])));
+ }
+
+ free(upperboundsbuf);
+ free(lowerboundsbuf);
+ free(upperfixedbuf);
+ free(lowerfixedbuf);
+ free(entryidsbuf);
+ free(entrytypesbuf);
+
+#ifdef RMANBENCHMARK
+ DBObject::readTimer.pause();
+#endif
+
+ // (5) --- fill dbobject
+ DBObject::readFromDb();
+
+ RMDBGEXIT(5, RMDebug::module_indexif, "DBHierIndex", "readFromDb() " << myOId);
+ LEAVE( "DBHierIndex::readFromDb(), myOId=" << myOId );
+} // readFromDb()
+
+void
+DBHierIndex::updateInDb() throw (r_Error)
+{
+ RMDBGENTER(5, RMDebug::module_indexif, "DBHierIndex", "updateInDb() " << myOId);
+ ENTER( "DBHierIndex::updateInDb(), myOId=" << myOId );
+
+#ifdef NOTYET // should be in future
+/*
+ EXEC SQL BEGIN DECLARE SECTION;
+*/
+#endif // NOTYET
+ double id4;
+ long dimension4;
+ long size4;
+ double parentid4;
+ short count4;
+ short indexsubtype4;
+ Oid blobOid;
+ char pgQuery[SQL_QUERY_BUFFER_SIZE]; // prelim
+ PGresult *pgResult = NULL; // prelim
+#ifdef NOTYET // should be in future
+/*
+ EXEC SQL END DECLARE SECTION;
+*/
+#endif // NOTYET
+
+ // (0) --- prepare variables
+ id4 = myOId;
+ indexsubtype4 = _isNode;
+ dimension4 = myDomain.dimension();
+ size4 = myKeyObjects.size();
+ if (parent.getType() == OId::INVALID)
+ parentid4 = 0;
+ else
+ parentid4 = parent;
+
+ // (1) --- prepare buffer
+ //number of bytes for bounds for "size" entries and mydomain
+ r_Bytes boundssize = sizeof(r_Range) * (size4 + 1) * dimension4;
+ //number of bytes for fixes for "size" entries and mydomain
+ r_Bytes fixessize = sizeof(char) * (size4 + 1) * dimension4;
+ //number of bytes for ids of entries
+ r_Bytes idssize = sizeof(OId::OIdCounter) * size4;
+ //number of bytes for types of entries
+ r_Bytes typessize = sizeof(char) * size4;
+ //number of bytes for the dynamic data; 1 starter byte!
+ r_Bytes completesize = 1 + boundssize * 2 + fixessize * 2 + idssize + typessize;
+
+ char* completebuffer = (char*)mymalloc(completesize);
+ r_Range* upperboundsbuf = (r_Range*)mymalloc(boundssize);
+ r_Range* lowerboundsbuf = (r_Range*)mymalloc(boundssize);
+ char* upperfixedbuf = (char*)mymalloc(fixessize);
+ char* lowerfixedbuf = (char*)mymalloc(fixessize);
+ OId::OIdCounter* entryidsbuf = (OId::OIdCounter*)mymalloc(idssize);
+ char* entrytypesbuf = (char*)mymalloc(typessize);
+
+ // populate the buffers with data
+ myDomain.insertInDb(&(lowerboundsbuf[0]), &(upperboundsbuf[0]), &(lowerfixedbuf[0]), &(upperfixedbuf[0]));
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBHierIndex", "domain " << myDomain << " stored as " << InlineMinterval(dimension4, &(lowerboundsbuf[0]), &(upperboundsbuf[0]), &(lowerfixedbuf[0]), &(upperfixedbuf[0])));
+
+ KeyObjectVector::iterator it = myKeyObjects.begin();
+ InlineMinterval indom;
+ for (unsigned int i = 0; i < size4; i++, it++)
+ {
+ indom = (*it).getDomain();
+ indom.insertInDb(&(lowerboundsbuf[(i+1)*dimension4]), &(upperboundsbuf[(i+1)*dimension4]), &(lowerfixedbuf[(i+1)*dimension4]), &(upperfixedbuf[(i+1)*dimension4]));
+ entryidsbuf[i] = (*it).getObject().getOId().getCounter();
+ entrytypesbuf[i] = (char)(*it).getObject().getOId().getType();
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBHierIndex", "entry " << entryidsbuf[i] << " " << (OId::OIdType)entrytypesbuf[i] << " at " << InlineMinterval(dimension4, &(lowerboundsbuf[(i+1)*dimension4]), &(upperboundsbuf[(i+1)*dimension4]), &(lowerfixedbuf[(i+1)*dimension4]), &(upperfixedbuf[(i+1)*dimension4])));
+ }
+
+ RMDBGMIDDLE(8, RMDebug::module_indexif, "DBHierIndex", "complete=" << completesize << " bounds=" << boundssize << " fixes=" << fixessize << " ids=" << idssize << " types=" << typessize << ", size=" << size4 << " dimension=" << dimension4 );
+
+ // write the buffers in the complete buffer, plus starter byte
+ // this indirection is neccessary because of memory alignement of longs...
+ completebuffer[0] = 13; // write dummy starter byte
+ memcpy( &completebuffer[1], lowerboundsbuf, boundssize);
+ free(lowerboundsbuf);
+ memcpy( &completebuffer[boundssize + 1], upperboundsbuf, boundssize);
+ free(upperboundsbuf);
+ memcpy( &completebuffer[boundssize * 2 + 1], lowerfixedbuf, fixessize);
+ free(lowerfixedbuf);
+ memcpy( &completebuffer[boundssize * 2 + fixessize + 1], upperfixedbuf, fixessize);
+ free(upperfixedbuf);
+ memcpy( &completebuffer[boundssize * 2 + fixessize * 2 + 1], entryidsbuf, idssize);
+ free(entryidsbuf);
+ memcpy( &completebuffer[boundssize * 2 + fixessize * 2 + idssize + 1], entrytypesbuf, typessize);
+ free(entrytypesbuf);
+
+#ifdef RMANDEBUG // dump low-level blob byte string
+{
+ char printbuf[10000];
+ (void) sprintf( printbuf, "XXX DBHierIndex::updateInDb(): [%d]", completesize );
+ char bytebuf[3];
+ for (unsigned int i = 0; i < completesize; i++)
+ {
+ (void) sprintf( bytebuf, " %2X", (unsigned char) completebuffer[i] );
+ strcat( printbuf, bytebuf );
+ }
+ TALK( printbuf );
+}
+#endif // RMANDEBUG
+
+ // (2) --- write complete buffer to new database blob
+ // create, 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 << "DBHierIndex::updateInDb() cannot create blob, error: " << PQerrorMessage(pgConn) << endl;
+ LEAVE( "DBHierIndex::updateInDb(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 << " for " << completesize << " bytes" );
+ int loResult = lo_write( pgConn, fd, completebuffer, completesize );
+ if (loResult < 0)
+ {
+ RMInit::logOut << "DBHierIndex::updateInDb() cannot write blob, error: " << PQerrorMessage(pgConn) << endl;
+ LEAVE( "DBHierIndex::updateInDb() cannot write blob, error " << PQerrorMessage(pgConn) );
+ generateException();
+ }
+ else if (loResult != completesize) // did not get all
+ {
+ RMInit::dbgOut << "BLOB (" << myOId << ") update: wrote " << loResult << " instead of " << completesize << " bytes" << endl;
+ LEAVE( "DBHierIndex::updateInDb() wrote " << loResult << " instead of " << completesize << " 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 << "DBHierIndex::updateInDb() ignoring lo_close() error: " << PQerrorMessage(pgConn) << endl;
+ LEAVE( "DBHierIndex::updateInDb() cannot lo_close(): " << PQerrorMessage(pgConn) );
+ generateException();
+ }
+ free(completebuffer);
+ completebuffer = NULL;
+
+ // (3) -- update HierIx entry
+#ifdef NOTYET // should be in future
+/*
+ TALK( "EXEC SQL UPDATE RAS_HIERIX SET NumEntries = " << size4 << ", Dimension = " << dimension4 << ", ParentOId = " << parentid4 << ", IndexSubType = " << indexsubtype4 << ", DynData = " << blobOid );
+ EXEC SQL UPDATE RAS_HIERIX
+ SET NumEntries = :size4, Dimension = :dimension4, ParentOId = :parentid4, IndexSubType = :indexsubtype4, DynData = :blobOid
+ WHERE MDDObjIxOId = :id4;
+ if (SQLCODE != SQLOK)
+ {
+ check("DBHierIndex::updateInDb() update RAS_HIERIX");
+ LEAVE( "DBHierIndex::updateInDb(): db access error: " << SQLCODE );
+ generateException();
+ }
+*/
+#endif // NOTYET
+ // alternative solution for now:
+ (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "UPDATE RAS_HIERIX SET NumEntries = %d, Dimension = %d, ParentOId = %f, IndexSubType = %d, DynData = %d WHERE MDDObjIxOId = %f", size4, dimension4, parentid4, indexsubtype4, blobOid, id4 );
+ TALK( pgQuery );
+ pgResult = PQexec( pgConn, pgQuery );
+ if (PQresultStatus(pgResult) != PGRES_COMMAND_OK)
+ {
+ LEAVE( "DBHierIndex::updateInDb() libpq 'UPDATE HierIx' error: " << PQerrorMessage(pgConn) );
+ PQclear( pgResult );
+ generateException();
+ }
+ PQclear( pgResult );
+
+ // (4) --- dbobject update
+ DBObject::updateInDb();
+
+ RMDBGEXIT(5, RMDebug::module_indexif, "DBHierIndex", "updateInDb() " << myOId);
+ LEAVE( "DBHierIndex::updateInDb(), myOId=" << myOId );
+} // updateInDb()
+
+void
+DBHierIndex::deleteFromDb() throw (r_Error)
+{
+ RMDBGENTER(8, RMDebug::module_indexif, "DBHierIndex", "deleteFromDb() " << myOId);
+ ENTER( "DBHierIndex::deleteFromDb(), myOId=" << myOId );
+
+#ifdef NOTYET // should be in future
+/*
+ EXEC SQL BEGIN DECLARE SECTION;
+*/
+#endif // NOTYET
+ double id3;
+ Oid blobOid;
+ char pgQuery[SQL_QUERY_BUFFER_SIZE]; // prelim
+ PGresult *pgResult = NULL; // prelim
+#ifdef NOTYET // should be in future
+/*
+ EXEC SQL END DECLARE SECTION;
+*/
+#endif // NOTYET
+
+ OId oi;
+ DBObjectId dbo;
+ while (!myKeyObjects.empty())
+ {
+ oi = myKeyObjects.begin()->getObject().getOId();
+ DBObjectId dbo;
+ if ((oi.getType() == OId::BLOBOID) || (oi.getType() == OId::INLINETILEOID))
+ {
+ BLOBTile::kill(oi);
+ }
+ else
+ {
+ dbo = DBObjectId(oi);
+ if (!dbo.is_null())
+ {
+ dbo->setCached(false);
+ dbo->setPersistent(false);
+ dbo = (unsigned int)0;
+ }
+ }
+ myKeyObjects.erase(myKeyObjects.begin());
+ }
+
+ id3 = myOId;
+
+ // (1) --- get blob oid
+#ifdef NOTYET // should be in future
+/*
+ TALK( "EXEC SQL SELECT DynData INTO :blobOid FROM RAS_HIERIX WHERE MDDObjIxOId = " << id3 );
+ EXEC SQL SELECT DynData
+ INTO :blobOid
+ FROM RAS_HIERIX
+ WHERE MDDObjIxOId = :id3;
+ if (SQLCODE != SQLOK)
+ {
+ check("DBHierIndex::deleteFromDb() select from RAS_HIERIX");
+ LEAVE( "DBHierIndex::deleteFromDb() select from RAS_HIERIX: error: " << SQLCODE );
+ generateException();
+ }
+*/
+#endif // NOTYET
+ // alternative solution for now:
+ (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "SELECT DynData FROM RAS_HIERIX WHERE MDDObjIxOId = %f", id3 );
+ TALK( pgQuery );
+ pgResult = PQexec( pgConn, pgQuery );
+ if (PQresultStatus(pgResult) != PGRES_TUPLES_OK)
+ {
+ LEAVE( "DBHierIndex::deleteFromDb() libpq 'select RAS_HIERIX' error: " << PQerrorMessage(pgConn) );
+ PQclear( pgResult );
+ generateException();
+ }
+ blobOid = atoi( PQgetvalue( pgResult, 0, 0 ) ); // extract value from result
+ PQclear( pgResult );
+
+ // (2) --- delete blob
+ int loResult = lo_unlink( pgConn, blobOid );
+ if (loResult < 0) // no disaster if we can't so no exception
+ {
+ TALK( "DBHierIndex::deleteFromDb() warning: libpq 'unlink blob' error: " << PQerrorMessage(pgConn) );
+ }
+
+ // (3) --- delete tuple
+#ifdef NOTYET // should be in future
+/*
+ TALK( "EXEC SQL DELETE FROM RAS_HIERIX WHERE MDDObjIxOId = " << id3 );
+ EXEC SQL DELETE FROM RAS_HIERIX
+ WHERE MDDObjIxOId = :id3;
+ if (SQLCODE != SQLOK)
+ {
+ check("DBHierIndex::deleteFromDb() RAS_HIERIX");
+ LEAVE( "DBHierIndex::deleteFromDb(): db access error: " << SQLCODE );
+ generateException();
+ }
+*/
+#endif // NOTYET
+ // alternative solution for now:
+ (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "DELETE FROM RAS_HIERIX WHERE MDDObjIxOId = %f", id3 );
+ TALK( pgQuery );
+ pgResult = PQexec( pgConn, pgQuery );
+ if (PQresultStatus(pgResult) != PGRES_COMMAND_OK)
+ {
+ LEAVE( "DBHierIndex::updateInDb() libpq 'DELETE HierIx' error: " << PQerrorMessage(pgConn) );
+ PQclear( pgResult );
+ generateException();
+ }
+ PQclear( pgResult );
+
+ // (4) --- dbobject delete
+ DBObject::deleteFromDb();
+
+ RMDBGEXIT(8, RMDebug::module_indexif, "DBHierIndex", "deleteFromDb() " << myOId);
+ LEAVE( "DBHierIndex::deleteFromDb(), myOId=" << myOId );
+} // deleteFromDb()
+