1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Nokia Corporation (qt-info@nokia.com)
5**
6** This file is part of the QtSql module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain additional
24** rights. These rights are described in the Nokia Qt LGPL Exception
25** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
26**
27** GNU General Public License Usage
28** Alternatively, this file may be used under the terms of the GNU
29** General Public License version 3.0 as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL included in the
31** packaging of this file. Please review the following information to
32** ensure the GNU General Public License version 3.0 requirements will be
33** met: http://www.gnu.org/copyleft/gpl.html.
34**
35** If you have questions regarding the use of this file, please contact
36** Nokia at qt-info@nokia.com.
37** $QT_END_LICENSE$
38**
39****************************************************************************/
40
41#include "qsql_sqlite.h"
42
43#include <qcoreapplication.h>
44#include <qdatetime.h>
45#include <qvariant.h>
46#include <qsqlerror.h>
47#include <qsqlfield.h>
48#include <qsqlindex.h>
49#include <qsqlquery.h>
50#include <qstringlist.h>
51#include <qvector.h>
52#include <qdebug.h>
53
54#ifdef QT5_BUILD
55#include "QtSql/private/qsqldriver_p.h"
56#include "QtSql/private/qsqlcachedresult_p.h"
57#endif
58
59#if defined Q_OS_WIN
60# include <qt_windows.h>
61#else
62# include <unistd.h>
63#endif
64
65#include <sqlite3.h>
66
67#include <qthread.h>
68#include "sqlite_blocking.h"
69
70#ifdef QT5_BUILD
71Q_DECLARE_OPAQUE_POINTER(sqlite3*)
72Q_DECLARE_OPAQUE_POINTER(sqlite3_stmt*)
73#endif
74
75Q_DECLARE_METATYPE(sqlite3*)
76Q_DECLARE_METATYPE(sqlite3_stmt*)
77
78QT_BEGIN_NAMESPACE
79
80static QString _q_escapeIdentifier(const QString &identifier)
81{
82 QString res = identifier;
83 if(!identifier.isEmpty() && identifier.left(1) != QString(QLatin1Char('"')) && identifier.right(1) != QString(QLatin1Char('"')) ) {
84 res.replace(QLatin1Char('"'), QLatin1String("\"\""));
85 res.prepend(QLatin1Char('"')).append(QLatin1Char('"'));
86 res.replace(QLatin1Char('.'), QLatin1String("\".\""));
87 }
88 return res;
89}
90
91static QVariant::Type qGetColumnType(const QString &tpName)
92{
93 const QString typeName = tpName.toLower();
94
95 if (typeName == QLatin1String("integer")
96 || typeName == QLatin1String("int"))
97 return QVariant::Int;
98 if (typeName == QLatin1String("double")
99 || typeName == QLatin1String("float")
100 || typeName == QLatin1String("real")
101 || typeName.startsWith(QLatin1String("numeric")))
102 return QVariant::Double;
103 if (typeName == QLatin1String("blob"))
104 return QVariant::ByteArray;
105 if (typeName == QLatin1String("boolean")
106 || typeName == QLatin1String("bool"))
107 return QVariant::Bool;
108 return QVariant::String;
109}
110
111static QSqlError qMakeError(sqlite3 *access, const QString &descr, QSqlError::ErrorType type,
112 int errorCode = -1)
113{
114 return QSqlError(descr,
115 QString(reinterpret_cast<const QChar *>(sqlite3_errmsg16(access))),
116 type, errorCode);
117}
118
119class QSQLiteResultPrivate;
120
121class QSQLiteResult : public QSqlCachedResult
122{
123 friend class QSQLiteDriver;
124 friend class QSQLiteResultPrivate;
125public:
126 explicit QSQLiteResult(const QSQLiteDriver* db);
127 ~QSQLiteResult();
128 QVariant handle() const;
129
130protected:
131 bool gotoNext(QSqlCachedResult::ValueCache& row, int idx);
132 bool reset(const QString &query);
133 bool prepare(const QString &query);
134 bool exec();
135 int size();
136 int numRowsAffected();
137 QVariant lastInsertId() const;
138 QSqlRecord record() const;
139#ifdef QT5_BUILD
140 void detachFromResultSet();
141#endif
142 void virtual_hook(int id, void *data);
143
144private:
145 QSQLiteResultPrivate* d;
146};
147
148
149#ifdef QT5_BUILD
150class QSQLiteDriverPrivate : public QSqlDriverPrivate
151#else
152class QSQLiteDriverPrivate
153#endif
154{
155public:
156 inline QSQLiteDriverPrivate() : access(0) {
157#ifdef QT5_BUILD
158 dbmsType = SQLite;
159#endif
160 }
161 sqlite3 *access;
162 QList<QSQLiteResult *> results;
163};
164
165
166class QSQLiteResultPrivate
167{
168public:
169 QSQLiteResultPrivate(QSQLiteResult *res);
170 void cleanup();
171 bool fetchNext(QSqlCachedResult::ValueCache &values, int idx, bool initialFetch);
172 // initializes the recordInfo and the cache
173 void initColumns(bool emptyResultset);
174 void finalize();
175
176 QSQLiteResult* q;
177 sqlite3 *access;
178
179 sqlite3_stmt *stmt;
180
181 bool skippedStatus; // the status of the fetchNext() that's skipped
182 bool skipRow; // skip the next fetchNext()?
183 QSqlRecord rInf;
184 QVector<QVariant> firstRow;
185};
186
187QSQLiteResultPrivate::QSQLiteResultPrivate(QSQLiteResult* res) : q(res), access(0),
188 stmt(0), skippedStatus(false), skipRow(false)
189{
190}
191
192void QSQLiteResultPrivate::cleanup()
193{
194 finalize();
195 rInf.clear();
196 skippedStatus = false;
197 skipRow = false;
198 q->setAt(QSql::BeforeFirstRow);
199 q->setActive(false);
200 q->cleanup();
201}
202
203void QSQLiteResultPrivate::finalize()
204{
205 if (!stmt)
206 return;
207
208 sqlite3_finalize(stmt);
209 stmt = 0;
210}
211
212void QSQLiteResultPrivate::initColumns(bool emptyResultset)
213{
214 int nCols = sqlite3_column_count(stmt);
215 if (nCols <= 0)
216 return;
217
218 q->init(nCols);
219
220 for (int i = 0; i < nCols; ++i) {
221 QString colName = QString::fromUtf16(
222 static_cast<const ushort *>(sqlite3_column_name16(stmt, i))
223 ).remove(QLatin1Char('"'));
224
225 // must use typeName for resolving the type to match QSqliteDriver::record
226 QString typeName = QString::fromUtf16(
227 static_cast<const ushort *>(sqlite3_column_decltype16(stmt, i)));
228
229 // sqlite3_column_type is documented to have undefined behavior if the result set is empty
230 int stp = emptyResultset ? -1 : sqlite3_column_type(stmt, i);
231
232 QVariant::Type fieldType;
233
234 if (typeName.isEmpty()) {
235 fieldType = qGetColumnType(typeName);
236 } else {
237 // Get the proper type for the field based on stp value
238 switch (stp) {
239 case SQLITE_INTEGER:
240 fieldType = QVariant::Int;
241 break;
242 case SQLITE_FLOAT:
243 fieldType = QVariant::Double;
244 break;
245 case SQLITE_BLOB:
246 fieldType = QVariant::ByteArray;
247 break;
248 case SQLITE_TEXT:
249 fieldType = QVariant::String;
250 break;
251 case SQLITE_NULL:
252 default:
253 fieldType = QVariant::Invalid;
254 break;
255 }
256 }
257
258 QSqlField fld(colName, fieldType);
259 fld.setSqlType(stp);
260 rInf.append(fld);
261 }
262}
263
264bool QSQLiteResultPrivate::fetchNext(QSqlCachedResult::ValueCache &values, int idx, bool initialFetch)
265{
266 int res;
267 int i;
268
269 if (skipRow) {
270 // already fetched
271 Q_ASSERT(!initialFetch);
272 skipRow = false;
273 for(int i=0;i<firstRow.count();i++)
274 values[i]=firstRow[i];
275 return skippedStatus;
276 }
277 skipRow = initialFetch;
278
279 if(initialFetch) {
280 firstRow.clear();
281 firstRow.resize(sqlite3_column_count(stmt));
282 }
283
284 if (!stmt) {
285 q->setLastError(QSqlError(QCoreApplication::translate("QSQLiteResult", "Unable to fetch row"),
286 QCoreApplication::translate("QSQLiteResult", "No query"), QSqlError::ConnectionError));
287 q->setAt(QSql::AfterLastRow);
288 return false;
289 }
290 res = sqlite3_blocking_step(stmt);
291
292 switch(res) {
293 case SQLITE_ROW:
294 // check to see if should fill out columns
295 if (rInf.isEmpty())
296 // must be first call.
297 initColumns(false);
298 if (idx < 0 && !initialFetch)
299 return true;
300 for (i = 0; i < rInf.count(); ++i) {
301 switch (sqlite3_column_type(stmt, i)) {
302 case SQLITE_BLOB:
303 values[i + idx] = QByteArray(static_cast<const char *>(
304 sqlite3_column_blob(stmt, i)),
305 sqlite3_column_bytes(stmt, i));
306 break;
307 case SQLITE_INTEGER:
308 values[i + idx] = sqlite3_column_int64(stmt, i);
309 break;
310 case SQLITE_FLOAT:
311 switch(q->numericalPrecisionPolicy()) {
312 case QSql::LowPrecisionInt32:
313 values[i + idx] = sqlite3_column_int(stmt, i);
314 break;
315 case QSql::LowPrecisionInt64:
316 values[i + idx] = sqlite3_column_int64(stmt, i);
317 break;
318 case QSql::LowPrecisionDouble:
319 case QSql::HighPrecision:
320 default:
321 values[i + idx] = sqlite3_column_double(stmt, i);
322 break;
323 };
324 break;
325 case SQLITE_NULL:
326 values[i + idx] = QVariant(QVariant::String);
327 break;
328 default:
329 values[i + idx] = QString(reinterpret_cast<const QChar *>(
330 sqlite3_column_text16(stmt, i)),
331 sqlite3_column_bytes16(stmt, i) / sizeof(QChar));
332 break;
333 }
334 }
335 return true;
336 case SQLITE_DONE:
337 if (rInf.isEmpty())
338 // must be first call.
339 initColumns(true);
340 q->setAt(QSql::AfterLastRow);
341 sqlite3_reset(stmt);
342 return false;
343 case SQLITE_CONSTRAINT:
344 case SQLITE_ERROR:
345 // SQLITE_ERROR is a generic error code and we must call sqlite3_reset()
346 // to get the specific error message.
347 res = sqlite3_reset(stmt);
348 q->setLastError(qMakeError(access, QCoreApplication::translate("QSQLiteResult",
349 "Unable to fetch row"), QSqlError::ConnectionError, res));
350 q->setAt(QSql::AfterLastRow);
351 return false;
352 case SQLITE_MISUSE:
353 case SQLITE_BUSY:
354 default:
355 // something wrong, don't get col info, but still return false
356 q->setLastError(qMakeError(access, QCoreApplication::translate("QSQLiteResult",
357 "Unable to fetch row"), QSqlError::ConnectionError, res));
358 sqlite3_reset(stmt);
359 q->setAt(QSql::AfterLastRow);
360 return false;
361 }
362 return false;
363}
364
365QSQLiteResult::QSQLiteResult(const QSQLiteDriver* db)
366 : QSqlCachedResult(db)
367{
368 d = new QSQLiteResultPrivate(this);
369 d->access = db->d_func()->access;
370 const_cast<QSQLiteDriverPrivate*>(db->d_func())->results.append(this);
371}
372
373QSQLiteResult::~QSQLiteResult()
374{
375 const QSqlDriver *sqlDriver = driver();
376 if (sqlDriver)
377 const_cast<QSQLiteDriverPrivate*>(qobject_cast<const QSQLiteDriver *>(sqlDriver)->d_func())->results.removeOne(this);
378 d->cleanup();
379 delete d;
380}
381
382void QSQLiteResult::virtual_hook(int id, void *data)
383{
384#ifdef QT5_BUILD
385 QSqlCachedResult::virtual_hook(id, data);
386#else
387 switch (id) {
388 case QSqlResult::DetachFromResultSet:
389 if (d->stmt)
390 sqlite3_reset(d->stmt);
391 break;
392 default:
393 QSqlCachedResult::virtual_hook(id, data);
394 }
395#endif
396}
397
398bool QSQLiteResult::reset(const QString &query)
399{
400 if (!prepare(query))
401 return false;
402 return exec();
403}
404
405bool QSQLiteResult::prepare(const QString &query)
406{
407 if (!driver() || !driver()->isOpen() || driver()->isOpenError())
408 return false;
409
410 d->cleanup();
411
412 setSelect(false);
413
414 const void *pzTail = NULL;
415
416#if (SQLITE_VERSION_NUMBER >= 3003011)
417// int res = sqlite3_prepare16_v2(d->access, query.constData(), (query.size() + 1) * sizeof(QChar),
418// &d->stmt, 0);
419 int res = sqlite3_blocking_prepare16_v2(d->access, query.constData(), (query.size() + 1) * sizeof(QChar),
420 &d->stmt, &pzTail);
421#else
422 int res = sqlite3_prepare16(d->access, query.constData(), (query.size() + 1) * sizeof(QChar),
423 &d->stmt, &pzTail);
424#endif
425
426 if (res != SQLITE_OK) {
427 setLastError(qMakeError(d->access, QCoreApplication::translate("QSQLiteResult",
428 "Unable to execute statement"), QSqlError::StatementError, res));
429 d->finalize();
430 return false;
431 } else if (pzTail && !QString(reinterpret_cast<const QChar*>(pzTail)).trimmed().isEmpty()) {
432 setLastError(qMakeError(d->access, QCoreApplication::translate("QSQLiteResult",
433 "Unable to execute multiple statements at a time"), QSqlError::StatementError, SQLITE_MISUSE));
434 d->finalize();
435 return false;
436 }
437 return true;
438}
439
440bool QSQLiteResult::exec()
441{
442 const QVector<QVariant> values = boundValues();
443
444 d->skippedStatus = false;
445 d->skipRow = false;
446 d->rInf.clear();
447 clearValues();
448 setLastError(QSqlError());
449
450 int res = sqlite3_reset(d->stmt);
451 if (res != SQLITE_OK) {
452 setLastError(qMakeError(d->access, QCoreApplication::translate("QSQLiteResult",
453 "Unable to reset statement"), QSqlError::StatementError, res));
454 d->finalize();
455 return false;
456 }
457 int paramCount = sqlite3_bind_parameter_count(d->stmt);
458 if (paramCount == values.count()) {
459 for (int i = 0; i < paramCount; ++i) {
460 res = SQLITE_OK;
461 const QVariant value = values.at(i);
462
463 if (value.isNull()) {
464 res = sqlite3_bind_null(d->stmt, i + 1);
465 } else {
466 switch (value.type()) {
467 case QVariant::ByteArray: {
468 const QByteArray *ba = static_cast<const QByteArray*>(value.constData());
469 res = sqlite3_bind_blob(d->stmt, i + 1, ba->constData(),
470 ba->size(), SQLITE_STATIC);
471 break; }
472 case QVariant::Int:
473 case QVariant::Bool:
474 res = sqlite3_bind_int(d->stmt, i + 1, value.toInt());
475 break;
476 case QVariant::Double:
477 res = sqlite3_bind_double(d->stmt, i + 1, value.toDouble());
478 break;
479 case QVariant::UInt:
480 case QVariant::LongLong:
481 res = sqlite3_bind_int64(d->stmt, i + 1, value.toLongLong());
482 break;
483 case QVariant::DateTime: {
484 const QDateTime dateTime = value.toDateTime();
485#ifdef QT5_BUILD
486 const QString str = dateTime.toString(QStringLiteral("yyyy-MM-ddThh:mm:ss.zzz"));
487#else
488 const QString str = dateTime.toString(QLatin1String("yyyy-MM-ddThh:mm:ss.zzz"));
489#endif
490 res = sqlite3_bind_text16(d->stmt, i + 1, str.utf16(),
491 str.size() * sizeof(ushort), SQLITE_TRANSIENT);
492 break;
493 }
494 case QVariant::Time: {
495 const QTime time = value.toTime();
496#ifdef QT5_BUILD
497 const QString str = time.toString(QStringLiteral("hh:mm:ss.zzz"));
498#else
499 const QString str = time.toString(QLatin1String("hh:mm:ss.zzz"));
500#endif
501 res = sqlite3_bind_text16(d->stmt, i + 1, str.utf16(),
502 str.size() * sizeof(ushort), SQLITE_TRANSIENT);
503 break;
504 }
505 case QVariant::String: {
506 // lifetime of string == lifetime of its qvariant
507 const QString *str = static_cast<const QString*>(value.constData());
508 res = sqlite3_bind_text16(d->stmt, i + 1, str->utf16(),
509 (str->size()) * sizeof(QChar), SQLITE_STATIC);
510 break; }
511 default: {
512 QString str = value.toString();
513 // SQLITE_TRANSIENT makes sure that sqlite buffers the data
514 res = sqlite3_bind_text16(d->stmt, i + 1, str.utf16(),
515 (str.size()) * sizeof(QChar), SQLITE_TRANSIENT);
516 break; }
517 }
518 }
519 if (res != SQLITE_OK) {
520 setLastError(qMakeError(d->access, QCoreApplication::translate("QSQLiteResult",
521 "Unable to bind parameters"), QSqlError::StatementError, res));
522 d->finalize();
523 return false;
524 }
525 }
526 } else {
527 setLastError(QSqlError(QCoreApplication::translate("QSQLiteResult",
528 "Parameter count mismatch"), QString(), QSqlError::StatementError));
529 return false;
530 }
531 d->skippedStatus = d->fetchNext(d->firstRow, 0, true);
532 if (lastError().isValid()) {
533 setSelect(false);
534 setActive(false);
535 return false;
536 }
537 setSelect(!d->rInf.isEmpty());
538 setActive(true);
539 return true;
540}
541
542bool QSQLiteResult::gotoNext(QSqlCachedResult::ValueCache& row, int idx)
543{
544 return d->fetchNext(row, idx, false);
545}
546
547int QSQLiteResult::size()
548{
549 return -1;
550}
551
552int QSQLiteResult::numRowsAffected()
553{
554 return sqlite3_changes(d->access);
555}
556
557QVariant QSQLiteResult::lastInsertId() const
558{
559 if (isActive()) {
560 qint64 id = sqlite3_last_insert_rowid(d->access);
561 if (id)
562 return id;
563 }
564 return QVariant();
565}
566
567QSqlRecord QSQLiteResult::record() const
568{
569 if (!isActive() || !isSelect())
570 return QSqlRecord();
571 return d->rInf;
572}
573
574#ifdef QT5_BUILD
575void QSQLiteResult::detachFromResultSet()
576{
577 if (d->stmt)
578 sqlite3_reset(d->stmt);
579}
580#endif
581
582QVariant QSQLiteResult::handle() const
583{
584 return qVariantFromValue(d->stmt);
585}
586
587/////////////////////////////////////////////////////////
588
589QSQLiteDriver::QSQLiteDriver(QObject * parent)
590#ifdef QT5_BUILD
591 : QSqlDriver(*new QSQLiteDriverPrivate, parent)
592#else
593 : QSqlDriver(parent)
594#endif
595{
596#ifndef QT5_BUILD
597 d_ptr = new QSQLiteDriverPrivate();
598#endif
599}
600
601QSQLiteDriver::QSQLiteDriver(sqlite3 *connection, QObject *parent)
602#ifdef QT5_BUILD
603 : QSqlDriver(*new QSQLiteDriverPrivate, parent)
604#else
605 : QSqlDriver(parent)
606#endif
607{
608 Q_D(QSQLiteDriver);
609
610#ifndef QT5_BUILD
611 d_ptr = new QSQLiteDriverPrivate();
612#endif
613 d->access = connection;
614 setOpen(true);
615 setOpenError(false);
616}
617
618
619QSQLiteDriver::~QSQLiteDriver()
620{
621#ifndef QT5_BUILD
622 delete d_ptr;
623#endif
624}
625
626bool QSQLiteDriver::hasFeature(DriverFeature f) const
627{
628 switch (f) {
629 case BLOB:
630 case Transactions:
631 case Unicode:
632 case LastInsertId:
633 case PreparedQueries:
634 case PositionalPlaceholders:
635 case SimpleLocking:
636 case FinishQuery:
637 case LowPrecisionNumbers:
638 return true;
639 case QuerySize:
640 case NamedPlaceholders:
641 case BatchOperations:
642 case EventNotifications:
643 case MultipleResultSets:
644#ifdef QT5_BUILD
645 case CancelQuery:
646#endif
647 return false;
648 }
649 return false;
650}
651
652/*
653 SQLite dbs have no user name, passwords, hosts or ports.
654 just file names.
655*/
656bool QSQLiteDriver::open(const QString & db, const QString &, const QString &, const QString &, int, const QString &conOpts)
657{
658 Q_D(QSQLiteDriver);
659
660 if (isOpen())
661 close();
662
663 int timeout = 5000;
664 bool sharedCache = false;
665 bool openReadOnlyOption = false;
666 bool openUriOption = false;
667
668 const QStringList opts = QString(conOpts).remove(QLatin1Char(' ' )).split(QLatin1Char(';'));
669 Q_FOREACH (const QString &option, opts) {
670 if (option.startsWith(QLatin1String("QSQLITE_BUSY_TIMEOUT="))) {
671 bool ok;
672#ifdef QT5_BUILD
673 const int nt = option.midRef(21).toInt(&ok);
674#else
675 const int nt = option.mid(21).toInt(&ok);
676#endif
677 if (ok)
678 timeout = nt;
679 } else if (option == QLatin1String("QSQLITE_OPEN_READONLY")) {
680 openReadOnlyOption = true;
681 } else if (option == QLatin1String("QSQLITE_OPEN_URI")) {
682 openUriOption = true;
683 } else if (option == QLatin1String("QSQLITE_ENABLE_SHARED_CACHE")) {
684 sharedCache = true;
685 }
686 }
687
688 int openMode = (openReadOnlyOption ? SQLITE_OPEN_READONLY : (SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE));
689 if (openUriOption)
690 openMode |= SQLITE_OPEN_URI;
691
692 sqlite3_enable_shared_cache(sharedCache);
693
694 if (sqlite3_open_v2(db.toUtf8().constData(), &d->access, openMode, NULL) == SQLITE_OK) {
695 sqlite3_busy_timeout(d->access, timeout);
696 sqlite3_extended_result_codes(d->access, 1);
697 setOpen(true);
698 setOpenError(false);
699 return true;
700 } else {
701 if (d->access) {
702 sqlite3_close(d->access);
703 d->access = 0;
704 }
705
706 setLastError(qMakeError(d->access, tr("Error opening database"),
707 QSqlError::ConnectionError));
708 setOpenError(true);
709 return false;
710 }
711}
712
713void QSQLiteDriver::close()
714{
715 Q_D(QSQLiteDriver);
716
717 if (isOpen()) {
718 Q_FOREACH (QSQLiteResult *result, d->results) {
719 result->d->finalize();
720 }
721
722 if (sqlite3_close(d->access) != SQLITE_OK)
723 setLastError(qMakeError(d->access, tr("Error closing database"),
724 QSqlError::ConnectionError));
725 d->access = 0;
726 setOpen(false);
727 setOpenError(false);
728 }
729}
730
731QSqlResult *QSQLiteDriver::createResult() const
732{
733 return new QSQLiteResult(this);
734}
735
736bool QSQLiteDriver::beginTransaction()
737{
738 if (!isOpen() || isOpenError())
739 return false;
740
741 QSqlQuery q(createResult());
742 if (!q.exec(QLatin1String("BEGIN"))) {
743 setLastError(QSqlError(tr("Unable to begin transaction"),
744 q.lastError().databaseText(), QSqlError::TransactionError));
745 return false;
746 }
747
748 return true;
749}
750
751bool QSQLiteDriver::commitTransaction()
752{
753 if (!isOpen() || isOpenError())
754 return false;
755
756 QSqlQuery q(createResult());
757 if (!q.exec(QLatin1String("COMMIT"))) {
758 setLastError(QSqlError(tr("Unable to commit transaction"),
759 q.lastError().databaseText(), QSqlError::TransactionError));
760 return false;
761 }
762
763 return true;
764}
765
766bool QSQLiteDriver::rollbackTransaction()
767{
768 if (!isOpen() || isOpenError())
769 return false;
770
771 QSqlQuery q(createResult());
772 if (!q.exec(QLatin1String("ROLLBACK"))) {
773 setLastError(QSqlError(tr("Unable to rollback transaction"),
774 q.lastError().databaseText(), QSqlError::TransactionError));
775 return false;
776 }
777
778 return true;
779}
780
781QStringList QSQLiteDriver::tables(QSql::TableType type) const
782{
783 QStringList res;
784 if (!isOpen())
785 return res;
786
787 QSqlQuery q(createResult());
788 q.setForwardOnly(true);
789
790 QString sql = QLatin1String("SELECT name FROM sqlite_master WHERE %1 "
791 "UNION ALL SELECT name FROM sqlite_temp_master WHERE %1");
792 if ((type & QSql::Tables) && (type & QSql::Views))
793 sql = sql.arg(QLatin1String("type='table' OR type='view'"));
794 else if (type & QSql::Tables)
795 sql = sql.arg(QLatin1String("type='table'"));
796 else if (type & QSql::Views)
797 sql = sql.arg(QLatin1String("type='view'"));
798 else
799 sql.clear();
800
801 if (!sql.isEmpty() && q.exec(sql)) {
802 while(q.next())
803 res.append(q.value(0).toString());
804 }
805
806 if (type & QSql::SystemTables) {
807 // there are no internal tables beside this one:
808 res.append(QLatin1String("sqlite_master"));
809 }
810
811 return res;
812}
813
814static QSqlIndex qGetTableInfo(QSqlQuery &q, const QString &tableName, bool onlyPIndex = false)
815{
816 QString schema;
817 QString table(tableName);
818 int indexOfSeparator = tableName.indexOf(QLatin1Char('.'));
819 if (indexOfSeparator > -1) {
820 schema = tableName.left(indexOfSeparator).append(QLatin1Char('.'));
821 table = tableName.mid(indexOfSeparator + 1);
822 }
823 q.exec(QLatin1String("PRAGMA ") + schema + QLatin1String("table_info (") + _q_escapeIdentifier(table) + QLatin1String(")"));
824
825 QSqlIndex ind;
826 while (q.next()) {
827 bool isPk = q.value(5).toInt();
828 if (onlyPIndex && !isPk)
829 continue;
830 QString typeName = q.value(2).toString().toLower();
831 QSqlField fld(q.value(1).toString(), qGetColumnType(typeName));
832 if (isPk && (typeName == QLatin1String("integer")))
833 // INTEGER PRIMARY KEY fields are auto-generated in sqlite
834 // INT PRIMARY KEY is not the same as INTEGER PRIMARY KEY!
835 fld.setAutoValue(true);
836 fld.setRequired(q.value(3).toInt() != 0);
837 fld.setDefaultValue(q.value(4));
838 ind.append(fld);
839 }
840 return ind;
841}
842
843QSqlIndex QSQLiteDriver::primaryIndex(const QString &tblname) const
844{
845 if (!isOpen())
846 return QSqlIndex();
847
848 QString table = tblname;
849 if (isIdentifierEscaped(table, QSqlDriver::TableName))
850 table = stripDelimiters(table, QSqlDriver::TableName);
851
852 QSqlQuery q(createResult());
853 q.setForwardOnly(true);
854 return qGetTableInfo(q, table, true);
855}
856
857QSqlRecord QSQLiteDriver::record(const QString &tbl) const
858{
859 if (!isOpen())
860 return QSqlRecord();
861
862 QString table = tbl;
863 if (isIdentifierEscaped(table, QSqlDriver::TableName))
864 table = stripDelimiters(table, QSqlDriver::TableName);
865
866 QSqlQuery q(createResult());
867 q.setForwardOnly(true);
868 return qGetTableInfo(q, table);
869}
870
871QVariant QSQLiteDriver::handle() const
872{
873 Q_D(const QSQLiteDriver);
874 return QVariant::fromValue(d->access);
875}
876
877QString QSQLiteDriver::escapeIdentifier(const QString &identifier, IdentifierType type) const
878{
879 Q_UNUSED(type);
880 return _q_escapeIdentifier(identifier);
881}
882
883QT_END_NAMESPACE
884