| 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 | |