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);
80 class __attribute__ ((visibility("hidden"))) Expression {
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 __attribute__ ((visibility("hidden"))) 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 __attribute__ ((visibility("hidden"))) 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);
146 template<typename ColumnData, const char* Relation>
147 class __attribute__ ((visibility("hidden"))) Compare : public ExpressionWithArgument<typename ColumnData::ColumnType> {
149 explicit Compare(typename ColumnData::ColumnType column) :
150 ExpressionWithArgument<typename ColumnData::ColumnType>(column)
153 virtual std::string GetString() const
155 std::string statement;
156 statement += ColumnData::GetTableName();
158 statement += ColumnData::GetColumnName();
160 statement += Relation;
165 template<typename TableDefinition>
166 struct ValidForTable {
167 typedef typename TableDefinition::ColumnList::template Contains<ColumnData> Yes;
170 #define ORM_DEFINE_COMPARE_EXPRESSION(name, relationType) \
171 template<typename ColumnData> \
172 class __attribute__ ((visibility("hidden"))) name : public Compare<ColumnData, RelationTypes::relationType> { \
174 name(typename ColumnData::ColumnType column) : \
175 Compare<ColumnData, RelationTypes::relationType>(column) \
179 ORM_DEFINE_COMPARE_EXPRESSION(Equals, Equal)
180 ORM_DEFINE_COMPARE_EXPRESSION(Is, Is)
182 template<typename ColumnData1, typename ColumnData2>
183 class __attribute__ ((visibility("hidden"))) CompareBinaryColumn {
185 std::string m_relation;
187 CompareBinaryColumn(const char* Relation) :
191 virtual ~CompareBinaryColumn() {}
193 virtual std::string GetString() const
195 std::string statement;
196 statement += ColumnData1::GetTableName();
198 statement += ColumnData1::GetColumnName();
200 statement += m_relation;
202 statement += ColumnData2::GetTableName();
204 statement += ColumnData2::GetColumnName();
210 template<typename ColumnData1, typename ColumnData2>
211 CompareBinaryColumn<ColumnData1, ColumnData2>
214 return CompareBinaryColumn<ColumnData1, ColumnData2>(RelationTypes::Equal);
217 template<typename ColumnData, const char* Relation>
218 class __attribute__ ((visibility("hidden"))) NumerousArguments : public Expression {
220 std::set<typename ColumnData::ColumnType> m_argumentList;
222 NumerousArguments(const std::set<typename ColumnData::ColumnType>& argumentList) : m_argumentList(argumentList) {}
224 virtual std::string GetString() const
226 std::string statement;
227 statement += ColumnData::GetColumnName();
229 statement += Relation;
232 int argumentCount = m_argumentList.size();
248 virtual ArgumentIndex BindTo(DataCommand *command, ArgumentIndex index)
250 ArgumentIndex argumentIndex = index;
251 FOREACH(argumentIt, m_argumentList)
253 DataCommandUtils::BindArgument(command, argumentIndex, *argumentIt);
256 return argumentIndex + 1;
259 template<typename TableDefinition>
260 struct ValidForTable {
261 typedef typename TableDefinition::ColumnList::template Contains<ColumnData> Yes;
265 #define ORM_DEFINE_COMPARE_EXPRESSION_NUMEROUS_ARGUMENTS(name, relationType) \
266 template<typename ColumnData> \
267 class __attribute__ ((visibility("hidden"))) name : public NumerousArguments<ColumnData, RelationTypes::relationType> { \
269 name(std::set<typename ColumnData::ColumnType> column) : \
270 NumerousArguments<ColumnData, RelationTypes::relationType>(column) \
274 ORM_DEFINE_COMPARE_EXPRESSION_NUMEROUS_ARGUMENTS(In, In)
276 template<typename ColumnType>
277 ColumnType GetColumnFromCommand(ColumnIndex columnIndex, DataCommand *command);
279 class __attribute__ ((visibility("hidden"))) CustomColumnBase {
281 CustomColumnBase() {}
282 virtual ~CustomColumnBase() {}
285 template<typename ColumnType>
286 class __attribute__ ((visibility("hidden"))) CustomColumn : public CustomColumnBase {
288 ColumnType m_columnData;
292 CustomColumn(ColumnType data)
297 void SetColumnData(ColumnType data)
302 ColumnType GetColumnData() const
308 template<typename ColumnList>
309 class __attribute__ ((visibility("hidden"))) CustomRowUtil {
311 static void MakeColumnList(std::vector<CustomColumnBase*>& columnList)
313 typedef CustomColumn<typename ColumnList::Head::ColumnType> Type;
314 Type* pColumn = new Type();
315 columnList.push_back(pColumn);
316 CustomRowUtil<typename ColumnList::Tail>::MakeColumnList(columnList);
319 static void CopyColumnList(const std::vector<CustomColumnBase*>& srcList, std::vector<CustomColumnBase*>& dstList)
321 CopyColumnList(srcList, dstList, 0);
324 static ColumnIndex GetColumnIndex(const std::string& columnName)
326 return GetColumnIndex(columnName, 0);
330 static void CopyColumnList(const std::vector<CustomColumnBase*>& srcList, std::vector<CustomColumnBase*>& dstList, ColumnIndex index)
332 typedef CustomColumn<typename ColumnList::Head::ColumnType> Type;
333 Type* pColumn = new Type(((Type*)(srcList.at(index)))->GetColumnData());
334 dstList.push_back(pColumn);
335 CustomRowUtil<typename ColumnList::Tail>::CopyColumnList(srcList, dstList, index + 1);
338 static ColumnIndex GetColumnIndex(const std::string& columnName, ColumnIndex index)
340 if (ColumnList::Head::GetColumnName() == columnName)
343 return CustomRowUtil<typename ColumnList::Tail>::GetColumnIndex(columnName, index + 1);
346 template<typename Other>
347 friend class CustomRowUtil;
351 class __attribute__ ((visibility("hidden"))) CustomRowUtil<DPL::TypeListGuard> {
353 static void MakeColumnList(std::vector<CustomColumnBase*>&) {}
355 static void CopyColumnList(const std::vector<CustomColumnBase*>&, std::vector<CustomColumnBase*>&, ColumnIndex) {}
356 static ColumnIndex GetColumnIndex(const std::string&, ColumnIndex) { return -1; }
358 template<typename Other>
359 friend class CustomRowUtil;
362 template<typename ColumnList>
363 class __attribute__ ((visibility("hidden"))) CustomRow {
365 std::vector<CustomColumnBase*> m_columns;
370 CustomRowUtil<ColumnList>::MakeColumnList(m_columns);
373 CustomRow(const CustomRow& r)
375 CustomRowUtil<ColumnList>::CopyColumnList(r.m_columns, m_columns);
380 while (!m_columns.empty())
382 CustomColumnBase* pCustomColumn = m_columns.back();
383 m_columns.pop_back();
385 delete pCustomColumn;
389 template<typename ColumnType>
390 void SetColumnData(ColumnIndex columnIndex, ColumnType data)
392 typedef CustomColumn<ColumnType> Type;
393 Assert(columnIndex < m_columns.size());
394 Type* pColumn = dynamic_cast<Type*>(m_columns.at(columnIndex));
396 pColumn->SetColumnData(data);
399 template<typename ColumnData>
400 typename ColumnData::ColumnType GetColumnData()
402 typedef CustomColumn<typename ColumnData::ColumnType> Type;
403 ColumnIndex index = CustomRowUtil<ColumnList>::GetColumnIndex(ColumnData::GetColumnName());
404 Assert(index < m_columns.size());
405 Type* pColumn = dynamic_cast<Type*>(m_columns.at(index));
407 return pColumn->GetColumnData();
411 template<typename CustomRow, typename ColumnType>
412 void SetColumnData(CustomRow& row, ColumnType columnData, ColumnIndex columnIndex)
414 row.SetColumnData<ColumnType>(columnIndex, columnData);
417 template<typename ColumnList, typename CustomRow>
418 class __attribute__ ((visibility("hidden"))) FillCustomRowUtil {
420 static void FillCustomRow(CustomRow& row, DataCommand* command)
422 FillCustomRow(row, 0, command);
426 static void FillCustomRow(CustomRow& row, ColumnIndex columnIndex, DataCommand* command)
428 typename ColumnList::Head::ColumnType columnData;
429 columnData = GetColumnFromCommand<typename ColumnList::Head::ColumnType>(columnIndex, command);
430 SetColumnData<CustomRow, typename ColumnList::Head::ColumnType>(row, columnData, columnIndex);
431 FillCustomRowUtil<typename ColumnList::Tail, CustomRow>::FillCustomRow(row, columnIndex + 1, command);
434 template<typename Other, typename OtherRow>
435 friend class FillCustomRowUtil;
438 template<typename CustomRow>
439 class __attribute__ ((visibility("hidden"))) FillCustomRowUtil<DPL::TypeListGuard, CustomRow> {
441 static void FillCustomRow(CustomRow&, ColumnIndex, DataCommand *)
442 { /* do nothing, we're past the last element of column list */ }
444 template<typename Other, typename OtherRow>
445 friend class FillCustomRowUtil;
448 template<typename ColumnList, typename Row>
449 class __attribute__ ((visibility("hidden"))) FillRowUtil {
451 static void FillRow(Row& row, DataCommand *command)
453 FillRow(row, 0, command);
457 static void FillRow(Row& row, ColumnIndex columnIndex, DataCommand *command)
459 typename ColumnList::Head::ColumnType rowField;
460 rowField = GetColumnFromCommand<typename ColumnList::Head::ColumnType>(columnIndex, command);
461 ColumnList::Head::SetRowField(row, rowField);
462 FillRowUtil<typename ColumnList::Tail, Row>::FillRow(row, columnIndex + 1, command);
465 template<typename Other, typename OtherRow>
466 friend class FillRowUtil;
469 template<typename Row>
470 class __attribute__ ((visibility("hidden"))) FillRowUtil<DPL::TypeListGuard, Row> {
472 static void FillRow(Row&, ColumnIndex, DataCommand *)
473 { /* do nothing, we're past the last element of column list */ }
475 template<typename Other, typename OtherRow>
476 friend class FillRowUtil;
479 template<typename ColumnList>
480 class __attribute__ ((visibility("hidden"))) JoinUtil {
482 static std::string GetColumnNames()
485 result = ColumnList::Head::GetTableName();
487 result += ColumnList::Head::GetColumnName();
488 if (ColumnList::Tail::Size > 0)
491 return result += JoinUtil<typename ColumnList::Tail>::GetColumnNames();
494 static std::string GetJoinTableName(const std::string& tableName)
496 std::string joinTableName = ColumnList::Head::GetTableName();
497 if (tableName.find(joinTableName) == std::string::npos)
498 return joinTableName;
500 return JoinUtil<typename ColumnList::Tail>::GetJoinTableName(tableName);
505 class __attribute__ ((visibility("hidden"))) JoinUtil<DPL::TypeListGuard> {
507 static std::string GetColumnNames() { return ""; }
508 static std::string GetJoinTableName(std::string) { return ""; }
513 DECLARE_EXCEPTION_TYPE(DPL::Exception, Base)
514 DECLARE_EXCEPTION_TYPE(Base, SelectReuseWithDifferentQuerySignature)
515 DECLARE_EXCEPTION_TYPE(Base, RowFieldNotInitialized)
516 DECLARE_EXCEPTION_TYPE(Base, EmptyUpdateStatement)
519 template<typename TableDefinition>
520 class __attribute__ ((visibility("hidden"))) Query
523 explicit Query(IOrmInterface* interface) :
524 m_interface(interface),
531 if (m_command == NULL)
534 TableDefinition::FreeTableDataCommand(m_command, m_interface);
537 IOrmInterface* m_interface;
538 DataCommand *m_command;
539 std::string m_commandString;
540 ArgumentIndex m_bindArgumentIndex;
543 template<typename TableDefinition>
544 class __attribute__ ((visibility("hidden"))) QueryWithWhereClause : public Query<TableDefinition>
547 ExpressionPtr m_whereExpression;
551 if ( !!m_whereExpression )
553 this->m_commandString += " WHERE ";
554 this->m_commandString += m_whereExpression->GetString();
560 if ( !!m_whereExpression )
562 this->m_bindArgumentIndex = m_whereExpression->BindTo(
563 this->m_command, this->m_bindArgumentIndex);
568 explicit QueryWithWhereClause(IOrmInterface* interface) :
569 Query<TableDefinition>(interface)
573 template<typename Expression>
574 void Where(const Expression& expression)
576 DPL_CHECK_TYPE_INSTANTIABILITY(typename Expression::template ValidForTable<TableDefinition>::Yes);
577 if ( !!m_whereExpression && ( typeid(Expression) != typeid(*m_whereExpression) ) )
579 std::ostringstream str;
580 str << "Current ORM implementation doesn't allow to reuse Select"
581 " instance with different query signature (particularly "
582 "WHERE on different column).\n";
584 str << this->m_commandString;
585 ThrowMsg(Exception::SelectReuseWithDifferentQuerySignature,
588 //TODO maybe don't make a copy here but just generate the string part of the query.
589 m_whereExpression.Reset(new Expression(expression));
594 template<typename TableDefinition>
595 class __attribute__ ((visibility("hidden"))) Delete : public QueryWithWhereClause<TableDefinition>
600 if ( !this->m_command)
602 this->m_commandString = "DELETE FROM ";
603 this->m_commandString += TableDefinition::GetName();
605 QueryWithWhereClause<TableDefinition>::Prepare();
607 this->m_command = TableDefinition::AllocTableDataCommand(
608 this->m_commandString.c_str(),
609 Query<TableDefinition>::m_interface);
610 LogPedantic("Prepared SQL command " << this->m_commandString);
616 this->m_bindArgumentIndex = 1;
617 QueryWithWhereClause<TableDefinition>::Bind();
621 explicit Delete(IOrmInterface *interface = NULL) :
622 QueryWithWhereClause<TableDefinition>(interface)
630 this->m_command->Step();
631 this->m_command->Reset();
635 template<typename TableDefinition>
636 class __attribute__ ((visibility("hidden"))) Insert : public Query<TableDefinition>
639 typedef typename TableDefinition::Row Row;
640 typedef DPL::DB::SqlConnection::RowID RowID;
643 DPL::Optional<std::string> m_orClause;
646 class PrepareVisitor {
648 std::string m_columnNames;
649 std::string m_values;
651 template<typename ColumnType>
652 void Visit(const char* name, const ColumnType&, bool isSet)
656 if ( !m_columnNames.empty() )
658 m_columnNames += ", ";
661 m_columnNames += name;
669 if ( !this->m_command )
671 this->m_commandString = "INSERT ";
674 this->m_commandString += " OR " + *m_orClause + " ";
676 this->m_commandString += "INTO ";
677 this->m_commandString += TableDefinition::GetName();
679 PrepareVisitor visitor;
680 m_row.VisitColumns(visitor);
682 this->m_commandString += " ( " + visitor.m_columnNames + " ) ";
683 this->m_commandString += "VALUES ( " + visitor.m_values + " )";
685 LogPedantic("Prepared SQL command " << this->m_commandString);
686 this->m_command = TableDefinition::AllocTableDataCommand(
687 this->m_commandString.c_str(),
688 Query<TableDefinition>::m_interface);
694 DataCommand *m_command;
695 ArgumentIndex m_bindArgumentIndex;
697 BindVisitor(DataCommand *command) :
699 m_bindArgumentIndex(1)
702 template<typename ColumnType>
703 void Visit(const char*, const ColumnType& value, bool isSet)
707 DataCommandUtils::BindArgument(m_command, m_bindArgumentIndex, value);
708 m_bindArgumentIndex++;
715 BindVisitor visitor(this->m_command);
716 m_row.VisitColumns(visitor);
721 IOrmInterface* interface = NULL,
722 const DPL::Optional<std::string>& orClause = DPL::Optional<std::string>::Null) :
723 Query<TableDefinition>(interface),
728 void Values(const Row& row)
730 if ( this->m_command )
732 if ( !row.IsSignatureMatching(m_row) )
734 ThrowMsg(Exception::SelectReuseWithDifferentQuerySignature,
735 "Current ORM implementation doesn't allow to reuse Insert instance "
736 "with different query signature.");
746 this->m_command->Step();
748 RowID result = TableDefinition::GetLastInsertRowID(
749 Query<TableDefinition>::m_interface);
751 this->m_command->Reset();
756 template<typename TableDefinition>
757 class __attribute__ ((visibility("hidden"))) Select : public QueryWithWhereClause<TableDefinition>
760 typedef typename TableDefinition::ColumnList ColumnList;
761 typedef typename TableDefinition::Row Row;
763 typedef std::list<Row> RowList;
765 DPL::Optional<std::string> m_orderBy;
766 std::string m_JoinClause;
767 bool m_distinctResults;
769 void Prepare(const char* selectColumnName)
771 if ( !this->m_command )
773 this->m_commandString = "SELECT ";
774 if (m_distinctResults)
775 this->m_commandString += "DISTINCT ";
776 this->m_commandString += selectColumnName;
777 this->m_commandString += " FROM ";
778 this->m_commandString += TableDefinition::GetName();
780 this->m_commandString += m_JoinClause;
782 QueryWithWhereClause<TableDefinition>::Prepare();
784 if ( !m_orderBy.IsNull() )
786 this->m_commandString += " ORDER BY " + *m_orderBy;
789 this->m_command = TableDefinition::AllocTableDataCommand(
790 this->m_commandString.c_str(),
791 Query<TableDefinition>::m_interface);
793 LogPedantic("Prepared SQL command " << this->m_commandString);
799 this->m_bindArgumentIndex = 1;
800 QueryWithWhereClause<TableDefinition>::Bind();
803 template<typename ColumnType>
804 ColumnType GetColumn(ColumnIndex columnIndex)
806 return GetColumnFromCommand<ColumnType>(columnIndex, this->m_command);
812 FillRowUtil<ColumnList, Row>::FillRow(row, this->m_command);
816 template<typename ColumnList, typename CustomRow>
817 CustomRow GetCustomRow()
820 FillCustomRowUtil<ColumnList, CustomRow>::FillCustomRow(row, this->m_command);
826 explicit Select(IOrmInterface *interface = NULL) :
827 QueryWithWhereClause<TableDefinition>(interface),
828 m_distinctResults(false)
834 m_distinctResults = true;
837 void OrderBy(const std::string& orderBy)
842 template<typename ColumnList, typename Expression>
843 void Join(const Expression& expression) {
844 std::string usedTableNames = TableDefinition::GetName();
845 if (!m_JoinClause.empty())
846 usedTableNames += m_JoinClause;
848 this->m_JoinClause += " JOIN ";
849 this->m_JoinClause += JoinUtil<ColumnList>::GetJoinTableName(usedTableNames);
850 this->m_JoinClause += " ON ";
851 this->m_JoinClause += expression.GetString();
854 template<typename ColumnData>
855 typename ColumnData::ColumnType GetSingleValue()
857 Prepare(ColumnData::GetColumnName());
859 this->m_command->Step();
861 typename ColumnData::ColumnType result =
862 GetColumn<typename ColumnData::ColumnType>(0);
864 this->m_command->Reset();
868 //TODO return range - pair of custom iterators
869 template<typename ColumnData>
870 std::list<typename ColumnData::ColumnType> GetValueList()
872 Prepare(ColumnData::GetColumnName());
875 std::list<typename ColumnData::ColumnType> resultList;
877 while (this->m_command->Step())
878 resultList.push_back(GetColumn<typename ColumnData::ColumnType>(0));
880 this->m_command->Reset();
888 this->m_command->Step();
890 Row result = GetRow();
892 this->m_command->Reset();
896 //TODO return range - pair of custom iterators
904 while (this->m_command->Step())
905 resultList.push_back(GetRow());
907 this->m_command->Reset();
911 template<typename ColumnList, typename CustomRow>
912 CustomRow GetCustomSingleRow()
914 Prepare(JoinUtil<ColumnList>::GetColumnNames().c_str());
916 this->m_command->Step();
918 CustomRow result = GetCustomRow<ColumnList, CustomRow>();
920 this->m_command->Reset();
924 template<typename ColumnList, typename CustomRow>
925 std::list<CustomRow> GetCustomRowList()
927 Prepare(JoinUtil<ColumnList>::GetColumnNames().c_str());
930 std::list<CustomRow> resultList;
932 while (this->m_command->Step())
933 resultList.push_back(GetCustomRow<ColumnList, CustomRow>());
935 this->m_command->Reset();
940 template<typename TableDefinition>
941 class __attribute__ ((visibility("hidden"))) Update : public QueryWithWhereClause<TableDefinition> {
943 typedef typename TableDefinition::Row Row;
946 DPL::Optional<std::string> m_orClause;
949 class PrepareVisitor {
951 std::string m_setExpressions;
953 template<typename ColumnType>
954 void Visit(const char* name, const ColumnType&, bool isSet)
958 if ( !m_setExpressions.empty() )
960 m_setExpressions += ", ";
962 m_setExpressions += name;
963 m_setExpressions += " = ";
964 m_setExpressions += "?";
971 if ( !this->m_command )
973 this->m_commandString = "UPDATE ";
976 this->m_commandString += " OR " + *m_orClause + " ";
978 this->m_commandString += TableDefinition::GetName();
979 this->m_commandString += " SET ";
981 // got through row columns and values
982 PrepareVisitor visitor;
983 m_row.VisitColumns(visitor);
985 if(visitor.m_setExpressions.empty())
987 ThrowMsg(Exception::EmptyUpdateStatement, "No SET expressions in update statement");
990 this->m_commandString += visitor.m_setExpressions;
993 QueryWithWhereClause<TableDefinition>::Prepare();
995 this->m_command = TableDefinition::AllocTableDataCommand(
996 this->m_commandString.c_str(),
997 Query<TableDefinition>::m_interface);
998 LogPedantic("Prepared SQL command " << this->m_commandString);
1004 DataCommand *m_command;
1007 ArgumentIndex m_bindArgumentIndex;
1009 BindVisitor(DataCommand *command) :
1011 m_bindArgumentIndex(1)
1014 template<typename ColumnType>
1015 void Visit(const char*, const ColumnType& value, bool isSet)
1019 DataCommandUtils::BindArgument(m_command, m_bindArgumentIndex, value);
1020 m_bindArgumentIndex++;
1027 BindVisitor visitor(this->m_command);
1028 m_row.VisitColumns(visitor);
1030 this->m_bindArgumentIndex = visitor.m_bindArgumentIndex;
1031 QueryWithWhereClause<TableDefinition>::Bind();
1036 explicit Update(IOrmInterface *interface = NULL,
1037 const DPL::Optional<std::string>& orClause = DPL::Optional<std::string>::Null) :
1038 QueryWithWhereClause<TableDefinition>(interface),
1039 m_orClause(orClause)
1043 void Values(const Row& row)
1045 if ( this->m_command )
1047 if ( !row.IsSignatureMatching(m_row) )
1049 ThrowMsg(Exception::SelectReuseWithDifferentQuerySignature,
1050 "Current ORM implementation doesn't allow to reuse Update instance "
1051 "with different query signature.");
1061 this->m_command->Step();
1062 this->m_command->Reset();