diff --git a/qsqlite/src/qsql_sqlite.cpp b/qsqlite/src/qsql_sqlite.cpp
index c1e9508..5da232f 100644
--- a/qsqlite/src/qsql_sqlite.cpp
+++ b/qsqlite/src/qsql_sqlite.cpp
@@ -528,7 +528,7 @@ static int qGetSqliteOpenMode(QString opts)
return SQLITE_OPEN_READONLY;
}
// The SQLITE_OPEN_NOMUTEX flag causes the database connection to be in the multi-thread mode
- return SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX;
+ return SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_SHAREDCACHE;
}
/*
@@ -543,8 +543,10 @@ bool QSQLiteDriver::open(const QString & db, const QString &, const QString &, c
if (db.isEmpty())
return false;
+ sqlite3_enable_shared_cache(1);
if (sqlite3_open_v2(db.toUtf8().constData(), &d->access, qGetSqliteOpenMode(conOpts), NULL) == SQLITE_OK) {
sqlite3_busy_timeout(d->access, qGetSqliteTimeout(conOpts));
+ sqlite3_extended_result_codes(d->access, 1);
setOpen(true);
setOpenError(false);
return true;
diff --git a/qsqlite/src/sqlite_blocking.cpp b/qsqlite/src/sqlite_blocking.cpp
index c0fe3f2..180685c 100644
--- a/qsqlite/src/sqlite_blocking.cpp
+++ b/qsqlite/src/sqlite_blocking.cpp
@@ -1,63 +1,94 @@
+/*
+ Copyright (c) 2009 Bertjan Broeksema <broeksema@kde.org>
+ Copyright (c) 2014 Daniel Vrátil <dvratil@redhat.com>
+
+ This library is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Library General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This library is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
+ License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
#include "sqlite_blocking.h"
#include <sqlite3.h>
-#ifndef _WIN32
-#include <unistd.h>
-#else
-#include <Windows.h>
-#define usleep(x) Sleep(x/1000)
-#endif
-
-#include "qdebug.h"
+
+#include <QMutex>
+#include <QWaitCondition>
#include "qstringbuilder.h"
#include "qthread.h"
+#include <QDateTime>
+
+/* Based on example in http://www.sqlite.org/unlock_notify.html */
-QString debugString()
+struct UnlockNotification {
+ bool fired;
+ QWaitCondition cond;
+ QMutex mutex;
+};
+
+static void qSqlite3UnlockNotifyCb(void **apArg, int nArg)
{
- return QString( QLatin1Literal("[QSQLITE3: ") + QString::number( quint64( QThread::currentThreadId() ) ) + QLatin1Literal("] ") );
+ for (int i = 0; i < nArg; ++i) {
+ UnlockNotification *ntf = static_cast<UnlockNotification*>(apArg[i]);
+ ntf->mutex.lock();
+ ntf->fired = true;
+ ntf->cond.wakeOne();
+ ntf->mutex.unlock();
+ }
}
-int sqlite3_blocking_step( sqlite3_stmt *pStmt )
+static int qSqlite3WaitForUnlockNotify(sqlite3 *db)
{
- // NOTE: The example at http://www.sqlite.org/unlock_notify.html says to wait
- // for SQLITE_LOCK but for some reason I don't understand I get
- // SQLITE_BUSY.
- int rc = sqlite3_step( pStmt );
-
- QThread::currentThreadId();
- if ( rc == SQLITE_BUSY )
- qDebug() << debugString() << "sqlite3_blocking_step: Entering while loop";
-
- while( rc == SQLITE_BUSY ) {
- usleep(5000);
- sqlite3_reset( pStmt );
- rc = sqlite3_step( pStmt );
-
- if ( rc != SQLITE_BUSY ) {
- qDebug() << debugString() << "sqlite3_blocking_step: Leaving while loop";
+ int rc;
+ UnlockNotification un;
+ un.fired = false;
+
+ rc = sqlite3_unlock_notify(db, qSqlite3UnlockNotifyCb, (void *)&un);
+ Q_ASSERT(rc == SQLITE_LOCKED || rc == SQLITE_OK);
+
+ if (rc == SQLITE_OK) {
+ un.mutex.lock();
+ if (!un.fired) {
+ un.cond.wait(&un.mutex);
}
+ un.mutex.unlock();
}
return rc;
}
-int sqlite3_blocking_prepare16_v2( sqlite3 *db, /* Database handle. */
- const void *zSql, /* SQL statement, UTF-16 encoded */
- int nSql, /* Length of zSql in bytes. */
- sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
- const void **pzTail /* OUT: Pointer to unused portion of zSql */ )
+int sqlite3_blocking_step(sqlite3_stmt *pStmt)
{
- int rc = sqlite3_prepare16_v2( db, zSql, nSql, ppStmt, pzTail );
-
- if ( rc == SQLITE_BUSY )
- qDebug() << debugString() << "sqlite3_blocking_prepare16_v2: Entering while loop";
+ int rc;
+ while (SQLITE_LOCKED_SHAREDCACHE == (rc = sqlite3_step(pStmt))) {
+ rc = qSqlite3WaitForUnlockNotify(sqlite3_db_handle(pStmt));
+ if (rc != SQLITE_OK) {
+ break;
+ }
+ sqlite3_reset(pStmt);
+ }
- while( rc == SQLITE_BUSY ) {
- usleep(500000);
- rc = sqlite3_prepare16_v2( db, zSql, nSql, ppStmt, pzTail );
+ return rc;
+}
- if ( rc != SQLITE_BUSY ) {
- qDebug() << debugString() << "sqlite3_prepare16_v2: Leaving while loop";
+int sqlite3_blocking_prepare16_v2(sqlite3 *db, const void *zSql, int nSql,
+ sqlite3_stmt **ppStmt, const void **pzTail)
+{
+ int rc;
+ while (SQLITE_LOCKED_SHAREDCACHE == (rc = sqlite3_prepare16_v2(db, zSql, nSql, ppStmt, pzTail))) {
+ rc = qSqlite3WaitForUnlockNotify(db);
+ if (rc != SQLITE_OK) {
+ break;
}
}
diff --git a/qsqlite/src/sqlite_blocking.h b/qsqlite/src/sqlite_blocking.h
index 0d6f6a0..9f13946 100644
--- a/qsqlite/src/sqlite_blocking.h
+++ b/qsqlite/src/sqlite_blocking.h
@@ -1,3 +1,22 @@
+/*
+ Copyright (c) 2009 Bertjan Broeksema <broeksema@kde.org>
+
+ This library is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Library General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This library is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
+ License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
#ifndef SQLITE_BLOCKING_H
#define SQLITE_BLOCKING_H