28 ClassImp(TPgSQLStatement);
32 #include "libpq/libpq-fs.h"
34 static const Int_t kBindStringSize = 30;
40 TPgSQLStatement::TPgSQLStatement(PgSQL_Stmt_t* stmt, Bool_t errout):
41 TSQLStatement(errout),
54 if (fStmt->fRes != NULL) {
58 fStmt->fRes = PQdescribePrepared(fStmt->fConn,
"preparedstmt");
59 unsigned long paramcount = PQnparams(fStmt->fRes);
60 fNumResultCols = PQnfields(fStmt->fRes);
65 SetBuffersNumber(paramcount);
68 SetBuffersNumber(fNumResultCols);
75 TPgSQLStatement::~TPgSQLStatement()
83 void TPgSQLStatement::Close(Option_t *)
90 PGresult *res=PQexec(fStmt->fConn,
"DEALLOCATE preparedstmt;");
101 #define CheckStmt(method, res) \
105 SetError(-1,"Statement handle is 0",method); \
110 #define CheckErrNo(method, force, wtf) \
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); \
121 #define CheckErrResult(method, pqresult, retVal) \
123 ExecStatusType stmterrno=PQresultStatus(pqresult); \
124 if (!pgsql_success(stmterrno)) { \
125 const char* stmterrmsg = PQresultErrorMessage(fStmt->fRes); \
126 SetError(stmterrno, stmterrmsg, method); \
132 #define RollBackTransaction(method) \
134 PGresult *resnum=PQexec(fStmt->fConn,"COMMIT"); \
135 CheckErrResult("RollBackTransaction", resnum, kFALSE); \
140 #define CheckGetField(method, res) \
143 if (!IsResultSetMode()) { \
144 SetError(-1,"Cannot get statement parameters",method); \
147 if ((npar<0) || (npar>=fNumBuffers)) { \
148 SetError(-1,Form("Invalid parameter number %d", npar),method); \
156 Bool_t TPgSQLStatement::Process()
158 CheckStmt(
"Process",kFALSE);
162 if (fStmt->fRes != NULL) {
163 PQclear(fStmt->fRes);
166 if (IsSetParsMode()) {
167 fStmt->fRes= PQexecPrepared(fStmt->fConn,
"preparedstmt",fNumBuffers,
168 (
const char*
const*)fBind,
173 fStmt->fRes= PQexecPrepared(fStmt->fConn,
"preparedstmt",0,(
const char*
const*) 0,0,0,0);
175 ExecStatusType stat = PQresultStatus(fStmt->fRes);
176 if (!pgsql_success(stat))
177 CheckErrNo(
"Process",kTRUE, kFALSE);
184 Int_t TPgSQLStatement::GetNumAffectedRows()
186 CheckStmt(
"GetNumAffectedRows", -1);
188 return (Int_t) atoi(PQcmdTuples(fStmt->fRes));
194 Int_t TPgSQLStatement::GetNumParameters()
196 CheckStmt(
"GetNumParameters", -1);
198 if (IsSetParsMode()) {
209 Bool_t TPgSQLStatement::StoreResult()
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);
218 fNumResultRows=PQntuples(fStmt->fRes);
219 ExecStatusType stat = PQresultStatus(fStmt->fRes);
221 if (!pgsql_success(stat))
222 CheckErrNo(
"StoreResult",kTRUE, kFALSE);
229 Int_t TPgSQLStatement::GetNumFields()
234 return fNumResultCols;
241 const char* TPgSQLStatement::GetFieldName(Int_t nfield)
243 if (!IsResultSetMode() || (nfield<0) || (nfield>=fNumBuffers))
return 0;
245 return fFieldName[nfield];
251 Bool_t TPgSQLStatement::NextResultRow()
253 if ((fStmt==0) || !IsResultSetMode())
return kFALSE;
258 if (fIterationCount>=fNumResultRows)
268 Bool_t TPgSQLStatement::NextIteration()
272 if (!IsSetParsMode() || (fBind==0)) {
273 SetError(-1,
"Cannot call for that statement",
"NextIteration");
279 if (fIterationCount==0)
return kTRUE;
281 fStmt->fRes= PQexecPrepared(fStmt->fConn,
"preparedstmt",fNumBuffers,
282 (
const char*
const*)fBind,
286 ExecStatusType stat = PQresultStatus(fStmt->fRes);
287 if (!pgsql_success(stat) ){
288 CheckErrNo(
"NextIteration", kTRUE, kFALSE) ;
297 void TPgSQLStatement::FreeBuffers()
304 for (Int_t i=0;i<fNumBuffers;i++)
310 delete [] fParamLengths;
313 delete [] fParamFormats;
325 void TPgSQLStatement::SetBuffersNumber(Int_t numpars)
328 if (numpars<=0)
return;
330 fNumBuffers = numpars;
332 fBind =
new char*[fNumBuffers];
333 for(
int i=0; i<fNumBuffers; ++i){
334 fBind[i] =
new char[kBindStringSize];
336 fFieldName =
new char*[fNumBuffers];
338 fParamLengths =
new int[fNumBuffers];
339 memset(fParamLengths, 0,
sizeof(
int)*fNumBuffers);
341 fParamFormats =
new int[fNumBuffers];
342 memset(fParamFormats, 0,
sizeof(
int)*fNumBuffers);
348 const char* TPgSQLStatement::ConvertToString(Int_t npar)
350 const char *buf = PQgetvalue(fStmt->fRes, fIterationCount, npar);
357 long double TPgSQLStatement::ConvertToNumeric(Int_t npar)
359 if (PQgetisnull(fStmt->fRes,fIterationCount,npar))
360 return (
long double)0;
362 return (
long double) atof(PQgetvalue(fStmt->fRes,fIterationCount,npar));
368 Bool_t TPgSQLStatement::IsNull(Int_t npar)
370 CheckGetField(
"IsNull", kTRUE);
372 return PQgetisnull(fStmt->fRes,fIterationCount,npar);
378 Int_t TPgSQLStatement::GetInt(Int_t npar)
380 if (PQgetisnull(fStmt->fRes,fIterationCount,npar))
383 return (Int_t) atoi(PQgetvalue(fStmt->fRes,fIterationCount,npar));
389 UInt_t TPgSQLStatement::GetUInt(Int_t npar)
391 if (PQgetisnull(fStmt->fRes,fIterationCount,npar))
394 return (UInt_t) atoi(PQgetvalue(fStmt->fRes,fIterationCount,npar));
400 Long_t TPgSQLStatement::GetLong(Int_t npar)
402 if (PQgetisnull(fStmt->fRes,fIterationCount,npar))
405 return (Long_t) atol(PQgetvalue(fStmt->fRes,fIterationCount,npar));
411 Long64_t TPgSQLStatement::GetLong64(Int_t npar)
413 if (PQgetisnull(fStmt->fRes,fIterationCount,npar))
417 return (Long64_t) atoll(PQgetvalue(fStmt->fRes,fIterationCount,npar));
419 return (Long64_t) _atoi64(PQgetvalue(fStmt->fRes,fIterationCount,npar));
426 ULong64_t TPgSQLStatement::GetULong64(Int_t npar)
428 if (PQgetisnull(fStmt->fRes,fIterationCount,npar))
432 return (ULong64_t) atoll(PQgetvalue(fStmt->fRes,fIterationCount,npar));
434 return (ULong64_t) _atoi64(PQgetvalue(fStmt->fRes,fIterationCount,npar));
441 Double_t TPgSQLStatement::GetDouble(Int_t npar)
443 if (PQgetisnull(fStmt->fRes,fIterationCount,npar))
445 return (Double_t) atof(PQgetvalue(fStmt->fRes,fIterationCount,npar));
451 const char *TPgSQLStatement::GetString(Int_t npar)
453 return PQgetvalue(fStmt->fRes,fIterationCount,npar);
460 Bool_t TPgSQLStatement::GetBinary(Int_t npar,
void* &mem, Long_t& size)
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];
478 Bool_t TPgSQLStatement::GetLargeObject(Int_t npar,
void* &mem, Long_t& size)
480 Int_t objID = atoi(PQgetvalue(fStmt->fRes,fIterationCount,npar));
483 PGresult *res=PQexec(fStmt->fConn,
"BEGIN");
485 CheckErrResult(
"GetLargeObject", res, kFALSE);
488 Int_t lObjFD = lo_open(fStmt->fConn, objID, INV_READ);
491 Error(
"GetLargeObject",
"SQL Error on lo_open: %s", PQerrorMessage(fStmt->fConn));
492 RollBackTransaction(
"GetLargeObject");
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);
509 if ((Long_t)sz>size) {
510 delete [] (
unsigned char*) mem;
511 mem = (
void*)
new unsigned char[sz];
515 Int_t readBytes = lo_read(fStmt->fConn, lObjFD, (
char*)mem, size);
517 if (readBytes != sz) {
518 Error(
"GetLargeObject",
"SQL Error on lo_read: %s", PQerrorMessage(fStmt->fConn));
519 RollBackTransaction(
"GetLargeObject");
523 if (lo_close(fStmt->fConn, lObjFD) != 0) {
524 Error(
"GetLargeObject",
"SQL Error on lo_close: %s", PQerrorMessage(fStmt->fConn));
525 RollBackTransaction(
"GetLargeObject");
529 res=PQexec(fStmt->fConn,
"COMMIT");
531 ExecStatusType stat = PQresultStatus(res);
532 if (!pgsql_success(stat)) {
533 Error(
"GetLargeObject",
"SQL Error on COMMIT: %s", PQerrorMessage(fStmt->fConn));
534 RollBackTransaction(
"GetLargeObject");
545 Bool_t TPgSQLStatement::GetDate(Int_t npar, Int_t& year, Int_t& month, Int_t& day)
547 TString val=PQgetvalue(fStmt->fRes,fIterationCount,npar);
548 TDatime d = TDatime(val.Data());
550 month = d.GetMonth();
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);
562 Bool_t TPgSQLStatement::GetTime(Int_t npar, Int_t& hour, Int_t& min, Int_t& sec)
564 TString val=PQgetvalue(fStmt->fRes,fIterationCount,npar);
565 TDatime d = TDatime(val.Data());
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);
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)
581 TString val=PQgetvalue(fStmt->fRes,fIterationCount,npar);
582 TDatime d = TDatime(val.Data());
584 month = d.GetMonth();
589 ConvertTimeToUTC(val, year, month, day, hour, min, sec);
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)
598 Ssiz_t p = PQvalue.Last(
':');
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));
607 Ssiz_t tzM = PQvalue.Last(
'-');
608 if ((tzM != kNPOS) && (tzM > p) ) {
609 s_zone =
new TSubString(PQvalue(tzM+1,PQvalue.Length()-tzM));
613 if (hasZone == kTRUE) {
615 Int_t hourOffset, minuteOffset = 0;
616 Int_t conversions=sscanf(s_zone->Data(),
"%2d:%2d", &hourOffset, &minuteOffset);
617 Int_t secondOffset = hourOffset*3600;
620 secondOffset += (TMath::Sign(minuteOffset, hourOffset))*60;
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);
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)
646 TString val=PQgetvalue(fStmt->fRes,fIterationCount,npar);
647 TDatime d(val.Data());
649 month = d.GetMonth();
655 ConvertTimeToUTC(val, year, month, day, hour, min, sec);
657 Ssiz_t p = val.Last(
'.');
658 TSubString s_frac = val(p,val.Length()-p+1);
664 frac=(Int_t) (atof(s_frac.Data())*1.E6);
673 Bool_t TPgSQLStatement::GetTimestamp(Int_t npar, TTimeStamp& tm)
675 Int_t year, month, day, hour, min, sec, microsec;
676 GetTimestamp(npar, year, month, day, hour, min, sec, microsec);
679 SetError(-1,
"Date before year 1970 does not supported by TTimeStamp type",
"GetTimestamp");
683 tm.Set(year, month, day, hour, min, sec, microsec*1000, kTRUE, 0);
697 Bool_t TPgSQLStatement::SetNull(Int_t npar)
707 Bool_t TPgSQLStatement::SetInt(Int_t npar, Int_t value)
709 snprintf(fBind[npar],kBindStringSize,
"%d",value);
717 Bool_t TPgSQLStatement::SetUInt(Int_t npar, UInt_t value)
719 snprintf(fBind[npar],kBindStringSize,
"%u",value);
727 Bool_t TPgSQLStatement::SetLong(Int_t npar, Long_t value)
729 snprintf(fBind[npar],kBindStringSize,
"%ld",value);
737 Bool_t TPgSQLStatement::SetLong64(Int_t npar, Long64_t value)
739 snprintf(fBind[npar],kBindStringSize,
"%lld",(Long64_t)value);
747 Bool_t TPgSQLStatement::SetULong64(Int_t npar, ULong64_t value)
749 snprintf(fBind[npar],kBindStringSize,
"%llu",(ULong64_t)value);
757 Bool_t TPgSQLStatement::SetDouble(Int_t npar, Double_t value)
759 snprintf(fBind[npar],kBindStringSize,
"%lf",value);
767 Bool_t TPgSQLStatement::SetString(Int_t npar,
const char* value, Int_t maxsize)
769 if(
sizeof(fBind[npar])<(
unsigned)maxsize){
770 delete [] fBind[npar];
771 fBind[npar] =
new char[maxsize];
773 strlcpy(fBind[npar],value,maxsize);
780 Bool_t TPgSQLStatement::SetBinary(Int_t npar,
void* mem, Long_t size, Long_t maxsize)
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);
789 delete [] fBind[npar];
790 fBind[npar] =
new char[mxsz+1];
791 fBind[npar][mxsz] =
'\0';
792 memcpy(fBind[npar], binary_ptr, mxsz);
794 PQfreemem(binary_ptr);
801 Bool_t TPgSQLStatement::SetLargeObject(Int_t npar,
void* mem, Long_t size, Long_t )
804 PGresult *res=PQexec(fStmt->fConn,
"BEGIN");
806 CheckErrResult(
"GetLargeObject", res, kFALSE);
809 Int_t lObjID = lo_creat(fStmt->fConn, INV_READ | INV_WRITE);
811 Error(
"SetLargeObject",
"Error in SetLargeObject: %s", PQerrorMessage(fStmt->fConn));
812 RollBackTransaction(
"GetLargeObject");
816 Int_t lObjFD = lo_open(fStmt->fConn, lObjID, INV_READ | INV_WRITE);
818 Error(
"SetLargeObject",
"Error in SetLargeObject: %s", PQerrorMessage(fStmt->fConn));
819 RollBackTransaction(
"GetLargeObject");
823 Int_t writtenBytes = lo_write(fStmt->fConn, lObjFD, (
char*)mem, size);
825 if (writtenBytes != size) {
826 Error(
"SetLargeObject",
"SQL Error on lo_write: %s", PQerrorMessage(fStmt->fConn));
827 RollBackTransaction(
"GetLargeObject");
831 if (lo_close(fStmt->fConn, lObjFD) != 0) {
832 Error(
"SetLargeObject",
"SQL Error on lo_close: %s", PQerrorMessage(fStmt->fConn));
833 RollBackTransaction(
"GetLargeObject");
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));
846 snprintf(fBind[npar],kBindStringSize,
"%d",lObjID);
854 Bool_t TPgSQLStatement::SetDate(Int_t npar, Int_t year, Int_t month, Int_t day)
856 TDatime d =TDatime(year,month,day,0,0,0);
857 snprintf(fBind[npar],kBindStringSize,
"%s",(
char*)d.AsSQLString());
865 Bool_t TPgSQLStatement::SetTime(Int_t npar, Int_t hour, Int_t min, Int_t sec)
867 TDatime d=TDatime(2000,1,1,hour,min,sec);
868 snprintf(fBind[npar],kBindStringSize,
"%s",(
char*)d.AsSQLString());
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)
877 TDatime d=TDatime(year,month,day,hour,min,sec);
878 snprintf(fBind[npar],kBindStringSize,
"%s+00",(
char*)d.AsSQLString());
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)
890 TDatime d(year,month,day,hour,min,sec);
891 snprintf(fBind[npar],kBindStringSize,
"%s.%06d+00",(
char*)d.AsSQLString(),frac);
898 Bool_t TPgSQLStatement::SetTimestamp(Int_t npar,
const TTimeStamp& tm)
900 snprintf(fBind[npar], kBindStringSize,
"%s.%06d+00", (
char*)tm.AsString(
"s"), TMath::Nint(tm.GetNanoSec() / 1000.0));
910 TPgSQLStatement::TPgSQLStatement(PgSQL_Stmt_t*, Bool_t)
917 TPgSQLStatement::~TPgSQLStatement()
924 void TPgSQLStatement::Close(Option_t *)
931 Bool_t TPgSQLStatement::Process()
939 Int_t TPgSQLStatement::GetNumAffectedRows()
947 Int_t TPgSQLStatement::GetNumParameters()
956 Bool_t TPgSQLStatement::StoreResult()
964 Int_t TPgSQLStatement::GetNumFields()
972 const char* TPgSQLStatement::GetFieldName(Int_t)
980 Bool_t TPgSQLStatement::NextResultRow()
991 Bool_t TPgSQLStatement::NextIteration()
999 void TPgSQLStatement::FreeBuffers()
1006 void TPgSQLStatement::SetBuffersNumber(Int_t)
1013 const char* TPgSQLStatement::ConvertToString(Int_t)
1021 long double TPgSQLStatement::ConvertToNumeric(Int_t)
1029 Bool_t TPgSQLStatement::IsNull(Int_t)
1037 Int_t TPgSQLStatement::GetInt(Int_t)
1045 UInt_t TPgSQLStatement::GetUInt(Int_t)
1053 Long_t TPgSQLStatement::GetLong(Int_t)
1061 Long64_t TPgSQLStatement::GetLong64(Int_t)
1069 ULong64_t TPgSQLStatement::GetULong64(Int_t)
1077 Double_t TPgSQLStatement::GetDouble(Int_t)
1085 const char *TPgSQLStatement::GetString(Int_t)
1093 Bool_t TPgSQLStatement::GetBinary(Int_t,
void* &, Long_t&)
1101 Bool_t TPgSQLStatement::GetLargeObject(Int_t,
void* &, Long_t&)
1109 Bool_t TPgSQLStatement::GetDate(Int_t, Int_t&, Int_t&, Int_t&)
1117 Bool_t TPgSQLStatement::GetTime(Int_t, Int_t&, Int_t&, Int_t&)
1125 Bool_t TPgSQLStatement::GetDatime(Int_t, Int_t&, Int_t&, Int_t&, Int_t&, Int_t&, Int_t&)
1133 Bool_t TPgSQLStatement::GetTimestamp(Int_t, Int_t&, Int_t&, Int_t&, Int_t&, Int_t&, Int_t&, Int_t&)
1142 Bool_t TPgSQLStatement::GetTimestamp(Int_t npar, TTimeStamp& tm)
1152 Bool_t TPgSQLStatement::SetSQLParamType(Int_t,
int,
bool,
int)
1166 Bool_t TPgSQLStatement::SetNull(Int_t npar)
1168 if ((npar >= 0) && (npar < fNumBuffers))
1176 Bool_t TPgSQLStatement::SetInt(Int_t, Int_t)
1184 Bool_t TPgSQLStatement::SetUInt(Int_t, UInt_t)
1192 Bool_t TPgSQLStatement::SetLong(Int_t, Long_t)
1200 Bool_t TPgSQLStatement::SetLong64(Int_t, Long64_t)
1208 Bool_t TPgSQLStatement::SetULong64(Int_t, ULong64_t)
1216 Bool_t TPgSQLStatement::SetDouble(Int_t, Double_t)
1224 Bool_t TPgSQLStatement::SetString(Int_t,
const char*, Int_t)
1232 Bool_t TPgSQLStatement::SetBinary(Int_t,
void*, Long_t, Long_t)
1240 Bool_t TPgSQLStatement::SetLargeObject(Int_t,
void*, Long_t, Long_t)
1248 Bool_t TPgSQLStatement::SetDate(Int_t, Int_t, Int_t, Int_t)
1256 Bool_t TPgSQLStatement::SetTime(Int_t, Int_t, Int_t, Int_t)
1264 Bool_t TPgSQLStatement::SetDatime(Int_t, Int_t, Int_t, Int_t, Int_t, Int_t, Int_t)
1272 Bool_t TPgSQLStatement::SetTimestamp(Int_t, Int_t, Int_t, Int_t, Int_t, Int_t, Int_t, Int_t)
1280 Bool_t TPgSQLStatement::SetTimestamp(Int_t,
const TTimeStamp&)
1285 #endif //PG_VERSION_NUM