TDbiConnection.cxx
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007 #include <cctype>
00008 #include <cstdlib>
00009 #include <list>
00010 #include <sstream>
00011 #include <string>
00012
00013 #include "TList.h"
00014 #include "TString.h"
00015 #include "TSystem.h"
00016
00017 #include "TDbi.hxx"
00018 #include "TDbiAsciiDbImporter.hxx"
00019 #include "TDbiConnection.hxx"
00020 #include "TDbiExceptionLog.hxx"
00021 #include "TDbiServices.hxx"
00022 #include <TSK_DBI_Log.hxx>
00023 #include <MsgFormat.h>
00024 using std::endl;
00025 #include <TSK_DBI_Log.hxx>
00026
00027 ClassImp(TDbiConnection)
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041 TDbiConnection::TDbiConnection(const std::string& url ,
00042 const std::string& user ,
00043 const std::string& password ,
00044 int maxConnects) :
00045
00046 fUrl(url.c_str()),
00047 fUser(user),
00048 fPassword(password),
00049 fUrlValidated(false),
00050 fNumConnectedStatements(0),
00051 fIsTemporary(true),
00052 fServer(0)
00053 {
00054
00055
00056
00057
00058 fMaxConnectionAttempts = maxConnects;
00059
00060 SK_DBI_Trace( "Creating TDbiConnection" << " ");
00061
00062 if ( this->Open() ) {
00063 SK_DBI_Info( "Successfully opened connection to: " << this->GetUrl() << " ");
00064 fUrlValidated = true;
00065
00066
00067 this->SetTableExists();
00068
00069
00070 if ( fUrlValidated ) {
00071 #if ROOT_VERSION_CODE >= ROOT_VERSION(5,15,9)
00072 if ( ! fServer->HasStatement() ) {
00073 #else
00074 if ( ! fServer->IsSupportStatement() ) {
00075 #endif
00076 SK_DBI_Severe( " This client does not support prepared statements." << " ");
00077 fUrlValidated = false;
00078 #if ROOT_VERSION_CODE >= ROOT_VERSION(5,15,9)
00079 }
00080 #else
00081 }
00082 #endif
00083
00084 std::string serverInfo(fServer->ServerInfo());
00085 if ( serverInfo < "4.1" ) {
00086 SK_DBI_Severe( "This MySQL server (" << serverInfo
00087 << ") does NOT support prepared statements." << " ");
00088 fUrlValidated = false;
00089 }
00090 if ( fUrlValidated ) {
00091 SK_DBI_Info( "This client, and MySQL server (" << serverInfo
00092 << ") supports prepared statements." << " ");
00093 }
00094 else {
00095
00096 SK_DBI_Severe( "\n"
00097 << "This version of MySQL does not support prepared statements.\n"
00098 << "\n"
00099 << "Please upgrade to MySQL (client and server) version 4.1 or greater \n"
00100 << "\n"
00101 << " ");
00102 }
00103
00104 }
00105 }
00106 if ( ! fUrlValidated ) {
00107 SK_DBI_Severe( "FATAL: " << "Aborting due to above errors" << " ");
00108 throw EBadConnection();
00109 }
00110 fDbName = fUrl.GetFile();
00111
00112
00113 }
00114
00115
00116
00117 TDbiConnection::~TDbiConnection() {
00118
00119
00120
00121
00122
00123 SK_DBI_Trace( "Destroying TDbiConnection" << " ");
00124 this->Close(true);
00125
00126 }
00127
00128
00129
00130
00131
00132
00133
00134 Bool_t TDbiConnection::Close(Bool_t force ) {
00135
00136 this->ClearExceptionLog();
00137 if ( this->IsClosed() ) return true;
00138
00139 if ( fNumConnectedStatements ) {
00140 if ( ! force ) {
00141 SK_DBI_Info( "Unable to close connection: " << this->GetUrl()
00142 << "; it still has "
00143 << fNumConnectedStatements << "active statements. " << " ");
00144 return false;
00145 }
00146 SK_DBI_Info( "Closing connection: " << this->GetUrl()
00147 << "; even though it still has "
00148 << fNumConnectedStatements << " active statements. " << " ");
00149 }
00150
00151 delete fServer;
00152 fServer = 0;
00153 SK_DBI_Debug( "Closed connection: " << this->GetUrl() << " ");
00154 return true;
00155
00156 }
00157
00158
00159
00160
00161
00162
00163 void TDbiConnection::CloseIdleConnection() {
00164
00165 if ( fIsTemporary && fNumConnectedStatements == 0 ) this->Close();
00166
00167 }
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178 TSQLStatement* TDbiConnection::CreatePreparedStatement(const std::string& sql) {
00179
00180 TSQLStatement* stmt = 0;
00181 if ( ! this->Open() ) return stmt;
00182 stmt = fServer->Statement(sql.c_str());
00183 if ( ! stmt ) {
00184 fExceptionLog.AddEntry(*fServer);
00185 }
00186 else stmt->EnableErrorOutput(false);
00187
00188 return stmt;
00189 }
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212 TSQLServer* TDbiConnection::GetServer() {
00213
00214
00215 if ( ! this->Open() ) return 0;
00216 return fServer;
00217 }
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227 const std::string& TDbiConnection::GetUrl() const {
00228
00229
00230
00231 static std::string url;
00232 url = const_cast<TDbiConnection*>(this)->fUrl.GetUrl();
00233 return url;
00234
00235 }
00236
00237
00238
00239
00240
00241
00242 Bool_t TDbiConnection::Open() {
00243
00244
00245 this->ClearExceptionLog();
00246 if ( ! this->IsClosed() ) return true;
00247
00248 if ( ! fUrl.IsValid() ) {
00249
00250 ostringstream oss;
00251 oss << "Unable to open connection: URL '" << fUrl.GetUrl() << "' is invalid";
00252 SK_DBI_Severe( oss.str() << " ");
00253 fExceptionLog.AddEntry(oss.str());
00254 return false;
00255 }
00256
00257
00258 int maxAttempt = fUrlValidated ? 100: fMaxConnectionAttempts ;
00259 for (int attempt = 1; attempt <= maxAttempt; attempt++) {
00260 fServer = TSQLServer::Connect(fUrl.GetUrl(),fUser.c_str(),fPassword.c_str());
00261
00262 if ( ! fServer ) {
00263 ostringstream oss;
00264 oss << "Failing to open: " << fUrl.GetUrl() << " for user " << fUser
00265 << " and password " << fPassword << " (attempt " << attempt << ")";
00266 fExceptionLog.AddEntry(oss.str());
00267 if ( fMaxConnectionAttempts > attempt ){
00268
00269 if ( attempt == 1 ) {
00270 SK_DBI_Severe( " retrying ... " << " ");
00271 }
00272 SK_DBI_Log(" Waiting "<<attempt<<" seconds before trying again");
00273 gSystem->Sleep(attempt*1000);
00274 }
00275 }
00276
00277 else {
00278 fServer->EnableErrorOutput(false);
00279 if ( attempt > 1 ) SK_DBI_Warn( "... Connection opened on attempt " << attempt << " ");
00280 SK_DBI_Debug( "Successfully opened connection to: " << fUrl.GetUrl() << " ");
00281
00282
00283
00284
00285 TString ascii_file = fUrl.GetAnchor();
00286 if ( ascii_file.IsNull() ) return true;
00287 gSystem->Setenv("DBI_CATALOGUE_PATH",gSystem->DirName(fUrl.GetAnchor()));
00288 TDbiAsciiDbImporter importer(ascii_file,fServer);
00289 const TDbiExceptionLog& el(importer.GetExceptionLog());
00290 if ( ! el.IsEmpty() ) {
00291 SK_DBI_Severe( "Failed to populate ASCII database from " << fUrl.GetUrl() << "\n"
00292 << el << " ");
00293 delete fServer;
00294 fServer = 0;
00295 return false;
00296 }
00297 fIsTemporary = TDbiServices::AsciiDBConectionsTemporary();
00298
00299 const std::list<std::string> tableNames(importer.GetImportedTableNames());
00300 std::list<std::string>::const_iterator itr(tableNames.begin()), itrEnd(tableNames.end());
00301 while ( itr != itrEnd ) {
00302 this->SetTableExists(*itr);
00303 ++itr;
00304 }
00305 return true;
00306
00307 }
00308 }
00309 SK_DBI_Severe( "... Failed to open a connection to: " << fUrl.GetUrl()
00310 << " for user " << fUser << " and pwd " << fPassword << " ");
00311
00312 return false;
00313
00314 }
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325 Bool_t TDbiConnection::PrintExceptionLog(Int_t level) const {
00326
00327
00328 return fExceptionLog.Size() != 0;
00329
00330 }
00331
00332
00333
00334
00335
00336 void TDbiConnection::RecordException() {
00337
00338 fExceptionLog.AddEntry(*fServer);
00339
00340 }
00341
00342
00343
00344
00345
00346
00347
00348 void TDbiConnection::SetTableExists(const std::string& tableName) {
00349
00350 if ( tableName == "" ) {
00351 TSQLStatement* stmt = CreatePreparedStatement("show tables");
00352 if ( stmt ) {
00353 if (stmt->Process()) {
00354 stmt->StoreResult();
00355 while (stmt->NextResultRow()) {
00356 std::string tn(stmt->GetString(0));
00357 this->SetTableExists(tn);
00358 }
00359 }
00360 delete stmt;
00361 stmt = 0;
00362 }
00363 }
00364 else {
00365 if ( ! this->TableExists(tableName) ) {
00366 fExistingTableList += ",'";
00367 fExistingTableList += tableName;
00368 fExistingTableList += "'";
00369 }
00370 }
00371 }
00372
00373
00374
00375 Bool_t TDbiConnection::TableExists(const std::string& tableName) const {
00376
00377
00378 std::string test("'");
00379 test += tableName;
00380 test += "'";
00381 return fExistingTableList.find(test) != std::string::npos;
00382 }
00383