Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
TSQLDriverManager.cxx
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file TSQLDriverManager.cxx
1 // $Id: TSQLDriverManager.cxx,v 1.3 2012/09/07 16:00:43 bbannier Exp $
2 //*-- Author : Valeriy Onuchin 14/02/2000
3 //
4 
6 //
7 // The basic service for managing a set of drivers and providing
8 // access to database. To create connection use GetConnection() method.
9 // The connection string can be specified by DSN or URL.
10 // The default format of URL string is:
11 //
12 // protocol:[subprotocol:][driver:]//host[:port]/[database][?options]
13 //
14 // where:
15 // protocol - DBMS type , e.g. mysql,oracle, etc.
16 // subprotocol - driver type , currently: "odbc"
17 // driver - driver name ( it could be alias name defined in /etc/odbcinst )
18 // or path to the driver lib, e.g. myodbc - /usr/local/lib/libmyodbc.so
19 //
20 // If absolute pathname is not specified, driver manager will try to
21 // find "lib[driver].so" in the following directories"
22 // /usr/lib,
23 // /usr/local/lib,
24 // $ROOTSYS/lib,
25 //
26 // host - host name or IP address of database server
27 // port - port number
28 // database - name of database
29 // options - string key=value's separated by ';' or '&'
30 //
31 // Example: "mysql:odbc:myodbc://myhost:3306/test?Trace=Yes;TraceFile=qq.log"
32 //
33 // You can do the same via "mysql://myhost/test?Trace=Yes;TraceFile=qq.log"
34 // The missing parts of connect string are set to default values.
35 //
36 // For MySQL these values are:
37 //
38 // subprotcol = odbc
39 // driver = /usr/local/lib/libmyodbc.so
40 // port = 3306
41 // database = test
42 // options = "Trace=;TraceFile="
43 //
44 //
45 // See also:
46 // TSQLConnection TSQLDriverInfo
47 //
49 
50 #include <RDBC/TSQLDriverManager.h>
51 #include <RDBC/TSQLConnection.h>
52 #include <RDBC/TSQLUrl.h>
53 #include <TList.h>
54 #include <TSystem.h>
55 #include <TClassTable.h>
56 #include <iostream>
57 #include <TROOT.h>
58 #include <TString.h>
59 #include <stdlib.h>
60 #include <TSysEvtHandler.h>
61 #include <TApplication.h>
62 #include <TInterpreter.h>
63 #include <RDBC/TSQLImporter.h>
64 
67 TList* gDataSources; // list of data sources
68 TList* gDrivers; // list of drivers
69 TList* gConnections; // list of connections
70 TString gRDBClibPath; // path to RDBC library
71 TSignalHandler* gSIGTERMhandler; // SIGTERM handler
72 TSignalHandler* gSIGQUIThandler; // SIGQUIT handler
73 Bool_t gHandlersInitiated = kFALSE; // kTRUE if handlers are initiated
75 //___________________________________________________________________
77 {
78 
80  return gSQLDriverManager;
81 }
82 
85 //
86 // Handler of "program terminate" signals == SIGTERM, SIGQUIT
87 //
89 class SIGTERMhandler: public TSignalHandler
90 {
91 public:
92  SIGTERMhandler(ESignals sig) : TSignalHandler(sig, kFALSE) { }
93 
94  Bool_t Notify() {
95  delete gSQLDriverManager;
96  gApplication->Terminate(0);
97  return kTRUE;
98  }
99 };
100 
102 //
103 // TSQLini is used for "Dynamic DSN connections"
104 //
106 class TSQLini: public TObject
107 {
108 private:
109  TString fOldIni; // old $ODBCINI
110  TString fNewIni; // temp $ODBCINI
111 
112 public:
113  TSQLini(TSQLUrl* url);
114  ~TSQLini();
115 };
116 
117 //___________________________________________________________________
119 {
120  // - save current $ODBCINI
121  // - redifine $ODBCINI to temporary file
122  // - write TSQLUrl to temporary $ODBCINI file
123 
124  TString homedir = "/tmp"; // gSystem->HomeDirectory(); //
125  fOldIni = gSystem->Getenv("ODBCINI");
126  fNewIni = homedir + Form("/.odbcini.%d",gSystem->GetPid()); // temporary
127  gSystem->Setenv("ODBCINI",fNewIni.Data());
128 
129  url->Print(fNewIni.Data());
130 }
131 
132 //___________________________________________________________________
134 {
135  // deallocate resources
136 
137  gSystem->Setenv("ODBCINI",fOldIni.Data()); // restore old $ODBCINI
138 
139  if(gSystem->Unlink(fNewIni.Data())) { // failed to delete file
140  TString message = "Failed to delete file: ";
141  message += fNewIni;
142  Warning("Restore ODBCINI",message.Data());
143  }
144 }
145 
148 Bool_t InitRDBCpath()
149 {
150  // define pathname to RDBC library
151 
152  gRDBClibPath = gInterpreter->GetSharedLibs();
153  int i1 = gRDBClibPath.Index("libRDBC.");
154  if ( i1 < 0 ) return kFALSE;
155  TString str = gRDBClibPath(0,i1);
156  int i2 = str.Last(' ');
157  str = gRDBClibPath(i2+1,gRDBClibPath.Length()-i2-1);
158  i2 = str.Index(' ');
159 
160  if(i2 == kNPOS) gRDBClibPath = str;
161  else gRDBClibPath=str(0,i2-1);
162 
163  gRDBClibPath = gSystem->DirName(gRDBClibPath.Data());
164  return !gRDBClibPath.IsNull();
165 }
166 
167 static Bool_t dummy = InitRDBCpath();
169 //___________________________________________________________________
171 {
172  // All handlers are initated just before the first connection, but
173  // after allocation of main resources ( gSystem, gROOT etc. )
174 
175  if(gHandlersInitiated) return;
176 
177  if(gSystem) gSystem->RemoveOnExit(gSQLDriverManager); // remove on exit
178  if(gInterpreter) gInterpreter->SaveGlobalsContext(); // proof against gROOT->Reset()
179 
180  // catch program termination signals SIGTERM ( aka 'kill -15 pid', 'kill -TERM pid')
181  // and SIGQUIT ( ^\ ) to remove gSQLDriverManager ( deallocate resources )
182 
183  gSIGTERMhandler = new SIGTERMhandler(kSigTermination);
184  gSIGQUIThandler = new SIGTERMhandler(kSigQuit);
185  if(gSystem) gSystem->AddSignalHandler(gSIGTERMhandler);
186  if(gSystem) gSystem->AddSignalHandler(gSIGQUIThandler);
187 
188  if(TClassTable::GetDict("TSQL")) {
189  InitRDBCpath();
190  }
191 
192  gHandlersInitiated = kTRUE;
193 }
194 
196 //___________________________________________________________________
198 {
199  // contructor.
200 
201  if(!gSQLDriverManager) {
202  gSQLDriverManager = this;
203  gDataSources = new TList(); // list of data sources
204  gDrivers = new TList(); // list of drivers
205  gConnections = new TList(); // list of drivers
206  } else {
207  Destroyed(); //
208  }
209 }
210 
211 //___________________________________________________________________
213 {
214  // destructor
215  //
216  // - deallocate/close all connections
217  // - free global enviroment
218 
219  if(gDebug) Warning("~TSQLDriverManager()","Shutting down DriverManager");
220  Shutdown();
221  Destroyed(); //
222 }
223 
224 //___________________________________________________________________
226 {
227  // Should be called before an application is to exit
228 
229  gConnections->Delete();
230  gDrivers->Delete();
231  gDataSources->Delete();
232  delete gDrivers;
233  delete gDataSources;
234  delete gConnections;
235  gDrivers = 0;
236  gDataSources = 0;
237  gConnections = 0;
238 
239  if(gODBCini) delete gODBCini;
240  gSQLDriverManager = 0;
241 }
242 
243 //___________________________________________________________________
245 {
246  // Fetch a list of all of currently loaded drivers
247  // to which the current caller has access.
248 
249  if(!TClassTable::GetDict("ODBCConnection")) {
250  gSQLDriverManager->Throw(new TSQLException(
251  "TSQLDriverManager::GetDrivers:RDBC-ODBC driver not loaded"));
252  return 0;
253  }
254 
255  return gDrivers = (TList*)gROOT->ProcessLineFast(
256  Form("ODBCConnection::RefreshDrivers((TList*)%ul)",gDrivers));
257 }
258 
259 //___________________________________________________________________
261 {
262  // Fetch a list of of all available data sources
263 
264  if(!TClassTable::GetDict("ODBCConnection")) {
265  gSQLDriverManager->Throw(new TSQLException(
266  "TSQLDriverManager::GetDataSources:RDBC-ODBC driver not loaded"));
267  return 0;
268  }
269 
270  return gDataSources = (TList*)gROOT->ProcessLineFast(
271  Form("ODBCConnection::RefreshDataSources((TList*)%ul)",gDataSources));
272 }
273 
275 #ifndef WIN32
276 // #ifdef HAVE_TERMIOS_H
277 // #include <termios.h>
278 // #define TERMIO struct termios
279 // #else
280 // #ifdef HAVE_TERMIO_H
281  #include <termio.h>
282  #define TERMIO struct termio
283 // #endif
284 
285 //___________________________________________________________________
286 TString EnterPassword()
287 {
288  // - type promt to "Enter password:"
289  // - when password string is entered it's not echoed on the screen
290 
291  TERMIO org,tmp;
292  TString pswd;
293  const int bufsiz = 128;
294  char passtr[bufsiz];
295 
296  if(isatty(fileno(stdout))) {
297  fputs("Enter password:",stdout);
298  fflush(stdout);
299  }
300  ioctl(fileno(stdin), (int) TCGETA, &org);
301  tmp = org;
302  tmp.c_lflag &= ~(ECHO | ISIG | ICANON);
303  tmp.c_cc[VMIN] = 1;
304  tmp.c_cc[VTIME]= 0;
305  ioctl(fileno(stdin),(int) TCSETA, &tmp);
306 
307  fgets(passtr,bufsiz,stdin); // get password string ( mysql use it's own func )
308 
309  pswd = passtr;
310  pswd.Chop(); // chop last char ( either eol,'\n','\r' )
311  ioctl(fileno(stdin),(int) TCSETA, &org);
312 
313  if (isatty(fileno(stdout))) fputc('\n',stdout);
314  return pswd;
315 }
316 
317 #else // WIN32 case
318  #include <conio.h>
319 
320 //___________________________________________________________________
321 TString EnterPassword()
322 {
323  // code stolen from mysql libmysl/get_password.c ... not tested
324 
325  char to[80];
326  char *pos=to,*end = to+sizeof(to)-1;
327  int i = 0;
328 
329  fprintf(stdout,"Enter password: ");
330 
331  for (;;) {
332  char tmp;
333  tmp = _getch();
334 
335  if (tmp == '\b' || (int) tmp == 127) {
336  if (pos != to) {
337  _cputs("\b \b");
338  pos--;
339  continue;
340  }
341  }
342  if (tmp == '\n' || tmp == '\r' || tmp == 3) break;
343  if (iscntrl(tmp) || pos == end) continue;
344  _cputs("*");
345  *(pos++) = tmp;
346  }
347 
348  while (pos != to && isspace(pos[-1]) == ' ') pos--; // Allow dummy space at end
349 
350  *pos=0;
351  _cputs("\n");
352 
353  return to;
354 }
355 #endif // WIN32
356 
357 
358 //___________________________________________________________________
360  const TString& user,
361  const TString& password )
362 {
363  // Attempts to establish a connection to the given Data Source
364  // Name (DSN). The TSQLDriverManager attempts to select an appropriate
365  // driver from the set of registered drivers.
366  //
367  // Parameters:
368  // url - DataSourceName string
369  // user - the database user on whose behalf the TSQLConnection
370  // is being made
371  // password - the user's password
372  //
373  // Returns:
374  // a TSQLConnection to the data source
375  //
376  // Throws:
377  // TSQLException - if a database access error occurs
378  //
379 
381  gSQLDriverManager->GetWarnings()->Delete(); // clear previous warnings
382 
383  TSQLConnection* con = 0;
384  TSQLUrl sqlurl(url);
385 
386  if(!sqlurl.IsValid()) {
387  gSQLDriverManager->Throw(new TSQLException(
388  Form("TSQLDriverManager::GetConnection:URL %s is not valid:-\n"
389  " Protocol : %s SubProtocol: %s Driver: %s Port: %d",
390  url.Data(),
391  sqlurl.GetProtocol().Data(),
392  sqlurl.GetSubProtocol().Data(),
393  sqlurl.GetDriver().Data(),
394  sqlurl.GetPort()
395  )));
396  return 0;
397  }
398 
399  TString pswd = password;
400 
401  if(pswd.IsNull()) pswd = EnterPassword();
402 
403  // anchor is used to specify import table/file/tree for opened connection
404  TString anchor = sqlurl.GetAnchor();
405 
406  if( sqlurl.GetProtocol()=="file" ||
407  sqlurl.GetProtocol()=="http" ||
408  sqlurl.GetProtocol()=="ftp" ) {
409  anchor = sqlurl;
410  sqlurl = "mysql:odbc://localhost/test"; // localhost mysql as proxy server
411  }
412 
413  sqlurl.AddOption("User=" + user); //
414  con = (TSQLConnection*)gSQLDriverManager->GetConnections()->FindObject(sqlurl.GetUrl().Data());
415 
416  if(con) { // connection exists
417  con->AddReference();
418  goto exit;
419  }
420 
421  if( (sqlurl.GetProtocol()=="odbc" || sqlurl.GetSubProtocol()=="odbc") ) {
422  if(!TClassTable::GetDict("ODBCConnection")) {
423  gSQLDriverManager->Throw(new TSQLException(
424  "TSQLDriverManager::GetConnection:RDBC-ODBC driver not loaded"));
425  return 0;
426  }
427 
428  TString dsn = sqlurl.GetDSN();
429 
430  if(gODBCini) { delete gODBCini; gODBCini = 0; }
431  if(sqlurl.IsDynamicDSN()) gODBCini = new TSQLini(&sqlurl); //
432 
433  con = (TSQLConnection*) gROOT->ProcessLineFast(Form(
434  "new ODBCConnection(\"%s\",\"%s\",\"%s\")",dsn.Data(),user.Data(),pswd.Data()));
435 
436  if(gODBCini) { delete gODBCini; gODBCini = 0; }
437  goto exit;
438  }
439 
440 exit:
441  if ( con && !con->fImp ) {
442  delete con;
443  con = 0;
444  return 0;
445  }
446  if(!con) return con;
447  TSQLImporter* importer = 0;
448 
449  if(!anchor.IsNull()) {
450 
451  importer = new TSQLImporter();
452  importer->Connect("Throw(TSQLException*)","TSQLDriverManager",gSQLDriverManager,"Throw(TSQLException*)");
453  importer->Import(anchor,con);
454 
455  if(!importer->IsValid() || gSQLDriverManager->GetWarnings()->GetSize()) {
456  delete importer;
457  delete con;
458  return 0;
459  }
460  }
461 
462  if(con->fImp) { // fImp==0 in case of error
463  if(con->References()==1) {
464  gSQLDriverManager->GetConnections()->Add(con);
465  con->SetURL(sqlurl.GetUrl()); // == set the name of connection
466  }
467  } else {
468  delete con;
469  return 0;
470  }
471  if(importer) delete importer;
472 
473  return con;
474 }
475 
476 //___________________________________________________________________
477 TSQLConnection* TSQLDriverManager::GetConnection( const TString& connectString )
478 {
479  // Attempts to establish a connection to the given database
480  // by specified connection string. This string is simply
481  // a series of keyword/value pairs, searated by semicolons,
482  // that contains information used to establish the connection.
483  // The TSQLDriverManager attempts to select an appropriate driver
484  // from the set of registered drivers.
485  //
486  // Parameters:
487  // connectString usually something like:
488  // "dsn=minos;uid=scott;pwd=tiger"
489  // Returns:
490  // a connection to the data source
491  // Throws:
492  // TSQLException - if a database access error occurs
493 
495  gSQLDriverManager->GetWarnings()->Delete(); // clear previous warnings
496 
497  if(gODBCini) { delete gODBCini; gODBCini = 0; }
498  TSQLConnection* con = 0;
499  con = (TSQLConnection*)gSQLDriverManager->GetConnections()->FindObject(connectString.Data());
500 
501  if(con) { // connection exists
502  con->AddReference();
503  goto exit;
504  }
505 
506  if(!TClassTable::GetDict("ODBCConnection")) {
507  gSQLDriverManager->Throw(new TSQLException(
508  "TSQLDriverManager::GetConnection:RDBC-ODBC driver not loaded"));
509  return 0;
510  }
511 
512  con = (TSQLConnection*) gROOT->ProcessLineFast(Form(
513  "new ODBCConnection(\"%s\")",connectString.Data()));
514 exit:
515  if(con->fImp) { // fImp==0 in case of error
516  if(con->References()==1) {
517  gSQLDriverManager->GetConnections()->Add(con);
518  con->SetURL(connectString.Data());
519  }
520  } else {
521  delete con;
522  return 0;
523  }
524  return con;
525 }
526 
527 //___________________________________________________________________
529 {
530  // Sets the maximum time in seconds that a driver will wait while
531  // attempting to connect to a database. Set to 0 to disable.
532  //
533  // Parameters:
534  // seconds - the login time limit in seconds
535 
536  if(TClassTable::GetDict("ODBCConnection"))
537  gROOT->ProcessLineFast(Form("ODBCConnection::SetLoginTimeout(%d)",seconds));
538 }
539 
540 //___________________________________________________________________
542 {
543  // Gets the maximum time in seconds that a driver can wait when
544  // attempting to log in to a database.
545  //
546  // Returns:
547  // the driver login time limit in seconds, or 0 if disabled.
548 
549  return TClassTable::GetDict("ODBCConnection") ?
550  (Int_t) gROOT->ProcessLineFast("ODBCConnection::GetLoginTimeout()") : 0;
551 }
552 
553 //___________________________________________________________________
555 {
556  // Fetch a list of all of currently opened connections.
557 
558  return gConnections;
559 }