Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-03 08:22:06

0001 // $Id: TSQLDriverManager.cxx,v 1.3 2012/09/07 16:00:43 bbannier Exp $
0002 //*-- Author : Valeriy Onuchin 14/02/2000
0003 //
0004 
0005 ////////////////////////////////////////////////////////////////////
0006 //
0007 // The basic service for managing a set of drivers and providing 
0008 // access to database. To create connection use GetConnection() method. 
0009 // The connection string can be specified by DSN or URL.
0010 // The default format of URL string is:
0011 //
0012 // protocol:[subprotocol:][driver:]//host[:port]/[database][?options]
0013 //
0014 // where:
0015 //    protocol - DBMS type , e.g. mysql,oracle, etc.
0016 //    subprotocol - driver type , currently: "odbc"
0017 //    driver - driver name ( it could be alias name defined in /etc/odbcinst ) 
0018 //             or path to the driver lib, e.g. myodbc - /usr/local/lib/libmyodbc.so
0019 //
0020 //             If absolute pathname is not specified, driver manager will try to
0021 //             find "lib[driver].so" in the following directories"
0022 //                /usr/lib,
0023 //                /usr/local/lib,
0024 //                $ROOTSYS/lib, 
0025 //
0026 //    host - host name or IP address of database server
0027 //    port - port number
0028 //    database - name of database
0029 //    options - string key=value's separated by ';' or '&'     
0030 //
0031 //  Example: "mysql:odbc:myodbc://myhost:3306/test?Trace=Yes;TraceFile=qq.log"
0032 //
0033 //  You can do the same via "mysql://myhost/test?Trace=Yes;TraceFile=qq.log"
0034 //  The missing parts of connect string are set to default values.
0035 // 
0036 //    For MySQL these values are:
0037 //
0038 //    subprotcol = odbc
0039 //    driver = /usr/local/lib/libmyodbc.so 
0040 //    port = 3306
0041 //    database = test
0042 //    options = "Trace=;TraceFile="  
0043 //
0044 //
0045 // See also: 
0046 //     TSQLConnection TSQLDriverInfo 
0047 //
0048 /////////////////////////////////////////////////////////////////////
0049 
0050 #include <RDBC/TSQLDriverManager.h>
0051 #include <RDBC/TSQLConnection.h>
0052 #include <RDBC/TSQLUrl.h>
0053 #include <TList.h>
0054 #include <TSystem.h>
0055 #include <TClassTable.h>
0056 #include <iostream>
0057 #include <TROOT.h>
0058 #include <TString.h>
0059 #include <stdlib.h>
0060 #include <TSysEvtHandler.h>
0061 #include <TApplication.h>
0062 #include <TInterpreter.h>
0063 #include <RDBC/TSQLImporter.h>
0064 
0065 ClassImpQ(TSQLDriverManager)
0066 /////////////////////////////////////////////////////////////////////
0067 TList* gDataSources;                // list of data sources
0068 TList* gDrivers;                    // list of drivers
0069 TList* gConnections;                // list of connections
0070 TString gRDBClibPath;               // path to RDBC library
0071 TSignalHandler* gSIGTERMhandler;    // SIGTERM handler
0072 TSignalHandler* gSIGQUIThandler;    // SIGQUIT handler
0073 Bool_t gHandlersInitiated = kFALSE; // kTRUE if handlers are initiated
0074 /////////////////////////////////////////////////////////////////////
0075 //___________________________________________________________________
0076 TSQLDriverManager* InitGlobalDriverManager()
0077 {
0078 
0079    if (!gSQLDriverManager) gSQLDriverManager = new TSQLDriverManager();
0080    return gSQLDriverManager;
0081 }
0082 
0083 TSQLDriverManager* gSQLDriverManager = InitGlobalDriverManager(); // 
0084 /////////////////////////////////////////////////////////////////////
0085 //
0086 // Handler of "program terminate" signals == SIGTERM, SIGQUIT
0087 //
0088 /////////////////////////////////////////////////////////////////////
0089 class SIGTERMhandler: public TSignalHandler
0090 {
0091 public:
0092    SIGTERMhandler(ESignals sig) : TSignalHandler(sig, kFALSE) { }
0093 
0094    Bool_t  Notify() {
0095       delete gSQLDriverManager;
0096       gApplication->Terminate(0);
0097       return kTRUE;
0098    }
0099 };
0100 
0101 /////////////////////////////////////////////////////////////////////
0102 //
0103 // TSQLini is used for "Dynamic DSN connections" 
0104 //
0105 /////////////////////////////////////////////////////////////////////
0106 class TSQLini: public TObject 
0107 {
0108 private:
0109    TString  fOldIni;    // old   $ODBCINI 
0110    TString  fNewIni;    // temp  $ODBCINI 
0111   
0112 public:
0113    TSQLini(TSQLUrl* url);
0114    ~TSQLini();
0115 };
0116 
0117 //___________________________________________________________________
0118 TSQLini::TSQLini(TSQLUrl* url)
0119 {
0120    // - save current $ODBCINI
0121    // - redifine $ODBCINI to temporary file
0122    // - write TSQLUrl to temporary $ODBCINI file
0123 
0124    TString homedir = "/tmp"; // gSystem->HomeDirectory();   //
0125    fOldIni = gSystem->Getenv("ODBCINI");
0126    fNewIni = homedir + Form("/.odbcini.%d",gSystem->GetPid()); // temporary
0127    gSystem->Setenv("ODBCINI",fNewIni.Data());
0128 
0129    url->Print(fNewIni.Data()); 
0130 }
0131 
0132 //___________________________________________________________________
0133 TSQLini::~TSQLini()
0134 {
0135    // deallocate resources
0136 
0137    gSystem->Setenv("ODBCINI",fOldIni.Data());   // restore old $ODBCINI
0138 
0139    if(gSystem->Unlink(fNewIni.Data())) { // failed to delete file 
0140       TString message  = "Failed to delete file: ";
0141       message +=  fNewIni;
0142       Warning("Restore ODBCINI",message.Data());   
0143    }
0144 }
0145 
0146 TSQLini* gODBCini = 0;
0147 /////////////////////////////////////////////////////////////////////
0148 Bool_t InitRDBCpath()
0149 {
0150    // define pathname to RDBC library
0151    
0152    gRDBClibPath = gInterpreter->GetSharedLibs();
0153    int i1 = gRDBClibPath.Index("libRDBC.");
0154    if ( i1 < 0 ) return kFALSE;
0155    TString str = gRDBClibPath(0,i1);
0156    int i2 = str.Last(' ');
0157    str = gRDBClibPath(i2+1,gRDBClibPath.Length()-i2-1);
0158    i2 = str.Index(' ');
0159    
0160    if(i2 == kNPOS) gRDBClibPath = str;
0161    else gRDBClibPath=str(0,i2-1);
0162    
0163    gRDBClibPath = gSystem->DirName(gRDBClibPath.Data()); 
0164    return !gRDBClibPath.IsNull();
0165 }
0166 
0167 static Bool_t dummy = InitRDBCpath();
0168 /////////////////////////////////////////////////////////////////////
0169 //___________________________________________________________________
0170 void InitHandlers()
0171 {
0172    // All handlers are initated just before the first connection, but
0173    // after allocation of main resources ( gSystem, gROOT etc. )
0174 
0175    if(gHandlersInitiated) return;
0176 
0177    if(gSystem) gSystem->RemoveOnExit(gSQLDriverManager); // remove on exit
0178    if(gInterpreter) gInterpreter->SaveGlobalsContext();  // proof against gROOT->Reset()
0179 
0180    // catch program termination signals SIGTERM ( aka 'kill -15 pid', 'kill -TERM pid')
0181    // and SIGQUIT ( ^\ ) to remove gSQLDriverManager ( deallocate resources )
0182  
0183    gSIGTERMhandler = new SIGTERMhandler(kSigTermination);
0184    gSIGQUIThandler = new SIGTERMhandler(kSigQuit); 
0185    if(gSystem) gSystem->AddSignalHandler(gSIGTERMhandler);
0186    if(gSystem) gSystem->AddSignalHandler(gSIGQUIThandler);
0187 
0188    if(TClassTable::GetDict("TSQL")) {
0189       InitRDBCpath();
0190    }
0191 
0192    gHandlersInitiated = kTRUE;
0193 }
0194 
0195 /////////////////////////////////////////////////////////////////////
0196 //___________________________________________________________________
0197 TSQLDriverManager::TSQLDriverManager():TSQL(0)
0198 {
0199    // contructor. 
0200 
0201    if(!gSQLDriverManager) {
0202       gSQLDriverManager = this;
0203       gDataSources  = new TList(); // list of data sources
0204       gDrivers = new TList();     // list of drivers
0205       gConnections = new TList();     // list of drivers
0206    } else {
0207       Destroyed();   //
0208    } 
0209 }
0210    
0211 //___________________________________________________________________
0212 TSQLDriverManager::~TSQLDriverManager()
0213 {
0214    // destructor
0215    //
0216    //  - deallocate/close all connections
0217    //  - free global enviroment  
0218    
0219    if(gDebug) Warning("~TSQLDriverManager()","Shutting down DriverManager");
0220    Shutdown();
0221    Destroyed();   //   
0222 }
0223 
0224 //___________________________________________________________________
0225 void TSQLDriverManager::Shutdown()
0226 {
0227    // Should be called before an application is to exit
0228 
0229    gConnections->Delete();
0230    gDrivers->Delete();
0231    gDataSources->Delete();
0232    delete gDrivers;
0233    delete gDataSources;
0234    delete gConnections;
0235    gDrivers = 0;
0236    gDataSources = 0;
0237    gConnections = 0;
0238 
0239    if(gODBCini) delete gODBCini;
0240    gSQLDriverManager = 0;      
0241 }
0242 
0243 //___________________________________________________________________
0244 TList* TSQLDriverManager::GetDrivers()
0245 {
0246    // Fetch a list of all of currently loaded drivers
0247    // to which the current caller has access. 
0248 
0249    if(!TClassTable::GetDict("ODBCConnection"))  {
0250       gSQLDriverManager->Throw(new TSQLException(
0251             "TSQLDriverManager::GetDrivers:RDBC-ODBC driver not loaded"));
0252       return 0;
0253    }
0254 
0255    return gDrivers = (TList*)gROOT->ProcessLineFast(
0256       Form("ODBCConnection::RefreshDrivers((TList*)%ul)",gDrivers));
0257 }
0258 
0259 //___________________________________________________________________
0260 TList* TSQLDriverManager::GetDataSources()
0261 {
0262    // Fetch a list of of all available data sources
0263 
0264    if(!TClassTable::GetDict("ODBCConnection"))  {
0265       gSQLDriverManager->Throw(new TSQLException(
0266          "TSQLDriverManager::GetDataSources:RDBC-ODBC driver not loaded"));
0267       return 0;
0268    }
0269  
0270    return gDataSources = (TList*)gROOT->ProcessLineFast(
0271       Form("ODBCConnection::RefreshDataSources((TList*)%ul)",gDataSources));
0272 }
0273 
0274 ////// EnterPassword() noecho mode for password typing ///////////////
0275 #ifndef WIN32
0276 // #ifdef HAVE_TERMIOS_H  
0277 //   #include        <termios.h>
0278 //   #define TERMIO  struct termios
0279 // #else
0280 //   #ifdef HAVE_TERMIO_H 
0281    #include        <termio.h>
0282    #define TERMIO  struct termio
0283 // #endif   
0284 
0285 //___________________________________________________________________
0286 TString EnterPassword()
0287 {
0288    // - type promt to "Enter password:" 
0289    // - when password string is entered it's not echoed on the screen 
0290 
0291    TERMIO org,tmp;
0292    TString pswd;
0293    const int bufsiz = 128;
0294    char passtr[bufsiz];
0295 
0296    if(isatty(fileno(stdout))) {
0297       fputs("Enter password:",stdout);
0298       fflush(stdout);
0299    }
0300    ioctl(fileno(stdin), (int) TCGETA, &org);
0301    tmp = org;
0302    tmp.c_lflag &= ~(ECHO | ISIG | ICANON);
0303    tmp.c_cc[VMIN] = 1;
0304    tmp.c_cc[VTIME]= 0;
0305    ioctl(fileno(stdin),(int) TCSETA, &tmp);
0306 
0307    fgets(passtr,bufsiz,stdin); // get password string ( mysql use it's own func )
0308 
0309    pswd = passtr;
0310    pswd.Chop();   // chop last char ( either eol,'\n','\r' )
0311    ioctl(fileno(stdin),(int) TCSETA, &org); 
0312 
0313    if (isatty(fileno(stdout))) fputc('\n',stdout);
0314    return pswd;
0315 }
0316 
0317 #else // WIN32 case
0318  #include <conio.h>
0319 
0320 //___________________________________________________________________
0321 TString EnterPassword()
0322 {
0323    // code stolen from mysql libmysl/get_password.c ... not tested
0324 
0325    char to[80];
0326    char *pos=to,*end = to+sizeof(to)-1;
0327    int i = 0;
0328 
0329    fprintf(stdout,"Enter password: ");
0330 
0331    for (;;) {
0332       char tmp;
0333       tmp = _getch();
0334 
0335       if (tmp == '\b' || (int) tmp == 127) {
0336          if (pos != to) {
0337             _cputs("\b \b");
0338             pos--;
0339             continue;
0340          }
0341       }
0342       if (tmp == '\n' || tmp == '\r' || tmp == 3) break;
0343       if (iscntrl(tmp) || pos == end) continue;      
0344       _cputs("*");
0345       *(pos++) = tmp;
0346    }
0347   
0348    while (pos != to && isspace(pos[-1]) == ' ') pos--; // Allow dummy space at end
0349 
0350    *pos=0;
0351    _cputs("\n");
0352   
0353    return to;
0354 }
0355 #endif  //  WIN32
0356 //////////////////// end of EnterPassword //////////////////////////
0357 
0358 //___________________________________________________________________
0359 TSQLConnection* TSQLDriverManager::GetConnection( const TString& url, 
0360                                                   const TString& user, 
0361                                                   const TString& password )
0362 {
0363    // Attempts to establish a connection to the given Data Source 
0364    // Name (DSN). The TSQLDriverManager attempts to select an appropriate 
0365    // driver  from  the set of registered drivers.
0366    //
0367    // Parameters:
0368    //    url   - DataSourceName string
0369    //    user  - the database user on whose behalf the TSQLConnection
0370    //            is being made
0371    //    password - the user's password
0372    //
0373    // Returns:
0374    //    a TSQLConnection to the data source
0375    //
0376    // Throws:
0377    //    TSQLException - if a database access error occurs
0378    //  
0379 
0380    if(!gHandlersInitiated) InitHandlers();
0381    gSQLDriverManager->GetWarnings()->Delete(); // clear previous warnings
0382 
0383    TSQLConnection* con = 0;  
0384    TSQLUrl sqlurl(url);
0385 
0386    if(!sqlurl.IsValid()) {
0387       gSQLDriverManager->Throw(new TSQLException(
0388              Form("TSQLDriverManager::GetConnection:URL %s is not valid:-\n"
0389                   "    Protocol : %s  SubProtocol: %s Driver: %s Port: %d",
0390                   url.Data(), 
0391                   sqlurl.GetProtocol().Data(),
0392                   sqlurl.GetSubProtocol().Data(),
0393                   sqlurl.GetDriver().Data(),
0394                   sqlurl.GetPort()
0395              )));
0396       return 0;
0397    }
0398 
0399    TString pswd = password;
0400 
0401    if(pswd.IsNull()) pswd = EnterPassword();
0402 
0403    // anchor is used to specify import table/file/tree for opened connection
0404    TString anchor = sqlurl.GetAnchor();
0405 
0406    if( sqlurl.GetProtocol()=="file" ||
0407        sqlurl.GetProtocol()=="http" ||
0408        sqlurl.GetProtocol()=="ftp" ) {
0409       anchor = sqlurl;
0410       sqlurl = "mysql:odbc://localhost/test";   //  localhost mysql as proxy server
0411    }
0412 
0413    sqlurl.AddOption("User=" + user);   // 
0414    con = (TSQLConnection*)gSQLDriverManager->GetConnections()->FindObject(sqlurl.GetUrl().Data());
0415 
0416    if(con) {         // connection exists
0417       con->AddReference();
0418       goto exit;
0419    }
0420 
0421    if( (sqlurl.GetProtocol()=="odbc" || sqlurl.GetSubProtocol()=="odbc") ) {   
0422       if(!TClassTable::GetDict("ODBCConnection"))  {
0423          gSQLDriverManager->Throw(new TSQLException(
0424                "TSQLDriverManager::GetConnection:RDBC-ODBC driver not loaded"));
0425          return 0;
0426       }
0427 
0428       TString dsn = sqlurl.GetDSN();
0429 
0430       if(gODBCini) { delete gODBCini; gODBCini = 0; }  
0431       if(sqlurl.IsDynamicDSN()) gODBCini = new TSQLini(&sqlurl); // 
0432    
0433       con = (TSQLConnection*) gROOT->ProcessLineFast(Form(
0434          "new ODBCConnection(\"%s\",\"%s\",\"%s\")",dsn.Data(),user.Data(),pswd.Data()));
0435  
0436       if(gODBCini) { delete gODBCini; gODBCini = 0; }      
0437       goto exit;
0438    }
0439 
0440 exit:
0441    if ( con && !con->fImp ) {
0442       delete con;
0443       con = 0;
0444       return 0;
0445    }
0446    if(!con) return con;
0447    TSQLImporter* importer = 0;
0448 
0449    if(!anchor.IsNull()) {
0450   
0451       importer = new TSQLImporter();
0452       importer->Connect("Throw(TSQLException*)","TSQLDriverManager",gSQLDriverManager,"Throw(TSQLException*)");
0453       importer->Import(anchor,con);
0454 
0455       if(!importer->IsValid() || gSQLDriverManager->GetWarnings()->GetSize()) {
0456          delete importer;
0457          delete con;
0458          return 0;
0459       }
0460    }
0461 
0462    if(con->fImp) {            // fImp==0 in case of error 
0463       if(con->References()==1) { 
0464          gSQLDriverManager->GetConnections()->Add(con);
0465          con->SetURL(sqlurl.GetUrl()); // == set the name of connection
0466       }
0467    } else {
0468       delete con;     
0469       return 0;
0470    }
0471    if(importer) delete importer;
0472 
0473    return con;   
0474 }
0475 
0476 //___________________________________________________________________
0477 TSQLConnection* TSQLDriverManager::GetConnection( const TString& connectString )
0478 {
0479    // Attempts to establish a connection to the given database 
0480    // by specified connection string. This string is simply
0481    // a series of keyword/value pairs, searated by semicolons,
0482    // that contains information used to establish the connection.
0483    // The TSQLDriverManager attempts to select an appropriate driver
0484    // from the set of registered drivers.
0485    //
0486    // Parameters:
0487    //    connectString usually something like:
0488    //                   "dsn=minos;uid=scott;pwd=tiger"
0489    // Returns:
0490    //    a connection to the data source
0491    // Throws:
0492    //    TSQLException - if a database access error occurs
0493 
0494    if(!gHandlersInitiated) InitHandlers();
0495    gSQLDriverManager->GetWarnings()->Delete(); // clear previous warnings
0496 
0497    if(gODBCini) { delete gODBCini; gODBCini = 0; }  
0498    TSQLConnection* con = 0;
0499    con = (TSQLConnection*)gSQLDriverManager->GetConnections()->FindObject(connectString.Data());
0500 
0501    if(con) {         // connection exists
0502       con->AddReference();
0503       goto exit;
0504    }
0505 
0506    if(!TClassTable::GetDict("ODBCConnection"))  {
0507       gSQLDriverManager->Throw(new TSQLException(
0508          "TSQLDriverManager::GetConnection:RDBC-ODBC driver not loaded"));
0509       return 0;
0510    }
0511 
0512    con = (TSQLConnection*) gROOT->ProcessLineFast(Form(
0513          "new ODBCConnection(\"%s\")",connectString.Data()));
0514 exit:
0515    if(con->fImp) {            // fImp==0 in case of error 
0516       if(con->References()==1) { 
0517          gSQLDriverManager->GetConnections()->Add(con);
0518          con->SetURL(connectString.Data());
0519       }
0520    } else {
0521       delete con;     
0522       return 0;
0523    } 
0524    return con;    
0525 }
0526 
0527 //___________________________________________________________________
0528 void TSQLDriverManager::SetLoginTimeout( Int_t seconds )
0529 {
0530    // Sets the maximum time in seconds that a driver will wait while
0531    // attempting to connect to a database. Set to 0 to disable. 
0532    //
0533    // Parameters:
0534    //       seconds - the login time limit in seconds
0535 
0536    if(TClassTable::GetDict("ODBCConnection")) 
0537       gROOT->ProcessLineFast(Form("ODBCConnection::SetLoginTimeout(%d)",seconds));
0538 }
0539 
0540 //___________________________________________________________________
0541 Int_t TSQLDriverManager::GetLoginTimeout()
0542 {
0543    // Gets the maximum time in seconds that a driver can wait when
0544    // attempting to log in to a database. 
0545    //
0546    // Returns:
0547    //       the driver login time limit in seconds, or 0 if disabled.
0548 
0549    return TClassTable::GetDict("ODBCConnection") ?
0550             (Int_t) gROOT->ProcessLineFast("ODBCConnection::GetLoginTimeout()") : 0;
0551 }
0552 
0553 //___________________________________________________________________
0554 TList* TSQLDriverManager::GetConnections()
0555 {
0556    // Fetch a list of all of currently opened connections. 
0557 
0558    return gConnections;
0559 }