1 //
2 // ODBCMetaColumn.cpp
3 //
4 // Library: Data/ODBC
5 // Package: ODBC
6 // Module:  ODBCMetaColumn
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/ODBCMetaColumn.h"
16 #include "Poco/Data/ODBC/Utility.h"
17 
18 
19 namespace Poco {
20 namespace Data {
21 namespace ODBC {
22 
23 
ODBCMetaColumn(const StatementHandle & rStmt,std::size_t position)24 ODBCMetaColumn::ODBCMetaColumn(const StatementHandle& rStmt, std::size_t position) :
25 	MetaColumn(position),
26 	_rStmt(rStmt)
27 {
28 	init();
29 }
30 
31 
~ODBCMetaColumn()32 ODBCMetaColumn::~ODBCMetaColumn()
33 {
34 }
35 
36 
getDescription()37 void ODBCMetaColumn::getDescription()
38 {
39 	std::memset(_columnDesc.name, 0, NAME_BUFFER_LENGTH);
40 	_columnDesc.nameBufferLength = 0;
41 	_columnDesc.dataType = 0;
42 	_columnDesc.size = 0;
43 	_columnDesc.decimalDigits = 0;
44 	_columnDesc.isNullable = 0;
45 
46 	if (Utility::isError(Poco::Data::ODBC::SQLDescribeCol(_rStmt,
47 		(SQLUSMALLINT) position() + 1, // ODBC columns are 1-based
48 		_columnDesc.name,
49 		NAME_BUFFER_LENGTH,
50 		&_columnDesc.nameBufferLength,
51 		&_columnDesc.dataType,
52 		&_columnDesc.size,
53 		&_columnDesc.decimalDigits,
54 		&_columnDesc.isNullable)))
55 	{
56 		throw StatementException(_rStmt);
57 	}
58 }
59 
60 
isUnsigned() const61 bool ODBCMetaColumn::isUnsigned() const
62 {
63 	SQLLEN val = 0;
64 	if (Utility::isError(Poco::Data::ODBC::SQLColAttribute(_rStmt,
65 		(SQLUSMALLINT)position() + 1, // ODBC columns are 1-based
66 		SQL_DESC_UNSIGNED,
67 		0,
68 		0,
69 		0,
70 		&val)))
71 	{
72 		throw StatementException(_rStmt);
73 	}
74 	return (val == SQL_TRUE);
75 }
76 
77 
init()78 void ODBCMetaColumn::init()
79 {
80 	getDescription();
81 
82 	if (Utility::isError(Poco::Data::ODBC::SQLColAttribute(_rStmt,
83 			(SQLUSMALLINT) position() + 1, // ODBC columns are 1-based
84 			SQL_DESC_LENGTH,
85 			0,
86 			0,
87 			0,
88 			&_dataLength)))
89 	{
90 		throw StatementException(_rStmt);
91 	}
92 
93 	setName(std::string((char*) _columnDesc.name));
94 	setLength(_columnDesc.size);
95 	setPrecision(_columnDesc.decimalDigits);
96 	setNullable(SQL_NULLABLE == _columnDesc.isNullable);
97 	switch(_columnDesc.dataType)
98 	{
99 	case SQL_BIT:
100 		setType(MetaColumn::FDT_BOOL); break;
101 
102 	case SQL_CHAR:
103 	case SQL_VARCHAR:
104 	case SQL_LONGVARCHAR:
105 #ifdef SQL_GUID
106 	case SQL_GUID:
107 #endif
108 		setType(MetaColumn::FDT_STRING); break;
109 
110 	case SQL_WCHAR:
111 	case SQL_WVARCHAR:
112 	case SQL_WLONGVARCHAR:
113 		setType(MetaColumn::FDT_WSTRING); break;
114 
115 	case SQL_TINYINT:
116 		setType(isUnsigned() ? MetaColumn::FDT_UINT8 : MetaColumn::FDT_INT8);
117 		break;
118 
119 	case SQL_SMALLINT:
120 		setType(isUnsigned() ? MetaColumn::FDT_UINT16 : MetaColumn::FDT_INT16);
121 		break;
122 
123 	case SQL_INTEGER:
124 		setType(isUnsigned() ? MetaColumn::FDT_UINT32 : MetaColumn::FDT_INT32);
125 		break;
126 
127 	case SQL_BIGINT:
128 		setType(isUnsigned() ? MetaColumn::FDT_UINT64 : MetaColumn::FDT_INT64);
129 		break;
130 
131 	case SQL_DOUBLE:
132 	case SQL_FLOAT:
133 		setType(MetaColumn::FDT_DOUBLE); break;
134 
135 	case SQL_NUMERIC:
136 	case SQL_DECIMAL:
137 		// Oracle has no INTEGER type - it's essentially NUMBER with 38 whole and
138 		// 0 fractional digits. It also does not recognize SQL_BIGINT type,
139 		// so the workaround here is to hardcode it to 32 or 64 bit integer
140 		if (0 == _columnDesc.decimalDigits)
141 		{
142 			if (_columnDesc.size > 9)
143 				setType(MetaColumn::FDT_INT64);
144 			else
145 				setType(MetaColumn::FDT_INT32);
146 		}
147 		else
148 		{
149 			setType(MetaColumn::FDT_DOUBLE);
150 		}
151 		break;
152 
153 	case SQL_REAL:
154 		setType(MetaColumn::FDT_FLOAT); break;
155 
156 	case SQL_BINARY:
157 	case SQL_VARBINARY:
158 	case SQL_LONGVARBINARY:
159 	case -98:// IBM DB2 non-standard type
160 		setType(MetaColumn::FDT_BLOB); break;
161 
162 	case SQL_TYPE_DATE:
163 		setType(MetaColumn::FDT_DATE); break;
164 
165 	case SQL_TYPE_TIME:
166 		setType(MetaColumn::FDT_TIME); break;
167 
168 	case SQL_TYPE_TIMESTAMP:
169 		setType(MetaColumn::FDT_TIMESTAMP); break;
170 
171 	default:
172 		throw DataFormatException("Unsupported data type.");
173 	}
174 }
175 
176 
177 } } } // namespace Poco::Data::ODBC
178