Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TPgSQLStatement.cxx
Go to the documentation of this file.
1  // @(#)root/pgsql:$Id$
2 // Author: Dennis Box (dbox@fnal.gov) 3/12/2007
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2007, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 //////////////////////////////////////////////////////////////////////////
13 // //
14 // SQL statement class for PgSQL //
15 // //
16 // See TSQLStatement class documentation for more details. //
17 // //
18 //////////////////////////////////////////////////////////////////////////
19 
20 #include "TPgSQLStatement.h"
21 #include "TDataType.h"
22 #include "TDatime.h"
23 #include "TTimeStamp.h"
24 #include "TMath.h"
25 
26 #include <stdlib.h>
27 
28 ClassImp(TPgSQLStatement);
29 
30 #ifdef PG_VERSION_NUM
31 
32 #include "libpq/libpq-fs.h"
33 
34 static const Int_t kBindStringSize = 30; // big enough to handle text rep. of 64 bit number and timestamp (e.g. "1970-01-01 01:01:01.111111+00")
35 
36 ////////////////////////////////////////////////////////////////////////////////
37 /// Normal constructor.
38 /// Checks if statement contains parameters tags.
39 
40 TPgSQLStatement::TPgSQLStatement(PgSQL_Stmt_t* stmt, Bool_t errout):
41  TSQLStatement(errout),
42  fStmt(stmt),
43  fNumBuffers(0),
44  fBind(0),
45  fFieldName(0),
46  fWorkingMode(0),
47  fIterationCount(0),
48  fParamLengths(0),
49  fParamFormats(0),
50  fNumResultRows(0),
51  fNumResultCols(0)
52 {
53  // Given fRes not used, we retrieve the statement using the connection.
54  if (fStmt->fRes != NULL) {
55  PQclear(fStmt->fRes);
56  }
57 
58  fStmt->fRes = PQdescribePrepared(fStmt->fConn,"preparedstmt");
59  unsigned long paramcount = PQnparams(fStmt->fRes);
60  fNumResultCols = PQnfields(fStmt->fRes);
61  fIterationCount = -1;
62 
63  if (paramcount>0) {
64  fWorkingMode = 1;
65  SetBuffersNumber(paramcount);
66  } else {
67  fWorkingMode = 2;
68  SetBuffersNumber(fNumResultCols);
69  }
70 }
71 
72 ////////////////////////////////////////////////////////////////////////////////
73 /// Destructor.
74 
75 TPgSQLStatement::~TPgSQLStatement()
76 {
77  Close();
78 }
79 
80 ////////////////////////////////////////////////////////////////////////////////
81 /// Close statement.
82 
83 void TPgSQLStatement::Close(Option_t *)
84 {
85  if (fStmt->fRes)
86  PQclear(fStmt->fRes);
87 
88  fStmt->fRes = 0;
89 
90  PGresult *res=PQexec(fStmt->fConn,"DEALLOCATE preparedstmt;");
91  PQclear(res);
92 
93  FreeBuffers();
94  //TPgSQLServers responsibility to free connection
95  fStmt->fConn=0;
96  delete fStmt;
97 }
98 
99 
100 // Reset error and check that statement exists
101 #define CheckStmt(method, res) \
102  { \
103  ClearError(); \
104  if (fStmt==0) { \
105  SetError(-1,"Statement handle is 0",method); \
106  return res; \
107  } \
108  }
109 
110 #define CheckErrNo(method, force, wtf) \
111  { \
112  int stmterrno = PQresultStatus(fStmt->fRes); \
113  if ((stmterrno!=0) || force) { \
114  const char* stmterrmsg = PQresultErrorMessage(fStmt->fRes); \
115  if (stmterrno==0) { stmterrno = -1; stmterrmsg = "PgSQL statement error"; } \
116  SetError(stmterrno, stmterrmsg, method); \
117  return wtf; \
118  } \
119  }
120 
121 #define CheckErrResult(method, pqresult, retVal) \
122  { \
123  ExecStatusType stmterrno=PQresultStatus(pqresult); \
124  if (!pgsql_success(stmterrno)) { \
125  const char* stmterrmsg = PQresultErrorMessage(fStmt->fRes); \
126  SetError(stmterrno, stmterrmsg, method); \
127  PQclear(res); \
128  return retVal; \
129  } \
130  }
131 
132 #define RollBackTransaction(method) \
133  { \
134  PGresult *resnum=PQexec(fStmt->fConn,"COMMIT"); \
135  CheckErrResult("RollBackTransaction", resnum, kFALSE); \
136  PQclear(res); \
137  }
138 
139 // check last pgsql statement error code
140 #define CheckGetField(method, res) \
141  { \
142  ClearError(); \
143  if (!IsResultSetMode()) { \
144  SetError(-1,"Cannot get statement parameters",method); \
145  return res; \
146  } \
147  if ((npar<0) || (npar>=fNumBuffers)) { \
148  SetError(-1,Form("Invalid parameter number %d", npar),method); \
149  return res; \
150  } \
151  }
152 
153 ////////////////////////////////////////////////////////////////////////////////
154 /// Process statement.
155 
156 Bool_t TPgSQLStatement::Process()
157 {
158  CheckStmt("Process",kFALSE);
159 
160  // We create the prepared statement below, MUST delete the old one
161  // from our constructor first!
162  if (fStmt->fRes != NULL) {
163  PQclear(fStmt->fRes);
164  }
165 
166  if (IsSetParsMode()) {
167  fStmt->fRes= PQexecPrepared(fStmt->fConn,"preparedstmt",fNumBuffers,
168  (const char* const*)fBind,
169  0,0,0);
170 
171  } else { //result set mode
172 
173  fStmt->fRes= PQexecPrepared(fStmt->fConn,"preparedstmt",0,(const char* const*) 0,0,0,0);
174  }
175  ExecStatusType stat = PQresultStatus(fStmt->fRes);
176  if (!pgsql_success(stat))
177  CheckErrNo("Process",kTRUE, kFALSE);
178  return kTRUE;
179 }
180 
181 ////////////////////////////////////////////////////////////////////////////////
182 /// Return number of affected rows after statement is processed.
183 
184 Int_t TPgSQLStatement::GetNumAffectedRows()
185 {
186  CheckStmt("GetNumAffectedRows", -1);
187 
188  return (Int_t) atoi(PQcmdTuples(fStmt->fRes));
189 }
190 
191 ////////////////////////////////////////////////////////////////////////////////
192 /// Return number of statement parameters.
193 
194 Int_t TPgSQLStatement::GetNumParameters()
195 {
196  CheckStmt("GetNumParameters", -1);
197 
198  if (IsSetParsMode()) {
199  return fNumBuffers;
200  } else {
201  return 0;
202  }
203 }
204 
205 ////////////////////////////////////////////////////////////////////////////////
206 /// Store result of statement processing to access them
207 /// via GetInt(), GetDouble() and so on methods.
208 
209 Bool_t TPgSQLStatement::StoreResult()
210 {
211  int i;
212  for (i=0;i<fNumResultCols;i++){
213  fFieldName[i] = PQfname(fStmt->fRes,i);
214  fParamFormats[i]=PQftype(fStmt->fRes,i);
215  fParamLengths[i]=PQfsize(fStmt->fRes,i);
216 
217  }
218  fNumResultRows=PQntuples(fStmt->fRes);
219  ExecStatusType stat = PQresultStatus(fStmt->fRes);
220  fWorkingMode = 2;
221  if (!pgsql_success(stat))
222  CheckErrNo("StoreResult",kTRUE, kFALSE);
223  return kTRUE;
224 }
225 
226 ////////////////////////////////////////////////////////////////////////////////
227 /// Return number of fields in result set.
228 
229 Int_t TPgSQLStatement::GetNumFields()
230 {
231  if (fWorkingMode==1)
232  return fNumBuffers;
233  if (fWorkingMode==2)
234  return fNumResultCols;
235  return -1;
236 }
237 
238 ////////////////////////////////////////////////////////////////////////////////
239 /// Returns field name in result set.
240 
241 const char* TPgSQLStatement::GetFieldName(Int_t nfield)
242 {
243  if (!IsResultSetMode() || (nfield<0) || (nfield>=fNumBuffers)) return 0;
244 
245  return fFieldName[nfield];
246 }
247 
248 ////////////////////////////////////////////////////////////////////////////////
249 /// Shift cursor to nect row in result set.
250 
251 Bool_t TPgSQLStatement::NextResultRow()
252 {
253  if ((fStmt==0) || !IsResultSetMode()) return kFALSE;
254 
255  Bool_t res=kTRUE;
256 
257  fIterationCount++;
258  if (fIterationCount>=fNumResultRows)
259  res=kFALSE;
260  return res;
261 }
262 
263 ////////////////////////////////////////////////////////////////////////////////
264 /// Increment iteration counter for statement, where parameter can be set.
265 /// Statement with parameters of previous iteration
266 /// automatically will be applied to database.
267 
268 Bool_t TPgSQLStatement::NextIteration()
269 {
270  ClearError();
271 
272  if (!IsSetParsMode() || (fBind==0)) {
273  SetError(-1,"Cannot call for that statement","NextIteration");
274  return kFALSE;
275  }
276 
277  fIterationCount++;
278 
279  if (fIterationCount==0) return kTRUE;
280 
281  fStmt->fRes= PQexecPrepared(fStmt->fConn,"preparedstmt",fNumBuffers,
282  (const char* const*)fBind,
283  0,//fParamLengths,
284  0,//fParamFormats,
285  0);
286  ExecStatusType stat = PQresultStatus(fStmt->fRes);
287  if (!pgsql_success(stat) ){
288  CheckErrNo("NextIteration", kTRUE, kFALSE) ;
289  return kFALSE;
290  }
291  return kTRUE;
292 }
293 
294 ////////////////////////////////////////////////////////////////////////////////
295 /// Release all buffers, used by statement.
296 
297 void TPgSQLStatement::FreeBuffers()
298 {
299  //individual field names free()'ed by PQclear of fStmt->fRes
300  if (fFieldName)
301  delete[] fFieldName;
302 
303  if (fBind){
304  for (Int_t i=0;i<fNumBuffers;i++)
305  delete [] fBind[i];
306  delete[] fBind;
307  }
308 
309  if (fParamLengths)
310  delete [] fParamLengths;
311 
312  if (fParamFormats)
313  delete [] fParamFormats;
314 
315  fFieldName = 0;
316  fBind = 0;
317  fNumBuffers = 0;
318  fParamLengths = 0;
319  fParamFormats = 0;
320 }
321 
322 ////////////////////////////////////////////////////////////////////////////////
323 /// Allocate buffers for statement parameters/ result fields.
324 
325 void TPgSQLStatement::SetBuffersNumber(Int_t numpars)
326 {
327  FreeBuffers();
328  if (numpars<=0) return;
329 
330  fNumBuffers = numpars;
331 
332  fBind = new char*[fNumBuffers];
333  for(int i=0; i<fNumBuffers; ++i){
334  fBind[i] = new char[kBindStringSize];
335  }
336  fFieldName = new char*[fNumBuffers];
337 
338  fParamLengths = new int[fNumBuffers];
339  memset(fParamLengths, 0, sizeof(int)*fNumBuffers);
340 
341  fParamFormats = new int[fNumBuffers];
342  memset(fParamFormats, 0, sizeof(int)*fNumBuffers);
343 }
344 
345 ////////////////////////////////////////////////////////////////////////////////
346 /// Convert field value to string.
347 
348 const char* TPgSQLStatement::ConvertToString(Int_t npar)
349 {
350  const char *buf = PQgetvalue(fStmt->fRes, fIterationCount, npar);
351  return buf;
352 }
353 
354 ////////////////////////////////////////////////////////////////////////////////
355 /// Convert field to numeric.
356 
357 long double TPgSQLStatement::ConvertToNumeric(Int_t npar)
358 {
359  if (PQgetisnull(fStmt->fRes,fIterationCount,npar))
360  return (long double)0;
361 
362  return (long double) atof(PQgetvalue(fStmt->fRes,fIterationCount,npar));
363 }
364 
365 ////////////////////////////////////////////////////////////////////////////////
366 /// Checks if field value is null.
367 
368 Bool_t TPgSQLStatement::IsNull(Int_t npar)
369 {
370  CheckGetField("IsNull", kTRUE);
371 
372  return PQgetisnull(fStmt->fRes,fIterationCount,npar);
373 }
374 
375 ////////////////////////////////////////////////////////////////////////////////
376 /// Get integer.
377 
378 Int_t TPgSQLStatement::GetInt(Int_t npar)
379 {
380  if (PQgetisnull(fStmt->fRes,fIterationCount,npar))
381  return (Int_t)0;
382 
383  return (Int_t) atoi(PQgetvalue(fStmt->fRes,fIterationCount,npar));
384 }
385 
386 ////////////////////////////////////////////////////////////////////////////////
387 /// Get unsigned integer.
388 
389 UInt_t TPgSQLStatement::GetUInt(Int_t npar)
390 {
391  if (PQgetisnull(fStmt->fRes,fIterationCount,npar))
392  return (UInt_t)0;
393 
394  return (UInt_t) atoi(PQgetvalue(fStmt->fRes,fIterationCount,npar));
395 }
396 
397 ////////////////////////////////////////////////////////////////////////////////
398 /// Get long.
399 
400 Long_t TPgSQLStatement::GetLong(Int_t npar)
401 {
402  if (PQgetisnull(fStmt->fRes,fIterationCount,npar))
403  return (Long_t)0;
404 
405  return (Long_t) atol(PQgetvalue(fStmt->fRes,fIterationCount,npar));
406 }
407 
408 ////////////////////////////////////////////////////////////////////////////////
409 /// Get long64.
410 
411 Long64_t TPgSQLStatement::GetLong64(Int_t npar)
412 {
413  if (PQgetisnull(fStmt->fRes,fIterationCount,npar))
414  return (Long64_t)0;
415 
416 #ifndef R__WIN32
417  return (Long64_t) atoll(PQgetvalue(fStmt->fRes,fIterationCount,npar));
418 #else
419  return (Long64_t) _atoi64(PQgetvalue(fStmt->fRes,fIterationCount,npar));
420 #endif
421 }
422 
423 ////////////////////////////////////////////////////////////////////////////////
424 /// Return field value as unsigned 64-bit integer
425 
426 ULong64_t TPgSQLStatement::GetULong64(Int_t npar)
427 {
428  if (PQgetisnull(fStmt->fRes,fIterationCount,npar))
429  return (ULong64_t)0;
430 
431 #ifndef R__WIN32
432  return (ULong64_t) atoll(PQgetvalue(fStmt->fRes,fIterationCount,npar));
433 #else
434  return (ULong64_t) _atoi64(PQgetvalue(fStmt->fRes,fIterationCount,npar));
435 #endif
436 }
437 
438 ////////////////////////////////////////////////////////////////////////////////
439 /// Return field value as double.
440 
441 Double_t TPgSQLStatement::GetDouble(Int_t npar)
442 {
443  if (PQgetisnull(fStmt->fRes,fIterationCount,npar))
444  return (Double_t)0;
445  return (Double_t) atof(PQgetvalue(fStmt->fRes,fIterationCount,npar));
446 }
447 
448 ////////////////////////////////////////////////////////////////////////////////
449 /// Return field value as string.
450 
451 const char *TPgSQLStatement::GetString(Int_t npar)
452 {
453  return PQgetvalue(fStmt->fRes,fIterationCount,npar);
454 }
455 
456 ////////////////////////////////////////////////////////////////////////////////
457 /// Return field value as binary array.
458 /// Note PQgetvalue mallocs/frees and ROOT classes expect new/delete.
459 
460 Bool_t TPgSQLStatement::GetBinary(Int_t npar, void* &mem, Long_t& size)
461 {
462  size_t sz;
463  char *cptr = PQgetvalue(fStmt->fRes,fIterationCount,npar);
464  unsigned char * mptr = PQunescapeBytea((const unsigned char*)cptr,&sz);
465  if ((Long_t)sz>size) {
466  delete [] (unsigned char*) mem;
467  mem = (void*) new unsigned char[sz];
468  }
469  size=sz;
470  memcpy(mem,mptr,sz);
471  PQfreemem(mptr);
472  return kTRUE;
473 }
474 
475 ////////////////////////////////////////////////////////////////////////////////
476 /// Return large object whose oid is in the given field.
477 
478 Bool_t TPgSQLStatement::GetLargeObject(Int_t npar, void* &mem, Long_t& size)
479 {
480  Int_t objID = atoi(PQgetvalue(fStmt->fRes,fIterationCount,npar));
481 
482  // All this needs to happen inside a transaction, or it will NOT work.
483  PGresult *res=PQexec(fStmt->fConn,"BEGIN");
484 
485  CheckErrResult("GetLargeObject", res, kFALSE);
486  PQclear(res);
487 
488  Int_t lObjFD = lo_open(fStmt->fConn, objID, INV_READ);
489 
490  if (lObjFD<0) {
491  Error("GetLargeObject", "SQL Error on lo_open: %s", PQerrorMessage(fStmt->fConn));
492  RollBackTransaction("GetLargeObject");
493  return kFALSE;
494  }
495  // Object size is not known beforehand.
496  // Possible fast ways to get it are:
497  // (1) Create a function that does fopen, fseek, ftell on server
498  // (2) Query large object table with size()
499  // Both can not be expected to work in general,
500  // as (1) needs permissions and changes DB,
501  // and (2) needs permission.
502  // So we use
503  // (3) fopen, fseek and ftell locally.
504 
505  lo_lseek(fStmt->fConn, lObjFD, 0, SEEK_END);
506  Long_t sz = lo_tell(fStmt->fConn, lObjFD);
507  lo_lseek(fStmt->fConn, lObjFD, 0, SEEK_SET);
508 
509  if ((Long_t)sz>size) {
510  delete [] (unsigned char*) mem;
511  mem = (void*) new unsigned char[sz];
512  size=sz;
513  }
514 
515  Int_t readBytes = lo_read(fStmt->fConn, lObjFD, (char*)mem, size);
516 
517  if (readBytes != sz) {
518  Error("GetLargeObject", "SQL Error on lo_read: %s", PQerrorMessage(fStmt->fConn));
519  RollBackTransaction("GetLargeObject");
520  return kFALSE;
521  }
522 
523  if (lo_close(fStmt->fConn, lObjFD) != 0) {
524  Error("GetLargeObject", "SQL Error on lo_close: %s", PQerrorMessage(fStmt->fConn));
525  RollBackTransaction("GetLargeObject");
526  return kFALSE;
527  }
528 
529  res=PQexec(fStmt->fConn,"COMMIT");
530 
531  ExecStatusType stat = PQresultStatus(res);
532  if (!pgsql_success(stat)) {
533  Error("GetLargeObject", "SQL Error on COMMIT: %s", PQerrorMessage(fStmt->fConn));
534  RollBackTransaction("GetLargeObject");
535  return kFALSE;
536  }
537  PQclear(res);
538 
539  return kTRUE;
540 }
541 
542 ////////////////////////////////////////////////////////////////////////////////
543 /// Return field value as date, in UTC.
544 
545 Bool_t TPgSQLStatement::GetDate(Int_t npar, Int_t& year, Int_t& month, Int_t& day)
546 {
547  TString val=PQgetvalue(fStmt->fRes,fIterationCount,npar);
548  TDatime d = TDatime(val.Data());
549  year = d.GetYear();
550  month = d.GetMonth();
551  day= d.GetDay();
552  Int_t hour = d.GetHour();
553  Int_t min = d.GetMinute();
554  Int_t sec = d.GetSecond();
555  ConvertTimeToUTC(val, year, month, day, hour, min, sec);
556  return kTRUE;
557 }
558 
559 ////////////////////////////////////////////////////////////////////////////////
560 /// Return field as time, in UTC.
561 
562 Bool_t TPgSQLStatement::GetTime(Int_t npar, Int_t& hour, Int_t& min, Int_t& sec)
563 {
564  TString val=PQgetvalue(fStmt->fRes,fIterationCount,npar);
565  TDatime d = TDatime(val.Data());
566  hour = d.GetHour();
567  min = d.GetMinute();
568  sec= d.GetSecond();
569  Int_t year = d.GetYear();
570  Int_t month = d.GetMonth();
571  Int_t day = d.GetDay();
572  ConvertTimeToUTC(val, year, month, day, hour, min, sec);
573  return kTRUE;
574 }
575 
576 ////////////////////////////////////////////////////////////////////////////////
577 /// Return field value as date & time, in UTC.
578 
579 Bool_t TPgSQLStatement::GetDatime(Int_t npar, Int_t& year, Int_t& month, Int_t& day, Int_t& hour, Int_t& min, Int_t& sec)
580 {
581  TString val=PQgetvalue(fStmt->fRes,fIterationCount,npar);
582  TDatime d = TDatime(val.Data());
583  year = d.GetYear();
584  month = d.GetMonth();
585  day= d.GetDay();
586  hour = d.GetHour();
587  min = d.GetMinute();
588  sec= d.GetSecond();
589  ConvertTimeToUTC(val, year, month, day, hour, min, sec);
590  return kTRUE;
591 }
592 
593 ////////////////////////////////////////////////////////////////////////////////
594 /// Convert timestamp value to UTC if a zone is included.
595 
596 void TPgSQLStatement::ConvertTimeToUTC(const TString &PQvalue, Int_t& year, Int_t& month, Int_t& day, Int_t& hour, Int_t& min, Int_t& sec)
597 {
598  Ssiz_t p = PQvalue.Last(':');
599  // Check if timestamp has timezone
600  TSubString *s_zone = nullptr;
601  Bool_t hasZone = kFALSE;
602  Ssiz_t tzP = PQvalue.Last('+');
603  if ((tzP != kNPOS) && (tzP > p) ) {
604  s_zone = new TSubString(PQvalue(tzP+1,PQvalue.Length()-tzP));
605  hasZone=kTRUE;
606  } else {
607  Ssiz_t tzM = PQvalue.Last('-');
608  if ((tzM != kNPOS) && (tzM > p) ) {
609  s_zone = new TSubString(PQvalue(tzM+1,PQvalue.Length()-tzM));
610  hasZone = kTRUE;
611  }
612  }
613  if (hasZone == kTRUE) {
614  // Parse timezone, might look like e.g. +00 or -00:00
615  Int_t hourOffset, minuteOffset = 0;
616  Int_t conversions=sscanf(s_zone->Data(), "%2d:%2d", &hourOffset, &minuteOffset);
617  Int_t secondOffset = hourOffset*3600;
618  if (conversions>1) {
619  // Use sign from hour also for minute
620  secondOffset += (TMath::Sign(minuteOffset, hourOffset))*60;
621  }
622  // Use TTimeStamp so we do not have to take care of over-/underflows
623  TTimeStamp ts(year, month, day, hour, min, sec, 0, kTRUE, -secondOffset);
624  UInt_t uyear, umonth, uday, uhour, umin, usec;
625  ts.GetDate(kTRUE, 0, &uyear, &umonth, &uday);
626  ts.GetTime(kTRUE, 0, &uhour, &umin, &usec);
627  year=uyear;
628  month=umonth;
629  day=uday;
630  hour=uhour;
631  min=umin;
632  sec=usec;
633  delete s_zone;
634  }
635 }
636 
637 ////////////////////////////////////////////////////////////////////////////////
638 /// Return field as timestamp, in UTC.
639 /// Second fraction is to be interpreted as in the following example:
640 /// 2013-01-12 12:10:23.093854+02
641 /// Fraction is '93854', precision is fixed in this method to 6 decimal places.
642 /// This means the returned frac-value is always in microseconds.
643 
644 Bool_t TPgSQLStatement::GetTimestamp(Int_t npar, Int_t& year, Int_t& month, Int_t& day, Int_t& hour, Int_t& min, Int_t& sec, Int_t& frac)
645 {
646  TString val=PQgetvalue(fStmt->fRes,fIterationCount,npar);
647  TDatime d(val.Data());
648  year = d.GetYear();
649  month = d.GetMonth();
650  day= d.GetDay();
651  hour = d.GetHour();
652  min = d.GetMinute();
653  sec= d.GetSecond();
654 
655  ConvertTimeToUTC(val, year, month, day, hour, min, sec);
656 
657  Ssiz_t p = val.Last('.');
658  TSubString s_frac = val(p,val.Length()-p+1);
659 
660  // atoi ignores timezone part.
661  // We MUST use atof here to correctly convert the fraction of
662  // "12:23:01.093854" and put a limitation on precision,
663  // as we can only return an Int_t.
664  frac=(Int_t) (atof(s_frac.Data())*1.E6);
665 
666  return kTRUE;
667 }
668 
669 ////////////////////////////////////////////////////////////////////////////////
670 /// Return value of parameter in form of TTimeStamp
671 /// Be aware, that TTimeStamp does not allow dates before 1970-01-01
672 
673 Bool_t TPgSQLStatement::GetTimestamp(Int_t npar, TTimeStamp& tm)
674 {
675  Int_t year, month, day, hour, min, sec, microsec;
676  GetTimestamp(npar, year, month, day, hour, min, sec, microsec);
677 
678  if (year < 1970) {
679  SetError(-1, "Date before year 1970 does not supported by TTimeStamp type", "GetTimestamp");
680  return kFALSE;
681  }
682 
683  tm.Set(year, month, day, hour, min, sec, microsec*1000, kTRUE, 0);
684 
685  return kTRUE;
686 }
687 
688 ////////////////////////////////////////////////////////////////////////////////
689 /// Set NULL as parameter value.
690 /// If NULL should be set for statement parameter during first iteration,
691 /// one should call before proper Set... method to identify type of argument for
692 /// the future. For instance, if one suppose to have double as type of parameter,
693 /// code should look like:
694 /// stmt->SetDouble(2, 0.);
695 /// stmt->SetNull(2);
696 
697 Bool_t TPgSQLStatement::SetNull(Int_t npar)
698 {
699  fBind[npar] = 0;
700 
701  return kTRUE;
702 }
703 
704 ////////////////////////////////////////////////////////////////////////////////
705 /// Set parameter value as integer.
706 
707 Bool_t TPgSQLStatement::SetInt(Int_t npar, Int_t value)
708 {
709  snprintf(fBind[npar],kBindStringSize,"%d",value);
710 
711  return kTRUE;
712 }
713 
714 ////////////////////////////////////////////////////////////////////////////////
715 /// Set parameter value as unsinged integer.
716 
717 Bool_t TPgSQLStatement::SetUInt(Int_t npar, UInt_t value)
718 {
719  snprintf(fBind[npar],kBindStringSize,"%u",value);
720 
721  return kTRUE;
722 }
723 
724 ////////////////////////////////////////////////////////////////////////////////
725 /// Set parameter value as long.
726 
727 Bool_t TPgSQLStatement::SetLong(Int_t npar, Long_t value)
728 {
729  snprintf(fBind[npar],kBindStringSize,"%ld",value);
730 
731  return kTRUE;
732 }
733 
734 ////////////////////////////////////////////////////////////////////////////////
735 /// Set parameter value as 64-bit integer.
736 
737 Bool_t TPgSQLStatement::SetLong64(Int_t npar, Long64_t value)
738 {
739  snprintf(fBind[npar],kBindStringSize,"%lld",(Long64_t)value);
740 
741  return kTRUE;
742 }
743 
744 ////////////////////////////////////////////////////////////////////////////////
745 /// Set parameter value as unsinged 64-bit integer.
746 
747 Bool_t TPgSQLStatement::SetULong64(Int_t npar, ULong64_t value)
748 {
749  snprintf(fBind[npar],kBindStringSize,"%llu",(ULong64_t)value);
750 
751  return kTRUE;
752 }
753 
754 ////////////////////////////////////////////////////////////////////////////////
755 /// Set parameter value as double value.
756 
757 Bool_t TPgSQLStatement::SetDouble(Int_t npar, Double_t value)
758 {
759  snprintf(fBind[npar],kBindStringSize,"%lf",value);
760 
761  return kTRUE;
762 }
763 
764 ////////////////////////////////////////////////////////////////////////////////
765 /// Set parameter value as string.
766 
767 Bool_t TPgSQLStatement::SetString(Int_t npar, const char* value, Int_t maxsize)
768 {
769  if(sizeof(fBind[npar])<(unsigned)maxsize){
770  delete [] fBind[npar];
771  fBind[npar] = new char[maxsize];
772  }
773  strlcpy(fBind[npar],value,maxsize);
774  return kTRUE;
775 }
776 
777 ////////////////////////////////////////////////////////////////////////////////
778 /// Set parameter value as binary data.
779 
780 Bool_t TPgSQLStatement::SetBinary(Int_t npar, void* mem, Long_t size, Long_t maxsize)
781 {
782  // Set parameter value as binary data.
783 
784  size_t sz = size, mxsz = maxsize;
785  unsigned char* escape_ptr = PQescapeBytea((const unsigned char*)mem, sz, &mxsz);
786  unsigned char* binary_ptr = PQunescapeBytea((const unsigned char*)escape_ptr, &mxsz);
787  PQfreemem(escape_ptr);
788 
789  delete [] fBind[npar];
790  fBind[npar] = new char[mxsz+1];
791  fBind[npar][mxsz] = '\0';
792  memcpy(fBind[npar], binary_ptr, mxsz);
793 
794  PQfreemem(binary_ptr);
795  return kTRUE;
796 }
797 
798 ////////////////////////////////////////////////////////////////////////////////
799 /// Set parameter value to large object and immediately insert the large object into DB.
800 
801 Bool_t TPgSQLStatement::SetLargeObject(Int_t npar, void* mem, Long_t size, Long_t /*maxsize*/)
802 {
803  // All this needs to happen inside a transaction, or it will NOT work.
804  PGresult *res=PQexec(fStmt->fConn,"BEGIN");
805 
806  CheckErrResult("GetLargeObject", res, kFALSE);
807  PQclear(res);
808 
809  Int_t lObjID = lo_creat(fStmt->fConn, INV_READ | INV_WRITE);
810  if (lObjID<0) {
811  Error("SetLargeObject", "Error in SetLargeObject: %s", PQerrorMessage(fStmt->fConn));
812  RollBackTransaction("GetLargeObject");
813  return kFALSE;
814  }
815 
816  Int_t lObjFD = lo_open(fStmt->fConn, lObjID, INV_READ | INV_WRITE);
817  if (lObjFD<0) {
818  Error("SetLargeObject", "Error in SetLargeObject: %s", PQerrorMessage(fStmt->fConn));
819  RollBackTransaction("GetLargeObject");
820  return kFALSE;
821  }
822 
823  Int_t writtenBytes = lo_write(fStmt->fConn, lObjFD, (char*)mem, size);
824 
825  if (writtenBytes != size) {
826  Error("SetLargeObject", "SQL Error on lo_write: %s", PQerrorMessage(fStmt->fConn));
827  RollBackTransaction("GetLargeObject");
828  return kFALSE;
829  }
830 
831  if (lo_close(fStmt->fConn, lObjFD) != 0) {
832  Error("SetLargeObject", "SQL Error on lo_close: %s", PQerrorMessage(fStmt->fConn));
833  RollBackTransaction("GetLargeObject");
834  return kFALSE;
835  }
836 
837  res=PQexec(fStmt->fConn,"COMMIT");
838  ExecStatusType stat = PQresultStatus(res);
839  if (!pgsql_success(stat)) {
840  Error("SetLargeObject", "SQL Error on COMMIT: %s", PQerrorMessage(fStmt->fConn));
841  PQclear(res);
842  return kFALSE;
843  }
844  PQclear(res);
845 
846  snprintf(fBind[npar],kBindStringSize,"%d",lObjID);
847 
848  return kTRUE;
849 }
850 
851 ////////////////////////////////////////////////////////////////////////////////
852 /// Set parameter value as date.
853 
854 Bool_t TPgSQLStatement::SetDate(Int_t npar, Int_t year, Int_t month, Int_t day)
855 {
856  TDatime d =TDatime(year,month,day,0,0,0);
857  snprintf(fBind[npar],kBindStringSize,"%s",(char*)d.AsSQLString());
858 
859  return kTRUE;
860 }
861 
862 ////////////////////////////////////////////////////////////////////////////////
863 /// Set parameter value as time.
864 
865 Bool_t TPgSQLStatement::SetTime(Int_t npar, Int_t hour, Int_t min, Int_t sec)
866 {
867  TDatime d=TDatime(2000,1,1,hour,min,sec);
868  snprintf(fBind[npar],kBindStringSize,"%s",(char*)d.AsSQLString());
869  return kTRUE;
870 }
871 
872 ////////////////////////////////////////////////////////////////////////////////
873 /// Set parameter value as date & time, in UTC.
874 
875 Bool_t TPgSQLStatement::SetDatime(Int_t npar, Int_t year, Int_t month, Int_t day, Int_t hour, Int_t min, Int_t sec)
876 {
877  TDatime d=TDatime(year,month,day,hour,min,sec);
878  snprintf(fBind[npar],kBindStringSize,"%s+00",(char*)d.AsSQLString());
879  return kTRUE;
880 }
881 
882 ////////////////////////////////////////////////////////////////////////////////
883 /// Set parameter value as timestamp, in UTC.
884 /// Second fraction is assumed as value in microseconds,
885 /// i.e. as a fraction with six decimal places.
886 /// See GetTimestamp() for an example.
887 
888 Bool_t TPgSQLStatement::SetTimestamp(Int_t npar, Int_t year, Int_t month, Int_t day, Int_t hour, Int_t min, Int_t sec, Int_t frac)
889 {
890  TDatime d(year,month,day,hour,min,sec);
891  snprintf(fBind[npar],kBindStringSize,"%s.%06d+00",(char*)d.AsSQLString(),frac);
892  return kTRUE;
893 }
894 
895 ////////////////////////////////////////////////////////////////////////////////
896 /// Set parameter value as timestamp from TTimeStamp object
897 
898 Bool_t TPgSQLStatement::SetTimestamp(Int_t npar, const TTimeStamp& tm)
899 {
900  snprintf(fBind[npar], kBindStringSize, "%s.%06d+00", (char*)tm.AsString("s"), TMath::Nint(tm.GetNanoSec() / 1000.0));
901  return kTRUE;
902 }
903 
904 #else
905 
906 ////////////////////////////////////////////////////////////////////////////////
907 /// Normal constructor.
908 /// For PgSQL version < 8.2 no statement is supported.
909 
910 TPgSQLStatement::TPgSQLStatement(PgSQL_Stmt_t*, Bool_t)
911 {
912 }
913 
914 ////////////////////////////////////////////////////////////////////////////////
915 /// Destructor.
916 
917 TPgSQLStatement::~TPgSQLStatement()
918 {
919 }
920 
921 ////////////////////////////////////////////////////////////////////////////////
922 /// Close statement.
923 
924 void TPgSQLStatement::Close(Option_t *)
925 {
926 }
927 
928 ////////////////////////////////////////////////////////////////////////////////
929 /// Process statement.
930 
931 Bool_t TPgSQLStatement::Process()
932 {
933  return kFALSE;
934 }
935 
936 ////////////////////////////////////////////////////////////////////////////////
937 /// Return number of affected rows after statement is processed.
938 
939 Int_t TPgSQLStatement::GetNumAffectedRows()
940 {
941  return 0;
942 }
943 
944 ////////////////////////////////////////////////////////////////////////////////
945 /// Return number of statement parameters.
946 
947 Int_t TPgSQLStatement::GetNumParameters()
948 {
949  return 0;
950 }
951 
952 ////////////////////////////////////////////////////////////////////////////////
953 /// Store result of statement processing to access them
954 /// via GetInt(), GetDouble() and so on methods.
955 
956 Bool_t TPgSQLStatement::StoreResult()
957 {
958  return kFALSE;
959 }
960 
961 ////////////////////////////////////////////////////////////////////////////////
962 /// Return number of fields in result set.
963 
964 Int_t TPgSQLStatement::GetNumFields()
965 {
966  return 0;
967 }
968 
969 ////////////////////////////////////////////////////////////////////////////////
970 /// Returns field name in result set.
971 
972 const char* TPgSQLStatement::GetFieldName(Int_t)
973 {
974  return 0;
975 }
976 
977 ////////////////////////////////////////////////////////////////////////////////
978 /// Shift cursor to nect row in result set.
979 
980 Bool_t TPgSQLStatement::NextResultRow()
981 {
982  return kFALSE;
983 }
984 
985 
986 ////////////////////////////////////////////////////////////////////////////////
987 /// Increment iteration counter for statement, where parameter can be set.
988 /// Statement with parameters of previous iteration
989 /// automatically will be applied to database.
990 
991 Bool_t TPgSQLStatement::NextIteration()
992 {
993  return kFALSE;
994 }
995 
996 ////////////////////////////////////////////////////////////////////////////////
997 /// Release all buffers, used by statement.
998 
999 void TPgSQLStatement::FreeBuffers()
1000 {
1001 }
1002 
1003 ////////////////////////////////////////////////////////////////////////////////
1004 /// Allocate buffers for statement parameters/ result fields.
1005 
1006 void TPgSQLStatement::SetBuffersNumber(Int_t)
1007 {
1008 }
1009 
1010 ////////////////////////////////////////////////////////////////////////////////
1011 /// Convert field value to string.
1012 
1013 const char* TPgSQLStatement::ConvertToString(Int_t)
1014 {
1015  return 0;
1016 }
1017 
1018 ////////////////////////////////////////////////////////////////////////////////
1019 /// Convert field to numeric value.
1020 
1021 long double TPgSQLStatement::ConvertToNumeric(Int_t)
1022 {
1023  return 0;
1024 }
1025 
1026 ////////////////////////////////////////////////////////////////////////////////
1027 /// Checks if field value is null.
1028 
1029 Bool_t TPgSQLStatement::IsNull(Int_t)
1030 {
1031  return kTRUE;
1032 }
1033 
1034 ////////////////////////////////////////////////////////////////////////////////
1035 /// Return field value as integer.
1036 
1037 Int_t TPgSQLStatement::GetInt(Int_t)
1038 {
1039  return 0;
1040 }
1041 
1042 ////////////////////////////////////////////////////////////////////////////////
1043 /// Return field value as unsigned integer.
1044 
1045 UInt_t TPgSQLStatement::GetUInt(Int_t)
1046 {
1047  return 0;
1048 }
1049 
1050 ////////////////////////////////////////////////////////////////////////////////
1051 /// Return field value as long integer.
1052 
1053 Long_t TPgSQLStatement::GetLong(Int_t)
1054 {
1055  return 0;
1056 }
1057 
1058 ////////////////////////////////////////////////////////////////////////////////
1059 /// Return field value as 64-bit integer.
1060 
1061 Long64_t TPgSQLStatement::GetLong64(Int_t)
1062 {
1063  return 0;
1064 }
1065 
1066 ////////////////////////////////////////////////////////////////////////////////
1067 /// Return field value as unsigned 64-bit integer.
1068 
1069 ULong64_t TPgSQLStatement::GetULong64(Int_t)
1070 {
1071  return 0;
1072 }
1073 
1074 ////////////////////////////////////////////////////////////////////////////////
1075 /// Return field value as double.
1076 
1077 Double_t TPgSQLStatement::GetDouble(Int_t)
1078 {
1079  return 0.;
1080 }
1081 
1082 ////////////////////////////////////////////////////////////////////////////////
1083 /// Return field value as string.
1084 
1085 const char *TPgSQLStatement::GetString(Int_t)
1086 {
1087  return 0;
1088 }
1089 
1090 ////////////////////////////////////////////////////////////////////////////////
1091 /// Return field value as binary array.
1092 
1093 Bool_t TPgSQLStatement::GetBinary(Int_t, void* &, Long_t&)
1094 {
1095  return kFALSE;
1096 }
1097 
1098 ////////////////////////////////////////////////////////////////////////////////
1099 /// Return large object whose oid is in the given field.
1100 
1101 Bool_t TPgSQLStatement::GetLargeObject(Int_t, void* &, Long_t&)
1102 {
1103  return kFALSE;
1104 }
1105 
1106 ////////////////////////////////////////////////////////////////////////////////
1107 /// Return field value as date.
1108 
1109 Bool_t TPgSQLStatement::GetDate(Int_t, Int_t&, Int_t&, Int_t&)
1110 {
1111  return kFALSE;
1112 }
1113 
1114 ////////////////////////////////////////////////////////////////////////////////
1115 /// Return field value as time.
1116 
1117 Bool_t TPgSQLStatement::GetTime(Int_t, Int_t&, Int_t&, Int_t&)
1118 {
1119  return kFALSE;
1120 }
1121 
1122 ////////////////////////////////////////////////////////////////////////////////
1123 /// Return field value as date & time.
1124 
1125 Bool_t TPgSQLStatement::GetDatime(Int_t, Int_t&, Int_t&, Int_t&, Int_t&, Int_t&, Int_t&)
1126 {
1127  return kFALSE;
1128 }
1129 
1130 ////////////////////////////////////////////////////////////////////////////////
1131 /// Return field value as time stamp.
1132 
1133 Bool_t TPgSQLStatement::GetTimestamp(Int_t, Int_t&, Int_t&, Int_t&, Int_t&, Int_t&, Int_t&, Int_t&)
1134 {
1135  return kFALSE;
1136 }
1137 
1138 ////////////////////////////////////////////////////////////////////////////////
1139 /// Return value of parameter in form of TTimeStamp
1140 /// Be aware, that TTimeStamp does not allow dates before 1970-01-01
1141 
1142 Bool_t TPgSQLStatement::GetTimestamp(Int_t npar, TTimeStamp& tm)
1143 {
1144  return kFALSE;
1145 }
1146 
1147 ////////////////////////////////////////////////////////////////////////////////
1148 /// Set parameter type to be used as buffer.
1149 /// Used in both setting data to database and retriving data from data base.
1150 /// Initialize proper PGSQL_BIND structure and allocate required buffers.
1151 
1152 Bool_t TPgSQLStatement::SetSQLParamType(Int_t, int, bool, int)
1153 {
1154  return kFALSE;
1155 }
1156 
1157 ////////////////////////////////////////////////////////////////////////////////
1158 /// Set NULL as parameter value.
1159 /// If NULL should be set for statement parameter during first iteration,
1160 /// one should call before proper Set... method to identify type of argument for
1161 /// the future. For instance, if one suppose to have double as type of parameter,
1162 /// code should look like:
1163 /// stmt->SetDouble(2, 0.);
1164 /// stmt->SetNull(2);
1165 
1166 Bool_t TPgSQLStatement::SetNull(Int_t npar)
1167 {
1168  if ((npar >= 0) && (npar < fNumBuffers))
1169  fBind[npar] = 0;
1170  return kFALSE;
1171 }
1172 
1173 ////////////////////////////////////////////////////////////////////////////////
1174 /// Set parameter value as integer.
1175 
1176 Bool_t TPgSQLStatement::SetInt(Int_t, Int_t)
1177 {
1178  return kFALSE;
1179 }
1180 
1181 ////////////////////////////////////////////////////////////////////////////////
1182 /// Set parameter value as unsigned integer.
1183 
1184 Bool_t TPgSQLStatement::SetUInt(Int_t, UInt_t)
1185 {
1186  return kFALSE;
1187 }
1188 
1189 ////////////////////////////////////////////////////////////////////////////////
1190 /// Set parameter value as long integer.
1191 
1192 Bool_t TPgSQLStatement::SetLong(Int_t, Long_t)
1193 {
1194  return kFALSE;
1195 }
1196 
1197 ////////////////////////////////////////////////////////////////////////////////
1198 /// Set parameter value as 64-bit integer.
1199 
1200 Bool_t TPgSQLStatement::SetLong64(Int_t, Long64_t)
1201 {
1202  return kFALSE;
1203 }
1204 
1205 ////////////////////////////////////////////////////////////////////////////////
1206 /// Set parameter value as unsigned 64-bit integer.
1207 
1208 Bool_t TPgSQLStatement::SetULong64(Int_t, ULong64_t)
1209 {
1210  return kFALSE;
1211 }
1212 
1213 ////////////////////////////////////////////////////////////////////////////////
1214 /// Set parameter value as double.
1215 
1216 Bool_t TPgSQLStatement::SetDouble(Int_t, Double_t)
1217 {
1218  return kFALSE;
1219 }
1220 
1221 ////////////////////////////////////////////////////////////////////////////////
1222 /// Set parameter value as string.
1223 
1224 Bool_t TPgSQLStatement::SetString(Int_t, const char*, Int_t)
1225 {
1226  return kFALSE;
1227 }
1228 
1229 ////////////////////////////////////////////////////////////////////////////////
1230 /// Set parameter value as binary data.
1231 
1232 Bool_t TPgSQLStatement::SetBinary(Int_t, void*, Long_t, Long_t)
1233 {
1234  return kFALSE;
1235 }
1236 
1237 ////////////////////////////////////////////////////////////////////////////////
1238 /// Set parameter value to large object and immediately insert the large object into DB.
1239 
1240 Bool_t TPgSQLStatement::SetLargeObject(Int_t, void*, Long_t, Long_t)
1241 {
1242  return kFALSE;
1243 }
1244 
1245 ////////////////////////////////////////////////////////////////////////////////
1246 /// Set parameter value as date.
1247 
1248 Bool_t TPgSQLStatement::SetDate(Int_t, Int_t, Int_t, Int_t)
1249 {
1250  return kFALSE;
1251 }
1252 
1253 ////////////////////////////////////////////////////////////////////////////////
1254 /// Set parameter value as time.
1255 
1256 Bool_t TPgSQLStatement::SetTime(Int_t, Int_t, Int_t, Int_t)
1257 {
1258  return kFALSE;
1259 }
1260 
1261 ////////////////////////////////////////////////////////////////////////////////
1262 /// Set parameter value as date & time.
1263 
1264 Bool_t TPgSQLStatement::SetDatime(Int_t, Int_t, Int_t, Int_t, Int_t, Int_t, Int_t)
1265 {
1266  return kFALSE;
1267 }
1268 
1269 ////////////////////////////////////////////////////////////////////////////////
1270 /// Set parameter value as timestamp.
1271 
1272 Bool_t TPgSQLStatement::SetTimestamp(Int_t, Int_t, Int_t, Int_t, Int_t, Int_t, Int_t, Int_t)
1273 {
1274  return kFALSE;
1275 }
1276 
1277 ////////////////////////////////////////////////////////////////////////////////
1278 /// Set parameter value as timestamp from TTimeStamp object
1279 
1280 Bool_t TPgSQLStatement::SetTimestamp(Int_t, const TTimeStamp&)
1281 {
1282  return kFALSE;
1283 }
1284 
1285 #endif //PG_VERSION_NUM