1/*
2 * The contents of this file are subject to the Initial
3 * Developer's Public License Version 1.0 (the "License");
4 * you may not use this file except in compliance with the
5 * License. You may obtain a copy of the License at
6 * http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
7 *
8 * Software distributed under the License is distributed AS IS,
9 * WITHOUT WARRANTY OF ANY KIND, either express or implied.
10 * See the License for the specific language governing rights
11 * and limitations under the License.
12 *
13 * The Original Code was created by Adriano dos Santos Fernandes
14 * for the Firebird Open Source RDBMS project.
15 *
16 * Copyright (c) 2011 Adriano dos Santos Fernandes <adrianosf@uol.com.br>
17 * and all contributors signed below.
18 *
19 * All Rights Reserved.
20 * Contributor(s): ______________________________________.
21 */
22
23#ifndef FIREBIRD_MESSAGE_H
24#define FIREBIRD_MESSAGE_H
25
26#include "ibase.h"
27#include "./Provider.h"
28#include "./impl/boost/preprocessor/seq/for_each_i.hpp"
29#include <assert.h>
30#include <time.h>
31#include <string.h>
32
33#define FB_MESSAGE(name, fields) \
34 FB__MESSAGE_I(name, 2, FB_BOOST_PP_CAT(FB__MESSAGE_X fields, 0), )
35
36#define FB__MESSAGE_X(x, y) ((x, y)) FB__MESSAGE_Y
37#define FB__MESSAGE_Y(x, y) ((x, y)) FB__MESSAGE_X
38#define FB__MESSAGE_X0
39#define FB__MESSAGE_Y0
40
41#define FB_TRIGGER_MESSAGE(name, fields) \
42 FB__MESSAGE_I(name, 3, FB_BOOST_PP_CAT(FB_TRIGGER_MESSAGE_X fields, 0), \
43 FB_TRIGGER_MESSAGE_MOVE_NAMES(name, fields))
44
45#define FB_TRIGGER_MESSAGE_X(x, y, z) ((x, y, z)) FB_TRIGGER_MESSAGE_Y
46#define FB_TRIGGER_MESSAGE_Y(x, y, z) ((x, y, z)) FB_TRIGGER_MESSAGE_X
47#define FB_TRIGGER_MESSAGE_X0
48#define FB_TRIGGER_MESSAGE_Y0
49
50#define FB__MESSAGE_I(name, size, fields, moveNames) \
51 struct name \
52 { \
53 struct Type \
54 { \
55 FB_BOOST_PP_SEQ_FOR_EACH_I(FB__MESSAGE_FIELD, size, fields) \
56 }; \
57 \
58 static void setup(::Firebird::IStatus* status, ::Firebird::IMetadataBuilder* builder) \
59 { \
60 unsigned index = 0; \
61 moveNames \
62 FB_BOOST_PP_SEQ_FOR_EACH_I(FB__MESSAGE_META, size, fields) \
63 } \
64 \
65 name(::Firebird::IMaster* master) \
66 : desc(master, FB_BOOST_PP_SEQ_SIZE(fields), &setup) \
67 { \
68 } \
69 \
70 ::Firebird::IMessageMetadata* getMetadata() const \
71 { \
72 return desc.getMetadata(); \
73 } \
74 \
75 void clear() \
76 { \
77 memset(&data, 0, sizeof(data)); \
78 } \
79 \
80 Type* getData() \
81 { \
82 return &data; \
83 } \
84 \
85 const Type* getData() const \
86 { \
87 return &data; \
88 } \
89 \
90 Type* operator ->() \
91 { \
92 return getData(); \
93 } \
94 \
95 const Type* operator ->() const \
96 { \
97 return getData(); \
98 } \
99 \
100 Type data; \
101 ::Firebird::MessageDesc desc; \
102 }
103
104#define FB__MESSAGE_FIELD(r, _, i, xy) \
105 FB_BOOST_PP_CAT(FB__TYPE_, FB_BOOST_PP_TUPLE_ELEM(_, 0, xy)) FB_BOOST_PP_TUPLE_ELEM(_, 1, xy); \
106 ISC_SHORT FB_BOOST_PP_CAT(FB_BOOST_PP_TUPLE_ELEM(_, 1, xy), Null);
107
108#define FB__MESSAGE_META(r, _, i, xy) \
109 FB_BOOST_PP_CAT(FB__META_, FB_BOOST_PP_TUPLE_ELEM(_, 0, xy)) \
110 ++index;
111
112// Types - metadata
113
114#define FB__META_FB_SCALED_SMALLINT(scale) \
115 builder->setType(status, index, SQL_SHORT); \
116 builder->setLength(status, index, sizeof(ISC_SHORT)); \
117 builder->setScale(status, index, scale);
118
119#define FB__META_FB_SCALED_INTEGER(scale) \
120 builder->setType(status, index, SQL_LONG); \
121 builder->setLength(status, index, sizeof(ISC_LONG)); \
122 builder->setScale(status, index, scale);
123
124#define FB__META_FB_SCALED_BIGINT(scale) \
125 builder->setType(status, index, SQL_INT64); \
126 builder->setLength(status, index, sizeof(ISC_INT64)); \
127 builder->setScale(status, index, scale);
128
129#define FB__META_FB_FLOAT \
130 builder->setType(status, index, SQL_FLOAT); \
131 builder->setLength(status, index, sizeof(float));
132
133#define FB__META_FB_DOUBLE \
134 builder->setType(status, index, SQL_DOUBLE); \
135 builder->setLength(status, index, sizeof(double));
136
137#define FB__META_FB_BLOB \
138 builder->setType(status, index, SQL_BLOB); \
139 builder->setLength(status, index, sizeof(ISC_QUAD));
140
141#define FB__META_FB_BOOLEAN \
142 builder->setType(status, index, SQL_BOOLEAN); \
143 builder->setLength(status, index, sizeof(ISC_BOOLEAN));
144
145#define FB__META_FB_DATE \
146 builder->setType(status, index, SQL_DATE); \
147 builder->setLength(status, index, sizeof(FbDate));
148
149#define FB__META_FB_TIME \
150 builder->setType(status, index, SQL_TIME); \
151 builder->setLength(status, index, sizeof(FbTime));
152
153#define FB__META_FB_TIMESTAMP \
154 builder->setType(status, index, SQL_TIMESTAMP); \
155 builder->setLength(status, index, sizeof(FbTimestamp));
156
157#define FB__META_FB_CHAR(len) \
158 builder->setType(status, index, SQL_TEXT); \
159 builder->setLength(status, index, len);
160
161#define FB__META_FB_VARCHAR(len) \
162 builder->setType(status, index, SQL_VARYING); \
163 builder->setLength(status, index, len);
164
165#define FB__META_FB_INTL_CHAR(len, charSet) \
166 builder->setType(status, index, SQL_TEXT); \
167 builder->setLength(status, index, len); \
168 builder->setCharSet(status, index, charSet);
169
170#define FB__META_FB_INTL_VARCHAR(len, charSet) \
171 builder->setType(status, index, SQL_VARYING); \
172 builder->setLength(status, index, len); \
173 builder->setCharSet(status, index, charSet);
174
175#define FB__META_FB_SMALLINT FB__META_FB_SCALED_SMALLINT(0)
176#define FB__META_FB_INTEGER FB__META_FB_SCALED_INTEGER(0)
177#define FB__META_FB_BIGINT FB__META_FB_SCALED_BIGINT(0)
178
179// Types - struct
180
181#define FB__TYPE_FB_SCALED_SMALLINT(x) ISC_SHORT
182#define FB__TYPE_FB_SCALED_INTEGER(x) ISC_LONG
183#define FB__TYPE_FB_SCALED_BIGINT(x) ISC_INT64
184#define FB__TYPE_FB_SMALLINT ISC_SHORT
185#define FB__TYPE_FB_INTEGER ISC_LONG
186#define FB__TYPE_FB_BIGINT ISC_INT64
187#define FB__TYPE_FB_FLOAT float
188#define FB__TYPE_FB_DOUBLE double
189#define FB__TYPE_FB_BLOB ISC_QUAD
190#define FB__TYPE_FB_BOOLEAN ISC_UCHAR
191#define FB__TYPE_FB_DATE ::Firebird::FbDate
192#define FB__TYPE_FB_TIME ::Firebird::FbTime
193#define FB__TYPE_FB_TIMESTAMP ::Firebird::FbTimestamp
194#define FB__TYPE_FB_CHAR(len) ::Firebird::FbChar<(len)>
195#define FB__TYPE_FB_VARCHAR(len) ::Firebird::FbVarChar<(len)>
196
197#define FB_TRIGGER_MESSAGE_MOVE_NAMES(name, fields) \
198 FB_TRIGGER_MESSAGE_MOVE_NAMES_I(name, 3, FB_BOOST_PP_CAT(FB_TRIGGER_MESSAGE_MOVE_NAMES_X fields, 0))
199
200#define FB_TRIGGER_MESSAGE_MOVE_NAMES_X(x, y, z) ((x, y, z)) FB_TRIGGER_MESSAGE_MOVE_NAMES_Y
201#define FB_TRIGGER_MESSAGE_MOVE_NAMES_Y(x, y, z) ((x, y, z)) FB_TRIGGER_MESSAGE_MOVE_NAMES_X
202#define FB_TRIGGER_MESSAGE_MOVE_NAMES_X0
203#define FB_TRIGGER_MESSAGE_MOVE_NAMES_Y0
204
205#define FB_TRIGGER_MESSAGE_MOVE_NAMES_I(name, size, fields) \
206 FB_BOOST_PP_SEQ_FOR_EACH_I(FB_TRIGGER_MESSAGE_MOVE_NAME, size, fields) \
207 builder->truncate(status, index); \
208 index = 0;
209
210#define FB_TRIGGER_MESSAGE_MOVE_NAME(r, _, i, xy) \
211 builder->moveNameToIndex(status, FB_BOOST_PP_TUPLE_ELEM(_, 2, xy), index++);
212
213
214namespace Firebird {
215
216
217template <unsigned N>
218struct FbChar
219{
220 char str[N];
221};
222
223template <unsigned N>
224struct FbVarChar
225{
226 ISC_USHORT length;
227 char str[N];
228
229 void set(const char* s)
230 {
231 length = strlen(s);
232 assert(length <= N);
233 memcpy(str, s, length);
234 }
235};
236
237// This class has memory layout identical to ISC_DATE.
238class FbDate
239{
240public:
241 void decode(unsigned* year, unsigned* month, unsigned* day) const
242 {
243 tm times;
244 isc_decode_sql_date(&value, &times);
245
246 if (year)
247 *year = times.tm_year + 1900;
248 if (month)
249 *month = times.tm_mon + 1;
250 if (day)
251 *day = times.tm_mday;
252 }
253
254 unsigned getYear() const
255 {
256 unsigned year;
257 decode(&year, NULL, NULL);
258 return year;
259 }
260
261 unsigned getMonth() const
262 {
263 unsigned month;
264 decode(NULL, &month, NULL);
265 return month;
266 }
267
268 unsigned getDay() const
269 {
270 unsigned day;
271 decode(NULL, NULL, &day);
272 return day;
273 }
274
275 void encode(unsigned year, unsigned month, unsigned day)
276 {
277 tm times;
278 times.tm_year = year - 1900;
279 times.tm_mon = month - 1;
280 times.tm_mday = day;
281
282 isc_encode_sql_date(&times, &value);
283 }
284
285public:
286 ISC_DATE value;
287};
288
289// This class has memory layout identical to ISC_TIME.
290class FbTime
291{
292public:
293 void decode(unsigned* hours, unsigned* minutes, unsigned* seconds, unsigned* fractions) const
294 {
295 tm times;
296 isc_decode_sql_time(&value, &times);
297
298 if (hours)
299 *hours = times.tm_hour;
300 if (minutes)
301 *minutes = times.tm_min;
302 if (seconds)
303 *seconds = times.tm_sec;
304 if (fractions)
305 *fractions = value % ISC_TIME_SECONDS_PRECISION;
306 }
307
308 unsigned getHours() const
309 {
310 unsigned hours;
311 decode(&hours, NULL, NULL, NULL);
312 return hours;
313 }
314
315 unsigned getMinutes() const
316 {
317 unsigned minutes;
318 decode(NULL, &minutes, NULL, NULL);
319 return minutes;
320 }
321
322 unsigned getSeconds() const
323 {
324 unsigned seconds;
325 decode(NULL, NULL, &seconds, NULL);
326 return seconds;
327 }
328
329 unsigned getFractions() const
330 {
331 unsigned fractions;
332 decode(NULL, NULL, NULL, &fractions);
333 return fractions;
334 }
335
336 void encode(unsigned hours, unsigned minutes, unsigned seconds, unsigned fractions)
337 {
338 tm times;
339 times.tm_hour = hours;
340 times.tm_min = minutes;
341 times.tm_sec = seconds;
342
343 isc_encode_sql_time(&times, &value);
344 value += fractions;
345 }
346
347public:
348 ISC_TIME value;
349};
350
351// This class has memory layout identical to ISC_TIMESTAMP.
352class FbTimestamp
353{
354public:
355 FbDate date;
356 FbTime time;
357};
358
359class MessageDesc
360{
361public:
362 MessageDesc(IMaster* master, unsigned count, void (*setup)(IStatus*, IMetadataBuilder*))
363 {
364 IStatus* status = master->getStatus();
365 IMetadataBuilder* builder = master->getMetadataBuilder(status, count);
366
367 setup(status, builder);
368
369 metadata = builder->getMetadata(status);
370
371 builder->release();
372 status->dispose();
373 }
374
375 ~MessageDesc()
376 {
377 metadata->release();
378 }
379
380 IMessageMetadata* getMetadata() const
381 {
382 return metadata;
383 }
384
385private:
386 IMessageMetadata* metadata;
387};
388
389
390} // namespace Firebird
391
392#endif // FIREBIRD_MESSAGE_H
393