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

source code of qtbase/src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp