- SQL logging channel and archiving strategy

- row formatting refactored
- affected row count for insert, delete and update returned from Statement::execute()
- internal SQL string formatting capability using Poco::format()
This commit is contained in:
Aleksandar Fabijanic
2008-01-12 18:25:27 +00:00
parent b57f579d16
commit 9e8e627347
63 changed files with 2556 additions and 337 deletions

View File

@@ -247,6 +247,9 @@
<File
RelativePath=".\include\Poco\Data\SessionImpl.h">
</File>
<File
RelativePath=".\include\Poco\Data\SimpleRowFormatter.h">
</File>
<File
RelativePath=".\include\Poco\Data\Statement.h">
</File>
@@ -335,6 +338,9 @@
<File
RelativePath=".\src\SessionImpl.cpp">
</File>
<File
RelativePath=".\src\SimpleRowFormatter.cpp">
</File>
<File
RelativePath=".\src\Statement.cpp">
</File>
@@ -379,6 +385,30 @@
</File>
</Filter>
</Filter>
<Filter
Name="Logging"
Filter="">
<Filter
Name="Header Files"
Filter="">
<File
RelativePath=".\include\Poco\Data\ArchiveStrategy.h">
</File>
<File
RelativePath=".\include\Poco\Data\SQLChannel.h">
</File>
</Filter>
<Filter
Name="Source Files"
Filter="">
<File
RelativePath=".\src\ArchiveStrategy.cpp">
</File>
<File
RelativePath=".\src\SQLChannel.cpp">
</File>
</Filter>
</Filter>
</Files>
<Globals>
</Globals>

View File

@@ -333,6 +333,10 @@
RelativePath=".\include\Poco\Data\SessionImpl.h"
>
</File>
<File
RelativePath=".\include\Poco\Data\SimpleRowFormatter.h"
>
</File>
<File
RelativePath=".\include\Poco\Data\Statement.h"
>
@@ -449,6 +453,10 @@
RelativePath=".\src\SessionImpl.cpp"
>
</File>
<File
RelativePath=".\src\SimpleRowFormatter.cpp"
>
</File>
<File
RelativePath=".\src\Statement.cpp"
>
@@ -503,6 +511,34 @@
</File>
</Filter>
</Filter>
<Filter
Name="Logging"
>
<Filter
Name="Header Files"
>
<File
RelativePath=".\include\Poco\Data\ArchiveStrategy.h"
>
</File>
<File
RelativePath=".\include\Poco\Data\SQLChannel.h"
>
</File>
</Filter>
<Filter
Name="Source Files"
>
<File
RelativePath=".\src\ArchiveStrategy.cpp"
>
</File>
<File
RelativePath=".\src\SQLChannel.cpp"
>
</File>
</Filter>
</Filter>
</Files>
<Globals>
</Globals>

View File

@@ -9,12 +9,12 @@
include $(POCO_BASE)/build/rules/global
objects = AbstractBinder AbstractBinding AbstractExtraction \
AbstractExtractor AbstractPreparation AbstractPrepare Bulk \
Connector BLOB BLOBStream DataException Date Limit MetaColumn \
AbstractExtractor AbstractPreparation AbstractPrepare ArchiveStrategy \
Bulk Connector BLOB BLOBStream DataException Date Limit MetaColumn \
PooledSessionHolder PooledSessionImpl Position \
Range RecordSet Row RowFormatter RowIterator \
Session SessionFactory SessionImpl \
SessionPool Statement StatementCreator StatementImpl Time
SimpleRowFormatter Session SessionFactory SessionImpl \
SessionPool SQLChannel Statement StatementCreator StatementImpl Time
target = PocoData
target_version = $(LIBVERSION)

View File

@@ -62,6 +62,9 @@ public:
~Connector();
/// Destroys the Connector.
const std::string& name() const;
/// Returns the name associated with this connector.
Poco::AutoPtr<Poco::Data::SessionImpl> createSession(const std::string& connectionString);
/// Creates a ODBC SessionImpl object and initializes it with the given connectionString.
@@ -73,6 +76,15 @@ public:
};
///
/// inlines
///
inline const std::string& Connector::name() const
{
return KEY;
}
} } } // namespace Poco::Data::ODBC

View File

@@ -92,7 +92,7 @@ public:
return str;
std::string s;
format(s,
Poco::format(s,
"===========================\n"
"ODBC Diagnostic record #%d:\n"
"===========================\n"
@@ -112,7 +112,7 @@ public:
{
std::string str;
format(str,
Poco::format(str,
"Connection:%s\nServer:%s\n",
_diagnostics.connectionName(),
_diagnostics.serverName());

View File

@@ -78,6 +78,10 @@ protected:
Poco::UInt32 columnsReturned() const;
/// Returns number of columns returned by query.
Poco::UInt32 affectedRowCount() const;
/// Returns the number of affected rows.
/// Used to find out the number of rows affected by insert or update.
const MetaColumn& metaColumn(Poco::UInt32 pos) const;
/// Returns column meta data.
@@ -165,6 +169,7 @@ private:
int _nextResponse;
ColumnPtrVec _columnPtrs;
bool _prepared;
mutable Poco::UInt32 _affectedRowCount;
};

View File

@@ -134,14 +134,22 @@ void Binder::bind(std::size_t pos, const std::string& val, Direction dir)
}
else if (isInBound(dir))
{
pVal = (SQLPOINTER) val.c_str();
if (size) pVal = (SQLPOINTER) val.c_str();
_inParams.insert(ParamMap::value_type(pVal, size));
}
else
throw InvalidArgumentException("Parameter must be [in] OR [out] bound.");
SQLLEN* pLenIn = new SQLLEN;
*pLenIn = SQL_NTS;
if (0 != size) *pLenIn = SQL_NTS;
else
{
*pLenIn = SQL_NULL_DATA;
SQLINTEGER colSize = 0;
SQLSMALLINT decDigits = 0;
getColSizeAndPrecision(pos, SQL_C_CHAR, colSize, decDigits);
size = colSize;
}
if (PB_AT_EXEC == _paramBinding)
*pLenIn = SQL_LEN_DATA_AT_EXEC(size);
@@ -175,7 +183,16 @@ void Binder::bind(std::size_t pos, const BLOB& val, Direction dir)
_inParams.insert(ParamMap::value_type(pVal, size));
SQLLEN* pLenIn = new SQLLEN;
*pLenIn = size;
if (0 != size) *pLenIn = size;
else
{
*pLenIn = SQL_NULL_DATA;
SQLINTEGER colSize = 0;
SQLSMALLINT decDigits = 0;
getColSizeAndPrecision(pos, SQL_C_CHAR, colSize, decDigits);
size = colSize;
}
if (PB_AT_EXEC == _paramBinding)
*pLenIn = SQL_LEN_DATA_AT_EXEC(size);

View File

@@ -65,7 +65,7 @@ Poco::AutoPtr<Poco::Data::SessionImpl> Connector::createSession(const std::strin
void Connector::registerConnector()
{
Poco::Data::SessionFactory::instance().add(KEY, new Connector());
Poco::Data::SessionFactory::instance().add(new Connector());
}

View File

@@ -107,6 +107,7 @@ void ODBCMetaColumn::init()
case SQL_VARCHAR:
case SQL_LONGVARCHAR:
case -9:// SQL Server NVARCHAR
case -10:// PostgreSQL VARCHAR (without size specified)
setType(MetaColumn::FDT_STRING); break;
case SQL_TINYINT:
setType(MetaColumn::FDT_INT8); break;

View File

@@ -64,7 +64,8 @@ ODBCStatementImpl::ODBCStatementImpl(SessionImpl& rSession):
_stmt(rSession.dbc()),
_stepCalled(false),
_nextResponse(0),
_prepared(false)
_prepared(false),
_affectedRowCount(0)
{
}
@@ -205,6 +206,9 @@ void ODBCStatementImpl::doBind(bool clear, bool reset)
Bindings::iterator it = binds.begin();
Bindings::iterator itEnd = binds.end();
if (it != itEnd && 0 == _affectedRowCount)
_affectedRowCount = static_cast<Poco::UInt32>((*it)->numOfRowsHandled());
if (reset)
{
it = binds.begin();
@@ -257,6 +261,8 @@ void ODBCStatementImpl::clear()
{
SQLRETURN rc = SQLCloseCursor(_stmt);
_stepCalled = false;
_affectedRowCount = 0;
if (Utility::isError(rc))
{
StatementError err(_stmt);
@@ -438,4 +444,17 @@ const MetaColumn& ODBCStatementImpl::metaColumn(Poco::UInt32 pos) const
}
Poco::UInt32 ODBCStatementImpl::affectedRowCount() const
{
if (0 == _affectedRowCount)
{
SQLLEN rows;
if (!Utility::isError(SQLRowCount(_stmt, &rows)))
_affectedRowCount = static_cast<Poco::UInt32>(rows);
}
return _affectedRowCount;
}
} } } // namespace Poco::Data::ODBC

View File

@@ -555,6 +555,31 @@ void ODBCDB2Test::recreateMiscTable()
}
void ODBCDB2Test::recreateLogTable()
{
dropObject("TABLE", "T_POCO_LOG");
dropObject("TABLE", "T_POCO_LOG_ARCHIVE");
try
{
std::string sql = "CREATE TABLE %s "
"(Source VARCHAR(100),"
"Name VARCHAR(100),"
"ProcessId INTEGER,"
"Thread VARCHAR(100), "
"ThreadId INTEGER,"
"Priority INTEGER,"
"Text VARCHAR(100),"
"DateTime TIMESTAMP)";
session() << sql, "T_POCO_LOG", now;
session() << sql, "T_POCO_LOG_ARCHIVE", now;
} catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreateLogTable()"); }
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreateLogTable()"); }
}
CppUnit::Test* ODBCDB2Test::suite()
{
if (_pSession = init(_driver, _dsn, _uid, _pwd, _connectString))
@@ -580,6 +605,7 @@ CppUnit::Test* ODBCDB2Test::suite()
CppUnit_addTest(pSuite, ODBCDB2Test, testComplexTypeDeque);
CppUnit_addTest(pSuite, ODBCDB2Test, testInsertDeque);
CppUnit_addTest(pSuite, ODBCDB2Test, testInsertEmptyDeque);
CppUnit_addTest(pSuite, ODBCDB2Test, testAffectedRows);
CppUnit_addTest(pSuite, ODBCDB2Test, testInsertSingleBulk);
CppUnit_addTest(pSuite, ODBCDB2Test, testInsertSingleBulkVec);
CppUnit_addTest(pSuite, ODBCDB2Test, testLimit);
@@ -631,6 +657,8 @@ CppUnit::Test* ODBCDB2Test::suite()
CppUnit_addTest(pSuite, ODBCDB2Test, testAny);
CppUnit_addTest(pSuite, ODBCDB2Test, testDynamicAny);
CppUnit_addTest(pSuite, ODBCDB2Test, testMultipleResults);
CppUnit_addTest(pSuite, ODBCDB2Test, testSQLChannel);
CppUnit_addTest(pSuite, ODBCDB2Test, testSQLLogger);
return pSuite;
}

View File

@@ -78,6 +78,7 @@ private:
void recreateAnysTable();
void recreateNullsTable(const std::string& notNull = "");
void recreateMiscTable();
void recreateLogTable();
static ODBCTest::SessionPtr _pSession;
static ODBCTest::ExecPtr _pExecutor;

View File

@@ -373,6 +373,31 @@ void ODBCMySQLTest::recreateMiscTable()
}
void ODBCMySQLTest::recreateLogTable()
{
dropObject("TABLE", "T_POCO_LOG");
dropObject("TABLE", "T_POCO_LOG_ARCHIVE");
try
{
std::string sql = "CREATE TABLE %s "
"(Source VARCHAR(100),"
"Name VARCHAR(100),"
"ProcessId INTEGER,"
"Thread VARCHAR(100), "
"ThreadId INTEGER,"
"Priority INTEGER,"
"Text VARCHAR(100),"
"DateTime DATETIME)";
session() << sql, "T_POCO_LOG", now;
session() << sql, "T_POCO_LOG_ARCHIVE", now;
} catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreateLogTable()"); }
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreateLogTable()"); }
}
CppUnit::Test* ODBCMySQLTest::suite()
{
if (_pSession = init(_driver, _dsn, _uid, _pwd, _connectString))
@@ -398,6 +423,7 @@ CppUnit::Test* ODBCMySQLTest::suite()
CppUnit_addTest(pSuite, ODBCMySQLTest, testComplexTypeDeque);
CppUnit_addTest(pSuite, ODBCMySQLTest, testInsertDeque);
CppUnit_addTest(pSuite, ODBCMySQLTest, testInsertEmptyDeque);
CppUnit_addTest(pSuite, ODBCMySQLTest, testAffectedRows);
CppUnit_addTest(pSuite, ODBCMySQLTest, testInsertSingleBulk);
CppUnit_addTest(pSuite, ODBCMySQLTest, testInsertSingleBulkVec);
CppUnit_addTest(pSuite, ODBCMySQLTest, testLimit);
@@ -447,6 +473,8 @@ CppUnit::Test* ODBCMySQLTest::suite()
CppUnit_addTest(pSuite, ODBCMySQLTest, testAny);
CppUnit_addTest(pSuite, ODBCMySQLTest, testDynamicAny);
CppUnit_addTest(pSuite, ODBCMySQLTest, testMultipleResults);
CppUnit_addTest(pSuite, ODBCMySQLTest, testSQLChannel);
CppUnit_addTest(pSuite, ODBCMySQLTest, testSQLLogger);
return pSuite;
}

View File

@@ -83,6 +83,7 @@ private:
void recreateAnysTable();
void recreateNullsTable(const std::string& notNull = "");
void recreateMiscTable();
void recreateLogTable();
static ODBCTest::SessionPtr _pSession;
static ODBCTest::ExecPtr _pExecutor;

View File

@@ -755,6 +755,31 @@ void ODBCOracleTest::recreateMiscTable()
}
void ODBCOracleTest::recreateLogTable()
{
dropObject("TABLE", "T_POCO_LOG");
dropObject("TABLE", "T_POCO_LOG_ARCHIVE");
try
{
std::string sql = "CREATE TABLE %s "
"(Source VARCHAR(100),"
"Name VARCHAR(100),"
"ProcessId INTEGER,"
"Thread VARCHAR(100), "
"ThreadId INTEGER,"
"Priority INTEGER,"
"Text VARCHAR(100),"
"DateTime TIMESTAMP)";
session() << sql, "T_POCO_LOG", now;
session() << sql, "T_POCO_LOG_ARCHIVE", now;
} catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreateLogTable()"); }
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreateLogTable()"); }
}
CppUnit::Test* ODBCOracleTest::suite()
{
if (_pSession = init(_driver, _dsn, _uid, _pwd, _connectString))
@@ -780,6 +805,7 @@ CppUnit::Test* ODBCOracleTest::suite()
CppUnit_addTest(pSuite, ODBCOracleTest, testComplexTypeDeque);
CppUnit_addTest(pSuite, ODBCOracleTest, testInsertDeque);
CppUnit_addTest(pSuite, ODBCOracleTest, testInsertEmptyDeque);
CppUnit_addTest(pSuite, ODBCOracleTest, testAffectedRows);
CppUnit_addTest(pSuite, ODBCOracleTest, testInsertSingleBulk);
CppUnit_addTest(pSuite, ODBCOracleTest, testInsertSingleBulkVec);
CppUnit_addTest(pSuite, ODBCOracleTest, testLimit);
@@ -832,6 +858,8 @@ CppUnit::Test* ODBCOracleTest::suite()
CppUnit_addTest(pSuite, ODBCOracleTest, testAny);
CppUnit_addTest(pSuite, ODBCOracleTest, testDynamicAny);
CppUnit_addTest(pSuite, ODBCOracleTest, testMultipleResults);
CppUnit_addTest(pSuite, ODBCOracleTest, testSQLChannel);
CppUnit_addTest(pSuite, ODBCOracleTest, testSQLLogger);
return pSuite;
}

View File

@@ -85,9 +85,11 @@ private:
void recreateAnysTable();
void recreateNullsTable(const std::string& notNull = "");
void recreateMiscTable();
void recreateLogTable();
static ODBCTest::SessionPtr _pSession;
static ODBCTest::ExecPtr _pExecutor;
static std::string _driver;
static std::string _dsn;
static std::string _uid;

View File

