Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2025-06-17 01:30:03

0001 #ifndef CondCore_ConditionDatabase_DbCore_h
0002 #define CondCore_ConditionDatabase_DbCore_h
0003 //
0004 // Package:     CondDB
0005 // Class  :     DbCore
0006 //
0007 /**\class DbCore DbCore.h CondCore/CondDB/interface/DbCore.h
0008    Description: an interface wrapper for CORAL.  
0009 */
0010 //
0011 // Author:      Miguel Ojeda, Giacomo Govi
0012 // Created:     May 2013
0013 //
0014 //
0015 
0016 #include "CondCore/CondDB/interface/Exception.h"
0017 #include "CondCore/CondDB/interface/Binary.h"
0018 #include "CondCore/CondDB/interface/Time.h"
0019 #include "CondCore/CondDB/interface/Types.h"
0020 // coral includes
0021 #include "CoralBase/AttributeList.h"
0022 #include "CoralBase/Attribute.h"
0023 #include "CoralBase/AttributeSpecification.h"
0024 #include "CoralBase/Blob.h"
0025 #include "CoralBase/TimeStamp.h"
0026 #include "RelationalAccess/ICursor.h"
0027 #include "RelationalAccess/ISchema.h"
0028 #include "RelationalAccess/ISessionProxy.h"
0029 #include "RelationalAccess/IQuery.h"
0030 #include "RelationalAccess/TableDescription.h"
0031 #include "RelationalAccess/ITable.h"
0032 #include "RelationalAccess/IColumn.h"
0033 #include "RelationalAccess/ITableDataEditor.h"
0034 #include "RelationalAccess/IBulkOperation.h"
0035 #include "RelationalAccess/SchemaException.h"
0036 //
0037 #include <tuple>
0038 #include <cstring>
0039 #include <set>
0040 #include <map>
0041 #include <memory>
0042 #include <string_view>
0043 
0044 //
0045 #include <boost/date_time/posix_time/posix_time.hpp>
0046 
0047 // macros for the schema definition
0048 
0049 namespace condcore_detail {
0050   consteval int string_size(char const* iSize) { return std::string_view(iSize).size(); }
0051 
0052   template <int N, int M>
0053   consteval std::array<char, N + M + 2> makeFullName(const char* n, const char* m) {
0054     if (std::string_view(n).size() != N) {
0055       throw "makeFullName first argument incorrect size";
0056     }
0057     if (std::string_view(m).size() != M) {
0058       throw "makeFullName second argument incorrect size";
0059     }
0060     std::array<char, N + M + 2> ret = {};
0061     for (int i = 0; i < N; ++i) {
0062       ret[i] = n[i];
0063     }
0064     ret[N] = '.';
0065     for (int i = 0; i < M; ++i) {
0066       ret[i + N + 1] = m[i];
0067     }
0068     return ret;
0069   }
0070 
0071   consteval void test_makeFullName() {
0072     constexpr auto v = makeFullName<2, 3>("ab", "cde");
0073     static_assert(v.size() == 2 + 3 + 1 + 1);
0074     static_assert('a' == v[0]);
0075     static_assert('b' == v[1]);
0076     static_assert('.' == v[2]);
0077     static_assert('c' == v[3]);
0078     static_assert('d' == v[4]);
0079     static_assert('e' == v[5]);
0080     static_assert(0 == v[6]);
0081   }
0082 
0083   template <int N>
0084   consteval std::array<char, N + 5 + 1> addMin(std::string_view n) {
0085     if (n.size() != N) {
0086       throw "addMin argument wrong size";
0087     }
0088     std::array<char, N + 5 + 1> ret = {};
0089     ret[0] = 'M';
0090     ret[1] = 'I';
0091     ret[2] = 'N';
0092     ret[3] = '(';
0093     for (int i = 0; i < N; ++i) {
0094       ret[4 + i] = n[i];
0095     }
0096     ret[N + 4] = ')';
0097     return ret;
0098   }
0099 
0100   consteval void test_addMin() {
0101     constexpr std::string_view foo("Foo");
0102     constexpr auto addMin_ = addMin<3>(foo);
0103     static_assert(addMin_.size() == 9);
0104     static_assert(addMin_[0] == 'M');
0105     static_assert(addMin_[1] == 'I');
0106     static_assert(addMin_[2] == 'N');
0107     static_assert(addMin_[3] == '(');
0108     static_assert(addMin_[4] == 'F');
0109     static_assert(addMin_[5] == 'o');
0110     static_assert(addMin_[6] == 'o');
0111     static_assert(addMin_[7] == ')');
0112     static_assert(addMin_[8] == 0);
0113   }
0114 
0115   template <int N>
0116   consteval std::array<char, N + 5 + 1> addMax(std::string_view n) {
0117     if (n.size() != N) {
0118       throw "addMax argument wrong size";
0119     }
0120     std::array<char, N + 5 + 1> ret = {};
0121     ret[0] = 'M';
0122     ret[1] = 'A';
0123     ret[2] = 'X';
0124     ret[3] = '(';
0125     for (int i = 0; i < N; ++i) {
0126       ret[4 + i] = n[i];
0127     }
0128     ret[N + 4] = ')';
0129     return ret;
0130   }
0131 
0132   consteval void test_addMax() {
0133     constexpr std::string_view foo("Foo");
0134     constexpr auto addMin_ = addMax<3>(foo);
0135     static_assert(addMin_.size() == 9);
0136     static_assert(addMin_[0] == 'M');
0137     static_assert(addMin_[1] == 'A');
0138     static_assert(addMin_[2] == 'X');
0139     static_assert(addMin_[3] == '(');
0140     static_assert(addMin_[4] == 'F');
0141     static_assert(addMin_[5] == 'o');
0142     static_assert(addMin_[6] == 'o');
0143     static_assert(addMin_[7] == ')');
0144     static_assert(addMin_[8] == 0);
0145   }
0146 
0147 }  // namespace condcore_detail
0148 
0149 // table definition
0150 #define conddb_table(NAME)                      \
0151   namespace NAME {                              \
0152     static constexpr char const* tname = #NAME; \
0153   }                                             \
0154   namespace NAME
0155 
0156 // implementation for the column definition:
0157 
0158 // case with 3 params
0159 #define FIXSIZE_COLUMN(NAME, TYPE, SIZE)                                                                              \
0160   struct NAME {                                                                                                       \
0161     static constexpr char const* name = #NAME;                                                                        \
0162     typedef TYPE type;                                                                                                \
0163     static constexpr size_t size = SIZE;                                                                              \
0164     static constexpr std::string_view tableName() { return std::string_view(tname); }                                 \
0165     static constexpr auto fullyQualifiedName_ =                                                                       \
0166         condcore_detail::makeFullName<condcore_detail::string_size(tname), condcore_detail::string_size(name)>(tname, \
0167                                                                                                                name); \
0168     static constexpr std::string_view fullyQualifiedName() { return std::string_view(fullyQualifiedName_.data()); }   \
0169   };
0170 
0171 // case with 2 params
0172 #define VARSIZE_COLUMN(NAME, TYPE) FIXSIZE_COLUMN(NAME, TYPE, 0)
0173 
0174 // trick to select the case
0175 #define GET_4TH_ARG(arg1, arg2, arg3, arg4, ...) arg4
0176 #define WRONG_PAR_NUMBER_ERROR(...) static_assert(false, "\"column\" macro accepts exactly 2 or 3 parameters")
0177 #define SELECT_COLUMN_MACRO(...) GET_4TH_ARG(__VA_ARGS__, FIXSIZE_COLUMN, VARSIZE_COLUMN, WRONG_PAR_NUMBER_ERROR)
0178 
0179 // the final column definition macro
0180 #define conddb_column(...) SELECT_COLUMN_MACRO(__VA_ARGS__)(__VA_ARGS__)
0181 
0182 namespace cond {
0183 
0184   namespace persistency {
0185 
0186     // helper function to asses the equality of the underlying types, regardless if they are references and their constness
0187     template <typename T, typename P>
0188     inline void static_assert_is_same_decayed() {
0189       static_assert(std::is_same<typename std::decay<T>::type, typename std::decay<P>::type>::value,
0190                     "Parameter types don't match with the RowBuffer types");
0191     };
0192 
0193     // functions ( specilized for specific types ) for adding data in AttributeList buffers
0194     template <typename T>
0195     inline void f_add_attribute(coral::AttributeList& data,
0196                                 const std::string& attributeName,
0197                                 const T& param,
0198                                 bool init = true) {
0199       if (init)
0200         data.extend<T>(attributeName);
0201       data[attributeName].data<T>() = param;
0202     }
0203 
0204     template <>
0205     inline void f_add_attribute(coral::AttributeList& data,
0206                                 const std::string& attributeName,
0207                                 const cond::Binary& param,
0208                                 bool init) {
0209       if (init)
0210         data.extend<coral::Blob>(attributeName);
0211       data[attributeName].bind(param.get());
0212     }
0213 
0214     template <>
0215     inline void f_add_attribute(coral::AttributeList& data,
0216                                 const std::string& attributeName,
0217                                 const boost::posix_time::ptime& param,
0218                                 bool init) {
0219       if (init)
0220         data.extend<coral::TimeStamp>(attributeName);
0221       data[attributeName].data<coral::TimeStamp>() = coral::TimeStamp(param);
0222     }
0223 
0224     template <>
0225     inline void f_add_attribute(coral::AttributeList& data,
0226                                 const std::string& attributeName,
0227                                 const cond::TimeType& param,
0228                                 bool init) {
0229       if (init)
0230         data.extend<std::string>(attributeName);
0231       data[attributeName].data<std::string>() = cond::time::timeTypeName(param);
0232     }
0233 
0234     template <>
0235     inline void f_add_attribute(coral::AttributeList& data,
0236                                 const std::string& attributeName,
0237                                 const cond::SynchronizationType& param,
0238                                 bool init) {
0239       if (init)
0240         data.extend<std::string>(attributeName);
0241       data[attributeName].data<std::string>() = synchronizationTypeNames(param);
0242     }
0243 
0244     // function for adding into an AttributeList buffer data for a specified column. Performs type checking.
0245     template <typename Column, typename P>
0246     inline void f_add_column_data(coral::AttributeList& data, const P& param, bool init = true) {
0247       static_assert_is_same_decayed<typename Column::type, P>();
0248       f_add_attribute(data, Column::name, param, init);
0249     }
0250 
0251     // function for adding into an AttributeList buffer data for a specified condition. Performs type checking.
0252     template <typename Column, typename P>
0253     inline void f_add_condition_data(coral::AttributeList& data,
0254                                      std::string& whereClause,
0255                                      const P& value,
0256                                      const std::string condition = "=") {
0257       static_assert_is_same_decayed<typename Column::type, P>();
0258       std::stringstream varId;
0259       unsigned int id = data.size();
0260       varId << Column::name << "_" << id;
0261       if (!whereClause.empty())
0262         whereClause += " AND ";
0263       whereClause += std::string(Column::fullyQualifiedName()) + " " + condition + " :" + varId.str() + " ";
0264       //bool init = (id == 0);
0265       f_add_attribute(data, varId.str(), value);
0266     }
0267 
0268     // function for appending conditions to a where clause
0269     template <typename C1, typename C2>
0270     inline void f_add_condition(std::string& whereClause, const std::string condition = "=") {
0271       if (!whereClause.empty())
0272         whereClause += " AND ";
0273       whereClause += C1::fullyQualifiedName() + " " + condition + " " + C2::fullyQualifiedName() + " ";
0274     }
0275 
0276     // buffer for data to be inserted into a table
0277     // maybe better only leave the template set methods ( no class template )
0278     template <typename... Columns>
0279     class RowBuffer {
0280     private:
0281       template <typename Params, int n, typename T1, typename... Ts>
0282       void _set(const Params& params, bool init = true) {
0283         f_add_column_data<T1>(m_data, std::get<n>(params), init);
0284         _set<Params, n + 1, Ts...>(params, init);
0285       }
0286 
0287       template <typename Params, int n>
0288       void _set(const Params&, bool) {}
0289 
0290     public:
0291       RowBuffer() : m_data() {}
0292 
0293       template <typename P>
0294       explicit RowBuffer(const P& params) : m_data() {
0295         _set<P, 0, Columns...>(params);
0296       }
0297 
0298       template <typename P>
0299       void set(const P& params) {
0300         bool init = (m_data.size() == 0);
0301         // if RowBuffer becames a single type, we need to run either the equivalent of _RowBuffer ( having addAttribute ) when m_data.size()=0, or _set in all other cases
0302         _set<P, 0, Columns...>(params, init);
0303       }
0304 
0305       const coral::AttributeList& get() const { return m_data; }
0306 
0307     protected:
0308       coral::AttributeList m_data;
0309     };
0310 
0311     template <typename... Columns>
0312     class ConditionBuffer {
0313     private:
0314       template <typename Params, int n, typename T1, typename... Ts>
0315       void _set(const Params& params) {
0316         f_add_condition_data<T1>(m_data, m_clause, std::get<n>(params));
0317         _set<Params, n + 1, Ts...>(params);
0318       }
0319 
0320       template <typename Params, int n>
0321       void _set(const Params&) {}
0322 
0323     public:
0324       ConditionBuffer() : m_data(), m_clause() {}
0325 
0326       template <typename P>
0327       void set(const P& params) {
0328         // if RowBuffer becames a single type, we need to run either the equivalent of _RowBuffer ( having addAttribute ) when m_data.size()=0, or _set in all other cases
0329         _set<P, 0, Columns...>(params);
0330       }
0331 
0332       void addStaticCondition(const std::string& condition) {
0333         if (!m_clause.empty()) {
0334           m_clause += " AND ";
0335         }
0336         m_clause += condition;
0337       }
0338 
0339       const coral::AttributeList& get() const { return m_data; }
0340 
0341       const std::string& getClause() const { return m_clause; }
0342 
0343     protected:
0344       coral::AttributeList m_data;
0345       std::string m_clause;
0346     };
0347 
0348     template <typename T>
0349     struct AttributeTypeName {
0350       std::string operator()() { return coral::AttributeSpecification::typeNameForType<T>(); }
0351     };
0352     template <>
0353     struct AttributeTypeName<cond::Binary> {
0354       std::string operator()() { return coral::AttributeSpecification::typeNameForType<coral::Blob>(); }
0355     };
0356     template <>
0357     struct AttributeTypeName<boost::posix_time::ptime> {
0358       std::string operator()() { return coral::AttributeSpecification::typeNameForType<coral::TimeStamp>(); }
0359     };
0360     template <>
0361     struct AttributeTypeName<cond::TimeType> {
0362       std::string operator()() { return coral::AttributeSpecification::typeNameForType<std::string>(); }
0363     };
0364     template <>
0365     struct AttributeTypeName<cond::SynchronizationType> {
0366       std::string operator()() { return coral::AttributeSpecification::typeNameForType<std::string>(); }
0367     };
0368 
0369     template <typename T>
0370     void f_add_column_description(coral::TableDescription& table,
0371                                   const std::string& columnName,
0372                                   size_t size = 0,
0373                                   bool notNull = true) {
0374       table.insertColumn(columnName, AttributeTypeName<T>()(), size);
0375       if (notNull)
0376         table.setNotNullConstraint(columnName);
0377     }
0378 
0379     template <typename T, typename Arg1>
0380     constexpr bool is_same_any() {
0381       return std::is_same<T, Arg1>::value;
0382     };
0383 
0384     template <typename T, typename Arg1, typename Arg2, typename... Args>
0385     constexpr bool is_same_any() {
0386       return is_same_any<T, Arg1>() || is_same_any<T, Arg2, Args...>();
0387     };
0388 
0389     template <typename... Types>
0390     class TableDescription {
0391     private:
0392       template <int n>
0393       void addColumn(coral::TableDescription&) {}
0394 
0395       template <int n, typename Arg1, typename... Args>
0396       void addColumn(coral::TableDescription& tableDescription) {
0397         std::string columnName(Arg1::name);
0398         f_add_column_description<typename Arg1::type>(m_description, columnName, Arg1::size);
0399         addColumn<n + 1, Args...>(m_description);
0400       }
0401 
0402       template <int, typename Col1, typename... Cols>
0403       void checkColumns() {
0404         static_assert(is_same_any<Col1, Types...>(), "Specified Column has not been found in the table.");
0405         checkColumns<0, Cols...>();
0406       }
0407 
0408       template <int>
0409       void checkColumns() {}
0410 
0411     public:
0412       explicit TableDescription(const char* name) : m_description("ConditionDatabase") {
0413         m_description.setName(name);
0414         addColumn<0, Types...>(m_description);
0415       }
0416 
0417       // for all these methods, we should check that the specified columns belongs to the table columns...
0418       template <typename... ColumnTypes>
0419       void setPrimaryKey() {
0420         checkColumns<0, ColumnTypes...>();
0421         m_description.setPrimaryKey(makeList<ColumnTypes...>());
0422       }
0423 
0424       template <typename... ColumnTypes>
0425       void setUniqueConstraint(const std::string& name) {
0426         checkColumns<0, ColumnTypes...>();
0427         m_description.setUniqueConstraint(makeList<ColumnTypes...>(), name);
0428       }
0429 
0430       template <typename... ColumnTypes>
0431       void createIndex(const std::string& name) {
0432         checkColumns<0, ColumnTypes...>();
0433         m_description.createIndex(name, makeList<ColumnTypes...>());
0434       }
0435 
0436       template <typename Column, typename ReferencedColumn>
0437       void setForeignKey(const std::string& name) {
0438         checkColumns<0, Column>();
0439         m_description.createForeignKey(
0440             name, Column::name, std::string(ReferencedColumn::tableName()), ReferencedColumn::name);
0441       }
0442 
0443       const coral::TableDescription& get() { return m_description; }
0444 
0445     private:
0446       template <int n>
0447       void _makeList(std::vector<std::string>&) {}
0448 
0449       template <int n, typename Arg1, typename... Args>
0450       void _makeList(std::vector<std::string>& columnNames) {
0451         columnNames.push_back(Arg1::name);
0452         _makeList<n + 1, Args...>(columnNames);
0453       }
0454 
0455       template <typename... ColumnTypes>
0456       std::vector<std::string> makeList() {
0457         std::vector<std::string> columnList;
0458         _makeList<0, ColumnTypes...>(columnList);
0459         return columnList;
0460       }
0461 
0462     private:
0463       coral::TableDescription m_description;
0464     };
0465 
0466     template <typename T>
0467     struct GetFromRow {
0468       T operator()(const coral::AttributeList& row, const std::string& fullyQualifiedName) {
0469         return row[fullyQualifiedName].data<T>();
0470       }
0471     };
0472     template <>
0473     struct GetFromRow<cond::Binary> {
0474       cond::Binary operator()(const coral::AttributeList& row, const std::string& fullyQualifiedName) {
0475         return cond::Binary(row[fullyQualifiedName].data<coral::Blob>());
0476       }
0477     };
0478     template <>
0479     struct GetFromRow<boost::posix_time::ptime> {
0480       boost::posix_time::ptime operator()(const coral::AttributeList& row, const std::string& fullyQualifiedName) {
0481         return row[fullyQualifiedName].data<coral::TimeStamp>().time();
0482       }
0483     };
0484     template <>
0485     struct GetFromRow<cond::TimeType> {
0486       cond::TimeType operator()(const coral::AttributeList& row, const std::string& fullyQualifiedName) {
0487         return cond::time::timeTypeFromName(row[fullyQualifiedName].data<std::string>());
0488       }
0489     };
0490     template <>
0491     struct GetFromRow<cond::SynchronizationType> {
0492       cond::SynchronizationType operator()(const coral::AttributeList& row, const std::string& fullyQualifiedName) {
0493         return cond::synchronizationTypeFromName(row[fullyQualifiedName].data<std::string>());
0494       }
0495     };
0496     template <std::size_t n>
0497     struct GetFromRow<std::array<char, n>> {
0498       std::string operator()(const coral::AttributeList& row, const std::string& fullyQualifiedName) {
0499         std::string val = row[fullyQualifiedName].data<std::string>();
0500         if (val.size() != n)
0501           throwException("Retrieved string size does not match with the expected string size.", "getFromRow");
0502         std::array<char, n> ret;
0503         ::memcpy(ret.data(), val.c_str(), n);
0504         return ret;
0505       }
0506     };
0507 
0508     template <typename... Types>
0509     class Query;
0510 
0511     template <typename... Types>
0512     class QueryIterator {
0513     public:
0514       // C++17 compliant iterator definition
0515       using iterator_category = std::input_iterator_tag;
0516       using value_type = std::tuple<Types...>;
0517       using difference_type = void;  // Not used
0518       using pointer = void;          // Not used
0519       using reference = void;        // Not used
0520 
0521       QueryIterator() {}
0522 
0523       QueryIterator(const QueryIterator& rhs) : m_query(rhs.m_query), m_currentRow(rhs.m_currentRow) {}
0524 
0525       explicit QueryIterator(Query<Types...>* parent) : m_query(parent) {}
0526 
0527       QueryIterator& operator=(const QueryIterator& rhs) {
0528         m_query = rhs.m_query;
0529         m_currentRow = rhs.m_currentRow;
0530         return *this;
0531       }
0532 
0533       template <typename T>
0534       typename T::type get() const {
0535         return GetFromRow<typename T::type>()(*m_currentRow, std::string(T::fullyQualifiedName()));
0536       }
0537 
0538       auto operator*() -> decltype(std::make_tuple(this->get<Types>()...)) { return std::make_tuple(get<Types>()...); }
0539 
0540       QueryIterator& operator++() {
0541         m_currentRow = m_query->next() ? &m_query->currentRow() : nullptr;
0542         return *this;
0543       }
0544 
0545       QueryIterator operator++(int) {
0546         QueryIterator tmp(*this);
0547         operator++();
0548         return tmp;
0549       }
0550 
0551       bool operator==(const QueryIterator& rhs) const {
0552         if (rhs.m_query == nullptr && m_query == nullptr)
0553           return true;
0554         return m_query == rhs.m_query && m_currentRow == rhs.m_currentRow;
0555       }
0556       bool operator!=(const QueryIterator& rhs) const { return !operator==(rhs); }
0557 
0558       operator bool() const { return m_currentRow; }
0559 
0560     private:
0561       Query<Types...>* m_query = nullptr;
0562       const coral::AttributeList* m_currentRow = nullptr;
0563     };
0564 
0565     template <typename T>
0566     struct DefineQueryOutput {
0567       static void make(coral::IQuery& query, const std::string& fullyQualifiedName) {
0568         query.addToOutputList(fullyQualifiedName);
0569         query.defineOutputType(fullyQualifiedName, coral::AttributeSpecification::typeNameForType<T>());
0570       }
0571     };
0572     template <>
0573     struct DefineQueryOutput<cond::Binary> {
0574       static void make(coral::IQuery& query, const std::string& fullyQualifiedName) {
0575         query.addToOutputList(fullyQualifiedName);
0576         query.defineOutputType(fullyQualifiedName, coral::AttributeSpecification::typeNameForType<coral::Blob>());
0577       }
0578     };
0579     template <>
0580     struct DefineQueryOutput<boost::posix_time::ptime> {
0581       static void make(coral::IQuery& query, const std::string& fullyQualifiedName) {
0582         query.addToOutputList(fullyQualifiedName);
0583         query.defineOutputType(fullyQualifiedName, coral::AttributeSpecification::typeNameForType<coral::TimeStamp>());
0584       }
0585     };
0586     template <>
0587     struct DefineQueryOutput<cond::TimeType> {
0588       static void make(coral::IQuery& query, const std::string& fullyQualifiedName) {
0589         query.addToOutputList(fullyQualifiedName);
0590         query.defineOutputType(fullyQualifiedName, coral::AttributeSpecification::typeNameForType<std::string>());
0591       }
0592     };
0593     template <>
0594     struct DefineQueryOutput<cond::SynchronizationType> {
0595       static void make(coral::IQuery& query, const std::string& fullyQualifiedName) {
0596         query.addToOutputList(fullyQualifiedName);
0597         query.defineOutputType(fullyQualifiedName, coral::AttributeSpecification::typeNameForType<std::string>());
0598       }
0599     };
0600     template <std::size_t n>
0601     struct DefineQueryOutput<std::array<char, n>> {
0602       static void make(coral::IQuery& query, const std::string& fullyQualifiedName) {
0603         query.addToOutputList(fullyQualifiedName);
0604         query.defineOutputType(fullyQualifiedName, coral::AttributeSpecification::typeNameForType<std::string>());
0605       }
0606     };
0607 
0608     template <typename... Types>
0609     class Query {
0610     public:
0611       Query(const coral::ISchema& schema, bool distinct = false)
0612           : m_coralQuery(schema.newQuery()), m_whereData(), m_whereClause(""), m_tables() {
0613         _Query<0, Types...>();
0614         if (distinct)
0615           m_coralQuery->setDistinct();
0616       }
0617 
0618       ~Query() {}
0619 
0620       template <typename Col>
0621       Query& addTable() {
0622         if (m_tables.find(Col::tableName()) == m_tables.end()) {
0623           std::string const tb{Col::tableName()};
0624           m_coralQuery->addToTableList(std::string(tb));
0625           m_tables.insert(std::move(tb));
0626         }
0627         return *this;
0628       }
0629 
0630       template <int n>
0631       void _Query() {}
0632 
0633       template <int n, typename Arg1, typename... Args>
0634       void _Query() {
0635         addTable<Arg1>();
0636         DefineQueryOutput<typename Arg1::type>::make(*m_coralQuery, std::string(Arg1::fullyQualifiedName()));
0637         _Query<n + 1, Args...>();
0638       }
0639 
0640       template <typename C, typename T>
0641       Query& addCondition(const T& value, const std::string condition = "=") {
0642         addTable<C>();
0643         f_add_condition_data<C>(m_whereData, m_whereClause, value, condition);
0644         return *this;
0645       }
0646 
0647       template <typename C1, typename C2>
0648       Query& addCondition(const std::string condition = "=") {
0649         addTable<C1>();
0650         addTable<C2>();
0651         f_add_condition<C1, C2>(m_whereClause, condition);
0652         return *this;
0653       }
0654 
0655       template <typename C>
0656       Query& addOrderClause(bool ascending = true) {
0657         std::string orderClause(C::fullyQualifiedName());
0658         if (!ascending)
0659           orderClause += " DESC";
0660         m_coralQuery->addToOrderList(orderClause);
0661         return *this;
0662       }
0663 
0664       Query& groupBy(const std::string& expression) {
0665         m_coralQuery->groupBy(expression);
0666         return *this;
0667       }
0668 
0669       Query& setForUpdate() {
0670         m_coralQuery->setForUpdate();
0671         return *this;
0672       }
0673 
0674       Query& limitReturnedRows(size_t nrows) {
0675         m_coralQuery->limitReturnedRows(nrows);
0676         return *this;
0677       }
0678 
0679       bool next() {
0680         if (!m_cursor)
0681           throwException("The query has not been executed.", "Query::currentRow");
0682         bool ret = m_cursor->next();
0683         if (ret)
0684           m_retrievedRows++;
0685         return ret;
0686       }
0687 
0688       const coral::AttributeList& currentRow() const {
0689         if (!m_cursor)
0690           throwException("The query has not been executed.", "Query::currentRow");
0691         return m_cursor->currentRow();
0692       }
0693 
0694       const QueryIterator<Types...> begin() {
0695         m_coralQuery->setCondition(m_whereClause, m_whereData);
0696         m_cursor = &m_coralQuery->execute();
0697         m_retrievedRows = 0;
0698         QueryIterator<Types...> ret(this);
0699         return ++ret;
0700       }
0701 
0702       const QueryIterator<Types...> end() { return QueryIterator<Types...>(this); }
0703 
0704       size_t retrievedRows() const { return m_retrievedRows; }
0705 
0706     private:
0707       std::unique_ptr<coral::IQuery> m_coralQuery;
0708       coral::ICursor* m_cursor = nullptr;
0709       size_t m_retrievedRows = 0;
0710       coral::AttributeList m_whereData;
0711       std::string m_whereClause;
0712       std::set<std::string, std::less<>> m_tables;
0713     };
0714 
0715     class UpdateBuffer {
0716     private:
0717       template <typename Params, int n, typename C1, typename... Cs>
0718       void _set(const Params& params) {
0719         f_add_column_data<C1>(m_data, std::get<n>(params));
0720         if (!m_setClause.empty())
0721           m_setClause += ", ";
0722         m_setClause += std::string(C1::name) + " = :" + std::string(C1::name);
0723         _set<Params, n + 1, Cs...>(params);
0724       }
0725 
0726       template <typename Params, int n>
0727       void _set(const Params&) {}
0728 
0729     public:
0730       UpdateBuffer() : m_data(), m_setClause(""), m_whereClause("") {}
0731 
0732       template <typename... Columns, typename Params>
0733       void setColumnData(const Params& params) {
0734         _set<Params, 0, Columns...>(params);
0735       }
0736 
0737       template <typename Column1, typename Column2>
0738       void setColumnMatch() {
0739         if (!m_setClause.empty())
0740           m_setClause += ", ";
0741         m_setClause += std::string(Column1::name) + " = " + std::string(Column2::name);
0742       }
0743 
0744       template <typename Column, typename P>
0745       void addWhereCondition(const P& param, const std::string condition = "=") {
0746         f_add_condition_data<Column>(m_data, m_whereClause, param, condition);
0747       }
0748 
0749       template <typename Column1, typename Column2>
0750       void addWhereCondition(const std::string condition = "=") {
0751         f_add_condition<Column1, Column2>(m_whereClause, condition);
0752       }
0753 
0754       const coral::AttributeList& get() const { return m_data; }
0755 
0756       const std::string& setClause() const { return m_setClause; }
0757 
0758       const std::string& whereClause() const { return m_whereClause; }
0759 
0760     private:
0761       coral::AttributeList m_data;
0762       std::string m_setClause;
0763       std::string m_whereClause;
0764     };
0765 
0766     class DeleteBuffer {
0767     public:
0768       DeleteBuffer() : m_data(), m_whereClause("") {}
0769 
0770       template <typename Column, typename P>
0771       void addWhereCondition(const P& param, const std::string condition = "=") {
0772         f_add_condition_data<Column>(m_data, m_whereClause, param, condition);
0773       }
0774 
0775       template <typename Column1, typename Column2>
0776       void addWhereCondition(const std::string condition = "=") {
0777         f_add_condition<Column1, Column2>(m_whereClause, condition);
0778       }
0779 
0780       const coral::AttributeList& get() const { return m_data; }
0781 
0782       const std::string& whereClause() const { return m_whereClause; }
0783 
0784     private:
0785       coral::AttributeList m_data;
0786       std::string m_whereClause;
0787     };
0788 
0789     template <typename... Types>
0790     class BulkInserter {
0791     public:
0792       static constexpr size_t cacheSize = 1000;
0793       BulkInserter(coral::ISchema& schema, const char* tableName)
0794           : m_schema(schema), m_tableName(tableName), m_buffer(), m_coralInserter() {
0795         //fix me: maybe with
0796         //m_coralInserter.reset(  schema.tableHandle( std::string(tableName ) ).dataEditor().bulkInsert( m_buffer.get(), cacheSize ) );
0797       }
0798 
0799       template <typename P>
0800       void insert(const P& params) {
0801         m_buffer.set(params);
0802         if (!m_coralInserter.get())
0803           m_coralInserter.reset(m_schema.tableHandle(m_tableName).dataEditor().bulkInsert(m_buffer.get(), cacheSize));
0804         m_coralInserter->processNextIteration();
0805       }
0806 
0807       void flush() {
0808         if (m_coralInserter.get())
0809           m_coralInserter->flush();
0810       }
0811 
0812     private:
0813       // fixme
0814       coral::ISchema& m_schema;
0815       std::string m_tableName;
0816       //
0817       RowBuffer<Types...> m_buffer;
0818       std::unique_ptr<coral::IBulkOperation> m_coralInserter;
0819     };
0820 
0821     template <typename... Types>
0822     class BulkDeleter {
0823     public:
0824       static constexpr size_t cacheSize = 1000;
0825       explicit BulkDeleter(coral::ISchema& schema, const char* tableName)
0826           : m_schema(schema), m_tableName(tableName), m_buffer(), m_coralDeleter() {
0827         //fix me: maybe with
0828         //m_coralInserter.reset(  schema.tableHandle( std::string(tableName ) ).dataEditor().bulkInsert( m_buffer.get(), cacheSize ) );
0829       }
0830 
0831       void addStaticCondition(const std::string& condition) { m_buffer.addStaticCondition(condition); }
0832 
0833       template <typename P>
0834       void erase(const P& params) {
0835         m_buffer.set(params);
0836         if (!m_coralDeleter.get())
0837           m_coralDeleter.reset(m_schema.tableHandle(m_tableName)
0838                                    .dataEditor()
0839                                    .bulkDeleteRows(m_buffer.getClause(), m_buffer.get(), cacheSize));
0840         m_coralDeleter->processNextIteration();
0841       }
0842 
0843       void flush() {
0844         if (m_coralDeleter.get())
0845           m_coralDeleter->flush();
0846       }
0847 
0848     private:
0849       // fixme
0850       coral::ISchema& m_schema;
0851       std::string m_tableName;
0852       //
0853       ConditionBuffer<Types...> m_buffer;
0854       std::unique_ptr<coral::IBulkOperation> m_coralDeleter;
0855     };
0856 
0857     namespace {
0858 
0859       inline bool existsTable(coral::ISchema& schema, const char* tableName) {
0860         return schema.existsTable(std::string(tableName));
0861       }
0862 
0863       inline void createTable(coral::ISchema& schema, const coral::TableDescription& descr) {
0864         schema.createTable(descr);
0865       }
0866 
0867       inline bool insertInTable(coral::ISchema& schema,
0868                                 const char* tableName,
0869                                 const coral::AttributeList& row,
0870                                 bool failOnDuplicate = true) {
0871         bool ret = false;
0872         try {
0873           schema.tableHandle(std::string(tableName)).dataEditor().insertRow(row);
0874           ret = true;
0875         } catch (const coral::DuplicateEntryInUniqueKeyException&) {
0876           if (failOnDuplicate)
0877             throw;
0878         }
0879         return ret;
0880       }
0881 
0882       inline void updateTable(coral::ISchema& schema, const char* tableName, const UpdateBuffer& data) {
0883         schema.tableHandle(std::string(tableName))
0884             .dataEditor()
0885             .updateRows(data.setClause(), data.whereClause(), data.get());
0886       }
0887 
0888       inline void deleteFromTable(coral::ISchema& schema, const char* tableName, const DeleteBuffer& data) {
0889         schema.tableHandle(std::string(tableName)).dataEditor().deleteRows(data.whereClause(), data.get());
0890       }
0891     }  // namespace
0892 
0893   }  // namespace persistency
0894 
0895 }  // namespace cond
0896 
0897 #endif