poco/Data/DataTest/src/SQLExecutor.cpp
Aleksandar Fabijanic 9530a77347
Insert NULL using BULK #4001 (#4755)
* fix(ODBC): Insert NULL using BULK #4001
resolve bound types and sizes at compile time

* fix: remove string suffix for static_assert

* Insert NULL using BULK #4001

* fix: typo

* fix(SQLite): missing functions; consolidate extract calls

* chore(SQLite): remove unnecessary typedef

* fix(SQLite): remove duplicate functions

* fix(SQLite): compile errors and warnings

* fix(SQLite): extract implementation signatures

* fix(SQLite): long64 platforms compile errors

* fix(SQLite): long64 platforms compile errors, part ii

* fix(ODBC): windows build

* fix(ODBC): MSSQL big string on windows

* fix(Data): psql and mysql compile errors

* fix(PostgreSQL): add missing functions

* fix(ODBC): revert column size discovery (breaks Oracle)

* fix(PostgreSQL): Nullable extraction #4001

* fix(MySQL): Nullable extraction #4001

* chore(Data): code tidy up

* fix(ODBC): add missing changes
2024-11-11 18:23:21 +01:00

4600 lines
117 KiB
C++

//
// SQLExecutor.cpp
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "CppUnit/TestCase.h"
#include "CppUnit/CppUnitException.h"
#include "Poco/Data/Test/SQLExecutor.h"
#include "Poco/String.h"
#include "Poco/Format.h"
#include "Poco/Tuple.h"
#include "Poco/Nullable.h"
#include "Poco/Any.h"
#include "Poco/Dynamic/Var.h"
#include "Poco/DateTime.h"
#include "Poco/Stopwatch.h"
#include "Poco/NumberFormatter.h"
#include "Poco/Thread.h"
#include "Poco/Logger.h"
#include "Poco/Message.h"
#include "Poco/RefCountedObject.h"
#include "Poco/AutoPtr.h"
#include "Poco/SharedPtr.h"
#include "Poco/Exception.h"
#include "Poco/Data/Date.h"
#include "Poco/Data/Time.h"
#include "Poco/Data/LOB.h"
#include "Poco/Data/Session.h"
#include "Poco/Data/SessionPool.h"
#include "Poco/Data/StatementImpl.h"
#include "Poco/Data/RowIterator.h"
#include "Poco/Data/RowFilter.h"
#include "Poco/Data/BulkExtraction.h"
#include "Poco/Data/BulkBinding.h"
#include "Poco/Data/SQLChannel.h"
#include "Poco/Data/Transaction.h"
#include "Poco/UnicodeConverter.h"
#include "Poco/UTFString.h"
#include <iostream>
#include <sstream>
#include <iterator>
using Poco::Data::Session;
using Poco::Data::SessionPool;
using Poco::Data::Statement;
using Poco::Data::RecordSet;
using Poco::Data::Column;
using Poco::Data::Row;
using Poco::Data::RowFilter;
using Poco::Data::RowIterator;
using Poco::Data::SQLChannel;
using Poco::Data::LimitException;
using Poco::Data::BindingException;
using Poco::Data::CLOB;
using Poco::Data::Date;
using Poco::Data::Time;
using Poco::Data::Transaction;
using Poco::Data::NotConnectedException;
using Poco::Data::DataException;
using Poco::format;
using Poco::Tuple;
using Poco::Nullable;
using Poco::Any;
using Poco::AnyCast;
using Poco::Dynamic::Var;
using Poco::DateTime;
using Poco::Stopwatch;
using Poco::NumberFormatter;
using Poco::AutoPtr;
using Poco::Thread;
using Poco::Logger;
using Poco::Message;
using Poco::NotFoundException;
using Poco::InvalidAccessException;
using Poco::InvalidArgumentException;
using Poco::NotImplementedException;
using Poco::BadCastException;
using Poco::RangeException;
using Poco::TimeoutException;
using Poco::UnicodeConverter;
using Poco::UTF16String;
using Poco::UTF32String;
namespace {
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 the key
return lastName;
}
};
struct RefCountedPerson : public Poco::RefCountedObject
{
std::string lastName;
std::string firstName;
std::string address;
int age;
RefCountedPerson(){age = 0;}
RefCountedPerson(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 RefCountedPerson& 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 the key
return lastName;
}
private:
RefCountedPerson(const RefCountedPerson &);
RefCountedPerson& operator = (const RefCountedPerson&);
};
} // namespace
namespace Poco {
namespace Data {
template <>
class TypeHandler<Person>
{
public:
static void bind(std::size_t pos,
const Person& obj,
AbstractBinder::Ptr pBinder,
AbstractBinder::Direction dir = AbstractBinder::PD_IN)
{
// the table is defined as Person (LastName VARCHAR(30), FirstName VARCHAR, Address VARCHAR, Age INTEGER(3))
poco_assert_dbg (!pBinder.isNull());
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::Ptr pPrepare)
{
// the table is defined as Person (LastName VARCHAR(30), FirstName VARCHAR, Address VARCHAR, Age INTEGER(3))
poco_assert_dbg (!pPrepare.isNull());
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::Ptr pExt)
{
poco_assert_dbg (!pExt.isNull());
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(const TypeHandler&);
TypeHandler& operator=(const TypeHandler&);
};
template <>
class TypeHandler<RefCountedPerson>
{
public:
static void bind(std::size_t pos,
const RefCountedPerson& obj,
AbstractBinder::Ptr pBinder,
AbstractBinder::Direction dir = AbstractBinder::PD_IN)
{
// the table is defined as Person (LastName VARCHAR(30), FirstName VARCHAR, Address VARCHAR, Age INTEGER(3))
poco_assert_dbg (!pBinder.isNull());
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, RefCountedPerson& obj, AbstractPreparator::Ptr pPrepare)
{
// the table is defined as Person (LastName VARCHAR(30), FirstName VARCHAR, Address VARCHAR, Age INTEGER(3))
poco_assert_dbg (!pPrepare.isNull());
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, RefCountedPerson& obj, const RefCountedPerson& defVal, AbstractExtractor::Ptr pExt)
{
poco_assert_dbg (!pExt.isNull());
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(const TypeHandler&);
TypeHandler& operator=(const TypeHandler&);
};
namespace Test {
const std::string SQLExecutor::MULTI_INSERT =
"INSERT INTO Test VALUES ('1', 2, 3.5);"
"INSERT INTO Test VALUES ('2', 3, 4.5);"
"INSERT INTO Test VALUES ('3', 4, 5.5);"
"INSERT INTO Test VALUES ('4', 5, 6.5);"
"INSERT INTO Test VALUES ('5', 6, 7.5);";
const std::string SQLExecutor::MULTI_SELECT =
"SELECT * FROM Test WHERE First = '1';"
"SELECT * FROM Test WHERE First = '2';"
"SELECT * FROM Test WHERE First = '3';"
"SELECT * FROM Test WHERE First = '4';"
"SELECT * FROM Test WHERE First = '5';";
SQLExecutor::SQLExecutor(const std::string& name, Poco::Data::Session* pSession, Poco::Data::Session* pEncSession, bool numberedPlaceHolders):
CppUnit::TestCase(name),
_pSession(pSession),
_pEncSession(pEncSession),
_numberedPlaceHolders(numberedPlaceHolders)
{
}
SQLExecutor::~SQLExecutor()
{
}
Poco::Data::Session& SQLExecutor::session(bool enc)
{
if (!enc)
{
poco_check_ptr(_pSession);
return *_pSession;
}
else
{
poco_check_ptr(_pEncSession);
return *_pEncSession;
}
}
void SQLExecutor::execute(const std::string& sql)
{
try { session() << sql, now; } catch(DataException& ce){ std::cout << ce.displayText() << std::endl; fail (sql, __LINE__, __FILE__); }
}
void SQLExecutor::session(const std::string& connector, const std::string& connectString, int timeout)
{
Poco::Data::Session s(connector, connectString, timeout);
assertTrue (s.isConnected());
s.close();
assertTrue (!s.isConnected());
s.open();
assertTrue (s.isConnected());
s.reconnect();
assertTrue (s.isConnected());
s.close();
assertTrue (!s.isConnected());
s.reconnect();
assertTrue (s.isConnected());
}
void SQLExecutor::sessionPool(const std::string& connector, const std::string& connectString, int minSessions, int maxSessions, int idleTime, int timeout)
{
assertTrue (minSessions <= maxSessions);
SessionPool sp(connector, connectString, minSessions, maxSessions, idleTime, timeout);
assertEqual (0, sp.allocated());
assertEqual (maxSessions, sp.available());
Session s1 = sp.get();
assertEqual (minSessions, sp.allocated());
assertEqual (maxSessions-1, sp.available());
s1 = sp.get();
assertEqual (2, sp.allocated());
assertEqual (maxSessions-1, sp.available());
{
Session s2 = sp.get();
assertEqual (2, sp.allocated());
assertEqual (maxSessions-2, sp.available());
}
assertEqual (2, sp.allocated());
assertEqual (maxSessions-1, sp.available());
Thread::sleep(idleTime + 500);
assertEqual (maxSessions-minSessions, sp.available());
try
{
sp.setFeature("autoBind"s, true);
fail("SessionPool must throw on setFeature after the first session was created.", __LINE__, __FILE__);
} catch(const Poco::InvalidAccessException&) {}
try
{
sp.setProperty("storage"s, "deque"s);
fail("SessionPool must throw on valid setProperty after the first session was created.", __LINE__, __FILE__);
} catch(const Poco::InvalidAccessException&) {}
try
{
sp.setFeature("bulk"s, true);
fail("SessionPool must throw on valid setFeature after the first session was created.", __LINE__, __FILE__);
} catch(const Poco::InvalidAccessException&) {}
std::vector<Session> sessions;
for (int i = 0; i < maxSessions-minSessions; ++i)
{
sessions.push_back(sp.get());
}
try
{
Session s = sp.get();
fail("SessionPool must throw when no sesions available.", __LINE__, __FILE__);
} catch(const Poco::Data::SessionPoolExhaustedException&) {}
sp.shutdown();
try
{
Session s = sp.get();
fail("SessionPool that was shut down must throw on get.", __LINE__, __FILE__);
} catch(const Poco::InvalidAccessException&) {}
{
SessionPool pool(connector, connectString, 1, 4, 2, 10);
try { pool.getFeature("g1"); fail ("getting an unsuported feature must fail", __LINE__, __FILE__); }
catch ( Poco::NotFoundException& ) { }
try { pool.getProperty("r1"); fail ("getting an unsuported property must fail", __LINE__, __FILE__); }
catch ( Poco::NotFoundException& ) { }
assertTrue (pool.capacity() == 4);
assertTrue (pool.allocated() == 0);
assertTrue (pool.idle() == 0);
assertTrue (pool.connTimeout() == 10);
assertTrue (pool.available() == 4);
assertTrue (pool.dead() == 0);
assertTrue (pool.allocated() == pool.used() + pool.idle());
Session s1(pool.get());
try { pool.setFeature("f1", true); fail ("setting an unsuported feature must fail", __LINE__, __FILE__); }
catch (Poco::InvalidAccessException&) { }
catch (Poco::NotImplementedException&) { }
catch (Poco::Data::NotSupportedException&) { }
try { pool.setProperty("p1", 1); fail ("setting an unsuported property must fail", __LINE__, __FILE__); }
catch (Poco::InvalidAccessException&) { }
catch (Poco::NotImplementedException&) { }
catch (Poco::Data::NotSupportedException&) { }
assertTrue (pool.capacity() == 4);
assertTrue (pool.allocated() == 1);
assertTrue (pool.idle() == 0);
assertTrue (pool.connTimeout() == 10);
assertTrue (pool.available() == 3);
assertTrue (pool.dead() == 0);
assertTrue (pool.allocated() == pool.used() + pool.idle());
Session s2(pool.get());
assertTrue (pool.capacity() == 4);
assertTrue (pool.allocated() == 2);
assertTrue (pool.idle() == 0);
assertTrue (pool.connTimeout() == 10);
assertTrue (pool.available() == 2);
assertTrue (pool.dead() == 0);
assertTrue (pool.allocated() == pool.used() + pool.idle());
Session s4(pool.get());
assertTrue (pool.capacity() == 4);
assertTrue (pool.allocated() == 3);
assertTrue (pool.idle() == 0);
assertTrue (pool.connTimeout() == 10);
assertTrue (pool.available() == 1);
assertTrue (pool.dead() == 0);
assertTrue (pool.allocated() == pool.used() + pool.idle());
Session s5(pool.get());
assertTrue (pool.capacity() == 4);
assertTrue (pool.allocated() == 4);
assertTrue (pool.idle() == 0);
assertTrue (pool.connTimeout() == 10);
assertTrue (pool.available() == 0);
assertTrue (pool.dead() == 0);
assertTrue (pool.allocated() == pool.used() + pool.idle());
try
{
Session s6(pool.get());
fail("pool exhausted - must throw", __LINE__, __FILE__);
}
catch (Poco::Data::SessionPoolExhaustedException&) { }
s5.close();
assertTrue (pool.capacity() == 4);
assertTrue (pool.allocated() == 4);
assertTrue (pool.idle() == 1);
assertTrue (pool.connTimeout() == 10);
assertTrue (pool.available() == 1);
assertTrue (pool.dead() == 0);
assertTrue (pool.allocated() == pool.used() + pool.idle());
try
{
s5 << "DROP TABLE IF EXISTS Test", now;
fail("session unusable - must throw", __LINE__, __FILE__);
}
catch (Poco::Data::SessionUnavailableException&) { }
s4.close();
assertTrue (pool.capacity() == 4);
assertTrue (pool.allocated() == 4);
assertTrue (pool.idle() == 2);
assertTrue (pool.connTimeout() == 10);
assertTrue (pool.available() == 2);
assertTrue (pool.dead() == 0);
assertTrue (pool.allocated() == pool.used() + pool.idle());
Thread::sleep(5000); // time to clean up idle sessions
assertTrue (pool.capacity() == 4);
assertTrue (pool.allocated() == 2);
assertTrue (pool.idle() == 0);
assertTrue (pool.connTimeout() == 10);
assertTrue (pool.available() == 2);
assertTrue (pool.dead() == 0);
assertTrue (pool.allocated() == pool.used() + pool.idle());
Session s6(pool.get());
assertTrue (pool.capacity() == 4);
assertTrue (pool.allocated() == 3);
assertTrue (pool.idle() == 0);
assertTrue (pool.connTimeout() == 10);
assertTrue (pool.available() == 1);
assertTrue (pool.dead() == 0);
assertTrue (pool.allocated() == pool.used() + pool.idle());
s6.close();
assertTrue (pool.capacity() == 4);
assertTrue (pool.allocated() == 3);
assertTrue (pool.idle() == 1);
assertTrue (pool.connTimeout() == 10);
assertTrue (pool.available() == 2);
assertTrue (pool.dead() == 0);
assertTrue (pool.allocated() == pool.used() + pool.idle());
assertTrue (pool.isActive());
pool.shutdown();
assertTrue (!pool.isActive());
try
{
Session s7(pool.get());
fail("pool shut down - must throw", __LINE__, __FILE__);
}
catch (InvalidAccessException&) { }
assertTrue (pool.capacity() == 4);
assertTrue (pool.allocated() == 0);
assertTrue (pool.idle() == 0);
assertTrue (pool.connTimeout() == 10);
assertTrue (pool.available() == 0);
assertTrue (pool.dead() == 0);
assertTrue (pool.allocated() == 0);
assertTrue (pool.used() == 0);
assertTrue (pool.idle() == 0);
}
}
void SQLExecutor::zeroRows()
{
Statement stmt = (session() << "SELECT * FROM Person WHERE 0 = 1");
assertTrue (0 == stmt.execute());
}
void SQLExecutor::simpleAccess()
{
std::string lastName = "lastName";
std::string firstName("firstName");
std::string address("Address");
int age = 133132;
int count = 0;
std::string result;
try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(lastName), use(firstName), use(address), use(age), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
count = 0;
try { session() << "SELECT COUNT(*) FROM Person", into(count), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (count == 1);
try { session() << "SELECT LastName FROM Person", into(result), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (lastName == result);
try { session() << "SELECT Age FROM Person", into(count), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (count == age);
}
void SQLExecutor::complexType()
{
Person p1("LN1", "FN1", "ADDR1", 1);
Person p2("LN2", "FN2", "ADDR2", 2);
try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(p1), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(p2), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
int count = 0;
try { session() << "SELECT COUNT(*) FROM Person", into(count), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (count == 2);
Person c1;
try { session() << "SELECT * FROM Person WHERE LastName = 'LN1'", into(c1), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (c1 == p1);
}
void SQLExecutor::complexTypeTuple()
{
Person p1("LN1", "FN1", "ADDR1", 1);
Person p2("LN2", "FN2", "ADDR2", 2);
Tuple<Person,Person> t(p1,p2);
try { *_pSession << formatSQL("INSERT INTO Person VALUES(?,?,?,?,?,?,?,?)"), use(t), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
Tuple<Person,Person> ret;
assertTrue (ret != t);
try { *_pSession << "SELECT * FROM Person", into(ret), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (ret == t);
}
void SQLExecutor::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 { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(lastNames), use(firstNames), use(addresses), use(ages), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
try { session() << "SELECT COUNT(*) FROM Person", into(count), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (count == 2);
std::vector<std::string> lastNamesR;
std::vector<std::string> firstNamesR;
std::vector<std::string> addressesR;
std::vector<int> agesR;
try { session() << "SELECT * FROM Person", into(lastNamesR), into(firstNamesR), into(addressesR), into(agesR), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (ages == agesR);
assertTrue (lastNames == lastNamesR);
assertTrue (firstNames == firstNamesR);
assertTrue (addresses == addressesR);
}
void SQLExecutor::complexTypeVector()
{
std::vector<Person> people;
people.push_back(Person("LN1", "FN1", "ADDR1", 1));
people.push_back(Person("LN2", "FN2", "ADDR2", 2));
try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(people), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
int count = 0;
try { session() << "SELECT COUNT(*) FROM Person", into(count), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (count == 2);
std::vector<Person> result;
try { session() << "SELECT * FROM Person", into(result), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (result == people);
}
void SQLExecutor::sharedPtrComplexTypeVector()
{
std::vector<Poco::SharedPtr<Person> > people;
people.push_back(new Person("LN1", "FN1", "ADDR1", 1));
people.push_back(new Person("LN2", "FN2", "ADDR2", 2));
try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(people), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
int count = 0;
try { session() << "SELECT COUNT(*) FROM Person", into(count), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (count == 2);
std::vector<Person> result;
try { session() << "SELECT * FROM Person", into(result), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (2 == result.size());
assertTrue (result[0] == *people[0]);
assertTrue (result[1] == *people[1]);
}
void SQLExecutor::autoPtrComplexTypeVector()
{
std::vector<Poco::AutoPtr<RefCountedPerson> > people;
people.push_back(new RefCountedPerson("LN1", "FN1", "ADDR1", 1));
people.push_back(new RefCountedPerson("LN2", "FN2", "ADDR2", 2));
try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(people), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
int count = 0;
try { session() << "SELECT COUNT(*) FROM Person", into(count), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (count == 2);
std::vector<Person> result;
try { session() << "SELECT * FROM Person", into(result), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (2 == result.size());
assertTrue (result[0].address == people[0]->address);
assertTrue (result[0].age == people[0]->age);
assertTrue (result[0].firstName == people[0]->firstName);
assertTrue (result[0].lastName == people[0]->lastName);
assertTrue (result[1].address == people[1]->address);
assertTrue (result[1].age == people[1]->age);
assertTrue (result[1].firstName == people[1]->firstName);
assertTrue (result[1].lastName == people[1]->lastName);
}
void SQLExecutor::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((session() << formatSQL("INSERT INTO Strings VALUES (?)"), use(str)));
try { session() << "SELECT COUNT(*) FROM Strings", into(count), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (count == 0);
try { stmt.execute(); }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
try { session() << "SELECT COUNT(*) FROM Strings", into(count), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (count == 4);
}
count = 0;
try { session() << "SELECT COUNT(*) FROM Strings", into(count), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (count == 4);
}
void SQLExecutor::insertEmptyVector()
{
std::vector<std::string> str;
try
{
session() << formatSQL("INSERT INTO Strings VALUES (?)"), use(str), now;
fail("empty collections should not work", __LINE__, __FILE__);
} catch (Poco::Exception&)
{
}
}
void SQLExecutor::simpleAccessList()
{
std::list<std::string> lastNames;
std::list<std::string> firstNames;
std::list<std::string> addresses;
std::list<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 { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(lastNames), use(firstNames), use(addresses), use(ages), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
try { session() << "SELECT COUNT(*) FROM Person", into(count), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (count == 2);
std::list<std::string> lastNamesR;
std::list<std::string> firstNamesR;
std::list<std::string> addressesR;
std::list<int> agesR;
try { session() << "SELECT * FROM Person", into(lastNamesR), into(firstNamesR), into(addressesR), into(agesR), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (ages == agesR);
assertTrue (lastNames == lastNamesR);
assertTrue (firstNames == firstNamesR);
assertTrue (addresses == addressesR);
}
void SQLExecutor::complexTypeList()
{
std::list<Person> people;
people.push_back(Person("LN1", "FN1", "ADDR1", 1));
people.push_back(Person("LN2", "FN2", "ADDR2", 2));
try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(people), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
int count = 0;
try { session() << "SELECT COUNT(*) FROM Person", into(count), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (count == 2);
std::list<Person> result;
try { session() << "SELECT * FROM Person", into(result), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (result == people);
}
void SQLExecutor::insertList()
{
std::list<std::string> str;
str.push_back("s1");
str.push_back("s2");
str.push_back("s3");
str.push_back("s3");
int count = 100;
{
Statement stmt((session() << formatSQL("INSERT INTO Strings VALUES (?)"), use(str)));
try { session() << "SELECT COUNT(*) FROM Strings", into(count), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (count == 0);
try { stmt.execute(); }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
try { session() << "SELECT COUNT(*) FROM Strings", into(count), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (count == 4);
}
count = 0;
try { session() << "SELECT COUNT(*) FROM Strings", into(count), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (count == 4);
}
void SQLExecutor::insertEmptyList()
{
std::list<std::string> str;
try
{
session() << formatSQL("INSERT INTO Strings VALUES (?)"), use(str), now;
fail("empty collections should not work");
} catch (Poco::Exception&)
{
}
}
void SQLExecutor::simpleAccessDeque()
{
std::deque<std::string> lastNames;
std::deque<std::string> firstNames;
std::deque<std::string> addresses;
std::deque<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 { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(lastNames), use(firstNames), use(addresses), use(ages), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
try { session() << "SELECT COUNT(*) FROM Person", into(count), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (count == 2);
std::deque<std::string> lastNamesR;
std::deque<std::string> firstNamesR;
std::deque<std::string> addressesR;
std::deque<int> agesR;
try { session() << "SELECT * FROM Person", into(lastNamesR), into(firstNamesR), into(addressesR), into(agesR), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (ages == agesR);
assertTrue (lastNames == lastNamesR);
assertTrue (firstNames == firstNamesR);
assertTrue (addresses == addressesR);
}
void SQLExecutor::complexTypeDeque()
{
std::deque<Person> people;
people.push_back(Person("LN1", "FN1", "ADDR1", 1));
people.push_back(Person("LN2", "FN2", "ADDR2", 2));
try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(people), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
int count = 0;
try { session() << "SELECT COUNT(*) FROM Person", into(count), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (count == 2);
std::deque<Person> result;
try { session() << "SELECT * FROM Person", into(result), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (result == people);
}
void SQLExecutor::insertDeque()
{
std::deque<std::string> str;
str.push_back("s1");
str.push_back("s2");
str.push_back("s3");
str.push_back("s3");
int count = 100;
{
Statement stmt((session() << formatSQL("INSERT INTO Strings VALUES (?)"), use(str)));
try { session() << "SELECT COUNT(*) FROM Strings", into(count), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (count == 0);
try { stmt.execute(); }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
try { session() << "SELECT COUNT(*) FROM Strings", into(count), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (count == 4);
}
count = 0;
try { session() << "SELECT COUNT(*) FROM Strings", into(count), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (count == 4);
}
void SQLExecutor::insertEmptyDeque()
{
std::deque<std::string> str;
try
{
session() << "INSERT INTO Strings VALUES (?)", use(str), now;
fail("empty collections should not work");
} catch (Poco::Exception&)
{
}
}
void SQLExecutor::affectedRows(const std::string& whereClause)
{
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 stmt1((session() << formatSQL("INSERT INTO Strings VALUES(?)"), use(str)));
session() << "SELECT COUNT(*) FROM Strings", into(count), now;
assertTrue (count == 0);
assertTrue (4 == stmt1.execute());
session() << "SELECT COUNT(*) FROM Strings", into(count), now;
assertTrue (count == 4);
Statement stmt2(session() << "UPDATE Strings SET str = 's4' WHERE str = 's3'");
assertTrue (2 == stmt2.execute());
Statement stmt3(session() << "DELETE FROM Strings WHERE str = 's1'");
assertTrue (1 == stmt3.execute());
std::string sql;
format(sql, "DELETE FROM Strings %s", whereClause);
Statement stmt4(session() << formatSQL(sql));
assertTrue (3 == stmt4.execute());
}
void SQLExecutor::insertSingleBulk()
{
int x = 0;
Statement stmt((session() << formatSQL("INSERT INTO Strings VALUES (?)"), use(x)));
for (x = 0; x < 100; ++x)
{
std::size_t i = stmt.execute();
assertTrue (1 == i);
}
int count = 0;
try { session() << "SELECT COUNT(*) FROM Strings", into(count), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (count == 100);
try { session() << "SELECT SUM(str) FROM Strings", into(count), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (count == ((0+99)*100/2));
}
void SQLExecutor::floats()
{
float data = 1.5f;
float ret = 0.0f;
try { session() << formatSQL("INSERT INTO Strings VALUES (?)"), use(data), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
int count = 0;
try { session() << "SELECT COUNT(*) FROM Strings", into(count), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (count == 1);
try { session() << "SELECT str FROM Strings", into(ret), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (ret == data);
}
void SQLExecutor::doubles()
{
double data = 1.5;
double ret = 0.0;
try { session() << formatSQL("INSERT INTO Strings VALUES (?)"), use(data), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
int count = 0;
try { session() << "SELECT COUNT(*) FROM Strings", into(count), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (count == 1);
try { session() << "SELECT str FROM Strings", into(ret), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (ret == data);
}
void SQLExecutor::uuids()
{
Poco::UUID data("49cf6461-9b62-4163-9659-5472ef73153d");
Poco::UUID ret;
try { session() << formatSQL("INSERT INTO Strings VALUES (?)"), use(data), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
int count = 0;
try { session() << "SELECT COUNT(*) FROM Strings", into(count), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (count == 1);
try { session() << "SELECT str FROM Strings", into(ret), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (ret == data);
}
void SQLExecutor::insertSingleBulkVec()
{
std::vector<int> data;
for (int x = 0; x < 100; ++x)
data.push_back(x);
Statement stmt((session() << formatSQL("INSERT INTO Strings VALUES (?)"), use(data)));
stmt.execute();
int count = 0;
try { session() << "SELECT COUNT(*) FROM Strings", into(count), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (count == 100);
try { session() << "SELECT SUM(str) FROM Strings", into(count), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (count == ((0+99)*100/2));
}
void SQLExecutor::limits()
{
std::vector<int> data;
for (int x = 0; x < 100; ++x)
{
data.push_back(x);
}
try { session() << formatSQL("INSERT INTO Strings VALUES (?)"), use(data), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
std::vector<int> retData;
try { session() << "SELECT * FROM Strings", into(retData), limit(50), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (retData.size() == 50);
for (int x = 0; x < 50; ++x)
{
assertTrue (data[x] == retData[x]);
}
}
void SQLExecutor::limitZero()
{
std::vector<int> data;
for (int x = 0; x < 100; ++x)
{
data.push_back(x);
}
try { session() << formatSQL("INSERT INTO Strings VALUES (?)"), use(data), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
std::vector<int> retData;
try { session() << "SELECT * FROM Strings", into(retData), limit(0), now; }// stupid test, but at least we shouldn't crash
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (retData.size() == 0);
}
void SQLExecutor::limitOnce()
{
std::vector<int> data;
for (int x = 0; x < 101; ++x)
{
data.push_back(x);
}
try { session() << formatSQL("INSERT INTO Strings VALUES (?)"), use(data), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
std::vector<int> retData;
Statement stmt = (session() << "SELECT * FROM Strings", into(retData), limit(50), now);
assertTrue (!stmt.done());
assertTrue (retData.size() == 50);
stmt.execute();
assertTrue (!stmt.done());
assertTrue (retData.size() == 100);
stmt.execute();
assertTrue (stmt.done());
assertTrue (retData.size() == 101);
for (int x = 0; x < 101; ++x)
{
assertTrue (data[x] == retData[x]);
}
}
void SQLExecutor::limitPrepare()
{
std::vector<int> data;
for (int x = 0; x < 100; ++x)
{
data.push_back(x);
}
try
{
Statement stmt = (session() << formatSQL("INSERT INTO Strings VALUES (?)"), use(data));
assertTrue (100 == stmt.execute());
}
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
std::vector<int> retData;
Statement stmt = (session() << "SELECT * FROM Strings", into(retData), limit(50));
assertTrue (retData.size() == 0);
assertTrue (!stmt.done());
try { stmt.execute(); }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (!stmt.done());
assertTrue (retData.size() == 50);
try { stmt.execute(); }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (stmt.done());
assertTrue (retData.size() == 100);
try { stmt.execute(); } // will restart execution! catch(DataException& ce)
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (!stmt.done());
assertTrue (retData.size() == 150);
for (int x = 0; x < 150; ++x)
{
assertTrue (data[x%100] == retData[x]);
}
}
void SQLExecutor::prepare()
{
std::vector<int> data;
for (int x = 0; x < 100; x += 2)
{
data.push_back(x);
}
{
Statement stmt((session() << formatSQL("INSERT INTO Strings VALUES (?)"), use(data)));
}
// stmt should not have been executed when destroyed
int count = 100;
try { session() << "SELECT COUNT(*) FROM Strings", into(count), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (count == 0);
}
void SQLExecutor::doBulkPerformance(Poco::UInt32 size)
{
std::vector<int> ints(size, 1);
std::vector<std::string> strings(size, "abc");
std::vector<double> floats(size, .5);
std::vector<DateTime> dateTimes(size);
Stopwatch sw;
try
{
sw.start();
session() << formatSQL("INSERT INTO MiscTest (First, Third, Fourth, Fifth) VALUES (?,?,?,?)"),
use(strings),
use(ints),
use(floats),
use(dateTimes), now;
sw.stop();
} catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
double time = sw.elapsed() / 1000.0;
try { session() << "DELETE FROM MiscTest", now; } catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
try
{
sw.restart();
session() << formatSQL("INSERT INTO MiscTest (First, Third, Fourth, Fifth) VALUES (?,?,?,?)"),
use(strings, bulk),
use(ints, bulk),
use(floats, bulk),
use(dateTimes, bulk), now;
sw.stop();
} catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
double bulkTime = sw.elapsed() / 1000.0;
double speedup;
if (0.0 == bulkTime)
{
if (0.0 == time) speedup = 1.0;
else speedup = time;
}
else
speedup = time / bulkTime;
std::cout << "INSERT => Size:" << size
<< ", Time: " << time
<< ", Bulk Time: " << bulkTime
<< " [ms], Speedup: " << speedup
<< 'x' << std::endl;
ints.clear();
strings.clear();
floats.clear();
dateTimes.clear();
try
{
sw.restart();
session() << "SELECT First, Third, Fourth, Fifth FROM MiscTest",
into(strings),
into(ints),
into(floats),
into(dateTimes),
now;
sw.stop();
} catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
time = sw.elapsed() / 1000.0;
assertTrue (ints.size() == size);
ints.clear();
strings.clear();
floats.clear();
dateTimes.clear();
try
{
sw.restart();
session() << "SELECT First, Third, Fourth, Fifth FROM MiscTest",
into(strings, bulk(size)),
into(ints, bulk(size)),
into(floats, bulk(size)),
into(dateTimes, bulk(size)),
now;
sw.stop();
} catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
bulkTime = sw.elapsed() / 1000.0;
assertTrue (ints.size() == size);
if (0.0 == bulkTime)
{
if (0.0 == time) speedup = 1.0;
else speedup = time;
}
else
speedup = time / bulkTime;
std::cout << "SELECT => Size:" << size
<< ", Time: " << time
<< ", Bulk Time: " << bulkTime
<< " [ms], Speedup: " << speedup
<< 'x' << std::endl;
}
void SQLExecutor::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 { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(lastNames), use(firstNames), use(addresses), use(ages), now; } catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (count == 2);
std::set<std::string> lastNamesR;
std::set<std::string> firstNamesR;
std::set<std::string> addressesR;
std::set<int> agesR;
try { session() << "SELECT * FROM Person", into(lastNamesR), into(firstNamesR), into(addressesR), into(agesR), now; } catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (ages == agesR);
assertTrue (lastNames == lastNamesR);
assertTrue (firstNames == firstNamesR);
assertTrue (addresses == addressesR);
}
void SQLExecutor::setComplex()
{
std::set<Person> people;
people.insert(Person("LN1", "FN1", "ADDR1", 1));
people.insert(Person("LN2", "FN2", "ADDR2", 2));
try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(people), now; } catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
int count = 0;
try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (count == 2);
std::set<Person> result;
try { session() << "SELECT * FROM Person", into(result), now; } catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (result == people);
}
void SQLExecutor::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 { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(people), now; } catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
int count = 0;
try { session() << "SELECT COUNT(*) FROM Person", into(count), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (count == 5);
std::set<Person> result;
try { session() << "SELECT * FROM Person", into(result), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (result.size() == 2);
assertTrue (*result.begin() == p1);
assertTrue (*++result.begin() == p2);
}
void SQLExecutor::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 { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(lastNames), use(firstNames), use(addresses), use(ages), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
try { session() << "SELECT COUNT(*) FROM Person", into(count), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (count == 2);
std::multiset<std::string> lastNamesR;
std::multiset<std::string> firstNamesR;
std::multiset<std::string> addressesR;
std::multiset<int> agesR;
try { session() << "SELECT * FROM Person", into(lastNamesR), into(firstNamesR), into(addressesR), into(agesR), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (ages.size() == agesR.size());
assertTrue (lastNames.size() == lastNamesR.size());
assertTrue (firstNames.size() == firstNamesR.size());
assertTrue (addresses.size() == addressesR.size());
}
void SQLExecutor::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 { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(people), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
int count = 0;
try { session() << "SELECT COUNT(*) FROM Person", into(count), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (count == 5);
std::multiset<Person> result;
try { session() << "SELECT * FROM Person", into(result), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (result.size() == people.size());
}
void SQLExecutor::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 { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(people), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
int count = 0;
try { session() << "SELECT COUNT(*) FROM Person", into(count), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (count == 2);
std::map<std::string, Person> result;
try { session() << "SELECT * FROM Person", into(result), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (result == people);
}
void SQLExecutor::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 { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(people), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
int count = 0;
try { session() << "SELECT COUNT(*) FROM Person", into(count), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (count == 5);
std::map<std::string, Person> result;
try { session() << "SELECT * FROM Person", into(result), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (result.size() == 2);
}
void SQLExecutor::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 { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(people), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
int count = 0;
try { session() << "SELECT COUNT(*) FROM Person", into(count), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (count == 5);
std::multimap<std::string, Person> result;
try { session() << "SELECT * FROM Person", into(result), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (result.size() == people.size());
}
void SQLExecutor::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("LN2", p2));
try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(people), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
int count = 0;
try { session() << "SELECT COUNT(*) FROM Person", into(count), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (count == 2);
Person result;
try { session() << "SELECT * FROM Person ORDER BY LastName", into(result), limit(1), now; }// will return 1 object into one single result
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (result == p1);
}
void SQLExecutor::selectIntoSingleStep()
{
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("LN2", p2));
try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(people), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
int count = 0;
try { session() << "SELECT COUNT(*) FROM Person", into(count), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (count == 2);
Person result;
Statement stmt = (session() << "SELECT * FROM Person", into(result), limit(1));
stmt.execute();
assertTrue (result == p1);
assertTrue (!stmt.done());
stmt.execute();
assertTrue (result == p2);
assertTrue (stmt.done());
}
void SQLExecutor::selectIntoSingleFail()
{
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("LN2", p2));
try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(people), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
int count = 0;
try { session() << "SELECT COUNT(*) FROM Person", into(count), limit(2, true), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (count == 2);
Person result;
try
{
session() << "SELECT * FROM Person", into(result), limit(1, true), now; // will fail now
fail("hardLimit is set: must fail", __LINE__, __FILE__);
} catch(Poco::Data::LimitException&)
{
}
}
void SQLExecutor::lowerLimitOk()
{
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));
try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(people), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
int count = 0;
try { session() << "SELECT COUNT(*) FROM Person", into(count), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (count == 2);
Person result;
try
{
session() << "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", __LINE__, __FILE__);
} catch(Poco::Exception&)
{
}
}
void SQLExecutor::singleSelect()
{
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));
try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(people), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
int count = 0;
try { session() << "SELECT COUNT(*) FROM Person", into(count), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (count == 2);
Person result;
Statement stmt = (session() << "SELECT * FROM Person", into(result), limit(1));
stmt.execute();
assertTrue (result == p1);
assertTrue (!stmt.done());
stmt.execute();
assertTrue (result == p2);
assertTrue (stmt.done());
}
void SQLExecutor::lowerLimitFail()
{
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));
try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(people), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
int count = 0;
try { session() << "SELECT COUNT(*) FROM Person", into(count), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (count == 2);
Person result;
try
{
session() << "SELECT * FROM Person", into(result), lowerLimit(3), now; // will fail
fail("should fail. not enough data", __LINE__, __FILE__);
} catch(Poco::Exception&)
{
}
}
void SQLExecutor::combinedLimits()
{
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));
try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(people), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
int count = 0;
try { session() << "SELECT COUNT(*) FROM Person", into(count), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (count == 2);
std::vector <Person> result;
try { session() << "SELECT * FROM Person", into(result), lowerLimit(2), upperLimit(2), now; }// will return 2 objects
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (result.size() == 2);
assertTrue (result[0] == p1);
assertTrue (result[1] == p2);
}
void SQLExecutor::ranges()
{
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));
try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(people), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
int count = 0;
try { session() << "SELECT COUNT(*) FROM Person", into(count), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (count == 2);
std::vector <Person> result;
try { session() << "SELECT * FROM Person", into(result), range(2, 2), now; }// will return 2 objects
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (result.size() == 2);
assertTrue (result[0] == p1);
assertTrue (result[1] == p2);
}
void SQLExecutor::combinedIllegalLimits()
{
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));
try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(people), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
int count = 0;
try { session() << "SELECT COUNT(*) FROM Person", into(count), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (count == 2);
Person result;
try
{
session() << "SELECT * FROM Person", into(result), lowerLimit(3), upperLimit(2), now;
fail("lower > upper is not allowed", __LINE__, __FILE__);
} catch(LimitException&)
{
}
}
void SQLExecutor::illegalRange()
{
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));
try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(people), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
int count = 0;
try { session() << "SELECT COUNT(*) FROM Person", into(count), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (count == 2);
Person result;
try
{
session() << "SELECT * FROM Person", into(result), range(3, 2), now;
fail("lower > upper is not allowed", __LINE__, __FILE__);
} catch(LimitException&)
{
}
}
void SQLExecutor::emptyDB()
{
int count = 0;
try { session() << "SELECT COUNT(*) FROM Person", into(count), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (count == 0);
Person result;
Statement stmt = (session() << "SELECT * FROM Person", into(result), limit(1));
stmt.execute();
assertTrue (result.firstName.empty());
assertTrue (stmt.done());
}
void SQLExecutor::blob(int bigSize, const std::string& blobPlaceholder)
{
std::string lastName("lastname");
std::string firstName("firstname");
std::string address("Address");
CLOB img("0123456789", 10);
int count = 0;
try { session() << formatSQL(format("INSERT INTO Person VALUES (?,?,?,%s)", blobPlaceholder)),
use(lastName), use(firstName), use(address), use(img), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
try { session() << "SELECT COUNT(*) FROM Person", into(count), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (count == 1);
CLOB res;
assertTrue (res.size() == 0);
try { session() << "SELECT Image FROM Person", into(res), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (res == img);
CLOB big;
std::vector<char> v(bigSize, 'x');
big.assignRaw(&v[0], v.size());
assertTrue (big.size() == bigSize);
try { session() << "DELETE FROM Person", now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
try
{
session() << formatSQL(format("INSERT INTO Person VALUES (?,?,?,%s)", blobPlaceholder)),
use(lastName), use(firstName), use(address), use(big), now;
}
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
// sometimes throws (intentionally, caught in caller)
session() << "SELECT Image FROM Person", into(res), now;
// when it doesn't throw, this must be true
assertTrue (res == big);
}
void SQLExecutor::blobStmt()
{
std::string lastName("lastname");
std::string firstName("firstname");
std::string address("Address");
CLOB blob("0123456789", 10);
int count = 0;
Statement ins = (session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(lastName), use(firstName), use(address), use(blob));
ins.execute();
try { session() << "SELECT COUNT(*) FROM Person", into(count), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (count == 1);
CLOB res;
poco_assert (res.size() == 0);
Statement stmt = (session() << "SELECT Image FROM Person", into(res));
try { stmt.execute(); }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
poco_assert (res == blob);
}
void SQLExecutor::recordSet()
{
std::string lastName("lastname");
std::string firstName("firstname");
std::string address("Address");
DateTime born(1965, 6, 18, 5, 35, 1);
DateTime born2(1991, 6, 18, 14, 35, 1);
try
{
{
Statement stmt = (session() << "SELECT COUNT(*) AS row_count FROM Person", now);
RecordSet rset(stmt);
assertTrue (rset.rowCount() == 1);
assertTrue (rset["row_count"].convert<int>() == 0);
}
{
Statement stmt = (session() <<
formatSQL("INSERT INTO Person VALUES (?,?,?,?)"),
use(lastName), use(firstName), use(address), use(born), now);
RecordSet rset(stmt);
assertTrue (rset.rowCount() == 0);
assertTrue (rset.affectedRowCount() == 1);
}
{
Statement stmt = (session() << "SELECT COUNT(*) AS row_count FROM Person", now);
RecordSet rset(stmt);
assertTrue (rset.rowCount() == 1);
assertTrue (rset["row_count"].convert<int>() == 1);
}
{
Statement stmt = (session() << "SELECT Born FROM Person", now);
RecordSet rset(stmt);
assertTrue (rset.rowCount() == 1);
assertTrue (rset["Born"].convert<DateTime>() == born);
}
{
Statement stmt = (session() <<
formatSQL("DELETE FROM Person WHERE born = ?"), use(born), now);
RecordSet rset(stmt);
assertTrue (rset.rowCount() == 0);
assertTrue (rset.affectedRowCount() == 1);
}
{
Statement stmt = (session() <<
formatSQL("INSERT INTO Person VALUES (?,?,?,?)"),
use(lastName), use(firstName), use(address), use(born), now);
RecordSet rset(stmt);
assertTrue (rset.rowCount() == 0);
assertTrue (rset.affectedRowCount() == 1);
}
{
Statement stmt = (session() <<
formatSQL("INSERT INTO Person VALUES (?,?,?,?)"),
use(lastName), use(firstName), use(address), use(born2), now);
RecordSet rset(stmt);
assertTrue (rset.rowCount() == 0);
assertTrue (rset.affectedRowCount() == 1);
}
{
Statement stmt = (session() << "SELECT COUNT(*) AS row_count FROM Person", now);
RecordSet rset(stmt);
assertTrue (rset.rowCount() == 1);
assertTrue (rset["row_count"].convert<int>() == 2);
}
{
Statement stmt = (session() << "SELECT Born FROM Person ORDER BY Born DESC", now);
RecordSet rset(stmt);
assertTrue (rset.rowCount() == 2);
assertTrue (rset["Born"].convert<DateTime>() == born2);
rset.moveNext();
assertTrue (rset["Born"].convert<DateTime>() == born);
rset.moveFirst();
assertTrue (rset["Born"].convert<DateTime>() == born2);
rset.moveLast();
assertTrue (rset["Born"].convert<DateTime>() == born);
}
{
Statement stmt = (session() << "DELETE FROM Person", now);
RecordSet rset(stmt);
assertTrue (rset.rowCount() == 0);
assertTrue (rset.affectedRowCount() == 2);
}
} catch (ConnectionFailedException& ce){ std::cout << ce.displayText() << std::endl; failmsg (__func__); }
}
void SQLExecutor::dateTime()
{
std::string lastName("lastname");
std::string firstName("firstname");
std::string address("Address");
DateTime born(1965, 6, 18, 5, 35, 1);
int count = 0;
try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(lastName), use(firstName), use(address), use(born), now; } catch (ConnectionFailedException& ce){ std::cout << ce.displayText() << std::endl; failmsg (__func__); }
try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } catch (ConnectionFailedException& ce){ std::cout << ce.displayText() << std::endl; failmsg (__func__); }
assertTrue (count == 1);
DateTime res;
try { session() << "SELECT Born FROM Person", into(res), now; } catch (ConnectionFailedException& ce){ std::cout << ce.displayText() << std::endl; failmsg (__func__); }
assertTrue (res == born);
Statement stmt = (session() << "SELECT Born FROM Person", now);
RecordSet rset(stmt);
res = rset["Born"].convert<DateTime>();
assertTrue (res == born);
}
void SQLExecutor::date()
{
std::string lastName("lastname");
std::string firstName("firstname");
std::string address("Address");
Date bornDate(1965, 6, 18);
int count = 0;
try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"),
use(lastName),
use(firstName),
use(address),
use(bornDate),
now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
try { session() << "SELECT COUNT(*) FROM Person", into(count), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (count == 1);
Date d;
Time t;
try { session() << "SELECT BornDate FROM Person", into(d), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (d == bornDate);
Statement stmt = (session() << "SELECT BornDate FROM Person", now);
RecordSet rset(stmt);
DateTime dt1 = rset["BornDate"].convert<DateTime>();
Date d2(dt1);
assertTrue (d2 == bornDate);
}
void SQLExecutor::time()
{
std::string lastName("lastname");
std::string firstName("firstname");
std::string address("Address");
Time bornTime (5, 35, 1);
int count = 0;
try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"),
use(lastName),
use(firstName),
use(address),
use(bornTime),
now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
try { session() << "SELECT COUNT(*) FROM Person", into(count), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (count == 1);
Date d;
Time t;
try { session() << "SELECT BornTime FROM Person", into(t), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (t == bornTime);
Statement stmt = (session() << "SELECT BornTime FROM Person", now);
RecordSet rset(stmt);
DateTime dt2 = rset["BornTime"].convert<DateTime>();
Time t2(dt2);
assertTrue (t2 == bornTime);
}
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;
TupleType t(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19);
try { session() << formatSQL("INSERT INTO Tuples VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"), use(t), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
TupleType ret(-10,-11,-12,-13,-14,-15,-16,-17,-18,-19);
assertTrue (ret != t);
try { session() << "SELECT * FROM Tuples", into(ret), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (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;
TupleType t(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19);
Tuple<int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int>
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<TupleType> v;
v.push_back(t);
v.push_back(t10);
v.push_back(t100);
try { session() << formatSQL("INSERT INTO Tuples VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"), use(v), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
int count = 0;
try { session() << "SELECT COUNT(*) FROM Tuples", into(count), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (v.size() == count);
std::vector<Tuple<int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int> > ret;
try { session() << "SELECT * FROM Tuples", into(ret), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertTrue (ret == v);
}
void SQLExecutor::internalExtraction()
{
std::vector<Tuple<int, double, std::string> > v;
v.push_back(Tuple<int, double, std::string>(1, 1.5f, "3"));
v.push_back(Tuple<int, double, std::string>(2, 2.5f, "4"));
v.push_back(Tuple<int, double, std::string>(3, 3.5f, "5"));
v.push_back(Tuple<int, double, std::string>(4, 4.5f, "6"));
try { session() << formatSQL("INSERT INTO Vectors VALUES (?,?,?)"), use(v), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
try
{
Statement stmt = (session() << "SELECT * FROM Vectors", now);
RecordSet rset(stmt);
assertTrue (3 == rset.columnCount());
assertTrue (4 == rset.rowCount());
int curVal = 3;
do
{
assertTrue (rset["str0"] == curVal);
++curVal;
} while (rset.moveNext());
rset.moveFirst();
assertTrue (rset["str0"] == "3");
rset.moveLast();
assertTrue (rset["str0"] == "6");
RecordSet rset2(rset);
assertTrue (3 == rset2.columnCount());
assertTrue (4 == rset2.rowCount());
try
{
int i = rset.value<int>(0,0);
assertTrue (1 == i);
}
catch(BadCastException&)
{
Poco::Int64 l = rset.value<Poco::Int64>(0,0);
assertTrue (1 == l);
}
std::string s = rset.value(0,0).convert<std::string>();
assertTrue ("1" == s);
try
{
int a = rset.value<int>(0,2);
assertTrue (3 == a);
}
catch(BadCastException&)
{
Poco::Int64 l = rset.value<Poco::Int64>(0,2);
assertTrue (3 == l);
}
try
{
double d = rset.value<double>(1,1);
assertTrue (2.5 == d);
}
catch (BadCastException&)
{
float f = rset.value<float>(1,1);
assertTrue (2.5 == f);
}
try
{
s = rset.value<std::string>(2, 2);
}
catch (BadCastException&)
{
UTF16String us = rset.value<Poco::UTF16String>(2, 2);
Poco::UnicodeConverter::convert(us, s);
}
assertTrue ("5" == s);
int i = rset.value("str0", 2);
assertTrue (5 == i);
try
{
const Column<std::deque<int>>& col = rset.column<std::deque<int> >(0);
Column<std::deque<int>>::Iterator it = col.begin();
Column<std::deque<int>>::Iterator end = col.end();
for (int j = 1; it != end; ++it, ++j)
assertTrue (*it == j);
}
catch(BadCastException&)
{
const Column<std::deque<Poco::Int64>>& col = rset.column<std::deque<Poco::Int64> >(0);
Column<std::deque<Poco::Int64>>::Iterator it = col.begin();
Column<std::deque<Poco::Int64>>::Iterator end = col.end();
for (Poco::Int64 l = 1; it != end; ++it, ++l)
assertTrue (*it == l);
}
rset = (session() << "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<int>(0,0);
assertTrue (4 == i);
}
catch(BadCastException&)
{
try
{
//this is for Oracle
double i = rset.value<double>(0,0);
assertTrue (4 == int(i));
}
catch(BadCastException&)
{
//this is for PostgreSQL
Poco::Int64 big = rset.value<Poco::Int64>(0,0);
assertTrue (4 == big);
}
}
s = rset.value("cnt", 0).convert<std::string>();
assertTrue ("4" == s);
try { rset.column<std::deque<int> >(100); fail ("must fail"); }
catch (RangeException&) { }
try { rset.value<std::string>(0,0); fail ("must fail"); }
catch (BadCastException&) { }
stmt = (session() << "DELETE FROM Vectors", now);
rset = stmt;
try { rset.column<std::deque<int> >(0); fail ("must fail"); }
catch (RangeException&) { }
}
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
catch(Exception& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
}
void SQLExecutor::filter(const std::string& query, const std::string& intFldName)
{
std::vector<Tuple<int, double, std::string> > v;
v.push_back(Tuple<int, double, std::string>(1, 1.5f, "3"));
v.push_back(Tuple<int, double, std::string>(2, 2.5f, "4"));
v.push_back(Tuple<int, double, std::string>(3, 3.5f, "5"));
v.push_back(Tuple<int, double, std::string>(4, 4.5f, "6"));
try { session() << formatSQL("INSERT INTO Vectors VALUES (?,?,?)"), use(v), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
try
{
Statement stmt = (session() << query, now);
RecordSet rset(stmt);
assertTrue (rset.getTotalRowCount() == 4);
RowFilter::Ptr pRF = new RowFilter(&rset);
assertTrue (pRF->isEmpty());
pRF->add(intFldName, RowFilter::VALUE_EQUAL, 1);
assertTrue (!pRF->isEmpty());
Var da;
try
{
da = rset.value(0, 1);
fail ("must fail");
} catch (InvalidAccessException&)
{
da = rset.value(0, 1, false);
assertTrue (2 == da);
da = rset.value(0, 0);
assertTrue (1 == da);
}
assertTrue (rset.rowCount() == 1);
assertTrue (rset.moveFirst());
assertTrue (1 == rset[intFldName]);
assertTrue (!rset.moveNext());
pRF->add("flt0", RowFilter::VALUE_LESS_THAN_OR_EQUAL, 3.5f);
assertTrue (rset.rowCount() == 3);
assertTrue (rset.moveNext());
assertTrue (2.5 == rset["flt0"]);
assertTrue (rset.moveNext());
assertTrue (3.5 == rset["flt0"]);
assertTrue (!rset.moveNext());
pRF->add("str0", RowFilter::VALUE_EQUAL, 6);
assertTrue (rset.rowCount() == 4);
assertTrue (rset.moveLast());
assertTrue ("6" == rset["str0"]);
pRF->remove("flt0");
assertTrue (rset.rowCount() == 2);
assertTrue (rset.moveFirst());
assertTrue ("3" == rset["str0"]);
assertTrue (rset.moveNext());
assertTrue ("6" == rset["str0"]);
pRF->remove(intFldName);
pRF->remove("str0");
assertTrue (pRF->isEmpty());
pRF->add("str0", "!=", 3);
assertTrue (rset.rowCount() == 3);
RowFilter::Ptr pRF1 = new RowFilter(pRF, RowFilter::OP_AND);
pRF1->add(intFldName, "==", 2);
assertTrue (rset.rowCount() == 1);
pRF1->add(intFldName, "<", 2);
assertTrue (rset.rowCount() == 1);
pRF1->add(intFldName, ">", 3);
assertTrue (rset.rowCount() == 2);
pRF->removeFilter(pRF1);
pRF->remove("str0");
assertTrue (pRF->isEmpty());
assertTrue (rset.rowCount() == 4);
}
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
}
void SQLExecutor::nullBulk(const std::string& blobPlaceholder)
{
const int sz = 10;
{
std::vector<NullData> lastName(sz, null);
std::vector<NullData> firstName(sz, null);
std::vector<NullData> address(sz, null);
std::vector<NullData> blob(sz, null);
try
{
session() << Poco::format("INSERT INTO Person VALUES (?,?,?,%s)", blobPlaceholder),
use(lastName, bulk), use(firstName, bulk), use(address, bulk), use(blob, bulk), now;
}
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
}
{
std::vector<Nullable<std::string>> lastName(sz, null);
std::vector<Nullable<std::string>> firstName(sz, null);
std::vector<Nullable<std::string>> address(sz, null);
std::vector<Nullable<Poco::Data::CLOB>> blob(sz, null);
try
{
session() << "SELECT * FROM Person",
into(lastName), into(firstName), into(address), into(blob), now;
}
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertEqual (sz, lastName.size());
assertEqual (sz, firstName.size());
assertEqual (sz, address.size());
assertEqual (sz, blob.size());
for (int i = 0; i < sz; ++i)
{
assertTrue (lastName[i].isNull());
assertTrue (firstName[i].isNull());
assertTrue (address[i].isNull());
assertTrue (blob[i].isNull());
}
}
session() << "DELETE FROM Person", now;
{
std::vector<Nullable<std::string>> lastName(10, null);
std::vector<Nullable<std::string>> firstName(10, null);
std::vector<Nullable<std::string>> address(10, null);
std::vector<Nullable<BLOB>> blob(10, null);
for (int i = 0; i < sz; ++i)
{
std::ostringstream ostr;
ostr << "abc" << i;
lastName[i] = ostr.str();
if (i % 2)
{
ostr.str(""s);
ostr << "def" << i;
firstName[i] = ostr.str();
ostr.str(""s);
ostr << "ghi" << i;
address[i] = ostr.str();
ostr.str(""s);
ostr << "jkl" << i;
blob[i] = BLOB((unsigned char*)ostr.str().data(), ostr.str().length());
}
}
try
{
session() << Poco::format("INSERT INTO Person VALUES (?,?,?,%s)", blobPlaceholder),
use(lastName), use(firstName), use(address), use(blob), now;
}
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
lastName.clear();
firstName.clear();
address.clear();
blob.clear();
assertEqual (0, lastName.size());
assertEqual (0, firstName.size());
assertEqual (0, address.size());
assertEqual (0, blob.size());
try
{
session() << "SELECT * FROM Person ORDER BY lastName",
into(lastName), into(firstName), into(address), into(blob), now;
}
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
assertEqual (10, lastName.size());
assertEqual (10, firstName.size());
assertEqual (10, address.size());
assertEqual (10, blob.size());
for (int i = 0; i < sz; ++i)
{
assertFalse(lastName[i].isNull());
std::ostringstream ostr;
ostr << "abc" << i;
assertEqual(ostr.str(), lastName[i].value());
if (i % 2)
{
assertFalse(firstName[i].isNull());
ostr.str(""s);
ostr << "def" << i;
assertEqual(ostr.str(), firstName[i].value());
assertFalse(address[i].isNull());
ostr.str(""s);
ostr << "ghi" << i;
assertEqual(ostr.str(), address[i].value());
assertFalse(blob[i].isNull());
ostr.str(""s);
ostr << "jkl" << i;
assertTrue(BLOB((unsigned char*)ostr.str().data(), ostr.str().length()) == blob[i].value());
}
else
{
assertTrue(firstName[i].isNull());
assertTrue(address[i].isNull());
assertTrue(blob[i].isNull());
}
}
}
}
void SQLExecutor::internalBulkExtraction()
{
int size = 100;
std::vector<std::string> lastName(size);
std::vector<std::string> firstName(size);
std::vector<std::string> address(size);
std::vector<int> age(size);
for (int i = 0; i < size; ++i)
{
lastName[i] = "LN" + NumberFormatter::format(i);
firstName[i] = "FN" + NumberFormatter::format(i);
address[i] = "Addr" + NumberFormatter::format(i);
age[i] = i;
}
try
{
session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"),
use(lastName, bulk),
use(firstName, bulk),
use(address, bulk),
use(age, bulk),
now;
}
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
try
{
Statement stmt = (session() << "SELECT * FROM Person", bulk(size), now);
RecordSet rset(stmt);
assertTrue (size == rset.rowCount());
assertTrue ("LN0" == rset["LastName"]);
assertTrue (0 == rset["Age"]);
rset.moveNext();
assertTrue ("LN1" == rset["LastName"]);
assertTrue (1 == rset["Age"]);
rset.moveLast();
assertTrue (std::string("LN") + NumberFormatter::format(size - 1) == rset["LastName"]);
assertTrue (size - 1 == rset["Age"]);
}
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
try
{
Statement stmt = (session() << "SELECT * FROM Person", limit(size), bulk, now);
RecordSet rset(stmt);
assertTrue (size == rset.rowCount());
assertTrue ("LN0" == rset["LastName"]);
assertTrue (0 == rset["Age"]);
rset.moveLast();
assertTrue (std::string("LN") + NumberFormatter::format(size - 1) == rset["LastName"]);
assertTrue (size - 1 == rset["Age"]);
}
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
}
void SQLExecutor::internalBulkExtractionUTF16()
{
int size = 100;
std::vector<UTF16String> lastName(size);
std::vector<UTF16String> firstName(size);
std::vector<UTF16String> address(size);
std::vector<int> age(size);
for (int i = 0; i < size; ++i)
{
lastName[i] = Poco::UnicodeConverter::to<UTF16String>("LN" + NumberFormatter::format(i));
firstName[i] = Poco::UnicodeConverter::to<UTF16String>("FN" + NumberFormatter::format(i));
address[i] = Poco::UnicodeConverter::to<UTF16String>("Addr" + NumberFormatter::format(i));
age[i] = i;
}
try
{
session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"),
use(lastName, bulk),
use(firstName, bulk),
use(address, bulk),
use(age, bulk),
now;
} catch (ConnectionFailedException& ce){ std::cout << ce.displayText() << std::endl; failmsg (__func__); }
try
{
Statement stmt = (session() << "SELECT * FROM Person", bulk(size), now);
RecordSet rset(stmt);
assertTrue (size == rset.rowCount());
assertTrue (Poco::UnicodeConverter::to<UTF16String>("LN0") == rset["LastName"]);
assertTrue (0 == rset["Age"]);
rset.moveNext();
assertTrue (Poco::UnicodeConverter::to<UTF16String>("LN1") == rset["LastName"]);
assertTrue (1 == rset["Age"]);
rset.moveLast();
assertTrue (std::string("LN") + NumberFormatter::format(size - 1) == rset["LastName"]);
assertTrue (size - 1 == rset["Age"]);
} catch (ConnectionFailedException& ce){ std::cout << ce.displayText() << std::endl; failmsg (__func__); }
try
{
Statement stmt = (session() << "SELECT * FROM Person", limit(size), bulk, now);
RecordSet rset(stmt);
assertTrue (size == rset.rowCount());
assertTrue ("LN0" == rset["LastName"]);
assertTrue (0 == rset["Age"]);
rset.moveLast();
assertTrue (std::string("LN") + NumberFormatter::format(size - 1) == rset["LastName"]);
assertTrue (size - 1 == rset["Age"]);
} catch (ConnectionFailedException& ce){ std::cout << ce.displayText() << std::endl; failmsg (__func__); }
}
void SQLExecutor::internalStorageType()
{
std::vector<Statement::Manipulator> manips;
manips.push_back(list);
manips.push_back(deque);
manips.push_back(vector);
std::vector<Tuple<int, double, std::string> > v;
v.push_back(Tuple<int, double, std::string>(1, 1.5f, "3"));
v.push_back(Tuple<int, double, std::string>(2, 2.5f, "4"));
v.push_back(Tuple<int, double, std::string>(3, 3.5f, "5"));
v.push_back(Tuple<int, double, std::string>(4, 4.5f, "6"));
try { session() << formatSQL("INSERT INTO Vectors VALUES (?,?,?)"), use(v), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
try
{
std::vector<Statement::Manipulator>::iterator it = manips.begin();
std::vector<Statement::Manipulator>::iterator end = manips.end();
for (; it != end; ++it)
{
Statement stmt = (session() << "SELECT * FROM Vectors", *it, now);
RecordSet rset(stmt);
assertTrue (3 == rset.columnCount());
assertTrue (4 == rset.rowCount());
int curVal = 3;
do
{
assertTrue (rset["str0"] == curVal);
++curVal;
} while (rset.moveNext());
rset.moveFirst();
assertTrue (rset["str0"] == "3");
rset.moveLast();
assertTrue (rset["str0"] == "6");
try
{
stmt = (session() << "SELECT * FROM Vectors", now, *it);
fail ("must fail");
}
catch(InvalidAccessException&){}
try
{
stmt = (session() << "SELECT * FROM Vectors", into(v), now, *it);
fail ("must fail");
}
catch(InvalidAccessException&){}
try
{
stmt = (session() << "SELECT * FROM Vectors", into(v), *it, now);
fail ("must fail");
}
catch(InvalidAccessException&){}
}
}
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
}
void SQLExecutor::nulls()
{
try { session() << formatSQL("INSERT INTO NullTest (i,r,v) VALUES (?,?,?)"), use(null), use(null), use(null), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
RecordSet rs(session(), "SELECT * FROM NullTest");
assertTrue (1 == rs.rowCount());
rs.moveFirst();
assertTrue (rs.isNull("i"));
assertTrue (rs["i"] != 0);
assertTrue (rs.isNull("r"));
assertTrue (rs.isNull("v"));
assertTrue (rs["v"] != "");
assertTrue (rs.nvl<int>("i") == 0);
assertTrue (rs.nvl("i", -1) == -1);
assertTrue (rs.nvl<double>("r") == double());
assertTrue (rs.nvl("r", -1.5) == -1.5);
assertTrue (rs.nvl<std::string>("v") == "");
assertTrue (rs.nvl("v", "123") == "123");
try { session() << "DELETE FROM NullTest", now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
int i = 1;
double f = 1.5;
std::string s = "123";
try { session() << formatSQL("INSERT INTO NullTest (i, r, v) VALUES (?,?,?)"), use(i), use(f), use(s), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
rs = (session() << "SELECT * FROM NullTest", now);
assertTrue (1 == rs.rowCount());
rs.moveFirst();
assertTrue (!rs.isNull("i"));
assertTrue (rs["i"] == 1);
assertTrue (!rs.isNull("v"));
assertTrue (!rs.isNull("r"));
assertTrue (rs["v"] == "123");
assertTrue (rs.nvl<int>("i") == 1);
assertTrue (rs.nvl("i", -1) == 1);
assertTrue (rs.nvl<double>("r") == 1.5);
assertTrue (rs.nvl("r", -1.5) == 1.5);
assertTrue (rs.nvl<std::string>("v") == "123");
assertTrue (rs.nvl("v", "456") == "123");
try { session() << "UPDATE NullTest SET v = ? WHERE i = ?", use(null), use(i), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
i = 2;
f = 3.4;
try { session() << formatSQL("INSERT INTO NullTest (i, r, v) VALUES (?,?,?)"), use(i), use(null), use(null), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
rs = (session() << "SELECT i, r, v FROM NullTest ORDER BY i ASC", now);
assertTrue (2 == rs.rowCount());
rs.moveFirst();
assertTrue (!rs.isNull("i"));
assertTrue (rs["i"] == 1);
assertTrue (!rs.isNull("r"));
assertTrue (rs.isNull("v"));
assertTrue (rs["v"] != "");
assertTrue (rs.moveNext());
assertTrue (!rs.isNull("i"));
assertTrue (rs["i"] == 2);
assertTrue (rs.isNull("r"));
assertTrue (rs.isNull("v"));
assertTrue (rs["v"] != "");
try { session() << "DELETE FROM NullTest", now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
try { session() << formatSQL("INSERT INTO NullTest (v) VALUES (?)"), bind(""), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
bool esin = session().getFeature("emptyStringIsNull");
session().setFeature("emptyStringIsNull", true);
try
{
session().setFeature("forceEmptyString", true);
fail ("must fail");
} catch (InvalidAccessException&) { }
bool fes = session().getFeature("forceEmptyString");
session().setFeature("forceEmptyString", false);
RecordSet rs1(session(), "SELECT v FROM NullTest");
assertTrue (1 == rs1.rowCount());
rs1.moveFirst();
assertTrue (rs1.isNull("v"));
assertTrue (!(rs["v"] == ""));
session().setFeature("emptyStringIsNull", false);
session().setFeature("forceEmptyString", true);
RecordSet rs2(session(), "SELECT v FROM NullTest");
assertTrue (1 == rs2.rowCount());
rs2.moveFirst();
assertTrue (!rs2.isNull("v"));
assertTrue ((rs2["v"] == ""));
try
{
session().setFeature("emptyStringIsNull", true);
fail ("must fail");
} catch (InvalidAccessException&) { }
session().setFeature("emptyStringIsNull", esin);
session().setFeature("forceEmptyString", fes);
}
void SQLExecutor::rowIterator()
{
std::vector<Tuple<int, double, std::string> > v;
v.push_back(Tuple<int, double, std::string>(1, 1.5f, "3"));
v.push_back(Tuple<int, double, std::string>(2, 2.5f, "4"));
v.push_back(Tuple<int, double, std::string>(3, 3.5f, "5"));
v.push_back(Tuple<int, double, std::string>(4, 4.5f, "6"));
try { session() << "DELETE FROM Vectors", now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
RecordSet rset0(session(), "SELECT * FROM Vectors");
assertTrue (rset0.begin() == rset0.end());
try { session() << formatSQL("INSERT INTO Vectors VALUES (?,?,?)"), use(v), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
RecordSet rset(session(), "SELECT * FROM Vectors");
std::ostringstream osLoop;
RecordSet::Iterator it = rset.begin();
RecordSet::Iterator end = rset.end();
for (int i = 1; it != end; ++it, ++i)
{
assertTrue (it->get(0) == i);
osLoop << *it;
}
assertTrue (!osLoop.str().empty());
std::ostringstream osCopy;
std::copy(rset.begin(), rset.end(), std::ostream_iterator<Row>(osCopy));
assertTrue (osLoop.str() == osCopy.str());
RowFilter::Ptr pRF = new RowFilter(&rset);
assertTrue (pRF->isEmpty());
pRF->add("str0", RowFilter::VALUE_EQUAL, "3");
assertTrue (!pRF->isEmpty());
it = rset.begin();
end = rset.end();
for (int i = 1; it != end; ++it, ++i)
{
assertTrue (it->get(0) == i);
assertTrue (1 == i);
}
}
void SQLExecutor::stdVectorBool()
{
bool b = false;
try { session() << formatSQL("INSERT INTO BoolTest VALUES (?)"), use(b), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
b = true;
session() << "SELECT * FROM BoolTest", into(b), now;
assertTrue (false == b);
session() << "DELETE FROM BoolTest", now;
b = true;
try { session() << formatSQL("INSERT INTO BoolTest VALUES (?)"), use(b), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
b = false;
session() << "SELECT * FROM BoolTest", into(b), now;
assertTrue (true == b);
session() << "DELETE FROM BoolTest", now;
std::vector<bool> v;
v.push_back(true);
v.push_back(false);
v.push_back(false);
v.push_back(true);
try { session() << formatSQL("INSERT INTO BoolTest VALUES (?)"), use(v), now; }
catch(DataException& ce)
{
std::cout << ce.displayText() << std::endl;
failmsg (__func__);
}
v.clear();
session() << "SELECT * FROM BoolTest", into(v), now;
assertTrue (4 == v.size());
std::vector<bool>::iterator it = v.begin();
std::vector<bool>::iterator end = v.end();
int t = 0;
for (; it != end; ++it)
t += *it ? 1 : 0;
assertTrue (2 == t);
try { session() << formatSQL("SELECT * FROM BoolTest WHERE b = ?"), out(v), now; fail("must fail"); } catch (BindingException&) { }
try { session() << formatSQL("SELECT * FROM BoolTest WHERE b = ?"), io(v), now; fail("must fail"); } catch (BindingException&) { }
RecordSet rset(session(), "SELECT * FROM BoolTest");
t = 0;
for (int i = 0; i < 4; ++i)
t += rset.value<bool>(0, i) ? 1 : 0;
assertTrue (2 == t);
}
void SQLExecutor::asynchronous(int rowCount)
{
Session tmp = session();
std::vector<int> data(rowCount);
Statement stmt = (tmp << formatSQL("INSERT INTO Strings VALUES(?)"), use(data));
Statement::Result result = stmt.executeAsync();
assertTrue (!stmt.isAsync());
result.wait();
Statement stmt1 = (tmp << "SELECT * FROM Strings", into(data), async, now);
assertTrue (stmt1.isAsync());
assertTrue (stmt1.wait() == rowCount);
// +++ if this part of the test case fails, increase the rowCount until achieved
// that first execute is still executing when the second one is called
stmt1.execute();
try {
stmt1.execute();
fail ("execute() must fail");
} catch (InvalidAccessException&)
{
stmt1.wait();
stmt1.execute();
stmt1.wait();
}
// ---
stmt = tmp << "SELECT * FROM Strings", into(data), async, now;
assertTrue (stmt.isAsync());
stmt.wait();
assertTrue (stmt.execute() == 0);
// +++ if this part of the test case fails, increase the rowCount until achieved
// that first execute is still executing when the second one is called
try {
result = stmt.executeAsync();
fail ("executeAsync() must fail");
} catch (InvalidAccessException&)
{
assertTrue (stmt.isAsync());
stmt.wait();
result = stmt.executeAsync();
}
// ---
assertTrue (stmt.wait() == rowCount);
assertTrue (result.data() == rowCount);
stmt.setAsync(false);
assertTrue (!stmt.isAsync());
assertTrue (stmt.execute() == rowCount);
stmt = tmp << "SELECT * FROM Strings", into(data), sync, now;
assertTrue (!stmt.isAsync());
assertTrue (stmt.wait() == 0);
assertTrue (stmt.execute() == rowCount);
result = stmt.executeAsync();
assertTrue (!stmt.isAsync());
result.wait();
assertTrue (result.data() == rowCount);
assertTrue (0 == rowCount % 10);
int step = (int) (rowCount/10);
data.clear();
Statement stmt2 = (tmp << "SELECT * FROM Strings", into(data), async, limit(step));
assertTrue (data.size() == 0);
assertTrue (!stmt2.done());
std::size_t rows = 0;
for (int i = 0; !stmt2.done(); i += step)
{
stmt2.execute();
rows = stmt2.wait();
assertTrue (step == rows);
assertTrue (step + i == data.size());
}
assertTrue (stmt2.done());
assertTrue (rowCount == data.size());
stmt2 = tmp << "SELECT * FROM Strings", reset;
assertTrue (!stmt2.isAsync());
assertTrue ("deque" == stmt2.getStorage());
assertTrue (stmt2.execute() == rowCount);
}
void SQLExecutor::any()
{
Any i = 42;
Any f = 42.5;
std::string ss("42");
Any s = ss;
Session tmp = session();
tmp << formatSQL("INSERT INTO Anys VALUES (?, ?, ?)"), use(i), use(f), use(s), now;
int count = 0;
tmp << "SELECT COUNT(*) FROM Anys", into(count), now;
assertTrue (1 == count);
i = 0;
f = 0.0;
s = std::string("");
tmp << "SELECT * FROM Anys", into(i), into(f), into(s), now;
assertTrue (AnyCast<int>(i) == 42);
assertTrue (AnyCast<double>(f) == 42.5);
assertTrue (AnyCast<std::string>(s) == "42");
}
void SQLExecutor::dynamicAny()
{
Var i = 42;
Var f = 42.5;
Var s = "42";
Session tmp = session();
tmp << formatSQL("INSERT INTO Anys VALUES (?, ?, ?)"), use(i), use(f), use(s), now;
int count = 0;
tmp << "SELECT COUNT(*) FROM Anys", into(count), now;
assertTrue (1 == count);
i = 0;
f = 0.0;
s = std::string("");
tmp << "SELECT * FROM Anys", into(i), into(f), into(s), now;
assertTrue (42 == i);
assertTrue (42.5 == f);
assertTrue ("42" == s);
}
void SQLExecutor::multipleResults(const std::string& sql)
{
typedef Tuple<std::string, std::string, std::string, Poco::UInt32> Person;
std::vector<Person> people;
people.push_back(Person("Simpson", "Homer", "Springfield", 42));
people.push_back(Person("Simpson", "Marge", "Springfield", 38));
people.push_back(Person("Simpson", "Bart", "Springfield", 10));
people.push_back(Person("Simpson", "Lisa", "Springfield", 8));
people.push_back(Person("Simpson", "Maggie", "Springfield", 3));
session() << formatSQL("INSERT INTO Person VALUES (?, ?, ?, ?)"), use(people), now;
Person pHomer;
int aHomer = 42, aLisa = 8;
Poco::UInt32 aBart = 0;
Poco::UInt32 pos1 = 1;
int pos2 = 2;
std::vector<Person> people2;
Statement stmt(session());
stmt << sql, into(pHomer, from(0)), use(aHomer)
, into(aBart, pos1)
, into(people2, from(pos2)), use(aLisa), use(aHomer);
assertTrue (4 == stmt.execute());
assertTrue (Person("Simpson", "Homer", "Springfield", 42) == pHomer);
assertTrue (10 == aBart);
assertTrue (2 == people2.size());
assertTrue (Person("Simpson", "Lisa", "Springfield", 8) == people2[0]);
assertTrue (Person("Simpson", "Homer", "Springfield", 42) == people2[1]);
}
void SQLExecutor::sqlChannel(const std::string& connector, const std::string& connect)
{
try
{
AutoPtr<SQLChannel> pChannel = new SQLChannel(connector, connect, "TestSQLChannel");
Stopwatch sw; sw.start();
while (!pChannel->isRunning())
{
Thread::sleep(10);
if (sw.elapsedSeconds() > 3)
fail ("SQLExecutor::sqlLogger(): SQLChannel timed out");
}
pChannel->setProperty("bulk", "true");
pChannel->setProperty("keep", "2 seconds");
Message msgInf("InformationSource", "a Informational async message", Message::PRIO_INFORMATION);
pChannel->log(msgInf);
while (pChannel->logged() != 1) Thread::sleep(10);
Message msgWarn("WarningSource", "b Warning async message", Message::PRIO_WARNING);
pChannel->log(msgWarn);
while (pChannel->logged() != 2) Thread::sleep(10);
Message msgInfS("InformationSource", "c Informational sync message", Message::PRIO_INFORMATION);
pChannel->log(msgInfS);
while (pChannel->logged() != 3) Thread::sleep(10);
Message msgWarnS("WarningSource", "d Warning sync message", Message::PRIO_WARNING);
pChannel->log(msgWarnS);
while (pChannel->logged() != 4) Thread::sleep(10);
RecordSet rs(session(), "SELECT * FROM T_POCO_LOG ORDER by Text");
size_t rc = rs.rowCount();
assertTrue (4 == rc);
assertTrue ("InformationSource" == rs["Source"]);
assertTrue ("a Informational async message" == rs["Text"]);
rs.moveNext();
assertTrue ("WarningSource" == rs["Source"]);
assertTrue ("b Warning async message" == rs["Text"]);
rs.moveNext();
assertTrue ("InformationSource" == rs["Source"]);
assertTrue ("c Informational sync message" == rs["Text"]);
rs.moveNext();
assertTrue ("WarningSource" == rs["Source"]);
assertTrue ("d Warning sync message" == rs["Text"]);
Thread::sleep(3000); // give it time to archive
Message msgInfA("InformationSource", "e Informational sync message", Message::PRIO_INFORMATION);
pChannel->log(msgInfA);
while (pChannel->logged() != 5) Thread::sleep(10);
Message msgWarnA("WarningSource", "f Warning sync message", Message::PRIO_WARNING);
pChannel->log(msgWarnA);
while (pChannel->logged() != 6) Thread::sleep(10);
RecordSet rs1(session(), "SELECT * FROM T_POCO_LOG_ARCHIVE");
assertTrue (4 == rs1.rowCount());
pChannel->setProperty("keep", "");
assertTrue ("forever" == pChannel->getProperty("keep"));
RecordSet rs2(session(), "SELECT * FROM T_POCO_LOG ORDER by Text");
assertTrue (2 == rs2.rowCount());
assertTrue ("InformationSource" == rs2["Source"]);
assertTrue ("e Informational sync message" == rs2["Text"]);
rs2.moveNext();
assertTrue ("WarningSource" == rs2["Source"]);
assertTrue ("f Warning sync message" == rs2["Text"]);
} catch(DataException& ce){ std::cout << ce.displayText() << std::endl; fail ("sqlChannel()"); }
}
void SQLExecutor::sqlLogger(const std::string& connector, const std::string& connect)
{
try
{
Logger& root = Logger::root();
SQLChannel* pSQLChannel = new SQLChannel(connector, connect, "TestSQLChannel");
Stopwatch sw; sw.start();
while (!pSQLChannel->isRunning())
{
Thread::sleep(10);
if (sw.elapsedSeconds() > 3)
fail ("SQLExecutor::sqlLogger(): SQLChannel timed out");
}
root.setChannel(pSQLChannel);
root.setLevel(Message::PRIO_INFORMATION);
root.information("a Informational message");
root.warning("b Warning message");
root.debug("Debug message");
while (pSQLChannel->logged() != 2) Thread::sleep(100);
RecordSet rs(session(), "SELECT * FROM T_POCO_LOG ORDER by Text");
assertTrue (2 == rs.rowCount());
assertTrue ("TestSQLChannel" == rs["Source"]);
assertTrue ("a Informational message" == rs["Text"]);
rs.moveNext();
assertTrue ("TestSQLChannel" == rs["Source"]);
assertTrue ("b Warning message" == rs["Text"]);
} catch(DataException& ce){ std::cout << ce.displayText() << std::endl; fail ("sqlLogger()"); }
}
void SQLExecutor::setTransactionIsolation(Session& session, Poco::UInt32 ti)
{
if (session.hasTransactionIsolation(ti))
{
try
{
Transaction t(session, false);
t.setIsolation(ti);
assertTrue (ti == t.getIsolation());
assertTrue (t.isIsolation(ti));
assertTrue (ti == session.getTransactionIsolation());
assertTrue (session.isTransactionIsolation(ti));
}
catch(Poco::Exception& e){ std::cout << __func__ << ':' << e.displayText() << std::endl;}
}
else
{
std::cerr << '[' << name() << ']' << " Warning, transaction isolation not supported: ";
switch (ti)
{
case Session::TRANSACTION_READ_COMMITTED:
std::cerr << "READ COMMITTED"; break;
case Session::TRANSACTION_READ_UNCOMMITTED:
std::cerr << "READ UNCOMMITTED"; break;
case Session::TRANSACTION_REPEATABLE_READ:
std::cerr << "REPEATABLE READ"; break;
case Session::TRANSACTION_SERIALIZABLE:
std::cerr << "SERIALIZABLE"; break;
default:
std::cerr << "UNKNOWN"; break;
}
std::cerr << std::endl;
}
}
void SQLExecutor::autoCommit()
{
bool autoCommit = session().getFeature("autoCommit");
session().setFeature("autoCommit", true);
assertTrue (!session().isTransaction());
session().setFeature("autoCommit", false);
assertTrue (!session().isTransaction());
session().setFeature("autoCommit", true);
assertTrue (!session().isTransaction());
session().setFeature("autoCommit", autoCommit);
}
void SQLExecutor::transactionIsolation()
{
try
{
auto ti = session().getTransactionIsolation();
// these are just calls to check the transactional capabilities of the session
// they will print diagnostics to stderr if a transaction isolation level is not supported
setTransactionIsolation(session(), Session::TRANSACTION_READ_UNCOMMITTED);
setTransactionIsolation(session(), Session::TRANSACTION_REPEATABLE_READ);
setTransactionIsolation(session(), Session::TRANSACTION_SERIALIZABLE);
setTransactionIsolation(session(), Session::TRANSACTION_READ_COMMITTED);
setTransactionIsolation(session(), ti);
}
catch(const Poco::Exception& ex)
{
std::cerr << ex.displayText() << std::endl;
}
catch(const std::exception& ex)
{
std::cerr << ex.what() << std::endl;
}
}
void SQLExecutor::sessionTransaction(const std::string& connector, const std::string& connect)
{
if (!session().canTransact())
{
std::cout << "Session not capable of transactions." << std::endl;
return;
}
bool autoCommit = session().getFeature("autoCommit");
bool sqlParse = session().getFeature("sqlParse");
session().setFeature("sqlParse", true);
Session local(connector, connect);
std::string tableName("Person");
std::vector<std::string> lastNames = {"LN1", "LN2"};
std::vector<std::string> firstNames = {"FN1", "FN2"};
std::vector<std::string> addresses = {"ADDR1", "ADDR2"};
std::vector<int> ages = {1, 2};
int count = 0, locCount = 0;
std::string result;
session().setFeature("autoCommit", true);
assertTrue (session().getFeature("autoCommit"));
assertTrue (!session().isTransaction());
session().begin();
assertTrue (session().isTransaction());
assertTrue (!session().getFeature("autoCommit"));
// changing autocommit is invalid for session in transaction ...
try
{
session().setFeature("autoCommit", true);
fail ("must fail on autocommit setting during transaction");
} catch(const Poco::InvalidAccessException&) { }
// make sure nothing was changed ...
assertTrue (!session().getFeature("autoCommit"));
// but setting it to its current state is allowed (no-op)
session().setFeature("autoCommit", false);
assertTrue (!session().getFeature("autoCommit"));
session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(lastNames), use(firstNames), use(addresses), use(ages), now;
assertTrue (session().isTransaction());
Statement stmt = (local << "SELECT COUNT(*) FROM Person", into(locCount), async, now);
session() << "SELECT COUNT(*) FROM Person", into(count), now;
assertTrue (2 == count);
assertTrue (session().isTransaction());
session().rollback();
assertTrue (!session().isTransaction());
stmt.wait();
assertTrue (0 == locCount);
stmt.reset(session());
session() << "SELECT count(*) FROM Person", into(count), now;
assertTrue (0 == count);
assertTrue (!session().isTransaction());
session().begin();
session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(lastNames), use(firstNames), use(addresses), use(ages), now;
assertTrue (session().isTransaction());
stmt = (local << "SELECT COUNT(*) FROM Person", into(locCount), async, now);
assertTrue (0 == locCount);
session().commit();
assertTrue (!session().isTransaction());
stmt.wait();
// in general, no guarantee if stmt was executed before or after the commit
assertTrue (0 == locCount || 2 == locCount);
session() << "SELECT count(*) FROM Person", into(count), now;
assertTrue (2 == count);
// end autoCommit = true
// restore the original transaction state
session().setFeature("sqlParse", sqlParse);
session().setFeature("autoCommit", autoCommit);
}
void SQLExecutor::sessionTransactionNoAutoCommit(const std::string& connector, const std::string& connect)
{
bool autoCommit = session().getFeature("autoCommit");
bool sqlParse = session().getFeature("sqlParse");
session().setFeature("sqlParse", true);
Session local(connector, connect);
local.setFeature("autoCommit", false);
assertTrue (!local.getFeature("autoCommit"));
if (!local.canTransact())
{
std::cout << "Session not capable of transactions." << std::endl;
return;
}
std::vector<std::string> lastNames = {"LN1", "LN2"};
std::vector<std::string> firstNames = {"FN1", "FN2"};
std::vector<std::string> addresses = {"ADDR1", "ADDR2"};
std::vector<int> ages = {1, 2};
std::string tableName("Person");
int count = 0, locCount = 0;
std::string result;
// no autoCommit session becomes transaction without explicit begin()
assertTrue (!local.isTransaction());
assertTrue (!session().isTransaction());
local << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"),
use(lastNames), use(firstNames), use(addresses), use(ages), now;
Statement stmt = (session() << "SELECT COUNT(*) FROM Person",
into(count), async, now);
local << "SELECT COUNT(*) FROM Person", into(locCount), now;
assertTrue (0 == count);
assertTrue (2 == locCount);
#ifndef POCO_DATA_NO_SQL_PARSER
assertTrue (local.isTransaction());
// autocommit is invalid for session in transaction ...
try
{
local.setFeature("autoCommit", true);
fail ("must fail on autocommit setting during transaction", __LINE__, __FILE__);
} catch(const Poco::InvalidAccessException&) { }
// but setting it to its current state is allowed (no-op)
local.setFeature("autoCommit", false);
assertTrue (!session().isTransaction());
#else
session().commit();
#endif // POCO_DATA_NO_SQL_PARSER
local.commit();
assertTrue (!local.isTransaction());
stmt.wait();
// in general, there is no guarantee if stmt was exeuted before or after the commit
assertTrue (2 == count || 0 == count);
count = 0;
stmt.reset(session());
session() << "SELECT COUNT(*) FROM Person", into(count), now;
assertTrue (2 == count);
count = 0;
assertTrue (!local.isTransaction());
assertTrue (!session().isTransaction());
local << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"),
use(lastNames), use(firstNames), use(addresses), use(ages), now;
stmt = (session() << "SELECT COUNT(*) FROM Person", into(count), async, now);
local << "SELECT COUNT(*) FROM Person", into(locCount), now;
// no guarantee if stmt is executed or not:
assertTrue (0 == count || 2 == count);
assertTrue (4 == locCount);
#ifndef POCO_DATA_NO_SQL_PARSER
assertTrue (local.isTransaction());
assertTrue (!session().isTransaction());
#else
session().commit();
#endif
local.rollback();
assertTrue (!local.isTransaction());
stmt.wait();
assertTrue (2 == count);
locCount = 0;
session() << "SELECT COUNT(*) FROM Person", into(count), now;
local << "SELECT COUNT(*) FROM Person", into(locCount), now;
assertTrue (2 == count);
assertTrue (2 == locCount);
#ifndef POCO_DATA_NO_SQL_PARSER
session().commit();
local.commit();
#endif
session().setFeature("sqlParse", sqlParse);
session().setFeature("autoCommit", autoCommit);
}
void SQLExecutor::transaction(const std::string& connector, const std::string& connect, bool readUncommitted)
{
if (!session().canTransact())
{
std::cout << "Session not transaction-capable." << std::endl;
return;
}
Session local(connector, connect);
local.setFeature("autoCommit", true);
local.setFeature("sqlParse", true);
bool autoCommit = session().getFeature("autoCommit");
auto ti = session().getTransactionIsolation();
bool sqlParse = session().getFeature("sqlParse");
session().setFeature("sqlParse", true);
setTransactionIsolation(session(), Session::TRANSACTION_READ_COMMITTED);
if (local.hasTransactionIsolation(Session::TRANSACTION_READ_UNCOMMITTED))
setTransactionIsolation(local, Session::TRANSACTION_READ_UNCOMMITTED);
else if (local.hasTransactionIsolation(Session::TRANSACTION_READ_COMMITTED))
setTransactionIsolation(local, Session::TRANSACTION_READ_COMMITTED);
try
{
std::string tableName("Person");
std::vector<std::string> lastNames = {"LN1", "LN2"};
std::vector<std::string> firstNames = {"FN1", "FN2"};
std::vector<std::string> addresses = {"ADDR1", "ADDR2"};
std::vector<int> ages = {1, 2};
int count = 0, locCount = 0;
std::string result;
session().setFeature("autoCommit", true);
assertTrue (!session().isTransaction());
session().setFeature("autoCommit", false);
assertTrue (!session().isTransaction());
session().setTransactionIsolation(Session::TRANSACTION_READ_COMMITTED);
{
Transaction trans(session());
assertTrue (trans.isActive());
assertTrue (session().isTransaction());
session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(lastNames), use(firstNames), use(addresses), use(ages), now;
assertTrue (session().isTransaction());
assertTrue (trans.isActive());
session() << "SELECT COUNT(*) FROM Person", into(count), now;
assertEqual (2, count);
assertTrue (session().isTransaction());
assertTrue (trans.isActive());
}
assertTrue (!session().isTransaction());
session() << "SELECT count(*) FROM Person", into(count), now;
assertEqual (0, count);
assertTrue (!(session().impl()->shouldParse() && session().isTransaction()));
session().commit();
{
Transaction trans(session());
session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(lastNames), use(firstNames), use(addresses), use(ages), now;
Statement stmt1 = (local << "SELECT COUNT(*) FROM Person", into(locCount), async, now);
assertTrue (session().isTransaction());
assertTrue (trans.isActive());
trans.commit();
assertTrue (!session().isTransaction());
assertTrue (!trans.isActive());
stmt1.wait();
assertEqual (2, locCount);
}
session() << "SELECT count(*) FROM Person", into(count), now;
assertEqual (2, count);
session() << "DELETE FROM Person", now;
Statement stmt1 = (local << "SELECT count(*) FROM Person", into(locCount), async, now);
session() << "SELECT count(*) FROM Person", into(count), now;
assertEqual (0, count);
try
{
stmt1.wait(5000);
if (readUncommitted &&
local.hasTransactionIsolation(Session::TRANSACTION_READ_UNCOMMITTED) &&
local.getTransactionIsolation() == Session::TRANSACTION_READ_UNCOMMITTED)
assertEqual (0, locCount);
}
catch (TimeoutException&)
{
std::cerr << '[' << name() << ']' << " Warning: async query timed out." << std::endl;
}
catch (CppUnit::CppUnitException& ex)
{
std::cerr << " Warning: " << ex.what() << std::endl;
}
catch (std::exception& ex)
{
std::cerr << " Warning: " << ex.what() << std::endl;
}
session().commit();
// repeat for those that don't support uncommitted read isolation
if (local.getTransactionIsolation() == Session::TRANSACTION_READ_COMMITTED)
{
stmt1.wait();
local << "SELECT count(*) FROM Person", into(locCount), now;
assertEqual (0, locCount);
}
std::string sql1 = format("INSERT INTO Person VALUES ('%s','%s','%s',%d)", lastNames[0], firstNames[0], addresses[0], ages[0]);
std::string sql2 = format("INSERT INTO Person VALUES ('%s','%s','%s',%d)", lastNames[1], firstNames[1], addresses[1], ages[1]);
std::vector<std::string> sql;
sql.push_back(sql1);
sql.push_back(sql2);
Transaction trans(session());
trans.execute(sql1, false);
session() << "SELECT count(*) FROM Person", into(count), now;
assertEqual (1, count);
trans.execute(sql2, false);
session() << "SELECT count(*) FROM Person", into(count), now;
assertEqual (2, count);
Statement stmt2 = (local << "SELECT COUNT(*) FROM Person", into(locCount), async, now);
trans.rollback();
stmt2.wait();
assertEqual (0, locCount);
session() << "SELECT count(*) FROM Person", into(count), now;
assertEqual (0, count);
trans.execute(sql);
Statement stmt3 = (local << "SELECT COUNT(*) FROM Person", into(locCount), now);
assertEqual (2, locCount);
session() << "SELECT count(*) FROM Person", into(count), now;
assertEqual (2, count);
}
catch (std::exception& ex)
{
std::cerr << " Warning: " << ex.what() << std::endl;
}
session().commit();
// restore the original transaction state
session().setFeature("sqlParse", sqlParse);
session().setFeature("autoCommit", autoCommit);
setTransactionIsolation(session(), ti);
}
struct TestCommitTransactor
{
void operator () (Session& session) const
{
session << "INSERT INTO Person VALUES ('lastName','firstName','address',10)", now;
}
};
struct TestRollbackTransactor
{
void operator () (Session& session) const
{
session << "INSERT INTO Person VALUES ('lastName','firstName','address',10)", now;
throw Poco::Exception("test");
}
};
void SQLExecutor::transactor()
{
try
{
int count = 0;
bool autoCommit = session().getFeature("autoCommit");
auto ti = session().getTransactionIsolation();
session().setFeature("autoCommit", false);
session().setTransactionIsolation(Session::TRANSACTION_READ_COMMITTED);
bool sqlParse = session().getFeature("sqlParse");
session().setFeature("sqlParse", true);
TestCommitTransactor ct;
Transaction t1(session(), ct);
session() << "SELECT count(*) FROM Person", into(count), now;
assertTrue (1 == count);
session() << "DELETE FROM Person", now; session().commit();
session() << "SELECT count(*) FROM Person", into(count), now;
assertTrue (0 == count);
try
{
TestRollbackTransactor rt;
Transaction t(session(), rt);
fail ("must fail");
} catch (Poco::Exception&) { }
session() << "SELECT count(*) FROM Person", into(count), now;
assertTrue (0 == count);
try
{
TestRollbackTransactor rt;
Transaction t(session());
t.transact(rt);
fail ("must fail");
} catch (Poco::Exception&) { }
session() << "SELECT count(*) FROM Person", into(count), now;
assertTrue (0 == count);
try
{
TestRollbackTransactor rt;
Transaction t(session(), false);
t.transact(rt);
fail ("must fail");
} catch (Poco::Exception&) { }
session() << "SELECT count(*) FROM Person", into(count), now;
assertTrue (0 == count);
try
{
TestRollbackTransactor rt;
Transaction t(session(), true);
t.transact(rt);
fail ("must fail");
} catch (Poco::Exception&) { }
session() << "SELECT count(*) FROM Person", into(count), now;
assertTrue (0 == count);
session().commit();
// restore the original transaction state
session().setFeature("sqlParse", sqlParse);
session().setFeature("autoCommit", autoCommit);
setTransactionIsolation(session(), ti);
}
catch (Poco::Exception& ex)
{
std::cerr << __func__ << ':' << ex.displayText() << std::endl;
failmsg (__func__);
}
}
void SQLExecutor::nullable()
{
nullableImpl<Date>("EmptyDate"s);
nullableImpl<DateTime>("EmptyDateTime"s);
}
void SQLExecutor::reconnect()
{
std::string lastName = "lastName";
std::string firstName("firstName");
std::string address("Address");
int age = 133132;
int count = 0;
std::string result;
try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(lastName), use(firstName), use(address), use(age), now; }
catch(DataException& ce)
{
failmsg (ce.displayText());
}
count = 0;
try { session() << "SELECT COUNT(*) FROM Person", into(count), now; }
catch(DataException& ce)
{
failmsg(ce.displayText());
}
assertTrue (count == 1);
assertTrue (session().isConnected());
session().close();
assertTrue (!session().isConnected());
try
{
session() << "SELECT LastName FROM Person", into(result), now;
fail ("must fail");
} catch(NotConnectedException&){ }
assertTrue (!session().isConnected());
session().open();
assertTrue (session().isConnected());
try { session() << "SELECT Age FROM Person", into(count), now; }
catch(DataException& ce)
{
failmsg (ce.displayText());
}
assertTrue (count == age);
assertTrue (session().isConnected());
}
void SQLExecutor::unicode(const std::string& dbConnString)
{
const unsigned char supp[] = { 0x41, 0x42, 0xf0, 0x90, 0x82, 0xa4, 0xf0, 0xaf, 0xa6, 0xa0, 0xf0, 0xaf, 0xa8, 0x9d, 0x00 };
std::string text((const char*) supp);
UTF16String wtext;
Poco::UnicodeConverter::convert(text, wtext);
session() << formatSQL("INSERT INTO UnicodeTable VALUES (?)"), use(wtext), now;
wtext.clear();
text.clear();
session() << "SELECT str FROM UnicodeTable", into(wtext), now;
Poco::UnicodeConverter::convert(wtext, text);
assertTrue (text == std::string((const char*)supp));
}
void SQLExecutor::encoding(const std::string& dbConnString)
{
try
{
const unsigned char latinChars[] = { 'g', 252, 'n', 't', 'e', 'r', 0 };
const unsigned char utf8Chars[] = { 'g', 195, 188, 'n', 't', 'e', 'r', 0 };
std::string latinText((const char*)latinChars);
std::string utf8TextIn((const char*)utf8Chars);
session(true) << formatSQL("INSERT INTO Latin1Table VALUES (?)"), use(utf8TextIn), now;
std::string latinTextOut;
session() << "SELECT str FROM Latin1Table", into(latinTextOut), now;
assertTrue(latinText == latinTextOut);
std::string utf8TextOut;
session(true) << "SELECT str FROM Latin1Table", into(utf8TextOut), now;
assertTrue(utf8TextIn == utf8TextOut);
const unsigned char latinChars2[] = { 'G', 220, 'N', 'T', 'E', 'R', 0 };
const unsigned char utf8Chars2[] = { 'G', 195, 156, 'N', 'T', 'E', 'R', 0 };
std::string latinText2 = (const char*)latinChars2;
std::string utf8TextIn2 = (const char*)utf8Chars2;
session(true) << formatSQL("INSERT INTO Latin1Table VALUES (?)"), use(utf8TextIn2), now;
std::vector<std::string> textOutVec;
session() << "SELECT str FROM Latin1Table", into(textOutVec), now;
assertTrue(textOutVec.size() == 2);
assertTrue(textOutVec[0] == latinText);
assertTrue(textOutVec[1] == latinText2);
textOutVec.clear();
session(true) << "SELECT str FROM Latin1Table", into(textOutVec), now;
assertTrue(textOutVec.size() == 2);
assertTrue(textOutVec[0] == utf8TextIn);
assertTrue(textOutVec[1] == utf8TextIn2);
}
catch (Poco::Exception& ex)
{
std::cerr << ex.displayText() << std::endl;
throw;
}
catch (std::exception& ex)
{
std::cerr << ex.what() << std::endl;
throw;
}
}
std::string SQLExecutor::formatSQL(const std::string& s) const
{
if (!_numberedPlaceHolders)
return std::string(s);
std::string r;
r.reserve(s.size());
int idx = 0;
for (char c: s)
{
if (c == '?')
{
r += '$';
r += std::to_string(++idx);
}
else
r += c;
}
return r;
}
} } } // Poco::Data::Test