@@ -534,6 +534,31 @@ void ODBCPostgreSQLTest::recreateMiscTable()
}
void ODBCPostgreSQLTest::recreateLogTable()
{
dropObject("TABLE", "T_POCO_LOG");
dropObject("TABLE", "T_POCO_LOG_ARCHIVE");
try
{
std::string sql = "CREATE TABLE %s "
"(Source VARCHAR,"
"Name VARCHAR,"
"ProcessId INTEGER,"
"Thread VARCHAR, "
"ThreadId INTEGER,"
"Priority INTEGER,"
"Text VARCHAR,"
"DateTime TIMESTAMP)";
session() << sql, "T_POCO_LOG", now;
session() << sql, "T_POCO_LOG_ARCHIVE", now;
} catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreateLogTable()"); }
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreateLogTable()"); }
}
CppUnit::Test* ODBCPostgreSQLTest::suite()
{
if (_pSession = init(_driver, _dsn, _uid, _pwd, _connectString))
@@ -559,6 +584,7 @@ CppUnit::Test* ODBCPostgreSQLTest::suite()
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testComplexTypeDeque);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testInsertDeque);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testInsertEmptyDeque);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testAffectedRows);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testInsertSingleBulk);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testInsertSingleBulkVec);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testLimit);
@@ -624,6 +650,8 @@ CppUnit::Test* ODBCPostgreSQLTest::suite()
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testDynamicAny);
//neither pSQL ODBC nor Mammoth drivers support multiple results properly
//CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testMultipleResults);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testSQLChannel);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testSQLLogger);
return pSuite;
}

View File

@@ -87,6 +87,7 @@ private:
void recreateNullsTable(const std::string& notNull="");
void recreateBoolTable();
void recreateMiscTable();
void recreateLogTable();
void configurePLPgSQL();
/// Configures PL/pgSQL in the database. A reasonable defaults

View File

@@ -660,6 +660,31 @@ void ODBCSQLServerTest::recreateMiscTable()
}
void ODBCSQLServerTest::recreateLogTable()
{
dropObject("TABLE", "T_POCO_LOG");
dropObject("TABLE", "T_POCO_LOG_ARCHIVE");
try
{
std::string sql = "CREATE TABLE %s "
"(Source VARCHAR(max),"
"Name VARCHAR(max),"
"ProcessId INTEGER,"
"Thread VARCHAR(max), "
"ThreadId INTEGER,"
"Priority INTEGER,"
"Text VARCHAR(max),"
"DateTime DATETIME)";
session() << sql, "T_POCO_LOG", now;
session() << sql, "T_POCO_LOG_ARCHIVE", now;
} catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreateLogTable()"); }
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreateLogTable()"); }
}
CppUnit::Test* ODBCSQLServerTest::suite()
{
if (_pSession = init(_driver, _dsn, _uid, _pwd, _connectString, _db))
@@ -685,6 +710,7 @@ CppUnit::Test* ODBCSQLServerTest::suite()
CppUnit_addTest(pSuite, ODBCSQLServerTest, testComplexTypeDeque);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testInsertDeque);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testInsertEmptyDeque);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testAffectedRows);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testInsertSingleBulk);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testInsertSingleBulkVec);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testLimit);
@@ -736,6 +762,8 @@ CppUnit::Test* ODBCSQLServerTest::suite()
CppUnit_addTest(pSuite, ODBCSQLServerTest, testAny);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testDynamicAny);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testMultipleResults);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testSQLChannel);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testSQLLogger);
return pSuite;
}

View File

@@ -91,6 +91,7 @@ private:
void recreateNullsTable(const std::string& notNull = "");
void recreateBoolTable();
void recreateMiscTable();
void recreateLogTable();
static SessionPtr _pSession;
static ExecPtr _pExecutor;

View File

@@ -125,6 +125,23 @@ void ODBCSQLiteTest::testBareboneODBC()
}
void ODBCSQLiteTest::testAffectedRows()
{
if (!_pSession) fail ("Test not available.");
for (int i = 0; i < 8;)
{
recreateStringsTable();
_pSession->setFeature("autoBind", bindValue(i));
_pSession->setFeature("autoExtract", bindValue(i+1));
// see SQLiteStatementImpl::affectedRows() documentation for explanation
// why "WHERE 1" is necessary here
_pExecutor->affectedRows("WHERE 1");
i += 2;
}
}
void ODBCSQLiteTest::testNull()
{
if (!_pSession) fail ("Test not available.");
@@ -279,6 +296,31 @@ void ODBCSQLiteTest::recreateMiscTable()
}
void ODBCSQLiteTest::recreateLogTable()
{
dropObject("TABLE", "T_POCO_LOG");
dropObject("TABLE", "T_POCO_LOG_ARCHIVE");
try
{
std::string sql = "CREATE TABLE %s "
"(Source VARCHAR,"
"Name VARCHAR,"
"ProcessId INTEGER,"
"Thread VARCHAR, "
"ThreadId INTEGER,"
"Priority INTEGER,"
"Text VARCHAR,"
"DateTime DATETIME)";
session() << sql, "T_POCO_LOG", now;
session() << sql, "T_POCO_LOG_ARCHIVE", now;
} catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreateLogTable()"); }
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreateLogTable()"); }
}
CppUnit::Test* ODBCSQLiteTest::suite()
{
if (_pSession = init(_driver, _dsn, _uid, _pwd, _connectString))
@@ -304,6 +346,7 @@ CppUnit::Test* ODBCSQLiteTest::suite()
CppUnit_addTest(pSuite, ODBCSQLiteTest, testComplexTypeDeque);
CppUnit_addTest(pSuite, ODBCSQLiteTest, testInsertDeque);
CppUnit_addTest(pSuite, ODBCSQLiteTest, testInsertEmptyDeque);
CppUnit_addTest(pSuite, ODBCSQLiteTest, testAffectedRows);
CppUnit_addTest(pSuite, ODBCSQLiteTest, testInsertSingleBulk);
CppUnit_addTest(pSuite, ODBCSQLiteTest, testInsertSingleBulkVec);
CppUnit_addTest(pSuite, ODBCSQLiteTest, testLimit);
@@ -345,6 +388,8 @@ CppUnit::Test* ODBCSQLiteTest::suite()
CppUnit_addTest(pSuite, ODBCSQLiteTest, testAsync);
CppUnit_addTest(pSuite, ODBCSQLiteTest, testAny);
CppUnit_addTest(pSuite, ODBCSQLiteTest, testDynamicAny);
CppUnit_addTest(pSuite, ODBCSQLiteTest, testSQLChannel);
CppUnit_addTest(pSuite, ODBCSQLiteTest, testSQLLogger);
return pSuite;
}

View File

@@ -53,6 +53,7 @@ public:
~ODBCSQLiteTest();
void testBareboneODBC();
void testAffectedRows();
void testNull();
static CppUnit::Test* suite();
@@ -70,6 +71,7 @@ private:
void recreateAnysTable();
void recreateNullsTable(const std::string& notNull = "");
void recreateMiscTable();
void recreateLogTable();
static ODBCTest::SessionPtr _pSession;
static ODBCTest::ExecPtr _pExecutor;

View File

@@ -306,6 +306,21 @@ void ODBCTest::testInsertEmptyDeque()
}
void ODBCTest::testAffectedRows()
{
if (!_pSession) fail ("Test not available.");
for (int i = 0; i < 8;)
{
recreateStringsTable();
_pSession->setFeature("autoBind", bindValue(i));
_pSession->setFeature("autoExtract", bindValue(i+1));
_pExecutor->affectedRows();
i += 2;
}
}
void ODBCTest::testInsertSingleBulk()
{
if (!_pSession) fail ("Test not available.");
@@ -1048,6 +1063,38 @@ void ODBCTest::testMultipleResults()
}
void ODBCTest::testSQLChannel()
{
if (!_pSession) fail ("Test not available.");
for (int i = 0; i < 8;)
{
recreateLogTable();
_pSession->setFeature("autoBind", bindValue(i));
_pSession->setFeature("autoExtract", bindValue(i+1));
_pExecutor->sqlChannel(_rConnectString);
i += 2;
}
}
void ODBCTest::testSQLLogger()
{
if (!_pSession) fail ("Test not available.");
for (int i = 0; i < 8;)
{
recreateLogTable();
_pSession->setFeature("autoBind", bindValue(i));
_pSession->setFeature("autoExtract", bindValue(i+1));
_pExecutor->sqlLogger(_rConnectString);
i += 2;
}
}
bool ODBCTest::canConnect(const std::string& driver,
std::string& dsn,
std::string& uid,

View File

@@ -37,10 +37,11 @@
#include "Poco/Data/ODBC/ODBC.h"
#include "CppUnit/TestCase.h"
#include "Poco/Data/Session.h"
#include "Poco/Data/ODBC/Utility.h"
#include "Poco/SharedPtr.h"
#include "CppUnit/TestCase.h"
#include "Poco/Exception.h"
#include "SQLExecutor.h"
@@ -86,6 +87,8 @@ public:
virtual void testInsertDeque();
virtual void testInsertEmptyDeque();
virtual void testAffectedRows();
virtual void testInsertSingleBulk();
virtual void testInsertSingleBulkVec();
@@ -135,13 +138,13 @@ public:
virtual void testInternalBulkExtraction();
virtual void testInternalStorageType();
virtual void testStoredProcedure() { /* no-op */ };
virtual void testStoredProcedureAny() { /* no-op */ };
virtual void testStoredProcedureDynamicAny() { /* no-op */ };
virtual void testStoredProcedure();
virtual void testStoredProcedureAny();
virtual void testStoredProcedureDynamicAny();
virtual void testStoredFunction() { /* no-op */ };
virtual void testStoredFunctionAny() { /* no-op */ };
virtual void testStoredFunctionDynamicAny() { /* no-op */ };
virtual void testStoredFunction();
virtual void testStoredFunctionAny();
virtual void testStoredFunctionDynamicAny();
virtual void testNull();
virtual void testRowIterator();
@@ -154,24 +157,29 @@ public:
virtual void testMultipleResults();
virtual void testSQLChannel();
virtual void testSQLLogger();
protected:
typedef Poco::Data::ODBC::Utility::DriverMap Drivers;
virtual void dropObject(const std::string& type, const std::string& name) { /* no-op */ };
virtual void recreatePersonTable() { /* no-op */ };
virtual void recreatePersonBLOBTable() { /* no-op */ };
virtual void recreatePersonDateTimeTable() { /* no-op */ };
virtual void recreatePersonDateTable() { /* no-op */ };
virtual void recreatePersonTimeTable() { /* no-op */ };
virtual void recreateStringsTable() { /* no-op */ };
virtual void recreateIntsTable() { /* no-op */ };
virtual void recreateFloatsTable() { /* no-op */ };
virtual void recreateTuplesTable() { /* no-op */ };
virtual void recreateVectorsTable() { /* no-op */ };
virtual void recreateAnysTable() { /* no-op */ };
virtual void recreateNullsTable(const std::string& notNull="") { /* no-op */ };
virtual void recreateBoolTable() { /* no-op */ };
virtual void recreateMiscTable() { /* no-op */ };
virtual void dropObject(const std::string& type, const std::string& name);
virtual void recreatePersonTable();
virtual void recreatePersonBLOBTable();
virtual void recreatePersonDateTimeTable();
virtual void recreatePersonDateTable();
virtual void recreatePersonTimeTable();
virtual void recreateStringsTable();
virtual void recreateIntsTable();
virtual void recreateFloatsTable();
virtual void recreateTuplesTable();
virtual void recreateVectorsTable();
virtual void recreateAnysTable();
virtual void recreateNullsTable(const std::string& notNull="");
virtual void recreateBoolTable();
virtual void recreateMiscTable();
virtual void recreateLogTable();
static SessionPtr init(const std::string& driver,
std::string& dsn,
@@ -209,9 +217,142 @@ private:
};
///
/// inlines
///
//
// inlines
//
inline void ODBCTest::testStoredProcedure()
{
throw Poco::NotImplementedException("ODBCTest::testStoredProcedure()");
}
inline void ODBCTest::testStoredProcedureAny()
{
throw Poco::NotImplementedException("ODBCTest::testStoredProcedureAny()");
}
inline void ODBCTest::testStoredProcedureDynamicAny()
{
throw Poco::NotImplementedException("ODBCTest::testStoredProcedureDynamicAny()");
}
inline void ODBCTest::testStoredFunction()
{
throw Poco::NotImplementedException("ODBCTest::testStoredFunction()");
}
inline void ODBCTest::testStoredFunctionAny()
{
throw Poco::NotImplementedException("ODBCTest::testStoredFunctionAny()");
}
inline void ODBCTest::testStoredFunctionDynamicAny()
{
throw Poco::NotImplementedException("ODBCTest::testStoredFunctionDynamicAny()");
}
inline void ODBCTest::dropObject(const std::string& type, const std::string& name)
{
throw Poco::NotImplementedException("ODBCTest::dropObject()");
}
inline void ODBCTest::recreatePersonTable()
{
throw Poco::NotImplementedException("ODBCTest::testStoredFunctionDynamicAny()");
}
inline void ODBCTest::recreatePersonBLOBTable()
{
throw Poco::NotImplementedException("ODBCTest::testStoredFunctionDynamicAny()");
}
inline void ODBCTest::recreatePersonDateTimeTable()
{
throw Poco::NotImplementedException("ODBCTest::testStoredFunctionDynamicAny()");
}
inline void ODBCTest::recreatePersonDateTable()
{
throw Poco::NotImplementedException("ODBCTest::testStoredFunctionDynamicAny()");
}
inline void ODBCTest::recreatePersonTimeTable()
{
throw Poco::NotImplementedException("ODBCTest::testStoredFunctionDynamicAny()");
}
inline void ODBCTest::recreateStringsTable()
{
throw Poco::NotImplementedException("ODBCTest::recreateStringsTable()");
}
inline void ODBCTest::recreateIntsTable()
{
throw Poco::NotImplementedException("ODBCTest::recreateIntsTable()");
}
inline void ODBCTest::recreateFloatsTable()
{
throw Poco::NotImplementedException("ODBCTest::recreateFloatsTable()");
}
inline void ODBCTest::recreateTuplesTable()
{
throw Poco::NotImplementedException("ODBCTest::recreateTuplesTable()");
}
inline void ODBCTest::recreateVectorsTable()
{
throw Poco::NotImplementedException("ODBCTest::recreateVectorsTable()");
}
inline void ODBCTest::recreateAnysTable()
{
throw Poco::NotImplementedException("ODBCTest::recreateAnysTable()");
}
inline void ODBCTest::recreateNullsTable(const std::string&)
{
throw Poco::NotImplementedException("ODBCTest::recreateNullsTable()");
}
inline void ODBCTest::recreateBoolTable()
{
throw Poco::NotImplementedException("ODBCTest::recreateBoolTable()");
}
inline void ODBCTest::recreateMiscTable()
{
throw Poco::NotImplementedException("ODBCTest::recreateMiscTable()");
}
inline void ODBCTest::recreateLogTable()
{
throw Poco::NotImplementedException("ODBCTest::recreateLogTable()");
}
inline bool ODBCTest::bindValue(int i)
{
poco_assert (i < 8);

View File

@@ -40,6 +40,10 @@
#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/AutoPtr.h"
#include "Poco/Exception.h"
#include "Poco/Data/Date.h"
#include "Poco/Data/Time.h"
@@ -49,6 +53,7 @@
#include "Poco/Data/RowIterator.h"
#include "Poco/Data/BulkExtraction.h"
#include "Poco/Data/BulkBinding.h"
#include "Poco/Data/SQLChannel.h"
#include "Poco/Data/ODBC/Connector.h"
#include "Poco/Data/ODBC/Utility.h"
#include "Poco/Data/ODBC/Diagnostics.h"
@@ -76,6 +81,10 @@ using Poco::DynamicAny;
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;
@@ -1234,6 +1243,35 @@ void SQLExecutor::insertEmptyDeque()
}
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() << "INSERT INTO Strings VALUES(?)", use(str)));
session() << "SELECT COUNT(*) FROM Strings", into(count), now;
assert (count == 0);
assert (4 == stmt1.execute());
session() << "SELECT COUNT(*) FROM Strings", into(count), now;
assert (count == 4);
Statement stmt2(session() << "UPDATE Strings SET str = 's4' WHERE str = 's3'");
assert (2 == stmt2.execute());
Statement stmt3(session() << "DELETE FROM Strings WHERE str = 's1'");
assert (1 == stmt3.execute());
std::string sql;
format(sql, "DELETE FROM Strings %s", whereClause);
Statement stmt4(session() << sql);
assert (3 == stmt4.execute());
}
void SQLExecutor::insertSingleBulk()
{
std::string funct = "insertSingleBulk()";
@@ -1243,7 +1281,7 @@ void SQLExecutor::insertSingleBulk()
for (x = 0; x < 100; ++x)
{
int i = stmt.execute();
assert (i == 0);
assert (1 == i);
}
int count = 0;
try { session() << "SELECT COUNT(*) FROM Strings", into(count), now; }
@@ -1414,7 +1452,11 @@ void SQLExecutor::limitPrepare()
data.push_back(x);
}
try { session() << "INSERT INTO Strings VALUES (?)", use(data), now; }
try
{
Statement stmt = (session() << "INSERT INTO Strings VALUES (?)", use(data));
assert (100 == stmt.execute());
}
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
@@ -2932,3 +2974,87 @@ void SQLExecutor::multipleResults(const std::string& sql)
assert (12 == aBart);
assert (Person("Simpson", "Lisa", "Springfield", 10) == pLisa);
}
void SQLExecutor::sqlChannel(const std::string& connect)
{
try
{
AutoPtr<SQLChannel> pChannel = new SQLChannel(ODBC::Connector::KEY, connect, "TestSQLChannel");
pChannel->setProperty("keep", "2 seconds");
Message msgInf("InformationSource", "a Informational async message", Message::PRIO_INFORMATION);
pChannel->log(msgInf);
Message msgWarn("WarningSource", "b Warning async message", Message::PRIO_WARNING);
pChannel->log(msgWarn);
pChannel->wait();
pChannel->setProperty("async", "false");
Message msgInfS("InformationSource", "c Informational sync message", Message::PRIO_INFORMATION);
pChannel->log(msgInfS);
Message msgWarnS("WarningSource", "d Warning sync message", Message::PRIO_WARNING);
pChannel->log(msgWarnS);
RecordSet rs(session(), "SELECT * FROM T_POCO_LOG ORDER by Text");
assert (4 == rs.rowCount());
assert ("InformationSource" == rs["Source"]);
assert ("a Informational async message" == rs["Text"]);
rs.moveNext();
assert ("WarningSource" == rs["Source"]);
assert ("b Warning async message" == rs["Text"]);
rs.moveNext();
assert ("InformationSource" == rs["Source"]);
assert ("c Informational sync message" == rs["Text"]);
rs.moveNext();
assert ("WarningSource" == rs["Source"]);
assert ("d Warning sync message" == rs["Text"]);
Thread::sleep(3000);
Message msgInfA("InformationSource", "e Informational sync message", Message::PRIO_INFORMATION);
pChannel->log(msgInfA);
Message msgWarnA("WarningSource", "f Warning sync message", Message::PRIO_WARNING);
pChannel->log(msgWarnA);
RecordSet rs1(session(), "SELECT * FROM T_POCO_LOG_ARCHIVE");
assert (4 == rs1.rowCount());
pChannel->setProperty("keep", "");
assert ("forever" == pChannel->getProperty("keep"));
RecordSet rs2(session(), "SELECT * FROM T_POCO_LOG ORDER by Text");
assert (2 == rs2.rowCount());
assert ("InformationSource" == rs2["Source"]);
assert ("e Informational sync message" == rs2["Text"]);
rs2.moveNext();
assert ("WarningSource" == rs2["Source"]);
assert ("f Warning sync message" == rs2["Text"]);
}
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("sqlChannel()"); }
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("sqlChannel()"); }
}
void SQLExecutor::sqlLogger(const std::string& connect)
{
try
{
Logger& root = Logger::root();
root.setChannel(new SQLChannel(ODBC::Connector::KEY, connect, "TestSQLChannel"));
root.setLevel(Message::PRIO_INFORMATION);
root.information("a Informational message");
root.warning("b Warning message");
root.debug("Debug message");
Thread::sleep(100);
RecordSet rs(session(), "SELECT * FROM T_POCO_LOG ORDER by Text");
assert (2 == rs.rowCount());
assert ("TestSQLChannel" == rs["Source"]);
assert ("a Informational message" == rs["Text"]);
rs.moveNext();
assert ("TestSQLChannel" == rs["Source"]);
assert ("b Warning message" == rs["Text"]);
}
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("sqlChannel()"); }
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("sqlChannel()"); }
}

