see CHANGELOG

- upgraded SQLite to version 3.7.15.1 (2012-12-19)
- fixed SQLite affectedRows reporting and added tests
- added SQLite::Utility::isThreadSafe() function
- added SQLite::Utility::setThreadMode(int mode) function
- fixed GH #41: Buffer::resize crash
This commit is contained in:
aleks-f 2012-12-23 02:36:01 -06:00
parent 16533ef73b
commit 760fa4bbb0
12 changed files with 3969 additions and 2723 deletions

View File

@ -29,6 +29,11 @@ Release 1.5.0 (2012-12-17)
- fixed GH #30: Poco::Path::home() throws when called from Windows Service
- fixed GH #22: MySQL connection string lowercased
- added MySQL support for Date/Time
- upgraded SQLite to version 3.7.15.1 (2012-12-19)
- fixed SQLite affectedRows reporting and added tests
- added SQLite::Utility::isThreadSafe() function
- added SQLite::Utility::setThreadMode(int mode) function
- fixed GH #41: Buffer::resize crash
Release 1.5.0 (2012-10-14)
==========================

View File

@ -80,4 +80,16 @@
#endif
#endif
//
// Thread safety mode defaults to "serialized".
// See http://www.sqlite.org/threadsafe.html for details.
// Threading mode significantly affects performance
// (see TestSuite::benchmarkThreadModesTiming)
//
#ifndef SQLITE_THREADSAFE
#define SQLITE_THREADSAFE 1
#endif
#endif // SQLite_SQLite_INCLUDED

View File

@ -63,6 +63,10 @@ public:
static const std::string SQLITE_TIME_FORMAT;
typedef std::map<std::string, MetaColumn::ColumnDataType> TypeMap;
static const int THREAD_MODE_SINGLE;
static const int THREAD_MODE_MULTI;
static const int THREAD_MODE_SERIAL;
Utility();
/// Maps SQLite column declared types to Poco::Data types through
/// static TypeMap member.
@ -92,6 +96,14 @@ public:
///
/// Returns true if succesful
static bool isThreadSafe();
/// Returns true if SQLite was compiled in thread or serialized mode.
/// See http://www.sqlite.org/c3ref/threadsafe.html for details.
static bool setThreadMode(int mode);
/// Sets the threading mode to single, multi or serialized.
/// See http://www.sqlite.org/threadsafe.html for details.
private:
static TypeMap _types;
Poco::FastMutex _mutex;

View File

@ -215,14 +215,15 @@ void SQLiteStatementImpl::bindImpl()
else if (bindCount > remainingBindCount)
throw ParameterCountMismatchException();
std::size_t boundRowCount;
if (_bindBegin != bindings().end())
{
_affectedRowCount = (*_bindBegin)->numOfRowsHandled();
boundRowCount = (*_bindBegin)->numOfRowsHandled();
Bindings::iterator oldBegin = _bindBegin;
for (std::size_t pos = 1; _bindBegin != bindEnd && (*_bindBegin)->canBind(); ++_bindBegin)
{
if (_affectedRowCount != (*_bindBegin)->numOfRowsHandled())
if (boundRowCount != (*_bindBegin)->numOfRowsHandled())
throw BindingException("Size mismatch in Bindings. All Bindings MUST have the same size");
(*_bindBegin)->bind(pos);
@ -270,6 +271,9 @@ bool SQLiteStatementImpl::hasNext()
_stepCalled = true;
_nextResponse = sqlite3_step(_pStmt);
if (_affectedRowCount == POCO_SQLITE_INV_ROW_CNT) _affectedRowCount = 0;
_affectedRowCount += sqlite3_changes(_pDB);
if (_nextResponse != SQLITE_ROW && _nextResponse != SQLITE_OK && _nextResponse != SQLITE_DONE)
Utility::throwException(_nextResponse);
@ -296,6 +300,8 @@ std::size_t SQLiteStatementImpl::next()
_isExtracted = true;
}
_stepCalled = false;
if (_affectedRowCount == POCO_SQLITE_INV_ROW_CNT) _affectedRowCount = 0;
_affectedRowCount += (*extracts.begin())->numOfRowsHandled();
}
else if (SQLITE_DONE == _nextResponse)
{
@ -303,8 +309,7 @@ std::size_t SQLiteStatementImpl::next()
}
else
{
int rc = _nextResponse;
Utility::throwException(rc, std::string("Iterator Error: trying to access the next value"));
Utility::throwException(_nextResponse, std::string("Iterator Error: trying to access the next value"));
}
return 1u;

View File

