IOManagerDB.cpp

00001 #include "IOManagerDB.h"
00002 #include "IONameDB.h"
00003 #include "MySqlException.h"
00004 #include "ZlibStringCompressor.h"
00005 #include "Sct/Serializable.h"
00006 #include "Sct/SctNames.h"
00007 #include "Sct/XmlStyleStream.h"
00008 #include "Sct/StdExceptionWrapper.h"
00009 #include "Sct/Archive/IONameArchiveFile.h"
00010 
00011 #include "Sct/UniqueID.h"
00012 #include "SctData/ScanResult.h"
00013 #include "SctData/TestResult.h"
00014 #include "CalibrationController/Serialization/IsInfoWrapper.h"
00015 #include "CalibrationController/Serialization/TestDataWrapper.h"
00016 #include <sstream>
00017 #include "boost/lexical_cast.hpp"
00018 
00019 using std::string;
00020 using std::ostringstream;
00021 using boost::shared_ptr;
00022 using namespace Sct;
00023 
00024 namespace SctArchiving {
00025 //-------------------- Error handling --------------------//
00026   MysqlException::MysqlException(const string& msg, const string& file, int line){
00027     initialize("MYSQL_EXCEPTION", "ArchivingService::MysqlException", msg, 0, file, line);
00028   }
00029   MysqlException::MysqlException(const string& msg, const string& query, const string& file, int line) {
00030     std::ostringstream full_message;
00031     full_message << msg << "\nwhile executing query:\n" << query;
00032     initialize("MYSQL_EXCEPTION", "ArchivingService::MysqlException", full_message.str(), 0, file, line);
00033   }
00034   
00035   MysqlException::MysqlException(){}
00036   
00037   MysqlException::~MysqlException() throw(){}
00038   
00039   void IOManagerDB::checkForMySqlErrors(const string& msg, const string& file, int line) const{
00040     if(mysql_errno(m_mysql)){
00041       std::ostringstream full_message;
00042       full_message << msg << "\n" 
00043            << mysql_error(m_mysql) << "\n";
00044       std::cerr << "ERROR: " << full_message.str() << "\nat " << file << ":" << line << std::endl;
00045       throw MysqlException(full_message.str(), file, line);
00046     }
00047   }
00048   
00049   void IOManagerDB::checkForMySqlErrors(const string& msg, const string& query, const string& file, int line) const{
00050     if(mysql_errno(m_mysql)){
00051       std::ostringstream full_message;
00052       full_message << msg << "\n" 
00053                    << query << "\n"
00054            << mysql_error(m_mysql) << "\n";
00055 //      std::cerr << "ERROR: " << full_message.str()
00056 //      << "\n executing: "
00057 //      << query
00058 //      << "\nat " << file << ":" << line << std::endl;
00059 //      throw MysqlException(full_message.str(), query, file, line);
00060       throw MysqlException(full_message.str(), file, line);
00061     }
00062   }
00063 //-------------------- Error handling --------------------//
00064 
00065 //-------------------- Constructors, destructors, instance management --------------------//
00066   IOManagerDB::IOManagerDB() : m_dataSetName("nowhere"), 
00067                    m_nRead(0), m_nWrite(0), 
00068                    m_nCompress(0), m_nDecompress(0), 
00069                    read_time(0,0,0,0), write_time(0,0,0,0),
00070                    compress_time(0,0,0,0), decompress_time(0,0,0,0)
00071   {
00072     
00073     std::cout <<"Creating IOManagerDB" << std::endl;
00074     m_compressor = shared_ptr<ZlibStringCompressor>(new ZlibStringCompressor());
00075     m_mysql = mysql_init((MYSQL*) 0);
00076     checkForMySqlErrors("Problem during initialisation of MYSQL structure.", __FILE__, __LINE__);
00077     
00078     // connect to the server
00079     std::cout <<"Connecting IOManagerDB" << std::endl;
00080     mysql_real_connect(m_mysql, "localhost", "daquser", "", NULL, 3306, NULL, 0);
00081     checkForMySqlErrors("Failed to connect to mysql server", __FILE__, __LINE__);
00082     SctNames::Mrs() << MRS_TEXT("Have connected to mysql server") << "IOMANAGER_DB_CONNECT" 
00083                     << MRS_INFORMATION << ENDM;
00084 
00085     // connect to the database
00086     std::string dbname="test_dbSRD";
00087     std::cout <<"Connecting IOManagerDB to database name=`" << dbname << "'" << std::endl;
00088     mysql_select_db(m_mysql, dbname.c_str());
00089     std::string message("Failed to connect to database");
00090     message += dbname;
00091     checkForMySqlErrors(message, __FILE__, __LINE__);
00092     SctNames::Mrs() << MRS_TEXT("Have connected to mysql database") << "IOMANAGER_DB_CONNECT" 
00093                     << MRS_PARAM<const char*>("database_name",dbname.c_str())
00094                     << MRS_INFORMATION << ENDM;
00095   }
00096   
00097   IOManagerDB::~IOManagerDB(){
00098 #warning "AJB This never seems to get called because the manager is a static beast. **Hopefully** this dosent matter!"
00099     std::string message("Closing connection to mysql server");
00100     std::cout << message << endl;
00101     SctNames::Mrs() << MRS_TEXT(message) << "IOMANAGER_DB_CONNECT" 
00102                     << MRS_INFORMATION << ENDM;
00103     mysql_close(m_mysql);
00104   }
00105 
00106   IOManagerDB* IOManagerDB::s_man=0;
00107 
00108   IOManagerDB& IOManagerDB::instance() {
00109     if (!s_man) s_man=new IOManagerDB();
00110     return *s_man;
00111   }
00112 //-------------------- Constructors, destructors, instance management --------------------//
00113 
00114 //-------------------- String compressor stuff, not used yet --------------------//
00115 //JD: This one should return proper status info, like...what??
00116   std::string IOManagerDB::status() const {
00117     std::ostringstream oss;
00118     oss << "IOManagerDB";
00119     if (m_compressor.get()){
00120       oss << "String compressor buffer size: " 
00121       << m_compressor->getBufferSize() << std::endl;
00122     }
00123     else {
00124       oss << "String compressor not initialized" << endl;
00125     }
00126     {
00127       boost::recursive_mutex::scoped_lock lock (getMutex());      
00128       oss << "write time " << write_time << " for " << m_nWrite;
00129       oss << endl;
00130       
00131       oss << "read time " << read_time << " for " << m_nRead;
00132       oss << endl;
00133 
00134       oss << "compress time " << compress_time << " for " << m_nCompress;
00135       oss << endl;
00136       
00137       oss << "decompress time " << decompress_time << " for " << m_nDecompress;
00138       oss << endl;
00139       
00140       oss << "blob-add time " << blob_add_time << " for " << m_nBlobAdd;
00141       oss << endl;
00142 
00143       oss << "ostream time " << ostream_time << " for " << m_nWrite;
00144       oss << endl;
00145       
00146       oss << "istream time " << istream_time << " for " << m_nRead;
00147       oss << endl;
00148       
00149     }
00150     return oss.str();
00151   }
00152 
00153 //JD: Maybe not needed??
00154   const SctData::ResultHeader& IOManagerDB::getHeader(const Serializable& ob){
00155     const SctData::ResultHeader* header=0;
00156     if (ob.getClassName().find("TestResult")!=string::npos) {
00157       header = & dynamic_cast<const SctData::TestResult&>(ob).getHeader();
00158     } 
00159     if (ob.getClassName().find("ScanResult")!=string::npos) {
00160       header = & dynamic_cast<const SctData::ScanResult&>(ob).getHeader();
00161     }
00162     if (header) {
00163       return *header;
00164     } else {
00165       ostringstream oss;
00166       oss << "Dont know how to find a header for object with class name : " 
00167       << ob.getClassName() << " which has UniqueID : " 
00168       << (string) ob.getUniqueID();
00169       throw IoException(oss.str(), __FILE__, __LINE__);
00170     }
00171   }
00172 
00173 //JD: Maybe not needed??
00174   string IOManagerDB::getTable(const Serializable& ob){
00175     return "data";
00176   }
00177 //-------------------- String compressor stuff, not used yet --------------------//
00178 
00179 //-------------------- Read and write interface to clients --------------------//
00180   void IOManagerDB::write(const Serializable& ob, const IOParams* par) const {
00181     using namespace boost::posix_time;
00182     ptime write_start_time(microsec_clock::local_time());
00183     using SctCalibrationController::IsInfoWrapper;
00184 
00185     try{
00186       boost::recursive_mutex::scoped_lock lock (getMutex());
00187       setReadMode(false);  // for version control
00188       
00189       std::ostringstream oss;
00190       Sct::XmlStyleOStream out_ad(oss);
00191       
00192       ptime ostream_start_time(microsec_clock::local_time());
00193       writeImpl(out_ad, ob, false);
00194       {
00195     ptime ostream_end_time(microsec_clock::local_time());
00196     boost::recursive_mutex::scoped_lock lock(timingAccess);
00197     ostream_time=ostream_time+(ostream_end_time-ostream_start_time);
00198       }
00199       
00200       // Get header info from object
00201       const std::string classname = ob.getClassName();
00202       const Sct::UniqueID id = ob.getUniqueID();
00203 
00204 // Debug couts
00205 std::cout << "IOMwrite - str(id)    : " << (std::string)id << std::endl;
00206 std::cout << "IOMwrite - DataSetName: " << getDataSetName()  << std::endl;
00207 std::cout << "IOMwrite - ClassName  : " << classname << std::endl;
00208 std::cout << "IOMwrite - Scan#      : " << id.getScanNumber() << std::endl;
00209 std::cout << "IOMwrite - Run#       : " << id.getRunNumber() << std::endl;
00210 
00211       // Get the runID
00212       std::string runId = getRunID(id.getRunNumber());
00213 
00214       // Check which type of object we are dealing with
00215       if (classname == "TestData"){
00216         // Cast Serializable into a Wrapper; will throw std::bad_cast if not possible
00217         const IsInfoWrapper& wrapper = dynamic_cast<const IsInfoWrapper&>(ob);
00218 
00219         // Get the wrapped object
00220         boost::shared_ptr<const ISInfo> info = wrapper.getWrapped();
00221         if (info.get() == 0){
00222 // TODO: throw something
00223 std::cout << "IOMwrite - debug msg, failed to get wrapped object" << std::endl;
00224         }
00225 
00226         // Cast into TestData
00227         boost::shared_ptr<const TestData> td = boost::dynamic_pointer_cast<const TestData>(info); 
00228         if (td.get() == 0){
00229 // TODO: throw something
00230 std::cout << "IOMwrite - debug msg, cast into TestData failed" << std::endl;
00231         }
00232 
00233         // Add run to db if it does not exist there already
00234         if (runId == ""){
00235           addRun(id.getRunNumber(), false);
00236 // TODO: Check for errors???
00237           runId = getRunID(id.getRunNumber());
00238         }
00239 
00240     // Check if the test exist in the db
00241         std::string testId = getTestID(runId, id.getScanNumber());
00242         if (testId == ""){
00243           addTest(*td, true);
00244 // TODO: Check for errors???
00245           testId = getTestID(runId, id.getScanNumber());
00246         }
00247 
00248         // Loop over all modules in this TestData object
00249         for (unsigned int i=0; i < (*td).modules_size; ++i) {
00250           // Check if the module exist in the db, add if not
00251           std::string moduleId = getModuleID((*td).modules[i]);
00252           if (moduleId == ""){
00253             // Add modules to db, assign to dummy position
00254             addModule("DummyLayer", "0", "0", (*td).modules[i]);
00255             moduleId = getModuleID((*td).modules[i]);
00256           }
00257           // Loop over all scans in this TestData object
00258           for (unsigned int j=0; j < (*td).nScans; ++j) {
00259             // Add all mod-scan combinations to the tblRawData table
00260             std::string scanId = getScanID(testId, (*td).startScanNumber + j);
00261             addRawDataRecord(moduleId, scanId);
00262 // TODO: Check for errors??? Duplication error?
00263           }
00264         }
00265       }
00266       else {  // else not a TestData object
00267         // Throw exception if the run does not exist in the db
00268         if (runId == ""){
00269           ostringstream ossMsg;
00270           ossMsg << "The requested Run was not found in the db, runNr: " << id.getRunNumber();
00271           throw IoException(ossMsg.str(), __FILE__, __LINE__);
00272         }
00273 
00274         // Ask the db of the 1st scan# for the test of this scan
00275         unsigned firstScanNumber;
00276         std::ostringstream select;
00277         select << "SELECT Max(FirstScanNr) FROM tblTests "
00278                << "WHERE ((FirstScanNr <= " << id.getScanNumber() << ") "
00279                << "AND (RunID = " << runId << ")) "
00280                << "GROUP BY RunID ";
00281         firstScanNumber = boost::lexical_cast<int>(executeQueryReturnID(select.str()));
00282 
00283         // Check if the test exist in the db
00284         std::string testId = getTestID(runId, firstScanNumber);
00285         if (testId == ""){
00286 // TODO: throw exception here...
00287 std::cout << "IOMwrite - debug msg, oops, this test is not in the db" << std::endl;
00288         }
00289 
00290     // Check if the scan exist in the db (it should have been added with the test)
00291         std::string scanId = getScanID(testId, id.getScanNumber());
00292         if (scanId == ""){
00293           ostringstream ossMsg;
00294           ossMsg << "The requested Scan was not found in the db (runNr: " << id.getRunNumber()
00295                 << ", firstScanNr: " << firstScanNumber
00296                 << ", ScanNr: " << id.getScanNumber() << ")";
00297           throw IoException(ossMsg.str(), __FILE__, __LINE__);
00298         }
00299 
00300         // Check if the module exist in the db
00301         std::string moduleId = getModuleID(id.getModule());
00302         if (moduleId == ""){
00303           ostringstream ossMsg;
00304           ossMsg << "The requested Module was not found in the db, modNr: " << id.getModule();
00305           throw IoException(ossMsg.str(), __FILE__, __LINE__);
00306         }
00307 
00308         // Everything is ok in the db, store the data as a BLOB for this mod-scan
00309         const std::string& uncompressed = oss.str();
00310     ptime compress_start_time(microsec_clock::local_time());
00311         const std::string compressed = m_compressor->compress(uncompressed, getCompressionLevel());
00312     {
00313       ptime compress_end_time(microsec_clock::local_time());
00314       boost::recursive_mutex::scoped_lock lock(timingAccess);
00315       compress_time=compress_time+(compress_end_time-compress_start_time);
00316       m_nCompress++;
00317     }
00318     
00319     ptime blob_add_start_time(microsec_clock::local_time());
00320         addRawDataBlob(moduleId, scanId, compressed.c_str(), compressed.size());
00321     {
00322       ptime blob_add_end_time(microsec_clock::local_time());
00323       boost::recursive_mutex::scoped_lock lock(timingAccess);
00324       blob_add_time=blob_add_time+(blob_add_end_time-blob_add_start_time);
00325       m_nBlobAdd++;
00326     }
00327 
00328 // Debug couts
00329 std::cout << "IOMwrite - 1stScan# : " << firstScanNumber << std::endl;
00330 std::cout << "IOMwrite - RunID    : " << runId << std::endl;
00331 std::cout << "IOMwrite - ModID    : " << moduleId << std::endl;
00332 std::cout << "IOMwrite - TestID   : " << testId << std::endl;
00333 std::cout << "IOMwrite - ScanID   : " << scanId << std::endl;
00334       }
00335     }catch (Sct::Throwable& e){
00336       throw; // pass up to next level
00337     }catch(std::exception& e){
00338       StdExceptionWrapper sew(e);
00339       throw IoException(sew, __FILE__, __LINE__);
00340     }
00341 
00342     {
00343       ptime write_end_time(microsec_clock::local_time());
00344       boost::recursive_mutex::scoped_lock lock(timingAccess);
00345       write_time=write_time+(write_end_time-write_start_time);
00346       m_nWrite++;
00347     }
00348   }
00349 
00350 
00351   boost::shared_ptr<Serializable> IOManagerDB::read(const string& name, const IOParams* par) const {
00352     using namespace boost::posix_time;
00353     ptime read_start_time(microsec_clock::local_time());
00354     
00355     using SctCalibrationController::TestDataWrapper;
00356    try{
00357       boost::recursive_mutex::scoped_lock lock (getMutex());
00358       setReadMode(true);           // for version control
00359       getReadVersionMap().clear(); // for version control
00360 
00361       const IONameDB ioname(name);
00362       const Sct::UniqueID id = ioname.getUniqueID();
00363       const std::string classname = ioname.getClassName();
00364 
00365       // Create pointer which will be returned at then end of this method
00366       boost::shared_ptr<Serializable> p_ob;
00367 
00368 // Debug couts
00369 std::cout << "IOMread - name       : " << name << std::endl;
00370 std::cout << "IOMread - str(id)    : " << (std::string)id << std::endl;
00371 std::cout << "IOMread - DataSetName: " << getDataSetName()  << std::endl;
00372 std::cout << "IOMread - ClassName  : " << classname << std::endl;
00373 std::cout << "IOMread - Scan#      : " << id.getScanNumber() << std::endl;
00374 std::cout << "IOMread - Run#       : " << id.getRunNumber() << std::endl;
00375 
00376       // Get the runID
00377       std::string runId = getRunID(id.getRunNumber());
00378       if (runId == ""){
00379         ostringstream oss;
00380         oss << "The requested Run was not found in the db, runNr: " << id.getRunNumber();
00381         throw IoException(oss.str(), __FILE__, __LINE__);
00382       }
00383 
00384       // Check which type of object we are dealing with
00385       if (classname == "TestData"){
00386         // Check if the test exist in the db
00387         std::string testId = getTestID(runId, id.getScanNumber());
00388         if (testId == ""){
00389           ostringstream oss;
00390           oss << "The requested Test was not found in the db (runNr: " << id.getRunNumber()
00391               << ", firstScanNr: " << id.getScanNumber() << ")";
00392           throw IoException(oss.str(), __FILE__, __LINE__);
00393         }
00394 
00395         // Create a TestData object
00396         boost::shared_ptr<TestData> td(new TestData()); 
00397     
00398 /*
00399 TODO:
00400  - Fill TestData object with scans, modules, etc, from the db
00401    + get startTime and endTime from tblTests
00402    + get n.o. scans for testId from tblScans
00403    + startScanNumber = id.getScanNumber()
00404    + runNumber = id.getRunNumber()
00405    + testName = Extract from classname???
00406    + get module_size from tblRawData (n.o. rows for one of the scans)
00407    + get modules (uhh, this will be a tricky SQL)
00408    + anything else (testPoints, testVariable, version)???
00409 */
00410         // Jorgen needs to fill this with useful stuff!
00411         td->testName="blah";
00412     
00413         boost::shared_ptr<TestDataWrapper> wrapper(new TestDataWrapper(td));
00414     {
00415       ptime read_end_time(microsec_clock::local_time());
00416       boost::recursive_mutex::scoped_lock lock(timingAccess);
00417       read_time=read_time+(read_end_time-read_start_time);
00418       m_nRead++;
00419     }
00420         return wrapper;
00421       }
00422       else if (classname == "SctData::RawScanResult"){
00423         // Ask the db of the 1st scan# for the test of this scan
00424         unsigned firstScanNumber;
00425         std::ostringstream select;
00426         select << "SELECT Max(FirstScanNr) FROM tblTests "
00427                << "WHERE ((FirstScanNr <= " << id.getScanNumber() << ") "
00428                << "AND (RunID = " << runId << ")) "
00429                << "GROUP BY RunID ";
00430         firstScanNumber = boost::lexical_cast<int>(executeQueryReturnID(select.str()));
00431 
00432         // Check if the test exist in the db
00433         std::string testId = getTestID(runId, firstScanNumber);
00434         if (testId == ""){
00435 // TODO: throw exception here...
00436 std::cout << "IOMwrite - debug msg, oops, this test is not in the db" << std::endl;
00437         }
00438 
00439         // Check if the scan exist in the db (it should have been added with the test)
00440         std::string scanId = getScanID(testId, id.getScanNumber());
00441         if (scanId == ""){
00442           ostringstream oss;
00443           oss << "The requested Scan was not found in the db (runNr: " << id.getRunNumber()
00444               << ", firstScanNr: " << firstScanNumber
00445               << ", ScanNr: " << id.getScanNumber() << ")";
00446           throw IoException(oss.str(), __FILE__, __LINE__);
00447         }
00448 
00449         // Check if the module exist in the db
00450         std::string moduleId = getModuleID(id.getModule());
00451         if (moduleId == ""){
00452           ostringstream oss;
00453           oss << "The requested Module was not found in the db, modNr: " << id.getModule();
00454           throw IoException(oss.str(), __FILE__, __LINE__);
00455         }
00456 
00457 // Debug couts
00458 std::cout << "IOMread - 1stScan# : " << firstScanNumber << std::endl;
00459 std::cout << "IOMread - RunID    : " << runId << std::endl;
00460 std::cout << "IOMread - ModID    : " << moduleId << std::endl;
00461 std::cout << "IOMread - TestID   : " << testId << std::endl;
00462 std::cout << "IOMread - ScanID   : " << scanId << std::endl;
00463 
00464         // Get the desired data from the db
00465         std::string compressed;
00466         compressed = getRawDataBlob(moduleId, scanId);
00467 
00468         // Inflate and return the string
00469     ptime decompress_start_time(microsec_clock::local_time());
00470         const std::string uncompressed = m_compressor->inflate(compressed);
00471     {
00472       ptime decompress_end_time(microsec_clock::local_time());
00473       boost::recursive_mutex::scoped_lock lock(timingAccess);
00474       decompress_time=decompress_time+(decompress_end_time-decompress_start_time);
00475       m_nDecompress++;
00476     }
00477 
00478         std::istringstream iss(uncompressed);
00479         XmlStyleIStream in_ad(iss);
00480 
00481     ptime istream_start_time(microsec_clock::local_time());
00482         p_ob = boost::dynamic_pointer_cast<Serializable>(readImpl(in_ad));
00483     {
00484       ptime istream_end_time(microsec_clock::local_time());
00485       boost::recursive_mutex::scoped_lock lock(timingAccess);
00486       istream_time=istream_time+(istream_end_time-istream_start_time);
00487     }
00488       }
00489       else if (classname == "SctData::FitScanResult"){
00490 // TODO: fill tblFittedData here
00491     throw Sct::LogicError("not implimented!", __FILE__, __LINE__);
00492       }
00493       else if (classname == "xxxTestResult"){
00494 // TODO: fill tblAnalysedData here
00495     throw Sct::LogicError("not implimented!", __FILE__, __LINE__);
00496       }
00497       else {  // unkown object
00498         ostringstream oss;
00499         oss << "Unknown Class name: " << classname;
00500         throw IoException(oss.str(), __FILE__, __LINE__);
00501       }
00502 
00503       {
00504     ptime read_end_time(microsec_clock::local_time());
00505     boost::recursive_mutex::scoped_lock lock(timingAccess);
00506     read_time=read_time+(read_end_time-read_start_time);
00507     m_nRead++;
00508       }
00509       return p_ob;
00510       // Catch exceptions
00511     }catch (Sct::Throwable& e) {
00512       throw; // pass up to next level
00513     }catch(std::exception& e){
00514       StdExceptionWrapper sew(e);
00515       throw IoException(sew, __FILE__, __LINE__);
00516     }
00517   }
00518 //-------------------- Read and write interface to clients --------------------//
00519 
00520 //-------------------- Utility methods --------------------//
00521 std::string IOManagerDB::convertToMysqlDateTimeFormat(const std::string& original){
00522   std::string copy=original;
00523   unsigned t = copy.find('T');
00524   if (copy.empty()) {
00525     // Some tests seems to miss the end date-time. Return a '0' date-time for these cases
00526     copy = "0000-00-00 00:00:00";
00527   } else if (t==string::npos) {
00528     //Ooops, no 'T' found in string, throw!
00529     std::ostringstream msg;
00530     msg << "could not parse date/time since I couldn't find a `T' in " << copy;
00531     throw Sct::IoException(msg.str(), __FILE__, __LINE__);
00532   } else {
00533     // This looks like a proper date-time string
00534     copy = copy.erase(t,1);
00535   }
00536   return copy;
00537 }
00538 
00539 void IOManagerDB::setDataSetName(const std::string& name){
00540   m_dataSetName=name;
00541 }
00542 
00543 std::string IOManagerDB::getDataSetName() const{
00544   return m_dataSetName;
00545 }
00546 //-------------------- Utility methods --------------------//
00547 
00548 //-------------------- Get-an-ID methods --------------------//
00549 std::string IOManagerDB::getDataSetID() const{
00550   std::ostringstream select;
00551   select << "SELECT DataSetID FROM tblDataSets WHERE "
00552          << "(DataSetName = '" << getDataSetName() << "')";
00553   return executeQueryReturnID(select.str());
00554 }
00555 
00556 std::string IOManagerDB::getTestTypeID(const std::string& testName) const{
00557   std::ostringstream select;
00558   select << "SELECT TestTypeID FROM tblTestTypes WHERE "
00559          << "(TestTypeName = '" << testName << "')";
00560   return executeQueryReturnID(select.str());
00561 }
00562 
00563 std::string IOManagerDB::getRunID(const unsigned runNumber) const{
00564   std::ostringstream select;
00565   select << "SELECT RunID FROM tblRuns WHERE "
00566          << "(DataSetID = " << getDataSetID() << ") AND "
00567          << "(RunNr = " << runNumber << ")";  
00568   return executeQueryReturnID(select.str());
00569 }
00570 
00571 std::string IOManagerDB::getTestID(const std::string& runId, 
00572                    const unsigned firstScanNumber) const{
00573   std::ostringstream select;
00574   select << "SELECT TestID FROM tblTests WHERE "
00575          << "(RunID = " << runId << ") AND "
00576      << "(FirstScanNr = " << firstScanNumber << ")";
00577   return executeQueryReturnID(select.str());
00578 }
00579 
00580 std::string IOManagerDB::getScanID(const std::string& testId,
00581                                    const unsigned scanNumber) const{
00582   std::ostringstream select;
00583   select << "SELECT ScanID FROM tblScans WHERE "
00584          << "(TestID = " << testId << ") AND "
00585      << "(ScanNr = " << scanNumber << ")";
00586   return executeQueryReturnID(select.str());
00587 }
00588 
00589 std::string IOManagerDB::getLayerID(const std::string& layerName) const{
00590   std::ostringstream select;
00591   select << "SELECT LayerID FROM tblLayers WHERE "
00592      << "(LayerName = " << "'" << layerName << "'" << ")";
00593   return executeQueryReturnID(select.str());
00594 }
00595 
00596 std::string IOManagerDB::getRowID(const std::string& layerId,
00597                                   const std::string& LMTnr) const{
00598   std::ostringstream select;
00599   select << "SELECT RowID FROM tblRows WHERE "
00600          << "(LayerID = " << layerId << ") AND "
00601      << "(LMTNr = " << "'" << LMTnr << "'" << ")";
00602   return executeQueryReturnID(select.str());
00603 }
00604 
00605 std::string IOManagerDB::getPositionID(const std::string& rowId,
00606                                        const std::string& positionNumber) const{
00607   std::ostringstream select;
00608   select << "SELECT PositionID FROM tblPositions WHERE "
00609          << "(RowID = " << rowId << ") AND "
00610      << "(PositionNr = " << "'" << positionNumber << "'" << ")";
00611   return executeQueryReturnID(select.str());
00612 }
00613 
00614 std::string IOManagerDB::getModuleID(const std::string& moduleNumber) const{
00615   std::ostringstream select;
00616   select << "SELECT ModuleID FROM tblModules WHERE "
00617      << "(ModuleNr = " << "'" << moduleNumber << "'" << ")";
00618   return executeQueryReturnID(select.str());
00619 }
00620 //-------------------- Get-an-ID methods --------------------//
00621 
00622 //-------------------- Add-to-db methods --------------------//
00623 void IOManagerDB::addRun(unsigned long runNumber, bool trash) const{
00624   std::ostringstream select;
00625   select << "INSERT INTO tblRuns \n"
00626      << "(DataSetID, RunNr, Trash) \n"
00627          << "VALUES ( \n"
00628          << getDataSetID() << ", " << runNumber << ", " << trash << ")";
00629 
00630   executeQuery(select.str());
00631 
00632   if (mysql_affected_rows(m_mysql)!=1){
00633     throw MysqlException("Did NOT add row", select.str(), __FILE__, __LINE__);
00634   }
00635 }
00636 
00637 void IOManagerDB::addTest(const TestData& testdata, bool alsoAddScans) const{
00638   std::ostringstream select;
00639   select << "INSERT INTO tblTests \n"
00640      << "(RunID, TestTypeID, FirstScanNr, StartTime, EndTime) \n"
00641          << "VALUES ( \n"
00642          << getRunID(testdata.runNumber) << ", "
00643          << getTestTypeID(testdata.testName) << ", "
00644          << testdata.startScanNumber << ", "
00645      << "'" << convertToMysqlDateTimeFormat(testdata.startTime) << "', "
00646      << "'" << convertToMysqlDateTimeFormat(testdata.endTime) << "')";
00647 
00648   executeQuery(select.str());
00649 
00650   if (mysql_affected_rows(m_mysql)!=1){
00651     throw MysqlException("Did NOT add row", select.str(), __FILE__, __LINE__);
00652   }
00653   if (alsoAddScans){
00654     for (unsigned iscan=testdata.startScanNumber; 
00655      iscan < (testdata.startScanNumber + testdata.nScans);
00656      ++iscan){
00657       addScan(testdata, iscan);
00658     }
00659   }
00660 }
00661 
00662 void IOManagerDB::addScan(const TestData& testdata, unsigned scanNumber) const{
00663   std::ostringstream select;
00664   std::string runId = getRunID(testdata.runNumber);
00665   select << "INSERT INTO tblScans \n"
00666      << "(TestID, ScanNr) \n"
00667          << "VALUES ( \n"
00668          << getTestID(runId, testdata.startScanNumber) << ", "
00669          << scanNumber << ")";
00670 
00671   executeQuery(select.str());
00672 
00673   if (mysql_affected_rows(m_mysql)!=1){
00674     throw MysqlException("Did NOT add row", select.str(), __FILE__, __LINE__);
00675   }
00676 }
00677 
00678 void IOManagerDB::addModule(const std::string& layerName,
00679                             const std::string& LMTnr,
00680                             const std::string& positionNumber,
00681                             const std::string& moduleNumber) const{
00682   std::ostringstream select;
00683   std::string layerId = getLayerID(layerName);
00684   std::string rowId = getRowID(layerId, LMTnr);
00685   std::string positionId = getPositionID(rowId, positionNumber);
00686 
00687   select << "INSERT INTO tblModules \n"
00688      << "(PositionID, ModuleNr) \n"
00689          << "VALUES (" << positionId << ", "
00690          << "'" << moduleNumber<< "'" << ")";
00691 
00692   executeQuery(select.str());
00693 
00694   if (mysql_affected_rows(m_mysql)!=1){
00695     throw MysqlException("Did NOT add row", select.str(), __FILE__, __LINE__);
00696   }
00697 }
00698 
00699 void IOManagerDB::addRawDataRecord(const std::string& moduleId, const std::string& scanId) const{
00700   std::ostringstream insert;
00701 
00702   insert << "INSERT INTO tblRawData \n"
00703          << "(ModuleID, ScanID) \n"
00704          << "VALUES ( \n"
00705          << moduleId << ", "
00706          << scanId << ")";
00707 
00708   mysql_query(m_mysql, insert.str().c_str());
00709   checkForMySqlErrors("Cannot execute: ", insert.str(), __FILE__, __LINE__);
00710   if (mysql_affected_rows(m_mysql)!=1){
00711     throw MysqlException("Did NOT add row", insert.str(), __FILE__, __LINE__);
00712   }
00713 }
00714 
00715 void IOManagerDB::addRawDataBlob(const std::string& moduleId, const std::string& scanId,
00716                      const char *chBuf, const long bufSize) const{
00717 
00718 // Somebody (Alan?) should have a look at the handling of the buffers here...
00719 
00720 // Get file size & create a buffer of that size
00721 //    long bufSize = rawDataBlob.size();
00722 //    char *chBuf = new char [bufSize];
00723 
00724   // Start of query string
00725   char chMySql[1000000] = "UPDATE tblRawData SET RawDataBlob = '";
00726 
00727   // Pointer to end of query string
00728   char* chTail;
00729   chTail = chMySql + strlen(chMySql);
00730 
00731   // Check if buffer is large enough
00732   if ((chTail + 2*bufSize) + 3 > chMySql + sizeof(chMySql)) {
00733     throw MysqlException("Buffer to small for binary data", __FILE__, __LINE__);
00734   }
00735 
00736   // Add binary data to the query string
00737   chTail += mysql_real_escape_string(m_mysql, chTail, chBuf, bufSize);
00738 
00739   // End of query string
00740   std::string sqlEnd;
00741   sqlEnd = "' WHERE (ModuleID = " + moduleId + ") AND (" + "ScanID = " + scanId + ")";
00742   (void) strcpy (chTail, sqlEnd.c_str());
00743 
00744   // Write to MySQL db
00745   mysql_real_query(m_mysql, chMySql, strlen(chMySql));
00746   checkForMySqlErrors("Cannot execute: ", "...(binary data)..." + sqlEnd, __FILE__, __LINE__);
00747 
00748   // Check if exactly one row were updated. Note: this check seems to fail if exactly the same 
00749   //  binary contents in the buffer already exists in the db!? (How can the MySQL engine check this?)
00750   if (mysql_affected_rows(m_mysql) != 1){
00751     throw MysqlException("Did NOT update row", "...(binary data)..." + sqlEnd, __FILE__, __LINE__);
00752   }
00753 }
00754 //-------------------- Add-to-db methods --------------------//
00755 
00756 //-------------------- Read-from-db methods --------------------//
00757 std::string IOManagerDB::getRawDataBlob(const std::string& moduleId,
00758                                         const std::string& scanId) const{
00759 
00760   // MySQL variables. Use that boost stuff??
00761 //  shared_ptr<MYSQL_RES> rsBin;
00762   MYSQL_RES* rsBin; 
00763   MYSQL_ROW  rwBin; 
00764 
00765 // Create SQL string which retrieves the blob
00766   string sSQL;
00767   sSQL = "SELECT RawDataBlob FROM tblRawData WHERE (ModuleID = "
00768        + moduleId + ") AND (" + "ScanID = " + scanId + ")";
00769 
00770 // First check is the blob contains NULL (otherwise problems later with mysql_fetch_row)
00771   string sIsNullSQL;
00772   sIsNullSQL = "SELECT (" + sSQL + ") IS NULL";
00773 
00774   // Read data from MySQL db
00775   mysql_real_query(m_mysql, sIsNullSQL.c_str(), strlen(sIsNullSQL.c_str())); 
00776   checkForMySqlErrors("Cannot execute: ", sIsNullSQL, __FILE__, __LINE__);
00777 
00778   // Store the result
00779   rsBin = mysql_store_result(m_mysql); 
00780   checkForMySqlErrors("Can't store the result of query: ", sIsNullSQL, __FILE__, __LINE__);
00781 
00782   // Get the row (there should be only one row in the recordset)
00783   rwBin = mysql_fetch_row(rsBin); 
00784   checkForMySqlErrors("Can't fetch the first row of query: ", sIsNullSQL, __FILE__, __LINE__);
00785 
00786   // If the blob is not null, then the query will be "0".
00787   if ((string)rwBin[0] != "0"){
00788     std::cout << "Oops, blob is null in the db. Returning zero-length-string" << std::endl;
00789     return "";
00790   }
00791 
00792   // Now read the blob itself from the db
00793   mysql_real_query(m_mysql, sSQL.c_str(), strlen(sSQL.c_str())); 
00794   checkForMySqlErrors("Cannot execute: ", sSQL, __FILE__, __LINE__);
00795 
00796 // Debug cout
00797 std::cout << "getRawDataBlob: Binary data read from the MySQL db." << std::endl;
00798 
00799   // Store the result
00800   rsBin = mysql_store_result(m_mysql); 
00801   checkForMySqlErrors("Can't store the result of query: ", sSQL, __FILE__, __LINE__);
00802 
00803 // Debug cout
00804 std::cout << "getRawDataBlob: Recordset retrieved successfully." << std::endl;
00805 
00806   // Get number of rows in the record set
00807   int iNrOfRows = (int) mysql_num_rows(rsBin);
00808 
00809 // Debug cout
00810 std::cout << "getRawDataBlob: Number of records in recordset: " << iNrOfRows << std::endl;
00811 
00812   // Get the row (there should be only one row in the recordset)
00813   rwBin = mysql_fetch_row(rsBin); 
00814   checkForMySqlErrors("Can't fetch the first row of query: ", sSQL, __FILE__, __LINE__);
00815 
00816   // Copy the result to a str::string.
00817   // Careful, the result may contain NULL characters: use string(charArray, length) syntax
00818   unsigned long *lSize; 
00819   lSize = mysql_fetch_lengths(rsBin); 
00820   string sBin(rwBin[0], lSize[0]);
00821 
00822 // Debug cout
00823 std::cout << "getRawDataBlob: Size of blob: " << lSize[0] << endl;
00824 
00825   // Release the space allocated by mysql_store_data
00826   mysql_free_result(rsBin);
00827 
00828   // Close and return string with blob
00829   return sBin;
00830 }
00831 
00832 //-------------------- Read-from-db methods --------------------//
00833 
00834 //-------------------- Stuff to execute query --------------------//
00835 
00836 void IOManagerDB::executeQuery(std::string query) const {
00837   using namespace boost::posix_time;
00838   ptime query_start_time(microsec_clock::local_time());
00839   
00840   mysql_query(m_mysql, query.c_str());
00841 
00842   {
00843     ptime query_end_time(microsec_clock::local_time());
00844     boost::recursive_mutex::scoped_lock lock(timingAccess);
00845     query_time=query_time+(query_end_time-query_start_time);
00846     m_nQueries++;
00847   }
00848 
00849   checkForMySqlErrors("Cannot execute: ", query, __FILE__, __LINE__);
00850 
00851 }
00852 
00853 
00854 std::string IOManagerDB::executeQueryReturnID(std::string query) const{
00855   executeQuery(query);
00856   
00857   shared_ptr<MYSQL_RES> result = getResult();
00858   
00859   unsigned nmatch = mysql_num_rows(result.get());
00860   if (nmatch != 1){
00861     return "";
00862   }
00863   MYSQL_ROW row = mysql_fetch_row(result.get());
00864   checkForMySqlErrors("Can't fetch the first row of query: ", query, __FILE__, __LINE__);
00865   return row[0];
00866 }
00867 
00868 boost::shared_ptr<MYSQL_RES> IOManagerDB::getResult() const{
00869   if (!m_mysql) throw Sct::LogicError("m_mysql not initialised!", __FILE__, __LINE__);
00870 
00871   MySqlFreeResultDeleter d;
00872   shared_ptr<MYSQL_RES> result (mysql_store_result(m_mysql), d);
00873   checkForMySqlErrors("Error storing result", __FILE__, __LINE__);  
00874   return result;
00875 }
00876 
00877 void IOManagerDB::MySqlFreeResultDeleter::operator () (MYSQL_RES* result) throw() {
00878   //std::cout << "  IOManagerDB::MySqlFreeResultDeleter operator () called ! yippee! " << std::endl;
00879   mysql_free_result(result);
00880 //-------------------- Stuff to execute query --------------------//
00881 }
00882 
00883 } //End of namespace SctArchiving

Generated on Mon Feb 6 14:01:21 2006 for SCT DAQ/DCS Software - C++ by  doxygen 1.4.6