1//
2// TypeInfo.cpp
3//
4// Library: Data/ODBC
5// Package: ODBC
6// Module: TypeInfo
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/TypeInfo.h"
16#include "Poco/Data/ODBC/ODBCException.h"
17#include "Poco/Data/LOB.h"
18#include "Poco/Format.h"
19#include "Poco/Exception.h"
20#include <iostream>
21
22namespace Poco {
23namespace Data {
24namespace ODBC {
25
26
27TypeInfo::TypeInfo(SQLHDBC* pHDBC): _pHDBC(pHDBC)
28{
29 fillCTypes();
30 fillSQLTypes();
31 if (_pHDBC) fillTypeInfo(*_pHDBC);
32
33 _cppDataTypes.insert(CppTypeInfoMap::value_type(&typeid(std::string), SQL_C_CHAR));
34 _cppDataTypes.insert(CppTypeInfoMap::value_type(&typeid(std::wstring), SQL_C_WCHAR));
35 _cppDataTypes.insert(CppTypeInfoMap::value_type(&typeid(Poco::UTF16String), SQL_C_WCHAR));
36 _cppDataTypes.insert(CppTypeInfoMap::value_type(&typeid(Date), SQL_TYPE_DATE));
37 _cppDataTypes.insert(CppTypeInfoMap::value_type(&typeid(Time), SQL_TYPE_TIME));
38 _cppDataTypes.insert(CppTypeInfoMap::value_type(&typeid(DateTime), SQL_TYPE_TIMESTAMP));
39 _cppDataTypes.insert(CppTypeInfoMap::value_type(&typeid(BLOB), SQL_BINARY));
40 _cppDataTypes.insert(CppTypeInfoMap::value_type(&typeid(float), SQL_REAL));
41 _cppDataTypes.insert(CppTypeInfoMap::value_type(&typeid(double), SQL_DOUBLE));
42 _cppDataTypes.insert(CppTypeInfoMap::value_type(&typeid(bool), SQL_BIT));
43}
44
45
46TypeInfo::~TypeInfo()
47{
48}
49
50
51void TypeInfo::fillCTypes()
52{
53 _cDataTypes.insert(ValueType(SQL_CHAR, SQL_C_CHAR));
54 _cDataTypes.insert(ValueType(SQL_VARCHAR, SQL_C_CHAR));
55 _cDataTypes.insert(ValueType(SQL_LONGVARCHAR, SQL_C_CHAR));
56 _cDataTypes.insert(ValueType(SQL_DECIMAL, SQL_C_DOUBLE));
57 _cDataTypes.insert(ValueType(SQL_NUMERIC, SQL_C_DOUBLE));
58 _cDataTypes.insert(ValueType(SQL_BIT, SQL_C_BIT));
59 _cDataTypes.insert(ValueType(SQL_TINYINT, SQL_C_STINYINT));
60 _cDataTypes.insert(ValueType(SQL_SMALLINT, SQL_C_SSHORT));
61 _cDataTypes.insert(ValueType(SQL_INTEGER, SQL_C_SLONG));
62 _cDataTypes.insert(ValueType(SQL_BIGINT, SQL_C_SBIGINT));
63 _cDataTypes.insert(ValueType(SQL_REAL, SQL_C_FLOAT));
64 _cDataTypes.insert(ValueType(SQL_FLOAT, SQL_C_DOUBLE));
65 _cDataTypes.insert(ValueType(SQL_DOUBLE, SQL_C_DOUBLE));
66 _cDataTypes.insert(ValueType(SQL_BINARY, SQL_C_BINARY));
67 _cDataTypes.insert(ValueType(SQL_VARBINARY, SQL_C_BINARY));
68 _cDataTypes.insert(ValueType(SQL_LONGVARBINARY, SQL_C_BINARY));
69 _cDataTypes.insert(ValueType(SQL_TYPE_DATE, SQL_C_TYPE_DATE));
70 _cDataTypes.insert(ValueType(SQL_TYPE_TIME, SQL_C_TYPE_TIME));
71 _cDataTypes.insert(ValueType(SQL_TYPE_TIMESTAMP, SQL_C_TYPE_TIMESTAMP));
72}
73
74
75void TypeInfo::fillSQLTypes()
76{
77 _sqlDataTypes.insert(ValueType(SQL_C_CHAR, SQL_LONGVARCHAR));
78 _sqlDataTypes.insert(ValueType(SQL_C_BIT, SQL_BIT));
79 _sqlDataTypes.insert(ValueType(SQL_C_TINYINT, SQL_TINYINT));
80 _sqlDataTypes.insert(ValueType(SQL_C_STINYINT, SQL_TINYINT));
81 _sqlDataTypes.insert(ValueType(SQL_C_UTINYINT, SQL_TINYINT));
82 _sqlDataTypes.insert(ValueType(SQL_C_SHORT, SQL_SMALLINT));
83 _sqlDataTypes.insert(ValueType(SQL_C_SSHORT, SQL_SMALLINT));
84 _sqlDataTypes.insert(ValueType(SQL_C_USHORT, SQL_SMALLINT));
85 _sqlDataTypes.insert(ValueType(SQL_C_LONG, SQL_INTEGER));
86 _sqlDataTypes.insert(ValueType(SQL_C_SLONG, SQL_INTEGER));
87 _sqlDataTypes.insert(ValueType(SQL_C_ULONG, SQL_INTEGER));
88 _sqlDataTypes.insert(ValueType(SQL_C_SBIGINT, SQL_BIGINT));
89 _sqlDataTypes.insert(ValueType(SQL_C_UBIGINT, SQL_BIGINT));
90 _sqlDataTypes.insert(ValueType(SQL_C_FLOAT, SQL_REAL));
91 _sqlDataTypes.insert(ValueType(SQL_C_DOUBLE, SQL_DOUBLE));
92 _sqlDataTypes.insert(ValueType(SQL_C_BINARY, SQL_LONGVARBINARY));
93 _sqlDataTypes.insert(ValueType(SQL_C_TYPE_DATE, SQL_TYPE_DATE));
94 _sqlDataTypes.insert(ValueType(SQL_C_TYPE_TIME, SQL_TYPE_TIME));
95 _sqlDataTypes.insert(ValueType(SQL_C_TYPE_TIMESTAMP, SQL_TYPE_TIMESTAMP));
96}
97
98
99void TypeInfo::fillTypeInfo(SQLHDBC pHDBC)
100{
101 _pHDBC = &pHDBC;
102
103 if (_typeInfo.empty() && _pHDBC)
104 {
105 const static int stringSize = 512;
106 TypeInfoVec().swap(_typeInfo);
107
108 SQLRETURN rc;
109 SQLHSTMT hstmt = SQL_NULL_HSTMT;
110
111 rc = SQLAllocHandle(SQL_HANDLE_STMT, *_pHDBC, &hstmt);
112 if (!SQL_SUCCEEDED(rc))
113 throw StatementException(hstmt, "SQLGetData()");
114
115 rc = Poco::Data::ODBC::SQLGetTypeInfo(hstmt, SQL_ALL_TYPES);
116 if (SQL_SUCCEEDED(rc))
117 {
118 while (SQLFetch(hstmt) != SQL_NO_DATA_FOUND)
119 {
120 char typeName[stringSize] = { 0 };
121 char literalPrefix[stringSize] = { 0 };
122 char literalSuffix[stringSize] = { 0 };
123 char createParams[stringSize] = { 0 };
124 char localTypeName[stringSize] = { 0 };
125
126 TypeInfoTup ti("TYPE_NAME", "",
127 "DATA_TYPE", 0,
128 "COLUMN_SIZE", 0,
129 "LITERAL_PREFIX", "",
130 "LITERAL_SUFFIX", "",
131 "CREATE_PARAMS", "",
132 "NULLABLE", 0,
133 "CASE_SENSITIVE", 0,
134 "SEARCHABLE", 0,
135 "UNSIGNED_ATTRIBUTE", 0,
136 "FIXED_PREC_SCALE", 0,
137 "AUTO_UNIQUE_VALUE", 0,
138 "LOCAL_TYPE_NAME", "",
139 "MINIMUM_SCALE", 0,
140 "MAXIMUM_SCALE", 0,
141 "SQL_DATA_TYPE", 0,
142 "SQL_DATETIME_SUB", 0,
143 "NUM_PREC_RADIX", 0,
144 "INTERVAL_PRECISION", 0);
145
146 SQLLEN ind = 0;
147 rc = SQLGetData(hstmt, 1, SQL_C_CHAR, typeName, sizeof(typeName), &ind);
148 ti.set<0>(typeName);
149 rc = SQLGetData(hstmt, 2, SQL_C_SSHORT, &ti.get<1>(), sizeof(SQLSMALLINT), &ind);
150 rc = SQLGetData(hstmt, 3, SQL_C_SLONG, &ti.get<2>(), sizeof(SQLINTEGER), &ind);
151 rc = SQLGetData(hstmt, 4, SQL_C_CHAR, literalPrefix, sizeof(literalPrefix), &ind);
152 ti.set<3>(literalPrefix);
153 rc = SQLGetData(hstmt, 5, SQL_C_CHAR, literalSuffix, sizeof(literalSuffix), &ind);
154 ti.set<4>(literalSuffix);
155 rc = SQLGetData(hstmt, 6, SQL_C_CHAR, createParams, sizeof(createParams), &ind);
156 ti.set<5>(createParams);
157 rc = SQLGetData(hstmt, 7, SQL_C_SSHORT, &ti.get<6>(), sizeof(SQLSMALLINT), &ind);
158 rc = SQLGetData(hstmt, 8, SQL_C_SSHORT, &ti.get<7>(), sizeof(SQLSMALLINT), &ind);
159 rc = SQLGetData(hstmt, 9, SQL_C_SSHORT, &ti.get<8>(), sizeof(SQLSMALLINT), &ind);
160 rc = SQLGetData(hstmt, 10, SQL_C_SSHORT, &ti.get<9>(), sizeof(SQLSMALLINT), &ind);
161 rc = SQLGetData(hstmt, 11, SQL_C_SSHORT, &ti.get<10>(), sizeof(SQLSMALLINT), &ind);
162 rc = SQLGetData(hstmt, 12, SQL_C_SSHORT, &ti.get<11>(), sizeof(SQLSMALLINT), &ind);
163 rc = SQLGetData(hstmt, 13, SQL_C_CHAR, localTypeName, sizeof(localTypeName), &ind);
164 ti.set<12>(localTypeName);
165 rc = SQLGetData(hstmt, 14, SQL_C_SSHORT, &ti.get<13>(), sizeof(SQLSMALLINT), &ind);
166 rc = SQLGetData(hstmt, 15, SQL_C_SSHORT, &ti.get<14>(), sizeof(SQLSMALLINT), &ind);
167 rc = SQLGetData(hstmt, 16, SQL_C_SSHORT, &ti.get<15>(), sizeof(SQLSMALLINT), &ind);
168 rc = SQLGetData(hstmt, 17, SQL_C_SSHORT, &ti.get<16>(), sizeof(SQLSMALLINT), &ind);
169 rc = SQLGetData(hstmt, 18, SQL_C_SLONG, &ti.get<17>(), sizeof(SQLINTEGER), &ind);
170 rc = SQLGetData(hstmt, 19, SQL_C_SSHORT, &ti.get<18>(), sizeof(SQLSMALLINT), &ind);
171
172 _typeInfo.push_back(ti);
173 }
174 }
175
176 SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
177 }
178}
179
180
181DynamicAny TypeInfo::getInfo(SQLSMALLINT type, const std::string& param) const
182{
183 TypeInfoVec::const_iterator it = _typeInfo.begin();
184 TypeInfoVec::const_iterator end = _typeInfo.end();
185 for (; it != end; ++it)
186 {
187 if (type == it->get<1>())
188 return (*it)[param];
189 }
190
191 throw NotFoundException(param);
192}
193
194
195bool TypeInfo::tryGetInfo(SQLSMALLINT type, const std::string& param, DynamicAny& result) const
196{
197 TypeInfoVec::const_iterator it = _typeInfo.begin();
198 TypeInfoVec::const_iterator end = _typeInfo.end();
199 for (; it != end; ++it)
200 {
201 if (type == it->get<1>())
202 {
203 result = (*it)[param];
204 return true;
205 }
206 }
207
208 return false;
209}
210
211
212int TypeInfo::cDataType(int sqlDataType) const
213{
214 DataTypeMap::const_iterator it = _cDataTypes.find(sqlDataType);
215
216 if (_cDataTypes.end() == it)
217 throw NotFoundException(format("C data type not found for SQL data type: %d", sqlDataType));
218
219 return it->second;
220}
221
222
223int TypeInfo::sqlDataType(int cDataType) const
224{
225 DataTypeMap::const_iterator it = _sqlDataTypes.find(cDataType);
226
227 if (_sqlDataTypes.end() == it)
228 throw NotFoundException(format("SQL data type not found for C data type: %d", cDataType));
229
230 return it->second;
231}
232
233
234void TypeInfo::print(std::ostream& ostr)
235{
236 if (_typeInfo.empty())
237 {
238 ostr << "No data found.";
239 return;
240 }
241
242 TypeInfoTup::NameVec::const_iterator nIt = (*_typeInfo[0].names()).begin();
243 TypeInfoTup::NameVec::const_iterator nItEnd = (*_typeInfo[0].names()).end();
244 for (; nIt != nItEnd; ++nIt)
245 ostr << *nIt << "\t";
246
247 ostr << std::endl;
248
249 TypeInfoVec::const_iterator it = _typeInfo.begin();
250 TypeInfoVec::const_iterator end = _typeInfo.end();
251
252 for (; it != end; ++it)
253 {
254 ostr << it->get<0>() << "\t"
255 << it->get<1>() << "\t"
256 << it->get<2>() << "\t"
257 << it->get<3>() << "\t"
258 << it->get<4>() << "\t"
259 << it->get<5>() << "\t"
260 << it->get<6>() << "\t"
261 << it->get<7>() << "\t"
262 << it->get<8>() << "\t"
263 << it->get<9>() << "\t"
264 << it->get<10>() << "\t"
265 << it->get<11>() << "\t"
266 << it->get<12>() << "\t"
267 << it->get<13>() << "\t"
268 << it->get<14>() << "\t"
269 << it->get<15>() << "\t"
270 << it->get<16>() << "\t"
271 << it->get<17>() << "\t"
272 << it->get<18>() << std::endl;
273 }
274}
275
276
277SQLSMALLINT TypeInfo::tryTypeidToCType(const std::type_info& ti, SQLSMALLINT defaultVal) const
278{
279 CppTypeInfoMap::const_iterator res = _cppDataTypes.find(&ti);
280 if (res == _cppDataTypes.end())
281 return defaultVal;
282 return res->second;
283}
284
285
286SQLSMALLINT TypeInfo::nullDataType(const NullData val) const
287{
288 switch (val)
289 {
290 case NULL_GENERIC:
291 case DATA_NULL_INTEGER:
292 return SQL_C_TINYINT;
293
294 case DATA_NULL_STRING:
295 return SQL_C_CHAR;
296
297 case DATA_NULL_DATE:
298 return SQL_C_TYPE_DATE;
299
300 case DATA_NULL_TIME:
301 return SQL_C_TYPE_TIME;
302
303 case DATA_NULL_DATETIME:
304 return SQL_C_TYPE_TIMESTAMP;
305
306 case DATA_NULL_BLOB:
307 return SQL_C_BINARY;
308
309 case DATA_NULL_FLOAT:
310 return SQL_C_FLOAT;
311 }
312
313 return SQL_C_TINYINT;
314}
315
316} } } // namespace Poco::Data::ODBC
317