@ -53,6 +53,10 @@ namespace Data {
namespace SQLite {
const int Utility::THREAD_MODE_SINGLE = SQLITE_CONFIG_SINGLETHREAD;
const int Utility::THREAD_MODE_MULTI = SQLITE_CONFIG_MULTITHREAD;
const int Utility::THREAD_MODE_SERIAL = SQLITE_CONFIG_SERIALIZED;
const std::string Utility::SQLITE_DATE_FORMAT = "%Y-%m-%d";
const std::string Utility::SQLITE_TIME_FORMAT = "%H:%M:%S";
Utility::TypeMap Utility::_types;
@ -255,4 +259,16 @@ bool Utility::memoryToFile(const std::string& fileName, sqlite3* pInMemory)
}
bool Utility::isThreadSafe()
{
return 0 != sqlite3_threadsafe;
}
bool Utility::setThreadMode(int mode)
{
return SQLITE_OK == sqlite3_config((int) mode);
}
} } } // namespace Poco::Data::SQLite

File diff suppressed because it is too large Load Diff

View File

@ -107,9 +107,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
#define SQLITE_VERSION "3.7.14.1"
#define SQLITE_VERSION_NUMBER 3007014
#define SQLITE_SOURCE_ID "2012-10-04 19:37:12 091570e46d04e84b67228e0bdbcd6e1fb60c6bdb"
#define SQLITE_VERSION "3.7.15.1"
#define SQLITE_VERSION_NUMBER 3007015
#define SQLITE_SOURCE_ID "2012-12-19 20:39:10 6b85b767d0ff7975146156a99ad673f2c1a23318"
/*
** CAPI3REF: Run-Time Library Version Numbers
@ -474,10 +474,12 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_IOERR_SHMLOCK (SQLITE_IOERR | (20<<8))
#define SQLITE_IOERR_SHMMAP (SQLITE_IOERR | (21<<8))
#define SQLITE_IOERR_SEEK (SQLITE_IOERR | (22<<8))
#define SQLITE_IOERR_DELETE_NOENT (SQLITE_IOERR | (23<<8))
#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
#define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8))
#define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8))
#define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8))
#define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8))
#define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8))
#define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8))
@ -855,6 +857,26 @@ struct sqlite3_io_methods {
** compilation of the PRAGMA fails with an error. ^The [SQLITE_FCNTL_PRAGMA]
** file control occurs at the beginning of pragma statement analysis and so
** it is able to override built-in [PRAGMA] statements.
**
** <li>[[SQLITE_FCNTL_BUSYHANDLER]]
** ^This file-control may be invoked by SQLite on the database file handle
** shortly after it is opened in order to provide a custom VFS with access
** to the connections busy-handler callback. The argument is of type (void **)
** - an array of two (void *) values. The first (void *) actually points
** to a function of type (int (*)(void *)). In order to invoke the connections
** busy-handler, this function should be invoked with the second (void *) in
** the array as the only argument. If it returns non-zero, then the operation
** should be retried. If it returns zero, the custom VFS should abandon the
** current operation.
**
** <li>[[SQLITE_FCNTL_TEMPFILENAME]]
** ^Application can invoke this file-control to have SQLite generate a
** temporary filename using the same algorithm that is followed to generate
** temporary filenames for TEMP tables and other internal uses. The
** argument should be a char** which will be filled with the filename
** written into memory obtained from [sqlite3_malloc()]. The caller should
** invoke [sqlite3_free()] on the result to avoid a memory leak.
**
** </ul>
*/
#define SQLITE_FCNTL_LOCKSTATE 1
@ -871,6 +893,8 @@ struct sqlite3_io_methods {
#define SQLITE_FCNTL_VFSNAME 12
#define SQLITE_FCNTL_POWERSAFE_OVERWRITE 13
#define SQLITE_FCNTL_PRAGMA 14
#define SQLITE_FCNTL_BUSYHANDLER 15
#define SQLITE_FCNTL_TEMPFILENAME 16
/*
** CAPI3REF: Mutex Handle
@ -1567,11 +1591,39 @@ struct sqlite3_mem_methods {
** disabled. The default value may be changed by compiling with the
** [SQLITE_USE_URI] symbol defined.
**
** [[SQLITE_CONFIG_COVERING_INDEX_SCAN]] <dt>SQLITE_CONFIG_COVERING_INDEX_SCAN
** <dd> This option takes a single integer argument which is interpreted as
** a boolean in order to enable or disable the use of covering indices for
** full table scans in the query optimizer. The default setting is determined
** by the [SQLITE_ALLOW_COVERING_INDEX_SCAN] compile-time option, or is "on"
** if that compile-time option is omitted.
** The ability to disable the use of covering indices for full table scans
** is because some incorrectly coded legacy applications might malfunction
** malfunction when the optimization is enabled. Providing the ability to
** disable the optimization allows the older, buggy application code to work
** without change even with newer versions of SQLite.
**
** [[SQLITE_CONFIG_PCACHE]] [[SQLITE_CONFIG_GETPCACHE]]
** <dt>SQLITE_CONFIG_PCACHE and SQLITE_CONFIG_GETPCACHE
** <dd> These options are obsolete and should not be used by new code.
** They are retained for backwards compatibility but are now no-ops.
** </dl>
**
** [[SQLITE_CONFIG_SQLLOG]]
** <dt>SQLITE_CONFIG_SQLLOG
** <dd>This option is only available if sqlite is compiled with the
** SQLITE_ENABLE_SQLLOG pre-processor macro defined. The first argument should
** be a pointer to a function of type void(*)(void*,sqlite3*,const char*, int).
** The second should be of type (void*). The callback is invoked by the library
** in three separate circumstances, identified by the value passed as the
** fourth parameter. If the fourth parameter is 0, then the database connection
** passed as the second argument has just been opened. The third argument
** points to a buffer containing the name of the main database file. If the
** fourth parameter is 1, then the SQL statement that the third parameter
** points to has just been executed. Or, if the fourth parameter is 2, then
** the connection being passed as the second parameter is being closed. The
** third parameter is passed NULL In this case.
** </dl>
*/
#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
#define SQLITE_CONFIG_MULTITHREAD 2 /* nil */
@ -1592,6 +1644,8 @@ struct sqlite3_mem_methods {
#define SQLITE_CONFIG_URI 17 /* int */
#define SQLITE_CONFIG_PCACHE2 18 /* sqlite3_pcache_methods2* */
#define SQLITE_CONFIG_GETPCACHE2 19 /* sqlite3_pcache_methods2* */
#define SQLITE_CONFIG_COVERING_INDEX_SCAN 20 /* int */
#define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */
/*
** CAPI3REF: Database Connection Configuration Options
@ -2600,7 +2654,7 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** an error)^.
** ^If "ro" is specified, then the database is opened for read-only
** access, just as if the [SQLITE_OPEN_READONLY] flag had been set in the
** third argument to sqlite3_prepare_v2(). ^If the mode option is set to
** third argument to sqlite3_open_v2(). ^If the mode option is set to
** "rw", then the database is opened for read-write (but not create)
** access, as if SQLITE_OPEN_READWRITE (but not SQLITE_OPEN_CREATE) had
** been set. ^Value "rwc" is equivalent to setting both
@ -2752,6 +2806,11 @@ SQLITE_API sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int
** However, the error string might be overwritten or deallocated by
** subsequent calls to other SQLite interface functions.)^
**
** ^The sqlite3_errstr() interface returns the English-language text
** that describes the [result code], as UTF-8.
** ^(Memory to hold the error message string is managed internally
** and must not be freed by the application)^.
**
** When the serialized [threading mode] is in use, it might be the
** case that a second error occurs on a separate thread in between
** the time of the first error and the call to these interfaces.
@ -2770,6 +2829,7 @@ SQLITE_API int sqlite3_errcode(sqlite3 *db);
SQLITE_API int sqlite3_extended_errcode(sqlite3 *db);
SQLITE_API const char *sqlite3_errmsg(sqlite3*);
SQLITE_API const void *sqlite3_errmsg16(sqlite3*);
SQLITE_API const char *sqlite3_errstr(int);
/*
** CAPI3REF: SQL Statement Object
@ -4732,6 +4792,9 @@ SQLITE_API void *sqlite3_update_hook(
** future releases of SQLite. Applications that care about shared
** cache setting should set it explicitly.
**
** This interface is threadsafe on processors where writing a
** 32-bit integer is atomic.
**
** See Also: [SQLite Shared-Cache Mode]
*/
SQLITE_API int sqlite3_enable_shared_cache(int);

View File

@ -58,6 +58,7 @@
#include "Poco/AutoPtr.h"
#include "Poco/Exception.h"
#include "Poco/RefCountedObject.h"
#include "Poco/Stopwatch.h"
#include <iostream>
@ -618,7 +619,6 @@ void SQLiteTest::testSharedPtrComplexTypeVector()
}
void SQLiteTest::testInsertVector()
{
Session tmp (Poco::Data::SQLite::Connector::KEY, "dummy.db");
@ -680,6 +680,7 @@ void SQLiteTest::testAffectedRows()
assert (0 == stmt.execute());
Statement stmt1((tmp << "INSERT INTO Strings VALUES(:str)", use(str)));
count = -1;
tmp << "SELECT COUNT(*) FROM Strings", into(count), now;
assert (count == 0);
assert (4 == stmt1.execute());
@ -692,10 +693,13 @@ void SQLiteTest::testAffectedRows()
Statement stmt3(tmp << "DELETE FROM Strings WHERE str = 's1'");
assert (1 == stmt3.execute());
Statement stmt4(tmp << "DELETE FROM Strings WHERE str = 'bad value'");
assert (0 == stmt4.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());
Statement stmt5(tmp << "DELETE FROM Strings WHERE 1");
assert (3 == stmt5.execute());
}
@ -2263,8 +2267,6 @@ void SQLiteTest::testDynamicAny()
}
void SQLiteTest::testPair()
{
Session tmp (Poco::Data::SQLite::Connector::KEY, "dummy.db");
@ -2299,6 +2301,7 @@ void SQLiteTest::testPair()
}
void SQLiteTest::testSQLChannel()
{
Session tmp (Poco::Data::SQLite::Connector::KEY, "dummy.db");
@ -2580,6 +2583,51 @@ void SQLiteTest::testSystemTable()
}
void SQLiteTest::benchmarkThreadModesTiming()
{
using namespace Poco::Data::SQLite;
typedef std::vector<int> ModeVec;
const int datasize = 1000;
ModeVec mode;
mode.push_back(Utility::THREAD_MODE_SINGLE);
mode.push_back(Utility::THREAD_MODE_MULTI);
mode.push_back(Utility::THREAD_MODE_SERIAL);
Poco::Stopwatch sw;
ModeVec::iterator it = mode.begin();
ModeVec::iterator end = mode.end();
for (; it != end; ++it)
{
sw.start();
Utility::setThreadMode(*it);
Session tmp (Connector::KEY, "dummy.db");
std::vector<int> iv;
int count = 0;
for (int i =0; i < datasize; ++i) iv.push_back(i);
tmp << "DROP TABLE IF EXISTS Ints", now;
tmp << "CREATE TABLE IF NOT EXISTS Ints (theInt INTEGER)", now;
{
Statement stmt((tmp << "INSERT INTO Ints VALUES(?)", use(iv)));
tmp << "SELECT COUNT(*) FROM Ints", into(count), now;
assert (count == 0);
stmt.execute();
tmp << "SELECT COUNT(*) FROM Ints", into(count), now;
assert (count == datasize);
}
count = 0;
tmp << "SELECT COUNT(*) FROM Ints", into(count), now;
assert (count == datasize);
sw.stop();
std::cout << "Mode: " << ((*it == Utility::THREAD_MODE_SINGLE) ? "single,"
:(*it == Utility::THREAD_MODE_MULTI) ? "multi,"
:(*it == Utility::THREAD_MODE_SERIAL) ? "serial,"
: "unknown,") << " Time: " << sw.elapsed() / 1000.0 << " [ms]" << std::endl;
}
}
void SQLiteTest::setUp()
{
}
@ -2671,6 +2719,7 @@ CppUnit::Test* SQLiteTest::suite()
CppUnit_addTest(pSuite, SQLiteTest, testPair);
CppUnit_addTest(pSuite, SQLiteTest, testReconnect);
CppUnit_addTest(pSuite, SQLiteTest, testSystemTable);
CppUnit_addTest(pSuite, SQLiteTest, benchmarkThreadModesTiming);
return pSuite;
}

View File

@ -134,6 +134,8 @@ public:
void testReconnect();
void testSystemTable();
void benchmarkThreadModesTiming();
void setUp();
void tearDown();

View File

@ -96,7 +96,7 @@ public:
std::size_t numOfRowsHandled() const
{
return 1;
return 1u;
}
bool canBind() const
@ -120,8 +120,8 @@ public:
}
private:
const T& _val;
bool _bound;
const T& _val;
bool _bound;
};

View File

@ -96,7 +96,7 @@ public:
std::size_t numOfRowsHandled() const
{
return 0;
return _extracted ? 1u : 0;
}
std::size_t numOfRowsAllowed() const

View File

@ -142,10 +142,10 @@ public:
{
T* ptr = new T[newCapacity];
if (preserveContent)
std::memcpy(ptr, _ptr, newCapacity);
std::memcpy(ptr, _ptr, _capacity);
delete [] _ptr;
_ptr = ptr;
_ptr = ptr;
_capacity = newCapacity;
}