Index: src/libchcore/ErrorCodes.h =================================================================== diff -u -r30297d6aab17483da8e7b8323b4d17ff1a9f78d6 -r5693271a6736f524997e3951fc7b7b6323bc6447 --- src/libchcore/ErrorCodes.h (.../ErrorCodes.h) (revision 30297d6aab17483da8e7b8323b4d17ff1a9f78d6) +++ src/libchcore/ErrorCodes.h (.../ErrorCodes.h) (revision 5693271a6736f524997e3951fc7b7b6323bc6447) @@ -68,6 +68,7 @@ eErr_UnsupportedMultipleSubnodesLevels = 2505, eErr_CannotWriteArchive = 2506, eErr_InvalidSerializationData = 2507, + eErr_CannotSetDatabaseOptions = 2508, // Filesystem errors (3000+) eErr_FixedDriveWithoutDriveLetter = 3000, Index: src/libchcore/SerializerTrace.h =================================================================== diff -u --- src/libchcore/SerializerTrace.h (revision 0) +++ src/libchcore/SerializerTrace.h (revision 5693271a6736f524997e3951fc7b7b6323bc6447) @@ -0,0 +1,50 @@ +// ============================================================================ +// Copyright (C) 2001-2014 by Jozef Starosczyk +// ixen@copyhandler.com +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// (version 2) as published by the Free Software Foundation; +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this program; if not, write to the +// Free Software Foundation, Inc., +// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// ============================================================================ +#ifndef __SERIALIZERTRACE_H__ +#define __SERIALIZERTRACE_H__ + +#include + +#define TRACK_DB_QUERIES +//#define TRACK_DB_QUERIES_DETAILED + +#ifdef TRACK_DB_QUERIES + #define DBTRACE(fmt, val) ATLTRACE(fmt, val) + #define DBTRACE0(fmt) ATLTRACE(fmt) + #define DBTRACE2(fmt, val1, val2) ATLTRACE(fmt, val1, val2) + + #ifdef TRACK_DB_QUERIES_DETAILED + #define DBTRACE_D(fmt, val) ATLTRACE(fmt, val) + #define DBTRACE0_D(fmt) ATLTRACE(fmt) + #define DBTRACE2_D(fmt, val1, val2) ATLTRACE(fmt, val1, val2) + #else + #define DBTRACE_D(fmt, val) __noop; + #define DBTRACE0_D(fmt) __noop + #define DBTRACE2_D(fmt, val1, val2) __noop; + #endif +#else + #define DBTRACE(fmt, val) __noop; + #define DBTRACE0(fmt) __noop + #define DBTRACE2(fmt, val1, val2) __noop; + #define DBTRACE_D(fmt, val) __noop; + #define DBTRACE0_D(fmt) __noop + #define DBTRACE2_D(fmt, val1, val2) __noop; +#endif + +#endif Index: src/libchcore/TSQLiteSerializer.cpp =================================================================== diff -u -r30297d6aab17483da8e7b8323b4d17ff1a9f78d6 -r5693271a6736f524997e3951fc7b7b6323bc6447 --- src/libchcore/TSQLiteSerializer.cpp (.../TSQLiteSerializer.cpp) (revision 30297d6aab17483da8e7b8323b4d17ff1a9f78d6) +++ src/libchcore/TSQLiteSerializer.cpp (.../TSQLiteSerializer.cpp) (revision 5693271a6736f524997e3951fc7b7b6323bc6447) @@ -22,6 +22,9 @@ #include "TCoreException.h" #include "ErrorCodes.h" #include "TSQLiteTransaction.h" +#include "TSQLiteStatement.h" +#include "TSimpleTimer.h" +#include "SerializerTrace.h" BEGIN_CHCORE_NAMESPACE @@ -34,6 +37,9 @@ if(!m_spDatabase || !m_spSchema) THROW_CORE_EXCEPTION(eErr_InvalidArgument); + // initialize db params + SetupDBOptions(); + m_spSchema->Setup(m_spDatabase); } @@ -55,16 +61,42 @@ void TSQLiteSerializer::Flush() { + DBTRACE0(_T(" ## Serializer::Flush() - started\n")); + TSQLiteTransaction tran(m_spDatabase); + TSimpleTimer timer(true); + for(ContainerMap::iterator iterContainer = m_mapContainers.begin(); iterContainer != m_mapContainers.end(); ++iterContainer) { iterContainer->second->Flush(); } + unsigned long long ullFlushGatherTime = timer.Checkpoint(); ullFlushGatherTime; + tran.Commit(); + unsigned long long ullFlushCommitTime = timer.Checkpoint(); ullFlushCommitTime; + DBTRACE2(_T(" ## Serializer::Flush() - container flushes: %I64u ms, transaction commit: %I64u ms\n"), ullFlushGatherTime, ullFlushCommitTime); + m_mapContainers.clear(); + + unsigned long long ullFlushClearTime = timer.Stop(); ullFlushClearTime; + DBTRACE(_T(" ## Serializer::Flush() - container clearing: %I64u ms\n"), ullFlushClearTime); } +void TSQLiteSerializer::SetupDBOptions() +{ +/* + TSQLiteStatement tStatement(m_spDatabase); + tStatement.Prepare(_T("PRAGMA JOURNAL_MODE=WAL")); + TSQLiteStatement::EStepResult eResult = tStatement.Step(); + if(eResult != TSQLiteStatement::eStep_HasRow) + THROW_CORE_EXCEPTION(eErr_CannotSetDatabaseOptions); + + TString strResult = tStatement.GetText(0); + if(strResult != _T("wal")) + THROW_CORE_EXCEPTION(eErr_CannotSetDatabaseOptions);*/ +} + END_CHCORE_NAMESPACE Index: src/libchcore/TSQLiteSerializer.h =================================================================== diff -u -r0c5027d5173ab0daeba6aa6b735a2b11d4cd2164 -r5693271a6736f524997e3951fc7b7b6323bc6447 --- src/libchcore/TSQLiteSerializer.h (.../TSQLiteSerializer.h) (revision 0c5027d5173ab0daeba6aa6b735a2b11d4cd2164) +++ src/libchcore/TSQLiteSerializer.h (.../TSQLiteSerializer.h) (revision 5693271a6736f524997e3951fc7b7b6323bc6447) @@ -40,6 +40,7 @@ virtual ISerializerContainerPtr GetContainer(const TString& strContainerName); virtual void Flush(); + void SetupDBOptions(); private: #pragma warning(push) Index: src/libchcore/TSQLiteSerializerContainer.cpp =================================================================== diff -u -r293e52b38d46653068006262172018a0f0d0a31c -r5693271a6736f524997e3951fc7b7b6323bc6447 --- src/libchcore/TSQLiteSerializerContainer.cpp (.../TSQLiteSerializerContainer.cpp) (revision 293e52b38d46653068006262172018a0f0d0a31c) +++ src/libchcore/TSQLiteSerializerContainer.cpp (.../TSQLiteSerializerContainer.cpp) (revision 5693271a6736f524997e3951fc7b7b6323bc6447) @@ -26,6 +26,7 @@ #include "TSQLiteSerializerRowReader.h" #include #include "TRemovedObjects.h" +#include "SerializerTrace.h" BEGIN_CHCORE_NAMESPACE @@ -100,10 +101,44 @@ { FlushDeletions(); + // group rows that can be executed with one preparation + std::map> mapGroups; + std::map>::iterator iterMapGroups; + for(RowMap::iterator iterRows = m_mapRows.begin(); iterRows != m_mapRows.end(); ++iterRows) { - iterRows->second->Flush(m_spDB, m_strName); + TRowID rowID = iterRows->second->GetChangeIdentification(); + iterMapGroups = mapGroups.find(rowID); + if(iterMapGroups == mapGroups.end()) + iterMapGroups = mapGroups.insert(std::make_pair(rowID, std::vector())).first; + + iterMapGroups->second.push_back(iterRows->second); } + + TSQLiteStatement tStatement(m_spDB); + + for(iterMapGroups = mapGroups.begin(); iterMapGroups != mapGroups.end(); ++iterMapGroups) + { + if(iterMapGroups->first.HasAny()) + { + std::vector& rGroupRows = iterMapGroups->second; + + // query is generated from the first item in a group + TString strQuery = rGroupRows.front()->GetQuery(m_strName); + + DBTRACE2(_T("Preparing query for %lu records: %s\n"), (unsigned long)iterMapGroups->second.size(), (PCTSTR)strQuery); + + tStatement.Prepare(strQuery); + + for(std::vector::iterator iterRow = iterMapGroups->second.begin(); iterRow != iterMapGroups->second.end(); ++iterRow) + { + (*iterRow)->BindParamsAndExec(tStatement); + tStatement.ClearBindings(); + } + + tStatement.Close(); + } + } } void TSQLiteSerializerContainer::FlushDeletions() Index: src/libchcore/TSQLiteSerializerRowData.cpp =================================================================== diff -u -r19925be73ffcadd9f345f10e03e55aadb3f0eeac -r5693271a6736f524997e3951fc7b7b6323bc6447 --- src/libchcore/TSQLiteSerializerRowData.cpp (.../TSQLiteSerializerRowData.cpp) (revision 19925be73ffcadd9f345f10e03e55aadb3f0eeac) +++ src/libchcore/TSQLiteSerializerRowData.cpp (.../TSQLiteSerializerRowData.cpp) (revision 5693271a6736f524997e3951fc7b7b6323bc6447) @@ -23,6 +23,7 @@ #include #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 Index: src/libchcore/TSQLiteSerializerRowData.h =================================================================== diff -u -r31c4b1fc46687ed2cf35dd9fa0acec2543ae1886 -r5693271a6736f524997e3951fc7b7b6323bc6447 --- src/libchcore/TSQLiteSerializerRowData.h (.../TSQLiteSerializerRowData.h) (revision 31c4b1fc46687ed2cf35dd9fa0acec2543ae1886) +++ src/libchcore/TSQLiteSerializerRowData.h (.../TSQLiteSerializerRowData.h) (revision 5693271a6736f524997e3951fc7b7b6323bc6447) @@ -25,9 +25,34 @@ #include "ISerializerContainer.h" #include "TRowData.h" #include "TSQLiteDatabase.h" +#include "TSQLiteStatement.h" +#include BEGIN_CHCORE_NAMESPACE +class LIBCHCORE_API TRowID +{ +public: + TRowID(const TSQLiteColumnDefinitionPtr& spColumnDefinition); + ~TRowID(); + + void Clear(); + + void SetAddedBit(bool bAdded); + void SetColumnBit(size_t stIndex, bool bColumnExists); + + bool HasAny() const; + + bool operator==(const TRowID rSrc) const; + bool operator<(const TRowID rSrc) const; + +private: +#pragma warning(push) +#pragma warning(disable: 4251) + boost::dynamic_bitset<> m_bitset; +#pragma warning(pop) +}; + class LIBCHCORE_API TSQLiteSerializerRowData : public ISerializerRowData { public: @@ -37,8 +62,11 @@ virtual ISerializerRowData& operator%(const TRowData& rData); virtual ISerializerRowData& SetValue(const TRowData& rData); - void Flush(const sqlite::TSQLiteDatabasePtr& spDatabase, const TString& strContainerName); + TString GetQuery(const TString& strContainerName) const; + TRowID GetChangeIdentification() const; + void BindParamsAndExec(sqlite::TSQLiteStatement& tStatement); + private: size_t m_stRowID; bool m_bAdded; Index: src/libchcore/TSimpleTimer.cpp =================================================================== diff -u -r320c4eb6ba3a38dcd6fbda6a9a12a8350a153e41 -r5693271a6736f524997e3951fc7b7b6323bc6447 --- src/libchcore/TSimpleTimer.cpp (.../TSimpleTimer.cpp) (revision 320c4eb6ba3a38dcd6fbda6a9a12a8350a153e41) +++ src/libchcore/TSimpleTimer.cpp (.../TSimpleTimer.cpp) (revision 5693271a6736f524997e3951fc7b7b6323bc6447) @@ -69,6 +69,20 @@ return ullCurrent; } +unsigned long long TSimpleTimer::Checkpoint() +{ + if(m_bStarted) + { + Tick(); + unsigned long long ullCurrentTotal = m_ullTotalTime; + m_ullTotalTime = 0; + + return ullCurrentTotal; + } + else + return 0; +} + void TSimpleTimer::Reset() { m_bStarted = false; Index: src/libchcore/TSimpleTimer.h =================================================================== diff -u -r320c4eb6ba3a38dcd6fbda6a9a12a8350a153e41 -r5693271a6736f524997e3951fc7b7b6323bc6447 --- src/libchcore/TSimpleTimer.h (.../TSimpleTimer.h) (revision 320c4eb6ba3a38dcd6fbda6a9a12a8350a153e41) +++ src/libchcore/TSimpleTimer.h (.../TSimpleTimer.h) (revision 5693271a6736f524997e3951fc7b7b6323bc6447) @@ -36,6 +36,8 @@ unsigned long long Stop(); // returns total time unsigned long long Tick(); // returns current timestamp + unsigned long long Checkpoint(); // returns current total time and restarts the timer + void Reset(); bool IsRunning() const; Index: src/libchcore/TTask.cpp =================================================================== diff -u -rd0bc3c187684f54894c7280a936d5507a5e49f35 -r5693271a6736f524997e3951fc7b7b6323bc6447 --- src/libchcore/TTask.cpp (.../TTask.cpp) (revision d0bc3c187684f54894c7280a936d5507a5e49f35) +++ src/libchcore/TTask.cpp (.../TTask.cpp) (revision 5693271a6736f524997e3951fc7b7b6323bc6447) @@ -162,6 +162,9 @@ void TTask::Store() { + TSimpleTimer timer(true); + ATLTRACE(_T("###### Task::Store() - starting\n")); + using namespace chcore; { @@ -189,7 +192,12 @@ m_tSubTasksArray.Store(m_spSerializer); } + unsigned long long ullGatherTime = timer.Checkpoint(); ullGatherTime; + m_spSerializer->Flush(); + + unsigned long long ullFlushTime = timer.Stop(); ullFlushTime; + ATLTRACE(_T("###### Task::Store() - finished - gather: %I64u ms, flush: %I64u ms\n"), ullGatherTime, ullFlushTime); } void TTask::KillThread() Index: src/libchcore/TTaskManager.cpp =================================================================== diff -u -rd0bc3c187684f54894c7280a936d5507a5e49f35 -r5693271a6736f524997e3951fc7b7b6323bc6447 --- src/libchcore/TTaskManager.cpp (.../TTaskManager.cpp) (revision d0bc3c187684f54894c7280a936d5507a5e49f35) +++ src/libchcore/TTaskManager.cpp (.../TTaskManager.cpp) (revision 5693271a6736f524997e3951fc7b7b6323bc6447) @@ -432,6 +432,8 @@ void TTaskManager::Store() { + TSimpleTimer timer(true); + ISerializerContainerPtr spContainer = m_spSerializer->GetContainer(_T("tasks")); // store this container information @@ -446,7 +448,12 @@ } } + unsigned long long ullGatherTime = timer.Checkpoint(); ullGatherTime; + m_spSerializer->Flush(); + + unsigned long long ullFlushTime = timer.Stop(); ullFlushTime; + ATLTRACE(_T("TaskManager::Store() - gather: %I64u ms, flush: %I64u ms\n"), ullGatherTime, ullFlushTime); } void TTaskManager::Load() Index: src/libchcore/libchcore.vc90.vcproj =================================================================== diff -u -rb1e03eb232a784d6e2d40f67cbbbb33be0972228 -r5693271a6736f524997e3951fc7b7b6323bc6447 --- src/libchcore/libchcore.vc90.vcproj (.../libchcore.vc90.vcproj) (revision b1e03eb232a784d6e2d40f67cbbbb33be0972228) +++ src/libchcore/libchcore.vc90.vcproj (.../libchcore.vc90.vcproj) (revision 5693271a6736f524997e3951fc7b7b6323bc6447) @@ -1423,6 +1423,10 @@ Name="SQLite" > + +