1 | // |
---|---|
2 | // MySQLException.cpp |
3 | // |
4 | // Library: SQL/MySQL |
5 | // Package: MySQL |
6 | // Module: ResultMetadata |
7 | // |
8 | // Copyright (c) 2008, Applied Informatics Software Engineering GmbH. |
9 | // and Contributors. |
10 | // |
11 | // SPDX-License-Identifier: BSL-1.0 |
12 | // |
13 | |
14 | |
15 | #include "Poco/SQL/MySQL/ResultMetadata.h" |
16 | #include "Poco/SQL/MySQL/MySQLException.h" |
17 | #include <cstring> |
18 | |
19 | namespace |
20 | { |
21 | class ResultMetadataHandle |
22 | /// Simple exception-safe wrapper |
23 | { |
24 | public: |
25 | |
26 | explicit ResultMetadataHandle(MYSQL_STMT* stmt) |
27 | { |
28 | h = mysql_stmt_result_metadata(stmt); |
29 | } |
30 | |
31 | ~ResultMetadataHandle() |
32 | { |
33 | if (h) |
34 | { |
35 | mysql_free_result(h); |
36 | } |
37 | } |
38 | |
39 | operator MYSQL_RES* () |
40 | { |
41 | return h; |
42 | } |
43 | |
44 | private: |
45 | |
46 | MYSQL_RES* h; |
47 | }; |
48 | |
49 | std::size_t fieldSize(const MYSQL_FIELD& field) |
50 | /// Convert field MySQL-type and field MySQL-length to actual field length |
51 | { |
52 | switch (field.type) |
53 | { |
54 | case MYSQL_TYPE_TINY: return sizeof(char); |
55 | case MYSQL_TYPE_SHORT: return sizeof(short); |
56 | case MYSQL_TYPE_INT24: |
57 | case MYSQL_TYPE_LONG: return sizeof(Poco::Int32); |
58 | case MYSQL_TYPE_FLOAT: return sizeof(float); |
59 | case MYSQL_TYPE_DOUBLE: return sizeof(double); |
60 | case MYSQL_TYPE_LONGLONG: return sizeof(Poco::Int64); |
61 | |
62 | case MYSQL_TYPE_DATE: |
63 | case MYSQL_TYPE_TIME: |
64 | case MYSQL_TYPE_DATETIME: |
65 | return sizeof(MYSQL_TIME); |
66 | |
67 | case MYSQL_TYPE_DECIMAL: |
68 | case MYSQL_TYPE_NEWDECIMAL: |
69 | case MYSQL_TYPE_STRING: |
70 | case MYSQL_TYPE_VAR_STRING: |
71 | case MYSQL_TYPE_TINY_BLOB: |
72 | case MYSQL_TYPE_MEDIUM_BLOB: |
73 | case MYSQL_TYPE_LONG_BLOB: |
74 | case MYSQL_TYPE_BLOB: |
75 | return field.length; |
76 | |
77 | default: |
78 | throw Poco::SQL::MySQL::StatementException("unknown field type"); |
79 | } |
80 | } |
81 | |
82 | Poco::SQL::MetaColumn::ColumnDataType fieldType(const MYSQL_FIELD& field) |
83 | /// Convert field MySQL-type to Poco-type |
84 | { |
85 | bool unsig = ((field.flags & UNSIGNED_FLAG) == UNSIGNED_FLAG); |
86 | |
87 | switch (field.type) |
88 | { |
89 | case MYSQL_TYPE_TINY: |
90 | if (unsig) return Poco::SQL::MetaColumn::FDT_UINT8; |
91 | return Poco::SQL::MetaColumn::FDT_INT8; |
92 | |
93 | case MYSQL_TYPE_SHORT: |
94 | if (unsig) return Poco::SQL::MetaColumn::FDT_UINT16; |
95 | return Poco::SQL::MetaColumn::FDT_INT16; |
96 | |
97 | case MYSQL_TYPE_INT24: |
98 | case MYSQL_TYPE_LONG: |
99 | if (unsig) return Poco::SQL::MetaColumn::FDT_UINT32; |
100 | return Poco::SQL::MetaColumn::FDT_INT32; |
101 | |
102 | case MYSQL_TYPE_FLOAT: |
103 | return Poco::SQL::MetaColumn::FDT_FLOAT; |
104 | |
105 | case MYSQL_TYPE_DECIMAL: |
106 | case MYSQL_TYPE_NEWDECIMAL: |
107 | case MYSQL_TYPE_DOUBLE: |
108 | return Poco::SQL::MetaColumn::FDT_DOUBLE; |
109 | |
110 | case MYSQL_TYPE_LONGLONG: |
111 | if (unsig) return Poco::SQL::MetaColumn::FDT_UINT64; |
112 | return Poco::SQL::MetaColumn::FDT_INT64; |
113 | |
114 | case MYSQL_TYPE_DATE: |
115 | return Poco::SQL::MetaColumn::FDT_DATE; |
116 | |
117 | case MYSQL_TYPE_TIME: |
118 | return Poco::SQL::MetaColumn::FDT_TIME; |
119 | |
120 | case MYSQL_TYPE_DATETIME: |
121 | return Poco::SQL::MetaColumn::FDT_TIMESTAMP; |
122 | |
123 | case MYSQL_TYPE_STRING: |
124 | case MYSQL_TYPE_VAR_STRING: |
125 | return Poco::SQL::MetaColumn::FDT_STRING; |
126 | |
127 | case MYSQL_TYPE_TINY_BLOB: |
128 | case MYSQL_TYPE_MEDIUM_BLOB: |
129 | case MYSQL_TYPE_LONG_BLOB: |
130 | case MYSQL_TYPE_BLOB: |
131 | return Poco::SQL::MetaColumn::FDT_BLOB; |
132 | default: |
133 | return Poco::SQL::MetaColumn::FDT_UNKNOWN; |
134 | } |
135 | } |
136 | } // namespace |
137 | |
138 | |
139 | namespace Poco { |
140 | namespace SQL { |
141 | namespace MySQL { |
142 | |
143 | void ResultMetadata::reset() |
144 | { |
145 | _columns.resize(0); |
146 | _row.resize(0); |
147 | _buffer.resize(0); |
148 | _lengths.resize(0); |
149 | _isNull.resize(0); |
150 | } |
151 | |
152 | void ResultMetadata::init(MYSQL_STMT* stmt) |
153 | { |
154 | ResultMetadataHandle h(stmt); |
155 | |
156 | if (!h) |
157 | { |
158 | // all right, it is normal |
159 | // querys such an "INSERT INTO" just does not have result at all |
160 | reset(); |
161 | return; |
162 | } |
163 | |
164 | std::size_t count = mysql_num_fields(h); |
165 | MYSQL_FIELD* fields = mysql_fetch_fields(h); |
166 | |
167 | std::size_t commonSize = 0; |
168 | _columns.reserve(count); |
169 | |
170 | {for (std::size_t i = 0; i < count; i++) |
171 | { |
172 | std::size_t size = fieldSize(fields[i]); |
173 | if (size == 0xFFFFFFFF) size = 0; |
174 | |
175 | _columns.push_back(MetaColumn( |
176 | i, // position |
177 | fields[i].name, // name |
178 | fieldType(fields[i]), // type |
179 | size, // length |
180 | 0, // TODO: precision |
181 | !IS_NOT_NULL(fields[i].flags) // nullable |
182 | )); |
183 | |
184 | commonSize += _columns[i].length(); |
185 | }} |
186 | |
187 | _buffer.resize(commonSize); |
188 | _row.resize(count); |
189 | _lengths.resize(count); |
190 | _isNull.resize(count); |
191 | |
192 | std::size_t offset = 0; |
193 | |
194 | for (std::size_t i = 0; i < count; i++) |
195 | { |
196 | std::memset(&_row[i], 0, sizeof(MYSQL_BIND)); |
197 | unsigned int len = static_cast<unsigned int>(_columns[i].length()); |
198 | _row[i].buffer_type = fields[i].type; |
199 | _row[i].buffer_length = len; |
200 | _row[i].buffer = (len > 0) ? (&_buffer[0] + offset) : 0; |
201 | _row[i].length = &_lengths[i]; |
202 | _row[i].is_null = &_isNull[i]; |
203 | _row[i].is_unsigned = (fields[i].flags & UNSIGNED_FLAG) > 0; |
204 | |
205 | offset += _row[i].buffer_length; |
206 | } |
207 | } |
208 | |
209 | std::size_t ResultMetadata::columnsReturned() const |
210 | { |
211 | return static_cast<std::size_t>(_columns.size()); |
212 | } |
213 | |
214 | const MetaColumn& ResultMetadata::metaColumn(std::size_t pos) const |
215 | { |
216 | return _columns[pos]; |
217 | } |
218 | |
219 | MYSQL_BIND* ResultMetadata::row() |
220 | { |
221 | return &_row[0]; |
222 | } |
223 | |
224 | std::size_t ResultMetadata::length(std::size_t pos) const |
225 | { |
226 | return _lengths[pos]; |
227 | } |
228 | |
229 | const unsigned char* ResultMetadata::rawData(std::size_t pos) const |
230 | { |
231 | return reinterpret_cast<const unsigned char*>(_row[pos].buffer); |
232 | } |
233 | |
234 | bool ResultMetadata::isNull(std::size_t pos) const |
235 | { |
236 | return (_isNull[pos] != 0); |
237 | } |
238 | |
239 | }}} // namespace Poco::SQL::MySQL |
240 |