View File

@@ -148,6 +148,8 @@ public:
void insertDeque();
void insertEmptyDeque();
void affectedRows(const std::string& whereClause = "");
void insertSingleBulk();
void insertSingleBulkVec();
@@ -499,6 +501,9 @@ public:
"SELECT Age FROM Person WHERE FirstName = 'Bart'; "
"SELECT * FROM Person WHERE Age = ?; ");
void sqlChannel(const std::string& connect);
void sqlLogger(const std::string& connect);
private:
static const std::string MULTI_INSERT;
static const std::string MULTI_SELECT;

View File

@@ -36,8 +36,8 @@
//
#ifndef DataConnectors_SQLite_Binder_INCLUDED
#define DataConnectors_SQLite_Binder_INCLUDED
#ifndef Data_SQLite_Binder_INCLUDED
#define Data_SQLite_Binder_INCLUDED
#include "Poco/Data/SQLite/SQLite.h"
@@ -180,15 +180,6 @@ inline void Binder::bind(std::size_t pos, const Poco::UInt64 &val, Direction dir
}
#ifndef POCO_LONG_IS_64_BIT
inline void Binder::bind(std::size_t pos, const long &val, Direction dir)
{
long tmp = static_cast<long>(val);
bind(pos, tmp, dir);
}
#endif
inline void Binder::bind(std::size_t pos, const bool &val, Direction dir)
{
Poco::Int32 tmp = (val ? 1 : 0);
@@ -220,4 +211,4 @@ inline void Binder::bind(std::size_t pos, const char* const &pVal, Direction dir
} } } // namespace Poco::Data::SQLite
#endif // DataConnectors_SQLite_Binder_INCLUDED
#endif // Data_SQLite_Binder_INCLUDED

View File

@@ -36,8 +36,8 @@
//
#ifndef DataConnectors_SQLite_Connector_INCLUDED
#define DataConnectors_SQLite_Connector_INCLUDED
#ifndef Data_SQLite_Connector_INCLUDED
#define Data_SQLite_Connector_INCLUDED
#include "Poco/Data/SQLite/SQLite.h"
@@ -62,6 +62,9 @@ public:
~Connector();
/// Destroys the Connector.
const std::string& name() const;
/// Returns the name associated with this connector.
Poco::AutoPtr<Poco::Data::SessionImpl> createSession(const std::string& connectionString);
/// Creates a SQLite SessionImpl object and initializes it with the given connectionString.
@@ -73,7 +76,16 @@ public:
};
///
/// inlines
///
inline const std::string& Connector::name() const
{
return KEY;
}
} } } // namespace Poco::Data::SQLite
#endif // DataConnectors_SQLite_Connector_INCLUDED
#endif // Data_SQLite_Connector_INCLUDED

View File

@@ -36,8 +36,8 @@
//
#ifndef DataConnectors_SQLite_Extractor_INCLUDED
#define DataConnectors_SQLite_Extractor_INCLUDED
#ifndef Data_SQLite_Extractor_INCLUDED
#define Data_SQLite_Extractor_INCLUDED
#include "Poco/Data/SQLite/SQLite.h"
@@ -301,4 +301,4 @@ inline void Extractor::reset()
} } } // namespace Poco::Data::SQLite
#endif // DataConnectors_SQLite_Extractor_INCLUDED
#endif // Data_SQLite_Extractor_INCLUDED

View File

@@ -36,8 +36,8 @@
//
#ifndef DataConnectors_SQLite_SQLiteStatementImpl_INCLUDED
#define DataConnectors_SQLite_SQLiteStatementImpl_INCLUDED
#ifndef Data_SQLite_SQLiteStatementImpl_INCLUDED
#define Data_SQLite_SQLiteStatementImpl_INCLUDED
#include "Poco/Data/SQLite/SQLite.h"
@@ -71,6 +71,17 @@ protected:
Poco::UInt32 columnsReturned() const;
/// Returns number of columns returned by query.
Poco::UInt32 affectedRowCount() const;
/// Returns the number of affected rows.
/// Used to find out the number of rows affected by insert, delete or update.
/// All changes are counted, even if they are later undone by a ROLLBACK or ABORT.
/// Changes associated with creating and dropping tables are not counted.
/// SQLite implements the command "DELETE FROM table" without a WHERE clause by
/// dropping and recreating the table. Because of this optimization, the change count
/// for "DELETE FROM table" will be zero regardless of the number of elements that
/// were originally in the table. To get an accurate count of the number of rows deleted,
/// use "DELETE FROM table WHERE 1".
const MetaColumn& metaColumn(Poco::UInt32 pos) const;
/// Returns column meta data.
@@ -100,16 +111,20 @@ private:
void clear();
/// Removes the _pStmt
typedef Poco::SharedPtr<Binder> BinderPtr;
typedef Poco::SharedPtr<Extractor> ExtractorPtr;
typedef Poco::Data::AbstractBindingVec Bindings;
typedef Poco::Data::AbstractExtractionVec Extractions;
typedef std::vector<Poco::Data::MetaColumn> MetaColumnVec;
sqlite3* _pDB;
sqlite3_stmt* _pStmt;
bool _stepCalled;
int _nextResponse;
Poco::SharedPtr<Binder> _pBinder;
Poco::SharedPtr<Extractor> _pExtractor;
std::vector<Poco::Data::MetaColumn> _columns;
BinderPtr _pBinder;
ExtractorPtr _pExtractor;
MetaColumnVec _columns;
Poco::UInt32 _affectedRowCount;
};
@@ -131,4 +146,4 @@ inline AbstractBinder& SQLiteStatementImpl::binder()
} } } // namespace Poco::Data::SQLite
#endif // DataConnectors_SQLite_SQLiteStatementImpl_INCLUDED
#endif // Data_SQLite_SQLiteStatementImpl_INCLUDED

View File

@@ -36,8 +36,8 @@
//
#ifndef DataConnectors_SQLite_SessionImpl_INCLUDED
#define DataConnectors_SQLite_SessionImpl_INCLUDED
#ifndef Data_SQLite_SessionImpl_INCLUDED
#define Data_SQLite_SessionImpl_INCLUDED
#include "Poco/Data/SQLite/SQLite.h"
@@ -113,4 +113,4 @@ inline bool SessionImpl::isTransaction()
} } } // namespace Poco::Data::SQLite
#endif // DataConnectors_SQLite_SessionImpl_INCLUDED
#endif // Data_SQLite_SessionImpl_INCLUDED

View File

