diff options
Diffstat (limited to 'tests/auto/sql/kernel')
26 files changed, 1065 insertions, 433 deletions
diff --git a/tests/auto/sql/kernel/CMakeLists.txt b/tests/auto/sql/kernel/CMakeLists.txt index 7af31a24da..d51cb75f31 100644 --- a/tests/auto/sql/kernel/CMakeLists.txt +++ b/tests/auto/sql/kernel/CMakeLists.txt @@ -5,8 +5,10 @@ add_subdirectory(qsqlfield) add_subdirectory(qsqldatabase) add_subdirectory(qsqlerror) add_subdirectory(qsqldriver) +add_subdirectory(qsqlindex) add_subdirectory(qsqlquery) add_subdirectory(qsqlrecord) add_subdirectory(qsqlthread) add_subdirectory(qsql) add_subdirectory(qsqlresult) +add_subdirectory(qvfssql) diff --git a/tests/auto/sql/kernel/qsql/CMakeLists.txt b/tests/auto/sql/kernel/qsql/CMakeLists.txt index 836e06ce7c..8e0448a786 100644 --- a/tests/auto/sql/kernel/qsql/CMakeLists.txt +++ b/tests/auto/sql/kernel/qsql/CMakeLists.txt @@ -5,6 +5,12 @@ ## tst_qsql Test: ##################################################################### +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qsql LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + qt_internal_add_test(tst_qsql SOURCES tst_qsql.cpp diff --git a/tests/auto/sql/kernel/qsql/tst_qsql.cpp b/tests/auto/sql/kernel/qsql/tst_qsql.cpp index 78f48a4117..7b6e260ebf 100644 --- a/tests/auto/sql/kernel/qsql/tst_qsql.cpp +++ b/tests/auto/sql/kernel/qsql/tst_qsql.cpp @@ -1,5 +1,5 @@ // Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> @@ -121,6 +121,10 @@ void tst_QSql::open() void tst_QSql::openInvalid() { + int argc = 1; + char *argv[] = { const_cast<char*>(QTest::currentAppName()) }; + QCoreApplication app(argc, argv, false); + QSqlDatabase db; QVERIFY(!db.open()); diff --git a/tests/auto/sql/kernel/qsqldatabase/CMakeLists.txt b/tests/auto/sql/kernel/qsqldatabase/CMakeLists.txt index 25e4ff125c..97dbf94af7 100644 --- a/tests/auto/sql/kernel/qsqldatabase/CMakeLists.txt +++ b/tests/auto/sql/kernel/qsqldatabase/CMakeLists.txt @@ -5,6 +5,12 @@ ## tst_qsqldatabase Test: ##################################################################### +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qsqldatabase LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + qt_internal_add_test(tst_qsqldatabase SOURCES tst_qsqldatabase.cpp diff --git a/tests/auto/sql/kernel/qsqldatabase/tst_databases.h b/tests/auto/sql/kernel/qsqldatabase/tst_databases.h index c715c1c2a8..5a10bde814 100644 --- a/tests/auto/sql/kernel/qsqldatabase/tst_databases.h +++ b/tests/auto/sql/kernel/qsqldatabase/tst_databases.h @@ -1,5 +1,5 @@ // Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only /* possible connection parameters */ #ifndef TST_DATABASES_H @@ -9,6 +9,7 @@ #include <QSqlDriver> #include <QSqlError> #include <QSqlQuery> +#include <QSqlRecord> #include <QRegularExpression> #include <QRegularExpressionMatch> #include <QDir> @@ -20,9 +21,12 @@ #include <QJsonObject> #include <QJsonDocument> #include <QSysInfo> +#include <QVersionNumber> #include <QtSql/private/qsqldriver_p.h> #include <QTest> +using namespace Qt::StringLiterals; + #define CHECK_DATABASE( db ) \ if ( !db.isValid() ) { qFatal( "db is Invalid" ); } @@ -114,12 +118,14 @@ public: if (port > 0) cName += QLatin1Char(':') + QString::number(port); + QString opts = params; if (driver == "QSQLITE") { // Since the database for sqlite is generated at runtime it's always // available, but we use QTempDir so it's always in a different // location. Thus, let's ignore the path completely. cName = "SQLite"; qInfo("SQLite will use the database located at %ls", qUtf16Printable(dbName)); + opts += QStringLiteral(";QSQLITE_ENABLE_NON_ASCII_CASE_FOLDING"); } auto db = QSqlDatabase::addDatabase(driver, cName); @@ -133,7 +139,7 @@ public: db.setPassword(passwd); db.setHostName(host); db.setPort(port); - db.setConnectOptions(params); + db.setConnectOptions(opts); dbNames.append(cName); } @@ -434,6 +440,16 @@ public: return ver; } + static QVersionNumber getIbaseEngineVersion(const QSqlDatabase &db) + { + QSqlQuery q(db); + q.exec("SELECT rdb$get_context('SYSTEM', 'ENGINE_VERSION') as version from rdb$database;"_L1); + q.next(); + auto record = q.record(); + auto version = QVersionNumber::fromString(record.value(0).toString()); + return version; + } + QStringList dbNames; int counter = 0; @@ -481,5 +497,36 @@ private: QString m_tableName; }; +class ProcScope +{ +public: + ProcScope(const QSqlDatabase &db, const char *procName, const char *file) + : m_db(db), + m_procName(qTableName(procName, file, db)) + { + cleanup(); + } + ~ProcScope() + { + cleanup(); + } + QString name() const + { + return m_procName; + } +protected: + void cleanup() + { + QSqlQuery q(m_db); + if (m_db.driverName() == "QIBASE") + q.exec("DROP PROCEDURE " + m_procName); + else + q.exec("DROP PROCEDURE IF EXISTS " + m_procName); + } +private: + QSqlDatabase m_db; + const QString m_procName; +}; + #endif diff --git a/tests/auto/sql/kernel/qsqldatabase/tst_qsqldatabase.cpp b/tests/auto/sql/kernel/qsqldatabase/tst_qsqldatabase.cpp index f34045b2a0..79fe9d6333 100644 --- a/tests/auto/sql/kernel/qsqldatabase/tst_qsqldatabase.cpp +++ b/tests/auto/sql/kernel/qsqldatabase/tst_qsqldatabase.cpp @@ -1,5 +1,5 @@ // Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> @@ -104,6 +104,8 @@ private slots: void infinityAndNan(); void multipleThreads_data() { generic_data(); } void multipleThreads(); + void moveToThread_data() { generic_data(); } + void moveToThread(); void db2_valueCacheUpdate_data() { generic_data("QDB2"); } void db2_valueCacheUpdate(); @@ -175,13 +177,13 @@ private slots: void sqlite_check_json1(); private: - void createTestTables(QSqlDatabase db); - void dropTestTables(QSqlDatabase db); - void populateTestTables(QSqlDatabase db); + void createTestTables(const QSqlDatabase &db); + void dropTestTables(const QSqlDatabase &db); + void populateTestTables(const QSqlDatabase &db); void generic_data(const QString &engine=QString()); - void testRecord(const FieldDef fieldDefs[], const QSqlRecord& inf, QSqlDatabase db); - void commonFieldTest(const FieldDef fieldDefs[], QSqlDatabase, const int); + void testRecord(const FieldDef fieldDefs[], const QSqlRecord& inf, const QSqlDatabase &db); + void commonFieldTest(const FieldDef fieldDefs[], const QSqlDatabase &db, const int fieldCount); tst_Databases dbs; }; @@ -216,7 +218,7 @@ struct FieldDef { // creates a table out of the FieldDefs and returns the number of fields // excluding the primary key field -static int createFieldTable(const FieldDef fieldDefs[], QSqlDatabase db) +static int createFieldTable(const FieldDef fieldDefs[], const QSqlDatabase &db) { QSqlDriver::DbmsType dbType = tst_Databases::getDatabaseType(db); const QString tableName = qTableName("qtestfields", __FILE__, db); @@ -251,7 +253,7 @@ static int createFieldTable(const FieldDef fieldDefs[], QSqlDatabase db) return i; } -void tst_QSqlDatabase::createTestTables(QSqlDatabase db) +void tst_QSqlDatabase::createTestTables(const QSqlDatabase &db) { if (!db.isValid()) return; @@ -285,7 +287,7 @@ void tst_QSqlDatabase::createTestTables(QSqlDatabase db) QVERIFY_SQL(q, exec(qry)); } -void tst_QSqlDatabase::dropTestTables(QSqlDatabase db) +void tst_QSqlDatabase::dropTestTables(const QSqlDatabase &db) { if (!db.isValid()) return; @@ -297,30 +299,11 @@ void tst_QSqlDatabase::dropTestTables(QSqlDatabase db) } // drop the view first, otherwise we'll get dependency problems - tst_Databases::safeDropViews(db, QStringList() << qTableName("qtest_view", __FILE__, db) << qTableName("qtest_view2", __FILE__, db)); - const QString qtestTable = qTableName("qtest", __FILE__, db); - QStringList tableNames; - tableNames << qtestTable - << qTableName("qtest test", __FILE__, db) - << qTableName("qtestfields", __FILE__, db) - << qTableName("qtestalter", __FILE__, db) - << qTableName("qtest_temp", __FILE__, db) - << qTableName("qtest_xmltype", __FILE__, db) - << qTableName("latin1table", __FILE__, db) - << qTableName("qtest_sqlguid", __FILE__, db) - << qTableName("batable", __FILE__, db) - << qTableName("qtest_prec", __FILE__, db) - << qTableName("uint", __FILE__, db) - << qTableName("strings", __FILE__, db) - << qTableName("numericfields", __FILE__, db) - << qTableName("qtest_ibaseblobs", __FILE__, db) - << qTableName("qtestBindBool", __FILE__, db) - << qTableName("testqGetString", __FILE__, db) - << qTableName("qtest_sqlguid", __FILE__, db) - << qTableName("uint_table", __FILE__, db) - << qTableName("uint_test", __FILE__, db) - << qTableName("bug_249059", __FILE__, db) - << qTableName("regexp_test", __FILE__, db); + tst_Databases::safeDropViews(db, {qTableName("qtest_view", __FILE__, db), + qTableName("qtest_view2", __FILE__, db)}); + QStringList tableNames = {qTableName("qtest", __FILE__, db), + qTableName("qtest test", __FILE__, db), + qTableName("qtestfields", __FILE__, db)}; QSqlQuery q(0, db); if (dbType == QSqlDriver::PostgreSQL) { @@ -340,7 +323,7 @@ void tst_QSqlDatabase::dropTestTables(QSqlDatabase db) } } -void tst_QSqlDatabase::populateTestTables(QSqlDatabase db) +void tst_QSqlDatabase::populateTestTables(const QSqlDatabase &db) { if (!db.isValid()) return; @@ -526,11 +509,11 @@ void tst_QSqlDatabase::alterTable() QFETCH(QString, dbName); QSqlDatabase db = QSqlDatabase::database(dbName); CHECK_DATABASE(db); - const QString qtestalter(qTableName("qtestalter", __FILE__, db)); + TableScope ts(db, "qtestalter", __FILE__); QSqlQuery q(db); - QVERIFY_SQL(q, exec("create table " + qtestalter + " (F1 char(20), F2 char(20), F3 char(20))")); - QSqlRecord rec = db.record(qtestalter); + QVERIFY_SQL(q, exec("create table " + ts.tableName() + " (F1 char(20), F2 char(20), F3 char(20))")); + QSqlRecord rec = db.record(ts.tableName()); QCOMPARE((int)rec.count(), 3); int i; @@ -538,18 +521,18 @@ void tst_QSqlDatabase::alterTable() QCOMPARE(rec.field(i).name().toUpper(), QString("F%1").arg(i + 1)); } - if (!q.exec("alter table " + qtestalter + " drop column F2")) { + if (!q.exec("alter table " + ts.tableName() + " drop column F2")) { QSKIP("DBMS doesn't support dropping columns in ALTER TABLE statement"); } - rec = db.record(qtestalter); + rec = db.record(ts.tableName()); QCOMPARE(rec.count(), 2); QCOMPARE(rec.field(0).name().toUpper(), QString("F1")); QCOMPARE(rec.field(1).name().toUpper(), QString("F3")); - q.exec("select * from " + qtestalter); + q.exec("select * from " + ts.tableName()); } #if 0 @@ -577,12 +560,11 @@ void tst_QSqlDatabase::record() } #endif -void tst_QSqlDatabase::testRecord(const FieldDef fieldDefs[], const QSqlRecord& inf, QSqlDatabase db) +void tst_QSqlDatabase::testRecord(const FieldDef fieldDefs[], const QSqlRecord &inf, const QSqlDatabase &db) { - int i = 0; if (!tst_Databases::autoFieldName(db).isEmpty()) // Currently only MySQL is tested - QVERIFY2(inf.field(i).isAutoValue(), qPrintable(inf.field(i).name() + " should be reporting as an autovalue")); - for (i = 0; !fieldDefs[ i ].typeName.isNull(); ++i) { + QVERIFY2(inf.field(0).isAutoValue(), qPrintable(inf.field(0).name() + " should be reporting as an autovalue")); + for (int i = 0; !fieldDefs[ i ].typeName.isNull(); ++i) { QCOMPARE(inf.field(i+1).name().toUpper(), fieldDefs[ i ].fieldName().toUpper()); if (inf.field(i+1).metaType().id() != fieldDefs[ i ].type) { QFAIL(qPrintable(QString(" Expected: '%1' Received: '%2' for field %3 in testRecord").arg( @@ -597,7 +579,7 @@ void tst_QSqlDatabase::testRecord(const FieldDef fieldDefs[], const QSqlRecord& } // non-dbms specific tests -void tst_QSqlDatabase::commonFieldTest(const FieldDef fieldDefs[], QSqlDatabase db, const int fieldCount) +void tst_QSqlDatabase::commonFieldTest(const FieldDef fieldDefs[], const QSqlDatabase &db, const int fieldCount) { CHECK_DATABASE(db); @@ -1267,24 +1249,24 @@ void tst_QSqlDatabase::psql_escapeBytea() QFETCH(QString, dbName); QSqlDatabase db = QSqlDatabase::database(dbName); CHECK_DATABASE(db); + TableScope ts(db, "batable", __FILE__); const char dta[4] = {'\x71', '\x14', '\x32', '\x81'}; QByteArray ba(dta, 4); QSqlQuery q(db); - const QString tableName(qTableName("batable", __FILE__, db)); - QVERIFY_SQL(q, exec(QString("CREATE TABLE %1 (ba bytea)").arg(tableName))); + QVERIFY_SQL(q, exec(QString("CREATE TABLE %1 (ba bytea)").arg(ts.tableName()))); QSqlQuery iq(db); - QVERIFY_SQL(iq, prepare(QString("INSERT INTO %1 VALUES (?)").arg(tableName))); + QVERIFY_SQL(iq, prepare(QString("INSERT INTO %1 VALUES (?)").arg(ts.tableName()))); iq.bindValue(0, QVariant(ba)); QVERIFY_SQL(iq, exec()); - QVERIFY_SQL(q, exec(QString("SELECT ba FROM %1").arg(tableName))); + QVERIFY_SQL(q, exec(QString("SELECT ba FROM %1").arg(ts.tableName()))); QVERIFY_SQL(q, next()); QByteArray res = q.value(0).toByteArray(); - int i = 0; + qsizetype i = 0; for (; i < ba.size(); ++i){ if (ba[i] != res[i]) break; @@ -1298,13 +1280,13 @@ void tst_QSqlDatabase::psql_bug249059() QFETCH(QString, dbName); QSqlDatabase db = QSqlDatabase::database(dbName); CHECK_DATABASE(db); + TableScope ts(db, "bug_249059", __FILE__); QSqlQuery q(db); - const QString tableName(qTableName("bug_249059", __FILE__, db)); - QVERIFY_SQL(q, exec(QString("CREATE TABLE %1 (dt timestamp, t time)").arg(tableName))); + QVERIFY_SQL(q, exec(QString("CREATE TABLE %1 (dt timestamp, t time)").arg(ts.tableName()))); QSqlQuery iq(db); - QVERIFY_SQL(iq, prepare(QString("INSERT INTO %1 VALUES (?, ?)").arg(tableName))); + QVERIFY_SQL(iq, prepare(QString("INSERT INTO %1 VALUES (?, ?)").arg(ts.tableName()))); iq.bindValue(0, QVariant(QString("2001-09-09 04:05:06.789 -5:00"))); iq.bindValue(1, QVariant(QString("04:05:06.789 -5:00"))); QVERIFY_SQL(iq, exec()); @@ -1312,7 +1294,7 @@ void tst_QSqlDatabase::psql_bug249059() iq.bindValue(1, QVariant(QString("04:05:06.789 +5:00"))); QVERIFY_SQL(iq, exec()); - QVERIFY_SQL(q, exec(QString("SELECT dt, t FROM %1").arg(tableName))); + QVERIFY_SQL(q, exec(QString("SELECT dt, t FROM %1").arg(ts.tableName()))); QVERIFY_SQL(q, next()); QDateTime dt1=q.value(0).toDateTime(); QTime t1=q.value(1).toTime(); @@ -1325,17 +1307,15 @@ void tst_QSqlDatabase::psql_bug249059() QCOMPARE(t1, t2); } -// This test should be rewritten to work with Oracle as well - or the Oracle driver -// should be fixed to make this test pass (handle overflows) void tst_QSqlDatabase::precisionPolicy() { QFETCH(QString, dbName); QSqlDatabase db = QSqlDatabase::database(dbName); CHECK_DATABASE(db); -// DBMS_SPECIFIC(db, "QPSQL"); + TableScope ts(db, "qtest_prec", __FILE__); + const auto &tableName = ts.tableName(); QSqlQuery q(db); - const QString tableName(qTableName("qtest_prec", __FILE__, db)); if(!db.driver()->hasFeature(QSqlDriver::LowPrecisionNumbers)) QSKIP("Driver or database doesn't support setting precision policy"); @@ -1466,14 +1446,14 @@ void tst_QSqlDatabase::mysqlOdbc_unsignedIntegers() if (tst_Databases::getDatabaseType(db) != QSqlDriver::MySqlServer || !db.driverName().startsWith("QODBC")) QSKIP("MySQL through ODBC-driver specific test"); + TableScope ts(db, "uint", __FILE__); QSqlQuery q(db); - const QString tableName(qTableName("uint", __FILE__, db)); - QVERIFY_SQL(q, exec(QString("CREATE TABLE %1 (foo integer(10) unsigned, bar integer(10))").arg(tableName))); - QVERIFY_SQL(q, exec(QString("INSERT INTO %1 VALUES (-4000000000, -4000000000)").arg(tableName))); - QVERIFY_SQL(q, exec(QString("INSERT INTO %1 VALUES (4000000000, 4000000000)").arg(tableName))); + QVERIFY_SQL(q, exec(QString("CREATE TABLE %1 (foo integer(10) unsigned, bar integer(10))").arg(ts.tableName()))); + QVERIFY_SQL(q, exec(QString("INSERT INTO %1 VALUES (-4000000000, -4000000000)").arg(ts.tableName()))); + QVERIFY_SQL(q, exec(QString("INSERT INTO %1 VALUES (4000000000, 4000000000)").arg(ts.tableName()))); - QVERIFY_SQL(q, exec(QString("SELECT foo, bar FROM %1").arg(tableName))); + QVERIFY_SQL(q, exec(QString("SELECT foo, bar FROM %1").arg(ts.tableName()))); QVERIFY(q.next()); QCOMPARE(q.value(0).toString(), QString("0")); QCOMPARE(q.value(1).toString(), QString("-2147483648")); @@ -1490,13 +1470,13 @@ void tst_QSqlDatabase::accessOdbc_strings() if (!tst_Databases::isMSAccess(db)) QSKIP("MS Access specific test"); + TableScope ts(db, "strings", __FILE__); QSqlQuery q(db); - const QString tableName(qTableName("strings", __FILE__, db)); QVERIFY_SQL(q, exec(QString("CREATE TABLE %1 (aStr memo, bStr memo, cStr memo, dStr memo" - ", eStr memo, fStr memo, gStr memo, hStr memo)").arg(tableName))); + ", eStr memo, fStr memo, gStr memo, hStr memo)").arg(ts.tableName()))); - QVERIFY_SQL(q, prepare(QString("INSERT INTO %1 VALUES (?, ?, ?, ?, ?, ?, ?, ?)").arg(tableName))); + QVERIFY_SQL(q, prepare(QString("INSERT INTO %1 VALUES (?, ?, ?, ?, ?, ?, ?, ?)").arg(ts.tableName()))); QString aStr, bStr, cStr, dStr, eStr, fStr, gStr, hStr; q.bindValue(0, aStr.fill('A', 32)); @@ -1510,7 +1490,7 @@ void tst_QSqlDatabase::accessOdbc_strings() QVERIFY_SQL(q, exec()); - QVERIFY_SQL(q, exec(QString("SELECT aStr, bStr, cStr, dStr, eStr, fStr, gStr, hStr FROM %1").arg(tableName))); + QVERIFY_SQL(q, exec(QString("SELECT aStr, bStr, cStr, dStr, eStr, fStr, gStr, hStr FROM %1").arg(ts.tableName()))); q.next(); QCOMPARE(q.value(0).toString(), aStr); QCOMPARE(q.value(1).toString(), bStr); @@ -1528,9 +1508,10 @@ void tst_QSqlDatabase::ibase_numericFields() QFETCH(QString, dbName); QSqlDatabase db = QSqlDatabase::database(dbName); CHECK_DATABASE(db); + TableScope ts(db, "numericfields", __FILE__); + const auto &tableName = ts.tableName(); QSqlQuery q(db); - const QString tableName(qTableName("numericfields", __FILE__, db)); QVERIFY_SQL(q, exec(QString("CREATE TABLE %1 (id int not null, num1 NUMERIC(2,1), " "num2 NUMERIC(5,2), num3 NUMERIC(10,3), " "num4 NUMERIC(18,4))").arg(tableName))); @@ -1601,8 +1582,9 @@ void tst_QSqlDatabase::ibase_fetchBlobs() QFETCH(QString, dbName); QSqlDatabase db = QSqlDatabase::database(dbName); CHECK_DATABASE(db); + TableScope ts(db, "qtest_ibaseblobs", __FILE__); + const auto &tableName = ts.tableName(); - const QString tableName(qTableName("qtest_ibaseblobs", __FILE__, db)); QSqlQuery q(db); QVERIFY_SQL(q, exec(QString("CREATE TABLE %1 (blob1 BLOB segment size 256)").arg(tableName))); @@ -1633,13 +1615,11 @@ void tst_QSqlDatabase::ibase_procWithoutReturnValues() QFETCH(QString, dbName); QSqlDatabase db = QSqlDatabase::database(dbName); CHECK_DATABASE(db); + ProcScope ps(db, "qtest_proc1", __FILE__); QSqlQuery q(db); - const QString procName(qTableName("qtest_proc1", __FILE__, db)); - q.exec(QString("drop procedure %1").arg(procName)); - QVERIFY_SQL(q, exec("CREATE PROCEDURE " + procName + " (str VARCHAR(10))\nAS BEGIN\nstr='test';\nEND;")); - QVERIFY_SQL(q, exec(QString("execute procedure %1('qtest')").arg(procName))); - q.exec(QString("drop procedure %1").arg(procName)); + QVERIFY_SQL(q, exec("CREATE PROCEDURE " + ps.name() + " (str VARCHAR(10))\nAS BEGIN\nstr='test';\nEND;")); + QVERIFY_SQL(q, exec(QString("execute procedure %1('qtest')").arg(ps.name()))); } void tst_QSqlDatabase::ibase_procWithReturnValues() @@ -1647,12 +1627,10 @@ void tst_QSqlDatabase::ibase_procWithReturnValues() QFETCH(QString, dbName); QSqlDatabase db = QSqlDatabase::database(dbName); CHECK_DATABASE(db); - - const QString procName(qTableName("qtest_proc2", __FILE__, db)); + ProcScope ps(db, "qtest_proc2", __FILE__); QSqlQuery q(db); - q.exec(QString("drop procedure %1").arg(procName)); - QVERIFY_SQL(q, exec("CREATE PROCEDURE " + procName + " (" + QVERIFY_SQL(q, exec("CREATE PROCEDURE " + ps.name() + " (" "\nABC INTEGER)" "\nRETURNS (" "\nRESULT INTEGER)" @@ -1663,13 +1641,13 @@ void tst_QSqlDatabase::ibase_procWithReturnValues() "\nend")); // Interbase procedures can be executed in two ways: EXECUTE PROCEDURE or SELECT - QVERIFY_SQL(q, exec(QString("execute procedure %1(123)").arg(procName))); + QVERIFY_SQL(q, exec(QString("execute procedure %1(123)").arg(ps.name()))); QVERIFY_SQL(q, next()); QCOMPARE(q.value(0).toInt(), 1230); - QVERIFY_SQL(q, exec(QString("select result from %1(456)").arg(procName))); + QVERIFY_SQL(q, exec(QString("select result from %1(456)").arg(ps.name()))); QVERIFY_SQL(q, next()); QCOMPARE(q.value(0).toInt(), 4560); - QVERIFY_SQL(q, prepare(QLatin1String("execute procedure ")+procName+QLatin1String("(?)"))); + QVERIFY_SQL(q, prepare(QLatin1String("execute procedure ") + ps.name() + QLatin1String("(?)"))); q.bindValue(0, 123); QVERIFY_SQL(q, exec()); QVERIFY_SQL(q, next()); @@ -1678,8 +1656,6 @@ void tst_QSqlDatabase::ibase_procWithReturnValues() QVERIFY_SQL(q, exec()); QVERIFY_SQL(q, next()); QCOMPARE(q.value(0).toInt(), 4560); - - q.exec(QString("drop procedure %1").arg(procName)); } void tst_QSqlDatabase::formatValueTrimStrings() @@ -1736,13 +1712,13 @@ void tst_QSqlDatabase::odbc_bindBoolean() QSqlDriver::DbmsType dbType = tst_Databases::getDatabaseType(db); if (dbType == QSqlDriver::MySqlServer) QSKIP("MySql has inconsistent behaviour of bit field type across versions."); + TableScope ts(db, "qtestBindBool", __FILE__); QSqlQuery q(db); - const QString tableName = qTableName("qtestBindBool", __FILE__, db); - QVERIFY_SQL(q, exec("CREATE TABLE " + tableName + "(id int, boolvalue bit)")); + QVERIFY_SQL(q, exec("CREATE TABLE " + ts.tableName() + "(id int, boolvalue bit)")); // Bind and insert - QVERIFY_SQL(q, prepare("INSERT INTO " + tableName + " VALUES(?, ?)")); + QVERIFY_SQL(q, prepare("INSERT INTO " + ts.tableName() + " VALUES(?, ?)")); q.bindValue(0, 1); q.bindValue(1, true); QVERIFY_SQL(q, exec()); @@ -1751,7 +1727,7 @@ void tst_QSqlDatabase::odbc_bindBoolean() QVERIFY_SQL(q, exec()); // Retrive - QVERIFY_SQL(q, exec("SELECT id, boolvalue FROM " + tableName + " ORDER BY id")); + QVERIFY_SQL(q, exec("SELECT id, boolvalue FROM " + ts.tableName() + " ORDER BY id")); QVERIFY_SQL(q, next()); QCOMPARE(q.value(0).toInt(), 1); QCOMPARE(q.value(1).toBool(), true); @@ -1765,7 +1741,8 @@ void tst_QSqlDatabase::odbc_testqGetString() QFETCH(QString, dbName); QSqlDatabase db = QSqlDatabase::database(dbName); CHECK_DATABASE(db); - const QString testqGetString(qTableName("testqGetString", __FILE__, db)); + TableScope ts(db, "testqGetString", __FILE__); + const auto &testqGetString = ts.tableName(); QSqlQuery q(db); QSqlDriver::DbmsType dbType = tst_Databases::getDatabaseType(db); @@ -1845,8 +1822,9 @@ void tst_QSqlDatabase::oci_xmltypeSupport() QFETCH(QString, dbName); QSqlDatabase db = QSqlDatabase::database(dbName); CHECK_DATABASE(db); + TableScope ts(db, "qtest_xmltype", __FILE__); + const auto &tableName = ts.tableName(); - const QString tableName(qTableName("qtest_xmltype", __FILE__, db)); QString xml("<?xml version=\"1.0\"?>\n<TABLE_NAME>MY_TABLE</TABLE_NAME>\n"); QSqlQuery q(db); @@ -1924,14 +1902,14 @@ void tst_QSqlDatabase::odbc_uniqueidentifier() if (dbType != QSqlDriver::MSSqlServer) QSKIP("SQL Server (ODBC) specific test"); - const QString tableName(qTableName("qtest_sqlguid", __FILE__, db)); + TableScope ts(db, "qtest_sqlguid", __FILE__); QString guid = QString("AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE"); QString invalidGuid = QString("GAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE"); QSqlQuery q(db); - QVERIFY_SQL(q, exec(QString("CREATE TABLE %1(id uniqueidentifier)").arg(tableName))); + QVERIFY_SQL(q, exec(QString("CREATE TABLE %1(id uniqueidentifier)").arg(ts.tableName()))); - q.prepare(QString("INSERT INTO %1 VALUES(?)").arg(tableName));; + q.prepare(QString("INSERT INTO %1 VALUES(?)").arg(ts.tableName())); q.addBindValue(guid); QVERIFY_SQL(q, exec()); @@ -1940,7 +1918,7 @@ void tst_QSqlDatabase::odbc_uniqueidentifier() Continue); QVERIFY_SQL(q, exec()); - QVERIFY_SQL(q, exec(QString("SELECT id FROM %1").arg(tableName))); + QVERIFY_SQL(q, exec(QString("SELECT id FROM %1").arg(ts.tableName()))); QVERIFY_SQL(q, next()); QCOMPARE(q.value(0).toString(), guid); } @@ -1966,20 +1944,20 @@ void tst_QSqlDatabase::odbc_uintfield() QFETCH(QString, dbName); QSqlDatabase db = QSqlDatabase::database(dbName); CHECK_DATABASE(db); + TableScope ts(db, "uint_table", __FILE__); - const QString tableName(qTableName("uint_table", __FILE__, db)); - unsigned int val = 4294967295U; + constexpr auto val = std::numeric_limits<unsigned int>::max(); QSqlQuery q(db); if ( tst_Databases::isMSAccess( db ) ) - QVERIFY_SQL(q, exec(QString("CREATE TABLE %1(num number)").arg(tableName))); + QVERIFY_SQL(q, exec(QString("CREATE TABLE %1(num number)").arg(ts.tableName()))); else - QVERIFY_SQL(q, exec(QString("CREATE TABLE %1(num numeric(10))").arg(tableName))); - q.prepare(QString("INSERT INTO %1 VALUES(?)").arg(tableName)); + QVERIFY_SQL(q, exec(QString("CREATE TABLE %1(num numeric(10))").arg(ts.tableName()))); + q.prepare(QString("INSERT INTO %1 VALUES(?)").arg(ts.tableName())); q.addBindValue(val); QVERIFY_SQL(q, exec()); - q.exec(QString("SELECT num FROM %1").arg(tableName)); + q.exec(QString("SELECT num FROM %1").arg(ts.tableName())); if (q.next()) QCOMPARE(q.value(0).toUInt(), val); } @@ -2038,34 +2016,30 @@ void tst_QSqlDatabase::eventNotificationIBase() QSqlDatabase db = QSqlDatabase::database(dbName); CHECK_DATABASE(db); - const QString procedureName(qTableName("posteventProc", __FILE__, db)); + ProcScope ps(db, "posteventProc", __FILE__); QSqlDriver *driver=db.driver(); - QVERIFY_SQL(*driver, subscribeToNotification(procedureName)); + QVERIFY_SQL(*driver, subscribeToNotification(ps.name())); QTest::qWait(300); // Interbase needs some time to call the driver callback. db.transaction(); // InterBase events are posted from within transactions. QSqlQuery q(db); - q.exec(QString("DROP PROCEDURE %1").arg(procedureName)); - q.exec(QString("CREATE PROCEDURE %1\nAS BEGIN\nPOST_EVENT '%1';\nEND;").arg(procedureName)); - q.exec(QString("EXECUTE PROCEDURE %1").arg(procedureName)); - QSignalSpy spy(driver, QOverload<const QString &, QSqlDriver::NotificationSource, const QVariant &>::of(&QSqlDriver::notification)); + q.exec(QString("CREATE PROCEDURE %1\nAS BEGIN\nPOST_EVENT '%1';\nEND;").arg(ps.name())); + q.exec(QString("EXECUTE PROCEDURE %1").arg(ps.name())); + QSignalSpy spy(driver, &QSqlDriver::notification); db.commit(); // No notifications are posted until the transaction is committed. // Interbase needs some time to post the notification and call the driver callback. // This happends from another thread, and we have to process events in order for the // event handler in the driver to be executed and emit the notification signal. QTRY_COMPARE(spy.size(), 1); QList<QVariant> arguments = spy.takeFirst(); - QCOMPARE(arguments.at(0).toString(), procedureName); - QVERIFY_SQL(*driver, unsubscribeFromNotification(procedureName)); - q.exec(QString("DROP PROCEDURE %1").arg(procedureName)); + QCOMPARE(arguments.at(0).toString(), ps.name()); + QVERIFY_SQL(*driver, unsubscribeFromNotification(ps.name())); } void tst_QSqlDatabase::eventNotificationPSQL() { QFETCH(QString, dbName); QSqlDatabase db = QSqlDatabase::database(dbName); - if (db.driverName().compare(QLatin1String("QPSQL"), Qt::CaseInsensitive)) - QSKIP("QPSQL specific test"); CHECK_DATABASE(db); QSqlQuery query(db); @@ -2073,7 +2047,7 @@ void tst_QSqlDatabase::eventNotificationPSQL() QString payload = "payload"; QSqlDriver *driver = db.driver(); QVERIFY_SQL(*driver, subscribeToNotification(procedureName)); - QSignalSpy spy(driver, QOverload<const QString &, QSqlDriver::NotificationSource, const QVariant &>::of(&QSqlDriver::notification)); + QSignalSpy spy(driver, &QSqlDriver::notification); query.exec(QString("NOTIFY \"%1\", '%2'").arg(procedureName).arg(payload)); QTRY_COMPARE(spy.size(), 1); QList<QVariant> arguments = spy.takeFirst(); @@ -2087,15 +2061,13 @@ void tst_QSqlDatabase::eventNotificationSQLite() { QFETCH(QString, dbName); QSqlDatabase db = QSqlDatabase::database(dbName); - if (db.driverName().compare(QLatin1String("QSQLITE"), Qt::CaseInsensitive)) - QSKIP("QSQLITE specific test"); CHECK_DATABASE(db); TableScope ts(db, "sqlitnotifytest", __FILE__); TableScope tsEscape(db, "sqlitnotifytest", __FILE__, false); QSqlDriver *driver = db.driver(); - QSignalSpy spy(driver, QOverload<const QString &, QSqlDriver::NotificationSource, const QVariant &>::of(&QSqlDriver::notification)); + QSignalSpy spy(driver, &QSqlDriver::notification); QSqlQuery q(db); QVERIFY_SQL(q, exec("CREATE TABLE " + ts.tableName() + " (id INTEGER, realVal REAL)")); driver->subscribeToNotification(tsEscape.tableName()); @@ -2113,13 +2085,13 @@ void tst_QSqlDatabase::sqlite_bindAndFetchUInt() QFETCH(QString, dbName); QSqlDatabase db = QSqlDatabase::database(dbName); CHECK_DATABASE(db); + TableScope ts(db, "uint_test", __FILE__); QSqlQuery q(db); - const QString tableName(qTableName("uint_test", __FILE__, db)); - QVERIFY_SQL(q, exec(QString("CREATE TABLE %1(uint_field UNSIGNED INTEGER)").arg(tableName))); - QVERIFY_SQL(q, prepare(QString("INSERT INTO %1 VALUES(?)").arg(tableName))); + QVERIFY_SQL(q, exec(QString("CREATE TABLE %1(uint_field UNSIGNED INTEGER)").arg(ts.tableName()))); + QVERIFY_SQL(q, prepare(QString("INSERT INTO %1 VALUES(?)").arg(ts.tableName()))); q.addBindValue(4000000000U); QVERIFY_SQL(q, exec()); - QVERIFY_SQL(q, exec(QString("SELECT uint_field FROM %1").arg(tableName))); + QVERIFY_SQL(q, exec(QString("SELECT uint_field FROM %1").arg(ts.tableName()))); QVERIFY_SQL(q, next()); // All integers in SQLite are signed, so even though we bound the value @@ -2229,18 +2201,18 @@ void tst_QSqlDatabase::sqlite_enableRegexp() db.close(); db.setConnectOptions("QSQLITE_ENABLE_REGEXP"); QVERIFY_SQL(db, open()); + TableScope ts(db, "regexp_test", __FILE__); QSqlQuery q(db); - const QString tableName(qTableName("regexp_test", __FILE__, db)); - QVERIFY_SQL(q, exec(QString("CREATE TABLE %1(text TEXT)").arg(tableName))); - QVERIFY_SQL(q, prepare(QString("INSERT INTO %1 VALUES(?)").arg(tableName))); + QVERIFY_SQL(q, exec(QString("CREATE TABLE %1(text TEXT)").arg(ts.tableName()))); + QVERIFY_SQL(q, prepare(QString("INSERT INTO %1 VALUES(?)").arg(ts.tableName()))); q.addBindValue("a0"); QVERIFY_SQL(q, exec()); q.addBindValue("a1"); QVERIFY_SQL(q, exec()); QVERIFY_SQL(q, exec(QString("SELECT text FROM %1 WHERE text REGEXP 'a[^0]' " - "ORDER BY text").arg(tableName))); + "ORDER BY text").arg(ts.tableName()))); QVERIFY_SQL(q, next()); QCOMPARE(q.value(0).toString(), QString("a1")); QFAIL_SQL(q, next()); @@ -2365,5 +2337,32 @@ void tst_QSqlDatabase::multipleThreads() QTRY_VERIFY(t.isFinished()); } +void tst_QSqlDatabase::moveToThread() +{ + QFETCH(QString, dbName); + QSqlDatabase db = QSqlDatabase::database(dbName); + auto clonedDb = QSqlDatabase::cloneDatabase(db, "clonedDb"); + auto mainThread = QThread::currentThread(); + CHECK_DATABASE(db); + QCOMPARE(db.thread(), mainThread); + QCOMPARE(clonedDb.thread(), mainThread); + std::unique_ptr<QThread> t(QThread::create([&] { + db.moveToThread(mainThread); + QThread::currentThread()->exit(); + })); + db.moveToThread(t.get()); + QCOMPARE(db.thread(), t.get()); + QCOMPARE(clonedDb.thread(), mainThread); + t->start(); + QTRY_VERIFY(t->isRunning()); + QTRY_VERIFY(t->wait(30000)); + QCOMPARE(db.thread(), mainThread); + QCOMPARE(clonedDb.thread(), mainThread); + db = QSqlDatabase(); + clonedDb = QSqlDatabase(); + QSqlDatabase::removeDatabase("clonedDb"); +} + + QTEST_MAIN(tst_QSqlDatabase) #include "tst_qsqldatabase.moc" diff --git a/tests/auto/sql/kernel/qsqldriver/CMakeLists.txt b/tests/auto/sql/kernel/qsqldriver/CMakeLists.txt index 04f41409af..21dd3a6417 100644 --- a/tests/auto/sql/kernel/qsqldriver/CMakeLists.txt +++ b/tests/auto/sql/kernel/qsqldriver/CMakeLists.txt @@ -5,6 +5,12 @@ ## tst_qsqldriver Test: ##################################################################### +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qsqldriver LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + qt_internal_add_test(tst_qsqldriver SOURCES tst_qsqldriver.cpp diff --git a/tests/auto/sql/kernel/qsqldriver/tst_qsqldriver.cpp b/tests/auto/sql/kernel/qsqldriver/tst_qsqldriver.cpp index 85834b5179..fb8d804843 100644 --- a/tests/auto/sql/kernel/qsqldriver/tst_qsqldriver.cpp +++ b/tests/auto/sql/kernel/qsqldriver/tst_qsqldriver.cpp @@ -1,5 +1,5 @@ // Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> @@ -35,6 +35,7 @@ static bool driverSupportsDefaultValues(QSqlDriver::DbmsType dbType) case QSqlDriver::SQLite: case QSqlDriver::PostgreSQL: case QSqlDriver::Oracle: + case QSqlDriver::MySqlServer: return true; default: break; @@ -112,7 +113,7 @@ void tst_QSqlDriver::record() QSqlDatabase db = QSqlDatabase::database(dbName); CHECK_DATABASE(db); - QString tablename(qTableName("relTEST1", __FILE__, db)); + QString tablename(qTableName("relTEST1", __FILE__, db, false)); QStringList fields; fields << "id" << "name" << "title_key" << "another_title_key" << "more_data"; @@ -132,8 +133,14 @@ void tst_QSqlDriver::record() for (int i = 0; i < fields.size(); ++i) QCOMPARE(rec.fieldName(i), fields[i]); - if (driverSupportsDefaultValues(dbType)) - QCOMPARE(rec.field(QStringLiteral("name")).defaultValue().toString(), QStringLiteral("defaultVal")); + if (driverSupportsDefaultValues(dbType)) { + auto defVal = rec.field(QStringLiteral("name")).defaultValue().toString(); + if (dbType == QSqlDriver::MySqlServer && defVal.startsWith('\'') && defVal.endsWith('\'')) { + qDebug() << "MariaDB 10.6 default string value is escaped:" << defVal; + defVal = defVal.mid(1, defVal.size() - 2); + } + QCOMPARE(defVal, QStringLiteral("defaultVal")); + } if (dbType == QSqlDriver::Oracle || dbType == QSqlDriver::DB2) tablename = tablename.toUpper(); @@ -171,7 +178,7 @@ void tst_QSqlDriver::primaryIndex() QSqlDatabase db = QSqlDatabase::database(dbName); CHECK_DATABASE(db); - QString tablename(qTableName("relTEST1", __FILE__, db)); + QString tablename(qTableName("relTEST1", __FILE__, db, false)); //check that we can get primary index using unquoted mixed case table name QSqlIndex index = db.driver()->primaryIndex(tablename); QCOMPARE(index.count(), 1); diff --git a/tests/auto/sql/kernel/qsqlerror/CMakeLists.txt b/tests/auto/sql/kernel/qsqlerror/CMakeLists.txt index a456338a91..b604399ef1 100644 --- a/tests/auto/sql/kernel/qsqlerror/CMakeLists.txt +++ b/tests/auto/sql/kernel/qsqlerror/CMakeLists.txt @@ -5,6 +5,12 @@ ## tst_qsqlerror Test: ##################################################################### +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qsqlerror LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + qt_internal_add_test(tst_qsqlerror SOURCES tst_qsqlerror.cpp diff --git a/tests/auto/sql/kernel/qsqlerror/tst_qsqlerror.cpp b/tests/auto/sql/kernel/qsqlerror/tst_qsqlerror.cpp index c83867fcc4..2be7d08cf8 100644 --- a/tests/auto/sql/kernel/qsqlerror/tst_qsqlerror.cpp +++ b/tests/auto/sql/kernel/qsqlerror/tst_qsqlerror.cpp @@ -1,5 +1,5 @@ // Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> @@ -108,12 +108,16 @@ void tst_QSqlError::moveOperator() void tst_QSqlError::operators() { - QSqlError error1(QString(), QString(), QSqlError::NoError); - QSqlError error2(QString(), QString(), QSqlError::NoError); - QSqlError error3(QString(), QString(), QSqlError::UnknownError); + QSqlError error1(QStringLiteral("a"), QStringLiteral("b"), QSqlError::NoError, QStringLiteral("ec1")); + QSqlError error2(QStringLiteral("c"), QStringLiteral("d"), QSqlError::NoError, QStringLiteral("ec1")); + QSqlError error3(QString(), QString(), QSqlError::UnknownError, QStringLiteral("ec1")); + QSqlError error4(QString(), QString(), QSqlError::NoError, QStringLiteral("ec2")); + QSqlError error5(QString(), QString(), QSqlError::UnknownError, QStringLiteral("ec2")); QCOMPARE(error1, error2); QVERIFY(error1 != error3); + QVERIFY(error1 != error4); + QVERIFY(error4 != error5); } void tst_QSqlError::qtbug_74575() diff --git a/tests/auto/sql/kernel/qsqlfield/CMakeLists.txt b/tests/auto/sql/kernel/qsqlfield/CMakeLists.txt index 9e04209c0a..2fef227201 100644 --- a/tests/auto/sql/kernel/qsqlfield/CMakeLists.txt +++ b/tests/auto/sql/kernel/qsqlfield/CMakeLists.txt @@ -5,6 +5,12 @@ ## tst_qsqlfield Test: ##################################################################### +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qsqlfield LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + qt_internal_add_test(tst_qsqlfield SOURCES tst_qsqlfield.cpp diff --git a/tests/auto/sql/kernel/qsqlfield/tst_qsqlfield.cpp b/tests/auto/sql/kernel/qsqlfield/tst_qsqlfield.cpp index 79c774630d..5e012ba39c 100644 --- a/tests/auto/sql/kernel/qsqlfield/tst_qsqlfield.cpp +++ b/tests/auto/sql/kernel/qsqlfield/tst_qsqlfield.cpp @@ -1,5 +1,5 @@ // Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> @@ -39,6 +39,7 @@ private slots: void clear(); void setTableName_data(); void setTableName(); + void moveSemantics(); }; // Testing get/set functions @@ -344,5 +345,24 @@ void tst_QSqlField::setTableName() QCOMPARE(field.tableName(), tableName); } +void tst_QSqlField::moveSemantics() +{ + QSqlField field("test", QMetaType(QMetaType::QString), "testTable"); + QSqlField empty; + field.setValue("string"); + auto moved = std::move(field); + // `field` is now partially-formed + + // moving transfers state: + QCOMPARE(moved.value().toString(), QLatin1String("string")); + + // moved-from objects can be assigned-to: + field = empty; + QVERIFY(field.value().isNull()); + + // moved-from object can be destroyed: + moved = std::move(field); +} + QTEST_MAIN(tst_QSqlField) #include "tst_qsqlfield.moc" diff --git a/tests/auto/sql/kernel/qsqlindex/CMakeLists.txt b/tests/auto/sql/kernel/qsqlindex/CMakeLists.txt new file mode 100644 index 0000000000..3373948b5f --- /dev/null +++ b/tests/auto/sql/kernel/qsqlindex/CMakeLists.txt @@ -0,0 +1,21 @@ +# Copyright (C) 2023 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +##################################################################### +## tst_qsqlindex Test: +##################################################################### + +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qsqlindex LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +qt_internal_add_test(tst_qsqlindex + SOURCES + tst_qsqlindex.cpp + LIBRARIES + Qt::CorePrivate + Qt::Sql + Qt::SqlPrivate +) diff --git a/tests/auto/sql/kernel/qsqlindex/tst_qsqlindex.cpp b/tests/auto/sql/kernel/qsqlindex/tst_qsqlindex.cpp new file mode 100644 index 0000000000..2f44359133 --- /dev/null +++ b/tests/auto/sql/kernel/qsqlindex/tst_qsqlindex.cpp @@ -0,0 +1,126 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QTest> +#include <QtSql/QtSql> + +#include <QtCore/QDateTime> +#include <QtCore/QTimeZone> + +#include <numeric> + +#include "../qsqldatabase/tst_databases.h" + +using namespace Qt::StringLiterals; + +QString qtest; + +class tst_QSqlIndex : public QObject +{ + Q_OBJECT + +public: + tst_QSqlIndex(); + +private slots: + void construction_data(); + void construction(); + void assignment_data(); + void assignment(); + void basicFunctions(); +}; + +tst_QSqlIndex::tst_QSqlIndex() +{ +} + +void tst_QSqlIndex::construction_data() +{ + QTest::addColumn<QSqlIndex>("sqlIndex"); + QTest::addColumn<QString>("cursorName"); + QTest::addColumn<QString>("name"); + + const QString cursorName("cusorName"_L1); + const QString name("name"_L1); + QSqlIndex sqlIndex(cursorName, name); + QTest::newRow("ctor1") << QSqlIndex() << QString() << QString(); + QTest::newRow("ctor2") << sqlIndex << cursorName << name; + QTest::newRow("copy ctor") << QSqlIndex(sqlIndex) << cursorName << name; + QTest::newRow("move ctor") << QSqlIndex(std::move(sqlIndex)) << cursorName << name; +} + +void tst_QSqlIndex::construction() +{ + QFETCH(QSqlIndex, sqlIndex); + QFETCH(QString, cursorName); + QFETCH(QString, name); + + QCOMPARE(sqlIndex.cursorName(), cursorName); + QCOMPARE(sqlIndex.name(), name); + QCOMPARE(sqlIndex.isDescending(0), false); + QCOMPARE(sqlIndex.count(), 0); +} + +void tst_QSqlIndex::assignment_data() +{ + QTest::addColumn<QSqlIndex>("sqlIndex"); + QTest::addColumn<QString>("cursorName"); + QTest::addColumn<QString>("name"); + + const QString cursorName("cusorName"_L1); + const QString name("name"_L1); + QSqlIndex sqlIndex(cursorName, name); + QSqlIndex sqlIndex1 = sqlIndex; + QSqlIndex sqlIndex2 = std::move(sqlIndex); + sqlIndex = std::move(sqlIndex2); + QTest::newRow("copy assignment") << sqlIndex1 << cursorName << name; + QTest::newRow("move assignment") << sqlIndex << cursorName << name; +} + +void tst_QSqlIndex::assignment() +{ + QFETCH(QSqlIndex, sqlIndex); + QFETCH(QString, cursorName); + QFETCH(QString, name); + + QCOMPARE(sqlIndex.cursorName(), cursorName); + QCOMPARE(sqlIndex.name(), name); + QCOMPARE(sqlIndex.isDescending(0), false); + QCOMPARE(sqlIndex.count(), 0); +} + +void tst_QSqlIndex::basicFunctions() +{ + QSqlIndex sqlIndex("cursorName"_L1, "name"_L1); + const QSqlField f1("field1"_L1, QMetaType(QMetaType::UInt), "table1"_L1); + const QSqlField f2("field2"_L1, QMetaType(QMetaType::Double), "table2"_L1); + + QCOMPARE(sqlIndex.cursorName(), "cursorName"_L1); + sqlIndex.setCursorName("updatedCursorName"_L1); + QCOMPARE(sqlIndex.name(), "name"_L1); + sqlIndex.setName("updatedName"_L1); + QCOMPARE(sqlIndex.cursorName(), "updatedCursorName"_L1); + QCOMPARE(sqlIndex.name(), "updatedName"_L1); + + sqlIndex.append(f1); + QCOMPARE(sqlIndex.count(), 1); + QCOMPARE(sqlIndex.isDescending(0), false); + + sqlIndex.append(f2, true); + QCOMPARE(sqlIndex.count(), 2); + QCOMPARE(sqlIndex.isDescending(0), false); + QCOMPARE(sqlIndex.isDescending(1), true); + + sqlIndex.setDescending(0, true); + sqlIndex.setDescending(1, false); + sqlIndex.setDescending(2, true); + QCOMPARE(sqlIndex.count(), 2); + QCOMPARE(sqlIndex.isDescending(0), true); + QCOMPARE(sqlIndex.isDescending(1), false); + + QCOMPARE(sqlIndex.field(0), f1); + QCOMPARE(sqlIndex.field(1), f2); +} + +QTEST_MAIN(tst_QSqlIndex) +#include "tst_qsqlindex.moc" diff --git a/tests/auto/sql/kernel/qsqlquery/CMakeLists.txt b/tests/auto/sql/kernel/qsqlquery/CMakeLists.txt index a8e28704fd..e5a5b2b2f8 100644 --- a/tests/auto/sql/kernel/qsqlquery/CMakeLists.txt +++ b/tests/auto/sql/kernel/qsqlquery/CMakeLists.txt @@ -5,6 +5,12 @@ ## tst_qsqlquery Test: ##################################################################### +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qsqlquery LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + qt_internal_add_test(tst_qsqlquery SOURCES tst_qsqlquery.cpp diff --git a/tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp b/tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp index 048b9b0984..89033c30e0 100644 --- a/tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp +++ b/tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp @@ -1,5 +1,5 @@ // Copyright (C) 2022 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> #include <QtSql/QtSql> @@ -77,6 +77,9 @@ private slots: void psql_forwardOnlyQueryResultsLost_data() { generic_data("QPSQL"); } void psql_forwardOnlyQueryResultsLost(); + void positionalBindingEnabled_data() { generic_data(); } + void positionalBindingEnabled(); + // Bug-specific tests: void oci_nullBlob_data() { generic_data("QOCI"); } void oci_nullBlob(); @@ -170,11 +173,11 @@ private slots: void task_250026(); void crashQueryOnCloseDatabase(); - void task_233829_data() { generic_data("QPSQL"); } - void task_233829(); + void testNaN_data() { generic_data("QPSQL"); } + void testNaN(); - void QTBUG_12477_data() { generic_data("QPSQL"); } - void QTBUG_12477(); + void psqlNumericMetadata_data() { generic_data("QPSQL"); } + void psqlNumericMetadata(); void sqlServerReturn0_data() { generic_data(); } void sqlServerReturn0(); @@ -240,12 +243,26 @@ private slots: void QTBUG_73286_data() { generic_data("QODBC"); } void QTBUG_73286(); + void insertVarChar1_data() { generic_data("QODBC"); } + void insertVarChar1(); + void dateTime_data(); void dateTime(); void ibaseArray_data() { generic_data("QIBASE"); } void ibaseArray(); + void ibaseDateTimeWithTZ_data(); + void ibaseDateTimeWithTZ(); + void ibaseTimeStampTzArray_data() { generic_data("QIBASE"); } + void ibaseTimeStampTzArray(); + void ibaseInt128_data() { generic_data("QIBASE"); } + void ibaseInt128(); + + + void psqlJsonOperator_data() { generic_data("QPSQL"); } + void psqlJsonOperator(); + // Double addDatabase() with same name leaves system in a state that breaks // invalidQuery() if run later; so put this one last ! void prematureExec_data() { generic_data(); } @@ -332,59 +349,8 @@ void tst_QSqlQuery::dropTestTables(QSqlDatabase db) // Drop all the table in case a testcase failed: tablenames << qtest << qTableName("qtest_null", __FILE__, db) - << qTableName("qtest_writenull", __FILE__, db) - << qTableName("qtest_blob", __FILE__, db) - << qTableName("qtest_bittest", __FILE__, db) - << qTableName("qtest_nullblob", __FILE__, db) - << qTableName("qtest_rawtest", __FILE__, db) - << qTableName("qtest_precision", __FILE__, db) - << qTableName("qtest_prepare", __FILE__, db) - << qTableName("qtestj1", __FILE__, db) - << qTableName("qtestj2", __FILE__, db) - << qTableName("char1Select", __FILE__, db) - << qTableName("char1SU", __FILE__, db) - << qTableName("qxmltest", __FILE__, db) - << qTableName("qtest_exerr", __FILE__, db) - << qTableName("qtest_empty", __FILE__, db) - << qTableName("clobby", __FILE__, db) - << qTableName("bindtest", __FILE__, db) - << qTableName("more_results", __FILE__, db) - << qTableName("blobstest", __FILE__, db) - << qTableName("oraRowId", __FILE__, db) - << qTableName("bug43874", __FILE__, db) - << qTableName("bug6421", __FILE__, db).toUpper() - << qTableName("bug5765", __FILE__, db) - << qTableName("bug6852", __FILE__, db) - << qTableName("bug21884", __FILE__, db) - << qTableName("bug23895", __FILE__, db) - << qTableName("qtest_lockedtable", __FILE__, db) - << qTableName("Planet", __FILE__, db) - << qTableName("task_250026", __FILE__, db) - << qTableName("task_234422", __FILE__, db) - << qTableName("test141895", __FILE__, db) - << qTableName("qtest_oraOCINumber", __FILE__, db) - << qTableName("bug2192", __FILE__, db) << qTableName("tst_record", __FILE__, db); - if (dbType == QSqlDriver::PostgreSQL) - tablenames << qTableName("task_233829", __FILE__, db); - - if (dbType == QSqlDriver::SQLite) - tablenames << qTableName("record_sqlite", __FILE__, db); - - if (dbType == QSqlDriver::MSSqlServer || dbType == QSqlDriver::Oracle) - tablenames << qTableName("qtest_longstr", __FILE__, db); - - if (dbType == QSqlDriver::MSSqlServer) { - QSqlQuery q(db); - q.exec("DROP PROCEDURE " + qTableName("test141895_proc", __FILE__, db)); - } - - if (dbType == QSqlDriver::MySqlServer) { - QSqlQuery q(db); - q.exec("DROP PROCEDURE IF EXISTS " + qTableName("bug6852_proc", __FILE__, db)); - } - tst_Databases::safeDropTables(db, tablenames); if (dbType == QSqlDriver::Oracle) { @@ -452,12 +418,11 @@ void tst_QSqlQuery::char1Select() CHECK_DATABASE(db); { + TableScope ts(db, "char1Select", __FILE__); QSqlQuery q(db); - const QString tbl = qTableName("char1Select", __FILE__, db); - q.exec("drop table " + tbl); - QVERIFY_SQL(q, exec(QLatin1String("create table %1 (id char(1))").arg(tbl))); - QVERIFY_SQL(q, exec(QLatin1String("insert into %1 values ('a')").arg(tbl))); - QVERIFY_SQL(q, exec("select * from " + tbl)); + QVERIFY_SQL(q, exec(QLatin1String("create table %1 (id char(1))").arg(ts.tableName()))); + QVERIFY_SQL(q, exec(QLatin1String("insert into %1 values ('a')").arg(ts.tableName()))); + QVERIFY_SQL(q, exec("select * from " + ts.tableName())); QVERIFY(q.next()); if (tst_Databases::getDatabaseType(db) == QSqlDriver::Interbase) QCOMPARE(q.value(0).toString().left(1), u"a"); @@ -481,9 +446,9 @@ void tst_QSqlQuery::char1SelectUnicode() QSKIP("Database not unicode capable"); QString uniStr(QChar(0x0915)); // DEVANAGARI LETTER KA + TableScope ts(db, "char1SU", __FILE__); QSqlQuery q(db); QLatin1String createQuery; - const QString char1SelectUnicode(qTableName("char1SU", __FILE__, db)); switch (dbType) { case QSqlDriver::MimerSQL: @@ -506,12 +471,12 @@ void tst_QSqlQuery::char1SelectUnicode() break; } - QVERIFY_SQL(q, exec(createQuery.arg(char1SelectUnicode))); - QVERIFY_SQL(q, prepare(QLatin1String("insert into %1 values(?)").arg(char1SelectUnicode))); + QVERIFY_SQL(q, exec(createQuery.arg(ts.tableName()))); + QVERIFY_SQL(q, prepare(QLatin1String("insert into %1 values(?)").arg(ts.tableName()))); q.bindValue(0, uniStr); QVERIFY_SQL(q, exec()); - QVERIFY_SQL(q, exec("select * from " + char1SelectUnicode)); + QVERIFY_SQL(q, exec("select * from " + ts.tableName())); QVERIFY(q.next()); if (!q.value(0).toString().isEmpty()) @@ -526,7 +491,8 @@ void tst_QSqlQuery::oraRowId() QFETCH(QString, dbName); QSqlDatabase db = QSqlDatabase::database(dbName); CHECK_DATABASE(db); - const QString oraRowId(qTableName("oraRowId", __FILE__, db)); + TableScope ts(db, "oraRowId", __FILE__); + const auto &oraRowId = ts.tableName(); QSqlQuery q(db); QVERIFY_SQL(q, exec("select rowid from " + qtest)); @@ -562,7 +528,7 @@ void tst_QSqlQuery::mysql_outValues() QSqlDatabase db = QSqlDatabase::database(dbName); CHECK_DATABASE(db); const QString hello(qTableName("hello", __FILE__, db)); - const QString qtestproc(qTableName("qtestproc", __FILE__, db)); + ProcScope ps(db, "qtestproc", __FILE__); QSqlQuery q(db); @@ -584,25 +550,22 @@ void tst_QSqlQuery::mysql_outValues() QCOMPARE(q.value(0).toString(), u"Hello harald"); QVERIFY_SQL(q, exec("drop function " + hello)); - q.exec("drop procedure " + qtestproc); QVERIFY_SQL(q, exec(QLatin1String("create procedure %1 () BEGIN " - "select * from %2 order by id; END").arg(qtestproc, qtest))); - QVERIFY_SQL(q, exec(QLatin1String("call %1()").arg(qtestproc))); + "select * from %2 order by id; END").arg(ps.name(), qtest))); + QVERIFY_SQL(q, exec(QLatin1String("call %1()").arg(ps.name()))); QVERIFY_SQL(q, next()); QCOMPARE(q.value(1).toString(), u"VarChar1"); - QVERIFY_SQL(q, exec("drop procedure " + qtestproc)); + QVERIFY_SQL(q, exec("drop procedure " + ps.name())); QVERIFY_SQL(q, exec(QLatin1String("create procedure %1 (OUT param1 INT) " - "BEGIN set param1 = 42; END").arg(qtestproc))); + "BEGIN set param1 = 42; END").arg(ps.name()))); - QVERIFY_SQL(q, exec(QLatin1String("call %1 (@out)").arg(qtestproc))); + QVERIFY_SQL(q, exec(QLatin1String("call %1 (@out)").arg(ps.name()))); QVERIFY_SQL(q, exec("select @out")); QCOMPARE(q.record().fieldName(0), u"@out"); QVERIFY_SQL(q, next()); QCOMPARE(q.value(0).toInt(), 42); - - QVERIFY_SQL(q, exec("drop procedure " + qtestproc)); } void tst_QSqlQuery::bindBool() @@ -785,7 +748,8 @@ void tst_QSqlQuery::oraClob() QFETCH(QString, dbName); QSqlDatabase db = QSqlDatabase::database(dbName); CHECK_DATABASE(db); - const QString clobby(qTableName("clobby", __FILE__, db)); + TableScope ts(db, "clobby", __FILE__); + const auto &clobby = ts.tableName(); QSqlQuery q(db); @@ -861,19 +825,15 @@ void tst_QSqlQuery::storedProceduresIBase() QFETCH(QString, dbName); QSqlDatabase db = QSqlDatabase::database(dbName); CHECK_DATABASE(db); + ProcScope ps(db, "TESTPROC", __FILE__); QSqlQuery q(db); - const auto procName = qTableName("TESTPROC", __FILE__, db); - q.exec("drop procedure " + procName); - QVERIFY_SQL(q, exec(QLatin1String("create procedure %1 RETURNS (x integer, y varchar(20)) " "AS BEGIN " " x = 42; " " y = 'Hello Anders'; " - "END").arg(procName))); - const auto tidier = qScopeGuard([&]() { q.exec("drop procedure " + procName); }); - - QVERIFY_SQL(q, prepare("execute procedure " + procName)); + "END").arg(ps.name()))); + QVERIFY_SQL(q, prepare("execute procedure " + ps.name())); QVERIFY_SQL(q, exec()); // Check for a valid result set: @@ -900,12 +860,11 @@ void tst_QSqlQuery::outValuesDB2() if (!db.driver()->hasFeature(QSqlDriver::PreparedQueries)) QSKIP("Test requires prepared query support"); - QSqlQuery q(db); + ProcScope ps(db, "tst_outValues", __FILE__); + QSqlQuery q(db); q.setForwardOnly(true); - const QString procName = qTableName("tst_outValues", __FILE__, db); - q.exec("drop procedure " + procName); // non-fatal QVERIFY_SQL(q, exec(QLatin1String("CREATE PROCEDURE %1 " "(OUT x int, OUT x2 double, OUT x3 char(20))\n" "LANGUAGE SQL\n" @@ -913,9 +872,9 @@ void tst_QSqlQuery::outValuesDB2() " SET x = 42;\n" " SET x2 = 4.2;\n" " SET x3 = 'Homer';\n" - "END P1").arg(procName))); + "END P1").arg(ps.name()))); - QVERIFY_SQL(q, prepare(QLatin1String("call %1(?, ?, ?)").arg(procName))); + QVERIFY_SQL(q, prepare(QLatin1String("call %1(?, ?, ?)").arg(ps.name()))); q.addBindValue(0, QSql::Out); q.addBindValue(0.0, QSql::Out); @@ -933,11 +892,11 @@ void tst_QSqlQuery::outValues() QFETCH(QString, dbName); QSqlDatabase db = QSqlDatabase::database(dbName); CHECK_DATABASE(db); - const QString tst_outValues(qTableName("tst_outValues", __FILE__, db)); if (!db.driver()->hasFeature(QSqlDriver::PreparedQueries)) QSKIP("Test requires prepared query support"); + ProcScope ps(db, "tst_outValues", __FILE__); QSqlQuery q(db); q.setForwardOnly(true); @@ -951,7 +910,6 @@ void tst_QSqlQuery::outValues() caller = QLatin1String("call %1(?)"); break; case QSqlDriver::DB2: - q.exec("drop procedure " + tst_outValues); // non-fatal creator = QLatin1String("CREATE PROCEDURE %1 (OUT x int)\n" "LANGUAGE SQL\n" "P1: BEGIN\n" @@ -960,7 +918,6 @@ void tst_QSqlQuery::outValues() caller = QLatin1String("call %1(?)"); break; case QSqlDriver::MSSqlServer: - q.exec("drop procedure " + tst_outValues); // non-fatal creator = QLatin1String("create procedure %1 (@x int out) as\n" "begin\n" " set @x = 42\n" @@ -971,8 +928,8 @@ void tst_QSqlQuery::outValues() QSKIP("Don't know how to create a stored procedure for this database server, " "please fix this test"); } - QVERIFY_SQL(q, exec(creator.arg(tst_outValues))); - QVERIFY(q.prepare(caller.arg(tst_outValues))); + QVERIFY_SQL(q, exec(creator.arg(ps.name()))); + QVERIFY(q.prepare(caller.arg(ps.name()))); q.addBindValue(0, QSql::Out); @@ -998,15 +955,15 @@ void tst_QSqlQuery::blob() for (int i = 0; i < ba.size(); ++i) ba[i] = i % 256; + TableScope ts(db, "qtest_blob", __FILE__); QSqlQuery q(db); q.setForwardOnly(true); - const QString tableName = qTableName("qtest_blob", __FILE__, db); QVERIFY_SQL(q, exec(QLatin1String("create table %1 (id int not null primary key, t_blob %2)") - .arg(tableName, tst_Databases::blobTypeName(db, BLOBSIZE)))); + .arg(ts.tableName(), tst_Databases::blobTypeName(db, BLOBSIZE)))); QVERIFY_SQL(q, prepare(QLatin1String("insert into %1 (id, t_blob) values (?, ?)") - .arg(tableName))); + .arg(ts.tableName()))); for (int i = 0; i < BLOBCOUNT; ++i) { q.addBindValue(i); @@ -1014,7 +971,7 @@ void tst_QSqlQuery::blob() QVERIFY_SQL(q, exec()); } - QVERIFY_SQL(q, exec("select * from " + tableName)); + QVERIFY_SQL(q, exec("select * from " + ts.tableName())); for (int i = 0; i < BLOBCOUNT; ++i) { QVERIFY(q.next()); @@ -1024,10 +981,10 @@ void tst_QSqlQuery::blob() "array sizes differ, expected (at least) %" PRIdQSIZETYPE ", got %" PRIdQSIZETYPE, ba.size(), res.size()))); - for (int i2 = 0; i2 < ba.size(); ++i2) { + for (qsizetype i2 = 0; i2 < ba.size(); ++i2) { if (res[i2] != ba[i2]) { QFAIL(qPrintable(QString::asprintf( - "ByteArrays differ at position %d, expected %hhu, got %hhu", + "ByteArrays differ at position %lld, expected %hhu, got %hhu", i2, ba[i2], res[i2]))); } } @@ -1780,9 +1737,6 @@ void tst_QSqlQuery::writeNull() CHECK_DATABASE(db); const QSqlDriver::DbmsType dbType = tst_Databases::getDatabaseType(db); - QSqlQuery q(db); - const QString tableName = qTableName("qtest_writenull", __FILE__, db); - // The test data table is already used, so use a local hash to exercise the various // cases from the QSqlResultPrivate::isVariantNull helper. Only PostgreSQL and Mimer SQL // supports QUuid. @@ -1800,7 +1754,7 @@ void tst_QSqlQuery::writeNull() // Helper to count rows with null values in the data column. // Since QSqlDriver::QuerySize might not be supported, we have to count anyway - const auto countRowsWithNull = [&]{ + const auto countRowsWithNull = [&](QSqlQuery &q, const QString &tableName){ q.exec(QLatin1String("select id, data from %1 where data is null").arg(tableName)); int size = 0; while (q.next()) @@ -1809,37 +1763,37 @@ void tst_QSqlQuery::writeNull() }; for (const auto &nullableType : nullableTypes.keys()) { - const auto tableGuard = qScopeGuard([&]{ - q.exec("drop table " + tableName); - }); + TableScope ts(db, "qtest_writenull", __FILE__); + QSqlQuery q(db); + const QVariant nonNullValue = nullableTypes.value(nullableType); // some useful diagnostic output in case of any test failure auto errorHandler = qScopeGuard([&]{ qWarning() << "Test failure for data type" << nonNullValue.metaType().name(); - q.exec("select id, data from " + tableName); + q.exec("select id, data from " + ts.tableName()); while (q.next()) qWarning() << q.value(0) << q.value(1); }); QString createQuery = QLatin1String("create table %3 (id int, data %1%2)") .arg(nullableType, dbType == QSqlDriver::MSSqlServer || dbType == QSqlDriver::Sybase ? " null" : "", - tableName); + ts.tableName()); QVERIFY_SQL(q, exec(createQuery)); int expectedNullCount = 0; // Verify that inserting a non-null value works: - QVERIFY_SQL(q, prepare(QLatin1String("insert into %1 values(:id, :data)").arg(tableName))); + QVERIFY_SQL(q, prepare(QLatin1String("insert into %1 values(:id, :data)").arg(ts.tableName()))); q.bindValue(":id", expectedNullCount); q.bindValue(":data", nonNullValue); QVERIFY_SQL(q, exec()); - QCOMPARE(countRowsWithNull(), expectedNullCount); + QCOMPARE(countRowsWithNull(q, ts.tableName()), expectedNullCount); // Verify that inserting using a null QVariant produces a null entry in the database: - QVERIFY_SQL(q, prepare(QLatin1String("insert into %1 values(:id, :data)").arg(tableName))); + QVERIFY_SQL(q, prepare(QLatin1String("insert into %1 values(:id, :data)").arg(ts.tableName()))); q.bindValue(":id", ++expectedNullCount); q.bindValue(":data", QVariant()); QVERIFY_SQL(q, exec()); - QCOMPARE(countRowsWithNull(), expectedNullCount); + QCOMPARE(countRowsWithNull(q, ts.tableName()), expectedNullCount); // Verify that writing a null-value (but not a null-variant) produces a // null entry in the database: @@ -1854,11 +1808,11 @@ void tst_QSqlQuery::writeNull() const QVariant nullValueVariant(nullableMetaType, defaultData); QVERIFY(!nullValueVariant.isNull()); - QVERIFY_SQL(q, prepare(QLatin1String("insert into %1 values(:id, :data)").arg(tableName))); + QVERIFY_SQL(q, prepare(QLatin1String("insert into %1 values(:id, :data)").arg(ts.tableName()))); q.bindValue(":id", ++expectedNullCount); q.bindValue(":data", nullValueVariant); QVERIFY_SQL(q, exec()); - QCOMPARE(countRowsWithNull(), expectedNullCount); + QCOMPARE(countRowsWithNull(q, ts.tableName()), expectedNullCount); // All tests passed for this type if we got here, so don't print diagnostics: errorHandler.dismiss(); @@ -1871,19 +1825,19 @@ void tst_QSqlQuery::oci_nullBlob() QFETCH(QString, dbName); QSqlDatabase db = QSqlDatabase::database(dbName); CHECK_DATABASE(db); - const QString qtest_nullblob(qTableName("qtest_nullblob", __FILE__, db)); + TableScope ts(db, "qtest_nullblob", __FILE__); QSqlQuery q(db); QVERIFY_SQL(q, exec(QLatin1String("create table %1 (id int primary key, bb blob)") - .arg(qtest_nullblob))); + .arg(ts.tableName()))); QVERIFY_SQL(q, exec(QLatin1String("insert into %1 values (0, EMPTY_BLOB())") - .arg(qtest_nullblob))); - QVERIFY_SQL(q, exec(QLatin1String("insert into %1 values (1, NULL)").arg(qtest_nullblob))); + .arg(ts.tableName()))); + QVERIFY_SQL(q, exec(QLatin1String("insert into %1 values (1, NULL)").arg(ts.tableName()))); QVERIFY_SQL(q, exec(QLatin1String("insert into %1 values (2, 'aabbcc00112233445566')") - .arg(qtest_nullblob))); + .arg(ts.tableName()))); // Necessary otherwise Oracle will bombard you with internal errors: q.setForwardOnly(true); - QVERIFY_SQL(q, exec(QLatin1String("select * from %1 order by id").arg(qtest_nullblob))); + QVERIFY_SQL(q, exec(QLatin1String("select * from %1 order by id").arg(ts.tableName()))); QVERIFY(q.next()); QVERIFY(q.value(1).toByteArray().isEmpty()); @@ -1904,15 +1858,15 @@ void tst_QSqlQuery::oci_rawField() QFETCH(QString, dbName); QSqlDatabase db = QSqlDatabase::database(dbName); CHECK_DATABASE(db); - const QString qtest_rawtest(qTableName("qtest_rawtest", __FILE__, db)); + TableScope ts(db, "qtest_rawtest", __FILE__); QSqlQuery q(db); q.setForwardOnly(true); - QVERIFY_SQL(q, exec(QLatin1String("create table %1 (id int, col raw(20))").arg(qtest_rawtest))); - QVERIFY_SQL(q, exec(QLatin1String("insert into %1 values (0, NULL)").arg(qtest_rawtest))); + QVERIFY_SQL(q, exec(QLatin1String("create table %1 (id int, col raw(20))").arg(ts.tableName()))); + QVERIFY_SQL(q, exec(QLatin1String("insert into %1 values (0, NULL)").arg(ts.tableName()))); QVERIFY_SQL(q, exec(QLatin1String("insert into %1 values (1, '00aa1100ddeeff')") - .arg(qtest_rawtest))); - QVERIFY_SQL(q, exec(QLatin1String("select col from %1 order by id").arg(qtest_rawtest))); + .arg(ts.tableName()))); + QVERIFY_SQL(q, exec(QLatin1String("select col from %1 order by id").arg(ts.tableName()))); QVERIFY(q.next()); QVERIFY(q.isNull(0)); QVERIFY(q.value(0).toByteArray().isEmpty()); @@ -1924,53 +1878,54 @@ void tst_QSqlQuery::oci_rawField() // Test whether we can fetch values with more than DOUBLE precision // note that SQLite highest precision is that of a double, although // you can define field with higher precision: +// Test whether we can fetch values with more than DOUBLE precision +// note that SQLite highest precision is that of a double, although +// you can define field with higher precision: void tst_QSqlQuery::precision() { QFETCH(QString, dbName); QSqlDatabase db = QSqlDatabase::database(dbName); CHECK_DATABASE(db); const QSqlDriver::DbmsType dbType = tst_Databases::getDatabaseType(db); - if (dbType == QSqlDriver::Interbase) - QSKIP("DB unable to store high precision"); const auto tidier = qScopeGuard([db, oldPrecision = db.driver()->numericalPrecisionPolicy()]() { db.driver()->setNumericalPrecisionPolicy(oldPrecision); }); + int digits = 21; + int decimals = 20; + std::array<QLatin1String, 2> precStrings = { "1.2345678901234567891"_L1, + "-1.2345678901234567891"_L1 }; + if (dbType == QSqlDriver::SQLite) { + // SQLite 3.45 does not return more, even when speicfied + digits = 17; + decimals = 16; + precStrings = { "1.2345678901234567"_L1, "-1.2345678901234567"_L1 }; + } else if (dbType == QSqlDriver::Sybase) + decimals = 18; db.driver()->setNumericalPrecisionPolicy(QSql::HighPrecision); - const QString qtest_precision(qTableName("qtest_precision", __FILE__, db)); - static const QLatin1String precStr("1.2345678901234567891"); - - { - // need a new scope for SQLITE - QSqlQuery q(db); + TableScope ts(db, "qtest_precision", __FILE__); - q.exec("drop table " + qtest_precision); - QVERIFY_SQL(q, exec(QLatin1String(tst_Databases::isMSAccess(db) - ? "CREATE TABLE %1 (col1 number)" - : "CREATE TABLE %1 (col1 numeric(21, 20))") - .arg(qtest_precision))); - - QVERIFY_SQL(q, exec(QLatin1String("INSERT INTO %1 (col1) VALUES (%2)") - .arg(qtest_precision, precStr))); - QVERIFY_SQL(q, exec("SELECT * FROM " + qtest_precision)); + QSqlQuery q(db); + QString stmt = "CREATE TABLE %1 (col1 numeric("_L1 + QString::number(digits) + ", "_L1 + + QString::number(decimals) + "))"_L1; + if (tst_Databases::isMSAccess(db)) + stmt = "CREATE TABLE %1 (col1 number)"_L1; + QVERIFY_SQL(q, exec(stmt.arg(ts.tableName()))); + for (const auto &precStr : precStrings) { + QVERIFY_SQL(q, exec("DELETE FROM %1"_L1.arg(ts.tableName()))); + QVERIFY_SQL(q, exec("INSERT INTO %1 (col1) VALUES (%2)"_L1.arg(ts.tableName(), precStr))); + QVERIFY_SQL(q, exec("SELECT * FROM " + ts.tableName())); QVERIFY(q.next()); const QString val = q.value(0).toString(); if (!val.startsWith(precStr)) { int i = 0; - while (i < val.size() && precStr[i] != 0 && precStr[i] == val[i].toLatin1()) + while (i < val.size() && precStr[i] != 0 && precStr[i] == val[i]) ++i; - - // TDS has crappy precisions by default - if (dbType == QSqlDriver::Sybase) { - if (i < 18) - qWarning("TDS didn't return the right precision"); - } else { - qWarning() << tst_Databases::dbToString(db) << "didn't return the right precision (" - << i << "out of 21)," << val; - } + qWarning() << tst_Databases::dbToString(db) << "didn't return the right precision (" + << i << "out of " << digits << ")," << val; } - } // SQLITE scope + } } void tst_QSqlQuery::nullResult() @@ -1999,29 +1954,29 @@ void tst_QSqlQuery::joins() QSqlDatabase db = QSqlDatabase::database(dbName); CHECK_DATABASE(db); const QSqlDriver::DbmsType dbType = tst_Databases::getDatabaseType(db); - const QString qtestj1(qTableName("qtestj1", __FILE__, db)); - const QString qtestj2(qTableName("qtestj2", __FILE__, db)); if (dbType == QSqlDriver::Oracle || dbType == QSqlDriver::Sybase || dbType == QSqlDriver::Interbase || db.driverName().startsWith("QODBC")) { // Oracle broken beyond recognition - cannot outer join on more than one table: QSKIP("DBMS cannot understand standard SQL"); } + TableScope j1(db, "qtestj1", __FILE__); + TableScope j2(db, "qtestj2", __FILE__); QSqlQuery q(db); - QVERIFY_SQL(q, exec(QLatin1String("create table %1 (id1 int, id2 int)").arg(qtestj1))); - QVERIFY_SQL(q, exec(QLatin1String("create table %1 (id int, name varchar(20))").arg(qtestj2))); - QVERIFY_SQL(q, exec(QLatin1String("insert into %1 values (1, 1)").arg(qtestj1))); - QVERIFY_SQL(q, exec(QLatin1String("insert into %1 values (1, 2)").arg(qtestj1))); - QVERIFY_SQL(q, exec(QLatin1String("insert into %1 values(1, 'trenton')").arg(qtestj2))); - QVERIFY_SQL(q, exec(QLatin1String("insert into %1 values(2, 'marius')").arg(qtestj2))); + QVERIFY_SQL(q, exec(QLatin1String("create table %1 (id1 int, id2 int)").arg(j1.tableName()))); + QVERIFY_SQL(q, exec(QLatin1String("create table %1 (id int, name varchar(20))").arg(j2.tableName()))); + QVERIFY_SQL(q, exec(QLatin1String("insert into %1 values (1, 1)").arg(j1.tableName()))); + QVERIFY_SQL(q, exec(QLatin1String("insert into %1 values (1, 2)").arg(j1.tableName()))); + QVERIFY_SQL(q, exec(QLatin1String("insert into %1 values(1, 'trenton')").arg(j2.tableName()))); + QVERIFY_SQL(q, exec(QLatin1String("insert into %1 values(2, 'marius')").arg(j2.tableName()))); QVERIFY_SQL(q, exec(QLatin1String( "select qtestj1.id1, qtestj1.id2, qtestj2.id, qtestj2.name, " "qtestj3.id, qtestj3.name from %1 qtestj1 left outer join %2 qtestj2 " "on (qtestj1.id1 = qtestj2.id) left outer join %2 as qtestj3 " - "on (qtestj1.id2 = qtestj3.id)").arg(qtestj1, qtestj2))); + "on (qtestj1.id2 = qtestj3.id)").arg(j1.tableName(), j2.tableName()))); QVERIFY(q.next()); QCOMPARE(q.value(0).toInt(), 1); @@ -2069,7 +2024,8 @@ void tst_QSqlQuery::prepare_bind_exec() QSqlDatabase db = QSqlDatabase::database(dbName); CHECK_DATABASE(db); const QSqlDriver::DbmsType dbType = tst_Databases::getDatabaseType(db); - const QString qtest_prepare(qTableName("qtest_prepare", __FILE__, db)); + TableScope ts(db, "qtest_prepare", __FILE__); + const auto &qtest_prepare = ts.tableName(); if (dbType == QSqlDriver::DB2) QSKIP("Needs someone with more Unicode knowledge than I have to fix"); @@ -2110,13 +2066,10 @@ void tst_QSqlQuery::prepare_bind_exec() break; } - q.exec("drop table " + qtest_prepare); QVERIFY_SQL(q, exec(createQuery.arg(qtest_prepare))); QVERIFY(q.prepare(QLatin1String("insert into %1 (id, name) values (:id, :name)") .arg(qtest_prepare))); - int i; - - for (i = 0; i < 6; ++i) { + for (int i = 0; i < 6; ++i) { q.bindValue(":name", values[i]); q.bindValue(":id", i); QVERIFY_SQL(q, exec()); @@ -2124,6 +2077,12 @@ void tst_QSqlQuery::prepare_bind_exec() QCOMPARE(m.size(), qsizetype(2)); QCOMPARE(m.at(0).toInt(), i); QCOMPARE(m.at(1).toString(), values[i]); + const QStringList n = q.boundValueNames(); + QCOMPARE(n.size(), 2); + QCOMPARE(n.at(0), ":id"); + QCOMPARE(n.at(1), ":name"); + QCOMPARE(q.boundValueName(0), ":id"); + QCOMPARE(q.boundValueName(1), ":name"); } q.bindValue(":id", 8); @@ -2136,7 +2095,7 @@ void tst_QSqlQuery::prepare_bind_exec() } QVERIFY_SQL(q, exec(QLatin1String("SELECT * FROM %1 order by id").arg(qtest_prepare))); - for (i = 0; i < 6; ++i) { + for (int i = 0; i < 6; ++i) { QVERIFY(q.next()); QCOMPARE(q.value(0).toInt(), i); QCOMPARE(q.value(1).toString().trimmed(), values[i]); @@ -2161,7 +2120,7 @@ void tst_QSqlQuery::prepare_bind_exec() QVERIFY(q.exec(QLatin1String("select * from %1 where id > 98 order by id") .arg(qtest_prepare))); - for (i = 99; i <= 100; ++i) { + for (int i = 99; i <= 100; ++i) { QVERIFY(q.next()); QCOMPARE(q.value(0).toInt(), i); QCOMPARE(q.value(1).toString().trimmed(), u"Bart"); @@ -2170,7 +2129,7 @@ void tst_QSqlQuery::prepare_bind_exec() /*** SELECT stuff ***/ QVERIFY(q.prepare(QLatin1String("select * from %1 where id = :id").arg(qtest_prepare))); - for (i = 0; i < 6; ++i) { + for (int i = 0; i < 6; ++i) { q.bindValue(":id", i); QVERIFY_SQL(q, exec()); QVERIFY_SQL(q, next()); @@ -2283,7 +2242,7 @@ void tst_QSqlQuery::prepare_bind_exec() QFAIL_SQL(q, exec()); QVERIFY_SQL(q, exec(QLatin1String("SELECT * FROM %1 order by id").arg(qtest_prepare))); - for (i = 0; i < 6; ++i) { + for (int i = 0; i < 6; ++i) { QVERIFY(q.next()); QCOMPARE(q.value(0).toInt(), i); QCOMPARE(q.value(1).toString().trimmed(), values[i]); @@ -2309,7 +2268,7 @@ void tst_QSqlQuery::prepare_bind_exec() QVERIFY(q.exec(QLatin1String("select * from %1 where id > 98 order by id") .arg(qtest_prepare))); - for (i = 99; i <= 100; ++i) { + for (int i = 99; i <= 100; ++i) { QVERIFY(q.next()); QCOMPARE(q.value(0).toInt(), i); QCOMPARE(q.value(1).toString().trimmed(), u"Bart"); @@ -2328,7 +2287,7 @@ void tst_QSqlQuery::prepare_bind_exec() QVERIFY(q.prepare(QLatin1String( "insert into %1 (id, name, name2) values (:id, :name, :name)") .arg(qtest_prepare))); - for (i = 101; i < 103; ++i) { + for (int i = 101; i < 103; ++i) { q.bindValue(":id", i); q.bindValue(":name", "name"); QVERIFY(q.exec()); @@ -2346,7 +2305,7 @@ void tst_QSqlQuery::prepare_bind_exec() // works correctly - QTBUG-65150 QVERIFY(q.prepare(QLatin1String("insert into %1 (id, name, name2) values (:id, :id, :name)") .arg(qtest_prepare))); - for (i = 104; i < 106; ++i) { + for (int i = 104; i < 106; ++i) { q.bindValue(":id", i); q.bindValue(":name", "name"); QVERIFY(q.exec()); @@ -2361,7 +2320,7 @@ void tst_QSqlQuery::prepare_bind_exec() // Test that duplicated named placeholders in any order QVERIFY(q.prepare(QLatin1String("insert into %1 (id, name, name2) values (:id, :name, :id)") .arg(qtest_prepare))); - for (i = 107; i < 109; ++i) { + for (int i = 107; i < 109; ++i) { q.bindValue(":id", i); q.bindValue(":name", "name"); QVERIFY(q.exec()); @@ -2430,12 +2389,12 @@ void tst_QSqlQuery::sqlServerLongStrings() if (tst_Databases::getDatabaseType(db) != QSqlDriver::MSSqlServer) QSKIP("Test is specific to SQL Server"); + TableScope ts(db, "qtest_longstr", __FILE__); QSqlQuery q(db); - const QString tableName = qTableName("qtest_longstr", __FILE__, db); QVERIFY_SQL(q, exec(QLatin1String("CREATE TABLE %1 (id int primary key, longstring ntext)") - .arg(tableName))); - QVERIFY_SQL(q, prepare(QLatin1String("INSERT INTO %1 VALUES (?, ?)").arg(tableName))); + .arg(ts.tableName()))); + QVERIFY_SQL(q, prepare(QLatin1String("INSERT INTO %1 VALUES (?, ?)").arg(ts.tableName()))); q.addBindValue(0); q.addBindValue(u"bubu"_s); @@ -2446,7 +2405,7 @@ void tst_QSqlQuery::sqlServerLongStrings() q.addBindValue(1); q.addBindValue(testStr); QVERIFY_SQL(q, exec()); - QVERIFY_SQL(q, exec("select * from " + tableName)); + QVERIFY_SQL(q, exec("select * from " + ts.tableName())); QVERIFY_SQL(q, next()); QCOMPARE(q.value(0).toInt(), 0); @@ -2603,19 +2562,19 @@ void tst_QSqlQuery::QTBUG_43874() QFETCH(QString, dbName); QSqlDatabase db = QSqlDatabase::database(dbName); CHECK_DATABASE(db); + TableScope ts(db, "bug43874", __FILE__); QSqlQuery q(db); - const QString tableName = qTableName("bug43874", __FILE__, db); - QVERIFY_SQL(q, exec(QLatin1String("CREATE TABLE %1 (id INT)").arg(tableName))); - QVERIFY_SQL(q, prepare(QLatin1String("INSERT INTO %1 (id) VALUES (?)").arg(tableName))); + QVERIFY_SQL(q, exec(QLatin1String("CREATE TABLE %1 (id INT)").arg(ts.tableName()))); + QVERIFY_SQL(q, prepare(QLatin1String("INSERT INTO %1 (id) VALUES (?)").arg(ts.tableName()))); for (int i = 0; i < 2; ++i) { const QVariantList ids = { i }; q.addBindValue(ids); QVERIFY_SQL(q, execBatch()); } - QVERIFY_SQL(q, exec(QLatin1String("SELECT id FROM %1 ORDER BY id").arg(tableName))); + QVERIFY_SQL(q, exec(QLatin1String("SELECT id FROM %1 ORDER BY id").arg(ts.tableName()))); QVERIFY(q.next()); QCOMPARE(q.value(0).toInt(), 0); @@ -2710,14 +2669,14 @@ void tst_QSqlQuery::record_sqlite() QSqlDatabase db = QSqlDatabase::database(dbName); CHECK_DATABASE(db); + TableScope ts(db, "record_sqlite"); QSqlQuery q(db); - const QString tableName = qTableName("record_sqlite", __FILE__, db); QVERIFY_SQL(q, exec(QLatin1String( "create table %1(id integer primary key, name varchar, title int)") - .arg(tableName))); + .arg(ts.tableName()))); - QSqlRecord rec = db.record(tableName); + QSqlRecord rec = db.record(ts.tableName()); QCOMPARE(rec.count(), 3); QCOMPARE(rec.field(0).metaType().id(), QMetaType::Int); @@ -2725,7 +2684,7 @@ void tst_QSqlQuery::record_sqlite() QCOMPARE(rec.field(2).metaType().id(), QMetaType::Int); // Important - select from an empty table: - QVERIFY_SQL(q, exec("select id, name, title from " + tableName)); + QVERIFY_SQL(q, exec("select id, name, title from " + ts.tableName())); rec = q.record(); QCOMPARE(rec.count(), 3); @@ -2740,20 +2699,19 @@ void tst_QSqlQuery::oraLong() QSqlDatabase db = QSqlDatabase::database(dbName); CHECK_DATABASE(db); - QSqlQuery q(db); - QString aLotOfText(127000, QLatin1Char('H')); - const QString tableName = qTableName("qtest_longstr", __FILE__, db); + TableScope ts(db, "qtest_longstr", __FILE__); + QSqlQuery q(db); QVERIFY_SQL(q, exec(QLatin1String("create table %1 (id int primary key, astr long)") - .arg(tableName))); + .arg(ts.tableName()))); QVERIFY_SQL(q, prepare(QLatin1String("insert into %1 (id, astr) values (?, ?)") - .arg(tableName))); + .arg(ts.tableName()))); q.addBindValue(1); q.addBindValue(aLotOfText); QVERIFY_SQL(q, exec()); - QVERIFY_SQL(q, exec("select id,astr from " + tableName)); + QVERIFY_SQL(q, exec("select id,astr from " + ts.tableName())); QVERIFY(q.next()); QCOMPARE(q.value(0).toInt(), 1); @@ -2766,12 +2724,11 @@ void tst_QSqlQuery::execErrorRecovery() QSqlDatabase db = QSqlDatabase::database(dbName); CHECK_DATABASE(db); - QSqlQuery q(db); + TableScope ts(db, "qtest_exerr", __FILE__); - const QString tbl = qTableName("qtest_exerr", __FILE__, db); - q.exec("drop table " + tbl); - QVERIFY_SQL(q, exec(QLatin1String("create table %1 (id int not null primary key)").arg(tbl))); - QVERIFY_SQL(q, prepare(QLatin1String("insert into %1 values (?)").arg(tbl))); + QSqlQuery q(db); + QVERIFY_SQL(q, exec(QLatin1String("create table %1 (id int not null primary key)").arg(ts.tableName()))); + QVERIFY_SQL(q, prepare(QLatin1String("insert into %1 values (?)").arg(ts.tableName()))); q.addBindValue(1); QVERIFY_SQL(q, exec()); @@ -2828,13 +2785,12 @@ void tst_QSqlQuery::lastInsertId() // PostgreSQL >= 8.1 relies on lastval() which does not work if a value is // manually inserted to the serial field, so we create a table specifically if (tst_Databases::getDatabaseType(db) == QSqlDriver::PostgreSQL) { - const auto tableName = qTableName("tst_lastInsertId", __FILE__, db); - tst_Databases::safeDropTables(db, {tableName}); + TableScope ts(db, "tst_lastInsertId", __FILE__); QVERIFY_SQL(q, exec(QLatin1String("create table %1 (id serial not null, t_varchar " "varchar(20), t_char char(20), primary key(id))") - .arg(tableName))); + .arg(ts.tableName()))); QVERIFY_SQL(q, exec(QLatin1String("insert into %1 (t_varchar, t_char) values " - "('VarChar41', 'Char41')").arg(tableName))); + "('VarChar41', 'Char41')").arg(ts.tableName()))); } else { QVERIFY_SQL(q, exec(QLatin1String("insert into %1 values (41, 'VarChar41', 'Char41')") .arg(qtest))); @@ -2880,18 +2836,18 @@ void tst_QSqlQuery::psql_bindWithDoubleColonCastOperator() QSqlDatabase db = QSqlDatabase::database(dbName); CHECK_DATABASE(db); - const QString tablename(qTableName("bindtest", __FILE__, db)); + TableScope ts(db, "bindtest", __FILE__); QSqlQuery q(db); QVERIFY_SQL(q, exec(QLatin1String( "create table %1 (id1 int, id2 int, id3 int, fld1 int, fld2 int)") - .arg(tablename))); - QVERIFY_SQL(q, exec(QLatin1String("insert into %1 values (1, 2, 3, 10, 5)").arg(tablename))); + .arg(ts.tableName()))); + QVERIFY_SQL(q, exec(QLatin1String("insert into %1 values (1, 2, 3, 10, 5)").arg(ts.tableName()))); // Insert tableName last to let the other %-tokens' numbering match what they're replaced with: const auto queryTemplate = QLatin1String("select sum((fld1 - fld2)::int) from %4 where " "id1 = %1 and id2 =%2 and id3=%3"); - const QString query = queryTemplate.arg(":myid1", ":myid2", ":myid3", tablename); + const QString query = queryTemplate.arg(":myid1", ":myid2", ":myid3", ts.tableName()); QVERIFY_SQL(q, prepare(query)); q.bindValue(":myid1", 1); q.bindValue(":myid2", 2); @@ -2902,7 +2858,7 @@ void tst_QSqlQuery::psql_bindWithDoubleColonCastOperator() // The positional placeholders are converted to named placeholders in executedQuery() const QString expected = db.driver()->hasFeature(QSqlDriver::PreparedQueries) - ? query : queryTemplate.arg("1", "2", "3", tablename); + ? query : queryTemplate.arg("1", "2", "3", ts.tableName()); QCOMPARE(q.executedQuery(), expected); } @@ -3119,7 +3075,8 @@ void tst_QSqlQuery::nextResult() QSKIP("DBMS does not support multiple result sets"); QSqlQuery q(db); - const QString tableName(qTableName("more_results", __FILE__, db)); + TableScope ts(db, "more_results", __FILE__); + const auto &tableName = ts.tableName(); QVERIFY_SQL(q, exec(QLatin1String( "CREATE TABLE %1 (id integer, text varchar(20), " @@ -3346,7 +3303,7 @@ void tst_QSqlQuery::blobsPreparedQuery() QSKIP("DBMS does not support BLOBs or prepared queries"); } - const QString tableName(qTableName("blobstest", __FILE__, db)); + TableScope ts(db, "blobstest", __FILE__); QSqlQuery q(db); q.setForwardOnly(true); // This is needed to make the test work with DB2. @@ -3360,8 +3317,8 @@ void tst_QSqlQuery::blobsPreparedQuery() : dbType == QSqlDriver::MSSqlServer ? "IMAGE" : "BLOB"); QVERIFY_SQL(q, exec(QLatin1String("CREATE TABLE %1(id INTEGER, data %2)") - .arg(tableName, typeName))); - q.prepare(QLatin1String("INSERT INTO %1(id, data) VALUES(:id, :data)").arg(tableName)); + .arg(ts.tableName(), typeName))); + q.prepare(QLatin1String("INSERT INTO %1(id, data) VALUES(:id, :data)").arg(ts.tableName())); q.bindValue(":id", 1); q.bindValue(":data", shortBLOB); QVERIFY_SQL(q, exec()); @@ -3371,7 +3328,7 @@ void tst_QSqlQuery::blobsPreparedQuery() QVERIFY_SQL(q, exec()); // Two executions and result sets - q.prepare(QLatin1String("SELECT data FROM %1 WHERE id = ?").arg(tableName)); + q.prepare(QLatin1String("SELECT data FROM %1 WHERE id = ?").arg(ts.tableName())); q.bindValue(0, QVariant(1)); QVERIFY_SQL(q, exec()); QVERIFY_SQL(q, next()); @@ -3383,7 +3340,7 @@ void tst_QSqlQuery::blobsPreparedQuery() QCOMPARE(q.value(0).toString().toUtf8(), longerBLOB.toUtf8()); // Only one execution and result set - q.prepare(QLatin1String("SELECT id, data FROM %1 ORDER BY id").arg(tableName)); + q.prepare(QLatin1String("SELECT id, data FROM %1 ORDER BY id").arg(ts.tableName())); QVERIFY_SQL(q, exec()); QVERIFY_SQL(q, next()); QCOMPARE(q.value(1).toString(), shortBLOB); @@ -3399,11 +3356,11 @@ void tst_QSqlQuery::emptyTableNavigate() CHECK_DATABASE(db); { + TableScope ts(db, "qtest_empty", __FILE__); QSqlQuery q(db); - const QString tbl = qTableName("qtest_empty", __FILE__, db); - q.exec("drop table " + tbl); - QVERIFY_SQL(q, exec(QLatin1String("create table %1 (id char(10))").arg(tbl))); - QVERIFY_SQL(q, prepare("select * from " + tbl)); + q.exec("drop table " + ts.tableName()); + QVERIFY_SQL(q, exec(QLatin1String("create table %1 (id char(10))").arg(ts.tableName()))); + QVERIFY_SQL(q, prepare("select * from " + ts.tableName())); QVERIFY_SQL(q, exec()); QVERIFY(!q.next()); QVERIFY(!q.lastError().isValid()); @@ -3464,10 +3421,10 @@ void tst_QSqlQuery::task_217003() QFETCH(QString, dbName); QSqlDatabase db = QSqlDatabase::database(dbName); CHECK_DATABASE(db); - QSqlQuery q(db); - const QString planets = qTableName("Planet", __FILE__, db); + TableScope ts(db, "Planet", __FILE__); + const auto &planets = ts.tableName(); - q.exec("drop table " + planets); + QSqlQuery q(db); QVERIFY_SQL(q, exec(QLatin1String("create table %1 (Name varchar(20))").arg(planets))); QVERIFY_SQL(q, exec(QLatin1String("insert into %1 VALUES ('Mercury')").arg(planets))); QVERIFY_SQL(q, exec(QLatin1String("insert into %1 VALUES ('Venus')").arg(planets))); @@ -3493,11 +3450,10 @@ void tst_QSqlQuery::task_250026() QFETCH(QString, dbName); QSqlDatabase db = QSqlDatabase::database(dbName); CHECK_DATABASE(db); - QSqlQuery q(db); - - const QString tableName(qTableName("task_250026", __FILE__, db)); + TableScope ts(db, "task_250026", __FILE__); - if (!q.exec(QLatin1String("create table %1 (longfield varchar(1100))").arg(tableName))) { + QSqlQuery q(db); + if (!q.exec(QLatin1String("create table %1 (longfield varchar(1100))").arg(ts.tableName()))) { qDebug() << "Error" << q.lastError(); QSKIP("Db doesn't support \"1100\" as a size for fields"); } @@ -3505,12 +3461,12 @@ void tst_QSqlQuery::task_250026() const QString data258(258, QLatin1Char('A')); const QString data1026(1026, QLatin1Char('A')); QVERIFY_SQL(q, prepare(QLatin1String("insert into %1(longfield) VALUES (:longfield)") - .arg(tableName))); + .arg(ts.tableName()))); q.bindValue(":longfield", data258); QVERIFY_SQL(q, exec()); q.bindValue(":longfield", data1026); QVERIFY_SQL(q, exec()); - QVERIFY_SQL(q, exec("select * from " + tableName)); + QVERIFY_SQL(q, exec("select * from " + ts.tableName())); QVERIFY_SQL(q, next()); QCOMPARE(q.value(0).toString().size(), data258.size()); QVERIFY_SQL(q, next()); @@ -3531,19 +3487,19 @@ void tst_QSqlQuery::crashQueryOnCloseDatabase() } } -void tst_QSqlQuery::task_233829() +void tst_QSqlQuery::testNaN() { QFETCH(QString, dbName); QSqlDatabase db = QSqlDatabase::database(dbName); CHECK_DATABASE(db); + TableScope ts(db, "testNaN", __FILE__); QSqlQuery q(db); - const QString tableName(qTableName("task_233829", __FILE__, db)); QVERIFY_SQL(q, exec(QLatin1String( "CREATE TABLE %1(dbl1 double precision,dbl2 double precision) " - "without oids;").arg(tableName))); + "without oids;").arg(ts.tableName()))); const QString queryString = - QLatin1String("INSERT INTO %1(dbl1, dbl2) VALUES(?,?)").arg(tableName); + QLatin1String("INSERT INTO %1(dbl1, dbl2) VALUES(?,?)").arg(ts.tableName()); const double nan = qQNaN(); QVERIFY_SQL(q, prepare(queryString)); @@ -3552,13 +3508,11 @@ void tst_QSqlQuery::task_233829() QVERIFY_SQL(q, exec()); } -void tst_QSqlQuery::QTBUG_12477() +void tst_QSqlQuery::psqlNumericMetadata() { QFETCH(QString, dbName); QSqlDatabase db = QSqlDatabase::database(dbName); CHECK_DATABASE(db); - if (!db.driverName().startsWith("QPSQL")) - QSKIP("PostgreSQL-specific test"); QSqlQuery q(db); QVERIFY_SQL(q, exec("SELECT 1::bit, '10101010000111101101'::varbit, " @@ -3601,11 +3555,10 @@ void tst_QSqlQuery::sqlServerReturn0() if (tst_Databases::getDatabaseType(db) != QSqlDriver::MSSqlServer) QSKIP("Test is specific to SQL Server"); - const QString tableName(qTableName("test141895", __FILE__, db)); - const QString procName(qTableName("test141895_proc", __FILE__, db)); + ProcScope ps(db, "test141895_proc", __FILE__); + TableScope ts(db, "test141895", __FILE__); + const auto &tableName = ts.tableName(); QSqlQuery q(db); - q.exec("DROP TABLE " + tableName); - q.exec("DROP PROCEDURE " + procName); QVERIFY_SQL(q, exec(QLatin1String("CREATE TABLE %1 (id integer)").arg(tableName))); QVERIFY_SQL(q, exec(QLatin1String("INSERT INTO %1 (id) VALUES (1)").arg(tableName))); QVERIFY_SQL(q, exec(QLatin1String("INSERT INTO %1 (id) VALUES (2)").arg(tableName))); @@ -3613,10 +3566,10 @@ void tst_QSqlQuery::sqlServerReturn0() QVERIFY_SQL(q, exec(QLatin1String("INSERT INTO %1 (id) VALUES (3)").arg(tableName))); QVERIFY_SQL(q, exec(QLatin1String("INSERT INTO %1 (id) VALUES (1)").arg(tableName))); QVERIFY_SQL(q, exec(QLatin1String("CREATE PROCEDURE %1 AS " - "SELECT * FROM %1 WHERE ID = 2 " - "RETURN 0").arg(tableName))); + "SELECT * FROM %2 WHERE ID = 2 " + "RETURN 0").arg(ps.name(), ts.tableName()))); - QVERIFY_SQL(q, exec(QLatin1String("{CALL %1}").arg(procName))); + QVERIFY_SQL(q, exec(QLatin1String("{CALL %1}").arg(ps.name()))); QVERIFY_SQL(q, next()); } @@ -3714,24 +3667,21 @@ void tst_QSqlQuery::QTBUG_18435() if (dbType != QSqlDriver::MSSqlServer || !db.driverName().startsWith("QODBC")) QSKIP("Test is specific to SQL Server"); + ProcScope ps(db, "qtbug_18435_proc", __FILE__); QSqlQuery q(db); - QString procName(qTableName("qtbug_18435_proc", __FILE__, db)); - q.exec("DROP PROCEDURE " + procName); const QString stmt = QLatin1String("CREATE PROCEDURE %1 @key nvarchar(50) OUTPUT AS\n" "BEGIN\n" " SET NOCOUNT ON\n" " SET @key = 'TEST'\n" - "END\n").arg(procName); + "END\n").arg(ps.name()); QVERIFY_SQL(q, exec(stmt)); - QVERIFY_SQL(q, prepare(QLatin1String("{CALL %1(?)}").arg(procName))); + QVERIFY_SQL(q, prepare(QLatin1String("{CALL %1(?)}").arg(ps.name()))); const QString testStr = "0123"; q.bindValue(0, testStr, QSql::Out); QVERIFY_SQL(q, exec()); QCOMPARE(q.boundValue(0).toString(), QLatin1String("TEST")); - - QVERIFY_SQL(q, exec("DROP PROCEDURE " + procName)); } void tst_QSqlQuery::QTBUG_5251() @@ -3771,9 +3721,10 @@ void tst_QSqlQuery::QTBUG_6421() QFETCH(QString, dbName); QSqlDatabase db = QSqlDatabase::database(dbName); CHECK_DATABASE(db); + const QString tableName(qTableName("bug6421", __FILE__, db).toUpper()); + TableScope ts(db, tableName); QSqlQuery q(db); - const QString tableName(qTableName("bug6421", __FILE__, db).toUpper()); QVERIFY_SQL(q, exec(QLatin1String( "create table %1(COL1 char(10), COL2 char(10), COL3 char(10))") @@ -3801,9 +3752,8 @@ void tst_QSqlQuery::QTBUG_6618() if (tst_Databases::getDatabaseType(db) != QSqlDriver::MSSqlServer) QSKIP("Test is specific to SQL Server"); + ProcScope ps(db, "tst_raiseError", __FILE__); QSqlQuery q(db); - const QString procedureName = qTableName("tst_raiseError", __FILE__, db); - q.exec("drop procedure " + procedureName); // non-fatal QString errorString; for (int i = 0; i < 110; ++i) errorString += "reallylong"; @@ -3811,8 +3761,8 @@ void tst_QSqlQuery::QTBUG_6618() QVERIFY_SQL(q, exec(QLatin1String("create procedure %1 as\n" "begin\n" " raiserror('%2', 16, 1)\n" - "end\n").arg(procedureName, errorString))); - q.exec(QLatin1String("{call %1}").arg(procedureName)); + "end\n").arg(ps.name(), errorString))); + q.exec(QLatin1String("{call %1}").arg(ps.name())); QVERIFY(q.lastError().text().contains(errorString)); } @@ -3821,11 +3771,11 @@ void tst_QSqlQuery::QTBUG_6852() QFETCH(QString, dbName); QSqlDatabase db = QSqlDatabase::database(dbName); CHECK_DATABASE(db); - QSqlQuery q(db); - const QString tableName(qTableName("bug6852", __FILE__, db)); - const QString procName(qTableName("bug6852_proc", __FILE__, db)); + TableScope ts(db, "bug6852", __FILE__); + const auto &tableName = ts.tableName(); + ProcScope ps(db, "bug6852_proc", __FILE__); - QVERIFY_SQL(q, exec("DROP PROCEDURE IF EXISTS " + procName)); + QSqlQuery q(db); QVERIFY_SQL(q, exec(QLatin1String("CREATE TABLE %1(\n" "MainKey INT NOT NULL,\n" "OtherTextCol VARCHAR(45) NOT NULL,\n" @@ -3840,9 +3790,9 @@ void tst_QSqlQuery::QTBUG_6852() " SET @st = 'SELECT MainKey, OtherTextCol from %2';\n" " PREPARE stmt from @st;\n" " EXECUTE stmt;\n" - "END;").arg(procName, tableName))); + "END;").arg(ps.name(), tableName))); - QVERIFY_SQL(q, exec(QLatin1String("CALL %1()").arg(procName))); + QVERIFY_SQL(q, exec(QLatin1String("CALL %1()").arg(ps.name()))); QVERIFY_SQL(q, next()); QCOMPARE(q.value(0).toInt(), 0); QCOMPARE(q.value(1).toString(), QLatin1String("Disabled")); @@ -3853,19 +3803,19 @@ void tst_QSqlQuery::QTBUG_5765() QFETCH(QString, dbName); QSqlDatabase db = QSqlDatabase::database(dbName); CHECK_DATABASE(db); - QSqlQuery q(db); - const QString tableName(qTableName("bug5765", __FILE__, db)); + TableScope ts(db, "bug5765", __FILE__); + QSqlQuery q(db); QVERIFY_SQL(q, exec(QLatin1String("CREATE TABLE %1(testval TINYINT(1) DEFAULT 0)") - .arg(tableName))); - q.prepare(QLatin1String("INSERT INTO %1 SET testval = :VALUE").arg(tableName)); + .arg(ts.tableName()))); + q.prepare(QLatin1String("INSERT INTO %1 SET testval = :VALUE").arg(ts.tableName())); q.bindValue(":VALUE", 1); QVERIFY_SQL(q, exec()); q.bindValue(":VALUE", 12); QVERIFY_SQL(q, exec()); q.bindValue(":VALUE", 123); QVERIFY_SQL(q, exec()); - QString sql = "select testval from " + tableName; + QString sql = "select testval from " + ts.tableName(); QVERIFY_SQL(q, exec(sql)); QVERIFY_SQL(q, next()); QCOMPARE(q.value(0).toInt(), 1); @@ -3892,9 +3842,10 @@ void tst_QSqlQuery::QTBUG_21884() QFETCH(QString, dbName); QSqlDatabase db = QSqlDatabase::database(dbName); CHECK_DATABASE(db); + TableScope ts(db, "bug21884", __FILE__); + const auto &tableName = ts.tableName(); QSqlQuery q(db); - QString tableName(qTableName("bug21884", __FILE__, db)); { const QString good[] = { @@ -3991,10 +3942,11 @@ void tst_QSqlQuery::QTBUG_23895() QFETCH(QString, dbName); QSqlDatabase db = QSqlDatabase::database(dbName); CHECK_DATABASE(db); + TableScope ts(db, "bug23895", __FILE__); + const auto &tableName = ts.tableName(); QSqlQuery q(db); - QString tableName(qTableName("bug23895", __FILE__, db)); q.prepare(QLatin1String("create table %1(id integer primary key, val1 bool, val2 boolean)") .arg(tableName)); QVERIFY_SQL(q, exec()); @@ -4045,11 +3997,9 @@ void tst_QSqlQuery::QTBUG_14904() QFETCH(QString, dbName); QSqlDatabase db = QSqlDatabase::database(dbName); CHECK_DATABASE(db); - - QSqlQuery q(db); - TableScope ts(db, "bug14904", __FILE__); + QSqlQuery q(db); q.prepare(QLatin1String("create table %1(val1 bool)").arg(ts.tableName())); QVERIFY_SQL(q, exec()); q.prepare(QLatin1String("insert into %1(val1) values(?);").arg(ts.tableName())); @@ -4182,9 +4132,9 @@ void tst_QSqlQuery::gisPointDatatype() QFETCH(QString, dbName); QSqlDatabase db = QSqlDatabase::database(dbName); CHECK_DATABASE(db); + TableScope ts(db, "qtbug72140", __FILE__); QSqlQuery sqlQuery(db); - TableScope ts(db, "qtbug72140", __FILE__); QVERIFY(sqlQuery.exec(QLatin1String( "CREATE TABLE %1 (`lonlat_point` POINT NULL) ENGINE = InnoDB;") .arg(ts.tableName()))); @@ -4201,13 +4151,13 @@ void tst_QSqlQuery::oraOCINumber() QFETCH(QString, dbName); QSqlDatabase db = QSqlDatabase::database(dbName); CHECK_DATABASE(db); - const QString qtest_oraOCINumber(qTableName("qtest_oraOCINumber", __FILE__, db)); + TableScope ts(db, "qtest_oraOCINumber", __FILE__); QSqlQuery q(db); q.setForwardOnly(true); QVERIFY_SQL(q, exec(QLatin1String("create table %1 (col1 number(20), col2 number(20))") - .arg(qtest_oraOCINumber))); - QVERIFY(q.prepare(QLatin1String("insert into %1 values (?, ?)").arg(qtest_oraOCINumber))); + .arg(ts.tableName()))); + QVERIFY(q.prepare(QLatin1String("insert into %1 values (?, ?)").arg(ts.tableName()))); const QVariantList col1Values = { qulonglong(1), qulonglong(0), qulonglong(INT_MAX), qulonglong(UINT_MAX), @@ -4224,7 +4174,7 @@ void tst_QSqlQuery::oraOCINumber() QVERIFY(q.execBatch()); QVERIFY(q.prepare(QLatin1String( "select * from %1 where col1 = :bindValue0 AND col2 = :bindValue1") - .arg(qtest_oraOCINumber))); + .arg(ts.tableName()))); q.bindValue(":bindValue0", qulonglong(1), QSql::InOut); q.bindValue(":bindValue1", qlonglong(1), QSql::InOut); @@ -4296,8 +4246,6 @@ void tst_QSqlQuery::sqlite_constraint() QFETCH(QString, dbName); QSqlDatabase db = QSqlDatabase::database(dbName); CHECK_DATABASE(db); - if (tst_Databases::getDatabaseType(db) != QSqlDriver::SQLite) - QSKIP("SQLite3-specific test"); QSqlQuery q(db); const QString trigger(qTableName("test_constraint", __FILE__, db)); @@ -4517,7 +4465,7 @@ void tst_QSqlQuery::aggregateFunctionTypes() .arg(tableName))); QVERIFY_SQL(q, exec("SELECT MAX(txt) FROM " + tableName)); - QVERIFY(q.next()); + QVERIFY_SQL(q, next()); if (dbType == QSqlDriver::SQLite) QCOMPARE(q.record().field(0).metaType().id(), QMetaType::UnknownType); else @@ -4532,6 +4480,19 @@ void tst_QSqlQuery::aggregateFunctionTypes() QVERIFY(q.next()); QCOMPARE(q.value(0).toString(), QLatin1String("upper")); QCOMPARE(q.record().field(0).metaType().id(), QMetaType::QString); + + QVERIFY_SQL(q, exec(QLatin1String("DELETE FROM %1").arg(tableName))); + QVERIFY_SQL(q, exec(QString::fromUtf8("INSERT INTO %1 (id, txt) VALUES (1, 'löW€RÄ')") + .arg(tableName))); + QVERIFY_SQL(q, exec("SELECT LOWER(txt) FROM " + tableName)); + QVERIFY(q.next()); + QCOMPARE(q.value(0).toString(), QString::fromUtf8("löw€rä")); + QCOMPARE(q.record().field(0).metaType().id(), QMetaType::QString); + + QVERIFY_SQL(q, exec("SELECT UPPER(txt) FROM " + tableName)); + QVERIFY(q.next()); + QCOMPARE(q.value(0).toString(), QString::fromUtf8("LÖW€RÄ")); + QCOMPARE(q.record().field(0).metaType().id(), QMetaType::QString); } } @@ -4541,9 +4502,9 @@ void runIntegralTypesMysqlTest(QSqlDatabase &db, const QString &tableName, const { QList<QVariant> variantValues; variantValues.reserve(values.size()); + TableScope ts(db, tableName); QSqlQuery q(db); - QVERIFY_SQL(q, exec("DROP TABLE IF EXISTS " + tableName)); QVERIFY_SQL(q, exec(QLatin1String("CREATE TABLE %2 (id %1)").arg(type, tableName))); if (withPreparedStatement) { @@ -4649,9 +4610,9 @@ void tst_QSqlQuery::QTBUG_57138() QFETCH(QString, dbName); QSqlDatabase db = QSqlDatabase::database(dbName); CHECK_DATABASE(db); + TableScope ts(db, "qtbug57138", __FILE__); QSqlQuery create(db); - TableScope ts(db, "qtbug57138", __FILE__); QVERIFY_SQL(create, exec(QLatin1String( "create table %1 (id int, dt_utc datetime, dt_lt datetime, " @@ -4683,10 +4644,9 @@ void tst_QSqlQuery::QTBUG_73286() QFETCH(QString, dbName); QSqlDatabase db = QSqlDatabase::database(dbName); CHECK_DATABASE(db); - - QSqlQuery create(db); TableScope ts(db, "qtbug73286", __FILE__); + QSqlQuery create(db); QVERIFY_SQL(create, exec(QLatin1String( "create table %1 (dec2 decimal(4,2), dec0 decimal(20,0), " "dec3 decimal(20,3))").arg(ts.tableName()))); @@ -4712,6 +4672,22 @@ void tst_QSqlQuery::QTBUG_73286() QCOMPARE(q.value(2).toString(), "12345678901234567.890"); } +void tst_QSqlQuery::insertVarChar1() +{ + QFETCH(QString, dbName); + QSqlDatabase db = QSqlDatabase::database(dbName); + CHECK_DATABASE(db); + + QSqlQuery q(db); + TableScope ts(db, "testtable", __FILE__); + QVERIFY_SQL(q, exec(QLatin1String("CREATE TABLE %1 (smallcol VARCHAR(1))").arg(ts.tableName()))); + QVERIFY_SQL(q, prepare(QLatin1String("INSERT INTO %1 (smallcol) VALUES (?)").arg(ts.tableName()))); + QSqlField smallCol("smallcol"); + smallCol.setValue(QVariant(QString(QChar('F')))); + q.bindValue(0, smallCol.value()); + QVERIFY_SQL(q, exec()); +} + void tst_QSqlQuery::dateTime_data() { if (dbs.dbNames.isEmpty()) @@ -4768,8 +4744,6 @@ void tst_QSqlQuery::dateTime_data() if (!db.isValid()) continue; const QString tableNameTSWithTimeZone(qTableName("dateTimeTSWithTimeZone", __FILE__, db)); - const QString tableNameTSWithLocalTimeZone(qTableName("dateTimeTSWithLocalTimeZone", - __FILE__, db)); const QString tableNameTS(qTableName("dateTimeTS", __FILE__, db)); const QString tableNameDate(qTableName("dateTimeDate", __FILE__, db)); QTest::newRow(QString(dbName + " timestamp with time zone").toLatin1()) @@ -4818,6 +4792,82 @@ void tst_QSqlQuery::dateTime() } } +void tst_QSqlQuery::ibaseDateTimeWithTZ_data() +{ + if (dbs.dbNames.isEmpty()) + QSKIP("No database drivers are available in this Qt configuration"); + + QTest::addColumn<QString>("dbName"); + QTest::addColumn<QString>("tableName"); + QTest::addColumn<QList<QDateTime> >("initialDateTimes"); + QTest::addColumn<QList<QDateTime> >("expectedDateTimes"); + +#if QT_CONFIG(timezone) + const QTimeZone afterUTCTimeZone("Asia/Hong_Kong"); + const QTimeZone beforeUTCTimeZone("America/Los_Angeles"); + const QDateTime dtWithAfterTZ(QDate(2015, 5, 18), QTime(4, 26, 30, 500), afterUTCTimeZone); + const QDateTime dtWithBeforeTZ(QDate(2015, 5, 18), QTime(4, 26, 30, 500), beforeUTCTimeZone); + const QTimeZone utcTimeZone("UTC"); + const QDateTime dtWithUTCTZ(QDate(2015, 5, 18), QTime(4, 26, 30, 500), utcTimeZone); +#endif // QT_CONFIG(timezone) + const QDateTime dtLocalTZ(QDateTime::currentDateTime()); + + const QList<QDateTime> dateTimes = { +#if QT_CONFIG(timezone) + dtWithAfterTZ, + dtWithBeforeTZ, + dtWithUTCTZ, +#endif // QT_CONFIG(timezone) + dtLocalTZ + }; + + for (const QString &dbName : std::as_const(dbs.dbNames)) { + QSqlDatabase db = QSqlDatabase::database(dbName); + if (!db.isValid()) + continue; + + const QString tableNameTSWithTimeZone(qTableName("dateTimeTSWithTZ", __FILE__, db)); + + QTest::newRow(QString(dbName + " timestamp with time zone").toLatin1()) + << dbName + << tableNameTSWithTimeZone + << dateTimes + << dateTimes; + } +} + +void tst_QSqlQuery::ibaseDateTimeWithTZ() +{ + QFETCH(QString, dbName); + QSqlDatabase db = QSqlDatabase::database(dbName); + CHECK_DATABASE(db); + if (tst_Databases::getDatabaseType(db) != QSqlDriver::Interbase) + QSKIP("Implemented only for Interbase"); + + if (tst_Databases::getIbaseEngineVersion(db).majorVersion() < 4) + QSKIP("Time zone support only implemented for firebird engine version 4 and greater"); + + QFETCH(QString, tableName); + TableScope ts(db, tableName); + + QSqlQuery q(db); + QVERIFY_SQL(q, exec(QString("CREATE TABLE " + tableName + "(dt timestamp with time zone)"))); + + QFETCH(QList<QDateTime>, initialDateTimes); + QFETCH(QList<QDateTime>, expectedDateTimes); + + for (const QDateTime &dt : std::as_const(initialDateTimes)) { + QVERIFY_SQL(q, prepare(QLatin1String("INSERT INTO %1 values(:dt)").arg(tableName))); + q.bindValue(":dt", dt); + QVERIFY_SQL(q, exec()); + } + QVERIFY_SQL(q, exec("SELECT * FROM " + tableName)); + for (const QDateTime &dt : std::as_const(expectedDateTimes)) { + QVERIFY(q.next()); + QCOMPARE(q.value(0).toDateTime(), dt); + } +} + void tst_QSqlQuery::sqliteVirtualTable() { // Virtual tables can behave differently when it comes to prepared @@ -4953,6 +5003,90 @@ void tst_QSqlQuery::ibaseArray() QCOMPARE(qry.value(3).toList(), boolArray.toList()); } +void tst_QSqlQuery::ibaseTimeStampTzArray() +{ + QFETCH(QString, dbName); + QSqlDatabase db = QSqlDatabase::database(dbName); + CHECK_DATABASE(db); + + if (tst_Databases::getIbaseEngineVersion(db).majorVersion() < 4) + QSKIP("Time zone support only implemented for firebird engine version 4 and greater"); + + TableScope ts(db, "ibasetstzarray", __FILE__); + QSqlQuery qry(db); + QVERIFY_SQL(qry, exec(QLatin1String( + "create table %1 (timeStampData timestamp with time zone[0:4])").arg(ts.tableName()))); + QVERIFY_SQL(qry, prepare(QLatin1String("insert into %1 (timeStampData)" + " values(?)").arg(ts.tableName()))); +#if QT_CONFIG(timezone) + const QDateTime dtWithAfterTZ(QDate(2015, 5, 18), QTime(4, 26, 30, 500), QTimeZone("Asia/Hong_Kong")); + const QDateTime dtWithBeforeTZ(QDate(2015, 5, 18), QTime(4, 26, 30, 500), QTimeZone("America/Los_Angeles")); + const QDateTime dtWithUTCTZ(QDate(2015, 5, 18), QTime(4, 26, 30, 500), QTimeZone("UTC")); + const QDateTime dtLocalTZ(QDateTime::currentDateTime()); + const QDateTime dtWithMETTZ(QDate(2015, 5, 18), QTime(4, 26, 30, 500), QTimeZone("MET")); + + + const auto timeStampData = QVariant{QVariantList{dtWithAfterTZ, + dtWithBeforeTZ, + dtWithUTCTZ, + dtLocalTZ, + dtWithMETTZ}}; + qry.bindValue(0, timeStampData); + QVERIFY_SQL(qry, exec()); + QVERIFY_SQL(qry, exec("select * from " + ts.tableName())); + QVERIFY(qry.next()); + QCOMPARE(qry.value(0).toList(), timeStampData.toList()); +#endif // QT_CONFIG(timezone) +} + +void tst_QSqlQuery::ibaseInt128() +{ + QFETCH(QString, dbName); + QSqlDatabase db = QSqlDatabase::database(dbName); + CHECK_DATABASE(db); + + TableScope ts(db, "int128test", __FILE__); + db.setNumericalPrecisionPolicy(QSql::HighPrecision); + QSqlQuery q(db); + if (!q.exec("CREATE TABLE " + ts.tableName() + " (id INT PRIMARY KEY, price NUMERIC(20, 4))")) + QSKIP("Need at least Firebird 4 for this test - skipping"); + + QVERIFY_SQL(q, exec("INSERT INTO " + ts.tableName() + "(id,price) values(1,40001.1234)")); + QVERIFY_SQL(q, prepare("INSERT INTO " + ts.tableName() + "(id,price) values(2,:amount)")); + q.bindValue(":amount", 12345.67890); + QVERIFY_SQL(q, exec()); + { + QSqlQuery q2(db); + q2.setNumericalPrecisionPolicy(QSql::LowPrecisionDouble); + QVERIFY_SQL(q2, exec("SELECT price FROM " + ts.tableName() + " ORDER BY id")); + QVERIFY_SQL(q2, next()); + QCOMPARE(q2.value(0).metaType().id(), QMetaType::Double); + QCOMPARE(q2.value(0).toDouble(), 40001.1234); + QVERIFY_SQL(q2, next()); + QCOMPARE(q2.value("price").metaType().id(), QMetaType::Double); + QCOMPARE(q2.value("price").toDouble(), 12345.6789); + QVERIFY_SQL(q2, exec("SELECT sum(price) FROM " + ts.tableName())); + QVERIFY_SQL(q2, next()); + QCOMPARE(q2.value(0).metaType().id(), QMetaType::Double); + QCOMPARE(q2.value(0).toDouble(), 52346.8023); + } + { + QSqlQuery q2(db); + q2.setNumericalPrecisionPolicy(QSql::HighPrecision); + QVERIFY_SQL(q2, exec("SELECT price FROM " + ts.tableName() + " ORDER BY id")); + QVERIFY_SQL(q2, next()); + QCOMPARE(q2.value(0).metaType().id(), QMetaType::QString); + QCOMPARE(q2.value(0).toString(), "40001.1234"); + QVERIFY_SQL(q2, next()); + QCOMPARE(q2.value("price").metaType().id(), QMetaType::QString); + QCOMPARE(q2.value("price").toString(), "12345.6789"); + QVERIFY_SQL(q2, exec("SELECT sum(price) FROM " + ts.tableName())); + QVERIFY_SQL(q2, next()); + QCOMPARE(q2.value(0).metaType().id(), QMetaType::QString); + QCOMPARE(q2.value(0).toString(), "52346.8023"); + } +} + void tst_QSqlQuery::ibase_executeBlock() { QFETCH(QString, dbName); @@ -4973,5 +5107,83 @@ void tst_QSqlQuery::ibase_executeBlock() QCOMPARE(qry.value(0).toInt(), 4); } +void tst_QSqlQuery::positionalBindingEnabled() +{ + QFETCH(QString, dbName); + QSqlDatabase db = QSqlDatabase::database(dbName); + QSqlDriver::DbmsType dbType = tst_Databases::getDatabaseType(db); + CHECK_DATABASE(db); + TableScope ts(db, "positionalBinding", __FILE__); + const QString &tableName = ts.tableName(); + + QSqlQuery qry(db); + QVERIFY_SQL(qry, exec("CREATE TABLE " + tableName + " (integer_col integer)")); + QVERIFY_SQL(qry, exec("INSERT INTO " + tableName + "(integer_col) VALUES(42)")); + + qry.setPositionalBindingEnabled(true); + QCOMPARE(qry.isPositionalBindingEnabled(), true); + QVERIFY_SQL(qry, prepare("SELECT integer_col FROM " + tableName + " WHERE integer_col = :integer_val")); + qry.bindValue(":integer_val", 42); + QVERIFY_SQL(qry, exec()); + QVERIFY_SQL(qry, next()); + QCOMPARE(qry.value(0).toInt(), 42); + QVERIFY_SQL(qry, prepare("SELECT integer_col FROM " + tableName + " WHERE integer_col = ?")); + qry.bindValue(0, 42); + QVERIFY_SQL(qry, exec()); + QVERIFY_SQL(qry, next()); + QCOMPARE(qry.value(0).toInt(), 42); + + qry.setPositionalBindingEnabled(false); + QCOMPARE(qry.isPositionalBindingEnabled(), false); + QVERIFY_SQL(qry, prepare("SELECT integer_col FROM " + tableName + " WHERE integer_col = :integer_val")); + qry.bindValue(":integer_val", 42); + QVERIFY_SQL(qry, exec()); + QVERIFY_SQL(qry, next()); + QCOMPARE(qry.value(0).toInt(), 42); + // the next query will only work when the underlying database support question mark notation natively + if (dbType == QSqlDriver::PostgreSQL) { + QVERIFY(!qry.prepare("SELECT integer_col FROM " + tableName + " WHERE integer_col = ?")); + qry.bindValue(0, 42); + QVERIFY(!qry.exec()); + QVERIFY(!qry.next()); + } else { + QVERIFY_SQL(qry, prepare("SELECT integer_col FROM " + tableName + " WHERE integer_col = ?")); + qry.bindValue(0, 42); + QVERIFY_SQL(qry, exec()); + QVERIFY_SQL(qry, next()); + QCOMPARE(qry.value(0).toInt(), 42); + } +} + +void tst_QSqlQuery::psqlJsonOperator() +{ + QFETCH(QString, dbName); + QSqlDatabase db = QSqlDatabase::database(dbName); + CHECK_DATABASE(db); + TableScope ts(db, "qTableName", __FILE__); + const QString &tableName = ts.tableName(); + + QSqlQuery qry(db); + qry.setPositionalBindingEnabled(false); // don't allow / handle '?' as placeholder + QVERIFY_SQL(qry, exec("CREATE TABLE " + tableName + " (integer_col integer, json_col jsonb)")); + QVERIFY_SQL(qry, exec("INSERT INTO " + tableName + "(integer_col, json_col) VALUES(42, '{\"a\": [1, 2]}')")); + QVERIFY_SQL(qry, exec("INSERT INTO " + tableName + "(integer_col, json_col) VALUES(43, '{\"b\": [3, 4]}')")); + + QVERIFY_SQL(qry, prepare("SELECT integer_col, json_col FROM " + tableName + " WHERE json_col @? '$.a[*] ? (@ == 1)' and integer_col = :int")); + qry.bindValue(":int", 42); + QVERIFY_SQL(qry, exec()); + QVERIFY_SQL(qry, next()); + QCOMPARE(qry.value(0).toInt(), 42); + QCOMPARE(qry.value(1).toByteArray(), "{\"a\": [1, 2]}"); + + QVERIFY_SQL(qry, prepare("SELECT integer_col, json_col FROM " + tableName + " WHERE json_col ? 'b' and integer_col = :int")); + qry.bindValue(":int", 43); + QVERIFY_SQL(qry, exec()); + QVERIFY_SQL(qry, next()); + QCOMPARE(qry.value(0).toInt(), 43); + QCOMPARE(qry.value(1).toByteArray(), "{\"b\": [3, 4]}"); +} + + QTEST_MAIN(tst_QSqlQuery) #include "tst_qsqlquery.moc" diff --git a/tests/auto/sql/kernel/qsqlrecord/CMakeLists.txt b/tests/auto/sql/kernel/qsqlrecord/CMakeLists.txt index b648f1eb24..18d46669db 100644 --- a/tests/auto/sql/kernel/qsqlrecord/CMakeLists.txt +++ b/tests/auto/sql/kernel/qsqlrecord/CMakeLists.txt @@ -5,6 +5,12 @@ ## tst_qsqlrecord Test: ##################################################################### +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qsqlrecord LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + qt_internal_add_test(tst_qsqlrecord SOURCES tst_qsqlrecord.cpp diff --git a/tests/auto/sql/kernel/qsqlrecord/tst_qsqlrecord.cpp b/tests/auto/sql/kernel/qsqlrecord/tst_qsqlrecord.cpp index 2c9eedd8d4..8e7d5b502e 100644 --- a/tests/auto/sql/kernel/qsqlrecord/tst_qsqlrecord.cpp +++ b/tests/auto/sql/kernel/qsqlrecord/tst_qsqlrecord.cpp @@ -1,5 +1,5 @@ // Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> @@ -10,7 +10,7 @@ #include <qsqlrecord.h> -#define NUM_FIELDS 4 +#define NUM_FIELDS 5 class tst_QSqlRecord : public QObject { @@ -67,6 +67,7 @@ void tst_QSqlRecord::createTestRecord() fields[1] = std::make_unique<QSqlField>(QStringLiteral("int"), QMetaType(QMetaType::Int), QStringLiteral("inttable")); fields[2] = std::make_unique<QSqlField>(QStringLiteral("double"), QMetaType(QMetaType::Double), QStringLiteral("doubletable")); fields[3] = std::make_unique<QSqlField>(QStringLiteral("bool"), QMetaType(QMetaType::Bool)); + fields[4] = std::make_unique<QSqlField>(QStringLiteral("öäü@€"), QMetaType(QMetaType::Int)); for (const auto &field : fields) rec->append(*field); } @@ -173,9 +174,22 @@ void tst_QSqlRecord::clearValues() void tst_QSqlRecord::contains() { createTestRecord(); - for (const auto &field : fields) - QVERIFY(rec->contains(field->name())); - QVERIFY( !rec->contains( "__Harry__" ) ); + QStringList fieldNames; + for (const auto &field : fields) { + fieldNames.append(field->name()); + if (!field->tableName().isEmpty()) + fieldNames.append(field->tableName() + u'.' + field->name()); + } + for (const auto &name : std::as_const(fieldNames)) { + QVERIFY(rec->contains(name)); + const QByteArray nameBa = name.toUtf8(); + QVERIFY(rec->contains(nameBa)); + const char *nameStr = nameBa.constData(); + QVERIFY(rec->contains(nameStr)); + QVERIFY(!rec->contains(name.left(name.size() - 1))); + QVERIFY(!rec->contains(name + u'.' + name)); + } + QVERIFY(!rec->contains("__Harry__")); } void tst_QSqlRecord::count() diff --git a/tests/auto/sql/kernel/qsqlresult/CMakeLists.txt b/tests/auto/sql/kernel/qsqlresult/CMakeLists.txt index ebb3e255d6..1fc475b144 100644 --- a/tests/auto/sql/kernel/qsqlresult/CMakeLists.txt +++ b/tests/auto/sql/kernel/qsqlresult/CMakeLists.txt @@ -5,6 +5,12 @@ ## tst_qsqlresult Test: ##################################################################### +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qsqlresult LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + qt_internal_add_test(tst_qsqlresult SOURCES testsqldriver.h diff --git a/tests/auto/sql/kernel/qsqlresult/testsqldriver.h b/tests/auto/sql/kernel/qsqlresult/testsqldriver.h index 79be0dc230..072e683d68 100644 --- a/tests/auto/sql/kernel/qsqlresult/testsqldriver.h +++ b/tests/auto/sql/kernel/qsqlresult/testsqldriver.h @@ -1,5 +1,5 @@ // Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #ifndef TESTSQLDRIVER_H #define TESTSQLDRIVER_H diff --git a/tests/auto/sql/kernel/qsqlresult/tst_qsqlresult.cpp b/tests/auto/sql/kernel/qsqlresult/tst_qsqlresult.cpp index 6ef3ad4d19..da438dcfd6 100644 --- a/tests/auto/sql/kernel/qsqlresult/tst_qsqlresult.cpp +++ b/tests/auto/sql/kernel/qsqlresult/tst_qsqlresult.cpp @@ -1,5 +1,5 @@ // Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> #include <QtSql/QtSql> diff --git a/tests/auto/sql/kernel/qsqlthread/CMakeLists.txt b/tests/auto/sql/kernel/qsqlthread/CMakeLists.txt index f18a6e303d..98108528e6 100644 --- a/tests/auto/sql/kernel/qsqlthread/CMakeLists.txt +++ b/tests/auto/sql/kernel/qsqlthread/CMakeLists.txt @@ -5,6 +5,12 @@ ## tst_qsqlthread Test: ##################################################################### +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qsqlthread LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + qt_internal_add_test(tst_qsqlthread SOURCES tst_qsqlthread.cpp diff --git a/tests/auto/sql/kernel/qsqlthread/tst_qsqlthread.cpp b/tests/auto/sql/kernel/qsqlthread/tst_qsqlthread.cpp index a174ea6f37..0bebb7edd5 100644 --- a/tests/auto/sql/kernel/qsqlthread/tst_qsqlthread.cpp +++ b/tests/auto/sql/kernel/qsqlthread/tst_qsqlthread.cpp @@ -1,5 +1,5 @@ // Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> @@ -258,18 +258,16 @@ void tst_QSqlThread::generic_data(const QString& engine) void tst_QSqlThread::dropTestTables() { - for (int i = 0; i < dbs.dbNames.size(); ++i) { - QSqlDatabase db = QSqlDatabase::database(dbs.dbNames.at(i)); - QSqlQuery q(db); - - tst_Databases::safeDropTables(db, QStringList() << qtest << qTableName("qtest2", __FILE__, db) << qTableName("emptytable", __FILE__, db)); + for (const auto &dbName : dbs.dbNames) { + QSqlDatabase db = QSqlDatabase::database(dbName); + tst_Databases::safeDropTables(db, { qtest, qTableName("qtest2", __FILE__, db), qTableName("emptytable", __FILE__, db) }); } } void tst_QSqlThread::createTestTables() { - for (int i = 0; i < dbs.dbNames.size(); ++i) { - QSqlDatabase db = QSqlDatabase::database(dbs.dbNames.at(i)); + for (const auto &dbName : dbs.dbNames) { + QSqlDatabase db = QSqlDatabase::database(dbName); QSqlQuery q(db); QVERIFY_SQL(q, exec("create table " + qtest @@ -285,8 +283,8 @@ void tst_QSqlThread::createTestTables() void tst_QSqlThread::repopulateTestTables() { - for (int i = 0; i < dbs.dbNames.size(); ++i) { - QSqlDatabase db = QSqlDatabase::database(dbs.dbNames.at(i)); + for (const auto &dbName : dbs.dbNames) { + QSqlDatabase db = QSqlDatabase::database(dbName); QSqlQuery q(db); QVERIFY_SQL(q, exec("delete from " + qtest)); diff --git a/tests/auto/sql/kernel/qvfssql/CMakeLists.txt b/tests/auto/sql/kernel/qvfssql/CMakeLists.txt new file mode 100644 index 0000000000..7c66f055a6 --- /dev/null +++ b/tests/auto/sql/kernel/qvfssql/CMakeLists.txt @@ -0,0 +1,30 @@ +# Copyright (C) 2023 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +##################################################################### +## tst_qsqlfield Test: +##################################################################### + +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qvfssql LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +qt_internal_add_test(tst_qvfssql + SOURCES + tst_qvfssql.cpp + LIBRARIES + Qt::SqlPrivate +) + +set(qvfssql_resource_files + "sample.db" +) + +qt_internal_add_resource(tst_qvfssql "tst_qvfssql" + PREFIX + "/ro/" + FILES + ${qvfssql_resource_files} +) diff --git a/tests/auto/sql/kernel/qvfssql/sample.db b/tests/auto/sql/kernel/qvfssql/sample.db Binary files differnew file mode 100644 index 0000000000..56e6427e3c --- /dev/null +++ b/tests/auto/sql/kernel/qvfssql/sample.db diff --git a/tests/auto/sql/kernel/qvfssql/tst_qvfssql.cpp b/tests/auto/sql/kernel/qvfssql/tst_qvfssql.cpp new file mode 100644 index 0000000000..0dbdf7e60a --- /dev/null +++ b/tests/auto/sql/kernel/qvfssql/tst_qvfssql.cpp @@ -0,0 +1,94 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QTest> + +#include <qsqldatabase.h> +#include <qstandardpaths.h> + +#include "../qsqldatabase/tst_databases.h" + +using namespace Qt::StringLiterals; + +class tst_QVfsSql : public QObject +{ + Q_OBJECT +private slots: + void testRoDb(); + void testRwDb(); +}; + +void tst_QVfsSql::testRoDb() +{ + QVERIFY(QSqlDatabase::drivers().contains("QSQLITE"_L1)); + QSqlDatabase::addDatabase("QSQLITE"_L1, "ro_db"_L1); + QSqlDatabase db = QSqlDatabase::database("ro_db"_L1, false); + QVERIFY_SQL(db, isValid()); + db.setDatabaseName(":/ro/sample.db"_L1); + + db.setConnectOptions("QSQLITE_USE_QT_VFS"_L1); + QVERIFY(!db.open()); // can not open as the QSQLITE_OPEN_READONLY attribute is missing + + db.setConnectOptions("QSQLITE_USE_QT_VFS;QSQLITE_OPEN_READONLY"_L1); + QVERIFY_SQL(db, open()); + + QStringList tables = db.tables(); + QSqlQuery q{db}; + for (auto table : {"reltest1"_L1, "reltest2"_L1, "reltest3"_L1, "reltest4"_L1, "reltest5"_L1}) { + QVERIFY(tables.contains(table)); + QVERIFY_SQL(q, exec("select * from " + table)); + QVERIFY(q.next()); + } + QVERIFY_SQL(q, exec("select * from reltest1 where id = 4"_L1)); + QVERIFY_SQL(q, first()); + QVERIFY(q.value(0).toInt() == 4); + QVERIFY(q.value(1).toString() == "boris"_L1); + QVERIFY(q.value(2).toInt() == 2); + QVERIFY(q.value(3).toInt() == 2); +} + +void tst_QVfsSql::testRwDb() +{ + QSqlDatabase::addDatabase("QSQLITE"_L1, "rw_db"_L1); + QSqlDatabase db = QSqlDatabase::database("rw_db"_L1, false); + QVERIFY_SQL(db, isValid()); + const auto dbPath = QStandardPaths::writableLocation(QStandardPaths::TempLocation) + "/test_qt_vfs.db"_L1; + db.setDatabaseName(dbPath); + QFile::remove(dbPath); + + db.setConnectOptions("QSQLITE_USE_QT_VFS;QSQLITE_OPEN_READONLY"_L1); + QVERIFY(!db.open()); // can not open as the QSQLITE_OPEN_READONLY attribute is set and the file is missing + + db.setConnectOptions("QSQLITE_USE_QT_VFS"_L1); + QVERIFY_SQL(db, open()); + + QVERIFY(db.tables().isEmpty()); + QSqlQuery q{db}; + QVERIFY_SQL(q, exec("CREATE TABLE test (id INTEGER PRIMARY KEY AUTOINCREMENT, val INTEGER)"_L1)); + QVERIFY_SQL(q, exec("BEGIN"_L1)); + for (int i = 0; i < 1000; ++i) { + q.prepare("INSERT INTO test (val) VALUES (:val)"_L1); + q.bindValue(":val"_L1, i); + QVERIFY_SQL(q, exec()); + } + QVERIFY_SQL(q, exec("COMMIT"_L1)); + QVERIFY_SQL(q, exec("SELECT val FROM test ORDER BY val"_L1)); + for (int i = 0; i < 1000; ++i) { + QVERIFY_SQL(q, next()); + QCOMPARE(q.value(0).toInt() , i); + } + QVERIFY_SQL(q, exec("DELETE FROM test WHERE val < 500"_L1)); + auto fileSize = QFileInfo{dbPath}.size(); + QVERIFY_SQL(q, exec("VACUUM"_L1)); + QVERIFY(QFileInfo{dbPath}.size() < fileSize); // TEST xTruncate VFS + QVERIFY_SQL(q, exec("SELECT val FROM test ORDER BY val"_L1)); + for (int i = 500; i < 1000; ++i) { + QVERIFY_SQL(q, next()); + QCOMPARE(q.value(0).toInt() , i); + } + db.close(); + QFile::remove(dbPath); +} + +QTEST_MAIN(tst_QVfsSql) +#include "tst_qvfssql.moc" |