BRAT 2.4.5
Class index
Full class index
brahmlib
BRAHMS
ROOT page
//____________________________________________________________________
//  
// 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>
Last Update on by

Validate HTML
Validate CSS