@@ -80,6 +80,16 @@ void Binder::bind(std::size_t pos, const Poco::Int64 &val, Direction dir)
}
#ifndef POCO_LONG_IS_64_BIT
void Binder::bind(std::size_t pos, const long &val, Direction dir)
{
long tmp = static_cast<long>(val);
int rc = sqlite3_bind_int(_pStmt, (int) pos, val);
checkReturn(rc);
}
#endif
void Binder::bind(std::size_t pos, const double &val, Direction dir)
{
int rc = sqlite3_bind_double(_pStmt, (int) pos, val);

View File

@@ -65,7 +65,7 @@ Poco::AutoPtr<Poco::Data::SessionImpl> Connector::createSession(const std::strin
void Connector::registerConnector()
{
Poco::Data::SessionFactory::instance().add(KEY, new Connector());
Poco::Data::SessionFactory::instance().add(new Connector());
}

View File

@@ -53,7 +53,8 @@ SQLiteStatementImpl::SQLiteStatementImpl(Poco::Data::SessionImpl& rSession, sqli
_pDB(pDB),
_pStmt(0),
_stepCalled(false),
_nextResponse(0)
_nextResponse(0),
_affectedRowCount(0)
{
}
@@ -150,6 +151,8 @@ void SQLiteStatementImpl::bindImpl()
Bindings::iterator it = binds.begin();
Bindings::iterator itEnd = binds.end();
if (it != itEnd)
_affectedRowCount = (*it)->numOfRowsHandled();
for (; it != itEnd && (*it)->canBind(); ++it)
{
(*it)->bind(pos);
@@ -161,6 +164,7 @@ void SQLiteStatementImpl::bindImpl()
void SQLiteStatementImpl::clear()
{
_columns.clear();
_affectedRowCount = 0;
if (_pStmt)
{
@@ -240,4 +244,10 @@ const MetaColumn& SQLiteStatementImpl::metaColumn(Poco::UInt32 pos) const
}
Poco::UInt32 SQLiteStatementImpl::affectedRowCount() const
{
return _affectedRowCount ? _affectedRowCount : sqlite3_changes(_pDB);
}
} } } // namespace Poco::Data::SQLite

View File

@@ -38,6 +38,7 @@
#include "Poco/Data/BLOB.h"
#include "Poco/Data/Statement.h"
#include "Poco/Data/RecordSet.h"
#include "Poco/Data/SQLChannel.h"
#include "Poco/Data/SessionFactory.h"
#include "Poco/Data/SQLite/Connector.h"
#include "Poco/Data/SQLite/SQLiteException.h"
@@ -46,6 +47,10 @@
#include "Poco/Any.h"
#include "Poco/DynamicAny.h"
#include "Poco/DateTime.h"
#include "Poco/Logger.h"
#include "Poco/Message.h"
#include "Poco/Thread.h"
#include "Poco/AutoPtr.h"
#include "Poco/Exception.h"
#include <iostream>
@@ -56,6 +61,10 @@ using Poco::Any;
using Poco::AnyCast;
using Poco::DynamicAny;
using Poco::DateTime;
using Poco::Logger;
using Poco::Message;
using Poco::AutoPtr;
using Poco::Thread;
using Poco::InvalidAccessException;
using Poco::RangeException;
using Poco::BadCastException;
@@ -174,7 +183,7 @@ SQLiteTest::~SQLiteTest()
void SQLiteTest::testSimpleAccess()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
assert (tmp.isConnected());
std::string tableName("Person");
std::string lastName("lastname");
@@ -205,7 +214,7 @@ void SQLiteTest::testSimpleAccess()
void SQLiteTest::testInsertCharPointer()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
std::string tableName("Person");
std::string lastName("lastname");
std::string firstName("firstname");
@@ -229,7 +238,7 @@ void SQLiteTest::testInsertCharPointer()
void SQLiteTest::testInsertCharPointer2()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
std::string tableName("Person");
std::string lastName("lastname");
std::string firstName("firstname");
@@ -255,7 +264,7 @@ void SQLiteTest::testInsertCharPointer2()
void SQLiteTest::testComplexType()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
Person p1("LN1", "FN1", "ADDR1", 1);
Person p2("LN2", "FN2", "ADDR2", 2);
tmp << "DROP TABLE IF EXISTS Person", now;
@@ -276,7 +285,7 @@ void SQLiteTest::testComplexType()
void SQLiteTest::testSimpleAccessVector()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
std::vector<std::string> lastNames;
std::vector<std::string> firstNames;
std::vector<std::string> addresses;
@@ -313,7 +322,7 @@ void SQLiteTest::testSimpleAccessVector()
void SQLiteTest::testComplexTypeVector()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
std::vector<Person> people;
people.push_back(Person("LN1", "FN1", "ADDR1", 1));
people.push_back(Person("LN2", "FN2", "ADDR2", 2));
@@ -332,7 +341,7 @@ void SQLiteTest::testComplexTypeVector()
void SQLiteTest::testInsertVector()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
std::vector<std::string> str;
str.push_back("s1");
str.push_back("s2");
@@ -357,7 +366,7 @@ void SQLiteTest::testInsertVector()
void SQLiteTest::testInsertEmptyVector()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
std::vector<std::string> str;
tmp << "DROP TABLE IF EXISTS Strings", now;
@@ -373,9 +382,41 @@ void SQLiteTest::testInsertEmptyVector()
}
void SQLiteTest::testAffectedRows()
{
Session tmp (SQLite::Connector::KEY, "dummy.db");
std::vector<std::string> str;
str.push_back("s1");
str.push_back("s2");
str.push_back("s3");
str.push_back("s3");
int count = 100;
tmp << "DROP TABLE IF EXISTS Strings", now;
tmp << "CREATE TABLE IF NOT EXISTS Strings (str VARCHAR(30))", now;
Statement stmt1((tmp << "INSERT INTO Strings VALUES(:str)", use(str)));
tmp << "SELECT COUNT(*) FROM Strings", into(count), now;
assert (count == 0);
assert (4 == stmt1.execute());
tmp << "SELECT COUNT(*) FROM Strings", into(count), now;
assert (count == 4);
Statement stmt2(tmp << "UPDATE Strings SET str = 's4' WHERE str = 's3'");
assert (2 == stmt2.execute());
Statement stmt3(tmp << "DELETE FROM Strings WHERE str = 's1'");
assert (1 == stmt3.execute());
// see SQLiteStatementImpl::affectedRows() documentation for explanation
// why "WHERE 1" is necessary here
Statement stmt4(tmp << "DELETE FROM Strings WHERE 1");
assert (3 == stmt4.execute());
}
void SQLiteTest::testInsertSingleBulk()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
tmp << "DROP TABLE IF EXISTS Strings", now;
tmp << "CREATE TABLE IF NOT EXISTS Strings (str INTEGER(10))", now;
int x = 0;
@@ -384,7 +425,7 @@ void SQLiteTest::testInsertSingleBulk()
for (x = 0; x < 100; ++x)
{
int i = stmt.execute();
assert (i == 0);
assert (1 == i);
}
int count = 0;
tmp << "SELECT COUNT(*) FROM Strings", into(count), now;
@@ -396,7 +437,7 @@ void SQLiteTest::testInsertSingleBulk()
void SQLiteTest::testInsertSingleBulkVec()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
tmp << "DROP TABLE IF EXISTS Strings", now;
tmp << "CREATE TABLE IF NOT EXISTS Strings (str INTEGER(10))", now;
std::vector<int> data;
@@ -421,7 +462,7 @@ void SQLiteTest::testInsertSingleBulkVec()
void SQLiteTest::testLimit()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
tmp << "DROP TABLE IF EXISTS Strings", now;
tmp << "CREATE TABLE IF NOT EXISTS Strings (str INTEGER(10))", now;
std::vector<int> data;
@@ -443,7 +484,7 @@ void SQLiteTest::testLimit()
void SQLiteTest::testLimitZero()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
tmp << "DROP TABLE IF EXISTS Strings", now;
tmp << "CREATE TABLE IF NOT EXISTS Strings (str INTEGER(10))", now;
std::vector<int> data;
@@ -461,7 +502,7 @@ void SQLiteTest::testLimitZero()
void SQLiteTest::testLimitOnce()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
tmp << "DROP TABLE IF EXISTS Strings", now;
tmp << "CREATE TABLE IF NOT EXISTS Strings (str INTEGER(10))", now;
std::vector<int> data;
@@ -491,7 +532,7 @@ void SQLiteTest::testLimitOnce()
void SQLiteTest::testLimitPrepare()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
tmp << "DROP TABLE IF EXISTS Strings", now;
tmp << "CREATE TABLE IF NOT EXISTS Strings (str INTEGER(10))", now;
std::vector<int> data;
@@ -500,7 +541,9 @@ void SQLiteTest::testLimitPrepare()
data.push_back(x);
}
tmp << "INSERT INTO Strings VALUES(:str)", use(data), now;
Statement stmtIns = (tmp << "INSERT INTO Strings VALUES(:str)", use(data));
assert (100 == stmtIns.execute());
std::vector<int> retData;
Statement stmt = (tmp << "SELECT * FROM Strings", into(retData), limit(50));
assert (retData.size() == 0);
@@ -527,7 +570,7 @@ void SQLiteTest::testLimitPrepare()
void SQLiteTest::testPrepare()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
tmp << "DROP TABLE IF EXISTS Strings", now;
tmp << "CREATE TABLE IF NOT EXISTS Strings (str INTEGER(10))", now;
std::vector<int> data;
@@ -548,7 +591,7 @@ void SQLiteTest::testPrepare()
void SQLiteTest::testSetSimple()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
std::set<std::string> lastNames;
std::set<std::string> firstNames;
std::set<std::string> addresses;
@@ -585,7 +628,7 @@ void SQLiteTest::testSetSimple()
void SQLiteTest::testSetComplex()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
std::set<Person> people;
people.insert(Person("LN1", "FN1", "ADDR1", 1));
people.insert(Person("LN2", "FN2", "ADDR2", 2));
@@ -604,7 +647,7 @@ void SQLiteTest::testSetComplex()
void SQLiteTest::testSetComplexUnique()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
std::vector<Person> people;
Person p1("LN1", "FN1", "ADDR1", 1);
people.push_back(p1);
@@ -630,7 +673,7 @@ void SQLiteTest::testSetComplexUnique()
void SQLiteTest::testMultiSetSimple()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
std::multiset<std::string> lastNames;
std::multiset<std::string> firstNames;
std::multiset<std::string> addresses;
@@ -667,7 +710,7 @@ void SQLiteTest::testMultiSetSimple()
void SQLiteTest::testMultiSetComplex()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
std::multiset<Person> people;
Person p1("LN1", "FN1", "ADDR1", 1);
people.insert(p1);
@@ -692,7 +735,7 @@ void SQLiteTest::testMultiSetComplex()
void SQLiteTest::testMapComplex()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
std::map<std::string, Person> people;
Person p1("LN1", "FN1", "ADDR1", 1);
Person p2("LN2", "FN2", "ADDR2", 2);
@@ -713,7 +756,7 @@ void SQLiteTest::testMapComplex()
void SQLiteTest::testMapComplexUnique()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
std::multimap<std::string, Person> people;
Person p1("LN1", "FN1", "ADDR1", 1);
Person p2("LN2", "FN2", "ADDR2", 2);
@@ -737,7 +780,7 @@ void SQLiteTest::testMapComplexUnique()
void SQLiteTest::testMultiMapComplex()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
std::multimap<std::string, Person> people;
Person p1("LN1", "FN1", "ADDR1", 1);
Person p2("LN2", "FN2", "ADDR2", 2);
@@ -761,7 +804,7 @@ void SQLiteTest::testMultiMapComplex()
void SQLiteTest::testSelectIntoSingle()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
std::multimap<std::string, Person> people;
Person p1("LN1", "FN1", "ADDR1", 1);
Person p2("LN2", "FN2", "ADDR2", 2);
@@ -781,7 +824,7 @@ void SQLiteTest::testSelectIntoSingle()
void SQLiteTest::testSelectIntoSingleStep()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
std::multimap<std::string, Person> people;
Person p1("LN1", "FN1", "ADDR1", 1);
Person p2("LN2", "FN2", "ADDR2", 2);
@@ -806,7 +849,7 @@ void SQLiteTest::testSelectIntoSingleStep()
void SQLiteTest::testSelectIntoSingleFail()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
std::multimap<std::string, Person> people;
Person p1("LN1", "FN1", "ADDR1", 1);
Person p2("LN2", "FN2", "ADDR2", 2);
@@ -832,7 +875,7 @@ void SQLiteTest::testSelectIntoSingleFail()
void SQLiteTest::testLowerLimitOk()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
std::multimap<std::string, Person> people;
Person p1("LN1", "FN1", "ADDR1", 1);
Person p2("LN2", "FN2", "ADDR2", 2);
@@ -858,7 +901,7 @@ void SQLiteTest::testLowerLimitOk()
void SQLiteTest::testSingleSelect()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
std::multimap<std::string, Person> people;
Person p1("LN1", "FN1", "ADDR1", 1);
Person p2("LN2", "FN2", "ADDR2", 2);
@@ -883,7 +926,7 @@ void SQLiteTest::testSingleSelect()
void SQLiteTest::testLowerLimitFail()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
std::multimap<std::string, Person> people;
Person p1("LN1", "FN1", "ADDR1", 1);
Person p2("LN2", "FN2", "ADDR2", 2);
@@ -909,7 +952,7 @@ void SQLiteTest::testLowerLimitFail()
void SQLiteTest::testCombinedLimits()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
std::multimap<std::string, Person> people;
Person p1("LN1", "FN1", "ADDR1", 1);
Person p2("LN2", "FN2", "ADDR2", 2);
@@ -932,7 +975,7 @@ void SQLiteTest::testCombinedLimits()
void SQLiteTest::testRange()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
std::multimap<std::string, Person> people;
Person p1("LN1", "FN1", "ADDR1", 1);
Person p2("LN2", "FN2", "ADDR2", 2);
@@ -954,7 +997,7 @@ void SQLiteTest::testRange()
void SQLiteTest::testCombinedIllegalLimits()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
std::multimap<std::string, Person> people;
Person p1("LN1", "FN1", "ADDR1", 1);
Person p2("LN2", "FN2", "ADDR2", 2);
@@ -981,7 +1024,7 @@ void SQLiteTest::testCombinedIllegalLimits()
void SQLiteTest::testIllegalRange()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
std::multimap<std::string, Person> people;
Person p1("LN1", "FN1", "ADDR1", 1);
Person p2("LN2", "FN2", "ADDR2", 2);
@@ -1007,7 +1050,7 @@ void SQLiteTest::testIllegalRange()
void SQLiteTest::testEmptyDB()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (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, Age INTEGER(3))", now;
@@ -1027,7 +1070,7 @@ void SQLiteTest::testBLOB()
std::string lastName("lastname");
std::string firstName("firstname");
std::string address("Address");
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (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);
@@ -1044,7 +1087,7 @@ void SQLiteTest::testBLOB()
void SQLiteTest::testTuple10()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
tmp << "DROP TABLE IF EXISTS Tuples", now;
tmp << "CREATE TABLE Tuples "
"(int0 INTEGER, int1 INTEGER, int2 INTEGER, int3 INTEGER, int4 INTEGER, int5 INTEGER, int6 INTEGER, "
@@ -1063,7 +1106,7 @@ void SQLiteTest::testTuple10()
void SQLiteTest::testTupleVector10()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
tmp << "DROP TABLE IF EXISTS Tuples", now;
tmp << "CREATE TABLE Tuples "
"(int0 INTEGER, int1 INTEGER, int2 INTEGER, int3 INTEGER, int4 INTEGER, int5 INTEGER, int6 INTEGER, "
@@ -1092,7 +1135,7 @@ void SQLiteTest::testTupleVector10()
void SQLiteTest::testTuple9()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
tmp << "DROP TABLE IF EXISTS Tuples", now;
tmp << "CREATE TABLE Tuples "
"(int0 INTEGER, int1 INTEGER, int2 INTEGER, int3 INTEGER, int4 INTEGER, int5 INTEGER, int6 INTEGER, "
@@ -1111,7 +1154,7 @@ void SQLiteTest::testTuple9()
void SQLiteTest::testTupleVector9()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
tmp << "DROP TABLE IF EXISTS Tuples", now;
tmp << "CREATE TABLE Tuples "
"(int0 INTEGER, int1 INTEGER, int2 INTEGER, int3 INTEGER, int4 INTEGER, int5 INTEGER, int6 INTEGER, "
@@ -1140,7 +1183,7 @@ void SQLiteTest::testTupleVector9()
void SQLiteTest::testTuple8()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
tmp << "DROP TABLE IF EXISTS Tuples", now;
tmp << "CREATE TABLE Tuples "
"(int0 INTEGER, int1 INTEGER, int2 INTEGER, int3 INTEGER, int4 INTEGER, int5 INTEGER, int6 INTEGER, "
@@ -1159,7 +1202,7 @@ void SQLiteTest::testTuple8()
void SQLiteTest::testTupleVector8()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
tmp << "DROP TABLE IF EXISTS Tuples", now;
tmp << "CREATE TABLE Tuples "
"(int0 INTEGER, int1 INTEGER, int2 INTEGER, int3 INTEGER, int4 INTEGER, int5 INTEGER, int6 INTEGER, "
@@ -1188,7 +1231,7 @@ void SQLiteTest::testTupleVector8()
void SQLiteTest::testTuple7()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
tmp << "DROP TABLE IF EXISTS Tuples", now;
tmp << "CREATE TABLE Tuples "
"(int0 INTEGER, int1 INTEGER, int2 INTEGER, int3 INTEGER, int4 INTEGER, int5 INTEGER, int6 INTEGER)", now;
@@ -1206,7 +1249,7 @@ void SQLiteTest::testTuple7()
void SQLiteTest::testTupleVector7()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
tmp << "DROP TABLE IF EXISTS Tuples", now;
tmp << "CREATE TABLE Tuples "
"(int0 INTEGER, int1 INTEGER, int2 INTEGER, int3 INTEGER, int4 INTEGER, int5 INTEGER, int6 INTEGER)", now;
@@ -1234,7 +1277,7 @@ void SQLiteTest::testTupleVector7()
void SQLiteTest::testTuple6()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
tmp << "DROP TABLE IF EXISTS Tuples", now;
tmp << "CREATE TABLE Tuples "
"(int0 INTEGER, int1 INTEGER, int2 INTEGER, int3 INTEGER, int4 INTEGER, int5 INTEGER)", now;
@@ -1252,7 +1295,7 @@ void SQLiteTest::testTuple6()
void SQLiteTest::testTupleVector6()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
tmp << "DROP TABLE IF EXISTS Tuples", now;
tmp << "CREATE TABLE Tuples "
"(int0 INTEGER, int1 INTEGER, int2 INTEGER, int3 INTEGER, int4 INTEGER, int5 INTEGER)", now;
@@ -1280,7 +1323,7 @@ void SQLiteTest::testTupleVector6()
void SQLiteTest::testTuple5()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
tmp << "DROP TABLE IF EXISTS Tuples", now;
tmp << "CREATE TABLE Tuples "
"(int0 INTEGER, int1 INTEGER, int2 INTEGER, int3 INTEGER, int4 INTEGER)", now;
@@ -1298,7 +1341,7 @@ void SQLiteTest::testTuple5()
void SQLiteTest::testTupleVector5()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
tmp << "DROP TABLE IF EXISTS Tuples", now;
tmp << "CREATE TABLE Tuples "
"(int0 INTEGER, int1 INTEGER, int2 INTEGER, int3 INTEGER, int4 INTEGER)", now;
@@ -1326,7 +1369,7 @@ void SQLiteTest::testTupleVector5()
void SQLiteTest::testTuple4()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
tmp << "DROP TABLE IF EXISTS Tuples", now;
tmp << "CREATE TABLE Tuples "
"(int0 INTEGER, int1 INTEGER, int2 INTEGER, int3 INTEGER)", now;
@@ -1344,7 +1387,7 @@ void SQLiteTest::testTuple4()
void SQLiteTest::testTupleVector4()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
tmp << "DROP TABLE IF EXISTS Tuples", now;
tmp << "CREATE TABLE Tuples "
"(int0 INTEGER, int1 INTEGER, int2 INTEGER, int3 INTEGER)", now;
@@ -1372,7 +1415,7 @@ void SQLiteTest::testTupleVector4()
void SQLiteTest::testTuple3()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
tmp << "DROP TABLE IF EXISTS Tuples", now;
tmp << "CREATE TABLE Tuples "
"(int0 INTEGER, int1 INTEGER, int2 INTEGER)", now;
@@ -1390,7 +1433,7 @@ void SQLiteTest::testTuple3()
void SQLiteTest::testTupleVector3()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
tmp << "DROP TABLE IF EXISTS Tuples", now;
tmp << "CREATE TABLE Tuples "
"(int0 INTEGER, int1 INTEGER, int2 INTEGER)", now;
@@ -1418,7 +1461,7 @@ void SQLiteTest::testTupleVector3()
void SQLiteTest::testTuple2()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
tmp << "DROP TABLE IF EXISTS Tuples", now;
tmp << "CREATE TABLE Tuples (int0 INTEGER, int1 INTEGER)", now;
@@ -1435,7 +1478,7 @@ void SQLiteTest::testTuple2()
void SQLiteTest::testTupleVector2()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
tmp << "DROP TABLE IF EXISTS Tuples", now;
tmp << "CREATE TABLE Tuples (int0 INTEGER, int1 INTEGER)", now;
@@ -1462,7 +1505,7 @@ void SQLiteTest::testTupleVector2()
void SQLiteTest::testTuple1()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
tmp << "DROP TABLE IF EXISTS Tuples", now;
tmp << "CREATE TABLE Tuples (int0 INTEGER)", now;
@@ -1479,7 +1522,7 @@ void SQLiteTest::testTuple1()
void SQLiteTest::testTupleVector1()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
tmp << "DROP TABLE IF EXISTS Tuples", now;
tmp << "CREATE TABLE Tuples (int0 INTEGER)", now;
@@ -1506,7 +1549,7 @@ void SQLiteTest::testTupleVector1()
void SQLiteTest::testDateTime()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
tmp << "DROP TABLE IF EXISTS DateTimes", now;
tmp << "CREATE TABLE DateTimes (dt0 DATE)", now;
@@ -1542,7 +1585,7 @@ void SQLiteTest::testDateTime()
void SQLiteTest::testInternalExtraction()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
tmp << "DROP TABLE IF EXISTS Vectors", now;
tmp << "CREATE TABLE Vectors (int0 INTEGER, flt0 REAL, str0 VARCHAR)", now;
@@ -1608,7 +1651,7 @@ void SQLiteTest::testInternalExtraction()
void SQLiteTest::testPrimaryKeyConstraint()
{
Session ses (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session ses (SQLite::Connector::KEY, "dummy.db");
ses << "DROP TABLE IF EXISTS LogTest", now;
ses << "CREATE TABLE LogTest (Id INTEGER PRIMARY KEY, Time INTEGER, Value INTEGER)", now;
const double value = -200000000000.0;
@@ -1638,7 +1681,7 @@ void SQLiteTest::testPrimaryKeyConstraint()
void SQLiteTest::testNull()
{
Session ses (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session ses (SQLite::Connector::KEY, "dummy.db");
ses << "DROP TABLE IF EXISTS NullTest", now;
ses << "CREATE TABLE NullTest (i INTEGER NOT NULL)", now;
@@ -1708,7 +1751,7 @@ void SQLiteTest::testNull()
void SQLiteTest::testRowIterator()
{
Session ses (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session ses (SQLite::Connector::KEY, "dummy.db");
ses << "DROP TABLE IF EXISTS Vectors", now;
ses << "CREATE TABLE Vectors (int0 INTEGER, flt0 REAL, str0 VARCHAR)", now;
@@ -1740,7 +1783,7 @@ void SQLiteTest::testRowIterator()
void SQLiteTest::testAsync()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
tmp << "DROP TABLE IF EXISTS Strings", now;
tmp << "CREATE TABLE IF NOT EXISTS Strings (str INTEGER(10))", now;
@@ -1750,6 +1793,7 @@ void SQLiteTest::testAsync()
Statement::Result result = stmt.executeAsync();
assert (!stmt.isAsync());
result.wait();
assert (500 == result.data());
Statement stmt1 = (tmp << "SELECT * FROM Strings", into(data), async, now);
assert (stmt1.isAsync());
@@ -1823,7 +1867,7 @@ void SQLiteTest::testAsync()
void SQLiteTest::testAny()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
tmp << "DROP TABLE IF EXISTS Anys", now;
tmp << "CREATE TABLE Anys (int0 INTEGER, flt0 REAL, str0 VARCHAR)", now;
@@ -1849,7 +1893,7 @@ void SQLiteTest::testAny()
void SQLiteTest::testDynamicAny()
{
Session tmp (SessionFactory::instance().create(SQLite::Connector::KEY, "dummy.db"));
Session tmp (SQLite::Connector::KEY, "dummy.db");
tmp << "DROP TABLE IF EXISTS Anys", now;
tmp << "CREATE TABLE Anys (int0 INTEGER, flt0 REAL, str0 VARCHAR)", now;
@@ -1873,6 +1917,115 @@ void SQLiteTest::testDynamicAny()
}
void SQLiteTest::testSQLChannel()
{
Session tmp (SQLite::Connector::KEY, "dummy.db");
tmp << "DROP TABLE IF EXISTS T_POCO_LOG", now;
tmp << "CREATE TABLE T_POCO_LOG (Source VARCHAR,"
"Name VARCHAR,"
"ProcessId INTEGER,"
"Thread VARCHAR, "
"ThreadId INTEGER,"
"Priority INTEGER,"
"Text VARCHAR,"
"DateTime DATE)", now;
tmp << "DROP TABLE IF EXISTS T_POCO_LOG_ARCHIVE", now;
tmp << "CREATE TABLE T_POCO_LOG_ARCHIVE (Source VARCHAR,"
"Name VARCHAR,"
"ProcessId INTEGER,"
"Thread VARCHAR, "
"ThreadId INTEGER,"
"Priority INTEGER,"
"Text VARCHAR,"
"DateTime DATE)", now;
AutoPtr<SQLChannel> pChannel = new SQLChannel(SQLite::Connector::KEY, "dummy.db", "TestSQLChannel");
pChannel->setProperty("keep", "2 seconds");
Message msgInf("InformationSource", "a Informational async message", Message::PRIO_INFORMATION);
pChannel->log(msgInf);
Message msgWarn("WarningSource", "b Warning async message", Message::PRIO_WARNING);
pChannel->log(msgWarn);
pChannel->wait();
pChannel->setProperty("async", "false");
Message msgInfS("InformationSource", "c Informational sync message", Message::PRIO_INFORMATION);
pChannel->log(msgInfS);
Message msgWarnS("WarningSource", "d Warning sync message", Message::PRIO_WARNING);
pChannel->log(msgWarnS);
RecordSet rs(tmp, "SELECT * FROM T_POCO_LOG ORDER by Text");
assert (4 == rs.rowCount());
assert ("InformationSource" == rs["Source"]);
assert ("a Informational async message" == rs["Text"]);
rs.moveNext();
assert ("WarningSource" == rs["Source"]);
assert ("b Warning async message" == rs["Text"]);
rs.moveNext();
assert ("InformationSource" == rs["Source"]);
assert ("c Informational sync message" == rs["Text"]);
rs.moveNext();
assert ("WarningSource" == rs["Source"]);
assert ("d Warning sync message" == rs["Text"]);
Thread::sleep(3000);
Message msgInfA("InformationSource", "e Informational sync message", Message::PRIO_INFORMATION);
pChannel->log(msgInfA);
Message msgWarnA("WarningSource", "f Warning sync message", Message::PRIO_WARNING);
pChannel->log(msgWarnA);
RecordSet rs1(tmp, "SELECT * FROM T_POCO_LOG_ARCHIVE");
assert (4 == rs1.rowCount());
pChannel->setProperty("keep", "");
assert ("forever" == pChannel->getProperty("keep"));
RecordSet rs2(tmp, "SELECT * FROM T_POCO_LOG ORDER by Text");
assert (2 == rs2.rowCount());
assert ("InformationSource" == rs2["Source"]);
assert ("e Informational sync message" == rs2["Text"]);
rs2.moveNext();
assert ("WarningSource" == rs2["Source"]);
assert ("f Warning sync message" == rs2["Text"]);
}
void SQLiteTest::testSQLLogger()
{
Session tmp (SQLite::Connector::KEY, "dummy.db");
tmp << "DROP TABLE IF EXISTS T_POCO_LOG", now;
tmp << "CREATE TABLE T_POCO_LOG (Source VARCHAR,"
"Name VARCHAR,"
"ProcessId INTEGER,"
"Thread VARCHAR, "
"ThreadId INTEGER,"
"Priority INTEGER,"
"Text VARCHAR,"
"DateTime DATE)", now;
{
AutoPtr<SQLChannel> pChannel = new SQLChannel(SQLite::Connector::KEY, "dummy.db", "TestSQLChannel");
Logger& root = Logger::root();
root.setChannel(pChannel.get());
root.setLevel(Message::PRIO_INFORMATION);
root.information("Informational message");
root.warning("Warning message");
root.debug("Debug message");
}
Thread::sleep(100);
RecordSet rs(tmp, "SELECT * FROM T_POCO_LOG ORDER by DateTime");
assert (2 == rs.rowCount());
assert ("TestSQLChannel" == rs["Source"]);
assert ("Informational message" == rs["Text"]);
rs.moveNext();
assert ("TestSQLChannel" == rs["Source"]);
assert ("Warning message" == rs["Text"]);
}
void SQLiteTest::setUp()
{
}
@@ -1895,6 +2048,7 @@ CppUnit::Test* SQLiteTest::suite()
CppUnit_addTest(pSuite, SQLiteTest, testComplexTypeVector);
CppUnit_addTest(pSuite, SQLiteTest, testInsertVector);
CppUnit_addTest(pSuite, SQLiteTest, testInsertEmptyVector);
CppUnit_addTest(pSuite, SQLiteTest, testAffectedRows);
CppUnit_addTest(pSuite, SQLiteTest, testInsertSingleBulk);
CppUnit_addTest(pSuite, SQLiteTest, testInsertSingleBulkVec);
CppUnit_addTest(pSuite, SQLiteTest, testLimit);
@@ -1950,6 +2104,8 @@ CppUnit::Test* SQLiteTest::suite()
CppUnit_addTest(pSuite, SQLiteTest, testAsync);
CppUnit_addTest(pSuite, SQLiteTest, testAny);
CppUnit_addTest(pSuite, SQLiteTest, testDynamicAny);
CppUnit_addTest(pSuite, SQLiteTest, testSQLChannel);
CppUnit_addTest(pSuite, SQLiteTest, testSQLLogger);
return pSuite;
}

View File

@@ -54,7 +54,7 @@ public:
void testComplexTypeVector();
void testInsertVector();
void testInsertEmptyVector();
void testAffectedRows();
void testInsertSingleBulk();
void testInsertSingleBulkVec();
@@ -118,6 +118,9 @@ public:
void testAny();
void testDynamicAny();
void testSQLChannel();
void testSQLLogger();
void setUp();
void tearDown();

View File

@@ -0,0 +1,244 @@
//
// ArchiveStrategy.h
//
// $Id: //poco/Main/Data/include/Poco/ArchiveStrategy.h#1 $
//
// Library: Data
// Package: Logging
// Module: ArchiveStrategy
//
// Definition of the ArchiveStrategy class and subclasses.
//
// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
#ifndef Data_ArchiveStrategy_INCLUDED
#define Data_ArchiveStrategy_INCLUDED
#include "Poco/Data/Data.h"
#include "Poco/Data/Session.h"
#include "Poco/DateTime.h"
#include "Poco/Timespan.h"
#include "Poco/DynamicAny.h"
#include "Poco/SharedPtr.h"
namespace Poco {
namespace Data {
class Data_API ArchiveStrategy
/// The ArchiveStrategy is used by SQLChannel to archive log rows.
{
public:
static const std::string DEFAULT_ARCHIVE_DESTINATION;
ArchiveStrategy(const std::string& connector,
const std::string& connect,
const std::string& source,
const std::string& destination = DEFAULT_ARCHIVE_DESTINATION);
/// Creates archive strategy.
virtual ~ArchiveStrategy();
/// Destroys archive strategy.
void open();
/// Opens the session.
virtual void archive() = 0;
/// Archives the rows.
const std::string& getSource() const;
/// Returns the name of the source table containing rows to be archived.
void setSource(const std::string& source);
/// Sets the name of the source table.
const std::string& getDestination() const;
/// Returns the name of the destination table for rows to be archived.
void setDestination(const std::string& destination);
/// Sets the name of the destination table.
virtual const std::string& getThreshold() const = 0;
/// Returns the archive threshold.
virtual void setThreshold(const std::string& threshold) = 0;
/// Sets the archive threshold.
protected:
typedef Poco::SharedPtr<Session> SessionPtr;
typedef Poco::SharedPtr<Statement> StatementPtr;
Session& session();
void setCopyStatement();
void setDeleteStatement();
void setCountStatement();
Statement& getCopyStatement();
Statement& getDeleteStatement();
Statement& getCountStatement();
private:
ArchiveStrategy();
ArchiveStrategy(const ArchiveStrategy&);
ArchiveStrategy& operator = (const ArchiveStrategy&);
std::string _connector;
std::string _connect;
SessionPtr _pSession;
StatementPtr _pCopyStatement;
StatementPtr _pDeleteStatement;
StatementPtr _pCountStatement;
std::string _source;
std::string _destination;
};
//
// inlines
//
inline const std::string& ArchiveStrategy::getSource() const
{
return _source;
}
inline void ArchiveStrategy::setSource(const std::string& source)
{
_source = source;
}
inline void ArchiveStrategy::setDestination(const std::string& destination)
{
_destination = destination;
}
inline const std::string& ArchiveStrategy::getDestination() const
{
return _destination;
}
inline Session& ArchiveStrategy::session()
{
return *_pSession;
}
inline void ArchiveStrategy::setCopyStatement()
{
_pCopyStatement = new Statement(*_pSession);
}
inline void ArchiveStrategy::setDeleteStatement()
{
_pDeleteStatement = new Statement(*_pSession);
}
inline void ArchiveStrategy::setCountStatement()
{
_pCountStatement = new Statement(*_pSession);
}
inline Statement& ArchiveStrategy::getCopyStatement()
{
return *_pCopyStatement;
}
inline Statement& ArchiveStrategy::getDeleteStatement()
{
return *_pDeleteStatement;
}
inline Statement& ArchiveStrategy::getCountStatement()
{
return *_pCountStatement;
}
//
// ArchiveByAgeStrategy
//
class Data_API ArchiveByAgeStrategy: public ArchiveStrategy
/// Archives rows scheduled for archiving.
{
public:
ArchiveByAgeStrategy(const std::string& connector,
const std::string& connect,
const std::string& sourceTable,
const std::string& destinationTable = DEFAULT_ARCHIVE_DESTINATION);
~ArchiveByAgeStrategy();
void archive();
const std::string& getThreshold() const;
/// Returns the archive threshold.
void setThreshold(const std::string& threshold);
/// Sets the archive threshold.
private:
ArchiveByAgeStrategy();
ArchiveByAgeStrategy(const ArchiveByAgeStrategy&);
ArchiveByAgeStrategy& operator = (const ArchiveByAgeStrategy&);
void initStatements();
Timespan _maxAge;
std::string _ageString;
DateTime _archiveDateTime;
DynamicAny _archiveCount;
};
//
// inlines
//
inline const std::string& ArchiveByAgeStrategy::getThreshold() const
{
return _ageString;
}
} } // namespace Poco::Data
#endif // Data_ArchiveStrategy_INCLUDED

View File

@@ -99,7 +99,9 @@ public:
void reset ()
{
_bound = false;
getBinder()->reset();
AbstractBinder* pBinder = getBinder();
poco_check_ptr (pBinder);
pBinder->reset();
}
private:

View File

@@ -63,6 +63,9 @@ public:
virtual ~Connector();
/// Destroys the Connector.
virtual const std::string& name() const = 0;
/// Returns the name associated with this connector.
virtual Poco::AutoPtr<SessionImpl> createSession(const std::string& connectionString) = 0;
/// Create a SessionImpl object and initialize it with the given connectionString.
};

View File

@@ -45,7 +45,6 @@
#include "Poco/Data/BulkExtraction.h"
#include "Poco/Data/Statement.h"
#include "Poco/Data/RowIterator.h"
#include "Poco/Data/RowFormatter.h"
#include "Poco/Data/BLOB.h"
#include "Poco/String.h"
#include "Poco/DynamicAny.h"
@@ -85,6 +84,7 @@ public:
typedef RowIterator Iterator;
using Statement::isNull;
using Statement::setRowFormatter;
explicit RecordSet(const Statement& rStatement);
/// Creates the RecordSet.
@@ -288,15 +288,6 @@ public:
bool isNull(const std::string& name) const;
/// Returns true if column value of the current row is null.
void setFormatter(Row::FormatterPtr pRowFormatter);
/// Sets the row formatter for this recordset.
/// Row formatter is null pointer by default, indicating
/// use of default formatter for output formatting.
/// This function allows for custom formatters to be
/// supplied by users. After setting a user supplied formatter,
/// to revert back to the default one, call this function with
/// zero argument.
std::ostream& copyNames(std::ostream& os) const;
/// Copies the column names to the target output stream.
/// Copied string is formatted by the current RowFormatter.
@@ -346,9 +337,9 @@ private:
}
if (typeFound)
throw NotFoundException(format("Column name: %s", name));
throw NotFoundException(Poco::format("Column name: %s", name));
else
throw NotFoundException(format("Column type: %s, name: %s", std::string(typeid(T).name()), name));
throw NotFoundException(Poco::format("Column type: %s, name: %s", std::string(typeid(T).name()), name));
}
template <class C, class E>
@@ -369,7 +360,7 @@ private:
std::size_t s = rExtractions.size();
if (0 == s || pos >= s)
throw RangeException(format("Invalid column index: %z", pos));
throw RangeException(Poco::format("Invalid column index: %z", pos));
ExtractionVecPtr pExtraction = dynamic_cast<ExtractionVecPtr>(rExtractions[pos].get());
@@ -379,7 +370,7 @@ private:
}
else
{
throw Poco::BadCastException(format("Type cast failed!\nColumn: %z\nTarget type:\t%s",
throw Poco::BadCastException(Poco::format("Type cast failed!\nColumn: %z\nTarget type:\t%s",
pos,
std::string(typeid(T).name())));
}
@@ -389,7 +380,6 @@ private:
RowIterator* _pBegin;
RowIterator* _pEnd;
RowMap _rowMap;
Row::FormatterPtr _pRowFormatter;
};
@@ -519,12 +509,6 @@ inline RecordSet::Iterator RecordSet::end()
}
inline void RecordSet::setFormatter(Row::FormatterPtr pRowFormatter)
{
_pRowFormatter = pRowFormatter;
}
inline std::ostream& RecordSet::copyNames(std::ostream& os) const
{
os << (*_pBegin)->namesToString();

View File

@@ -82,7 +82,6 @@ public:
typedef RowFormatter::NameVec NameVec;
typedef RowFormatter::NameVecPtr NameVecPtr;
typedef RowFormatter::ValueVec ValueVec;
typedef SharedPtr<RowFormatter> FormatterPtr;
enum ComparisonType
{
@@ -94,7 +93,7 @@ public:
Row();
/// Creates the Row.
explicit Row(NameVecPtr pNames, FormatterPtr* pFormatter = 0);
Row(NameVecPtr pNames, const RowFormatterPtr& pFormatter = 0);
/// Creates the Row.
~Row();
@@ -201,7 +200,7 @@ public:
const ValueVec& values() const;
/// Returns the const reference to values vector.
void setFormatter(FormatterPtr* pFormatter);
void setFormatter(const RowFormatterPtr& pFormatter);
/// Sets the formatter for this row and takes the
/// shared ownership of it.
@@ -226,7 +225,7 @@ private:
NameVecPtr _pNames;
ValueVec _values;
SortMap _sortFields;
FormatterPtr _pFormatter;
RowFormatterPtr _pFormatter;
mutable std::string _nameStr;
mutable std::string _valueStr;
};

View File

@@ -42,6 +42,7 @@
#include "Poco/Data/Data.h"
#include "Poco/SharedPtr.h"
#include "Poco/RefCountedObject.h"
#include "Poco/DynamicAny.h"
#include <sstream>
#include <vector>
@@ -52,51 +53,53 @@ namespace Data {
class Data_API RowFormatter
/// Row formatter is a rudimentary formatting class providing
/// basic row formatting. For custom formatting
/// strategies, inherit from this class and override formatNames()
/// Row formatter is an abstract class providing definition for row formatting functionality.
/// For custom formatting strategies, inherit from this class and override formatNames()
/// and formatValues() member functions.
///
/// Row formatter can be either passed to the RecordSet at construction time,
/// like in the following example:
///
/// RecordSet rs(session. "SELECT * FROM Table", new MyRowFormater);
///
/// or it can be supplied to the statement as in the following example:
///
/// MyRowFormatter rf
/// session << "SELECT * FROM Table", format(rf);
///
/// If no formatter is externally supplied to the statement, the SimpleRowFormatter is used.
/// Statement always has the ownership of the row formatter and shares
/// it with rows through RecordSet.
///
{
public:
typedef std::vector<std::string> NameVec;
typedef SharedPtr<std::vector<std::string> > NameVecPtr;
typedef std::vector<DynamicAny> ValueVec;
static const int DEFAULT_COLUMN_WIDTH = 16;
RowFormatter(std::streamsize width);
/// Creates the RowFormatter and sets the column width to specified value.
RowFormatter(const std::string& prefix = "", const std::string& postfix = "");
/// Creates the RowFormatter and sets the prefix and postfix to specified values.
virtual ~RowFormatter();
/// Destroys the RowFormatter.
virtual std::string& formatNames(const NameVecPtr pNames, std::string& formattedNames) const = 0;
/// Formats the row field names.
virtual std::string& formatValues(const ValueVec& vals, std::string& formattedValues) const = 0;
/// Formats the row values.
const std::string& prefix() const;
/// Returns prefix string;
virtual std::string& formatNames(const NameVecPtr pNames, std::string& formattedNames) const;
/// Formats the row field names.
virtual std::string& formatValues(const ValueVec& vals, std::string& formattedValues) const;
/// Formats the row values.
const std::string& postfix() const;
/// Returns postfix string;
void setWidth(std::streamsize width);
/// Sets the column width.
std::streamsize getWidth() const;
/// Returns the column width.
protected:
void setPrefix(const std::string& prefix);
void setPostfix(const std::string& postfix);
private:
std::streamsize _width;
std::string _prefix;
std::string _postfix;
};
@@ -106,17 +109,6 @@ private:
/// inlines
///
inline void RowFormatter::setWidth(std::streamsize width)
{
_width = width;
}
inline std::streamsize RowFormatter::getWidth() const
{
return _width;
}
inline void RowFormatter::setPrefix(const std::string& prefix)
{
@@ -142,6 +134,18 @@ inline const std::string& RowFormatter::postfix() const
}
template <typename T>
inline T* format(const T& formatter)
/// Utility function used to pass formatter to the statement.
/// Statement takes the ownership of the formatter.
{
return new T(formatter);
}
typedef SharedPtr<RowFormatter> RowFormatterPtr;
} } // namespace Poco::Data

View File

@@ -0,0 +1,242 @@
//
// SQLChannel.h
//
// $Id: //poco/Main/Data/include/Poco/Data/SQLChannel.h#4 $
//
// Library: Net
// Package: Logging
// Module: SQLChannel
//
// Definition of the SQLChannel class.
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
#ifndef Data_SQLChannel_INCLUDED
#define Data_SQLChannel_INCLUDED
#include "Poco/Data/Data.h"
#include "Poco/Data/Connector.h"
#include "Poco/Data/Session.h"
#include "Poco/Data/Statement.h"
#include "Poco/Data/ArchiveStrategy.h"
#include "Poco/Channel.h"
#include "Poco/Message.h"
#include "Poco/AutoPtr.h"
#include "Poco/String.h"
#include "Poco/DynamicAny.h"
namespace Poco {
namespace Data {
class Data_API SQLChannel: public Poco::Channel
/// This Channel implements logging to a SQL database.
/// The channel is dependent on the schema. The DDL for
/// table creation (subject to target DDL dialect dependent
/// modifications) is:
///
/// "CREATE TABLE T_POCO_LOG (Source VARCHAR,
/// Name VARCHAR,
/// ProcessId INTEGER,
/// Thread VARCHAR,
/// ThreadId INTEGER,
/// Priority INTEGER,
/// Text VARCHAR,
/// DateTime DATE)"
///
/// The table name is configurable through "table" property.
/// Other than DateTime filed name used for optiona time-based archiving purposes, currently the
/// field names are not mandated. However, it is recomended to use names as specified above.
///
/// To provide as non-intrusive operation as possbile, the log entries are cached and
/// inserted into the target database asynchronously by default . The blocking, however, will occur
/// before the next entry insertion with default timeout of 1 second. The default settings can be
/// overriden (see async, timeout and throw properties for details).
/// If throw property is false, insertion timeouts are ignored, otherwise a TimeoutException is thrown.
/// To force insertion of every entry, set timeout to 0. This setting, however, introduces
/// a risk of long blocking periods in case of remote server communication delays.
{
public:
typedef Statement::ResultType ResultType;
SQLChannel();
/// Creates SQLChannel.
SQLChannel(const std::string& connector,
const std::string& connect,
const std::string& name = "-");
/// Creates a SQLChannel with the given connector, connect string, timeout, table and name.
/// The connector must be already registered.
void open();
/// Opens the SQLChannel.
void close();
/// Closes the SQLChannel.
void log(const Message& msg);
/// Sends the message's text to the syslog service.
void setProperty(const std::string& name, const std::string& value);
/// Sets the property with the given value.
///
/// The following properties are supported:
/// * name: The name used to identify the source of log messages.
/// Defaults to "-".
///
/// * target: The target data storage type ("SQLite", "ODBC", ...).
///
/// * connector: The target data storage connector name.
///
/// * connect: The target data storage connection string.
///
/// * table: Destination log table name. Defaults to "T_POCO_LOG".
/// Table must exist in the target database.
///
/// * keep: Max row age for the log table. To disable archiving,
/// set this property to empty string or "forever".
///
/// * archive: Archive table name. Defaults to "T_POCO_LOG_ARCHIVE".
/// Table must exist in the target database. To disable archiving,
/// set this property to empty string.
///
/// * async: Indicates asynchronous execution. When excuting asynchronously,
/// messages are sent to the target using asyncronous execution.
/// However, prior to the next message being processed and sent to
/// the target, the previous operation must have been either completed
/// or timed out (see timeout and throw properties for details on
/// how abnormal conditos are handled).
///
/// * timeout: Timeout (ms) to wait for previous log operation completion.
/// Values "0" and "" mean no timeout. Only valid when logging
/// is asynchronous, otherwise ignored.
///
/// * throw: Boolean value indicating whether to throw in case of timeout.
/// Setting this property to false may result in log entries being lost.
/// True values are (case insensitive) "true", "t", "yes", "y".
/// Anything else yields false.
std::string getProperty(const std::string& name) const;
/// Returns the value of the property with the given name.
ResultType wait();
/// Waits for the completion of the previous operation and returns
/// the result. If chanel is in synchronous mode, returns 0 immediately.
static void registerChannel();
/// Registers the channel with the global LoggingFactory.
static const std::string PROP_CONNECT;
static const std::string PROP_CONNECTOR;
static const std::string PROP_NAME;
static const std::string PROP_TABLE;
static const std::string PROP_ARCHIVE_TABLE;
static const std::string PROP_MAX_AGE;
static const std::string PROP_ASYNC;
static const std::string PROP_TIMEOUT;
static const std::string PROP_THROW;
protected:
~SQLChannel();
private:
typedef Poco::SharedPtr<Session> SessionPtr;
typedef Poco::SharedPtr<Statement> StatementPtr;
typedef Poco::Message::Priority Priority;
typedef Poco::SharedPtr<ArchiveStrategy> StrategyPtr;
void initLogStatement();
/// Initiallizes the log statement.
void initArchiveStatements();
/// Initiallizes the archive statement.
void logAsync(const Message& msg);
/// Waits for previous operation completion and
/// calls logSync(). If the previous operation times out,
/// and _throw is true, TimeoutException is thrown, oterwise
/// the timeout is ignored and log entry is lost.
void logSync(const Message& msg);
/// Inserts the message in the target database.
bool isTrue(const std::string& value) const;
/// Returns true is value is "true", "t", "yes" or "y".
/// Case insensitive.
std::string _connector;
std::string _connect;
SessionPtr _pSession;
StatementPtr _pLogStatement;
std::string _name;
std::string _table;
int _timeout;
bool _throw;
bool _async;
// members for log entry cache (needed for async mode)
std::string _source;
long _pid;
std::string _thread;
long _tid;
int _priority;
std::string _text;
DateTime _dateTime;
StrategyPtr _pArchiveStrategy;
};
//
// inlines
//
inline SQLChannel::ResultType SQLChannel::wait()
{
if (_async && _pLogStatement)
return _pLogStatement->wait(_timeout);
return 0;
}
inline bool SQLChannel::isTrue(const std::string& value) const
{
return ((0 == icompare(value, "true")) ||
(0 == icompare(value, "t")) ||
(0 == icompare(value, "yes")) ||
(0 == icompare(value, "y")));
}
} } // namespace Poco::Data
#endif // Data_SQLChannel_INCLUDED

View File

@@ -143,9 +143,10 @@ class Data_API Session
/// ses << "INSERT INTO Person (LastName, Age) VALUES(:ln, :age)", use(nameVec), use(ageVec);
///
/// The size of all use parameters MUST be the same, otherwise an exception is thrown. Furthermore,
/// the amount of use clauses must match the number of wildcards in the query (to be more precisely:
/// each binding has a numberOfColumnsHandled() value which is per default 1. The sum of all these values must match the wildcard count in the query.
/// But this is only important if you have written your own TypeHandler specializations).
/// the amount of use clauses must match the number of wildcards in the query (to be more precise:
/// each binding has a numberOfColumnsHandled() value which defaults to 1. The sum of all these values
/// must match the wildcard count in the query.
/// However, this is only important if you have written your own TypeHandler specializations.
/// If you plan to map complex object types to tables see the TypeHandler documentation.
/// For now, we simply assume we have written one TypeHandler for Person objects. Instead of having n different vectors,
/// we have one collection:
@@ -159,6 +160,17 @@ class Data_API Session
///
/// std::vector<Person> people;
/// ses << "SELECT * FROM PERSON", into(people);
///
/// Mixing constants or variables with manipulators is allowed provided there are corresponding placeholders for the constants provided in
/// the SQL string, such as in following example:
///
/// std::vector<Person> people;
/// ses << "SELECT * FROM %s", into(people), "PERSON";
///
/// Formatting only kicks in if there are values to be injected into the SQL string, otherwise it is skipped.
/// If the formatting will occur and the percent sign is part of the query itself, it can be passed to the query by entering it twice (%%).
/// However, if no formatting is used, one percent sign is sufficient as the string will be passed unaltered.
/// For complete list of supported data types with their respective specifications, see the documentation for format in Foundation.
{
public:
Session(Poco::AutoPtr<SessionImpl> ptrImpl);
@@ -172,7 +184,7 @@ public:
/// Creates a session by copying another one.
Session& operator = (const Session&);
/// Assignement operator.
/// Assignment operator.
~Session();
/// Destroys the Session.

View File

@@ -74,8 +74,8 @@ public:
static SessionFactory& instance();
/// returns the static instance of the singleton.
void add(const std::string& key, Connector* pIn);
/// Registers a Connector under the given key at the factory. If a registration for that
void add(Connector* pIn);
/// Registers a Connector under its key at the factory. If a registration for that
/// key is already active, the first registration will be kept, only its reference count will be increased.
/// Always takes ownership of parameter pIn.

View File

@@ -0,0 +1,125 @@
//
// RowFormatter.h
//
// $Id: //poco/Main/Data/include/Poco/Data/SimpleRowFormatter.h#1 $
//
// Library: Data
// Package: DataCore
// Module: SimpleRowFormatter
//
// Definition of the RowFormatter class.
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
#ifndef Data_SimpleRowFormatter_INCLUDED
#define Data_SimpleRowFormatter_INCLUDED
#include "Poco/Data/Data.h"
#include "Poco/Data/RowFormatter.h"
namespace Poco {
namespace Data {
class Data_API SimpleRowFormatter: public RowFormatter
/// A simple row formatting class.
{
public:
//typedef RowFormatter::NameVec NameVec;
//typedef RowFormatter::NameVecPtr NameVecPtr;
//typedef RowFormatter::ValueVec ValueVec;
static const int DEFAULT_COLUMN_WIDTH = 16;
SimpleRowFormatter(std::streamsize columnWidth = DEFAULT_COLUMN_WIDTH);
/// Creates the SimpleRowFormatter and sets the column width to specified value.
SimpleRowFormatter(const SimpleRowFormatter& other);
/// Creates the copy of the supplied SimpleRowFormatter.
SimpleRowFormatter& operator = (const SimpleRowFormatter& row);
/// Assignment operator.
~SimpleRowFormatter();
/// Destroys the SimpleRowFormatter.
void swap(SimpleRowFormatter& other);
/// Swaps the row formatter with another one.
std::string& formatNames(const NameVecPtr pNames, std::string& formattedNames) const;
/// Formats the row field names.
std::string& formatValues(const ValueVec& vals, std::string& formattedValues) const;
/// Formats the row values.
void setColumnWidth(std::streamsize width);
/// Sets the column width.
std::streamsize getColumnWidth() const;
/// Returns the column width.
private:
std::streamsize _colWidth;
};
///
/// inlines
///
inline void SimpleRowFormatter::setColumnWidth(std::streamsize columnWidth)
{
_colWidth = columnWidth;
}
inline std::streamsize SimpleRowFormatter::getColumnWidth() const
{
return _colWidth;
}
} } // namespace Poco::Data
namespace std
{
template<>
inline void swap<Poco::Data::SimpleRowFormatter>(Poco::Data::SimpleRowFormatter& s1,
Poco::Data::SimpleRowFormatter& s2)
/// Full template specalization of std:::swap for SimpleRowFormatter
{
s1.swap(s2);
}
}
#endif // Data_SimpleRowFormatter_INCLUDED

View File

@@ -44,10 +44,13 @@
#include "Poco/Data/StatementImpl.h"
#include "Poco/Data/Range.h"
#include "Poco/Data/Bulk.h"
#include "Poco/Data/Row.h"
#include "Poco/Data/SimpleRowFormatter.h"
#include "Poco/SharedPtr.h"
#include "Poco/Mutex.h"
#include "Poco/ActiveMethod.h"
#include "Poco/ActiveResult.h"
#include "Poco/Format.h"
namespace Poco {
@@ -68,35 +71,6 @@ class Data_API Statement
/// 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:
///
@@ -112,6 +86,10 @@ class Data_API Statement
///
/// See individual functions documentation for more details.
///
/// Statement owns the RowFormatter, which can be provided externaly through setFormatter()
/// member function.
/// If no formatter is externally supplied to the statement, the SimpleRowFormatter is lazy
/// created and used.
{
public:
typedef void (*Manipulator)(Statement&);
@@ -122,6 +100,8 @@ public:
typedef ActiveMethod<ResultType, void, StatementImpl> AsyncExecMethod;
typedef SharedPtr<AsyncExecMethod> AsyncExecMethodPtr;
static const int WAIT_FOREVER = -1;
enum Storage
{
STORAGE_DEQUE = StatementImpl::STORAGE_DEQUE_IMPL,
@@ -200,28 +180,83 @@ public:
///
/// Set per default to zero to Limit::LIMIT_UNLIMITED, which disables the limit.
Statement& operator , (RowFormatter* pRowFformatter);
/// Sets the row formatter for the statement.
Statement& operator , (const Range& extrRange);
/// Sets a an extraction range for the maximum number of rows a select is allowed to return.
///
/// Set per default to Limit::LIMIT_UNLIMITED which disables the range.
std::string toString() const;
Statement& operator , (char value);
/// Adds the value to the list of values to be supplied to the SQL string formatting function.
Statement& operator , (Poco::UInt8 value);
/// Adds the value to the list of values to be supplied to the SQL string formatting function.
Statement& operator , (Poco::Int8 value);
/// Adds the value to the list of values to be supplied to the SQL string formatting function.
Statement& operator , (Poco::UInt16 value);
/// Adds the value to the list of values to be supplied to the SQL string formatting function.
Statement& operator , (Poco::Int16 value);
/// Adds the value to the list of values to be supplied to the SQL string formatting function.
Statement& operator , (Poco::UInt32 value);
/// Adds the value to the list of values to be supplied to the SQL string formatting function.
Statement& operator , (Poco::Int32 value);
/// Adds the value to the list of values to be supplied to the SQL string formatting function.
#ifndef POCO_LONG_IS_64_BIT
Statement& operator , (long value);
/// Adds the value to the list of values to be supplied to the SQL string formatting function.
Statement& operator , (unsigned long value);
/// Adds the value to the list of values to be supplied to the SQL string formatting function.
#endif
Statement& operator , (Poco::UInt64 value);
/// Adds the value to the list of values to be supplied to the SQL string formatting function.
Statement& operator , (Poco::Int64 value);
/// Adds the value to the list of values to be supplied to the SQL string formatting function.
Statement& operator , (double value);
/// Adds the value to the list of values to be supplied to the SQL string formatting function.
Statement& operator , (float value);
/// Adds the value to the list of values to be supplied to the SQL string formatting function.
Statement& operator , (bool value);
/// Adds the value to the list of values to be supplied to the SQL string formatting function.
Statement& operator , (const std::string& value);
/// Adds the value to the list of values to be supplied to the SQL string formatting function.
Statement& operator , (const char* value);
/// Adds the value to the list of values to be supplied to the SQL string formatting function.
const std::string& toString() const;
/// Creates a string from the accumulated SQL statement.
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.
/// Returns the number of rows extracted from the database (for statements
/// returning data) or number of rows affected (for all other statements).
/// 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().
/// The result of execution (i.e. number of returned or affected rows) can be
/// obtained by calling wait() on the statement at a later point in time.
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.
/// Returns immediately. Calling wait() (on either the result returned from this
/// call or the statement itself) returns the number of rows extracted or number
/// of rows affected by the statement execution.
/// When executed on a synchronous statement, this method does not alter the
/// statement's synchronous nature.
@@ -269,6 +304,10 @@ public:
/// Returns the number of extraction storage buffers associated
/// with the statement.
void setRowFormatter(RowFormatter* pRowFormatter);
/// Sets the row formatter for this statement.
/// Statement takes the ownership of the formatter.
protected:
typedef Poco::AutoPtr<StatementImpl> StatementImplPtr;
@@ -290,12 +329,20 @@ protected:
StatementImplPtr impl() const;
/// Returns pointer to statement implementation.
private:
static const int WAIT_FOREVER = -1;
const RowFormatterPtr& getRowFormatter();
/// Returns the row formatter for this statement.
private:
const Result& doAsyncExec();
/// Asynchronously executes the statement.
template <typename T>
Statement& commaImpl (const T& val)
{
_arguments.push_back(val);
return *this;
}
StatementImplPtr _pImpl;
// asynchronous execution related members
@@ -303,6 +350,9 @@ private:
mutable ResultPtr _pResult;
Mutex _mutex;
AsyncExecMethodPtr _pAsyncExec;
std::vector<Any> _arguments;
RowFormatterPtr _pRowFormatter;
mutable std::string _stmtString;
};
@@ -381,6 +431,110 @@ inline void Data_API reset(Statement& statement)
// inlines
//
inline Statement& Statement::operator , (RowFormatter* pRowFformatter)
{
_pRowFormatter = pRowFformatter;
return *this;
}
inline Statement& Statement::operator , (char value)
{
return commaImpl(value);
}
inline Statement& Statement::operator , (Poco::UInt8 value)
{
return commaImpl(value);
}
inline Statement& Statement::operator , (Poco::Int8 value)
{
return commaImpl(value);
}
inline Statement& Statement::operator , (Poco::UInt16 value)
{
return commaImpl(value);
}
inline Statement& Statement::operator , (Poco::Int16 value)
{
return commaImpl(value);
}
inline Statement& Statement::operator , (Poco::UInt32 value)
{
return commaImpl(value);
}
inline Statement& Statement::operator , (Poco::Int32 value)
{
return commaImpl(value);
}
#ifndef POCO_LONG_IS_64_BIT
inline Statement& Statement::operator , (long value)
{
return commaImpl(value);
}
inline Statement& Statement::operator , (unsigned long value)
{
return commaImpl(value);
}
#endif
inline Statement& Statement::operator , (Poco::UInt64 value)
{
return commaImpl(value);
}
inline Statement& Statement::operator , (Poco::Int64 value)
{
return commaImpl(value);
}
inline Statement& Statement::operator , (double value)
{
return commaImpl(value);
}
inline Statement& Statement::operator , (float value)
{
return commaImpl(value);
}
inline Statement& Statement::operator , (bool value)
{
return commaImpl(value);
}
inline Statement& Statement::operator , (const std::string& value)
{
return commaImpl(value);
}
inline Statement& Statement::operator , (const char* value)
{
return commaImpl(std::string(value));
}
inline Statement::StatementImplPtr Statement::impl() const
{
@@ -388,12 +542,11 @@ inline Statement::StatementImplPtr Statement::impl() const
}
inline std::string Statement::toString() const
inline const std::string& Statement::toString() const
{
return _pImpl->toString();
return _stmtString = _pImpl->toString();
}
inline const AbstractExtractionVec& Statement::extractions() const
{
return _pImpl->extractions();
@@ -472,6 +625,19 @@ inline bool Statement::isAsync() const
}
inline void Statement::setRowFormatter(RowFormatter* pRowFormatter)
{
_pRowFormatter = pRowFormatter;
}
inline const RowFormatterPtr& Statement::getRowFormatter()
{
if (!_pRowFormatter) _pRowFormatter = new SimpleRowFormatter;
return _pRowFormatter;
}
inline void swap(Statement& s1, Statement& s2)
{
s1.swap(s2);

View File

@@ -138,7 +138,8 @@ public:
/// Create a string version of the SQL statement.
Poco::UInt32 execute();
/// Executes a statement. Returns the number of rows extracted.
/// Executes a statement. Returns the number of rows extracted for statements
/// returning data or number of rows affected for all other statements (insert, update, delete).
void reset();
/// Resets the statement, so that we can reuse all bindings and re-execute again.
@@ -166,6 +167,10 @@ protected:
virtual Poco::UInt32 columnsReturned() const = 0;
/// Returns number of columns returned by query.
virtual Poco::UInt32 affectedRowCount() const = 0;
/// Returns the number of affected rows.
/// Used to find out the number of rows affected by insert, delete or update.
virtual const MetaColumn& metaColumn(Poco::UInt32 pos) const = 0;
/// Returns column meta data.
@@ -395,6 +400,9 @@ private:
bool isBulkSupported() const;
/// Returns true if connector and session support bulk operation.
void formatSQL(std::vector<Any>& arguments);
/// Formats the SQL string by filling in placeholders with values from supplied vector.
StatementImpl(const StatementImpl& stmt);
StatementImpl& operator = (const StatementImpl& stmt);
@@ -421,7 +429,6 @@ private:
inline void StatementImpl::addBinding(AbstractBinding* pBinding)
{
poco_check_ptr (pBinding);
_bindings.push_back(pBinding);
}

View File

@@ -20,6 +20,7 @@
#include "Poco/SharedPtr.h"
#include "Poco/Data/SessionFactory.h"
#include "Poco/Data/Session.h"
#include "Poco/Data/Statement.h"
#include "Poco/Data/RecordSet.h"
#include "Poco/Data/RowFormatter.h"
#include "Poco/Data/SQLite/Connector.h"
@@ -88,19 +89,30 @@ int main(int argc, char** argv)
Session session("SQLite", "sample.db");
// drop sample table, if it exists
session << "DROP TABLE IF EXISTS Person", now;
session << "DROP TABLE IF EXISTS Simpsons", now;
// (re)create table
session << "CREATE TABLE Person (Name VARCHAR(30), Address VARCHAR, Age INTEGER(3))", now;
session << "CREATE TABLE Simpsons (Name VARCHAR(30), Address VARCHAR, Age INTEGER(3))", now;
// insert some rows
session << "INSERT INTO Person VALUES('Homer Simpson', 'Springfield', 42)", now;
session << "INSERT INTO Person VALUES('Marge Simpson', 'Springfield', 38)", now;
session << "INSERT INTO Person VALUES('Bart Simpson', 'Springfield', 12)", now;
session << "INSERT INTO Person VALUES('Lisa Simpson', 'Springfield', 10)", now;
session << "INSERT INTO Simpsons VALUES('Homer Simpson', 'Springfield', 42)", now;
session << "INSERT INTO Simpsons VALUES('Marge Simpson', 'Springfield', 38)", now;
session << "INSERT INTO Simpsons VALUES('Bart Simpson', 'Springfield', 12)", now;
session << "INSERT INTO Simpsons VALUES('Lisa Simpson', 'Springfield', 10)", now;
// create a recordset and print the column names and data as HTML table
std::cout << RecordSet(session, "SELECT * FROM Person", new HTMLTableFormatter);
// create a statement and print the column names and data as HTML table
HTMLTableFormatter tf;
Statement stmt = (session << "SELECT * FROM Simpsons", format(tf), now);
RecordSet rs(stmt);
std::cout << rs << std::endl;
// Note: The code above is divided into individual steps for clarity purpose.
// The four lines can be reduced to the following single line of code:
std::cout << RecordSet(session, "SELECT * FROM Simpsons", new HTMLTableFormatter);
// simple formatting example (uses the default SimpleRowFormatter provided by framework)
std::cout << std::endl << "Simple formatting:" << std::endl << std::endl;
std::cout << RecordSet(session, "SELECT * FROM Simpsons");
return 0;
}

View File

@@ -0,0 +1,166 @@
//
// ArchiveStrategy.cpp
//
// $Id: //poco/Main/Data/src/ArchiveStrategy.cpp#8 $
//
// Library: Data
// Package: Logging
// Module: ArchiveStrategy
//
// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
#include "Poco/Data/ArchiveStrategy.h"
namespace Poco {
namespace Data {
//
// ArchiveStrategy
//
const std::string ArchiveStrategy::DEFAULT_ARCHIVE_DESTINATION = "T_POCO_LOG_ARCHIVE";
ArchiveStrategy::ArchiveStrategy(const std::string& connector,
const std::string& connect,
const std::string& source,
const std::string& destination):
_connector(connector),
_connect(connect),
_source(source),
_destination(destination)
{
open();
}
ArchiveStrategy::~ArchiveStrategy()
{
}
void ArchiveStrategy::open()
{
if (_connector.empty() || _connect.empty())
throw IllegalStateException("Connector and connect string must be non-empty.");
_pSession = new Session(_connector, _connect);
}
//
// ArchiveByAgeStrategy
//
ArchiveByAgeStrategy::ArchiveByAgeStrategy(const std::string& connector,
const std::string& connect,
const std::string& sourceTable,
const std::string& destinationTable):
ArchiveStrategy(connector, connect, sourceTable, destinationTable)
{
initStatements();
}
ArchiveByAgeStrategy::~ArchiveByAgeStrategy()
{
}
void ArchiveByAgeStrategy::archive()
{
if (!session().isConnected()) open();
DateTime now;
_archiveDateTime = now - _maxAge;
getCountStatement().execute();
if (_archiveCount > 0)
{
getCopyStatement().execute();
getDeleteStatement().execute();
}
}
void ArchiveByAgeStrategy::initStatements()
{
std::string src = getSource();
std::string dest = getDestination();
setCountStatement();
_archiveCount = 0;
std::string sql;
Poco::format(sql, "SELECT COUNT(*) FROM %s WHERE DateTime < ?", src);
getCountStatement() << sql, into(_archiveCount), use(_archiveDateTime);
setCopyStatement();
sql.clear();
Poco::format(sql, "INSERT INTO %s SELECT * FROM %s WHERE DateTime < ?", dest, src);
getCopyStatement() << sql, use(_archiveDateTime);
setDeleteStatement();
sql.clear();
Poco::format(sql, "DELETE FROM %s WHERE DateTime < ?", src);
getDeleteStatement() << sql, use(_archiveDateTime);
}
void ArchiveByAgeStrategy::setThreshold(const std::string& age)
{
std::string::const_iterator it = age.begin();
std::string::const_iterator end = age.end();
int n = 0;
while (it != end && std::isspace(*it)) ++it;
while (it != end && std::isdigit(*it)) { n *= 10; n += *it++ - '0'; }
while (it != end && std::isspace(*it)) ++it;
std::string unit;
while (it != end && std::isalpha(*it)) unit += *it++;
Timespan::TimeDiff factor = Timespan::SECONDS;
if (unit == "minutes")
factor = Timespan::MINUTES;
else if (unit == "hours")
factor = Timespan::HOURS;
else if (unit == "days")
factor = Timespan::DAYS;
else if (unit == "weeks")
factor = 7*Timespan::DAYS;
else if (unit == "months")
factor = 30*Timespan::DAYS;
else if (unit != "seconds")
throw InvalidArgumentException("setMaxAge", age);
_maxAge = factor * n;
}
} } // namespace Poco::Data

View File

@@ -64,9 +64,9 @@ RecordSet::RecordSet(Session& rSession,
Statement((rSession << query, now)),
_currentRow(0),
_pBegin(new RowIterator(this)),
_pEnd(new RowIterator(this, true)),
_pRowFormatter(pRowFormatter)
_pEnd(new RowIterator(this, true))
{
if (pRowFormatter) setRowFormatter(pRowFormatter);
}
@@ -74,8 +74,7 @@ RecordSet::RecordSet(const RecordSet& other):
Statement(other.impl().duplicate()),
_currentRow(other._currentRow),
_pBegin(new RowIterator(this)),
_pEnd(new RowIterator(this, true)),
_pRowFormatter(other._pRowFormatter)
_pEnd(new RowIterator(this, true))
{
}
@@ -155,14 +154,14 @@ Row& RecordSet::row(std::size_t pos)
{
if (_rowMap.size())//reuse first row column names to save some memory
{
pRow = new Row(_rowMap.begin()->second->names(), &_pRowFormatter);
pRow = new Row(_rowMap.begin()->second->names(), getRowFormatter());
for (std::size_t col = 0; col < columns; ++col)
pRow->set(col, value(col, pos));
}
else
{
pRow = new Row;
if (_pRowFormatter) pRow->setFormatter(&_pRowFormatter);
pRow->setFormatter(getRowFormatter());
for (std::size_t col = 0; col < columns; ++col)
pRow->append(metaColumn(static_cast<UInt32>(col)).name(), value(col, pos));
}

View File

@@ -35,7 +35,7 @@
#include "Poco/Data/Row.h"
#include "Poco/Data/RowFormatter.h"
#include "Poco/Data/SimpleRowFormatter.h"
#include "Poco/Exception.h"
@@ -52,18 +52,17 @@ std::ostream& operator << (std::ostream &os, const Row& row)
Row::Row():
_pNames(0),
_pFormatter(new RowFormatter)
_pFormatter(new SimpleRowFormatter)
{
}
Row::Row(NameVecPtr pNames, FormatterPtr* pFormatter):
Row::Row(NameVecPtr pNames, const RowFormatterPtr& pFormatter):
_pNames(pNames)
{
if (!_pNames) throw NullPointerException();
if (pFormatter && *pFormatter) _pFormatter = *pFormatter;
else _pFormatter = new RowFormatter;
setFormatter(pFormatter);
_values.resize(_pNames->size());
addSortField(0);
@@ -315,12 +314,12 @@ bool Row::operator < (const Row& other) const
}
void Row::setFormatter(FormatterPtr* pFormatter)
void Row::setFormatter(const RowFormatterPtr& pFormatter)
{
if (pFormatter && *pFormatter)
_pFormatter = *pFormatter;
if (pFormatter)
_pFormatter = pFormatter;
else
_pFormatter = new RowFormatter;
_pFormatter = new SimpleRowFormatter;
}

View File

@@ -43,14 +43,7 @@ namespace Poco {
namespace Data {
RowFormatter::RowFormatter(std::streamsize width):
_width(width)
{
}
RowFormatter::RowFormatter(const std::string& prefix, const std::string& postfix):
_width(DEFAULT_COLUMN_WIDTH),
_prefix(prefix),
_postfix(postfix)
{
@@ -62,44 +55,4 @@ RowFormatter::~RowFormatter()
}
std::string& RowFormatter::formatNames(const NameVecPtr pNames, std::string& formattedNames) const
{
std::ostringstream str;
std::string line(_width * pNames->size(), '-');
NameVec::const_iterator it = pNames->begin();
NameVec::const_iterator end = pNames->end();
for (; it != end; ++it)
{
str << std::left << std::setw(_width) << *it;
}
str << std::endl << line << std::endl;
return formattedNames = str.str();
}
std::string& RowFormatter::formatValues(const ValueVec& vals, std::string& formattedValues) const
{
std::ostringstream str;
ValueVec::const_iterator it = vals.begin();
ValueVec::const_iterator end = vals.end();
for (; it != end; ++it)
{
if (it->isNumeric())
{
str << std::right
<< std::fixed
<< std::setprecision(2);
}
else str << std::left;
str << std::setw(_width) << it->convert<std::string>();
}
str << std::endl;
return formattedValues = str.str();
}
} } // namespace Poco::Data

296
Data/src/SQLChannel.cpp Normal file
View File

@@ -0,0 +1,296 @@
//
// SQLChannel.cpp
//
// $Id: //poco/Main/Data/src/SQLChannel.cpp#3 $
//
// Library: Net
// Package: Logging
// Module: SQLChannel
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
#include "Poco/Data/SQLChannel.h"
#include "Poco/Data/SessionFactory.h"
#include "Poco/DateTime.h"
#include "Poco/LoggingFactory.h"
#include "Poco/Instantiator.h"
#include "Poco/NumberParser.h"
#include "Poco/NumberFormatter.h"
#include "Poco/Format.h"
namespace Poco {
namespace Data {
const std::string SQLChannel::PROP_CONNECTOR("connector");
const std::string SQLChannel::PROP_CONNECT("connect");
const std::string SQLChannel::PROP_NAME("name");
const std::string SQLChannel::PROP_TABLE("table");
const std::string SQLChannel::PROP_ARCHIVE_TABLE("archive");
const std::string SQLChannel::PROP_MAX_AGE("keep");
const std::string SQLChannel::PROP_ASYNC("async");
const std::string SQLChannel::PROP_TIMEOUT("timeout");
const std::string SQLChannel::PROP_THROW("throw");
SQLChannel::SQLChannel():
_name("-"),
_table("T_POCO_LOG"),
_timeout(1000),
_throw(true),
_async(true)
{
}
SQLChannel::SQLChannel(const std::string& connector,
const std::string& connect,
const std::string& name):
_connector(connector),
_connect(connect),
_name(name),
_table("T_POCO_LOG"),
_timeout(1000),
_throw(true),
_async(true)
{
open();
}
SQLChannel::~SQLChannel()
{
close();
}
void SQLChannel::open()
{
if (_connector.empty() || _connect.empty())
throw IllegalStateException("Connector and connect string must be non-empty.");
_pSession = new Session(_connector, _connect);
initLogStatement();
}
void SQLChannel::close()
{
wait();
}
void SQLChannel::log(const Message& msg)
{
if (_async) logAsync(msg);
else logSync(msg);
}
void SQLChannel::logAsync(const Message& msg)
{
if (!_pSession || !_pSession->isConnected()) open();
Statement::ResultType ret = wait();
if (0 == ret && !_pLogStatement->done() && !_pLogStatement->initialized())
{
if (_throw)
throw TimeoutException("Timed out waiting for previous statement completion");
else return;
}
logSync(msg);
}
void SQLChannel::logSync(const Message& msg)
{
//if (isArchiving()) archive();
if (_pArchiveStrategy) _pArchiveStrategy->archive();
_source = msg.getSource();
_pid = msg.getPid();
_thread = msg.getThread();
_tid = msg.getTid();
_priority = msg.getPriority();
_text = msg.getText();
_dateTime = msg.getTime();
if (_source.empty()) _source = _name;
_pLogStatement->execute();
}
void SQLChannel::setProperty(const std::string& name, const std::string& value)
{
if (name == PROP_NAME)
{
_name = value;
if (_name.empty()) _name = "-";
}
else if (name == PROP_CONNECTOR)
{
_connector = value;
close(); open();
}
else if (name == PROP_CONNECT)
{
_connect = value;
close(); open();
}
else if (name == PROP_TABLE)
{
_table = value;
initLogStatement();
}
else if (name == PROP_ARCHIVE_TABLE)
{
if (value.empty())
{
_pArchiveStrategy = 0;
}
else if (_pArchiveStrategy)
{
_pArchiveStrategy->setDestination(value);
}
else
{
_pArchiveStrategy = new ArchiveByAgeStrategy(_connector, _connect, _table, value);
}
}
else if (name == PROP_MAX_AGE)
{
if (value.empty() || "forever" == value)
{
_pArchiveStrategy = 0;
}
else if (_pArchiveStrategy)
{
_pArchiveStrategy->setThreshold(value);
}
else
{
ArchiveByAgeStrategy* p = new ArchiveByAgeStrategy(_connector, _connect, _table);
p->setThreshold(value);
_pArchiveStrategy = p;
}
}
else if (name == PROP_ASYNC)
{
_async = isTrue(value);
initLogStatement();
}
else if (name == PROP_TIMEOUT)
{
if (value.empty() || '0' == value[0])
_timeout = Statement::WAIT_FOREVER;
else
_timeout = NumberParser::parse(value);
}
else if (name == PROP_THROW)
{
_throw = isTrue(value);
}
else
{
Channel::setProperty(name, value);
}
}
std::string SQLChannel::getProperty(const std::string& name) const
{
if (name == PROP_NAME)
{
if (_name != "-") return _name;
else return "";
}
else if (name == PROP_CONNECTOR)
{
return _connector;
}
else if (name == PROP_CONNECT)
{
return _connect;
}
else if (name == PROP_TABLE)
{
return _table;
}
else if (name == PROP_ARCHIVE_TABLE)
{
return _pArchiveStrategy ? _pArchiveStrategy->getDestination() : "" ;
}
else if (name == PROP_MAX_AGE)
{
return _pArchiveStrategy ? _pArchiveStrategy->getThreshold() : "forever";
}
else if (name == PROP_TIMEOUT)
{
return NumberFormatter::format(_timeout);
}
else if (name == PROP_THROW)
{
if (_throw) return "true";
else return "false";
}
else
{
return Channel::getProperty(name);
}
}
void SQLChannel::initLogStatement()
{
_pLogStatement = new Statement(*_pSession);
std::string sql;
Poco::format(sql, "INSERT INTO %s VALUES (?,?,?,?,?,?,?,?)", _table);
*_pLogStatement << sql,
use(_source),
use(_name),
use(_pid),
use(_thread),
use(_tid),
use(_priority),
use(_text),
use(_dateTime);
if (_async) _pLogStatement->setAsync();
}
void SQLChannel::registerChannel()
{
Poco::LoggingFactory::defaultFactory().registerChannelClass("SQLChannel", new Poco::Instantiator<SQLChannel, Poco::Channel>);
}
} } // namespace Poco::Data

View File

@@ -58,11 +58,11 @@ SessionFactory& SessionFactory::instance()
}
void SessionFactory::add(const std::string& key, Connector* pIn)
void SessionFactory::add(Connector* pIn)
{
Poco::FastMutex::ScopedLock lock(_mutex);
SessionInfo info(pIn);
std::pair<Connectors::iterator, bool> res = _connectors.insert(std::make_pair(key, info));
std::pair<Connectors::iterator, bool> res = _connectors.insert(std::make_pair(pIn->name(), info));
if (!res.second)
{
res.first->second.cnt++;

View File

@@ -0,0 +1,123 @@
//
// RowFormatter.cpp
//
// $Id: //poco/Main/Data/src/RowFormatter.cpp#1 $
//
// Library: Data
// Package: DataCore
// Module: RowFormatter
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
#include "Poco/Data/SimpleRowFormatter.h"
#include "Poco/Exception.h"
#include <iomanip>
namespace Poco {
namespace Data {
SimpleRowFormatter::SimpleRowFormatter(std::streamsize columnWidth):
_colWidth(columnWidth)
{
}
SimpleRowFormatter::SimpleRowFormatter(const SimpleRowFormatter& other):
RowFormatter(other.prefix(), other.postfix()),
_colWidth(other._colWidth)
{
}
SimpleRowFormatter::~SimpleRowFormatter()
{
}
SimpleRowFormatter& SimpleRowFormatter::operator = (const SimpleRowFormatter& row)
{
SimpleRowFormatter tmp(row);
swap(tmp);
return *this;
}
void SimpleRowFormatter::swap(SimpleRowFormatter& other)
{
using std::swap;
setPrefix(other.prefix());
setPostfix(other.postfix());
swap(_colWidth, other._colWidth);
}
std::string& SimpleRowFormatter::formatNames(const NameVecPtr pNames, std::string& formattedNames) const
{
std::ostringstream str;
std::string line(_colWidth * pNames->size(), '-');
NameVec::const_iterator it = pNames->begin();
NameVec::const_iterator end = pNames->end();
for (; it != end; ++it)
{
str << std::left << std::setw(_colWidth) << *it;
}
str << std::endl << line << std::endl;
return formattedNames = str.str();
}
std::string& SimpleRowFormatter::formatValues(const ValueVec& vals, std::string& formattedValues) const
{
std::ostringstream str;
ValueVec::const_iterator it = vals.begin();
ValueVec::const_iterator end = vals.end();
for (; it != end; ++it)
{
if (it->isNumeric())
{
str << std::right
<< std::fixed
<< std::setprecision(2);
}
else str << std::left;
str << std::setw(_colWidth) << it->convert<std::string>();
}
str << std::endl;
return formattedValues = str.str();
}
} } // namespace Poco::Data

View File

@@ -68,7 +68,9 @@ Statement::Statement(const Statement& stmt):
_pImpl(stmt._pImpl),
_async(stmt._async),
_pResult(stmt._pResult),
_pAsyncExec(stmt._pAsyncExec)
_pAsyncExec(stmt._pAsyncExec),
_arguments(stmt._arguments),
_pRowFormatter(stmt._pRowFormatter)
{
}
@@ -94,6 +96,8 @@ void Statement::swap(Statement& other)
swap(_async, other._async);
swap(_pAsyncExec, other._pAsyncExec);
swap(_pResult, other._pResult);
_arguments.swap(other._arguments);
swap(_pRowFormatter, other._pRowFormatter);
}
@@ -111,6 +115,12 @@ Statement::ResultType Statement::execute()
bool isDone = done();
if (initialized() || paused() || isDone)
{
if (_arguments.size())
{
_pImpl->formatSQL(_arguments);
_arguments.clear();
}
if (!isAsync())
{
if (isDone) _pImpl->reset();
@@ -141,9 +151,7 @@ const Statement::Result& Statement::doAsyncExec()
if (done()) _pImpl->reset();
if (!_pAsyncExec)
_pAsyncExec = new AsyncExecMethod(_pImpl, &StatementImpl::execute);
poco_check_ptr (_pAsyncExec);
_pResult = new Result((*_pAsyncExec)());
poco_check_ptr (_pResult);
return *_pResult;
}

View File

@@ -96,6 +96,8 @@ Poco::UInt32 StatementImpl::execute()
if (lim < _lowerLimit)
throw LimitException("Did not receive enough data.");
if (0 == lim) lim = affectedRowCount();
return lim;
}
@@ -361,4 +363,12 @@ void StatementImpl::addExtract(AbstractExtraction* pExtraction)
}
void StatementImpl::formatSQL(std::vector<Any>& arguments)
{
std::string sql;
Poco::format(sql, _ostr.str(), arguments);
_ostr.str(""); _ostr << sql;
}
} } // namespace Poco::Data

View File

@@ -61,7 +61,7 @@ Poco::AutoPtr<Poco::Data::SessionImpl> Connector::createSession(const std::strin
void Connector::addToFactory()
{
Poco::Data::SessionFactory::instance().add(KEY, new Connector());
Poco::Data::SessionFactory::instance().add(new Connector());
}

View File

@@ -57,6 +57,9 @@ public:
~Connector();
/// Destroys the Connector.
const std::string& name() const;
/// Returns the name associated with this connector.
Poco::AutoPtr<Poco::Data::SessionImpl> createSession(const std::string& connectionString);
/// Creates a test SessionImpl object and initializes it with the given connectionString.
@@ -68,6 +71,15 @@ public:
};
///
/// inlines
///
inline const std::string& Connector::name() const
{
return KEY;
}
} } } // namespace Poco::Data::Test

