7#include <qcoreapplication.h>
11#include <qloggingcategory.h>
16#include <QtSql/private/qsqlcachedresult_p.h>
17#include <QtSql/private/qsqldriver_p.h>
18#include <qstringlist.h>
20#if QT_CONFIG(regularexpression)
22#include <qregularexpression.h>
24#include <QScopedValueRollback>
27# include <qt_windows.h>
35Q_DECLARE_OPAQUE_POINTER(sqlite3*)
36Q_DECLARE_METATYPE(sqlite3*)
38Q_DECLARE_OPAQUE_POINTER(sqlite3_stmt*)
39Q_DECLARE_METATYPE(sqlite3_stmt*)
45using namespace Qt::StringLiterals;
49 const QString typeName = tpName.toLower();
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;
65static QSqlError
qMakeError(sqlite3 *access,
const QString &descr, QSqlError::ErrorType type,
68 return QSqlError(descr,
69 QString(
reinterpret_cast<
const QChar *>(sqlite3_errmsg16(access))),
70 type, QString::number(errorCode));
86 bool gotoNext(QSqlCachedResult::ValueCache& row,
int idx)
override;
87 bool reset(
const QString &query)
override;
88 bool prepare(
const QString &query)
override;
101 Q_DECLARE_PUBLIC(QSQLiteDriver)
107 bool onlyPIndex =
false)
const;
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']')));
123 bool onlyPIndex)
const
125 Q_Q(
const QSQLiteDriver);
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();
138 query.exec(
"PRAGMA "_L1 + schema +
"table_xinfo ("_L1 + table + u')');
140 while (query.next()) {
141 bool isPk = query.value(5).toInt();
142 if (onlyPIndex && !isPk)
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'\'');
149 defVal = defVal.mid(1, end - 1);
152 QSqlField fld(query.value(1).toString(), QMetaType(qGetColumnType(typeName)), tableName);
153 if (isPk && (typeName ==
"integer"_L1))
156 fld.setAutoValue(
true);
157 fld.setRequired(query.value(3).toInt() != 0);
158 fld.setDefaultValue(defVal);
166 Q_DECLARE_PUBLIC(QSQLiteResult)
172 bool fetchNext(QSqlCachedResult::ValueCache &values,
int idx,
bool initialFetch);
191 q->setAt(QSql::BeforeFirstRow);
201 sqlite3_finalize(
stmt);
208 int nCols = sqlite3_column_count(
stmt);
214 for (
int i = 0; i < nCols; ++i) {
215 QString colName = QString(
reinterpret_cast<
const QChar *>(
216 sqlite3_column_name16(stmt, i))
218 const QString tableName = QString(
reinterpret_cast<
const QChar *>(
219 sqlite3_column_table_name16(
stmt, i))
222 QString typeName = QString(
reinterpret_cast<
const QChar *>(
223 sqlite3_column_decltype16(stmt, i)));
225 int stp = emptyResultset ? -1 : sqlite3_column_type(
stmt, i);
229 if (!typeName.isEmpty()) {
230 fieldType = qGetColumnType(typeName);
235 fieldType = QMetaType::Int;
238 fieldType = QMetaType::Double;
241 fieldType = QMetaType::QByteArray;
244 fieldType = QMetaType::QString;
248 fieldType = QMetaType::UnknownType;
253 QSqlField fld(colName, QMetaType(fieldType), tableName);
264 Q_ASSERT(!initialFetch);
266 for(
int i=0;i<firstRow.size();i++)
267 values[i]=firstRow[i];
274 firstRow.resize(sqlite3_column_count(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);
283 int res = sqlite3_step(
stmt);
290 if (idx < 0 && !initialFetch)
292 for (
int i = 0; i < rInf.count(); ++i) {
293 switch (sqlite3_column_type(
stmt, i)) {
295 values[i + idx] = QByteArray(
static_cast<
const char *>(
296 sqlite3_column_blob(
stmt, i)),
297 sqlite3_column_bytes(
stmt, i));
300 values[i + idx] = sqlite3_column_int64(
stmt, i);
303 switch(q->numericalPrecisionPolicy()) {
304 case QSql::LowPrecisionInt32:
305 values[i + idx] = sqlite3_column_int(
stmt, i);
307 case QSql::LowPrecisionInt64:
308 values[i + idx] = sqlite3_column_int64(
stmt, i);
310 case QSql::LowPrecisionDouble:
311 case QSql::HighPrecision:
313 values[i + idx] = sqlite3_column_double(
stmt, i);
318 values[i + idx] = QVariant(QMetaType::fromType<QString>());
321 values[i + idx] = QString(
reinterpret_cast<
const QChar *>(
322 sqlite3_column_text16(stmt, i)),
323 sqlite3_column_bytes16(stmt, i) /
sizeof(QChar));
332 q->setAt(QSql::AfterLastRow);
335 case SQLITE_CONSTRAINT:
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);
348 q->setLastError(qMakeError(drv_d_func()->access, QCoreApplication::translate(
"QSQLiteResult",
349 "Unable to fetch row"), QSqlError::ConnectionError, res));
351 q->setAt(QSql::AfterLastRow);
361 const_cast<QSQLiteDriverPrivate*>(d->drv_d_func())->results.append(
this);
368 const_cast<QSQLiteDriverPrivate*>(d->drv_d_func())->results.removeOne(
this);
374 QSqlCachedResult::virtual_hook(id, data);
387 if (!driver() || !driver()->isOpen() || driver()->isOpenError())
394 const void *pzTail =
nullptr;
395 const auto size =
int((query.size() + 1) *
sizeof(QChar));
397#if (SQLITE_VERSION_NUMBER
>= 3003011
)
398 int res = sqlite3_prepare16_v2(d->drv_d_func()->access, query.constData(), size,
401 int res = sqlite3_prepare16(d->access, query.constData(), size,
405 if (res != SQLITE_OK) {
406 setLastError(qMakeError(d->drv_d_func()->access, QCoreApplication::translate(
"QSQLiteResult",
407 "Unable to execute statement"), QSqlError::StatementError, res));
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));
423 QScopedValueRollback<QList<QVariant>> valuesScope(d->values);
424 QList<QVariant> values = d->values;
425 if (values.size() == 0)
428 for (
int i = 0; i < values.at(0).toList().size(); ++i) {
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);
445 QList<QVariant> values = boundValues();
447 d->skippedStatus =
false;
451 setLastError(QSqlError());
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));
461 int paramCount = sqlite3_bind_parameter_count(d->stmt);
462 bool paramCountIsValid = paramCount == values.size();
464#if (SQLITE_VERSION_NUMBER
>= 3003011
)
469 if (paramCount >= 1 && paramCount < values.size()) {
470 const auto countIndexes = [](
int counter,
const QList<
int> &indexList) {
471 return counter + indexList.size();
474 const int bindParamCount = std::accumulate(d->indexes.cbegin(),
479 paramCountIsValid = bindParamCount == values.size();
483 QList<QVariant> prunedValues;
484 QList<
int> handledIndexes;
485 for (
int i = 0, currentIndex = 0; i < values.size(); ++i) {
486 if (handledIndexes.contains(i))
488 const char *parameterName = sqlite3_bind_parameter_name(d->stmt, currentIndex + 1);
489 if (!parameterName) {
490 paramCountIsValid =
false;
493 const auto placeHolder = QString::fromUtf8(parameterName);
494 const auto &indexes = d->indexes.value(placeHolder);
495 handledIndexes << indexes;
496 prunedValues << values.at(indexes.first());
499 values = prunedValues;
503 if (paramCountIsValid) {
504 for (
int i = 0; i < paramCount; ++i) {
506 const QVariant &value = values.at(i);
508 if (QSqlResultPrivate::isVariantNull(value)) {
509 res = sqlite3_bind_null(d->stmt, i + 1);
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);
518 case QMetaType::Bool:
519 res = sqlite3_bind_int(d->stmt, i + 1, value.toInt());
521 case QMetaType::Double:
522 res = sqlite3_bind_double(d->stmt, i + 1, value.toDouble());
524 case QMetaType::UInt:
525 case QMetaType::LongLong:
526 res = sqlite3_bind_int64(d->stmt, i + 1, value.toLongLong());
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)),
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)),
544 case QMetaType::QString: {
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),
552 const QString str = value.toString();
554 res = sqlite3_bind_text16(d->stmt, i + 1, str.data(),
555 int(str.size()) *
sizeof(QChar),
560 if (res != SQLITE_OK) {
561 setLastError(qMakeError(d->drv_d_func()->access, QCoreApplication::translate(
"QSQLiteResult",
562 "Unable to bind parameters"), QSqlError::StatementError, res));
568 setLastError(QSqlError(QCoreApplication::translate(
"QSQLiteResult",
569 "Parameter count mismatch"), QString(), QSqlError::StatementError));
572 d->skippedStatus = d->fetchNext(d->firstRow, 0,
true);
573 if (lastError().isValid()) {
578 setSelect(!d->rInf.isEmpty());
586 return d->fetchNext(row, idx,
false);
596 Q_D(
const QSQLiteResult);
597 return sqlite3_changes(d->drv_d_func()->access);
602 Q_D(
const QSQLiteResult);
604 qint64 id = sqlite3_last_insert_rowid(d->drv_d_func()->access);
613 Q_D(
const QSQLiteResult);
614 if (!isActive() || !isSelect())
623 sqlite3_reset(d->stmt);
628 Q_D(
const QSQLiteResult);
629 return QVariant::fromValue(d->stmt);
634#if QT_CONFIG(regularexpression)
635static void _q_regexp(sqlite3_context* context,
int argc, sqlite3_value** argv)
637 if (Q_UNLIKELY(argc != 2)) {
638 sqlite3_result_int(context, 0);
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])));
647 auto cache =
static_cast<QCache<QString, QRegularExpression>*>(sqlite3_user_data(context));
648 auto regexp = cache->object(pattern);
649 const bool wasCached = regexp;
652 regexp =
new QRegularExpression(pattern, QRegularExpression::DontCaptureOption);
654 const bool found = subject.contains(*regexp);
657 cache->insert(pattern, regexp);
659 sqlite3_result_int(context,
int(found));
662static void _q_regexp_cleanup(
void *cache)
664 delete static_cast<QCache<QString, QRegularExpression>*>(cache);
668static void _q_lower(sqlite3_context* context,
int argc, sqlite3_value** argv)
670 if (Q_UNLIKELY(argc != 1)) {
671 sqlite3_result_text(context,
nullptr, 0,
nullptr);
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);
680static void _q_upper(sqlite3_context* context,
int argc, sqlite3_value** argv)
682 if (Q_UNLIKELY(argc != 1)) {
683 sqlite3_result_text(context,
nullptr, 0,
nullptr);
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);
692QSQLiteDriver::QSQLiteDriver(QObject * parent)
693 : QSqlDriver(*
new QSQLiteDriverPrivate, parent)
697QSQLiteDriver::QSQLiteDriver(sqlite3 *connection, QObject *parent)
698 : QSqlDriver(*
new QSQLiteDriverPrivate, parent)
701 d->access = connection;
707QSQLiteDriver::~QSQLiteDriver()
712bool QSQLiteDriver::hasFeature(DriverFeature f)
const
719 case PreparedQueries:
720 case PositionalPlaceholders:
723 case LowPrecisionNumbers:
724 case EventNotifications:
727 case BatchOperations:
728 case MultipleResultSets:
731 case NamedPlaceholders:
732#if (SQLITE_VERSION_NUMBER
< 3003011
)
743
744
745
746bool QSQLiteDriver::open(
const QString & db,
const QString &,
const QString &,
const QString &,
int,
const QString &conOpts)
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;
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'=')) {
774 const int nt = option.mid(1).trimmed().toInt(&ok);
778 }
else if (option ==
"QSQLITE_USE_QT_VFS"_L1) {
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) {
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) {
793#if QT_CONFIG(regularexpression)
794 else if (option.startsWith(regexpConnectOption)) {
795 option = option.mid(regexpConnectOption.size()).trimmed();
796 if (option.isEmpty()) {
798 }
else if (option.startsWith(u'=')) {
800 const int cacheSize = option.mid(1).trimmed().toInt(&ok);
804 regexpCacheSize = cacheSize;
810 qCWarning(lcSqlite,
"Unsupported option '%ls'", qUtf16Printable(option.toString()));
813 int openMode = (openReadOnlyOption ? SQLITE_OPEN_READONLY : (SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE));
814 openMode |= (sharedCache ? SQLITE_OPEN_SHAREDCACHE : SQLITE_OPEN_PRIVATECACHE);
816 openMode |= SQLITE_OPEN_URI;
818#if defined(SQLITE_OPEN_NOFOLLOW
)
819 openMode |= SQLITE_OPEN_NOFOLLOW;
821 qCWarning(lcSqlite,
"SQLITE_OPEN_NOFOLLOW not supported with the SQLite version %s", sqlite3_libversion());
825 openMode |= SQLITE_OPEN_NOMUTEX;
827 const int res = sqlite3_open_v2(db.toUtf8().constData(), &d->access, openMode, useQtVfs ?
"QtVFS" :
nullptr);
829 if (res == SQLITE_OK) {
830 sqlite3_busy_timeout(d->access, timeOut);
831 sqlite3_extended_result_codes(d->access, useExtendedResultCodes);
834#if QT_CONFIG(regularexpression)
836 auto cache =
new QCache<QString, QRegularExpression>(regexpCacheSize);
837 sqlite3_create_function_v2(d->access,
"regexp", 2, SQLITE_UTF8, cache,
839 nullptr, &_q_regexp_cleanup);
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);
850 setLastError(qMakeError(d->access, tr(
"Error opening database"),
851 QSqlError::ConnectionError, res));
855 sqlite3_close(d->access);
863void QSQLiteDriver::close()
867 for (QSQLiteResult *result : std::as_const(d->results))
868 result->d_func()->finalize();
870 if (d->access && (d->notificationid.size() > 0)) {
871 d->notificationid.clear();
872 sqlite3_update_hook(d->access,
nullptr,
nullptr);
875 const int res = sqlite3_close(d->access);
877 if (res != SQLITE_OK)
878 setLastError(qMakeError(d->access, tr(
"Error closing database"), QSqlError::ConnectionError, res));
885QSqlResult *QSQLiteDriver::createResult()
const
887 return new QSQLiteResult(
this);
890bool QSQLiteDriver::beginTransaction()
892 if (!isOpen() || isOpenError())
895 QSqlQuery q(createResult());
896 if (!q.exec(
"BEGIN"_L1)) {
897 setLastError(QSqlError(tr(
"Unable to begin transaction"),
898 q.lastError().databaseText(), QSqlError::TransactionError));
905bool QSQLiteDriver::commitTransaction()
907 if (!isOpen() || isOpenError())
910 QSqlQuery q(createResult());
911 if (!q.exec(
"COMMIT"_L1)) {
912 setLastError(QSqlError(tr(
"Unable to commit transaction"),
913 q.lastError().databaseText(), QSqlError::TransactionError));
920bool QSQLiteDriver::rollbackTransaction()
922 if (!isOpen() || isOpenError())
925 QSqlQuery q(createResult());
926 if (!q.exec(
"ROLLBACK"_L1)) {
927 setLastError(QSqlError(tr(
"Unable to rollback transaction"),
928 q.lastError().databaseText(), QSqlError::TransactionError));
935QStringList QSQLiteDriver::tables(QSql::TableType type)
const
941 QSqlQuery q(createResult());
942 q.setForwardOnly(
true);
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);
955 if (!sql.isEmpty() && q.exec(sql)) {
957 res.append(q.value(0).toString());
960 if (type & QSql::SystemTables) {
962 res.append(
"sqlite_master"_L1);
968QSqlIndex QSQLiteDriver::primaryIndex(
const QString &tablename)
const
970 Q_D(
const QSQLiteDriver);
974 QSqlQuery q(createResult());
975 q.setForwardOnly(
true);
976 return d->getTableInfo(q, tablename,
true);
979QSqlRecord QSQLiteDriver::record(
const QString &tablename)
const
981 Q_D(
const QSQLiteDriver);
985 QSqlQuery q(createResult());
986 q.setForwardOnly(
true);
987 return d->getTableInfo(q, tablename);
990QVariant QSQLiteDriver::handle()
const
992 Q_D(
const QSQLiteDriver);
993 return QVariant::fromValue(d->access);
996QString QSQLiteDriver::escapeIdentifier(
const QString &identifier, IdentifierType type)
const
998 Q_D(
const QSQLiteDriver);
999 if (identifier.isEmpty() || isIdentifierEscaped(identifier, type))
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
1012 return u'"' + identifier + u'"';
1015bool QSQLiteDriver::isIdentifierEscaped(
const QString &identifier, IdentifierType type)
const
1017 Q_D(
const QSQLiteDriver);
1019 return d->isIdentifierEscaped(QStringView{identifier});
1022QString QSQLiteDriver::stripDelimiters(
const QString &identifier, IdentifierType type)
const
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) {
1033 leftName = leftName.sliced(1).chopped(1);
1035 rightName = rightName.sliced(1).chopped(1);
1036 return leftName + u'.' + rightName;
1040 if (isIdentifierEscaped(identifier, type))
1041 return identifier.mid(1, identifier.size() - 2);
1047 sqlite3_int64 arowid)
1049 Q_UNUSED(aoperation);
1051 QSQLiteDriver *driver =
static_cast<QSQLiteDriver *>(qobj);
1053 QMetaObject::invokeMethod(driver,
"handleNotification", Qt::QueuedConnection,
1054 Q_ARG(QString, QString::fromUtf8(atablename)), Q_ARG(qint64, arowid));
1058bool QSQLiteDriver::subscribeToNotification(
const QString &name)
1062 qCWarning(lcSqlite,
"QSQLiteDriver::subscribeToNotification: Database not open.");
1066 if (d->notificationid.contains(name)) {
1067 qCWarning(lcSqlite,
"QSQLiteDriver::subscribeToNotification: Already subscribing to '%ls'.",
1068 qUtf16Printable(name));
1073 d->notificationid << name;
1074 if (d->notificationid.size() == 1)
1075 sqlite3_update_hook(d->access, &handle_sqlite_callback,
reinterpret_cast<
void *> (
this));
1080bool QSQLiteDriver::unsubscribeFromNotification(
const QString &name)
1084 qCWarning(lcSqlite,
"QSQLiteDriver::unsubscribeFromNotification: Database not open.");
1088 if (!d->notificationid.contains(name)) {
1089 qCWarning(lcSqlite,
"QSQLiteDriver::unsubscribeFromNotification: Not subscribed to '%ls'.",
1090 qUtf16Printable(name));
1094 d->notificationid.removeAll(name);
1095 if (d->notificationid.isEmpty())
1096 sqlite3_update_hook(d->access,
nullptr,
nullptr);
1101QStringList QSQLiteDriver::subscribedToNotifications()
const
1103 Q_D(
const QSQLiteDriver);
1104 return d->notificationid;
1107void QSQLiteDriver::handleNotification(
const QString &tableName, qint64 rowid)
1109 Q_D(
const QSQLiteDriver);
1110 if (d->notificationid.contains(tableName))
1111 emit notification(tableName, QSqlDriver::UnknownSource, QVariant(rowid));
1116#include "moc_qsql_sqlite_p.cpp"
QList< QSQLiteResult * > results
QSqlIndex getTableInfo(QSqlQuery &query, const QString &tableName, bool onlyPIndex=false) const
QStringList notificationid
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.
#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)