diff options
Diffstat (limited to 'relindexif/hierindex.pgc')
-rw-r--r-- | relindexif/hierindex.pgc | 745 |
1 files changed, 745 insertions, 0 deletions
diff --git a/relindexif/hierindex.pgc b/relindexif/hierindex.pgc new file mode 100644 index 0000000..fa56b8b --- /dev/null +++ b/relindexif/hierindex.pgc @@ -0,0 +1,745 @@ +#include "mymalloc/mymalloc.h" + +/* +* This file is part of rasdaman community. +* +* Rasdaman community is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* Rasdaman community is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>. +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see <http://www.rasdaman.org> +* or contact Peter Baumann via <baumann@rasdaman.com>. +*/ +/************************************************************* + * + * + * PURPOSE: + * Code with embedded SQL for PostgreSQL DBMS + * + * + * COMMENTS: + * - blobs contain 13c as first byte; this is not required here, + * but kept for data compatibility with other base DBMSs. + * + ************************************************************/ + +// PG stuff: +#include "libpq-fe.h" /* C interface to PgSQL */ +#include "libpq/libpq-fs.h" /* large object (lo) api */ + +#include "debug-srv.hh" + +// general embedded SQL related definitions +EXEC SQL include "../reladminif/sqlglobals.h"; + +#include "hierindex.hh" +#include "raslib/rmdebug.hh" +#include "reladminif/sqlerror.hh" +#include "relblobif/blobtile.hh" +#include "indexmgr/keyobject.hh" + +// libpg connection maintenance +extern PGconn *pgConn; + +void +DBHierIndex::insertInDb() throw (r_Error) +{ + RMDBGENTER(5, RMDebug::module_indexif, "DBHierIndex", "insertInDb() " << myOId); + ENTER( "DBHierIndex::insertInDb(), myOId=" << myOId ); + +#ifdef NOTYET // should be in future +/* + EXEC SQL BEGIN DECLARE SECTION; +*/ +#endif // NOTYET + double id2; + long dimension2; + long size2; + double parentid2; + short indexsubtype2; + Oid blobOid; + char pgQuery[SQL_QUERY_BUFFER_SIZE]; // prelim + PGresult *pgResult = NULL; // prelim +#ifdef NOTYET // should be in future +/* + EXEC SQL END DECLARE SECTION; +*/ +#endif // NOTYET + + // (0) --- prepare variables + id2 = myOId; + dimension2 = myDomain.dimension(); + // size2 = myKeyObjects.size(); + size2 = getSize(); + indexsubtype2 = _isNode; + + if (parent.getType() == OId::INVALID) + parentid2 = 0; + else + parentid2 = parent; + + // (1) -- set all buffers + //number of bytes for bounds for "size" entries and mydomain + r_Bytes boundssize = sizeof(r_Range) * (size2 + 1) * dimension2; + //number of bytes for fixes for "size" entries and mydomain + r_Bytes fixessize = sizeof(char) * (size2 + 1) * dimension2; + //number of bytes for ids of entries + r_Bytes idssize = sizeof(OId::OIdCounter) * size2; + //number of bytes for types of entries + r_Bytes typessize = sizeof(char) * size2; + //number of bytes for the dynamic data, plus 1 starter byte (see below) + r_Bytes completesize = 1 + boundssize * 2 + fixessize * 2 + idssize + typessize; + + char* completebuffer = (char*)mymalloc(completesize); + if (completebuffer == NULL) + { + RMInit::logOut << "DBHierIndex::insertInDb() cannot malloc buffer" << endl; + LEAVE( "DBHierIndex::insertInDb() cannot malloc buffer" ); + throw r_Error( r_Error::r_Error_MemoryAllocation ); + } + r_Range* upperboundsbuf = (r_Range*)mymalloc(boundssize); + if (upperboundsbuf == NULL) + { + RMInit::logOut << "DBHierIndex::insertInDb() cannot malloc buffer" << endl; + LEAVE( "DBHierIndex::insertInDb() cannot malloc buffer" ); + throw r_Error( r_Error::r_Error_MemoryAllocation ); + } + r_Range* lowerboundsbuf = (r_Range*)mymalloc(boundssize); + if (lowerboundsbuf == NULL) + { + RMInit::logOut << "DBHierIndex::insertInDb() cannot malloc buffer" << endl; + LEAVE( "DBHierIndex::insertInDb() cannot malloc buffer" ); + throw r_Error( r_Error::r_Error_MemoryAllocation ); + } + char* upperfixedbuf = (char*)mymalloc(fixessize); + if (upperfixedbuf == NULL) + { + RMInit::logOut << "DBHierIndex::insertInDb() cannot malloc buffer" << endl; + LEAVE( "DBHierIndex::insertInDb() cannot malloc buffer" ); + throw r_Error( r_Error::r_Error_MemoryAllocation ); + } + char* lowerfixedbuf = (char*)mymalloc(fixessize); + if (lowerfixedbuf == NULL) + { + RMInit::logOut << "DBHierIndex::insertInDb() cannot malloc buffer" << endl; + LEAVE( "DBHierIndex::insertInDb() cannot malloc buffer" ); + throw r_Error( r_Error::r_Error_MemoryAllocation ); + } + OId::OIdCounter* entryidsbuf = (OId::OIdCounter*)mymalloc(idssize); + if (entryidsbuf == NULL) + { + RMInit::logOut << "DBHierIndex::insertInDb() cannot malloc buffer" << endl; + LEAVE( "DBHierIndex::insertInDb() cannot malloc buffer" ); + throw r_Error( r_Error::r_Error_MemoryAllocation ); + } + char* entrytypesbuf = (char*)mymalloc(typessize); + if (entrytypesbuf == NULL) + { + RMInit::logOut << "DBHierIndex::insertInDb() cannot malloc buffer" << endl; + LEAVE( "DBHierIndex::insertInDb() cannot malloc buffer" ); + throw r_Error( r_Error::r_Error_MemoryAllocation ); + } + + RMDBGMIDDLE(8, RMDebug::module_indexif, "DBHierIndex", "complete=" << completesize << " bounds=" << boundssize << " fixes=" << fixessize << " ids=" << idssize << " types=" << typessize << ", size=" << size2 << " dimension=" << dimension2 ); + + myDomain.insertInDb(&(lowerboundsbuf[0]), &(upperboundsbuf[0]), &(lowerfixedbuf[0]), &(upperfixedbuf[0])); + RMDBGMIDDLE(5, RMDebug::module_indexif, "DBHierIndex", "domain " << myDomain << " stored as " << InlineMinterval(dimension2, &(lowerboundsbuf[0]), &(upperboundsbuf[0]), &(lowerfixedbuf[0]), &(upperfixedbuf[0]))); + //populate the buffers with data + KeyObjectVector::iterator it = myKeyObjects.begin(); + InlineMinterval indom; + for (unsigned int i = 0; i < size2; i++, it++) + { + indom = (*it).getDomain(); + indom.insertInDb(&(lowerboundsbuf[(i+1)*dimension2]), &(upperboundsbuf[(i+1)*dimension2]), &(lowerfixedbuf[(i+1)*dimension2]), &(upperfixedbuf[(i+1)*dimension2])); + entryidsbuf[i] = (*it).getObject().getOId().getCounter(); + entrytypesbuf[i] = (char)(*it).getObject().getOId().getType(); + RMDBGMIDDLE(5, RMDebug::module_indexif, "DBHierIndex", "entry " << entryidsbuf[i] << " " << (OId::OIdType)entrytypesbuf[i] << " at " << InlineMinterval(dimension2, &(lowerboundsbuf[(i+1)*dimension2]), &(upperboundsbuf[(i+1)*dimension2]), &(lowerfixedbuf[(i+1)*dimension2]), &(upperfixedbuf[(i+1)*dimension2]))); + } + + // write the buffers in the complete buffer, free all unnecessary buffers + // this indirection is neccessary because of memory alignement of longs... + completebuffer[0] = 13; //the first char must not be a \0 + (void) memcpy( &completebuffer[1], lowerboundsbuf, boundssize); + free(lowerboundsbuf); + (void) memcpy( &completebuffer[boundssize + 1], upperboundsbuf, boundssize); + free(upperboundsbuf); + (void) memcpy( &completebuffer[boundssize * 2 + 1], lowerfixedbuf, fixessize); + free(lowerfixedbuf); + (void) memcpy( &completebuffer[boundssize * 2 + fixessize + 1], upperfixedbuf, fixessize); + free(upperfixedbuf); + (void) memcpy( &completebuffer[boundssize * 2 + fixessize * 2 + 1], entryidsbuf, idssize); + free(entryidsbuf); + (void) memcpy( &completebuffer[boundssize * 2 + fixessize * 2 + idssize + 1], entrytypesbuf, typessize); + free(entrytypesbuf); + +#ifdef RMANDEBUG // dump low-level blob byte string +{ + char printbuf[10000]; + (void) sprintf( printbuf, "XXX DBHierIndex::insertInDb(): [%d]", completesize ); + char bytebuf[3]; + for (unsigned int i = 0; i < completesize; i++) + { + (void) sprintf( bytebuf, " %2X", (unsigned char) completebuffer[i] ); + strcat( printbuf, bytebuf ); + } + TALK( printbuf ); +} +#endif // RMANDEBUG + + // (2) --- create, open, write, close blob; generates new 'oid' for subsequent storage in tuple + TALK( "lo_creat()" ); + blobOid = lo_creat( pgConn, INV_READ|INV_WRITE ); // create -- not clear what INV_* here means so indicate all + if (blobOid == 0) + { + RMInit::logOut << "DBHierIndex::insertInDb() cannot create blob, error: " << PQerrorMessage(pgConn) << endl; + LEAVE( "DBHierIndex::insertInDb(pgConn)" ); + generateException(); + } + TALK( "lo_open() for oid " << blobOid ); + int fd = lo_open( pgConn, blobOid, INV_WRITE ); // no error code indicated, 0 seems to be no error + TALK( "lo_write() for fd " << fd << " with " << completesize << " bytes" ); + int loResult = lo_write( pgConn, fd, completebuffer, completesize ); + if (loResult < 0) + { + RMInit::logOut << "DBHierIndex::insertInDb() cannot write blob, error: " << PQerrorMessage(pgConn) << endl; + LEAVE( "DBHierIndex::insertInDb() cannot write blob, error " << PQerrorMessage(pgConn) ); + generateException(); + } + else if (loResult != completesize) // did not get all + { + RMInit::dbgOut << "BLOB (" << myOId << ") insert: wrote " << loResult << " instead of " << completesize << " bytes" << endl; + LEAVE( "DBHierIndex::insertInDb() wrote " << loResult << " instead of " << completesize << " bytes" ); + generateException(); + } + TALK( "lo_close()" ); + loResult = lo_close( pgConn, fd ); + if (loResult < 0) // can't close, don't know if data are written + { + RMInit::logOut << "DBHierIndex::insertInDb() ignoring lo_close() error: " << PQerrorMessage(pgConn) << endl; + LEAVE( "DBHierIndex::insertInDb() cannot lo_close(): " << PQerrorMessage(pgConn) ); + generateException(); + } + + free(completebuffer); // free main buffer + + // (3) --- insert HIERIX tuple into db +#ifdef NOTYET // should be in future +/* + TALK( "EXEC SQL INSERT INTO RAS_HIERIX ( MDDObjIxOId, NumEntries, Dimension, ParentOId, IndexSubType, DynData ) VALUES ( " << id2 << "," << size2 << "," << dimension2 << "," << parentid2 << "," << indexsubtype2 << ", " << blobOid << " )" ); + EXEC SQL INSERT INTO RAS_HIERIX ( MDDObjIxOId, NumEntries, Dimension, ParentOId, IndexSubType, DynData) + VALUES ( :id2, :size2, :dimension2, :parentid2, :indexsubtype2, :blobOid); + if (SQLCODE != SQLOK) + { + check("DBHierIndex::insertInDb() insert into RAS_HIERIX\0"); + LEAVE( "DBHierIndex::insertInDb(): db access error: " << SQLCODE ); + generateException(); + } +*/ +#endif // NOTYET + // alternative solution for now: + (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "INSERT INTO RAS_HIERIX ( MDDObjIxOId, NumEntries, Dimension, ParentOId, IndexSubType, DynData ) VALUES ( %f, %d, %d, %f, %d, %d )", id2, size2, dimension2, parentid2, indexsubtype2, blobOid ); + TALK( pgQuery ); + pgResult = PQexec( pgConn, pgQuery ); + if (PQresultStatus(pgResult) != PGRES_COMMAND_OK) + { + LEAVE( "DBHierIndex::insertInDb() libpq 'insert RAS_HIERIX' error: " << PQerrorMessage(pgConn) ); + PQclear( pgResult ); + generateException(); + } + PQclear( pgResult ); + + // (4) --- dbobject insert + DBObject::insertInDb(); + + RMDBGEXIT(5, RMDebug::module_indexif, "DBHierIndex", "insertInDb() " << myOId); + LEAVE( "DBHierIndex::insertInDb(), myOId=" << myOId ); +} // insertInDb() + +void +DBHierIndex::readFromDb() throw (r_Error) +{ + RMDBGENTER(5, RMDebug::module_indexif, "DBHierIndex", "readFromDb() " << myOId); + ENTER( "DBHierIndex::readFromDb(), myOId=" << myOId ); + +#ifdef RMANBENCHMARK + DBObject::readTimer.resume(); +#endif +#ifdef NOTYET // should be in future +/* + EXEC SQL BEGIN DECLARE SECTION; +*/ +#endif // NOTYET + double id1; + double parentid1; + long dimension1; + long size1; + short indexsubtype1; + short lowerfind; + Oid blobOid; + char pgQuery[SQL_QUERY_BUFFER_SIZE]; // prelim + PGresult *pgResult = NULL; // prelim +#ifdef NOTYET // should be in future +/* + EXEC SQL END DECLARE SECTION; +*/ +#endif // NOTYET + + // (0) --- prepare variables + id1 = myOId; + + // (1) --- fetch tuple from database +#ifdef NOTYET // should be in future +/* + TALK( "EXEC SQL SELECT NumEntries, Dimension, ParentOId, IndexSubType, DynData INTO :size1, :dimension1, :parentid1, :indexsubtype1, blobOid FROM RAS_HIERIX WHERE MDDObjIxOId = " << id1 ); + EXEC SQL SELECT NumEntries, Dimension, ParentOId, IndexSubType, DynData + INTO :size1, :dimension1, :parentid1, :indexsubtype1, :blobOid + FROM RAS_HIERIX + WHERE MDDObjIxOId = :id1; + if (SQLCODE != SQLOK) + { + check("DBHierIndex::readFromDb() select from RAS_HIERIX"); + LEAVE( "DBHierIndex::insertInDb() 'select from RAS_HIERIX' error: " << SQLCODE ); + generateException(); + } +*/ +#endif // NOTYET + // alternative solution for now: + (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "SELECT NumEntries, Dimension, ParentOId, IndexSubType, DynData FROM RAS_HIERIX WHERE MDDObjIxOId = %f", id1 ); + TALK( pgQuery ); + pgResult = PQexec( pgConn, pgQuery ); + if (PQresultStatus(pgResult) != PGRES_TUPLES_OK) + { + LEAVE( "DBHierIndex::insertInDb() libpq 'select RAS_HIERIX' error: " << PQerrorMessage(pgConn) ); + PQclear( pgResult ); + generateException(); + } + size1 = atoi( PQgetvalue( pgResult, 0, 0 ) ); // extract value #1 from result + dimension1 = atoi( PQgetvalue( pgResult, 0, 1 ) ); // extract value #2 from result + parentid1 = atoi( PQgetvalue( pgResult, 0, 2 ) ); // extract value #3 from result + indexsubtype1 = atoi( PQgetvalue( pgResult, 0, 3 ) ); // extract value #4 from result + blobOid = atoi( PQgetvalue( pgResult, 0, 4 ) ); // extract value #5 from result + PQclear( pgResult ); + + // (2) --- fill variables and buffers + + _isNode = indexsubtype1; + + if (parentid1) + parent = OId(parentid1); + else + parent = OId(0, OId::INVALID); + + //number of bytes for bounds for "size" entries and mydomain + r_Bytes boundssize = sizeof(r_Range) * (size1 + 1) * dimension1; + //number of bytes for fixes for "size" entries and mydomain + r_Bytes fixessize = sizeof(char) * (size1 + 1) * dimension1; + //number of bytes for ids of entries + r_Bytes idssize = sizeof(OId::OIdCounter) * size1; + //number of bytes for types of entries + r_Bytes typessize = sizeof(char) * size1; + //number of bytes for the dynamic data (1 starter byte!) + r_Bytes completesize = 1 + boundssize * 2 + fixessize * 2 + idssize + typessize; + + RMDBGMIDDLE(8, RMDebug::module_indexif, "DBHierIndex", "complete=" << completesize << " bounds=" << boundssize << " fixes=" << fixessize << " ids=" << idssize << " types=" << typessize << ", size=" << size1 << " dimension=" << dimension1 ); + + char* completebuffer = (char*)mymalloc(completesize); + r_Range* upperboundsbuf = (r_Range*)mymalloc(boundssize); + r_Range* lowerboundsbuf = (r_Range*)mymalloc(boundssize); + char* upperfixedbuf = (char*)mymalloc(fixessize); + char* lowerfixedbuf = (char*)mymalloc(fixessize); + OId::OIdCounter* entryidsbuf = (OId::OIdCounter*)mymalloc(idssize); + char* entrytypesbuf = (char*)mymalloc(typessize); + + // (3) --- open, read, close blob + TALK( "lo_open()" ); + int fd = lo_open( pgConn, blobOid, INV_READ ); // open; manual tells no error indication + TALK( "lo_lseek() end" ); + int bytesToDo = lo_lseek( pgConn, fd, 0, SEEK_END ); // determine blob size; FIXME: more efficient method?? + TALK( "lo_lseek() start" ); + (void) lo_lseek( pgConn, fd, 0, SEEK_SET ); // rewind for reading + TALK( "lo_read() for " << completesize << " bytes" ); // read blob + int loResult = lo_read( pgConn, fd, completebuffer, completesize ); + if (loResult < 0) + { + RMInit::logOut << "DBHierIndex::readFromDb() cannot read blob, error: " << pgResult << endl; + LEAVE( "DBHierIndex::readFromDb: cannot read blob, error " << pgResult ); + throw r_Error( r_Error::r_Error_BaseDBMSFailed ); + } + else if (loResult != bytesToDo) // did not get all + { + RMInit::dbgOut << "BLOB (" << myOId << ") read: want to read (" << bytesToDo << " bytes, but got " << loResult << " bytes" << endl; + LEAVE( "DBHierIndex::readFromDb: want to read " << bytesToDo << " bytes, but got " << loResult << " bytes" ); + throw r_Error( r_Error::r_Error_LimitsMismatch ); + } + else if (completesize != bytesToDo) // this because I don't trust computations + { + RMInit::dbgOut << "BLOB (" << myOId << ") read: completesize=" << completesize << ", but bytesToDo=" << bytesToDo << endl; + LEAVE( "DBHierIndex::readFromDb: completesize=" << completesize << ", but bytesToDo=" << bytesToDo ); + throw r_Error( r_Error::r_Error_LimitsMismatch ); + } + TALK( "lo_close()" ); + int ignoredPgResult = lo_close( pgConn, fd ); // close blob + if (ignoredPgResult < 0) // we note, but ignore errors, as we have the data + { + RMInit::logOut << "DBHierIndex::readFromDb() ignoring lo_close() error: " << ignoredPgResult << endl; + TALK( "DBHierIndex::readFromDb: ignoring lo_close() error: " << ignoredPgResult ); + } + +#ifdef RMANDEBUG // dump low-level blob byte string +{ + char printbuf[10000]; + (void) sprintf( printbuf, "XXX DBHierIndex::readFromDb(): [%d]", completesize ); + char bytebuf[3]; + for (unsigned int i = 0; i < completesize; i++) + { + (void) sprintf( bytebuf, " %2X", (unsigned char) completebuffer[i] ); + strcat( printbuf, bytebuf ); + } + TALK( printbuf ); +} +#endif // RMANDEBUG + + // (4) --- copy data into buffers + // all dynamic data ( plus starter byte) is in completebuffer, put that stuff in the correct buffers + memcpy(lowerboundsbuf, &completebuffer[1], boundssize); + memcpy(upperboundsbuf, &completebuffer[boundssize + 1], boundssize); + memcpy(lowerfixedbuf, &completebuffer[boundssize * 2 + 1], fixessize); + memcpy(upperfixedbuf, &completebuffer[boundssize * 2 + fixessize + 1], fixessize); + memcpy(entryidsbuf, &completebuffer[boundssize * 2 + fixessize * 2 + 1], idssize); + memcpy(entrytypesbuf, &completebuffer[boundssize * 2 + fixessize * 2 + idssize + 1], typessize); + // now all dynamic data is in its private buffer + free (completebuffer); + completebuffer = NULL; + + // rebuild the attributes from the buffers + int i = 0; + myDomain = InlineMinterval(dimension1, &(lowerboundsbuf[0]), &(upperboundsbuf[0]), &(lowerfixedbuf[0]), &(upperfixedbuf[i*dimension1])); + RMDBGMIDDLE(5, RMDebug::module_indexif, "DBHierIndex", "domain " << myDomain << " constructed from " << InlineMinterval(dimension1, &(lowerboundsbuf[0]), &(upperboundsbuf[0]), &(lowerfixedbuf[0]), &(upperfixedbuf[0]))); + KeyObject theKey = KeyObject(DBObjectId(), myDomain); + for (i = 0; i < size1; i++) + { + theKey.setDomain(InlineMinterval(dimension1, &(lowerboundsbuf[(i+1)*dimension1]), &(upperboundsbuf[(i+1)*dimension1]), &(lowerfixedbuf[(i+1)*dimension1]), &(upperfixedbuf[(i+1)*dimension1]))); + theKey.setObject(OId(entryidsbuf[i], (OId::OIdType)entrytypesbuf[i])); + myKeyObjects.push_back(theKey); + RMDBGMIDDLE(5, RMDebug::module_indexif, "DBHierIndex", "entry " << entryidsbuf[i] << " " << (OId::OIdType)entrytypesbuf[i] << " at " << InlineMinterval(dimension1, &(lowerboundsbuf[(i+1)*dimension1]), &(upperboundsbuf[(i+1)*dimension1]), &(lowerfixedbuf[(i+1)*dimension1]), &(upperfixedbuf[(i+1)*dimension1]))); + } + + free(upperboundsbuf); + free(lowerboundsbuf); + free(upperfixedbuf); + free(lowerfixedbuf); + free(entryidsbuf); + free(entrytypesbuf); + +#ifdef RMANBENCHMARK + DBObject::readTimer.pause(); +#endif + + // (5) --- fill dbobject + DBObject::readFromDb(); + + RMDBGEXIT(5, RMDebug::module_indexif, "DBHierIndex", "readFromDb() " << myOId); + LEAVE( "DBHierIndex::readFromDb(), myOId=" << myOId ); +} // readFromDb() + +void +DBHierIndex::updateInDb() throw (r_Error) +{ + RMDBGENTER(5, RMDebug::module_indexif, "DBHierIndex", "updateInDb() " << myOId); + ENTER( "DBHierIndex::updateInDb(), myOId=" << myOId ); + +#ifdef NOTYET // should be in future +/* + EXEC SQL BEGIN DECLARE SECTION; +*/ +#endif // NOTYET + double id4; + long dimension4; + long size4; + double parentid4; + short count4; + short indexsubtype4; + Oid blobOid; + char pgQuery[SQL_QUERY_BUFFER_SIZE]; // prelim + PGresult *pgResult = NULL; // prelim +#ifdef NOTYET // should be in future +/* + EXEC SQL END DECLARE SECTION; +*/ +#endif // NOTYET + + // (0) --- prepare variables + id4 = myOId; + indexsubtype4 = _isNode; + dimension4 = myDomain.dimension(); + size4 = myKeyObjects.size(); + if (parent.getType() == OId::INVALID) + parentid4 = 0; + else + parentid4 = parent; + + // (1) --- prepare buffer + //number of bytes for bounds for "size" entries and mydomain + r_Bytes boundssize = sizeof(r_Range) * (size4 + 1) * dimension4; + //number of bytes for fixes for "size" entries and mydomain + r_Bytes fixessize = sizeof(char) * (size4 + 1) * dimension4; + //number of bytes for ids of entries + r_Bytes idssize = sizeof(OId::OIdCounter) * size4; + //number of bytes for types of entries + r_Bytes typessize = sizeof(char) * size4; + //number of bytes for the dynamic data; 1 starter byte! + r_Bytes completesize = 1 + boundssize * 2 + fixessize * 2 + idssize + typessize; + + char* completebuffer = (char*)mymalloc(completesize); + r_Range* upperboundsbuf = (r_Range*)mymalloc(boundssize); + r_Range* lowerboundsbuf = (r_Range*)mymalloc(boundssize); + char* upperfixedbuf = (char*)mymalloc(fixessize); + char* lowerfixedbuf = (char*)mymalloc(fixessize); + OId::OIdCounter* entryidsbuf = (OId::OIdCounter*)mymalloc(idssize); + char* entrytypesbuf = (char*)mymalloc(typessize); + + // populate the buffers with data + myDomain.insertInDb(&(lowerboundsbuf[0]), &(upperboundsbuf[0]), &(lowerfixedbuf[0]), &(upperfixedbuf[0])); + RMDBGMIDDLE(5, RMDebug::module_indexif, "DBHierIndex", "domain " << myDomain << " stored as " << InlineMinterval(dimension4, &(lowerboundsbuf[0]), &(upperboundsbuf[0]), &(lowerfixedbuf[0]), &(upperfixedbuf[0]))); + + KeyObjectVector::iterator it = myKeyObjects.begin(); + InlineMinterval indom; + for (unsigned int i = 0; i < size4; i++, it++) + { + indom = (*it).getDomain(); + indom.insertInDb(&(lowerboundsbuf[(i+1)*dimension4]), &(upperboundsbuf[(i+1)*dimension4]), &(lowerfixedbuf[(i+1)*dimension4]), &(upperfixedbuf[(i+1)*dimension4])); + entryidsbuf[i] = (*it).getObject().getOId().getCounter(); + entrytypesbuf[i] = (char)(*it).getObject().getOId().getType(); + RMDBGMIDDLE(5, RMDebug::module_indexif, "DBHierIndex", "entry " << entryidsbuf[i] << " " << (OId::OIdType)entrytypesbuf[i] << " at " << InlineMinterval(dimension4, &(lowerboundsbuf[(i+1)*dimension4]), &(upperboundsbuf[(i+1)*dimension4]), &(lowerfixedbuf[(i+1)*dimension4]), &(upperfixedbuf[(i+1)*dimension4]))); + } + + RMDBGMIDDLE(8, RMDebug::module_indexif, "DBHierIndex", "complete=" << completesize << " bounds=" << boundssize << " fixes=" << fixessize << " ids=" << idssize << " types=" << typessize << ", size=" << size4 << " dimension=" << dimension4 ); + + // write the buffers in the complete buffer, plus starter byte + // this indirection is neccessary because of memory alignement of longs... + completebuffer[0] = 13; // write dummy starter byte + memcpy( &completebuffer[1], lowerboundsbuf, boundssize); + free(lowerboundsbuf); + memcpy( &completebuffer[boundssize + 1], upperboundsbuf, boundssize); + free(upperboundsbuf); + memcpy( &completebuffer[boundssize * 2 + 1], lowerfixedbuf, fixessize); + free(lowerfixedbuf); + memcpy( &completebuffer[boundssize * 2 + fixessize + 1], upperfixedbuf, fixessize); + free(upperfixedbuf); + memcpy( &completebuffer[boundssize * 2 + fixessize * 2 + 1], entryidsbuf, idssize); + free(entryidsbuf); + memcpy( &completebuffer[boundssize * 2 + fixessize * 2 + idssize + 1], entrytypesbuf, typessize); + free(entrytypesbuf); + +#ifdef RMANDEBUG // dump low-level blob byte string +{ + char printbuf[10000]; + (void) sprintf( printbuf, "XXX DBHierIndex::updateInDb(): [%d]", completesize ); + char bytebuf[3]; + for (unsigned int i = 0; i < completesize; i++) + { + (void) sprintf( bytebuf, " %2X", (unsigned char) completebuffer[i] ); + strcat( printbuf, bytebuf ); + } + TALK( printbuf ); +} +#endif // RMANDEBUG + + // (2) --- write complete buffer to new database blob + // create, open, write, close blob; generates new 'oid' for subsequent storage in tuple + TALK( "lo_creat()" ); + blobOid = lo_creat( pgConn, INV_READ|INV_WRITE ); // create -- not clear what INV_* here means so indicate all + if (blobOid == 0) + { + RMInit::logOut << "DBHierIndex::updateInDb() cannot create blob, error: " << PQerrorMessage(pgConn) << endl; + LEAVE( "DBHierIndex::updateInDb(pgConn)" ); + generateException(); + } + TALK( "lo_open() for oid " << blobOid ); + int fd = lo_open( pgConn, blobOid, INV_WRITE ); // no error code indicated, 0 seems to be no error + TALK( "lo_write() for fd " << fd << " for " << completesize << " bytes" ); + int loResult = lo_write( pgConn, fd, completebuffer, completesize ); + if (loResult < 0) + { + RMInit::logOut << "DBHierIndex::updateInDb() cannot write blob, error: " << PQerrorMessage(pgConn) << endl; + LEAVE( "DBHierIndex::updateInDb() cannot write blob, error " << PQerrorMessage(pgConn) ); + generateException(); + } + else if (loResult != completesize) // did not get all + { + RMInit::dbgOut << "BLOB (" << myOId << ") update: wrote " << loResult << " instead of " << completesize << " bytes" << endl; + LEAVE( "DBHierIndex::updateInDb() wrote " << loResult << " instead of " << completesize << " bytes" ); + generateException(); + } + TALK( "lo_close()" ); + loResult = lo_close( pgConn, fd ); + if (loResult < 0) // can't close, don't know if data are written + { + RMInit::logOut << "DBHierIndex::updateInDb() ignoring lo_close() error: " << PQerrorMessage(pgConn) << endl; + LEAVE( "DBHierIndex::updateInDb() cannot lo_close(): " << PQerrorMessage(pgConn) ); + generateException(); + } + free(completebuffer); + completebuffer = NULL; + + // (3) -- update HierIx entry +#ifdef NOTYET // should be in future +/* + TALK( "EXEC SQL UPDATE RAS_HIERIX SET NumEntries = " << size4 << ", Dimension = " << dimension4 << ", ParentOId = " << parentid4 << ", IndexSubType = " << indexsubtype4 << ", DynData = " << blobOid ); + EXEC SQL UPDATE RAS_HIERIX + SET NumEntries = :size4, Dimension = :dimension4, ParentOId = :parentid4, IndexSubType = :indexsubtype4, DynData = :blobOid + WHERE MDDObjIxOId = :id4; + if (SQLCODE != SQLOK) + { + check("DBHierIndex::updateInDb() update RAS_HIERIX"); + LEAVE( "DBHierIndex::updateInDb(): db access error: " << SQLCODE ); + generateException(); + } +*/ +#endif // NOTYET + // alternative solution for now: + (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "UPDATE RAS_HIERIX SET NumEntries = %d, Dimension = %d, ParentOId = %f, IndexSubType = %d, DynData = %d WHERE MDDObjIxOId = %f", size4, dimension4, parentid4, indexsubtype4, blobOid, id4 ); + TALK( pgQuery ); + pgResult = PQexec( pgConn, pgQuery ); + if (PQresultStatus(pgResult) != PGRES_COMMAND_OK) + { + LEAVE( "DBHierIndex::updateInDb() libpq 'UPDATE HierIx' error: " << PQerrorMessage(pgConn) ); + PQclear( pgResult ); + generateException(); + } + PQclear( pgResult ); + + // (4) --- dbobject update + DBObject::updateInDb(); + + RMDBGEXIT(5, RMDebug::module_indexif, "DBHierIndex", "updateInDb() " << myOId); + LEAVE( "DBHierIndex::updateInDb(), myOId=" << myOId ); +} // updateInDb() + +void +DBHierIndex::deleteFromDb() throw (r_Error) +{ + RMDBGENTER(8, RMDebug::module_indexif, "DBHierIndex", "deleteFromDb() " << myOId); + ENTER( "DBHierIndex::deleteFromDb(), myOId=" << myOId ); + +#ifdef NOTYET // should be in future +/* + EXEC SQL BEGIN DECLARE SECTION; +*/ +#endif // NOTYET + double id3; + Oid blobOid; + char pgQuery[SQL_QUERY_BUFFER_SIZE]; // prelim + PGresult *pgResult = NULL; // prelim +#ifdef NOTYET // should be in future +/* + EXEC SQL END DECLARE SECTION; +*/ +#endif // NOTYET + + OId oi; + DBObjectId dbo; + while (!myKeyObjects.empty()) + { + oi = myKeyObjects.begin()->getObject().getOId(); + DBObjectId dbo; + if ((oi.getType() == OId::BLOBOID) || (oi.getType() == OId::INLINETILEOID)) + { + BLOBTile::kill(oi); + } + else + { + dbo = DBObjectId(oi); + if (!dbo.is_null()) + { + dbo->setCached(false); + dbo->setPersistent(false); + dbo = (unsigned int)0; + } + } + myKeyObjects.erase(myKeyObjects.begin()); + } + + id3 = myOId; + + // (1) --- get blob oid +#ifdef NOTYET // should be in future +/* + TALK( "EXEC SQL SELECT DynData INTO :blobOid FROM RAS_HIERIX WHERE MDDObjIxOId = " << id3 ); + EXEC SQL SELECT DynData + INTO :blobOid + FROM RAS_HIERIX + WHERE MDDObjIxOId = :id3; + if (SQLCODE != SQLOK) + { + check("DBHierIndex::deleteFromDb() select from RAS_HIERIX"); + LEAVE( "DBHierIndex::deleteFromDb() select from RAS_HIERIX: error: " << SQLCODE ); + generateException(); + } +*/ +#endif // NOTYET + // alternative solution for now: + (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "SELECT DynData FROM RAS_HIERIX WHERE MDDObjIxOId = %f", id3 ); + TALK( pgQuery ); + pgResult = PQexec( pgConn, pgQuery ); + if (PQresultStatus(pgResult) != PGRES_TUPLES_OK) + { + LEAVE( "DBHierIndex::deleteFromDb() libpq 'select RAS_HIERIX' error: " << PQerrorMessage(pgConn) ); + PQclear( pgResult ); + generateException(); + } + blobOid = atoi( PQgetvalue( pgResult, 0, 0 ) ); // extract value from result + PQclear( pgResult ); + + // (2) --- delete blob + int loResult = lo_unlink( pgConn, blobOid ); + if (loResult < 0) // no disaster if we can't so no exception + { + TALK( "DBHierIndex::deleteFromDb() warning: libpq 'unlink blob' error: " << PQerrorMessage(pgConn) ); + } + + // (3) --- delete tuple +#ifdef NOTYET // should be in future +/* + TALK( "EXEC SQL DELETE FROM RAS_HIERIX WHERE MDDObjIxOId = " << id3 ); + EXEC SQL DELETE FROM RAS_HIERIX + WHERE MDDObjIxOId = :id3; + if (SQLCODE != SQLOK) + { + check("DBHierIndex::deleteFromDb() RAS_HIERIX"); + LEAVE( "DBHierIndex::deleteFromDb(): db access error: " << SQLCODE ); + generateException(); + } +*/ +#endif // NOTYET + // alternative solution for now: + (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "DELETE FROM RAS_HIERIX WHERE MDDObjIxOId = %f", id3 ); + TALK( pgQuery ); + pgResult = PQexec( pgConn, pgQuery ); + if (PQresultStatus(pgResult) != PGRES_COMMAND_OK) + { + LEAVE( "DBHierIndex::updateInDb() libpq 'DELETE HierIx' error: " << PQerrorMessage(pgConn) ); + PQclear( pgResult ); + generateException(); + } + PQclear( pgResult ); + + // (4) --- dbobject delete + DBObject::deleteFromDb(); + + RMDBGEXIT(8, RMDebug::module_indexif, "DBHierIndex", "deleteFromDb() " << myOId); + LEAVE( "DBHierIndex::deleteFromDb(), myOId=" << myOId ); +} // deleteFromDb() + |