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