Skip to content
Browse files

MySQL DateTime support, samples Linux compile

  • Loading branch information...
1 parent 245dc64 commit 2a81e59e8c990c49d8f2fa092d8506645cb06ac9 @aleks-f aleks-f committed Dec 14, 2012
View
6 Data/MySQL/src/ResultMetadata.cpp
@@ -130,7 +130,11 @@ namespace
case MYSQL_TYPE_LONGLONG:
if (unsig) return Poco::Data::MetaColumn::FDT_UINT64;
return Poco::Data::MetaColumn::FDT_INT64;
-
+ case MYSQL_TYPE_DATE:
+ case MYSQL_TYPE_TIME:
+ case MYSQL_TYPE_DATETIME:
+ return Poco::Data::MetaColumn::FDT_TIMESTAMP;
+
case MYSQL_TYPE_STRING:
case MYSQL_TYPE_VAR_STRING:
return Poco::Data::MetaColumn::FDT_STRING;
View
246 Data/MySQL/src/ResultMetadata.cpp~
@@ -0,0 +1,246 @@
+//
+// MySQLException.cpp
+//
+// $Id: //poco/1.4/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"
+#include <cstring>
+
+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;
+ };
+
+ std::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_INT24:
+ 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_DATE:
+ case MYSQL_TYPE_TIME:
+ case MYSQL_TYPE_DATETIME:
+ return sizeof(MYSQL_TIME);
+
+ 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:
+ return field.length;
+
+ default:
+ 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_INT24:
+ 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;
+ default:
+ return Poco::Data::MetaColumn::FDT_UNKNOWN;
+ }
+ }
+} // namespace
+
+
+namespace Poco {
+namespace Data {
+namespace MySQL {
+
+void ResultMetadata::reset()
+{
+ _columns.resize(0);
+ _row.resize(0);
+ _buffer.resize(0);
+ _lengths.resize(0);
+ _isNull.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;
+ }
+
+ std::size_t count = mysql_num_fields(h);
+ MYSQL_FIELD* fields = mysql_fetch_fields(h);
+
+ std::size_t commonSize = 0;
+ _columns.reserve(count);
+
+ {for (std::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
+ !IS_NOT_NULL(fields[i].flags) // nullable
+ ));
+
+ commonSize += _columns[i].length();
+ }}
+
+ _buffer.resize(commonSize);
+ _row.resize(count);
+ _lengths.resize(count);
+ _isNull.resize(count);
+
+ std::size_t offset = 0;
+
+ {for (std::size_t i = 0; i < count; i++)
+ {
+ std::memset(&_row[i], 0, sizeof(MYSQL_BIND));
+
+ _row[i].buffer_type = fields[i].type;
+ _row[i].buffer_length = static_cast<unsigned int>(_columns[i].length());
+ _row[i].buffer = &_buffer[0] + offset;
+ _row[i].length = &_lengths[i];
+ _row[i].is_null = &_isNull[i];
+
+ offset += _row[i].buffer_length;
+ }}
+}
+
+std::size_t ResultMetadata::columnsReturned() const
+{
+ return static_cast<std::size_t>(_columns.size());
+}
+
+const MetaColumn& ResultMetadata::metaColumn(std::size_t pos) const
+{
+ return _columns[pos];
+}
+
+MYSQL_BIND* ResultMetadata::row()
+{
+ return &_row[0];
+}
+
+std::size_t ResultMetadata::length(std::size_t pos) const
+{
+ return _lengths[pos];
+}
+
+const unsigned char* ResultMetadata::rawData(std::size_t pos) const
+{
+ return reinterpret_cast<const unsigned char*>(_row[pos].buffer);
+}
+
+bool ResultMetadata::isNull(std::size_t pos) const
+{
+ return (_isNull[pos] != 0);
+}
+
+}}} // namespace Poco::Data::MySQL
View
4 Data/MySQL/src/SessionImpl.cpp
@@ -1,5 +1,5 @@
//
-// MySQLException.cpp
+// SessionImpl.cpp
//
// $Id: //poco/1.4/Data/MySQL/src/SessionImpl.cpp#1 $
//
@@ -67,7 +67,7 @@ const std::string SessionImpl::MYSQL_SERIALIZABLE = "SERIALIZABLE";
SessionImpl::SessionImpl(const std::string& connectionString, std::size_t loginTimeout) :
- Poco::Data::AbstractSessionImpl<SessionImpl>(toLower(connectionString), loginTimeout),
+ Poco::Data::AbstractSessionImpl<SessionImpl>(connectionString, loginTimeout),
_handle(0),
_connected(false),
_inTransaction(false)
View
290 Data/MySQL/src/SessionImpl.cpp~
@@ -0,0 +1,290 @@
+//
+// MySQLException.cpp
+//
+// $Id: //poco/1.4/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"
+#include "Poco/Data/Session.h"
+#include "Poco/NumberParser.h"
+#include "Poco/String.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 {
+
+
+const std::string SessionImpl::MYSQL_READ_UNCOMMITTED = "READ UNCOMMITTED";
+const std::string SessionImpl::MYSQL_READ_COMMITTED = "READ COMMITTED";
+const std::string SessionImpl::MYSQL_REPEATABLE_READ = "REPEATABLE READ";
+const std::string SessionImpl::MYSQL_SERIALIZABLE = "SERIALIZABLE";
+
+
+SessionImpl::SessionImpl(const std::string& connectionString, std::size_t loginTimeout) :
+ Poco::Data::AbstractSessionImpl<SessionImpl>(toLower(connectionString), loginTimeout),
+ _handle(0),
+ _connected(false),
+ _inTransaction(false)
+{
+ addProperty("insertId",
+ &SessionImpl::setInsertId,
+ &SessionImpl::getInsertId);
+
+ open();
+ setConnectionTimeout(CONNECTION_TIMEOUT_DEFAULT);
+}
+
+
+void SessionImpl::open(const std::string& connect)
+{
+ if (connect != connectionString())
+ {
+ if (isConnected())
+ throw InvalidAccessException("Session already connected");
+
+ if (!connect.empty())
+ setConnectionString(connect);
+ }
+
+ poco_assert_dbg (!connectionString().empty());
+
+ _handle.init();
+
+ unsigned int timeout = static_cast<unsigned int>(getLoginTimeout());
+ _handle.options(MYSQL_OPT_CONNECT_TIMEOUT, timeout);
+
+ std::map<std::string, std::string> options;
+
+ // Default values
+ options["host"] = "localhost";
+ options["port"] = "3306";
+ options["user"] = "";
+ options["password"] = "";
+ options["db"] = "";
+ options["compress"] = "";
+ options["auto-reconnect"] = "";
+
+ const std::string& connString = connectionString();
+ for (std::string::const_iterator start = connString.begin();;)
+ {
+ std::string::const_iterator finish = std::find(start, connString.end(), ';');
+ std::string::const_iterator middle = std::find(start, finish, '=');
+
+ if (middle == finish)
+ throw MySQLException("create session: bad connection string format, can not find '='");
+
+ options[copyStripped(start, middle)] = copyStripped(middle + 1, finish);
+
+ if ((finish == connString.end()) || (finish + 1 == connString.end())) break;
+
+ start = finish + 1;
+ }
+
+ if (options["user"] == "")
+ throw MySQLException("create session: specify user name");
+
+ const char * db = NULL;
+ if (!options["db"].empty())
+ db = options["db"].c_str();
+
+ unsigned int port = 0;
+ if (!NumberParser::tryParseUnsigned(options["port"], port) || 0 == port || port > 65535)
+ throw MySQLException("create session: specify correct port (numeric in decimal notation)");
+
+ if (options["compress"] == "true")
+ _handle.options(MYSQL_OPT_COMPRESS);
+ else if (options["compress"] == "false")
+ ;
+ else if (options["compress"] != "")
+ throw MySQLException("create session: specify correct compress option (true or false) or skip it");
+
+ if (options["auto-reconnect"] == "true")
+ _handle.options(MYSQL_OPT_RECONNECT, true);
+ else if (options["auto-reconnect"] == "false")
+ _handle.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
+ _handle.connect(options["host"].c_str(),
+ options["user"].c_str(),
+ options["password"].c_str(),
+ db,
+ port);
+
+ addFeature("autoCommit",
+ &SessionImpl::autoCommit,
+ &SessionImpl::isAutoCommit);
+
+ _connected = true;
+}
+
+
+SessionImpl::~SessionImpl()
+{
+ close();
+}
+
+
+Poco::Data::StatementImpl* SessionImpl::createStatementImpl()
+{
+ return new MySQLStatementImpl(*this);
+}
+
+
+void SessionImpl::begin()
+{
+ Poco::FastMutex::ScopedLock l(_mutex);
+
+ if (_inTransaction)
+ throw Poco::InvalidAccessException("Already in transaction.");
+
+ _handle.startTransaction();
+ _inTransaction = true;
+}
+
+
+void SessionImpl::commit()
+{
+ _handle.commit();
+ _inTransaction = false;
+}
+
+
+void SessionImpl::rollback()
+{
+ _handle.rollback();
+ _inTransaction = false;
+}
+
+
+void SessionImpl::autoCommit(const std::string&, bool val)
+{
+ StatementExecutor ex(_handle);
+ ex.prepare(Poco::format("SET autocommit=%d", val ? 1 : 0));
+ ex.execute();
+}
+
+
+bool SessionImpl::isAutoCommit(const std::string&)
+{
+ int ac = 0;
+ return 1 == getSetting("autocommit", ac);
+}
+
+
+void SessionImpl::setTransactionIsolation(Poco::UInt32 ti)
+{
+ std::string isolation;
+ switch (ti)
+ {
+ case Session::TRANSACTION_READ_UNCOMMITTED:
+ isolation = MYSQL_READ_UNCOMMITTED; break;
+ case Session::TRANSACTION_READ_COMMITTED:
+ isolation = MYSQL_READ_COMMITTED; break;
+ case Session::TRANSACTION_REPEATABLE_READ:
+ isolation = MYSQL_REPEATABLE_READ; break;
+ case Session::TRANSACTION_SERIALIZABLE:
+ isolation = MYSQL_SERIALIZABLE; break;
+ default:
+ throw Poco::InvalidArgumentException("setTransactionIsolation()");
+ }
+
+ StatementExecutor ex(_handle);
+ ex.prepare(Poco::format("SET SESSION TRANSACTION ISOLATION LEVEL %s", isolation));
+ ex.execute();
+}
+
+
+Poco::UInt32 SessionImpl::getTransactionIsolation()
+{
+ std::string isolation;
+ getSetting("tx_isolation", isolation);
+ Poco::replaceInPlace(isolation, "-", " ");
+ if (MYSQL_READ_UNCOMMITTED == isolation)
+ return Session::TRANSACTION_READ_UNCOMMITTED;
+ else if (MYSQL_READ_COMMITTED == isolation)
+ return Session::TRANSACTION_READ_COMMITTED;
+ else if (MYSQL_REPEATABLE_READ == isolation)
+ return Session::TRANSACTION_REPEATABLE_READ;
+ else if (MYSQL_SERIALIZABLE == isolation)
+ return Session::TRANSACTION_SERIALIZABLE;
+
+ throw InvalidArgumentException("getTransactionIsolation()");
+}
+
+
+bool SessionImpl::hasTransactionIsolation(Poco::UInt32 ti)
+{
+ return Session::TRANSACTION_READ_UNCOMMITTED == ti ||
+ Session::TRANSACTION_READ_COMMITTED == ti ||
+ Session::TRANSACTION_REPEATABLE_READ == ti ||
+ Session::TRANSACTION_SERIALIZABLE == ti;
+}
+
+
+void SessionImpl::close()
+{
+ if (_connected)
+ {
+ _handle.close();
+ _connected = false;
+ }
+}
+
+
+void SessionImpl::setConnectionTimeout(std::size_t timeout)
+{
+ _handle.options(MYSQL_OPT_READ_TIMEOUT, static_cast<unsigned int>(timeout));
+ _handle.options(MYSQL_OPT_WRITE_TIMEOUT, static_cast<unsigned int>(timeout));
+ _timeout = timeout;
+}
+
+
+}}}
View
21 Data/MySQL/testsuite/src/MySQLTest.cpp
@@ -64,7 +64,7 @@ Poco::SharedPtr<SQLExecutor> MySQLTest::_pExecutor = 0;
// Parameters for barebone-test
#define MYSQL_USER "root"
#define MYSQL_PWD "poco"
-#define MYSQL_HOST "localhost"
+#define MYSQL_HOST "192.168.1.33"
#define MYSQL_PORT 3306
#define MYSQL_DB "test"
@@ -417,6 +417,15 @@ void MySQLTest::testEmptyDB()
}
+void MySQLTest::testDateTime()
+{
+ if (!_pSession) fail ("Test not available.");
+
+ recreatePersonDateTimeTable();
+ _pExecutor->dateTime();
+}
+
+
void MySQLTest::testBLOB()
{
if (!_pSession) fail ("Test not available.");
@@ -697,6 +706,15 @@ void MySQLTest::recreatePersonBLOBTable()
}
+void MySQLTest::recreatePersonDateTimeTable()
+{
+ dropTable("Person");
+ try { *_pSession << "CREATE TABLE Person (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), Birthday DATETIME)", now; }
+ catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail ("recreatePersonDateTimeTable()"); }
+ catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail ("recreatePersonDateTimeTable()"); }
+}
+
+
void MySQLTest::recreateIntsTable()
{
dropTable("Strings");
@@ -833,6 +851,7 @@ CppUnit::Test* MySQLTest::suite()
CppUnit_addTest(pSuite, MySQLTest, testIllegalRange);
CppUnit_addTest(pSuite, MySQLTest, testSingleSelect);
CppUnit_addTest(pSuite, MySQLTest, testEmptyDB);
+ CppUnit_addTest(pSuite, MySQLTest, testDateTime);
//CppUnit_addTest(pSuite, MySQLTest, testBLOB);
CppUnit_addTest(pSuite, MySQLTest, testBLOBStmt);
CppUnit_addTest(pSuite, MySQLTest, testFloat);
View
861 Data/MySQL/testsuite/src/MySQLTest.cpp~
@@ -0,0 +1,861 @@
+//
+// MySQLTest.cpp
+//
+// $Id: //poco/1.4/Data/MySQL/testsuite/src/MySQLTest.cpp#1 $
+//
+// 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/Tuple.h"
+#include "Poco/NamedTuple.h"
+#include "Poco/Exception.h"
+#include "Poco/Data/LOB.h"
+#include "Poco/Data/StatementImpl.h"
+#include "Poco/Data/MySQL/Connector.h"
+#include "Poco/Data/MySQL/MySQLException.h"
+#include "Poco/Nullable.h"
+#include "Poco/Data/DataException.h"
+#include <iostream>
+
+using namespace Poco::Data;
+using namespace Poco::Data::Keywords;
+using Poco::Data::MySQL::ConnectionException;
+using Poco::Data::MySQL::StatementException;
+using Poco::format;
+using Poco::NotFoundException;
+using Poco::Int32;
+using Poco::Nullable;
+using Poco::Tuple;
+using Poco::NamedTuple;
+
+Poco::SharedPtr<Poco::Data::Session> MySQLTest::_pSession = 0;
+Poco::SharedPtr<SQLExecutor> MySQLTest::_pExecutor = 0;
+
+//
+// Parameters for barebone-test
+#define MYSQL_USER "root"
+#define MYSQL_PWD "poco"
+#define MYSQL_HOST "192.168.1.33"
+#define MYSQL_PORT 3306
+#define MYSQL_DB "test"
+
+//
+// Connection string
+std::string MySQLTest::_dbConnString = "host=" MYSQL_HOST
+ ";user=" MYSQL_USER
+ ";password=" MYSQL_PWD
+ ";db=" MYSQL_DB
+ ";compress=true;auto-reconnect=true";
+
+
+MySQLTest::MySQLTest(const std::string& name):
+ CppUnit::TestCase(name)
+{
+ MySQL::Connector::registerConnector();
+}
+
+
+MySQLTest::~MySQLTest()
+{
+ MySQL::Connector::unregisterConnector();
+}
+
+
+void MySQLTest::testConnectNoDB()
+{
+ std::string dbConnString = "host=" MYSQL_HOST
+ ";user=" MYSQL_USER
+ ";password=" MYSQL_PWD
+ ";compress=true;auto-reconnect=true";
+
+ try
+ {
+ Session session(MySQL::Connector::KEY, dbConnString);
+ std::cout << "Connected to [" << "MySQL" << "] without database. Disconnecting ..." << std::endl;
+ session.close();
+ std::cout << "Disconnected." << std::endl;
+ }
+ catch (ConnectionFailedException& ex)
+ {
+ std::cout << ex.displayText() << std::endl;
+ }
+}
+
+
+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::testNull()
+{
+ if (!_pSession) fail ("Test not available.");
+
+ recreateVectorsTable();
+ _pExecutor->doNull();
+}
+
+
+void MySQLTest::testSessionTransaction()
+{
+ if (!_pSession) fail ("Test not available.");
+
+ recreatePersonTable();
+ _pExecutor->sessionTransaction(_dbConnString);
+}
+
+
+void MySQLTest::testTransaction()
+{
+ if (!_pSession) fail ("Test not available.");
+
+ recreatePersonTable();
+ _pExecutor->transaction(_dbConnString);
+}
+
+
+void MySQLTest::testReconnect()
+{
+ if (!_pSession) fail ("Test not available.");
+
+ recreatePersonTable();
+ _pExecutor->reconnect();
+}
+
+
+void MySQLTest::testNullableInt()
+{
+ if (!_pSession) fail ("Test not available.");
+
+ recreateNullableIntTable();
+
+ Nullable<Int32> i1(1);
+ Nullable<Int32> i2;
+
+ int id = 1;
+ *_pSession << "INSERT INTO NullableIntTest VALUES(?, ?)", use(id), use(i1), now;
+ id = 2;
+ *_pSession << "INSERT INTO NullableIntTest VALUES(?, ?)", use(id), use(i2), now;
+ id = 3;
+ i2 = 3;
+ *_pSession << "INSERT INTO NullableIntTest VALUES(?, ?)", use(id), use(i2), now;
+
+ int count = 0;
+ *_pSession << "SELECT COUNT(*) FROM NullableIntTest", into(count), now;
+ assert (count == 3);
+
+ Nullable<Int32> ci1;
+ Nullable<Int32> ci2;
+ Nullable<Int32> ci3;
+ id = 1;
+ *_pSession << "SELECT Value FROM NullableIntTest WHERE Id = ?", into(ci1), use(id), now;
+ assert (ci1 == i1);
+ id = 2;
+ *_pSession << "SELECT Value FROM NullableIntTest WHERE Id = ?", into(ci2), use(id), now;
+ assert (ci2.isNull());
+ assert (!(0 == ci2));
+ assert (0 != ci2);
+ assert (!(ci2 == 0));
+ assert (ci2 != 0);
+ ci2 = 10;
+ assert (10 == ci2);
+ assert (ci2 == 10);
+ assert (!ci2.isNull());
+ id = 3;
+ *_pSession << "SELECT Value FROM NullableIntTest WHERE Id = ?", into(ci3), use(id), now;
+ assert (!ci3.isNull());
+ assert (ci3 == 3);
+ assert (3 == ci3);
+}
+
+
+void MySQLTest::testNullableString()
+{
+ if (!_pSession) fail ("Test not available.");
+
+ recreateNullableStringTable();
+
+ Int32 id = 0;
+ Nullable<std::string> address("Address");
+ Nullable<Int32> age = 10;
+ *_pSession << "INSERT INTO NullableStringTest VALUES(?, ?, ?)", use(id), use(address), use(age), now;
+ id++;
+ address = null;
+ age = null;
+ *_pSession << "INSERT INTO NullableStringTest VALUES(?, ?, ?)", use(id), use(address), use(age), now;
+
+ Nullable<std::string> resAddress;
+ Nullable<Int32> resAge;
+ *_pSession << "SELECT Address, Age FROM NullableStringTest WHERE Id = ?", into(resAddress), into(resAge), use(id), now;
+ assert(resAddress == address);
+ assert(resAge == age);
+ assert(resAddress.isNull());
+ assert(null == resAddress);
+ assert(resAddress == null);
+
+ resAddress = std::string("Test");
+ assert(!resAddress.isNull());
+ assert(resAddress == std::string("Test"));
+ assert(std::string("Test") == resAddress);
+ assert(null != resAddress);
+ assert(resAddress != null);
+}
+
+
+void MySQLTest::testTupleWithNullable()
+{
+ if (!_pSession) fail ("Test not available.");
+
+ recreateNullableStringTable();
+
+ typedef Poco::Tuple<Int32, Nullable<std::string>, Nullable<Int32> > Info;
+
+ Info info(0, std::string("Address"), 10);
+ *_pSession << "INSERT INTO NullableStringTest VALUES(?, ?, ?)", use(info), now;
+
+ info.set<0>(info.get<0>()++);
+ info.set<1>(null);
+ *_pSession << "INSERT INTO NullableStringTest VALUES(?, ?, ?)", use(info), now;
+
+ info.set<0>(info.get<0>()++);
+ info.set<1>(std::string("Address!"));
+ info.set<2>(null);
+ *_pSession << "INSERT INTO NullableStringTest VALUES(?, ?, ?)", use(info), now;
+
+ std::vector<Info> infos;
+ infos.push_back(Info(10, std::string("A"), 0));
+ infos.push_back(Info(11, null, 12));
+ infos.push_back(Info(12, std::string("B"), null));
+
+ *_pSession << "INSERT INTO NullableStringTest VALUES(?, ?, ?)", use(infos), now;
+
+ std::vector<Info> result;
+
+ *_pSession << "SELECT Id, Address, Age FROM NullableStringTest", into(result), now;
+
+ assert(result[0].get<1>() == std::string("Address"));
+ assert(result[0].get<2>() == 10);
+
+ assert(result[1].get<1>() == null);
+ assert(result[1].get<2>() == 10);
+
+ assert(result[2].get<1>() == std::string("Address!"));
+ assert(result[2].get<2>() == null);
+
+ assert(result[3].get<1>() == std::string("A"));
+ assert(result[3].get<2>() == 0);
+
+ assert(result[4].get<1>() == null);
+ assert(result[4].get<2>() == 12);
+
+ assert(result[5].get<1>() == std::string("B"));
+ assert(result[5].get<2>() == null);
+
+}
+
+
+void MySQLTest::dropTable(const std::string& tableName)
+{
+
+ try { *_pSession << format("DROP TABLE IF EXISTS %s", tableName), now; }
+ catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail ("dropTable()"); }
+ catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail ("dropTable()"); }
+}
+
+
+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::recreatePersonDateTimeTable()
+{
+ dropTable("Person");
+ try { *_pSession << "CREATE TABLE Person (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), Birthday DATETIME)", now; }
+ catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail ("recreatePersonDateTimeTable()"); }
+ catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail ("recreatePersonDateTimeTable()"); }
+}
+
+
+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::recreateNullableIntTable()
+{
+ dropTable("NullableIntTest");
+ try {
+ *_pSession << "CREATE TABLE NullableIntTest (Id INTEGER(10), Value INTEGER(10))", now;
+ }
+ catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail ("recreateNullableIntTable()"); }
+ catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail ("recreateNullableIntTable()"); }
+}
+
+
+void MySQLTest::recreateNullableStringTable()
+{
+ dropTable("NullableStringTest");
+ try {
+ *_pSession << "CREATE TABLE NullableStringTest (Id INTEGER(10), Address VARCHAR(30), Age INTEGER(10))", now;
+ }
+ catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail ("recreateNullableStringTable()"); }
+ catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail ("recreateNullableStringTable()"); }
+}
+
+
+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()
+{
+ MySQL::Connector::registerConnector();
+
+ try
+ {
+ _pSession = new Session(MySQL::Connector::KEY, _dbConnString);
+ }
+ catch (ConnectionFailedException& ex)
+ {
+ std::cout << ex.displayText() << std::endl;
+ return 0;
+ }
+
+ std::cout << "*** Connected to [" << "MySQL" << "] test database." << std::endl;
+
+ _pExecutor = new SQLExecutor("MySQL SQL Executor", _pSession);
+
+ CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("MySQLTest");
+
+ CppUnit_addTest(pSuite, MySQLTest, testConnectNoDB);
+ 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);
+ CppUnit_addTest(pSuite, MySQLTest, testNull);
+ CppUnit_addTest(pSuite, MySQLTest, testNullableInt);
+ CppUnit_addTest(pSuite, MySQLTest, testNullableString);
+ CppUnit_addTest(pSuite, MySQLTest, testTupleWithNullable);
+ CppUnit_addTest(pSuite, MySQLTest, testSessionTransaction);
+ CppUnit_addTest(pSuite, MySQLTest, testTransaction);
+ CppUnit_addTest(pSuite, MySQLTest, testReconnect);
+
+ return pSuite;
+}
View
3 Data/MySQL/testsuite/src/MySQLTest.h
@@ -95,7 +95,7 @@ class MySQLTest: public CppUnit::TestCase
void testIllegalRange();
void testSingleSelect();
void testEmptyDB();
-
+ void testDateTime();
void testBLOB();
void testBLOBStmt();
@@ -129,6 +129,7 @@ class MySQLTest: public CppUnit::TestCase
void dropTable(const std::string& tableName);
void recreatePersonTable();
void recreatePersonBLOBTable();
+ void recreatePersonDateTimeTable();
void recreateStringsTable();
void recreateIntsTable();
void recreateFloatsTable();
View
148 Data/MySQL/testsuite/src/MySQLTest.h~
@@ -0,0 +1,148 @@
+//
+// ODBCMySQLTest.h
+//
+// $Id: //poco/1.4/Data/MySQL/testsuite/src/ODBCMySQLTest.h#1 $
+//
+// 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 testConnectNoDB();
+ 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 testNull();
+ void testNullVector();
+
+ void testNullableInt();
+ void testNullableString();
+ void testTupleWithNullable();
+
+ void testSessionTransaction();
+ void testTransaction();
+
+ void testReconnect();
+
+ void setUp();
+ void tearDown();
+
+ static CppUnit::Test* suite();
+
+private:
+
+ void dropTable(const std::string& tableName);
+ void recreatePersonTable();
+ void recreatePersonBLOBTable();
+ void recreatePersonDateTimeTable();
+ void recreateStringsTable();
+ void recreateIntsTable();
+ void recreateFloatsTable();
+ void recreateTuplesTable();
+ void recreateVectorsTable();
+ void recreateNullableIntTable();
+ void recreateNullableStringTable();
+
+ static std::string _dbConnString;
+ static Poco::SharedPtr<Poco::Data::Session> _pSession;
+ static Poco::SharedPtr<SQLExecutor> _pExecutor;
+ static const bool bindValues[8];
+};
+
+
+#endif // MySQLTest_INCLUDED
View
33 Data/MySQL/testsuite/src/SQLExecutor.cpp
@@ -35,6 +35,7 @@
#include "Poco/String.h"
#include "Poco/Format.h"
#include "Poco/Tuple.h"
+#include "Poco/DateTime.h"
#include "Poco/Any.h"
#include "Poco/Exception.h"
#include "Poco/Data/LOB.h"
@@ -58,6 +59,7 @@ using Poco::Data::MySQL::ConnectionException;
using Poco::Data::MySQL::StatementException;
using Poco::format;
using Poco::Tuple;
+using Poco::DateTime;
using Poco::Any;
using Poco::AnyCast;
using Poco::NotFoundException;
@@ -1295,6 +1297,35 @@ void SQLExecutor::blob(int bigSize)
assert (res == big);
}
+
+void SQLExecutor::dateTime()
+{
+ std::string funct = "dateTime()";
+ std::string lastName("Bart");
+ std::string firstName("Simpson");
+ std::string address("Springfield");
+ DateTime birthday(1980, 4, 1, 5, 45, 12);
+
+ int count = 0;
+ try { *_pSession << "INSERT INTO Person VALUES (?,?,?,?)", use(lastName), use(firstName), use(address), use(birthday), 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);
+
+ DateTime bd;
+ assert (bd != birthday);
+ try { *_pSession << "SELECT Birthday FROM Person", into(bd), now; }
+ catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); }
+ catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); }
+ assert (bd == birthday);
+
+ std::cout << std::endl << RecordSet(*_pSession, "SELECT * FROM Person");
+}
+
+
void SQLExecutor::blobStmt()
{
std::string funct = "blobStmt()";
@@ -1320,6 +1351,7 @@ void SQLExecutor::blobStmt()
poco_assert (res == blob);
}
+
void SQLExecutor::tuples()
{
typedef Tuple<int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int> TupleType;
@@ -1338,6 +1370,7 @@ void SQLExecutor::tuples()
assert (ret == t);
}
+
void SQLExecutor::tupleVector()
{
typedef Tuple<int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int> TupleType;
View
1,878 Data/MySQL/testsuite/src/SQLExecutor.cpp~
@@ -0,0 +1,1878 @@
+//
+// SQLExecutor.cpp
+//
+// $Id: //poco/1.4/Data/MySQL/testsuite/src/SQLExecutor.cpp#1 $
+//
+// 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/DateTime.h"
+#include "Poco/Any.h"
+#include "Poco/Exception.h"
+#include "Poco/Data/LOB.h"
+#include "Poco/Data/StatementImpl.h"
+#include "Poco/Data/RecordSet.h"
+#include "Poco/Data/Transaction.h"
+#include "Poco/Data/MySQL/Connector.h"
+#include "Poco/Data/MySQL/MySQLException.h"
+
+#ifdef _WIN32
+#include <Winsock2.h>
+#endif
+
+#include <mysql.h>
+#include <iostream>
+
+
+using namespace Poco::Data;
+using namespace Poco::Data::Keywords;
+using Poco::Data::MySQL::ConnectionException;
+using Poco::Data::MySQL::StatementException;
+using Poco::format;
+using Poco::Tuple;
+using Poco::DateTime;
+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<Person>
+{
+public:
+ static void bind(std::size_t pos, const Person& obj, AbstractBinder* pBinder, AbstractBinder::Direction dir)
+ {
+ // 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, dir);
+ pBinder->bind(pos++, obj.firstName, dir);
+ pBinder->bind(pos++, obj.address, dir);
+ pBinder->bind(pos++, obj.age, dir);
+ }
+
+ static void prepare(std::size_t pos, const Person& obj, AbstractPreparator* 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<unsigned long>(sql.length()));
+
+ sql = tableCreateString;
+ rc = mysql_stmt_prepare(hstmt, sql.c_str(), static_cast<unsigned long>(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<unsigned long>(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<char*>(str[0].c_str());
+ bind_param[0].buffer_length = static_cast<unsigned long>(str[0].length());
+ bind_param[0].buffer_type = MYSQL_TYPE_STRING;
+
+ bind_param[1].buffer = const_cast<char*>(str[1].c_str());
+ bind_param[1].buffer_length = static_cast<unsigned long>(str[1].length());
+ bind_param[1].buffer_type = MYSQL_TYPE_STRING;
+
+ bind_param[2].buffer = const_cast<char*>(str[2].c_str());
+ bind_param[2].buffer_length = static_cast<unsigned long>(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<unsigned long>(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 == std::strncmp("111", chr[0], 3));
+ assert (0 == std::strncmp("222", chr[1], 3));
+ assert (0 == std::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<unsigned long>(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<std::string> lastNames;
+ std::vector<std::string> firstNames;
+ std::vector<std::string> addresses;
+ std::vector<int> 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<std::string> lastNamesR;
+ std::vector<std::string> firstNamesR;
+ std::vector<std::string> addressesR;
+ std::vector<int> 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<Person> 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<Person> 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<std::string> 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<std::string> 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)
+ {
+ std::size_t 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<int> 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<int> 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<int> 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<int> 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<int> 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<int> 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<int> 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<int> 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<int> 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<int> 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<std::string> lastNames;
+ std::set<std::string> firstNames;
+ std::set<std::string> addresses;
+ std::set<int> 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<std::string> lastNamesR;
+ std::set<std::string> firstNamesR;
+ std::set<std::string> addressesR;
+ std::set<int> 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<Person> 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<Person> 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<Person> 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<Person> 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<std::string> lastNames;
+ std::multiset<std::string> firstNames;
+ std::multiset<std::string> addresses;
+ std::multiset<int> 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<std::string> lastNamesR;
+ std::multiset<std::string> firstNamesR;
+ std::multiset<std::string> addressesR;
+ std::multiset<int> 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<Person> 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<Person> 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<std::string, Person> 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<std::string, Person> 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<std::string, Person> 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<std::string, Person> 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<std::string, Person> 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<std::string, Person> 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<std::string, Person> 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));
+