Logo ROOT  
Reference Guide
TODBCStatement.cxx
Go to the documentation of this file.
1// @(#)root/odbc:$Id$
2// Author: Sergey Linev 6/02/2006
3
4/*************************************************************************
5 * Copyright (C) 1995-2006, 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//
15// SQL statement class for ODBC
16//
17// See TSQLStatement class documentation for more details
18//
19//________________________________________________________________________
20
21
22#include "TODBCStatement.h"
23#include "TODBCServer.h"
24#include "TDataType.h"
25#include "Riostream.h"
26
27#include <sqlext.h>
28#include <stdlib.h>
29
30#define kSqlTime 123781
31#define kSqlDate 123782
32#define kSqlTimestamp 123783
33#define kSqlBinary 123784
34
35
37
38////////////////////////////////////////////////////////////////////////////////
39///constructor
40
41TODBCStatement::TODBCStatement(SQLHSTMT stmt, Int_t rowarrsize, Bool_t errout) :
42 TSQLStatement(errout)
43{
44 fHstmt = stmt;
45 fBufferPreferredSize = rowarrsize;
46
47 fBuffer = 0;
48 fStatusBuffer = 0;
49 fNumBuffers = 0;
50 fBufferLength = 0;
52
53 fWorkingMode = 0;
54
57
58 SQLSMALLINT paramsCount = 0;
59 SQLRETURN retcode = SQLNumParams(fHstmt, &paramsCount);
60 if (ExtractErrors(retcode,"Constructor"))
61 paramsCount = 0;
62
63 if (paramsCount>0) {
64
65 fWorkingMode = 1; // we are now using buffers for parameters
67
68 SQLSetStmtAttr(fHstmt, SQL_ATTR_PARAM_BIND_TYPE, SQL_PARAM_BIND_BY_COLUMN, 0);
69
70 SQLUINTEGER setsize = fBufferPreferredSize;
71 retcode = SQLSetStmtAttr(fHstmt, SQL_ATTR_PARAMSET_SIZE, (SQLPOINTER) (long) setsize, 0);
72 ExtractErrors(retcode,"Constructor");
73
74 SQLUINTEGER getsize = 0;
75
76 retcode = SQLGetStmtAttr(fHstmt, SQL_ATTR_PARAMSET_SIZE, &getsize, 0, 0);
77 ExtractErrors(retcode,"Constructor");
78
79 Int_t bufferlen = fBufferPreferredSize;
80
81 // MySQL is not yet support array of parameters
82 if (getsize<=1) bufferlen=1; else
83 if (getsize!=setsize) {
84 SQLSetStmtAttr(fHstmt, SQL_ATTR_PARAMSET_SIZE, (SQLPOINTER) 1, 0);
85 bufferlen = 1;
86 }
87
88 SetNumBuffers(paramsCount, bufferlen);
89
90 SQLSetStmtAttr(fHstmt, SQL_ATTR_PARAM_STATUS_PTR, fStatusBuffer, 0);
91 SQLSetStmtAttr(fHstmt, SQL_ATTR_PARAMS_PROCESSED_PTR, &fNumParsProcessed, 0);
92
93 // indicates that we are starting
94 fBufferCounter = -1;
95 }
96
99}
100
101////////////////////////////////////////////////////////////////////////////////
102///destructor
103
105{
106 Close();
107}
108
109////////////////////////////////////////////////////////////////////////////////
110/// Close statement
111
113{
114 FreeBuffers();
115
116 SQLFreeHandle(SQL_HANDLE_STMT, fHstmt);
117
118 fHstmt=0;
119}
120
121////////////////////////////////////////////////////////////////////////////////
122/// process statement
123
125{
126 ClearError();
127
128 SQLRETURN retcode = SQL_SUCCESS;
129
130 if (IsParSettMode()) {
131
132 // check if we start filling buffers, but not complete it
133 if (fBufferCounter>=0) {
134 // if buffer used not fully, set smaller size of buffer arrays
136 SQLUINTEGER setsize = fBufferCounter+1;
137 SQLSetStmtAttr(fHstmt, SQL_ATTR_PARAMSET_SIZE, (SQLPOINTER) (long) setsize, 0);
138 }
139 retcode = SQLExecute(fHstmt);
140 }
141
142 // after Process we finish working with parameters data,
143 // if necessary, user can try to access resultset of statement
144 fWorkingMode = 0;
145 FreeBuffers();
146 fBufferCounter = -1;
147 } else {
148
149 // just execute statement,
150 // later one can try to access results of statement
151 retcode = SQLExecute(fHstmt);
152 }
153
154 return !ExtractErrors(retcode, "Process");
155}
156
157////////////////////////////////////////////////////////////////////////////////
158///get number of affected rows
159
161{
162 ClearError();
163
164 SQLLEN rowCount;
165 SQLRETURN retcode = SQL_SUCCESS;
166
167 retcode = SQLRowCount(fHstmt, &rowCount);
168
169 if (ExtractErrors(retcode, "GetNumAffectedRows")) return -1;
170
171 return rowCount;
172}
173
174////////////////////////////////////////////////////////////////////////////////
175/// Store result of statement processing.
176/// Results set, produced by processing of statement, can be stored, and accessed by
177/// TODBCStamenet methoods like NextResultRow(), GetInt(), GetLong() and so on.
178
180{
181 ClearError();
182
183 if (IsParSettMode()) {
184 SetError(-1,"Call Process() method before","StoreResult");
185 return kFALSE;
186 }
187
188 FreeBuffers();
189
190 SQLSMALLINT columnCount = 0;
191
192 SQLRETURN retcode = SQLNumResultCols(fHstmt, &columnCount);
193 if (ExtractErrors(retcode, "StoreResult")) return kFALSE;
194
195 if (columnCount==0) return kFALSE;
196
198
199 SQLULEN arrsize = fBufferLength;
200
201 SQLSetStmtAttr(fHstmt, SQL_ATTR_ROW_BIND_TYPE, SQL_BIND_BY_COLUMN, 0);
202 SQLSetStmtAttr(fHstmt, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER) arrsize, 0);
203 SQLSetStmtAttr(fHstmt, SQL_ATTR_ROW_STATUS_PTR, fStatusBuffer, 0);
204 SQLSetStmtAttr(fHstmt, SQL_ATTR_ROWS_FETCHED_PTR, &fNumRowsFetched, 0);
205
206 for (int n=0;n<fNumBuffers;n++) {
207 SQLCHAR columnName[1024];
208 SQLSMALLINT nameLength;
209 SQLSMALLINT dataType;
210 SQLULEN columnSize;
211 SQLSMALLINT decimalDigits;
212 SQLSMALLINT nullable;
213
214 retcode = SQLDescribeCol(fHstmt, n+1, columnName, 1024,
215 &nameLength, &dataType,
216 &columnSize, &decimalDigits, &nullable);
217
218 BindColumn(n, dataType, columnSize);
219
220 if (nameLength>0) {
221 fBuffer[n].fBnamebuffer = new char[nameLength+1];
222 strlcpy(fBuffer[n].fBnamebuffer, (const char*) columnName, nameLength+1);
223 }
224 }
225
226 fNumRowsFetched = 0;
227 fLastResultRow = 0;
228
229 fWorkingMode = 2;
230
231 return kTRUE;
232}
233
234////////////////////////////////////////////////////////////////////////////////
235///return number of fields
236
238{
239 return IsResultSet() ? fNumBuffers : -1;
240}
241
242////////////////////////////////////////////////////////////////////////////////
243///return field name
244
246{
247 ClearError();
248
249 if (!IsResultSet() || (nfield<0) || (nfield>=fNumBuffers)) return 0;
250
251 return fBuffer[nfield].fBnamebuffer;
252}
253
254
255////////////////////////////////////////////////////////////////////////////////
256///next result row
257
259{
260 ClearError();
261
262 if (!IsResultSet()) return kFALSE;
263
264 if ((fNumRowsFetched==0) ||
265 (1.*fBufferCounter >= 1.*(fNumRowsFetched-1))) {
266
267 fBufferCounter = 0;
268 fNumRowsFetched = 0;
269
270 SQLRETURN retcode = SQLFetchScroll(fHstmt, SQL_FETCH_NEXT, 0);
271 if (retcode==SQL_NO_DATA) fNumRowsFetched=0; else
272 ExtractErrors(retcode,"NextResultRow");
273
274 // this is workaround of Oracle Linux ODBC driver
275 // it does not returns number of fetched lines, therefore one should
276 // calculate it from current row number
277 if (!IsError() && (retcode!=SQL_NO_DATA) && (fNumRowsFetched==0)) {
278 SQLULEN rownumber = 0;
279 SQLRETURN retcode2 = SQLGetStmtAttr(fHstmt, SQL_ATTR_ROW_NUMBER, &rownumber, 0, 0);
280 ExtractErrors(retcode2, "NextResultRow");
281
282 if (!IsError()) {
283 fNumRowsFetched = rownumber - fLastResultRow;
284 fLastResultRow = rownumber;
285 }
286 }
287
289 SetError(-1, "Missmatch between buffer length and fetched rows number", "NextResultRow");
290
291 if (IsError() || (fNumRowsFetched==0)) {
292 fWorkingMode = 0;
293 FreeBuffers();
294 }
295
296 } else
298
299 return IsResultSet();
300}
301
302////////////////////////////////////////////////////////////////////////////////
303/// Extract errors, produced by last ODBC function call
304
305Bool_t TODBCStatement::ExtractErrors(SQLRETURN retcode, const char* method)
306{
307 if ((retcode== SQL_SUCCESS) || (retcode == SQL_SUCCESS_WITH_INFO)) return kFALSE;
308
309 SQLINTEGER i = 0;
310 SQLINTEGER native;
311 SQLCHAR state[ 7 ];
312 SQLCHAR text[256];
313 SQLSMALLINT len;
314 SQLRETURN ret;
315 do {
316 ret = SQLGetDiagRec(SQL_HANDLE_STMT, fHstmt, ++i, state, &native, text,
317 sizeof(text), &len );
318 if (ret == SQL_SUCCESS) SetError(native, (const char*) text, method);
319// Error(method, "%s:%ld:%ld:%s\n", state, i, native, text);
320 }
321 while( ret == SQL_SUCCESS );
322 return kTRUE;
323}
324
325////////////////////////////////////////////////////////////////////////////////
326///run next iteration
327
329{
330 ClearError();
331
332 if (!IsParSettMode() || (fBuffer==0) || (fBufferLength<=0)) return kFALSE;
333
335 SQLRETURN retcode = SQLExecute(fHstmt);
336 if (ExtractErrors(retcode,"NextIteration")) return kFALSE;
337 fBufferCounter = 0;
338 } else
340
341 // probably, we do not need it, but anyway
342 fStatusBuffer[fBufferCounter] = SQL_ROW_SUCCESS;
343
344 return kTRUE;
345}
346
347////////////////////////////////////////////////////////////////////////////////
348///return number of parameters
349
351{
352 return IsParSettMode() ? fNumBuffers : 0;
353}
354
355////////////////////////////////////////////////////////////////////////////////
356///set number of buffers
357
359{
360 FreeBuffers();
361
362 fNumBuffers = isize;
363 fBufferLength = ilen;
364 fBufferCounter = 0;
365
367 for (Int_t n=0;n<fNumBuffers;n++) {
368 fBuffer[n].fBroottype = 0;
369 fBuffer[n].fBsqltype = 0;
370 fBuffer[n].fBsqlctype = 0;
371 fBuffer[n].fBbuffer = 0;
373 fBuffer[n].fBlenarray = 0;
374 fBuffer[n].fBstrbuffer = 0;
376 }
377
378 fStatusBuffer = new SQLUSMALLINT[fBufferLength];
379}
380
381////////////////////////////////////////////////////////////////////////////////
382/// Free allocated buffers
383
385{
386 if (fBuffer==0) return;
387 for (Int_t n=0;n<fNumBuffers;n++) {
388 if (fBuffer[n].fBbuffer!=0)
389 free(fBuffer[n].fBbuffer);
390 delete[] fBuffer[n].fBlenarray;
391 delete[] fBuffer[n].fBstrbuffer;
392 delete[] fBuffer[n].fBnamebuffer;
393 }
394
395 delete[] fStatusBuffer;
396 delete[] fBuffer;
397 fBuffer = 0;
398 fNumBuffers = 0;
399 fBufferLength = 0;
400 fStatusBuffer = 0;
401}
402
403////////////////////////////////////////////////////////////////////////////////
404/// Bind result column to buffer. Allocate buffer of appropriate type
405
406Bool_t TODBCStatement::BindColumn(Int_t ncol, SQLSMALLINT sqltype, SQLUINTEGER size)
407{
408 ClearError();
409
410 if ((ncol<0) || (ncol>=fNumBuffers)) {
411 SetError(-1,"Internal error. Column number invalid","BindColumn");
412 return kFALSE;
413 }
414
415 if (fBuffer[ncol].fBsqltype!=0) {
416 SetError(-1,"Internal error. Bind for column already done","BindColumn");
417 return kFALSE;
418 }
419
420 SQLSMALLINT sqlctype = 0;
421 switch (sqltype) {
422 case SQL_CHAR:
423 case SQL_VARCHAR: sqlctype = SQL_C_CHAR; break;
424 case SQL_BINARY:
425 case SQL_LONGVARBINARY:
426 case SQL_VARBINARY: sqlctype = SQL_C_BINARY; break;
427 case SQL_LONGVARCHAR: Info("BindColumn","BIG VARCHAR not supported yet"); return kFALSE; break;
428
429 case SQL_DECIMAL: sqlctype = SQL_C_DOUBLE; break;
430 case SQL_NUMERIC: sqlctype = SQL_C_DOUBLE; break;
431 case SQL_SMALLINT: sqlctype = SQL_C_SLONG; break;
432 case SQL_INTEGER: sqlctype = SQL_C_SLONG; break;
433 case SQL_FLOAT: sqlctype = SQL_C_FLOAT; break;
434 case SQL_REAL:
435 case SQL_DOUBLE: sqlctype = SQL_C_DOUBLE; break;
436 case SQL_TINYINT: sqlctype = SQL_C_STINYINT; break;
437 case SQL_BIGINT: sqlctype = SQL_C_SBIGINT; break;
438 case SQL_TYPE_DATE: sqlctype = SQL_C_TYPE_DATE; break;
439 case SQL_TYPE_TIME: sqlctype = SQL_C_TYPE_TIME; break;
440 case SQL_TYPE_TIMESTAMP: sqlctype = SQL_C_TYPE_TIMESTAMP; break;
441 default: {
442 SetError(-1, Form("SQL type %d not supported",sqltype), "BindColumn");
443 return kFALSE;
444 }
445 }
446
447 int elemsize = 0;
448
449 switch (sqlctype) {
450 case SQL_C_ULONG: elemsize = sizeof(SQLUINTEGER); break;
451 case SQL_C_SLONG: elemsize = sizeof(SQLINTEGER); break;
452 case SQL_C_UBIGINT: elemsize = sizeof(ULong64_t); break; // should be SQLUBIGINT, but it is 64-bit structure on some platforms
453 case SQL_C_SBIGINT: elemsize = sizeof(Long64_t); break; // should be SQLBIGINT, but it is 64-bit structure on some platforms
454 case SQL_C_USHORT: elemsize = sizeof(SQLUSMALLINT); break;
455 case SQL_C_SSHORT: elemsize = sizeof(SQLSMALLINT); break;
456 case SQL_C_UTINYINT: elemsize = sizeof(SQLCHAR); break;
457 case SQL_C_STINYINT: elemsize = sizeof(SQLSCHAR); break;
458 case SQL_C_FLOAT: elemsize = sizeof(SQLREAL); break;
459 case SQL_C_DOUBLE: elemsize = sizeof(SQLDOUBLE); break;
460 case SQL_C_CHAR: elemsize = size; break;
461 case SQL_C_BINARY: elemsize = size; break;
462 case SQL_C_TYPE_DATE: elemsize = sizeof(DATE_STRUCT); break;
463 case SQL_C_TYPE_TIME: elemsize = sizeof(TIME_STRUCT); break;
464 case SQL_C_TYPE_TIMESTAMP: elemsize = sizeof(TIMESTAMP_STRUCT); break;
465
466 default: {
467 SetError(-1, Form("SQL C Type %d is not supported",sqlctype), "BindColumn");
468 return kFALSE;
469 }
470 }
471
472 fBuffer[ncol].fBroottype = 0;
473 fBuffer[ncol].fBsqltype = sqltype;
474 fBuffer[ncol].fBsqlctype = sqlctype;
475 fBuffer[ncol].fBbuffer = malloc(elemsize * fBufferLength);
476 fBuffer[ncol].fBelementsize = elemsize;
477 fBuffer[ncol].fBlenarray = new SQLLEN[fBufferLength];
478
479 SQLRETURN retcode =
480 SQLBindCol(fHstmt, ncol+1, sqlctype, fBuffer[ncol].fBbuffer,
481 elemsize,
482 fBuffer[ncol].fBlenarray);
483
484 return !ExtractErrors(retcode, "BindColumn");
485}
486
487////////////////////////////////////////////////////////////////////////////////
488/// Bind query parameter with buffer. Creates buffer of appropriate type
489
491{
492 ClearError();
493
494 if ((npar<0) || (npar>=fNumBuffers)) return kFALSE;
495
496 if (fBuffer[npar].fBroottype!=0) {
497 SetError(-1,Form("ParameterType for par %d already specified", npar),"BindParam");
498 return kFALSE;
499 }
500
501 SQLSMALLINT sqltype = 0, sqlctype = 0;
502 int elemsize = 0;
503
504 switch (roottype) {
505 case kUInt_t: sqltype = SQL_INTEGER; sqlctype = SQL_C_ULONG; elemsize = sizeof(SQLUINTEGER); break;
506 case kInt_t: sqltype = SQL_INTEGER; sqlctype = SQL_C_SLONG; elemsize = sizeof(SQLINTEGER); break;
507 case kULong_t: sqltype = SQL_INTEGER; sqlctype = SQL_C_ULONG; elemsize = sizeof(SQLUINTEGER); break;
508 case kLong_t: sqltype = SQL_INTEGER; sqlctype = SQL_C_SLONG; elemsize = sizeof(SQLINTEGER); break;
509
510 // here SQLUBIGINT/SQLBIGINT types should be used,
511 // but on 32-bit platforms it is structures, which makes its usage inconvinient
512 case kULong64_t: sqltype = SQL_BIGINT; sqlctype = SQL_C_UBIGINT; elemsize = sizeof(ULong64_t); break;
513 case kLong64_t: sqltype = SQL_BIGINT; sqlctype = SQL_C_SBIGINT; elemsize = sizeof(Long64_t); break;
514
515 case kUShort_t: sqltype = SQL_SMALLINT;sqlctype = SQL_C_USHORT; elemsize = sizeof(SQLUSMALLINT); break;
516 case kShort_t: sqltype = SQL_SMALLINT;sqlctype = SQL_C_SSHORT; elemsize = sizeof(SQLSMALLINT); break;
517 case kUChar_t: sqltype = SQL_TINYINT; sqlctype = SQL_C_UTINYINT; elemsize = sizeof(SQLCHAR); break;
518 case kChar_t: sqltype = SQL_TINYINT; sqlctype = SQL_C_STINYINT; elemsize = sizeof(SQLSCHAR); break;
519 case kBool_t: sqltype = SQL_TINYINT; sqlctype = SQL_C_UTINYINT; elemsize = sizeof(SQLCHAR); break;
520 case kFloat_t: sqltype = SQL_FLOAT; sqlctype = SQL_C_FLOAT; elemsize = sizeof(SQLREAL); break;
521 case kFloat16_t: sqltype = SQL_FLOAT; sqlctype = SQL_C_FLOAT; elemsize = sizeof(SQLREAL); break;
522 case kDouble_t: sqltype = SQL_DOUBLE; sqlctype = SQL_C_DOUBLE; elemsize = sizeof(SQLDOUBLE); break;
523 case kDouble32_t: sqltype = SQL_DOUBLE; sqlctype = SQL_C_DOUBLE; elemsize = sizeof(SQLDOUBLE); break;
524 case kCharStar: sqltype = SQL_CHAR; sqlctype = SQL_C_CHAR; elemsize = size; break;
525 case kSqlBinary: sqltype = SQL_BINARY; sqlctype = SQL_C_BINARY; elemsize = size; break;
526 case kSqlDate: sqltype = SQL_TYPE_DATE; sqlctype = SQL_C_TYPE_DATE; elemsize = sizeof(DATE_STRUCT); break;
527 case kSqlTime: sqltype = SQL_TYPE_TIME; sqlctype = SQL_C_TYPE_TIME; elemsize = sizeof(TIME_STRUCT); break;
528 case kSqlTimestamp: sqltype = SQL_TYPE_TIMESTAMP; sqlctype = SQL_C_TYPE_TIMESTAMP; elemsize = sizeof(TIMESTAMP_STRUCT); break;
529 default: {
530 SetError(-1, Form("Root type %d is not supported", roottype), "BindParam");
531 return kFALSE;
532 }
533 }
534
535 void* buffer = malloc(elemsize * fBufferLength);
536 SQLLEN* lenarray = new SQLLEN[fBufferLength];
537 SQLRETURN retcode =
538 SQLBindParameter(fHstmt, npar+1, SQL_PARAM_INPUT,
539 sqlctype, sqltype, 0, 0,
540 buffer, elemsize, lenarray);
541
542 if (ExtractErrors(retcode, "BindParam")) {
543 free(buffer);
544 delete[] lenarray;
545 return kFALSE;
546 }
547
548 fBuffer[npar].fBroottype = roottype;
549 fBuffer[npar].fBsqlctype = sqlctype;
550 fBuffer[npar].fBsqltype = sqltype;
551 fBuffer[npar].fBbuffer = buffer;
552 fBuffer[npar].fBelementsize = elemsize;
553 fBuffer[npar].fBlenarray = lenarray;
554
555 return kTRUE;
556}
557
558////////////////////////////////////////////////////////////////////////////////
559/// Get parameter address
560
561void* TODBCStatement::GetParAddr(Int_t npar, Int_t roottype, Int_t length)
562{
563 ClearError();
564
565 if ((fBuffer==0) || (npar<0) || (npar>=fNumBuffers) || (fBufferCounter<0)) {
566 SetError(-1, "Invalid parameter number","GetParAddr");
567 return 0;
568 }
569
570 if (fBuffer[npar].fBbuffer==0) {
571 if (IsParSettMode() && (roottype!=0) && (fBufferCounter==0))
572 if (!BindParam(npar, roottype, length)) return 0;
573
574 if (fBuffer[npar].fBbuffer==0) return 0;
575 }
576
577 if (roottype!=0)
578 if (fBuffer[npar].fBroottype!=roottype) return 0;
579
580 return (char*)fBuffer[npar].fBbuffer + fBufferCounter*fBuffer[npar].fBelementsize;
581}
582
583////////////////////////////////////////////////////////////////////////////////
584///convert to numeric type
585
587{
588 void* addr = GetParAddr(npar);
589 if (addr==0) return 0;
590
591 switch (fBuffer[npar].fBsqlctype) {
592 case SQL_C_ULONG: return *((SQLUINTEGER*) addr); break;
593 case SQL_C_SLONG: return *((SQLINTEGER*) addr); break;
594 case SQL_C_UBIGINT: return *((ULong64_t*) addr); break;
595 case SQL_C_SBIGINT: return *((Long64_t*) addr); break;
596 case SQL_C_USHORT: return *((SQLUSMALLINT*) addr); break;
597 case SQL_C_SSHORT: return *((SQLSMALLINT*) addr); break;
598 case SQL_C_UTINYINT: return *((SQLCHAR*) addr); break;
599 case SQL_C_STINYINT: return *((SQLSCHAR*) addr); break;
600 case SQL_C_FLOAT: return *((SQLREAL*) addr); break;
601 case SQL_C_DOUBLE: return *((SQLDOUBLE*) addr); break;
602 case SQL_C_TYPE_DATE: {
603 DATE_STRUCT* dt = (DATE_STRUCT*) addr;
604 TDatime rtm(dt->year, dt->month, dt->day, 0, 0, 0);
605 return rtm.GetDate();
606 break;
607 }
608 case SQL_C_TYPE_TIME: {
609 TIME_STRUCT* tm = (TIME_STRUCT*) addr;
610 TDatime rtm(2000, 1, 1, tm->hour, tm->minute, tm->second);
611 return rtm.GetTime();
612 break;
613 }
614 case SQL_C_TYPE_TIMESTAMP: {
615 TIMESTAMP_STRUCT* tm = (TIMESTAMP_STRUCT*) addr;
616 TDatime rtm(tm->year, tm->month, tm->day,
617 tm->hour, tm->minute, tm->second);
618 return rtm.Get();
619 break;
620 }
621 }
622 return 0;
623}
624
625////////////////////////////////////////////////////////////////////////////////
626///convert to string
627
629{
630 void* addr = GetParAddr(npar);
631 if (addr==0) return 0;
632 if (fBuffer[npar].fBstrbuffer==0)
633 fBuffer[npar].fBstrbuffer = new char[100];
634
635 char* buf = fBuffer[npar].fBstrbuffer;
636
637 switch(fBuffer[npar].fBsqlctype) {
638#if (SIZEOF_LONG == 8)
639 case SQL_C_SLONG: snprintf(buf, 100, "%d", *((SQLINTEGER*) addr)); break;
640 case SQL_C_ULONG: snprintf(buf, 100, "%u", *((SQLUINTEGER*) addr)); break;
641#else
642 case SQL_C_SLONG: snprintf(buf, 100, "%ld", (long)*((SQLINTEGER*) addr)); break;
643 case SQL_C_ULONG: snprintf(buf, 100, "%lu", (unsigned long)*((SQLUINTEGER*) addr)); break;
644#endif
645 case SQL_C_SBIGINT: snprintf(buf, 100, "%lld", *((Long64_t*) addr)); break;
646 case SQL_C_UBIGINT: snprintf(buf, 100, "%llu", *((ULong64_t*) addr)); break;
647 case SQL_C_SSHORT: snprintf(buf, 100, "%hd", *((SQLSMALLINT*) addr)); break;
648 case SQL_C_USHORT: snprintf(buf, 100, "%hu", *((SQLUSMALLINT*) addr)); break;
649 case SQL_C_STINYINT:snprintf(buf, 100, "%d", *((SQLSCHAR*) addr)); break;
650 case SQL_C_UTINYINT:snprintf(buf, 100, "%u", *((SQLCHAR*) addr)); break;
651 case SQL_C_FLOAT: snprintf(buf, 100, TSQLServer::GetFloatFormat(), *((SQLREAL*) addr)); break;
652 case SQL_C_DOUBLE: snprintf(buf, 100, TSQLServer::GetFloatFormat(), *((SQLDOUBLE*) addr)); break;
653 case SQL_C_TYPE_DATE: {
654 DATE_STRUCT* dt = (DATE_STRUCT*) addr;
655 snprintf(buf,100,"%4.4d-%2.2d-%2.2d",
656 dt->year, dt->month, dt->day);
657 break;
658 }
659 case SQL_C_TYPE_TIME: {
660 TIME_STRUCT* tm = (TIME_STRUCT*) addr;
661 snprintf(buf,100,"%2.2d:%2.2d:%2.2d",
662 tm->hour, tm->minute, tm->second);
663 break;
664 }
665 case SQL_C_TYPE_TIMESTAMP: {
666 TIMESTAMP_STRUCT* tm = (TIMESTAMP_STRUCT*) addr;
667 snprintf(buf,100,"%4.4d-%2.2d-%2.2d %2.2d:%2.2d:%2.2d",
668 tm->year, tm->month, tm->day,
669 tm->hour, tm->minute, tm->second);
670 break;
671 }
672 default: return 0;
673 }
674
675 return buf;
676}
677
678////////////////////////////////////////////////////////////////////////////////
679/// Verifies if field value is NULL
680
682{
683 void* addr = GetParAddr(npar);
684 if (addr==0) return kTRUE;
685
686 return fBuffer[npar].fBlenarray[fBufferCounter] == SQL_NULL_DATA;
687}
688
689////////////////////////////////////////////////////////////////////////////////
690///get parameter as integer
691
693{
694 void* addr = GetParAddr(npar);
695 if (addr==0) return 0;
696
697 if (fBuffer[npar].fBsqlctype==SQL_C_SLONG)
698 return (Int_t) *((SQLINTEGER*) addr);
699
700 return (Int_t) ConvertToNumeric(npar);
701}
702
703////////////////////////////////////////////////////////////////////////////////
704///get parameter as unsigned integer
705
707{
708 void* addr = GetParAddr(npar);
709 if (addr==0) return 0;
710
711 if (fBuffer[npar].fBsqlctype==SQL_C_ULONG)
712 return (UInt_t) *((SQLUINTEGER*) addr);
713
714 return (UInt_t) ConvertToNumeric(npar);
715}
716
717////////////////////////////////////////////////////////////////////////////////
718///get parameter as Long_t
719
721{
722 void* addr = GetParAddr(npar);
723 if (addr==0) return 0;
724
725 if (fBuffer[npar].fBsqlctype==SQL_C_SLONG)
726 return (Long_t) *((SQLINTEGER*) addr);
727
728 return (Long_t) ConvertToNumeric(npar);
729}
730
731////////////////////////////////////////////////////////////////////////////////
732///get parameter as Long64_t
733
735{
736 void* addr = GetParAddr(npar);
737 if (addr==0) return 0;
738
739 if (fBuffer[npar].fBsqlctype==SQL_C_SBIGINT)
740 return *((Long64_t*) addr);
741
742 return (Long64_t) ConvertToNumeric(npar);
743}
744
745////////////////////////////////////////////////////////////////////////////////
746///get parameter as ULong64_t
747
749{
750 void* addr = GetParAddr(npar);
751 if (addr==0) return 0;
752
753 if (fBuffer[npar].fBsqlctype==SQL_C_UBIGINT)
754 return *((ULong64_t*) addr);
755
756 return (ULong64_t) ConvertToNumeric(npar);
757}
758
759////////////////////////////////////////////////////////////////////////////////
760///get parameter as Double_t
761
763{
764 void* addr = GetParAddr(npar);
765 if (addr==0) return 0;
766
767 if (fBuffer[npar].fBsqlctype==SQL_C_DOUBLE)
768 return *((SQLDOUBLE*) addr);
769
770 return (Double_t) ConvertToNumeric(npar);
771}
772
773////////////////////////////////////////////////////////////////////////////////
774///get parameter as string
775
777{
778 void* addr = GetParAddr(npar);
779 if (addr==0) return 0;
780
781 if (fBuffer[npar].fBsqlctype==SQL_C_CHAR) {
782 // first check if string is null
783
784 int len = fBuffer[npar].fBlenarray[fBufferCounter];
785
786 if ((len == SQL_NULL_DATA) || (len==0)) return 0;
787
788 char* res = (char*) addr;
789 if (len < fBuffer[npar].fBelementsize) {
790 *(res + len) = 0;
791 return res;
792 }
793
794 if (len > fBuffer[npar].fBelementsize) {
795 SetError(-1, Form("Problems with string size %d", len), "GetString");
796 return 0;
797 }
798
799 if (fBuffer[npar].fBstrbuffer==0)
800 fBuffer[npar].fBstrbuffer = new char[len+1];
801
802 strlcpy(fBuffer[npar].fBstrbuffer, res, len+1);
803
804 res = fBuffer[npar].fBstrbuffer;
805 *(res + len) = 0;
806 return res;
807 }
808
809 return ConvertToString(npar);
810}
811
812////////////////////////////////////////////////////////////////////////////////
813/// return parameter as binary data
814
816{
817 mem = 0;
818 size = 0;
819
820 void* addr = GetParAddr(npar);
821 if (addr==0) return kFALSE;
822
823 if ((fBuffer[npar].fBsqlctype==SQL_C_BINARY) ||
824 (fBuffer[npar].fBsqlctype==SQL_C_CHAR)) {
825
826 // first check if data length is null
827 int len = fBuffer[npar].fBlenarray[fBufferCounter];
828
829 if ((len == SQL_NULL_DATA) || (len==0)) return kTRUE;
830
831 size = len;
832
833 if (fBuffer[npar].fBstrbuffer==0)
834 fBuffer[npar].fBstrbuffer = new char[size];
835
836 memcpy(fBuffer[npar].fBstrbuffer, addr, size);
837
838 mem = fBuffer[npar].fBstrbuffer;
839
840 return kTRUE;
841 }
842
843 return kFALSE;
844}
845
846
847////////////////////////////////////////////////////////////////////////////////
848/// return field value as date
849
851{
852 void* addr = GetParAddr(npar);
853 if (addr==0) return kFALSE;
854
855 if (fBuffer[npar].fBsqlctype!=SQL_C_TYPE_DATE) return kFALSE;
856
857 DATE_STRUCT* dt = (DATE_STRUCT*) addr;
858 year = dt->year;
859 month = dt->month;
860 day = dt->day;
861
862 return kTRUE;
863}
864
865////////////////////////////////////////////////////////////////////////////////
866/// return field value as time
867
869{
870 void* addr = GetParAddr(npar);
871 if (addr==0) return kFALSE;
872
873 if (fBuffer[npar].fBsqlctype!=SQL_C_TYPE_TIME) return kFALSE;
874
875 TIME_STRUCT* tm = (TIME_STRUCT*) addr;
876 hour = tm->hour;
877 min = tm->minute;
878 sec = tm->second;
879
880 return kTRUE;
881}
882
883////////////////////////////////////////////////////////////////////////////////
884/// return field value as date & time
885
886Bool_t TODBCStatement::GetDatime(Int_t npar, Int_t& year, Int_t& month, Int_t& day, Int_t& hour, Int_t& min, Int_t& sec)
887{
888 void* addr = GetParAddr(npar);
889 if (addr==0) return kFALSE;
890
891 if (fBuffer[npar].fBsqlctype!=SQL_C_TYPE_TIMESTAMP) return kFALSE;
892
893 TIMESTAMP_STRUCT* tm = (TIMESTAMP_STRUCT*) addr;
894
895 year = tm->year;
896 month = tm->month;
897 day = tm->day;
898 hour = tm->hour;
899 min = tm->minute;
900 sec = tm->second;
901 return kTRUE;
902}
903
904////////////////////////////////////////////////////////////////////////////////
905/// return field value as time stamp
906
907Bool_t TODBCStatement::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)
908{
909 void* addr = GetParAddr(npar);
910 if (addr==0) return kFALSE;
911
912 if (fBuffer[npar].fBsqlctype!=SQL_C_TYPE_TIMESTAMP) return kFALSE;
913
914 TIMESTAMP_STRUCT* tm = (TIMESTAMP_STRUCT*) addr;
915
916 year = tm->year;
917 month = tm->month;
918 day = tm->day;
919 hour = tm->hour;
920 min = tm->minute;
921 sec = tm->second;
922 frac = tm->fraction;
923 return kTRUE;
924}
925
926
927////////////////////////////////////////////////////////////////////////////////
928/// Set NULL as parameter value
929/// If NULL should be set for statement parameter during first iteration,
930/// one should call before proper Set... method to identify type of argument for
931/// the future. For instance, if one suppose to have double as type of parameter,
932/// code should look like:
933/// stmt->SetDouble(2, 0.);
934/// stmt->SetNull(2);
935
937{
938 void* addr = GetParAddr(npar, kInt_t);
939 if (addr!=0)
940 *((SQLINTEGER*) addr) = 0;
941
942 if ((npar>=0) && (npar<fNumBuffers))
943 fBuffer[npar].fBlenarray[fBufferCounter] = SQL_NULL_DATA;
944
945 return kTRUE;
946}
947
948////////////////////////////////////////////////////////////////////////////////
949///set parameter as Int_t
950
952{
953 void* addr = GetParAddr(npar, kInt_t);
954 if (addr==0) return kFALSE;
955
956 *((SQLINTEGER*) addr) = value;
957
959
960 return kTRUE;
961}
962
963////////////////////////////////////////////////////////////////////////////////
964///set parameter as UInt_t
965
967{
968 void* addr = GetParAddr(npar, kUInt_t);
969 if (addr==0) return kFALSE;
970
971 *((SQLUINTEGER*) addr) = value;
972
974
975 return kTRUE;
976}
977
978////////////////////////////////////////////////////////////////////////////////
979///set parameter as Long_t
980
982{
983 void* addr = GetParAddr(npar, kLong_t);
984 if (addr==0) return kFALSE;
985
986 *((SQLINTEGER*) addr) = value;
987
989
990 return kTRUE;
991}
992
993////////////////////////////////////////////////////////////////////////////////
994///set parameter as Long64_t
995
997{
998 void* addr = GetParAddr(npar, kLong64_t);
999 if (addr==0) return kFALSE;
1000
1001 *((Long64_t*) addr) = value;
1002
1004
1005 return kTRUE;
1006}
1007
1008////////////////////////////////////////////////////////////////////////////////
1009///set parameter as ULong64_t
1010
1012{
1013 void* addr = GetParAddr(npar, kULong64_t);
1014 if (addr==0) return kFALSE;
1015
1016 *((ULong64_t*) addr) = value;
1017
1019
1020 return kTRUE;
1021}
1022
1023////////////////////////////////////////////////////////////////////////////////
1024///set parameter as Double_t
1025
1027{
1028 void* addr = GetParAddr(npar, kDouble_t);
1029 if (addr==0) return kFALSE;
1030
1031 *((SQLDOUBLE*) addr) = value;
1032
1034
1035 return kTRUE;
1036}
1037
1038////////////////////////////////////////////////////////////////////////////////
1039///set parameter as string
1040
1041Bool_t TODBCStatement::SetString(Int_t npar, const char* value, Int_t maxsize)
1042{
1043 void* addr = GetParAddr(npar, kCharStar, maxsize);
1044
1045 if (addr==0) return kFALSE;
1046
1047 if (value) {
1048 int len = strlen(value);
1049
1050 if (len>=fBuffer[npar].fBelementsize) {
1051 len = fBuffer[npar].fBelementsize;
1052 strlcpy((char*) addr, value, len+1);
1053 fBuffer[npar].fBlenarray[fBufferCounter] = len;
1054
1055 } else if (len>0) {
1056 strlcpy((char*) addr, value, maxsize);
1057 fBuffer[npar].fBlenarray[fBufferCounter] = SQL_NTS;
1058 } else {
1059 *((char*) addr) = 0;
1060 fBuffer[npar].fBlenarray[fBufferCounter] = SQL_NTS;
1061 }
1062 } else {
1063 *((char*) addr) = 0;
1064 fBuffer[npar].fBlenarray[fBufferCounter] = SQL_NTS;
1065 }
1066
1067 return kTRUE;
1068}
1069
1070////////////////////////////////////////////////////////////////////////////////
1071///set parameter value as binary data
1072
1073Bool_t TODBCStatement::SetBinary(Int_t npar, void* mem, Long_t size, Long_t maxsize)
1074{
1075 void* addr = GetParAddr(npar, kSqlBinary, maxsize);
1076 if (addr==0) return kFALSE;
1077
1078 if (size>fBuffer[npar].fBelementsize)
1079 size = fBuffer[npar].fBelementsize;
1080
1081 memcpy(addr, mem, size);
1082 fBuffer[npar].fBlenarray[fBufferCounter] = size;
1083
1084 return kTRUE;
1085}
1086
1087////////////////////////////////////////////////////////////////////////////////
1088/// set parameter value as date
1089
1091{
1092 void* addr = GetParAddr(npar, kSqlDate);
1093 if (addr==0) return kFALSE;
1094
1095 DATE_STRUCT* dt = (DATE_STRUCT*) addr;
1096 dt->year = year;
1097 dt->month = month;
1098 dt->day = day;
1099
1101
1102 return kTRUE;
1103}
1104
1105////////////////////////////////////////////////////////////////////////////////
1106/// set parameter value as time
1107
1109{
1110 void* addr = GetParAddr(npar, kSqlTime);
1111 if (addr==0) return kFALSE;
1112
1113 TIME_STRUCT* tm = (TIME_STRUCT*) addr;
1114 tm->hour = hour;
1115 tm->minute = min;
1116 tm->second = sec;
1117
1119
1120 return kTRUE;
1121}
1122
1123////////////////////////////////////////////////////////////////////////////////
1124/// set parameter value as date & time
1125
1126Bool_t TODBCStatement::SetDatime(Int_t npar, Int_t year, Int_t month, Int_t day, Int_t hour, Int_t min, Int_t sec)
1127{
1128 void* addr = GetParAddr(npar, kSqlTimestamp);
1129 if (addr==0) return kFALSE;
1130
1131 TIMESTAMP_STRUCT* tm = (TIMESTAMP_STRUCT*) addr;
1132 tm->year = year;
1133 tm->month = month;
1134 tm->day = day;
1135 tm->hour = hour;
1136 tm->minute = min;
1137 tm->second = sec;
1138 tm->fraction = 0;
1139
1141
1142 return kTRUE;
1143}
1144
1145////////////////////////////////////////////////////////////////////////////////
1146/// set parameter value as timestamp
1147
1148Bool_t TODBCStatement::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)
1149{
1150 void* addr = GetParAddr(npar, kSqlTimestamp);
1151 if (addr==0) return kFALSE;
1152
1153 TIMESTAMP_STRUCT* tm = (TIMESTAMP_STRUCT*) addr;
1154 tm->year = year;
1155 tm->month = month;
1156 tm->day = day;
1157 tm->hour = hour;
1158 tm->minute = min;
1159 tm->second = sec;
1160 tm->fraction = frac;
1161
1163
1164 return kTRUE;
1165}
int Int_t
Definition: RtypesCore.h:41
unsigned int UInt_t
Definition: RtypesCore.h:42
const Bool_t kFALSE
Definition: RtypesCore.h:88
long Long_t
Definition: RtypesCore.h:50
bool Bool_t
Definition: RtypesCore.h:59
double Double_t
Definition: RtypesCore.h:55
long long Long64_t
Definition: RtypesCore.h:69
unsigned long long ULong64_t
Definition: RtypesCore.h:70
const Bool_t kTRUE
Definition: RtypesCore.h:87
const char Option_t
Definition: RtypesCore.h:62
#define ClassImp(name)
Definition: Rtypes.h:365
@ kFloat_t
Definition: TDataType.h:31
@ kULong64_t
Definition: TDataType.h:32
@ kInt_t
Definition: TDataType.h:30
@ kLong_t
Definition: TDataType.h:30
@ kDouble32_t
Definition: TDataType.h:31
@ kShort_t
Definition: TDataType.h:29
@ kBool_t
Definition: TDataType.h:32
@ kULong_t
Definition: TDataType.h:30
@ kLong64_t
Definition: TDataType.h:32
@ kUShort_t
Definition: TDataType.h:29
@ kDouble_t
Definition: TDataType.h:31
@ kCharStar
Definition: TDataType.h:34
@ kChar_t
Definition: TDataType.h:29
@ kUChar_t
Definition: TDataType.h:29
@ kUInt_t
Definition: TDataType.h:30
@ kFloat16_t
Definition: TDataType.h:33
#define kSqlBinary
#define kSqlDate
#define kSqlTimestamp
#define kSqlTime
char * Form(const char *fmt,...)
#define free
Definition: civetweb.c:1539
#define snprintf
Definition: civetweb.c:1540
#define malloc
Definition: civetweb.c:1536
This class stores the date and time with a precision of one second in an unsigned 32 bit word (950130...
Definition: TDatime.h:37
Int_t GetDate() const
Return date in form of 19971224 (i.e. 24/12/1997)
Definition: TDatime.cxx:247
UInt_t Get() const
Return raw date/time as encoded by TDatime.
Definition: TDatime.cxx:239
Int_t GetTime() const
Return time in form of 123623 (i.e. 12:36:23)
Definition: TDatime.cxx:258
void SetNumBuffers(Int_t isize, Int_t ilen)
set number of buffers
virtual Bool_t NextIteration()
run next iteration
virtual Bool_t SetDouble(Int_t npar, Double_t value)
set parameter as Double_t
virtual Bool_t GetDatime(Int_t npar, Int_t &year, Int_t &month, Int_t &day, Int_t &hour, Int_t &min, Int_t &sec)
return field value as date & time
void FreeBuffers()
Free allocated buffers.
virtual const char * GetString(Int_t npar)
get parameter as string
Bool_t BindParam(Int_t n, Int_t type, Int_t size=1024)
Bind query parameter with buffer. Creates buffer of appropriate type.
TODBCStatement(SQLHSTMT stmt, Int_t rowarrsize, Bool_t errout=kTRUE)
constructor
virtual UInt_t GetUInt(Int_t npar)
get parameter as unsigned integer
virtual Bool_t StoreResult()
Store result of statement processing.
Bool_t IsParSettMode() const
virtual Bool_t 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=0)
set parameter value as timestamp
const char * ConvertToString(Int_t npar)
convert to string
virtual Bool_t SetDate(Int_t npar, Int_t year, Int_t month, Int_t day)
set parameter value as date
ULong64_t fLastResultRow
virtual Bool_t SetInt(Int_t npar, Int_t value)
set parameter as Int_t
virtual Bool_t GetTime(Int_t npar, Int_t &hour, Int_t &min, Int_t &sec)
return field value as time
long double ConvertToNumeric(Int_t npar)
convert to numeric type
virtual ~TODBCStatement()
destructor
virtual Long_t GetLong(Int_t npar)
get parameter as Long_t
virtual void Close(Option_t *="")
Close statement.
virtual Bool_t SetLong(Int_t npar, Long_t value)
set parameter as Long_t
virtual Long64_t GetLong64(Int_t npar)
get parameter as Long64_t
virtual Bool_t GetBinary(Int_t npar, void *&mem, Long_t &size)
return parameter as binary data
void * GetParAddr(Int_t npar, Int_t roottype=0, Int_t length=0)
Get parameter address.
virtual Bool_t SetUInt(Int_t npar, UInt_t value)
set parameter as UInt_t
virtual Int_t GetInt(Int_t npar)
get parameter as integer
Int_t fBufferPreferredSize
virtual Int_t GetNumFields()
return number of fields
virtual Bool_t SetLong64(Int_t npar, Long64_t value)
set parameter as Long64_t
virtual Bool_t SetULong64(Int_t npar, ULong64_t value)
set parameter as ULong64_t
SQLUSMALLINT * fStatusBuffer
virtual Int_t GetNumParameters()
return number of parameters
virtual const char * GetFieldName(Int_t nfield)
return field name
virtual Bool_t SetDatime(Int_t npar, Int_t year, Int_t month, Int_t day, Int_t hour, Int_t min, Int_t sec)
set parameter value as date & time
virtual Int_t GetNumAffectedRows()
get number of affected rows
virtual Double_t GetDouble(Int_t npar)
get parameter as Double_t
virtual Bool_t Process()
process statement
virtual Bool_t GetDate(Int_t npar, Int_t &year, Int_t &month, Int_t &day)
return field value as date
SQLUINTEGER fNumRowsFetched
Bool_t BindColumn(Int_t ncol, SQLSMALLINT sqltype, SQLUINTEGER size)
Bind result column to buffer. Allocate buffer of appropriate type.
virtual Bool_t NextResultRow()
next result row
virtual Bool_t SetTime(Int_t npar, Int_t hour, Int_t min, Int_t sec)
set parameter value as time
SQLUINTEGER fNumParsProcessed
virtual Bool_t SetNull(Int_t npar)
Set NULL as parameter value If NULL should be set for statement parameter during first iteration,...
virtual ULong64_t GetULong64(Int_t npar)
get parameter as ULong64_t
virtual Bool_t GetTimestamp(Int_t npar, Int_t &year, Int_t &month, Int_t &day, Int_t &hour, Int_t &min, Int_t &sec, Int_t &)
return field value as time stamp
Bool_t ExtractErrors(SQLRETURN retcode, const char *method)
Extract errors, produced by last ODBC function call.
Bool_t IsResultSet() const
ODBCBufferRec_t * fBuffer
virtual Bool_t SetString(Int_t npar, const char *value, Int_t maxsize=256)
set parameter as string
virtual Bool_t SetBinary(Int_t npar, void *mem, Long_t size, Long_t maxsize=0x1000)
set parameter value as binary data
virtual Bool_t IsNull(Int_t)
Verifies if field value is NULL.
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition: TObject.cxx:854
static const char * GetFloatFormat()
return current printf format for float/double members, default "%e"
Definition: TSQLServer.cxx:269
virtual Bool_t IsError() const
void SetError(Int_t code, const char *msg, const char *method=0)
set new values for error fields if method specified, displays error message
void ClearError()
reset error fields
TText * text
const Int_t n
Definition: legend1.C:16