Refactor log system
[platform/core/security/cert-svc.git] / vcore / src / dpl / db / include / dpl / db / orm.h
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
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  *        http://www.apache.org/licenses/LICENSE-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  * @file        orm.h
18  * @author      Bartosz Janiak (b.janiak@samsung.com)
19  * @version     1.0
20  * @brief       DPL-ORM: Object-relational mapping for sqlite database, written on top of DPL.
21  */
22
23 #include <cstdlib>
24 #include <cstdio>
25 #include <string>
26 #include <typeinfo>
27 #include <utility>
28 #include <set>
29 #include <list>
30 #include <memory>
31 #include <boost/optional.hpp>
32
33 #include <dpl/db/sql_connection.h>
34 #include <dpl/db/orm_interface.h>
35 #include <dpl/string.h>
36 #include <dpl/type_list.h>
37 #include <dpl/assert.h>
38 #include <dpl/foreach.h>
39
40 #ifndef DPL_ORM_H
41 #define DPL_ORM_H
42
43 namespace VcoreDPL {
44 namespace DB {
45 namespace ORM {
46
47 //TODO move to type utils
48 #define DPL_CHECK_TYPE_INSTANTIABILITY(type) \
49     { \
50         type _ignored_; \
51         (void)_ignored_; \
52     }
53
54 #define DECLARE_COLUMN_TYPE_LIST() typedef VcoreDPL::TypeListDecl<
55 #define SELECTED_COLUMN(table_name, column_name) table_name::column_name,
56 #define DECLARE_COLUMN_TYPE_LIST_END(name) VcoreDPL::TypeListGuard>::Type name;
57
58 typedef size_t ColumnIndex;
59 typedef size_t ArgumentIndex;
60 typedef boost::optional<VcoreDPL::String> OptionalString;
61 typedef boost::optional<int> OptionalInteger;
62 typedef VcoreDPL::DB::SqlConnection::DataCommand DataCommand;
63
64 namespace RelationTypes {
65     extern const char Equal[];
66     extern const char LessThan[];
67     extern const char And[];
68     extern const char Or[];
69     extern const char Is[];
70     extern const char In[];
71     //TODO define more relation types
72 }
73
74 namespace DataCommandUtils {
75     //TODO move to VcoreDPL::DataCommand?
76     void BindArgument(DataCommand *command, ArgumentIndex index, int argument);
77     void BindArgument(DataCommand *command, ArgumentIndex index, const OptionalInteger& argument);
78     void BindArgument(DataCommand *command, ArgumentIndex index, const VcoreDPL::String& argument);
79     void BindArgument(DataCommand *command, ArgumentIndex index, const OptionalString& argument);
80 }
81 class __attribute__ ((visibility("hidden"))) Expression {
82 public:
83     virtual ~Expression() {}
84     virtual std::string GetString() const = 0;
85     virtual ArgumentIndex BindTo(DataCommand *command, ArgumentIndex index) = 0;
86 };
87
88 typedef std::shared_ptr<Expression> ExpressionPtr;
89
90 namespace OrderingUtils {
91
92 template<typename CompoundType> inline std::string OrderByInternal()
93 {
94     std::string order = OrderByInternal<typename CompoundType::Tail>();
95     if(!order.empty()) return CompoundType::Head::GetString() + ", " + order;
96     else return CompoundType::Head::GetString();
97 }
98
99 template<> inline std::string OrderByInternal<TypeListGuard>()
100 {
101     return std::string();
102 }
103
104 }
105
106 template<typename ColumnType>
107 class __attribute__ ((visibility("hidden"))) OrderingExpression {
108 protected:
109     static std::string GetSchemaAndName()
110     {
111         std::string statement;
112         statement += ColumnType::GetTableName();
113         statement += ".";
114         statement += ColumnType::GetColumnName();
115         statement += " ";
116         return statement;
117     }
118 public:
119     virtual ~OrderingExpression() {}
120 };
121
122 template<const char* Operator, typename LeftExpression, typename RightExpression>
123 class __attribute__ ((visibility("hidden"))) BinaryExpression : public Expression {
124 protected:
125     LeftExpression  m_leftExpression;
126     RightExpression m_rightExpression;
127     bool            m_outerParenthesis;
128 public:
129     BinaryExpression(const LeftExpression& leftExpression, const RightExpression& rightExpression, bool outerParenthesis = true) :
130         m_leftExpression(leftExpression),
131         m_rightExpression(rightExpression),
132         m_outerParenthesis(outerParenthesis)
133     {}
134
135     virtual std::string GetString() const
136     {
137         return  (m_outerParenthesis ? "( " : " " ) +
138                  m_leftExpression.GetString() + " " + Operator + " " + m_rightExpression.GetString() +
139                 (m_outerParenthesis ? " )" : " " ) ;
140     }
141
142     virtual ArgumentIndex BindTo(DataCommand *command, ArgumentIndex index)
143     {
144         index = m_leftExpression.BindTo(command, index);
145         return  m_rightExpression.BindTo(command, index);
146     }
147
148     template<typename TableDefinition>
149     struct ValidForTable {
150         typedef std::pair<typename LeftExpression ::template ValidForTable<TableDefinition>::Yes ,
151                           typename RightExpression::template ValidForTable<TableDefinition>::Yes >
152                 Yes;
153     };
154 };
155
156 template<typename LeftExpression, typename RightExpression>
157 BinaryExpression<RelationTypes::And, LeftExpression, RightExpression>
158     And(const LeftExpression& leftExpression, const RightExpression& rightExpression)
159 {
160     return BinaryExpression<RelationTypes::And, LeftExpression, RightExpression>
161             (leftExpression, rightExpression);
162 }
163
164 template<typename LeftExpression, typename RightExpression>
165 BinaryExpression<RelationTypes::Or, LeftExpression, RightExpression>
166     Or(const LeftExpression& leftExpression, const RightExpression& rightExpression)
167 {
168     return BinaryExpression<RelationTypes::Or, LeftExpression, RightExpression>
169             (leftExpression, rightExpression);
170 }
171
172 template<typename ArgumentType>
173 class __attribute__ ((visibility("hidden"))) ExpressionWithArgument : public Expression {
174 protected:
175     ArgumentType argument;
176
177 public:
178     explicit ExpressionWithArgument(const ArgumentType& _argument) : argument(_argument) {}
179
180     virtual ArgumentIndex BindTo(DataCommand *command, ArgumentIndex index)
181     {
182         DataCommandUtils::BindArgument(command, index, argument);
183         return index + 1;
184     }
185 };
186
187 template<typename ColumnData, const char* Relation>
188 class __attribute__ ((visibility("hidden"))) Compare : public ExpressionWithArgument<typename ColumnData::ColumnType> {
189 public:
190     explicit Compare(typename ColumnData::ColumnType column) :
191         ExpressionWithArgument<typename ColumnData::ColumnType>(column)
192     {}
193
194     virtual std::string GetString() const
195     {
196         std::string statement;
197         statement += ColumnData::GetTableName();
198         statement += ".";
199         statement += ColumnData::GetColumnName();
200         statement += " ";
201         statement += Relation;
202         statement += " ?";
203         return statement;
204     }
205
206     template<typename TableDefinition>
207     struct ValidForTable {
208         typedef typename TableDefinition::ColumnList::template Contains<ColumnData> Yes;
209     };
210 };
211 #define ORM_DEFINE_COMPARE_EXPRESSION(name, relationType)                      \
212     template<typename ColumnData>                                              \
213     class __attribute__ ((visibility("hidden"))) name : public Compare<ColumnData, RelationTypes::relationType> {     \
214     public:                                                                    \
215         name(typename ColumnData::ColumnType column) :                         \
216             Compare<ColumnData, RelationTypes::relationType>(column)           \
217         {}                                                                     \
218     };
219
220 ORM_DEFINE_COMPARE_EXPRESSION(Equals, Equal)
221 ORM_DEFINE_COMPARE_EXPRESSION(Is, Is)
222
223 #define ORM_DEFINE_ORDERING_EXPRESSION(name, value)                                     \
224     template<typename ColumnType>                                                       \
225     class __attribute__ ((visibility("hidden"))) name                                   \
226         : OrderingExpression<ColumnType> {                                              \
227     public:                                                                             \
228         static std::string GetString()                                                  \
229         {                                                                               \
230             std::string statement = OrderingExpression<ColumnType>::GetSchemaAndName(); \
231             statement += value;                                                         \
232             return statement;                                                           \
233         }                                                                               \
234     };
235
236 ORM_DEFINE_ORDERING_EXPRESSION(OrderingAscending, "ASC")
237 ORM_DEFINE_ORDERING_EXPRESSION(OrderingDescending, "DESC")
238
239 template<typename ColumnData1, typename ColumnData2>
240 class __attribute__ ((visibility("hidden"))) CompareBinaryColumn {
241 private:
242     std::string m_relation;
243 public:
244     CompareBinaryColumn(const char* Relation) :
245       m_relation(Relation)
246     {}
247
248     virtual ~CompareBinaryColumn() {}
249
250     virtual std::string GetString() const
251     {
252         std::string statement;
253         statement += ColumnData1::GetTableName();
254         statement += ".";
255         statement += ColumnData1::GetColumnName();
256         statement += " ";
257         statement += m_relation;
258         statement += " ";
259         statement += ColumnData2::GetTableName();
260         statement += ".";
261         statement += ColumnData2::GetColumnName();
262
263         return statement;
264     }
265 };
266
267 template<typename ColumnData1, typename ColumnData2>
268 CompareBinaryColumn<ColumnData1, ColumnData2>
269     Equal()
270 {
271     return CompareBinaryColumn<ColumnData1, ColumnData2>(RelationTypes::Equal);
272 }
273
274 template<typename ColumnData, const char* Relation>
275 class __attribute__ ((visibility("hidden"))) NumerousArguments : public Expression {
276 protected:
277     std::set<typename ColumnData::ColumnType> m_argumentList;
278 public:
279     NumerousArguments(const std::set<typename ColumnData::ColumnType>& argumentList) : m_argumentList(argumentList) {}
280
281     virtual std::string GetString() const
282     {
283         std::string statement;
284         statement += ColumnData::GetColumnName();
285         statement += " ";
286         statement += Relation;
287         statement += " ( ";
288
289         int argumentCount = m_argumentList.size();
290         while(argumentCount)
291         {
292             statement += "?";
293             argumentCount--;
294             if (argumentCount)
295             {
296                 statement += ", ";
297             }
298         }
299
300         statement += " )";
301
302         return statement;
303     }
304
305     virtual ArgumentIndex BindTo(DataCommand *command, ArgumentIndex index)
306     {
307         ArgumentIndex argumentIndex = index;
308         FOREACH(argumentIt, m_argumentList)
309         {
310             DataCommandUtils::BindArgument(command, argumentIndex, *argumentIt);
311             argumentIndex++;
312         }
313         return  argumentIndex + 1;
314     }
315
316     template<typename TableDefinition>
317     struct ValidForTable {
318         typedef typename TableDefinition::ColumnList::template Contains<ColumnData> Yes;
319     };
320 };
321
322 #define ORM_DEFINE_COMPARE_EXPRESSION_NUMEROUS_ARGUMENTS(name, relationType)                      \
323     template<typename ColumnData>                                              \
324     class __attribute__ ((visibility("hidden"))) name : public NumerousArguments<ColumnData, RelationTypes::relationType> {     \
325     public:                                                                    \
326         name(std::set<typename ColumnData::ColumnType> column) :                         \
327             NumerousArguments<ColumnData, RelationTypes::relationType>(column)           \
328         {}                                                                     \
329     };
330
331 ORM_DEFINE_COMPARE_EXPRESSION_NUMEROUS_ARGUMENTS(In, In)
332
333 template<typename ColumnType>
334 ColumnType GetColumnFromCommand(ColumnIndex columnIndex, DataCommand *command);
335
336 class __attribute__ ((visibility("hidden"))) CustomColumnBase {
337 public:
338     CustomColumnBase() {}
339     virtual ~CustomColumnBase() {}
340 };
341
342 template<typename ColumnType>
343 class __attribute__ ((visibility("hidden"))) CustomColumn : public CustomColumnBase {
344 private:
345     ColumnType m_columnData;
346
347 public:
348     CustomColumn() {}
349     CustomColumn(ColumnType data)
350     {
351         m_columnData = data;
352     }
353
354     void SetColumnData(ColumnType data)
355     {
356         m_columnData = data;
357     }
358
359     ColumnType GetColumnData() const
360     {
361         return m_columnData;
362     }
363 };
364
365 template<typename ColumnList>
366 class __attribute__ ((visibility("hidden"))) CustomRowUtil {
367 public:
368     static void MakeColumnList(std::vector<CustomColumnBase*>& columnList)
369     {
370         typedef CustomColumn<typename ColumnList::Head::ColumnType> Type;
371         Type* pColumn = new Type();
372         columnList.push_back(pColumn);
373         CustomRowUtil<typename ColumnList::Tail>::MakeColumnList(columnList);
374     }
375
376     static void CopyColumnList(const std::vector<CustomColumnBase*>& srcList, std::vector<CustomColumnBase*>& dstList)
377     {
378         CopyColumnList(srcList, dstList, 0);
379     }
380
381     static ColumnIndex GetColumnIndex(const std::string& columnName)
382     {
383         return GetColumnIndex(columnName, 0);
384     }
385
386 private:
387     static void CopyColumnList(const std::vector<CustomColumnBase*>& srcList, std::vector<CustomColumnBase*>& dstList, ColumnIndex index)
388     {
389         typedef CustomColumn<typename ColumnList::Head::ColumnType> Type;
390         Type* pColumn = new Type(((Type*)(srcList.at(index)))->GetColumnData());
391         dstList.push_back(pColumn);
392         CustomRowUtil<typename ColumnList::Tail>::CopyColumnList(srcList, dstList, index + 1);
393     }
394
395     static ColumnIndex GetColumnIndex(const std::string& columnName, ColumnIndex index)
396     {
397         if (ColumnList::Head::GetColumnName() == columnName)
398             return index;
399
400         return CustomRowUtil<typename ColumnList::Tail>::GetColumnIndex(columnName, index + 1);
401     }
402
403 template<typename Other>
404 friend class CustomRowUtil;
405 };
406
407 template<>
408 class __attribute__ ((visibility("hidden"))) CustomRowUtil<VcoreDPL::TypeListGuard> {
409 public:
410     static void MakeColumnList(std::vector<CustomColumnBase*>&) {}
411 private:
412     static void CopyColumnList(const std::vector<CustomColumnBase*>&, std::vector<CustomColumnBase*>&, ColumnIndex) {}
413     static ColumnIndex GetColumnIndex(const std::string&, ColumnIndex) { return -1; }
414
415 template<typename Other>
416 friend class CustomRowUtil;
417 };
418
419 template<typename ColumnList>
420 class __attribute__ ((visibility("hidden"))) CustomRow {
421 private:
422     std::vector<CustomColumnBase*> m_columns;
423
424 public:
425     CustomRow()
426     {
427         CustomRowUtil<ColumnList>::MakeColumnList(m_columns);
428     }
429
430     CustomRow(const CustomRow& r)
431     {
432         CustomRowUtil<ColumnList>::CopyColumnList(r.m_columns, m_columns);
433     }
434
435     virtual ~CustomRow()
436     {
437         while (!m_columns.empty())
438         {
439             CustomColumnBase* pCustomColumn = m_columns.back();
440             m_columns.pop_back();
441             if (pCustomColumn)
442                 delete pCustomColumn;
443         }
444     }
445
446     template<typename ColumnType>
447     void SetColumnData(ColumnIndex columnIndex, ColumnType data)
448     {
449         typedef CustomColumn<ColumnType> Type;
450         Assert(columnIndex < m_columns.size());
451         Type* pColumn = dynamic_cast<Type*>(m_columns.at(columnIndex));
452         Assert(pColumn);
453         pColumn->SetColumnData(data);
454     }
455
456     template<typename ColumnData>
457     typename ColumnData::ColumnType GetColumnData()
458     {
459         typedef CustomColumn<typename ColumnData::ColumnType> Type;
460         ColumnIndex index = CustomRowUtil<ColumnList>::GetColumnIndex(ColumnData::GetColumnName());
461         Assert(index < m_columns.size());
462         Type* pColumn = dynamic_cast<Type*>(m_columns.at(index));
463         Assert(pColumn);
464         return pColumn->GetColumnData();
465     }
466 };
467
468 template<typename CustomRow, typename ColumnType>
469 void SetColumnData(CustomRow& row, ColumnType columnData, ColumnIndex columnIndex)
470 {
471     row.SetColumnData<ColumnType>(columnIndex, columnData);
472 }
473
474 template<typename ColumnList, typename CustomRow>
475 class  __attribute__ ((visibility("hidden"))) FillCustomRowUtil {
476 public:
477     static void FillCustomRow(CustomRow& row, DataCommand* command)
478     {
479         FillCustomRow(row, 0, command);
480     }
481
482 private:
483     static void FillCustomRow(CustomRow& row, ColumnIndex columnIndex, DataCommand* command)
484     {
485         typename ColumnList::Head::ColumnType columnData;
486         columnData = GetColumnFromCommand<typename ColumnList::Head::ColumnType>(columnIndex, command);
487         SetColumnData<CustomRow, typename ColumnList::Head::ColumnType>(row, columnData, columnIndex);
488         FillCustomRowUtil<typename ColumnList::Tail, CustomRow>::FillCustomRow(row, columnIndex + 1, command);
489     }
490
491 template<typename Other, typename OtherRow>
492 friend class FillCustomRowUtil;
493 };
494
495 template<typename CustomRow>
496 class  __attribute__ ((visibility("hidden"))) FillCustomRowUtil<VcoreDPL::TypeListGuard, CustomRow> {
497 private:
498     static void FillCustomRow(CustomRow&, ColumnIndex, DataCommand *)
499     { /* do nothing, we're past the last element of column list */ }
500
501 template<typename Other, typename OtherRow>
502 friend class FillCustomRowUtil;
503 };
504
505 template<typename ColumnList, typename Row>
506 class  __attribute__ ((visibility("hidden"))) FillRowUtil {
507 public:
508     static void FillRow(Row& row, DataCommand *command)
509     {
510         FillRow(row, 0, command);
511     }
512
513 private:
514     static void FillRow(Row& row, ColumnIndex columnIndex, DataCommand *command)
515     {
516         typename ColumnList::Head::ColumnType rowField;
517         rowField = GetColumnFromCommand<typename ColumnList::Head::ColumnType>(columnIndex, command);
518         ColumnList::Head::SetRowField(row, rowField);
519         FillRowUtil<typename ColumnList::Tail, Row>::FillRow(row, columnIndex + 1, command);
520     }
521
522 template<typename Other, typename OtherRow>
523 friend class FillRowUtil;
524 };
525
526 template<typename Row>
527 class  __attribute__ ((visibility("hidden"))) FillRowUtil<VcoreDPL::TypeListGuard, Row> {
528 private:
529     static void FillRow(Row&, ColumnIndex, DataCommand *)
530     { /* do nothing, we're past the last element of column list */ }
531
532 template<typename Other, typename OtherRow>
533 friend class FillRowUtil;
534 };
535
536 template<typename ColumnList>
537 class  __attribute__ ((visibility("hidden"))) JoinUtil {
538 public:
539     static std::string GetColumnNames()
540     {
541         std::string result;
542         result = ColumnList::Head::GetTableName();
543         result += ".";
544         result += ColumnList::Head::GetColumnName();
545         if (ColumnList::Tail::Size > 0)
546             result += ", ";
547
548         return result += JoinUtil<typename ColumnList::Tail>::GetColumnNames();
549     }
550
551     static std::string GetJoinTableName(const std::string& tableName)
552     {
553         std::string joinTableName = ColumnList::Head::GetTableName();
554         if (tableName.find(joinTableName) == std::string::npos)
555             return joinTableName;
556
557         return JoinUtil<typename ColumnList::Tail>::GetJoinTableName(tableName);
558     }
559 };
560
561 template<>
562 class  __attribute__ ((visibility("hidden"))) JoinUtil<VcoreDPL::TypeListGuard> {
563 public:
564     static std::string GetColumnNames() { return ""; }
565     static std::string GetJoinTableName(std::string) { return ""; }
566 };
567
568 class Exception {
569 public:
570     DECLARE_EXCEPTION_TYPE(VcoreDPL::Exception, Base)
571     DECLARE_EXCEPTION_TYPE(Base, SelectReuseWithDifferentQuerySignature)
572     DECLARE_EXCEPTION_TYPE(Base, RowFieldNotInitialized)
573     DECLARE_EXCEPTION_TYPE(Base, EmptyUpdateStatement)
574 };
575
576 template<typename TableDefinition>
577 class  __attribute__ ((visibility("hidden"))) Query
578 {
579 protected:
580     explicit Query(IOrmInterface* interface) :
581         m_interface(interface),
582         m_command(NULL)
583     {
584     }
585
586     virtual ~Query()
587     {
588         if (m_command == NULL)
589             return;
590
591         TableDefinition::FreeTableDataCommand(m_command, m_interface);
592     }
593
594     IOrmInterface* m_interface;
595     DataCommand *m_command;
596     std::string m_commandString;
597     ArgumentIndex m_bindArgumentIndex;
598 };
599
600 template<typename TableDefinition>
601 class  __attribute__ ((visibility("hidden"))) QueryWithWhereClause : public Query<TableDefinition>
602 {
603 protected:
604     ExpressionPtr m_whereExpression;
605
606     void Prepare()
607     {
608         if ( !!m_whereExpression )
609         {
610             this->m_commandString += " WHERE ";
611             this->m_commandString += m_whereExpression->GetString();
612         }
613     }
614
615     void Bind()
616     {
617         if ( !!m_whereExpression )
618         {
619             this->m_bindArgumentIndex = m_whereExpression->BindTo(
620                 this->m_command, this->m_bindArgumentIndex);
621         }
622     }
623
624 public:
625     explicit QueryWithWhereClause(IOrmInterface* interface) :
626         Query<TableDefinition>(interface)
627     {
628     }
629
630     template<typename Expression>
631     void Where(const Expression& expression)
632     {
633         DPL_CHECK_TYPE_INSTANTIABILITY(typename Expression::template ValidForTable<TableDefinition>::Yes);
634         if ( !!m_whereExpression && ( typeid(Expression) != typeid(*m_whereExpression) ) )
635         {
636             std::ostringstream str;
637             str << "Current ORM implementation doesn't allow to reuse Select"
638                     " instance with different query signature (particularly "
639                     "WHERE on different column).\n";
640             str << "Query: ";
641             str << this->m_commandString;
642             ThrowMsg(Exception::SelectReuseWithDifferentQuerySignature,
643                 str.str());
644         }
645         //TODO maybe don't make a copy here but just generate the string part of the query.
646         m_whereExpression.reset(new Expression(expression));
647     }
648
649 };
650
651 template<typename TableDefinition>
652 class  __attribute__ ((visibility("hidden"))) Delete : public QueryWithWhereClause<TableDefinition>
653 {
654 protected:
655     void Prepare()
656     {
657         if ( !this->m_command)
658         {
659             this->m_commandString  = "DELETE FROM ";
660             this->m_commandString += TableDefinition::GetName();
661
662             QueryWithWhereClause<TableDefinition>::Prepare();
663
664             this->m_command = TableDefinition::AllocTableDataCommand(
665                     this->m_commandString.c_str(),
666                     Query<TableDefinition>::m_interface);
667             LogDebug("Prepared SQL command " << this->m_commandString);
668         }
669     }
670
671     void Bind()
672     {
673         this->m_bindArgumentIndex = 1;
674         QueryWithWhereClause<TableDefinition>::Bind();
675     }
676
677 public:
678     explicit Delete(IOrmInterface *interface = NULL) :
679         QueryWithWhereClause<TableDefinition>(interface)
680     {
681     }
682
683     void Execute()
684     {
685         Prepare();
686         Bind();
687         this->m_command->Step();
688         this->m_command->Reset();
689     }
690 };
691
692 namespace {
693 class BindVisitor {
694 private:
695     DataCommand *m_command;
696 public:
697     ArgumentIndex m_bindArgumentIndex;
698
699     BindVisitor(DataCommand *command) :
700         m_command(command),
701         m_bindArgumentIndex(1)
702     {}
703
704     template<typename ColumnType>
705     void Visit(const char*, const ColumnType& value, bool isSet)
706     {
707         if ( isSet )
708         {
709             DataCommandUtils::BindArgument(m_command, m_bindArgumentIndex, value);
710             m_bindArgumentIndex++;
711         }
712     }
713 };
714 } //anonymous namespace
715 template<typename TableDefinition>
716 class __attribute__ ((visibility("hidden"))) Insert : public Query<TableDefinition>
717 {
718 public:
719     typedef typename TableDefinition::Row Row;
720     typedef VcoreDPL::DB::SqlConnection::RowID RowID;
721
722 protected:
723     boost::optional<std::string> m_orClause;
724     Row m_row;
725
726     class PrepareVisitor {
727     public:
728         std::string m_columnNames;
729         std::string m_values;
730
731         template<typename ColumnType>
732         void Visit(const char* name, const ColumnType&, bool isSet)
733         {
734             if ( isSet )
735             {
736                 if ( !m_columnNames.empty() )
737                 {
738                     m_columnNames += ", ";
739                     m_values += ", ";
740                 }
741                 m_columnNames += name;
742                 m_values += "?";
743             }
744         }
745     };
746
747     void Prepare()
748     {
749         if ( !this->m_command )
750         {
751             this->m_commandString = "INSERT ";
752             if ( !!m_orClause )
753             {
754                 this->m_commandString += " OR " + *m_orClause + " ";
755             }
756             this->m_commandString += "INTO ";
757             this->m_commandString += TableDefinition::GetName();
758
759             PrepareVisitor visitor;
760             m_row.VisitColumns(visitor);
761
762             this->m_commandString += " ( " + visitor.m_columnNames + " ) ";
763             this->m_commandString += "VALUES ( " + visitor.m_values + " )";
764
765             LogDebug("Prepared SQL command " << this->m_commandString);
766             this->m_command = TableDefinition::AllocTableDataCommand(
767                 this->m_commandString.c_str(),
768                 Query<TableDefinition>::m_interface);
769         }
770     }
771
772     void Bind()
773     {
774         BindVisitor visitor(this->m_command);
775         m_row.VisitColumns(visitor);
776     }
777
778 public:
779     explicit Insert(
780             IOrmInterface* interface = NULL,
781             const boost::optional<std::string>& orClause = boost::optional<std::string>()) :
782         Query<TableDefinition>(interface),
783         m_orClause(orClause)
784     {
785     }
786
787     void Values(const Row& row)
788     {
789         if ( this->m_command )
790         {
791             if ( !row.IsSignatureMatching(m_row) )
792             {
793                 ThrowMsg(Exception::SelectReuseWithDifferentQuerySignature,
794                     "Current ORM implementation doesn't allow to reuse Insert instance "
795                     "with different query signature.");
796             }
797         }
798         m_row = row;
799     }
800
801     RowID Execute()
802     {
803         Prepare();
804         Bind();
805         this->m_command->Step();
806
807         RowID result = TableDefinition::GetLastInsertRowID(
808             Query<TableDefinition>::m_interface);
809
810         this->m_command->Reset();
811         return result;
812     }
813 };
814
815 template<typename TableDefinition>
816 class __attribute__ ((visibility("hidden"))) Select : public QueryWithWhereClause<TableDefinition>
817 {
818 public:
819     typedef typename TableDefinition::ColumnList       ColumnList;
820     typedef typename TableDefinition::Row              Row;
821
822     typedef std::list<Row>                             RowList;
823 protected:
824     boost::optional<std::string> m_orderBy;
825     std::string m_JoinClause;
826     bool                       m_distinctResults;
827
828     void Prepare(const char* selectColumnName)
829     {
830         if ( !this->m_command )
831         {
832             this->m_commandString  = "SELECT ";
833             if (m_distinctResults)
834                 this->m_commandString += "DISTINCT ";
835             this->m_commandString += selectColumnName;
836             this->m_commandString += " FROM ";
837             this->m_commandString += TableDefinition::GetName();
838
839             this->m_commandString += m_JoinClause;
840
841             QueryWithWhereClause<TableDefinition>::Prepare();
842
843             if ( !!m_orderBy )
844             {
845                 this->m_commandString += " ORDER BY " + *m_orderBy;
846             }
847
848             this->m_command = TableDefinition::AllocTableDataCommand(
849                 this->m_commandString.c_str(),
850                 Query<TableDefinition>::m_interface);
851
852             LogDebug("Prepared SQL command " << this->m_commandString);
853         }
854     }
855
856     void Bind()
857     {
858         this->m_bindArgumentIndex = 1;
859         QueryWithWhereClause<TableDefinition>::Bind();
860     }
861
862     template<typename ColumnType>
863     ColumnType GetColumn(ColumnIndex columnIndex)
864     {
865         return GetColumnFromCommand<ColumnType>(columnIndex, this->m_command);
866     }
867
868     Row GetRow()
869     {
870         Row row;
871         FillRowUtil<ColumnList, Row>::FillRow(row, this->m_command);
872         return row;
873     }
874
875     template<typename ColumnList, typename CustomRow>
876     CustomRow GetCustomRow()
877     {
878         CustomRow row;
879         FillCustomRowUtil<ColumnList, CustomRow>::FillCustomRow(row, this->m_command);
880         return row;
881     }
882
883 public:
884
885     explicit Select(IOrmInterface *interface = NULL) :
886         QueryWithWhereClause<TableDefinition>(interface),
887         m_distinctResults(false)
888     {
889     }
890
891     void Distinct()
892     {
893         m_distinctResults = true;
894     }
895
896     template<typename CompoundType>
897     void OrderBy(const CompoundType&)
898     {
899         m_orderBy = OrderingUtils::OrderByInternal<typename CompoundType::Type>();
900     }
901
902     void OrderBy(const std::string & orderBy) //backward compatibility
903     {
904         m_orderBy = orderBy;
905     }
906
907     void OrderBy(const char * orderBy) //backward compatibility
908     {
909         m_orderBy = std::string(orderBy);
910     }
911
912     template<typename ColumnList, typename Expression>
913     void Join(const Expression& expression) {
914         std::string usedTableNames = TableDefinition::GetName();
915         if (!m_JoinClause.empty())
916             usedTableNames += m_JoinClause;
917
918         this->m_JoinClause += " JOIN ";
919         this->m_JoinClause += JoinUtil<ColumnList>::GetJoinTableName(usedTableNames);
920         this->m_JoinClause += " ON ";
921         this->m_JoinClause += expression.GetString();
922     }
923
924     template<typename ColumnData>
925     typename ColumnData::ColumnType GetSingleValue()
926     {
927         Prepare(ColumnData::GetColumnName());
928         Bind();
929         this->m_command->Step();
930
931         typename ColumnData::ColumnType result =
932             GetColumn<typename ColumnData::ColumnType>(0);
933
934         this->m_command->Reset();
935         return result;
936     }
937
938     //TODO return range - pair of custom iterators
939     template<typename ColumnData>
940     std::list<typename ColumnData::ColumnType> GetValueList()
941     {
942         Prepare(ColumnData::GetColumnName());
943         Bind();
944
945         std::list<typename ColumnData::ColumnType> resultList;
946
947         while (this->m_command->Step())
948             resultList.push_back(GetColumn<typename ColumnData::ColumnType>(0));
949
950         this->m_command->Reset();
951         return resultList;
952     }
953
954     Row GetSingleRow()
955     {
956         Prepare("*");
957         Bind();
958         this->m_command->Step();
959
960         Row result = GetRow();
961
962         this->m_command->Reset();
963         return result;
964     }
965
966     //TODO return range - pair of custom iterators
967     RowList GetRowList()
968     {
969         Prepare("*");
970         Bind();
971
972         RowList resultList;
973
974         while (this->m_command->Step())
975             resultList.push_back(GetRow());
976
977         this->m_command->Reset();
978         return resultList;
979     }
980
981     template<typename ColumnList, typename CustomRow>
982     CustomRow GetCustomSingleRow()
983     {
984         Prepare(JoinUtil<ColumnList>::GetColumnNames().c_str());
985         Bind();
986         this->m_command->Step();
987
988         CustomRow result = GetCustomRow<ColumnList, CustomRow>();
989
990         this->m_command->Reset();
991         return result;
992     }
993
994     template<typename ColumnList, typename CustomRow>
995     std::list<CustomRow> GetCustomRowList()
996     {
997         Prepare(JoinUtil<ColumnList>::GetColumnNames().c_str());
998         Bind();
999
1000         std::list<CustomRow> resultList;
1001
1002         while (this->m_command->Step())
1003             resultList.push_back(GetCustomRow<ColumnList, CustomRow>());
1004
1005         this->m_command->Reset();
1006         return resultList;
1007     }
1008 };
1009
1010 template<typename TableDefinition>
1011 class __attribute__ ((visibility("hidden"))) Update : public QueryWithWhereClause<TableDefinition> {
1012 public:
1013     typedef typename TableDefinition::Row Row;
1014
1015 protected:
1016     boost::optional<std::string> m_orClause;
1017     Row m_row;
1018
1019     class PrepareVisitor {
1020     public:
1021         std::string m_setExpressions;
1022
1023         template<typename ColumnType>
1024         void Visit(const char* name, const ColumnType&, bool isSet)
1025         {
1026             if ( isSet )
1027             {
1028                 if ( !m_setExpressions.empty() )
1029                 {
1030                     m_setExpressions += ", ";
1031                 }
1032                 m_setExpressions += name;
1033                 m_setExpressions += " = ";
1034                 m_setExpressions += "?";
1035             }
1036         }
1037     };
1038
1039     void Prepare()
1040     {
1041         if ( !this->m_command )
1042         {
1043             this->m_commandString = "UPDATE ";
1044             if ( !!m_orClause )
1045             {
1046                 this->m_commandString += " OR " + *m_orClause + " ";
1047             }
1048             this->m_commandString += TableDefinition::GetName();
1049             this->m_commandString += " SET ";
1050
1051             // got through row columns and values
1052             PrepareVisitor visitor;
1053             m_row.VisitColumns(visitor);
1054
1055             if(visitor.m_setExpressions.empty())
1056             {
1057                 ThrowMsg(Exception::EmptyUpdateStatement, "No SET expressions in update statement");
1058             }
1059
1060             this->m_commandString += visitor.m_setExpressions;
1061
1062             // where
1063             QueryWithWhereClause<TableDefinition>::Prepare();
1064
1065             this->m_command = TableDefinition::AllocTableDataCommand(
1066                     this->m_commandString.c_str(),
1067                     Query<TableDefinition>::m_interface);
1068             LogDebug("Prepared SQL command " << this->m_commandString);
1069         }
1070     }
1071
1072     void Bind()
1073     {
1074         BindVisitor visitor(this->m_command);
1075         m_row.VisitColumns(visitor);
1076
1077         this->m_bindArgumentIndex = visitor.m_bindArgumentIndex;
1078         QueryWithWhereClause<TableDefinition>::Bind();
1079     }
1080
1081
1082 public:
1083     explicit Update(IOrmInterface *interface = NULL,
1084                     const boost::optional<std::string>& orClause = boost::optional<std::string>()) :
1085         QueryWithWhereClause<TableDefinition>(interface),
1086         m_orClause(orClause)
1087     {
1088     }
1089
1090     void Values(const Row& row)
1091     {
1092         if ( this->m_command )
1093         {
1094             if ( !row.IsSignatureMatching(m_row) )
1095             {
1096                 ThrowMsg(Exception::SelectReuseWithDifferentQuerySignature,
1097                     "Current ORM implementation doesn't allow to reuse Update instance "
1098                     "with different query signature.");
1099             }
1100         }
1101         m_row = row;
1102     }
1103
1104     void Execute()
1105     {
1106         Prepare();
1107         Bind();
1108         this->m_command->Step();
1109         this->m_command->Reset();
1110     }
1111 };
1112
1113 } //namespace ORM
1114 } //namespace DB
1115 } //namespace VcoreDPL
1116
1117 #endif // DPL_ORM_H