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 | |
22 | namespace Poco { |
23 | namespace Data { |
24 | namespace ODBC { |
25 | |
26 | |
27 | TypeInfo::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 | |
46 | TypeInfo::~TypeInfo() |
47 | { |
48 | } |
49 | |
50 | |
51 | void 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 | |
75 | void 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 | |
99 | void 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 | |
181 | DynamicAny 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 | |
195 | bool 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 | |
212 | int 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 | |
223 | int 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 | |
234 | void 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 | |
277 | SQLSMALLINT 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 | |
286 | SQLSMALLINT 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 | |