2 * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 * @author Bartosz Janiak (b.janiak@samsung.com)
20 * @brief DPL-ORM: Object-relational mapping for sqlite database, written on top of DPL.
30 #include <dpl/db/sql_connection.h>
31 #include <dpl/db/orm_interface.h>
32 #include <dpl/string.h>
33 #include <dpl/optional.h>
34 #include <dpl/shared_ptr.h>
35 #include <dpl/type_list.h>
36 #include <dpl/assert.h>
37 #include <dpl/foreach.h>
46 //TODO move to type utils
47 #define DPL_CHECK_TYPE_INSTANTIABILITY(type) \
53 #define DECLARE_COLUMN_TYPE_LIST() typedef DPL::TypeListDecl<
54 #define SELECTED_COLUMN(table_name, column_name) table_name::column_name,
55 #define DECLARE_COLUMN_TYPE_LIST_END(name) DPL::TypeListGuard>::Type name;
57 typedef size_t ColumnIndex;
58 typedef size_t ArgumentIndex;
59 typedef DPL::Optional<DPL::String> OptionalString;
60 typedef DPL::Optional<int> OptionalInteger;
61 typedef DPL::DB::SqlConnection::DataCommand DataCommand;
63 namespace RelationTypes {
64 extern const char Equal[];
65 extern const char LessThan[];
66 extern const char And[];
67 extern const char Or[];
68 extern const char Is[];
69 extern const char In[];
70 //TODO define more relation types
73 namespace DataCommandUtils {
74 //TODO move to DPL::DataCommand?
75 void BindArgument(DataCommand *command, ArgumentIndex index, int argument);
76 void BindArgument(DataCommand *command, ArgumentIndex index, const OptionalInteger& argument);
77 void BindArgument(DataCommand *command, ArgumentIndex index, const DPL::String& argument);
78 void BindArgument(DataCommand *command, ArgumentIndex index, const OptionalString& argument);
82 virtual ~Expression() {}
83 virtual std::string GetString() const = 0;
84 virtual ArgumentIndex BindTo(DataCommand *command, ArgumentIndex index) = 0;
87 typedef DPL::SharedPtr<Expression> ExpressionPtr;
89 template<const char* Operator, typename LeftExpression, typename RightExpression>
90 class BinaryExpression : public Expression {
92 LeftExpression m_leftExpression;
93 RightExpression m_rightExpression;
94 bool m_outerParenthesis;
96 BinaryExpression(const LeftExpression& leftExpression, const RightExpression& rightExpression, bool outerParenthesis = true) :
97 m_leftExpression(leftExpression),
98 m_rightExpression(rightExpression),
99 m_outerParenthesis(outerParenthesis)
102 virtual std::string GetString() const
104 return (m_outerParenthesis ? "( " : " " ) +
105 m_leftExpression.GetString() + " " + Operator + " " + m_rightExpression.GetString() +
106 (m_outerParenthesis ? " )" : " " ) ;
109 virtual ArgumentIndex BindTo(DataCommand *command, ArgumentIndex index)
111 index = m_leftExpression.BindTo(command, index);
112 return m_rightExpression.BindTo(command, index);
115 template<typename TableDefinition>
116 struct ValidForTable {
117 typedef std::pair<typename LeftExpression ::template ValidForTable<TableDefinition>::Yes ,
118 typename RightExpression::template ValidForTable<TableDefinition>::Yes >
123 template<typename LeftExpression, typename RightExpression>
124 BinaryExpression<RelationTypes::And, LeftExpression, RightExpression>
125 And(const LeftExpression& leftExpression, const RightExpression& rightExpression)
127 return BinaryExpression<RelationTypes::And, LeftExpression, RightExpression>
128 (leftExpression, rightExpression);
131 template<typename ArgumentType>
132 class ExpressionWithArgument : public Expression {
134 ArgumentType argument;
137 explicit ExpressionWithArgument(const ArgumentType& _argument) : argument(_argument) {}
139 virtual ArgumentIndex BindTo(DataCommand *command, ArgumentIndex index)
141 DataCommandUtils::BindArgument(command, index, argument);
147 template<typename ColumnData, const char* Relation>
148 class Compare : public ExpressionWithArgument<typename ColumnData::ColumnType> {
150 explicit Compare(typename ColumnData::ColumnType column) :
151 ExpressionWithArgument<typename ColumnData::ColumnType>(column)
154 virtual std::string GetString() const
156 std::string statement;
157 statement += ColumnData::GetTableName();
159 statement += ColumnData::GetColumnName();
161 statement += Relation;
166 template<typename TableDefinition>
167 struct ValidForTable {
168 typedef typename TableDefinition::ColumnList::template Contains<ColumnData> Yes;
171 #define ORM_DEFINE_COMPARE_EXPRESSION(name, relationType) \
172 template<typename ColumnData> \
173 class name : public Compare<ColumnData, RelationTypes::relationType> { \
175 name(typename ColumnData::ColumnType column) : \
176 Compare<ColumnData, RelationTypes::relationType>(column) \
180 ORM_DEFINE_COMPARE_EXPRESSION(Equals, Equal)
181 ORM_DEFINE_COMPARE_EXPRESSION(Is, Is)
183 template<typename ColumnData1, typename ColumnData2>
184 class CompareBinaryColumn {
186 std::string m_relation;
188 CompareBinaryColumn(const char* Relation) :
192 virtual std::string GetString() const
194 std::string statement;
195 statement += ColumnData1::GetTableName();
197 statement += ColumnData1::GetColumnName();
199 statement += m_relation;
201 statement += ColumnData2::GetTableName();
203 statement += ColumnData2::GetColumnName();
209 template<typename ColumnData1, typename ColumnData2>
210 CompareBinaryColumn<ColumnData1, ColumnData2>
213 return CompareBinaryColumn<ColumnData1, ColumnData2>(RelationTypes::Equal);
216 template<typename ColumnData, const char* Relation>
217 class NumerousArguments : public Expression {
219 std::set<typename ColumnData::ColumnType> m_argumentList;
221 NumerousArguments(const std::set<typename ColumnData::ColumnType>& argumentList) : m_argumentList(argumentList) {}
223 virtual std::string GetString() const
225 std::string statement;
226 statement += ColumnData::GetColumnName();
228 statement += Relation;
231 int argumentCount = m_argumentList.size();
247 virtual ArgumentIndex BindTo(DataCommand *command, ArgumentIndex index)
249 ArgumentIndex argumentIndex = index;
250 FOREACH(argumentIt, m_argumentList)
252 DataCommandUtils::BindArgument(command, argumentIndex, *argumentIt);
255 return argumentIndex + 1;
258 template<typename TableDefinition>
259 struct ValidForTable {
260 typedef typename TableDefinition::ColumnList::template Contains<ColumnData> Yes;
264 #define ORM_DEFINE_COMPARE_EXPRESSION_NUMEROUS_ARGUMENTS(name, relationType) \
265 template<typename ColumnData> \
266 class name : public NumerousArguments<ColumnData, RelationTypes::relationType> { \
268 name(std::set<typename ColumnData::ColumnType> column) : \
269 NumerousArguments<ColumnData, RelationTypes::relationType>(column) \
273 ORM_DEFINE_COMPARE_EXPRESSION_NUMEROUS_ARGUMENTS(In, In)
275 template<typename ColumnType>
276 ColumnType GetColumnFromCommand(ColumnIndex columnIndex, DataCommand *command);
278 class CustomColumnBase {
280 CustomColumnBase() {}
281 virtual ~CustomColumnBase() {}
284 template<typename ColumnType>
285 class CustomColumn : public CustomColumnBase {
287 ColumnType m_columnData;
291 CustomColumn(ColumnType data)
296 void SetColumnData(ColumnType data)
301 ColumnType GetColumnData() const
307 template<typename ColumnList>
308 class CustomRowUtil {
310 static void MakeColumnList(std::vector<CustomColumnBase*>& columnList)
312 typedef CustomColumn<typename ColumnList::Head::ColumnType> Type;
313 Type* pColumn = new Type();
314 columnList.push_back(pColumn);
315 CustomRowUtil<typename ColumnList::Tail>::MakeColumnList(columnList);
318 static void CopyColumnList(const std::vector<CustomColumnBase*>& srcList, std::vector<CustomColumnBase*>& dstList)
320 CopyColumnList(srcList, dstList, 0);
323 static ColumnIndex GetColumnIndex(const std::string& columnName)
325 return GetColumnIndex(columnName, 0);
329 static void CopyColumnList(const std::vector<CustomColumnBase*>& srcList, std::vector<CustomColumnBase*>& dstList, ColumnIndex index)
331 typedef CustomColumn<typename ColumnList::Head::ColumnType> Type;
332 Type* pColumn = new Type(((Type*)(srcList.at(index)))->GetColumnData());
333 dstList.push_back(pColumn);
334 CustomRowUtil<typename ColumnList::Tail>::CopyColumnList(srcList, dstList, index + 1);
337 static ColumnIndex GetColumnIndex(const std::string& columnName, ColumnIndex index)
339 if (ColumnList::Head::GetColumnName() == columnName)
342 return CustomRowUtil<typename ColumnList::Tail>::GetColumnIndex(columnName, index + 1);
345 template<typename Other>
346 friend class CustomRowUtil;
350 class CustomRowUtil<DPL::TypeListGuard> {
352 static void MakeColumnList(std::vector<CustomColumnBase*>&) {}
354 static void CopyColumnList(const std::vector<CustomColumnBase*>&, std::vector<CustomColumnBase*>&, ColumnIndex) {}
355 static ColumnIndex GetColumnIndex(const std::string&, ColumnIndex) { return -1; }
357 template<typename Other>
358 friend class CustomRowUtil;
361 template<typename ColumnList>
364 std::vector<CustomColumnBase*> m_columns;
369 CustomRowUtil<ColumnList>::MakeColumnList(m_columns);
372 CustomRow(const CustomRow& r)
374 CustomRowUtil<ColumnList>::CopyColumnList(r.m_columns, m_columns);
379 while (!m_columns.empty())
381 CustomColumnBase* pCustomColumn = m_columns.back();
382 m_columns.pop_back();
384 delete pCustomColumn;
388 template<typename ColumnType>
389 void SetColumnData(ColumnIndex columnIndex, ColumnType data)
391 typedef CustomColumn<ColumnType> Type;
392 Assert(columnIndex >= 0 && columnIndex < m_columns.size());
393 Type* pColumn = dynamic_cast<Type*>(m_columns.at(columnIndex));
395 pColumn->SetColumnData(data);
398 template<typename ColumnData>
399 typename ColumnData::ColumnType GetColumnData()
401 typedef CustomColumn<typename ColumnData::ColumnType> Type;
402 ColumnIndex index = CustomRowUtil<ColumnList>::GetColumnIndex(ColumnData::GetColumnName());
403 Assert(index >= 0 && index < m_columns.size());
404 Type* pColumn = dynamic_cast<Type*>(m_columns.at(index));
406 return pColumn->GetColumnData();
410 template<typename CustomRow, typename ColumnType>
411 void SetColumnData(CustomRow& row, ColumnType columnData, ColumnIndex columnIndex)
413 row.SetColumnData<ColumnType>(columnIndex, columnData);
416 template<typename ColumnList, typename CustomRow>
417 class FillCustomRowUtil {
419 static void FillCustomRow(CustomRow& row, DataCommand* command)
421 FillCustomRow(row, 0, command);
425 static void FillCustomRow(CustomRow& row, ColumnIndex columnIndex, DataCommand* command)
427 typename ColumnList::Head::ColumnType columnData;
428 columnData = GetColumnFromCommand<typename ColumnList::Head::ColumnType>(columnIndex, command);
429 SetColumnData<CustomRow, typename ColumnList::Head::ColumnType>(row, columnData, columnIndex);
430 FillCustomRowUtil<typename ColumnList::Tail, CustomRow>::FillCustomRow(row, columnIndex + 1, command);
433 template<typename Other, typename OtherRow>
434 friend class FillCustomRowUtil;
437 template<typename CustomRow>
438 class FillCustomRowUtil<DPL::TypeListGuard, CustomRow> {
440 static void FillCustomRow(CustomRow&, ColumnIndex, DataCommand *)
441 { /* do nothing, we're past the last element of column list */ }
443 template<typename Other, typename OtherRow>
444 friend class FillCustomRowUtil;
447 template<typename ColumnList, typename Row>
450 static void FillRow(Row& row, DataCommand *command)
452 FillRow(row, 0, command);
456 static void FillRow(Row& row, ColumnIndex columnIndex, DataCommand *command)
458 typename ColumnList::Head::ColumnType rowField;
459 rowField = GetColumnFromCommand<typename ColumnList::Head::ColumnType>(columnIndex, command);
460 ColumnList::Head::SetRowField(row, rowField);
461 FillRowUtil<typename ColumnList::Tail, Row>::FillRow(row, columnIndex + 1, command);
464 template<typename Other, typename OtherRow>
465 friend class FillRowUtil;
468 template<typename Row>
469 class FillRowUtil<DPL::TypeListGuard, Row> {
471 static void FillRow(Row&, ColumnIndex, DataCommand *)
472 { /* do nothing, we're past the last element of column list */ }
474 template<typename Other, typename OtherRow>
475 friend class FillRowUtil;
478 template<typename ColumnList>
481 static std::string GetColumnNames()
484 result = ColumnList::Head::GetTableName();
486 result += ColumnList::Head::GetColumnName();
487 if (ColumnList::Tail::Size > 0)
490 return result += JoinUtil<typename ColumnList::Tail>::GetColumnNames();
493 static std::string GetJoinTableName(const std::string& tableName)
495 std::string joinTableName = ColumnList::Head::GetTableName();
496 if (tableName.find(joinTableName) == std::string::npos)
497 return joinTableName;
499 return JoinUtil<typename ColumnList::Tail>::GetJoinTableName(tableName);
504 class JoinUtil<DPL::TypeListGuard> {
506 static std::string GetColumnNames() { return ""; }
507 static std::string GetJoinTableName(std::string) { return ""; }
512 DECLARE_EXCEPTION_TYPE(DPL::Exception, Base)
513 DECLARE_EXCEPTION_TYPE(Base, SelectReuseWithDifferentQuerySignature)
514 DECLARE_EXCEPTION_TYPE(Base, RowFieldNotInitialized)
515 DECLARE_EXCEPTION_TYPE(Base, EmptyUpdateStatement)
518 template<typename TableDefinition>
522 explicit Query(IOrmInterface* interface) :
523 m_interface(interface),
530 if (m_command == NULL)
533 TableDefinition::FreeTableDataCommand(m_command, m_interface);
536 IOrmInterface* m_interface;
537 DataCommand *m_command;
538 std::string m_commandString;
539 ArgumentIndex m_bindArgumentIndex;
542 template<typename TableDefinition>
543 class QueryWithWhereClause : public Query<TableDefinition>
546 ExpressionPtr m_whereExpression;
550 if ( !!m_whereExpression )
552 this->m_commandString += " WHERE ";
553 this->m_commandString += m_whereExpression->GetString();
559 if ( !!m_whereExpression )
561 this->m_bindArgumentIndex = m_whereExpression->BindTo(
562 this->m_command, this->m_bindArgumentIndex);
567 explicit QueryWithWhereClause(IOrmInterface* interface) :
568 Query<TableDefinition>(interface)
572 template<typename Expression>
573 void Where(const Expression& expression)
575 DPL_CHECK_TYPE_INSTANTIABILITY(typename Expression::template ValidForTable<TableDefinition>::Yes);
576 if ( !!m_whereExpression && ( typeid(Expression) != typeid(*m_whereExpression) ) )
578 std::ostringstream str;
579 str << "Current ORM implementation doesn't allow to reuse Select"
580 " instance with different query signature (particularly "
581 "WHERE on different column).\n";
583 str << this->m_commandString;
584 ThrowMsg(Exception::SelectReuseWithDifferentQuerySignature,
587 //TODO maybe don't make a copy here but just generate the string part of the query.
588 m_whereExpression.Reset(new Expression(expression));
593 template<typename TableDefinition>
594 class Delete : public QueryWithWhereClause<TableDefinition>
599 if ( !this->m_command)
601 this->m_commandString = "DELETE FROM ";
602 this->m_commandString += TableDefinition::GetName();
604 QueryWithWhereClause<TableDefinition>::Prepare();
606 this->m_command = TableDefinition::AllocTableDataCommand(
607 this->m_commandString.c_str(),
608 Query<TableDefinition>::m_interface);
609 LogPedantic("Prepared SQL command " << this->m_commandString);
615 this->m_bindArgumentIndex = 1;
616 QueryWithWhereClause<TableDefinition>::Bind();
620 explicit Delete(IOrmInterface *interface = NULL) :
621 QueryWithWhereClause<TableDefinition>(interface)
629 this->m_command->Step();
630 this->m_command->Reset();
634 template<typename TableDefinition>
635 class Insert : public Query<TableDefinition>
638 typedef typename TableDefinition::Row Row;
639 typedef DPL::DB::SqlConnection::RowID RowID;
642 DPL::Optional<std::string> m_orClause;
645 class PrepareVisitor {
647 std::string m_columnNames;
648 std::string m_values;
650 template<typename ColumnType>
651 void Visit(const char* name, const ColumnType&, bool isSet)
655 if ( !m_columnNames.empty() )
657 m_columnNames += ", ";
660 m_columnNames += name;
668 if ( !this->m_command )
670 this->m_commandString = "INSERT ";
673 this->m_commandString += " OR " + *m_orClause + " ";
675 this->m_commandString += "INTO ";
676 this->m_commandString += TableDefinition::GetName();
678 PrepareVisitor visitor;
679 m_row.VisitColumns(visitor);
681 this->m_commandString += " ( " + visitor.m_columnNames + " ) ";
682 this->m_commandString += "VALUES ( " + visitor.m_values + " )";
684 LogPedantic("Prepared SQL command " << this->m_commandString);
685 this->m_command = TableDefinition::AllocTableDataCommand(
686 this->m_commandString.c_str(),
687 Query<TableDefinition>::m_interface);
693 DataCommand *m_command;
694 ArgumentIndex m_bindArgumentIndex;
696 BindVisitor(DataCommand *command) :
698 m_bindArgumentIndex(1)
701 template<typename ColumnType>
702 void Visit(const char*, const ColumnType& value, bool isSet)
706 DataCommandUtils::BindArgument(m_command, m_bindArgumentIndex, value);
707 m_bindArgumentIndex++;
714 BindVisitor visitor(this->m_command);
715 m_row.VisitColumns(visitor);
720 IOrmInterface* interface = NULL,
721 const DPL::Optional<std::string>& orClause = DPL::Optional<std::string>::Null) :
722 Query<TableDefinition>(interface),
727 void Values(const Row& row)
729 if ( this->m_command )
731 if ( !row.IsSignatureMatching(m_row) )
733 ThrowMsg(Exception::SelectReuseWithDifferentQuerySignature,
734 "Current ORM implementation doesn't allow to reuse Insert instance "
735 "with different query signature.");
745 this->m_command->Step();
747 RowID result = TableDefinition::GetLastInsertRowID(
748 Query<TableDefinition>::m_interface);
750 this->m_command->Reset();
755 template<typename TableDefinition>
756 class Select : public QueryWithWhereClause<TableDefinition>
759 typedef typename TableDefinition::ColumnList ColumnList;
760 typedef typename TableDefinition::Row Row;
762 typedef std::list<Row> RowList;
764 DPL::Optional<std::string> m_orderBy;
765 std::string m_JoinClause;
766 bool m_distinctResults;
768 void Prepare(const char* selectColumnName)
770 if ( !this->m_command )
772 this->m_commandString = "SELECT ";
773 if (m_distinctResults)
774 this->m_commandString += "DISTINCT ";
775 this->m_commandString += selectColumnName;
776 this->m_commandString += " FROM ";
777 this->m_commandString += TableDefinition::GetName();
779 this->m_commandString += m_JoinClause;
781 QueryWithWhereClause<TableDefinition>::Prepare();
783 if ( !m_orderBy.IsNull() )
785 this->m_commandString += " ORDER BY " + *m_orderBy;
788 this->m_command = TableDefinition::AllocTableDataCommand(
789 this->m_commandString.c_str(),
790 Query<TableDefinition>::m_interface);
792 LogPedantic("Prepared SQL command " << this->m_commandString);
798 this->m_bindArgumentIndex = 1;
799 QueryWithWhereClause<TableDefinition>::Bind();
802 template<typename ColumnType>
803 ColumnType GetColumn(ColumnIndex columnIndex)
805 return GetColumnFromCommand<ColumnType>(columnIndex, this->m_command);
811 FillRowUtil<ColumnList, Row>::FillRow(row, this->m_command);
815 template<typename ColumnList, typename CustomRow>
816 CustomRow GetCustomRow()
819 FillCustomRowUtil<ColumnList, CustomRow>::FillCustomRow(row, this->m_command);
825 explicit Select(IOrmInterface *interface = NULL) :
826 QueryWithWhereClause<TableDefinition>(interface),
827 m_distinctResults(false)
833 m_distinctResults = true;
836 void OrderBy(const std::string& orderBy)
841 template<typename ColumnList, typename Expression>
842 void Join(const Expression& expression) {
843 std::string usedTableNames = TableDefinition::GetName();
844 if (!m_JoinClause.empty())
845 usedTableNames += m_JoinClause;
847 this->m_JoinClause += " JOIN ";
848 this->m_JoinClause += JoinUtil<ColumnList>::GetJoinTableName(usedTableNames);
849 this->m_JoinClause += " ON ";
850 this->m_JoinClause += expression.GetString();
853 template<typename ColumnData>
854 typename ColumnData::ColumnType GetSingleValue()
856 Prepare(ColumnData::GetColumnName());
858 this->m_command->Step();
860 typename ColumnData::ColumnType result =
861 GetColumn<typename ColumnData::ColumnType>(0);
863 this->m_command->Reset();
867 //TODO return range - pair of custom iterators
868 template<typename ColumnData>
869 std::list<typename ColumnData::ColumnType> GetValueList()
871 Prepare(ColumnData::GetColumnName());
874 std::list<typename ColumnData::ColumnType> resultList;
876 while (this->m_command->Step())
877 resultList.push_back(GetColumn<typename ColumnData::ColumnType>(0));
879 this->m_command->Reset();
887 this->m_command->Step();
889 Row result = GetRow();
891 this->m_command->Reset();
895 //TODO return range - pair of custom iterators
903 while (this->m_command->Step())
904 resultList.push_back(GetRow());
906 this->m_command->Reset();
910 template<typename ColumnList, typename CustomRow>
911 CustomRow GetCustomSingleRow()
913 Prepare(JoinUtil<ColumnList>::GetColumnNames().c_str());
915 this->m_command->Step();
917 CustomRow result = GetCustomRow<ColumnList, CustomRow>();
919 this->m_command->Reset();
923 template<typename ColumnList, typename CustomRow>
924 std::list<CustomRow> GetCustomRowList()
926 Prepare(JoinUtil<ColumnList>::GetColumnNames().c_str());
929 std::list<CustomRow> resultList;
931 while (this->m_command->Step())
932 resultList.push_back(GetCustomRow<ColumnList, CustomRow>());
934 this->m_command->Reset();
939 template<typename TableDefinition>
940 class Update : public QueryWithWhereClause<TableDefinition> {
942 typedef typename TableDefinition::Row Row;
945 DPL::Optional<std::string> m_orClause;
948 class PrepareVisitor {
950 std::string m_setExpressions;
952 template<typename ColumnType>
953 void Visit(const char* name, const ColumnType&, bool isSet)
957 if ( !m_setExpressions.empty() )
959 m_setExpressions += ", ";
961 m_setExpressions += name;
962 m_setExpressions += " = ";
963 m_setExpressions += "?";
970 if ( !this->m_command )
972 this->m_commandString = "UPDATE ";
975 this->m_commandString += " OR " + *m_orClause + " ";
977 this->m_commandString += TableDefinition::GetName();
978 this->m_commandString += " SET ";
980 // got through row columns and values
981 PrepareVisitor visitor;
982 m_row.VisitColumns(visitor);
984 if(visitor.m_setExpressions.empty())
986 ThrowMsg(Exception::EmptyUpdateStatement, "No SET expressions in update statement");
989 this->m_commandString += visitor.m_setExpressions;
992 QueryWithWhereClause<TableDefinition>::Prepare();
994 this->m_command = TableDefinition::AllocTableDataCommand(
995 this->m_commandString.c_str(),
996 Query<TableDefinition>::m_interface);
997 LogPedantic("Prepared SQL command " << this->m_commandString);
1003 DataCommand *m_command;
1006 ArgumentIndex m_bindArgumentIndex;
1008 BindVisitor(DataCommand *command) :
1010 m_bindArgumentIndex(1)
1013 template<typename ColumnType>
1014 void Visit(const char*, const ColumnType& value, bool isSet)
1018 DataCommandUtils::BindArgument(m_command, m_bindArgumentIndex, value);
1019 m_bindArgumentIndex++;
1026 BindVisitor visitor(this->m_command);
1027 m_row.VisitColumns(visitor);
1029 this->m_bindArgumentIndex = visitor.m_bindArgumentIndex;
1030 QueryWithWhereClause<TableDefinition>::Bind();
1035 explicit Update(IOrmInterface *interface = NULL,
1036 const DPL::Optional<std::string>& orClause = DPL::Optional<std::string>::Null) :
1037 QueryWithWhereClause<TableDefinition>(interface),
1038 m_orClause(orClause)
1042 void Values(const Row& row)
1044 if ( this->m_command )
1046 if ( !row.IsSignatureMatching(m_row) )
1048 ThrowMsg(Exception::SelectReuseWithDifferentQuerySignature,
1049 "Current ORM implementation doesn't allow to reuse Update instance "
1050 "with different query signature.");
1060 this->m_command->Step();
1061 this->m_command->Reset();