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:
Aleksandar Fabijanic 2007-09-29 18:40:43 +00:00
parent 0dfd7bec3b
commit 6e380b6b13
34 changed files with 598 additions and 116 deletions

View File

@ -300,15 +300,21 @@ SQLSMALLINT Binder::toODBCDirection(Direction dir) const
void Binder::synchronize()
{
TimestampMap::iterator itTS = _timestamps.begin();
TimestampMap::iterator itTSEnd = _timestamps.end();
for(; itTS != itTSEnd; ++itTS)
Utility::dateTimeSync(*itTS->second, *itTS->first);
if (_timestamps.size())
{
TimestampMap::iterator itTS = _timestamps.begin();
TimestampMap::iterator itTSEnd = _timestamps.end();
for(; itTS != itTSEnd; ++itTS)
Utility::dateTimeSync(*itTS->second, *itTS->first);
}
StringMap::iterator itStr = _strings.begin();
StringMap::iterator itStrEnd = _strings.end();
for(; itStr != itStrEnd; ++itStr)
itStr->second->assign(itStr->first, strlen(itStr->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));
}
}

View File

@ -212,6 +212,7 @@ void ODBCStatementImpl::putData()
void ODBCStatementImpl::clear()
{
SQLRETURN rc = SQLCloseCursor(_stmt);
_stepCalled = false;
if (Utility::isError(rc))
{
StatementError err(_stmt);

View File

@ -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;
}

View File

@ -125,6 +125,8 @@ public:
void testNull();
void testRowIterator();
void testAsync();
void setUp();
void tearDown();

View File

@ -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;
}

View File

@ -127,6 +127,8 @@ public:
void testNull();
void testRowIterator();
void testAsync();
void setUp();
void tearDown();

View File

@ -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;
}

View File

@ -125,6 +125,8 @@ public:
void testNull();
void testRowIterator();
void testAsync();
void setUp();
void tearDown();

View File

@ -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;
}

View File

@ -133,6 +133,8 @@ public:
void testRowIterator();
void testStdVectorBool();
void testAsync();
void setUp();
void tearDown();

View File

@ -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;
}

View File

@ -129,6 +129,8 @@ public:
void testRowIterator();
void testStdVectorBool();
void testAsync();
void setUp();
void tearDown();

View File

@ -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;
}

View File

@ -122,6 +122,8 @@ public:
void testNull();
void testRowIterator();
void testAsync();
void setUp();
void tearDown();

View File

@ -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);
}

View File

@ -134,6 +134,8 @@ public:
void rowIterator();
void stdVectorBool();
void asynchronous();
private:
Poco::Data::Session* _pSession;
};

View File

@ -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") ||

View File

@ -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;
}

View File

@ -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();

View File

@ -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()

View File

@ -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

View File

@ -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.
///

View File

@ -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.");

View File

@ -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.
///

View File

@ -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;
StatementImplPtr _ptr;
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

View File

@ -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;

View File

@ -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);

View File

@ -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;
}
return _ptr->execute();
}
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

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -47,6 +47,7 @@ public:
~ActiveMethodTest();
void testWait();
void testCopy();
void testWaitInterval();
void testTryWait();
void testFailure();

View File

@ -3,4 +3,7 @@ XML
Util
Net
NetSSL_OpenSSL
Data
Data/SQLite
Data/ODBC
CppUnit