summaryrefslogtreecommitdiffstats
path: root/relindexif
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 /relindexif
downloadrasdaman-upstream-8f27e65bddd7d4b8515ce620fb485fdd78fcdf89.tar.gz
rasdaman-upstream-8f27e65bddd7d4b8515ce620fb485fdd78fcdf89.tar.xz
rasdaman-upstream-8f27e65bddd7d4b8515ce620fb485fdd78fcdf89.zip
Initial commitv8.0
Diffstat (limited to 'relindexif')
-rw-r--r--relindexif/Makefile.am49
-rw-r--r--relindexif/dbrcindexds.hh210
-rw-r--r--relindexif/dbrcindexds.pgc495
-rw-r--r--relindexif/dbrcindexdscommon.cc286
-rw-r--r--relindexif/dbtcindex.hh192
-rw-r--r--relindexif/dbtcindex.pgc338
-rw-r--r--relindexif/dbtcindexcommon.cc357
-rw-r--r--relindexif/hierindex.hh219
-rw-r--r--relindexif/hierindex.pgc745
-rw-r--r--relindexif/hierindexcommon.cc1033
-rw-r--r--relindexif/indexid.hh37
-rw-r--r--relindexif/test/Makefile97
-rw-r--r--relindexif/test/computedindex.cc109
-rw-r--r--relindexif/test/exportindex.cc234
-rw-r--r--relindexif/test/miteratest.cc53
-rw-r--r--relindexif/test/testindex.pc262
16 files changed, 4716 insertions, 0 deletions
diff --git a/relindexif/Makefile.am b/relindexif/Makefile.am
new file mode 100644
index 0000000..d7ab48d
--- /dev/null
+++ b/relindexif/Makefile.am
@@ -0,0 +1,49 @@
+# -*-Makefile-*- (for Emacs)
+#
+# 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>.
+#
+# MAKEFILE FOR:
+# indexif
+#
+##################################################################
+
+AM_CXXFLAGS=@BASEDBCXXFLAGS@
+AM_LDFLAGS=@BASEDBLDFLAGS@
+
+.SUFFIXES= .@EMBEDDEDSQLEXT@ .@EMBEDDEDSQLOUT@
+.@EMBEDDEDSQLEXT@.@EMBEDDEDSQLOUT@:
+ $(EMBEDDEDSQLPRECOMPILER) $@ $<
+
+noinst_LIBRARIES=librelindexif.a
+librelindexif_a_SOURCES=dbrcindexdscommon.cc dbrcindexds.hh \
+ dbtcindexcommon.cc dbtcindex.hh \
+ hierindexcommon.cc hierindex.hh \
+ indexid.hh
+EXTRA_librelindexif_a_SOURCES=dbrcindexds.pgc dbtcindex.pgc hierindex.pgc
+
+librelindexif_a_LIBADD=dbrcindexds.$(OBJEXT) dbtcindex.$(OBJEXT) hierindex.$(OBJEXT)
+librelindexif_a_DEPENDENCIES=dbrcindexds.$(OBJEXT) dbtcindex.$(OBJEXT) hierindex.$(OBJEXT)
+
+BUILT_SOURCES=dbrcindexds.@EMBEDDEDSQLOUT@ dbtcindex.@EMBEDDEDSQLOUT@ hierindex.@EMBEDDEDSQLOUT@
+
+CLEANFILES=dbrcindexds.@EMBEDDEDSQLOUT@ dbtcindex.@EMBEDDEDSQLOUT@ hierindex.@EMBEDDEDSQLOUT@
+
diff --git a/relindexif/dbrcindexds.hh b/relindexif/dbrcindexds.hh
new file mode 100644
index 0000000..ee74061
--- /dev/null
+++ b/relindexif/dbrcindexds.hh
@@ -0,0 +1,210 @@
+/*
+* 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:
+ * RC index RDBMS adaptor include file.
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#ifndef _DBRCINDEXDS_HH_
+#define _DBRCINDEXDS_HH_
+
+#include "reladminif/dbobject.hh"
+#include "indexmgr/indexds.hh"
+#include "relcatalogif/inlineminterval.hh"
+
+//@ManMemo: Module: {\bf relindexif}
+/*@Doc:
+Can't have DBRCIndex and DBHierIndex under a common father class because the compiler has problems resolving the DBRef<> functions correctly.
+
+Persistent class for storing data on regular computed indexes.
+
+Beware of the cache when droping the IndexDS classes!
+
+See indexmgr/indexds.hh for documentation.
+
+Data to store:
+RAS_RCINDEXDYN
+ OId NUMBER(15,0),
+ Count NUMBER(3,0),
+ DynData VARCHAR(3990)
+NB: under Oracle 9i, Dyndata is defined as:
+ DynData BLOB NOT NULL
+This should be done for the other systems too,
+as VARCHAR usually is subject to charset translation
+which we don't want on our binary data.
+
+DynData holds: r_Dimension, OId::OIdType, OId::OIdCounter, InlineMinterval, InlineMinterval
+As:
+ r_Dimension dimension 4
+ OId::OIdType myBaseOIdType 2
+ OId::OIdCounter myBaseCounter 4
+ unsigned int mySize 4
+ InlineMinterval myDomain 10 * dim
+
+*/
+class DBRCIndexDS : public IndexDS
+ {
+ public:
+ DBRCIndexDS(const r_Minterval& definedDomain, unsigned int numberTiles, OId::OIdType theEntryType = OId::BLOBOID);
+ /*@Doc:
+ Create a new index which handles the domain definedDomain, with tiles of domain
+ tileConfig. As soon as you create this index it will check if the tileConfig fits
+ the definedDomain (the tileConfig must completely cover the definedDomain) and then
+ allocate as many oids as are neccessary to fill the definedDomain.
+ */
+
+ virtual r_Minterval getCoveredDomain() const;
+ /// return defined domain
+
+ virtual r_Minterval getAssignedDomain() const;
+ /// return defined domain
+
+ virtual r_Minterval getObjectDomain(unsigned int pos) const;
+ /// throw r_Error_FeatureNotSupported
+
+ virtual r_Dimension getDimension() const;
+
+ virtual void setAssignedDomain(const r_Minterval& domain);
+ /// throw r_Error_FeatureNotSupported
+
+ virtual unsigned int getSize() const;
+ /// this will return the maximum number of tiles that can be stored in the definedDomain.
+
+ virtual r_Bytes getTotalStorageSize() const;
+
+ virtual bool isValid() const;
+ /// returns true
+
+ virtual bool isUnderFull() const;
+ /// returns false
+
+ virtual bool isOverFull() const;
+ /// returns false
+
+ virtual bool isSameAs(const IndexDS* pix) const;
+
+ virtual bool removeObject(unsigned int pos);
+ /// throw r_Error_FeatureNotSupported
+
+ virtual bool removeObject(const KeyObject& theKey);
+ /// throw r_Error_FeatureNotSupported
+
+ virtual void insertObject(const KeyObject& theKey, unsigned int pos);
+ /// throw r_Error_FeatureNotSupported
+
+ virtual void setObject(const KeyObject& theKey, unsigned int pos);
+ /// throw r_Error_FeatureNotSupported
+
+ virtual void setObjectDomain(const r_Minterval& dom, unsigned int pos);
+ /// throw r_Error_FeatureNotSupported
+
+ virtual const KeyObject& getObject(unsigned int pos) const;
+ /// throw r_Error_FeatureNotSupported
+
+ virtual void getObjects(KeyObjectVector& objs) const;
+ /// throw r_Error_FeatureNotSupported
+
+ virtual unsigned int getOptimalSize() const;
+ /// returns the maximum number of entries that can be stored in this index
+
+ virtual void freeDS();
+
+ virtual OId::OIdPrimitive getIdentifier() const;
+
+ static r_Bytes BytesPerTupel;
+ /*@Doc:
+ tuning parameter. used to calculate the optimal size of
+ an index. this is also the number of bytes written to the
+ database.
+ */
+
+ virtual void printStatus(unsigned int level = 0, std::ostream& stream = std::cout) const;
+
+ virtual ~DBRCIndexDS();
+
+ virtual void destroy();
+
+ virtual IndexDS* getNewInstance() const;
+ /// throw r_Error_FeatureNotSupported
+
+ virtual OId::OIdType getBaseOIdType() const;
+
+ virtual OId::OIdCounter getBaseCounter() const;
+
+ protected:
+ friend class ObjectBroker;
+ /*@Doc:
+ ObjectBroker needs to access OId constructor
+ */
+
+ DBRCIndexDS(const OId& id);
+ /*@Doc:
+ */
+
+ virtual void readFromDb() throw (r_Error);
+ /*@Doc:
+ */
+
+ virtual void updateInDb() throw (r_Error);
+ /*@Doc:
+ */
+
+ virtual void deleteFromDb() throw (r_Error);
+ /*@Doc:
+ */
+
+ virtual void insertInDb() throw (r_Error);
+ /*@Doc:
+ */
+
+ OId::OIdCounter myBaseCounter;
+ /*@Doc:
+ The first oid that will be used to store entries.
+ */
+
+ OId::OIdType myBaseOIdType;
+ /*@Doc:
+ The type of objects to store in this index (most of the time this will be OId::BLOBOID).
+ */
+
+ OId::OIdCounter mySize;
+
+ InlineMinterval myDomain;
+ /*@Doc:
+ Defined domain of this index.
+ */
+
+ short currentDbRows;
+ /*@Doc:
+ is needed to support update of index in database
+ keeps the number of rows currently taken up in the db by
+ this instance
+ */
+ };
+#endif
diff --git a/relindexif/dbrcindexds.pgc b/relindexif/dbrcindexds.pgc
new file mode 100644
index 0000000..a476920
--- /dev/null
+++ b/relindexif/dbrcindexds.pgc
@@ -0,0 +1,495 @@
+#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:
+ * - attribute name 'OId' -> 'UOId' (for UDFs), 'OId' -> 'Id' (for IXs)
+ * to avoid PG name clash with attr type
+ *
+ ************************************************************/
+
+// PG stuff:
+#include "libpq-fe.h" /* C interface to PgSQL */
+#include "libpq/libpq-fs.h" /* large object (lo) api */
+
+#include "debug-srv.hh"
+
+#include "dbrcindexds.hh"
+#include "reladminif/sqlerror.hh"
+#include "raslib/rmdebug.hh"
+
+// general embedded SQL related definitions
+EXEC SQL include "../reladminif/sqlglobals.h";
+
+// container size for index node
+// BEWARE: keep these parameters always consistent!
+#define BYTES_PER_TUPLE 3990
+EXEC SQL define SQL_BYTES_PER_TUPLE 3991;
+
+// libpg connection maintenance
+extern PGconn *pgConn;
+
+r_Bytes
+DBRCIndexDS::BytesPerTupel = BYTES_PER_TUPLE;
+
+void
+DBRCIndexDS::insertInDb() throw (r_Error)
+{
+ RMDBGENTER(5, RMDebug::module_indexif, "DBRCIndexDS", "insertInDb() " << myOId);
+ ENTER( "DBRCIndexDS::insertInDb" );
+
+#ifdef NOTYET // should be in future
+/*
+ EXEC SQL BEGIN DECLARE SECTION;
+*/
+#endif //NOTYET
+ double id2;
+ short count2;
+ 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
+
+ // alternative solution for now:
+
+ // (1) --- prepare buffer
+ id2 = myOId;
+ r_Dimension dimension = myDomain.dimension();
+
+ //number of bytes for bounds in 1 minterval
+ r_Bytes boundssize = sizeof(r_Range) * dimension;
+ //number of bytes for fixes in 1 minterval
+ r_Bytes fixessize = sizeof(char) * dimension;
+ //number of bytes for the dynamic data
+ r_Bytes completesize = sizeof(r_Dimension) + sizeof(short) + sizeof(OId::OIdCounter) + sizeof(unsigned int) + boundssize * 2 + fixessize * 2;
+
+ 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);
+
+ RMDBGMIDDLE(8, RMDebug::module_indexif, "DBRCIndexDS", "complete " << completesize << " bounds " << boundssize << " fixes " << fixessize);
+ TALK( "DBRCIndexDS: complete " << completesize << " bounds " << boundssize << " fixes " << fixessize);
+
+ // insert myDomain in buffers
+ myDomain.insertInDb(&(lowerboundsbuf[0]), &(upperboundsbuf[0]), &(lowerfixedbuf[0]), &(upperfixedbuf[0]));
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBRCIndexDS", "domain " << myDomain << " stored as " << InlineMinterval(dimension, &(lowerboundsbuf[0]), &(upperboundsbuf[0]), &(lowerfixedbuf[0]), &(upperfixedbuf[0])));
+ TALK( "DBRCIndexDS: domain " << myDomain << " stored as " << InlineMinterval(dimension, &(lowerboundsbuf[0]), &(upperboundsbuf[0]), &(lowerfixedbuf[0]), &(upperfixedbuf[0])) );
+
+ char* insertionpointer = completebuffer;
+ // write the buffers in the complete buffer
+ // this indirection is neccessary because of memory alignment of longs...
+ // insert dimension
+ memcpy(insertionpointer, &dimension, sizeof(r_Dimension));
+ insertionpointer = insertionpointer + sizeof(r_Dimension);
+
+ // insert oid type
+ memcpy(insertionpointer, &myBaseOIdType, sizeof(short));
+ insertionpointer = insertionpointer + sizeof(short);
+
+ // insert oid counter
+ memcpy(insertionpointer, &myBaseCounter, sizeof(OId::OIdCounter));
+ insertionpointer = insertionpointer + sizeof(OId::OIdCounter);
+
+ // insert oid counter
+ memcpy(insertionpointer, &mySize, sizeof(unsigned int));
+ insertionpointer = insertionpointer + sizeof(unsigned int);
+
+ // insert domains
+ memcpy(insertionpointer, lowerboundsbuf, boundssize);
+ insertionpointer = insertionpointer + boundssize;
+ free(lowerboundsbuf);
+
+ memcpy(insertionpointer, upperboundsbuf, boundssize);
+ insertionpointer = insertionpointer + boundssize;
+ free(upperboundsbuf);
+
+ memcpy(insertionpointer, lowerfixedbuf, fixessize);
+ insertionpointer = insertionpointer + fixessize;
+ free(lowerfixedbuf);
+
+ memcpy(insertionpointer, upperfixedbuf, fixessize);
+ free(upperfixedbuf);
+
+#ifdef RMANDEBUG // dump low-level blob byte string
+{
+ char printbuf[10000];
+ (void) sprintf( printbuf, "DBRCIndexDS::insertInDb(): [%d]", completesize );
+#if 0 // extra verbose output: dump buffer
+ char bytebuf[3];
+ for (unsigned int i = 0; i < completesize; i++)
+ {
+ (void) sprintf( bytebuf, " %2X", (unsigned char) completebuffer[i] );
+ strcat( printbuf, bytebuf );
+ }
+#endif // 0
+ 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)
+ {
+ free(completebuffer);
+ completebuffer = NULL;
+ RMInit::logOut << "DBRCIndexDS::insertInDb() cannot create blob, error: " << PQerrorMessage(pgConn) << endl;
+ LEAVE( "DBRCIndexDS::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)
+ {
+ free(completebuffer);
+ completebuffer = NULL;
+ RMInit::logOut << "DBRCIndexDS::insertInDb() cannot write blob, error: " << PQerrorMessage(pgConn) << endl;
+ LEAVE( "DBRCIndexDS::insertInDb() cannot write blob, error " << PQerrorMessage(pgConn) );
+ generateException();
+ }
+ else if (loResult != completesize) // did not get all
+ {
+ free(completebuffer);
+ completebuffer = NULL;
+ RMInit::dbgOut << "BLOB (" << myOId << ") insert: wrote " << loResult << " instead of " << completesize << " bytes" << endl;
+ LEAVE( "DBRCIndexDS::insertInDb() wrote " << loResult << " instead of " << completesize << " bytes" );
+ generateException();
+ }
+ TALK( "lo_close(), " << completesize << " bytes written" );
+ loResult = lo_close( pgConn, fd );
+ if (loResult < 0) // can't close, don't know if data are written
+ {
+ free(completebuffer);
+ completebuffer = NULL;
+ RMInit::logOut << "DBRCIndexDS::insertInDb() ignoring lo_close() error: " << PQerrorMessage(pgConn) << endl;
+ LEAVE( "DBRCIndexDS::insertInDb() cannot lo_close(): " << PQerrorMessage(pgConn) );
+ generateException();
+ }
+ free(completebuffer);
+
+ // (3) --- insert HIERIX tuple into db
+ count2 = 0; // we only have one entry
+#ifdef NOTYET // should be in future
+/*
+ TALK( "EXEC SQL INSERT INTO RAS_RCINDEXDYN ( Id, Count, DynData ) VALUES ( " << id2 << "," << count2 << "," << blobOid << " )" );
+ EXEC SQL INSERT INTO RAS_RCINDEXDYN ( Id, Count, DynData )
+ VALUES ( :id2, :count2, :blobOid );
+ if (SQLCODE != SQLOK)
+ {
+ check("DBRCIndexDS::insertInDb() insert into RAS_HIERIXDYN\0");
+ LEAVE( "DBRCIndexDS::insertInDb(): db access error: " << SQLCODE );
+ generateException();
+ }
+*/
+#endif // NOTYET
+ // alternative solution for now:
+ (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "INSERT INTO RAS_RCINDEXDYN ( Id, Count, DynData ) VALUES ( %f, %d, %d )", id2, count2, blobOid );
+ TALK( pgQuery );
+ pgResult = PQexec( pgConn, pgQuery );
+ if (PQresultStatus(pgResult) != PGRES_COMMAND_OK)
+ {
+ LEAVE( "DBRCIndexDS::insertInDb() libpq 'insert RAS_HIERIX' error: " << PQerrorMessage(pgConn) );
+ PQclear( pgResult );
+ generateException();
+ }
+ PQclear( pgResult );
+
+ // (4) --- dbobject insert
+ DBObject::insertInDb();
+
+ LEAVE( "DBRCIndexDS::insertInDb" );
+ RMDBGEXIT(5, RMDebug::module_indexif, "DBRCIndexDS", "insertInDb() " << myOId);
+}
+
+void
+DBRCIndexDS::readFromDb() throw (r_Error)
+{
+ RMDBGENTER(5, RMDebug::module_indexif, "DBRCIndexDS", "readFromDb() " << myOId);
+ ENTER( "DBRCIndexDS::readFromDb" );
+
+#ifdef RMANBENCHMARK
+ DBObject::readTimer.resume();
+#endif
+
+#ifdef NOTYET // should be in future
+/*
+ EXEC SQL BEGIN DECLARE SECTION;
+*/
+#endif //NOTYET
+ double id1;
+ 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
+
+ // (1) --- prepare variables
+ id1 = myOId;
+
+ // (2) --- get tuple
+#ifdef NOTYET // should be in future
+/*
+ TALK( "EXEC SQL SELECT DynData FROM RAS_RCINDEXDYN WHERE Id = " << id1 );
+ EXEC SQL SELECT DynData FROM RAS_RCINDEXDYN WHERE Id = :id1;
+ if (SQLCODE != SQLOK)
+ {
+ check("DBRCIndexDS::readFromDb() select from RAS_RCINDEXDYN");
+ LEAVE("DBRCIndexDS::readFromDb() 'select from RAS_RCINDEXDYN' error: " << SQLCODE );
+ generateException();
+ }
+*/
+#endif // NOTYET
+ // alternative solution for now:
+ (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "SELECT DynData FROM RAS_RCINDEXDYN WHERE Id = %f", id1 );
+ TALK( pgQuery );
+ pgResult = PQexec( pgConn, pgQuery );
+ if (PQresultStatus(pgResult) != PGRES_TUPLES_OK)
+ {
+ LEAVE( "DBRCIndexDS::readFromDb() libpq 'insert RAS_HIERIX' error: " << PQerrorMessage(pgConn) );
+ PQclear( pgResult );
+ generateException();
+ }
+ blobOid = atoi( PQgetvalue( pgResult, 0, 0 ) ); // extract value from result
+ PQclear( pgResult );
+
+ // (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 blobSize = 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
+ char* completebuffer = (char*)mymalloc(blobSize); // receives blob contents
+ if (completebuffer == NULL)
+ {
+ RMInit::logOut << "DBRCIndexDS::readFromDb() cannot allocate blob buffer" << endl;
+ LEAVE( "DBRCIndexDS::readFromDb: cannot allocate blob buffer" );
+ throw r_Error( r_Error::r_Error_MemoryAllocation );
+ }
+ TALK( "lo_read() for " << blobSize << " bytes" ); // read blob
+ int loResult = lo_read( pgConn, fd, completebuffer, blobSize );
+ if (loResult < 0)
+ {
+ RMInit::logOut << "DBRCIndexDS::readFromDb() cannot read blob, error: " << loResult << endl;
+ LEAVE( "DBRCIndexDS::readFromDb: cannot read blob, error " << loResult );
+ throw r_Error( r_Error::r_Error_BaseDBMSFailed );
+ }
+ else if (loResult != blobSize) // did not get all
+ {
+ RMInit::dbgOut << "BLOB (" << myOId << ") read: want to read (" << blobSize << " bytes, but got " << loResult << " bytes" << endl;
+ LEAVE( "DBRCIndexDS::readFromDb: want to read " << blobSize << " bytes, but got " << loResult << " bytes" );
+ 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 << "DBRCIndexDS::readFromDb() ignoring lo_close() error: " << ignoredPgResult << endl;
+ TALK( "DBRCIndexDS::readFromDb: ignoring lo_close() error: " << ignoredPgResult );
+ }
+
+#ifdef RMANDEBUG // dump low-level blob byte string
+{
+ char printbuf[10000];
+ (void) sprintf( printbuf, "XXX DBRCIndexDS::readFromDb(): [%d]", blobSize );
+ char bytebuf[3];
+ for (unsigned int i = 0; i < blobSize; i++)
+ {
+ (void) sprintf( bytebuf, " %2X", (unsigned char) completebuffer[i] );
+ strcat( printbuf, bytebuf );
+ }
+ TALK( printbuf );
+}
+#endif // RMANDEBUG
+
+ // (4) --- fill variables and buffers
+ r_Dimension dimension = 0;
+ (void) memcpy(&dimension, completebuffer, sizeof(r_Dimension));
+ unsigned int bytesdone = sizeof(r_Dimension);
+
+ (void) memcpy(&myBaseOIdType, &(completebuffer[bytesdone]), sizeof(short));
+ bytesdone += sizeof(short);
+ (void) memcpy(&myBaseCounter, &(completebuffer[bytesdone]), sizeof(OId::OIdCounter));
+ bytesdone += sizeof(OId::OIdCounter);
+ (void) memcpy(&mySize, &(completebuffer[bytesdone]), sizeof(unsigned int));
+ bytesdone += sizeof(unsigned int);
+
+ r_Bytes boundssize = sizeof(r_Range) * dimension; //number of bytes for bounds in 2 domains
+ r_Bytes fixessize = sizeof(char) * dimension; //number of bytes for fixes in 2 domains
+ r_Bytes completesize = boundssize * 2 + fixessize * 2; //number of bytes for the dynamic data
+ char *dynamicBuffer = &completebuffer[bytesdone]; // ptr to start of dynamic part of buffer
+
+ // additional plausi check
+ if (blobSize != bytesdone + completesize)
+ {
+ RMInit::logOut << "DBRCIndexDS::readFromDb() blob size inconsistency: blobSize (" << blobSize << " != bytesdone (" << bytesdone << ") + completesize (" << completesize << ")";
+ TALK( "DBRCIndexDS::readFromDb() blob size inconsistency: blobSize (" << blobSize << " != bytesdone (" << bytesdone << ") + completesize (" << completesize << ")" );
+ throw r_Error( r_Error::r_Error_LimitsMismatch );
+ }
+
+ RMDBGMIDDLE(7, RMDebug::module_indexif, "DBRCIndexDS", "dimension " << dimension << ", base oid type " << myBaseOIdType << ", base counter " << myBaseCounter << ", size " << mySize << ", complete data size " << 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);
+
+ // all dynamic data is in dynamicBuffer
+ // put that stuff in the correct buffers
+ memcpy(lowerboundsbuf, dynamicBuffer, boundssize);
+ memcpy(upperboundsbuf, &dynamicBuffer[boundssize], boundssize);
+ memcpy(lowerfixedbuf, &dynamicBuffer[boundssize * 2], fixessize);
+ memcpy(upperfixedbuf, &dynamicBuffer[boundssize * 2 + fixessize], fixessize);
+
+ // all dynamic data is in its buffer
+ free (completebuffer);
+ dynamicBuffer = completebuffer = NULL;
+
+ // rebuild attributes from buffers
+ myDomain = InlineMinterval(dimension, &(lowerboundsbuf[0]), &(upperboundsbuf[0]), &(lowerfixedbuf[0]), &(upperfixedbuf[0]));
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBRCIndexDS", "domain " << myDomain << " constructed from " << InlineMinterval(dimension, &(lowerboundsbuf[0]), &(upperboundsbuf[0]), &(lowerfixedbuf[0]), &(upperfixedbuf[0])));
+
+ free(upperboundsbuf);
+ upperboundsbuf = NULL;
+ free(lowerboundsbuf);
+ lowerboundsbuf = NULL;
+ free(upperfixedbuf);
+ upperfixedbuf = NULL;
+ free(lowerfixedbuf);
+ lowerfixedbuf = NULL;
+
+#ifdef RMANBENCHMARK
+ DBObject::readTimer.pause();
+#endif
+
+ // (5) --- dbobject read
+ DBObject::readFromDb();
+
+ LEAVE( "DBRCIndexDS::readFromDb, myOId=" << myOId );
+ RMDBGEXIT(5, RMDebug::module_indexif, "DBRCIndexDS", "readFromDb() " << myOId);
+}
+
+void
+DBRCIndexDS::deleteFromDb() throw (r_Error)
+{
+ RMDBGENTER(8, RMDebug::module_indexif, "DBRCIndexDS", "deleteFromDb() " << myOId);
+ ENTER( "DBRCIndexDS::deleteFromDb" );
+
+#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
+
+ // (1) --- set variables
+ id3 = myOId;
+
+ // (2) --- fetch blob oid
+#ifdef NOTYET // should be in future
+/*
+ TALK( "EXEC SQL SELECT DynData FROM RAS_RCINDEXDYN WHERE Id = " << id3 );
+ EXEC SQL SELECT DynData FROM RAS_RCINDEXDYN
+ WHERE Id = :id3;
+ if (check("DBRCIndexDS::deleteFromDb() RAS_RCINDEX") != 0)
+ generateException();
+*/
+#endif // NOTYET
+ // alternative solution for now:
+ (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "SELECT DynData FROM RAS_RCINDEXDYN WHERE Id = %f", id3 );
+ TALK( pgQuery );
+ pgResult = PQexec( pgConn, pgQuery );
+ if (PQresultStatus(pgResult) != PGRES_TUPLES_OK)
+ {
+ LEAVE( "DBRCIndexDS::deleteFromDb() libpq 'select RAS_RCINDEXDYN' error: " << PQerrorMessage(pgConn) );
+ PQclear( pgResult );
+ generateException();
+ }
+ blobOid = atoi( PQgetvalue( pgResult, 0, 0 ) ); // extract value from result
+ PQclear( pgResult );
+
+ // (3) --- delete blob
+ int loResult = lo_unlink( pgConn, blobOid );
+ if (loResult < 0) // no disaster if we can't so no exception
+ {
+ TALK( "DBRCIndexDS::deleteFromDb() warning: libpq 'unlink blob' error: " << PQerrorMessage(pgConn) );
+ }
+
+ // (3) --- delete tuple
+#ifdef NOTYET // should be in future
+/*
+ TALK( "EXEC SQL DELETE FROM RAS_RCINDEXDYN WHERE Id = " << id3 );
+ EXEC SQL DELETE FROM RAS_RCINDEXDYN
+ WHERE Id = :id3;
+ if (SQLCODE != SQLOK)
+ {
+ check("DBRCIndexDS::deleteFromDb() delete from RAS_RCINDEX");
+ LEAVE("DBRCIndexDS::deleteFromDb() 'delete from RAS_RCINDEX' error: " << SQLCODE );
+ generateException();
+ }
+*/
+#endif // NOTYET
+ // alternative solution for now:
+ (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "DELETE FROM RAS_RCINDEXDYN WHERE Id = %f", id3 );
+ TALK( pgQuery );
+ pgResult = PQexec( pgConn, pgQuery );
+ if (PQresultStatus(pgResult) != PGRES_COMMAND_OK)
+ {
+ LEAVE( "DBRCIndexDS::deleteFromDb() libpq 'select RAS_RCINDEXDYN' error: " << PQerrorMessage(pgConn) );
+ PQclear( pgResult );
+ generateException();
+ }
+
+ // (4) --- dbobject delete
+ DBObject::deleteFromDb();
+
+ LEAVE( "DBRCIndexDS::deleteFromDb" );
+ RMDBGEXIT(8, RMDebug::module_indexif, "DBRCIndexDS", "deleteFromDb() " << myOId);
+}
+
diff --git a/relindexif/dbrcindexdscommon.cc b/relindexif/dbrcindexdscommon.cc
new file mode 100644
index 0000000..e8ede17
--- /dev/null
+++ b/relindexif/dbrcindexdscommon.cc
@@ -0,0 +1,286 @@
+/*
+* 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:
+ * C++ part (i.e., RDBMS independent) of the RC index adaptor.
+ *
+ *
+ * COMMENTS:
+ * uses embedded SQL
+ *
+ ************************************************************/
+
+#include "mymalloc/mymalloc.h"
+#include "dbrcindexds.hh"
+#include "reladminif/objectbroker.hh"
+#include "reladminif/dbref.hh"
+#include "raslib/rmdebug.hh"
+#include "reladminif/lists.h"
+#include "reladminif/sqlerror.hh"
+#include "reladminif/externs.h"
+#include "relblobif/blobtile.hh"
+#include "indexmgr/keyobject.hh"
+#include "storagemgr/sstoragelayout.hh"
+
+DBRCIndexDS::DBRCIndexDS(const OId& id)
+ : IndexDS(id),
+ currentDbRows(0),
+ myDomain(0),
+ myBaseCounter(0),
+ myBaseOIdType(OId::INVALID),
+ mySize(0)
+{
+ RMDBGENTER(7, RMDebug::module_indexif, "DBRCIndexDS", "DBRCIndexDS(" << myOId << ")");
+ objecttype = OId::MDDRCIXOID;
+ readFromDb();
+ RMDBGEXIT(7, RMDebug::module_indexif, "DBRCIndexDS", "DBRCIndexDS(" << myOId << ")");
+}
+
+DBRCIndexDS::DBRCIndexDS(const r_Minterval& definedDomain, unsigned int size, OId::OIdType theEntryType)
+ : IndexDS(),
+ myDomain(definedDomain),
+ currentDbRows(-1),
+ myBaseCounter(0),
+ myBaseOIdType(theEntryType),
+ mySize(size)
+{
+ RMDBGENTER(7, RMDebug::module_indexif, "DBRCIndexDS", "DBRCIndexDS(" << definedDomain << ", " << size << ", " << theEntryType << ") " << myOId);
+ objecttype = OId::MDDRCIXOID;
+ OId t;
+ OId::allocateOId(t, myBaseOIdType, mySize);
+ myBaseCounter = t.getCounter();
+ RMDBGMIDDLE(7, RMDebug::module_indexif, "DBRCIndexDS", "base counter " << myBaseCounter);
+ setPersistent(true);
+ setCached(true);
+ RMDBGEXIT(7, RMDebug::module_indexif, "DBRCIndexDS", "DBRCIndexDS(" << definedDomain << ", " << size << ", " << theEntryType << ") " << myOId);
+}
+
+IndexDS*
+DBRCIndexDS::getNewInstance() const
+{
+ RMInit::logOut << "DBRCIndexDS::getNewInstance() not suported" << std::endl;
+ throw r_Error(r_Error::r_Error_FeatureNotSupported);
+}
+
+OId::OIdPrimitive
+DBRCIndexDS::getIdentifier() const
+{
+ return myOId;
+}
+
+bool
+DBRCIndexDS::removeObject(const KeyObject& entry)
+{
+ RMInit::logOut << "DBRCIndexDS::removeObject(" << entry << ") not suported" << std::endl;
+ throw r_Error(r_Error::r_Error_FeatureNotSupported);
+}
+
+bool
+DBRCIndexDS::removeObject(unsigned int pos)
+{
+ RMInit::logOut << "DBRCIndexDS::removeObject(" << pos << ") not suported" << std::endl;
+ throw r_Error(r_Error::r_Error_FeatureNotSupported);
+}
+
+
+void
+DBRCIndexDS::insertObject(const KeyObject& theKey, unsigned int pos)
+{
+ RMInit::logOut << "DBRCIndexDS::insertObject(" << theKey << ", " << pos << ") not suported" << std::endl;
+ throw r_Error(r_Error::r_Error_FeatureNotSupported);
+}
+
+void
+DBRCIndexDS::setObjectDomain(const r_Minterval& dom, unsigned int pos)
+{
+ RMInit::logOut << "DBRCIndexDS::setObjectDomain(" << dom << ", " << pos << ") not suported" << std::endl;
+ throw r_Error(r_Error::r_Error_FeatureNotSupported);
+}
+
+void
+DBRCIndexDS::setObject(const KeyObject& theKey, unsigned int pos)
+{
+ RMInit::logOut << "DBRCIndexDS::setObject(" << theKey << ", " << pos << ") not suported" << std::endl;
+ throw r_Error(r_Error::r_Error_FeatureNotSupported);
+}
+
+r_Minterval
+DBRCIndexDS::getCoveredDomain() const
+{
+ RMDBGONCE(7, RMDebug::module_indexif, "DBRCIndexDS", "getCoveredDomain() const " << myOId << " " << myDomain);
+ return myDomain;
+}
+
+r_Dimension
+DBRCIndexDS::getDimension() const
+{
+ RMDBGONCE(7, RMDebug::module_indexif, "DBDDObjIx", "getDimension() const " << myOId << " " << myDomain.dimension());
+ return myDomain.dimension();
+}
+
+r_Bytes
+DBRCIndexDS::getTotalStorageSize() const
+{
+ RMDBGENTER(4, RMDebug::module_indexif, "DBRCIndexDS", "getTotalStorageSize() " << myOId);
+ r_Bytes sz = 0;
+
+ RMDBGEXIT(4, RMDebug::module_indexif, "DBRCIndexDS", "getTotalStorageSize() " << myOId << " " << sz);
+ return sz;
+}
+
+bool
+DBRCIndexDS::isValid() const
+{
+ return true;
+}
+
+void
+DBRCIndexDS::printStatus(unsigned int level, std::ostream& stream) const
+{
+ char* indent = new char[level*2 +1];
+ for (unsigned int j = 0; j < level*2 ; j++)
+ indent[j] = ' ';
+ indent[level*2] = '\0';
+
+ stream << indent << "DBRCIndexDS" << std::endl;
+ stream << indent << " current db rows " << currentDbRows << std::endl;
+ stream << indent << " domain " << myDomain << std::endl;
+ stream << indent << " base oid counter " << myBaseCounter << std::endl;
+ stream << indent << " base oid type " << myBaseOIdType << std::endl;
+ stream << indent << " size " << mySize << std::endl;
+ DBObject::printStatus(level, stream);
+ delete[] indent;
+}
+
+OId::OIdCounter
+DBRCIndexDS::getBaseCounter() const
+{
+ return myBaseCounter;
+}
+
+OId::OIdType
+DBRCIndexDS::getBaseOIdType() const
+{
+ return myBaseOIdType;
+}
+
+unsigned int
+DBRCIndexDS::getSize() const
+{
+ return mySize;
+}
+
+bool
+DBRCIndexDS::isUnderFull() const
+{
+ //redistribute in srptindexlogic has to be checked first before any other return value may be assigned
+ return false;
+}
+
+bool
+DBRCIndexDS::isOverFull() const
+{
+ return false;
+}
+
+unsigned int
+DBRCIndexDS::getOptimalSize() const
+{
+ return getSize();
+}
+
+r_Minterval
+DBRCIndexDS::getAssignedDomain() const
+{
+ return myDomain;
+}
+
+void
+DBRCIndexDS::setAssignedDomain(const r_Minterval& newDomain)
+{
+ RMInit::logOut << "DBRCIndexDS::setAssignedDomain(" << newDomain << ") not suported" << std::endl;
+ throw r_Error(r_Error::r_Error_FeatureNotSupported);
+}
+
+void
+DBRCIndexDS::freeDS()
+{
+ setPersistent(false);
+}
+
+bool
+DBRCIndexDS::isSameAs(const IndexDS* other) const
+{
+ if (other->isPersistent())
+ if (myOId == other->getIdentifier())
+ return true;
+ return false;
+}
+
+const KeyObject&
+DBRCIndexDS::getObject(unsigned int pos) const
+{
+ RMInit::logOut << "DBRCIndexDS::getObject(" << pos << ") not suported" << std::endl;
+ throw r_Error(r_Error::r_Error_FeatureNotSupported);
+}
+
+void
+DBRCIndexDS::getObjects(KeyObjectVector& objs) const
+{
+ RMInit::logOut << "DBRCIndexDS::getObjects(vec) not suported" << std::endl;
+ throw r_Error(r_Error::r_Error_FeatureNotSupported);
+}
+
+r_Minterval
+DBRCIndexDS::getObjectDomain(unsigned int pos) const
+{
+ RMInit::logOut << "DBRCIndexDS::getObjectDomain(" << pos << ") not suported" << std::endl;
+ throw r_Error(r_Error::r_Error_FeatureNotSupported);
+}
+
+void
+DBRCIndexDS::destroy()
+{
+ DBObject::destroy();
+}
+
+DBRCIndexDS::~DBRCIndexDS()
+{
+ RMDBGENTER(7, RMDebug::module_indexif, "DBRCIndexDS", "~DBRCIndexDS() " << myOId);
+ validate();
+ currentDbRows = 0;
+ RMDBGEXIT(7, RMDebug::module_indexif, "DBRCIndexDS", "~DBRCIndexDS() " << myOId);
+}
+
+void
+DBRCIndexDS::updateInDb() throw (r_Error)
+{
+ RMDBGENTER(5, RMDebug::module_indexif, "DBRCIndexDS", "updateInDb() " << myOId);
+ // this operation is illegal
+ RMInit::logOut << "DBRCIndexDS::updateInDb() update is not possible" << std::endl;
+ throw r_Error(r_Error::r_Error_FeatureNotSupported);
+ RMDBGEXIT(5, RMDebug::module_indexif, "DBRCIndexDS", "updateInDb() " << myOId);
+}
+
diff --git a/relindexif/dbtcindex.hh b/relindexif/dbtcindex.hh
new file mode 100644
index 0000000..e1f9688
--- /dev/null
+++ b/relindexif/dbtcindex.hh
@@ -0,0 +1,192 @@
+/*
+* 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>.
+*/
+#ifndef _DBTCINDEX_HH_
+#define _DBTCINDEX_HH_
+
+#include "hierindex.hh"
+#include "relblobif/tileid.hh"
+
+//@ManMemo: Module: {\bf relindexif}
+/*@Doc:
+This class stores data of hierarchical indexes in the database. It is extended to store tiles _inline_. this means it is possible for this class to concatenate several tiles into one large blob and store this blob in the database. the tiles must be inlinetiles. it is only interessting if the size of the tiles is very small (smaller than a disc page).
+
+for further information on the methods of this class see hierindexds and indexds interface classes in indexmgr.
+*/
+class DBTCIndex : public DBHierIndex
+ {
+ public:
+ DBTCIndex(r_Dimension dim, bool isNode);
+ /*@Doc:
+ constructs a new index with dimension dim.
+ instance is imediately persistent
+ */
+
+ virtual void printStatus(unsigned int level = 0, std::ostream& stream = std::cout) const;
+ /*@Doc:
+ Prints current status of index, in hierarchical format.
+ */
+
+ ~DBTCIndex();
+ /*@Doc:
+ */
+
+ virtual bool removeObject(const KeyObject& entry);
+ /*@Doc:
+ will take care of inlined tiles when they are removed.
+ */
+
+ virtual bool removeObject(unsigned int pos);
+ /*@Doc:
+ will take care of inlined tiles when they are removed.
+ */
+
+ virtual void removeInlineTile(InlineTile*);
+ /*@Doc:
+ this method is called by inlinetile to removeitselve from the index when it is outlined. the oid of this tile is still stored in the index. do not confuse with removeObejct!
+ */
+
+ virtual void addInlineTile(InlineTile*);
+ /*@Doc:
+ this method is called by inlinetile when it is told to inline itself into this index.
+ */
+
+ void setInlineTileHasChanged();
+ /*@Doc:
+ called by an inlined inlinetile when it is modified. the index must know about this in order to update the inlinetile in the database.
+ */
+
+ virtual IndexDS* getNewInstance() const;
+ /*@Doc:
+ used by indexmgr index logic classes to generate new nodes/leaves without knowing what kind of index structure it is operating with. in essence a clone() pattern.
+ */
+
+ protected:
+ friend class ObjectBroker;
+ /*@Doc:
+ ObjectBroker needs to access OId constructor and getInlineTile
+ */
+
+ InlineTile* getInlineTile(const OId& itid);
+ /*@Doc:
+ returns the specified inline tile.
+ memory management is done by the DBTCIndex object.
+ */
+
+
+ void changeIOIdToBOId();
+ /*@Doc:
+ changes all inlineoids to bloboids. needed in order to be able to use dbhierindex database functionality.
+ */
+
+
+ void readyForRemoval(const OId& id);
+ /*@Doc:
+ inlined inlinetiles must be loaded previous to removing them in order to get them outlined.
+ */
+
+ void changeBOIdToIOId();
+ /*@Doc:
+ changes the bloboids of the inlinetiles which are stored in this index into inlineoids. also neccessary to be able to use dbhierindex functionality.
+ */
+
+ void registerIOIds();
+ /*@Doc:
+ registers all inline oids with the objectbroker. changeIOIdToBOId is supposed to be called afterwards.
+ */
+
+ void readInlineTiles() throw (r_Error);
+ /*
+ loads the tiles from the blob tablespace.
+ errors are database errors.
+ */
+
+ void decideForInlining();
+ /*
+ makes blobtiles to inlinetiles and vice versa.
+ */
+
+ void insertBlob();
+ /*@Doc:
+ insert empty blob into db
+ */
+
+ void storeTiles();
+ /*@Doc:
+ write the tiles into the blob space if neccessary.
+ */
+
+ void writeInlineTiles(char* cells, r_Bytes blobSize) throw (r_Error);
+ /*
+ writes the tiles into the blob tablespace.
+ errors are database errors.
+ */
+
+ void updateTileIndexMappings() throw (r_Error);
+ /*
+ writes the mappings among dbtcindex and inlinetiles into the database for objectbroker to see.
+ errors are database errors.
+ */
+
+ DBTCIndex(const OId& id);
+
+ void setMappingHasChanged();
+ /*@Doc:
+ tells the index that it has to update the table for mapping inlined inlinetile oids to dbtcindexes.
+ */
+
+ virtual void readFromDb() throw (r_Error);
+
+ virtual void updateInDb() throw (r_Error);
+
+ virtual void deleteFromDb() throw (r_Error);
+
+ virtual void insertInDb() throw (r_Error);
+
+ bool mappingHasChanged;
+ /*@Doc:
+ is true when an inlinetile has been added or removed.
+ */
+
+ bool inlineTileHasChanged;
+ /*@Doc:
+ is true when the inlined tiles need to be updated.
+ */
+
+ bool _isLoaded;
+ /*@Doc:
+ transient, tells if the object has loaded its inlined tiles.
+ */
+
+ bool hasBlob;
+ /*@Doc:
+ transient, tells if the object has already a blob in the database or not.
+ */
+
+ DBObjectPMap inlineTiles;
+ /*@Doc:
+ transient, contains pointers to materialised inlinetiles.
+ is filled on demand by loadInlineTiles.
+ */
+
+ };
+#endif
diff --git a/relindexif/dbtcindex.pgc b/relindexif/dbtcindex.pgc
new file mode 100644
index 0000000..10e8318
--- /dev/null
+++ b/relindexif/dbtcindex.pgc
@@ -0,0 +1,338 @@
+#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:
+ * - not yet implemented.
+ *
+ ************************************************************/
+
+// 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 "dbtcindex.hh"
+#include "raslib/rmdebug.hh"
+#include "reladminif/sqlerror.hh"
+
+void
+DBTCIndex::deleteFromDb() throw (r_Error)
+{
+ RMDBGENTER(5, RMDebug::module_indexif, "DBTCIndex", "deleteFromDb() " << myOId);
+ throw r_Error( r_Error::r_Error_BaseDBMSFailed );
+
+/*
+ EXEC SQL BEGIN DECLARE SECTION;
+ long id3;
+ Oid blobOid;
+ char pgQuery[SQL_QUERY_BUFFER_SIZE]; // prelim
+ PGresult *pgResult = NULL; // prelim
+ EXEC SQL END DECLARE SECTION;
+
+ if (!_isLoaded)
+ readInlineTiles();
+
+ DBHierIndex::deleteFromDb();
+
+ id3 = myOId.getCounter();
+
+ TALK( "EXEC SQL DELETE FROM RAS_ITILES WHERE ITileId = " << id3 );
+ EXEC SQL DELETE FROM RAS_ITILES
+ WHERE ITileId = :id3;
+ if (SQLCODE != 0)
+ {
+ if (SQLCODE != 100)
+ {
+ check("DBTCIndex::deleteFromDb() RAS_ITILES");
+ generateException();
+ }
+ }
+
+ TALK( "EXEC SQL DELETE FROM RAS_ITMAP WHERE IndexId = " << id3 );
+ EXEC SQL DELETE FROM
+ RAS_ITMAP
+ WHERE
+ IndexId = :id3;
+ if (SQLCODE != 0)
+ {
+ if (SQLCODE != 100)
+ {
+ check("DBTCIndex::deleteFromDb() RAS_ITMAP");
+ generateException();
+ }
+ }
+
+ RMDBGEXIT(5, RMDebug::module_indexif, "DBTCIndex", "deleteFromDb() " << myOId);
+*/
+}
+
+void
+DBTCIndex::storeTiles()
+{
+ RMDBGENTER(5, RMDebug::module_indexif, "DBTCIndex", "storeTiles() " << myOId);
+ throw r_Error( r_Error::r_Error_BaseDBMSFailed );
+
+ /*
+ char* cells = NULL;
+ r_Bytes blobSize = 0;
+ r_Bytes currinlinesize = 0;
+ char* from = NULL;
+ DBObjectPMap::iterator itit;
+
+ for (itit = inlineTiles.begin(); inlineTiles.end() != itit; itit++)
+ {
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBTCIndex", "InlineTile " << (*itit).second->getOId() << " has size " << ((InlineTile*)(*itit).second)->getStorageSize());
+ blobSize = ((InlineTile*)(*itit).second)->getStorageSize() + blobSize;
+ }
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBTCIndex", "blobSize " << blobSize << " hasBlob " << (int)hasBlob);
+ if (hasBlob && (blobSize == 0))
+ {
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBTCIndex", "dropping blob");
+ //drop blob
+ EXEC SQL BEGIN DECLARE SECTION;
+ long blspcoid4;
+ EXEC SQL END DECLARE SECTION;
+ blspcoid4 = myOId.getCounter();
+
+ TALK( "EXEC SQL DELETE FROM RAS_ITILES WHERE ITileId = " << blspcoid4 );
+ EXEC SQL DELETE FROM RAS_ITILES WHERE ITileId = :blspcoid4;
+ if (SQLCODE != 0)
+ {
+ if (SQLCODE != 100)
+ {
+ check("DBTCIndex::storeTiles drop blob()");
+ generateException();
+ }
+ else
+ {
+ RMInit::logOut << "Tile container index: error in BLOB Space." << endl << "Please contact Customer support." << endl;
+ RMInit::dbgOut << "Tile container index: store tiles, but can't find my blob!" << endl;
+ throw r_Error(TILE_CONTAINER_NOT_FOUND);
+ }
+ }
+ hasBlob = false;
+ }
+ else
+ {
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBTCIndex", "not dropping blob");
+ if (blobSize == 0)
+ {
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBTCIndex", "nothing to insert");
+ }
+ else
+ {
+ if (!hasBlob)
+ {
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBTCIndex", "but inserting blob");
+ insertBlob();
+ }
+ hasBlob = true;
+ cells = (char*)mymalloc(blobSize * sizeof(char));
+ from = cells;
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBTCIndex", "inserting " << blobSize << " bytes");
+ for (itit = inlineTiles.begin(); inlineTiles.end() != itit; itit++)
+ {
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBTCIndex", "inserting " << (*itit).second->getOId() << " from " << (r_Bytes)(from - cells));
+ from = ((InlineTile*)((*itit).second))->insertInMemBlock(from);
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBTCIndex", "inserted to " << (r_Bytes)(from - cells));
+ }
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBTCIndex", "will write " << (r_Bytes)(from - cells) << " bytes");
+ writeInlineTiles(cells, blobSize);
+ for (itit = inlineTiles.begin(); itit != inlineTiles.end(); itit++)
+ {
+ delete (*(inlineTiles.begin())).second;
+ (*(inlineTiles.begin())).second = NULL;
+ }
+ }
+ }
+ RMDBGEXIT(5, RMDebug::module_indexif, "DBTCIndex", "storeTiles() " << myOId);
+ */
+}
+
+void
+DBTCIndex::insertBlob()
+{
+ RMDBGENTER(5, RMDebug::module_indexif, "DBTCIndex", "insertBlob() " << myOId);
+
+ throw r_Error( r_Error::r_Error_BaseDBMSFailed );
+
+ EXEC SQL BEGIN DECLARE SECTION;
+ long blspcoid3;
+ EXEC SQL END DECLARE SECTION;
+ blspcoid3 = myOId.getCounter();
+
+/*
+ EXEC SQL INSERT INTO RAS_ITILES (
+ ITileId,
+ ITile
+ )
+ VALUES (
+ :blspcoid3,
+ EMPTY_BLOB()
+ );
+ if (check("DBTCIndex::insertBlob()") != 0)
+ {
+ if (SQLCODE == -1)
+ RMInit::logOut << "Counter for DBTCIndexs corrupted." << endl << "Please increment Rows in RAS_COUNTERS manually." << endl;
+ generateException();
+ }
+*/
+ hasBlob = true;
+ RMDBGEXIT(5, RMDebug::module_indexif, "DBTCIndex", "insertBlob() " << myOId);
+}
+
+void
+DBTCIndex::writeInlineTiles(char* theblob, r_Bytes blobSize) throw (r_Error)
+{
+ RMDBGENTER(3, RMDebug::module_indexif, "DBTCIndex", "writeInlineTiles() " << myOId);
+ throw r_Error( r_Error::r_Error_BaseDBMSFailed );
+
+ /*
+ EXEC SQL BEGIN DECLARE SECTION;
+ long blspcoid2;
+ EXEC SQL END DECLARE SECTION;
+
+ if (blobSize == 0)
+ {
+ RMInit::logOut << "DBTCIndex encountered an internal Error: blobSize is zero." << endl;
+ RMInit::logOut << "Please check your Oracle Instance and contact Customer Support." << endl;
+ RMDBGONCE(0, RMDebug::module_indexif, "DBTCIndex", "writeInlineTiles blobSize = 0!");
+ throw r_Error(r_Error::r_Error_BaseDBMSFailed);
+ }
+ do
+ {
+
+ //EXEC SQL SELECT ITile INTO :loc1 FROM RAS_ITILES WHERE ITileId = :blspcoid2;
+ if (check("Select Loblocator") != 0)
+ generateException();
+
+ } while ((retries < 5) && (tnserror));
+
+ _isLoaded = false;
+ inlineTileHasChanged = false;
+
+ RMDBGEXIT(3, RMDebug::module_indexif, "DBTCIndex", "writeInlineTiles() " << myOId << " " << myOId.getType());
+*/
+}
+
+void
+DBTCIndex::readInlineTiles() throw (r_Error)
+{
+ RMDBGENTER(3, RMDebug::module_indexif, "DBTCIndex", "readInlineTiles() " << myOId);
+ throw r_Error( r_Error::r_Error_BaseDBMSFailed );
+
+/*
+ EXEC SQL BEGIN DECLARE SECTION;
+ long blspcoid1;
+ EXEC SQL END DECLARE SECTION;
+ blspcoid1 = myOId.getCounter();
+
+ long from = 0;
+ long newsize = 0;
+ char* theblob = NULL;
+
+
+ //EXEC SQL SELECT ITile INTO :loc FROM RAS_ITILES WHERE ITileId = :blspcoid1;
+ if (check("DBTCIndex::loadInlineTiles() SELECT LOBLOCATOR"))
+ throw r_Error(r_Error::r_Error_ObjectUnknown);
+
+ if (loblength != 0)
+ {
+ theblob = (char*)mymalloc(loblength * sizeof(char));
+ }
+ inlineTiles = DBObjectPMap();
+ InlineTile* t = NULL;
+ char* end = (theblob + loblength);
+ RMDBGMIDDLE(3, RMDebug::module_indexif, "DBTCIndex", "end is at " << (r_Bytes)end);
+ while (theblob != end)
+ {
+ RMDBGMIDDLE(3, RMDebug::module_indexif, "DBTCIndex", "reading from " << (r_Bytes)theblob);
+ t = new InlineTile(myOId, theblob);
+ t->setCached(true);
+ DBObjectPPair p(t->getOId(), t);
+ inlineTiles.insert(p);
+ }
+
+#ifdef RMANBENCHMARK
+ DBObject::readTimer.pause();
+#endif
+ _isLoaded = true;
+ inlineTileHasChanged = false;
+ mappingHasChanged = false;
+ RMDBGEXIT(3, RMDebug::module_indexif, "DBTCIndex", "readInlineTiles() " << myOId);
+ */
+}
+
+void
+DBTCIndex::updateTileIndexMappings() throw (r_Error)
+{
+ RMDBGENTER(5, RMDebug::module_indexif, "DBTCIndex", "updateTileIndexMappings() " << myOId);
+ throw r_Error( r_Error::r_Error_BaseDBMSFailed );
+
+ EXEC SQL BEGIN DECLARE SECTION;
+ long indexid;
+ long inlineid;
+ EXEC SQL END DECLARE SECTION;
+
+ indexid = myOId.getCounter();
+
+ TALK( "EXEC SQL DELETE FROM RAS_ITMAP WHERE IndexId = " << indexid );
+ EXEC SQL DELETE FROM
+ RAS_ITMAP
+ WHERE
+ IndexId = :indexid;
+
+ DBObjectPMap::iterator itit;
+ for (itit = inlineTiles.begin(); itit != inlineTiles.end(); itit++)
+ {
+ inlineid = OId((*itit).first).getCounter();
+
+ TALK( "EXEC SQL INSERT INTO RAS_ITMAP ( TileId, IndexId) VALUES ( " << inlineid << "," << indexid << ")" );
+ EXEC SQL INSERT INTO RAS_ITMAP (
+ TileId,
+ IndexId
+ )
+ VALUES (
+ :inlineid,
+ :indexid
+ );
+ RMDBGMIDDLE(6, RMDebug::module_indexif, "DBTCIndex", "TileId: " << inlineid << " IndexId: " << indexid);
+ if (check("DBTCIndex::updateTileIndexMappings() insert in RAS_ITMAP") != 0)
+ generateException();
+ }
+ mappingHasChanged = false;
+ RMDBGEXIT(5, RMDebug::module_indexif, "DBTCIndex", "updateTileIndexMappings() " << myOId);
+}
+
diff --git a/relindexif/dbtcindexcommon.cc b/relindexif/dbtcindexcommon.cc
new file mode 100644
index 0000000..fb44354
--- /dev/null
+++ b/relindexif/dbtcindexcommon.cc
@@ -0,0 +1,357 @@
+/*
+* 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 <unistd.h>
+
+#include "dbtcindex.hh"
+#include "raslib/rmdebug.hh"
+#include "reladminif/lists.h"
+#include "reladminif/sqlerror.hh"
+#include "reladminif/externs.h"
+#include "relblobif/blobtile.hh"
+#include "relblobif/inlinetile.hh"
+#include "relblobif/tileid.hh"
+#include "reladminif/objectbroker.hh"
+#include "reladminif/adminif.hh"
+#include "reladminif/dbref.hh"
+#include "storagemgr/sstoragelayout.hh"
+#include "indexmgr/keyobject.hh"
+
+void
+DBTCIndex::setMappingHasChanged()
+ {
+ mappingHasChanged = true;
+ }
+
+void
+DBTCIndex::setInlineTileHasChanged()
+ {
+ inlineTileHasChanged = true;
+ }
+
+DBTCIndex::DBTCIndex(const OId& id)
+ : DBHierIndex(id),
+ _isLoaded(false),
+ inlineTileHasChanged(false),
+ mappingHasChanged(false),
+ hasBlob(false)
+ {
+ RMDBGENTER(7, RMDebug::module_indexif, "DBTCIndex", "DBTCIndex(" << myOId << ")");
+ throw r_Error(r_Error::r_Error_FeatureNotSupported);
+ readFromDb();
+ _isLoaded = !hasBlob;
+ RMDBGEXIT(7, RMDebug::module_indexif, "DBTCIndex", "DBTCIndex(" << myOId << ")");
+ }
+
+IndexDS*
+DBTCIndex::getNewInstance() const
+ {
+ return (HierIndexDS*)new DBTCIndex(getDimension(), !isLeaf());
+ }
+
+DBTCIndex::DBTCIndex(r_Dimension dim, bool isNode)
+ : DBHierIndex(dim, isNode, false),
+ _isLoaded(true),
+ inlineTileHasChanged(false),
+ mappingHasChanged(false),
+ hasBlob(false)
+ {
+ RMDBGENTER(7, RMDebug::module_indexif, "DBTCIndex", "DBTCIndex(" << dim << ", " << (int)_isLoaded << ") " << myOId);
+ throw r_Error(r_Error::r_Error_FeatureNotSupported);
+ objecttype = OId::DBTCINDEXOID;
+ setPersistent(true);
+ setCached(true);
+ RMDBGEXIT(7, RMDebug::module_indexif, "DBTCIndex", "DBTCIndex(" << dim << ") " << myOId);
+ }
+
+void
+DBTCIndex::printStatus(unsigned int level, std::ostream& stream) const
+ {
+ char* indent = new char[level*2 +1];
+ for (unsigned int j = 0; j < level*2 ; j++)
+ indent[j] = ' ';
+ indent[level*2] = '\0';
+
+ stream << indent << "DBTCIndex ";
+ DBHierIndex::printStatus(level + 1, stream);
+ delete[] indent;
+ }
+
+
+DBTCIndex::~DBTCIndex()
+ {
+ RMDBGENTER(7, RMDebug::module_indexif, "DBTCIndex", "~DBTCIndex() " << myOId);
+ if (!isModified())
+ {
+ if (!AdminIf::isReadOnlyTA())
+ {
+ if (isLeaf())
+ decideForInlining();
+ if (mappingHasChanged)
+ updateTileIndexMappings();
+ if (inlineTileHasChanged)
+ {
+ storeTiles();
+ changeBOIdToIOId();
+ }
+ if (isModified())
+ DBHierIndex::updateInDb();
+ if (isLeaf())
+ changeIOIdToBOId();
+ }
+ }
+ else
+ validate();
+ currentDbRows = 0;
+ parent = OId(0);
+ RMDBGEXIT(7, RMDebug::module_indexif, "DBTCIndex", "~DBTCIndex() " << myOId);
+ }
+
+void
+DBTCIndex::registerIOIds()
+ {
+ RMDBGENTER(7, RMDebug::module_indexif, "DBTCIndex", "registerIOIds() " << myOId);
+ for (KeyObjectVector::iterator i = myKeyObjects.begin(); i != myKeyObjects.end(); i++)
+ if ((*i).getObject().getOId().getType() == OId::INNEROID)
+ {
+ RMDBGMIDDLE(7, RMDebug::module_indexif, "DBTCIndex", "registering tileoid " << OId((*i).getObject().getOId().getCounter(), OId::INLINETILEOID) << " indexoid " << myOId);
+ ObjectBroker::registerTileIndexMapping(OId((*i).getObject().getOId().getCounter(), OId::INLINETILEOID), myOId);
+ hasBlob = true;
+ }
+ RMDBGEXIT(7, RMDebug::module_indexif, "DBTCIndex", "registerIOIds() " << myOId);
+ }
+
+void
+DBTCIndex::changeIOIdToBOId()
+ {
+ for (KeyObjectVector::iterator it = myKeyObjects.begin(); it != myKeyObjects.end(); it++)
+ if ((*it).getObject().getOId().getType() == OId::INNEROID)
+ {
+ OId o((*it).getObject().getOId().getCounter(), OId::INLINETILEOID);
+ DBObjectPPair p(o, 0);
+ inlineTiles.insert(p);
+ (*it).setObject(o);
+ }
+ }
+
+void
+DBTCIndex::changeBOIdToIOId()
+ {
+ for (KeyObjectVector::iterator it = myKeyObjects.begin(); it != myKeyObjects.end(); it++)
+ {
+ DBObjectPMap::iterator itit = inlineTiles.find((*it).getObject().getOId());
+ if (itit != inlineTiles.end())
+ {
+ (*it).setObject(OId((*it).getObject().getOId().getCounter(), OId::INNEROID));
+ }
+ }
+ }
+
+void
+DBTCIndex::removeInlineTile(InlineTile* it)
+ {
+ DBObjectPMap::iterator itit = inlineTiles.find(it->getOId());
+ if (itit != inlineTiles.end())
+ {
+ inlineTiles.erase(itit);
+ setMappingHasChanged();
+ setInlineTileHasChanged();
+ ObjectBroker::deregisterTileIndexMapping(it->getOId(), myOId);
+ }
+ else {
+ RMDBGONCE(0, RMDebug::module_indexif, "DBTCIndex", "deregisterInlineTile(" << it->getOId() << ") it not found")
+ }
+ }
+
+void
+DBTCIndex::addInlineTile(InlineTile* it)
+ {
+ if (!_isLoaded)
+ readInlineTiles();
+ DBObjectPPair p(it->getOId(), it);
+ inlineTiles.insert(p);
+ ObjectBroker::registerTileIndexMapping(it->getOId(), myOId);
+ setMappingHasChanged();
+ setInlineTileHasChanged();
+ }
+
+void
+DBTCIndex::insertInDb() throw (r_Error)
+ {
+ RMDBGENTER(5, RMDebug::module_indexif, "DBTCIndex", "insertInDb() " << myOId);
+ if (isLeaf())
+ {
+ decideForInlining();
+ if (inlineTileHasChanged || mappingHasChanged)
+ {
+ updateTileIndexMappings();
+ insertBlob();
+ storeTiles();
+ changeBOIdToIOId();
+ }
+ }
+ DBHierIndex::insertInDb();
+ if (isLeaf())
+ changeIOIdToBOId();
+ RMDBGEXIT(5, RMDebug::module_indexif, "DBTCIndex", "insertInDb() " << myOId);
+ }
+
+void
+DBTCIndex::readFromDb() throw (r_Error)
+ {
+ RMDBGENTER(5, RMDebug::module_indexif, "DBTCIndex", "readFromDb() " << myOId);
+ DBHierIndex::readFromDb();
+ if (isLeaf())
+ {
+ registerIOIds();
+ changeIOIdToBOId();
+ }
+ inlineTileHasChanged = false;
+ mappingHasChanged = false;
+ RMDBGEXIT(5, RMDebug::module_indexif, "DBTCIndex", "readFromDb() " << myOId);
+ }
+
+void
+DBTCIndex::updateInDb() throw (r_Error)
+ {
+ RMDBGENTER(5, RMDebug::module_indexif, "DBTCIndex", "updateInDb() " << myOId);
+ if (isLeaf())
+ decideForInlining();
+ if (mappingHasChanged)
+ updateTileIndexMappings();
+ if (inlineTileHasChanged)
+ storeTiles();
+ if (inlineTiles.size() != 0)
+ changeBOIdToIOId();
+ DBHierIndex::updateInDb();
+ if (isLeaf())
+ changeIOIdToBOId();
+ RMDBGEXIT(5, RMDebug::module_indexif, "DBTCIndex", "updateInDb() " << myOId);
+ }
+
+InlineTile*
+DBTCIndex::getInlineTile(const OId& itid)
+ {
+ InlineTile* retval = 0;
+ DBObjectPMap::iterator itit;
+ if (!_isLoaded)
+ {
+ readInlineTiles();
+ }
+ itit = inlineTiles.find(itid);
+ if (itit != inlineTiles.end())
+ {
+ retval = (InlineTile*)(*itit).second;
+ }
+ return retval;
+ }
+
+void
+DBTCIndex::readyForRemoval(const OId& id)
+ {
+ if (id.getType() == OId::INLINETILEOID)
+ {
+ DBObjectPMap::iterator itit;
+
+ itit = inlineTiles.find(id);
+ if (inlineTiles.end() != itit)
+ {
+ if (!_isLoaded)
+ {
+ readInlineTiles();
+ itit = inlineTiles.find(id);
+ ((*itit).second)->setCached(false);
+ ((InlineTile*)(*itit).second)->outlineTile();
+ }
+ else {
+ ((*itit).second)->setCached(false);
+ ((InlineTile*)(*itit).second)->outlineTile();
+ }
+ }
+ }
+ }
+
+bool
+DBTCIndex::removeObject(const KeyObject& entry)
+ {
+ RMDBGENTER(4, RMDebug::module_indexif, "DBTCIndex", "removeObject(" << entry << ") " << myOId);
+ if (isLeaf())
+ readyForRemoval(entry.getObject().getOId());
+ bool found = DBHierIndex::removeObject(entry);
+ RMDBGEXIT(4, RMDebug::module_indexif, "DBTCIndex", "removeEntry(" << entry << ") " << myOId << " " << found);
+ return found;
+ }
+
+bool
+DBTCIndex::removeObject(unsigned int pos)
+ {
+ RMDBGENTER(4, RMDebug::module_indexif, "DBTCIndex", "removeObject(" << pos << ") " << myOId);
+ if (isLeaf())
+ if (pos <= myKeyObjects.size())
+ readyForRemoval(myKeyObjects[pos].getObject().getOId());
+ bool found = DBHierIndex::removeObject((unsigned int)pos);
+ RMDBGEXIT(4, RMDebug::module_indexif, "DBTCIndex", "removeEntry(" << pos << ") " << myOId << " " << found);
+ return found;
+ }
+
+void
+DBTCIndex::decideForInlining()
+ {
+ RMDBGENTER(5, RMDebug::module_indexif, "DBTCIndex", "decideForInlining() " << myOId);
+ if (isLeaf())
+ {
+ InlineTile* itile = NULL;
+ KeyObjectVector::iterator it;
+ for (it = myKeyObjects.begin(); it != myKeyObjects.end(); it++)
+ {
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBTCIndex", " we do oid " << (*it));
+ if ((*it).getObject().getOId().getType() == OId::INLINETILEOID)
+ if ((itile = (InlineTile*)ObjectBroker::isInMemory((*it).getObject().getOId())) != 0)
+ {
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBTCIndex", "in memory");
+ //decide for inlineing
+ if (itile->isInlined())
+ {
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBTCIndex", "inlined");
+ if (itile->getSize() > StorageLayout::DefaultPCTMax)
+ {
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBTCIndex", "needs to be outlined");
+ itile->outlineTile();
+ }
+ }
+ else {
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBTCIndex", "outlined");
+ if (itile->getSize() < StorageLayout::DefaultMinimalTileSize)
+ {
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBTCIndex", "needs to be inlined");
+ itile->inlineTile(myOId);
+ }
+ }
+ }
+ else {
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBTCIndex", "not in memory");
+ }
+ }
+ }
+ RMDBGEXIT(5, RMDebug::module_indexif, "DBTCIndex", "decideForInlining() " << myOId);
+ }
+
diff --git a/relindexif/hierindex.hh b/relindexif/hierindex.hh
new file mode 100644
index 0000000..89b2043
--- /dev/null
+++ b/relindexif/hierindex.hh
@@ -0,0 +1,219 @@
+/*
+* 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>.
+*/
+#ifndef _DBHIERINDEX_HH_
+#define _DBHIERINDEX_HH_
+
+#include "reladminif/dbobject.hh"
+#include "indexmgr/hierindexds.hh"
+#include "relcatalogif/inlineminterval.hh"
+
+//@ManMemo: Module: {\bf relindexif}
+/*@Doc:
+This class stores data of hierarchical indexes in the database.
+
+There should be another interface to include the isLeaf/isRoot/...
+functionality.
+
+Beware of the cache when droping the IndexDS classes!
+
+See indexmgr/hierindexds.hh and indexmgr/indexds.hh for documentation.
+*/
+class DBHierIndex : public HierIndexDS
+ {
+ public:
+ DBHierIndex(r_Dimension dim, bool isNode, bool makePersistent);
+ /*@Doc:
+ constructs a new index with type ixType, dimension dim.
+ if isNode is true the index behaves as a node, else as
+ a leaf instance is imediately persistent
+ */
+
+ virtual double getOccupancy() const;
+
+ HierIndexDS* getParent() const;
+
+ void setParent(const HierIndexDS* newPa);
+
+ virtual void setIsNode(bool beNode);
+
+ virtual bool isLeaf() const;
+
+ virtual bool isRoot() const;
+ /*@Doc:
+ is a check for a valid myParent OId
+ */
+
+ virtual unsigned int getHeight() const;
+
+ virtual unsigned int getHeightOfTree() const;
+ /*@Doc:
+ Recursive function to get height of the tree.
+ */
+
+ virtual unsigned int getHeightToRoot() const;
+ /*@Doc:
+ Recursive function to get the number of levels to the root.
+ */
+
+ virtual unsigned int getHeightToLeaf() const;
+ /*@Doc:
+ Recursive function to get the number of levels to the
+ leafs.
+ */
+
+ virtual unsigned int getTotalEntryCount() const;
+
+ virtual unsigned int getTotalNodeCount() const;
+
+ virtual unsigned int getTotalLeafCount() const;
+
+ virtual r_Minterval getCoveredDomain() const;
+
+ virtual r_Minterval getAssignedDomain() const;
+
+ virtual r_Minterval getObjectDomain(unsigned int pos) const;
+
+ virtual r_Dimension getDimension() const;
+
+ virtual void setAssignedDomain(const r_Minterval& domain);
+
+ virtual unsigned int getSize() const;
+
+ virtual r_Bytes getTotalStorageSize() const;
+
+ virtual bool isValid() const;
+
+ virtual bool isUnderFull() const;
+
+ virtual bool isOverFull() const;
+
+ virtual bool isSameAs(const IndexDS* pix) const;
+
+ virtual bool removeObject(unsigned int pos);
+
+ virtual bool removeObject(const KeyObject& theKey);
+
+ virtual void insertObject(const KeyObject& theKey, unsigned int pos);
+
+ virtual void setObject(const KeyObject& theKey, unsigned int pos);
+
+ virtual void setObjectDomain(const r_Minterval& dom, unsigned int pos);
+
+ virtual const KeyObject& getObject(unsigned int pos) const;
+
+ virtual void getObjects(KeyObjectVector& objs) const;
+
+ virtual unsigned int getOptimalSize() const;
+
+ static unsigned int getOptimalSize(r_Dimension dim);
+ /*@Doc:
+ Used to calculate the optimal number of entries for
+ that dimension
+ */
+
+ virtual void freeDS();
+
+ virtual OId::OIdPrimitive getIdentifier() const;
+
+ static r_Bytes BytesPerTupel;
+ /*@Doc:
+ tuning parameter. used to calculate the optimal size of
+ an index. this is also the number of bytes written to the
+ database.
+ */
+
+ virtual void printStatus(unsigned int level = 0, std::ostream& stream = std::cout) const;
+
+ virtual ~DBHierIndex();
+
+ virtual void destroy();
+
+ virtual IndexDS* getNewInstance() const;
+
+ virtual BinaryRepresentation getBinaryRepresentation() const throw (r_Error);
+
+ virtual void setBinaryRepresentation(const BinaryRepresentation&) throw (r_Error);
+
+ protected:
+ friend class ObjectBroker;
+ /*@Doc:
+ ObjectBroker needs to access OId constructor
+ */
+
+ DBHierIndex(const OId& id);
+ /*@Doc:
+ */
+
+ virtual void readFromDb() throw (r_Error);
+ /*@Doc:
+ */
+
+ virtual void updateInDb() throw (r_Error);
+ /*@Doc:
+ */
+
+ virtual void deleteFromDb() throw (r_Error);
+ /*@Doc:
+ */
+
+ virtual void insertInDb() throw (r_Error);
+ /*@Doc:
+ */
+
+ void extendCoveredDomain(const r_Minterval& newTilesExtents) throw (r_Edim_mismatch, r_Eno_interval);
+ /*@Doc:
+ Recalculates the current domain of this index to
+ include newTilesExtents.
+ */
+
+ OId parent;
+ /*@Doc:
+ persistent, identifies the parent
+ */
+
+ bool _isNode;
+ /*@Doc:
+ persistent, tells the object what it is.
+ */
+
+
+ unsigned int maxSize;
+ /*@Doc:
+ Non persistent attribute. a cache so the maxSize does not have to be calculated all the time.
+ */
+
+ KeyObjectVector myKeyObjects;
+
+ InlineMinterval myDomain;
+ /*@Doc:
+ Defined domain of this index.
+ */
+
+ short currentDbRows;
+ /*@Doc:
+ is needed to support update of index in database
+ keeps the number of rows currently taken up in the db by
+ this instance
+ */
+ };
+#endif
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()
+
diff --git a/relindexif/hierindexcommon.cc b/relindexif/hierindexcommon.cc
new file mode 100644
index 0000000..61ce20c
--- /dev/null
+++ b/relindexif/hierindexcommon.cc
@@ -0,0 +1,1033 @@
+/*
+* 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:
+ * maintain the hierarchical index in the DBMS.
+ *
+ *
+ * COMMENTS:
+ * - relies on the same-name DBMS preprocessor sources for the
+ * various DBMSs supported.
+ *
+ ************************************************************/
+
+#include <cstring>
+
+#include "mymalloc/mymalloc.h"
+#include "hierindex.hh"
+#include "reladminif/objectbroker.hh"
+#include "reladminif/dbref.hh"
+#include "raslib/rmdebug.hh"
+#include "reladminif/lists.h"
+#include "reladminif/sqlerror.hh"
+#include "reladminif/externs.h"
+#include "relblobif/blobtile.hh"
+#include "indexmgr/keyobject.hh"
+#include "storagemgr/sstoragelayout.hh"
+#include "raslib/endian.hh"
+#include "debug.hh"
+
+DBHierIndex::DBHierIndex(const OId& id)
+ : HierIndexDS(id),
+ currentDbRows(0),
+ myDomain((r_Dimension)0),
+ maxSize(0),
+ parent(0),
+ _isNode(false)
+ {
+ RMDBGENTER(7, RMDebug::module_indexif, "DBHierIndex", "DBHierIndex(" << myOId << ")");
+ ENTER( "DBHierIndex::DBHierIndex(" << myOId << ")" );
+
+ if (id.getType() == OId::MDDHIERIXOID)
+ readFromDb();
+ maxSize = DBHierIndex::getOptimalSize(getDimension());
+ myKeyObjects.reserve(maxSize);
+
+ LEAVE( "DBHierIndex::DBHierIndex(" << myOId << ")" );
+ RMDBGEXIT(7, RMDebug::module_indexif, "DBHierIndex", "DBHierIndex(" << myOId << ")");
+ }
+
+DBHierIndex::DBHierIndex(r_Dimension dim, bool isNODE, bool makePersistent)
+ : HierIndexDS(),
+ maxSize(0),
+ myDomain(dim),
+ currentDbRows(-1),
+ parent(0),
+ _isNode(isNODE)
+ {
+ RMDBGENTER(7, RMDebug::module_indexif, "DBHierIndex", "DBHierIndex(" << dim << ", " << (int)isNODE << ", " << makePersistent << ") " << myOId);
+ ENTER( "DBHierIndex::DBHierIndex( dim=" << dim << ", isNODE=" << (int) isNODE << ", makePersistent=" << makePersistent << " ) - myOId=" << myOId );
+
+ objecttype = OId::MDDHIERIXOID;
+ if (makePersistent)
+ setPersistent(true);
+
+ maxSize = getOptimalSize(dim);
+ myKeyObjects.reserve(maxSize);
+ setCached(true);
+
+ LEAVE( "DBHierIndex::DBHierIndex( dim=" << dim << ", isNODE=" << (int) isNODE << ", makePersistent=" << makePersistent << " ) - myOId=" << myOId );
+ RMDBGEXIT(7, RMDebug::module_indexif, "DBHierIndex", "DBHierIndex(" << dim << ", " << (int)isNODE << ", " << makePersistent << ") " << myOId);
+ }
+
+IndexDS*
+DBHierIndex::getNewInstance() const
+ {
+ ENTER( "DBHierIndex::getNewInstance()" );
+ LEAVE( "DBHierIndex::getNewInstance() - dim=" << getDimension() << ", !isLeaf=" << (!isLeaf()) );
+ return new DBHierIndex(getDimension(), !isLeaf(), true);
+ }
+
+OId::OIdPrimitive
+DBHierIndex::getIdentifier() const
+ {
+ ENTER( "DBHierIndex::getIdentifier()" );
+ LEAVE( "DBHierIndex::getIdentifier() - myOId=" << myOId );
+ return myOId;
+ }
+
+bool
+DBHierIndex::removeObject(const KeyObject& entry)
+ {
+ RMDBGENTER(4, RMDebug::module_indexif, "DBHierIndex", "removeObject(" << entry << ") " << myOId);
+ ENTER( "DBHierIndex::removeObject() - entry=" << entry << ", myOId=" << myOId );
+
+ bool found = false;
+ unsigned int pos = 0;
+ OId oid(entry.getObject().getOId());
+ for (KeyObjectVector::iterator i = myKeyObjects.begin(); i != myKeyObjects.end(); i++)
+ {
+ RMDBGMIDDLE(9, RMDebug::module_indexif, "DBHierIndex", "at pos " << pos << " of " << myKeyObjects.size());
+ TALK( "DBHierIndex::removeObject() touching object in vector at pos " << pos << " of " << myKeyObjects.size());
+ if (oid == (*i).getObject().getOId())
+ {
+ found = true;
+ myKeyObjects.erase(i);
+ setModified();
+ break;
+ }
+ else {
+ RMDBGMIDDLE(9, RMDebug::module_indexif, "DBHierIndex", "did not match " << oid << " with " << *i);
+ }
+ }
+
+ LEAVE( "DBHierIndex::removeObject() - entry=" << entry << ", myOId=" << myOId << ", found=" << found );
+ RMDBGEXIT(4, RMDebug::module_indexif, "DBHierIndex", "removeObject(" << entry << ") " << myOId << " " << found);
+ return found;
+ }
+
+bool
+DBHierIndex::removeObject(unsigned int pos)
+ {
+ RMDBGENTER(4, RMDebug::module_indexif, "DBHierIndex", "removeObject(" << pos << ") " << myOId);
+ ENTER( "DBHierIndex::removeObject() - pos=" << pos << ", myOId=" << myOId );
+
+ bool found = false;
+ if (pos <= myKeyObjects.size())
+ {
+ found = true;
+ myKeyObjects.erase(myKeyObjects.begin() + pos);
+ setModified();
+ }
+
+ LEAVE( "DBHierIndex::removeObject() - pos=" << pos << ", myOId=" << myOId << ", found=" << found );
+ RMDBGEXIT(4, RMDebug::module_indexif, "DBHierIndex", "removeObject(" << pos << ") " << myOId << " " << found);
+ return found;
+ }
+
+
+void
+DBHierIndex::insertObject(const KeyObject& theKey, unsigned int pos)
+ {
+ RMDBGENTER(8, RMDebug::module_indexif, "DBHierIndex", "insertObject(" << theKey << ", " << pos << ") " << myOId);
+ ENTER( "DBHierIndex::insertObject() - theKey=" << theKey << ", pos=" << pos << ", myOId=" << myOId );
+
+ if (!isLeaf())
+ DBHierIndexId(theKey.getObject())->setParent(this);
+ if (myKeyObjects.size() == 0)
+ {
+ // first tile to be inserted in the index, initialize domain
+ myDomain = theKey.getDomain();
+ }
+ else
+ extendCoveredDomain(theKey.getDomain());
+ myKeyObjects.insert(myKeyObjects.begin() + pos, theKey);
+ TALK( "now have " << myKeyObjects.size() << " objects in key object vector." );
+ setModified();
+
+ LEAVE( "DBHierIndex::insertObject() - theKey=" << theKey << ", pos=" << pos << ", myOId=" << myOId << ", CoveredDomain " << getCoveredDomain() << std::endl << std::endl );
+ TALK( " CoveredDomain=" << getCoveredDomain() << std::endl << std::endl );
+ RMDBGEXIT(8, RMDebug::module_indexif, "DBHierIndex", "insertObject(" << theKey << ", " << pos << ") " << myOId << " CoveredDomain " << getCoveredDomain());
+ }
+
+void
+DBHierIndex::setObjectDomain(const r_Minterval& dom, unsigned int pos)
+ {
+ RMDBGENTER(7, RMDebug::module_indexif, "DBHierIndex", "setObjectDomain(" << dom << ", " << pos << ") " << myOId);
+ ENTER( "DBHierIndex::setObjectDomain() - dom=" << dom << ", pos=" << pos << ", myOId=" << myOId );
+
+ myKeyObjects[pos].setDomain(dom);
+ //might be unneccessary/harmfull, check later
+ extendCoveredDomain(dom);
+
+ //setModified(); done in domain extension
+ if (!isLeaf())
+ {
+ DBHierIndexId t(myKeyObjects[pos].getObject());
+ t->setAssignedDomain(dom);
+ }
+
+ LEAVE( "DBHierIndex::setObjectDomain() - dom=" << dom << ", pos=" << pos << ", myOId=" << myOId );
+ RMDBGEXIT(7, RMDebug::module_indexif, "DBHierIndex", "setObjectDomain(" << dom << ", " << pos << ") " << myOId);
+ }
+
+void
+DBHierIndex::setObject(const KeyObject& theKey, unsigned int pos)
+ {
+ RMDBGENTER(7, RMDebug::module_indexif, "DBHierIndex", "setObject(" << theKey << ", " << pos << ") " << myOId);
+ ENTER( "DBHierIndex::setObject() - theKey=" << theKey << ", pos=" << pos << ", myOId=" << myOId );
+
+ myKeyObjects[pos] = theKey;
+ setModified();
+ if (!isLeaf())
+ {
+ DBHierIndexId(theKey.getObject())->setParent(this);
+ }
+
+ LEAVE( "DBHierIndex::setObject() - theKey=" << theKey << ", pos=" << pos << ", myOId=" << myOId );
+ RMDBGEXIT(7, RMDebug::module_indexif, "DBHierIndex", "setObject(" << theKey << ", " << pos << ") " << myOId);
+ }
+
+r_Minterval
+DBHierIndex::getCoveredDomain() const
+ {
+ RMDBGONCE(7, RMDebug::module_indexif, "DBHierIndex", "getCoveredDomain() const " << myOId << " " << myDomain);
+ TALK( "DBHierIndex::getCoveredDomain( " << myOId << ") -> " << myDomain );
+ return myDomain;
+ }
+
+r_Dimension
+DBHierIndex::getDimension() const
+ {
+ RMDBGONCE(7, RMDebug::module_indexif, "DBDDObjIx", "getDimension() const " << myOId << " " << myDomain.dimension());
+ TALK( "DBHierIndex::getDimension( " << myOId << ") -> " << myDomain.dimension() );
+ return myDomain.dimension();
+ }
+
+r_Bytes
+DBHierIndex::getTotalStorageSize() const
+ {
+ RMDBGENTER(4, RMDebug::module_indexif, "DBHierIndex", "getTotalStorageSize() " << myOId);
+ ENTER( "DBHierIndex::getTotalStorageSize() - myOId=" << myOId );
+
+ r_Bytes sz = 0;
+
+ for (KeyObjectVector::const_iterator i = myKeyObjects.begin(); i != myKeyObjects.end(); i++)
+ {
+ sz = sz + ((DBObject*)ObjectBroker::getObjectByOId(i->getObject().getOId()))->getTotalStorageSize();
+ }
+
+ LEAVE( "DBHierIndex::getTotalStorageSize( " << myOId << " ) for " << myKeyObjects.size() << " objects -> sz=" << sz );
+ RMDBGEXIT(4, RMDebug::module_indexif, "DBHierIndex", "getTotalStorageSize() " << myOId << " " << sz);
+ return sz;
+ }
+
+bool
+DBHierIndex::isValid() const
+ {
+ ENTER( "DBHierIndex::isValid()" );
+
+ bool valid = true;
+ //may not be unsigned int (r_Area) because of error check
+ int area = 0;
+ if (!isLeaf())
+ {
+ area = myDomain.cell_count();
+ DBHierIndexId tempIx;
+ TALK( "inspecting " << myKeyObjects.size() << " objects in key object vector." );
+ for (KeyObjectVector::const_iterator i = myKeyObjects.begin(); i != myKeyObjects.end(); i++)
+ {
+ if (myDomain.covers((*i).getDomain()))
+ {
+ //ok
+ area = area - (*i).getDomain().cell_count();
+ }
+ else {
+ if (myDomain == (*i).getDomain())
+ {
+ //ok
+ area = area - (*i).getDomain().cell_count();
+ tempIx = DBHierIndexId((*i).getObject());
+ if (!tempIx->isValid())
+ {
+ valid = false;
+ break;
+ }
+ }
+ else {
+ RMDBGONCE(0, RMDebug::module_indexif, "DBHierIndex", "isValid() " << myOId << " key does not cover domain: myDomain " << myDomain << " key " << *i);
+ valid = false;
+ break;
+ }
+ }
+ }
+ if (valid)
+ {
+ if (area < 0)
+ {
+ RMDBGONCE(0, RMDebug::module_indexif, "DBHierIndex", "isValid() " << myOId << " there are double entries");
+ valid = false;
+ }
+ }
+ }
+ else {
+ area = myDomain.cell_count();
+ valid = true;
+ for (KeyObjectVector::const_iterator i = myKeyObjects.begin(); i != myKeyObjects.end(); i++)
+ {
+ if (myDomain.intersects_with((*i).getDomain()))
+ {
+ //ok
+ area = area - (*i).getDomain().create_intersection(myDomain).cell_count();
+ }
+ else {
+ RMDBGONCE(0, RMDebug::module_indexif, "DBHierIndex", "isValid() " << myOId << " key does not intersect domain: myDomain " << myDomain << " key " << *i);
+ valid = false;
+ break;
+ }
+ }
+ if (!valid)
+ {
+ if (area < 0)
+ {
+ RMDBGONCE(0, RMDebug::module_indexif, "DBHierIndex", "isValid() " << myOId << " there are double entries");
+ valid = false;
+ }
+ }
+ }
+
+ ENTER( "DBHierIndex::isValid() -> valid=" << valid );
+ return valid;
+ }
+
+void
+DBHierIndex::printStatus(unsigned int level, std::ostream& stream) const
+ {
+ ENTER( "DBHierIndex::printStatus() - level=" << level );
+
+ DBObjectId t;
+ char* indent = new char[level*2 +1];
+ for (unsigned int j = 0; j < level*2 ; j++)
+ indent[j] = ' ';
+ indent[level*2] = '\0';
+
+ stream << indent << "DBHierIndex ";
+ if (isRoot())
+ stream << "is Root ";
+ else
+ stream << "Parent " << parent << " ";
+ if (isLeaf())
+ stream << "Leaf ";
+ else
+ stream << "Node ";
+ DBObject::printStatus(level, stream);
+ stream << " size " << myKeyObjects.size() << " domain " << myDomain << std::endl;
+ int count = 0;
+ TALK( "inspecting " << myKeyObjects.size() << " objects in key object vector." );
+ for (KeyObjectVector::const_iterator i = myKeyObjects.begin(); i != myKeyObjects.end(); i++)
+ {
+ stream << indent << " entry #" << count << " is " << *i << std::endl;
+ if (!isLeaf())
+ {
+ t = DBObjectId((*i).getObject());
+ if (t.is_null())
+ stream << indent << " entry is null";
+ else
+ t->printStatus(level + 1, stream);
+ }
+ stream << std::endl;
+ count++;
+ }
+ delete[] indent;
+
+ LEAVE( "DBHierIndex::printStatus()" );
+ }
+
+unsigned int
+DBHierIndex::getSize() const
+ {
+ RMDBGONCE(4, RMDebug::module_indexif, "DBHierIndex", "getSize() " << myOId << " " << myKeyObjects.size());
+ TALK( "DBHierIndex::getSize() - myOId=" << myOId << ", size=" << myKeyObjects.size() );
+ return myKeyObjects.size();
+ }
+
+bool
+DBHierIndex::isUnderFull() const
+ {
+ //redistribute in srptindexlogic has to be checked first before any other return value may be assigned
+ TALK( "DBHierIndex::isUnderFull() -> false" );
+ return false;
+ }
+
+bool
+DBHierIndex::isOverFull() const
+ {
+ ENTER( "DBHierIndex::isOverFull()" );
+
+ bool retval = false;
+ if (getSize() >= maxSize)
+ retval = true;
+
+ RMDBGONCE(4, RMDebug::module_indexif, "DBHierIndex", "isOverFull() " << myOId << " maxSize " << maxSize << " size " << getSize() << " retval " << retval)
+ ENTER( "DBHierIndex::isOverFull() -> " << retval );
+ return retval;
+ }
+
+unsigned int
+DBHierIndex::getOptimalSize(r_Dimension dim)
+ {
+ ENTER( "DBHierIndex::getOptimalSize() - dim=" << dim );
+
+ unsigned int retval = 0;
+ //BLOCKSIZE
+ unsigned int blocksize = 0;
+ unsigned int useablespace = 0;
+ //dimension * (upperbound + upperfixed + lowerbound + lowerfixed) + entryid + entryoidtype
+ unsigned int oneentry = dim * (sizeof(r_Range) * 2 + sizeof(char) * 2) + sizeof(OId::OIdCounter) + sizeof(char);
+
+#ifdef BASEDB_ORACLE
+ blocksize = 2048;
+ //BLOCKSIZE - (BLOCK OVERHEAD + ROW OVERHEAD + 1 * largerow + number(15,0) + short)
+ useablespace = blocksize - (130 + 3 + 1 * 3 + 12 + 2);
+#else
+#ifdef BASEDB_DB2
+ blocksize = 4096;
+ //from the manual
+ useablespace = 3990;
+#else
+#ifdef BASEDB_INFORMIX
+ blocksize = 4096;
+ //from the manual
+ useablespace = 3990;
+#else
+#ifdef BASEDB_PGSQL
+ blocksize = 8192; // default only!!!;
+ useablespace = 7000; // no indication for any less space available, but to be sure we go a little lower -- PB 2005-jan-10
+#else
+#error "BASEDB not defined! please check for BASEDB_XXX define in Makefile.inc!"
+#endif // pgsql
+#endif // informix
+#endif // db2
+#endif // oracle
+
+ //remove mydomain size
+ useablespace = useablespace - dim * (sizeof(r_Range) * 2 + sizeof(char) * 2);
+ //minimum size is 8-lucky guess(good for 1,2,3,4 dimensions)
+ retval = std::max((unsigned int)8, useablespace / oneentry);
+ if (StorageLayout::DefaultIndexSize != 0)
+ retval = StorageLayout::DefaultIndexSize;
+
+ LEAVE( "DBHierIndex::getOptimalSize() - maxSize=" << retval );
+ RMDBGONCE(4, RMDebug::module_indexif, "DBHierIndex", "getOptimalSize(" << dim << ") maxSize " << retval)
+ return retval;
+ }
+
+unsigned int
+DBHierIndex::getOptimalSize() const
+ {
+ TALK( "DBHierIndex::getOptimalSize() -> " << maxSize );
+ return maxSize;
+ }
+
+r_Minterval
+DBHierIndex::getAssignedDomain() const
+ {
+ TALK( "DBHierIndex::getAssignedDomain() -> " << myDomain );
+ return myDomain;
+ }
+
+void
+DBHierIndex::setAssignedDomain(const r_Minterval& newDomain)
+ {
+ RMDBGENTER(7, RMDebug::module_indexif, "DBHierIndex", "setAssignedDomain(" << newDomain << ") " << myOId);
+ ENTER( "DBHierIndex::setAssignedDomain() - newDomain=" << newDomain << ", myOId=" << myOId );
+
+ myDomain = newDomain;
+ setModified();
+
+ LEAVE( "DBHierIndex::setAssignedDomain()" );
+ RMDBGEXIT(7, RMDebug::module_indexif, "DBHierIndex", "setAssignedDomain(" << newDomain << ") " << myOId);
+ }
+
+void
+DBHierIndex::extendCoveredDomain(const r_Minterval& newTilesExtents) throw (r_Edim_mismatch, r_Eno_interval)
+ {
+ RMDBGENTER(7, RMDebug::module_indexif, "DBHierIndex", "extendCoveredDomain(" << newTilesExtents << ") " << myOId);
+ ENTER( "DBHierIndex::extendCoveredDomain() - newTilesExtents=" << newTilesExtents << ", myOId=" << myOId );
+
+ myDomain.closure_with(newTilesExtents);
+ setModified();
+
+ LEAVE( "DBHierIndex::extendCoveredDomain()" );
+ RMDBGEXIT(7, RMDebug::module_indexif, "DBHierIndex", "extendCoveredDomain(" << newTilesExtents << ") " << myOId);
+ }
+
+void
+DBHierIndex::setParent(const HierIndexDS* newPa)
+ {
+ RMDBGENTER(7, RMDebug::module_indexif, "DBHierIndex", "setParent(" << OId(newPa->getIdentifier()) << ") " << myOId);
+ ENTER( "DBHierIndex::setParent() - newPa=" << newPa << ", myOId=" << myOId );
+
+ if ((OId::OIdPrimitive)parent != newPa->getIdentifier())
+ {
+ parent = newPa->getIdentifier();
+ setModified();
+ }
+
+ LEAVE( "DBHierIndex::setParent()" );
+ RMDBGEXIT(7, RMDebug::module_indexif, "DBHierIndex", "setParent(" << OId(newPa->getIdentifier()) << ") " << myOId);
+ }
+
+HierIndexDS*
+DBHierIndex::getParent() const
+ {
+ RMDBGONCE(7, RMDebug::module_indexif, "DBHierIndex", "getParent() const " << myOId << " " << parent << " " << parent);
+ ENTER( "DBHierIndex::getParent() - myOId=" << myOId << ", parent=" << parent );
+
+ DBHierIndexId t(parent);
+
+ LEAVE( "DBHierIndex::getParent() - t=" << t );
+ return (HierIndexDS*)t;
+ }
+
+bool
+DBHierIndex::isRoot() const
+ {
+ RMDBGONCE(7, RMDebug::module_indexif, "DBHierIndex", "isRoot() const " << myOId << " " << (int)(parent.getType() == OId::INVALID));
+ TALK( "DBHierIndex::isRoot() -> " << (parent.getType() == OId::INVALID) );
+ return (parent.getType() == OId::INVALID);
+ }
+
+bool
+DBHierIndex::isLeaf() const
+ {
+ RMDBGONCE(7, RMDebug::module_indexif, "DBHierIndex", "isLeaf() const " << myOId << " " << (int)(!_isNode));
+ TALK( "DBHierIndex::isLeaf() -> " << !_isNode );
+ return !_isNode;
+ }
+
+void
+DBHierIndex::setIsNode(bool isNodea)
+ {
+ RMDBGONCE(7, RMDebug::module_indexif, "DBHierIndex", "setIsNode(" << isNodea << ") " << myOId << " was " << _isNode);
+ TALK( "DBHierIndex::setIsNode() - isNodea=" << isNodea );
+ _isNode = isNodea;
+ }
+
+void
+DBHierIndex::freeDS()
+ {
+ TALK( "DBHierIndex::freeDS()" );
+ setPersistent(false);
+ }
+bool
+DBHierIndex::isSameAs(const IndexDS* other) const
+ {
+ ENTER( "DBHierIndex::isSameAs() - other=" << other );
+
+ bool result = false;
+ if (other->isPersistent())
+ if (myOId == other->getIdentifier())
+ result = true;
+
+ LEAVE( "DBHierIndex::isSameAs() -> " << result );
+ return result;
+ }
+
+
+double
+DBHierIndex::getOccupancy() const
+ {
+ cout << "DBHierIndex::getOccupancy() const NOT IMPLEMENTED" << std::endl;
+ TALK( "DBHierIndex::getOccupancy() NOT IMPLEMENTED" );
+ return 0;
+ }
+
+const KeyObject&
+DBHierIndex::getObject(unsigned int pos) const
+ {
+ RMDBGONCE(4, RMDebug::module_indexif, "DBHierIndex", "getObject(" << pos << ") " << myOId << " " << myKeyObjects[pos]);
+ TALK( "DBHierIndex::getObject() - pos=" << pos << ", myOId=" << myOId << " -> " << myKeyObjects[pos] );
+
+ return myKeyObjects[pos];
+ }
+
+void
+DBHierIndex::getObjects(KeyObjectVector& objs) const
+ {
+ RMDBGENTER(4, RMDebug::module_indexif, "DBHierIndex", "getObjects() " << myOId);
+ ENTER( "DBHierIndex::getObjects() - myOId=" << myOId );
+
+ for (KeyObjectVector::const_iterator keyIt = myKeyObjects.begin(); keyIt != myKeyObjects.end(); keyIt++)
+ {
+ objs.push_back(*keyIt);
+ }
+
+ LEAVE( "DBHierIndex::getObjects() - size=" << objs.size() );
+ RMDBGEXIT(4, RMDebug::module_indexif, "DBHierIndex", "getObjects() " << myOId << " vec.size " << objs.size());
+ }
+
+r_Minterval
+DBHierIndex::getObjectDomain(unsigned int pos) const
+ {
+ RMDBGONCE(4, RMDebug::module_indexif, "DBHierIndex", "getObjectDomain(" << pos << ") " << myOId << " " << myKeyObjects[pos]);
+ TALK( "DBHierIndex::getObjectDomain() - pos=" << pos << ", myOId=" << myOId << " -> " << myKeyObjects[pos] );
+ return myKeyObjects[pos].getDomain();
+ }
+
+unsigned int
+DBHierIndex::getHeight() const
+ {
+ TALK( "DBHierIndex::getHeight() -> " << getHeightToLeaf() );
+ return getHeightToLeaf();
+ }
+
+unsigned int
+DBHierIndex::getHeightOfTree() const
+ {
+ ENTER( "DBHierIndex::getHeightOfTree() - myOId=" << myOId );
+
+ unsigned int retval = getHeightToLeaf() + getHeightToRoot();
+
+ LEAVE( "DBHierIndex::getHeightOfTree() -> " << retval );
+ RMDBGONCE(7, RMDebug::module_indexif, "DBHierIndex", "getHeightOfTree() const " << myOId << " " << retval);
+ return retval;
+ }
+
+unsigned int
+DBHierIndex::getHeightToRoot() const
+ {
+ ENTER( "DBHierIndex::getHeightToRoot() - myOId=" << myOId );
+
+ unsigned int retval = 0;
+ if (isRoot())
+ retval = 0;
+ else {
+ DBHierIndexId t(parent);
+ const DBHierIndex* tp = (DBHierIndex*)t.ptr();
+ retval = tp->getHeightToRoot() + 1;
+ }
+
+ LEAVE( "DBHierIndex::getHeightToRoot() -> " << retval );
+ RMDBGONCE(7, RMDebug::module_indexif, "DBHierIndex", "getHeightToRoot() const " << myOId << " " << retval);
+ return retval;
+ }
+
+unsigned int
+DBHierIndex::getHeightToLeaf() const
+ {
+ ENTER( "DBHierIndex::getHeightToLeaf() - myOId=" << myOId );
+
+ unsigned int retval = 0;
+ if (isLeaf())
+ retval = 0;
+ else {
+ DBHierIndexId t(parent);
+ const DBHierIndex* tp = (DBHierIndex*)t.ptr();
+ retval = tp->getHeightToLeaf() + 1;
+ }
+
+ LEAVE( "DBHierIndex::getHeightToLeaf() -> " << retval );
+ RMDBGONCE(7, RMDebug::module_indexif, "DBHierIndex", "getHeightToLeaf() const " << myOId << " " << retval);
+ return retval;
+ }
+
+unsigned int
+DBHierIndex::getTotalLeafCount() const
+ {
+ RMDBGENTER(7, RMDebug::module_indexif, "DBHierIndex", "getTotalLeafCount() const " << myOId);
+ ENTER( "DBHierIndex::getTotalLeafCount() - myOId=" << myOId );
+
+ unsigned int retval = 0;
+ if (!isLeaf())
+ {
+ //i am not a leaf
+ if (DBHierIndexId(myKeyObjects.begin()->getObject())->isLeaf())
+ {
+ //i contain only leafs, so i return the number of entries i contain
+ retval = getSize();
+ }
+ else {
+ //i contain only nodes, so i ask my children how many leafs there are
+ for (KeyObjectVector::const_iterator keyIt = myKeyObjects.begin(); keyIt != myKeyObjects.end(); keyIt++)
+ {
+ DBHierIndexId accessedIx((*keyIt).getObject());
+ retval = retval + accessedIx->getTotalLeafCount();
+ }
+ }
+ }
+ else {
+ retval = 1;
+ }
+
+ LEAVE( "DBHierIndex::getTotalLeafCount() -> " << retval );
+ RMDBGEXIT(7, RMDebug::module_indexif, "DBHierIndex", "getTotalLeafCount() const " << myOId << " " << retval);
+ return retval;
+ }
+
+unsigned int
+DBHierIndex::getTotalNodeCount() const
+ {
+ RMDBGENTER(7, RMDebug::module_indexif, "DBHierIndex", "getTotalNodeCount() const " << myOId);
+ ENTER( "DBHierIndex::getTotalNodeCount() - myOId=" << myOId );
+
+ unsigned int retval = 0;
+ if (!isLeaf())
+ {
+ //i am not a leaf
+ if (DBHierIndexId(myKeyObjects.begin()->getObject())->isLeaf())
+ {
+ //i contain only nodes
+ //i add the nodes i contain
+ retval = getSize();
+ //i add the nodes my children contain
+ for (KeyObjectVector::const_iterator keyIt = myKeyObjects.begin(); keyIt != myKeyObjects.end(); keyIt++)
+ {
+ DBHierIndexId accessedIx((*keyIt).getObject());
+ retval = retval + accessedIx->getTotalNodeCount();
+ }
+ }
+ }
+ //else : a leaf does not contain nodes
+
+ LEAVE( "DBHierIndex::getTotalNodeCount() -> " << retval );
+ RMDBGEXIT(7, RMDebug::module_indexif, "DBHierIndex", "getTotalNodeCount() const " << myOId << " " << retval);
+ return retval;
+ }
+
+unsigned int
+DBHierIndex::getTotalEntryCount() const
+ {
+ RMDBGENTER(7, RMDebug::module_indexif, "DBHierIndex", "getTotoalEntryCount() const " << myOId);
+ ENTER( "DBHierIndex::getTotalEntryCount() - myOId=" << myOId );
+
+ unsigned int retval = 0;
+ if (isLeaf())
+ {
+ //i contain only entries
+ //i return the number of entries i contain
+ retval = getSize();
+ }
+ else {
+ //i contain only nodes, no entries
+ //i ask my children how many entries they contain
+ for (KeyObjectVector::const_iterator keyIt = myKeyObjects.begin(); keyIt != myKeyObjects.end(); keyIt++)
+ {
+ DBHierIndexId accessedIx((*keyIt).getObject());
+ retval = retval + accessedIx->getTotalEntryCount();
+ }
+ }
+
+ LEAVE( "DBHierIndex::getTotalEntryCount() -> " << retval );
+ RMDBGEXIT(7, RMDebug::module_indexif, "DBHierIndex", "getTotoalEntryCount() const " << myOId << " " << retval);
+ return retval;
+ }
+
+void
+DBHierIndex::destroy()
+ {
+ TALK( "DBObject::destroy()" );
+ DBObject::destroy();
+ }
+
+DBHierIndex::~DBHierIndex()
+ {
+ RMDBGENTER(7, RMDebug::module_indexif, "DBHierIndex", "~DBHierIndex() " << myOId);
+ ENTER( "DBHierIndex::~DBHierIndex() - myOId=" << myOId );
+
+ validate();
+ currentDbRows = 0;
+ parent = OId(0);
+ myKeyObjects.clear();
+ myDomain = (InlineMinterval) NULL;
+ maxSize = 0;
+ _isNode = true;
+
+ LEAVE( "DBHierIndex::~DBHierIndex()" );
+ RMDBGEXIT(7, RMDebug::module_indexif, "DBHierIndex", "~DBHierIndex() " << myOId);
+ }
+
+/*
+Encoding:
+name :
+ type_oid.raw
+value :
+ common
+ 1 byte version
+ 1 byte endianness
+ 2 bytes type
+ 4 bytes oid
+ 1 byte flags
+ 2 byte reserved
+ special
+ 4 bytes size
+ 2 bytes dimension
+ 8 bytes parent oid
+ 1 byte subtype
+ x bytes database layout
+*/
+
+BinaryRepresentation
+DBHierIndex::getBinaryRepresentation() const throw (r_Error)
+ {
+ ENTER( "DBHierIndex::getBinaryRepresentation()" );
+
+ BinaryRepresentation brp;
+ brp.binaryName = getBinaryName();
+ brp.binaryData = NULL;
+ brp.binaryLength = 0;
+ short dimension2 = myDomain.dimension();
+ size_t size2 = myKeyObjects.size();
+ short subtype = _isNode;
+ double parentid2 = 0;
+
+ if (parent.getType() == OId::INVALID)
+ parentid2 = 0;
+ else
+ parentid2 = parent;
+
+ //INSERTINTO
+
+ //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
+ r_Bytes completesize = boundssize * 2 + fixessize * 2 + idssize + typessize;
+
+ char* completebuffer = new char[completesize];
+ r_Range* upperboundsbuf = new r_Range[boundssize];
+ r_Range* lowerboundsbuf = new r_Range[boundssize];
+ char* upperfixedbuf = new char[fixessize];
+ char* lowerfixedbuf = new char[fixessize];
+ OId::OIdCounter* entryidsbuf = new OId::OIdCounter[idssize];
+ char* entrytypesbuf = new char[typessize];
+
+ RMDBGMIDDLE(8, RMDebug::module_indexif, "DBHierIndex", "complete " << completesize << " bounds " << boundssize << " fixes " << fixessize << " ids " << idssize << " types " << typessize);
+
+ //counter which keeps track of the bytes that have been written to the db
+ r_Bytes byteswritten = 0;
+ //counter which keeps track of the bytes that have to be written to the db
+ r_Bytes bytestowrite = 0;
+
+ 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::const_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
+ //this indirection is neccessary because of memory alignement of longs...
+ memcpy(completebuffer, lowerboundsbuf, boundssize);
+ delete [] lowerboundsbuf;
+ memcpy(&completebuffer[boundssize], upperboundsbuf, boundssize);
+ delete [] upperboundsbuf;
+ memcpy(&completebuffer[boundssize * 2], lowerfixedbuf, fixessize);
+ delete [] lowerfixedbuf;
+ memcpy(&completebuffer[boundssize * 2 + fixessize], upperfixedbuf, fixessize);
+ delete [] upperfixedbuf;
+ memcpy(&completebuffer[boundssize * 2 + fixessize * 2], entryidsbuf, idssize);
+ delete [] entryidsbuf;
+ memcpy(&completebuffer[boundssize * 2 + fixessize * 2 + idssize], entrytypesbuf, typessize);
+ delete [] entrytypesbuf;
+
+/*
+ 5 bytes tag
+ 1 byte version
+ 1 byte endianness
+ 8 bytes oid
+*/
+ //version + endianness + oid + size + dimension + parentoid + subtype
+ brp.binaryLength = 7 + sizeof(double) + sizeof(int) + sizeof(short) + sizeof(double) + sizeof(char) + completesize;
+ brp.binaryData = new char[brp.binaryLength];
+ memcpy(brp.binaryData, BinaryRepresentation::fileTag, 5);
+ memset(&brp.binaryData[5], 1, 1);
+ if (r_Endian::get_endianness() == r_Endian::r_Endian_Little)
+ {
+ memset(&brp.binaryData[6], 1, 1);
+ }
+ else {
+ memset(&brp.binaryData[6], 0, 1);
+ }
+ double tempd = myOId;
+ memcpy(&brp.binaryData[7], &tempd, sizeof(double));
+/*
+ special
+ 4 bytes size
+ 2 bytes dimension
+ 8 bytes parent oid
+ 1 byte subtype
+ x bytes database layout
+*/
+ int tempi = size2;
+ memcpy(&brp.binaryData[7 + sizeof(double)], &tempi, sizeof(int));
+ short temps = dimension2;
+ memcpy(&brp.binaryData[7 + sizeof(double) + sizeof(int)], &temps, sizeof(short));
+ memcpy(&brp.binaryData[7 + sizeof(double) + sizeof(int) + sizeof(short)], &parentid2, sizeof(double));
+ char tempc = subtype;
+ memcpy(&brp.binaryData[7 + sizeof(double) + sizeof(int) + sizeof(short) + sizeof(double)], &tempc, sizeof(char));
+ memcpy(&brp.binaryData[7 + sizeof(double) + sizeof(int) + sizeof(short) + sizeof(double) + sizeof(char)], completebuffer, completesize);
+
+ delete [] completebuffer;
+
+ LEAVE( "DBHierIndex::getBinaryRepresentation()" );
+ return brp;
+ }
+
+void
+DBHierIndex::setBinaryRepresentation(const BinaryRepresentation& brp) throw (r_Error)
+ {
+ ENTER( "DBHierIndex::setBinaryRepresentation()" );
+
+ if (memcmp(brp.binaryData, BinaryRepresentation::fileTag, 5) != 0)
+ {
+ RMInit::logOut << "DBHierIndex::setBinaryRepresentation(brp:" << brp.binaryName << ") not a correct data set " << brp.binaryData << endl;
+ throw r_Error();
+ }
+ if (brp.binaryData[5] != 1)
+ {
+ RMInit::logOut << "DBHierIndex::setBinaryRepresentation(brp:" << brp.binaryName << ") not unknown export version " << (int)brp.binaryData[5] << endl;
+ throw r_Error();
+ }
+ if (brp.binaryData[6] != (r_Endian::get_endianness() == r_Endian::r_Endian_Little))
+ {
+ RMInit::logOut << "DBHierIndex::setBinaryRepresentation(brp:" << brp.binaryName << ") endianess conversion not supported" << endl;
+ throw r_Error();
+ }
+ size_t size1;
+ short dimension1;
+ double parentid1;
+ int tempi;
+ short temps;
+ char tempc;
+ double tempd;
+
+ memcpy((char*)&tempd, &brp.binaryData[7], sizeof(double));
+ myOId = tempd;
+ char* temp = getBinaryName();
+ if (strcmp(temp, brp.binaryName) != 0)
+ {
+ RMInit::logOut << "DBHierIndex::setBinaryRepresentation(brp:" << brp.binaryName << ") my name should be " << temp << endl;
+ delete [] temp;
+ throw r_Error();
+ }
+ delete [] temp;
+ temp = NULL;
+ memcpy(&tempi, &brp.binaryData[7 + sizeof(double)], sizeof(int));
+ size1 = tempi;
+ memcpy(&temps, &brp.binaryData[7 + sizeof(double) + sizeof(int)], sizeof(short));
+ dimension1 = temps;
+ memcpy(&parentid1, &brp.binaryData[7 + sizeof(double) + sizeof(int) + sizeof(short)], sizeof(double));
+ memcpy(&tempc, &brp.binaryData[7 + sizeof(double) + sizeof(int) + sizeof(short) + sizeof(double)], sizeof(char));
+ _isNode = tempc;
+
+ 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
+ r_Bytes completesize = boundssize * 2 + fixessize * 2 + idssize + typessize;
+
+ RMDBGMIDDLE(8, RMDebug::module_indexif, "DBHierIndex", "size " << size1 << " dimension " << dimension1 << " fixes " << fixessize << " ids " << idssize << " types " << typessize);
+ TALK( "DBHierIndex::setBinaryRepresentation(): size=" << size1 << ", dimension=" << dimension1 << ", fixes=" << fixessize << ", ids=" << idssize << ", types=" << typessize );
+
+ char* completebuffer = new char[completesize];
+ r_Range* upperboundsbuf = new r_Range[boundssize];
+ r_Range* lowerboundsbuf = new r_Range[boundssize];
+ char* upperfixedbuf = new char[fixessize];
+ char* lowerfixedbuf = new char[fixessize];
+ OId::OIdCounter* entryidsbuf = new OId::OIdCounter[idssize];
+ char* entrytypesbuf = new char[typessize];
+ memcpy(completebuffer, &brp.binaryData[7 + sizeof(double) + sizeof(int) + sizeof(short) + sizeof(double) + sizeof(char)], completesize);
+
+ //all dynamic data is in completebuffer
+ //put that stuff in the correct buffers
+ memcpy(lowerboundsbuf, completebuffer, boundssize);
+ memcpy(upperboundsbuf, &completebuffer[boundssize], boundssize);
+ memcpy(lowerfixedbuf, &completebuffer[boundssize * 2], fixessize);
+ memcpy(upperfixedbuf, &completebuffer[boundssize * 2 + fixessize], fixessize);
+ memcpy(entryidsbuf, &completebuffer[boundssize * 2 + fixessize * 2], idssize);
+ memcpy(entrytypesbuf, &completebuffer[boundssize * 2 + fixessize * 2 + idssize], typessize);
+ //all dynamic data is in its buffer
+ delete [] completebuffer;
+ completebuffer = NULL;
+ int i = 0;
+ //rebuild the attributes from the buffers
+ 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])));
+ }
+
+ delete [] upperboundsbuf;
+ delete [] lowerboundsbuf;
+ delete [] upperfixedbuf;
+ delete [] lowerfixedbuf;
+ delete [] entryidsbuf;
+ delete [] entrytypesbuf;
+ _isInDatabase = true;
+ _isPersistent = true;
+ _isModified = true;
+ currentDbRows = 1;
+
+ LEAVE( "DBHierIndex::setBinaryRepresentation()" );
+ }
+
diff --git a/relindexif/indexid.hh b/relindexif/indexid.hh
new file mode 100644
index 0000000..be9b0b5
--- /dev/null
+++ b/relindexif/indexid.hh
@@ -0,0 +1,37 @@
+/*
+* 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>.
+*/
+#ifndef _INDEXID_HH_
+#define _INDEXID_HH_
+
+class DBHierIndex;
+class DBTCIndex;
+//class DBIndexDS;
+class DBRCIndexDS;
+
+template <class T> class DBRef;
+
+typedef DBRef<DBHierIndex> DBHierIndexId;
+typedef DBRef<DBTCIndex> DBTCIndexId;
+typedef DBRef<DBRCIndexDS> DBRCIndexDSId;
+//typedef DBRef<DBIndexDS> DBIndexDSId;
+#endif
diff --git a/relindexif/test/Makefile b/relindexif/test/Makefile
new file mode 100644
index 0000000..b21e636
--- /dev/null
+++ b/relindexif/test/Makefile
@@ -0,0 +1,97 @@
+# -*-Makefile-*-
+#
+# 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>. # Top Level makefile. This points to the various modules that have to be build
+# and/or deployed
+#
+
+# MAKEFILE FOR:
+# test programs of module relindexif
+#
+#
+# COMMENTS:
+# List environment dependencies, known bugs, specialities etc.
+#
+########################################################################
+
+# standard include with general options
+include $(RMANBASE)/Makefile.inc
+
+CPPSOURCES = testindex.c
+
+# Not needed if BASEDB flag correctly set
+INDEXIF = $(RELINDEXIF)
+
+# all test programs
+ALLTESTS = testindex
+
+# Needed RasDaMan libraries for linking. To be copmpleted.
+#NEEDEDLIBS = $(CACHETAMGR) $(QLPARSER) $(INDEXMGR) $(RELADMINIF) $(RELMDDIF) $(RELBLOBIF) $(RELINDEXIF) $(CACHETAMGR) $(RELCATALOGIF) $(RASLIB) $(RELADMINIF) $(RELMDDIF)
+NEEDEDLIBS = $(RASLIB) $(CLIENTCOMM)
+
+MISCCLEAN := client.bm client.dbg client.log ir.out core
+OBJS := testindex.o miteratest.o
+# some additional flags for compiling and linking
+
+
+############################## Targets #################################
+
+# make all tests
+.PHONY: test
+test: $(ALLTESTS)
+
+# delete object and test programs
+.PHONY: clean
+clean:
+ -rm $(ALLTESTS)
+ -rm *.c
+ -rm *.o
+
+# deletes all non modified, but checked out files
+.PHONY: rcsclean
+rcsclean:
+ -rcsclean
+
+########################### Dependencies ###############################
+
+
+# make all tests
+.PHONY: test
+test: $(ALLTESTS)
+
+# See reladminif/test/Makefile for an example of how to add
+# here test files.
+
+testindex : testindex.o
+testindex.o : testindex.c
+testindex.c : testindex.pc
+
+miteratest : miteratest.o
+ $(PURIFY) $(CXX) $(LDFLAGS) -o miteratest miteratest.o $(RASLIB) ../../mymalloc/mymalloc_cln.o
+miteratest.o : miteratest.cc
+ $(CXX) -c $(CPPFLAGS) $(CXXFLAGS) $<
+
+computeindex : computedindex.o
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ wurzelprungt
+computeindex.o : computedindex.cc
+ $(CXX) -c $(CPPFLAGS) -mt $(CXXFLAGS) $< asdlfkajsd
+
+
diff --git a/relindexif/test/computedindex.cc b/relindexif/test/computedindex.cc
new file mode 100644
index 0000000..0a63254
--- /dev/null
+++ b/relindexif/test/computedindex.cc
@@ -0,0 +1,109 @@
+/*
+* 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 <iostream>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "raslib/rmdebug.hh"
+#include "raslib/rminit.hh"
+#include "raslib/minterval.hh"
+
+RMINITGLOBALS('C')
+
+/*
+ You need to know the defined domain:
+ check if the tile config fits the defined domain
+ check if the requested/inserted tile fits into the defined domain
+ You need to know the tile config:
+ check if the inserted tile has the proper domain
+ You need to know the normalized domain:
+ it is translated to the origin
+ its extent is divided by the extent of the tile config
+ You request a point in the index:
+ the point is translated to the normalized domain
+ the point is normalized (divided by the tile config extent)
+ you get the cell offset of this point from the normalized domain
+ you add the base counter to the cell offset
+ You request a domain in the index
+ the domain is translated to the normalized domain
+ the domain is normalized (divided by the tile config extent)
+ for each point in the resulting domain you do a point query
+*/
+
+r_Minterval
+createNormalizedDomain(const r_Point& mddDomainExtent, const r_Point& tileConfigExtent)
+ {
+ r_Dimension theDim = mddDomainExtent.dimension();
+ r_Minterval normalizedDomain(theDim);
+ r_Range normalized = 0;
+
+ for (r_Dimension dim = 0; dim < theDim; dim++)
+ {
+ normalized = (r_Range)(mddDomainExtent[dim]/tileConfigExtent[dim]) - 1;
+ cout << "mdd domain extent [" << dim << "] " << mddDomainExtent[dim] << endl;
+ cout << "tile config extent [" << dim << "] " << tileConfigExtent[dim] << endl;
+ cout << "division " << mddDomainExtent[dim]/tileConfigExtent[dim] << endl;
+ if ((normalized + 1)* tileConfigExtent[dim] != mddDomainExtent[dim])
+ {
+ cout << "got you" << endl;
+ }
+ normalizedDomain[dim] = r_Sinterval(0, normalized);
+ }
+ return normalizedDomain;
+ }
+
+r_Point
+createNormalizedPoint(const r_Point& toNormalize, const r_Point& tileConfigExtent, const r_Point& mddDomainOrigin)
+ {
+ r_Dimension theDim = mddDomainOrigin.dimension();
+ r_Point normalizedPoint(theDim);
+
+ for (r_Dimension dim = 0; dim < theDim; dim++)
+ {
+ normalizedPoint[dim] = (r_Range)((toNormalize[dim] - mddDomainOrigin[dim])/tileConfigExtent[dim]);
+ }
+ return normalizedPoint;
+ }
+
+void
+main(unsigned int argc, const char** argv)
+ {
+ unsigned int baseCounter = 0;
+ unsigned int entryType = 0;
+ r_Area index = 0;
+
+ r_Minterval tileConfig("[0:1,0:2]");
+
+ r_Minterval mddDomain("[10:21,0:11]");
+
+ r_Point whereToSearch("[11,9]");
+
+ r_Minterval normalizedDomain = createNormalizedDomain(mddDomain.get_extent(), tileConfig.get_extent());
+ cout << "normalized domain " << normalizedDomain << endl;
+
+ r_Point normalizedSearch = createNormalizedPoint(whereToSearch, tileConfig.get_extent(), mddDomain.get_origin());
+ cout << "normalized search " << normalizedSearch << endl;
+ cout << "index of search point " << normalizedDomain.cell_offset(normalizedSearch) << endl;
+
+ }
+
diff --git a/relindexif/test/exportindex.cc b/relindexif/test/exportindex.cc
new file mode 100644
index 0000000..1e4e45b
--- /dev/null
+++ b/relindexif/test/exportindex.cc
@@ -0,0 +1,234 @@
+/*
+* 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>.
+*/
+/*
+get mddoid, iterate domain, dataformat
+
+select mdd
+get domain
+ {
+ begin ta
+ iterate over domain
+ retrieve tiles
+ alter tiles
+ commit ta
+ }
+*/
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#include "server/template_inst.hh"
+#endif
+
+#include "reladminif/adminif.hh"
+#include "reladminif/databaseif.hh"
+#include "reladminif/transactionif.hh"
+#include "reladminif/oidif.hh"
+#include "cmlparser.hh"
+#include "relindexif/indexid.hh"
+
+#define ALLDONE 0
+#define ERRORPARSINGCOMMANDLINE 1
+#define DOMAINMISSING 2
+#define OIDMISSING 3
+#define OIDINVALID 4
+#define DOMAINMISMATCH 5
+#define FAILED 6
+#define DOMAININVALID 7
+#define UNKNOWNDATAFORMAT 8
+
+char globalConnectId[256];
+
+RMINITGLOBALS('S')
+
+r_Minterval domain;
+OId oid;
+
+int
+main(int argc, char** argv)
+ {
+ RMInit::logOut.rdbuf(cout.rdbuf());
+ RMInit::dbgOut.rdbuf(cout.rdbuf());
+ int retval = 0;
+ bool import = false;
+ const char* fileName = NULL;
+ CommandLineParser &cmlInter = CommandLineParser::getInstance();
+ CommandLineParameter &clp_help = cmlInter.addFlagParameter('h', "help", "show command line switches");
+ CommandLineParameter &clp_import = cmlInter.addStringParameter('i', "import", "import data");
+
+ CommandLineParameter &clp_connect = cmlInter.addStringParameter(CommandLineParser::noShortName, "connect", "database connect string", "/");
+ CommandLineParameter &clp_oid = cmlInter.addStringParameter(CommandLineParser::noShortName, "oid", "the oid of the mdd to operate on");
+ try {
+ cmlInter.processCommandLine(argc, argv);
+ }
+ catch(CmlException& err)
+ {
+ cmlInter.printHelp();
+ cout << "Error parsing command line:" << endl;
+ cout << err.what() << endl;
+ return ERRORPARSINGCOMMANDLINE;
+ }
+ if (cmlInter.isPresent('h'))
+ {
+ cmlInter.printHelp();
+ return ALLDONE;
+ }
+ if (cmlInter.isPresent("oid"))
+ {
+ oid = OId(atol(cmlInter.getValueAsString("oid")));
+ if (oid.getType() != OId::MDDHIERIXOID)
+ {
+ cout << "oid is not a mdd oid" << endl;
+ return OIDINVALID;
+ }
+ }
+ else {
+ if (cmlInter.isPresent('i'))
+ {
+ import = true;
+ fileName = cmlInter.getValueAsString('i');
+ }
+ else {
+ cout << "oid is missing" << endl;
+ return OIDMISSING;
+ }
+ }
+ strcpy((char*)globalConnectId, cmlInter.getValueAsString("connect"));
+ cout << "connect " << globalConnectId << endl;
+ cout << "set up done" << endl;
+ AdminIf::instance();
+ DatabaseIf d;
+ TransactionIf t;
+ if (import)
+ {
+ std::ifstream i;
+ i.open(fileName);
+ if (i.is_open())
+ {
+ i.seekg(0, std::ios::end);
+ std::streampos end = i.tellg();
+ size_t length = end;
+ BinaryRepresentation brp;
+ brp.binaryLength = length;
+ brp.binaryName = new char[strlen(fileName) + 1];
+ memcpy(brp.binaryName, fileName, strlen(fileName) + 1);
+ brp.binaryData = new char[length];
+ i.seekg(0, std::ios::beg);
+ i.read(brp.binaryData, end);
+ i.close();
+ DBHierIndex* p = new DBHierIndex(0, false, false);
+ p->setBinaryRepresentation(brp);
+ delete [] brp.binaryData;
+ brp.binaryData = NULL;
+ delete [] brp.binaryName;
+ brp.binaryName = NULL;
+ p->printStatus();
+ try {
+ d.open("RASBASE");
+ t.begin(&d, false);
+ ObjectBroker::registerDBObject(p);
+ t.commit();
+ d.close();
+ }
+ catch (const r_Error& e)
+ {
+ cout << "Caught exception " << e.get_errorno() << " " << e.what() << endl;
+ try {
+ t.abort();
+ }
+ catch (const r_Error& ee)
+ {
+ cout << "Caugh exception while aborting " << ee.get_errorno() << " " << ee.what() << endl;
+ try {
+ t.abort();
+ }
+ catch (const r_Error& eee)
+ {
+ cout << "Caugh exception while 2nd aborting " << eee.get_errorno() << " " << eee.what() << endl;
+ }
+ }
+ try {
+ d.close();
+ }
+ catch (const r_Error& eeee)
+ {
+ cout << "Caugh exception while closing " << eeee.get_errorno() << " " << eeee.what() << endl;
+ }
+ return FAILED;
+ }
+ }
+ else {
+ cout << "Unable to open file " << fileName << endl;
+ }
+ }
+ else {
+ try {
+ d.open("RASBASE");
+ t.begin(&d, true);
+ DBHierIndexId index(oid);
+ BinaryRepresentation bin = index->getBinaryRepresentation();
+ index->printStatus();
+ std::ofstream o;
+ o.open(bin.binaryName);
+ if (o.is_open())
+ {
+ o.write(bin.binaryData, bin.binaryLength);
+ o.flush();
+ o.close();
+ }
+ else {
+ cout << "Unable to open file " << bin.binaryName << endl;
+ }
+ delete [] bin.binaryName;
+ delete [] bin.binaryData;
+ t.commit();
+ d.close();
+ }
+ catch (const r_Error& e)
+ {
+ cout << "Caught exception " << e.get_errorno() << " " << e.what() << endl;
+ try {
+ t.abort();
+ }
+ catch (const r_Error& ee)
+ {
+ cout << "Caugh exception while aborting " << ee.get_errorno() << " " << ee.what() << endl;
+ try {
+ t.abort();
+ }
+ catch (const r_Error& eee)
+ {
+ cout << "Caugh exception while 2nd aborting " << eee.get_errorno() << " " << eee.what() << endl;
+ }
+ }
+ try {
+ d.close();
+ }
+ catch (const r_Error& eeee)
+ {
+ cout << "Caugh exception while closing " << eeee.get_errorno() << " " << eeee.what() << endl;
+ }
+ return FAILED;
+ }
+ }
+ return retval;
+ }
diff --git a/relindexif/test/miteratest.cc b/relindexif/test/miteratest.cc
new file mode 100644
index 0000000..f76f461
--- /dev/null
+++ b/relindexif/test/miteratest.cc
@@ -0,0 +1,53 @@
+/*
+* 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 <iostream>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "raslib/rmdebug.hh"
+#include "raslib/rminit.hh"
+#include "raslib/minterval.hh"
+#include "raslib/mitera.hh"
+
+RMINITGLOBALS('C')
+
+
+void
+main(unsigned int argc, const char** argv)
+ {
+ r_Minterval indexDomain("[0:99,0:99]");
+ cout << "index " << indexDomain << endl;
+ r_Minterval iterationDomain("[0:0,0:0]");
+ cout << "iterd " << iterationDomain << endl;
+ r_Minterval iterationResult(2);
+ //r_MiterArea iter(&indexDomain, &iterationDomain);
+ r_MiterArea iter(&iterationDomain, &indexDomain);
+ unsigned int i = 0;
+ while (!iter.isDone())
+ {
+ i++;
+ cout << iter.nextArea() << endl;
+ }
+ cout << " i is " << i << endl;
+ }
+
diff --git a/relindexif/test/testindex.pc b/relindexif/test/testindex.pc
new file mode 100644
index 0000000..df867aa
--- /dev/null
+++ b/relindexif/test/testindex.pc
@@ -0,0 +1,262 @@
+/*
+* 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"
+#include <iostream>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "adminif.hh"
+#include "transactionif.hh"
+#include "databaseif.hh"
+#include "raslib/rmdebug.hh"
+#include "indexmgr/mddstorage.hh"
+#include "raslib/mddtypes.hh"
+#include "oidif.hh"
+#include "inlineminterval.hh"
+#include "externs.h"
+
+
+
+RMINITGLOBALS('C')
+
+unsigned int size = 0;
+r_Dimension dimension = 0;
+MDDStorage::IndexType myType = 0;
+int _isNode = 0;
+OId myOId = (double)0;
+OId parent = (double)0;
+
+void
+readFromDb()
+ {
+ RMDBGOUT(8, "(relindexif)" << "\tDBHierIndex::readFromDb() " << myOId);
+ EXEC SQL BEGIN DECLARE SECTION;
+ double id1;
+ double parentid1;
+ short indextype1;
+ long dimension1;
+ long size1;
+ short indexsubtype1;
+ short lowerfind;
+ struct {
+ short length;
+ char data[3990];
+ } dyndata1;
+ short dyndataind1;
+ EXEC SQL END DECLARE SECTION;
+
+ id1 = myOId;
+
+ EXEC SQL SELECT
+ IndexType,
+ NumEntries,
+ Dimension,
+ ParentOId,
+ IndexSubType
+ INTO
+ :indextype1,
+ :size1,
+ :dimension1,
+ :parentid1,
+ :indexsubtype1
+ FROM
+ RAS_HIERIX
+ WHERE
+ MDDObjIxOId = :id1;
+ if (SQLCODE != 0)
+ {
+ check("DBHierIndex::readFromDb() RAS_HIERIX\0");
+ if (SQLCODE == 100)
+ throw r_Error(r_Error::r_Error_ObjectUnknown);
+ else
+ throw r_Error(r_Error::r_Error_BaseDBMSFailed);
+ }
+
+ switch (indextype1)
+ {
+ case 0:
+ myType = MDDStorage::AutoIx;
+ break;
+ case 1:
+ myType = MDDStorage::DirTilesIx;
+ break;
+ case 2:
+ myType = MDDStorage::RegDirIx;
+ break;
+ case 3:
+ myType = MDDStorage::RPlusTreeNode;
+ break;
+ case 4:
+ myType = MDDStorage::RegRPlusTreeNode;
+ break;
+ default:
+ RMDBGOUT(0, "DBHierIndex::readFromDb() UNKNOWN INDEXTYPE " << indextype1 << "\t " << myOId << " " << myOId.getType());
+ break;
+ }
+ cout << "myType\t\t" << myType << endl;
+
+ size = size1;
+
+ cout << "size\t\t" << size << endl;
+
+ _isNode = indexsubtype1;
+
+ cout << "node\t\t" << _isNode << endl;
+
+ dimension = dimension1;
+
+ cout << "dimension\t\t" << dimension << endl;
+
+ if (parentid1)
+ parent = OId(parentid1);
+ else
+ parent = OId(0, OId::INVALID);
+
+ cout << "parent\t\t" << parent << " " << parent.getIdAsLong() << " " << parent.getType() << endl;
+
+ //number of bytes for bounds for "size" entries and mydomain
+ unsigned long boundssize = sizeof(r_Range) * (size + 1) * dimension;
+ //number of bytes for fixes for "size" entries and mydomain
+ unsigned long fixessize = sizeof(char) * (size + 1) * dimension;
+ //number of bytes for ids of entries
+ unsigned long idssize = sizeof(OId::Id) * size;
+ //number of bytes for types of entries
+ unsigned long typessize = sizeof(char) * size;
+ //number of bytes for the dynamic data
+ unsigned long completesize = 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::Id* entryidsbuf = (OId::Id*)mymalloc(idssize);
+ char* entrytypesbuf = (char*)mymalloc(typessize);
+
+ RMDBGOUT(8, "(relindexif)" << "\t\tcomplete " << completesize << " bounds " << boundssize << " fixes " << fixessize << " ids " << idssize << " types " << typessize);
+ //counter which keeps track of the bytes that have been read from the db
+ unsigned long bytesdone = 0;
+ //counter which keeps track of the bytes that have to be read from the db
+ unsigned long bytestogo = 0;
+
+ int i = 0;
+ currentDbRows = 0;
+
+ EXEC SQL DECLARE C CURSOR FOR
+ SELECT
+ DynData
+ FROM
+ RAS_HIERIXDYN
+ WHERE
+ MDDObjIxOId = :id1
+ ORDER BY
+ Count;
+
+ EXEC SQL OPEN C;
+
+ do {
+ EXEC SQL FETCH C INTO :dyndata1 :dyndataind1;
+ if (SQLCODE != 0)
+ {
+ if (SQLCODE != 100)
+ {
+ check("DBHierIndex::readFromDb() FETCH\0");
+ RMDBGOUT(7, "(relindexif)" << "\t\tSQLCODE " << SQLCODE);
+ free(upperboundsbuf);
+ free(lowerboundsbuf);
+ free(upperfixedbuf);
+ free(lowerfixedbuf);
+ free(entryidsbuf);
+ free(entrytypesbuf);
+ free(completebuffer);
+
+ throw r_Error(r_Error::r_Error_BaseDBMSFailed);
+ }
+ break;
+ }
+ RMDBGOUT(7, "(relindexif)" << "\t\tbytes allready read " << bytesdone << " bytes read now " << dyndata1.length);
+ memcpy(&completebuffer[bytesdone], dyndata1.data, dyndata1.length);
+ bytesdone = dyndata1.length + bytesdone;
+ currentDbRows = currentDbRows + 1;
+ }
+ while (1);
+
+ //all dynamic data is in completebuffer
+ //put that stuff in the correct buffers
+ memcpy(lowerboundsbuf, completebuffer, boundssize);
+ memcpy(upperboundsbuf, &completebuffer[boundssize], boundssize);
+ memcpy(lowerfixedbuf, &completebuffer[boundssize * 2], fixessize);
+ memcpy(upperfixedbuf, &completebuffer[boundssize * 2 + fixessize], fixessize);
+ memcpy(entryidsbuf, &completebuffer[boundssize * 2 + fixessize * 2], idssize);
+ memcpy(entrytypesbuf, &completebuffer[boundssize * 2 + fixessize * 2 + idssize], typessize);
+ //all dynamic data is in its buffer
+ free (completebuffer);
+
+ //rebuild the attributes from the buffers
+ myDomain = InlineMinterval(dimension, &(lowerboundsbuf[0]), &(upperboundsbuf[0]), &(lowerfixedbuf[0]), &(upperfixedbuf[i*dimension]));
+ cout << "myDomain\t\t" << myDomain << endl;
+
+ for (i = 0; i < size; i++)
+ {
+ domainList.push_back(InlineMinterval(dimension, &(lowerboundsbuf[(i+1)*dimension]), &(upperboundsbuf[(i+1)*dimension]), &(lowerfixedbuf[(i+1)*dimension]), &(upperfixedbuf[(i+1)*dimension])));
+ entryOIdList.push_back(OId(entryidsbuf[i], (OId::OIdType)entrytypesbuf[i]));
+ RMDBGOUT(8, "(relindexif)" << "\t\tentry " << entryidsbuf[i] << " " << (OId::OIdType)entrytypesbuf[i] << " at " << InlineMinterval(dimension, &(lowerboundsbuf[(i+1)*dimension]), &(upperboundsbuf[(i+1)*dimension]), &(lowerfixedbuf[(i+1)*dimension]), &(upperfixedbuf[(i+1)*dimension])));
+ }
+
+ free(upperboundsbuf);
+ free(lowerboundsbuf);
+ free(upperfixedbuf);
+ free(lowerfixedbuf);
+ free(entryidsbuf);
+ free(entrytypesbuf);
+ EXEC SQL CLOSE C;
+ RMDBGOUT(8, "(relindexif)" << "\t\tDBHierIndex::readFromDb() END " << myOId);
+ }
+
+int
+main(int argc, char** argv)
+ {
+ AdminIf* myAdmin = AdminIf::instance();
+ DatabaseIf database;
+ TransactionIf ta;
+
+ if (!myAdmin)
+ {
+ cout << "Error at connecting " << endl;
+ cout << "Goodbye "<< endl;
+ exit (-1);
+ }
+
+ if (!database.open("RASBASE"))
+ {
+ cout << "could not open database" << endl;
+ }
+ if (argc == 2)
+ {
+ myOId = (double)a2l(argv[1]);
+ cout << "myOId " << myOId << endl;
+ readFromDb();
+ }
+ }
+
+