diff options
Diffstat (limited to 'relindexif/dbrcindexds.pgc')
-rw-r--r-- | relindexif/dbrcindexds.pgc | 495 |
1 files changed, 495 insertions, 0 deletions
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); +} + |