1 //
2 // Preparator.cpp
3 //
4 // Library: Data/ODBC
5 // Package: ODBC
6 // Module: Preparator
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/Preparator.h"
16 #include "Poco/Data/ODBC/ODBCMetaColumn.h"
17 #include "Poco/Exception.h"
18
19
20 using Poco::InvalidArgumentException;
21
22
23 namespace Poco {
24 namespace Data {
25 namespace ODBC {
26
27
Preparator(const StatementHandle & rStmt,const std::string & statement,std::size_t maxFieldSize,DataExtraction dataExtraction)28 Preparator::Preparator(const StatementHandle& rStmt,
29 const std::string& statement,
30 std::size_t maxFieldSize,
31 DataExtraction dataExtraction):
32 _rStmt(rStmt),
33 _maxFieldSize(maxFieldSize),
34 _dataExtraction(dataExtraction)
35 {
36 SQLCHAR* pStr = (SQLCHAR*) statement.c_str();
37 if (Utility::isError(Poco::Data::ODBC::SQLPrepare(_rStmt, pStr, (SQLINTEGER) statement.length())))
38 throw StatementException(_rStmt);
39 }
40
41
Preparator(const Preparator & other)42 Preparator::Preparator(const Preparator& other):
43 _rStmt(other._rStmt),
44 _maxFieldSize(other._maxFieldSize),
45 _dataExtraction(other._dataExtraction)
46 {
47 resize();
48 }
49
50
~Preparator()51 Preparator::~Preparator()
52 {
53 try
54 {
55 freeMemory();
56 }
57 catch (...)
58 {
59 poco_unexpected();
60 }
61 }
62
63
freeMemory() const64 void Preparator::freeMemory() const
65 {
66 IndexMap::iterator it = _varLengthArrays.begin();
67 IndexMap::iterator end = _varLengthArrays.end();
68 for (; it != end; ++it)
69 {
70 switch (it->second)
71 {
72 case DT_BOOL:
73 deleteCachedArray<bool>(it->first);
74 break;
75
76 case DT_CHAR:
77 deleteCachedArray<char>(it->first);
78 break;
79
80 case DT_WCHAR:
81 deleteCachedArray<UTF16String::value_type>(it->first);
82 break;
83
84 case DT_UCHAR:
85 deleteCachedArray<unsigned char>(it->first);
86 break;
87
88 case DT_CHAR_ARRAY:
89 {
90 char** pc = AnyCast<char*>(&_values[it->first]);
91 if (pc) std::free(*pc);
92 break;
93 }
94
95 case DT_WCHAR_ARRAY:
96 {
97 UTF16String::value_type** pc = AnyCast<UTF16String::value_type*>(&_values[it->first]);
98 if (pc) std::free(*pc);
99 break;
100 }
101
102 case DT_UCHAR_ARRAY:
103 {
104 unsigned char** pc = AnyCast<unsigned char*>(&_values[it->first]);
105 if (pc) std::free(*pc);
106 break;
107 }
108
109 case DT_BOOL_ARRAY:
110 {
111 bool** pb = AnyCast<bool*>(&_values[it->first]);
112 if (pb) std::free(*pb);
113 break;
114 }
115
116 default:
117 throw InvalidArgumentException("Unknown data type.");
118 }
119 }
120 }
121
122
columns() const123 std::size_t Preparator::columns() const
124 {
125 if (_values.empty()) resize();
126 return _values.size();
127 }
128
129
resize() const130 void Preparator::resize() const
131 {
132 SQLSMALLINT nCol = 0;
133 if (!Utility::isError(SQLNumResultCols(_rStmt, &nCol)) && 0 != nCol)
134 {
135 _values.resize(nCol, 0);
136 _lengths.resize(nCol, 0);
137 _lenLengths.resize(nCol);
138 if(_varLengthArrays.size())
139 {
140 freeMemory();
141 _varLengthArrays.clear();
142 }
143 }
144 }
145
146
maxDataSize(std::size_t pos) const147 std::size_t Preparator::maxDataSize(std::size_t pos) const
148 {
149 poco_assert_dbg (pos < _values.size());
150
151 std::size_t sz = 0;
152 std::size_t maxsz = getMaxFieldSize();
153
154 try
155 {
156 ODBCMetaColumn mc(_rStmt, pos);
157 sz = mc.length();
158
159 // accomodate for terminating zero (non-bulk only!)
160 MetaColumn::ColumnDataType type = mc.type();
161 if (!isBulk() && ((ODBCMetaColumn::FDT_WSTRING == type) || (ODBCMetaColumn::FDT_STRING == type))) ++sz;
162 }
163 catch (StatementException&) { }
164
165 if (!sz || sz > maxsz) sz = maxsz;
166
167 return sz;
168 }
169
170
actualDataSize(std::size_t col,std::size_t row) const171 std::size_t Preparator::actualDataSize(std::size_t col, std::size_t row) const
172 {
173 SQLLEN size = (POCO_DATA_INVALID_ROW == row) ? _lengths.at(col) :
174 _lenLengths.at(col).at(row);
175
176 // workaround for drivers returning negative length
177 if (size < 0 && SQL_NULL_DATA != size) size *= -1;
178
179 return size;
180 }
181
182
prepareBoolArray(std::size_t pos,SQLSMALLINT valueType,std::size_t length)183 void Preparator::prepareBoolArray(std::size_t pos, SQLSMALLINT valueType, std::size_t length)
184 {
185 poco_assert_dbg (DE_BOUND == _dataExtraction);
186 poco_assert_dbg (pos < _values.size());
187 poco_assert_dbg (pos < _lengths.size());
188 poco_assert_dbg (pos < _lenLengths.size());
189
190 bool* pArray = (bool*) std::calloc(length, sizeof(bool));
191
192 _values[pos] = Any(pArray);
193 _lengths[pos] = 0;
194 _lenLengths[pos].resize(length);
195 _varLengthArrays.insert(IndexMap::value_type(pos, DT_BOOL_ARRAY));
196
197 if (Utility::isError(SQLBindCol(_rStmt,
198 (SQLUSMALLINT) pos + 1,
199 valueType,
200 (SQLPOINTER) pArray,
201 (SQLINTEGER) sizeof(bool),
202 &_lenLengths[pos][0])))
203 {
204 throw StatementException(_rStmt, "SQLBindCol()");
205 }
206 }
207
208
209 } } } // namespace Poco::Data::ODBC
210