00001
00005
00006 #include <sstream>
00007
00008 #include "DatabaseInterface/DbiFieldType.h"
00009 #include "DatabaseInterface/DbiResultSet.h"
00010 #include "DatabaseInterface/DbiString.h"
00011 #include "DatabaseInterface/DbiStatement.h"
00012 #include "DatabaseInterface/DbiTableMetaData.h"
00013 #include "LeakChecker/Lea.h"
00014 #include "MessageService/MsgService.h"
00015 #include "Util/UtilString.h"
00016 #include "Validity/VldTimeStamp.h"
00017
00018 ClassImp(DbiResultSet)
00019
00020
00021
00022
00023
00024 CVSID("$Id: DbiResultSet.cxx,v 1.40 2007/07/05 11:36:05 west Exp $");
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 DbiResultSet::DbiResultSet(DbiStatement* stmtDb,
00035 const DbiString& sql,
00036 const DbiTableMetaData* metaData,
00037 const DbiTableProxy* tableProxy,
00038 UInt_t dbNo,
00039 const string& fillOpts) :
00040 DbiRowStream(metaData),
00041 fCurRow(0),
00042 fDbNo(dbNo),
00043 fDbType(Dbi::kMySQL),
00044 fStatement(stmtDb),
00045 fTSQLStatement(0),
00046 fExhausted(true),
00047 fTableProxy(tableProxy),
00048 fFillOpts(fillOpts)
00049 {
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076 LEA_CTOR
00077
00078 MSG("Dbi", Msg::kVerbose) << "Creating DbiResultSet" << endl;
00079
00080 if ( stmtDb ) {
00081 fDbType = stmtDb->GetDBType();
00082 fTSQLStatement = stmtDb->ExecuteQuery(sql.c_str());
00083 if ( fTSQLStatement && fTSQLStatement->NextResultRow() ) fExhausted = false;
00084 stmtDb->PrintExceptions(Msg::kDebug);
00085 }
00086
00087 }
00088
00089
00090
00091
00092 DbiResultSet::~DbiResultSet() {
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115 LEA_DTOR
00116
00117 MSG("Dbi", Msg::kVerbose) << "Destroying DbiResultSet" << endl;
00118 delete fTSQLStatement;
00119 fTSQLStatement = 0;
00120 delete fStatement;
00121 fStatement = 0;
00122
00123 }
00124
00125
00126
00127
00128 #define IN(t) istringstream in(AsString(t)); in
00129
00130
00131
00132
00133 #define IN2(t,m) \
00134 int col = CurColNum()-1; \
00135 if ( CurRowNum() == 0 ) { \
00136 istringstream in(AsString(t)); \
00137 in >> dest; \
00138 } \
00139 else { \
00140 dest = fTSQLStatement->m(col); \
00141 IncrementCurCol(); \
00142 } \
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153 #define IN3(t) \
00154 int col = this->CurColNum()-1; \
00155 const DbiFieldType& fType = this->ColFieldType(col+1); \
00156 if ( fType.GetSize() == 8 ) { \
00157 dest=fTSQLStatement->GetUInt(col); \
00158 } \
00159 else { \
00160 t dest_signed; \
00161 *this >> dest_signed; \
00162 dest = dest_signed; \
00163 if ( fType.GetSize() == 1 ) dest &= 0xff; \
00164 if ( fType.GetSize() == 2 ) dest &= 0xffff; \
00165 if ( fType.GetSize() == 4 ) dest &= 0xffffffff; \
00166 }\
00167
00168 DbiResultSet& DbiResultSet::operator>>(Bool_t& dest) {
00169 IN(Dbi::kBool) >> dest; return *this;}
00170 DbiResultSet& DbiResultSet::operator>>(Char_t& dest) {
00171 IN(Dbi::kChar) >> dest; return *this;}
00172 DbiResultSet& DbiResultSet::operator>>(Short_t& dest) {
00173 IN2(Dbi::kInt,GetInt); return *this;}
00174 DbiResultSet& DbiResultSet::operator>>(UShort_t& dest) {
00175 IN3(Short_t); return *this;}
00176 DbiResultSet& DbiResultSet::operator>>(Int_t& dest) {
00177 IN2(Dbi::kInt,GetInt); return *this;}
00178 DbiResultSet& DbiResultSet::operator>>(UInt_t& dest) {
00179 IN3(Int_t); return *this;}
00180 DbiResultSet& DbiResultSet::operator>>(Long_t& dest) {
00181 IN2(Dbi::kLong, GetLong); return *this;}
00182 DbiResultSet& DbiResultSet::operator>>(ULong_t& dest) {
00183 IN3(Long_t); return *this;}
00184 DbiResultSet& DbiResultSet::operator>>(Float_t& dest) {
00185 IN2(Dbi::kFloat,GetDouble); return *this;}
00186 DbiResultSet& DbiResultSet::operator>>(Double_t& dest) {
00187 IN2(Dbi::kDouble,GetDouble);return *this;}
00188
00189
00190
00191 DbiResultSet& DbiResultSet::operator>>(string& dest) {
00192 dest = AsString(Dbi::kString); return *this;}
00193 DbiResultSet& DbiResultSet::operator>>(VldTimeStamp& dest){
00194 dest=Dbi::MakeTimeStamp(AsString(Dbi::kDate)); return *this;}
00195
00196
00197
00198 string& DbiResultSet::AsString(Dbi::DataTypes type) {
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228 DbiFieldType reqdt(type);
00229
00230
00231
00232 Bool_t fail = ! LoadCurValue();
00233
00234 UInt_t col = CurColNum();
00235 IncrementCurCol();
00236
00237 if ( fail ) {
00238 string udef = reqdt.UndefinedValue();
00239 MAXMSG("Dbi",Msg::kError,20)
00240 << "... value \"" << udef
00241 << "\" will be substitued." << endl;
00242 fValString = udef;
00243 return fValString;
00244 }
00245
00246
00247
00248 const DbiFieldType& actdt = MetaData()->ColFieldType(col);
00249
00250 if ( reqdt.IsCompatible(actdt) ) {
00251 Bool_t smaller = reqdt.IsSmaller(actdt);
00252
00253 if ( reqdt.GetConcept() == Dbi::kChar && fValString.size() == 1
00254 ) smaller = kFALSE;
00255 if ( smaller ) {
00256 MAXMSG("Dbi",Msg::kWarning,20)
00257 << "In table " << TableNameTc()
00258 << " row " << fCurRow
00259 << " column "<< col
00260 << " (" << MetaData()->ColName(col) << ")"
00261 << " value \"" << fValString
00262 << "\" of type " << actdt.AsString()
00263 << " may be truncated before storing in " << reqdt.AsString()
00264 << endl;
00265 }
00266 }
00267 else {
00268 string udef = reqdt.UndefinedValue();
00269 MAXMSG("Dbi",Msg::kError,20)
00270 << "In table " << TableNameTc()
00271 << " row " << fCurRow
00272 << " column "<< col
00273 << " (" << MetaData()->ColName(col) << ")"
00274 << " value \"" << fValString
00275 << "\" of type " << actdt.AsString()
00276 << " is incompatible with user type " << reqdt.AsString()
00277 << ", value \"" << udef
00278 << "\" will be substituted." << endl;
00279 fValString = udef;
00280 }
00281
00282 return fValString;
00283 }
00284
00285
00286
00287
00288 Bool_t DbiResultSet::CurColExists() const {
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309 Int_t col = CurColNum();
00310
00311 if ( IsExhausted() ) {
00312 MAXMSG("Dbi",Msg::kError,20)
00313 << "In table " << TableNameTc()
00314 << " attempting to access row " << fCurRow
00315 << " column " << col
00316 << " but only " << fCurRow << " rows in table." << endl;
00317 return kFALSE;
00318 }
00319
00320 int numCols = NumCols();
00321 if ( col > numCols ) {
00322 MAXMSG("Dbi",Msg::kError,20)
00323 << "In table " << TableNameTc()
00324 << " row " << fCurRow
00325 << " attempting to access column "<< col
00326 << " but only " << NumCols() << " in table ." << endl;
00327 return kFALSE;
00328 }
00329
00330 return kTRUE;
00331
00332 }
00333
00334
00335 string DbiResultSet::CurColString() const {
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356 if ( ! CurColExists() ) return "";
00357
00358 TString valStr = this->GetStringFromTSQL(CurColNum());
00359 return valStr.Data();
00360
00361 }
00362
00363
00364
00365 Bool_t DbiResultSet::FetchRow() {
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387 ClearCurCol();
00388 if ( IsExhausted() ) return kFALSE;
00389 ++fCurRow;
00390 if ( ! fTSQLStatement->NextResultRow() ) fExhausted = true;
00391 return ! fExhausted;
00392
00393 }
00394
00395
00396 TString DbiResultSet::GetStringFromTSQL(Int_t col) const {
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412 TString valStr = fTSQLStatement->GetString(col-1);
00413 if ( this->GetDBType() == Dbi::kOracle
00414 && this->ColFieldType(col).GetConcept() == Dbi::kString ) {
00415 MSG("Dbi",Msg::kDebug) << "ORACLE string conversion from: " << valStr << endl;
00416 valStr.ReplaceAll("\\n", "\n");
00417 valStr.ReplaceAll("\\t", "\t");
00418 valStr.ReplaceAll("\\\'","\'");
00419 valStr.ReplaceAll("\\\"","\"");
00420 valStr.ReplaceAll("\\\\","\\");
00421 MSG("Dbi",Msg::kDebug) << " to: " << valStr <<endl;
00422 }
00423 return valStr;
00424 }
00425
00426
00427
00428 Bool_t DbiResultSet::LoadCurValue() const{
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446 fValString.clear();
00447
00448 if ( ! CurColExists() ) return kFALSE;
00449
00450 Int_t col = CurColNum();
00451 TString valStr = this->GetStringFromTSQL(col);
00452
00453
00454
00455 if ( CurColFieldType().GetConcept() == Dbi::kFloat ) {
00456 ostringstream out;
00457 out << setprecision(8);
00458 if ( CurColFieldType().GetType() == Dbi::kDouble ) out << setprecision(16);
00459
00460 out << fTSQLStatement->GetDouble(col-1);
00461 valStr = out.str().c_str();
00462 }
00463 int len = valStr.Length();
00464
00465
00466
00467 const char* pVal = valStr.Data();
00468
00469 if ( len >= 2
00470 && ( *pVal == *(pVal+len-1) )
00471 && ( *pVal == '\'' || *pVal == '"' ) ) {
00472 ++pVal;
00473 len -= 2;
00474 }
00475 fValString.assign(pVal,len);
00476
00477 return kTRUE;
00478
00479 }
00480
00481
00482 void DbiResultSet::RowAsCsv(string& row) const {
00483
00484
00485
00486
00487
00488
00489
00490
00491 const DbiTableMetaData* md = this->MetaData();
00492
00493 Int_t maxCol = this->NumCols();
00494 for (Int_t col = 1; col <= maxCol; ++col) {
00495
00496 if ( fTSQLStatement->IsNull(col-1) ) {
00497 row += "NULL";
00498 if ( col < maxCol ) row += ',';
00499 continue;
00500 }
00501 Bool_t mustDelimit = md->ColMustDelimit(col);
00502 UInt_t concept = md->ColFieldConcept(col);
00503 if ( mustDelimit ) row += '\'';
00504 TString str = this->GetStringFromTSQL(col);
00505 const char* value = str.Data();
00506
00507
00508 if ( concept == Dbi::kString ) UtilString::MakePrintable(value,row);
00509
00510
00511
00512 else if ( concept == Dbi::kFloat ) {
00513 ostringstream out;
00514 out << setprecision(8);
00515 if ( md->ColFieldType(col).GetType() == Dbi::kDouble ) out << setprecision(16);
00516 out << fTSQLStatement->GetDouble(col-1);
00517 row += out.str();
00518 }
00519
00520
00521 else row += value;
00522
00523 if ( mustDelimit ) row += '\'';
00524 if ( col < maxCol ) row += ',';
00525 }
00526 }
00527
00528