diff options
Diffstat (limited to 'src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp')
-rw-r--r-- | src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp | 369 |
1 files changed, 208 insertions, 161 deletions
diff --git a/src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp b/src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp index 54d734683b..c574772fd7 100644 --- a/src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp +++ b/src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtSql module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qsql_sqlite_p.h" @@ -43,6 +7,7 @@ #include <qdatetime.h> #include <qdebug.h> #include <qlist.h> +#include <qloggingcategory.h> #include <qsqlerror.h> #include <qsqlfield.h> #include <qsqlindex.h> @@ -74,38 +39,24 @@ Q_DECLARE_METATYPE(sqlite3_stmt*) QT_BEGIN_NAMESPACE -static QString _q_escapeIdentifier(const QString &identifier, QSqlDriver::IdentifierType type) -{ - QString res = identifier; - // If it contains [ and ] then we assume it to be escaped properly already as this indicates - // the syntax is exactly how it should be - if (identifier.contains(QLatin1Char('[')) && identifier.contains(QLatin1Char(']'))) - return res; - if (!identifier.isEmpty() && !identifier.startsWith(QLatin1Char('"')) && !identifier.endsWith(QLatin1Char('"'))) { - res.replace(QLatin1Char('"'), QLatin1String("\"\"")); - res.prepend(QLatin1Char('"')).append(QLatin1Char('"')); - if (type == QSqlDriver::TableName) - res.replace(QLatin1Char('.'), QLatin1String("\".\"")); - } - return res; -} +static Q_LOGGING_CATEGORY(lcSqlite, "qt.sql.sqlite") + +using namespace Qt::StringLiterals; static int qGetColumnType(const QString &tpName) { const QString typeName = tpName.toLower(); - if (typeName == QLatin1String("integer") - || typeName == QLatin1String("int")) + if (typeName == "integer"_L1 || typeName == "int"_L1) return QMetaType::Int; - if (typeName == QLatin1String("double") - || typeName == QLatin1String("float") - || typeName == QLatin1String("real") - || typeName.startsWith(QLatin1String("numeric"))) + if (typeName == "double"_L1 + || typeName == "float"_L1 + || typeName == "real"_L1 + || typeName.startsWith("numeric"_L1)) return QMetaType::Double; - if (typeName == QLatin1String("blob")) + if (typeName == "blob"_L1) return QMetaType::QByteArray; - if (typeName == QLatin1String("boolean") - || typeName == QLatin1String("bool")) + if (typeName == "boolean"_L1 || typeName == "bool"_L1) return QMetaType::Bool; return QMetaType::QString; } @@ -150,11 +101,64 @@ class QSQLiteDriverPrivate : public QSqlDriverPrivate public: inline QSQLiteDriverPrivate() : QSqlDriverPrivate(QSqlDriver::SQLite) {} + bool isIdentifierEscaped(QStringView identifier) const; + QSqlIndex getTableInfo(QSqlQuery &query, const QString &tableName, + bool onlyPIndex = false) const; + sqlite3 *access = nullptr; QList<QSQLiteResult *> results; QStringList notificationid; }; +bool QSQLiteDriverPrivate::isIdentifierEscaped(QStringView identifier) const +{ + return identifier.size() > 2 + && ((identifier.startsWith(u'"') && identifier.endsWith(u'"')) + || (identifier.startsWith(u'`') && identifier.endsWith(u'`')) + || (identifier.startsWith(u'[') && identifier.endsWith(u']'))); +} + +QSqlIndex QSQLiteDriverPrivate::getTableInfo(QSqlQuery &query, const QString &tableName, + bool onlyPIndex) const +{ + Q_Q(const QSQLiteDriver); + QString schema; + QString table = q->escapeIdentifier(tableName, QSqlDriver::TableName); + const auto indexOfSeparator = table.indexOf(u'.'); + if (indexOfSeparator > -1) { + auto leftName = QStringView{table}.first(indexOfSeparator); + auto rightName = QStringView{table}.sliced(indexOfSeparator + 1); + if (isIdentifierEscaped(leftName) && isIdentifierEscaped(rightName)) { + schema = leftName.toString() + u'.'; + table = rightName.toString(); + } + } + + query.exec("PRAGMA "_L1 + schema + "table_info ("_L1 + table + u')'); + QSqlIndex ind; + while (query.next()) { + bool isPk = query.value(5).toInt(); + if (onlyPIndex && !isPk) + continue; + QString typeName = query.value(2).toString().toLower(); + QString defVal = query.value(4).toString(); + if (!defVal.isEmpty() && defVal.at(0) == u'\'') { + const int end = defVal.lastIndexOf(u'\''); + if (end > 0) + defVal = defVal.mid(1, end - 1); + } + + QSqlField fld(query.value(1).toString(), QMetaType(qGetColumnType(typeName)), tableName); + if (isPk && (typeName == "integer"_L1)) + // INTEGER PRIMARY KEY fields are auto-generated in sqlite + // INT PRIMARY KEY is not the same as INTEGER PRIMARY KEY! + fld.setAutoValue(true); + fld.setRequired(query.value(3).toInt() != 0); + fld.setDefaultValue(defVal); + ind.append(fld); + } + return ind; +} class QSQLiteResultPrivate : public QSqlCachedResultPrivate { @@ -194,7 +198,7 @@ void QSQLiteResultPrivate::finalize() return; sqlite3_finalize(stmt); - stmt = 0; + stmt = nullptr; } void QSQLiteResultPrivate::initColumns(bool emptyResultset) @@ -209,10 +213,10 @@ void QSQLiteResultPrivate::initColumns(bool emptyResultset) for (int i = 0; i < nCols; ++i) { QString colName = QString(reinterpret_cast<const QChar *>( sqlite3_column_name16(stmt, i)) - ).remove(QLatin1Char('"')); + ).remove(u'"'); const QString tableName = QString(reinterpret_cast<const QChar *>( sqlite3_column_table_name16(stmt, i)) - ).remove(QLatin1Char('"')); + ).remove(u'"'); // must use typeName for resolving the type to match QSqliteDriver::record QString typeName = QString(reinterpret_cast<const QChar *>( sqlite3_column_decltype16(stmt, i))); @@ -246,7 +250,6 @@ void QSQLiteResultPrivate::initColumns(bool emptyResultset) } QSqlField fld(colName, QMetaType(fieldType), tableName); - fld.setSqlType(stp); rInf.append(fld); } } @@ -259,7 +262,7 @@ bool QSQLiteResultPrivate::fetchNext(QSqlCachedResult::ValueCache &values, int i // already fetched Q_ASSERT(!initialFetch); skipRow = false; - for(int i=0;i<firstRow.count();i++) + for(int i=0;i<firstRow.size();i++) values[i]=firstRow[i]; return skippedStatus; } @@ -418,10 +421,10 @@ bool QSQLiteResult::execBatch(bool arrayBind) Q_D(QSqlResult); QScopedValueRollback<QList<QVariant>> valuesScope(d->values); QList<QVariant> values = d->values; - if (values.count() == 0) + if (values.size() == 0) return false; - for (int i = 0; i < values.at(0).toList().count(); ++i) { + for (int i = 0; i < values.at(0).toList().size(); ++i) { d->values.clear(); QScopedValueRollback<QHash<QString, QList<int>>> indexesScope(d->indexes); auto it = d->indexes.constBegin(); @@ -455,16 +458,16 @@ bool QSQLiteResult::exec() } int paramCount = sqlite3_bind_parameter_count(d->stmt); - bool paramCountIsValid = paramCount == values.count(); + bool paramCountIsValid = paramCount == values.size(); #if (SQLITE_VERSION_NUMBER >= 3003011) // In the case of the reuse of a named placeholder // We need to check explicitly that paramCount is greater than or equal to 1, as sqlite // can end up in a case where for virtual tables it returns 0 even though it // has parameters - if (paramCount >= 1 && paramCount < values.count()) { + if (paramCount >= 1 && paramCount < values.size()) { const auto countIndexes = [](int counter, const QList<int> &indexList) { - return counter + indexList.length(); + return counter + indexList.size(); }; const int bindParamCount = std::accumulate(d->indexes.cbegin(), @@ -472,7 +475,7 @@ bool QSQLiteResult::exec() 0, countIndexes); - paramCountIsValid = bindParamCount == values.count(); + paramCountIsValid = bindParamCount == values.size(); // When using named placeholders, it will reuse the index for duplicated // placeholders. So we need to ensure the QList has only one instance of // each value as SQLite will do the rest for us. @@ -661,6 +664,30 @@ static void _q_regexp_cleanup(void *cache) } #endif +static void _q_lower(sqlite3_context* context, int argc, sqlite3_value** argv) +{ + if (Q_UNLIKELY(argc != 1)) { + sqlite3_result_text(context, nullptr, 0, nullptr); + return; + } + const QString lower = QString::fromUtf8( + reinterpret_cast<const char*>(sqlite3_value_text(argv[0]))).toLower(); + const QByteArray ba = lower.toUtf8(); + sqlite3_result_text(context, ba.data(), ba.size(), SQLITE_TRANSIENT); +} + +static void _q_upper(sqlite3_context* context, int argc, sqlite3_value** argv) +{ + if (Q_UNLIKELY(argc != 1)) { + sqlite3_result_text(context, nullptr, 0, nullptr); + return; + } + const QString upper = QString::fromUtf8( + reinterpret_cast<const char*>(sqlite3_value_text(argv[0]))).toUpper(); + const QByteArray ba = upper.toUtf8(); + sqlite3_result_text(context, ba.data(), ba.size(), SQLITE_TRANSIENT); +} + QSQLiteDriver::QSQLiteDriver(QObject * parent) : QSqlDriver(*new QSQLiteDriverPrivate, parent) { @@ -727,38 +754,47 @@ bool QSQLiteDriver::open(const QString & db, const QString &, const QString &, c bool openReadOnlyOption = false; bool openUriOption = false; bool useExtendedResultCodes = true; + bool useQtVfs = false; + bool useQtCaseFolding = false; + bool openNoFollow = false; #if QT_CONFIG(regularexpression) - static const QLatin1String regexpConnectOption = QLatin1String("QSQLITE_ENABLE_REGEXP"); + static const auto regexpConnectOption = "QSQLITE_ENABLE_REGEXP"_L1; bool defineRegexp = false; int regexpCacheSize = 25; #endif - const auto opts = QStringView{conOpts}.split(QLatin1Char(';')); + const auto opts = QStringView{conOpts}.split(u';', Qt::SkipEmptyParts); for (auto option : opts) { option = option.trimmed(); - if (option.startsWith(QLatin1String("QSQLITE_BUSY_TIMEOUT"))) { + if (option.startsWith("QSQLITE_BUSY_TIMEOUT"_L1)) { option = option.mid(20).trimmed(); - if (option.startsWith(QLatin1Char('='))) { + if (option.startsWith(u'=')) { bool ok; const int nt = option.mid(1).trimmed().toInt(&ok); if (ok) timeOut = nt; } - } else if (option == QLatin1String("QSQLITE_OPEN_READONLY")) { + } else if (option == "QSQLITE_USE_QT_VFS"_L1) { + useQtVfs = true; + } else if (option == "QSQLITE_OPEN_READONLY"_L1) { openReadOnlyOption = true; - } else if (option == QLatin1String("QSQLITE_OPEN_URI")) { + } else if (option == "QSQLITE_OPEN_URI"_L1) { openUriOption = true; - } else if (option == QLatin1String("QSQLITE_ENABLE_SHARED_CACHE")) { + } else if (option == "QSQLITE_ENABLE_SHARED_CACHE"_L1) { sharedCache = true; - } else if (option == QLatin1String("QSQLITE_NO_USE_EXTENDED_RESULT_CODES")) { + } else if (option == "QSQLITE_NO_USE_EXTENDED_RESULT_CODES"_L1) { useExtendedResultCodes = false; + } else if (option == "QSQLITE_ENABLE_NON_ASCII_CASE_FOLDING"_L1) { + useQtCaseFolding = true; + } else if (option == "QSQLITE_OPEN_NOFOLLOW"_L1) { + openNoFollow = true; } #if QT_CONFIG(regularexpression) else if (option.startsWith(regexpConnectOption)) { option = option.mid(regexpConnectOption.size()).trimmed(); if (option.isEmpty()) { defineRegexp = true; - } else if (option.startsWith(QLatin1Char('='))) { + } else if (option.startsWith(u'=')) { bool ok = false; const int cacheSize = option.mid(1).trimmed().toInt(&ok); if (ok) { @@ -769,16 +805,25 @@ bool QSQLiteDriver::open(const QString & db, const QString &, const QString &, c } } #endif + else + qCWarning(lcSqlite, "Unsupported option '%ls'", qUtf16Printable(option.toString())); } int openMode = (openReadOnlyOption ? SQLITE_OPEN_READONLY : (SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE)); openMode |= (sharedCache ? SQLITE_OPEN_SHAREDCACHE : SQLITE_OPEN_PRIVATECACHE); if (openUriOption) openMode |= SQLITE_OPEN_URI; + if (openNoFollow) { +#if defined(SQLITE_OPEN_NOFOLLOW) + openMode |= SQLITE_OPEN_NOFOLLOW; +#else + qCWarning(lcSqlite, "SQLITE_OPEN_NOFOLLOW not supported with the SQLite version %s", sqlite3_libversion()); +#endif + } openMode |= SQLITE_OPEN_NOMUTEX; - const int res = sqlite3_open_v2(db.toUtf8().constData(), &d->access, openMode, nullptr); + const int res = sqlite3_open_v2(db.toUtf8().constData(), &d->access, openMode, useQtVfs ? "QtVFS" : nullptr); if (res == SQLITE_OK) { sqlite3_busy_timeout(d->access, timeOut); @@ -793,6 +838,12 @@ bool QSQLiteDriver::open(const QString & db, const QString &, const QString &, c nullptr, &_q_regexp_cleanup); } #endif + if (useQtCaseFolding) { + sqlite3_create_function_v2(d->access, "lower", 1, SQLITE_UTF8, nullptr, + &_q_lower, nullptr, nullptr, nullptr); + sqlite3_create_function_v2(d->access, "upper", 1, SQLITE_UTF8, nullptr, + &_q_upper, nullptr, nullptr, nullptr); + } return true; } else { setLastError(qMakeError(d->access, tr("Error opening database"), @@ -801,7 +852,7 @@ bool QSQLiteDriver::open(const QString & db, const QString &, const QString &, c if (d->access) { sqlite3_close(d->access); - d->access = 0; + d->access = nullptr; } return false; @@ -812,10 +863,10 @@ void QSQLiteDriver::close() { Q_D(QSQLiteDriver); if (isOpen()) { - for (QSQLiteResult *result : qAsConst(d->results)) + for (QSQLiteResult *result : std::as_const(d->results)) result->d_func()->finalize(); - if (d->access && (d->notificationid.count() > 0)) { + if (d->access && (d->notificationid.size() > 0)) { d->notificationid.clear(); sqlite3_update_hook(d->access, nullptr, nullptr); } @@ -824,7 +875,7 @@ void QSQLiteDriver::close() if (res != SQLITE_OK) setLastError(qMakeError(d->access, tr("Error closing database"), QSqlError::ConnectionError, res)); - d->access = 0; + d->access = nullptr; setOpen(false); setOpenError(false); } @@ -841,7 +892,7 @@ bool QSQLiteDriver::beginTransaction() return false; QSqlQuery q(createResult()); - if (!q.exec(QLatin1String("BEGIN"))) { + if (!q.exec("BEGIN"_L1)) { setLastError(QSqlError(tr("Unable to begin transaction"), q.lastError().databaseText(), QSqlError::TransactionError)); return false; @@ -856,7 +907,7 @@ bool QSQLiteDriver::commitTransaction() return false; QSqlQuery q(createResult()); - if (!q.exec(QLatin1String("COMMIT"))) { + if (!q.exec("COMMIT"_L1)) { setLastError(QSqlError(tr("Unable to commit transaction"), q.lastError().databaseText(), QSqlError::TransactionError)); return false; @@ -871,7 +922,7 @@ bool QSQLiteDriver::rollbackTransaction() return false; QSqlQuery q(createResult()); - if (!q.exec(QLatin1String("ROLLBACK"))) { + if (!q.exec("ROLLBACK"_L1)) { setLastError(QSqlError(tr("Unable to rollback transaction"), q.lastError().databaseText(), QSqlError::TransactionError)); return false; @@ -889,14 +940,14 @@ QStringList QSQLiteDriver::tables(QSql::TableType type) const QSqlQuery q(createResult()); q.setForwardOnly(true); - QString sql = QLatin1String("SELECT name FROM sqlite_master WHERE %1 " - "UNION ALL SELECT name FROM sqlite_temp_master WHERE %1"); + QString sql = "SELECT name FROM sqlite_master WHERE %1 " + "UNION ALL SELECT name FROM sqlite_temp_master WHERE %1"_L1; if ((type & QSql::Tables) && (type & QSql::Views)) - sql = sql.arg(QLatin1String("type='table' OR type='view'")); + sql = sql.arg("type='table' OR type='view'"_L1); else if (type & QSql::Tables) - sql = sql.arg(QLatin1String("type='table'")); + sql = sql.arg("type='table'"_L1); else if (type & QSql::Views) - sql = sql.arg(QLatin1String("type='view'")); + sql = sql.arg("type='view'"_L1); else sql.clear(); @@ -907,85 +958,32 @@ QStringList QSQLiteDriver::tables(QSql::TableType type) const if (type & QSql::SystemTables) { // there are no internal tables beside this one: - res.append(QLatin1String("sqlite_master")); + res.append("sqlite_master"_L1); } return res; } -static QSqlIndex qGetTableInfo(QSqlQuery &q, const QString &tableName, bool onlyPIndex = false) -{ - QString schema; - QString table(tableName); - const int indexOfSeparator = tableName.indexOf(QLatin1Char('.')); - if (indexOfSeparator > -1) { - const int indexOfCloseBracket = tableName.indexOf(QLatin1Char(']')); - if (indexOfCloseBracket != tableName.size() - 1) { - // Handles a case like databaseName.tableName - schema = tableName.left(indexOfSeparator + 1); - table = tableName.mid(indexOfSeparator + 1); - } else { - const int indexOfOpenBracket = tableName.lastIndexOf(QLatin1Char('['), indexOfCloseBracket); - if (indexOfOpenBracket > 0) { - // Handles a case like databaseName.[tableName] - schema = tableName.left(indexOfOpenBracket); - table = tableName.mid(indexOfOpenBracket); - } - } - } - q.exec(QLatin1String("PRAGMA ") + schema + QLatin1String("table_info (") + - _q_escapeIdentifier(table, QSqlDriver::TableName) + QLatin1Char(')')); - QSqlIndex ind; - while (q.next()) { - bool isPk = q.value(5).toInt(); - if (onlyPIndex && !isPk) - continue; - QString typeName = q.value(2).toString().toLower(); - QString defVal = q.value(4).toString(); - if (!defVal.isEmpty() && defVal.at(0) == QLatin1Char('\'')) { - const int end = defVal.lastIndexOf(QLatin1Char('\'')); - if (end > 0) - defVal = defVal.mid(1, end - 1); - } - - QSqlField fld(q.value(1).toString(), QMetaType(qGetColumnType(typeName)), tableName); - if (isPk && (typeName == QLatin1String("integer"))) - // INTEGER PRIMARY KEY fields are auto-generated in sqlite - // INT PRIMARY KEY is not the same as INTEGER PRIMARY KEY! - fld.setAutoValue(true); - fld.setRequired(q.value(3).toInt() != 0); - fld.setDefaultValue(defVal); - ind.append(fld); - } - return ind; -} - -QSqlIndex QSQLiteDriver::primaryIndex(const QString &tblname) const +QSqlIndex QSQLiteDriver::primaryIndex(const QString &tablename) const { + Q_D(const QSQLiteDriver); if (!isOpen()) return QSqlIndex(); - QString table = tblname; - if (isIdentifierEscaped(table, QSqlDriver::TableName)) - table = stripDelimiters(table, QSqlDriver::TableName); - QSqlQuery q(createResult()); q.setForwardOnly(true); - return qGetTableInfo(q, table, true); + return d->getTableInfo(q, tablename, true); } -QSqlRecord QSQLiteDriver::record(const QString &tbl) const +QSqlRecord QSQLiteDriver::record(const QString &tablename) const { + Q_D(const QSQLiteDriver); if (!isOpen()) return QSqlRecord(); - QString table = tbl; - if (isIdentifierEscaped(table, QSqlDriver::TableName)) - table = stripDelimiters(table, QSqlDriver::TableName); - QSqlQuery q(createResult()); q.setForwardOnly(true); - return qGetTableInfo(q, table); + return d->getTableInfo(q, tablename); } QVariant QSQLiteDriver::handle() const @@ -996,7 +994,52 @@ QVariant QSQLiteDriver::handle() const QString QSQLiteDriver::escapeIdentifier(const QString &identifier, IdentifierType type) const { - return _q_escapeIdentifier(identifier, type); + Q_D(const QSQLiteDriver); + if (identifier.isEmpty() || isIdentifierEscaped(identifier, type)) + return identifier; + + const auto indexOfSeparator = identifier.indexOf(u'.'); + if (indexOfSeparator > -1) { + auto leftName = QStringView{identifier}.first(indexOfSeparator); + auto rightName = QStringView{identifier}.sliced(indexOfSeparator + 1); + const QStringView leftEnclose = d->isIdentifierEscaped(leftName) ? u"" : u"\""; + const QStringView rightEnclose = d->isIdentifierEscaped(rightName) ? u"" : u"\""; + if (leftEnclose.isEmpty() || rightEnclose.isEmpty()) + return (leftEnclose + leftName + leftEnclose + u'.' + rightEnclose + rightName + + rightEnclose); + } + return u'"' + identifier + u'"'; +} + +bool QSQLiteDriver::isIdentifierEscaped(const QString &identifier, IdentifierType type) const +{ + Q_D(const QSQLiteDriver); + Q_UNUSED(type); + return d->isIdentifierEscaped(QStringView{identifier}); +} + +QString QSQLiteDriver::stripDelimiters(const QString &identifier, IdentifierType type) const +{ + Q_D(const QSQLiteDriver); + const auto indexOfSeparator = identifier.indexOf(u'.'); + if (indexOfSeparator > -1) { + auto leftName = QStringView{identifier}.first(indexOfSeparator); + auto rightName = QStringView{identifier}.sliced(indexOfSeparator + 1); + const auto leftEscaped = d->isIdentifierEscaped(leftName); + const auto rightEscaped = d->isIdentifierEscaped(rightName); + if (leftEscaped || rightEscaped) { + if (leftEscaped) + leftName = leftName.sliced(1).chopped(1); + if (rightEscaped) + rightName = rightName.sliced(1).chopped(1); + return leftName + u'.' + rightName; + } + } + + if (isIdentifierEscaped(identifier, type)) + return identifier.mid(1, identifier.size() - 2); + + return identifier; } static void handle_sqlite_callback(void *qobj,int aoperation, char const *adbname, char const *atablename, @@ -1015,18 +1058,19 @@ bool QSQLiteDriver::subscribeToNotification(const QString &name) { Q_D(QSQLiteDriver); if (!isOpen()) { - qWarning("Database not open."); + qCWarning(lcSqlite, "QSQLiteDriver::subscribeToNotification: Database not open."); return false; } if (d->notificationid.contains(name)) { - qWarning("Already subscribing to '%s'.", qPrintable(name)); + qCWarning(lcSqlite, "QSQLiteDriver::subscribeToNotification: Already subscribing to '%ls'.", + qUtf16Printable(name)); return false; } //sqlite supports only one notification callback, so only the first is registered d->notificationid << name; - if (d->notificationid.count() == 1) + if (d->notificationid.size() == 1) sqlite3_update_hook(d->access, &handle_sqlite_callback, reinterpret_cast<void *> (this)); return true; @@ -1036,12 +1080,13 @@ bool QSQLiteDriver::unsubscribeFromNotification(const QString &name) { Q_D(QSQLiteDriver); if (!isOpen()) { - qWarning("Database not open."); + qCWarning(lcSqlite, "QSQLiteDriver::unsubscribeFromNotification: Database not open."); return false; } if (!d->notificationid.contains(name)) { - qWarning("Not subscribed to '%s'.", qPrintable(name)); + qCWarning(lcSqlite, "QSQLiteDriver::unsubscribeFromNotification: Not subscribed to '%ls'.", + qUtf16Printable(name)); return false; } @@ -1066,3 +1111,5 @@ void QSQLiteDriver::handleNotification(const QString &tableName, qint64 rowid) } QT_END_NAMESPACE + +#include "moc_qsql_sqlite_p.cpp" |