diff --git a/Data/MySQL/Makefile b/Data/MySQL/Makefile new file mode 100644 index 000000000..b50e5d111 --- /dev/null +++ b/Data/MySQL/Makefile @@ -0,0 +1,23 @@ +# +# Makefile +# +# $Id: //poco/1.3/Data/MySQL/Makefile#3 $ +# +# Makefile for Poco MySQL +# + +include $(POCO_BASE)/build/rules/global + +SYSLIBS += -L/usr/local/lib/mysql +INCLUDE += -I/usr/local/include/mysql/ +SYSFLAGS += -DTHREADSAFE -DNO_TCL + +objects = Binder Extractor SessionImpl Connector \ + MySQLStatementImpl ResultMetadata MySQLException \ + SessionHandle StatementExecutor + +target = PocoMySQL +target_version = $(LIBVERSION) +target_libs = PocoData PocoFoundation + +include $(POCO_BASE)/build/rules/lib diff --git a/Data/MySQL/MySQL_VS80.sln b/Data/MySQL/MySQL_VS80.sln new file mode 100644 index 000000000..528a7f3d4 --- /dev/null +++ b/Data/MySQL/MySQL_VS80.sln @@ -0,0 +1,29 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestSuite", "testsuite\TestSuite_VS80.vcproj", "{1B30A91B-375F-11DB-837B-00123FC423B5}" + ProjectSection(ProjectDependencies) = postProject + {73E19FDE-1570-488C-B3DB-72A60FADD408} = {73E19FDE-1570-488C-B3DB-72A60FADD408} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MySQL", "MySQL_VS80.vcproj", "{73E19FDE-1570-488C-B3DB-72A60FADD408}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + debug_shared|Win32 = debug_shared|Win32 + release_shared|Win32 = release_shared|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1B30A91B-375F-11DB-837B-00123FC423B5}.debug_shared|Win32.ActiveCfg = debug_shared|Win32 + {1B30A91B-375F-11DB-837B-00123FC423B5}.debug_shared|Win32.Build.0 = debug_shared|Win32 + {1B30A91B-375F-11DB-837B-00123FC423B5}.release_shared|Win32.ActiveCfg = release_shared|Win32 + {1B30A91B-375F-11DB-837B-00123FC423B5}.release_shared|Win32.Build.0 = release_shared|Win32 + {73E19FDE-1570-488C-B3DB-72A60FADD408}.debug_shared|Win32.ActiveCfg = debug_shared|Win32 + {73E19FDE-1570-488C-B3DB-72A60FADD408}.debug_shared|Win32.Build.0 = debug_shared|Win32 + {73E19FDE-1570-488C-B3DB-72A60FADD408}.release_shared|Win32.ActiveCfg = release_shared|Win32 + {73E19FDE-1570-488C-B3DB-72A60FADD408}.release_shared|Win32.Build.0 = release_shared|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Data/MySQL/MySQL_VS80.vcproj b/Data/MySQL/MySQL_VS80.vcproj new file mode 100644 index 000000000..5adcde9db --- /dev/null +++ b/Data/MySQL/MySQL_VS80.vcproj @@ -0,0 +1,279 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Data/MySQL/include/Poco/Data/MySQL/Binder.h b/Data/MySQL/include/Poco/Data/MySQL/Binder.h new file mode 100644 index 000000000..2a5b742ae --- /dev/null +++ b/Data/MySQL/include/Poco/Data/MySQL/Binder.h @@ -0,0 +1,133 @@ +// +// Binder.h +// +// $Id: //poco/1.3/Data/MySQL/include/Poco/Data/MySQL/Binder.h#1 $ +// +// Library: Data +// Package: MySQL +// Module: Binder +// +// Definition of the Binder class. +// +// Copyright (c) 2008, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +#ifndef Data_MySQL_Binder_INCLUDED +#define Data_MySQL_Binder_INCLUDED + +#include "Poco/Data/MySQL/MySQL.h" +#include "Poco/Data/AbstractBinder.h" +#include "Poco/Data/BLOB.h" +#include "Poco/Data/MySQL/MySQLException.h" +#include + +namespace Poco { +namespace Data { +namespace MySQL { + + +class MySQL_API Binder: public Poco::Data::AbstractBinder + /// Binds placeholders in the sql query to the provided values. Performs data types mapping. +{ +public: + + Binder(); + /// Creates the Binder. + + virtual ~Binder(); + /// Destroys the Binder. + + virtual void bind(std::size_t pos, const Poco::Int8& val); + /// Binds an Int8. + + virtual void bind(std::size_t pos, const Poco::UInt8& val); + /// Binds an UInt8. + + virtual void bind(std::size_t pos, const Poco::Int16& val); + /// Binds an Int16. + + virtual void bind(std::size_t pos, const Poco::UInt16& val); + /// Binds an UInt16. + + virtual void bind(std::size_t pos, const Poco::Int32& val); + /// Binds an Int32. + + virtual void bind(std::size_t pos, const Poco::UInt32& val); + /// Binds an UInt32. + + virtual void bind(std::size_t pos, const Poco::Int64& val); + /// Binds an Int64. + + virtual void bind(std::size_t pos, const Poco::UInt64& val); + /// Binds an UInt64. + + virtual void bind(std::size_t pos, const bool& val); + /// Binds a boolean. + + virtual void bind(std::size_t pos, const float& val); + /// Binds a float. + + virtual void bind(std::size_t pos, const double& val); + /// Binds a double. + + virtual void bind(std::size_t pos, const char& val); + /// Binds a single character. + + virtual void bind(std::size_t pos, const std::string& val); + /// Binds a string. + + virtual void bind(std::size_t pos, const Poco::Data::BLOB& val); + /// Binds a BLOB. + + size_t size() const; + /// Return count of binded parameters + + MYSQL_BIND* getBindArray() const; + /// Return array + +private: + + virtual void bind(std::size_t, const char* const&) + /// Binds a const char ptr. + /// This is a private no-op in this implementation + /// due to security risk. + { + } + + void realBind(std::size_t pos, enum_field_types type, const void* buffer, int length); + /// Common bind implementation + +private: + + std::vector _bindArray; +}; + + +} } } // namespace Poco::Data::MySQL + + +#endif // Data_MySQL_Binder_INCLUDED diff --git a/Data/MySQL/include/Poco/Data/MySQL/Connector.h b/Data/MySQL/include/Poco/Data/MySQL/Connector.h new file mode 100644 index 000000000..397336f2c --- /dev/null +++ b/Data/MySQL/include/Poco/Data/MySQL/Connector.h @@ -0,0 +1,76 @@ +// +// Connector.h +// +// $Id: //poco/1.3/Data/MySQL/include/Poco/Data/MySQL/Connector.h#1 $ +// +// Library: Data +// Package: MySQL +// Module: Connector +// +// Definition of the Connector class. +// +// Copyright (c) 2008, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +#ifndef Data_MySQL_Connector_INCLUDED +#define Data_MySQL_Connector_INCLUDED + +#include "MySQL.h" +#include "Poco/Data/Connector.h" + +namespace Poco { +namespace Data { +namespace MySQL { + +class MySQL_API Connector: public Poco::Data::Connector + /// Connector instantiates MySQL SessionImpl objects. +{ +public: + + static std::string KEY; + + Connector(); + /// Creates the Connector. + + virtual ~Connector(); + /// Destroys the Connector. + + virtual Poco::AutoPtr createSession(const std::string& connectionString); + /// Creates a MySQL SessionImpl object and initializes it with the given connectionString. + + static void registerConnector(); + /// Registers the Connector under the Keyword Connector::KEY at the Poco::Data::SessionFactory + + static void unregisterConnector(); + /// Unregisters the Connector under the Keyword Connector::KEY at the Poco::Data::SessionFactory +}; + + +} } } // namespace Poco::Data::MySQL + + +#endif // Data_MySQL_Connector_INCLUDED diff --git a/Data/MySQL/include/Poco/Data/MySQL/Extractor.h b/Data/MySQL/include/Poco/Data/MySQL/Extractor.h new file mode 100644 index 000000000..0e5eb068b --- /dev/null +++ b/Data/MySQL/include/Poco/Data/MySQL/Extractor.h @@ -0,0 +1,124 @@ +// +// Extractor.h +// +// $Id: //poco/1.3/Data/MySQL/include/Poco/Data/MySQL/Extractor.h#1 $ +// +// Library: Data +// Package: MySQL +// Module: Extractor +// +// Definition of the Extractor class. +// +// Copyright (c) 2008, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +#ifndef Data_MySQL_Extractor_INCLUDED +#define Data_MySQL_Extractor_INCLUDED + + +#include "Poco/Data/MySQL/MySQL.h" +#include "Poco/Data/MySQL/StatementExecutor.h" +#include "Poco/Data/MySQL/ResultMetadata.h" +#include "Poco/Data/AbstractExtractor.h" +#include "Poco/Data/BLOB.h" + + +namespace Poco { +namespace Data { +namespace MySQL { + + +class MySQL_API Extractor: public Poco::Data::AbstractExtractor + /// Extracts and converts data values from the result row returned by MySQL. + /// If NULL is received, the incoming val value is not changed and false is returned +{ +public: + Extractor(StatementExecutor& st, ResultMetadata& md); + /// Creates the Extractor. + + virtual ~Extractor(); + /// Destroys the Extractor. + + virtual bool extract(std::size_t pos, Poco::Int8& val); + /// Extracts an Int8. + + virtual bool extract(std::size_t pos, Poco::UInt8& val); + /// Extracts an UInt8. + + virtual bool extract(std::size_t pos, Poco::Int16& val); + /// Extracts an Int16. + + virtual bool extract(std::size_t pos, Poco::UInt16& val); + /// Extracts an UInt16. + + virtual bool extract(std::size_t pos, Poco::Int32& val); + /// Extracts an Int32. + + virtual bool extract(std::size_t pos, Poco::UInt32& val); + /// Extracts an UInt32. + + virtual bool extract(std::size_t pos, Poco::Int64& val); + /// Extracts an Int64. + + virtual bool extract(std::size_t pos, Poco::UInt64& val); + /// Extracts an UInt64. + + virtual bool extract(std::size_t pos, bool& val); + /// Extracts a boolean. + + virtual bool extract(std::size_t pos, float& val); + /// Extracts a float. + + virtual bool extract(std::size_t pos, double& val); + /// Extracts a double. + + virtual bool extract(std::size_t pos, char& val); + /// Extracts a single character. + + virtual bool extract(std::size_t pos, std::string& val); + /// Extracts a string. + + virtual bool extract(std::size_t pos, Poco::Data::BLOB& val); + /// Extracts a BLOB. + +private: + + bool realExtractFixed(std::size_t pos, enum_field_types type, void* buffer, size_t length = 0); + + // Prevent VC8 warning "operator= could not be generated" + Extractor& operator=(const Extractor&); + +private: + + StatementExecutor& _stmt; + ResultMetadata& _metadata; +}; + +} } } // namespace Poco::Data::MySQL + + +#endif // Data_MySQL_Extractor_INCLUDED diff --git a/Data/MySQL/include/Poco/Data/MySQL/MySQL.h b/Data/MySQL/include/Poco/Data/MySQL/MySQL.h new file mode 100644 index 000000000..cf57af789 --- /dev/null +++ b/Data/MySQL/include/Poco/Data/MySQL/MySQL.h @@ -0,0 +1,90 @@ +// +// MySQL.h +// +// $Id: //poco/1.3/Data/MySQL/include/Poco/Data/MySQL/MySQL.h#1 $ +// +// Library: Data +// Package: MySQL +// Module: MySQL +// +// Basic definitions for the MySQL library. +// +// Copyright (c) 2008, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +#ifndef MySQL_MySQL_INCLUDED +#define MySQL_MySQL_INCLUDED + + +#include "Poco/Foundation.h" + + +// +// The following block is the standard way of creating macros which make exporting +// from a DLL simpler. All files within this DLL are compiled with the ODBC_EXPORTS +// symbol defined on the command line. this symbol should not be defined on any project +// that uses this DLL. This way any other project whose source files include this file see +// ODBC_API functions as being imported from a DLL, wheras this DLL sees symbols +// defined with this macro as being exported. +// +#if defined(_WIN32) && defined(POCO_DLL) + #if defined(MYSQL_EXPORTS) + #define MySQL_API __declspec(dllexport) + #else + #define MySQL_API __declspec(dllimport) + #endif +#endif + + +#if !defined(MySQL_API) + #define MySQL_API +#endif + + +// +// Automatically link Data library. +// +#if defined(_MSC_VER) + #if !defined(POCO_NO_AUTOMATIC_LIBS) && !defined(MYSQL_EXPORTS) + #if defined(POCO_DLL) + #if defined(_DEBUG) + #pragma comment(lib, "PocoMySQLd.lib") + #else + #pragma comment(lib, "PocoMySQL.lib") + #endif + #else + #if defined(_DEBUG) + #pragma comment(lib, "PocoMySQLmtd.lib") + #else + #pragma comment(lib, "PocoMySQLmt.lib") + #endif + #endif + #endif +#endif + + +#endif // MySQL_MySQL_INCLUDED diff --git a/Data/MySQL/include/Poco/Data/MySQL/MySQLException.h b/Data/MySQL/include/Poco/Data/MySQL/MySQLException.h new file mode 100644 index 000000000..8cb5b7dfd --- /dev/null +++ b/Data/MySQL/include/Poco/Data/MySQL/MySQLException.h @@ -0,0 +1,165 @@ +// +// MySQLException.h +// +// $Id: //poco/1.3/Data/MySQL/include/Poco/Data/MySQL/MySQLException.h#1 $ +// +// Library: Data +// Package: MySQL +// Module: MySQLException +// +// Definition of the MySQLException class. +// +// Copyright (c) 2008, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +#ifndef Data_MySQL_MySQLException_INCLUDED +#define Data_MySQL_MySQLException_INCLUDED + +#include "Poco/Data/MySQL/MySQL.h" +#include "Poco/Data/DataException.h" +#include +#include + + +typedef struct st_mysql MYSQL; +typedef struct st_mysql_stmt MYSQL_STMT; + + +namespace Poco { +namespace Data { +namespace MySQL { + +// End-user include this file and use in code ConnectionException/StatementException +// So it need not know + +class MySQL_API MySQLException: public Poco::Data::DataException + /// Base class for all MySQL exceptions +{ +public: + + MySQLException(const std::string& msg); + /// Creates MySQLException. + + MySQLException(const MySQLException& exc); + /// Creates MySQLException. + + ~MySQLException() throw(); + /// Destroys MySQLexception. + + MySQLException& operator=(const MySQLException& exc); + /// Assignment operator. + + const char* name() const throw(); + /// Returns exception name. + + const char* className() const throw(); + /// Returns the name of the exception class. + + Poco::Exception* clone() const; + /// Creates an exact copy of the exception. + /// + /// The copy can later be thrown again by + /// invoking rethrow() on it. + + void rethrow() const; + /// (Re)Throws the exception. + /// + /// This is useful for temporarily storing a + /// copy of an exception (see clone()), then + /// throwing it again. +}; + + +class ConnectionException : public MySQLException + /// ConnectionException +{ +public: + + ConnectionException(const std::string& msg); + /// Creates ConnectionException. + + ConnectionException(const std::string& text, MYSQL* h); + /// Destroys ConnectionException. + +private: + + static std::string compose(const std::string& text, MYSQL* h); + +}; + + +class StatementException : public MySQLException + /// StatementException +{ +public: + + StatementException(const std::string& msg); + /// Creates StatementException. + + StatementException(const std::string& text, MYSQL_STMT* h, const std::string& stmt = ""); + /// Destroys StatementException. + +private: + + static std::string compose(const std::string& text, MYSQL_STMT* h, const std::string& stmt); +}; + + +// +// inlines +// + +inline MySQLException& MySQLException::operator=(const MySQLException& exc) +{ + Poco::Data::DataException::operator=(exc); + return *this; +} + +inline const char* MySQLException::name() const throw() +{ + return "MySQL"; +} + +inline const char* MySQLException::className() const throw() +{ + return typeid(*this).name(); +} + +inline Poco::Exception* MySQLException::clone() const +{ + return new MySQLException(*this); +} + +inline void MySQLException::rethrow() const +{ + throw *this; +} + + +} } } // namespace Poco::Data::MySQL + +#endif //Data_MySQL_MySQLException_INCLUDED diff --git a/Data/MySQL/include/Poco/Data/MySQL/MySQLStatementImpl.h b/Data/MySQL/include/Poco/Data/MySQL/MySQLStatementImpl.h new file mode 100644 index 000000000..b1eb9be49 --- /dev/null +++ b/Data/MySQL/include/Poco/Data/MySQL/MySQLStatementImpl.h @@ -0,0 +1,118 @@ +// +// MySQLstatementImpl.h +// +// $Id: //poco/1.3/Data/MySQL/include/Poco/Data/MySQL/MySQLStatementImpl.h#1 $ +// +// Library: Data +// Package: MySQL +// Module: MySQLstatementImpl +// +// Definition of the MySQLStatementImpl class. +// +// Copyright (c) 2008, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +#ifndef Data_MySQL_MySQLStatementImpl_INCLUDED +#define Data_MySQL_MySQLStatementImpl_INCLUDED + +#include "Poco/Data/MySQL/MySQL.h" +#include "Poco/Data/MySQL/SessionImpl.h" +#include "Poco/Data/MySQL/Binder.h" +#include "Poco/Data/MySQL/Extractor.h" +#include "Poco/Data/MySQL/StatementExecutor.h" +#include "Poco/Data/MySQL/ResultMetadata.h" +#include "Poco/Data/StatementImpl.h" +#include "Poco/SharedPtr.h" +#include "Poco/Format.h" + + +namespace Poco { +namespace Data { +namespace MySQL { + + +class MySQL_API MySQLStatementImpl: public Poco::Data::StatementImpl + /// Implements statement functionality needed for MySQL +{ +public: + + MySQLStatementImpl(SessionHandle& h); + /// Creates the MySQLStatementImpl. + + ~MySQLStatementImpl(); + /// Destroys the MySQLStatementImpl. + +protected: + + virtual Poco::UInt32 columnsReturned() const; + /// Returns number of columns returned by query. + + virtual const MetaColumn& metaColumn(Poco::UInt32 pos) const; + /// Returns column meta data. + + virtual bool hasNext(); + /// Returns true if a call to next() will return data. + + virtual void next(); + /// Retrieves the next row from the resultset. + /// Will throw, if the resultset is empty. + + virtual bool canBind() const; + /// Returns true if a valid statement is set and we can bind. + + virtual void compileImpl(); + /// Compiles the statement, doesn't bind yet + + virtual void bindImpl(); + /// Binds parameters + + virtual AbstractExtractor& extractor(); + /// Returns the concrete extractor used by the statement. + + virtual AbstractBinder& binder(); + /// Returns the concrete binder used by the statement. + +private: + enum + { + NEXT_DONTKNOW, + NEXT_TRUE, + NEXT_FALSE + }; + + StatementExecutor _stmt; + ResultMetadata _metadata; + Binder _binder; + Extractor _extractor; + int _hasNext; +}; + + +} } } // namespace Poco::Data::MySQL + + +#endif // Data_MySQL_MySQLStatementImpl_INCLUDED diff --git a/Data/MySQL/include/Poco/Data/MySQL/ResultMetadata.h b/Data/MySQL/include/Poco/Data/MySQL/ResultMetadata.h new file mode 100644 index 000000000..46299fbaf --- /dev/null +++ b/Data/MySQL/include/Poco/Data/MySQL/ResultMetadata.h @@ -0,0 +1,86 @@ +// +// ResultMetadata.h +// +// $Id: //poco/1.3/Data/MySQL/include/Poco/Data/MySQL/ResultMetadata.h#1 $ +// +// Library: Data +// Package: MySQL +// Module: ResultMetadata +// +// Definition of the ResultMetadata class. +// +// Copyright (c) 2008, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +#ifndef Data_MySQL_ResultMetadata_INCLUDED +#define Data_MySQL_ResultMetadata_INCLUDED + +#include +#include +#include "Poco/Data/MetaColumn.h" + +namespace Poco { +namespace Data { +namespace MySQL { + +class ResultMetadata + /// MySQL result metadata +{ +public: + + void reset(); + /// Resets the metadata. + + void init(MYSQL_STMT* stmt); + /// Initializes the metadata. + + Poco::UInt32 columnsReturned() const; + /// Returns the number of columns in resultset. + + const MetaColumn& metaColumn(Poco::UInt32 pos) const; + /// Returns the reference to the specified metacolumn. + + MYSQL_BIND* row(); + /// + + size_t length(size_t pos); + /// + + const char* rawData(size_t pos); + /// + +private: + + std::vector _columns; + std::vector _row; + std::vector _buffer; + std::vector _lengths; +}; + +}}} + +#endif //Data_MySQL_ResultMetadata_INCLUDED diff --git a/Data/MySQL/include/Poco/Data/MySQL/SessionHandle.h b/Data/MySQL/include/Poco/Data/MySQL/SessionHandle.h new file mode 100644 index 000000000..b3f48636b --- /dev/null +++ b/Data/MySQL/include/Poco/Data/MySQL/SessionHandle.h @@ -0,0 +1,95 @@ +// +// SesssionHandle.h +// +// $Id: //poco/1.3/Data/MySQL/include/Poco/Data/MySQL/SessionHandle.h#1 $ +// +// Library: Data +// Package: MySQL +// Module: SessionHandle +// +// Definition of the SessionHandle class. +// +// Copyright (c) 2008, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +#ifndef Data_MySQL_SessionHandle_INCLUDED +#define Data_MySQL_SessionHandle_INCLUDED + +#include +#include "Poco/Data/MySQL/MySQLException.h" + +#include + +namespace Poco { +namespace Data { +namespace MySQL { + +class SessionHandle + /// MySQL session handle +{ +public: + + explicit SessionHandle(MYSQL* mysql); + + ~SessionHandle(); + + void options(mysql_option opt); + + void options(mysql_option opt, bool b); + + void connect(const char* host, const char* user, const char* password, const char* db, unsigned int port); + + void close(); + + void query(const char* str); + + operator MYSQL* (); + +private: + + SessionHandle(const SessionHandle&); + SessionHandle& operator=(const SessionHandle&); + +private: + + MYSQL* h; +}; + + +// +// inlines +// + +inline SessionHandle::operator MYSQL* () +{ + return h; +} + + +}}} + +#endif // Data_MySQL_SessionHandle_INCLUDED diff --git a/Data/MySQL/include/Poco/Data/MySQL/SessionImpl.h b/Data/MySQL/include/Poco/Data/MySQL/SessionImpl.h new file mode 100644 index 000000000..459ee9c4f --- /dev/null +++ b/Data/MySQL/include/Poco/Data/MySQL/SessionImpl.h @@ -0,0 +1,127 @@ +// +// SessionImpl.h +// +// $Id: //poco/1.3/Data/MySQL/include/Poco/Data/MySQL/SessionImpl.h#1 $ +// +// Library: Data +// Package: MySQL +// Module: SessionImpl +// +// Definition of the SessionImpl class. +// +// Copyright (c) 2008, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +#ifndef Data_MySQL_SessionImpl_INCLUDED +#define Data_MySQL_SessionImpl_INCLUDED + + +#include "Poco/Data/MySQL/MySQL.h" +#include "Poco/Data/AbstractSessionImpl.h" +#include "Poco/Data/MySQL/SessionHandle.h" + + +namespace Poco { +namespace Data { +namespace MySQL { + + +class MySQL_API SessionImpl: public Poco::Data::AbstractSessionImpl + /// Implements SessionImpl interface +{ +public: + + SessionImpl(const std::string& connectionString); + /// Creates the SessionImpl. Opens a connection to the database + /// + /// Connection string format: + /// == | ';' + /// == '=' + /// == 'host' | 'port' | 'user' | 'password' | 'db' } 'compress' | 'auto-reconnect' + /// == [~;]* + /// + /// for compress and auto-reconnect correct values are true/false + /// for port - numeric in decimal notation + /// + + ~SessionImpl(); + /// Destroys the SessionImpl. + + virtual Poco::Data::StatementImpl* createStatementImpl(); + /// Returns an MySQL StatementImpl + + virtual void begin(); + /// Starts a transaction + + virtual void commit(); + /// Commits and ends a transaction + + virtual void rollback(); + /// Aborts a transaction + + virtual void close(); + /// Closes the connection + + virtual bool isConnected(); + /// Returns true iff session is connected. + + virtual bool isTransaction(); + /// Returns true iff a transaction is in progress. + + void setInsertId(const std::string&, const Poco::Any&); + /// Try to set insert id - do nothing. + + Poco::Any getInsertId(const std::string&); + /// Get insert id + +private: + + SessionHandle _mysql; + bool _connected; + int _inTransaction; +}; + + +// +// inlines +// + +inline void SessionImpl::setInsertId(const std::string&, const Poco::Any&) +{ +} + + +inline Poco::Any SessionImpl::getInsertId(const std::string&) +{ + return Poco::Any(Poco::UInt64(mysql_insert_id(_mysql))); +} + + +} } } // namespace Poco::Data::MySQL + + +#endif // Data_MySQL_SessionImpl_INCLUDED diff --git a/Data/MySQL/include/Poco/Data/MySQL/StatementExecutor.h b/Data/MySQL/include/Poco/Data/MySQL/StatementExecutor.h new file mode 100644 index 000000000..923224c59 --- /dev/null +++ b/Data/MySQL/include/Poco/Data/MySQL/StatementExecutor.h @@ -0,0 +1,118 @@ +// +// StatementExecutor.h +// +// $Id: //poco/1.3/Data/MySQL/include/Poco/Data/MySQL/StatementExecutor.h#1 $ +// +// Library: Data +// Package: MySQL +// Module: StatementExecutor +// +// Definition of the StatementExecutor class. +// +// Copyright (c) 2008, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +#ifndef Data_MySQL_StatementHandle_INCLUDED +#define Data_MySQL_StatementHandle_INCLUDED + +#include +#include "Poco/Data/MySQL/MySQLException.h" + +#include + +namespace Poco { +namespace Data { +namespace MySQL { + +class StatementExecutor + /// MySQL statement executor. +{ +public: + enum State + { + STMT_INITED, + STMT_COMPILED, + STMT_EXECUTED + }; + + explicit StatementExecutor(MYSQL* mysql); + /// Creates the StatementExecutor. + + ~StatementExecutor(); + /// Destroys the StatementExecutor. + + int state() const; + /// Returns the current state. + + void prepare(const std::string& query); + /// Prepares the statement for execution. + + void bindParams(MYSQL_BIND* params, size_t count); + /// Binds the params. + + void bindResult(MYSQL_BIND* result); + /// Binds result. + + void execute(); + /// Executes the statement. + + bool fetch(); + /// Fetches the data. + + bool fetchColumn(size_t n, MYSQL_BIND *bind); + /// Fetches the column. + + operator MYSQL_STMT* (); + /// Cast operator to native handle type. + +private: + + StatementExecutor(const StatementExecutor&); + StatementExecutor& operator=(const StatementExecutor&); + +private: + + MYSQL_STMT* h; + int _state; + std::string _query; +}; + + +// +// inlines +// + +inline StatementExecutor::operator MYSQL_STMT* () +{ + return h; +} + + +}}} + + +#endif // Data_MySQL_StatementHandle_INCLUDED diff --git a/Data/MySQL/src/Binder.cpp b/Data/MySQL/src/Binder.cpp new file mode 100644 index 000000000..da991773d --- /dev/null +++ b/Data/MySQL/src/Binder.cpp @@ -0,0 +1,181 @@ +// +// MySQLException.cpp +// +// $Id: //poco/1.3/Data/MySQL/src/Binder.cpp#1 $ +// +// Library: Data +// Package: MySQL +// Module: Binder +// +// Copyright (c) 2008, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +#include "Poco/Data/MySQL/Binder.h" + + +namespace Poco { +namespace Data { +namespace MySQL { + + +Binder::Binder() +{ +} + + +Binder::~Binder() +{ +} + + +void Binder::bind(std::size_t pos, const Poco::Int8& val) +{ + realBind(pos, MYSQL_TYPE_TINY, &val, 0); +} + + +void Binder::bind(std::size_t pos, const Poco::UInt8& val) +{ + realBind(pos, MYSQL_TYPE_TINY, &val, 0); +} + + +void Binder::bind(std::size_t pos, const Poco::Int16& val) +{ + realBind(pos, MYSQL_TYPE_SHORT, &val, 0); +} + + +void Binder::bind(std::size_t pos, const Poco::UInt16& val) +{ + realBind(pos, MYSQL_TYPE_SHORT, &val, 0); +} + + +void Binder::bind(std::size_t pos, const Poco::Int32& val) +{ + realBind(pos, MYSQL_TYPE_LONG, &val, 0); +} + + +void Binder::bind(std::size_t pos, const Poco::UInt32& val) +{ + realBind(pos, MYSQL_TYPE_LONG, &val, 0); +} + + +void Binder::bind(std::size_t pos, const Poco::Int64& val) +{ + realBind(pos, MYSQL_TYPE_LONGLONG, &val, 0); +} + + +void Binder::bind(std::size_t pos, const Poco::UInt64& val) +{ + realBind(pos, MYSQL_TYPE_LONGLONG, &val, 0); +} + + +void Binder::bind(std::size_t pos, const bool& val) +{ + realBind(pos, MYSQL_TYPE_TINY, &val, 0); +} + + +void Binder::bind(std::size_t pos, const float& val) +{ + realBind(pos, MYSQL_TYPE_FLOAT, &val, 0); +} + + +void Binder::bind(std::size_t pos, const double& val) +{ + realBind(pos, MYSQL_TYPE_DOUBLE, &val, 0); +} + + +void Binder::bind(std::size_t pos, const char& val) +{ + realBind(pos, MYSQL_TYPE_TINY, &val, 0); +} + + +void Binder::bind(std::size_t pos, const std::string& val) +{ + realBind(pos, MYSQL_TYPE_STRING, val.c_str(), static_cast(val.length())); +} + + +void Binder::bind(std::size_t pos, const Poco::Data::BLOB& val) +{ + realBind(pos, MYSQL_TYPE_STRING, val.rawContent(), static_cast(val.size())); +} + + +size_t Binder::size() const +{ + return _bindArray.size(); +} + + +MYSQL_BIND* Binder::getBindArray() const +{ + if (_bindArray.size() == 0) + { + return 0; + } + + return const_cast(&_bindArray[0]); +} + + +void Binder::realBind(std::size_t pos, enum_field_types type, const void* buffer, int length) +{ + if (pos > 1024) + { + throw StatementException("too many bind parameters"); + } + + if (pos >= _bindArray.size()) + { + size_t s = _bindArray.size(); + _bindArray.resize(pos + 1); + + memset(&_bindArray[s], 0, sizeof(MYSQL_BIND) * (_bindArray.size() - s)); + } + + MYSQL_BIND b = {0}; + + b.buffer_type = type; + b.buffer = const_cast(buffer); + b.buffer_length = length; + + _bindArray[pos] = b; +} + + +} } } // namespace Poco::Data::MySQL diff --git a/Data/MySQL/src/Connector.cpp b/Data/MySQL/src/Connector.cpp new file mode 100644 index 000000000..f515813fc --- /dev/null +++ b/Data/MySQL/src/Connector.cpp @@ -0,0 +1,88 @@ +// +// MySQLException.cpp +// +// $Id: //poco/1.3/Data/MySQL/src/Connector.cpp#1 $ +// +// Library: Data +// Package: MySQL +// Module: Connector +// +// Copyright (c) 2008, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +#include "Poco/Data/MySQL/Connector.h" +#include "Poco/Data/MySQL/SessionImpl.h" +#include "Poco/Data/SessionFactory.h" +#include "Poco/Exception.h" + +#include + + +namespace Poco { +namespace Data { +namespace MySQL { + + +std::string Connector::KEY("MySQL"); + + +Connector::Connector() +{ +} + + +Connector::~Connector() +{ +} + + +Poco::AutoPtr Connector::createSession(const std::string& connectionString) +{ + return Poco::AutoPtr(new SessionImpl(connectionString)); +} + + +void Connector::registerConnector() +{ + if (mysql_library_init(0, 0, 0) != 0) + { + throw Exception("mysql_library_init error"); + } + + Poco::Data::SessionFactory::instance().add(KEY, new Connector()); +} + + +void Connector::unregisterConnector() +{ + Poco::Data::SessionFactory::instance().remove(KEY); + mysql_library_end(); +} + + +} } } // namespace Poco::Data::MySQL + diff --git a/Data/MySQL/src/Extractor.cpp b/Data/MySQL/src/Extractor.cpp new file mode 100644 index 000000000..e7fb6b062 --- /dev/null +++ b/Data/MySQL/src/Extractor.cpp @@ -0,0 +1,173 @@ +// +// MySQLException.cpp +// +// $Id: //poco/1.3/Data/MySQL/src/Extractor.cpp#1 $ +// +// Library: Data +// Package: MySQL +// Module: Extractor +// +// Copyright (c) 2008, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +#include "Poco/Data/MySQL/Extractor.h" + + +namespace Poco { +namespace Data { +namespace MySQL { + + +Extractor::Extractor(StatementExecutor& st, ResultMetadata& md): _stmt(st), _metadata(md) +{ +} + + +Extractor::~Extractor() +{ +} + + +bool Extractor::extract(std::size_t pos, Poco::Int8& val) +{ + return realExtractFixed(pos, MYSQL_TYPE_TINY, &val); +} + + +bool Extractor::extract(std::size_t pos, Poco::UInt8& val) +{ + return realExtractFixed(pos, MYSQL_TYPE_TINY, &val); +} + + +bool Extractor::extract(std::size_t pos, Poco::Int16& val) +{ + return realExtractFixed(pos, MYSQL_TYPE_SHORT, &val); +} + + +bool Extractor::extract(std::size_t pos, Poco::UInt16& val) +{ + return realExtractFixed(pos, MYSQL_TYPE_SHORT, &val); +} + + +bool Extractor::extract(std::size_t pos, Poco::Int32& val) +{ + return realExtractFixed(pos, MYSQL_TYPE_LONG, &val); +} + + +bool Extractor::extract(std::size_t pos, Poco::UInt32& val) +{ + return realExtractFixed(pos, MYSQL_TYPE_LONG, &val); +} + + +bool Extractor::extract(std::size_t pos, Poco::Int64& val) +{ + return realExtractFixed(pos, MYSQL_TYPE_LONGLONG, &val); +} + + +bool Extractor::extract(std::size_t pos, Poco::UInt64& val) +{ + return realExtractFixed(pos, MYSQL_TYPE_LONGLONG, &val); +} + + +bool Extractor::extract(std::size_t pos, bool& val) +{ + return realExtractFixed(pos, MYSQL_TYPE_TINY, &val); +} + + +bool Extractor::extract(std::size_t pos, float& val) +{ + return realExtractFixed(pos, MYSQL_TYPE_FLOAT, &val); +} + + +bool Extractor::extract(std::size_t pos, double& val) +{ + return realExtractFixed(pos, MYSQL_TYPE_DOUBLE, &val); +} + + +bool Extractor::extract(std::size_t pos, char& val) +{ + return realExtractFixed(pos, MYSQL_TYPE_TINY, &val); +} + + +bool Extractor::extract(std::size_t pos, std::string& val) +{ + if (_metadata.columnsReturned() <= pos) + { + return false; + } + + if (_metadata.metaColumn(static_cast(pos)).type() != Poco::Data::MetaColumn::FDT_STRING) + { + return false; + } + + val.assign(_metadata.rawData(pos), _metadata.length(pos)); + return true; +} + + +bool Extractor::extract(std::size_t pos, Poco::Data::BLOB& val) +{ + if (_metadata.columnsReturned() <= pos) + { + return false; + } + + if (_metadata.metaColumn(static_cast(pos)).type() != Poco::Data::MetaColumn::FDT_BLOB) + { + return false; + } + + val.assignRaw(_metadata.rawData(pos), _metadata.length(pos)); + return true; +} + + +bool Extractor::realExtractFixed(std::size_t pos, enum_field_types type, void* buffer, size_t length) +{ + MYSQL_BIND bind = {0}; + + bind.buffer_type = type; + bind.buffer = buffer; + bind.buffer_length = static_cast(length); + + return _stmt.fetchColumn(pos, &bind); +} + + +} } } // namespace Poco::Data::MySQL diff --git a/Data/MySQL/src/MySQLException.cpp b/Data/MySQL/src/MySQLException.cpp new file mode 100644 index 000000000..5e679db44 --- /dev/null +++ b/Data/MySQL/src/MySQLException.cpp @@ -0,0 +1,129 @@ +// +// MySQLException.cpp +// +// $Id: //poco/1.3/Data/MySQL/src/MySQLException.cpp#1 $ +// +// Library: Data +// Package: MySQL +// Module: MySQLException +// +// Copyright (c) 2008, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +#include "Poco/Data/MySQL/MySQLException.h" +#include + + +namespace Poco { +namespace Data { +namespace MySQL { + + +MySQLException::MySQLException(const std::string& msg) : Poco::Data::DataException(std::string("[MySQL]: ") + msg) +{ +} + + +MySQLException::MySQLException(const MySQLException& exc) : Poco::Data::DataException(exc) +{ +} + + +MySQLException::~MySQLException() throw() +{ +} + + +ConnectionException::ConnectionException(const std::string& msg) : MySQLException(msg) +{ +} + + +ConnectionException::ConnectionException(const std::string& text, MYSQL* h) : MySQLException(compose(text, h)) +{ +} + + +StatementException::StatementException(const std::string& msg) : MySQLException(msg) +{ +} + + +StatementException::StatementException(const std::string& text, MYSQL_STMT* h, const std::string& stmt) : MySQLException(compose(text, h, stmt)) +{ +} + + +std::string ConnectionException::compose(const std::string& text, MYSQL* h) +{ + std::string str; + str += "[Comment]: "; + str += text; + str += "\t[mysql_error]: "; + str += mysql_error(h); + + str += "\t[mysql_errno]: "; + char buff[30]; + sprintf(buff, "%d", mysql_errno(h)); + str += buff; + + str += "\t[mysql_sqlstate]: "; + str += mysql_sqlstate(h); + return str; +} + +std::string StatementException::compose(const std::string& text, MYSQL_STMT* h, const std::string& stmt) +{ + std::string str; + str += "[Comment]: "; + str += text; + + if (h != 0) + { + str += "\t[mysql_stmt_error]: "; + str += mysql_stmt_error(h); + + str += "\t[mysql_stmt_errno]: "; + char buff[30]; + sprintf(buff, "%d", mysql_stmt_errno(h)); + str += buff; + + str += "\t[mysql_stmt_sqlstate]: "; + str += mysql_stmt_sqlstate(h); + } + + if (stmt.length() > 0) + { + str += "\t[statemnt]: "; + str += stmt; + } + + return str; +} + + +} } } // namespace Poco::Data::MySQL diff --git a/Data/MySQL/src/MySQLStatementImpl.cpp b/Data/MySQL/src/MySQLStatementImpl.cpp new file mode 100644 index 000000000..4f51ef6b3 --- /dev/null +++ b/Data/MySQL/src/MySQLStatementImpl.cpp @@ -0,0 +1,175 @@ +// +// MySQLException.cpp +// +// $Id: //poco/1.3/Data/MySQL/src/MySQLStatementImpl.cpp#1 $ +// +// Library: Data +// Package: MySQL +// Module: MySQLStatementImpl +// +// Copyright (c) 2008, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +#include "Poco/Data/MySQL/MySQLStatementImpl.h" + + +namespace Poco { +namespace Data { +namespace MySQL { + + +MySQLStatementImpl::MySQLStatementImpl(SessionHandle& h): + _stmt(h), + _extractor(_stmt, _metadata), + _hasNext(NEXT_DONTKNOW) +{ +} + + +MySQLStatementImpl::~MySQLStatementImpl() +{ +} + + +Poco::UInt32 MySQLStatementImpl::columnsReturned() const +{ + return _metadata.columnsReturned(); +} + + +const MetaColumn& MySQLStatementImpl::metaColumn(Poco::UInt32 pos) const +{ + return _metadata.metaColumn(pos); +} + + +bool MySQLStatementImpl::hasNext() +{ + if (_hasNext == NEXT_DONTKNOW) + { + if (_metadata.columnsReturned() == 0) + { + return false; + } + + if (_stmt.fetch()) + { + _hasNext = NEXT_TRUE; + return true; + } + + _hasNext = NEXT_FALSE; + return false; + } + else if (_hasNext == NEXT_TRUE) + { + return true; + } + + return false; +} + + +void MySQLStatementImpl::next() +{ + if (!hasNext()) + throw StatementException("No data received"); + + Poco::Data::AbstractExtractionVec::iterator it = extractions().begin(); + Poco::Data::AbstractExtractionVec::iterator itEnd = extractions().end(); + std::size_t pos = 0; + + for (; it != itEnd; ++it) + { + (*it)->extract(pos); + pos += (*it)->numOfColumnsHandled(); + } + + _hasNext = NEXT_DONTKNOW; +} + + +bool MySQLStatementImpl::canBind() const +{ + bool ret = false; + + if ((_stmt.state() >= StatementExecutor::STMT_COMPILED) && !bindings().empty()) + ret = (*bindings().begin())->canBind(); + + return ret; +} + + +void MySQLStatementImpl::compileImpl() +{ + _metadata.reset(); + _stmt.prepare(toString()); + _metadata.init(_stmt); + + if (_metadata.columnsReturned() > 0) + { + _stmt.bindResult(_metadata.row()); + } +} + + +void MySQLStatementImpl::bindImpl() +{ + { + Poco::Data::AbstractBindingVec& binds = bindings(); + size_t pos = 0; + Poco::Data::AbstractBindingVec::iterator it = binds.begin(); + Poco::Data::AbstractBindingVec::iterator itEnd = binds.end(); + + for (; it != itEnd && (*it)->canBind(); ++it) + { + (*it)->bind(pos); + pos += (*it)->numOfColumnsHandled(); + } + } + + _stmt.bindParams(_binder.getBindArray(), _binder.size()); + + _stmt.execute(); + + _hasNext = NEXT_DONTKNOW; +} + + +AbstractExtractor& MySQLStatementImpl::extractor() +{ + return _extractor; +} + + +AbstractBinder& MySQLStatementImpl::binder() +{ + return _binder; +} + + +} } } // namespace Poco::Data::MySQL diff --git a/Data/MySQL/src/ResultMetadata.cpp b/Data/MySQL/src/ResultMetadata.cpp new file mode 100644 index 000000000..33cd3ad8f --- /dev/null +++ b/Data/MySQL/src/ResultMetadata.cpp @@ -0,0 +1,259 @@ +// +// MySQLException.cpp +// +// $Id: //poco/1.3/Data/MySQL/src/ResultMetadata.cpp#1 $ +// +// Library: Data +// Package: MySQL +// Module: ResultMetadata +// +// Copyright (c) 2008, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +#include "Poco/Data/MySQL/ResultMetadata.h" +#include "Poco/Data/MySQL/MySQLException.h" + +namespace +{ + class ResultMetadataHandle + /// Simple exception-safe wrapper + { + public: + + explicit ResultMetadataHandle(MYSQL_STMT* stmt) + { + h = mysql_stmt_result_metadata(stmt); + } + + ~ResultMetadataHandle() + { + if (h) + { + mysql_free_result(h); + } + } + + operator MYSQL_RES* () + { + return h; + } + + private: + + MYSQL_RES* h; + }; + + size_t fieldSize(const MYSQL_FIELD& field) + /// Convert field MySQL-type and field MySQL-length to actual field length + { + switch (field.type) + { + case MYSQL_TYPE_TINY: return sizeof(char); + case MYSQL_TYPE_SHORT: return sizeof(short); + case MYSQL_TYPE_LONG: return sizeof(Poco::Int32); + case MYSQL_TYPE_FLOAT: return sizeof(float); + case MYSQL_TYPE_DOUBLE: return sizeof(double); + case MYSQL_TYPE_LONGLONG: return sizeof(Poco::Int64); + + case MYSQL_TYPE_DECIMAL: + case MYSQL_TYPE_NEWDECIMAL: + case MYSQL_TYPE_STRING: + case MYSQL_TYPE_VAR_STRING: + case MYSQL_TYPE_TINY_BLOB: + case MYSQL_TYPE_MEDIUM_BLOB: + case MYSQL_TYPE_LONG_BLOB: + case MYSQL_TYPE_BLOB: + case MYSQL_TYPE_NULL: + case MYSQL_TYPE_TIMESTAMP: + case MYSQL_TYPE_INT24: + case MYSQL_TYPE_DATE: + case MYSQL_TYPE_TIME: + case MYSQL_TYPE_DATETIME: + case MYSQL_TYPE_YEAR: + case MYSQL_TYPE_NEWDATE: + case MYSQL_TYPE_VARCHAR: + case MYSQL_TYPE_BIT: + case MYSQL_TYPE_ENUM: + case MYSQL_TYPE_SET: + case MYSQL_TYPE_GEOMETRY: + default: + return field.length; + } + + throw Poco::Data::MySQL::StatementException("unknown field type"); + } + + Poco::Data::MetaColumn::ColumnDataType fieldType(const MYSQL_FIELD& field) + /// Convert field MySQL-type to Poco-type + { + bool unsig = ((field.flags & UNSIGNED_FLAG) == UNSIGNED_FLAG); + + switch (field.type) + { + case MYSQL_TYPE_TINY: + if (unsig) return Poco::Data::MetaColumn::FDT_UINT8; + return Poco::Data::MetaColumn::FDT_INT8; + + case MYSQL_TYPE_SHORT: + if (unsig) return Poco::Data::MetaColumn::FDT_UINT16; + return Poco::Data::MetaColumn::FDT_INT16; + + case MYSQL_TYPE_LONG: + if (unsig) return Poco::Data::MetaColumn::FDT_UINT32; + return Poco::Data::MetaColumn::FDT_INT32; + + case MYSQL_TYPE_FLOAT: + return Poco::Data::MetaColumn::FDT_FLOAT; + + case MYSQL_TYPE_DOUBLE: + return Poco::Data::MetaColumn::FDT_DOUBLE; + + case MYSQL_TYPE_LONGLONG: + if (unsig) return Poco::Data::MetaColumn::FDT_UINT64; + return Poco::Data::MetaColumn::FDT_INT64; + + case MYSQL_TYPE_STRING: + case MYSQL_TYPE_VAR_STRING: + return Poco::Data::MetaColumn::FDT_STRING; + + case MYSQL_TYPE_TINY_BLOB: + case MYSQL_TYPE_MEDIUM_BLOB: + case MYSQL_TYPE_LONG_BLOB: + case MYSQL_TYPE_BLOB: + return Poco::Data::MetaColumn::FDT_BLOB; + + case MYSQL_TYPE_DECIMAL: + case MYSQL_TYPE_NEWDECIMAL: + case MYSQL_TYPE_NULL: + case MYSQL_TYPE_TIMESTAMP: + case MYSQL_TYPE_INT24: + case MYSQL_TYPE_DATE: + case MYSQL_TYPE_TIME: + case MYSQL_TYPE_DATETIME: + case MYSQL_TYPE_YEAR: + case MYSQL_TYPE_NEWDATE: + case MYSQL_TYPE_VARCHAR: + case MYSQL_TYPE_BIT: + case MYSQL_TYPE_ENUM: + case MYSQL_TYPE_SET: + case MYSQL_TYPE_GEOMETRY: + default: + return Poco::Data::MetaColumn::FDT_UNKNOWN; + } + } +} + + +namespace Poco { +namespace Data { +namespace MySQL { + +void ResultMetadata::reset() +{ + _columns.resize(0); + _row.resize(0); + _buffer.resize(0); + _lengths.resize(0); +} + +void ResultMetadata::init(MYSQL_STMT* stmt) +{ + ResultMetadataHandle h(stmt); + + if (!h) + { + // all right, it is normal + // querys such an "INSERT INTO" just does not have result at all + reset(); + return; + } + + size_t count = mysql_num_fields(h); + MYSQL_FIELD* fields = mysql_fetch_fields(h); + + size_t commonSize = 0; + _columns.reserve(count); + + {for (size_t i = 0; i < count; i++) + { + _columns.push_back(MetaColumn( + i, // position + fields[i].name, // name + fieldType(fields[i]), // type + fieldSize(fields[i]), // length + 0, // TODO: precision (Now I dont know how to get it) + !IS_NOT_NULL(fields[i].flags) // nullable + )); + + commonSize += _columns[i].length(); + }} + + _buffer.resize(commonSize); + _row.resize(count); + _lengths.resize(count); + + size_t offset = 0; + + {for (size_t i = 0; i < count; i++) + { + memset(&_row[i], 0, sizeof(MYSQL_BIND)); + + _row[i].buffer_type = fields[i].type; + _row[i].buffer_length = static_cast(_columns[i].length()); + _row[i].buffer = &_buffer[0] + offset; + _row[i].length = &_lengths[i]; + + offset += _row[i].buffer_length; + }} +} + +Poco::UInt32 ResultMetadata::columnsReturned() const +{ + return static_cast(_columns.size()); +} + +const MetaColumn& ResultMetadata::metaColumn(Poco::UInt32 pos) const +{ + return _columns[pos]; +} + +MYSQL_BIND* ResultMetadata::row() +{ + return &_row[0]; +} + +size_t ResultMetadata::length(size_t pos) +{ + return _lengths[pos]; +} + +const char* ResultMetadata::rawData(size_t pos) +{ + return reinterpret_cast(_row[pos].buffer); +} + +}}} diff --git a/Data/MySQL/src/SessionHandle.cpp b/Data/MySQL/src/SessionHandle.cpp new file mode 100644 index 000000000..d6778e42c --- /dev/null +++ b/Data/MySQL/src/SessionHandle.cpp @@ -0,0 +1,119 @@ +// +// SesssionHandle.cpp +// +// $Id: //poco/1.3/Data/MySQL/src/SessionHandle.cpp#1 $ +// +// Library: Data +// Package: MySQL +// Module: SessionHandle +// +// Copyright (c) 2008, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +#include "Poco/Data/MySQL/SessionHandle.h" + + +namespace Poco { +namespace Data { +namespace MySQL { + + +SessionHandle::SessionHandle(MYSQL* mysql) +{ + h = mysql_init(mysql); + + if (!h) + { + throw ConnectionException("mysql_init error"); + } +} + + +SessionHandle::~SessionHandle() +{ + close(); +} + + +void SessionHandle::options(mysql_option opt) +{ + int res = mysql_options(h, opt, 0); + + if (res != 0) + { + throw ConnectionException("mysql_options error", h); + } +} + + +void SessionHandle::options(mysql_option opt, bool b) +{ + my_bool tmp = b; + int res = mysql_options(h, opt, &tmp); + + if (res != 0) + { + throw ConnectionException("mysql_options error", h); + } +} + + +void SessionHandle::connect(const char* host, const char* user, const char* password, const char* db, unsigned int port) +{ + if (!mysql_real_connect(h, host, user, password, db, port, 0, 0)) + { + throw ConnectionException("create session: mysql_real_connect error", h); + } +} + + +void SessionHandle::close() +{ + if (h) + { + mysql_close(h); + h = 0; + } +} + + +void SessionHandle::query(const char* str) +{ + int res = mysql_real_query(h, str, static_cast(strlen(str))); + + if (res != 0) + { + std::string msg; + msg += "mysql_real_query('"; + msg += str; + msg += "') error"; + throw ConnectionException(msg, h); + } +} + + +}}} // Poco::Data::MySQL diff --git a/Data/MySQL/src/SessionImpl.cpp b/Data/MySQL/src/SessionImpl.cpp new file mode 100644 index 000000000..ece215895 --- /dev/null +++ b/Data/MySQL/src/SessionImpl.cpp @@ -0,0 +1,232 @@ +// +// MySQLException.cpp +// +// $Id: //poco/1.3/Data/MySQL/src/SessionImpl.cpp#1 $ +// +// Library: Data +// Package: MySQL +// Module: SessionImpl +// +// Copyright (c) 2008, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +#include "Poco/Data/MySQL/SessionImpl.h" +#include "Poco/Data/MySQL/MySQLStatementImpl.h" + + +namespace +{ + std::string copyStripped(std::string::const_iterator from, std::string::const_iterator to) + { + // skip leading spaces + while ((from != to) && isspace(*from)) from++; + // skip trailing spaces + while ((from != to) && isspace(*(to - 1))) to--; + + return std::string(from, to); + } +} + + +namespace Poco { +namespace Data { +namespace MySQL { + + +SessionImpl::SessionImpl(const std::string& connectionString) : _mysql(0), _connected(false), _inTransaction(0) +{ + addProperty("insertId", + &SessionImpl::setInsertId, + &SessionImpl::getInsertId); + + std::map options; + + // Default values + options["host"] = "localhost"; + options["port"] = "3306"; + options["user"] = ""; + options["password"] = ""; + options["db"] = ""; + options["compress"] = ""; + options["auto-reconnect"] = ""; + + // + // Parse string + // + + for (std::string::const_iterator start = connectionString.begin();;) + { + // find next ';' + std::string::const_iterator finish = std::find(start, connectionString.end(), ';'); + + // find '=' + std::string::const_iterator middle = std::find(start, finish, '='); + + if (middle == finish) + { + throw MySQLException("create session: bad connection string format, can not find '='"); + } + + // Parse name and value, skip all spaces + options[copyStripped(start, middle)] = copyStripped(middle + 1, finish); + + if (finish == connectionString.end()) + { + // end of parse + break; + } + + // move start position after ';' + start = finish + 1; + } + + // + // Checking + // + + if (options["user"] == "") + { + throw MySQLException("create session: specify user name"); + } + + if (options["db"] == "") + { + throw MySQLException("create session: specify database"); + } + + if (atoi(options["port"].c_str()) == 0) + { + throw MySQLException("create session: specify correct port (numeric in decimal notation)"); + } + + // + // Options + // + + if (options["compress"] == "true") + { + _mysql.options(MYSQL_OPT_COMPRESS); + } + else if (options["compress"] == "false") + { + // do nothing + } + else if (options["compress"] != "") + { + throw MySQLException("create session: specify correct compress option (true or false) or skip it"); + } + + if (options["auto-reconnect"] == "true") + { + _mysql.options(MYSQL_OPT_RECONNECT, true); + } + else if (options["auto-reconnect"] == "false") + { + _mysql.options(MYSQL_OPT_RECONNECT, false); + } + else if (options["auto-reconnect"] != "") + { + throw MySQLException("create session: specify correct auto-reconnect option (true or false) or skip it"); + } + + // + // Real connect + // + + _mysql.connect( + options["host"].c_str(), + options["user"].c_str(), + options["password"].c_str(), + options["db"].c_str(), + atoi(options["port"].c_str())); + + _connected = true; +} + + +SessionImpl::~SessionImpl() +{ + close(); +} + + +Poco::Data::StatementImpl* SessionImpl::createStatementImpl() +{ + return new MySQLStatementImpl(_mysql); +} + + +void SessionImpl::begin() +{ + _mysql.query("START TRANSACTION"); + _inTransaction++; +} + + +void SessionImpl::commit() +{ + _mysql.query("COMMIT"); + _inTransaction--; + + // ? + // mysql_commit(fMysql); +} + + +void SessionImpl::rollback() +{ + _mysql.query("ROLLBACK"); + _inTransaction--; + + // ? + // mysql_commit(fMysql); +} + + +void SessionImpl::close() +{ + if (_connected) + { + _mysql.close(); + _connected = false; + } +} + + +bool SessionImpl::isConnected() +{ + return _connected; +} + + +bool SessionImpl::isTransaction() +{ + return (_inTransaction > 0); +} + + +}}} diff --git a/Data/MySQL/src/StatementExecutor.cpp b/Data/MySQL/src/StatementExecutor.cpp new file mode 100644 index 000000000..9a13b2887 --- /dev/null +++ b/Data/MySQL/src/StatementExecutor.cpp @@ -0,0 +1,195 @@ +// +// StatementExecutor.cpp +// +// $Id: //poco/1.3/Data/MySQL/src/StatementExecutor.cpp#1 $ +// +// Library: Data +// Package: MySQL +// Module: StatementExecutor +// +// Copyright (c) 2008, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +#include +#include "Poco/Data/MySQL/StatementExecutor.h" + + +namespace Poco { +namespace Data { +namespace MySQL { + + +StatementExecutor::StatementExecutor(MYSQL* mysql) +{ + h = mysql_stmt_init(mysql); + + if (!h) + { + throw StatementException("mysql_stmt_init error"); + } + + _state = STMT_INITED; +} + + +StatementExecutor::~StatementExecutor() +{ + mysql_stmt_close(h); +} + + +int StatementExecutor::state() const +{ + return _state; +} + + +void StatementExecutor::prepare(const std::string& query) +{ + if (_state >= STMT_COMPILED) + { + throw StatementException("Satement is already compiled"); + } + + // compile + int res = mysql_stmt_prepare(h, query.c_str(), static_cast(query.length())); + + if (res != 0) + { + throw StatementException("mysql_stmt_prepare error", h, query); + } + + _query = query; + _state = STMT_COMPILED; +} + + +void StatementExecutor::bindParams(MYSQL_BIND* params, size_t count) +{ + if (_state < STMT_COMPILED) + { + throw StatementException("Satement is not compiled yet"); + } + + if (count != mysql_stmt_param_count(h)) + { + throw StatementException("wrong bind parameters count", 0, _query); + } + + if (count == 0) + { + return; + } + + int res = mysql_stmt_bind_param(h, params); + + if (res != 0) + { + throw StatementException("mysql_stmt_bind_param() error ", h, _query); + } +} + + +void StatementExecutor::bindResult(MYSQL_BIND* result) +{ + if (_state < STMT_COMPILED) + { + throw StatementException("Satement is not compiled yet"); + } + + int res = mysql_stmt_bind_result(h, result); + + if (res != 0) + { + throw StatementException("mysql_stmt_bind_result error ", h, _query); + } +} + + +void StatementExecutor::execute() +{ + if (_state < STMT_COMPILED) + { + throw StatementException("Satement is not compiled yet"); + } + + int res = mysql_stmt_execute(h); + + if (res != 0) + { + throw StatementException("mysql_stmt_execute error", h, _query); + } + + _state = STMT_EXECUTED; +} + + +bool StatementExecutor::fetch() +{ + if (_state < STMT_EXECUTED) + { + throw StatementException("Satement is not executed yet"); + } + + int res = mysql_stmt_fetch(h); + + if ((res != 0) && (res != MYSQL_NO_DATA)) + { + throw StatementException("mysql_stmt_fetch error", h, _query); + } + + return (res == 0); +} + + +bool StatementExecutor::fetchColumn(size_t n, MYSQL_BIND *bind) +{ + if (_state < STMT_EXECUTED) + { + throw StatementException("Satement is not executed yet"); + } + + int res = mysql_stmt_fetch_column(h, bind, static_cast(n), 0); + + if ((res != 0) && (res != MYSQL_NO_DATA)) + { + std::string msg; + msg += "mysql_stmt_fetch_column("; + + char buff[30]; + sprintf(buff, "%d", n); + msg += buff; + + msg += ") error"; + throw StatementException(msg, h, _query); + } + + return (res == 0); +} + + +}}} diff --git a/Data/MySQL/testsuite/Makefile b/Data/MySQL/testsuite/Makefile new file mode 100644 index 000000000..e6e16465a --- /dev/null +++ b/Data/MySQL/testsuite/Makefile @@ -0,0 +1,21 @@ +# +# Makefile +# +# $Id: //poco/1.3/Data/MySQL/testsuite/Makefile#1 $ +# +# Makefile for Poco MySQL testsuite +# + +include $(POCO_BASE)/build/rules/global + +INCLUDE += -I./../include -I/usr/local/include/mysql +SYSLIBS += -L/usr/local/lib/mysql -lmysqlclient -lz + +objects = MySQLTestSuite Driver \ + MySQLTest SQLExecutor + +target = testrunner +target_version = 1 +target_libs = PocoMySQL PocoData PocoFoundation CppUnit + +include $(POCO_BASE)/build/rules/exec diff --git a/Data/MySQL/testsuite/TestSuite_VS80.vcproj b/Data/MySQL/testsuite/TestSuite_VS80.vcproj new file mode 100644 index 000000000..bd99269b6 --- /dev/null +++ b/Data/MySQL/testsuite/TestSuite_VS80.vcproj @@ -0,0 +1,259 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Data/MySQL/testsuite/src/Driver.cpp b/Data/MySQL/testsuite/src/Driver.cpp new file mode 100644 index 000000000..c96881a73 --- /dev/null +++ b/Data/MySQL/testsuite/src/Driver.cpp @@ -0,0 +1,39 @@ +// +// Driver.cpp +// +// $Id: //poco/1.3/Data/ODBC/testsuite/src/Driver.cpp#2 $ +// +// Console-based test driver for Poco SQLite. +// +// Copyright (c) 2006, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +#include "CppUnit/TestRunner.h" +#include "MySQLTestSuite.h" + + +CppUnitMain(MySQLTestSuite) diff --git a/Data/MySQL/testsuite/src/MySQLTest.cpp b/Data/MySQL/testsuite/src/MySQLTest.cpp new file mode 100644 index 000000000..b7a08b7d0 --- /dev/null +++ b/Data/MySQL/testsuite/src/MySQLTest.cpp @@ -0,0 +1,627 @@ +// +// MySQLTest.cpp +// +// $Id: //poco/1.3/Data/MySQL/testsuite/src/MySQLTest.cpp#4 $ +// +// Copyright (c) 2008, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +#include "MySQLTest.h" +#include "CppUnit/TestCaller.h" +#include "CppUnit/TestSuite.h" +#include "Poco/String.h" +#include "Poco/Format.h" +#include "Poco/Exception.h" +#include "Poco/Data/Common.h" +#include "Poco/Data/BLOB.h" +#include "Poco/Data/StatementImpl.h" +#include "Poco/Data/MySQL/Connector.h" +#include "Poco/Data/MySQL/MySQLException.h" +#include + +using namespace Poco::Data; +using Poco::Data::MySQL::ConnectionException; +using Poco::Data::MySQL::StatementException; +using Poco::format; +using Poco::NotFoundException; + +Poco::SharedPtr MySQLTest::_pSession = 0; +Poco::SharedPtr MySQLTest::_pExecutor = 0; + +// Parameters for barebone-test +#define MYSQL_USER "root" +#define MYSQL_PWD "" +#define MYSQL_HOST "localhost" +#define MYSQL_PORT 3306 +#define MYSQL_DB "test" + +// Connection string to POCO +std::string MySQLTest::_dbConnString = "user=root;password=;db=test;compress=true;auto-reconnect=true"; + + +MySQLTest::MySQLTest(const std::string& name): + CppUnit::TestCase(name) +{ + static bool beenHere = false; + MySQL::Connector::registerConnector(); + + if (!beenHere) + { + try + { + _pSession = new Session(SessionFactory::instance().create(MySQL::Connector::KEY, _dbConnString)); + }catch (ConnectionException& ex) + { + std::cout << "!!! WARNING: Connection failed. MySQL tests will fail !!!" << std::endl; + std::cout << ex.displayText() << std::endl; + } + + if (_pSession && _pSession->isConnected()) + std::cout << "*** Connected to " << '(' << _dbConnString << ')' << std::endl; + if (!_pExecutor) _pExecutor = new SQLExecutor("MySQL SQL Executor", _pSession); + } + + beenHere = true; +} + + +MySQLTest::~MySQLTest() +{ + MySQL::Connector::unregisterConnector(); +} + + +void MySQLTest::testBareboneMySQL() +{ + if (!_pSession) fail ("Test not available."); + + std::string tableCreateString = "CREATE TABLE Test " + "(First VARCHAR(30)," + "Second VARCHAR(30)," + "Third VARBINARY(30)," + "Fourth INTEGER," + "Fifth FLOAT)"; + + _pExecutor->bareboneMySQLTest(MYSQL_HOST, MYSQL_USER, MYSQL_PWD, MYSQL_DB, MYSQL_PORT, tableCreateString.c_str()); +} + + +void MySQLTest::testSimpleAccess() +{ + if (!_pSession) fail ("Test not available."); + + recreatePersonTable(); + _pExecutor->simpleAccess(); +} + + +void MySQLTest::testComplexType() +{ + if (!_pSession) fail ("Test not available."); + + recreatePersonTable(); + _pExecutor->complexType(); +} + + +void MySQLTest::testSimpleAccessVector() +{ + if (!_pSession) fail ("Test not available."); + + recreatePersonTable(); + _pExecutor->simpleAccessVector(); +} + + +void MySQLTest::testComplexTypeVector() +{ + if (!_pSession) fail ("Test not available."); + + recreatePersonTable(); + _pExecutor->complexTypeVector(); +} + + +void MySQLTest::testInsertVector() +{ + if (!_pSession) fail ("Test not available."); + + recreateStringsTable(); + _pExecutor->insertVector(); +} + + +void MySQLTest::testInsertEmptyVector() +{ + if (!_pSession) fail ("Test not available."); + + recreateStringsTable(); + _pExecutor->insertEmptyVector(); +} + + +void MySQLTest::testInsertSingleBulk() +{ + if (!_pSession) fail ("Test not available."); + + recreateIntsTable(); + _pExecutor->insertSingleBulk(); +} + + +void MySQLTest::testInsertSingleBulkVec() +{ + if (!_pSession) fail ("Test not available."); + + recreateIntsTable(); + _pExecutor->insertSingleBulkVec(); +} + + +void MySQLTest::testLimit() +{ + if (!_pSession) fail ("Test not available."); + + recreateIntsTable(); + _pExecutor->limits(); +} + + +void MySQLTest::testLimitZero() +{ + if (!_pSession) fail ("Test not available."); + + recreateIntsTable(); + _pExecutor->limitZero(); +} + + +void MySQLTest::testLimitOnce() +{ + if (!_pSession) fail ("Test not available."); + + recreateIntsTable(); + _pExecutor->limitOnce(); + +} + + +void MySQLTest::testLimitPrepare() +{ + if (!_pSession) fail ("Test not available."); + + recreateIntsTable(); + _pExecutor->limitPrepare(); +} + + + +void MySQLTest::testPrepare() +{ + if (!_pSession) fail ("Test not available."); + + recreateIntsTable(); + _pExecutor->prepare(); +} + + +void MySQLTest::testSetSimple() +{ + if (!_pSession) fail ("Test not available."); + + recreatePersonTable(); + _pExecutor->setSimple(); +} + + +void MySQLTest::testSetComplex() +{ + if (!_pSession) fail ("Test not available."); + + recreatePersonTable(); + _pExecutor->setComplex(); +} + + +void MySQLTest::testSetComplexUnique() +{ + if (!_pSession) fail ("Test not available."); + + recreatePersonTable(); + _pExecutor->setComplexUnique(); +} + +void MySQLTest::testMultiSetSimple() +{ + if (!_pSession) fail ("Test not available."); + + recreatePersonTable(); + _pExecutor->multiSetSimple(); +} + + +void MySQLTest::testMultiSetComplex() +{ + if (!_pSession) fail ("Test not available."); + + recreatePersonTable(); + _pExecutor->multiSetComplex(); +} + + +void MySQLTest::testMapComplex() +{ + if (!_pSession) fail ("Test not available."); + + recreatePersonTable(); + _pExecutor->mapComplex(); +} + + +void MySQLTest::testMapComplexUnique() +{ + if (!_pSession) fail ("Test not available."); + + recreatePersonTable(); + _pExecutor->mapComplexUnique(); +} + + +void MySQLTest::testMultiMapComplex() +{ + if (!_pSession) fail ("Test not available."); + + recreatePersonTable(); + _pExecutor->multiMapComplex(); +} + + +void MySQLTest::testSelectIntoSingle() +{ + if (!_pSession) fail ("Test not available."); + + recreatePersonTable(); + _pExecutor->selectIntoSingle(); +} + + +void MySQLTest::testSelectIntoSingleStep() +{ + if (!_pSession) fail ("Test not available."); + + recreatePersonTable(); + _pExecutor->selectIntoSingleStep(); +} + + +void MySQLTest::testSelectIntoSingleFail() +{ + if (!_pSession) fail ("Test not available."); + + recreatePersonTable(); + _pExecutor->selectIntoSingleFail(); +} + + +void MySQLTest::testLowerLimitOk() +{ + if (!_pSession) fail ("Test not available."); + + recreatePersonTable(); + _pExecutor->lowerLimitOk(); +} + + +void MySQLTest::testSingleSelect() +{ + if (!_pSession) fail ("Test not available."); + + recreatePersonTable(); + _pExecutor->singleSelect(); +} + + +void MySQLTest::testLowerLimitFail() +{ + if (!_pSession) fail ("Test not available."); + + recreatePersonTable(); + _pExecutor->lowerLimitFail(); +} + + +void MySQLTest::testCombinedLimits() +{ + if (!_pSession) fail ("Test not available."); + + recreatePersonTable(); + _pExecutor->combinedLimits(); +} + + + +void MySQLTest::testRange() +{ + if (!_pSession) fail ("Test not available."); + + recreatePersonTable(); + _pExecutor->ranges(); +} + + +void MySQLTest::testCombinedIllegalLimits() +{ + if (!_pSession) fail ("Test not available."); + + recreatePersonTable(); + _pExecutor->combinedIllegalLimits(); +} + + + +void MySQLTest::testIllegalRange() +{ + if (!_pSession) fail ("Test not available."); + + recreatePersonTable(); + _pExecutor->illegalRange(); +} + + +void MySQLTest::testEmptyDB() +{ + if (!_pSession) fail ("Test not available."); + + recreatePersonTable(); + _pExecutor->emptyDB(); +} + + +void MySQLTest::testBLOB() +{ + if (!_pSession) fail ("Test not available."); + + const std::size_t maxFldSize = 65534; + _pSession->setProperty("maxFieldSize", Poco::Any(maxFldSize-1)); + recreatePersonBLOBTable(); + + try + { + _pExecutor->blob(maxFldSize); + fail ("must fail"); + } + catch (DataException&) + { + _pSession->setProperty("maxFieldSize", Poco::Any(maxFldSize)); + } + + recreatePersonBLOBTable(); + _pExecutor->blob(maxFldSize); + + recreatePersonBLOBTable(); + + try + { + _pExecutor->blob(maxFldSize+1); + fail ("must fail"); + } + catch (DataException&) { } +} + + +void MySQLTest::testBLOBStmt() +{ + if (!_pSession) fail ("Test not available."); + + recreatePersonBLOBTable(); + _pExecutor->blobStmt(); +} + + +void MySQLTest::testFloat() +{ + if (!_pSession) fail ("Test not available."); + + recreateFloatsTable(); + _pExecutor->floats(); +} + + +void MySQLTest::testDouble() +{ + if (!_pSession) fail ("Test not available."); + + recreateFloatsTable(); + _pExecutor->doubles(); +} + + +void MySQLTest::testTuple() +{ + if (!_pSession) fail ("Test not available."); + + recreateTuplesTable(); + _pExecutor->tuples(); +} + + +void MySQLTest::testTupleVector() +{ + if (!_pSession) fail ("Test not available."); + + recreateTuplesTable(); + _pExecutor->tupleVector(); +} + + +void MySQLTest::testInternalExtraction() +{ + if (!_pSession) fail ("Test not available."); + + recreateVectorsTable(); + _pExecutor->internalExtraction(); +} + + +void MySQLTest::dropTable(const std::string& tableName) +{ + try + { + *_pSession << format("DROP TABLE %s", tableName), now; + } + catch (StatementException& ) + { + //throw; + } +} + + +void MySQLTest::recreatePersonTable() +{ + dropTable("Person"); + try { *_pSession << "CREATE TABLE Person (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), Age INTEGER)", now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail ("recreatePersonTable()"); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail ("recreatePersonTable()"); } +} + + +void MySQLTest::recreatePersonBLOBTable() +{ + dropTable("Person"); + try { *_pSession << "CREATE TABLE Person (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), Image BLOB)", now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail ("recreatePersonBLOBTable()"); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail ("recreatePersonBLOBTable()"); } +} + + +void MySQLTest::recreateIntsTable() +{ + dropTable("Strings"); + try { *_pSession << "CREATE TABLE Strings (str INTEGER)", now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail ("recreateIntsTable()"); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail ("recreateIntsTable()"); } +} + + +void MySQLTest::recreateStringsTable() +{ + dropTable("Strings"); + try { *_pSession << "CREATE TABLE Strings (str VARCHAR(30))", now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail ("recreateStringsTable()"); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail ("recreateStringsTable()"); } +} + + +void MySQLTest::recreateFloatsTable() +{ + dropTable("Strings"); + try { *_pSession << "CREATE TABLE Strings (str FLOAT)", now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail ("recreateFloatsTable()"); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail ("recreateFloatsTable()"); } +} + + +void MySQLTest::recreateTuplesTable() +{ + dropTable("Tuples"); + try { *_pSession << "CREATE TABLE Tuples " + "(i0 INTEGER, i1 INTEGER, i2 INTEGER, i3 INTEGER, i4 INTEGER, i5 INTEGER, i6 INTEGER, " + "i7 INTEGER, i8 INTEGER, i9 INTEGER, i10 INTEGER, i11 INTEGER, i12 INTEGER, i13 INTEGER," + "i14 INTEGER, i15 INTEGER, i16 INTEGER, i17 INTEGER, i18 INTEGER, i19 INTEGER)", now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail ("recreateTuplesTable()"); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail ("recreateTuplesTable()"); } +} + + +void MySQLTest::recreateVectorsTable() +{ + dropTable("Vectors"); + try { *_pSession << "CREATE TABLE Vectors (i0 INTEGER, flt0 FLOAT, str0 VARCHAR(30))", now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail ("recreateVectorsTable()"); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail ("recreateVectorsTable()"); } +} + + +void MySQLTest::setUp() +{ +} + + +void MySQLTest::tearDown() +{ + dropTable("Person"); + dropTable("Strings"); +} + + +CppUnit::Test* MySQLTest::suite() +{ + CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("MySQLTest"); + + CppUnit_addTest(pSuite, MySQLTest, testBareboneMySQL); + CppUnit_addTest(pSuite, MySQLTest, testSimpleAccess); + CppUnit_addTest(pSuite, MySQLTest, testComplexType); + CppUnit_addTest(pSuite, MySQLTest, testSimpleAccessVector); + CppUnit_addTest(pSuite, MySQLTest, testComplexTypeVector); + CppUnit_addTest(pSuite, MySQLTest, testInsertVector); + CppUnit_addTest(pSuite, MySQLTest, testInsertEmptyVector); + CppUnit_addTest(pSuite, MySQLTest, testInsertSingleBulk); + CppUnit_addTest(pSuite, MySQLTest, testInsertSingleBulkVec); + CppUnit_addTest(pSuite, MySQLTest, testLimit); + CppUnit_addTest(pSuite, MySQLTest, testLimitOnce); + CppUnit_addTest(pSuite, MySQLTest, testLimitPrepare); + CppUnit_addTest(pSuite, MySQLTest, testLimitZero); + CppUnit_addTest(pSuite, MySQLTest, testPrepare); + CppUnit_addTest(pSuite, MySQLTest, testSetSimple); + CppUnit_addTest(pSuite, MySQLTest, testSetComplex); + CppUnit_addTest(pSuite, MySQLTest, testSetComplexUnique); + CppUnit_addTest(pSuite, MySQLTest, testMultiSetSimple); + CppUnit_addTest(pSuite, MySQLTest, testMultiSetComplex); + CppUnit_addTest(pSuite, MySQLTest, testMapComplex); + CppUnit_addTest(pSuite, MySQLTest, testMapComplexUnique); + CppUnit_addTest(pSuite, MySQLTest, testMultiMapComplex); + CppUnit_addTest(pSuite, MySQLTest, testSelectIntoSingle); + CppUnit_addTest(pSuite, MySQLTest, testSelectIntoSingleStep); + CppUnit_addTest(pSuite, MySQLTest, testSelectIntoSingleFail); + CppUnit_addTest(pSuite, MySQLTest, testLowerLimitOk); + CppUnit_addTest(pSuite, MySQLTest, testLowerLimitFail); + CppUnit_addTest(pSuite, MySQLTest, testCombinedLimits); + CppUnit_addTest(pSuite, MySQLTest, testCombinedIllegalLimits); + CppUnit_addTest(pSuite, MySQLTest, testRange); + CppUnit_addTest(pSuite, MySQLTest, testIllegalRange); + CppUnit_addTest(pSuite, MySQLTest, testSingleSelect); + CppUnit_addTest(pSuite, MySQLTest, testEmptyDB); + //CppUnit_addTest(pSuite, MySQLTest, testBLOB); + CppUnit_addTest(pSuite, MySQLTest, testBLOBStmt); + CppUnit_addTest(pSuite, MySQLTest, testFloat); + CppUnit_addTest(pSuite, MySQLTest, testDouble); + CppUnit_addTest(pSuite, MySQLTest, testTuple); + CppUnit_addTest(pSuite, MySQLTest, testTupleVector); + CppUnit_addTest(pSuite, MySQLTest, testInternalExtraction); + + return pSuite; +} diff --git a/Data/MySQL/testsuite/src/MySQLTest.h b/Data/MySQL/testsuite/src/MySQLTest.h new file mode 100644 index 000000000..bc0949b12 --- /dev/null +++ b/Data/MySQL/testsuite/src/MySQLTest.h @@ -0,0 +1,132 @@ +// +// ODBCMySQLTest.h +// +// $Id: //poco/1.3/Data/MySQL/testsuite/src/ODBCMySQLTest.h#2 $ +// +// Definition of the MySQLTest class. +// +// Copyright (c) 2008, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +#ifndef MySQLTest_INCLUDED +#define MySQLTest_INCLUDED + + +#include "Poco/Data/MySQL/MySQL.h" +#include "Poco/Data/Session.h" +#include "Poco/SharedPtr.h" +#include "CppUnit/TestCase.h" +#include "SQLExecutor.h" + + +class MySQLTest: public CppUnit::TestCase + /// MySQL test class + /// Tested: + /// + /// Driver | DB | OS + /// ----------------+---------------------------+------------------------------------------ + /// 03.51.12.00 | MySQL 5.0.27-community-nt | MS Windows XP Professional x64 v.2003/SP1 + /// + +{ +public: + MySQLTest(const std::string& name); + ~MySQLTest(); + + void testBareboneMySQL(); + + void testSimpleAccess(); + void testComplexType(); + void testSimpleAccessVector(); + void testComplexTypeVector(); + void testInsertVector(); + void testInsertEmptyVector(); + + void testInsertSingleBulk(); + void testInsertSingleBulkVec(); + + void testLimit(); + void testLimitOnce(); + void testLimitPrepare(); + void testLimitZero(); + void testPrepare(); + + void testSetSimple(); + void testSetComplex(); + void testSetComplexUnique(); + void testMultiSetSimple(); + void testMultiSetComplex(); + void testMapComplex(); + void testMapComplexUnique(); + void testMultiMapComplex(); + void testSelectIntoSingle(); + void testSelectIntoSingleStep(); + void testSelectIntoSingleFail(); + void testLowerLimitOk(); + void testLowerLimitFail(); + void testCombinedLimits(); + void testCombinedIllegalLimits(); + void testRange(); + void testIllegalRange(); + void testSingleSelect(); + void testEmptyDB(); + + void testBLOB(); + void testBLOBStmt(); + + void testFloat(); + void testDouble(); + + void testTuple(); + void testTupleVector(); + + void testInternalExtraction(); + + void setUp(); + void tearDown(); + + static CppUnit::Test* suite(); + +private: + + void dropTable(const std::string& tableName); + void recreatePersonTable(); + void recreatePersonBLOBTable(); + void recreateStringsTable(); + void recreateIntsTable(); + void recreateFloatsTable(); + void recreateTuplesTable(); + void recreateVectorsTable(); + + static std::string _dbConnString; + static Poco::SharedPtr _pSession; + static Poco::SharedPtr _pExecutor; + static const bool bindValues[8]; +}; + + +#endif // MySQLTest_INCLUDED diff --git a/Data/MySQL/testsuite/src/MySQLTestSuite.cpp b/Data/MySQL/testsuite/src/MySQLTestSuite.cpp new file mode 100644 index 000000000..f21dfd658 --- /dev/null +++ b/Data/MySQL/testsuite/src/MySQLTestSuite.cpp @@ -0,0 +1,41 @@ +// +// ODBCTestSuite.cpp +// +// $Id: //poco/1.3/Data/ODBC/testsuite/src/ODBCTestSuite.cpp#2 $ +// +// Copyright (c) 2008, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +#include "MySQLTestSuite.h" +#include "MySQLTest.h" + +CppUnit::Test* MySQLTestSuite::suite() +{ + CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("MySQLTestSuite"); + pSuite->addTest(MySQLTest::suite()); + return pSuite; +} diff --git a/Data/MySQL/testsuite/src/MySQLTestSuite.h b/Data/MySQL/testsuite/src/MySQLTestSuite.h new file mode 100644 index 000000000..2676006d9 --- /dev/null +++ b/Data/MySQL/testsuite/src/MySQLTestSuite.h @@ -0,0 +1,49 @@ +// +// ODBCTestSuite.h +// +// $Id: //poco/1.3/Data/ODBC/testsuite/src/ODBCTestSuite.h#2 $ +// +// Definition of the ODBCTestSuite class. +// +// Copyright (c) 2008, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +#ifndef MySQLTestSuite_INCLUDED +#define MySQLTestSuite_INCLUDED + + +#include "CppUnit/TestSuite.h" + + +class MySQLTestSuite +{ +public: + static CppUnit::Test* suite(); +}; + + +#endif // MySQLTestSuite_INCLUDED diff --git a/Data/MySQL/testsuite/src/SQLExecutor.cpp b/Data/MySQL/testsuite/src/SQLExecutor.cpp new file mode 100644 index 000000000..b3119e855 --- /dev/null +++ b/Data/MySQL/testsuite/src/SQLExecutor.cpp @@ -0,0 +1,1481 @@ +// +// SQLExecutor.cpp +// +// $Id: //poco/Main/DataConnectors/ODBC/testsuite/src/SQLExecutor.cpp#14 $ +// +// Copyright (c) 2008, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +#include "CppUnit/TestCase.h" +#include "SQLExecutor.h" +#include "Poco/String.h" +#include "Poco/Format.h" +#include "Poco/Tuple.h" +#include "Poco/Any.h" +#include "Poco/Exception.h" +#include "Poco/Data/Common.h" +#include "Poco/Data/BLOB.h" +#include "Poco/Data/StatementImpl.h" +#include "Poco/Data/RecordSet.h" +#include "Poco/Data/MySQL/Connector.h" +#include "Poco/Data/MySQL/MySQLException.h" + +#ifdef _WIN32 +#include +#endif + +#include +#include + + +using namespace Poco::Data; +using Poco::Data::MySQL::ConnectionException; +using Poco::Data::MySQL::StatementException; +using Poco::format; +using Poco::Tuple; +using Poco::Any; +using Poco::AnyCast; +using Poco::NotFoundException; +using Poco::InvalidAccessException; +using Poco::BadCastException; +using Poco::RangeException; + + +struct Person +{ + std::string lastName; + std::string firstName; + std::string address; + int age; + Person(){age = 0;} + Person(const std::string& ln, const std::string& fn, const std::string& adr, int a):lastName(ln), firstName(fn), address(adr), age(a) + { + } + bool operator==(const Person& other) const + { + return lastName == other.lastName && firstName == other.firstName && address == other.address && age == other.age; + } + + bool operator < (const Person& p) const + { + if (age < p.age) + return true; + if (lastName < p.lastName) + return true; + if (firstName < p.firstName) + return true; + return (address < p.address); + } + + const std::string& operator () () const + /// This method is required so we can extract data to a map! + { + // we choose the lastName as examplary key + return lastName; + } +}; + + +namespace Poco { +namespace Data { + + +template <> +class TypeHandler +{ +public: + static void bind(std::size_t pos, const Person& obj, AbstractBinder* pBinder) + { + // the table is defined as Person (LastName VARCHAR(30), FirstName VARCHAR, Address VARCHAR, Age INTEGER(3)) + poco_assert_dbg (pBinder != 0); + pBinder->bind(pos++, obj.lastName); + pBinder->bind(pos++, obj.firstName); + pBinder->bind(pos++, obj.address); + pBinder->bind(pos++, obj.age); + } + + static void prepare(std::size_t pos, const Person& obj, AbstractPreparation* pPrepare) + { + // the table is defined as Person (LastName VARCHAR(30), FirstName VARCHAR, Address VARCHAR, Age INTEGER(3)) + poco_assert_dbg (pPrepare != 0); + pPrepare->prepare(pos++, obj.lastName); + pPrepare->prepare(pos++, obj.firstName); + pPrepare->prepare(pos++, obj.address); + pPrepare->prepare(pos++, obj.age); + } + + static std::size_t size() + { + return 4; + } + + static void extract(std::size_t pos, Person& obj, const Person& defVal, AbstractExtractor* pExt) + { + poco_assert_dbg (pExt != 0); + if (!pExt->extract(pos++, obj.lastName)) + obj.lastName = defVal.lastName; + if (!pExt->extract(pos++, obj.firstName)) + obj.firstName = defVal.firstName; + if (!pExt->extract(pos++, obj.address)) + obj.address = defVal.address; + if (!pExt->extract(pos++, obj.age)) + obj.age = defVal.age; + } + +private: + TypeHandler(); + ~TypeHandler(); + TypeHandler(const TypeHandler&); + TypeHandler& operator=(const TypeHandler&); +}; + + +} } // namespace Poco::Data + + +SQLExecutor::SQLExecutor(const std::string& name, Poco::Data::Session* pSession): + CppUnit::TestCase(name), + _pSession(pSession) +{ +} + + +SQLExecutor::~SQLExecutor() +{ +} + + +void SQLExecutor::bareboneMySQLTest(const char* host, const char* user, const char* pwd, const char* db, int port, const char* tableCreateString) +{ + int rc; + MYSQL* hsession = mysql_init(0); + assert (hsession != 0); + + MYSQL* tmp = mysql_real_connect(hsession, host, user, pwd, db, port, 0, 0); + assert(tmp == hsession); + + MYSQL_STMT* hstmt = mysql_stmt_init(hsession); + assert(hstmt != 0); + + std::string sql = "DROP TABLE Test"; + mysql_real_query(hsession, sql.c_str(), static_cast(sql.length())); + + sql = tableCreateString; + rc = mysql_stmt_prepare(hstmt, sql.c_str(), static_cast(sql.length())); + assert(rc == 0); + + rc = mysql_stmt_execute(hstmt); + assert(rc == 0); + + sql = "INSERT INTO Test VALUES (?,?,?,?,?)"; + rc = mysql_stmt_prepare(hstmt, sql.c_str(), static_cast(sql.length())); + assert(rc == 0); + + std::string str[3] = { "111", "222", "333" }; + int fourth = 4; + float fifth = 1.5; + + MYSQL_BIND bind_param[5] = {{0}}; + + bind_param[0].buffer = const_cast(str[0].c_str()); + bind_param[0].buffer_length = static_cast(str[0].length()); + bind_param[0].buffer_type = MYSQL_TYPE_STRING; + + bind_param[1].buffer = const_cast(str[1].c_str()); + bind_param[1].buffer_length = static_cast(str[1].length()); + bind_param[1].buffer_type = MYSQL_TYPE_STRING; + + bind_param[2].buffer = const_cast(str[2].c_str()); + bind_param[2].buffer_length = static_cast(str[2].length()); + bind_param[2].buffer_type = MYSQL_TYPE_STRING; + + bind_param[3].buffer = &fourth; + bind_param[3].buffer_type = MYSQL_TYPE_LONG; + + bind_param[4].buffer = &fifth; + bind_param[4].buffer_type = MYSQL_TYPE_FLOAT; + + rc = mysql_stmt_bind_param(hstmt, bind_param); + assert (rc == 0); + + rc = mysql_stmt_execute(hstmt); + assert (rc == 0); + + sql = "SELECT * FROM Test"; + rc = mysql_stmt_prepare(hstmt, sql.c_str(), static_cast(sql.length())); + assert (rc == 0); + + char chr[3][5] = {{ 0 }}; + unsigned long lengths[5] = { 0 }; + fourth = 0; + fifth = 0.0f; + + MYSQL_BIND bind_result[5] = {{0}}; + + bind_result[0].buffer = chr[0]; + bind_result[0].buffer_length = sizeof(chr[0]); + bind_result[0].buffer_type = MYSQL_TYPE_STRING; + bind_result[0].length = &lengths[0]; + + bind_result[1].buffer = chr[1]; + bind_result[1].buffer_length = sizeof(chr[1]); + bind_result[1].buffer_type = MYSQL_TYPE_STRING; + bind_result[1].length = &lengths[1]; + + bind_result[2].buffer = chr[2]; + bind_result[2].buffer_length = sizeof(chr[2]); + bind_result[2].buffer_type = MYSQL_TYPE_STRING; + bind_result[2].length = &lengths[2]; + + bind_result[3].buffer = &fourth; + bind_result[3].buffer_type = MYSQL_TYPE_LONG; + bind_result[3].length = &lengths[3]; + + bind_result[4].buffer = &fifth; + bind_result[4].buffer_type = MYSQL_TYPE_FLOAT; + bind_result[4].length = &lengths[4]; + + rc = mysql_stmt_bind_result(hstmt, bind_result); + assert (rc == 0); + + rc = mysql_stmt_execute(hstmt); + assert (rc == 0); + rc = mysql_stmt_fetch(hstmt); + assert (rc == 0); + + assert (0 == strncmp("111", chr[0], 3)); + assert (0 == strncmp("222", chr[1], 3)); + assert (0 == strncmp("333", chr[2], 3)); + assert (4 == fourth); + assert (1.5 == fifth); + + rc = mysql_stmt_close(hstmt); + assert(rc == 0); + + sql = "DROP TABLE Test"; + rc = mysql_real_query(hsession, sql.c_str(), static_cast(sql.length())); + assert(rc == 0); + + mysql_close(hsession); +} + + +void SQLExecutor::simpleAccess() +{ + std::string funct = "simpleAccess()"; + std::string lastName = "lastName"; + std::string firstName("firstName"); + std::string address("Address"); + int age = 133132; + int count = 0; + std::string result; + + count = 0; + try + { + Statement stmt(*_pSession); + stmt << "INSERT INTO Person VALUES (?,?,?,?)", use(lastName), use(firstName), use(address), use(age);//, now; + stmt.execute(); + } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + + try { *_pSession << "SELECT COUNT(*) FROM Person", into(count), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + + assert (count == 1); + + try { *_pSession << "SELECT LastName FROM Person", into(result), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (lastName == result); + + try { *_pSession << "SELECT Age FROM Person", into(count), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (count == age); +} + + +void SQLExecutor::complexType() +{ + std::string funct = "complexType()"; + Person p1("LN1", "FN1", "ADDR1", 1); + Person p2("LN2", "FN2", "ADDR2", 2); + + try { *_pSession << "INSERT INTO Person VALUES (?,?,?,?)", use(p1), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + + try { *_pSession << "INSERT INTO Person VALUES (?,?,?,?)", use(p2), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + + int count = 0; + try { *_pSession << "SELECT COUNT(*) FROM Person", into(count), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (count == 2); + + Person c1; + Person c2; + try { *_pSession << "SELECT * FROM Person WHERE LastName = 'LN1'", into(c1), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (c1 == p1); +} + + +void SQLExecutor::simpleAccessVector() +{ + std::string funct = "simpleAccessVector()"; + 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; + std::string result; + + try { *_pSession << "INSERT INTO Person VALUES (?,?,?,?)", use(lastNames), use(firstNames), use(addresses), use(ages), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + + try { *_pSession << "SELECT COUNT(*) FROM Person", into(count), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (count == 2); + + std::vector lastNamesR; + std::vector firstNamesR; + std::vector addressesR; + std::vector agesR; + try { *_pSession << "SELECT * FROM Person", into(lastNamesR), into(firstNamesR), into(addressesR), into(agesR), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (ages == agesR); + assert (lastNames == lastNamesR); + assert (firstNames == firstNamesR); + assert (addresses == addressesR); +} + + +void SQLExecutor::complexTypeVector() +{ + std::string funct = "complexTypeVector()"; + std::vector people; + people.push_back(Person("LN1", "FN1", "ADDR1", 1)); + people.push_back(Person("LN2", "FN2", "ADDR2", 2)); + + try { *_pSession << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + + int count = 0; + try { *_pSession << "SELECT COUNT(*) FROM Person", into(count), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (count == 2); + + std::vector result; + try { *_pSession << "SELECT * FROM Person", into(result), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (result == people); +} + + +void SQLExecutor::insertVector() +{ + std::string funct = "insertVector()"; + std::vector str; + str.push_back("s1"); + str.push_back("s2"); + str.push_back("s3"); + str.push_back("s3"); + int count = 100; + + { + Statement stmt((*_pSession << "INSERT INTO Strings VALUES (?)", use(str))); + try { *_pSession << "SELECT COUNT(*) FROM Strings", into(count), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (count == 0); + + try { stmt.execute(); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + + try { *_pSession << "SELECT COUNT(*) FROM Strings", into(count), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (count == 4); + } + count = 0; + try { *_pSession << "SELECT COUNT(*) FROM Strings", into(count), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (count == 4); +} + + +void SQLExecutor::insertEmptyVector() +{ + std::string funct = "insertEmptyVector()"; + std::vector str; + + try + { + *_pSession << "INSERT INTO Strings VALUES (?)", use(str), now; + fail("empty collections should not work"); + } + catch (Poco::Exception&) + { + } +} + + +void SQLExecutor::insertSingleBulk() +{ + std::string funct = "insertSingleBulk()"; + int x = 0; + Statement stmt((*_pSession << "INSERT INTO Strings VALUES (?)", use(x))); + + for (x = 0; x < 100; ++x) + { + int i = stmt.execute(); + assert (i == 0); + } + + int count = 0; + try { *_pSession << "SELECT COUNT(*) FROM Strings", into(count), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (count == 100); + + try { *_pSession << "SELECT SUM(str) FROM Strings", into(count), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (count == ((0+99)*100/2)); +} + + +void SQLExecutor::floats() +{ + std::string funct = "floats()"; + float data = 1.5f; + float ret = 0.0f; + + try { *_pSession << "INSERT INTO Strings VALUES (?)", use(data), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + + int count = 0; + try { *_pSession << "SELECT COUNT(*) FROM Strings", into(count), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (count == 1); + + try { *_pSession << "SELECT str FROM Strings", into(ret), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (ret == data); +} + + +void SQLExecutor::doubles() +{ + std::string funct = "floats()"; + double data = 1.5; + double ret = 0.0; + + try { *_pSession << "INSERT INTO Strings VALUES (?)", use(data), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + + int count = 0; + try { *_pSession << "SELECT COUNT(*) FROM Strings", into(count), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (count == 1); + + try { *_pSession << "SELECT str FROM Strings", into(ret), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (ret == data); +} + + +void SQLExecutor::insertSingleBulkVec() +{ + std::string funct = "insertSingleBulkVec()"; + std::vector data; + + for (int x = 0; x < 100; ++x) + data.push_back(x); + + Statement stmt((*_pSession << "INSERT INTO Strings VALUES (?)", use(data))); + stmt.execute(); + + int count = 0; + try { *_pSession << "SELECT COUNT(*) FROM Strings", into(count), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + + assert (count == 100); + try { *_pSession << "SELECT SUM(str) FROM Strings", into(count), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (count == ((0+99)*100/2)); +} + + +void SQLExecutor::limits() +{ + std::string funct = "limit()"; + std::vector data; + for (int x = 0; x < 100; ++x) + { + data.push_back(x); + } + + try { *_pSession << "INSERT INTO Strings VALUES (?)", use(data), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + + std::vector retData; + try { *_pSession << "SELECT * FROM Strings", into(retData), limit(50), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (retData.size() == 50); + for (int x = 0; x < 50; ++x) + { + assert(data[x] == retData[x]); + } +} + + +void SQLExecutor::limitZero() +{ + std::string funct = "limitZero()"; + std::vector data; + for (int x = 0; x < 100; ++x) + { + data.push_back(x); + } + + try { *_pSession << "INSERT INTO Strings VALUES (?)", use(data), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + + std::vector retData; + try { *_pSession << "SELECT * FROM Strings", into(retData), limit(0), now; }// stupid test, but at least we shouldn't crash + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (retData.size() == 0); +} + + +void SQLExecutor::limitOnce() +{ + std::string funct = "limitOnce()"; + std::vector data; + for (int x = 0; x < 101; ++x) + { + data.push_back(x); + } + + try { *_pSession << "INSERT INTO Strings VALUES (?)", use(data), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + + std::vector retData; + Statement stmt = (*_pSession << "SELECT * FROM Strings", into(retData), limit(50), now); + assert (!stmt.done()); + assert (retData.size() == 50); + stmt.execute(); + assert (!stmt.done()); + assert (retData.size() == 100); + stmt.execute(); + assert (stmt.done()); + assert (retData.size() == 101); + + for (int x = 0; x < 101; ++x) + { + assert(data[x] == retData[x]); + } +} + + +void SQLExecutor::limitPrepare() +{ + std::string funct = "limitPrepare()"; + std::vector data; + for (int x = 0; x < 100; ++x) + { + data.push_back(x); + } + + try { *_pSession << "INSERT INTO Strings VALUES (?)", use(data), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + + std::vector retData; + Statement stmt = (*_pSession << "SELECT * FROM Strings", into(retData), limit(50)); + assert (retData.size() == 0); + assert (!stmt.done()); + + try { stmt.execute(); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (!stmt.done()); + assert (retData.size() == 50); + + try { stmt.execute(); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (stmt.done()); + assert (retData.size() == 100); + + try { stmt.execute(); }// will restart execution! + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (!stmt.done()); + assert (retData.size() == 150); + for (int x = 0; x < 150; ++x) + { + assert(data[x%100] == retData[x]); + } +} + + + +void SQLExecutor::prepare() +{ + std::string funct = "prepare()"; + std::vector data; + for (int x = 0; x < 100; x += 2) + { + data.push_back(x); + } + + { + Statement stmt((*_pSession << "INSERT INTO Strings VALUES (?)", use(data))); + } + // stmt should not have been executed when destroyed + int count = 100; + try { *_pSession << "SELECT COUNT(*) FROM Strings", into(count), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (count == 0); +} + + +void SQLExecutor::setSimple() +{ + std::string funct = "setSimple()"; + std::set lastNames; + std::set firstNames; + std::set addresses; + std::set ages; + std::string tableName("Person"); + lastNames.insert("LN1"); + lastNames.insert("LN2"); + firstNames.insert("FN1"); + firstNames.insert("FN2"); + addresses.insert("ADDR1"); + addresses.insert("ADDR2"); + ages.insert(1); + ages.insert(2); + int count = 0; + std::string result; + + try { *_pSession << "INSERT INTO Person VALUES (?,?,?,?)", use(lastNames), use(firstNames), use(addresses), use(ages), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + try { *_pSession << "SELECT COUNT(*) FROM Person", into(count), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (count == 2); + + std::set lastNamesR; + std::set firstNamesR; + std::set addressesR; + std::set agesR; + try { *_pSession << "SELECT * FROM Person", into(lastNamesR), into(firstNamesR), into(addressesR), into(agesR), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (ages == agesR); + assert (lastNames == lastNamesR); + assert (firstNames == firstNamesR); + assert (addresses == addressesR); +} + + +void SQLExecutor::setComplex() +{ + std::string funct = "setComplex()"; + std::set people; + people.insert(Person("LN1", "FN1", "ADDR1", 1)); + people.insert(Person("LN2", "FN2", "ADDR2", 2)); + + try { *_pSession << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + int count = 0; + try { *_pSession << "SELECT COUNT(*) FROM Person", into(count), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (count == 2); + + std::set result; + try { *_pSession << "SELECT * FROM Person", into(result), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (result == people); +} + + +void SQLExecutor::setComplexUnique() +{ + std::string funct = "setComplexUnique()"; + std::vector people; + Person p1("LN1", "FN1", "ADDR1", 1); + people.push_back(p1); + people.push_back(p1); + people.push_back(p1); + people.push_back(p1); + Person p2("LN2", "FN2", "ADDR2", 2); + people.push_back(p2); + + try { *_pSession << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + int count = 0; + try { *_pSession << "SELECT COUNT(*) FROM Person", into(count), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (count == 5); + + std::set result; + try { *_pSession << "SELECT * FROM Person", into(result), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (result.size() == 2); + assert (*result.begin() == p1); + assert (*++result.begin() == p2); +} + +void SQLExecutor::multiSetSimple() +{ + std::string funct = "multiSetSimple()"; + std::multiset lastNames; + std::multiset firstNames; + std::multiset addresses; + std::multiset ages; + std::string tableName("Person"); + lastNames.insert("LN1"); + lastNames.insert("LN2"); + firstNames.insert("FN1"); + firstNames.insert("FN2"); + addresses.insert("ADDR1"); + addresses.insert("ADDR2"); + ages.insert(1); + ages.insert(2); + int count = 0; + std::string result; + + try { *_pSession << "INSERT INTO Person VALUES (?,?,?,?)", use(lastNames), use(firstNames), use(addresses), use(ages), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + try { *_pSession << "SELECT COUNT(*) FROM Person", into(count), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (count == 2); + + std::multiset lastNamesR; + std::multiset firstNamesR; + std::multiset addressesR; + std::multiset agesR; + try { *_pSession << "SELECT * FROM Person", into(lastNamesR), into(firstNamesR), into(addressesR), into(agesR), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (ages.size() == agesR.size()); + assert (lastNames.size() == lastNamesR.size()); + assert (firstNames.size() == firstNamesR.size()); + assert (addresses.size() == addressesR.size()); +} + + +void SQLExecutor::multiSetComplex() +{ + std::string funct = "multiSetComplex()"; + std::multiset people; + Person p1("LN1", "FN1", "ADDR1", 1); + people.insert(p1); + people.insert(p1); + people.insert(p1); + people.insert(p1); + Person p2("LN2", "FN2", "ADDR2", 2); + people.insert(p2); + + try { *_pSession << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + int count = 0; + try { *_pSession << "SELECT COUNT(*) FROM Person", into(count), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (count == 5); + + std::multiset result; + try { *_pSession << "SELECT * FROM Person", into(result), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (result.size() == people.size()); +} + + +void SQLExecutor::mapComplex() +{ + std::string funct = "mapComplex()"; + std::map people; + Person p1("LN1", "FN1", "ADDR1", 1); + Person p2("LN2", "FN2", "ADDR2", 2); + people.insert(std::make_pair("LN1", p1)); + people.insert(std::make_pair("LN2", p2)); + + try { *_pSession << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + int count = 0; + try { *_pSession << "SELECT COUNT(*) FROM Person", into(count), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (count == 2); + + std::map result; + try { *_pSession << "SELECT * FROM Person", into(result), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (result == people); +} + + +void SQLExecutor::mapComplexUnique() +{ + std::string funct = "mapComplexUnique()"; + std::multimap people; + Person p1("LN1", "FN1", "ADDR1", 1); + Person p2("LN2", "FN2", "ADDR2", 2); + people.insert(std::make_pair("LN1", p1)); + people.insert(std::make_pair("LN1", p1)); + people.insert(std::make_pair("LN1", p1)); + people.insert(std::make_pair("LN1", p1)); + people.insert(std::make_pair("LN2", p2)); + + try { *_pSession << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + int count = 0; + try { *_pSession << "SELECT COUNT(*) FROM Person", into(count), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (count == 5); + + std::map result; + try { *_pSession << "SELECT * FROM Person", into(result), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (result.size() == 2); +} + + +void SQLExecutor::multiMapComplex() +{ + std::string funct = "multiMapComplex()"; + std::multimap people; + Person p1("LN1", "FN1", "ADDR1", 1); + Person p2("LN2", "FN2", "ADDR2", 2); + people.insert(std::make_pair("LN1", p1)); + people.insert(std::make_pair("LN1", p1)); + people.insert(std::make_pair("LN1", p1)); + people.insert(std::make_pair("LN1", p1)); + people.insert(std::make_pair("LN2", p2)); + + try { *_pSession << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + int count = 0; + try { *_pSession << "SELECT COUNT(*) FROM Person", into(count), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (count == 5); + + std::multimap result; + try { *_pSession << "SELECT * FROM Person", into(result), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (result.size() == people.size()); +} + + +void SQLExecutor::selectIntoSingle() +{ + std::string funct = "selectIntoSingle()"; + std::multimap people; + Person p1("LN1", "FN1", "ADDR1", 1); + Person p2("LN2", "FN2", "ADDR2", 2); + people.insert(std::make_pair("LN1", p1)); + people.insert(std::make_pair("LN1", p2)); + + try { *_pSession << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + int count = 0; + try { *_pSession << "SELECT COUNT(*) FROM Person", into(count), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (count == 2); + Person result; + try { *_pSession << "SELECT * FROM Person", into(result), limit(1), now; }// will return 1 object into one single result + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (result == p1); +} + + +void SQLExecutor::selectIntoSingleStep() +{ + std::string funct = "selectIntoSingleStep()"; + std::multimap people; + Person p1("LN1", "FN1", "ADDR1", 1); + Person p2("LN2", "FN2", "ADDR2", 2); + people.insert(std::make_pair("LN1", p1)); + people.insert(std::make_pair("LN1", p2)); + + try { *_pSession << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + + int count = 0; + try { *_pSession << "SELECT COUNT(*) FROM Person", into(count), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (count == 2); + Person result; + Statement stmt = (*_pSession << "SELECT * FROM Person", into(result), limit(1)); + stmt.execute(); + assert (result == p1); + assert (!stmt.done()); + stmt.execute(); + assert (result == p2); + assert (stmt.done()); +} + + +void SQLExecutor::selectIntoSingleFail() +{ + std::string funct = "selectIntoSingleFail()"; + std::multimap people; + Person p1("LN1", "FN1", "ADDR1", 1); + Person p2("LN2", "FN2", "ADDR2", 2); + people.insert(std::make_pair("LN1", p1)); + people.insert(std::make_pair("LN1", p2)); + + try { *_pSession << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + int count = 0; + try { *_pSession << "SELECT COUNT(*) FROM Person", into(count), limit(2, true), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (count == 2); + Person result; + try + { + *_pSession << "SELECT * FROM Person", into(result), limit(1, true), now; // will fail now + fail("hardLimit is set: must fail"); + } + catch(Poco::Data::LimitException&) + { + } +} + + +void SQLExecutor::lowerLimitOk() +{ + std::string funct = "lowerLimitOk()"; + std::multimap people; + Person p1("LN1", "FN1", "ADDR1", 1); + Person p2("LN2", "FN2", "ADDR2", 2); + people.insert(std::make_pair("LN1", p1)); + people.insert(std::make_pair("LN1", p2)); + + try { *_pSession << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + + int count = 0; + try { *_pSession << "SELECT COUNT(*) FROM Person", into(count), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (count == 2); + Person result; + try + { + *_pSession << "SELECT * FROM Person", into(result), lowerLimit(2), now; // will return 2 objects into one single result but only room for one! + fail("Not enough space for results"); + } + catch(Poco::Exception&) + { + } +} + + +void SQLExecutor::singleSelect() +{ + std::string funct = "singleSelect()"; + std::multimap people; + Person p1("LN1", "FN1", "ADDR1", 1); + Person p2("LN2", "FN2", "ADDR2", 2); + people.insert(std::make_pair("LN1", p1)); + people.insert(std::make_pair("LN1", p2)); + + try { *_pSession << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + + int count = 0; + try { *_pSession << "SELECT COUNT(*) FROM Person", into(count), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (count == 2); + Person result; + Statement stmt = (*_pSession << "SELECT * FROM Person", into(result), limit(1)); + stmt.execute(); + assert (result == p1); + assert (!stmt.done()); + stmt.execute(); + assert (result == p2); + assert (stmt.done()); +} + + +void SQLExecutor::lowerLimitFail() +{ + std::string funct = "lowerLimitFail()"; + std::multimap people; + Person p1("LN1", "FN1", "ADDR1", 1); + Person p2("LN2", "FN2", "ADDR2", 2); + people.insert(std::make_pair("LN1", p1)); + people.insert(std::make_pair("LN1", p2)); + + try { *_pSession << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + int count = 0; + try { *_pSession << "SELECT COUNT(*) FROM Person", into(count), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (count == 2); + Person result; + try + { + *_pSession << "SELECT * FROM Person", into(result), lowerLimit(3), now; // will fail + fail("should fail. not enough data"); + } + catch(Poco::Exception&) + { + } +} + + +void SQLExecutor::combinedLimits() +{ + std::string funct = "combinedLimits()"; + std::multimap people; + Person p1("LN1", "FN1", "ADDR1", 1); + Person p2("LN2", "FN2", "ADDR2", 2); + people.insert(std::make_pair("LN1", p1)); + people.insert(std::make_pair("LN1", p2)); + + try { *_pSession << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + int count = 0; + try { *_pSession << "SELECT COUNT(*) FROM Person", into(count), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (count == 2); + std::vector result; + try { *_pSession << "SELECT * FROM Person", into(result), lowerLimit(2), upperLimit(2), now; }// will return 2 objects + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (result.size() == 2); + assert (result[0] == p1); + assert (result[1] == p2); +} + + + +void SQLExecutor::ranges() +{ + std::string funct = "range()"; + std::multimap people; + Person p1("LN1", "FN1", "ADDR1", 1); + Person p2("LN2", "FN2", "ADDR2", 2); + people.insert(std::make_pair("LN1", p1)); + people.insert(std::make_pair("LN1", p2)); + + try { *_pSession << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + int count = 0; + try { *_pSession << "SELECT COUNT(*) FROM Person", into(count), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (count == 2); + std::vector result; + try { *_pSession << "SELECT * FROM Person", into(result), range(2, 2), now; }// will return 2 objects + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (result.size() == 2); + assert (result[0] == p1); + assert (result[1] == p2); +} + + +void SQLExecutor::combinedIllegalLimits() +{ + std::string funct = "combinedIllegalLimits()"; + std::multimap people; + Person p1("LN1", "FN1", "ADDR1", 1); + Person p2("LN2", "FN2", "ADDR2", 2); + people.insert(std::make_pair("LN1", p1)); + people.insert(std::make_pair("LN1", p2)); + + try { *_pSession << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + int count = 0; + try { *_pSession << "SELECT COUNT(*) FROM Person", into(count), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (count == 2); + Person result; + try + { + *_pSession << "SELECT * FROM Person", into(result), lowerLimit(3), upperLimit(2), now; + fail("lower > upper is not allowed"); + } + catch(LimitException&) + { + } +} + + +void SQLExecutor::illegalRange() +{ + std::string funct = "illegalRange()"; + std::multimap people; + Person p1("LN1", "FN1", "ADDR1", 1); + Person p2("LN2", "FN2", "ADDR2", 2); + people.insert(std::make_pair("LN1", p1)); + people.insert(std::make_pair("LN1", p2)); + + try { *_pSession << "INSERT INTO Person VALUES (?,?,?,?)", use(people), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + int count = 0; + try { *_pSession << "SELECT COUNT(*) FROM Person", into(count), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (count == 2); + Person result; + try + { + *_pSession << "SELECT * FROM Person", into(result), range(3, 2), now; + fail("lower > upper is not allowed"); + } + catch(LimitException&) + { + } +} + + +void SQLExecutor::emptyDB() +{ + std::string funct = "emptyDB()"; + int count = 0; + try { *_pSession << "SELECT COUNT(*) FROM Person", into(count), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (count == 0); + + Person result; + Statement stmt = (*_pSession << "SELECT * FROM Person", into(result), limit(1)); + stmt.execute(); + assert (result.firstName.empty()); + assert (stmt.done()); +} + + +void SQLExecutor::blob(int bigSize) +{ + std::string funct = "blob()"; + std::string lastName("lastname"); + std::string firstName("firstname"); + std::string address("Address"); + + Poco::Data::BLOB img("0123456789", 10); + int count = 0; + try { *_pSession << "INSERT INTO Person VALUES (?,?,?,?)", use(lastName), use(firstName), use(address), use(img), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + try { *_pSession << "SELECT COUNT(*) FROM Person", into(count), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (count == 1); + + Poco::Data::BLOB res; + assert (res.size() == 0); + try { *_pSession << "SELECT Image FROM Person", into(res), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (res == img); + + Poco::Data::BLOB big; + std::vector v(bigSize, 'x'); + big.assignRaw(&v[0], v.size()); + + assert (big.size() == bigSize); + + try { *_pSession << "DELETE FROM Person", now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + + try { *_pSession << "INSERT INTO Person VALUES(?,?,?,?)", use(lastName), use(firstName), use(address), use(big), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + + try { *_pSession << "SELECT Image FROM Person", into(res), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (res == big); +} + +void SQLExecutor::blobStmt() +{ + std::string funct = "blobStmt()"; + std::string lastName("lastname"); + std::string firstName("firstname"); + std::string address("Address"); + Poco::Data::BLOB blob("0123456789", 10); + + int count = 0; + Statement ins = (*_pSession << "INSERT INTO Person VALUES (?,?,?,?)", use(lastName), use(firstName), use(address), use(blob)); + ins.execute(); + try { *_pSession << "SELECT COUNT(*) FROM Person", into(count), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (count == 1); + + Poco::Data::BLOB res; + poco_assert (res.size() == 0); + Statement stmt = (*_pSession << "SELECT Image FROM Person", into(res)); + try { stmt.execute(); } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + poco_assert (res == blob); +} + +void SQLExecutor::tuples() +{ + typedef Tuple TupleType; + std::string funct = "tuples()"; + TupleType t(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19); + + try { *_pSession << "INSERT INTO Tuples VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", use(t), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + + TupleType ret(-10,-11,-12,-13,-14,-15,-16,-17,-18,-19); + assert (ret != t); + try { *_pSession << "SELECT * FROM Tuples", into(ret), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (ret == t); +} + +void SQLExecutor::tupleVector() +{ + typedef Tuple TupleType; + std::string funct = "tupleVector()"; + TupleType t(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19); + Tuple + t10(10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29); + TupleType t100(100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119); + std::vector v; + v.push_back(t); + v.push_back(t10); + v.push_back(t100); + + try { *_pSession << "INSERT INTO Tuples VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", use(v), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + + int count = 0; + try { *_pSession << "SELECT COUNT(*) FROM Tuples", into(count), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (v.size() == count); + + std::vector > ret; + try { *_pSession << "SELECT * FROM Tuples", into(ret), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (ret == v); +} + + +void SQLExecutor::internalExtraction() +{ + std::string funct = "internalExtraction()"; + std::vector > v; + v.push_back(Tuple(1, 1.5f, "3")); + v.push_back(Tuple(2, 2.5f, "4")); + v.push_back(Tuple(3, 3.5f, "5")); + v.push_back(Tuple(4, 4.5f, "6")); + + try { *_pSession << "INSERT INTO Vectors VALUES (?,?,?)", use(v), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + + try + { + Statement stmt = (*_pSession << "SELECT * FROM Vectors", now); + RecordSet rset(stmt); + + assert (3 == rset.columnCount()); + assert (4 == rset.rowCount()); + + int curVal = 3; + do + { + assert (rset["str0"] == curVal); + ++curVal; + } while (rset.moveNext()); + + rset.moveFirst(); + assert (rset["str0"] == "3"); + rset.moveLast(); + assert (rset["str0"] == "6"); + + RecordSet rset2(rset); + assert (3 == rset2.columnCount()); + assert (4 == rset2.rowCount()); + + int i = rset.value(0,0); + assert (1 == i); + + std::string s = rset.value(0,0); + assert ("1" == s); + + int a = rset.value(0,2); + assert (3 == a); + + try + { + double d = rset.value(1,1); + assert (2.5 == d); + } + catch (BadCastException&) + { + float f = rset.value(1,1); + assert (2.5 == f); + } + + s = rset.value(2,2); + assert ("5" == s); + i = rset.value("str0", 2); + assert (5 == i); + + const Column& col = rset.column(0); + Column::Iterator it = col.begin(); + Column::Iterator end = col.end(); + for (int i = 1; it != end; ++it, ++i) + assert (*it == i); + + rset = (*_pSession << "SELECT COUNT(*) AS cnt FROM Vectors", now); + + //various results for COUNT(*) are received from different drivers + try + { + //this is what most drivers will return + int i = rset.value(0,0); + assert (4 == i); + } + catch(BadCastException&) + { + try + { + //this is for Oracle + double i = rset.value(0,0); + assert (4 == int(i)); + } + catch(BadCastException&) + { + //this is for PostgreSQL + Poco::Int64 big = rset.value(0,0); + assert (4 == big); + } + } + + s = rset.value("cnt", 0).convert(); + assert ("4" == s); + + try { const Column& col1 = rset.column(100); fail ("must fail"); } + catch (RangeException&) { } + + try { rset.value(0,0); fail ("must fail"); } + catch (BadCastException&) { } + + stmt = (*_pSession << "DELETE FROM Vectors", now); + rset = stmt; + + try { const Column& col1 = rset.column(0); fail ("must fail"); } + catch (RangeException&) { } + } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } +} diff --git a/Data/MySQL/testsuite/src/SQLExecutor.h b/Data/MySQL/testsuite/src/SQLExecutor.h new file mode 100644 index 000000000..8a20af20a --- /dev/null +++ b/Data/MySQL/testsuite/src/SQLExecutor.h @@ -0,0 +1,117 @@ +// +// SQLExecutor.h +// +// $Id: //poco/1.3/Data/MySQL/testsuite/src/SQLExecutor.h#2 $ +// +// Definition of the SQLExecutor class. +// +// Copyright (c) 2008, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +#ifndef SQLExecutor_INCLUDED +#define SQLExecutor_INCLUDED + + +#include "Poco/Data/MySQL/MySQL.h" +#include "Poco/Data/Session.h" + +class SQLExecutor: public CppUnit::TestCase +{ +public: + enum DataBinding + { + PB_IMMEDIATE, + PB_AT_EXEC + }; + + enum DataExtraction + { + DE_MANUAL, + DE_BOUND + }; + + SQLExecutor(const std::string& name, Poco::Data::Session* _pSession); + ~SQLExecutor(); + + void bareboneMySQLTest(const char* host, const char* user, const char* pwd, const char* db, int port, const char* tableCreateString); + /// This function uses "bare bone" MySQL API calls (i.e. calls are not + /// "wrapped" in PocoData framework structures). + /// The purpose of the function is to verify that driver behaves + /// correctly. If this test passes, subsequent tests failures are likely ours. + + void simpleAccess(); + void complexType(); + void simpleAccessVector(); + void complexTypeVector(); + void insertVector(); + void insertEmptyVector(); + + void insertSingleBulk(); + void insertSingleBulkVec(); + + void limits(); + void limitOnce(); + void limitPrepare(); + void limitZero(); + void prepare(); + + void setSimple(); + void setComplex(); + void setComplexUnique(); + void multiSetSimple(); + void multiSetComplex(); + void mapComplex(); + void mapComplexUnique(); + void multiMapComplex(); + void selectIntoSingle(); + void selectIntoSingleStep(); + void selectIntoSingleFail(); + void lowerLimitOk(); + void lowerLimitFail(); + void combinedLimits(); + void combinedIllegalLimits(); + void ranges(); + void illegalRange(); + void singleSelect(); + void emptyDB(); + + void blob(int bigSize = 1024); + void blobStmt(); + + void floats(); + void doubles(); + void tuples(); + void tupleVector(); + + void internalExtraction(); + +private: + Poco::Data::Session* _pSession; +}; + + +#endif // SQLExecutor_INCLUDED diff --git a/Data/MySQL/testsuite/src/WinDriver.cpp b/Data/MySQL/testsuite/src/WinDriver.cpp new file mode 100644 index 000000000..0512574af --- /dev/null +++ b/Data/MySQL/testsuite/src/WinDriver.cpp @@ -0,0 +1,50 @@ +// +// WinDriver.cpp +// +// $Id: //poco/1.3/Data/MySQL/testsuite/src/WinDriver.cpp#2 $ +// +// Windows test driver for Poco MySQL. +// +// Copyright (c) 2008, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +#include "WinTestRunner/WinTestRunner.h" +#include "MySQLTestSuite.h" + + +class TestDriver: public CppUnit::WinTestRunnerApp +{ + void TestMain() + { + CppUnit::WinTestRunner runner; + runner.addTest(MySQLTestSuite::suite()); + runner.run(); + } +}; + + +TestDriver theDriver; diff --git a/Foundation/include/Poco/DynamicAnyHolder.h b/Foundation/include/Poco/DynamicAnyHolder.h index 802a5f606..0b04eaf7e 100644 --- a/Foundation/include/Poco/DynamicAnyHolder.h +++ b/Foundation/include/Poco/DynamicAnyHolder.h @@ -106,8 +106,8 @@ protected: poco_static_assert (std::numeric_limits::is_signed); poco_static_assert (std::numeric_limits::is_signed); - checkUpperLimit(from, to); - checkLowerLimit(from, to); + checkUpperLimit(from); + checkLowerLimit(from); to = static_cast(from); } @@ -124,7 +124,7 @@ protected: poco_static_assert (!std::numeric_limits::is_signed); poco_static_assert (!std::numeric_limits::is_signed); - checkUpperLimit(from, to); + checkUpperLimit(from); to = static_cast(from); } @@ -142,7 +142,7 @@ protected: if (from < 0) throw RangeException("Value too small."); - checkUpperLimit(from, to); + checkUpperLimit(from); to = static_cast(from); } @@ -158,20 +158,20 @@ protected: poco_static_assert (!std::numeric_limits::is_signed); poco_static_assert (std::numeric_limits::is_signed); - checkUpperLimit(from, to); + checkUpperLimit(from); to = static_cast(from); } private: template - void checkUpperLimit(const F& from, T& to) const + void checkUpperLimit(const F& from) const { if (from > std::numeric_limits::max()) throw RangeException("Value too large."); } template - void checkLowerLimit(const F& from, T& to) const + void checkLowerLimit(const F& from) const { if (from < std::numeric_limits::min()) throw RangeException("Value too small.");