~smartboyhw/ubuntu/raring/calligra/2.6.0-0ubuntu1

« back to all changes in this revision

Viewing changes to libs/db/drivers/sqlite/sqliteconnection.cpp

  • Committer: Package Import Robot
  • Author(s): Philip Muškovac
  • Date: 2012-10-23 21:09:16 UTC
  • mfrom: (1.1.13)
  • Revision ID: package-import@ubuntu.com-20121023210916-m82w6zxnxhaxz7va
Tags: 1:2.5.90-0ubuntu1
* New upstream alpha release (LP: #1070436)
  - Add libkactivities-dev and libopenimageio-dev to build-depends
  - Add kubuntu_build_calligraactive.diff to build calligraactive by default
  - Add package for calligraauthor and move files that are shared between
    calligrawords and calligraauthor to calligrawords-common
* Document the patches
* Remove numbers from patches so they follow the same naming scheme as
  the rest of our patches.
* calligra-data breaks replaces krita-data (<< 1:2.5.3) (LP: #1071686)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* This file is part of the KDE project
 
2
   Copyright (C) 2003-2006 Jarosław Staniek <staniek@kde.org>
 
3
 
 
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.
 
8
 
 
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.
 
13
 
 
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.
 
18
*/
 
19
 
 
20
#include "sqliteconnection.h"
 
21
#include "sqliteconnection_p.h"
 
22
#include "sqlitecursor.h"
 
23
#include "sqlitepreparedstatement.h"
 
24
 
 
25
#include <sqlite3.h>
 
26
 
 
27
#include <db/driver.h>
 
28
#include <db/cursor.h>
 
29
#include <db/error.h>
 
30
#include <db/utils.h>
 
31
#include <db/calligradb_global.h>
 
32
 
 
33
#include <QFile>
 
34
#include <QDir>
 
35
#include <QRegExp>
 
36
 
 
37
#include <KDebug>
 
38
#include <KLocale>
 
39
#include <KStandardDirs>
 
40
 
 
41
//remove debug
 
42
#undef KexiDBDrvDbg
 
43
#define KexiDBDrvDbg if (0) kDebug()
 
44
 
 
45
#if defined(Q_OS_WIN)
 
46
#define SHARED_LIB_EXTENSION ".dll"
 
47
#elif defined(Q_OS_MAC)
 
48
#define SHARED_LIB_EXTENSION ".dylib"
 
49
#else
 
50
#define SHARED_LIB_EXTENSION ".so"
 
51
#endif
 
52
 
 
53
using namespace KexiDB;
 
54
 
 
55
SQLiteConnectionInternal::SQLiteConnectionInternal(Connection *connection)
 
56
        : ConnectionInternal(connection)
 
57
        , data(0)
 
58
        , data_owned(true)
 
59
        , errmsg_p(0)
 
60
        , res(SQLITE_OK)
 
61
        , result_name(0)
 
62
        , m_extensionsLoadingEnabled(false)
 
63
{
 
64
}
 
65
 
 
66
SQLiteConnectionInternal::~SQLiteConnectionInternal()
 
67
{
 
68
    if (data_owned && data) {
 
69
        sqlite3_close(data);
 
70
        data = 0;
 
71
    }
 
72
}
 
73
 
 
74
void SQLiteConnectionInternal::storeResult()
 
75
{
 
76
    if (errmsg_p) {
 
77
        errmsg = errmsg_p;
 
78
        sqlite3_free(errmsg_p);
 
79
        errmsg_p = 0;
 
80
    }
 
81
    errmsg = (data && res != SQLITE_OK) ? sqlite3_errmsg(data) : 0;
 
82
}
 
83
 
 
84
bool SQLiteConnectionInternal::extensionsLoadingEnabled() const
 
85
{
 
86
    return m_extensionsLoadingEnabled;
 
87
}
 
88
 
 
89
void SQLiteConnectionInternal::setExtensionsLoadingEnabled(bool set)
 
90
{
 
91
    if (set == m_extensionsLoadingEnabled)
 
92
        return;
 
93
    sqlite3_enable_load_extension(data, set);
 
94
    m_extensionsLoadingEnabled = set;
 
95
}
 
96
 
 
97
/*! Used by driver */
 
98
SQLiteConnection::SQLiteConnection(Driver *driver, ConnectionData &conn_data)
 
99
        : Connection(driver, conn_data)
 
100
        , d(new SQLiteConnectionInternal(this))
 
101
{
 
102
}
 
103
 
 
104
SQLiteConnection::~SQLiteConnection()
 
105
{
 
106
    KexiDBDrvDbg << "SQLiteConnection::~SQLiteConnection()";
 
107
    //disconnect if was connected
 
108
// disconnect();
 
109
    destroy();
 
110
    delete d;
 
111
    KexiDBDrvDbg << "SQLiteConnection::~SQLiteConnection() ok";
 
112
}
 
113
 
 
114
bool SQLiteConnection::drv_connect(KexiDB::ServerVersionInfo& version)
 
115
{
 
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();
 
123
    }
 
124
    return true;
 
125
}
 
126
 
 
127
bool SQLiteConnection::drv_disconnect()
 
128
{
 
129
    KexiDBDrvDbg << "SQLiteConnection::disconnect()";
 
130
    return true;
 
131
}
 
132
 
 
133
bool SQLiteConnection::drv_getDatabasesList(QStringList &list)
 
134
{
 
135
    //this is one-db-per-file database
 
136
    list.append(data()->fileName());   //more consistent than dbFileName() ?
 
137
    return true;
 
138
}
 
139
 
 
140
bool SQLiteConnection::drv_containsTable(const QString &tableName)
 
141
{
 
142
    bool success=false;
 
143
    return resultExists(QString("select name from sqlite_master where type='table' and name LIKE %1")
 
144
                        .arg(driver()->escapeString(tableName)), success) && success;
 
145
}
 
146
 
 
147
bool SQLiteConnection::drv_getTablesList(QStringList &list)
 
148
{
 
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()";
 
153
        return false;
 
154
    }
 
155
    list.clear();
 
156
    cursor->moveFirst();
 
157
    while (!cursor->eof() && !cursor->error()) {
 
158
        list += cursor->value(0).toString();
 
159
        cursor->moveNext();
 
160
    }
 
161
    if (cursor->error()) {
 
162
        deleteCursor(cursor);
 
163
        return false;
 
164
    }
 
165
    return deleteCursor(cursor);
 
166
}
 
