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 if (tpName.compare(
"integer"_L1, Qt::CaseInsensitive) == 0 || tpName.compare(
"int"_L1, Qt::CaseInsensitive) == 0)
50 return QMetaType::Int;
51 if (tpName.compare(
"double"_L1, Qt::CaseInsensitive) == 0
52 || tpName.compare(
"float"_L1, Qt::CaseInsensitive) == 0
53 || tpName.compare(
"real"_L1, Qt::CaseInsensitive) == 0
54 || tpName.startsWith(
"numeric"_L1, Qt::CaseInsensitive))
55 return QMetaType::Double;
56 if (tpName.compare(
"blob"_L1, Qt::CaseInsensitive) == 0)
57 return QMetaType::QByteArray;
58 if (tpName.compare(
"boolean"_L1, Qt::CaseInsensitive) == 0 || tpName.compare(
"bool"_L1, Qt::CaseInsensitive) == 0)
59 return QMetaType::Bool;
60 return QMetaType::QString;
63static QSqlError
qMakeError(sqlite3 *access,
const QString &descr, QSqlError::ErrorType type,
66 return QSqlError(descr,
67 QString(
reinterpret_cast<
const QChar *>(sqlite3_errmsg16(access))),
68 type, QString::number(errorCode));
84 bool gotoNext(QSqlCachedResult::ValueCache& row,
int idx)
override;
85 bool reset(
const QString &query)
override;
86 bool prepare(
const QString &query)
override;
99 Q_DECLARE_PUBLIC(QSQLiteDriver)
105 bool onlyPIndex =
false)
const;
114 return identifier.size() > 2
115 && ((identifier.startsWith(u'"') && identifier.endsWith(u'"'))
116 || (identifier.startsWith(u'`') && identifier.endsWith(u'`'))
117 || (identifier.startsWith(u'[') && identifier.endsWith(u']')));
121 bool onlyPIndex)
const
123 Q_Q(
const QSQLiteDriver);
125 QString table = q->escapeIdentifier(tableName, QSqlDriver::TableName);
126 const auto indexOfSeparator = table.indexOf(u'.');
127 if (indexOfSeparator > -1) {
128 auto leftName = QStringView{table}.first(indexOfSeparator);
129 auto rightName = QStringView{table}.sliced(indexOfSeparator + 1);
130 if (isIdentifierEscaped(leftName) && isIdentifierEscaped(rightName)) {
131 schema = leftName.toString() + u'.';
132 table = rightName.toString();
136 query.exec(
"PRAGMA "_L1 + schema +
"table_xinfo ("_L1 + table + u')');
138 while (query.next()) {
139 bool isPk = query.value(5).toInt();
140 if (onlyPIndex && !isPk)
142 QString typeName = query.value(2).toString().toLower();
143 QString defVal = query.value(4).toString();
144 if (!defVal.isEmpty() && defVal.at(0) == u'\'') {
145 const int end = defVal.lastIndexOf(u'\'');
147 defVal = defVal.mid(1, end - 1);
150 QSqlField fld(query.value(1).toString(), QMetaType(qGetColumnType(typeName)), tableName);
151 if (isPk && (typeName ==
"integer"_L1))
154 fld.setAutoValue(
true);
155 fld.setRequired(query.value(3).toInt() != 0);
156 fld.setDefaultValue(defVal);
164 Q_DECLARE_PUBLIC(QSQLiteResult)
170 bool fetchNext(QSqlCachedResult::ValueCache &values,
int idx,
bool initialFetch);
189 q->setAt(QSql::BeforeFirstRow);
199 sqlite3_finalize(
stmt);
206 int nCols = sqlite3_column_count(
stmt);
212 for (
int i = 0; i < nCols; ++i) {
213 QString colName = QString(
reinterpret_cast<
const QChar *>(
214 sqlite3_column_name16(stmt, i))
216 const QString tableName = QString(
reinterpret_cast<
const QChar *>(
217 sqlite3_column_table_name16(
stmt, i))
220 QString typeName = QString(
reinterpret_cast<
const QChar *>(
221 sqlite3_column_decltype16(stmt, i)));
223 int stp = emptyResultset ? -1 : sqlite3_column_type(
stmt, i);
227 if (!typeName.isEmpty()) {
228 fieldType = qGetColumnType(typeName);
233 fieldType = QMetaType::Int;
236 fieldType = QMetaType::Double;
239 fieldType = QMetaType::QByteArray;
242 fieldType = QMetaType::QString;
246 fieldType = QMetaType::UnknownType;
251 QSqlField fld(colName, QMetaType(fieldType), tableName);
262 Q_ASSERT(!initialFetch);
264 for(
int i=0;i<firstRow.size();i++)
265 values[i]=firstRow[i];
272 firstRow.resize(sqlite3_column_count(stmt));
276 q->setLastError(QSqlError(QCoreApplication::translate(
"QSQLiteResult",
"Unable to fetch row"),
277 QCoreApplication::translate(
"QSQLiteResult",
"No query"), QSqlError::ConnectionError));
278 q->setAt(QSql::AfterLastRow);
281 int res = sqlite3_step(
stmt);
288 if (idx < 0 && !initialFetch)
290 for (
int i = 0; i < rInf.count(); ++i) {
291 switch (sqlite3_column_type(
stmt, i)) {
293 values[i + idx] = QByteArray(
static_cast<
const char *>(
294 sqlite3_column_blob(
stmt, i)),
295 sqlite3_column_bytes(
stmt, i));
298 values[i + idx] = sqlite3_column_int64(
stmt, i);
301 switch(q->numericalPrecisionPolicy()) {
302 case QSql::LowPrecisionInt32:
303 values[i + idx] = sqlite3_column_int(
stmt, i);
305 case QSql::LowPrecisionInt64:
306 values[i + idx] = sqlite3_column_int64(
stmt, i);
308 case QSql::LowPrecisionDouble:
309 case QSql::HighPrecision:
311 values[i + idx] = sqlite3_column_double(
stmt, i);
316 values[i + idx] = QVariant(QMetaType::fromType<QString>());
319 values[i + idx] = QString(
reinterpret_cast<
const QChar *>(
320 sqlite3_column_text16(
stmt, i)),
321 sqlite3_column_bytes16(stmt, i) /
sizeof(QChar));
330 q->setAt(QSql::AfterLastRow);
333 case SQLITE_CONSTRAINT:
337 res = sqlite3_reset(
stmt);
338 q->setLastError(qMakeError(drv_d_func()->access, QCoreApplication::translate(
"QSQLiteResult",
339 "Unable to fetch row"), QSqlError::ConnectionError, res));
340 q->setAt(QSql::AfterLastRow);
346 q->setLastError(qMakeError(drv_d_func()->access, QCoreApplication::translate(
"QSQLiteResult",
347 "Unable to fetch row"), QSqlError::ConnectionError, res));
349 q->setAt(QSql::AfterLastRow);
359 const_cast<QSQLiteDriverPrivate*>(d->drv_d_func())->results.append(
this);
366 const_cast<QSQLiteDriverPrivate*>(d->drv_d_func())->results.removeOne(
this);
372 QSqlCachedResult::virtual_hook(id, data);
385 if (!driver() || !driver()->isOpen() || driver()->isOpenError())
392 const void *pzTail =
nullptr;
393 const auto size =
int((query.size() + 1) *
sizeof(QChar));
395#if (SQLITE_VERSION_NUMBER
>= 3003011
)
396 int res = sqlite3_prepare16_v2(d->drv_d_func()->access, query.constData(), size,
399 int res = sqlite3_prepare16(d->access, query.constData(), size,
403 if (res != SQLITE_OK) {
404 setLastError(qMakeError(d->drv_d_func()->access, QCoreApplication::translate(
"QSQLiteResult",
405 "Unable to execute statement"), QSqlError::StatementError, res));
408 }
else if (pzTail && !QString(
reinterpret_cast<
const QChar *>(pzTail)).trimmed().isEmpty()) {
409 setLastError(qMakeError(d->drv_d_func()->access, QCoreApplication::translate(
"QSQLiteResult",
410 "Unable to execute multiple statements at a time"), QSqlError::StatementError, SQLITE_MISUSE));
421 QScopedValueRollback<QList<QVariant>> valuesScope(d->values);
422 QList<QVariant> values = d->values;
423 if (values.size() == 0)
426 for (
int i = 0; i < values.at(0).toList().size(); ++i) {
428 QScopedValueRollback<QHash<QString, QList<
int>>> indexesScope(d->indexes);
429 auto it = d->indexes.constBegin();
430 while (it != d->indexes.constEnd()) {
431 bindValue(it.key(), values.at(it.value().first()).toList().at(i), QSql::In);
443 QList<QVariant> values = boundValues();
445 d->skippedStatus =
false;
449 setLastError(QSqlError());
451 int res = sqlite3_reset(d->stmt);
452 if (res != SQLITE_OK) {
453 setLastError(qMakeError(d->drv_d_func()->access, QCoreApplication::translate(
"QSQLiteResult",
454 "Unable to reset statement"), QSqlError::StatementError, res));
459 int paramCount = sqlite3_bind_parameter_count(d->stmt);
460 bool paramCountIsValid = paramCount == values.size();
462#if (SQLITE_VERSION_NUMBER
>= 3003011
)
467 if (paramCount >= 1 && paramCount < values.size()) {
468 const auto countIndexes = [](
int counter,
const QList<
int> &indexList) {
469 return counter + indexList.size();
472 const int bindParamCount = std::accumulate(d->indexes.cbegin(),
477 paramCountIsValid = bindParamCount == values.size();
481 QList<QVariant> prunedValues;
482 QList<
int> handledIndexes;
483 for (
int i = 0, currentIndex = 0; i < values.size(); ++i) {
484 if (handledIndexes.contains(i))
486 const char *parameterName = sqlite3_bind_parameter_name(d->stmt, currentIndex + 1);
487 if (!parameterName) {
488 paramCountIsValid =
false;
491 const auto placeHolder = QString::fromUtf8(parameterName);
492 const auto &indexes = d->indexes.value(placeHolder);
493 handledIndexes << indexes;
494 prunedValues << values.at(indexes.first());
497 values = prunedValues;
501 if (paramCountIsValid) {
502 for (
int i = 0; i < paramCount; ++i) {
504 const QVariant &value = values.at(i);
506 if (QSqlResultPrivate::isVariantNull(value)) {
507 res = sqlite3_bind_null(d->stmt, i + 1);
509 switch (value.userType()) {
510 case QMetaType::QByteArray: {
511 const QByteArray *ba =
static_cast<
const QByteArray*>(value.constData());
512 res = sqlite3_bind_blob(d->stmt, i + 1, ba->constData(),
513 ba->size(), SQLITE_STATIC);
516 case QMetaType::Bool:
517 res = sqlite3_bind_int(d->stmt, i + 1, value.toInt());
519 case QMetaType::Double:
520 res = sqlite3_bind_double(d->stmt, i + 1, value.toDouble());
522 case QMetaType::UInt:
523 case QMetaType::LongLong:
524 res = sqlite3_bind_int64(d->stmt, i + 1, value.toLongLong());
526 case QMetaType::QDateTime: {
527 const QDateTime dateTime = value.toDateTime();
528 const QString str = dateTime.toString(Qt::ISODateWithMs);
529 res = sqlite3_bind_text16(d->stmt, i + 1, str.data(),
530 int(str.size() *
sizeof(ushort)),
534 case QMetaType::QTime: {
535 const QTime time = value.toTime();
536 const QString str = time.toString(u"hh:mm:ss.zzz");
537 res = sqlite3_bind_text16(d->stmt, i + 1, str.data(),
538 int(str.size() *
sizeof(ushort)),
542 case QMetaType::QString: {
544 const QString *str =
static_cast<
const QString*>(value.constData());
545 res = sqlite3_bind_text16(d->stmt, i + 1, str->unicode(),
546 int(str->size()) *
sizeof(QChar),
550 const QString str = value.toString();
552 res = sqlite3_bind_text16(d->stmt, i + 1, str.data(),
553 int(str.size()) *
sizeof(QChar),
558 if (res != SQLITE_OK) {
559 setLastError(qMakeError(d->drv_d_func()->access, QCoreApplication::translate(
"QSQLiteResult",
560 "Unable to bind parameters"), QSqlError::StatementError, res));
566 setLastError(QSqlError(QCoreApplication::translate(
"QSQLiteResult",
567 "Parameter count mismatch"), QString(), QSqlError::StatementError));
570 d->skippedStatus = d->fetchNext(d->firstRow, 0,
true);
571 if (lastError().isValid()) {
576 setSelect(!d->rInf.isEmpty());
584 return d->fetchNext(row, idx,
false);
594 Q_D(
const QSQLiteResult);
595 return sqlite3_changes(d->drv_d_func()->access);
600 Q_D(
const QSQLiteResult);
602 qint64 id = sqlite3_last_insert_rowid(d->drv_d_func()->access);
611 Q_D(
const QSQLiteResult);
612 if (!isActive() || !isSelect())
621 sqlite3_reset(d->stmt);
626 Q_D(
const QSQLiteResult);
627 return QVariant::fromValue(d->stmt);
632#if QT_CONFIG(regularexpression)
633static void _q_regexp(sqlite3_context* context,
int argc, sqlite3_value** argv)
635 if (Q_UNLIKELY(argc != 2)) {
636 sqlite3_result_int(context, 0);
640 const QString pattern = QString::fromUtf8(
641 reinterpret_cast<
const char*>(sqlite3_value_text(argv[0])));
642 const QString subject = QString::fromUtf8(
643 reinterpret_cast<
const char*>(sqlite3_value_text(argv[1])));
645 auto cache =
static_cast<QCache<QString, QRegularExpression>*>(sqlite3_user_data(context));
646 auto regexp = cache->object(pattern);
647 const bool wasCached = regexp;
650 regexp =
new QRegularExpression(pattern, QRegularExpression::DontCaptureOption);
652 const bool found = subject.contains(*regexp);
655 cache->insert(pattern, regexp);
657 sqlite3_result_int(context,
int(found));
660static void _q_regexp_cleanup(
void *cache)
662 delete static_cast<QCache<QString, QRegularExpression>*>(cache);
666static void _q_lower(sqlite3_context* context,
int argc, sqlite3_value** argv)
668 if (Q_UNLIKELY(argc != 1)) {
669 sqlite3_result_text(context,
nullptr, 0,
nullptr);
672 const QString lower = QString::fromUtf8(
673 reinterpret_cast<
const char*>(sqlite3_value_text(argv[0]))).toLower();
674 const QByteArray ba = lower.toUtf8();
675 sqlite3_result_text(context, ba.data(), ba.size(), SQLITE_TRANSIENT);
678static void _q_upper(sqlite3_context* context,
int argc, sqlite3_value** argv)
680 if (Q_UNLIKELY(argc != 1)) {
681 sqlite3_result_text(context,
nullptr, 0,
nullptr);
684 const QString upper = QString::fromUtf8(
685 reinterpret_cast<
const char*>(sqlite3_value_text(argv[0]))).toUpper();
686 const QByteArray ba = upper.toUtf8();
687 sqlite3_result_text(context, ba.data(), ba.size(), SQLITE_TRANSIENT);
690QSQLiteDriver::QSQLiteDriver(QObject * parent)
691 : QSqlDriver(*
new QSQLiteDriverPrivate, parent)
695QSQLiteDriver::QSQLiteDriver(sqlite3 *connection, QObject *parent)
696 : QSqlDriver(*
new QSQLiteDriverPrivate, parent)
699 d->access = connection;
705QSQLiteDriver::~QSQLiteDriver()
710bool QSQLiteDriver::hasFeature(DriverFeature f)
const
717 case PreparedQueries:
718 case PositionalPlaceholders:
721 case LowPrecisionNumbers:
722 case EventNotifications:
725 case BatchOperations:
726 case MultipleResultSets:
729 case NamedPlaceholders:
730#if (SQLITE_VERSION_NUMBER
< 3003011
)
741
742
743
744bool QSQLiteDriver::open(
const QString & db,
const QString &,
const QString &,
const QString &,
int,
const QString &conOpts)
752 bool sharedCache =
false;
753 bool openReadOnlyOption =
false;
754 bool openUriOption =
false;
755 bool useExtendedResultCodes =
true;
756 bool useQtVfs =
false;
757 bool useQtCaseFolding =
false;
758 bool openNoFollow =
false;
759#if QT_CONFIG(regularexpression)
760 static const auto regexpConnectOption =
"QSQLITE_ENABLE_REGEXP"_L1;
761 bool defineRegexp =
false;
762 int regexpCacheSize = 25;
765 const auto opts = QStringView{conOpts}.split(u';', Qt::SkipEmptyParts);
766 for (
auto option : opts) {
767 option = option.trimmed();
768 if (option.startsWith(
"QSQLITE_BUSY_TIMEOUT"_L1)) {
769 option = option.mid(20).trimmed();
770 if (option.startsWith(u'=')) {
772 const int nt = option.mid(1).trimmed().toInt(&ok);
776 }
else if (option ==
"QSQLITE_USE_QT_VFS"_L1) {
778 }
else if (option ==
"QSQLITE_OPEN_READONLY"_L1) {
779 openReadOnlyOption =
true;
780 }
else if (option ==
"QSQLITE_OPEN_URI"_L1) {
781 openUriOption =
true;
782 }
else if (option ==
"QSQLITE_ENABLE_SHARED_CACHE"_L1) {
784 }
else if (option ==
"QSQLITE_NO_USE_EXTENDED_RESULT_CODES"_L1) {
785 useExtendedResultCodes =
false;
786 }
else if (option ==
"QSQLITE_ENABLE_NON_ASCII_CASE_FOLDING"_L1) {
787 useQtCaseFolding =
true;
788 }
else if (option ==
"QSQLITE_OPEN_NOFOLLOW"_L1) {
791#if QT_CONFIG(regularexpression)
792 else if (option.startsWith(regexpConnectOption)) {
793 option = option.mid(regexpConnectOption.size()).trimmed();
794 if (option.isEmpty()) {
796 }
else if (option.startsWith(u'=')) {
798 const int cacheSize = option.mid(1).trimmed().toInt(&ok);
802 regexpCacheSize = cacheSize;
808 qCWarning(lcSqlite,
"Unsupported option '%ls'", qUtf16Printable(option.toString()));
811 int openMode = (openReadOnlyOption ? SQLITE_OPEN_READONLY : (SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE));
812 openMode |= (sharedCache ? SQLITE_OPEN_SHAREDCACHE : SQLITE_OPEN_PRIVATECACHE);
814 openMode |= SQLITE_OPEN_URI;
816#if defined(SQLITE_OPEN_NOFOLLOW
)
817 openMode |= SQLITE_OPEN_NOFOLLOW;
819 qCWarning(lcSqlite,
"SQLITE_OPEN_NOFOLLOW not supported with the SQLite version %s", sqlite3_libversion());
823 openMode |= SQLITE_OPEN_NOMUTEX;
825 const int res = sqlite3_open_v2(db.toUtf8().constData(), &d->access, openMode, useQtVfs ?
"QtVFS" :
nullptr);
827 if (res == SQLITE_OK) {
828 sqlite3_busy_timeout(d->access, timeOut);
829 sqlite3_extended_result_codes(d->access, useExtendedResultCodes);
832#if QT_CONFIG(regularexpression)
834 auto cache =
new QCache<QString, QRegularExpression>(regexpCacheSize);
835 sqlite3_create_function_v2(d->access,
"regexp", 2, SQLITE_UTF8, cache,
837 nullptr, &_q_regexp_cleanup);
840 if (useQtCaseFolding) {
841 sqlite3_create_function_v2(d->access,
"lower", 1, SQLITE_UTF8,
nullptr,
842 &_q_lower,
nullptr,
nullptr,
nullptr);
843 sqlite3_create_function_v2(d->access,
"upper", 1, SQLITE_UTF8,
nullptr,
844 &_q_upper,
nullptr,
nullptr,
nullptr);
848 setLastError(qMakeError(d->access, tr(
"Error opening database"),
849 QSqlError::ConnectionError, res));
853 sqlite3_close(d->access);
861void QSQLiteDriver::close()
865 for (QSQLiteResult *result : std::as_const(d->results))
866 result->d_func()->finalize();
868 if (d->access && (d->notificationid.size() > 0)) {
869 d->notificationid.clear();
870 sqlite3_update_hook(d->access,
nullptr,
nullptr);
873 const int res = sqlite3_close(d->access);
875 if (res != SQLITE_OK)
876 setLastError(qMakeError(d->access, tr(
"Error closing database"), QSqlError::ConnectionError, res));
883QSqlResult *QSQLiteDriver::createResult()
const
885 return new QSQLiteResult(
this);
888bool QSQLiteDriver::beginTransaction()
890 if (!isOpen() || isOpenError())
893 QSqlQuery q(createResult());
894 if (!q.exec(
"BEGIN"_L1)) {
895 setLastError(QSqlError(tr(
"Unable to begin transaction"),
896 q.lastError().databaseText(), QSqlError::TransactionError));
903bool QSQLiteDriver::commitTransaction()
905 if (!isOpen() || isOpenError())
908 QSqlQuery q(createResult());
909 if (!q.exec(
"COMMIT"_L1)) {
910 setLastError(QSqlError(tr(
"Unable to commit transaction"),
911 q.lastError().databaseText(), QSqlError::TransactionError));
918bool QSQLiteDriver::rollbackTransaction()
920 if (!isOpen() || isOpenError())
923 QSqlQuery q(createResult());
924 if (!q.exec(
"ROLLBACK"_L1)) {
925 setLastError(QSqlError(tr(
"Unable to rollback transaction"),
926 q.lastError().databaseText(), QSqlError::TransactionError));
933QStringList QSQLiteDriver::tables(QSql::TableType type)
const
939 QSqlQuery q(createResult());
940 q.setForwardOnly(
true);
942 QString sql =
"SELECT name FROM sqlite_master WHERE %1 "
943 "UNION ALL SELECT name FROM sqlite_temp_master WHERE %1"_L1;
944 if ((type & QSql::Tables) && (type & QSql::Views))
945 sql = sql.arg(
"type='table' OR type='view'"_L1);
946 else if (type & QSql::Tables)
947 sql = sql.arg(
"type='table'"_L1);
948 else if (type & QSql::Views)
949 sql = sql.arg(
"type='view'"_L1);
953 if (!sql.isEmpty() && q.exec(sql)) {
955 res.append(q.value(0).toString());
958 if (type & QSql::SystemTables) {
960 res.append(
"sqlite_master"_L1);
966QSqlIndex QSQLiteDriver::primaryIndex(
const QString &tablename)
const
968 Q_D(
const QSQLiteDriver);
972 QSqlQuery q(createResult());
973 q.setForwardOnly(
true);
974 return d->getTableInfo(q, tablename,
true);
977QSqlRecord QSQLiteDriver::record(
const QString &tablename)
const
979 Q_D(
const QSQLiteDriver);
983 QSqlQuery q(createResult());
984 q.setForwardOnly(
true);
985 return d->getTableInfo(q, tablename);
988QVariant QSQLiteDriver::handle()
const
990 Q_D(
const QSQLiteDriver);
991 return QVariant::fromValue(d->access);
994QString QSQLiteDriver::escapeIdentifier(
const QString &identifier, IdentifierType type)
const
996 Q_D(
const QSQLiteDriver);
997 if (identifier.isEmpty() || isIdentifierEscaped(identifier, type))
1000 const auto indexOfSeparator = identifier.indexOf(u'.');
1001 if (indexOfSeparator > -1) {
1002 auto leftName = QStringView{identifier}.first(indexOfSeparator);
1003 auto rightName = QStringView{identifier}.sliced(indexOfSeparator + 1);
1004 const QStringView leftEnclose = d->isIdentifierEscaped(leftName) ? u"" : u"\"";
1005 const QStringView rightEnclose = d->isIdentifierEscaped(rightName) ? u"" : u"\"";
1006 if (leftEnclose.isEmpty() || rightEnclose.isEmpty())
1007 return (leftEnclose + leftName + leftEnclose + u'.' + rightEnclose + rightName
1010 return u'"' + identifier + u'"';
1013bool QSQLiteDriver::isIdentifierEscaped(
const QString &identifier, IdentifierType type)
const
1015 Q_D(
const QSQLiteDriver);
1017 return d->isIdentifierEscaped(QStringView{identifier});
1020QString QSQLiteDriver::stripDelimiters(
const QString &identifier, IdentifierType type)
const
1022 Q_D(
const QSQLiteDriver);
1023 const auto indexOfSeparator = identifier.indexOf(u'.');
1024 if (indexOfSeparator > -1) {
1025 auto leftName = QStringView{identifier}.first(indexOfSeparator);
1026 auto rightName = QStringView{identifier}.sliced(indexOfSeparator + 1);
1027 const auto leftEscaped = d->isIdentifierEscaped(leftName);
1028 const auto rightEscaped = d->isIdentifierEscaped(rightName);
1029 if (leftEscaped || rightEscaped) {
1031 leftName = leftName.sliced(1).chopped(1);
1033 rightName = rightName.sliced(1).chopped(1);
1034 return leftName + u'.' + rightName;
1038 if (isIdentifierEscaped(identifier, type))
1039 return identifier.mid(1, identifier.size() - 2);
1045 sqlite3_int64 arowid)
1047 Q_UNUSED(aoperation);
1049 QSQLiteDriver *driver =
static_cast<QSQLiteDriver *>(qobj);
1051 QMetaObject::invokeMethod(driver,
"handleNotification", Qt::QueuedConnection,
1052 Q_ARG(QString, QString::fromUtf8(atablename)), Q_ARG(qint64, arowid));
1056bool QSQLiteDriver::subscribeToNotification(
const QString &name)
1060 qCWarning(lcSqlite,
"QSQLiteDriver::subscribeToNotification: Database not open.");
1064 if (d->notificationid.contains(name)) {
1065 qCWarning(lcSqlite,
"QSQLiteDriver::subscribeToNotification: Already subscribing to '%ls'.",
1066 qUtf16Printable(name));
1071 d->notificationid << name;
1072 if (d->notificationid.size() == 1)
1073 sqlite3_update_hook(d->access, &handle_sqlite_callback,
reinterpret_cast<
void *> (
this));
1078bool QSQLiteDriver::unsubscribeFromNotification(
const QString &name)
1082 qCWarning(lcSqlite,
"QSQLiteDriver::unsubscribeFromNotification: Database not open.");
1086 if (!d->notificationid.contains(name)) {
1087 qCWarning(lcSqlite,
"QSQLiteDriver::unsubscribeFromNotification: Not subscribed to '%ls'.",
1088 qUtf16Printable(name));
1092 d->notificationid.removeAll(name);
1093 if (d->notificationid.isEmpty())
1094 sqlite3_update_hook(d->access,
nullptr,
nullptr);
1099QStringList QSQLiteDriver::subscribedToNotifications()
const
1101 Q_D(
const QSQLiteDriver);
1102 return d->notificationid;
1105void QSQLiteDriver::handleNotification(
const QString &tableName, qint64 rowid)
1107 Q_D(
const QSQLiteDriver);
1108 if (d->notificationid.contains(tableName))
1109 emit notification(tableName, QSqlDriver::UnknownSource, QVariant(rowid));
1114#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.
\macro QT_RESTRICTED_CAST_FROM_ASCII
#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)