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

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