1//
2// Binder.cpp
3//
4// Library: Data/ODBC
5// Package: ODBC
6// Module: Binder
7//
8// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
9// and Contributors.
10//
11// SPDX-License-Identifier: BSL-1.0
12//
13
14
15#include "Poco/Data/ODBC/Binder.h"
16#include "Poco/Data/ODBC/Utility.h"
17#include "Poco/Data/LOB.h"
18#include "Poco/Data/ODBC/ODBCException.h"
19#include "Poco/DateTime.h"
20#include "Poco/Exception.h"
21#include <sql.h>
22
23
24namespace Poco {
25namespace Data {
26namespace ODBC {
27
28static void getProp(const TypeInfo& dataTypes, SQLSMALLINT sqlType, size_t& val)
29{
30 const std::string NM("COLUMN_SIZE");
31 Poco::DynamicAny r;
32 if (dataTypes.tryGetInfo(sqlType, NM, r))
33 {
34#ifndef POCO_LONG_IS_64_BIT
35 long sz = r.convert<long>();
36#else
37 Poco::Int64 sz = r.convert<Poco::Int64>();
38#endif
39 // Postgres driver returns SQL_NO_TOTAL(-4) in some cases
40 if (sz >= 0)
41 val = static_cast<size_t>(sz);
42 }
43}
44
45Binder::Binder(const StatementHandle& rStmt,
46 std::size_t maxFieldSize,
47 Binder::ParameterBinding dataBinding,
48 TypeInfo* pDataTypes,
49 bool insertOnly) :
50 _rStmt(rStmt),
51 _paramBinding(dataBinding),
52 _pTypeInfo(pDataTypes),
53 _paramSetSize(0),
54 _maxFieldSize(maxFieldSize),
55 _maxCharColLength(1024),
56 _maxWCharColLength(1024),
57 _maxVarBinColSize(1024),
58 _insertOnly(insertOnly)
59{
60 getProp(*_pTypeInfo, SQL_WVARCHAR, _maxWCharColLength);
61 getProp(*_pTypeInfo, SQL_VARCHAR, _maxCharColLength);
62 getProp(*_pTypeInfo, SQL_VARBINARY, _maxVarBinColSize);
63}
64
65
66Binder::~Binder()
67{
68 freeMemory();
69}
70
71
72void Binder::freeMemory()
73{
74 if (_lengthIndicator.size() > 0)
75 {
76 LengthPtrVec::iterator itLen = _lengthIndicator.begin();
77 LengthPtrVec::iterator itLenEnd = _lengthIndicator.end();
78 for (; itLen != itLenEnd; ++itLen) delete *itLen;
79 }
80
81 if (_vecLengthIndicator.size() > 0)
82 {
83 LengthVecVec::iterator itVecLen = _vecLengthIndicator.begin();
84 LengthVecVec::iterator itVecLenEnd = _vecLengthIndicator.end();
85 for (; itVecLen != itVecLenEnd; ++itVecLen) delete *itVecLen;
86 }
87
88 if (_times.size() > 0)
89 {
90 TimeMap::iterator itT = _times.begin();
91 TimeMap::iterator itTEnd = _times.end();
92 for (; itT != itTEnd; ++itT) delete itT->first;
93 }
94
95 if (_dates.size() > 0)
96 {
97 DateMap::iterator itD = _dates.begin();
98 DateMap::iterator itDEnd = _dates.end();
99 for (; itD != itDEnd; ++itD) delete itD->first;
100 }
101
102 if (_timestamps.size() > 0)
103 {
104 TimestampMap::iterator itTS = _timestamps.begin();
105 TimestampMap::iterator itTSEnd = _timestamps.end();
106 for (; itTS != itTSEnd; ++itTS) delete itTS->first;
107 }
108
109 if (_strings.size() > 0)
110 {
111 StringMap::iterator itStr = _strings.begin();
112 StringMap::iterator itStrEnd = _strings.end();
113 for (; itStr != itStrEnd; ++itStr) std::free(itStr->first);
114 }
115
116 if (_utf16Strings.size() > 0)
117 {
118 UTF16StringMap::iterator itStr = _utf16Strings.begin();
119 UTF16StringMap::iterator itStrEnd = _utf16Strings.end();
120 for (; itStr != itStrEnd; ++itStr) std::free(itStr->first);
121 }
122
123 if (_charPtrs.size() > 0)
124 {
125 CharPtrVec::iterator itChr = _charPtrs.begin();
126 CharPtrVec::iterator endChr = _charPtrs.end();
127 for (; itChr != endChr; ++itChr) std::free(*itChr);
128 }
129
130 if (_utf16CharPtrs.size() > 0)
131 {
132 UTF16CharPtrVec::iterator itUTF16Chr = _utf16CharPtrs.begin();
133 UTF16CharPtrVec::iterator endUTF16Chr = _utf16CharPtrs.end();
134 for (; itUTF16Chr != endUTF16Chr; ++itUTF16Chr) std::free(*itUTF16Chr);
135 }
136
137 if (_boolPtrs.size() > 0)
138 {
139 BoolPtrVec::iterator itBool = _boolPtrs.begin();
140 BoolPtrVec::iterator endBool = _boolPtrs.end();
141 for (; itBool != endBool; ++itBool) delete[] * itBool;
142 }
143
144 if (_dateVecVec.size() > 0)
145 {
146 DateVecVec::iterator itDateVec = _dateVecVec.begin();
147 DateVecVec::iterator itDateVecEnd = _dateVecVec.end();
148 for (; itDateVec != itDateVecEnd; ++itDateVec) delete *itDateVec;
149 }
150
151 if (_timeVecVec.size() > 0)
152 {
153 TimeVecVec::iterator itTimeVec = _timeVecVec.begin();
154 TimeVecVec::iterator itTimeVecEnd = _timeVecVec.end();
155 for (; itTimeVec != itTimeVecEnd; ++itTimeVec) delete *itTimeVec;
156 }
157
158 if (_dateTimeVecVec.size() > 0)
159 {
160 DateTimeVecVec::iterator itDateTimeVec = _dateTimeVecVec.begin();
161 DateTimeVecVec::iterator itDateTimeVecEnd = _dateTimeVecVec.end();
162 for (; itDateTimeVec != itDateTimeVecEnd; ++itDateTimeVec) delete *itDateTimeVec;
163 }
164
165 if (_containers.size() > 0)
166 {
167 AnyPtrVecVec::iterator itAnyVec = _containers.begin();
168 AnyPtrVecVec::iterator itAnyVecEnd = _containers.end();
169 for (; itAnyVec != itAnyVecEnd; ++itAnyVec)
170 {
171 AnyPtrVec::iterator b = itAnyVec->begin();
172 AnyPtrVec::iterator e = itAnyVec->end();
173 for (; b != e; ++b) delete *b;
174 }
175 }
176}
177
178
179void Binder::bind(std::size_t pos, const std::string& val, Direction dir, const WhenNullCb& nullCb)
180{
181 SQLPOINTER pVal = 0;
182 SQLINTEGER size = (SQLINTEGER) val.size();
183 SQLINTEGER colSize = 0;
184 SQLSMALLINT decDigits = 0;
185 getColSizeAndPrecision(pos, SQL_C_CHAR, colSize, decDigits, val.size());
186
187 if (isOutBound(dir))
188 {
189 getColumnOrParameterSize(pos, size);
190 char* pChar = (char*) std::calloc(size, sizeof(char));
191
192 if (isInOutBound(dir))
193 std::strcpy(pChar,val.c_str());
194
195 pVal = (SQLPOINTER) pChar;
196 _outParams.insert(ParamMap::value_type(pVal, size));
197 _strings.insert(StringMap::value_type(pChar, const_cast<std::string*>(&val)));
198 }
199 else if (isInBound(dir))
200 {
201 pVal = (SQLPOINTER) val.c_str();
202 _inParams.insert(ParamMap::value_type(pVal, size));
203 }
204 else
205 throw InvalidArgumentException("Parameter must be [in] OR [out] bound.");
206
207 SQLLEN* pLenIn = new SQLLEN;
208 if (isOutBound(dir) && nullCb.defined())
209 _nullCbMap.insert(NullCbMap::value_type( pLenIn, nullCb) );
210
211 *pLenIn = SQL_NTS;
212
213 if (PB_AT_EXEC == _paramBinding)
214 *pLenIn = SQL_LEN_DATA_AT_EXEC(size);
215
216 _lengthIndicator.push_back(pLenIn);
217
218 SQLSMALLINT sqType = (size <= _maxCharColLength) ? SQL_VARCHAR : SQL_LONGVARCHAR;
219
220 if (Utility::isError(SQLBindParameter(_rStmt,
221 (SQLUSMALLINT) pos + 1,
222 toODBCDirection(dir),
223 SQL_C_CHAR,
224 sqType,
225 (SQLUINTEGER) colSize,
226 0,
227 pVal,
228 (SQLINTEGER) size,
229 _lengthIndicator.back())))
230 {
231 throw StatementException(_rStmt, "SQLBindParameter(std::string)");
232 }
233}
234
235
236void Binder::bind(std::size_t pos, const UTF16String& val, Direction dir, const WhenNullCb& nullCb)
237{
238 typedef UTF16String::value_type CharT;
239
240 SQLPOINTER pVal = 0;
241 SQLINTEGER size = (SQLINTEGER)(val.size() * sizeof(CharT));
242 SQLINTEGER colSize = 0;
243 SQLSMALLINT decDigits = 0;
244 getColSizeAndPrecision(pos, SQL_C_WCHAR, colSize, decDigits, val.size() * sizeof(CharT));
245
246 if (isOutBound(dir))
247 {
248 getColumnOrParameterSize(pos, size);
249 CharT* pChar = (CharT*)std::calloc(size, sizeof(CharT));
250 pVal = (SQLPOINTER)pChar;
251 if (isInOutBound(dir))
252 std::copy(val.begin(), val.end(), pChar);
253 _outParams.insert(ParamMap::value_type(pVal, size));
254 _utf16Strings.insert(UTF16StringMap::value_type(pChar, const_cast<UTF16String*>(&val)));
255 }
256 else if (isInBound(dir))
257 {
258 pVal = (SQLPOINTER)val.c_str();
259 _inParams.insert(ParamMap::value_type(pVal, size));
260 }
261 else
262 throw InvalidArgumentException("Parameter must be [in] OR [out] bound.");
263
264 SQLLEN* pLenIn = new SQLLEN;
265 if (isOutBound(dir) && nullCb.defined())
266 _nullCbMap.insert(NullCbMap::value_type(pLenIn, nullCb));
267
268 *pLenIn = SQL_NTS;
269
270 if (PB_AT_EXEC == _paramBinding)
271 {
272 *pLenIn = SQL_LEN_DATA_AT_EXEC(size);
273 }
274
275 _lengthIndicator.push_back(pLenIn);
276
277 SQLSMALLINT sqType = (size <= _maxWCharColLength) ? SQL_WVARCHAR : SQL_WLONGVARCHAR;
278
279 if (Utility::isError(SQLBindParameter(_rStmt,
280 (SQLUSMALLINT)pos + 1,
281 toODBCDirection(dir),
282 SQL_C_WCHAR,
283 sqType,
284 (SQLUINTEGER)colSize,
285 0,
286 pVal,
287 (SQLINTEGER)size,
288 _lengthIndicator.back())))
289 {
290 throw StatementException(_rStmt, "SQLBindParameter(std::string)");
291 }
292}
293
294
295void Binder::bind(std::size_t pos, const Date& val, Direction dir, const WhenNullCb& nullCb)
296{
297 SQLLEN* pLenIn = new SQLLEN;
298 *pLenIn = SQL_NTS; // microsoft example does that, otherwise no null indicator is returned
299
300 _lengthIndicator.push_back(pLenIn);
301 if (isOutBound(dir) && nullCb.defined())
302 _nullCbMap.insert(NullCbMap::value_type(pLenIn, nullCb));
303 SQL_DATE_STRUCT* pDS = new SQL_DATE_STRUCT;
304 Utility::dateSync(*pDS, val);
305
306 _dates.insert(DateMap::value_type(pDS, const_cast<Date*>(&val)));
307
308 SQLINTEGER colSize = 0;
309 SQLSMALLINT decDigits = 0;
310 getColSizeAndPrecision(pos, SQL_TYPE_DATE, colSize, decDigits);
311
312 if (Utility::isError(SQLBindParameter(_rStmt,
313 (SQLUSMALLINT) pos + 1,
314 toODBCDirection(dir),
315 SQL_C_TYPE_DATE,
316 SQL_TYPE_DATE,
317 colSize,
318 decDigits,
319 (SQLPOINTER) pDS,
320 0,
321 _lengthIndicator.back())))
322 {
323 throw StatementException(_rStmt, "SQLBindParameter(Date)");
324 }
325}
326
327
328void Binder::bind(std::size_t pos, const Time& val, Direction dir, const WhenNullCb& nullCb)
329{
330 SQLLEN* pLenIn = new SQLLEN;
331 *pLenIn = SQL_NTS; // microsoft example does that, otherwise no null indicator is returned
332 if (isOutBound(dir) && nullCb.defined())
333 _nullCbMap.insert(NullCbMap::value_type(pLenIn, nullCb));
334
335 _lengthIndicator.push_back(pLenIn);
336
337 SQL_TIME_STRUCT* pTS = new SQL_TIME_STRUCT;
338 Utility::timeSync(*pTS, val);
339
340 _times.insert(TimeMap::value_type(pTS, const_cast<Time*>(&val)));
341
342 SQLINTEGER colSize = 0;
343 SQLSMALLINT decDigits = 0;
344 getColSizeAndPrecision(pos, SQL_TYPE_TIME, colSize, decDigits);
345
346 if (Utility::isError(SQLBindParameter(_rStmt,
347 (SQLUSMALLINT) pos + 1,
348 toODBCDirection(dir),
349 SQL_C_TYPE_TIME,
350 SQL_TYPE_TIME,
351 colSize,
352 decDigits,
353 (SQLPOINTER) pTS,
354 0,
355 _lengthIndicator.back())))
356 {
357 throw StatementException(_rStmt, "SQLBindParameter(Time)");
358 }
359}
360
361
362void Binder::bind(std::size_t pos, const Poco::DateTime& val, Direction dir, const WhenNullCb& nullCb)
363{
364 SQLLEN* pLenIn = new SQLLEN;
365 *pLenIn = SQL_NTS; // microsoft example does that, otherwise no null indicator is returned
366 if (isOutBound(dir) && nullCb.defined())
367 _nullCbMap.insert(NullCbMap::value_type(pLenIn, nullCb));
368
369 _lengthIndicator.push_back(pLenIn);
370
371 SQL_TIMESTAMP_STRUCT* pTS = new SQL_TIMESTAMP_STRUCT;
372 Utility::dateTimeSync(*pTS, val);
373
374 _timestamps.insert(TimestampMap::value_type(pTS, const_cast<DateTime*>(&val)));
375
376 SQLINTEGER colSize = 0;
377 SQLSMALLINT decDigits = 0;
378 getColSizeAndPrecision(pos, SQL_TYPE_TIMESTAMP, colSize, decDigits);
379
380 if (Utility::isError(SQLBindParameter(_rStmt,
381 (SQLUSMALLINT) pos + 1,
382 toODBCDirection(dir),
383 SQL_C_TYPE_TIMESTAMP,
384 SQL_TYPE_TIMESTAMP,
385 colSize,
386 decDigits,
387 (SQLPOINTER) pTS,
388 0,
389 _lengthIndicator.back())))
390 {
391 throw StatementException(_rStmt, "SQLBindParameter(DateTime)");
392 }
393}
394
395
396void Binder::bind(std::size_t pos, const NullData& val, Direction dir, const std::type_info& bindType)
397{
398 if (isOutBound(dir) || !isInBound(dir))
399 throw NotImplementedException("NULL parameter type can only be inbound.");
400
401 _inParams.insert(ParamMap::value_type(SQLPOINTER(0), SQLINTEGER(0)));
402
403 SQLLEN* pLenIn = new SQLLEN;
404 *pLenIn = SQL_NULL_DATA;
405
406 _lengthIndicator.push_back(pLenIn);
407
408 SQLINTEGER colSize = 0;
409 SQLSMALLINT decDigits = 0;
410
411 const SQLSMALLINT colType = (bindType == typeid(void) ||
412 bindType == typeid(NullData) ||
413 bindType == typeid(NullType)) ?
414 _pTypeInfo->nullDataType(val) :
415 _pTypeInfo->tryTypeidToCType(bindType, SQL_C_TINYINT);
416
417 getColSizeAndPrecision(pos, colType, colSize, decDigits);
418
419 if (Utility::isError(SQLBindParameter(_rStmt,
420 (SQLUSMALLINT) pos + 1,
421 SQL_PARAM_INPUT,
422 colType,
423 Utility::sqlDataType(colType),
424 colSize,
425 decDigits,
426 0,
427 0,
428 _lengthIndicator.back())))
429 {
430 throw StatementException(_rStmt, "SQLBindParameter()");
431 }
432}
433
434
435std::size_t Binder::parameterSize(SQLPOINTER pAddr) const
436{
437 ParamMap::const_iterator it = _inParams.find(pAddr);
438 if (it != _inParams.end()) return it->second;
439
440 it = _outParams.find(pAddr);
441 if (it != _outParams.end()) return it->second;
442
443 throw NotFoundException("Requested data size not found.");
444}
445
446
447void Binder::bind(std::size_t pos, const char* const &pVal, Direction dir, const WhenNullCb& nullCb)
448{
449 throw NotImplementedException("char* binding not implemented, Use std::string instead.");
450}
451
452
453SQLSMALLINT Binder::toODBCDirection(Direction dir) const
454{
455 bool in = isInBound(dir);
456 bool out = isOutBound(dir);
457 SQLSMALLINT ioType = SQL_PARAM_TYPE_UNKNOWN;
458 if (in && out) ioType = SQL_PARAM_INPUT_OUTPUT;
459 else if(in) ioType = SQL_PARAM_INPUT;
460 else if(out) ioType = SQL_PARAM_OUTPUT;
461 else throw Poco::IllegalStateException("Binder not bound (must be [in] OR [out]).");
462
463 return ioType;
464}
465
466
467void Binder::synchronize()
468{
469
470 if (_dates.size())
471 {
472 DateMap::iterator it = _dates.begin();
473 DateMap::iterator end = _dates.end();
474 for(; it != end; ++it)
475 Utility::dateSync(*it->second, *it->first);
476 }
477
478 if (_times.size())
479 {
480 TimeMap::iterator it = _times.begin();
481 TimeMap::iterator end = _times.end();
482 for(; it != end; ++it)
483 Utility::timeSync(*it->second, *it->first);
484 }
485
486 if (_timestamps.size())
487 {
488 TimestampMap::iterator it = _timestamps.begin();
489 TimestampMap::iterator end = _timestamps.end();
490 for(; it != end; ++it)
491 Utility::dateTimeSync(*it->second, *it->first);
492 }
493
494 if (_strings.size())
495 {
496 StringMap::iterator it = _strings.begin();
497 StringMap::iterator end = _strings.end();
498 for(; it != end; ++it)
499 it->second->assign(it->first, std::strlen(it->first));
500 }
501
502 if (_utf16Strings.size())
503 {
504 UTF16StringMap::iterator it = _utf16Strings.begin();
505 UTF16StringMap::iterator end = _utf16Strings.end();
506 for (; it != end; ++it)
507 it->second->assign(it->first, UTF16CharTraits::length((UTF16CharTraits::char_type*)it->first));
508 }
509
510 if (_nullCbMap.size())
511 {
512 NullCbMap::iterator it = _nullCbMap.begin();
513 NullCbMap::iterator end = _nullCbMap.end();
514 for (; it != end; ++it)
515 if (*it->first == SQL_NULL_DATA) it->second.onNull();
516 }
517}
518
519
520void Binder::reset()
521{
522 freeMemory();
523
524 if (_lengthIndicator.size() > 0)
525 LengthPtrVec().swap(_lengthIndicator);
526 if (_inParams.size() > 0)
527 _inParams.clear();
528 if (_outParams.size() > 0)
529 _outParams.clear();
530 if (_dates.size() > 0)
531 _dates.clear();
532 if (_times.size() > 0)
533 _times.clear();
534 if (_timestamps.size() > 0)
535 _timestamps.clear();
536 if (_strings.size() > 0)
537 _strings.clear();
538 if (_utf16Strings.size() > 0)
539 _utf16Strings.clear();
540 if (_dateVecVec.size() > 0)
541 _dateVecVec.clear();
542 if (_timeVecVec.size() > 0)
543 _timeVecVec.clear();
544 if (_dateTimeVecVec.size() > 0)
545 _dateTimeVecVec.clear();
546 if (_charPtrs.size() > 0)
547 _charPtrs.clear();
548 if (_boolPtrs.size() > 0)
549 _boolPtrs.clear();
550 if (_containers.size() > 0)
551 _containers.clear();
552 if (_nullCbMap.size() > 0)
553 _nullCbMap.clear();
554 _paramSetSize = 0;
555 if (!_insertOnly)
556 _parameters.clear();
557}
558
559
560void Binder::getColSizeAndPrecision(std::size_t pos,
561 SQLSMALLINT cDataType,
562 SQLINTEGER& colSize,
563 SQLSMALLINT& decDigits,
564 std::size_t actualSize)
565{
566 colSize = 0;
567 decDigits = 0;
568 // Not all drivers are equally willing to cooperate in this matter.
569 // Hence the funky flow control.
570
571 if (_pTypeInfo)
572 {
573 DynamicAny tmp;
574 bool found = _pTypeInfo->tryGetInfo(cDataType, "COLUMN_SIZE", tmp);
575 if (found) colSize = tmp;
576 if (colSize && actualSize > colSize)
577 {
578 throw LengthExceededException(Poco::format("Error binding column %z size=%z, max size=%ld)",
579 pos, actualSize, static_cast<long>(colSize)));
580 }
581 found = _pTypeInfo->tryGetInfo(cDataType, "MINIMUM_SCALE", tmp);
582 if (found)
583 {
584 decDigits = tmp;
585 return;
586 }
587 }
588
589 if (_parameters.size() <= pos || !_parameters[pos].defined())
590 {
591 if (_parameters.size() <= pos)
592 _parameters.resize(pos + 1);
593 _parameters[pos] = ParamDescriptor(0, cDataType, 0);
594
595 try
596 {
597 {
598 Parameter p(_rStmt, pos);
599 _parameters[pos] = ParamDescriptor(static_cast<SQLINTEGER>(p.columnSize()), cDataType, static_cast<SQLSMALLINT>(p.decimalDigits()));
600 }
601 }
602 catch (StatementException&)
603 {
604 try
605 {
606 ODBCMetaColumn c(_rStmt, pos);
607 _parameters[pos] = ParamDescriptor(static_cast<SQLINTEGER>(c.length()), cDataType, static_cast<SQLSMALLINT>(c.precision()));
608 }
609 catch (StatementException&) {}
610 }
611 }
612
613 // we may have no success, so use zeros and hope for the best
614 // (most drivers do not require these most of the times anyway)
615 if (0 == colSize)
616 {
617 colSize = _parameters[pos].colSize;
618 if (actualSize > colSize)
619 {
620 throw LengthExceededException(Poco::format("Error binding column %z size=%z, max size=%ld)",
621 pos, actualSize, static_cast<long>(colSize)));
622 }
623 }
624 decDigits = _parameters[pos].decDigits;
625}
626
627
628void Binder::getColumnOrParameterSize(std::size_t pos, SQLINTEGER& size)
629{
630 std::size_t colSize = 0;
631 std::size_t paramSize = 0;
632
633 try
634 {
635 ODBCMetaColumn col(_rStmt, pos);
636 colSize = col.length();
637 }
638 catch (StatementException&) { }
639
640 try
641 {
642 Parameter p(_rStmt, pos);
643 paramSize = p.columnSize();
644 }
645 catch (StatementException&)
646 {
647 size = DEFAULT_PARAM_SIZE;
648//On Linux, PostgreSQL driver segfaults on SQLGetDescField, so this is disabled for now
649#ifdef POCO_OS_FAMILY_WINDOWS
650 SQLHDESC hIPD = 0;
651 if (!Utility::isError(Poco::Data::ODBC::SQLGetStmtAttr(_rStmt, SQL_ATTR_IMP_PARAM_DESC, &hIPD, SQL_IS_POINTER, 0)))
652 {
653 SQLUINTEGER sz = 0;
654 if (!Utility::isError(Poco::Data::ODBC::SQLGetDescField(hIPD, (SQLSMALLINT)pos + 1, SQL_DESC_LENGTH, &sz, SQL_IS_UINTEGER, 0)) &&
655 sz > 0)
656 {
657 size = sz;
658 }
659 }
660#endif
661 }
662
663 if (colSize > 0 && paramSize > 0)
664 size = colSize < paramSize ? static_cast<SQLINTEGER>(colSize) : static_cast<SQLINTEGER>(paramSize);
665 else if (colSize > 0)
666 size = static_cast<SQLINTEGER>(colSize);
667 else if (paramSize > 0)
668 size = static_cast<SQLINTEGER>(paramSize);
669
670 if (size > _maxFieldSize) size = static_cast<SQLINTEGER>(_maxFieldSize);
671}
672
673
674void Binder::setParamSetSize(std::size_t length)
675{
676 if (0 == _paramSetSize)
677 {
678 if (Utility::isError(Poco::Data::ODBC::SQLSetStmtAttr(_rStmt, SQL_ATTR_PARAM_BIND_TYPE, SQL_PARAM_BIND_BY_COLUMN, SQL_IS_UINTEGER)) ||
679 Utility::isError(Poco::Data::ODBC::SQLSetStmtAttr(_rStmt, SQL_ATTR_PARAMSET_SIZE, (SQLPOINTER) length, SQL_IS_UINTEGER)))
680 throw StatementException(_rStmt, "SQLSetStmtAttr()");
681
682 _paramSetSize = static_cast<SQLINTEGER>(length);
683 }
684}
685
686
687} } } // namespace Poco::Data::ODBC
688