1
/* This file is part of the KDE project
2
Copyright (C) 2003-2006 Jarosław Staniek <staniek@kde.org>
4
This program is free software; you can redistribute it and/or
5
modify it under the terms of the GNU Library General Public
6
License as published by the Free Software Foundation; either
7
version 2 of the License, or (at your option) any later version.
9
This program is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
Library General Public License for more details.
14
You should have received a copy of the GNU Library General Public License
15
along with this program; see the file COPYING. If not, write to
16
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17
* Boston, MA 02110-1301, USA.
20
#include "sqliteconnection.h"
21
#include "sqliteconnection_p.h"
22
#include "sqlitecursor.h"
23
#include "sqlitepreparedstatement.h"
27
#include <db/driver.h>
28
#include <db/cursor.h>
31
#include <db/calligradb_global.h>
39
#include <KStandardDirs>
43
#define KexiDBDrvDbg if (0) kDebug()
46
#define SHARED_LIB_EXTENSION ".dll"
47
#elif defined(Q_OS_MAC)
48
#define SHARED_LIB_EXTENSION ".dylib"
50
#define SHARED_LIB_EXTENSION ".so"
53
using namespace KexiDB;
55
SQLiteConnectionInternal::SQLiteConnectionInternal(Connection *connection)
56
: ConnectionInternal(connection)
62
, m_extensionsLoadingEnabled(false)
66
SQLiteConnectionInternal::~SQLiteConnectionInternal()
68
if (data_owned && data) {
74
void SQLiteConnectionInternal::storeResult()
78
sqlite3_free(errmsg_p);
81
errmsg = (data && res != SQLITE_OK) ? sqlite3_errmsg(data) : 0;
84
bool SQLiteConnectionInternal::extensionsLoadingEnabled() const
86
return m_extensionsLoadingEnabled;
89
void SQLiteConnectionInternal::setExtensionsLoadingEnabled(bool set)
91
if (set == m_extensionsLoadingEnabled)
93
sqlite3_enable_load_extension(data, set);
94
m_extensionsLoadingEnabled = set;
98
SQLiteConnection::SQLiteConnection(Driver *driver, ConnectionData &conn_data)
99
: Connection(driver, conn_data)
100
, d(new SQLiteConnectionInternal(this))
104
SQLiteConnection::~SQLiteConnection()
106
KexiDBDrvDbg << "SQLiteConnection::~SQLiteConnection()";
107
//disconnect if was connected
111
KexiDBDrvDbg << "SQLiteConnection::~SQLiteConnection() ok";
114
bool SQLiteConnection::drv_connect(KexiDB::ServerVersionInfo& version)
116
KexiDBDrvDbg << "SQLiteConnection::connect()";
117
version.string = QString(SQLITE_VERSION); //defined in sqlite3.h
118
QRegExp re("(\\d+)\\.(\\d+)\\.(\\d+)");
119
if (re.exactMatch(version.string)) {
120
version.major = re.cap(1).toUInt();
121
version.minor = re.cap(2).toUInt();
122
version.release = re.cap(3).toUInt();
127
bool SQLiteConnection::drv_disconnect()
129
KexiDBDrvDbg << "SQLiteConnection::disconnect()";
133
bool SQLiteConnection::drv_getDatabasesList(QStringList &list)
135
//this is one-db-per-file database
136
list.append(data()->fileName()); //more consistent than dbFileName() ?
140
bool SQLiteConnection::drv_containsTable(const QString &tableName)
143
return resultExists(QString("select name from sqlite_master where type='table' and name LIKE %1")
144
.arg(driver()->escapeString(tableName)), success) && success;
147
bool SQLiteConnection::drv_getTablesList(QStringList &list)
149
KexiDB::Cursor *cursor;
150
m_sql = "select lower(name) from sqlite_master where type='table'";
151
if (!(cursor = executeQuery(m_sql))) {
152
KexiDBWarn << "Connection::drv_getTablesList(): !executeQuery()";
157
while (!cursor->eof() && !cursor->error()) {
158
list += cursor->value(0).toString();
161
if (cursor->error()) {
162
deleteCursor(cursor);
165
return deleteCursor(cursor);
168
bool SQLiteConnection::drv_createDatabase(const QString &dbName)
171
return drv_useDatabaseInternal(0, 0, true/*create if missing*/);
174
bool SQLiteConnection::drv_useDatabase(const QString &dbName, bool *cancelled,
175
MessageHandler* msgHandler)
178
return drv_useDatabaseInternal(cancelled, msgHandler, false/*do not create if missing*/);
181
bool SQLiteConnection::drv_useDatabaseInternal(bool *cancelled,
182
MessageHandler* msgHandler, bool createIfMissing)
184
//! @todo add option (command line or in kexirc?)
185
//! @todo int exclusiveFlag = Connection::isReadOnly() ? SQLITE_OPEN_READONLY : SQLITE_OPEN_WRITE_LOCKED; // <-- shared read + (if !r/o): exclusive write
188
openFlags |= SQLITE_OPEN_READONLY;
191
openFlags |= SQLITE_OPEN_READWRITE;
192
if (createIfMissing) {
193
openFlags |= SQLITE_OPEN_CREATE;
198
// int allowReadonly = 1;
199
// const bool wasReadOnly = Connection::isReadOnly();
201
d->res = sqlite3_open_v2(
202
//QFile::encodeName( data()->fileName() ),
203
data()->fileName().toUtf8().constData(), /* unicode expected since SQLite 3.1 */
205
openFlags, /*exclusiveFlag,
206
allowReadonly *//* If 1 and locking fails, try opening in read-only mode */
211
if (d->res == SQLITE_OK) {
212
// Set the secure-delete on, so SQLite overwrites deleted content with zeros.
213
// The default setting is determined by the SQLITE_SECURE_DELETE compile-time option but we overwrite it here.
214
// Works with 3.6.23. Earlier versions just ignore this pragma.
215
// See http://www.sqlite.org/pragma.html#pragma_secure_delete
216
//! @todo add connection flags to the driver and global setting to control the "secure delete" pragma
217
if (!drv_executeSQL("PRAGMA secure_delete = on")) {
218
drv_closeDatabaseSilently();
221
// Load ICU extension for unicode collations
222
QString icuExtensionFilename(
223
KStandardDirs::locate("module", QLatin1String("kexidb_sqlite3_icu" SHARED_LIB_EXTENSION)));
224
if (!loadExtension(icuExtensionFilename)) {
225
drv_closeDatabaseSilently();
228
// load ROOT collation for use as default collation
229
if (!drv_executeSQL("SELECT icu_load_collation('', '')")) {
230
drv_closeDatabaseSilently();
235
//! @todo check exclusive status
237
Q_UNUSED(msgHandler);
239
if (d->res == SQLITE_OK && cancelled && !wasReadOnly && allowReadonly && isReadOnly()) {
240
//opened as read only, ask
241
if (KMessageBox::Continue !=
243
i18n("Do you want to open file \"%1\" as read-only?",
244
QDir::convertSeparators(data()->fileName()))
246
+ i18n("The file is probably already open on this or another computer.") + " "
247
+ i18n("Could not gain exclusive access for writing the file."),
248
KMessageBox::WarningContinueCancel, KMessageBox::Continue,
249
KGuiItem(i18n("Open As Read-Only"), koIconName("document-open")), KStandardGuiItem::cancel(),
250
"askBeforeOpeningFileReadOnly", KMessageBox::Notify, msgHandler)) {
252
if (!drv_closeDatabase())
260
if (d->res == SQLITE_CANTOPEN_WITH_LOCKED_READWRITE) {
261
setError(ERR_ACCESS_RIGHTS,
262
i18n("The file is probably already open on this or another computer.") + "\n\n"
263
+ i18n("Could not gain exclusive access for reading and writing the file.") + " "
264
+ i18n("Check the file's permissions and whether it is already opened and locked by another application."));
265
} else if (d->res == SQLITE_CANTOPEN_WITH_LOCKED_WRITE) {
266
setError(ERR_ACCESS_RIGHTS,
267
i18n("The file is probably already open on this or another computer.") + "\n\n"
268
+ i18n("Could not gain exclusive access for writing the file.") + " "
269
+ i18n("Check the file's permissions and whether it is already opened and locked by another application."));
273
return d->res == SQLITE_OK;
276
bool SQLiteConnection::drv_closeDatabase()
281
const int res = sqlite3_close(d->data);
282
if (SQLITE_OK == res) {
286
if (SQLITE_BUSY == res) {
287
#if 0 //this is ANNOYING, needs fixing (by closing cursors or waiting)
288
setError(ERR_CLOSE_FAILED, i18n("Could not close busy database."));
296
void SQLiteConnection::drv_closeDatabaseSilently()
298
const QString errmsg(d->errmsg); // save
299
const int res = d->res; // save
305
bool SQLiteConnection::drv_dropDatabase(const QString &dbName)
307
Q_UNUSED(dbName); // Each database is one single SQLite file.
308
const QString filename = data()->fileName();
309
if (QFile(filename).exists() && !QDir().remove(filename)) {
310
setError(ERR_ACCESS_RIGHTS, i18n("Could not remove file \"%1\".",
311
QDir::convertSeparators(filename)) + " "
312
+ i18n("Check the file's permissions and whether it is already opened and locked by another application."));
318
//CursorData* SQLiteConnection::drv_createCursor( const QString& statement )
319
Cursor* SQLiteConnection::prepareQuery(const QString& statement, uint cursor_options)
321
return new SQLiteCursor(this, statement, cursor_options);
324
Cursor* SQLiteConnection::prepareQuery(QuerySchema& query, uint cursor_options)
326
return new SQLiteCursor(this, query, cursor_options);
329
bool SQLiteConnection::drv_executeSQL(const QString& statement)
331
// KexiDBDrvDbg << "SQLiteConnection::drv_executeSQL(" << statement << ")";
332
// QCString st(statement.length()*2);
333
// st = escapeString( statement.local8Bit() ); //?
335
d->temp_st = statement.toUtf8();
337
d->temp_st = statement.toLocal8Bit(); //latin1 only
340
#ifdef CALLIGRADB_DEBUG_GUI
341
KexiDB::debugGUI(QString("ExecuteSQL (SQLite): ") + statement);
344
d->res = sqlite3_exec(
346
(const char*)d->temp_st,
351
#ifdef CALLIGRADB_DEBUG_GUI
352
KexiDB::debugGUI(d->res == SQLITE_OK ? " Success" : " Failure");
354
return d->res == SQLITE_OK;
357
quint64 SQLiteConnection::drv_lastInsertRowID()
359
return (quint64)sqlite3_last_insert_rowid(d->data);
362
int SQLiteConnection::serverResult()
364
return d->res == 0 ? Connection::serverResult() : d->res;
367
static const char* serverResultNames[] = {
394
"SQLITE_NOTADB", // 26
397
QString SQLiteConnection::serverResultName()
399
if (d->res >= 0 && d->res <= SQLITE_NOTADB)
400
return QString::fromLatin1(serverResultNames[d->res]);
401
else if (d->res == SQLITE_ROW)
402
return QLatin1String("SQLITE_ROW");
403
else if (d->res == SQLITE_DONE)
404
return QLatin1String("SQLITE_DONE");
408
void SQLiteConnection::drv_clearServerResult()
415
QString SQLiteConnection::serverErrorMsg()
417
return d->errmsg.isEmpty() ? Connection::serverErrorMsg() : d->errmsg;
420
PreparedStatement::Ptr SQLiteConnection::prepareStatement(PreparedStatement::StatementType type,
423
return KSharedPtr<PreparedStatement>(new SQLitePreparedStatement(type, *d, fields));
426
bool SQLiteConnection::isReadOnly() const
430
return (d->data ? sqlite3_is_readonly(d->data) : false)
431
|| Connection::isReadOnly();
433
return Connection::isReadOnly();
437
bool SQLiteConnection::loadExtension(const QString& path)
439
bool tempEnable = false;
440
if (!d->extensionsLoadingEnabled()) {
442
d->setExtensionsLoadingEnabled(true);
444
d->res = sqlite3_load_extension(d->data, path.toUtf8().constData(), 0, &d->errmsg_p);
446
bool ok = SQLITE_OK == d->res;
448
d->setExtensionsLoadingEnabled(false);
451
kWarning() << "Could not load SQLite extension" << path << ":" << d->errmsg_p;
456
#include "sqliteconnection.moc"