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