|
//____________________________________________________________________ // // Base class for BRAHMS databases. Individual database classes can // inherit from this and then define the mathods in needs. E.g., a // calibration databse classs, can define the methods // "BrCalibObj* GetAround(time_t t)" to get calibration valid around // the unix_timestamp t, and a run database could define "BrRunInfo* // GetRun(int no)" etc. // // The actual database name is stored on the TNamed::fTitle, while the // symbolic name is stored in TNamed::fName // // $Author: videbaek $ // $Date: 2002/04/23 15:35:33 $ // $Copyright: BRAHMS Collabration // $Id: BrRdbmDb.cxx,v 1.4 2002/04/23 15:35:33 videbaek Exp $ // #include <BrRdbmDb.h> #include <TString.h> #include <Getline.h> #include <TSystem.h> #include <TInetAddress.h> #ifndef ROOT_TRegexp #include "TRegexp.h" #endif #include <iostream.h> #include <fstream.h> #include <iomanip.h> #include <sys/stat.h> #ifdef BR_USE_EXCEPTIONS #undef BR_USE_EXCEPTIONS #endif //____________________________________________________________________ ClassImp(BrRdbmDb); // Brahms Database class //____________________________________________________________________ BrRdbmDb::BrRdbmDb(const Char_t* name, const Char_t* title) : BrVirtualDb(name, title) { // Protected constructor. fConnection = 0; fRdbmType = BRAHMS_RDBM_TYPE; } //____________________________________________________________________ BrRdbmDb::~BrRdbmDb() { Close(); } //____________________________________________________________________ Bool_t BrRdbmDb::Connect(Option_t* option) { // Connect to the database. If we're already connected, just return // the connection. This method fails and returns 0 (zero) if: // // Server host name isn't set // Database isn't set // Can't get the password (See ReadUserPasswd) // Can't get the username (See ReadUserPasswd) // Some DB server/client error // // Options: // NONE // // If we're already connected, then just return the connection if (fConnection && fConnection->IsConnected()) return kTRUE; // If the server hostname isn't set, return 0; if (fHostName.IsNull()) { Error("Connect", "no host specified"); return 0; } // If the database name isn't set return 0 if (!GetDbName()) { Error("Connect", "no database specified"); return 0; } // If the password isn't set, try to get it. if (fPasswd.IsNull()) { if (!ReadUserPasswd()) { #ifdef BR_USE_EXCEPTIONS throw new BrError("Connect", "Couldn't get user and password"); #else Error("Connect", "Couldn't get user and password"); return kFALSE; #endif } } // Correct local host to the real host name, needed by MySQL C API if (!fHostName.CompareTo("localhost")) fHostName = gSystem->HostName(); // Make the full name out of the components Char_t * fullName=Form("%s://%s/%s", fRdbmType.Data(), fHostName.Data(), GetDbName()); // Make the actual connect, or at least try to fConnection = TSQLServer::Connect(fullName, fUserName.Data(), (fPasswd.IsNull() ? "" : fPasswd.Data() )); if (!fConnection || !fConnection->IsConnected()) { #ifdef BR_USE_EXCEPTIONS throw new BrFatal("BrRdbmDb::Connect", "User %s couldn't connect to database %s @ %s", fUserName.Data(), GetDbName(), fHostName.Data()); #else Error("Connect", "User %s couldn't connect to database %s @ %s", fUserName.Data(), GetDbName(), fHostName.Data()); return kFALSE; #endif } return kTRUE; } //____________________________________________________________________ void BrRdbmDb::Close(Option_t* option) { // Clsoe the database connection if (!fConnection) return; fConnection->Close(); delete fConnection; fConnection = 0; } //____________________________________________________________________ Bool_t BrRdbmDb::ReadUserPasswd() { // // See ReadBratDbRc, PromptUser, and PromptPasswd // if (ReadBratDbRc()) return kTRUE; if (fUserName.IsNull()) { if (!PromptUser()) return kFALSE; } if (!PromptPasswd()) return kFALSE; return kTRUE; } //____________________________________________________________________ Bool_t BrRdbmDb::ReadBratDbRc() { // Read ~/.bratdbrc to look for a valid host, db, user, and password // entry. The file MUST be read-write for user ONLY! // // Format of file is // // host db user passwd // // Lines starting with '#' are ignored. // if (fHostName.IsNull() || !GetDbName()) { #ifdef BR_USE_EXCEPTIONS throw new BrError("ReadBratDbRc", "Need a host and a database name"); #else Error("ReadBratDbRc", "Need a host and a database name"); return kFALSE; #endif } // The file name char* fileName = gSystem->ConcatFileName(gSystem->HomeDirectory(), ".bratdbrc"); #ifndef WIN32 struct stat statBuffer; if (stat(fileName, &statBuffer) != 0) { cout << "Coulnd't stat \"" << fileName << "\"" << endl; return kFALSE; } if (!S_ISREG(statBuffer.st_mode)) { cout << "\"" << fileName << "\" isn't a regular file" << endl; return kFALSE; } if (S_ISDIR(statBuffer.st_mode)) { cout << "\"" << fileName << "\" is a directory" << endl; return kFALSE; } if ((statBuffer.st_mode & 0777) != (S_IRUSR | S_IWUSR)) { Warning("ReadBratDbRc", "Protection mode on \"%\" isn't 0600, but %o", fileName, (statBuffer.st_mode & 0777)); return kFALSE; } #endif ifstream file(fileName); if (file.fail()) { cout << "Couldn't open file \"" << fileName << "\"" << endl; return kFALSE; } TInetAddress addr = gSystem->GetHostByName(fHostName.Data()); if (addr.IsValid()) { fHostName = (char*)addr.GetHostName(); if (fHostName == "UnNamedHost") fHostName = (char*)addr.GetHostAddress(); } while (kTRUE) { TString hostFromFile(""); // Check for comment line signed char c = (char)file.peek(); if (c == '#') { // comment line hostFromFile.ReadLine(file); continue; } // Check for EOF if (c == EOF) break; // Read host name file >> hostFromFile; // Check for eof or read error if (file.fail()) break; // Check if we got the right host if (hostFromFile.CompareTo(fHostName)){ // Read rest of non-matching line hostFromFile.ReadLine(file); continue; } // Got matching host, now read database TString dbFromFile(""); file >> dbFromFile; // Check for eof or read error if (file.fail()) break; // Check if we got the right database if (dbFromFile.CompareTo(GetDbName())){ // Read rest of non-matching line hostFromFile.ReadLine(file); continue; } // Got the right database, now read the user. TString userFromFile(""); file >> userFromFile; // Check for eof or read error if (file.fail()) break; // if we got a user name in, we compare to user name from file, // otherwise, we accept it. if (!fUserName.IsNull()) { if (userFromFile.CompareTo(fUserName)){ // Read rest of non-matching line hostFromFile.ReadLine(file); continue; } } else fUserName = userFromFile; // Got the right user, now read the password, which we always // accept. TString passwdFromFile(""); file >> passwdFromFile; // Check for eof or read error if (file.fail()) break; // Set the output string fPasswd = passwdFromFile; break; } // Check for eof if (file.eof()) { cout << "No matching entry" << endl; return kFALSE; } // Check for read error if (file.fail()) { cerr << "Failure while read" << endl; return kFALSE; } return kTRUE; } //____________________________________________________________________ Bool_t BrRdbmDb::PromptUser() { // Prompt the user for a user name Gl_config("noecho", 0); char *us = Getline(Form("User name for database %s@%s: ", GetDbName(), fHostName.Data())); if (!us[0]) { cout << "Blank user name" << endl; return kFALSE; } us[strlen(us)-1] = 0; // get rid of n fUserName = us; return kTRUE; } //____________________________________________________________________ Bool_t BrRdbmDb::PromptPasswd() { // Prompt the user for a user name Gl_config("noecho", 1); char *pw = Getline(Form("%s's password for database %s@%s: ", fUserName.Data(), GetDbName(), fHostName.Data())); Gl_config("noecho", 0); if (!pw[0]) { cout << "No password" << endl; return kFALSE; } pw[strlen(pw)-1] = 0; // get rid of n fPasswd = pw; return kTRUE; } //____________________________________________________________________ Bool_t BrRdbmDb::IsConnected(void) const { // Checks to see if we're still connected to the server. Throws a // BrException on error. if (!fConnection) { #ifdef BR_USE_EXCEPTIONS throw new BrError("BrRdbmDb::IsConnected", "No conenction to database %s on %host", GetDbName(), fHostName.Data()); #else // Warning("IsConnected", // "No conenction to database %s on %s", // GetDbName(), fHostName.Data()); return kFALSE; #endif } if (!fConnection->IsConnected()) { #ifdef BR_USE_EXCEPTIONS throw new BrWarning("BrRdbmDb::IsConnected", "Isn't connected to database %s on %host", GetDbName(), fHostName.Data()); #else // Warning("IsConnected", // "Isn't connected to database %s on %s", // GetDbName(), fHostName.Data()); return kFALSE; #endif } return kTRUE; } //____________________________________________________________________ void BrRdbmDb::LockTables(const Char_t* writetables, int) { // Lock the tables specifed as a comma sepearated string, present in // the table. Throws BrException. BrDbQuery* query = new BrDbQuery("LOCK TABLES "); query->Append(BrDb::SplitList(writetables,"WRITE")); query->Append(", sequence WRITE"); if (!Query(query)) { #ifdef BR_USE_EXCEPTIONS throw new BrWarning("BrRdbmDb::LockTables", "Couldn't lock tables %s for WRITE", writetables); #else Warning("LockTables", "Couldn't lock tables %s for WRITE", writetables); return; #endif } fIsLocked = kTRUE; } //____________________________________________________________________ void BrRdbmDb::UnLockTables(void) { // Unlock previous locked tables. Throws BrException. if (!Query(new BrDbQuery("UNLOCK TABLES"))) { #ifdef BR_USE_EXCEPTIONS throw new BrWarning("BrRdbmDb::UnlockTables", "Couldn't unlock tables"); #else Warning("UnlockTables", "Couldn't unlock tables"); return; #endif } fIsLocked = kFALSE; } //____________________________________________________________________ Int_t BrRdbmDb::Increment(void) { // Increment sequnne in the database, and return the new // number. Should _always_ be inside the scope of a // LockTables("sequence, ...")! Throws a BrException. if (!fIsLocked) { #ifdef BR_USE_EXCEPTIONS throw new BrError("BrRdbmDb::Increment", "Tables are NOT locked"); #else Error("Increment", "Tables are NOT locked"); return -1; #endif } if(!Query(new BrDbQuery("UPDATE sequence SET id=LAST_INSERT_ID(id+1)"))) { #ifdef BR_USE_EXCEPTIONS throw new BrError("BrRdbmDb::Increment", "Couldn't increment sequence"); #else Error("Increment", "Couldn't increment sequence"); return -1; #endif } TSQLResult* res = Query(new BrDbQuery("SELECT LAST_INSERT_ID()")); if (!res) { #ifdef BR_USE_EXCEPTIONS throw new BrError("BrDb::Increment", "Couldn't get incremented sequence"); #else Error("BrDb::Increment", "Couldn't get incremented sequence"); delete res; return -1; #endif } TSQLRow* row = res->Next(); Int_t id = strtol(row->GetField(0), NULL, 0); delete res; delete row; return id; } //____________________________________________________________________ void BrRdbmDb::CreateSequence(void) { // Create the sequnce table in the database. This table is needed // to make unigue id's if (!fConnection->Query("CREATE TABLE sequence (id INT NOT NULL)")) { #ifdef BR_USE_EXCEPTIONS throw new BrError("CreateSequence", "Couldn't create sequence in db"); #else Error("CreateSequence", "Couldn't create sequence in db"); return; #endif } if (!fConnection->Query("INSERT INTO sequence VALUES(0)")) { #ifdef BR_USE_EXCEPTIONS throw new BrError("CreateSequence", "Couldn't init sequnce in db"); #else Error("CreateSequence", "Couldn't init sequnce in db"); #endif } } //____________________________________________________________________ TSQLResult* BrRdbmDb::Query(BrDbQuery* query) { if (!fConnection && fConnection->IsConnected()) return 0; return fConnection->Query(query->Data()); } //____________________________________________________________________ TSQLRow* BrRdbmDb::GetSingle(const Char_t* tablename, const Char_t* condition) { // Get a single instance of a table. the first argument should be a // valid SQL command, like "SELECT * FROM Persons WHERE", the second // SQL where-like condition(s) e.g., "name like '%%%s%%'" // The third is a (optional) list of variadic arguments - akin to // printf(...) et al. // Please note indiviual Get... methods for valid fields. // NB: Double "%%" is used to mean single "%" in the SQL query - // that is, a C escape of "%" variadic functions. BrDbQuery* query = BrDbQuery::Select(tablename, 0, condition); TSQLResult* res = Query(query); Int_t count = res->GetRowCount(); if(count != 1) { #ifdef BR_USE_EXCEPTIONS throw new BrWarning("BrRdbmDb::GetSingle", "Too many or too few matches on query %s: %d", query->Data(), count); #else Warning("GetSingle", "Too many or too few matches on query %s: %d", query->Data(), count); delete query; return 0; #endif } delete query; return res->Next(); } //____________________________________________________________________ TSQLResult* BrRdbmDb::GetMultiple(const Char_t* tablename, const Char_t* condition) { // As above, but a result set is returned. BrDbQuery* query = BrDbQuery::Select(tablename, 0, condition); TSQLResult* res = Query(query); Int_t count = res->GetRowCount(); if(count < 1) return 0; // throw new BrWarning("BrRdbmDb::GetMultiple", // "No matches on query %s: %d", // query->Data()); return res; } |
||||||
This page automatically generated by script docBrat by Christian Holm |
Copyright ; 2002 BRAHMS Collaboration
<brahmlib@rcf.rhic.bnl.gov>
|