Web Wispers 1.2.2 C++ Unit Test Coverage
Current view: top level - ssrc/wispers/database - types.h (source / functions) Hit Total Coverage
Test: Web Wispers 1.2.2 C++ Unit Tests Lines: 74 90 82.2 %
Date: 2012-04-09 Functions: 37 42 88.1 %
Branches: 22 68 32.4 %

           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