Permalink
Browse files

see CHANGELOG

- added Poco::istring (case-insensitive string) and Poco::isubstr
(case-insensitive substring search)
- improved SQLite execute() return (affected rows) value
- added SQLite sys.dual (in-memory system table)
- applied SF Patch #120: The ExpireLRUCache does not compile with a
tuple as key on Visual Studio 2010
- fixed SF Bug #599: JSON::Array and JSON::Object size() member can
implicitly lose precision
- fixed SF Bug #602: iterating database table rows not correct if no
data in table
- fixed SF Bug #603: count() is missing in HashMap
- fixed GH #23: JSON::Object::stringify throw BadCastException
- fixed GH #16: NetworkInterface::firstAddress() should not throw on
unconfigured interfaces
- Android compile/build support (by Rangel Reale)
- TypeHandler::prepare() now takes const-reference
  • Loading branch information...
aleks-f committed Dec 5, 2012
1 parent 1138f43 commit eaa74307a6937b73fd927712af5309f8eb4a9532
View
@@ -3,6 +3,17 @@ This is the changelog file for the POCO C++ Libraries.
Release 1.5.0 (2012-12-17)
==========================
- using double-conversion library for floating-point numeric/string conversions
+- added Poco::istring (case-insensitive string) and Poco::isubstr
+- improved SQLite execute() return (affected rows) value
+- added SQLite sys.dual (in-memory system table)
+- applied SF Patch #120: The ExpireLRUCache does not compile with a tuple as key on Visual Studio 2010
+- fixed SF Bug #599: JSON::Array and JSON::Object size() member can implicitly lose precision
+- fixed SF Bug #602: iterating database table rows not correct if no data in table
+- fixed SF Bug #603: count() is missing in HashMap
+- fixed GH #23: JSON::Object::stringify throw BadCastException
+- fixed GH #16: NetworkInterface::firstAddress() should not throw on unconfigured interfaces
+- Android compile/build support (by Rangel Reale)
+- TypeHandler::prepare() now takes const-reference
Release 1.5.0 (2012-10-14)
==========================
View
@@ -24,6 +24,10 @@ Marian Krivos
Franky Braem
Philip Prindeville
Anton Yabchinskiy
+Rangel Reale
+Fabrizio Duhem
+Patrick White
+Mike Naquin
--
$Id$
@@ -119,7 +119,7 @@ class TypeHandler<Person>
pBinder->bind(pos++, obj.age, dir);
}
- static void prepare(std::size_t pos, Person& obj, AbstractPreparator* pPrepare)
+ static void prepare(std::size_t pos, const Person& obj, AbstractPreparator* pPrepare)
{
// the table is defined as Person (LastName VARCHAR(30), FirstName VARCHAR, Address VARCHAR, Age INTEGER(3))
poco_assert_dbg (pPrepare != 0);
@@ -211,7 +211,7 @@ class TypeHandler<Person>
pBinder->bind(pos++, obj.age, dir);
}
- static void prepare(std::size_t pos, Person& obj, AbstractPreparator* pPrepare)
+ static void prepare(std::size_t pos, const Person& obj, AbstractPreparator* pPrepare)
{
// the table is defined as Person (LastName VARCHAR(30), FirstName VARCHAR, Address VARCHAR, Age INTEGER(3))
poco_assert_dbg (pPrepare != 0);
@@ -141,6 +141,8 @@ class SQLite_API SQLiteStatementImpl: public Poco::Data::StatementImpl
bool _canBind;
bool _isExtracted;
bool _canCompile;
+
+ static const std::size_t POCO_SQLITE_INV_ROW_CNT;
};
@@ -71,6 +71,17 @@ class SQLite_API SessionImpl: public Poco::Data::AbstractSessionImpl<SessionImpl
void open(const std::string& connect = "");
/// Opens a connection to the Database.
+ ///
+ /// An in-memory system database (sys), with a single table (dual)
+ /// containing single field (dummy) is attached to the database.
+ /// The in-memory system database is used to force change count
+ /// to be reset to zero on every new query (or batch of queries)
+ /// execution. Without this functionality, select statements
+ /// executions that do not return any rows return the count of
+ /// changes effected by the most recent insert, update or delete.
+ /// In-memory system database can be queried and updated but can not
+ /// be dropped. It may be used for other purposes
+ /// in the future.
void close();
/// Closes the session.
@@ -52,13 +52,16 @@ namespace Data {
namespace SQLite {
+const std::size_t SQLiteStatementImpl::POCO_SQLITE_INV_ROW_CNT = std::numeric_limits<std::size_t>::max();
+
+
SQLiteStatementImpl::SQLiteStatementImpl(Poco::Data::SessionImpl& rSession, sqlite3* pDB):
StatementImpl(rSession),
_pDB(pDB),
_pStmt(0),
_stepCalled(false),
_nextResponse(0),
- _affectedRowCount(0),
+ _affectedRowCount(POCO_SQLITE_INV_ROW_CNT),
_canBind(false),
_isExtracted(false),
_canCompile(true)
@@ -75,9 +78,29 @@ SQLiteStatementImpl::~SQLiteStatementImpl()
void SQLiteStatementImpl::compileImpl()
{
- if (!_pLeftover) _bindBegin = bindings().begin();
+ if (!_pLeftover)
+ {
+ // Executed to force reset of previous changes count to zero.
+ // Without this, execute() will not return accurate (zero) count if select
+ // statement returns no results previous [insert|update|delete] affected rows.
+ if (sqlite3_changes(_pDB))
+ {
+ if (SQLITE_OK != sqlite3_exec(_pDB, "delete from sys.dual where 1 <> 1;", 0, 0, 0))
+ throw ExecutionException("Error updating system database.");
+ }
+
+ _bindBegin = bindings().begin();
+ }
std::string statement(toString());
+
+ if (isubstr(statement, std::string("drop")) != istring::npos &&
+ isubstr(statement, std::string("table")) != istring::npos &&
+ isubstr(statement, std::string("dual")) != istring::npos)
+ {
+ throw InvalidAccessException("Cannot drop system table!");
+ }
+
sqlite3_stmt* pStmt = 0;
const char* pSql = _pLeftover ? _pLeftover->c_str() : statement.c_str();
@@ -194,12 +217,12 @@ void SQLiteStatementImpl::bindImpl()
if (_bindBegin != bindings().end())
{
- std::size_t boundRowCount = (*_bindBegin)->numOfRowsHandled();
+ _affectedRowCount = (*_bindBegin)->numOfRowsHandled();
Bindings::iterator oldBegin = _bindBegin;
for (std::size_t pos = 1; _bindBegin != bindEnd && (*_bindBegin)->canBind(); ++_bindBegin)
{
- if (boundRowCount != (*_bindBegin)->numOfRowsHandled())
+ if (_affectedRowCount != (*_bindBegin)->numOfRowsHandled())
throw BindingException("Size mismatch in Bindings. All Bindings MUST have the same size");
(*_bindBegin)->bind(pos);
@@ -220,7 +243,7 @@ void SQLiteStatementImpl::bindImpl()
void SQLiteStatementImpl::clear()
{
_columns[currentDataSet()].clear();
- _affectedRowCount = 0;
+ _affectedRowCount = POCO_SQLITE_INV_ROW_CNT;
if (_pStmt)
{
@@ -304,7 +327,7 @@ const MetaColumn& SQLiteStatementImpl::metaColumn(std::size_t pos) const
std::size_t SQLiteStatementImpl::affectedRowCount() const
{
- return _affectedRowCount ? _affectedRowCount : sqlite3_changes(_pDB);
+ return _affectedRowCount != POCO_SQLITE_INV_ROW_CNT ? _affectedRowCount : sqlite3_changes(_pDB);
}
@@ -43,7 +43,7 @@
#include "Poco/ActiveMethod.h"
#include "Poco/ActiveResult.h"
#include "Poco/String.h"
-#include "Poco/Exception.h"
+#include "Poco/Data/DataException.h"
#include "sqlite3.h"
#include <cstdlib>
@@ -195,6 +195,14 @@ void SessionImpl::open(const std::string& connect)
throw ConnectionFailedException(ex.displayText());
}
+ if (SQLITE_OK != sqlite3_exec(_pDB,
+ "attach database ':memory:' as sys;"
+ "create table sys.dual (dummy);",
+ 0, 0, 0))
+ {
+ throw ExecutionException("Cannot create system database.");
+ }
+
_connected = true;
}
@@ -193,7 +193,7 @@ class TypeHandler<Person>
pBinder->bind(pos++, obj.getAge(), dir);
}
- static void prepare(std::size_t pos, Person& obj, AbstractPreparator* pPrepare)
+ static void prepare(std::size_t pos, const Person& obj, AbstractPreparator* pPrepare)
{
// the table is defined as Person (LastName VARCHAR(30), FirstName VARCHAR, Address VARCHAR, Age INTEGER(3))
poco_assert_dbg (pPrepare != 0);
@@ -674,6 +674,11 @@ void SQLiteTest::testAffectedRows()
tmp << "DROP TABLE IF EXISTS Strings", now;
tmp << "CREATE TABLE IF NOT EXISTS Strings (str VARCHAR(30))", now;
+ Statement stmt((tmp << "SELECT * FROM Strings"));
+ tmp << "SELECT COUNT(*) FROM Strings", into(count), now;
+ assert (count == 0);
+ assert (0 == stmt.execute());
+
Statement stmt1((tmp << "INSERT INTO Strings VALUES(:str)", use(str)));
tmp << "SELECT COUNT(*) FROM Strings", into(count), now;
assert (count == 0);
@@ -1242,6 +1247,12 @@ void SQLiteTest::testCombinedLimits()
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;
tmp << "INSERT INTO PERSON VALUES(:ln, :fn, :ad, :age)", use(people), now;
+
+ std::string a, b, c;
+ Statement stmt = (tmp << "SELECT LastName, FirstName, Address FROM Person WHERE Address = 'invalid value'",
+ into(a), into(b), into(c), limit(1));
+ assert (!stmt.done() && stmt.execute() == 0);
+
int count = 0;
tmp << "SELECT COUNT(*) FROM PERSON", into(count), now;
assert (count == 2);
@@ -2543,6 +2554,32 @@ void SQLiteTest::testReconnect()
}
+void SQLiteTest::testSystemTable()
+{
+ Session session (Poco::Data::SQLite::Connector::KEY, "dummy.db");
+
+ int cnt = -1;
+ session << "SELECT count(*) FROM sys.dual", into(cnt), now;
+ assert (0 == cnt);
+
+ session << "INSERT INTO sys.dual VALUES ('test')", now;
+ session << "SELECT count(*) FROM sys.dual", into(cnt), now;
+ assert (1 == cnt);
+
+ session << "DELETE FROM sys.dual", now;
+ session << "SELECT count(*) FROM sys.dual", into(cnt), now;
+ assert (0 == cnt);
+
+ try
+ {
+ session << "DROP TABLE sys.dual", now;
+ fail ("must throw");
+ }
+ catch (InvalidAccessException&) { }
+
+}
+
+
void SQLiteTest::setUp()
{
}
@@ -2633,6 +2670,7 @@ CppUnit::Test* SQLiteTest::suite()
CppUnit_addTest(pSuite, SQLiteTest, testMultipleResults);
CppUnit_addTest(pSuite, SQLiteTest, testPair);
CppUnit_addTest(pSuite, SQLiteTest, testReconnect);
+ CppUnit_addTest(pSuite, SQLiteTest, testSystemTable);
return pSuite;
}
@@ -132,6 +132,7 @@ class SQLiteTest: public CppUnit::TestCase
void testMultipleResults();
void testReconnect();
+ void testSystemTable();
void setUp();
void tearDown();
@@ -96,7 +96,7 @@ class Extraction: public AbstractExtraction
std::size_t numOfRowsHandled() const
{
- return 1u;
+ return 0;
}
std::size_t numOfRowsAllowed() const
Oops, something went wrong.

0 comments on commit eaa7430

Please sign in to comment.