Index: src/libchcore/TSQLiteSerializerRowData.cpp
===================================================================
diff -u -N -r19925be73ffcadd9f345f10e03e55aadb3f0eeac -r5693271a6736f524997e3951fc7b7b6323bc6447
--- src/libchcore/TSQLiteSerializerRowData.cpp	(.../TSQLiteSerializerRowData.cpp)	(revision 19925be73ffcadd9f345f10e03e55aadb3f0eeac)
+++ src/libchcore/TSQLiteSerializerRowData.cpp	(.../TSQLiteSerializerRowData.cpp)	(revision 5693271a6736f524997e3951fc7b7b6323bc6447)
@@ -23,6 +23,7 @@
 #include <atltrace.h>
 #include "TSerializerException.h"
 #include "ErrorCodes.h"
+#include "SerializerTrace.h"
 
 BEGIN_CHCORE_NAMESPACE
 
@@ -38,86 +39,136 @@
 
 		void operator()(bool value) const
 		{
-			ATLTRACE(_T("- param(bool): %ld\n"), value ? 1l : 0l);
+			DBTRACE_D(_T("- param(bool): %ld\n"), value ? 1l : 0l);
 			m_rStatement.BindValue(m_rColumn++, value);
 		}
 
 		void operator()(short value) const
 		{
-			ATLTRACE(_T("- param(short): %d\n"), value);
+			DBTRACE_D(_T("- param(short): %d\n"), value);
 			m_rStatement.BindValue(m_rColumn++, value);
 		}
 
 		void operator()(unsigned short value) const
 		{
-			ATLTRACE(_T("- param(ushort): %u\n"), value);
+			DBTRACE_D(_T("- param(ushort): %u\n"), value);
 			m_rStatement.BindValue(m_rColumn++, value);
 		}
 
 		void operator()(int value) const
 		{
-			ATLTRACE(_T("- param(int): %ld\n"), value);
+			DBTRACE_D(_T("- param(int): %ld\n"), value);
 			m_rStatement.BindValue(m_rColumn++, value);
 		}
 
 		void operator()(unsigned int value) const
 		{
-			ATLTRACE(_T("- param(uint): %lu\n"), value);
+			DBTRACE_D(_T("- param(uint): %lu\n"), value);
 			m_rStatement.BindValue(m_rColumn++, value);
 		}
 
 		void operator()(long value) const
 		{
-			ATLTRACE(_T("- param(long): %ld\n"), value);
+			DBTRACE_D(_T("- param(long): %ld\n"), value);
 			m_rStatement.BindValue(m_rColumn++, value);
 		}
 
 		void operator()(unsigned long value) const
 		{
-			ATLTRACE(_T("- param(ulong): %lu\n"), value);
+			DBTRACE_D(_T("- param(ulong): %lu\n"), value);
 			m_rStatement.BindValue(m_rColumn++, value);
 		}
 
 		void operator()(long long value) const
 		{
-			ATLTRACE(_T("- param(longlong): %I64d\n"), value);
+			DBTRACE_D(_T("- param(longlong): %I64d\n"), value);
 			m_rStatement.BindValue(m_rColumn++, value);
 		}
 
 		void operator()(unsigned long long value) const
 		{
-			ATLTRACE(_T("- param(ulonglong): %I64u\n"), value);
+			DBTRACE_D(_T("- param(ulonglong): %I64u\n"), value);
 			m_rStatement.BindValue(m_rColumn++, value);
 		}
 
 		void operator()(double value) const
 		{
-			ATLTRACE(_T("- param(double): %f\n"), value);
+			DBTRACE_D(_T("- param(double): %f\n"), value);
 			m_rStatement.BindValue(m_rColumn++, value);
 		}
 
 		void operator()(const TString& value) const
 		{
-			ATLTRACE(_T("- param(string): '%s'\n"), (PCTSTR)value);
+			DBTRACE_D(_T("- param(string): '%s'\n"), (PCTSTR)value);
 			m_rStatement.BindValue(m_rColumn++, value);
 		}
 
 		void operator()(const TSmartPath& value) const
 		{
-			ATLTRACE(_T("- param(path): %s\n"), value.ToString());
+			DBTRACE_D(_T("- param(path): %s\n"), value.ToString());
 			m_rStatement.BindValue(m_rColumn++, value);
 		}
 
 		int& m_rColumn;
 		sqlite::TSQLiteStatement& m_rStatement;
 	};
+
 }
 
+
+///////////////////////////////////////////////////////////////////////////
+TRowID::TRowID(const TSQLiteColumnDefinitionPtr& spColumnDefinition) :
+	m_bitset(spColumnDefinition->GetCount() + 1)	// count of columns and a bit for add/modify
+{
+}
+
+TRowID::~TRowID()
+{
+}
+
+void TRowID::SetAddedBit(bool bAdded)
+{
+	m_bitset[0] = bAdded;
+}
+
+void TRowID::SetColumnBit(size_t stIndex, bool bColumnExists)
+{
+	++stIndex;
+
+	if(stIndex >= m_bitset.size())
+		THROW_SERIALIZER_EXCEPTION(eErr_BoundsExceeded, _T("Row identification info cannot be generated"));
+
+	m_bitset[stIndex] = bColumnExists;
+}
+
+bool TRowID::operator==(const TRowID rSrc) const
+{
+	return m_bitset == rSrc.m_bitset;
+}
+
+bool TRowID::operator<(const TRowID rSrc) const
+{
+	return m_bitset < rSrc.m_bitset;
+}
+
+void TRowID::Clear()
+{
+	m_bitset.reset();
+}
+
+bool TRowID::HasAny() const
+{
+	return m_bitset.any();
+}
+
+///////////////////////////////////////////////////////////////////////////
 TSQLiteSerializerRowData::TSQLiteSerializerRowData(size_t stRowID, const TSQLiteColumnDefinitionPtr& spColumnDefinition, bool bAdded) :
 	m_stRowID(stRowID),
 	m_spColumns(spColumnDefinition),
 	m_bAdded(bAdded)
 {
+	if(!spColumnDefinition)
+		THROW_SERIALIZER_EXCEPTION(eErr_InvalidArgument, _T("No column definition provided"));
 }
 
 TSQLiteSerializerRowData::~TSQLiteSerializerRowData()