View File

@@ -41,6 +41,7 @@
#include "Poco/Data/Column.h"
#include "Poco/Data/Date.h"
#include "Poco/Data/Time.h"
#include "Poco/Data/SimpleRowFormatter.h"
#include "Connector.h"
#include "Poco/BinaryReader.h"
#include "Poco/BinaryWriter.h"
@@ -94,6 +95,17 @@ void DataTest::testSession()
}
void DataTest::testStatementFormatting()
{
Session sess(SessionFactory::instance().create("test", "cs"));
Statement stmt = (sess << "SELECT %s%c%s,%d,%u,%f,%s FROM Person WHERE Name LIKE 'Simp%%'",
"'",'a',"'",-1, 1u, 1.5, "42", now);
assert ("SELECT 'a',-1,1,1.500000,42 FROM Person WHERE Name LIKE 'Simp%'" == stmt.toString());
}
void DataTest::testFeatures()
{
Session sess(SessionFactory::instance().create("test", "cs"));
@@ -1001,8 +1013,8 @@ void DataTest::testRowFormat()
row1.append("field3", 3);
row1.append("field4", 4);
RowFormatter rf;
std::streamsize sz = rf.getWidth();
SimpleRowFormatter rf;
std::streamsize sz = rf.getColumnWidth();
std::string line(sz * 5, '-');
std::ostringstream os;
@@ -1125,6 +1137,7 @@ CppUnit::Test* DataTest::suite()
CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("DataTest");
CppUnit_addTest(pSuite, DataTest, testSession);
CppUnit_addTest(pSuite, DataTest, testStatementFormatting);
CppUnit_addTest(pSuite, DataTest, testFeatures);
CppUnit_addTest(pSuite, DataTest, testProperties);
CppUnit_addTest(pSuite, DataTest, testBLOB);

View File

@@ -50,6 +50,7 @@ public:
~DataTest();
void testSession();
void testStatementFormatting();
void testFeatures();
void testProperties();
void testBLOB();

View File

@@ -66,6 +66,10 @@ protected:
Poco::UInt32 columnsReturned() const;
/// Returns number of columns returned by query.
Poco::UInt32 affectedRowCount() const;
/// Returns the number of affected rows.
/// Used to find out the number of rows affected by insert or update.
const MetaColumn& metaColumn(Poco::UInt32 pos) const;
/// Returns column meta data.
@@ -113,6 +117,12 @@ inline AbstractBinder& TestStatementImpl::binder()
}
inline Poco::UInt32 TestStatementImpl::affectedRowCount() const
{
return 0;
}
} } } // namespace Poco::Data::Test