mirror of
https://github.com/pocoproject/poco.git
synced 2024-12-12 10:13:51 +01:00
Various feature additions and fixes:
- asynchronous execution for Data::Statement - ActiveMethod copy and assignment - added Data components to $POCO_BASE/components - SQLite 64-bit integer default - SessionPool timer seconds to milliseconds - ODBC fix for subsequent calls to execute() - std::deque (instead of std::vector) as default container
This commit is contained in:
parent
0dfd7bec3b
commit
6e380b6b13
@ -300,15 +300,21 @@ SQLSMALLINT Binder::toODBCDirection(Direction dir) const
|
||||
|
||||
void Binder::synchronize()
|
||||
{
|
||||
if (_timestamps.size())
|
||||
{
|
||||
TimestampMap::iterator itTS = _timestamps.begin();
|
||||
TimestampMap::iterator itTSEnd = _timestamps.end();
|
||||
for(; itTS != itTSEnd; ++itTS)
|
||||
Utility::dateTimeSync(*itTS->second, *itTS->first);
|
||||
}
|
||||
|
||||
if (_strings.size())
|
||||
{
|
||||
StringMap::iterator itStr = _strings.begin();
|
||||
StringMap::iterator itStrEnd = _strings.end();
|
||||
for(; itStr != itStrEnd; ++itStr)
|
||||
itStr->second->assign(itStr->first, strlen(itStr->first));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -212,6 +212,7 @@ void ODBCStatementImpl::putData()
|
||||
void ODBCStatementImpl::clear()
|
||||
{
|
||||
SQLRETURN rc = SQLCloseCursor(_stmt);
|
||||
_stepCalled = false;
|
||||
if (Utility::isError(rc))
|
||||
{
|
||||
StatementError err(_stmt);
|
||||
|
@ -1067,6 +1067,21 @@ void ODBCDB2Test::testRowIterator()
|
||||
}
|
||||
|
||||
|
||||
void ODBCDB2Test::testAsync()
|
||||
{
|
||||
if (!_pSession) fail ("Test not available.");
|
||||
|
||||
for (int i = 0; i < 8;)
|
||||
{
|
||||
recreateIntsTable();
|
||||
_pSession->setFeature("autoBind", bindValues[i]);
|
||||
_pSession->setFeature("autoExtract", bindValues[i+1]);
|
||||
_pExecutor->asynchronous();
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ODBCDB2Test::dropObject(const std::string& type, const std::string& name)
|
||||
{
|
||||
try
|
||||
@ -1322,6 +1337,7 @@ CppUnit::Test* ODBCDB2Test::suite()
|
||||
CppUnit_addTest(pSuite, ODBCDB2Test, testStoredFunction);
|
||||
CppUnit_addTest(pSuite, ODBCDB2Test, testNull);
|
||||
CppUnit_addTest(pSuite, ODBCDB2Test, testRowIterator);
|
||||
CppUnit_addTest(pSuite, ODBCDB2Test, testAsync);
|
||||
|
||||
return pSuite;
|
||||
}
|
||||
|
@ -125,6 +125,8 @@ public:
|
||||
void testNull();
|
||||
void testRowIterator();
|
||||
|
||||
void testAsync();
|
||||
|
||||
void setUp();
|
||||
void tearDown();
|
||||
|
||||
|
@ -931,6 +931,21 @@ void ODBCMySQLTest::testRowIterator()
|
||||
}
|
||||
|
||||
|
||||
void ODBCMySQLTest::testAsync()
|
||||
{
|
||||
if (!_pSession) fail ("Test not available.");
|
||||
|
||||
for (int i = 0; i < 8;)
|
||||
{
|
||||
recreateIntsTable();
|
||||
_pSession->setFeature("autoBind", bindValues[i]);
|
||||
_pSession->setFeature("autoExtract", bindValues[i+1]);
|
||||
_pExecutor->asynchronous();
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ODBCMySQLTest::dropObject(const std::string& type, const std::string& name)
|
||||
{
|
||||
*_pSession << format("DROP %s IF EXISTS %s", type, name), now;
|
||||
@ -1169,6 +1184,8 @@ CppUnit::Test* ODBCMySQLTest::suite()
|
||||
CppUnit_addTest(pSuite, ODBCMySQLTest, testInternalStorageType);
|
||||
CppUnit_addTest(pSuite, ODBCMySQLTest, testNull);
|
||||
CppUnit_addTest(pSuite, ODBCMySQLTest, testRowIterator);
|
||||
CppUnit_addTest(pSuite, ODBCMySQLTest, testAsync);
|
||||
|
||||
return pSuite;
|
||||
}
|
||||
|
||||
|
@ -127,6 +127,8 @@ public:
|
||||
void testNull();
|
||||
void testRowIterator();
|
||||
|
||||
void testAsync();
|
||||
|
||||
void setUp();
|
||||
void tearDown();
|
||||
|
||||
|
@ -1082,6 +1082,21 @@ void ODBCOracleTest::testRowIterator()
|
||||
}
|
||||
|
||||
|
||||
void ODBCOracleTest::testAsync()
|
||||
{
|
||||
if (!_pSession) fail ("Test not available.");
|
||||
|
||||
for (int i = 0; i < 8;)
|
||||
{
|
||||
recreateIntsTable();
|
||||
_pSession->setFeature("autoBind", bindValues[i]);
|
||||
_pSession->setFeature("autoExtract", bindValues[i+1]);
|
||||
_pExecutor->asynchronous();
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ODBCOracleTest::dropObject(const std::string& type, const std::string& name)
|
||||
{
|
||||
try
|
||||
@ -1369,6 +1384,7 @@ CppUnit::Test* ODBCOracleTest::suite()
|
||||
CppUnit_addTest(pSuite, ODBCOracleTest, testInternalStorageType);
|
||||
CppUnit_addTest(pSuite, ODBCOracleTest, testNull);
|
||||
CppUnit_addTest(pSuite, ODBCOracleTest, testRowIterator);
|
||||
CppUnit_addTest(pSuite, ODBCOracleTest, testAsync);
|
||||
|
||||
return pSuite;
|
||||
}
|
||||
|
@ -125,6 +125,8 @@ public:
|
||||
void testNull();
|
||||
void testRowIterator();
|
||||
|
||||
void testAsync();
|
||||
|
||||
void setUp();
|
||||
void tearDown();
|
||||
|
||||
|
@ -994,6 +994,21 @@ void ODBCPostgreSQLTest::testStdVectorBool()
|
||||
}
|
||||
|
||||
|
||||
void ODBCPostgreSQLTest::testAsync()
|
||||
{
|
||||
if (!_pSession) fail ("Test not available.");
|
||||
|
||||
for (int i = 0; i < 8;)
|
||||
{
|
||||
recreateIntsTable();
|
||||
_pSession->setFeature("autoBind", bindValues[i]);
|
||||
_pSession->setFeature("autoExtract", bindValues[i+1]);
|
||||
_pExecutor->asynchronous();
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ODBCPostgreSQLTest::configurePLPgSQL()
|
||||
{
|
||||
if (!_pSession) fail ("Test not available.");
|
||||
@ -1317,6 +1332,7 @@ CppUnit::Test* ODBCPostgreSQLTest::suite()
|
||||
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testNull);
|
||||
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testRowIterator);
|
||||
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testStdVectorBool);
|
||||
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testAsync);
|
||||
|
||||
return pSuite;
|
||||
}
|
||||
|
@ -133,6 +133,8 @@ public:
|
||||
void testRowIterator();
|
||||
void testStdVectorBool();
|
||||
|
||||
void testAsync();
|
||||
|
||||
void setUp();
|
||||
void tearDown();
|
||||
|
||||
|
@ -1085,6 +1085,21 @@ void ODBCSQLServerTest::testStdVectorBool()
|
||||
}
|
||||
|
||||
|
||||
void ODBCSQLServerTest::testAsync()
|
||||
{
|
||||
if (!_pSession) fail ("Test not available.");
|
||||
|
||||
for (int i = 0; i < 8;)
|
||||
{
|
||||
recreateIntsTable();
|
||||
_pSession->setFeature("autoBind", bindValues[i]);
|
||||
_pSession->setFeature("autoExtract", bindValues[i+1]);
|
||||
_pExecutor->asynchronous();
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ODBCSQLServerTest::dropObject(const std::string& type, const std::string& name)
|
||||
{
|
||||
try
|
||||
@ -1362,6 +1377,7 @@ CppUnit::Test* ODBCSQLServerTest::suite()
|
||||
CppUnit_addTest(pSuite, ODBCSQLServerTest, testNull);
|
||||
CppUnit_addTest(pSuite, ODBCSQLServerTest, testRowIterator);
|
||||
CppUnit_addTest(pSuite, ODBCSQLServerTest, testStdVectorBool);
|
||||
CppUnit_addTest(pSuite, ODBCSQLServerTest, testAsync);
|
||||
|
||||
return pSuite;
|
||||
}
|
||||
|
@ -129,6 +129,8 @@ public:
|
||||
void testRowIterator();
|
||||
void testStdVectorBool();
|
||||
|
||||
void testAsync();
|
||||
|
||||
void setUp();
|
||||
void tearDown();
|
||||
|
||||
|
@ -906,6 +906,21 @@ void ODBCSQLiteTest::testRowIterator()
|
||||
}
|
||||
|
||||
|
||||
void ODBCSQLiteTest::testAsync()
|
||||
{
|
||||
if (!_pSession) fail ("Test not available.");
|
||||
|
||||
for (int i = 0; i < 8;)
|
||||
{
|
||||
recreateIntsTable();
|
||||
_pSession->setFeature("autoBind", bindValues[i]);
|
||||
_pSession->setFeature("autoExtract", bindValues[i+1]);
|
||||
_pExecutor->asynchronous();
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ODBCSQLiteTest::dropObject(const std::string& type, const std::string& name)
|
||||
{
|
||||
try
|
||||
@ -1153,6 +1168,7 @@ CppUnit::Test* ODBCSQLiteTest::suite()
|
||||
CppUnit_addTest(pSuite, ODBCSQLiteTest, testInternalStorageType);
|
||||
CppUnit_addTest(pSuite, ODBCSQLiteTest, testNull);
|
||||
CppUnit_addTest(pSuite, ODBCSQLiteTest, testRowIterator);
|
||||
CppUnit_addTest(pSuite, ODBCSQLiteTest, testAsync);
|
||||
|
||||
return pSuite;
|
||||
}
|
||||
|
@ -122,6 +122,8 @@ public:
|
||||
void testNull();
|
||||
void testRowIterator();
|
||||
|
||||
void testAsync();
|
||||
|
||||
void setUp();
|
||||
void tearDown();
|
||||
|
||||
|
@ -1952,7 +1952,7 @@ void SQLExecutor::internalExtraction()
|
||||
i = rset.value("str0", 2);
|
||||
assert (5 == i);
|
||||
|
||||
const Column<int>& col = rset.column<int, std::vector<int> >(0);
|
||||
const Column<int>& col = rset.column<int, std::deque<int> >(0);
|
||||
Column<int>::Iterator it = col.begin();
|
||||
Column<int>::Iterator end = col.end();
|
||||
for (int i = 1; it != end; ++it, ++i)
|
||||
@ -2239,3 +2239,46 @@ void SQLExecutor::stdVectorBool()
|
||||
t += rset.value<bool>(0, i) ? 1 : 0;
|
||||
assert (2 == t);
|
||||
}
|
||||
|
||||
|
||||
void SQLExecutor::asynchronous()
|
||||
{
|
||||
Session tmp = *_pSession;
|
||||
|
||||
int rowCount = 500;
|
||||
std::vector<int> data(rowCount);
|
||||
Statement stmt = (tmp << "INSERT INTO Strings VALUES(?)", use(data));
|
||||
Statement::Result result = stmt.executeAsync();
|
||||
assert (!stmt.isAsync());
|
||||
result.wait();
|
||||
|
||||
stmt = tmp << "SELECT * FROM Strings", into(data), async, now;
|
||||
assert (stmt.isAsync());
|
||||
stmt.wait();
|
||||
assert (stmt.execute() == 0);
|
||||
|
||||
try {
|
||||
result = stmt.executeAsync();
|
||||
fail ("must fail");
|
||||
} catch (InvalidAccessException&)
|
||||
{
|
||||
assert (stmt.isAsync());
|
||||
stmt.wait();
|
||||
result = stmt.executeAsync();
|
||||
}
|
||||
|
||||
assert (stmt.wait() == rowCount);
|
||||
assert (result.data() == rowCount);
|
||||
stmt.setAsync(false);
|
||||
assert (!stmt.isAsync());
|
||||
assert (stmt.execute() == rowCount);
|
||||
|
||||
stmt = tmp << "SELECT * FROM Strings", into(data), sync, now;
|
||||
assert (!stmt.isAsync());
|
||||
assert (stmt.wait() == 0);
|
||||
assert (stmt.execute() == rowCount);
|
||||
result = stmt.executeAsync();
|
||||
assert (!stmt.isAsync());
|
||||
result.wait();
|
||||
assert (result.data() == rowCount);
|
||||
}
|
||||
|
@ -134,6 +134,8 @@ public:
|
||||
void rowIterator();
|
||||
void stdVectorBool();
|
||||
|
||||
void asynchronous();
|
||||
|
||||
private:
|
||||
Poco::Data::Session* _pSession;
|
||||
};
|
||||
|
@ -64,7 +64,7 @@ MetaColumn::ColumnDataType Utility::getColumnType(sqlite3_stmt* pStmt, std::size
|
||||
Poco::toUpperInPlace(sqliteType);
|
||||
|
||||
if (sqliteType.npos != sqliteType.find("INT"))
|
||||
return MetaColumn::FDT_INT32;
|
||||
return MetaColumn::FDT_INT64;
|
||||
else if (sqliteType.empty() ||
|
||||
sqliteType.npos != sqliteType.find("CHAR") ||
|
||||
sqliteType.npos != sqliteType.find("CLOB") ||
|
||||
|
@ -54,6 +54,8 @@ using Poco::InvalidAccessException;
|
||||
using Poco::RangeException;
|
||||
using Poco::BadCastException;
|
||||
using Poco::Data::SQLite::InvalidSQLStatementException;
|
||||
using Poco::Int64;
|
||||
|
||||
|
||||
struct Person
|
||||
{
|
||||
@ -496,13 +498,16 @@ void SQLiteTest::testLimitPrepare()
|
||||
Statement stmt = (tmp << "SELECT * FROM Strings", into(retData), limit(50));
|
||||
assert (retData.size() == 0);
|
||||
assert (!stmt.done());
|
||||
stmt.execute();
|
||||
Poco::UInt32 rows = stmt.execute();
|
||||
assert (50 == rows);
|
||||
assert (!stmt.done());
|
||||
assert (retData.size() == 50);
|
||||
stmt.execute();
|
||||
rows = stmt.execute();
|
||||
assert (50 == rows);
|
||||
assert (stmt.done());
|
||||
assert (retData.size() == 100);
|
||||
stmt.execute(); // will restart execution!
|
||||
rows = stmt.execute(); // will restart execution!
|
||||
assert (50 == rows);
|
||||
assert (!stmt.done());
|
||||
assert (retData.size() == 150);
|
||||
for (int x = 0; x < 150; ++x)
|
||||
@ -1030,28 +1035,6 @@ void SQLiteTest::testBLOB()
|
||||
}
|
||||
|
||||
|
||||
void SQLiteTest::testBLOBStmt()
|
||||
{
|
||||
// the following test will fail becuase we use a temporary object as parameter to use
|
||||
/*
|
||||
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
|
||||
tmp << "DROP TABLE IF EXISTS Person", now;
|
||||
tmp << "CREATE TABLE IF NOT EXISTS Person (LastName VARCHAR(30), FirstName VARCHAR, Address VARCHAR, Image BLOB)", now;
|
||||
BLOB img("0123456789", 10);
|
||||
int count = 0;
|
||||
Statement ins = (tmp << "INSERT INTO PERSON VALUES(:ln, :fn, :ad, :img)", use("lastname"), use("firstname"), use("Address"), use(BLOB("0123456789", 10)));
|
||||
ins.execute();
|
||||
tmp << "SELECT COUNT(*) FROM PERSON", into(count), now;
|
||||
assert (count == 1);
|
||||
BLOB res;
|
||||
poco_assert (res.size() == 0);
|
||||
Statement stmt = (tmp << "SELECT Image FROM Person WHERE LastName == :ln", use("lastname"), into(res));
|
||||
stmt.execute();
|
||||
poco_assert (res == img);
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
void SQLiteTest::testTuple10()
|
||||
{
|
||||
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
|
||||
@ -1537,10 +1520,13 @@ void SQLiteTest::testInternalExtraction()
|
||||
assert (3 == rset2.columnCount());
|
||||
assert (4 == rset2.rowCount());
|
||||
|
||||
int a = rset.value<int>(0,2);
|
||||
Int64 a = rset.value<Int64>(0,2);
|
||||
assert (3 == a);
|
||||
|
||||
int b = rset2.value<int>("InT0",2);
|
||||
int c = rset2.value(0);
|
||||
assert (1 == c);
|
||||
|
||||
Int64 b = rset2.value<Int64>("InT0",2);
|
||||
assert (3 == b);
|
||||
|
||||
double d = rset.value<double>(1,0);
|
||||
@ -1549,18 +1535,18 @@ void SQLiteTest::testInternalExtraction()
|
||||
std::string s = rset.value<std::string>(2,1);
|
||||
assert ("4" == s);
|
||||
|
||||
typedef std::vector<int> IntVec;
|
||||
typedef std::deque<Int64> IntDeq;
|
||||
|
||||
const Column<int, IntVec>& col = rset.column<int, IntVec>(0);
|
||||
const Column<Int64>& col = rset.column<Int64, IntDeq>(0);
|
||||
assert (col[0] == 1);
|
||||
|
||||
try { rset.column<int, IntVec>(100); fail ("must fail"); }
|
||||
try { rset.column<Int64, IntDeq>(100); fail ("must fail"); }
|
||||
catch (RangeException&) { }
|
||||
|
||||
const Column<int, IntVec>& col1 = rset.column<int, IntVec>(0);
|
||||
const Column<Int64>& col1 = rset.column<Int64, IntDeq>(0);
|
||||
assert ("int0" == col1.name());
|
||||
Column<int>::Iterator it = col1.begin();
|
||||
Column<int>::Iterator itEnd = col1.end();
|
||||
Column<Int64>::Iterator it = col1.begin();
|
||||
Column<Int64>::Iterator itEnd = col1.end();
|
||||
int counter = 1;
|
||||
for (; it != itEnd; ++it, ++counter)
|
||||
assert (counter == *it);
|
||||
@ -1572,7 +1558,7 @@ void SQLiteTest::testInternalExtraction()
|
||||
stmt = (tmp << "DELETE FROM Vectors", now);
|
||||
rset = stmt;
|
||||
|
||||
try { rset.column<int, IntVec>(0); fail ("must fail"); }
|
||||
try { rset.column<Int64, IntDeq>(0); fail ("must fail"); }
|
||||
catch (RangeException&) { }
|
||||
}
|
||||
|
||||
@ -1701,6 +1687,51 @@ void SQLiteTest::testRowIterator()
|
||||
}
|
||||
|
||||
|
||||
void SQLiteTest::testAsync()
|
||||
{
|
||||
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
|
||||
tmp << "DROP TABLE IF EXISTS Strings", now;
|
||||
tmp << "CREATE TABLE IF NOT EXISTS Strings (str INTEGER(10))", now;
|
||||
|
||||
int rowCount = 500;
|
||||
std::vector<int> data(rowCount);
|
||||
Statement stmt = (tmp << "INSERT INTO Strings VALUES(:str)", use(data));
|
||||
Statement::Result result = stmt.executeAsync();
|
||||
assert (!stmt.isAsync());
|
||||
result.wait();
|
||||
|
||||
stmt = tmp << "SELECT * FROM Strings", into(data), async, now;
|
||||
assert (stmt.isAsync());
|
||||
stmt.wait();
|
||||
|
||||
assert (stmt.execute() == 0);
|
||||
assert (stmt.isAsync());
|
||||
try {
|
||||
result = stmt.executeAsync();
|
||||
fail ("must fail");
|
||||
} catch (InvalidAccessException&)
|
||||
{
|
||||
stmt.wait();
|
||||
result = stmt.executeAsync();
|
||||
}
|
||||
|
||||
assert (stmt.wait() == rowCount);
|
||||
assert (result.data() == rowCount);
|
||||
stmt.setAsync(false);
|
||||
assert (!stmt.isAsync());
|
||||
assert (stmt.execute() == rowCount);
|
||||
|
||||
stmt = tmp << "SELECT * FROM Strings", into(data), sync, now;
|
||||
assert (!stmt.isAsync());
|
||||
assert (stmt.wait() == 0);
|
||||
assert (stmt.execute() == rowCount);
|
||||
result = stmt.executeAsync();
|
||||
assert (!stmt.isAsync());
|
||||
result.wait();
|
||||
assert (result.data() == rowCount);
|
||||
}
|
||||
|
||||
|
||||
void SQLiteTest::setUp()
|
||||
{
|
||||
}
|
||||
@ -1750,7 +1781,6 @@ CppUnit::Test* SQLiteTest::suite()
|
||||
CppUnit_addTest(pSuite, SQLiteTest, testSingleSelect);
|
||||
CppUnit_addTest(pSuite, SQLiteTest, testEmptyDB);
|
||||
CppUnit_addTest(pSuite, SQLiteTest, testBLOB);
|
||||
CppUnit_addTest(pSuite, SQLiteTest, testBLOBStmt);
|
||||
CppUnit_addTest(pSuite, SQLiteTest, testTuple10);
|
||||
CppUnit_addTest(pSuite, SQLiteTest, testTupleVector10);
|
||||
CppUnit_addTest(pSuite, SQLiteTest, testTuple9);
|
||||
@ -1775,6 +1805,7 @@ CppUnit::Test* SQLiteTest::suite()
|
||||
CppUnit_addTest(pSuite, SQLiteTest, testPrimaryKeyConstraint);
|
||||
CppUnit_addTest(pSuite, SQLiteTest, testNull);
|
||||
CppUnit_addTest(pSuite, SQLiteTest, testRowIterator);
|
||||
CppUnit_addTest(pSuite, SQLiteTest, testAsync);
|
||||
|
||||
return pSuite;
|
||||
}
|
||||
|
@ -85,7 +85,6 @@ public:
|
||||
void testEmptyDB();
|
||||
|
||||
void testBLOB();
|
||||
void testBLOBStmt();
|
||||
|
||||
void testTuple1();
|
||||
void testTupleVector1();
|
||||
@ -112,6 +111,7 @@ public:
|
||||
void testPrimaryKeyConstraint();
|
||||
void testNull();
|
||||
void testRowIterator();
|
||||
void testAsync();
|
||||
|
||||
void setUp();
|
||||
void tearDown();
|
||||
|
@ -75,7 +75,7 @@ public:
|
||||
AbstractSessionImpl()
|
||||
/// Creates the AbstractSessionImpl.
|
||||
/// Adds "storage" property and sets the default internal storage container
|
||||
/// type to std::vector.
|
||||
/// type to std::deque.
|
||||
/// The storage is created by statements automatically whenever a query
|
||||
/// returning results is executed but external storage is provided by the user.
|
||||
/// Storage type can be reconfigured at runtime both globally (for the
|
||||
@ -86,7 +86,7 @@ public:
|
||||
&AbstractSessionImpl<C>::setStorage,
|
||||
&AbstractSessionImpl<C>::getStorage);
|
||||
|
||||
setProperty("storage", std::string("vector"));
|
||||
setProperty("storage", std::string("deque"));
|
||||
}
|
||||
|
||||
~AbstractSessionImpl()
|
||||
|
@ -52,7 +52,7 @@ namespace Poco {
|
||||
namespace Data {
|
||||
|
||||
|
||||
template <class T, class C = std::vector<T> >
|
||||
template <class T, class C = std::deque<T> >
|
||||
class Column
|
||||
/// Column class is column data container.
|
||||
/// Data (a pointer to container) is assigned to the class
|
||||
|
@ -352,7 +352,7 @@ private:
|
||||
};
|
||||
|
||||
|
||||
template <class T, class C = std::vector<T> >
|
||||
template <class T, class C = std::deque<T> >
|
||||
class InternalExtraction: public Extraction<C>
|
||||
/// Container Data Type specialization extension for extraction of values from a query result set.
|
||||
///
|
||||
|
@ -144,11 +144,11 @@ public:
|
||||
switch (storage())
|
||||
{
|
||||
case STORAGE_VECTOR:
|
||||
case STORAGE_UNKNOWN:
|
||||
return column<T, std::vector<T> >(col).value(row);
|
||||
case STORAGE_LIST:
|
||||
return column<T, std::list<T> >(col).value(row);
|
||||
case STORAGE_DEQUE:
|
||||
case STORAGE_UNKNOWN:
|
||||
return column<T, std::deque<T> >(col).value(row);
|
||||
default:
|
||||
throw IllegalStateException("Invalid storage setting.");
|
||||
@ -162,11 +162,11 @@ public:
|
||||
switch (storage())
|
||||
{
|
||||
case STORAGE_VECTOR:
|
||||
case STORAGE_UNKNOWN:
|
||||
return column<T, std::vector<T> >(name).value(row);
|
||||
case STORAGE_LIST:
|
||||
return column<T, std::list<T> >(name).value(row);
|
||||
case STORAGE_DEQUE:
|
||||
case STORAGE_UNKNOWN:
|
||||
return column<T, std::deque<T> >(name).value(row);
|
||||
default:
|
||||
throw IllegalStateException("Invalid storage setting.");
|
||||
|
@ -87,7 +87,11 @@ class Data_API SessionPool
|
||||
/// ...
|
||||
{
|
||||
public:
|
||||
SessionPool(const std::string& sessionKey, const std::string& connectionString, int minSessions = 1, int maxSessions = 32, int idleTime = 60);
|
||||
SessionPool(const std::string& sessionKey,
|
||||
const std::string& connectionString,
|
||||
int minSessions = 1,
|
||||
int maxSessions = 32,
|
||||
int idleTime = 60);
|
||||
/// Creates the SessionPool for sessions with the given sessionKey
|
||||
/// and connectionString.
|
||||
///
|
||||
|
@ -44,6 +44,8 @@
|
||||
#include "Poco/Data/StatementImpl.h"
|
||||
#include "Poco/Data/Range.h"
|
||||
#include "Poco/SharedPtr.h"
|
||||
#include "Poco/ActiveMethod.h"
|
||||
#include "Poco/ActiveResult.h"
|
||||
|
||||
|
||||
namespace Poco {
|
||||
@ -60,15 +62,67 @@ class Data_API Statement
|
||||
/// A Statement is used to execute SQL statements.
|
||||
/// It does not contain code of its own.
|
||||
/// Its main purpose is to forward calls to the concrete StatementImpl stored inside.
|
||||
/// Statement execution can be synchronous or asynchronous.
|
||||
/// Synchronous ececution is achieved through execute() call, while asynchronous is
|
||||
/// achieved through executeAsync() method call.
|
||||
/// An asynchronously executing statement should not be copied during the execution.
|
||||
/// Copying is not prohibited, however the benefits of the asynchronous call shall
|
||||
/// be lost for that particular call since the synchronizing call shall internally be
|
||||
/// called in the copy constructor.
|
||||
///
|
||||
/// For example, in the following case, although the execution is asyncronous, the
|
||||
/// synchronization part happens in the copy constructor, so the asynchronous nature
|
||||
/// of the statement is lost for the end user:
|
||||
///
|
||||
/// Statement stmt = (session << "SELECT * FROM Table", async, now);
|
||||
///
|
||||
/// while in this case it is preserved:
|
||||
///
|
||||
/// Statement stmt = session << "SELECT * FROM Table", async, now;
|
||||
///
|
||||
/// There are two ways to preserve the asynchronous nature of a statement:
|
||||
///
|
||||
/// 1) Call executeAsync() method directly:
|
||||
///
|
||||
/// Statement stmt = session << "SELECT * FROM Table"; // no execution yet
|
||||
/// stmt.executeAsync(); // asynchronous execution
|
||||
/// // do something else ...
|
||||
/// stmt.wait(); // synchronize
|
||||
///
|
||||
/// 2) Ensure asynchronous execution through careful syntax constructs:
|
||||
///
|
||||
/// Statement stmt(session);
|
||||
/// stmt = session << "SELECT * FROM Table", async, now;
|
||||
/// // do something else ...
|
||||
/// stmt.wait(); // synchronize
|
||||
///
|
||||
/// Note:
|
||||
///
|
||||
/// Once set as asynchronous through 'async' manipulator, statement remains
|
||||
/// asynchronous for all subsequent execution calls, both execute() and executeAsync().
|
||||
/// However, calling executAsync() on a synchronous statement shall execute
|
||||
/// asynchronously but without altering the underlying statement's synchronous nature.
|
||||
///
|
||||
/// Once asyncronous, a statement can be reverted back to synchronous state in two ways:
|
||||
///
|
||||
/// 1) By calling setAsync(false)
|
||||
/// 2) By means of 'sync' or 'reset' manipulators
|
||||
///
|
||||
/// See individual functions documentation for more details.
|
||||
///
|
||||
{
|
||||
public:
|
||||
typedef void (*Manipulator)(Statement&);
|
||||
typedef Poco::UInt32 ResultType;
|
||||
typedef ActiveResult<ResultType> Result;
|
||||
typedef SharedPtr<Result> ResultPtr;
|
||||
typedef ActiveMethod<ResultType, void, StatementImpl> AsyncExecMethod;
|
||||
|
||||
enum Storage
|
||||
{
|
||||
STORAGE_DEQUE = StatementImpl::STORAGE_DEQUE_IMPL,
|
||||
STORAGE_VECTOR = StatementImpl::STORAGE_VECTOR_IMPL,
|
||||
STORAGE_LIST = StatementImpl::STORAGE_LIST_IMPL,
|
||||
STORAGE_DEQUE = StatementImpl::STORAGE_DEQUE_IMPL,
|
||||
STORAGE_UNKNOWN = StatementImpl::STORAGE_UNKNOWN_IMPL
|
||||
};
|
||||
|
||||
@ -93,7 +147,10 @@ public:
|
||||
/// Destroys the Statement.
|
||||
|
||||
Statement(const Statement& stmt);
|
||||
/// Copy constructor
|
||||
/// Copy constructor.
|
||||
/// If the statement has been executed asynchronously and has not been
|
||||
/// synchronized prior to copy operation (i.e. is copied while executing),
|
||||
/// this constructor shall synchronize it.
|
||||
|
||||
Statement& operator = (const Statement& stmt);
|
||||
/// Assignment operator.
|
||||
@ -103,7 +160,7 @@ public:
|
||||
|
||||
template <typename T>
|
||||
Statement& operator << (const T& t)
|
||||
/// Concatenates the send data to a string version of the SQL statement.
|
||||
/// Concatenates data with the SQL statement string.
|
||||
{
|
||||
_ptr->add(t);
|
||||
return *this;
|
||||
@ -121,7 +178,7 @@ public:
|
||||
Statement& operator , (const Limit& extrLimit);
|
||||
/// Sets a limit on the maximum number of rows a select is allowed to return.
|
||||
///
|
||||
/// Set per default to Limit::LIMIT_UNLIMITED which disables the limit.
|
||||
/// Set per default to zero to Limit::LIMIT_UNLIMITED, which disables the limit.
|
||||
|
||||
Statement& operator , (const Range& extrRange);
|
||||
/// Sets a an etxraction Range on the maximum number of rows a select is allowed to return.
|
||||
@ -131,13 +188,43 @@ public:
|
||||
std::string toString() const;
|
||||
/// Creates a string from the accumulated SQL statement
|
||||
|
||||
Poco::UInt32 execute();
|
||||
/// Executes the whole statement. Stops when either a limit is hit or the whole statement was executed.
|
||||
/// Returns the number of rows extracted from the Database.
|
||||
ResultType execute();
|
||||
/// Executes the statement synchronously or asynchronously.
|
||||
/// Stops when either a limit is hit or the whole statement was executed.
|
||||
/// Returns the number of rows extracted from the database.
|
||||
/// If isAsync() returns true, the statement is executed asynchronously
|
||||
/// and the return value from this function is zero.
|
||||
/// The number of extracted rows from the query can be obtained by calling
|
||||
/// wait().
|
||||
|
||||
const Result& executeAsync();
|
||||
/// Executes the statement asynchronously.
|
||||
/// Stops when either a limit is hit or the whole statement was executed.
|
||||
/// Returns immediately. For statements returning data, the number of rows extracted is
|
||||
/// available by calling wait() method on either the returned value or the statement itself.
|
||||
/// When executed on otherwise synchronous statement, this method does not alter the
|
||||
/// statement's synchronous nature.
|
||||
|
||||
void setAsync(bool async);
|
||||
/// Sets the asynchronous flag. If this flag is true, executeAsync() is called
|
||||
/// from the now() manipulator. This setting does not affect the statement's
|
||||
/// capability to be executed synchronously by directly calling execute().
|
||||
|
||||
bool isAsync() const;
|
||||
/// Returns true if statement was marked for asynchronous execution.
|
||||
|
||||
Statement::ResultType wait(long milliseconds = WAIT_FOREVER);
|
||||
/// Waits for the execution completion for asynchronous statements or
|
||||
/// returns immediately for synchronous ones. The return value for
|
||||
/// asynchronous statement is the execution result (i.e. number of
|
||||
/// rows retrieved). For synchronous statements, the return value is zero.
|
||||
|
||||
bool initialized();
|
||||
/// Returns true if the statement was initialized (i.e. not executed yet).
|
||||
|
||||
bool done();
|
||||
/// Returns if the statement was completely executed or if a previously set limit stopped it
|
||||
/// and there is more work to do. When no limit is set, it will always - after calling execute() - return true.
|
||||
/// Returns true if the statement was completely executed or false if a range limit stopped it
|
||||
/// and there is more work to do. When no limit is set, it will always return true after calling execute().
|
||||
|
||||
Statement& reset(Session& session);
|
||||
/// Resets the Statement so that it can be filled with a new SQL command.
|
||||
@ -174,25 +261,59 @@ protected:
|
||||
private:
|
||||
typedef Poco::SharedPtr<StatementImpl> StatementImplPtr;
|
||||
|
||||
static const int WAIT_FOREVER = -1;
|
||||
|
||||
StatementImplPtr _ptr;
|
||||
|
||||
// asynchronous execution related members
|
||||
bool _isAsync;
|
||||
mutable ResultPtr _pResult;
|
||||
FastMutex _mutex;
|
||||
AsyncExecMethod _asyncExec;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Manipulators
|
||||
//
|
||||
|
||||
void Data_API now(Statement& statement);
|
||||
/// Enforces immediate execution of the statement.
|
||||
/// If _isAsync flag has been set, execution is invoked asynchronously.
|
||||
|
||||
void Data_API vector(Statement& statement);
|
||||
|
||||
void Data_API list(Statement& statement);
|
||||
void Data_API sync(Statement& statement);
|
||||
/// Sets the _isAsync flag to false, signalling synchronous execution.
|
||||
/// Synchronous execution is default, so specifying this manipulator
|
||||
/// only makes sense if async() was called for the statement before.
|
||||
|
||||
|
||||
void Data_API async(Statement& statement);
|
||||
/// Sets the _isAsync flag to true, signalling asynchronous execution.
|
||||
|
||||
|
||||
void Data_API deque(Statement& statement);
|
||||
/// Sets the internal storage to std::deque.
|
||||
/// std::deque is default storage, so specifying this manipulator
|
||||
/// only makes sense if list() or deque() were called for the statement before.
|
||||
|
||||
|
||||
void Data_API vector(Statement& statement);
|
||||
/// Sets the internal storage to std::vector.
|
||||
|
||||
|
||||
void Data_API list(Statement& statement);
|
||||
/// Sets the internal storage to std::list.
|
||||
|
||||
|
||||
void Data_API reset(Statement& statement);
|
||||
/// Sets all internal settings to their respective default values.
|
||||
|
||||
|
||||
//
|
||||
// inlines
|
||||
//
|
||||
|
||||
inline Statement& Statement::operator , (Manipulator manip)
|
||||
{
|
||||
manip(*this);
|
||||
@ -271,12 +392,42 @@ inline Statement::Storage Statement::storage() const
|
||||
}
|
||||
|
||||
|
||||
inline bool Statement::canModifyStorage()
|
||||
{
|
||||
return (0 == extractionCount()) && (initialized() || done());
|
||||
}
|
||||
|
||||
|
||||
inline bool Statement::initialized()
|
||||
{
|
||||
return _ptr->getState() == StatementImpl::ST_INITIALIZED;
|
||||
}
|
||||
|
||||
|
||||
inline bool Statement::done()
|
||||
{
|
||||
return _ptr->getState() == StatementImpl::ST_DONE;
|
||||
}
|
||||
|
||||
|
||||
inline bool Statement::isNull(std::size_t col, std::size_t row) const
|
||||
{
|
||||
return _ptr->isNull(col, row);
|
||||
}
|
||||
|
||||
|
||||
inline void Statement::setAsync(bool async)
|
||||
{
|
||||
_isAsync = async;
|
||||
}
|
||||
|
||||
|
||||
inline bool Statement::isAsync() const
|
||||
{
|
||||
return _isAsync;
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Data
|
||||
|
||||
|
||||
|
@ -79,15 +79,15 @@ public:
|
||||
|
||||
enum Storage
|
||||
{
|
||||
STORAGE_DEQUE_IMPL,
|
||||
STORAGE_VECTOR_IMPL,
|
||||
STORAGE_LIST_IMPL,
|
||||
STORAGE_DEQUE_IMPL,
|
||||
STORAGE_UNKNOWN_IMPL
|
||||
};
|
||||
|
||||
static const std::string DEQUE;
|
||||
static const std::string VECTOR;
|
||||
static const std::string LIST;
|
||||
static const std::string DEQUE;
|
||||
static const std::string UNKNOWN;
|
||||
|
||||
StatementImpl(SessionImpl& rSession);
|
||||
@ -97,7 +97,7 @@ public:
|
||||
/// Destroys the StatementImpl.
|
||||
|
||||
template <typename T> void add(const T& t)
|
||||
/// Appends SQl statement (fragments).
|
||||
/// Appends SQL statement (fragments).
|
||||
{
|
||||
_ostr << t;
|
||||
}
|
||||
@ -272,31 +272,31 @@ private:
|
||||
/// overrides the session setting for storage, otherwise the
|
||||
/// session setting is used.
|
||||
/// If neither this statement nor the session have the storage
|
||||
/// type set, std::vector is the default container type used.
|
||||
/// type set, std::deque is the default container type used.
|
||||
{
|
||||
std::string storage;
|
||||
|
||||
switch (_storage)
|
||||
{
|
||||
case STORAGE_DEQUE_IMPL:
|
||||
storage = DEQUE; break;
|
||||
case STORAGE_VECTOR_IMPL:
|
||||
storage = VECTOR; break;
|
||||
case STORAGE_LIST_IMPL:
|
||||
storage = LIST; break;
|
||||
case STORAGE_DEQUE_IMPL:
|
||||
storage = DEQUE; break;
|
||||
case STORAGE_UNKNOWN_IMPL:
|
||||
storage = AnyCast<std::string>(session().getProperty("storage"));
|
||||
break;
|
||||
}
|
||||
|
||||
if (storage.empty()) storage = VECTOR;
|
||||
if (storage.empty()) storage = DEQUE;
|
||||
|
||||
if (0 == icompare(VECTOR, storage))
|
||||
if (0 == icompare(DEQUE, storage))
|
||||
addExtract(createExtract<T, std::deque<T> >(mc));
|
||||
else if (0 == icompare(VECTOR, storage))
|
||||
addExtract(createExtract<T, std::vector<T> >(mc));
|
||||
else if (0 == icompare(LIST, storage))
|
||||
addExtract(createExtract<T, std::list<T> >(mc));
|
||||
else if (0 == icompare(DEQUE, storage))
|
||||
addExtract(createExtract<T, std::deque<T> >(mc));
|
||||
}
|
||||
|
||||
bool isNull(std::size_t col, std::size_t row) const;
|
||||
|
@ -51,7 +51,7 @@ SessionPool::SessionPool(const std::string& sessionKey, const std::string& conne
|
||||
_maxSessions(maxSessions),
|
||||
_idleTime(idleTime),
|
||||
_nSessions(0),
|
||||
_janitorTimer(idleTime, idleTime/4)
|
||||
_janitorTimer(1000*idleTime, 1000*idleTime/4)
|
||||
{
|
||||
Poco::TimerCallback<SessionPool> callback(*this, &SessionPool::onJanitorTimer);
|
||||
_janitorTimer.start(callback);
|
||||
|
@ -40,6 +40,7 @@
|
||||
#include "Poco/Data/Session.h"
|
||||
#include "Poco/Any.h"
|
||||
#include "Poco/Tuple.h"
|
||||
#include "Poco/ActiveMethod.h"
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
@ -48,21 +49,30 @@ namespace Data {
|
||||
|
||||
|
||||
Statement::Statement(StatementImpl* pImpl):
|
||||
_ptr(pImpl)
|
||||
_ptr(pImpl),
|
||||
_isAsync(false),
|
||||
_asyncExec(_ptr, &StatementImpl::execute)
|
||||
{
|
||||
poco_check_ptr (pImpl);
|
||||
}
|
||||
|
||||
|
||||
Statement::Statement(Session& session)
|
||||
Statement::Statement(Session& session):
|
||||
_asyncExec(_ptr, &StatementImpl::execute)
|
||||
{
|
||||
reset(session);
|
||||
}
|
||||
|
||||
|
||||
Statement::Statement(const Statement& stmt):
|
||||
_ptr(stmt._ptr)
|
||||
_ptr(stmt._ptr),
|
||||
_isAsync(stmt._isAsync),
|
||||
_pResult(stmt._pResult),
|
||||
_asyncExec(_ptr, &StatementImpl::execute)
|
||||
{
|
||||
// if executing asynchronously, wait
|
||||
if (stmt._pResult)
|
||||
stmt._pResult->wait();
|
||||
}
|
||||
|
||||
|
||||
@ -82,31 +92,56 @@ Statement& Statement::operator = (const Statement& stmt)
|
||||
void Statement::swap(Statement& other)
|
||||
{
|
||||
std::swap(_ptr, other._ptr);
|
||||
std::swap(_isAsync, other._isAsync);
|
||||
std::swap(_asyncExec, other._asyncExec);
|
||||
std::swap(_pResult, other._pResult);
|
||||
}
|
||||
|
||||
|
||||
Poco::UInt32 Statement::execute()
|
||||
Statement::ResultType Statement::execute()
|
||||
{
|
||||
if (done())
|
||||
if (!isAsync())
|
||||
{
|
||||
_ptr->reset();
|
||||
}
|
||||
|
||||
if (done()) _ptr->reset();
|
||||
return _ptr->execute();
|
||||
}
|
||||
else
|
||||
{
|
||||
executeAsync();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool Statement::done()
|
||||
const Statement::Result& Statement::executeAsync()
|
||||
{
|
||||
return _ptr->getState() == StatementImpl::ST_DONE;
|
||||
FastMutex::ScopedLock lock(_mutex);
|
||||
bool isDone = done();
|
||||
if (initialized() || isDone)
|
||||
{
|
||||
if (isDone) _ptr->reset();
|
||||
_pResult = new Result(_asyncExec());
|
||||
poco_check_ptr (_pResult);
|
||||
return *_pResult;
|
||||
}
|
||||
else
|
||||
throw InvalidAccessException("Statement still executing.");
|
||||
}
|
||||
|
||||
|
||||
bool Statement::canModifyStorage()
|
||||
Statement::ResultType Statement::wait(long milliseconds)
|
||||
{
|
||||
return 0 == extractionCount() &&
|
||||
(_ptr->getState() == StatementImpl::ST_INITIALIZED ||
|
||||
_ptr->getState() == StatementImpl::ST_RESET);
|
||||
if (!_pResult) return 0;
|
||||
|
||||
if (WAIT_FOREVER != milliseconds)
|
||||
_pResult->wait(milliseconds);
|
||||
else
|
||||
_pResult->wait();
|
||||
|
||||
if (_pResult->exception())
|
||||
throw *_pResult->exception();
|
||||
|
||||
return _pResult->data();
|
||||
}
|
||||
|
||||
|
||||
@ -142,6 +177,18 @@ void now(Statement& statement)
|
||||
}
|
||||
|
||||
|
||||
void sync(Statement& statement)
|
||||
{
|
||||
statement.setAsync(false);
|
||||
}
|
||||
|
||||
|
||||
void async(Statement& statement)
|
||||
{
|
||||
statement.setAsync(true);
|
||||
}
|
||||
|
||||
|
||||
void vector(Statement& statement)
|
||||
{
|
||||
if (!statement.canModifyStorage())
|
||||
@ -169,4 +216,14 @@ void deque(Statement& statement)
|
||||
}
|
||||
|
||||
|
||||
void reset(Statement& statement)
|
||||
{
|
||||
if (!statement.canModifyStorage())
|
||||
throw InvalidAccessException("Storage not modifiable.");
|
||||
|
||||
statement.setStorage("deque");
|
||||
statement.setAsync(false);
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Data
|
||||
|
@ -99,9 +99,7 @@ Poco::UInt32 StatementImpl::execute()
|
||||
Poco::UInt32 StatementImpl::executeWithLimit()
|
||||
{
|
||||
poco_assert (_state != ST_DONE);
|
||||
|
||||
compile();
|
||||
|
||||
Poco::UInt32 count = 0;
|
||||
do
|
||||
{
|
||||
@ -111,8 +109,7 @@ Poco::UInt32 StatementImpl::executeWithLimit()
|
||||
next();
|
||||
++count;
|
||||
}
|
||||
}
|
||||
while (canBind());
|
||||
} while (canBind());
|
||||
|
||||
if (!canBind() && (!hasNext() || _extrLimit.value() == 0))
|
||||
_state = ST_DONE;
|
||||
@ -126,9 +123,7 @@ Poco::UInt32 StatementImpl::executeWithLimit()
|
||||
Poco::UInt32 StatementImpl::executeWithoutLimit()
|
||||
{
|
||||
poco_assert (_state != ST_DONE);
|
||||
|
||||
compile();
|
||||
|
||||
Poco::UInt32 count = 0;
|
||||
do
|
||||
{
|
||||
@ -138,8 +133,7 @@ Poco::UInt32 StatementImpl::executeWithoutLimit()
|
||||
next();
|
||||
++count;
|
||||
}
|
||||
}
|
||||
while (canBind());
|
||||
} while (canBind());
|
||||
|
||||
_state = ST_DONE;
|
||||
return count;
|
||||
@ -268,12 +262,12 @@ void StatementImpl::resetExtraction()
|
||||
|
||||
void StatementImpl::setStorage(const std::string& storage)
|
||||
{
|
||||
if (0 == icompare(VECTOR, storage))
|
||||
if (0 == icompare(DEQUE, storage))
|
||||
_storage = STORAGE_DEQUE_IMPL;
|
||||
else if (0 == icompare(VECTOR, storage))
|
||||
_storage = STORAGE_VECTOR_IMPL;
|
||||
else if (0 == icompare(LIST, storage))
|
||||
_storage = STORAGE_LIST_IMPL;
|
||||
else if (0 == icompare(DEQUE, storage))
|
||||
_storage = STORAGE_DEQUE_IMPL;
|
||||
else if (0 == icompare(UNKNOWN, storage))
|
||||
_storage = STORAGE_UNKNOWN_IMPL;
|
||||
else
|
||||
|
@ -368,7 +368,7 @@ void DataTest::testColumnVector()
|
||||
pData->push_back(4);
|
||||
pData->push_back(5);
|
||||
|
||||
Column<int> c(mc, pData);
|
||||
Column<int, std::vector<int> > c(mc, pData);
|
||||
|
||||
assert (c.rowCount() == 5);
|
||||
assert (c[0] == 1);
|
||||
@ -389,7 +389,7 @@ void DataTest::testColumnVector()
|
||||
}
|
||||
catch (RangeException&) { }
|
||||
|
||||
Column<int> c1 = c;
|
||||
Column<int, std::vector<int> > c1 = c;
|
||||
|
||||
assert (c1.rowCount() == 5);
|
||||
assert (c1[0] == 1);
|
||||
@ -398,7 +398,7 @@ void DataTest::testColumnVector()
|
||||
assert (c1[3] == 4);
|
||||
assert (c1[4] == 5);
|
||||
|
||||
Column<int> c2(c1);
|
||||
Column<int, std::vector<int> > c2(c1);
|
||||
|
||||
assert (c2.rowCount() == 5);
|
||||
assert (c2[0] == 1);
|
||||
@ -434,7 +434,7 @@ void DataTest::testColumnVectorBool()
|
||||
pData->push_back(false);
|
||||
pData->push_back(true);
|
||||
|
||||
Column<bool> c(mc, pData);
|
||||
Column<bool, std::vector<bool> > c(mc, pData);
|
||||
|
||||
assert (c.rowCount() == 5);
|
||||
assert (c[0] == true);
|
||||
@ -451,7 +451,7 @@ void DataTest::testColumnVectorBool()
|
||||
}
|
||||
catch (RangeException&) { }
|
||||
|
||||
Column<bool> c1 = c;
|
||||
Column<bool, std::vector<bool> > c1 = c;
|
||||
|
||||
assert (c1.rowCount() == 5);
|
||||
assert (c1[0] == true);
|
||||
@ -460,7 +460,7 @@ void DataTest::testColumnVectorBool()
|
||||
assert (c1[3] == false);
|
||||
assert (c1[4] == true);
|
||||
|
||||
Column<bool> c2(c1);
|
||||
Column<bool, std::vector<bool> > c2(c1);
|
||||
|
||||
assert (c2.rowCount() == 5);
|
||||
assert (c2[0] == true);
|
||||
@ -488,7 +488,7 @@ void DataTest::testColumnVectorBool()
|
||||
void DataTest::testColumnDeque()
|
||||
{
|
||||
typedef std::deque<int> ContainerType;
|
||||
typedef Column<int, ContainerType> ColumnType;
|
||||
typedef Column<int> ColumnType;
|
||||
|
||||
MetaColumn mc(0, "mc", MetaColumn::FDT_DOUBLE, 2, 3, true);
|
||||
|
||||
|
@ -115,10 +115,27 @@ public:
|
||||
return result;
|
||||
}
|
||||
|
||||
ActiveMethod(const ActiveMethod& other):
|
||||
_pOwner(other._pOwner),
|
||||
_method(other._method)
|
||||
{
|
||||
}
|
||||
|
||||
ActiveMethod& operator = (const ActiveMethod& other)
|
||||
{
|
||||
ActiveMethod tmp(other);
|
||||
swap(tmp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void swap(ActiveMethod& other)
|
||||
{
|
||||
std::swap(_pOwner, other._pOwner);
|
||||
std::swap(_method, other._method);
|
||||
}
|
||||
|
||||
private:
|
||||
ActiveMethod();
|
||||
ActiveMethod(const ActiveMethod&);
|
||||
ActiveMethod& operator = (const ActiveMethod&);
|
||||
|
||||
OwnerType* _pOwner;
|
||||
Callback _method;
|
||||
@ -190,10 +207,27 @@ public:
|
||||
return result;
|
||||
}
|
||||
|
||||
ActiveMethod(const ActiveMethod& other):
|
||||
_pOwner(other._pOwner),
|
||||
_method(other._method)
|
||||
{
|
||||
}
|
||||
|
||||
ActiveMethod& operator = (const ActiveMethod& other)
|
||||
{
|
||||
ActiveMethod tmp(other);
|
||||
swap(tmp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void swap(ActiveMethod& other)
|
||||
{
|
||||
std::swap(_pOwner, other._pOwner);
|
||||
std::swap(_method, other._method);
|
||||
}
|
||||
|
||||
private:
|
||||
ActiveMethod();
|
||||
ActiveMethod(const ActiveMethod&);
|
||||
ActiveMethod& operator = (const ActiveMethod&);
|
||||
|
||||
OwnerType* _pOwner;
|
||||
Callback _method;
|
||||
|
@ -51,6 +51,11 @@ namespace
|
||||
class ActiveObject
|
||||
{
|
||||
public:
|
||||
typedef ActiveMethod<int, int, ActiveObject> IntIntType;
|
||||
typedef ActiveMethod<void, int, ActiveObject> VoidIntType;
|
||||
typedef ActiveMethod<void, void, ActiveObject> VoidVoidType;
|
||||
typedef ActiveMethod<int, void, ActiveObject> IntVoidType;
|
||||
|
||||
ActiveObject():
|
||||
testMethod(this, &ActiveObject::testMethodImpl),
|
||||
testVoid(this,&ActiveObject::testVoidOutImpl),
|
||||
@ -63,13 +68,13 @@ namespace
|
||||
{
|
||||
}
|
||||
|
||||
ActiveMethod<int, int, ActiveObject> testMethod;
|
||||
IntIntType testMethod;
|
||||
|
||||
ActiveMethod<void, int, ActiveObject> testVoid;
|
||||
VoidIntType testVoid;
|
||||
|
||||
ActiveMethod<void, void, ActiveObject> testVoidInOut;
|
||||
VoidVoidType testVoidInOut;
|
||||
|
||||
ActiveMethod<int, void, ActiveObject> testVoidIn;
|
||||
IntVoidType testVoidIn;
|
||||
|
||||
void cont()
|
||||
{
|
||||
@ -130,6 +135,46 @@ void ActiveMethodTest::testWait()
|
||||
}
|
||||
|
||||
|
||||
void ActiveMethodTest::testCopy()
|
||||
{
|
||||
ActiveObject activeObj;
|
||||
|
||||
ActiveObject::IntIntType ii = activeObj.testMethod;
|
||||
ActiveResult<int> rii = ii(123);
|
||||
assert (!rii.available());
|
||||
activeObj.cont();
|
||||
rii.wait();
|
||||
assert (rii.available());
|
||||
assert (rii.data() == 123);
|
||||
assert (!rii.failed());
|
||||
|
||||
ActiveObject::VoidIntType vi = activeObj.testVoid;
|
||||
ActiveResult<void> rvi = vi(123);
|
||||
assert (!rvi.available());
|
||||
activeObj.cont();
|
||||
rvi.wait();
|
||||
assert (rvi.available());
|
||||
assert (!rvi.failed());
|
||||
|
||||
ActiveObject::VoidVoidType vv = activeObj.testVoidInOut;
|
||||
ActiveResult<void> rvv = vv();
|
||||
assert (!rvv.available());
|
||||
activeObj.cont();
|
||||
rvv.wait();
|
||||
assert (rvv.available());
|
||||
assert (!rvv.failed());
|
||||
|
||||
ActiveObject::IntVoidType iv = activeObj.testVoidIn;
|
||||
ActiveResult<int> riv = iv();
|
||||
assert (!riv.available());
|
||||
activeObj.cont();
|
||||
riv.wait();
|
||||
assert (riv.available());
|
||||
assert (riv.data() == 123);
|
||||
assert (!riv.failed());
|
||||
}
|
||||
|
||||
|
||||
void ActiveMethodTest::testWaitInterval()
|
||||
{
|
||||
ActiveObject activeObj;
|
||||
@ -226,6 +271,7 @@ CppUnit::Test* ActiveMethodTest::suite()
|
||||
CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("ActiveMethodTest");
|
||||
|
||||
CppUnit_addTest(pSuite, ActiveMethodTest, testWait);
|
||||
CppUnit_addTest(pSuite, ActiveMethodTest, testCopy);
|
||||
CppUnit_addTest(pSuite, ActiveMethodTest, testWaitInterval);
|
||||
CppUnit_addTest(pSuite, ActiveMethodTest, testTryWait);
|
||||
CppUnit_addTest(pSuite, ActiveMethodTest, testFailure);
|
||||
|
@ -47,6 +47,7 @@ public:
|
||||
~ActiveMethodTest();
|
||||
|
||||
void testWait();
|
||||
void testCopy();
|
||||
void testWaitInterval();
|
||||
void testTryWait();
|
||||
void testFailure();
|
||||
|
@ -3,4 +3,7 @@ XML
|
||||
Util
|
||||
Net
|
||||
NetSSL_OpenSSL
|
||||
Data
|
||||
Data/SQLite
|
||||
Data/ODBC
|
||||
CppUnit
|
||||
|
Loading…
Reference in New Issue
Block a user