Branch data Line data Source code
1 : : /*
2 : : * Copyright 2006-2009 Savarese Software Research Corporation
3 : : *
4 : : * Licensed under the Apache License, Version 2.0 (the "License");
5 : : * you may not use this file except in compliance with the License.
6 : : * You may obtain a copy of the License at
7 : : *
8 : : * https://www.savarese.com/software/ApacheLicense-2.0
9 : : *
10 : : * Unless required by applicable law or agreed to in writing, software
11 : : * distributed under the License is distributed on an "AS IS" BASIS,
12 : : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 : : * See the License for the specific language governing permissions and
14 : : * limitations under the License.
15 : : */
16 : :
17 : : /**
18 : : * @file
19 : : * This header defines macros for generating database row objects.
20 : : */
21 : :
22 : : #ifndef __SSRC_WSPR_DATABASE_TYPES_H
23 : : #define __SSRC_WSPR_DATABASE_TYPES_H
24 : :
25 : : // This is actually the maximum number of parameters + 1
26 : : // (e.g., specify 10 parameters with a value of 11).
27 : : #define WSPR_DB_MAX_PARAMETERS 21
28 : :
29 : : #include <ssrc/wispers/utility/CTypeWrapper.h>
30 : : #include <ssrc/wisp/utility/wisp_struct.h>
31 : :
32 : : #include <boost/preprocessor/repetition.hpp>
33 : : #include <cstdint>
34 : : #include <climits>
35 : :
36 : : #include <string>
37 : : #include <stdexcept>
38 : :
39 : : __BEGIN_NS_SQLITE3_INCLUDE
40 : : #include <sqlite3.h>
41 : : __END_NS_SQLITE3_INCLUDE
42 : :
43 : : __BEGIN_NS_SSRC_WSPR_DATABASE
44 : :
45 : : using std::string;
46 : : using NS_SSRC_WSPR_UTILITY::CTypeWrapper;
47 : : // We need this for SQLITE_STATIC and SQLITE_TRANSIENT macros to work.
48 : : using SQLite3::sqlite3_destructor_type;
49 : :
50 : : namespace detail {
51 : :
52 : : struct sqlite3_init {
53 : 23 : int operator()(SQLite3::sqlite3 **p, const string & db_name = ":memory:")
54 : : const
55 : : {
56 : 23 : return SQLite3::sqlite3_open(db_name.c_str(), p);
57 : : }
58 : : };
59 : :
60 : : struct sqlite3_delete;
61 : :
62 : : typedef
63 : : CTypeWrapper<SQLite3::sqlite3, int, sqlite3_init, sqlite3_delete>
64 : : sqlite3_ptr;
65 : :
66 : : struct sqlite3_stmt_initializer {
67 : : sqlite3_ptr & database;
68 : : const string & statement;
69 : :
70 : 868 : sqlite3_stmt_initializer(sqlite3_ptr & database,
71 : : const string & statement) :
72 : 868 : database(database), statement(statement)
73 : 868 : { }
74 : : };
75 : :
76 : : struct sqlite3_stmt_init {
77 : : int operator()(SQLite3::sqlite3_stmt **p) const {
78 : : return SQLITE_ERROR;
79 : : }
80 : 868 : int operator()(SQLite3::sqlite3_stmt **p,
81 : : sqlite3_stmt_initializer initializer)
82 : : const
83 : : {
84 : : const char *tail;
85 : : return
86 : : SQLite3::sqlite3_prepare_v2(initializer.database.get(),
87 : : initializer.statement.c_str(),
88 : 868 : initializer.statement.size(),
89 : 868 : p, &tail);
90 : : }
91 : : };
92 : :
93 : : struct sqlite3_stmt_delete {
94 : 868 : void operator()(SQLite3::sqlite3_stmt *p) const {
95 [ + - ]: 868 : if(p)
96 : 868 : SQLite3::sqlite3_finalize(p);
97 : 868 : }
98 : : };
99 : :
100 : : typedef
101 : : CTypeWrapper<SQLite3::sqlite3_stmt, int,
102 : : sqlite3_stmt_init, sqlite3_stmt_delete>
103 : : sqlite3_stmt_ptr;
104 : : }
105 : :
106 : : using detail::sqlite3_ptr;
107 : : using detail::sqlite3_stmt_ptr;
108 : :
109 [ # # ]: 0 : class DatabaseException : public std::runtime_error {
110 : : typedef std::runtime_error super;
111 : :
112 : : bool _statement_reset;
113 : :
114 : : public:
115 : 0 : explicit DatabaseException(const string & message) :
116 : 0 : super(message), _statement_reset(false)
117 : 0 : { }
118 : :
119 : 0 : explicit DatabaseException(SQLite3::sqlite3 *db) :
120 [ # # # # : 0 : super(SQLite3::sqlite3_errmsg(db)), _statement_reset(false)
# # # # ]
121 : 0 : { }
122 : :
123 : : explicit DatabaseException(const sqlite3_ptr & db) :
124 : : super(SQLite3::sqlite3_errmsg(db.get())), _statement_reset(false)
125 : : { }
126 : :
127 : 0 : explicit DatabaseException(const sqlite3_stmt_ptr & stmt) :
128 [ # # # # : 0 : super(string(SQLite3::sqlite3_errmsg(SQLite3::sqlite3_db_handle(stmt.get()))).append(":\n").append(SQLite3::sqlite3_sql(stmt.get()))),
# # # # #
# # # ]
129 [ # # # # ]: 0 : _statement_reset((SQLite3::sqlite3_reset(stmt.get()) == SQLITE_OK))
130 : 0 : { }
131 : :
132 : : bool statement_reset() const { return _statement_reset; }
133 : : };
134 : :
135 : : namespace detail {
136 : :
137 : : struct sqlite3_delete {
138 : 23 : void operator()(SQLite3::sqlite3 *p) const {
139 : : // We violate the boost::shared_ptr contract by throwing, but what
140 : : // else can we do...
141 [ + - - + : 23 : if(p && SQLite3::sqlite3_close(p) != SQLITE_OK)
- + ]
142 [ # # ]: 0 : throw DatabaseException(p);
143 : 23 : }
144 : : };
145 : :
146 : 331 : inline int step(const sqlite3_stmt_ptr & statement)
147 : : SSRC_DECL_THROW(DatabaseException)
148 : : {
149 : 331 : int result = SQLite3::sqlite3_step(statement.get());
150 : :
151 [ + + ]: 331 : if(result == SQLITE_DONE) {
152 [ - + ]: 189 : if(SQLite3::sqlite3_reset(statement.get()) != SQLITE_OK)
153 [ # # ]: 0 : throw DatabaseException(statement);
154 : : }
155 : :
156 : 331 : return result;
157 : : }
158 : :
159 : : template<typename T, int elements> struct Values;
160 : : }
161 : :
162 : : // IMPORTANT: Leave second member as non-const. Also, note that
163 : : // first member is pointer to a const, not a const in itself.
164 : : // This is so we can reuse a blob_type in a loop.
165 : : typedef std::pair<const void *, unsigned int> blob_type;
166 : :
167 : : // Forward declaration.
168 : : class ResultSet;
169 : : template<typename T> inline T value(const ResultSet & result_set,
170 : : const unsigned int index);
171 : : template<typename T> inline T values(const ResultSet & result_set);
172 : :
173 : 103 : class ResultSet {
174 : : friend class PreparedStatement;
175 : :
176 : : bool _done;
177 : : unsigned int _row_number;
178 : : sqlite3_stmt_ptr _statement;
179 : :
180 : : explicit
181 : 103 : ResultSet(const sqlite3_stmt_ptr & statement) :
182 : 103 : _done(false), _row_number(0), _statement(statement)
183 : 103 : { }
184 : :
185 : : public:
186 : :
187 : : enum ColumnType {
188 : : Integer = SQLITE_INTEGER,
189 : : Float = SQLITE_FLOAT,
190 : : Text = SQLITE_TEXT,
191 : : Blob = SQLITE_BLOB,
192 : : Null = SQLITE_NULL
193 : : };
194 : :
195 : 3 : unsigned int count_values() const {
196 : 3 : return SQLite3::sqlite3_data_count(_statement.get());
197 : : }
198 : :
199 : 99 : bool done() const { return _done; }
200 : :
201 : : unsigned int row_number() const { return _row_number; }
202 : :
203 : 71 : bool next() SSRC_DECL_THROW(DatabaseException) {
204 : 71 : int result = detail::step(_statement);
205 : :
206 [ + + - + ]: 71 : if(result == SQLITE_DONE || result == SQLITE_MISUSE) {
207 : 32 : _done = true;
208 : 32 : ++_row_number;
209 [ - + ]: 39 : } else if(result != SQLITE_ROW) {
210 : 0 : _done = true;
211 [ # # ]: 0 : throw DatabaseException(_statement);
212 : : } else
213 : 39 : ++_row_number;
214 : :
215 : 71 : return !_done;
216 : : }
217 : :
218 : 2 : ColumnType column_type(const unsigned int index) const {
219 : : return
220 : 2 : static_cast<ColumnType>(SQLite3::sqlite3_column_type(_statement.get(), index));
221 : : }
222 : :
223 : : template<typename T> inline T value(unsigned int index = 0) const {
224 : : return NS_SSRC_WSPR_DATABASE::value<T>(*this, index);
225 : : }
226 : :
227 : 42 : template<typename T> T values() const {
228 : 42 : return NS_SSRC_WSPR_DATABASE::values<T>(*this);
229 : : }
230 : :
231 : : #define WSPR_DB_VALUES_ARG(z, i, _) BOOST_PP_COMMA_IF(i) value<V ## i>(i)
232 : :
233 : : #define WSPR_DB_VALUES(z, i, _) \
234 : : template<BOOST_PP_ENUM_PARAMS(i, typename V)> \
235 : : std::tuple<BOOST_PP_ENUM_PARAMS(i, V)> values() const { \
236 : : return std::make_tuple<BOOST_PP_ENUM_PARAMS(i, V)>(BOOST_PP_REPEAT(i, WSPR_DB_VALUES_ARG, _)); \
237 : : }
238 : :
239 [ + - ]: 4 : BOOST_PP_REPEAT_FROM_TO(2, WSPR_DB_MAX_PARAMETERS, WSPR_DB_VALUES, _)
240 : :
241 : : #undef WSPR_DB_VALUES
242 : : #undef WSPR_DB_VALUES_ARG
243 : :
244 : 41 : template<typename T> operator T() const {
245 : 41 : return values<T>();
246 : : }
247 : :
248 : : // Returns the number of iterations.
249 : : template<typename functor>
250 : 30 : unsigned int for_each(const functor & apply)
251 : : SSRC_DECL_THROW(DatabaseException)
252 : : {
253 : 30 : unsigned int starting_row(_row_number);
254 : :
255 [ + + + + : 129 : while(!done()) {
+ + ]
256 [ + - + - ]: 69 : apply(*this);
257 : 69 : next();
258 : : }
259 : :
260 : 30 : return (_row_number - starting_row);
261 : : }
262 : :
263 : : };
264 : :
265 : 102 : template<> inline string ResultSet::value<string>(unsigned int index) const
266 : : SSRC_DECL_THROW(DatabaseException)
267 : : {
268 : : const unsigned char* result =
269 : 102 : SQLite3::sqlite3_column_text(_statement.get(), index);
270 : :
271 [ - + ]: 102 : if(!result)
272 [ # # ]: 0 : throw DatabaseException(_statement);
273 : :
274 [ + - ]: 102 : return string(reinterpret_cast<char*>(const_cast<unsigned char*>(result)));
275 : : }
276 : :
277 : 143 : template<> inline int ResultSet::value<int>(unsigned int index) const {
278 : 143 : return SQLite3::sqlite3_column_int(_statement.get(), index);
279 : : }
280 : :
281 : : template<> inline
282 : 72 : unsigned int ResultSet::value<unsigned int>(unsigned int index) const {
283 : 72 : return value<int>(index);
284 : : }
285 : :
286 : : template<> inline
287 : : std::int16_t ResultSet::value<std::int16_t>(unsigned int index) const {
288 : : return value<int>(index);
289 : : }
290 : :
291 : : template<> inline
292 : 33 : std::uint16_t ResultSet::value<std::uint16_t>(unsigned int index) const {
293 : 33 : return value<int>(index);
294 : : }
295 : :
296 : : template<> inline bool ResultSet::value<bool>(unsigned int index) const {
297 : : return value<int>(index);
298 : : }
299 : :
300 : : template<> inline
301 : 158 : std::int64_t ResultSet::value<std::int64_t>(unsigned int index) const {
302 : 158 : return SQLite3::sqlite3_column_int64(_statement.get(), index);
303 : : }
304 : :
305 : : template<> inline
306 : 66 : std::uint64_t ResultSet::value<std::uint64_t>(unsigned int index) const {
307 : 66 : return static_cast<std::uint64_t>(value<std::int64_t>(index));
308 : : }
309 : :
310 : : #if (LONG_MAX == INT_MAX)
311 : : template<> inline long ResultSet::value<long>(unsigned int index) const {
312 : : return static_cast<long>(value<std::int64_t>(index));
313 : : }
314 : :
315 : : template<>
316 : : inline unsigned long ResultSet::value<unsigned long>(unsigned int index) const {
317 : : return static_cast<unsigned long>(value<std::int64_t>(index));
318 : : }
319 : : #endif
320 : :
321 : : template<> inline double ResultSet::value<double>(unsigned int index) const {
322 : : return SQLite3::sqlite3_column_double(_statement.get(), index);
323 : : }
324 : :
325 : : template<> inline
326 : 3 : const void * ResultSet::value<const void *>(unsigned int index) const {
327 : 3 : return SQLite3::sqlite3_column_blob(_statement.get(), index);
328 : : }
329 : :
330 : : template<> inline
331 : 3 : blob_type ResultSet::value<blob_type>(unsigned int index) const {
332 : : return
333 : 3 : blob_type(value<const void *>(index),
334 : 6 : SQLite3::sqlite3_column_bytes(_statement.get(), index));
335 : : }
336 : :
337 : : namespace detail {
338 : : using std::tuple_element;
339 : :
340 : : #define WSPR_DB_VALUES_ARG(z, i, _) \
341 : : BOOST_PP_COMMA_IF(i) typename tuple_element<i,T>::type
342 : :
343 : : #define WSPR_DB_VALUES(z, i, _) \
344 : : template<typename T> struct Values<T, i> { \
345 : : static T values(const ResultSet & result_set) { \
346 : : return result_set.values<BOOST_PP_REPEAT(i, WSPR_DB_VALUES_ARG, _)>(); \
347 : : } \
348 : : };
349 : :
350 : 2 : BOOST_PP_REPEAT_FROM_TO(2, WSPR_DB_MAX_PARAMETERS, WSPR_DB_VALUES, _)
351 : :
352 : : #undef WSPR_DB_VALUES
353 : : #undef WSPR_DB_VALUES_ARG
354 : : }
355 : :
356 : : // You can specialize this function to create your own result_set conversions.
357 : : // The general function converts variable-length tuples.
358 : 2 : template<typename T> inline T values(const ResultSet & result_set) {
359 : : return
360 : 2 : detail::Values<T, std::tuple_size<T>::value>::values(result_set);
361 : : }
362 : :
363 : : template<> inline string values<string>(const ResultSet & result_set) {
364 : : return result_set.value<string>();
365 : : }
366 : :
367 : : template<> inline int values<int>(const ResultSet & result_set) {
368 : : return result_set.value<int>();
369 : : }
370 : :
371 : : template<> inline
372 : : unsigned int values<unsigned int>(const ResultSet & result_set) {
373 : : return result_set.value<unsigned int>();
374 : : }
375 : :
376 : : template<> inline
377 : : std::int16_t values<std::int16_t>(const ResultSet & result_set) {
378 : : return result_set.value<std::int16_t>();
379 : : }
380 : :
381 : : template<> inline
382 : : std::uint16_t values<std::uint16_t>(const ResultSet & result_set) {
383 : : return result_set.value<std::uint16_t>();
384 : : }
385 : :
386 : : template<> inline bool values<bool>(const ResultSet & result_set) {
387 : : return result_set.value<bool>();
388 : : }
389 : :
390 : : template<>
391 : 9 : inline std::int64_t values<std::int64_t>(const ResultSet & result_set) {
392 : 9 : return result_set.value<std::int64_t>();
393 : : }
394 : :
395 : : template<>
396 : 31 : inline std::uint64_t values<std::uint64_t>(const ResultSet & result_set) {
397 : 31 : return result_set.value<std::uint64_t>();
398 : : }
399 : :
400 : : #if (LONG_MAX == INT_MAX)
401 : : template<> inline long values<long>(const ResultSet & result_set) {
402 : : return result_set.value<long>();
403 : : }
404 : :
405 : : template<>
406 : : inline unsigned long values<unsigned long>(const ResultSet & result_set) {
407 : : return result_set.value<unsigned long>();
408 : : }
409 : : #endif
410 : :
411 : : template<> inline double values<double>(const ResultSet & result_set) {
412 : : return result_set.value<double>();
413 : : }
414 : :
415 : : template<>
416 : : inline blob_type values<blob_type>(const ResultSet & result_set) {
417 : : return result_set.value<blob_type>();
418 : : }
419 : :
420 : : typedef boost::shared_ptr<ResultSet> result_set_ptr;
421 : :
422 : : namespace detail {
423 : :
424 : : template<typename T>
425 : : struct is_basic_type {
426 : : static const bool value = false;
427 : : };
428 : :
429 : : #if (LONG_MAX == INT_MAX)
430 : : # define __BASIC_TYPES \
431 : : (std::string)(int)(unsigned int)(std::int16_t)(std::uint16_t)(bool)(std::int64_t)(std::uint64_t)(long)(unsigned long)(double)(blob_type)
432 : : #else
433 : : # define __BASIC_TYPES \
434 : : (std::string)(int)(unsigned int)(std::int16_t)(std::uint16_t)(bool)(std::int64_t)(std::uint64_t)(double)(blob_type)
435 : : #endif
436 : :
437 : : #define __IS_BASIC(r, data, type) \
438 : : template<> struct is_basic_type<type> { \
439 : : static const bool value = true; \
440 : : };
441 : :
442 : : BOOST_PP_SEQ_FOR_EACH(__IS_BASIC, _, __BASIC_TYPES)
443 : :
444 : : #undef __IS_BASIC
445 : :
446 : : #undef __BASIC_TYPES
447 : :
448 : : template<typename T, bool is_basic> struct ResultSetValueTraits;
449 : :
450 : : template<typename T>
451 : : struct ResultSetValueTraits<T, true> {
452 : : typedef T type;
453 : : typedef T db_value_type;
454 : : };
455 : :
456 : : template<typename T>
457 : : struct ResultSetValueTraits<T, false> {
458 : : typedef T type;
459 : : typedef typename T::db_value_type db_value_type;
460 : : };
461 : : }
462 : :
463 : : #define __WSPR_DB_INIT_RESULT_SET(r, rs, i, arg) \
464 : : BOOST_PP_COMMA_IF(i) BOOST_PP_TUPLE_ELEM(2, 1, arg)(std::move(rs.value<NS_SSRC_WSPR_DATABASE::detail::ResultSetValueTraits<BOOST_PP_TUPLE_ELEM(2, 0, arg), NS_SSRC_WSPR_DATABASE::detail::is_basic_type<BOOST_PP_TUPLE_ELEM(2, 0, arg)>::value >::db_value_type>(i)))
465 : :
466 : : #define __WSPR_DB_BIND_ROW(r, data, i, arg) \
467 : : BOOST_PP_COMMA_IF(i) BOOST_PP_TUPLE_ELEM(2, 1, arg)
468 : :
469 : : #define __WSPR_DB_LOAD_ROW __WSPR_DB_BIND_ROW
470 : :
471 : : #define __WSPR_DB_ROW_ELEMENT(r, name, i, arg) \
472 : : template<> struct name::Element<i> { \
473 : : typedef BOOST_PP_TUPLE_ELEM(2, 0, arg) type; \
474 : : }; \
475 : : template<> inline const name::Element<i>::type & name::get<i>() const { \
476 : : return BOOST_PP_TUPLE_ELEM(2, 1, arg); \
477 : : } \
478 : : template<> inline std::string name::column_name<i>() { \
479 : : return BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(2, 1, arg)); \
480 : : }
481 : :
482 : : #define __WSPR_DB_ROW_KEY(r, name, i, arg) \
483 : : template<> struct name::Key<i> { \
484 : : static const unsigned int column = arg; \
485 : : };
486 : :
487 : : #define __WSPR_DB_ROW_IS_PRIMARY_KEY_CONDITION(r, column, i, arg) \
488 : : BOOST_PP_EXPR_IF(i, ||) (column == arg)
489 : :
490 : : #define __WSPR_DB_ROW_IS_PRIMARY_KEY(r, name, arg) \
491 : : template<> inline bool name::is_primary_key<arg>() { return true; }
492 : :
493 : : #define __WSPR_DB_RETURN_COLUMN_NAME(r, data, i, arg) \
494 : : case i: return BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(2, 1, arg)); break;
495 : :
496 : : #define __WSPR_DB_ROW_PRIMARY_KEY_ELEMENT_TYPES(r, member_sequence, i, arg) \
497 : : BOOST_PP_COMMA_IF(i) BOOST_PP_TUPLE_ELEM(2, 0, BOOST_PP_SEQ_ELEM(arg, member_sequence))
498 : :
499 : : #define __WSPR_DB_ROW_PRIMARY_KEY_ELEMENT_REF_TYPES(r, member_sequence, i, arg) \
500 : : BOOST_PP_COMMA_IF(i) const BOOST_PP_TUPLE_ELEM(2, 0, BOOST_PP_SEQ_ELEM(arg, member_sequence))&
501 : :
502 : : #define __WSPR_DB_ROW_PRIMARY_KEY_TYPE(member_sequence, key_sequence) \
503 : : BOOST_PP_IIF(BOOST_PP_EQUAL(1, BOOST_PP_SEQ_SIZE(key_sequence)), \
504 : : BOOST_PP_TUPLE_ELEM(2, 0, BOOST_PP_SEQ_ELEM(BOOST_PP_SEQ_ELEM(0, key_sequence), member_sequence)), primary_key_tuple_type)
505 : :
506 : : #define __WSPR_DB_ROW_PRIMARY_KEY_REF_TYPE(member_sequence, key_sequence) \
507 : : BOOST_PP_IIF(BOOST_PP_EQUAL(1, BOOST_PP_SEQ_SIZE(key_sequence)), \
508 : : const BOOST_PP_TUPLE_ELEM(2, 0, BOOST_PP_SEQ_ELEM(BOOST_PP_SEQ_ELEM(0, key_sequence), member_sequence))&, primary_key_tie_type)
509 : :
510 : : #define __WSPR_DB_ROW_PRIMARY_KEY_ELEMENTS(r, member_sequence, i, arg) \
511 : : BOOST_PP_COMMA_IF(i) BOOST_PP_TUPLE_ELEM(2, 1, BOOST_PP_SEQ_ELEM(arg, member_sequence))
512 : :
513 : : #define __WSPR_DB_ROW_PRIMARY_KEY_BIND_PARAM(z, i, key) \
514 : : BOOST_PP_COMMA_IF(i) std::get<i>(key)
515 : :
516 : : #define __WSPR_DB_ROW_PRIMARY_KEY_BIND_PARAM_OFFSET(z, i, key) \
517 : : .bind(offset + i + 1, std::get<i>(key))
518 : :
519 : : #define __WSPR_DB_ROW_CONST_UINT(z, i, _) \
520 : : BOOST_PP_COMMA_IF(i) const unsigned int
521 : :
522 : : #define __WSPR_DB_ROW_PRIMARY_KEY_INDEX(z, _, i, arg) \
523 : : BOOST_PP_COMMA_IF(i) arg
524 : :
525 : : #define __WSPR_DB_ROW_WITH_KEY(name, member_sequence, key_sequence) \
526 : : struct name : public NS_SSRC_WISP_UTILITY::wisp_struct { \
527 : : enum { ElementCount = BOOST_PP_SEQ_SIZE(member_sequence) }; \
528 : : enum { PrimaryKeyCount = BOOST_PP_SEQ_SIZE(key_sequence) }; \
529 : : static inline std::string table_name() {return BOOST_PP_STRINGIZE(name);} \
530 : : static inline std::string column_name(const unsigned int column) { \
531 : : switch(column) { \
532 : : BOOST_PP_SEQ_FOR_EACH_I(__WSPR_DB_RETURN_COLUMN_NAME, _, member_sequence) \
533 : : }; \
534 : : return std::string(); \
535 : : } \
536 : : static inline bool is_primary_key(unsigned int column) { \
537 : : return ( BOOST_PP_SEQ_FOR_EACH_I(__WSPR_DB_ROW_IS_PRIMARY_KEY_CONDITION, column, key_sequence) ); \
538 : : } \
539 : : typedef std::tuple<BOOST_PP_REPEAT(BOOST_PP_SEQ_SIZE(key_sequence), __WSPR_DB_ROW_CONST_UINT, _)> primary_key_columns_type; \
540 : : static inline primary_key_columns_type primary_key_columns() { \
541 : : return primary_key_columns_type(BOOST_PP_SEQ_FOR_EACH_I(__WSPR_DB_ROW_PRIMARY_KEY_INDEX, _, key_sequence)); \
542 : : } \
543 : : __WISP_STRUCT(0, name, member_sequence) \
544 : : name(const NS_SSRC_WSPR_DATABASE::ResultSet & result) : \
545 : : BOOST_PP_SEQ_FOR_EACH_I(__WSPR_DB_INIT_RESULT_SET, result, member_sequence) { } \
546 : : template<class Binder> \
547 : : void bind_row(Binder & binder) const SSRC_DECL_THROW(NS_SSRC_WSPR_DATABASE::DatabaseException) { \
548 : : binder.bindp(BOOST_PP_SEQ_FOR_EACH_I(__WSPR_DB_BIND_ROW, _, member_sequence)); \
549 : : } \
550 : : template<class Loader, const unsigned int offset = 0> \
551 : : void load_row(const NS_SSRC_WSPR_DATABASE::ResultSet & result, \
552 : : Loader & loader) \
553 : : SSRC_DECL_THROW(NS_SSRC_WSPR_DATABASE::DatabaseException) \
554 : : { \
555 : : loader.template loadp<offset>(result, BOOST_PP_SEQ_FOR_EACH_I(__WSPR_DB_LOAD_ROW, _, member_sequence)); \
556 : : } \
557 : : template<unsigned int i> struct Element; \
558 : : template<unsigned int i> struct Key; \
559 : : template<unsigned int i> inline \
560 : : const typename name::template Element<i>::type & get() const; \
561 : : template<unsigned int i> inline static std::string column_name(); \
562 : : template<unsigned int i> inline static bool is_primary_key() { \
563 : : return false; \
564 : : } \
565 : : typedef std::tuple<BOOST_PP_SEQ_FOR_EACH_I(__WSPR_DB_ROW_PRIMARY_KEY_ELEMENT_TYPES, member_sequence, key_sequence)> primary_key_tuple_type; \
566 : : typedef std::tuple<BOOST_PP_SEQ_FOR_EACH_I(__WSPR_DB_ROW_PRIMARY_KEY_ELEMENT_REF_TYPES, member_sequence, key_sequence)> primary_key_tie_type; \
567 : : typedef __WSPR_DB_ROW_PRIMARY_KEY_TYPE(member_sequence, key_sequence) primary_key_type; \
568 : : typedef __WSPR_DB_ROW_PRIMARY_KEY_REF_TYPE(member_sequence, key_sequence) primary_key_ref_type; \
569 : : const primary_key_tie_type primary_key_tie_value() const { \
570 : : return primary_key_tie_type(BOOST_PP_SEQ_FOR_EACH_I(__WSPR_DB_ROW_PRIMARY_KEY_ELEMENTS, member_sequence, key_sequence)); \
571 : : } \
572 : : const primary_key_ref_type primary_key_value() const { \
573 : : return BOOST_PP_IIF(BOOST_PP_EQUAL(1, BOOST_PP_SEQ_SIZE(key_sequence)), BOOST_PP_TUPLE_ELEM(2, 1, BOOST_PP_SEQ_ELEM(BOOST_PP_SEQ_ELEM(0, key_sequence), member_sequence)), primary_key_tie_value()); \
574 : : } \
575 : : template<typename Binder, typename KeyType> \
576 : : static void bind_primary_key(Binder & binder, const KeyType & key) SSRC_DECL_THROW(NS_SSRC_WSPR_DATABASE::DatabaseException) { \
577 : : BOOST_PP_IIF(BOOST_PP_EQUAL(1, BOOST_PP_SEQ_SIZE(key_sequence)), binder.bind(1, key), binder.bindp(BOOST_PP_REPEAT(BOOST_PP_SEQ_SIZE(key_sequence), __WSPR_DB_ROW_PRIMARY_KEY_BIND_PARAM, key))); \
578 : : } \
579 : : template<typename Binder, typename KeyType> \
580 : : static void bind_primary_key(Binder & binder, const KeyType & key, const unsigned int offset) SSRC_DECL_THROW(NS_SSRC_WSPR_DATABASE::DatabaseException) { \
581 : : BOOST_PP_IIF(BOOST_PP_EQUAL(1, BOOST_PP_SEQ_SIZE(key_sequence)), binder.bind(offset + 1, key), binder BOOST_PP_REPEAT(BOOST_PP_SEQ_SIZE(key_sequence), __WSPR_DB_ROW_PRIMARY_KEY_BIND_PARAM_OFFSET, key)); \
582 : : } \
583 : : template<typename Binder> \
584 : : void bind_primary_key(Binder & binder) const SSRC_DECL_THROW(NS_SSRC_WSPR_DATABASE::DatabaseException) { \
585 : : binder.bindp(BOOST_PP_SEQ_FOR_EACH_I(__WSPR_DB_ROW_PRIMARY_KEY_ELEMENTS, member_sequence, key_sequence)); \
586 : : } \
587 : : }; \
588 : : BOOST_PP_SEQ_FOR_EACH_I(__WSPR_DB_ROW_KEY, name, key_sequence) \
589 : : BOOST_PP_SEQ_FOR_EACH_I(__WSPR_DB_ROW_ELEMENT, name, member_sequence) \
590 : : BOOST_PP_SEQ_FOR_EACH(__WSPR_DB_ROW_IS_PRIMARY_KEY, name, key_sequence)
591 : :
592 : : #define WSPR_DB_ROW_WITH_KEY(name, member_sequence, key_sequence) \
593 : : __WSPR_DB_ROW_WITH_KEY(name, member_sequence, key_sequence)
594 : :
595 : : #define __WSPR_DB_ROW_MEMBER_INDEX_SEQ(r, data, i, arg) (i)
596 : :
597 : : #define __WSPR_DB_ROW_ALL_KEYS_SEQ(member_sequence) \
598 : : BOOST_PP_SEQ_FOR_EACH_I(__WSPR_DB_ROW_MEMBER_INDEX_SEQ, _, member_sequence)
599 : :
600 : : #define WSPR_DB_ROW(name, member_sequence) \
601 : : __WSPR_DB_ROW_WITH_KEY(name, member_sequence, __WSPR_DB_ROW_ALL_KEYS_SEQ(member_sequence))
602 : :
603 : : __END_NS_SSRC_WSPR_DATABASE
604 : :
605 : : #endif
|