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