@@ -148,19 +199,49 @@
 	return *this;
 }
 
-void TSQLiteSerializerRowData::Flush(const sqlite::TSQLiteDatabasePtr& spDatabase, const TString& strContainerName)
+void TSQLiteSerializerRowData::BindParamsAndExec(sqlite::TSQLiteStatement& tStatement)
 {
 	using namespace sqlite;
 
-	TSQLiteStatement tStatement(spDatabase);
+	if(m_bAdded)
+	{
+		// exec query
+		int iColumn = 1;
+		tStatement.BindValue(iColumn++, m_stRowID);
+		for(MapVariants::iterator iterVariant = m_mapValues.begin(); iterVariant != m_mapValues.end(); ++iterVariant)
+		{
+			boost::apply_visitor(SQLiteBindValueVisitor(tStatement, iColumn), iterVariant->second);
+		}
 
+		tStatement.Step();
+	}
+	else if(!m_mapValues.empty())
+	{
+		int iColumn = 1;
+		for(MapVariants::iterator iterVariant = m_mapValues.begin(); iterVariant != m_mapValues.end(); ++iterVariant)
+		{
+			boost::apply_visitor(SQLiteBindValueVisitor(tStatement, iColumn), iterVariant->second);
+		}
+		tStatement.BindValue(iColumn++, m_stRowID);
+
+		tStatement.Step();
+
+		int iChanges = tStatement.Changes();
+		_ASSERTE(iChanges == 1);
+		if(iChanges != 1)
+			THROW_SERIALIZER_EXCEPTION(eErr_InvalidData, _T("Update query did not update record in the database"));
+	}
+}
+
+TString TSQLiteSerializerRowData::GetQuery(const TString& strContainerName) const
+{
 	if(m_bAdded)
 	{
 		// prepare insert query
 		TString strQuery = boost::str(boost::wformat(L"INSERT INTO %1%(id,") % strContainerName).c_str();
 		TString strParams;
 
-		for(MapVariants::iterator iterVariant = m_mapValues.begin(); iterVariant != m_mapValues.end(); ++iterVariant)
+		for(MapVariants::const_iterator iterVariant = m_mapValues.begin(); iterVariant != m_mapValues.end(); ++iterVariant)
 		{
 			strQuery += boost::str(boost::wformat(_T("%1%,")) % m_spColumns->GetColumnName(iterVariant->first)).c_str();
 			strParams += _T("?,");
@@ -173,48 +254,37 @@
 		strQuery += strParams;
 		strQuery += _T(")");
 
-		// exec query
-		int iColumn = 1;
-		tStatement.Prepare(strQuery);
-		tStatement.BindValue(iColumn++, m_stRowID);
-		for(MapVariants::iterator iterVariant = m_mapValues.begin(); iterVariant != m_mapValues.end(); ++iterVariant)
-		{
-			boost::apply_visitor(SQLiteBindValueVisitor(tStatement, iColumn), iterVariant->second);
-		}
-
-		ATLTRACE(_T("Executing query: %s\n"), (PCTSTR)strQuery);
-		tStatement.Step();
+		return strQuery;
 	}
 	else if(!m_mapValues.empty())
 	{
 		// prepare update query
 		TString strQuery = boost::str(boost::wformat(L"UPDATE %1% SET ") % strContainerName).c_str();
 
-		for(MapVariants::iterator iterVariant = m_mapValues.begin(); iterVariant != m_mapValues.end(); ++iterVariant)
+		for(MapVariants::const_iterator iterVariant = m_mapValues.begin(); iterVariant != m_mapValues.end(); ++iterVariant)
 		{
 			strQuery += boost::str(boost::wformat(_T("%1%=?,")) % m_spColumns->GetColumnName(iterVariant->first)).c_str();
 		}
 
 		strQuery.TrimRightSelf(_T(","));
 		strQuery += _T(" WHERE id=?");
 
-		int iColumn = 1;
+		return strQuery;
+	}
+	else
+		return TString();
+}
 
-		ATLTRACE(_T("Executing query: %s\n"), (PCTSTR)strQuery);
-		tStatement.Prepare(strQuery);
-		for(MapVariants::iterator iterVariant = m_mapValues.begin(); iterVariant != m_mapValues.end(); ++iterVariant)
-		{
-			boost::apply_visitor(SQLiteBindValueVisitor(tStatement, iColumn), iterVariant->second);
-		}
-		tStatement.BindValue(iColumn++, m_stRowID);
-
-		tStatement.Step();
-
-		int iChanges = tStatement.Changes();
-		_ASSERTE(iChanges == 1);
-		if(iChanges != 1)
-			THROW_SERIALIZER_EXCEPTION(eErr_InvalidData, _T("Update query did not update record in the database"));
+TRowID TSQLiteSerializerRowData::GetChangeIdentification() const
+{
+	TRowID rowID(m_spColumns);
+	rowID.SetAddedBit(m_bAdded);
+	for(MapVariants::const_iterator iterVariant = m_mapValues.begin(); iterVariant != m_mapValues.end(); ++iterVariant)
+	{
+		rowID.SetColumnBit(iterVariant->first, true);
 	}
+
+	return rowID;
 }
 
 END_CHCORE_NAMESPACE