167
 
 
168
bool SQLiteConnection::drv_createDatabase(const QString &dbName)
 
169
{
 
170
    Q_UNUSED(dbName);
 
171
    return drv_useDatabaseInternal(0, 0, true/*create if missing*/);
 
172
}
 
173
 
 
174
bool SQLiteConnection::drv_useDatabase(const QString &dbName, bool *cancelled,
 
175
                                       MessageHandler* msgHandler)
 
176
{
 
177
    Q_UNUSED(dbName);
 
178
    return drv_useDatabaseInternal(cancelled, msgHandler, false/*do not create if missing*/);
 
179
}
 
180
 
 
181
bool SQLiteConnection::drv_useDatabaseInternal(bool *cancelled,
 
182
                                               MessageHandler* msgHandler, bool createIfMissing)
 
183
{
 
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
 
186
    int openFlags = 0;
 
187
    if (isReadOnly()) {
 
188
        openFlags |= SQLITE_OPEN_READONLY;
 
189
    }
 
190
    else {
 
191
        openFlags |= SQLITE_OPEN_READWRITE;
 
192
        if (createIfMissing) {
 
193
            openFlags |= SQLITE_OPEN_CREATE;
 
194
        }
 
195
    }
 
196
 
 
197
//! @todo add option
 
198
//    int allowReadonly = 1;
 
199
//    const bool wasReadOnly = Connection::isReadOnly();
 
200
 
 
201
    d->res = sqlite3_open_v2(
 
202
                 //QFile::encodeName( data()->fileName() ),
 
203
                 data()->fileName().toUtf8().constData(), /* unicode expected since SQLite 3.1 */
 
204
                 &d->data,
 
205
                 openFlags, /*exclusiveFlag,
 
206
                 allowReadonly *//* If 1 and locking fails, try opening in read-only mode */
 
207
                 0
 
208
             );
 
209
    d->storeResult();
 
210
 
 
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();
 
219
            return false;
 
220
        }
 
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();
 
