#include <DbiStatement.h>
Public Member Functions | |
| DbiStatement (DbiConnection &conDb) | |
| virtual | ~DbiStatement () |
| Dbi::DbTypes | GetDBType () const |
| Bool_t | PrintExceptions (Int_t level=3) const |
| const DbiExceptionLog & | GetExceptionLog () const |
| std::list< TString > | TestTranslateSQL (const TString &sql, Dbi::DbTypes type) |
| Debugging of SQL translation. | |
| TSQLStatement * | ExecuteQuery (const TString &sql="") |
| Give caller a TSQLStatement of results (Process() and StoreResult() already performed.). | |
| Bool_t | ExecuteUpdate (const TString &sql="") |
| Apply an update and return success/fail. | |
Private Member Functions | |
| void | AppendExceptionLog (DbiException *e) |
| void | AppendExceptionLog (TSQLStatement *s) |
| void | AppendExceptionLog (DbiConnection &c) |
| void | ClearExceptionLog () |
| TSQLStatement * | CreateProcessedStatement (const TString &sql="") |
| std::list< TString > | TranslateSQL (const TString &sql) |
Private Attributes | |
| DbiConnection & | fConDb |
| Connection associated with this statement. | |
| Dbi::DbTypes | fDbType |
| Type of database (MySQL, Oracle). | |
| DbiExceptionLog | fExceptionLog |
DatabaseInterface
Contact: n.west1@physics.ox.ac.uk
Definition at line 44 of file DbiStatement.h.
|
|
Definition at line 35 of file DbiStatement.cxx. 00035 : 00036 fConDb(conDb), 00037 fDbType(conDb.GetDbType()) 00038 { 00039 // 00040 // 00041 // Purpose: Constructor 00042 // 00043 // Arguments: None. 00044 // 00045 // Return: 00046 // 00047 // conDb in The connection associated with the statement. 00048 // 00049 00050 LEA_CTOR //Leak Checker 00051 00052 MSG("Dbi", Msg::kVerbose) << "Creating DbiStatement" << endl; 00053 fConDb.ConnectStatement(); 00054 00055 }
|
|
|
Definition at line 59 of file DbiStatement.cxx. References DbiConnection::DisConnectStatement(), fConDb, LEA_DTOR, and MSG. 00059 {
00060 //
00061 //
00062 // Purpose: Destructor
00063
00064 LEA_DTOR //Leak Checker
00065 MSG("Dbi", Msg::kVerbose) << "Destroying DbiStatement" << endl;
00066
00067 fConDb.DisConnectStatement();
00068 }
|
|
|
Definition at line 83 of file DbiStatement.h. References DbiConnection::GetExceptionLog(). 00083 { fExceptionLog.AddLog(c.GetExceptionLog()); }
|
|
|
Definition at line 82 of file DbiStatement.h. References s(). 00082 { if ( s ) fExceptionLog.AddEntry(*s); }
|
|
|
Definition at line 81 of file DbiStatement.h. Referenced by CreateProcessedStatement(), ExecuteQuery(), and ExecuteUpdate(). 00081 { if ( e ) fExceptionLog.AddEntry(*e); }
|
|
|
Definition at line 84 of file DbiStatement.h. Referenced by ExecuteQuery(), and ExecuteUpdate(). 00084 { fExceptionLog.Clear(); }
|
|
|
Definition at line 72 of file DbiStatement.cxx. References AppendExceptionLog(), DbiConnection::CreatePreparedStatement(), and fConDb. Referenced by ExecuteQuery(). 00072 {
00073
00074 // Attempt to create a processed statement (caller must delete). Return 0 if failure.
00075
00076 TSQLStatement* stmt = fConDb.CreatePreparedStatement(sql.Data());
00077 if ( ! stmt ) {
00078 this->AppendExceptionLog(fConDb);
00079 return 0;
00080 }
00081 if ( stmt->Process() ) return stmt;
00082 this->AppendExceptionLog(stmt);
00083 delete stmt;
00084 stmt = 0;
00085 return 0;
00086
00087 }
|
|
|
Give caller a TSQLStatement of results (Process() and StoreResult() already performed.).
Definition at line 92 of file DbiStatement.cxx. References DbiExceptionLog::AddEntry(), AppendExceptionLog(), ClearExceptionLog(), CreateProcessedStatement(), fConDb, fExceptionLog, DbiConnection::GetDbName(), DbiExceptionLog::IsEmpty(), and MSG. Referenced by do_command(), DbuDaqConfigFilesText::LookupSeqNo(), and DbmValidate::TestGlobaliseSeqNo(). 00092 {
00093 //
00094 //
00095 // Purpose: Translate SQL if required and execute.
00096 // Return: TSQLStatement with Process() and StoreResult() already performed.
00097
00098 this->ClearExceptionLog();
00099
00100 std::list<TString> sqlList(this->TranslateSQL(sql));
00101 std::list<TString>::const_iterator itr(sqlList.begin()), itrEnd(sqlList.end());
00102
00103 TSQLStatement* stmt = 0;
00104 while (itr != itrEnd) {
00105 const TString& sql = *itr++;
00106 MSG("Dbi",Msg::kSynopsis) << "SQL:" << fConDb.GetDbName() << ":" << sql << endl;
00107 delete stmt;
00108 stmt = this->CreateProcessedStatement(sql);
00109 if ( ! stmt ) return 0;
00110 }
00111 // Store results from last SQL command (when multiple commands are generated
00112 // the last will be the one that performs the query).
00113 if ( stmt && ! stmt->StoreResult() ) {
00114 this->AppendExceptionLog(stmt);
00115 delete stmt;
00116 stmt = 0;
00117 }
00118
00119 // Final sanity check: If there is a statement then the exception log should still
00120 // be clear otherwise it should not be.
00121 if ( stmt ) {
00122 if ( ! fExceptionLog.IsEmpty() ) {
00123 delete stmt;
00124 stmt = 0;
00125 }
00126 }
00127 else if ( fExceptionLog.IsEmpty() ) {
00128 ostringstream oss;
00129 oss << "Unknown failure (no execption but no TSQLStatement either executing " << sql;
00130 fExceptionLog.AddEntry(oss.str().c_str());
00131 }
00132 return stmt;
00133
00134 }
|
|
|
Apply an update and return success/fail.
Definition at line 138 of file DbiStatement.cxx. References AppendExceptionLog(), ClearExceptionLog(), fConDb, fExceptionLog, DbiConnection::GetDbName(), DbiConnection::GetServer(), DbiExceptionLog::IsEmpty(), MSG, and DbiConnection::RecordException(). Referenced by DbuRunSummary::Commit(), DbuDaqFileSummary::Commit(), createSpillTables(), PhotonStatSummarizer::CreateTables(), CreateTables(), DbiCascader::CreateTemporaryTable(), do_command(), DbmValidate::PrepareDb(), DbiCascader::Lock::SetLock(), and DbuDaqMonitorModule::WriteSubRunSummaryEntry(). 00138 {
00139 //
00140 //
00141 // Purpose: Translate SQL if required and Execute.
00142 //
00143 // Return true if all updates successful.
00144
00145
00146 this->ClearExceptionLog();
00147
00148 std::list<TString> sqlList(this->TranslateSQL(sql));
00149 std::list<TString>::const_iterator itr(sqlList.begin()), itrEnd(sqlList.end());
00150
00151 while (itr != itrEnd) {
00152 const TString& sql = *itr++;
00153 MSG("Dbi",Msg::kSynopsis) << "SQL:" << fConDb.GetDbName() << ":" << sql << endl;
00154 bool ok = fConDb.GetServer()->Exec(sql.Data());
00155 if ( ! ok ) {
00156 fConDb.RecordException();
00157 this->AppendExceptionLog(fConDb);
00158 return false;
00159 }
00160 }
00161 return fExceptionLog.IsEmpty();
00162
00163 }
|
|
|
Definition at line 55 of file DbiStatement.h. Referenced by DbiCascader::Lock::SetLock(). 00055 { return fDbType; }
|
|
|
Definition at line 64 of file DbiStatement.h. Referenced by DbiCascader::Lock::SetLock(). 00064 { return fExceptionLog; }
|
|
|
Print accumulated exceptions at supplied Msg level, add them to the Global Exception Log if level >= kWarning and return true if there are any. Definition at line 167 of file DbiStatement.cxx. References DbiExceptionLog::AddLog(), DbiExceptionLog::GetGELog(), and MSG. Referenced by DbuRunSummary::Commit(), DbuDaqFileSummary::Commit(), DbiCascader::CreateStatement(), DbmValidate::PrepareDb(), DbiCascader::Lock::SetLock(), and DbmValidate::TestGlobaliseSeqNo(). 00167 {
00168
00169 // Purpose: Print accumulated exceptions at supplied Msg level,
00170 // add them to the Global Exception Log if level >= kWarning
00171 // and return true if there are any.
00172
00173 const DbiExceptionLog& el(this->GetExceptionLog());
00174 if ( el.IsEmpty() ) return false;
00175 MSG("Dbi", level) << el;
00176 if ( level >= Msg::kWarning ) DbiExceptionLog::GetGELog().AddLog(el);
00177 return true;
00178
00179 }
|
|
||||||||||||
|
Debugging of SQL translation.
Definition at line 183 of file DbiStatement.cxx. References fDbType. 00183 {
00184 //
00185 //
00186 // Purpose: Debugging aid: Test translate from MySQL to other dialects of SQL.
00187 //
00188 // Arguments:
00189 // sql in The string to be translated
00190 // type in The database type to translate to.
00191 //
00192 // Return: A list of translated SQL
00193 // NB A single MySQL command can generate multiple ORACLE ones.
00194
00195 Dbi::DbTypes fDbTypeSave = fDbType;
00196 fDbType = type;
00197 std::list<TString> sqlTrans(this->TranslateSQL(sql));
00198 fDbType = fDbTypeSave;
00199 return sqlTrans;
00200
00201 }
|
|
|
Definition at line 205 of file DbiStatement.cxx. References fDbType, MSG, DbiTableMetaData::SetFromSql(), DbiTableMetaData::Sql(), and UtilString::StringTok(). 00205 {
00206 //
00207 //
00208 // Purpose: Translate from MySQL to other dialects of SQL.
00209 //
00210 // Arguments:
00211 // sql in The string to be translated
00212 //
00213 //
00214 // Return: A list of translated SQL
00215 // NB A single MySQL command can generate multiple ORACLE ones.
00216 //
00217 // Contact: N. West
00218 //
00219 // Specification:-
00220 // =============
00221 //
00222 // Translate MySQL to other dialects of SQL.
00223
00224 // This is NOT meant to be a general purpose SQL translator, but rather a very
00225 // simple translater of the SQL that the DBI employs which is dialect specific.
00226
00227 // The only translations supported are as follows:-
00228
00229 // 1) MySQL -> Oracle:-
00230 // Set date format to be compatible with MySQL.
00231 //
00232 // 2) MySQL -> Oracle:-
00233 // Convert WHERE expressions of the form A & B to bitand(A,B) != 0
00234 //
00235 // 3) MySQL -> Oracle:-
00236 // In CREATE TABLE
00237 //
00238 // Conversion is achieved by creating a DbiTableMetaData object
00239 // from the SQL and then asking it to generate the Oracle equivalent.
00240 // See DbiTableMetaData for details.
00241 //
00242 // 4) MySQL -> Oracle:-
00243 // SHOW TABLES -> SELECT TABLE_NAME FROM ALL_TABLES
00244 //
00245 // 5) MySQL -> Oracle:-
00246 // \' -> '' (in general ORACLE doesn't respect escape sequences
00247 // except single quotes and only then as '' not \').
00248 //
00249 // 6) MySQL -> Oracle:-
00250 // Convert now() into sysdate
00251
00252 std::list<TString> sqlTransList;
00253
00254 if ( fDbType != Dbi::kOracle ) {
00255 sqlTransList.push_back(sql);
00256 return sqlTransList;
00257 }
00258
00259 Bool_t translated = false; //Once true, sqlTransList contains the translation. No further translation possible.
00260 Bool_t modified = false; //sqlTrans has been modified, but further translation possible.
00261
00262 TString sqlTrans(sql);
00263 sqlTrans.ToUpper();
00264
00265 // Set date format to be compatible with MySQL.
00266 sqlTransList.push_back("ALTER SESSION SET NLS_DATE_FORMAT='YYYY-MM-DD hh24:mi:ss'");
00267
00268 // Translate NOW()
00269 if ( sqlTrans.Index("NOW()") != kNPOS ) {
00270 sqlTrans.ReplaceAll("NOW()","SYSDATE");
00271 modified = true;
00272 }
00273
00274 // Translate SHOW TABLES
00275 if (sqlTrans == "SHOW TABLES" ) {
00276 sqlTrans = "SELECT TABLE_NAME FROM ALL_TABLES";
00277 sqlTransList.push_back(sqlTrans);
00278 translated = true;
00279 }
00280
00281 TString sqlIncant;
00282
00283 // Translate CREATE TABLE commands using DbiTableMetaData.
00284 Ssiz_t createTableIndex = sqlTrans.Index("CREATE TABLE",0,TString::kIgnoreCase );
00285 if ( ! translated && createTableIndex != kNPOS ) {
00286 DbiTableMetaData tmd;
00287 tmd.SetFromSql(sql.Data());
00288 std::vector<std::string> sql_list;
00289 UtilString::StringTok(sql_list,tmd.Sql(Dbi::kOracle),";");
00290 std::vector<std::string>::const_iterator itr(sql_list.begin()), itrEnd(sql_list.end());
00291 while ( itr != itrEnd ) {
00292 sqlTransList.push_back(*itr);
00293 ++itr;
00294 }
00295 translated = true;
00296 }
00297
00298
00299 // Translate DROP TABLE commands.
00300 Ssiz_t dropTableIndex = sqlTrans.Index("DROP TABLE",0,TString::kIgnoreCase );
00301 if ( ! translated && dropTableIndex != kNPOS ) {
00302 // Remove any "IF EXISTS"
00303 sqlTrans.ReplaceAll(" IF EXISTS ", " ");
00304
00305 //add the drop table command, then work on the synonym
00306 sqlTransList.push_back(sqlTrans);
00307
00308 // Extract the table name
00309 Ssiz_t startIndex = dropTableIndex + 10;
00310 while ( isspace(sqlTrans[startIndex]) ) ++startIndex;
00311 Ssiz_t endIndex = startIndex + 1;
00312 Ssiz_t endIndexMax = sqlTrans.Length();
00313 while ( endIndex < endIndexMax
00314 && (isalnum(sqlTrans[endIndex]) || sqlTrans[endIndex] == '_')
00315 ) ++endIndex;
00316 TString name(sqlTrans.Data()+startIndex,endIndex-startIndex);
00317 translated = true;
00318
00319 // Add extra ORACLE incantations required when dropping a table with
00320 // a public synonym
00321 TString sqlIncant("DROP PUBLIC SYNONYM ");
00322 sqlIncant += name ;
00323 sqlTransList.push_back(sqlIncant);
00324 }
00325
00326 // Translate commands with a WHERE keyword, but take care if this is
00327 // an INSERT INTO command - it could include "where" as part of a character value!
00328 Ssiz_t whereStart = sqlTrans.Index("INSERT INTO",0,TString::kIgnoreCase );
00329 if ( whereStart == kNPOS ) whereStart = 0;
00330 else {
00331 // Skip to end of INSERT by looking for the trailing ")" at level 0
00332 // Yes, I know this can be defeated by mismatched "(" and ")" within
00333 // character values, but it's better than giving up on a possible WHERE clause
00334 // altogether.
00335 Ssiz_t whereStartMax = sqlTrans.Length();
00336 whereStart = sqlTrans.Index("(",whereStart,TString::kIgnoreCase );
00337 if ( whereStart == kNPOS ) whereStart = whereStartMax;
00338 else ++whereStart;
00339 int level = 1;
00340 while ( whereStart < whereStartMax && level ) {
00341 char chr = sqlTrans[whereStart++];
00342 if ( chr == '(' ) ++level;
00343 if ( chr == ')' ) --level;
00344 }
00345 }
00346 // Look for space separated WHERE (so not fooled by e.g. FABWHERE!)
00347 Ssiz_t whereIndex = sqlTrans.Index(" WHERE ",whereStart,TString::kIgnoreCase );
00348 if ( ! translated && whereIndex != kNPOS ) {
00349
00350 // Set limit of WHERE clause
00351 ++whereIndex; // Step over leading space
00352 Ssiz_t whereEnd = sqlTrans.Length();
00353 std::string whereDelim[] = { "GROUP BY", "HAVING", "ORDER BY", "LIMIT" };
00354 int numDelims = sizeof(whereDelim)/sizeof(string);
00355 for (int iDelim = 0; iDelim < numDelims; ++iDelim ) {
00356 const string& delimName = whereDelim[iDelim];
00357 Ssiz_t delimIndex = sqlTrans.Index(delimName.c_str(), delimName.size(), whereIndex + 5, TString::kIgnoreCase );
00358 if (delimIndex != kNPOS && delimIndex < whereEnd) whereEnd = delimIndex;
00359 }
00360
00361 // Translate all bitwise and expressions within the WHERE clause.
00362
00363 TString whereClause(sql.Data()+whereIndex,whereEnd-whereIndex);
00364 // Convert \n to space so that tokenising works.
00365 whereClause.ReplaceAll("\n"," ");
00366
00367 std::vector<std::string> tokens;
00368 UtilString::StringTok(tokens,whereClause.Data()," ");
00369 int numTokens = tokens.size();
00370 for (int ithToken = 1; ithToken < numTokens-1; ++ithToken ) {
00371 if ( tokens[ithToken] == "&" ) {
00372 string tmp("bitand(");
00373 tmp += tokens[ithToken-1] + "," + tokens[ithToken+1] + ") != 0";
00374 tokens[ithToken] = tmp;
00375 tokens[ithToken-1] = "";
00376 tokens[ithToken+1] = "";
00377 }
00378 }
00379
00380 sqlTrans = sql(0,whereIndex);
00381 for (int ithToken = 0; ithToken < numTokens; ++ithToken ) {
00382 sqlTrans += " ";
00383 sqlTrans += tokens[ithToken].c_str();
00384 }
00385 sqlTrans += " " + sql(whereEnd,999999);
00386 modified = true;
00387 }
00388
00389 // Translate \' to ''
00390 if ( ! translated && sqlTrans.Index("\\\'") != kNPOS ) {
00391 // Bit of a kludge, if not yet modified, undo upper case conversion
00392 // as quoted data is likely to contain characters.
00393 if ( not modified ) sqlTrans = sql;
00394 sqlTrans.ReplaceAll("\\\'","\'\'");
00395 modified = true;
00396 }
00397
00398 if ( modified && ! translated ) {
00399 sqlTransList.push_back(sqlTrans);
00400 translated = true;
00401 }
00402
00403 if ( translated ) {
00404 MSG("Dbi",Msg::kSynopsis) << "sql: " << sql << endl
00405 << "translates to " << sqlTransList.size()
00406 << " statements:- \n";
00407 std::list<TString>::const_iterator itr(sqlTransList.begin()), itrEnd(sqlTransList.end());
00408 while (itr != itrEnd) { MSG("Dbi",Msg::kSynopsis) << " " << *itr << endl; ++itr;}
00409 }
00410 else {
00411 sqlTransList.push_back(sql);
00412 }
00413
00414 return sqlTransList;
00415
00416 }
|
|
|
Connection associated with this statement.
Definition at line 92 of file DbiStatement.h. Referenced by CreateProcessedStatement(), ExecuteQuery(), ExecuteUpdate(), and ~DbiStatement(). |
|
|
Type of database (MySQL, Oracle).
Definition at line 95 of file DbiStatement.h. Referenced by TestTranslateSQL(), and TranslateSQL(). |
|
|
A log of reported exceptions. Cleared by calling ExecuteQuery, ExecuteUpdate Definition at line 99 of file DbiStatement.h. Referenced by ExecuteQuery(), and ExecuteUpdate(). |
1.3.9.1