diff --git a/.gitignore b/.gitignore index 951d94454..cf52c1cab 100644 --- a/.gitignore +++ b/.gitignore @@ -100,3 +100,6 @@ lib/ lib64/ pocomsg.h +# Temporary files # +################### +*.bak diff --git a/ApacheConnector/ApacheConnector_x64_vs100.vcxproj b/ApacheConnector/ApacheConnector_x64_vs100.vcxproj index 1fcb7634f..2583983fb 100644 --- a/ApacheConnector/ApacheConnector_x64_vs100.vcxproj +++ b/ApacheConnector/ApacheConnector_x64_vs100.vcxproj @@ -1,4 +1,4 @@ - + @@ -16,40 +16,40 @@ ApacheConnector Win32Proj - - + + DynamicLibrary MultiByte - + DynamicLibrary MultiByte - - - - + + + + - - + + - + <_ProjectFileVersion>10.0.40219.1 - ..\bin64\ - obj64\$(Configuration)\ - true - ..\bin64\ - obj64\$(Configuration)\ - false - mod_poco64d - mod_poco64 + ..\bin64\ + obj64\$(Configuration)\ + true + ..\bin64\ + obj64\$(Configuration)\ + false + mod_poco64d + mod_poco64 - + Disabled .\include;..\Foundation\include;..\Net\include;..\Util\include;%(AdditionalIncludeDirectories) - WIN32;_DEBUG;_WINDOWS;_USRDLL;ApacheHandlers_EXPORTS;%(PreprocessorDefinitions) + WIN32;_WIN64;_DEBUG;_WINDOWS;_USRDLL;ApacheHandlers_EXPORTS;%(PreprocessorDefinitions) true true EnableFastChecks @@ -58,7 +58,7 @@ true true true - + Level3 ProgramDatabase Default @@ -76,7 +76,7 @@ MachineX64 - + Disabled OnlyExplicitInline @@ -84,16 +84,16 @@ Speed true .\include;..\Foundation\include;..\Net\include;..\Util\include;%(AdditionalIncludeDirectories) - WIN32;NDEBUG;_WINDOWS;_USRDLL;ApacheHandlers_EXPORTS;%(PreprocessorDefinitions) + WIN32;_WIN64;NDEBUG;_WINDOWS;_USRDLL;ApacheHandlers_EXPORTS;%(PreprocessorDefinitions) true MultiThreadedDLL false true true true - + Level3 - + Default %(DisableSpecificWarnings) @@ -111,23 +111,23 @@ - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - + + + \ No newline at end of file diff --git a/CppUnit/WinTestRunner/src/ActiveTest.h b/CppUnit/WinTestRunner/src/ActiveTest.h index 232747a9c..bf9df5e7d 100644 --- a/CppUnit/WinTestRunner/src/ActiveTest.h +++ b/CppUnit/WinTestRunner/src/ActiveTest.h @@ -38,16 +38,16 @@ public: ActiveTest(Test* test); ~ActiveTest(); - void run(TestResult* result); + void run(TestResult* result); protected: - HANDLE _threadHandle; - CEvent _runCompleted; - TestResult* _currentTestResult; - - void run (); - void setTestResult(TestResult* result); - static UINT threadFunction(LPVOID thisInstance); + HANDLE _threadHandle; + CEvent _runCompleted; + TestResult* _currentTestResult; + + void run (); + void setTestResult(TestResult* result); + static UINT threadFunction(LPVOID thisInstance); }; diff --git a/Crypto/testsuite/TestSuite_x64_vs100.vcxproj b/Crypto/testsuite/TestSuite_x64_vs100.vcxproj index 9b7eadef4..32bde0615 100644 --- a/Crypto/testsuite/TestSuite_x64_vs100.vcxproj +++ b/Crypto/testsuite/TestSuite_x64_vs100.vcxproj @@ -1,4 +1,4 @@ - + @@ -32,90 +32,92 @@ TestSuite Win32Proj - - + + Application Dynamic MultiByte - + Application Dynamic MultiByte - + Application Static MultiByte - + Application Static MultiByte - + Application Dynamic MultiByte - + Application Dynamic MultiByte - - - - + + + + - - + + - - + + - - + + - - + + - - + + - + <_ProjectFileVersion>10.0.40219.1 - bin64\ - obj64\$(Configuration)\ - true - bin64\ - obj64\$(Configuration)\ - false - bin64\static_mt\ - obj64\$(Configuration)\ - true - bin64\static_mt\ - obj64\$(Configuration)\ - false - bin64\static_md\ - obj64\$(Configuration)\ - true - bin64\static_md\ - obj64\$(Configuration)\ - false - TestSuited - TestSuited - TestSuited - TestSuite - TestSuite - TestSuite + bin64\ + obj64\$(Configuration)\ + true + bin64\ + obj64\$(Configuration)\ + false + bin64\static_mt\ + obj64\$(Configuration)\ + true + bin64\static_mt\ + obj64\$(Configuration)\ + false + bin64\static_md\ + obj64\$(Configuration)\ + true + bin64\static_md\ + obj64\$(Configuration)\ + false + TestSuited + TestSuited + TestSuited + TestSuite + TestSuite + TestSuite + C:\openssl\include;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSdkDir)include;$(FrameworkSDKDir)\include; + C:\openssl\lib;$(VCInstallDir)lib\amd64;$(VCInstallDir)atlmfc\lib\amd64;$(WindowsSdkDir)lib\x64; - + Disabled ..\include;..\..\CppUnit\include;..\..\CppUnit\WinTestRunner\include;..\..\Foundation\include;%(AdditionalIncludeDirectories) - WIN32;_DEBUG;_WINDOWS;WINVER=0x0600;%(PreprocessorDefinitions) + WIN32;_WIN64;_DEBUG;_WINDOWS;WINVER=0x0600;%(PreprocessorDefinitions) true true EnableFastChecks @@ -124,7 +126,7 @@ true true true - + Level3 ProgramDatabase Default @@ -141,7 +143,7 @@ MachineX64 - + Disabled OnlyExplicitInline @@ -149,16 +151,16 @@ Speed true ..\include;..\..\CppUnit\include;..\..\CppUnit\WinTestRunner\include;..\..\Foundation\include;%(AdditionalIncludeDirectories) - WIN32;NDEBUG;_WINDOWS;WINVER=0x0600;%(PreprocessorDefinitions) + WIN32;_WIN64;NDEBUG;_WINDOWS;WINVER=0x0600;%(PreprocessorDefinitions) true MultiThreadedDLL false true true true - + Level3 - + Default %(DisableSpecificWarnings) @@ -173,11 +175,11 @@ MachineX64 - + Disabled ..\include;..\..\CppUnit\include;..\..\CppUnit\WinTestRunner\include;..\..\Foundation\include;%(AdditionalIncludeDirectories) - WIN32;_DEBUG;_WINDOWS;WINVER=0x0600;POCO_STATIC;%(PreprocessorDefinitions) + WIN32;_WIN64;_DEBUG;_WINDOWS;WINVER=0x0600;POCO_STATIC;%(PreprocessorDefinitions) true true EnableFastChecks @@ -186,7 +188,7 @@ true true true - + Level3 ProgramDatabase Default @@ -204,7 +206,7 @@ MachineX64 - + Disabled OnlyExplicitInline @@ -212,16 +214,16 @@ Speed true ..\include;..\..\CppUnit\include;..\..\CppUnit\WinTestRunner\include;..\..\Foundation\include;%(AdditionalIncludeDirectories) - WIN32;NDEBUG;_WINDOWS;WINVER=0x0600;POCO_STATIC;%(PreprocessorDefinitions) + WIN32;_WIN64;NDEBUG;_WINDOWS;WINVER=0x0600;POCO_STATIC;%(PreprocessorDefinitions) true MultiThreaded false true true true - + Level3 - + Default %(DisableSpecificWarnings) @@ -237,11 +239,11 @@ MachineX64 - + Disabled ..\include;..\..\CppUnit\include;..\..\CppUnit\WinTestRunner\include;..\..\Foundation\include;%(AdditionalIncludeDirectories) - WIN32;_DEBUG;_WINDOWS;WINVER=0x0600;POCO_STATIC;%(PreprocessorDefinitions) + WIN32;_WIN64;_DEBUG;_WINDOWS;WINVER=0x0600;POCO_STATIC;%(PreprocessorDefinitions) true true EnableFastChecks @@ -250,7 +252,7 @@ true true true - + Level3 ProgramDatabase Default @@ -267,7 +269,7 @@ MachineX64 - + Disabled OnlyExplicitInline @@ -275,16 +277,16 @@ Speed true ..\include;..\..\CppUnit\include;..\..\CppUnit\WinTestRunner\include;..\..\Foundation\include;%(AdditionalIncludeDirectories) - WIN32;NDEBUG;_WINDOWS;WINVER=0x0600;POCO_STATIC;%(PreprocessorDefinitions) + WIN32;_WIN64;NDEBUG;_WINDOWS;WINVER=0x0600;POCO_STATIC;%(PreprocessorDefinitions) true MultiThreadedDLL false true true true - + Level3 - + Default %(DisableSpecificWarnings) @@ -300,18 +302,18 @@ - - - - + + + + - - - - - + + + + + - - - + + + \ No newline at end of file diff --git a/Data/MySQL/include/Poco/Data/MySQL/Connector.h b/Data/MySQL/include/Poco/Data/MySQL/Connector.h index 47c8dd7c7..a9986e531 100644 --- a/Data/MySQL/include/Poco/Data/MySQL/Connector.h +++ b/Data/MySQL/include/Poco/Data/MySQL/Connector.h @@ -44,6 +44,12 @@ #include "Poco/Data/Connector.h" +// Note: to avoid static (de)initialization problems, +// during connector automatic (un)registration, it is +// best to have this as a macro. +#define POCO_DATA_MYSQL_CONNECTOR_NAME "mysql" + + namespace Poco { namespace Data { namespace MySQL { @@ -80,4 +86,55 @@ public: } } } // namespace Poco::Data::MySQL +// +// Automatic Connector registration +// + +struct MySQL_API MySQLConnectorRegistrator + /// Connector registering class. + /// A global instance of this class is instantiated + /// with sole purpose to automatically register the + /// MySQL connector with central Poco Data registry. +{ + MySQLConnectorRegistrator() + /// Calls Poco::Data::MySQL::registerConnector(); + { + Poco::Data::MySQL::Connector::registerConnector(); + } + + ~MySQLConnectorRegistrator() + /// Calls Poco::Data::MySQL::unregisterConnector(); + { + Poco::Data::MySQL::Connector::unregisterConnector(); + } +}; + + +#if !defined(POCO_NO_AUTOMATIC_LIB_INIT) + #if defined(POCO_OS_FAMILY_WINDOWS) + extern "C" const struct MySQL_API MySQLConnectorRegistrator pocoMySQLConnectorRegistrator; + #if defined(MySQL_EXPORTS) + #if defined(_WIN64) + #define POCO_DATA_MYSQL_FORCE_SYMBOL(s) __pragma(comment (linker, "/export:"#s)) + #elif defined(_WIN32) + #define POCO_DATA_MYSQL_FORCE_SYMBOL(s) __pragma(comment (linker, "/export:_"#s)) + #endif + #else // !MySQL_EXPORTS + #if defined(_WIN64) + #define POCO_DATA_MYSQL_FORCE_SYMBOL(s) __pragma(comment (linker, "/include:"#s)) + #elif defined(_WIN32) + #define POCO_DATA_MYSQL_FORCE_SYMBOL(s) __pragma(comment (linker, "/include:_"#s)) + #endif + #endif // MySQL_EXPORTS + #else // !POCO_OS_FAMILY_WINDOWS + #define POCO_DATA_MYSQL_FORCE_SYMBOL(s) extern "C" const struct MySQLConnectorRegistrator s; + #endif // POCO_OS_FAMILY_WINDOWS + POCO_DATA_MYSQL_FORCE_SYMBOL(pocoMySQLConnectorRegistrator) +#endif // POCO_NO_AUTOMATIC_LIB_INIT + +// +// End automatic Connector registration +// + + #endif // Data_MySQL_Connector_INCLUDED diff --git a/Data/MySQL/include/Poco/Data/MySQL/SessionImpl.h b/Data/MySQL/include/Poco/Data/MySQL/SessionImpl.h index 1e890db1a..47fb2ced7 100644 --- a/Data/MySQL/include/Poco/Data/MySQL/SessionImpl.h +++ b/Data/MySQL/include/Poco/Data/MySQL/SessionImpl.h @@ -141,7 +141,7 @@ public: SessionHandle& handle(); // Get handle - const std::string& connectorName(); + const std::string& connectorName() const; /// Returns the name of the connector. private: @@ -208,7 +208,7 @@ inline SessionHandle& SessionImpl::handle() } -inline const std::string& SessionImpl::connectorName() +inline const std::string& SessionImpl::connectorName() const { return _connector; } diff --git a/Data/MySQL/src/Connector.cpp b/Data/MySQL/src/Connector.cpp index 9739518d6..6e21ef2fd 100644 --- a/Data/MySQL/src/Connector.cpp +++ b/Data/MySQL/src/Connector.cpp @@ -38,16 +38,18 @@ #include "Poco/Data/MySQL/SessionImpl.h" #include "Poco/Data/SessionFactory.h" #include "Poco/Exception.h" - #include +const MySQLConnectorRegistrator pocoMySQLConnectorRegistrator; + + namespace Poco { namespace Data { namespace MySQL { -std::string Connector::KEY("mysql"); +std::string Connector::KEY(POCO_DATA_MYSQL_CONNECTOR_NAME); Connector::Connector() @@ -61,7 +63,8 @@ Connector::~Connector() const std::string& Connector::name() const { - return KEY; + static const std::string n(POCO_DATA_MYSQL_CONNECTOR_NAME); + return n; } Poco::AutoPtr Connector::createSession(const std::string& connectionString, @@ -84,7 +87,7 @@ void Connector::registerConnector() void Connector::unregisterConnector() { - Poco::Data::SessionFactory::instance().remove(KEY); + Poco::Data::SessionFactory::instance().remove(POCO_DATA_MYSQL_CONNECTOR_NAME); mysql_library_end(); } diff --git a/Data/ODBC/include/Poco/Data/ODBC/Connector.h b/Data/ODBC/include/Poco/Data/ODBC/Connector.h index d9c3fb11f..ab5f887ef 100644 --- a/Data/ODBC/include/Poco/Data/ODBC/Connector.h +++ b/Data/ODBC/include/Poco/Data/ODBC/Connector.h @@ -44,6 +44,12 @@ #include "Poco/Data/Connector.h" +// Note: to avoid static (de)initialization problems, +// during connector automatic (un)registration, it is +// best to have this as a macro. +#define POCO_DATA_ODBC_CONNECTOR_NAME "odbc" + + namespace Poco { namespace Data { namespace ODBC { @@ -83,11 +89,63 @@ public: inline const std::string& Connector::name() const { - return KEY; + static const std::string n(POCO_DATA_ODBC_CONNECTOR_NAME); + return n; } } } } // namespace Poco::Data::ODBC +// +// Automatic Connector registration +// + +struct ODBC_API ODBCConnectorRegistrator + /// Connector registering class. + /// A global instance of this class is instantiated + /// with sole purpose to automatically register the + /// ODBC connector with central Poco Data registry. +{ + ODBCConnectorRegistrator() + /// Calls Poco::Data::ODBC::registerConnector(); + { + Poco::Data::ODBC::Connector::registerConnector(); + } + + ~ODBCConnectorRegistrator() + /// Calls Poco::Data::ODBC::unregisterConnector(); + { + Poco::Data::ODBC::Connector::unregisterConnector(); + } +}; + + +#if !defined(POCO_NO_AUTOMATIC_LIB_INIT) + #if defined(POCO_OS_FAMILY_WINDOWS) + extern "C" const struct ODBC_API ODBCConnectorRegistrator pocoODBCConnectorRegistrator; + #if defined(ODBC_EXPORTS) + #if defined(_WIN64) + #define POCO_DATA_ODBC_FORCE_SYMBOL(s) __pragma(comment (linker, "/export:"#s)) + #elif defined(_WIN32) + #define POCO_DATA_ODBC_FORCE_SYMBOL(s) __pragma(comment (linker, "/export:_"#s)) + #endif + #else // !ODBC_EXPORTS + #if defined(_WIN64) + #define POCO_DATA_ODBC_FORCE_SYMBOL(s) __pragma(comment (linker, "/include:"#s)) + #elif defined(_WIN32) + #define POCO_DATA_ODBC_FORCE_SYMBOL(s) __pragma(comment (linker, "/include:_"#s)) + #endif + #endif // ODBC_EXPORTS + #else // !POCO_OS_FAMILY_WINDOWS + #define POCO_DATA_ODBC_FORCE_SYMBOL(s) extern "C" const struct ODBCConnectorRegistrator s; + #endif // POCO_OS_FAMILY_WINDOWS + POCO_DATA_ODBC_FORCE_SYMBOL(pocoODBCConnectorRegistrator) +#endif // POCO_NO_AUTOMATIC_LIB_INIT + +// +// End automatic Connector registration +// + + #endif // Data_ODBC_Connector_INCLUDED diff --git a/Data/ODBC/include/Poco/Data/ODBC/SessionImpl.h b/Data/ODBC/include/Poco/Data/ODBC/SessionImpl.h index 965ac6a5a..0fb2a38ec 100644 --- a/Data/ODBC/include/Poco/Data/ODBC/SessionImpl.h +++ b/Data/ODBC/include/Poco/Data/ODBC/SessionImpl.h @@ -122,7 +122,7 @@ public: bool isTransaction(); /// Returns true iff a transaction is in progress. - const std::string& connectorName(); + const std::string& connectorName() const; /// Returns the name of the connector. bool canTransact(); @@ -263,7 +263,7 @@ inline bool SessionImpl::isAutoExtract(const std::string& name) } -inline const std::string& SessionImpl::connectorName() +inline const std::string& SessionImpl::connectorName() const { return _connector; } diff --git a/Data/ODBC/src/Connector.cpp b/Data/ODBC/src/Connector.cpp index b6d6b9ac3..28139fe58 100644 --- a/Data/ODBC/src/Connector.cpp +++ b/Data/ODBC/src/Connector.cpp @@ -39,12 +39,15 @@ #include "Poco/Data/SessionFactory.h" +const ODBCConnectorRegistrator pocoODBCConnectorRegistrator; + + namespace Poco { namespace Data { namespace ODBC { -const std::string Connector::KEY("odbc"); +const std::string Connector::KEY(POCO_DATA_ODBC_CONNECTOR_NAME); Connector::Connector() @@ -72,7 +75,7 @@ void Connector::registerConnector() void Connector::unregisterConnector() { - Poco::Data::SessionFactory::instance().remove(KEY); + Poco::Data::SessionFactory::instance().remove(POCO_DATA_ODBC_CONNECTOR_NAME); } diff --git a/Data/ODBC/testsuite/src/ODBCTest.cpp b/Data/ODBC/testsuite/src/ODBCTest.cpp index 0f4cbe7ab..1ff616f71 100644 --- a/Data/ODBC/testsuite/src/ODBCTest.cpp +++ b/Data/ODBC/testsuite/src/ODBCTest.cpp @@ -1313,7 +1313,6 @@ ODBCTest::SessionPtr ODBCTest::init(const std::string& driver, Utility::drivers(_drivers); if (!canConnect(driver, dsn, uid, pwd, dbConnString, db)) return 0; - Poco::Data::ODBC::Connector::registerConnector(); try { std::cout << "Conecting to [" << dbConnString << ']' << std::endl; diff --git a/Data/SQLite/SQLite_vs100.vcxproj b/Data/SQLite/SQLite_vs100.vcxproj index 64a095484..c7d8b1cb8 100644 --- a/Data/SQLite/SQLite_vs100.vcxproj +++ b/Data/SQLite/SQLite_vs100.vcxproj @@ -1,4 +1,4 @@ - + @@ -32,76 +32,76 @@ SQLite Win32Proj - - + + StaticLibrary MultiByte - + StaticLibrary MultiByte - + StaticLibrary MultiByte - + StaticLibrary MultiByte - + DynamicLibrary MultiByte - + DynamicLibrary MultiByte - - - - + + + + - - + + - - + + - - + + - - + + - - + + - + <_ProjectFileVersion>10.0.40219.1 - ..\..\bin\ - obj\$(Configuration)\ - true - ..\..\bin\ - obj\$(Configuration)\ - false - ..\..\lib\ - obj\$(Configuration)\ - ..\..\lib\ - obj\$(Configuration)\ - ..\..\lib\ - obj\$(Configuration)\ - ..\..\lib\ - obj\$(Configuration)\ - PocoDataSQLited - PocoDataSQLitemdd - PocoDataSQLitemtd - PocoDataSQLite - PocoDataSQLitemd - PocoDataSQLitemt + ..\..\bin\ + obj\$(Configuration)\ + true + ..\..\bin\ + obj\$(Configuration)\ + false + ..\..\lib\ + obj\$(Configuration)\ + ..\..\lib\ + obj\$(Configuration)\ + ..\..\lib\ + obj\$(Configuration)\ + ..\..\lib\ + obj\$(Configuration)\ + PocoDataSQLited + PocoDataSQLitemdd + PocoDataSQLitemtd + PocoDataSQLite + PocoDataSQLitemd + PocoDataSQLitemt - + Disabled .\include;..\..\Foundation\include;..\..\Data\include;%(AdditionalIncludeDirectories) @@ -114,7 +114,7 @@ true true true - + Level3 EditAndContinue Default @@ -132,7 +132,7 @@ MachineX86 - + Disabled OnlyExplicitInline @@ -147,9 +147,9 @@ true true true - + Level3 - + Default 4996;4244;4018;%(DisableSpecificWarnings) @@ -166,7 +166,7 @@ MachineX86 - + Disabled .\include;..\..\Foundation\include;..\..\Data\include;%(AdditionalIncludeDirectories) @@ -179,7 +179,7 @@ true true true - + ..\..\lib\PocoDataSQLitemtd.pdb Level3 EditAndContinue @@ -190,7 +190,7 @@ ..\..\lib\PocoDataSQLitemtd.lib - + Disabled OnlyExplicitInline @@ -205,9 +205,9 @@ true true true - + Level3 - + Default 4996;4244;4018;%(DisableSpecificWarnings) @@ -215,7 +215,7 @@ ..\..\lib\PocoDataSQLitemt.lib - + Disabled .\include;..\..\Foundation\include;..\..\Data\include;%(AdditionalIncludeDirectories) @@ -228,7 +228,7 @@ true true true - + ..\..\lib\PocoDataSQLitemdd.pdb Level3 EditAndContinue @@ -239,7 +239,7 @@ ..\..\lib\PocoDataSQLitemdd.lib - + Disabled OnlyExplicitInline @@ -254,10 +254,10 @@ true true true - + ..\..\lib\PocoDataSQLitemd.pdb Level3 - + Default 4996;4244;4018;%(DisableSpecificWarnings) @@ -267,26 +267,26 @@ - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - - + + + \ No newline at end of file diff --git a/Data/SQLite/include/Poco/Data/SQLite/Connector.h b/Data/SQLite/include/Poco/Data/SQLite/Connector.h index eefe6961f..f509acbdf 100644 --- a/Data/SQLite/include/Poco/Data/SQLite/Connector.h +++ b/Data/SQLite/include/Poco/Data/SQLite/Connector.h @@ -44,6 +44,12 @@ #include "Poco/Data/Connector.h" +// Note: to avoid static (de)initialization problems, +// during connector automatic (un)registration, it is +// best to have this as a macro. +#define POCO_DATA_SQLITE_CONNECTOR_NAME "sqlite" + + namespace Poco { namespace Data { namespace SQLite { @@ -91,11 +97,62 @@ public: /// inline const std::string& Connector::name() const { - return KEY; + static const std::string n(POCO_DATA_SQLITE_CONNECTOR_NAME); + return n; } } } } // namespace Poco::Data::SQLite +// +// Automatic Connector registration +// + +struct SQLite_API SQLiteConnectorRegistrator + /// Connector registering class. + /// A global instance of this class is instantiated + /// with sole purpose to automatically register the + /// SQLite connector with central Poco Data registry. +{ + SQLiteConnectorRegistrator() + /// Calls Poco::Data::SQLite::registerConnector(); + { + Poco::Data::SQLite::Connector::registerConnector(); + } + + ~SQLiteConnectorRegistrator() + /// Calls Poco::Data::SQLite::unregisterConnector(); + { + Poco::Data::SQLite::Connector::unregisterConnector(); + } +}; + + +#if !defined(POCO_NO_AUTOMATIC_LIB_INIT) + #if defined(POCO_OS_FAMILY_WINDOWS) + extern "C" const struct SQLite_API SQLiteConnectorRegistrator pocoSQLiteConnectorRegistrator; + #if defined(SQLite_EXPORTS) + #if defined(_WIN64) + #define POCO_DATA_SQLITE_FORCE_SYMBOL(s) __pragma(comment (linker, "/export:"#s)) + #elif defined(_WIN32) + #define POCO_DATA_SQLITE_FORCE_SYMBOL(s) __pragma(comment (linker, "/export:_"#s)) + #endif + #else // !SQLite_EXPORTS + #if defined(_WIN64) + #define POCO_DATA_SQLITE_FORCE_SYMBOL(s) __pragma(comment (linker, "/include:"#s)) + #elif defined(_WIN32) + #define POCO_DATA_SQLITE_FORCE_SYMBOL(s) __pragma(comment (linker, "/include:_"#s)) + #endif + #endif // SQLite_EXPORTS + #else // !POCO_OS_FAMILY_WINDOWS + #define POCO_DATA_SQLITE_FORCE_SYMBOL(s) extern "C" const struct SQLiteConnectorRegistrator s; + #endif // POCO_OS_FAMILY_WINDOWS + POCO_DATA_SQLITE_FORCE_SYMBOL(pocoSQLiteConnectorRegistrator) +#endif // POCO_NO_AUTOMATIC_LIB_INIT + +// +// End automatic Connector registration +// + #endif // Data_SQLite_Connector_INCLUDED diff --git a/Data/SQLite/include/Poco/Data/SQLite/SQLite.h b/Data/SQLite/include/Poco/Data/SQLite/SQLite.h index ea013103a..15ea80b9b 100644 --- a/Data/SQLite/include/Poco/Data/SQLite/SQLite.h +++ b/Data/SQLite/include/Poco/Data/SQLite/SQLite.h @@ -84,7 +84,7 @@ // // Thread safety mode defaults to "serialized". // See http://www.sqlite.org/threadsafe.html for details. -// Threading mode significantly affects performance +// Threading mode may significantly affect performance // (see TestSuite::benchmarkThreadModesTiming) // #ifndef SQLITE_THREADSAFE diff --git a/Data/SQLite/include/Poco/Data/SQLite/SessionImpl.h b/Data/SQLite/include/Poco/Data/SQLite/SessionImpl.h index 912c74c57..dd758f583 100644 --- a/Data/SQLite/include/Poco/Data/SQLite/SessionImpl.h +++ b/Data/SQLite/include/Poco/Data/SQLite/SessionImpl.h @@ -41,6 +41,7 @@ #include "Poco/Data/SQLite/SQLite.h" +#include "Poco/Data/SQLite/Connector.h" #include "Poco/Data/SQLite/Binder.h" #include "Poco/Data/AbstractSessionImpl.h" #include "Poco/SharedPtr.h" @@ -51,6 +52,9 @@ struct sqlite3_stmt; namespace Poco { + +class Mutex; + namespace Data { namespace SQLite { @@ -124,17 +128,22 @@ public: /// Returns true iff the transaction isolation level corresponds /// to the supplied bitmask. - const std::string& connectorName(); + void autoCommit(const std::string&, bool val); + /// Sets autocommit property for the session. + + bool isAutoCommit(const std::string& name=""); + /// Returns autocommit property value. + + const std::string& connectorName() const; /// Returns the name of the connector. private: - std::string _connector; sqlite3* _pDB; bool _connected; bool _isTransaction; int _timeout; - + Mutex _mutex; static const std::string DEFERRED_BEGIN_TRANSACTION; static const std::string COMMIT_TRANSACTION; static const std::string ABORT_TRANSACTION; @@ -156,7 +165,7 @@ inline bool SessionImpl::isTransaction() } -inline const std::string& SessionImpl::connectorName() +inline const std::string& SessionImpl::connectorName() const { return _connector; } diff --git a/Data/SQLite/include/Poco/Data/SQLite/Utility.h b/Data/SQLite/include/Poco/Data/SQLite/Utility.h index 14990f0d4..a274c8c67 100644 --- a/Data/SQLite/include/Poco/Data/SQLite/Utility.h +++ b/Data/SQLite/include/Poco/Data/SQLite/Utility.h @@ -42,7 +42,9 @@ #include "Poco/Data/SQLite/SQLite.h" #include "Poco/Data/MetaColumn.h" +#include "Poco/Data/Session.h" #include "Poco/Mutex.h" +#include "Poco/Types.h" #include @@ -56,7 +58,7 @@ namespace SQLite { class SQLite_API Utility - /// Various utility functions for SQLite, mostly return code handling + /// Various utility functions for SQLite. { public: static const std::string SQLITE_DATE_FORMAT; @@ -67,16 +69,18 @@ public: static const int THREAD_MODE_MULTI; static const int THREAD_MODE_SERIAL; - Utility(); - /// Maps SQLite column declared types to Poco::Data types through - /// static TypeMap member. - /// Note: SQLite is type-agnostic and it is the end-user responsibility - /// to ensure that column declared data type corresponds to the type of - /// data actually held in the database. - /// Column types are case-insensitive. + static const int OPERATION_INSERT; + static const int OPERATION_DELETE; + static const int OPERATION_UPDATE; + + static sqlite3* dbHandle(const Session& session); + /// Returns native DB handle. static std::string lastError(sqlite3* pDb); - /// Retreives the last error code from sqlite and converts it to a string + /// Retreives the last error code from sqlite and converts it to a string. + + static std::string lastError(const Session& session); + /// Retreives the last error code from sqlite and converts it to a string. static void throwException(int rc, const std::string& addErrMsg = std::string()); /// Throws for an error code the appropriate exception @@ -88,13 +92,25 @@ public: /// Loads the contents of a database file on disk into an opened /// database in memory. /// - /// Returns true if succesful + /// Returns true if succesful. + + static bool fileToMemory(const Session& session, const std::string& fileName); + /// Loads the contents of a database file on disk into an opened + /// database in memory. + /// + /// Returns true if succesful. static bool memoryToFile(const std::string& fileName, sqlite3* pInMemory); /// Saves the contents of an opened database in memory to the /// database on disk. /// - /// Returns true if succesful + /// Returns true if succesful. + + static bool memoryToFile(const std::string& fileName, const Session& session); + /// Saves the contents of an opened database in memory to the + /// database on disk. + /// + /// Returns true if succesful. static bool isThreadSafe(); /// Returns true if SQLite was compiled in multi-thread or serialized mode. @@ -111,14 +127,131 @@ public: static int getThreadMode(); /// Returns the thread mode. + typedef void(*UpdateCallbackType)(void*, int, const char*, const char*, Poco::Int64); + /// Update callback function type. + + typedef int(*CommitCallbackType)(void*); + /// Commit callback function type. + + typedef void(*RollbackCallbackType)(void*); + /// Rollback callback function type. + + template + static bool registerUpdateHandler(sqlite3* pDB, CBT callbackFn, T* pParam) + /// Registers the callback for (1)(insert, delete, update), (2)(commit) or + /// or (3)(rollback) events. Only one function per group can be registered + /// at a time. Registration is not thread-safe. Storage pointed to by pParam + /// must remain valid as long as registration is active. Registering with + /// callbackFn set to zero disables notifications. + /// + /// See http://www.sqlite.org/c3ref/update_hook.html and + /// http://www.sqlite.org/c3ref/commit_hook.html for details. + { + typedef std::pair CBPair; + typedef std::multimap CBMap; + typedef typename CBMap::iterator CBMapIt; + typedef std::pair CBMapItPair; + + static CBMap retMap; + T* pRet = reinterpret_cast(eventHookRegister(pDB, callbackFn, pParam)); + + if (pRet == 0) + { + if (retMap.find(pDB) == retMap.end()) + { + retMap.insert(std::make_pair(pDB, CBPair(callbackFn, pParam))); + return true; + } + } + else + { + CBMapItPair retMapRange = retMap.equal_range(pDB); + for (CBMapIt it = retMapRange.first; it != retMapRange.second; ++it) + { + poco_assert (it->second.first != 0); + if ((callbackFn == 0) && (*pRet == *it->second.second)) + { + retMap.erase(it); + return true; + } + + if ((callbackFn == it->second.first) && (*pRet == *it->second.second)) + { + it->second.second = pParam; + return true; + } + } + } + + return false; + } + + template + static bool registerUpdateHandler(const Session& session, CBT callbackFn, T* pParam) + /// Registers the callback by calling registerUpdateHandler(sqlite3*, CBT, T*). + { + return registerUpdateHandler(dbHandle(session), callbackFn, pParam); + } + private: - static TypeMap _types; - Poco::FastMutex _mutex; - static int _threadMode; + Utility(); + /// Maps SQLite column declared types to Poco::Data types through + /// static TypeMap member. + /// + /// Note: SQLite is type-agnostic and it is the end-user responsibility + /// to ensure that column declared data type corresponds to the type of + /// data actually held in the database. + /// + /// Column types are case-insensitive. + + Utility(const Utility&); + Utility& operator = (const Utility&); + + static void* eventHookRegister(sqlite3* pDB, UpdateCallbackType callbackFn, void* pParam); + static void* eventHookRegister(sqlite3* pDB, CommitCallbackType callbackFn, void* pParam); + static void* eventHookRegister(sqlite3* pDB, RollbackCallbackType callbackFn, void* pParam); + + static TypeMap _types; + static Poco::Mutex _mutex; + static int _threadMode; }; +// +// inlines +// + +inline sqlite3* Utility::dbHandle(const Session& session) +{ +#ifdef POCO_COMPILER_CLANG + sqlite3* p = 0; Any a = p; // ??? clang fails to AnyCast without these ??? +#endif + return AnyCast(session.getProperty("handle")); +} + + +inline std::string Utility::lastError(const Session& session) +{ + poco_assert_dbg ((0 == icompare(session.connector(), 0, 6, "sqlite"))); + return lastError(dbHandle(session)); +} + + +inline bool Utility::memoryToFile(const std::string& fileName, const Session& session) +{ + poco_assert_dbg ((0 == icompare(session.connector(), 0, 6, "sqlite"))); + return memoryToFile(fileName, dbHandle(session)); +} + + +inline bool Utility::fileToMemory(const Session& session, const std::string& fileName) +{ + poco_assert_dbg ((0 == icompare(session.connector(), 0, 6, "sqlite"))); + return fileToMemory(dbHandle(session), fileName); +} + + } } } // namespace Poco::Data::SQLite -#endif +#endif // SQLite_Utility_INCLUDED diff --git a/Data/SQLite/src/Connector.cpp b/Data/SQLite/src/Connector.cpp index c4c6fa6db..70de69a80 100644 --- a/Data/SQLite/src/Connector.cpp +++ b/Data/SQLite/src/Connector.cpp @@ -44,12 +44,15 @@ #endif +const SQLiteConnectorRegistrator pocoSQLiteConnectorRegistrator; + + namespace Poco { namespace Data { namespace SQLite { -const std::string Connector::KEY("sqlite"); +const std::string Connector::KEY(POCO_DATA_SQLITE_CONNECTOR_NAME); Connector::Connector() @@ -77,7 +80,7 @@ void Connector::registerConnector() void Connector::unregisterConnector() { - Poco::Data::SessionFactory::instance().remove(KEY); + Poco::Data::SessionFactory::instance().remove(POCO_DATA_SQLITE_CONNECTOR_NAME); } diff --git a/Data/SQLite/src/SessionImpl.cpp b/Data/SQLite/src/SessionImpl.cpp index 91bbb0029..50edc98cd 100644 --- a/Data/SQLite/src/SessionImpl.cpp +++ b/Data/SQLite/src/SessionImpl.cpp @@ -37,12 +37,12 @@ #include "Poco/Data/SQLite/SessionImpl.h" #include "Poco/Data/SQLite/Utility.h" #include "Poco/Data/SQLite/SQLiteStatementImpl.h" -#include "Poco/Data/SQLite/Connector.h" #include "Poco/Data/SQLite/SQLiteException.h" #include "Poco/Data/Session.h" #include "Poco/ActiveMethod.h" #include "Poco/ActiveResult.h" #include "Poco/String.h" +#include "Poco/Mutex.h" #include "Poco/Data/DataException.h" #include "sqlite3.h" #include @@ -68,6 +68,9 @@ SessionImpl::SessionImpl(const std::string& fileName, std::size_t loginTimeout): open(); setConnectionTimeout(CONNECTION_TIMEOUT_DEFAULT); setProperty("handle", _pDB); + addFeature("autoCommit", + &SessionImpl::autoCommit, + &SessionImpl::isAutoCommit); } @@ -86,6 +89,7 @@ Poco::Data::StatementImpl* SessionImpl::createStatementImpl() void SessionImpl::begin() { + Poco::Mutex::ScopedLock l(_mutex); SQLiteStatementImpl tmp(*this, _pDB); tmp.add(DEFERRED_BEGIN_TRANSACTION); tmp.execute(); @@ -95,6 +99,7 @@ void SessionImpl::begin() void SessionImpl::commit() { + Poco::Mutex::ScopedLock l(_mutex); SQLiteStatementImpl tmp(*this, _pDB); tmp.add(COMMIT_TRANSACTION); tmp.execute(); @@ -104,6 +109,7 @@ void SessionImpl::commit() void SessionImpl::rollback() { + Poco::Mutex::ScopedLock l(_mutex); SQLiteStatementImpl tmp(*this, _pDB); tmp.add(ABORT_TRANSACTION); tmp.execute(); @@ -234,4 +240,21 @@ void SessionImpl::setConnectionTimeout(std::size_t timeout) } +void SessionImpl::autoCommit(const std::string&, bool) +{ + // The problem here is to decide whether to call commit or rollback + // when autocommit is set to true. Hence, it is best not to implement + // this explicit call and only implicitly support autocommit setting. + throw NotImplementedException( + "SQLite autocommit is implicit with begin/commit/rollback."); +} + + +bool SessionImpl::isAutoCommit(const std::string&) +{ + Poco::Mutex::ScopedLock l(_mutex); + return (0 != sqlite3_get_autocommit(_pDB)); +} + + } } } // namespace Poco::Data::SQLite diff --git a/Data/SQLite/src/Utility.cpp b/Data/SQLite/src/Utility.cpp index c48a9da9a..edb16913e 100644 --- a/Data/SQLite/src/Utility.cpp +++ b/Data/SQLite/src/Utility.cpp @@ -40,6 +40,7 @@ #include "Poco/Data/SQLite/SQLiteException.h" #include "Poco/NumberFormatter.h" #include "Poco/String.h" +#include "Poco/Any.h" #include "Poco/Exception.h" #if defined(POCO_UNBUNDLED) #include @@ -65,14 +66,18 @@ int Utility::_threadMode = SQLITE_CONFIG_MULTITHREAD; #endif +const int Utility::OPERATION_INSERT = SQLITE_INSERT; +const int Utility::OPERATION_DELETE = SQLITE_DELETE; +const int Utility::OPERATION_UPDATE = SQLITE_UPDATE; + const std::string Utility::SQLITE_DATE_FORMAT = "%Y-%m-%d"; const std::string Utility::SQLITE_TIME_FORMAT = "%H:%M:%S"; Utility::TypeMap Utility::_types; - +Poco::Mutex Utility::_mutex; Utility::Utility() { - Poco::FastMutex::ScopedLock l(_mutex); + Poco::Mutex::ScopedLock l(_mutex); if (_types.empty()) { @@ -129,7 +134,7 @@ Utility::Utility() } -std::string Utility::lastError(sqlite3 *pDB) +std::string Utility::lastError(sqlite3* pDB) { return std::string(sqlite3_errmsg(pDB)); } @@ -216,7 +221,7 @@ void Utility::throwException(int rc, const std::string& addErrMsg) case SQLITE_DONE: break; // sqlite_step() has finished executing default: - throw SQLiteException(std::string("Unkown error code: ") + Poco::NumberFormatter::format(rc), addErrMsg); + throw SQLiteException(std::string("Unknown error code: ") + Poco::NumberFormatter::format(rc), addErrMsg); } } @@ -299,4 +304,25 @@ bool Utility::setThreadMode(int mode) } +void* Utility::eventHookRegister(sqlite3* pDB, UpdateCallbackType callbackFn, void* pParam) +{ + typedef void(*pF)(void*, int, const char*, const char*, sqlite3_int64); + return sqlite3_update_hook(pDB, reinterpret_cast(callbackFn), pParam); +} + + +void* Utility::eventHookRegister(sqlite3* pDB, CommitCallbackType callbackFn, void* pParam) +{ + return sqlite3_commit_hook(pDB, callbackFn, pParam); +} + + +void* Utility::eventHookRegister(sqlite3* pDB, RollbackCallbackType callbackFn, void* pParam) +{ + return sqlite3_rollback_hook(pDB, callbackFn, pParam); +} + + + + } } } // namespace Poco::Data::SQLite diff --git a/Data/SQLite/testsuite/src/SQLiteTest.cpp b/Data/SQLite/testsuite/src/SQLiteTest.cpp index 443ed141b..0224f59bb 100644 --- a/Data/SQLite/testsuite/src/SQLiteTest.cpp +++ b/Data/SQLite/testsuite/src/SQLiteTest.cpp @@ -45,6 +45,7 @@ #include "Poco/Dynamic/Var.h" #include "Poco/Data/TypeHandler.h" #include "Poco/Nullable.h" +#include "Poco/Data/Transaction.h" #include "Poco/Data/DataException.h" #include "Poco/Data/SQLite/SQLiteException.h" #include "Poco/Tuple.h" @@ -73,6 +74,7 @@ using Poco::Data::LimitException; using Poco::Data::CLOB; using Poco::Data::Date; using Poco::Data::Time; +using Poco::Data::Transaction; using Poco::Data::AbstractExtractionVec; using Poco::Data::AbstractExtractionVecVec; using Poco::Data::AbstractBindingVec; @@ -87,15 +89,19 @@ using Poco::Logger; using Poco::Message; using Poco::AutoPtr; using Poco::Thread; +using Poco::format; using Poco::InvalidAccessException; using Poco::RangeException; using Poco::BadCastException; using Poco::NotFoundException; using Poco::NullPointerException; +using Poco::TimeoutException; +using Poco::NotImplementedException; using Poco::Data::SQLite::ConstraintViolationException; using Poco::Data::SQLite::ParameterCountMismatchException; using Poco::Int32; using Poco::Dynamic::Var; +using Poco::Data::SQLite::Utility; class Person @@ -249,15 +255,18 @@ private: } } // namespace Poco::Data +int SQLiteTest::_insertCounter; +int SQLiteTest::_updateCounter; +int SQLiteTest::_deleteCounter; + + SQLiteTest::SQLiteTest(const std::string& name): CppUnit::TestCase(name) { - Poco::Data::SQLite::Connector::registerConnector(); } SQLiteTest::~SQLiteTest() { - Poco::Data::SQLite::Connector::unregisterConnector(); } @@ -358,9 +367,7 @@ void SQLiteTest::testInMemory() // load db from file to memory Session mem (Poco::Data::SQLite::Connector::KEY, ":memory:"); - sqlite3* p = 0; Any a = p; // ??? clang generated code fails to AnyCast without these - sqlite3* pMemHandle = AnyCast(mem.getProperty("handle")); - assert (Poco::Data::SQLite::Utility::fileToMemory(pMemHandle, "dummy.db")); + assert (Poco::Data::SQLite::Utility::fileToMemory(mem, "dummy.db")); mem << "SELECT COUNT(*) FROM PERSON", into(count), now; assert (count == 1); @@ -374,7 +381,7 @@ void SQLiteTest::testInMemory() // save db from memory to file on the disk Session dsk (Poco::Data::SQLite::Connector::KEY, "dsk.db"); - assert (Poco::Data::SQLite::Utility::memoryToFile("dsk.db", pMemHandle)); + assert (Poco::Data::SQLite::Utility::memoryToFile("dsk.db", mem)); dsk << "SELECT COUNT(*) FROM PERSON", into(count), now; assert (count == 1); @@ -2657,6 +2664,551 @@ void SQLiteTest::testThreadModes() } +void SQLiteTest::sqliteUpdateCallbackFn(void* pVal, int opCode, const char* pDB, const char* pTable, Poco::Int64 row) +{ + poco_check_ptr(pVal); + Poco::Int64* pV = reinterpret_cast(pVal); + if (opCode == Utility::OPERATION_INSERT) + { + poco_assert (*pV == 2); + poco_assert (row == 1); + std::cout << "Inserted " << pDB << '.' << pTable << ", RowID=" << row << std::endl; + ++_insertCounter; + } + else if (opCode == Utility::OPERATION_UPDATE) + { + poco_assert (*pV == 3); + poco_assert (row == 1); + std::cout << "Updated " << pDB << '.' << pTable << ", RowID=" << row << std::endl; + ++_updateCounter; + } + else if (opCode == Utility::OPERATION_DELETE) + { + poco_assert (*pV == 4); + poco_assert (row == 1); + std::cout << "Deleted " << pDB << '.' << pTable << ", RowID=" << row << std::endl; + ++_deleteCounter; + } +} + + +void SQLiteTest::testUpdateCallback() +{ + // will be updated by callback + _insertCounter = 0; + _updateCounter = 0; + _deleteCounter = 0; + + Session tmp (Poco::Data::SQLite::Connector::KEY, "dummy.db"); + assert (tmp.isConnected()); + Poco::Int64 val = 1; + assert (Utility::registerUpdateHandler(tmp, &sqliteUpdateCallbackFn, &val)); + + std::string tableName("Person"); + std::string lastName("lastname"); + std::string firstName("firstname"); + std::string address("Address"); + int age = 133132; + int count = 0; + std::string result; + tmp << "DROP TABLE IF EXISTS Person", now; + tmp << "CREATE TABLE IF NOT EXISTS Person (LastName VARCHAR(30), FirstName VARCHAR, Address VARCHAR, Age INTEGER(3))", now; + tmp << "SELECT name FROM sqlite_master WHERE tbl_name=?", use(tableName), into(result), now; + assert (result == tableName); + + // insert + val = 2; + tmp << "INSERT INTO PERSON VALUES(:ln, :fn, :ad, :age)", use(lastName), use(firstName), use(address), use(age), now; + tmp << "SELECT COUNT(*) FROM PERSON", into(count), now; + assert (count == 1); + assert (_insertCounter == 1); + tmp << "SELECT LastName FROM PERSON", into(result), now; + assert (lastName == result); + tmp << "SELECT Age FROM PERSON", into(count), now; + assert (count == age); + + // update + val = 3; + tmp << "UPDATE PERSON SET Age = -1", now; + tmp << "SELECT Age FROM PERSON", into(age), now; + assert (-1 == age); + assert (_updateCounter == 1); + + // delete + val =4; + tmp << "DELETE FROM Person WHERE Age = -1", now; + tmp << "SELECT COUNT(*) FROM PERSON", into(count), now; + assert (count == 0); + assert (_deleteCounter == 1); + + // disarm callback and do the same drill + assert (Utility::registerUpdateHandler(tmp, (Utility::UpdateCallbackType) 0, &val)); + + tmp << "DROP TABLE IF EXISTS Person", now; + tmp << "CREATE TABLE IF NOT EXISTS Person (LastName VARCHAR(30), FirstName VARCHAR, Address VARCHAR, Age INTEGER(3))", now; + tmp << "SELECT name FROM sqlite_master WHERE tbl_name=?", use(tableName), into(result), now; + assert (result == tableName); + + // must remain zero now + _insertCounter = 0; + _updateCounter = 0; + _deleteCounter = 0; + + // insert + tmp << "INSERT INTO PERSON VALUES(:ln, :fn, :ad, :age)", use(lastName), use(firstName), use(address), use(age), now; + tmp << "SELECT COUNT(*) FROM PERSON", into(count), now; + assert (count == 1); + assert (_insertCounter == 0); + tmp << "SELECT LastName FROM PERSON", into(result), now; + assert (lastName == result); + tmp << "SELECT Age FROM PERSON", into(count), now; + assert (count == age); + + // update + tmp << "UPDATE PERSON SET Age = -1", now; + tmp << "SELECT Age FROM PERSON", into(age), now; + assert (-1 == age); + assert (_updateCounter == 0); + + // delete + tmp << "DELETE FROM Person WHERE Age = -1", now; + tmp << "SELECT COUNT(*) FROM PERSON", into(count), now; + assert (count == 0); + assert (_deleteCounter == 0); + + tmp.close(); + assert (!tmp.isConnected()); +} + + +int SQLiteTest::sqliteCommitCallbackFn(void* pVal) +{ + poco_check_ptr(pVal); + Poco::Int64* pV = reinterpret_cast(pVal); + poco_assert ((*pV) == 1); + ++(*pV); + return 0; +} + + +void SQLiteTest::testCommitCallback() +{ + Session tmp (Poco::Data::SQLite::Connector::KEY, "dummy.db"); + assert (tmp.isConnected()); + Poco::Int64 val = 1; + assert (Utility::registerUpdateHandler(tmp, &sqliteCommitCallbackFn, &val)); + + std::string tableName("Person"); + std::string lastName("lastname"); + std::string firstName("firstname"); + std::string address("Address"); + int age = 133132; + std::string result; + tmp.begin(); + tmp << "DROP TABLE IF EXISTS Person", now; + tmp << "CREATE TABLE IF NOT EXISTS Person (LastName VARCHAR(30), FirstName VARCHAR, Address VARCHAR, Age INTEGER(3))", now; + tmp << "INSERT INTO PERSON VALUES(:ln, :fn, :ad, :age)", use(lastName), use(firstName), use(address), use(age), now; + tmp.commit(); + assert (val == 2); + + assert (Utility::registerUpdateHandler(tmp, (Utility::CommitCallbackType) 0, &val)); + val = 0; + tmp.begin(); + tmp << "DROP TABLE IF EXISTS Person", now; + tmp << "CREATE TABLE IF NOT EXISTS Person (LastName VARCHAR(30), FirstName VARCHAR, Address VARCHAR, Age INTEGER(3))", now; + tmp << "INSERT INTO PERSON VALUES(:ln, :fn, :ad, :age)", use(lastName), use(firstName), use(address), use(age), now; + tmp.commit(); + assert (val == 0); + +} + + +void SQLiteTest::sqliteRollbackCallbackFn(void* pVal) +{ + poco_check_ptr(pVal); + Poco::Int64* pV = reinterpret_cast(pVal); + poco_assert ((*pV) == 1); + ++(*pV); +} + + +void SQLiteTest::testRollbackCallback() +{ + Session tmp (Poco::Data::SQLite::Connector::KEY, "dummy.db"); + assert (tmp.isConnected()); + Poco::Int64 val = 1; + assert (Utility::registerUpdateHandler(tmp, &sqliteRollbackCallbackFn, &val)); + + std::string tableName("Person"); + std::string lastName("lastname"); + std::string firstName("firstname"); + std::string address("Address"); + int age = 133132; + std::string result; + tmp.begin(); + tmp << "DROP TABLE IF EXISTS Person", now; + tmp << "CREATE TABLE IF NOT EXISTS Person (LastName VARCHAR(30), FirstName VARCHAR, Address VARCHAR, Age INTEGER(3))", now; + tmp << "INSERT INTO PERSON VALUES(:ln, :fn, :ad, :age)", use(lastName), use(firstName), use(address), use(age), now; + tmp.rollback(); + assert (val == 2); + + assert (Utility::registerUpdateHandler(tmp, (Utility::RollbackCallbackType) 0, &val)); + val = 0; + tmp.begin(); + tmp << "DROP TABLE IF EXISTS Person", now; + tmp << "CREATE TABLE IF NOT EXISTS Person (LastName VARCHAR(30), FirstName VARCHAR, Address VARCHAR, Age INTEGER(3))", now; + tmp << "INSERT INTO PERSON VALUES(:ln, :fn, :ad, :age)", use(lastName), use(firstName), use(address), use(age), now; + tmp.rollback(); + assert (val == 0); +} + + +void SQLiteTest::setTransactionIsolation(Session& session, Poco::UInt32 ti) +{ + if (session.hasTransactionIsolation(ti)) + { + std::string funct = "setTransactionIsolation()"; + + try + { + Transaction t(session, false); + t.setIsolation(ti); + + assert (ti == t.getIsolation()); + assert (t.isIsolation(ti)); + + assert (ti == session.getTransactionIsolation()); + assert (session.isTransactionIsolation(ti)); + } + catch(Poco::Exception& e){ std::cout << funct << ':' << e.displayText() << std::endl;} + } + else + { + std::cerr << '[' << name() << ']' << " Warning, transaction isolation not supported: "; + switch (ti) + { + case Session::TRANSACTION_READ_COMMITTED: + std::cerr << "READ COMMITTED"; break; + case Session::TRANSACTION_READ_UNCOMMITTED: + std::cerr << "READ UNCOMMITTED"; break; + case Session::TRANSACTION_REPEATABLE_READ: + std::cerr << "REPEATABLE READ"; break; + case Session::TRANSACTION_SERIALIZABLE: + std::cerr << "SERIALIZABLE"; break; + default: + std::cerr << "UNKNOWN"; break; + } + std::cerr << std::endl; + } +} + + +void SQLiteTest::testSessionTransaction() +{ + Session session (Poco::Data::SQLite::Connector::KEY, "dummy.db"); + assert (session.isConnected()); + + session << "DROP TABLE IF EXISTS Person", now; + session << "CREATE TABLE IF NOT EXISTS Person (LastName VARCHAR(30), FirstName VARCHAR, Address VARCHAR, Age INTEGER(3))", now; + + if (!session.canTransact()) + { + std::cout << "Session not capable of transactions." << std::endl; + return; + } + + Session local (Poco::Data::SQLite::Connector::KEY, "dummy.db"); + assert (local.isConnected()); + + try + { + local.setFeature("autoCommit", true); + fail ("Setting SQLite auto-commit explicitly must fail!"); + } + catch (NotImplementedException&) { } + assert (local.getFeature("autoCommit")); + + std::string funct = "transaction()"; + std::vector lastNames; + std::vector firstNames; + std::vector addresses; + std::vector ages; + std::string tableName("Person"); + lastNames.push_back("LN1"); + lastNames.push_back("LN2"); + firstNames.push_back("FN1"); + firstNames.push_back("FN2"); + addresses.push_back("ADDR1"); + addresses.push_back("ADDR2"); + ages.push_back(1); + ages.push_back(2); + int count = 0, locCount = 0; + std::string result; + + setTransactionIsolation(session, Session::TRANSACTION_READ_COMMITTED); + + session.begin(); + assert (!session.getFeature("autoCommit")); + assert (session.isTransaction()); + session << "INSERT INTO Person VALUES (?,?,?,?)", use(lastNames), use(firstNames), use(addresses), use(ages), now; + assert (session.isTransaction()); + + Statement stmt = (local << "SELECT COUNT(*) FROM Person", into(locCount), async, now); + + session << "SELECT COUNT(*) FROM Person", into(count), now; + assert (2 == count); + assert (session.isTransaction()); + session.rollback(); + assert (!session.isTransaction()); + assert (session.getFeature("autoCommit")); + + stmt.wait(); + assert (0 == locCount); + + session << "SELECT count(*) FROM Person", into(count), now; + assert (0 == count); + assert (!session.isTransaction()); + + session.begin(); + session << "INSERT INTO Person VALUES (?,?,?,?)", use(lastNames), use(firstNames), use(addresses), use(ages), now; + assert (session.isTransaction()); + assert (!session.getFeature("autoCommit")); + + Statement stmt1 = (local << "SELECT COUNT(*) FROM Person", into(locCount), now); + assert (0 == locCount); + + session << "SELECT count(*) FROM Person", into(count), now; + assert (2 == count); + + session.commit(); + assert (!session.isTransaction()); + assert (session.getFeature("autoCommit")); + + session << "SELECT count(*) FROM Person", into(count), now; + assert (2 == count); + + /* TODO: see http://www.sqlite.org/pragma.html#pragma_read_uncommitted + setTransactionIsolation(session, Session::TRANSACTION_READ_UNCOMMITTED); + */ + + session.close(); + assert (!session.isConnected()); + + local.close(); + assert (!local.isConnected()); +} + + +void SQLiteTest::testTransaction() +{ + Session session (Poco::Data::SQLite::Connector::KEY, "dummy.db"); + assert (session.isConnected()); + + session << "DROP TABLE IF EXISTS Person", now; + session << "CREATE TABLE IF NOT EXISTS Person (LastName VARCHAR(30), FirstName VARCHAR, Address VARCHAR, Age INTEGER(3))", now; + + if (!session.canTransact()) + { + std::cout << "Session not transaction-capable." << std::endl; + return; + } + + Session local(Poco::Data::SQLite::Connector::KEY, "dummy.db"); + + setTransactionIsolation(session, Session::TRANSACTION_READ_COMMITTED); + + std::string funct = "transaction()"; + std::vector lastNames; + std::vector firstNames; + std::vector addresses; + std::vector ages; + std::string tableName("Person"); + lastNames.push_back("LN1"); + lastNames.push_back("LN2"); + firstNames.push_back("FN1"); + firstNames.push_back("FN2"); + addresses.push_back("ADDR1"); + addresses.push_back("ADDR2"); + ages.push_back(1); + ages.push_back(2); + int count = 0, locCount = 0; + std::string result; + + session.setTransactionIsolation(Session::TRANSACTION_READ_COMMITTED); + + { + Transaction trans(session); + assert (trans.isActive()); + assert (session.isTransaction()); + + session << "INSERT INTO Person VALUES (?,?,?,?)", use(lastNames), use(firstNames), use(addresses), use(ages), now; + + assert (session.isTransaction()); + assert (trans.isActive()); + + session << "SELECT COUNT(*) FROM Person", into(count), now; + assert (2 == count); + assert (session.isTransaction()); + assert (trans.isActive()); + // no explicit commit, so transaction RAII must roll back here + } + assert (!session.isTransaction()); + + session << "SELECT count(*) FROM Person", into(count), now; + assert (0 == count); + assert (!session.isTransaction()); + + { + Transaction trans(session); + session << "INSERT INTO Person VALUES (?,?,?,?)", use(lastNames), use(firstNames), use(addresses), use(ages), now; + + Statement stmt1 = (local << "SELECT COUNT(*) FROM Person", into(locCount), now); + + assert (session.isTransaction()); + assert (trans.isActive()); + trans.commit(); + assert (!session.isTransaction()); + assert (!trans.isActive()); + assert (0 == locCount); + } + + session << "SELECT count(*) FROM Person", into(count), now; + assert (2 == count); + local << "SELECT count(*) FROM Person", into(count), now; + assert (2 == count); + + session << "DELETE FROM Person", now; + + std::string sql1 = format("INSERT INTO Person VALUES ('%s','%s','%s',%d)", lastNames[0], firstNames[0], addresses[0], ages[0]); + std::string sql2 = format("INSERT INTO Person VALUES ('%s','%s','%s',%d)", lastNames[1], firstNames[1], addresses[1], ages[1]); + std::vector sql; + sql.push_back(sql1); + sql.push_back(sql2); + + Transaction trans(session); + + trans.execute(sql1, false); + session << "SELECT count(*) FROM Person", into(count), now; + assert (1 == count); + trans.execute(sql2, false); + session << "SELECT count(*) FROM Person", into(count), now; + assert (2 == count); + + Statement stmt2 = (local << "SELECT COUNT(*) FROM Person", into(locCount), now); + assert (0 == locCount); + + trans.rollback(); + + session << "SELECT count(*) FROM Person", into(count), now; + assert (0 == count); + + trans.execute(sql); + + Statement stmt3 = (local << "SELECT COUNT(*) FROM Person", into(locCount), now); + assert (2 == locCount); + + session << "SELECT count(*) FROM Person", into(count), now; + assert (2 == count); + + session.close(); + assert (!session.isConnected()); + + local.close(); + assert (!local.isConnected()); +} + + +struct TestCommitTransactor +{ + void operator () (Session& session) const + { + session << "INSERT INTO Person VALUES ('lastName','firstName','address',10)", now; + } +}; + + +struct TestRollbackTransactor +{ + void operator () (Session& session) const + { + session << "INSERT INTO Person VALUES ('lastName','firstName','address',10)", now; + throw Poco::Exception("test"); + } +}; + + +void SQLiteTest::testTransactor() +{ + Session session (Poco::Data::SQLite::Connector::KEY, "dummy.db"); + assert (session.isConnected()); + + session << "DROP TABLE IF EXISTS Person", now; + session << "CREATE TABLE IF NOT EXISTS Person (LastName VARCHAR(30), FirstName VARCHAR, Address VARCHAR, Age INTEGER(3))", now; + + std::string funct = "transaction()"; + int count = 0; + + assert (session.getFeature("autoCommit")); + session.setTransactionIsolation(Session::TRANSACTION_READ_COMMITTED); + + TestCommitTransactor ct; + Transaction t1(session, ct); + + session << "SELECT count(*) FROM Person", into(count), now; + assert (1 == count); + + session << "DELETE FROM Person", now; + session << "SELECT count(*) FROM Person", into(count), now; + assert (0 == count); + + try + { + TestRollbackTransactor rt; + Transaction t(session, rt); + fail ("must fail"); + } catch (Poco::Exception&) { } + + session << "SELECT count(*) FROM Person", into(count), now; + assert (0 == count); + + try + { + TestRollbackTransactor rt; + Transaction t(session); + t.transact(rt); + fail ("must fail"); + } catch (Poco::Exception&) { } + + session << "SELECT count(*) FROM Person", into(count), now; + assert (0 == count); + + try + { + TestRollbackTransactor rt; + Transaction t(session, false); + t.transact(rt); + fail ("must fail"); + } catch (Poco::Exception&) { } + + session << "SELECT count(*) FROM Person", into(count), now; + assert (0 == count); + + try + { + TestRollbackTransactor rt; + Transaction t(session, true); + t.transact(rt); + fail ("must fail"); + } catch (Poco::Exception&) { } + + session << "SELECT count(*) FROM Person", into(count), now; + assert (0 == count); + + session.close(); + assert (!session.isConnected()); +} + + void SQLiteTest::setUp() { } @@ -2749,6 +3301,12 @@ CppUnit::Test* SQLiteTest::suite() CppUnit_addTest(pSuite, SQLiteTest, testReconnect); CppUnit_addTest(pSuite, SQLiteTest, testSystemTable); CppUnit_addTest(pSuite, SQLiteTest, testThreadModes); + CppUnit_addTest(pSuite, SQLiteTest, testUpdateCallback); + CppUnit_addTest(pSuite, SQLiteTest, testCommitCallback); + CppUnit_addTest(pSuite, SQLiteTest, testRollbackCallback); + CppUnit_addTest(pSuite, SQLiteTest, testSessionTransaction); + CppUnit_addTest(pSuite, SQLiteTest, testTransaction); + CppUnit_addTest(pSuite, SQLiteTest, testTransactor); return pSuite; } diff --git a/Data/SQLite/testsuite/src/SQLiteTest.h b/Data/SQLite/testsuite/src/SQLiteTest.h index 7229fa0c3..5b369e49e 100644 --- a/Data/SQLite/testsuite/src/SQLiteTest.h +++ b/Data/SQLite/testsuite/src/SQLiteTest.h @@ -40,6 +40,14 @@ #include "CppUnit/TestCase.h" +namespace Poco { +namespace Data { + +class Session; + +} } + + class SQLiteTest: public CppUnit::TestCase { public: @@ -136,12 +144,29 @@ public: void testThreadModes(); + void testUpdateCallback(); + void testCommitCallback(); + void testRollbackCallback(); + + void testSessionTransaction(); + void testTransaction(); + void testTransactor(); + void setUp(); void tearDown(); + static void sqliteUpdateCallbackFn(void*, int, const char*, const char*, Poco::Int64); + static int sqliteCommitCallbackFn(void*); + static void sqliteRollbackCallbackFn(void*); + static CppUnit::Test* suite(); private: + void setTransactionIsolation(Poco::Data::Session& session, Poco::UInt32 ti); + + static int _insertCounter; + static int _updateCounter; + static int _deleteCounter; }; diff --git a/Data/include/Poco/Data/Date.h b/Data/include/Poco/Data/Date.h index db11d1b2e..876c70555 100644 --- a/Data/include/Poco/Data/Date.h +++ b/Data/include/Poco/Data/Date.h @@ -225,9 +225,9 @@ public: val = DateTimeFormatter::format(dt, "%Y/%m/%d"); } - VarHolder* clone() const + VarHolder* clone(Placeholder* pVarHolder = 0) const { - return new VarHolderImpl(_val); + return cloneHolder(pVarHolder, _val); } const Poco::Data::Date& value() const diff --git a/Data/include/Poco/Data/LOB.h b/Data/include/Poco/Data/LOB.h index e2b1f7392..82c1d686e 100644 --- a/Data/include/Poco/Data/LOB.h +++ b/Data/include/Poco/Data/LOB.h @@ -272,9 +272,9 @@ public: val.assign(_val.begin(), _val.end()); } - VarHolder* clone() const + VarHolder* clone(Placeholder* pVarHolder = 0) const { - return new VarHolderImpl(_val); + return cloneHolder(pVarHolder, _val); } const Poco::Data::BLOB& value() const @@ -310,9 +310,9 @@ public: val.assign(_val.begin(), _val.end()); } - VarHolder* clone() const + VarHolder* clone(Placeholder* pVarHolder = 0) const { - return new VarHolderImpl(_val); + return cloneHolder(pVarHolder, _val); } const Poco::Data::CLOB& value() const diff --git a/Data/include/Poco/Data/PooledSessionImpl.h b/Data/include/Poco/Data/PooledSessionImpl.h index 5fb3045e6..6ee85b415 100644 --- a/Data/include/Poco/Data/PooledSessionImpl.h +++ b/Data/include/Poco/Data/PooledSessionImpl.h @@ -81,14 +81,14 @@ public: Poco::UInt32 getTransactionIsolation(); bool hasTransactionIsolation(Poco::UInt32); bool isTransactionIsolation(Poco::UInt32); - const std::string& connectorName(); + const std::string& connectorName() const; void setFeature(const std::string& name, bool state); bool getFeature(const std::string& name); void setProperty(const std::string& name, const Poco::Any& value); Poco::Any getProperty(const std::string& name); protected: - SessionImpl* access(); + SessionImpl* access() const; /// Updates the last access timestamp, /// verifies validity of the session /// and returns the session if it is valid. @@ -96,18 +96,18 @@ protected: /// Throws an SessionUnavailableException if the /// session is no longer valid. - SessionImpl* impl(); + SessionImpl* impl() const; /// Returns a pointer to the SessionImpl. private: - Poco::AutoPtr _pHolder; + mutable Poco::AutoPtr _pHolder; }; // // inlines // -inline SessionImpl* PooledSessionImpl::impl() +inline SessionImpl* PooledSessionImpl::impl() const { return _pHolder->session(); } diff --git a/Data/include/Poco/Data/Session.h b/Data/include/Poco/Data/Session.h index 1fbe6046a..22c79d79c 100644 --- a/Data/include/Poco/Data/Session.h +++ b/Data/include/Poco/Data/Session.h @@ -274,10 +274,10 @@ public: /// Returns true iff the transaction isolation level corresponds /// to the supplied bitmask. - std::string connector(); + std::string connector() const; /// Returns the connector name for this session. - std::string uri(); + std::string uri() const; /// Returns the URI for this session. static std::string uri(const std::string& connector, @@ -443,7 +443,7 @@ inline bool Session::isTransactionIsolation(Poco::UInt32 ti) } -inline std::string Session::connector() +inline std::string Session::connector() const { return _pImpl->connectorName(); } @@ -456,7 +456,7 @@ inline std::string Session::uri(const std::string& connector, } -inline std::string Session::uri() +inline std::string Session::uri() const { return _pImpl->uri(); } diff --git a/Data/include/Poco/Data/SessionImpl.h b/Data/include/Poco/Data/SessionImpl.h index 292d01305..abc21ea98 100644 --- a/Data/include/Poco/Data/SessionImpl.h +++ b/Data/include/Poco/Data/SessionImpl.h @@ -139,16 +139,16 @@ public: /// Returns true iff the transaction isolation level corresponds /// to the supplied bitmask. - virtual const std::string& connectorName() = 0; + virtual const std::string& connectorName() const = 0; /// Returns the name of the connector. - const std::string& connectionString(); + const std::string& connectionString() const; /// Returns the connection string. static std::string uri(const std::string& connector, const std::string& connectionString); /// Returns formatted URI. - std::string uri(); + std::string uri() const; /// Returns the URI for this session. virtual void setFeature(const std::string& name, bool state) = 0; @@ -206,7 +206,7 @@ private: // // inlines // -inline const std::string& SessionImpl::connectionString() +inline const std::string& SessionImpl::connectionString() const { return _connectionString; } @@ -231,7 +231,7 @@ inline std::string SessionImpl::uri(const std::string& connector, } -inline std::string SessionImpl::uri() +inline std::string SessionImpl::uri() const { return uri(connectorName(), connectionString()); } diff --git a/Data/include/Poco/Data/Time.h b/Data/include/Poco/Data/Time.h index eb9e477f0..758e7cf94 100644 --- a/Data/include/Poco/Data/Time.h +++ b/Data/include/Poco/Data/Time.h @@ -229,9 +229,9 @@ public: val = DateTimeFormatter::format(dt, "%H:%M:%S"); } - VarHolder* clone() const + VarHolder* clone(Placeholder* pVarHolder = 0) const { - return new VarHolderImpl(_val); + return cloneHolder(pVarHolder, _val); } const Poco::Data::Time& value() const diff --git a/Data/samples/Binding/src/Binding.cpp b/Data/samples/Binding/src/Binding.cpp index 214b1fedd..07964acd8 100644 --- a/Data/samples/Binding/src/Binding.cpp +++ b/Data/samples/Binding/src/Binding.cpp @@ -52,9 +52,6 @@ struct Person int main(int argc, char** argv) { - // register SQLite connector - Poco::Data::SQLite::Connector::registerConnector(); - // create a session Session session("SQLite", "sample.db"); diff --git a/Data/samples/RecordSet/RecordSet_vs100.vcxproj b/Data/samples/RecordSet/RecordSet_vs100.vcxproj index 47b6e5310..234912723 100644 --- a/Data/samples/RecordSet/RecordSet_vs100.vcxproj +++ b/Data/samples/RecordSet/RecordSet_vs100.vcxproj @@ -1,4 +1,4 @@ - + @@ -32,84 +32,84 @@ RecordSet Win32Proj - - + + Application MultiByte - + Application MultiByte - + Application MultiByte - + Application MultiByte - + Application MultiByte - + Application MultiByte - - - - + + + + - - + + - - + + - - + + - - + + - - + + - + <_ProjectFileVersion>10.0.40219.1 - bin\ - obj\$(Configuration)\ - true - bin\ - obj\$(Configuration)\ - false - bin\static_mt\ - obj\$(Configuration)\ - true - bin\static_mt\ - obj\$(Configuration)\ - false - bin\static_md\ - obj\$(Configuration)\ - true - bin\static_md\ - obj\$(Configuration)\ - false - RecordSetd - RecordSetd - RecordSetd - RecordSet - RecordSet - RecordSet + bin\ + obj\$(Configuration)\ + true + bin\ + obj\$(Configuration)\ + false + bin\static_mt\ + obj\$(Configuration)\ + true + bin\static_mt\ + obj\$(Configuration)\ + false + bin\static_md\ + obj\$(Configuration)\ + true + bin\static_md\ + obj\$(Configuration)\ + false + RecordSetd + RecordSetd + RecordSetd + RecordSet + RecordSet + RecordSet - + Disabled .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\Util\include;..\..\..\Data\include;..\..\..\Data\SQLite\include;%(AdditionalIncludeDirectories) - WIN32;_DEBUG;_WINDOWS;WINVER=0x0500;%(PreprocessorDefinitions) + WIN32;_DEBUG;_WINDOWS;WINVER=0x0500;POCO_DLL;%(PreprocessorDefinitions) true true EnableFastChecks @@ -118,7 +118,7 @@ true true true - + Level3 EditAndContinue Default @@ -135,7 +135,7 @@ MachineX86 - + Disabled OnlyExplicitInline @@ -150,9 +150,9 @@ true true true - + Level3 - + Default %(DisableSpecificWarnings) @@ -167,7 +167,7 @@ MachineX86 - + Disabled .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\Util\include;..\..\..\Data\include;..\..\..\Data\SQLite\include;%(AdditionalIncludeDirectories) @@ -180,7 +180,7 @@ true true true - + Level3 EditAndContinue Default @@ -197,7 +197,7 @@ MachineX86 - + Disabled OnlyExplicitInline @@ -212,9 +212,9 @@ true true true - + Level3 - + Default %(DisableSpecificWarnings) @@ -229,7 +229,7 @@ MachineX86 - + Disabled .\include;..\..\..\Foundation\include;..\..\..\XML\include;..\..\..\Util\include;..\..\..\Data\include;..\..\..\Data\SQLite\include;%(AdditionalIncludeDirectories) @@ -242,7 +242,7 @@ true true true - + Level3 EditAndContinue Default @@ -259,7 +259,7 @@ MachineX86 - + Disabled OnlyExplicitInline @@ -274,9 +274,9 @@ true true true - + Level3 - + Default %(DisableSpecificWarnings) @@ -292,8 +292,8 @@ - + - - - + + + \ No newline at end of file diff --git a/Data/samples/RecordSet/src/RecordSet.cpp b/Data/samples/RecordSet/src/RecordSet.cpp index a1a4823fb..f9a6c438c 100644 --- a/Data/samples/RecordSet/src/RecordSet.cpp +++ b/Data/samples/RecordSet/src/RecordSet.cpp @@ -58,9 +58,6 @@ struct Person int main(int argc, char** argv) { - // register SQLite connector - Poco::Data::SQLite::Connector::registerConnector(); - // create a session Session session("SQLite", "sample.db"); diff --git a/Data/samples/RowFormatter/src/RowFormatter.cpp b/Data/samples/RowFormatter/src/RowFormatter.cpp index 37da2ac10..87b8f80eb 100644 --- a/Data/samples/RowFormatter/src/RowFormatter.cpp +++ b/Data/samples/RowFormatter/src/RowFormatter.cpp @@ -103,9 +103,6 @@ public: int main(int argc, char** argv) { - // register SQLite connector - Poco::Data::SQLite::Connector::registerConnector(); - // create a session Session session("SQLite", "sample.db"); diff --git a/Data/samples/Tuple/src/Tuple.cpp b/Data/samples/Tuple/src/Tuple.cpp index a0aa8636d..91c60384b 100644 --- a/Data/samples/Tuple/src/Tuple.cpp +++ b/Data/samples/Tuple/src/Tuple.cpp @@ -50,9 +50,6 @@ int main(int argc, char** argv) typedef Poco::Tuple Person; typedef std::vector People; - // register SQLite connector - Poco::Data::SQLite::Connector::registerConnector(); - // create a session Session session("SQLite", "sample.db"); diff --git a/Data/samples/TypeHandler/src/TypeHandler.cpp b/Data/samples/TypeHandler/src/TypeHandler.cpp index 52d8315f1..8e193d3e2 100644 --- a/Data/samples/TypeHandler/src/TypeHandler.cpp +++ b/Data/samples/TypeHandler/src/TypeHandler.cpp @@ -103,9 +103,6 @@ public: int main(int argc, char** argv) { - // register SQLite connector - Poco::Data::SQLite::Connector::registerConnector(); - // create a session Session session("SQLite", "sample.db"); diff --git a/Data/src/Date.cpp b/Data/src/Date.cpp index 254ef69ad..b371e5dfe 100644 --- a/Data/src/Date.cpp +++ b/Data/src/Date.cpp @@ -142,15 +142,17 @@ using Poco::DateTime; template <> Var::operator Date () const { - if (!_pHolder) + VarHolder* pHolder = content(); + + if (!pHolder) throw InvalidAccessException("Can not convert empty value."); - if (typeid(Date) == _pHolder->type()) + if (typeid(Date) == pHolder->type()) return extract(); else { Poco::DateTime result; - _pHolder->convert(result); + pHolder->convert(result); return Date(result); } } diff --git a/Data/src/DynamicLOB.cpp b/Data/src/DynamicLOB.cpp index b99d70825..5b76e4a28 100644 --- a/Data/src/DynamicLOB.cpp +++ b/Data/src/DynamicLOB.cpp @@ -53,15 +53,17 @@ using Poco::Data::BLOB; template <> Var::operator CLOB () const { - if (!_pHolder) + VarHolder* pHolder = content(); + + if (!pHolder) throw InvalidAccessException("Can not convert empty value."); - if (typeid(CLOB) == _pHolder->type()) + if (typeid(CLOB) == pHolder->type()) return extract(); else { std::string result; - _pHolder->convert(result); + pHolder->convert(result); return CLOB(result); } } @@ -70,15 +72,17 @@ Var::operator CLOB () const template <> Var::operator BLOB () const { - if (!_pHolder) + VarHolder* pHolder = content(); + + if (!pHolder) throw InvalidAccessException("Can not convert empty value."); - if (typeid(BLOB) == _pHolder->type()) + if (typeid(BLOB) == pHolder->type()) return extract(); else { std::string result; - _pHolder->convert(result); + pHolder->convert(result); return BLOB(reinterpret_cast(result.data()), result.size()); } diff --git a/Data/src/PooledSessionImpl.cpp b/Data/src/PooledSessionImpl.cpp index c6c253d1d..8c8c0bd78 100644 --- a/Data/src/PooledSessionImpl.cpp +++ b/Data/src/PooledSessionImpl.cpp @@ -163,7 +163,7 @@ void PooledSessionImpl::close() } -const std::string& PooledSessionImpl::connectorName() +const std::string& PooledSessionImpl::connectorName() const { return access()->connectorName(); } @@ -193,7 +193,7 @@ Poco::Any PooledSessionImpl::getProperty(const std::string& name) } -SessionImpl* PooledSessionImpl::access() +SessionImpl* PooledSessionImpl::access() const { if (_pHolder) { diff --git a/Data/src/StatementImpl.cpp b/Data/src/StatementImpl.cpp index 57b254345..0c8ba0995 100644 --- a/Data/src/StatementImpl.cpp +++ b/Data/src/StatementImpl.cpp @@ -476,7 +476,8 @@ void StatementImpl::formatSQL(std::vector& arguments) { std::string sql; Poco::format(sql, _ostr.str(), arguments); - _ostr.str(""); _ostr << sql; + _ostr.str(""); + _ostr << sql; } diff --git a/Data/src/Time.cpp b/Data/src/Time.cpp index cc57cc697..e9d01082f 100644 --- a/Data/src/Time.cpp +++ b/Data/src/Time.cpp @@ -139,15 +139,17 @@ using Poco::DateTime; template <> Var::operator Time () const { - if (!_pHolder) + VarHolder* pHolder = content(); + + if (!pHolder) throw InvalidAccessException("Can not convert empty value."); - if (typeid(Time) == _pHolder->type()) + if (typeid(Time) == pHolder->type()) return extract