226
            return false;
 
227
        }
 
228
        // load ROOT collation for use as default collation
 
229
        if (!drv_executeSQL("SELECT icu_load_collation('', '')")) {
 
230
            drv_closeDatabaseSilently();
 
231
            return false;
 
232
        }
 
233
    }
 
234
 
 
235
//! @todo check exclusive status
 
236
    Q_UNUSED(cancelled);
 
237
    Q_UNUSED(msgHandler);
 
238
#if 0
 
239
    if (d->res == SQLITE_OK && cancelled && !wasReadOnly && allowReadonly && isReadOnly()) {
 
240
        //opened as read only, ask
 
241
        if (KMessageBox::Continue !=
 
242
                askQuestion(
 
243
                    i18n("Do you want to open file \"%1\" as read-only?",
 
244
                         QDir::convertSeparators(data()->fileName()))
 
245
                    + "\n\n"
 
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)) {
 
251
            clearError();
 
252
            if (!drv_closeDatabase())
 
253
                return false;
 
254
            *cancelled = true;
 
255
            return false;
 
256
        }
 
257
    }
 
258
//! @todo
 
259
/*
 
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."));
 
270
    }
 
271
    */
 
272
#endif
 
273
    return d->res == SQLITE_OK;
 
274
}
 
275
 
 
276
bool SQLiteConnection::drv_closeDatabase()
 
277
{
 
278
    if (!d->data)
 
279
        return false;
 
280
 
 
281
    const int res = sqlite3_close(d->data);
 
282
    if (SQLITE_OK == res) {
 
283
        d->data = 0;
 
284
        return true;
 
285
    }
 
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."));
 
289
#else
 
290
        return true;
 
291
#endif
 
292
    }
 
293
    return false;
 
294
}
 
295
 
 
296
void SQLiteConnection::drv_closeDatabaseSilently()
 
297
{
 
298
    const QString errmsg(d->errmsg); // save
 
299
    const int res = d->res; // save
 
300
    drv_closeDatabase();
 
301
    d->errmsg = errmsg;
 
302
    d->res = res;
 
303
}
 
304
 
 
305
bool SQLiteConnection::drv_dropDatabase(const QString &dbName)
 
306
{
 
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."));
 
313
        return false;
 
314
    }
 
315
    return true;
 
316
}
 
317
 
 
318
//CursorData* SQLiteConnection::drv_createCursor( const QString& statement )
 
319
Cursor* SQLiteConnection::prepareQuery(const QString& statement, uint cursor_options)
 
320
{
 
321
    return new SQLiteCursor(this, statement, cursor_options);
 
322
}
 
323
 
 
324
Cursor* SQLiteConnection::prepareQuery(QuerySchema& query, uint cursor_options)
 
325
{
 
326
    return new SQLiteCursor(this, query, cursor_options);
 
327
}
 
328
 
 
329
bool SQLiteConnection::drv_executeSQL(const QString& statement)
 
330
{
 
331
// KexiDBDrvDbg << "SQLiteConnection::drv_executeSQL(" << statement << ")";
 
332
// QCString st(statement.length()*2);
 
333
// st = escapeString( statement.local8Bit() ); //?
 
334
#ifdef SQLITE_UTF8
 
335
    d->temp_st = statement.toUtf8();
 
336
#else
 
337
    d->temp_st = statement.toLocal8Bit(); //latin1 only
 
338
#endif
 
339
 
 
340
#ifdef CALLIGRADB_DEBUG_GUI
 
341
    KexiDB::debugGUI(QString("ExecuteSQL (SQLite): ") + statement);
 
342
#endif
 
343
 
 
344
    d->res = sqlite3_exec(
 
345
                 d->data,
 
346
                 (const char*)d->temp_st,
 
347
                 0/*callback*/,
 
348
                 0,
 
349
                 &d->errmsg_p);
 
350
    d->storeResult();
 
351
#ifdef CALLIGRADB_DEBUG_GUI
 
352
    KexiDB::debugGUI(d->res == SQLITE_OK ? "  Success" : "  Failure");
 
353
#endif
 
354
    return d->res == SQLITE_OK;
 
355
}
 
