1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtSql module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qsql_sqlite_p.h"
41
42#include <qcoreapplication.h>
43#include <qdatetime.h>
44#include <qdebug.h>
45#include <qlist.h>
46#include <qsqlerror.h>
47#include <qsqlfield.h>
48#include <qsqlindex.h>
49#include <qsqlquery.h>
50#include <QtSql/private/qsqlcachedresult_p.h>
51#include <QtSql/private/qsqldriver_p.h>
52#include <qstringlist.h>
53#include <qvariant.h>
54#if QT_CONFIG(regularexpression)
55#include <qcache.h>
56#include <qregularexpression.h>
57#endif
58#include <QScopedValueRollback>
59
60#if defined Q_OS_WIN
61# include <qt_windows.h>
62#else
63# include <unistd.h>
64#endif
65
66#include <sqlite3.h>
67#include <functional>
68
69Q_DECLARE_OPAQUE_POINTER(sqlite3*)
70Q_DECLARE_METATYPE(sqlite3*)
71
72Q_DECLARE_OPAQUE_POINTER(sqlite3_stmt*)
73Q_DECLARE_METATYPE(sqlite3_stmt*)
74
75QT_BEGIN_NAMESPACE
76
77static QString _q_escapeIdentifier(const QString &identifier)
78{
79 QString res = identifier;
80 if (!identifier.isEmpty() && !identifier.startsWith(QLatin1Char('"')) && !identifier.endsWith(QLatin1Char('"'))) {
81 res.replace(QLatin1Char('"'), QLatin1String("\"\""));
82 res.prepend(QLatin1Char('"')).append(QLatin1Char('"'));
83 res.replace(QLatin1Char('.'), QLatin1String("\".\""));
84 }
85 return res;
86}
87
88static int qGetColumnType(const QString &tpName)
89{
90 const QString typeName = tpName.toLower();
91
92 if (typeName == QLatin1String("integer")
93 || typeName == QLatin1String("int"))
94 return QMetaType::Int;
95 if (typeName == QLatin1String("double")
96 || typeName == QLatin1String("float")
97 || typeName == QLatin1String("real")
98 || typeName.startsWith(QLatin1String("numeric")))
99 return QMetaType::Double;
100 if (typeName == QLatin1String("blob"))
101 return QMetaType::QByteArray;
102 if (typeName == QLatin1String("boolean")
103 || typeName == QLatin1String("bool"))
104 return QMetaType::Bool;
105 return QMetaType::QString;
106}
107
108static QSqlError qMakeError(sqlite3 *access, const QString &descr, QSqlError::ErrorType type,
109 int errorCode)
110{
111 return QSqlError(descr,
112 QString(reinterpret_cast<const QChar *>(sqlite3_errmsg16(access))),
113 type, QString::number(errorCode));
114}
115
116class QSQLiteResultPrivate;
117
118class QSQLiteResult : public QSqlCachedResult
119{
120 Q_DECLARE_PRIVATE(QSQLiteResult)
121 friend class QSQLiteDriver;
122
123public:
124 explicit QSQLiteResult(const QSQLiteDriver* db);
125 ~QSQLiteResult();
126 QVariant handle() const override;
127
128protected:
129 bool gotoNext(QSqlCachedResult::ValueCache& row, int idx) override;
130 bool reset(const QString &query) override;
131 bool prepare(const QString &query) override;
132 bool execBatch(bool arrayBind) override;
133 bool exec() override;
134 int size() override;
135 int numRowsAffected() override;
136 QVariant lastInsertId() const override;
137 QSqlRecord record() const override;
138 void detachFromResultSet() override;
139 void virtual_hook(int id, void *data) override;
140};
141
142class QSQLiteDriverPrivate : public QSqlDriverPrivate
143{
144 Q_DECLARE_PUBLIC(QSQLiteDriver)
145
146public:
147 inline QSQLiteDriverPrivate() : QSqlDriverPrivate(QSqlDriver::SQLite) {}
148 sqlite3 *access = nullptr;
149 QList<QSQLiteResult *> results;
150 QStringList notificationid;
151};
152
153
154class QSQLiteResultPrivate : public QSqlCachedResultPrivate
155{
156 Q_DECLARE_PUBLIC(QSQLiteResult)
157
158public:
159 Q_DECLARE_SQLDRIVER_PRIVATE(QSQLiteDriver)
160 using QSqlCachedResultPrivate::QSqlCachedResultPrivate;
161 void cleanup();
162 bool fetchNext(QSqlCachedResult::ValueCache &values, int idx, bool initialFetch);
163 // initializes the recordInfo and the cache
164 void initColumns(bool emptyResultset);
165 void finalize();
166
167 sqlite3_stmt *stmt = nullptr;
168 QSqlRecord rInf;
169 QList<QVariant> firstRow;
170 bool skippedStatus = false; // the status of the fetchNext() that's skipped
171 bool skipRow = false; // skip the next fetchNext()?
172};
173
174void QSQLiteResultPrivate::cleanup()
175{
176 Q_Q(QSQLiteResult);
177 finalize();
178 rInf.clear();
179 skippedStatus = false;
180 skipRow = false;
181 q->setAt(QSql::BeforeFirstRow);
182 q->setActive(false);
183 q->cleanup();
184}
185
186void QSQLiteResultPrivate::finalize()
187{
188 if (!stmt)
189 return;
190
191 sqlite3_finalize(stmt);
192 stmt = 0;
193}
194
195void QSQLiteResultPrivate::initColumns(bool emptyResultset)
196{
197 Q_Q(QSQLiteResult);
198 int nCols = sqlite3_column_count(stmt);
199 if (nCols <= 0)
200 return;
201
202 q->init(nCols);
203
204 for (int i = 0; i < nCols; ++i) {
205 QString colName = QString(reinterpret_cast<const QChar *>(
206 sqlite3_column_name16(stmt, i))
207 ).remove(QLatin1Char('"'));
208 const QString tableName = QString(reinterpret_cast<const QChar *>(
209 sqlite3_column_table_name16(stmt, i))
210 ).remove(QLatin1Char('"'));
211 // must use typeName for resolving the type to match QSqliteDriver::record
212 QString typeName = QString(reinterpret_cast<const QChar *>(
213 sqlite3_column_decltype16(stmt, i)));
214 // sqlite3_column_type is documented to have undefined behavior if the result set is empty
215 int stp = emptyResultset ? -1 : sqlite3_column_type(stmt, i);
216
217 int fieldType;
218
219 if (!typeName.isEmpty()) {
220 fieldType = qGetColumnType(typeName);
221 } else {
222 // Get the proper type for the field based on stp value
223 switch (stp) {
224 case SQLITE_INTEGER:
225 fieldType = QMetaType::Int;
226 break;
227 case SQLITE_FLOAT:
228 fieldType = QMetaType::Double;
229 break;
230 case SQLITE_BLOB:
231 fieldType = QMetaType::QByteArray;
232 break;
233 case SQLITE_TEXT:
234 fieldType = QMetaType::QString;
235 break;
236 case SQLITE_NULL:
237 default:
238 fieldType = QMetaType::UnknownType;
239 break;
240 }
241 }
242
243 QSqlField fld(colName, QMetaType(fieldType), tableName);
244 fld.setSqlType(stp);
245 rInf.append(fld);
246 }
247}
248
249bool QSQLiteResultPrivate::fetchNext(QSqlCachedResult::ValueCache &values, int idx, bool initialFetch)
250{
251 Q_Q(QSQLiteResult);
252 int res;
253 int i;
254
255 if (skipRow) {
256 // already fetched
257 Q_ASSERT(!initialFetch);
258 skipRow = false;
259 for(int i=0;i<firstRow.count();i++)
260 values[i]=firstRow[i];
261 return skippedStatus;
262 }
263 skipRow = initialFetch;
264
265 if(initialFetch) {
266 firstRow.clear();
267 firstRow.resize(sqlite3_column_count(stmt));
268 }
269
270 if (!stmt) {
271 q->setLastError(QSqlError(QCoreApplication::translate("QSQLiteResult", "Unable to fetch row"),
272 QCoreApplication::translate("QSQLiteResult", "No query"), QSqlError::ConnectionError));
273 q->setAt(QSql::AfterLastRow);
274 return false;
275 }
276 res = sqlite3_step(stmt);
277
278 switch(res) {
279 case SQLITE_ROW:
280 // check to see if should fill out columns
281 if (rInf.isEmpty())
282 // must be first call.
283 initColumns(false);
284 if (idx < 0 && !initialFetch)
285 return true;
286 for (i = 0; i < rInf.count(); ++i) {
287 switch (sqlite3_column_type(stmt, i)) {
288 case SQLITE_BLOB:
289 values[i + idx] = QByteArray(static_cast<const char *>(
290 sqlite3_column_blob(stmt, i)),
291 sqlite3_column_bytes(stmt, i));
292 break;
293 case SQLITE_INTEGER:
294 values[i + idx] = sqlite3_column_int64(stmt, i);
295 break;
296 case SQLITE_FLOAT:
297 switch(q->numericalPrecisionPolicy()) {
298 case QSql::LowPrecisionInt32:
299 values[i + idx] = sqlite3_column_int(stmt, i);
300 break;
301 case QSql::LowPrecisionInt64:
302 values[i + idx] = sqlite3_column_int64(stmt, i);
303 break;
304 case QSql::LowPrecisionDouble:
305 case QSql::HighPrecision:
306 default:
307 values[i + idx] = sqlite3_column_double(stmt, i);
308 break;
309 };
310 break;
311 case SQLITE_NULL:
312 values[i + idx] = QVariant(QMetaType::fromType<QString>());
313 break;
314 default:
315 values[i + idx] = QString(reinterpret_cast<const QChar *>(
316 sqlite3_column_text16(stmt, i)),
317 sqlite3_column_bytes16(stmt, i) / sizeof(QChar));
318 break;
319 }
320 }
321 return true;
322 case SQLITE_DONE:
323 if (rInf.isEmpty())
324 // must be first call.
325 initColumns(true);
326 q->setAt(QSql::AfterLastRow);
327 sqlite3_reset(stmt);
328 return false;
329 case SQLITE_CONSTRAINT:
330 case SQLITE_ERROR:
331 // SQLITE_ERROR is a generic error code and we must call sqlite3_reset()
332 // to get the specific error message.
333 res = sqlite3_reset(stmt);
334 q->setLastError(qMakeError(drv_d_func()->access, QCoreApplication::translate("QSQLiteResult",
335 "Unable to fetch row"), QSqlError::ConnectionError, res));
336 q->setAt(QSql::AfterLastRow);
337 return false;
338 case SQLITE_MISUSE:
339 case SQLITE_BUSY:
340 default:
341 // something wrong, don't get col info, but still return false
342 q->setLastError(qMakeError(drv_d_func()->access, QCoreApplication::translate("QSQLiteResult",
343 "Unable to fetch row"), QSqlError::ConnectionError, res));
344 sqlite3_reset(stmt);
345 q->setAt(QSql::AfterLastRow);
346 return false;
347 }
348 return false;
349}
350
351QSQLiteResult::QSQLiteResult(const QSQLiteDriver* db)
352 : QSqlCachedResult(*new QSQLiteResultPrivate(this, db))
353{
354 Q_D(QSQLiteResult);
355 const_cast<QSQLiteDriverPrivate*>(d->drv_d_func())->results.append(this);
356}
357
358QSQLiteResult::~QSQLiteResult()
359{
360 Q_D(QSQLiteResult);
361 if (d->drv_d_func())
362 const_cast<QSQLiteDriverPrivate*>(d->drv_d_func())->results.removeOne(this);
363 d->cleanup();
364}
365
366void QSQLiteResult::virtual_hook(int id, void *data)
367{
368 QSqlCachedResult::virtual_hook(id, data);
369}
370
371bool QSQLiteResult::reset(const QString &query)
372{
373 if (!prepare(query))
374 return false;
375 return exec();
376}
377
378bool QSQLiteResult::prepare(const QString &query)
379{
380 Q_D(QSQLiteResult);
381 if (!driver() || !driver()->isOpen() || driver()->isOpenError())
382 return false;
383
384 d->cleanup();
385
386 setSelect(false);
387
388 const void *pzTail = NULL;
389
390#if (SQLITE_VERSION_NUMBER >= 3003011)
391 int res = sqlite3_prepare16_v2(d->drv_d_func()->access, query.constData(), (query.size() + 1) * sizeof(QChar),
392 &d->stmt, &pzTail);
393#else
394 int res = sqlite3_prepare16(d->access, query.constData(), (query.size() + 1) * sizeof(QChar),
395 &d->stmt, &pzTail);
396#endif
397
398 if (res != SQLITE_OK) {
399 setLastError(qMakeError(d->drv_d_func()->access, QCoreApplication::translate("QSQLiteResult",
400 "Unable to execute statement"), QSqlError::StatementError, res));
401 d->finalize();
402 return false;
403 } else if (pzTail && !QString(reinterpret_cast<const QChar *>(pzTail)).trimmed().isEmpty()) {
404 setLastError(qMakeError(d->drv_d_func()->access, QCoreApplication::translate("QSQLiteResult",
405 "Unable to execute multiple statements at a time"), QSqlError::StatementError, SQLITE_MISUSE));
406 d->finalize();
407 return false;
408 }
409 return true;
410}
411
412bool QSQLiteResult::execBatch(bool arrayBind)
413{
414 Q_UNUSED(arrayBind);
415 Q_D(QSqlResult);
416 QScopedValueRollback<QList<QVariant>> valuesScope(d->values);
417 QList<QVariant> values = d->values;
418 if (values.count() == 0)
419 return false;
420
421 for (int i = 0; i < values.at(0).toList().count(); ++i) {
422 d->values.clear();
423 QScopedValueRollback<QHash<QString, QList<int>>> indexesScope(d->indexes);
424 auto it = d->indexes.constBegin();
425 while (it != d->indexes.constEnd()) {
426 bindValue(it.key(), values.at(it.value().first()).toList().at(i), QSql::In);
427 ++it;
428 }
429 if (!exec())
430 return false;
431 }
432 return true;
433}
434
435bool QSQLiteResult::exec()
436{
437 Q_D(QSQLiteResult);
438 QList<QVariant> values = boundValues();
439
440 d->skippedStatus = false;
441 d->skipRow = false;
442 d->rInf.clear();
443 clearValues();
444 setLastError(QSqlError());
445
446 int res = sqlite3_reset(d->stmt);
447 if (res != SQLITE_OK) {
448 setLastError(qMakeError(d->drv_d_func()->access, QCoreApplication::translate("QSQLiteResult",
449 "Unable to reset statement"), QSqlError::StatementError, res));
450 d->finalize();
451 return false;
452 }
453
454 int paramCount = sqlite3_bind_parameter_count(d->stmt);
455 bool paramCountIsValid = paramCount == values.count();
456
457#if (SQLITE_VERSION_NUMBER >= 3003011)
458 // In the case of the reuse of a named placeholder
459 // We need to check explicitly that paramCount is greater than or equal to 1, as sqlite
460 // can end up in a case where for virtual tables it returns 0 even though it
461 // has parameters
462 if (paramCount >= 1 && paramCount < values.count()) {
463 const auto countIndexes = [](int counter, const QList<int> &indexList) {
464 return counter + indexList.length();
465 };
466
467 const int bindParamCount = std::accumulate(d->indexes.cbegin(),
468 d->indexes.cend(),
469 0,
470 countIndexes);
471
472 paramCountIsValid = bindParamCount == values.count();
473 // When using named placeholders, it will reuse the index for duplicated
474 // placeholders. So we need to ensure the QList has only one instance of
475 // each value as SQLite will do the rest for us.
476 QList<QVariant> prunedValues;
477 QList<int> handledIndexes;
478 for (int i = 0, currentIndex = 0; i < values.size(); ++i) {
479 if (handledIndexes.contains(i))
480 continue;
481 const char *parameterName = sqlite3_bind_parameter_name(d->stmt, currentIndex + 1);
482 if (!parameterName) {
483 paramCountIsValid = false;
484 continue;
485 }
486 const auto placeHolder = QString::fromUtf8(parameterName);
487 const auto &indexes = d->indexes.value(placeHolder);
488 handledIndexes << indexes;
489 prunedValues << values.at(indexes.first());
490 ++currentIndex;
491 }
492 values = prunedValues;
493 }
494#endif
495
496 if (paramCountIsValid) {
497 for (int i = 0; i < paramCount; ++i) {
498 res = SQLITE_OK;
499 const QVariant value = values.at(i);
500
501 if (value.isNull()) {
502 res = sqlite3_bind_null(d->stmt, i + 1);
503 } else {
504 switch (value.userType()) {
505 case QMetaType::QByteArray: {
506 const QByteArray *ba = static_cast<const QByteArray*>(value.constData());
507 res = sqlite3_bind_blob(d->stmt, i + 1, ba->constData(),
508 ba->size(), SQLITE_STATIC);
509 break; }
510 case QMetaType::Int:
511 case QMetaType::Bool:
512 res = sqlite3_bind_int(d->stmt, i + 1, value.toInt());
513 break;
514 case QMetaType::Double:
515 res = sqlite3_bind_double(d->stmt, i + 1, value.toDouble());
516 break;
517 case QMetaType::UInt:
518 case QMetaType::LongLong:
519 res = sqlite3_bind_int64(d->stmt, i + 1, value.toLongLong());
520 break;
521 case QMetaType::QDateTime: {
522 const QDateTime dateTime = value.toDateTime();
523 const QString str = dateTime.toString(Qt::ISODateWithMs);
524 res = sqlite3_bind_text16(d->stmt, i + 1, str.utf16(),
525 str.size() * sizeof(ushort), SQLITE_TRANSIENT);
526 break;
527 }
528 case QMetaType::QTime: {
529 const QTime time = value.toTime();
530 const QString str = time.toString(u"hh:mm:ss.zzz");
531 res = sqlite3_bind_text16(d->stmt, i + 1, str.utf16(),
532 str.size() * sizeof(ushort), SQLITE_TRANSIENT);
533 break;
534 }
535 case QMetaType::QString: {
536 // lifetime of string == lifetime of its qvariant
537 const QString *str = static_cast<const QString*>(value.constData());
538 res = sqlite3_bind_text16(d->stmt, i + 1, str->utf16(),
539 (str->size()) * sizeof(QChar), SQLITE_STATIC);
540 break; }
541 default: {
542 QString str = value.toString();
543 // SQLITE_TRANSIENT makes sure that sqlite buffers the data
544 res = sqlite3_bind_text16(d->stmt, i + 1, str.utf16(),
545 (str.size()) * sizeof(QChar), SQLITE_TRANSIENT);
546 break; }
547 }
548 }
549 if (res != SQLITE_OK) {
550 setLastError(qMakeError(d->drv_d_func()->access, QCoreApplication::translate("QSQLiteResult",
551 "Unable to bind parameters"), QSqlError::StatementError, res));
552 d->finalize();
553 return false;
554 }
555 }
556 } else {
557 setLastError(QSqlError(QCoreApplication::translate("QSQLiteResult",
558 "Parameter count mismatch"), QString(), QSqlError::StatementError));
559 return false;
560 }
561 d->skippedStatus = d->fetchNext(d->firstRow, 0, true);
562 if (lastError().isValid()) {
563 setSelect(false);
564 setActive(false);
565 return false;
566 }
567 setSelect(!d->rInf.isEmpty());
568 setActive(true);
569 return true;
570}
571
572bool QSQLiteResult::gotoNext(QSqlCachedResult::ValueCache& row, int idx)
573{
574 Q_D(QSQLiteResult);
575 return d->fetchNext(row, idx, false);
576}
577
578int QSQLiteResult::size()
579{
580 return -1;
581}
582
583int QSQLiteResult::numRowsAffected()
584{
585 Q_D(const QSQLiteResult);
586 return sqlite3_changes(d->drv_d_func()->access);
587}
588
589QVariant QSQLiteResult::lastInsertId() const
590{
591 Q_D(const QSQLiteResult);
592 if (isActive()) {
593 qint64 id = sqlite3_last_insert_rowid(d->drv_d_func()->access);
594 if (id)
595 return id;
596 }
597 return QVariant();
598}
599
600QSqlRecord QSQLiteResult::record() const
601{
602 Q_D(const QSQLiteResult);
603 if (!isActive() || !isSelect())
604 return QSqlRecord();
605 return d->rInf;
606}
607
608void QSQLiteResult::detachFromResultSet()
609{
610 Q_D(QSQLiteResult);
611 if (d->stmt)
612 sqlite3_reset(d->stmt);
613}
614
615QVariant QSQLiteResult::handle() const
616{
617 Q_D(const QSQLiteResult);
618 return QVariant::fromValue(d->stmt);
619}
620
621/////////////////////////////////////////////////////////
622
623#if QT_CONFIG(regularexpression)
624static void _q_regexp(sqlite3_context* context, int argc, sqlite3_value** argv)
625{
626 if (Q_UNLIKELY(argc != 2)) {
627 sqlite3_result_int(context, 0);
628 return;
629 }
630
631 const QString pattern = QString::fromUtf8(
632 reinterpret_cast<const char*>(sqlite3_value_text(argv[0])));
633 const QString subject = QString::fromUtf8(
634 reinterpret_cast<const char*>(sqlite3_value_text(argv[1])));
635
636 auto cache = static_cast<QCache<QString, QRegularExpression>*>(sqlite3_user_data(context));
637 auto regexp = cache->object(pattern);
638 const bool wasCached = regexp;
639
640 if (!wasCached)
641 regexp = new QRegularExpression(pattern, QRegularExpression::DontCaptureOption);
642
643 const bool found = subject.contains(*regexp);
644
645 if (!wasCached)
646 cache->insert(pattern, regexp);
647
648 sqlite3_result_int(context, int(found));
649}
650
651static void _q_regexp_cleanup(void *cache)
652{
653 delete static_cast<QCache<QString, QRegularExpression>*>(cache);
654}
655#endif
656
657QSQLiteDriver::QSQLiteDriver(QObject * parent)
658 : QSqlDriver(*new QSQLiteDriverPrivate, parent)
659{
660}
661
662QSQLiteDriver::QSQLiteDriver(sqlite3 *connection, QObject *parent)
663 : QSqlDriver(*new QSQLiteDriverPrivate, parent)
664{
665 Q_D(QSQLiteDriver);
666 d->access = connection;
667 setOpen(true);
668 setOpenError(false);
669}
670
671
672QSQLiteDriver::~QSQLiteDriver()
673{
674 close();
675}
676
677bool QSQLiteDriver::hasFeature(DriverFeature f) const
678{
679 switch (f) {
680 case BLOB:
681 case Transactions:
682 case Unicode:
683 case LastInsertId:
684 case PreparedQueries:
685 case PositionalPlaceholders:
686 case SimpleLocking:
687 case FinishQuery:
688 case LowPrecisionNumbers:
689 case EventNotifications:
690 return true;
691 case QuerySize:
692 case BatchOperations:
693 case MultipleResultSets:
694 case CancelQuery:
695 return false;
696 case NamedPlaceholders:
697#if (SQLITE_VERSION_NUMBER < 3003011)
698 return false;
699#else
700 return true;
701#endif
702
703 }
704 return false;
705}
706
707/*
708 SQLite dbs have no user name, passwords, hosts or ports.
709 just file names.
710*/
711bool QSQLiteDriver::open(const QString & db, const QString &, const QString &, const QString &, int, const QString &conOpts)
712{
713 Q_D(QSQLiteDriver);
714 if (isOpen())
715 close();
716
717
718 int timeOut = 5000;
719 bool sharedCache = false;
720 bool openReadOnlyOption = false;
721 bool openUriOption = false;
722#if QT_CONFIG(regularexpression)
723 static const QLatin1String regexpConnectOption = QLatin1String("QSQLITE_ENABLE_REGEXP");
724 bool defineRegexp = false;
725 int regexpCacheSize = 25;
726#endif
727
728 const auto opts = QStringView{conOpts}.split(QLatin1Char(';'));
729 for (auto option : opts) {
730 option = option.trimmed();
731 if (option.startsWith(QLatin1String("QSQLITE_BUSY_TIMEOUT"))) {
732 option = option.mid(20).trimmed();
733 if (option.startsWith(QLatin1Char('='))) {
734 bool ok;
735 const int nt = option.mid(1).trimmed().toInt(&ok);
736 if (ok)
737 timeOut = nt;
738 }
739 } else if (option == QLatin1String("QSQLITE_OPEN_READONLY")) {
740 openReadOnlyOption = true;
741 } else if (option == QLatin1String("QSQLITE_OPEN_URI")) {
742 openUriOption = true;
743 } else if (option == QLatin1String("QSQLITE_ENABLE_SHARED_CACHE")) {
744 sharedCache = true;
745 }
746#if QT_CONFIG(regularexpression)
747 else if (option.startsWith(regexpConnectOption)) {
748 option = option.mid(regexpConnectOption.size()).trimmed();
749 if (option.isEmpty()) {
750 defineRegexp = true;
751 } else if (option.startsWith(QLatin1Char('='))) {
752 bool ok = false;
753 const int cacheSize = option.mid(1).trimmed().toInt(&ok);
754 if (ok) {
755 defineRegexp = true;
756 if (cacheSize > 0)
757 regexpCacheSize = cacheSize;
758 }
759 }
760 }
761#endif
762 }
763
764 int openMode = (openReadOnlyOption ? SQLITE_OPEN_READONLY : (SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE));
765 openMode |= (sharedCache ? SQLITE_OPEN_SHAREDCACHE : SQLITE_OPEN_PRIVATECACHE);
766 if (openUriOption)
767 openMode |= SQLITE_OPEN_URI;
768
769 openMode |= SQLITE_OPEN_NOMUTEX;
770
771 const int res = sqlite3_open_v2(db.toUtf8().constData(), &d->access, openMode, NULL);
772
773 if (res == SQLITE_OK) {
774 sqlite3_busy_timeout(d->access, timeOut);
775 setOpen(true);
776 setOpenError(false);
777#if QT_CONFIG(regularexpression)
778 if (defineRegexp) {
779 auto cache = new QCache<QString, QRegularExpression>(regexpCacheSize);
780 sqlite3_create_function_v2(d->access, "regexp", 2, SQLITE_UTF8, cache, &_q_regexp, NULL,
781 NULL, &_q_regexp_cleanup);
782 }
783#endif
784 return true;
785 } else {
786 setLastError(qMakeError(d->access, tr("Error opening database"),
787 QSqlError::ConnectionError, res));
788 setOpenError(true);
789
790 if (d->access) {
791 sqlite3_close(d->access);
792 d->access = 0;
793 }
794
795 return false;
796 }
797}
798
799void QSQLiteDriver::close()
800{
801 Q_D(QSQLiteDriver);
802 if (isOpen()) {
803 for (QSQLiteResult *result : qAsConst(d->results))
804 result->d_func()->finalize();
805
806 if (d->access && (d->notificationid.count() > 0)) {
807 d->notificationid.clear();
808 sqlite3_update_hook(d->access, NULL, NULL);
809 }
810
811 const int res = sqlite3_close(d->access);
812
813 if (res != SQLITE_OK)
814 setLastError(qMakeError(d->access, tr("Error closing database"), QSqlError::ConnectionError, res));
815 d->access = 0;
816 setOpen(false);
817 setOpenError(false);
818 }
819}
820
821QSqlResult *QSQLiteDriver::createResult() const
822{
823 return new QSQLiteResult(this);
824}
825
826bool QSQLiteDriver::beginTransaction()
827{
828 if (!isOpen() || isOpenError())
829 return false;
830
831 QSqlQuery q(createResult());
832 if (!q.exec(QLatin1String("BEGIN"))) {
833 setLastError(QSqlError(tr("Unable to begin transaction"),
834 q.lastError().databaseText(), QSqlError::TransactionError));
835 return false;
836 }
837
838 return true;
839}
840
841bool QSQLiteDriver::commitTransaction()
842{
843 if (!isOpen() || isOpenError())
844 return false;
845
846 QSqlQuery q(createResult());
847 if (!q.exec(QLatin1String("COMMIT"))) {
848 setLastError(QSqlError(tr("Unable to commit transaction"),
849 q.lastError().databaseText(), QSqlError::TransactionError));
850 return false;
851 }
852
853 return true;
854}
855
856bool QSQLiteDriver::rollbackTransaction()
857{
858 if (!isOpen() || isOpenError())
859 return false;
860
861 QSqlQuery q(createResult());
862 if (!q.exec(QLatin1String("ROLLBACK"))) {
863 setLastError(QSqlError(tr("Unable to rollback transaction"),
864 q.lastError().databaseText(), QSqlError::TransactionError));
865 return false;
866 }
867
868 return true;
869}
870
871QStringList QSQLiteDriver::tables(QSql::TableType type) const
872{
873 QStringList res;
874 if (!isOpen())
875 return res;
876
877 QSqlQuery q(createResult());
878 q.setForwardOnly(true);
879
880 QString sql = QLatin1String("SELECT name FROM sqlite_master WHERE %1 "
881 "UNION ALL SELECT name FROM sqlite_temp_master WHERE %1");
882 if ((type & QSql::Tables) && (type & QSql::Views))
883 sql = sql.arg(QLatin1String("type='table' OR type='view'"));
884 else if (type & QSql::Tables)
885 sql = sql.arg(QLatin1String("type='table'"));
886 else if (type & QSql::Views)
887 sql = sql.arg(QLatin1String("type='view'"));
888 else
889 sql.clear();
890
891 if (!sql.isEmpty() && q.exec(sql)) {
892 while(q.next())
893 res.append(q.value(0).toString());
894 }
895
896 if (type & QSql::SystemTables) {
897 // there are no internal tables beside this one:
898 res.append(QLatin1String("sqlite_master"));
899 }
900
901 return res;
902}
903
904static QSqlIndex qGetTableInfo(QSqlQuery &q, const QString &tableName, bool onlyPIndex = false)
905{
906 QString schema;
907 QString table(tableName);
908 int indexOfSeparator = tableName.indexOf(QLatin1Char('.'));
909 if (indexOfSeparator > -1) {
910 schema = tableName.left(indexOfSeparator).append(QLatin1Char('.'));
911 table = tableName.mid(indexOfSeparator + 1);
912 }
913 q.exec(QLatin1String("PRAGMA ") + schema + QLatin1String("table_info (") + _q_escapeIdentifier(table) + QLatin1Char(')'));
914
915 QSqlIndex ind;
916 while (q.next()) {
917 bool isPk = q.value(5).toInt();
918 if (onlyPIndex && !isPk)
919 continue;
920 QString typeName = q.value(2).toString().toLower();
921 QString defVal = q.value(4).toString();
922 if (!defVal.isEmpty() && defVal.at(0) == QLatin1Char('\'')) {
923 const int end = defVal.lastIndexOf(QLatin1Char('\''));
924 if (end > 0)
925 defVal = defVal.mid(1, end - 1);
926 }
927
928 QSqlField fld(q.value(1).toString(), QMetaType(qGetColumnType(typeName)), tableName);
929 if (isPk && (typeName == QLatin1String("integer")))
930 // INTEGER PRIMARY KEY fields are auto-generated in sqlite
931 // INT PRIMARY KEY is not the same as INTEGER PRIMARY KEY!
932 fld.setAutoValue(true);
933 fld.setRequired(q.value(3).toInt() != 0);
934 fld.setDefaultValue(defVal);
935 ind.append(fld);
936 }
937 return ind;
938}
939
940QSqlIndex QSQLiteDriver::primaryIndex(const QString &tblname) const
941{
942 if (!isOpen())
943 return QSqlIndex();
944
945 QString table = tblname;
946 if (isIdentifierEscaped(table, QSqlDriver::TableName))
947 table = stripDelimiters(table, QSqlDriver::TableName);
948
949 QSqlQuery q(createResult());
950 q.setForwardOnly(true);
951 return qGetTableInfo(q, table, true);
952}
953
954QSqlRecord QSQLiteDriver::record(const QString &tbl) const
955{
956 if (!isOpen())
957 return QSqlRecord();
958
959 QString table = tbl;
960 if (isIdentifierEscaped(table, QSqlDriver::TableName))
961 table = stripDelimiters(table, QSqlDriver::TableName);
962
963 QSqlQuery q(createResult());
964 q.setForwardOnly(true);
965 return qGetTableInfo(q, table);
966}
967
968QVariant QSQLiteDriver::handle() const
969{
970 Q_D(const QSQLiteDriver);
971 return QVariant::fromValue(d->access);
972}
973
974QString QSQLiteDriver::escapeIdentifier(const QString &identifier, IdentifierType type) const
975{
976 Q_UNUSED(type);
977 return _q_escapeIdentifier(identifier);
978}
979
980static void handle_sqlite_callback(void *qobj,int aoperation, char const *adbname, char const *atablename,
981 sqlite3_int64 arowid)
982{
983 Q_UNUSED(aoperation);
984 Q_UNUSED(adbname);
985 QSQLiteDriver *driver = static_cast<QSQLiteDriver *>(qobj);
986 if (driver) {
987 QMetaObject::invokeMethod(driver, "handleNotification", Qt::QueuedConnection,
988 Q_ARG(QString, QString::fromUtf8(atablename)), Q_ARG(qint64, arowid));
989 }
990}
991
992bool QSQLiteDriver::subscribeToNotification(const QString &name)
993{
994 Q_D(QSQLiteDriver);
995 if (!isOpen()) {
996 qWarning("Database not open.");
997 return false;
998 }
999
1000 if (d->notificationid.contains(name)) {
1001 qWarning("Already subscribing to '%s'.", qPrintable(name));
1002 return false;
1003 }
1004
1005 //sqlite supports only one notification callback, so only the first is registered
1006 d->notificationid << name;
1007 if (d->notificationid.count() == 1)
1008 sqlite3_update_hook(d->access, &handle_sqlite_callback, reinterpret_cast<void *> (this));
1009
1010 return true;
1011}
1012
1013bool QSQLiteDriver::unsubscribeFromNotification(const QString &name)
1014{
1015 Q_D(QSQLiteDriver);
1016 if (!isOpen()) {
1017 qWarning("Database not open.");
1018 return false;
1019 }
1020
1021 if (!d->notificationid.contains(name)) {
1022 qWarning("Not subscribed to '%s'.", qPrintable(name));
1023 return false;
1024 }
1025
1026 d->notificationid.removeAll(name);
1027 if (d->notificationid.isEmpty())
1028 sqlite3_update_hook(d->access, NULL, NULL);
1029
1030 return true;
1031}
1032
1033QStringList QSQLiteDriver::subscribedToNotifications() const
1034{
1035 Q_D(const QSQLiteDriver);
1036 return d->notificationid;
1037}
1038
1039void QSQLiteDriver::handleNotification(const QString &tableName, qint64 rowid)
1040{
1041 Q_D(const QSQLiteDriver);
1042 if (d->notificationid.contains(tableName))
1043 emit notification(tableName, QSqlDriver::UnknownSource, QVariant(rowid));
1044}
1045
1046QT_END_NAMESPACE
1047