356
 
 
357
quint64 SQLiteConnection::drv_lastInsertRowID()
 
358
{
 
359
    return (quint64)sqlite3_last_insert_rowid(d->data);
 
360
}
 
361
 
 
362
int SQLiteConnection::serverResult()
 
363
{
 
364
    return d->res == 0 ? Connection::serverResult() : d->res;
 
365
}
 
366
 
 
367
static const char* serverResultNames[] = {
 
368
    "SQLITE_OK", // 0
 
369
    "SQLITE_ERROR",
 
370
    "SQLITE_INTERNAL",
 
371
    "SQLITE_PERM",
 
372
    "SQLITE_ABORT",
 
373
    "SQLITE_BUSY",
 
374
    "SQLITE_LOCKED",
 
375
    "SQLITE_NOMEM",
 
376
    "SQLITE_READONLY",
 
377
    "SQLITE_INTERRUPT",
 
378
    "SQLITE_IOERR",
 
379
    "SQLITE_CORRUPT",
 
380
    "SQLITE_NOTFOUND",
 
381
    "SQLITE_FULL",
 
382
    "SQLITE_CANTOPEN",
 
383
    "SQLITE_PROTOCOL",
 
384
    "SQLITE_EMPTY",
 
385
    "SQLITE_SCHEMA",
 
386
    "SQLITE_TOOBIG",
 
387
    "SQLITE_CONSTRAINT",
 
388
    "SQLITE_MISMATCH",
 
389
    "SQLITE_MISUSE",
 
390
    "SQLITE_NOLFS",
 
391
    "SQLITE_AUTH",
 
392
    "SQLITE_FORMAT",
 
393
    "SQLITE_RANGE",
 
394
    "SQLITE_NOTADB", // 26
 
395
};
 
396
 
 
397
QString SQLiteConnection::serverResultName()
 
398
{
 
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");
 
405
    return QString();
 
406
}
 
407
 
 
408
void SQLiteConnection::drv_clearServerResult()
 
409
{
 
410
    if (!d)
 
411
        return;
 
412
    d->res = SQLITE_OK;
 
413
}
 
414
 
 
415
QString SQLiteConnection::serverErrorMsg()
 
416
{
 
417
    return d->errmsg.isEmpty() ? Connection::serverErrorMsg() : d->errmsg;
 
418
}
 
419
 
 
420
PreparedStatement::Ptr SQLiteConnection::prepareStatement(PreparedStatement::StatementType type,
 
421
        FieldList& fields)
 
422
{
 
423
    return KSharedPtr<PreparedStatement>(new SQLitePreparedStatement(type, *d, fields));
 
424
}
 
425
 
 
426
bool SQLiteConnection::isReadOnly() const
 
427
{
 
428
    //! @todo
 
429
#if 0
 
430
    return (d->data ? sqlite3_is_readonly(d->data) : false)
 
431
           || Connection::isReadOnly();
 
432
#else
 
433
    return Connection::isReadOnly();
 
434
#endif
 
435
}
 
436
 
 
437
bool SQLiteConnection::loadExtension(const QString& path)
 
438
{
 
439
    bool tempEnable = false;
 
440
    if (!d->extensionsLoadingEnabled()) {
 
441
        tempEnable = true;
 
442
        d->setExtensionsLoadingEnabled(true);
 
443
    }
 
444
    d->res = sqlite3_load_extension(d->data, path.toUtf8().constData(), 0, &d->errmsg_p);
 
445
    d->storeResult();
 
446
    bool ok = SQLITE_OK == d->res;
 
447
    if (tempEnable) {
 
448
        d->setExtensionsLoadingEnabled(false);
 
449
    }
 
450
    if (!ok) {
 
451
        kWarning() << "Could not load SQLite extension" << path << ":" << d->errmsg_p;
 
452
    }
 
453
    return ok;
 
454
}
 
455
 
 
456
#include "sqliteconnection.moc"