mirror of
https://github.com/crystalidea/qt6windows7.git
synced 2025-07-02 23:35:28 +08:00
qt 6.5.1 original
This commit is contained in:
5
tests/auto/sql/CMakeLists.txt
Normal file
5
tests/auto/sql/CMakeLists.txt
Normal file
@ -0,0 +1,5 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
add_subdirectory(kernel)
|
||||
add_subdirectory(models)
|
12
tests/auto/sql/kernel/CMakeLists.txt
Normal file
12
tests/auto/sql/kernel/CMakeLists.txt
Normal file
@ -0,0 +1,12 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
add_subdirectory(qsqlfield)
|
||||
add_subdirectory(qsqldatabase)
|
||||
add_subdirectory(qsqlerror)
|
||||
add_subdirectory(qsqldriver)
|
||||
add_subdirectory(qsqlquery)
|
||||
add_subdirectory(qsqlrecord)
|
||||
add_subdirectory(qsqlthread)
|
||||
add_subdirectory(qsql)
|
||||
add_subdirectory(qsqlresult)
|
14
tests/auto/sql/kernel/qsql/CMakeLists.txt
Normal file
14
tests/auto/sql/kernel/qsql/CMakeLists.txt
Normal file
@ -0,0 +1,14 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_qsql Test:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_test(tst_qsql
|
||||
SOURCES
|
||||
tst_qsql.cpp
|
||||
LIBRARIES
|
||||
Qt::CorePrivate
|
||||
Qt::SqlPrivate
|
||||
)
|
239
tests/auto/sql/kernel/qsql/tst_qsql.cpp
Normal file
239
tests/auto/sql/kernel/qsql/tst_qsql.cpp
Normal file
@ -0,0 +1,239 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
|
||||
#include <QTest>
|
||||
#include <qcoreapplication.h>
|
||||
#include <qsqldatabase.h>
|
||||
#include <qsqlerror.h>
|
||||
#include <qsqlquery.h>
|
||||
#include <qsqlrecord.h>
|
||||
#include <qsqlresult.h>
|
||||
#include <qsqldriver.h>
|
||||
#include <qdebug.h>
|
||||
#include <private/qsqlnulldriver_p.h>
|
||||
|
||||
#include "../qsqldatabase/tst_databases.h"
|
||||
|
||||
class tst_QSql : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
tst_QSql();
|
||||
virtual ~tst_QSql();
|
||||
|
||||
|
||||
public slots:
|
||||
void initTestCase();
|
||||
void cleanupTestCase();
|
||||
void init();
|
||||
void cleanup();
|
||||
private slots:
|
||||
void open();
|
||||
void openInvalid();
|
||||
void registerSqlDriver();
|
||||
|
||||
// problem specific tests
|
||||
void openErrorRecovery();
|
||||
void concurrentAccess();
|
||||
void basicDriverTest();
|
||||
};
|
||||
|
||||
/****************** General Qt SQL Module tests *****************/
|
||||
|
||||
tst_QSql::tst_QSql()
|
||||
{
|
||||
}
|
||||
|
||||
tst_QSql::~tst_QSql()
|
||||
{
|
||||
}
|
||||
|
||||
void tst_QSql::initTestCase()
|
||||
{
|
||||
}
|
||||
|
||||
void tst_QSql::cleanupTestCase()
|
||||
{
|
||||
}
|
||||
|
||||
void tst_QSql::init()
|
||||
{
|
||||
}
|
||||
|
||||
void tst_QSql::cleanup()
|
||||
{
|
||||
}
|
||||
|
||||
// this is a very basic test for drivers that cannot create/delete tables
|
||||
// it can be used while developing new drivers,
|
||||
// it's original purpose is to test ODBC Text datasources that are basically
|
||||
// to stupid to do anything more advanced than SELECT/INSERT/UPDATE/DELETE
|
||||
// the datasource has to have a table called "qtest_basictest" consisting
|
||||
// of a field "id"(integer) and "name"(char/varchar).
|
||||
void tst_QSql::basicDriverTest()
|
||||
{
|
||||
int argc = 1;
|
||||
char *argv[] = { const_cast<char*>(QTest::currentAppName()) };
|
||||
QCoreApplication app(argc, argv, false);
|
||||
tst_Databases dbs;
|
||||
QVERIFY(dbs.open());
|
||||
|
||||
foreach (const QString& dbName, dbs.dbNames) {
|
||||
QSqlDatabase db = QSqlDatabase::database(dbName);
|
||||
QVERIFY_SQL(db, isValid());
|
||||
|
||||
QStringList tables = db.tables();
|
||||
QString tableName;
|
||||
|
||||
if (tables.contains("qtest_basictest.txt"))
|
||||
tableName = "qtest_basictest.txt";
|
||||
else if (tables.contains("qtest_basictest"))
|
||||
tableName = "qtest_basictest";
|
||||
else if (tables.contains("QTEST_BASICTEST"))
|
||||
tableName = "QTEST_BASICTEST";
|
||||
else {
|
||||
QVERIFY(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
qDebug("Testing: %s", qPrintable(tst_Databases::dbToString(db)));
|
||||
|
||||
QSqlRecord rInf = db.record(tableName);
|
||||
QCOMPARE(rInf.count(), 2);
|
||||
QCOMPARE(rInf.fieldName(0).toLower(), QString("id"));
|
||||
QCOMPARE(rInf.fieldName(1).toLower(), QString("name"));
|
||||
}
|
||||
|
||||
dbs.close();
|
||||
QVERIFY(1); // make sure the test doesn't fail if no database drivers are there
|
||||
}
|
||||
|
||||
// make sure that the static stuff will be deleted
|
||||
// when using multiple QCoreApplication objects
|
||||
void tst_QSql::open()
|
||||
{
|
||||
int i;
|
||||
int argc = 1;
|
||||
char *argv[] = { const_cast<char*>(QTest::currentAppName()) };
|
||||
int count = -1;
|
||||
for (i = 0; i < 10; ++i) {
|
||||
QCoreApplication app(argc, argv, false);
|
||||
tst_Databases dbs;
|
||||
|
||||
QVERIFY(dbs.open());
|
||||
if (count == -1)
|
||||
// first iteration: see how many dbs are open
|
||||
count = (int) dbs.dbNames.size();
|
||||
else
|
||||
// next iterations: make sure all are opened again
|
||||
QCOMPARE(count, (int)dbs.dbNames.size());
|
||||
dbs.close();
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QSql::openInvalid()
|
||||
{
|
||||
QSqlDatabase db;
|
||||
QVERIFY(!db.open());
|
||||
|
||||
QSqlDatabase db2 = QSqlDatabase::addDatabase("doesnt_exist_will_never_exist", "blah");
|
||||
QFAIL_SQL(db2, open());
|
||||
}
|
||||
|
||||
void tst_QSql::concurrentAccess()
|
||||
{
|
||||
int argc = 1;
|
||||
char *argv[] = { const_cast<char*>(QTest::currentAppName()) };
|
||||
QCoreApplication app(argc, argv, false);
|
||||
tst_Databases dbs;
|
||||
|
||||
QVERIFY(dbs.open());
|
||||
foreach (const QString& dbName, dbs.dbNames) {
|
||||
QSqlDatabase db = QSqlDatabase::database(dbName);
|
||||
QVERIFY(db.isValid());
|
||||
if (tst_Databases::isMSAccess(db))
|
||||
continue;
|
||||
|
||||
QSqlDatabase ndb = QSqlDatabase::addDatabase(db.driverName(), "tst_QSql::concurrentAccess");
|
||||
ndb.setDatabaseName(db.databaseName());
|
||||
ndb.setHostName(db.hostName());
|
||||
ndb.setPort(db.port());
|
||||
ndb.setUserName(db.userName());
|
||||
ndb.setPassword(db.password());
|
||||
QVERIFY_SQL(ndb, open());
|
||||
|
||||
QCOMPARE(db.tables(), ndb.tables());
|
||||
ndb.close();
|
||||
}
|
||||
// no database servers installed - don't fail
|
||||
QVERIFY(1);
|
||||
dbs.close();
|
||||
}
|
||||
|
||||
void tst_QSql::openErrorRecovery()
|
||||
{
|
||||
int argc = 1;
|
||||
char *argv[] = { const_cast<char*>(QTest::currentAppName()) };
|
||||
QCoreApplication app(argc, argv, false);
|
||||
tst_Databases dbs;
|
||||
|
||||
QVERIFY(dbs.addDbs());
|
||||
if (dbs.dbNames.isEmpty())
|
||||
QSKIP("No database drivers installed");
|
||||
foreach (const QString& dbName, dbs.dbNames) {
|
||||
QSqlDatabase db = QSqlDatabase::database(dbName, false);
|
||||
CHECK_DATABASE(db);
|
||||
|
||||
QString userName = db.userName();
|
||||
QString password = db.password();
|
||||
|
||||
// force an open error
|
||||
if (db.open("dummy130977", "doesnt_exist")) {
|
||||
qDebug("Promiscuous database server without access control - test skipped for %s",
|
||||
qPrintable(tst_Databases::dbToString(db)));
|
||||
QVERIFY(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
QFAIL_SQL(db, isOpen());
|
||||
QVERIFY_SQL(db, isOpenError());
|
||||
|
||||
// now open it
|
||||
if (!db.open(userName, password)) {
|
||||
qDebug() << "Could not open Database " << tst_Databases::dbToString(db) <<
|
||||
". Assuming DB is down, skipping... (Error: " <<
|
||||
tst_Databases::printError(db.lastError()) << ")";
|
||||
continue;
|
||||
}
|
||||
QVERIFY_SQL(db, open(userName, password));
|
||||
QVERIFY_SQL(db, isOpen());
|
||||
QFAIL_SQL(db, isOpenError());
|
||||
db.close();
|
||||
QFAIL_SQL(db, isOpen());
|
||||
|
||||
// force another open error
|
||||
QFAIL_SQL(db, open("dummy130977", "doesnt_exist"));
|
||||
QFAIL_SQL(db, isOpen());
|
||||
QVERIFY_SQL(db, isOpenError());
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QSql::registerSqlDriver()
|
||||
{
|
||||
int argc = 1;
|
||||
char *argv[] = { const_cast<char*>(QTest::currentAppName()) };
|
||||
QCoreApplication app(argc, argv, false);
|
||||
|
||||
QSqlDatabase::registerSqlDriver("QSQLTESTDRIVER", new QSqlDriverCreator<QSqlNullDriver>);
|
||||
QVERIFY(QSqlDatabase::drivers().contains("QSQLTESTDRIVER"));
|
||||
|
||||
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLTESTDRIVER");
|
||||
QVERIFY(db.isValid());
|
||||
|
||||
QCOMPARE(db.tables(), QStringList());
|
||||
}
|
||||
|
||||
QTEST_APPLESS_MAIN(tst_QSql)
|
||||
#include "tst_qsql.moc"
|
15
tests/auto/sql/kernel/qsqldatabase/CMakeLists.txt
Normal file
15
tests/auto/sql/kernel/qsqldatabase/CMakeLists.txt
Normal file
@ -0,0 +1,15 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_qsqldatabase Test:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_test(tst_qsqldatabase
|
||||
SOURCES
|
||||
tst_qsqldatabase.cpp
|
||||
LIBRARIES
|
||||
Qt::CorePrivate
|
||||
Qt::Sql
|
||||
Qt::SqlPrivate
|
||||
)
|
BIN
tests/auto/sql/kernel/qsqldatabase/testdata/qtest.mdb
vendored
Normal file
BIN
tests/auto/sql/kernel/qsqldatabase/testdata/qtest.mdb
vendored
Normal file
Binary file not shown.
574
tests/auto/sql/kernel/qsqldatabase/tst_databases.h
Normal file
574
tests/auto/sql/kernel/qsqldatabase/tst_databases.h
Normal file
@ -0,0 +1,574 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
/* possible connection parameters */
|
||||
|
||||
#ifndef TST_DATABASES_H
|
||||
#define TST_DATABASES_H
|
||||
|
||||
#include <QSqlDatabase>
|
||||
#include <QSqlDriver>
|
||||
#include <QSqlError>
|
||||
#include <QSqlQuery>
|
||||
#include <QRegularExpression>
|
||||
#include <QRegularExpressionMatch>
|
||||
#include <QDir>
|
||||
#include <QScopedPointer>
|
||||
#include <QVariant>
|
||||
#include <QDebug>
|
||||
#include <QSqlTableModel>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonDocument>
|
||||
#include <QtSql/private/qsqldriver_p.h>
|
||||
#include <QTest>
|
||||
|
||||
#define CHECK_DATABASE( db ) \
|
||||
if ( !db.isValid() ) { qFatal( "db is Invalid" ); }
|
||||
|
||||
#define QVERIFY_SQL(q, stmt) QVERIFY2((q).stmt, tst_Databases::printError((q).lastError(), db))
|
||||
#define QFAIL_SQL(q, stmt) QVERIFY2(!(q).stmt, tst_Databases::printError((q).lastError(), db))
|
||||
|
||||
#define DBMS_SPECIFIC(db, driver) \
|
||||
if (!db.driverName().startsWith(driver)) { QSKIP(driver " specific test"); }
|
||||
|
||||
// ### use QSystem::hostName if it is integrated in qtest/main
|
||||
static QString qGetHostName()
|
||||
{
|
||||
static QString hostname;
|
||||
|
||||
if (hostname.isEmpty()) {
|
||||
hostname = QSysInfo::machineHostName();
|
||||
hostname.replace(QLatin1Char( '.' ), QLatin1Char( '_' ));
|
||||
hostname.replace(QLatin1Char( '-' ), QLatin1Char( '_' ));
|
||||
}
|
||||
|
||||
return hostname;
|
||||
}
|
||||
|
||||
inline QString fixupTableName(const QString &tableName, QSqlDatabase db)
|
||||
{
|
||||
QString tbName = tableName;
|
||||
// On Oracle we are limited to 30 character tablenames
|
||||
QSqlDriverPrivate *d = static_cast<QSqlDriverPrivate *>(QObjectPrivate::get(db.driver()));
|
||||
if (d && d->dbmsType == QSqlDriver::Oracle)
|
||||
tbName.truncate(30);
|
||||
// On Interbase we are limited to 31 character tablenames
|
||||
if (d && d->dbmsType == QSqlDriver::Interbase)
|
||||
tbName.truncate(31);
|
||||
return tbName;
|
||||
}
|
||||
|
||||
// to prevent nameclashes on our database server, each machine
|
||||
// will use its own set of table names. Call this function to get
|
||||
// "tablename_hostname"
|
||||
inline static QString qTableName(const QString &prefix, const char *sourceFileName,
|
||||
QSqlDatabase db, bool escape = true)
|
||||
{
|
||||
const auto tableStr = fixupTableName(QString(QLatin1String("dbtst") + db.driverName() + "_" +
|
||||
prefix + QString::number(qHash(QLatin1String(sourceFileName) +
|
||||
"_" + qGetHostName().replace("-", "_")), 16)), db);
|
||||
return escape ? db.driver()->escapeIdentifier(tableStr, QSqlDriver::TableName) : tableStr;
|
||||
}
|
||||
|
||||
inline static QString qTableName(const QString& prefix, QSqlDatabase db)
|
||||
{
|
||||
QString tableStr;
|
||||
if (db.driverName().toLower().contains("ODBC"))
|
||||
tableStr += QLatin1String("_odbc");
|
||||
return fixupTableName(QString(db.driver()->escapeIdentifier(prefix + tableStr + QLatin1Char('_') +
|
||||
qGetHostName(), QSqlDriver::TableName)),db);
|
||||
}
|
||||
|
||||
inline static bool testWhiteSpaceNames( const QString &name )
|
||||
{
|
||||
/* return name.startsWith( "QPSQL" )
|
||||
|| name.startsWith( "QODBC" )
|
||||
|| name.startsWith( "QSQLITE" )
|
||||
|| name.startsWith( "QMYSQL" );*/
|
||||
return name != QLatin1String("QSQLITE2");
|
||||
}
|
||||
|
||||
inline static QString toHex( const QString& binary )
|
||||
{
|
||||
QString str;
|
||||
static char const hexchars[] = "0123456789ABCDEF";
|
||||
|
||||
for ( int i = 0; i < binary.size(); i++ ) {
|
||||
ushort code = binary.at(i).unicode();
|
||||
str += (QChar)(hexchars[ (code >> 12) & 0x0F ]);
|
||||
str += (QChar)(hexchars[ (code >> 8) & 0x0F ]);
|
||||
str += (QChar)(hexchars[ (code >> 4) & 0x0F ]);
|
||||
str += (QChar)(hexchars[ code & 0x0F ]);
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
class tst_Databases
|
||||
{
|
||||
|
||||
public:
|
||||
tst_Databases(): counter( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
~tst_Databases()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
// returns a testtable consisting of the names of all database connections if
|
||||
// driverPrefix is empty, otherwise only those that start with driverPrefix.
|
||||
int fillTestTable( const QString& driverPrefix = QString() ) const
|
||||
{
|
||||
QTest::addColumn<QString>( "dbName" );
|
||||
int count = 0;
|
||||
|
||||
for ( int i = 0; i < dbNames.size(); ++i ) {
|
||||
QSqlDatabase db = QSqlDatabase::database( dbNames.at( i ) );
|
||||
|
||||
if ( !db.isValid() )
|
||||
continue;
|
||||
|
||||
if ( driverPrefix.isEmpty() || db.driverName().startsWith( driverPrefix ) ) {
|
||||
QTest::newRow( dbNames.at( i ).toLatin1() ) << dbNames.at( i );
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int fillTestTableWithStrategies( const QString& driverPrefix = QString() ) const
|
||||
{
|
||||
QTest::addColumn<QString>( "dbName" );
|
||||
QTest::addColumn<int>("submitpolicy_i");
|
||||
int count = 0;
|
||||
|
||||
for ( int i = 0; i < dbNames.size(); ++i ) {
|
||||
QSqlDatabase db = QSqlDatabase::database( dbNames.at( i ) );
|
||||
|
||||
if ( !db.isValid() )
|
||||
continue;
|
||||
|
||||
if ( driverPrefix.isEmpty() || db.driverName().startsWith( driverPrefix ) ) {
|
||||
QTest::newRow( QString("%1 [field]").arg(dbNames.at( i )).toLatin1() ) << dbNames.at( i ) << (int)QSqlTableModel::OnFieldChange;
|
||||
QTest::newRow( QString("%1 [row]").arg(dbNames.at( i )).toLatin1() ) << dbNames.at( i ) << (int)QSqlTableModel::OnRowChange;
|
||||
QTest::newRow( QString("%1 [manual]").arg(dbNames.at( i )).toLatin1() ) << dbNames.at( i ) << (int)QSqlTableModel::OnManualSubmit;
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
void addDb( const QString& driver, const QString& dbName,
|
||||
const QString& user = QString(), const QString& passwd = QString(),
|
||||
const QString& host = QString(), int port = -1, const QString params = QString() )
|
||||
{
|
||||
QSqlDatabase db;
|
||||
|
||||
if ( !QSqlDatabase::drivers().contains( driver ) ) {
|
||||
qWarning() << "Driver" << driver << "is not installed";
|
||||
return;
|
||||
}
|
||||
|
||||
// construct a stupid unique name
|
||||
QString cName = QString::number( counter++ ) + QLatin1Char('_') + driver + QLatin1Char('@');
|
||||
|
||||
cName += host.isEmpty() ? dbName : host;
|
||||
|
||||
if ( port > 0 )
|
||||
cName += QLatin1Char(':') + QString::number( port );
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
db = QSqlDatabase::addDatabase( driver, cName );
|
||||
|
||||
if ( !db.isValid() ) {
|
||||
qWarning( "Could not create database object" );
|
||||
return;
|
||||
}
|
||||
|
||||
db.setDatabaseName( dbName );
|
||||
|
||||
db.setUserName( user );
|
||||
db.setPassword( passwd );
|
||||
db.setHostName( host );
|
||||
db.setPort( port );
|
||||
db.setConnectOptions( params );
|
||||
dbNames.append( cName );
|
||||
}
|
||||
|
||||
bool addDbs()
|
||||
{
|
||||
// Test databases can be defined in a file using the following format:
|
||||
//
|
||||
// {
|
||||
// "entries": [
|
||||
// {
|
||||
// "driver": "QPSQL",
|
||||
// "name": "testdb",
|
||||
// "username": "postgres",
|
||||
// "password": "password",
|
||||
// "hostname": "localhost",
|
||||
// "port": 5432,
|
||||
// "parameters": "extraoptions"
|
||||
// },
|
||||
// {
|
||||
// ....
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
|
||||
bool added = false;
|
||||
const QString databasesFile(qgetenv("QT_TEST_DATABASES_FILE"));
|
||||
QFile f(databasesFile.isEmpty() ? "testdbs.json" : databasesFile);
|
||||
if (f.exists() && f.open(QIODevice::ReadOnly)) {
|
||||
const QJsonDocument doc = QJsonDocument::fromJson(f.readAll());
|
||||
f.close();
|
||||
const QJsonValue entriesV = doc.object().value(QLatin1String("entries"));
|
||||
if (!entriesV.isArray()) {
|
||||
qWarning() << "No entries in " + f.fileName();
|
||||
} else {
|
||||
const QJsonArray entriesA = entriesV.toArray();
|
||||
QJsonArray::const_iterator it = entriesA.constBegin();
|
||||
while (it != entriesA.constEnd()) {
|
||||
if ((*it).isObject()) {
|
||||
const QJsonObject object = (*it).toObject();
|
||||
addDb(object.value(QStringLiteral("driver")).toString(),
|
||||
object.value(QStringLiteral("name")).toString(),
|
||||
object.value(QStringLiteral("username")).toString(),
|
||||
object.value(QStringLiteral("password")).toString(),
|
||||
object.value(QStringLiteral("hostname")).toString(),
|
||||
object.value(QStringLiteral("port")).toInt(),
|
||||
object.value(QStringLiteral("parameters")).toString());
|
||||
added = true;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
QTemporaryDir *sqLiteDir = dbDir();
|
||||
if (sqLiteDir) {
|
||||
addDb(QStringLiteral("QSQLITE"), QDir::toNativeSeparators(sqLiteDir->path() + QStringLiteral("/sqlite.db")));
|
||||
added = true;
|
||||
}
|
||||
return added;
|
||||
}
|
||||
|
||||
// 'false' return indicates a system error, for example failure to create a temporary directory.
|
||||
bool open()
|
||||
{
|
||||
if (!addDbs())
|
||||
return false;
|
||||
|
||||
QStringList::Iterator it = dbNames.begin();
|
||||
|
||||
while ( it != dbNames.end() ) {
|
||||
QSqlDatabase db = QSqlDatabase::database(( *it ), false );
|
||||
qDebug() << "Opening:" << (*it);
|
||||
|
||||
if ( db.isValid() && !db.isOpen() ) {
|
||||
if ( !db.open() ) {
|
||||
qWarning( "tst_Databases: Unable to open %s on %s:\n%s", qPrintable( db.driverName() ), qPrintable( *it ), qPrintable( db.lastError().databaseText() ) );
|
||||
// well... opening failed, so we just ignore the server, maybe it is not running
|
||||
it = dbNames.erase( it );
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void close()
|
||||
{
|
||||
for ( QStringList::Iterator it = dbNames.begin(); it != dbNames.end(); ++it ) {
|
||||
{
|
||||
QSqlDatabase db = QSqlDatabase::database(( *it ), false );
|
||||
|
||||
if ( db.isValid() && db.isOpen() )
|
||||
db.close();
|
||||
}
|
||||
|
||||
QSqlDatabase::removeDatabase(( *it ) );
|
||||
}
|
||||
|
||||
dbNames.clear();
|
||||
}
|
||||
|
||||
// for debugging only: outputs the connection as string
|
||||
static QString dbToString( const QSqlDatabase db )
|
||||
{
|
||||
QString res = db.driverName() + QLatin1Char('@');
|
||||
|
||||
if ( db.driverName().startsWith( "QODBC" ) || db.driverName().startsWith( "QOCI" ) ) {
|
||||
res += db.databaseName();
|
||||
} else {
|
||||
res += db.hostName();
|
||||
}
|
||||
|
||||
if ( db.port() > 0 ) {
|
||||
res += QLatin1Char(':') + QString::number( db.port() );
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// drop a table only if it exists to prevent warnings
|
||||
static void safeDropTables( QSqlDatabase db, const QStringList& tableNames )
|
||||
{
|
||||
bool wasDropped;
|
||||
QSqlQuery q( db );
|
||||
QStringList dbtables=db.tables();
|
||||
QSqlDriver::DbmsType dbType = getDatabaseType(db);
|
||||
foreach(const QString &tableName, tableNames)
|
||||
{
|
||||
wasDropped = true;
|
||||
QString table=tableName;
|
||||
if ( db.driver()->isIdentifierEscaped(table, QSqlDriver::TableName))
|
||||
table = db.driver()->stripDelimiters(table, QSqlDriver::TableName);
|
||||
|
||||
if ( dbtables.contains( table, Qt::CaseInsensitive ) ) {
|
||||
foreach(const QString &table2, dbtables.filter(table, Qt::CaseInsensitive)) {
|
||||
if(table2.compare(table.section('.', -1, -1), Qt::CaseInsensitive) == 0) {
|
||||
table=db.driver()->escapeIdentifier(table2, QSqlDriver::TableName);
|
||||
if (dbType == QSqlDriver::PostgreSQL)
|
||||
wasDropped = q.exec( "drop table " + table + " cascade");
|
||||
else
|
||||
wasDropped = q.exec( "drop table " + table);
|
||||
dbtables.removeAll(table2);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( !wasDropped ) {
|
||||
qWarning() << dbToString(db) << "unable to drop table" << tableName << ':' << q.lastError();
|
||||
// qWarning() << "last query:" << q.lastQuery();
|
||||
// qWarning() << "dbtables:" << dbtables;
|
||||
// qWarning() << "db.tables():" << db.tables();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void safeDropTable( QSqlDatabase db, const QString& tableName )
|
||||
{
|
||||
safeDropTables(db, QStringList() << tableName);
|
||||
}
|
||||
|
||||
static void safeDropViews( QSqlDatabase db, const QStringList &viewNames )
|
||||
{
|
||||
if ( isMSAccess( db ) ) // Access is sooo stupid.
|
||||
safeDropTables( db, viewNames );
|
||||
|
||||
bool wasDropped;
|
||||
QSqlQuery q( db );
|
||||
QStringList dbtables=db.tables(QSql::Views);
|
||||
|
||||
foreach(QString viewName, viewNames)
|
||||
{
|
||||
wasDropped = true;
|
||||
QString view=viewName;
|
||||
if ( db.driver()->isIdentifierEscaped(view, QSqlDriver::TableName))
|
||||
view = db.driver()->stripDelimiters(view, QSqlDriver::TableName);
|
||||
|
||||
if ( dbtables.contains( view, Qt::CaseInsensitive ) ) {
|
||||
foreach(const QString &view2, dbtables.filter(view, Qt::CaseInsensitive)) {
|
||||
if(view2.compare(view.section('.', -1, -1), Qt::CaseInsensitive) == 0) {
|
||||
view=db.driver()->escapeIdentifier(view2, QSqlDriver::TableName);
|
||||
wasDropped = q.exec( "drop view " + view);
|
||||
dbtables.removeAll(view);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( !wasDropped )
|
||||
qWarning() << dbToString(db) << "unable to drop view" << viewName << ':' << q.lastError();
|
||||
// << "\nlast query:" << q.lastQuery()
|
||||
// << "\ndbtables:" << dbtables
|
||||
// << "\ndb.tables(QSql::Views):" << db.tables(QSql::Views);
|
||||
}
|
||||
}
|
||||
|
||||
static void safeDropView( QSqlDatabase db, const QString& tableName )
|
||||
{
|
||||
safeDropViews(db, QStringList() << tableName);
|
||||
}
|
||||
|
||||
// returns the type name of the blob datatype for the database db.
|
||||
// blobSize is only used if the db doesn't have a generic blob type
|
||||
static QString blobTypeName( QSqlDatabase db, int blobSize = 10000 )
|
||||
{
|
||||
const QSqlDriver::DbmsType dbType = getDatabaseType(db);
|
||||
if (dbType == QSqlDriver::MySqlServer)
|
||||
return "longblob";
|
||||
|
||||
if (dbType == QSqlDriver::PostgreSQL)
|
||||
return "bytea";
|
||||
|
||||
if (dbType == QSqlDriver::Sybase
|
||||
|| dbType == QSqlDriver::MSSqlServer
|
||||
|| isMSAccess( db ) )
|
||||
return "image";
|
||||
|
||||
if (dbType == QSqlDriver::DB2)
|
||||
return QString( "blob(%1)" ).arg( blobSize );
|
||||
|
||||
if (dbType == QSqlDriver::Interbase)
|
||||
return QString( "blob sub_type 0 segment size 4096" );
|
||||
|
||||
if (dbType == QSqlDriver::Oracle
|
||||
|| dbType == QSqlDriver::SQLite)
|
||||
return "blob";
|
||||
|
||||
qDebug() << "tst_Databases::blobTypeName: Don't know the blob type for" << dbToString( db );
|
||||
|
||||
return "blob";
|
||||
}
|
||||
|
||||
static QString dateTimeTypeName(QSqlDatabase db)
|
||||
{
|
||||
const QSqlDriver::DbmsType dbType = tst_Databases::getDatabaseType(db);
|
||||
if (dbType == QSqlDriver::PostgreSQL)
|
||||
return QLatin1String("timestamptz");
|
||||
if (dbType == QSqlDriver::Oracle && getOraVersion(db) >= 9)
|
||||
return QLatin1String("timestamp(0)");
|
||||
if (dbType == QSqlDriver::Interbase)
|
||||
return QLatin1String("timestamp");
|
||||
return QLatin1String("datetime");
|
||||
}
|
||||
|
||||
static QString timeTypeName(QSqlDatabase db)
|
||||
{
|
||||
const QSqlDriver::DbmsType dbType = tst_Databases::getDatabaseType(db);
|
||||
if (dbType == QSqlDriver::Oracle && getOraVersion(db) >= 9)
|
||||
return QLatin1String("timestamp(0)");
|
||||
return QLatin1String("time");
|
||||
}
|
||||
|
||||
static QString dateTypeName(QSqlDatabase db)
|
||||
{
|
||||
const QSqlDriver::DbmsType dbType = tst_Databases::getDatabaseType(db);
|
||||
if (dbType == QSqlDriver::Oracle && getOraVersion(db) >= 9)
|
||||
return QLatin1String("timestamp(0)");
|
||||
return QLatin1String("date");
|
||||
}
|
||||
|
||||
static QString autoFieldName( QSqlDatabase db )
|
||||
{
|
||||
const QSqlDriver::DbmsType dbType = tst_Databases::getDatabaseType(db);
|
||||
if (dbType == QSqlDriver::MySqlServer)
|
||||
return "AUTO_INCREMENT";
|
||||
if (dbType == QSqlDriver::Sybase || dbType == QSqlDriver::MSSqlServer)
|
||||
return "IDENTITY";
|
||||
/* if (dbType == QSqlDriver::PostgreSQL)
|
||||
return "SERIAL";*/
|
||||
// if (dbType == QSqlDriver::DB2)
|
||||
// return "GENERATED BY DEFAULT AS IDENTITY";
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
static QByteArray printError( const QSqlError& err )
|
||||
{
|
||||
QString result;
|
||||
if (!err.nativeErrorCode().isEmpty())
|
||||
result += '(' + err.nativeErrorCode() + ") ";
|
||||
result += '\'';
|
||||
if(!err.driverText().isEmpty())
|
||||
result += err.driverText() + "' || '";
|
||||
result += err.databaseText() + QLatin1Char('\'');
|
||||
return result.toLocal8Bit();
|
||||
}
|
||||
|
||||
static QByteArray printError( const QSqlError& err, const QSqlDatabase& db )
|
||||
{
|
||||
QString result(dbToString(db) + ": ");
|
||||
if (!err.nativeErrorCode().isEmpty())
|
||||
result += '(' + err.nativeErrorCode() + ") ";
|
||||
result += '\'';
|
||||
if(!err.driverText().isEmpty())
|
||||
result += err.driverText() + "' || '";
|
||||
result += err.databaseText() + QLatin1Char('\'');
|
||||
return result.toLocal8Bit();
|
||||
}
|
||||
|
||||
static QSqlDriver::DbmsType getDatabaseType(QSqlDatabase db)
|
||||
{
|
||||
QSqlDriverPrivate *d = static_cast<QSqlDriverPrivate *>(QObjectPrivate::get(db.driver()));
|
||||
return d->dbmsType;
|
||||
}
|
||||
|
||||
static bool isMSAccess( QSqlDatabase db )
|
||||
{
|
||||
return db.databaseName().contains( "Access Driver", Qt::CaseInsensitive );
|
||||
}
|
||||
|
||||
// -1 on fail, else Oracle version
|
||||
static int getOraVersion( QSqlDatabase db )
|
||||
{
|
||||
int ver = -1;
|
||||
QSqlQuery q( "SELECT banner FROM v$version", db );
|
||||
q.next();
|
||||
|
||||
QRegularExpression vers("([0-9]+)\\.[0-9\\.]+[0-9]");
|
||||
QRegularExpressionMatch match = vers.match(q.value(0).toString());
|
||||
if (match.hasMatch()) {
|
||||
bool ok;
|
||||
ver = match.captured(1).toInt(&ok);
|
||||
|
||||
if (!ok)
|
||||
ver = -1;
|
||||
}
|
||||
|
||||
return ver;
|
||||
}
|
||||
|
||||
static QString getMySqlVersion( const QSqlDatabase &db )
|
||||
{
|
||||
QSqlQuery q(db);
|
||||
q.exec( "select version()" );
|
||||
if(q.next())
|
||||
return q.value( 0 ).toString();
|
||||
else
|
||||
return QString();
|
||||
}
|
||||
|
||||
static QString getPSQLVersion( const QSqlDatabase &db )
|
||||
{
|
||||
QSqlQuery q(db);
|
||||
q.exec( "select version()" );
|
||||
if(q.next())
|
||||
return q.value( 0 ).toString();
|
||||
else
|
||||
return QString();
|
||||
}
|
||||
|
||||
QStringList dbNames;
|
||||
int counter;
|
||||
|
||||
private:
|
||||
QTemporaryDir *dbDir()
|
||||
{
|
||||
if (m_dbDir.isNull()) {
|
||||
m_dbDir.reset(new QTemporaryDir);
|
||||
if (!m_dbDir->isValid()) {
|
||||
qWarning() << Q_FUNC_INFO << "Unable to create a temporary directory: " << QDir::toNativeSeparators(m_dbDir->path());
|
||||
m_dbDir.reset();
|
||||
}
|
||||
}
|
||||
return m_dbDir.data();
|
||||
}
|
||||
|
||||
QScopedPointer<QTemporaryDir> m_dbDir;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
2515
tests/auto/sql/kernel/qsqldatabase/tst_qsqldatabase.cpp
Normal file
2515
tests/auto/sql/kernel/qsqldatabase/tst_qsqldatabase.cpp
Normal file
File diff suppressed because it is too large
Load Diff
15
tests/auto/sql/kernel/qsqldriver/CMakeLists.txt
Normal file
15
tests/auto/sql/kernel/qsqldriver/CMakeLists.txt
Normal file
@ -0,0 +1,15 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_qsqldriver Test:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_test(tst_qsqldriver
|
||||
SOURCES
|
||||
tst_qsqldriver.cpp
|
||||
LIBRARIES
|
||||
Qt::CorePrivate
|
||||
Qt::Sql
|
||||
Qt::SqlPrivate
|
||||
)
|
245
tests/auto/sql/kernel/qsqldriver/tst_qsqldriver.cpp
Normal file
245
tests/auto/sql/kernel/qsqldriver/tst_qsqldriver.cpp
Normal file
@ -0,0 +1,245 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
|
||||
#include <QTest>
|
||||
#include <QtSql/QtSql>
|
||||
|
||||
#include "../qsqldatabase/tst_databases.h"
|
||||
|
||||
class tst_QSqlDriver : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
void recreateTestTables(QSqlDatabase);
|
||||
|
||||
tst_Databases dbs;
|
||||
|
||||
public slots:
|
||||
void initTestCase_data();
|
||||
void initTestCase();
|
||||
void cleanupTestCase();
|
||||
void init();
|
||||
void cleanup();
|
||||
|
||||
private slots:
|
||||
void record();
|
||||
void primaryIndex();
|
||||
void formatValue();
|
||||
};
|
||||
|
||||
static bool driverSupportsDefaultValues(QSqlDriver::DbmsType dbType)
|
||||
{
|
||||
switch (dbType) {
|
||||
case QSqlDriver::SQLite:
|
||||
case QSqlDriver::PostgreSQL:
|
||||
case QSqlDriver::Oracle:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void tst_QSqlDriver::initTestCase_data()
|
||||
{
|
||||
QVERIFY(dbs.open());
|
||||
if (dbs.fillTestTable() == 0)
|
||||
QSKIP("No database drivers are available in this Qt configuration");
|
||||
}
|
||||
|
||||
void tst_QSqlDriver::recreateTestTables(QSqlDatabase db)
|
||||
{
|
||||
QSqlQuery q(db);
|
||||
const QString relTEST1(qTableName("relTEST1", __FILE__, db));
|
||||
|
||||
QSqlDriver::DbmsType dbType = tst_Databases::getDatabaseType(db);
|
||||
if (dbType == QSqlDriver::PostgreSQL)
|
||||
QVERIFY_SQL( q, exec("set client_min_messages='warning'"));
|
||||
|
||||
tst_Databases::safeDropTable( db, relTEST1 );
|
||||
QString doubleField;
|
||||
if (dbType == QSqlDriver::SQLite)
|
||||
doubleField = "more_data double";
|
||||
else if (dbType == QSqlDriver::Oracle)
|
||||
doubleField = "more_data number(8,7)";
|
||||
else if (dbType == QSqlDriver::PostgreSQL)
|
||||
doubleField = "more_data double precision";
|
||||
else if (dbType == QSqlDriver::Interbase)
|
||||
doubleField = "more_data numeric(8,7)";
|
||||
else
|
||||
doubleField = "more_data double(8,7)";
|
||||
const QString defValue(driverSupportsDefaultValues(dbType) ? QStringLiteral("DEFAULT 'defaultVal'") : QString());
|
||||
QVERIFY_SQL( q, exec("create table " + relTEST1 +
|
||||
" (id int not null primary key, name varchar(20) " + defValue + ", title_key int, another_title_key int, " + doubleField + QLatin1Char(')')));
|
||||
QVERIFY_SQL( q, exec("insert into " + relTEST1 + " values(1, 'harry', 1, 2, 1.234567)"));
|
||||
QVERIFY_SQL( q, exec("insert into " + relTEST1 + " values(2, 'trond', 2, 1, 8.901234)"));
|
||||
QVERIFY_SQL( q, exec("insert into " + relTEST1 + " values(3, 'vohi', 1, 2, 5.678901)"));
|
||||
QVERIFY_SQL( q, exec("insert into " + relTEST1 + " values(4, 'boris', 2, 2, 2.345678)"));
|
||||
}
|
||||
|
||||
void tst_QSqlDriver::initTestCase()
|
||||
{
|
||||
foreach (const QString &dbname, dbs.dbNames)
|
||||
recreateTestTables(QSqlDatabase::database(dbname));
|
||||
}
|
||||
|
||||
void tst_QSqlDriver::cleanupTestCase()
|
||||
{
|
||||
foreach (const QString &dbName, dbs.dbNames) {
|
||||
QSqlDatabase db = QSqlDatabase::database(dbName);
|
||||
tst_Databases::safeDropTable(db, qTableName("relTEST1", __FILE__, db));
|
||||
const QSqlDriver::DbmsType dbType = tst_Databases::getDatabaseType(db);
|
||||
if (dbType == QSqlDriver::Oracle)
|
||||
tst_Databases::safeDropTable(db, qTableName("clobTable", __FILE__, db));
|
||||
}
|
||||
dbs.close();
|
||||
}
|
||||
|
||||
void tst_QSqlDriver::init()
|
||||
{
|
||||
}
|
||||
|
||||
void tst_QSqlDriver::cleanup()
|
||||
{
|
||||
}
|
||||
|
||||
void tst_QSqlDriver::record()
|
||||
{
|
||||
QFETCH_GLOBAL(QString, dbName);
|
||||
QSqlDatabase db = QSqlDatabase::database(dbName);
|
||||
CHECK_DATABASE(db);
|
||||
|
||||
QString tablename(qTableName("relTEST1", __FILE__, db));
|
||||
QStringList fields;
|
||||
fields << "id" << "name" << "title_key" << "another_title_key" << "more_data";
|
||||
|
||||
//check we can get records using an unquoted mixed case table name
|
||||
QSqlRecord rec = db.driver()->record(tablename);
|
||||
QCOMPARE(rec.count(), fields.size());
|
||||
|
||||
QSqlDriver::DbmsType dbType = tst_Databases::getDatabaseType(db);
|
||||
// QTBUG-1363: QSqlField::length() always return -1 when using QODBC driver and QSqlDatabase::record()
|
||||
if (dbType == QSqlDriver::MSSqlServer && db.driverName().startsWith("QODBC"))
|
||||
QCOMPARE(rec.field(1).length(), 20);
|
||||
|
||||
if (dbType == QSqlDriver::Interbase || dbType == QSqlDriver::Oracle || dbType == QSqlDriver::DB2)
|
||||
for(int i = 0; i < fields.size(); ++i)
|
||||
fields[i] = fields[i].toUpper();
|
||||
|
||||
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 (dbType == QSqlDriver::Oracle || dbType == QSqlDriver::DB2)
|
||||
tablename = tablename.toUpper();
|
||||
else if (dbType == QSqlDriver::PostgreSQL)
|
||||
tablename = tablename.toLower();
|
||||
|
||||
if (dbType != QSqlDriver::PostgreSQL && !db.driverName().startsWith("QODBC")) {
|
||||
//check we can get records using a properly quoted table name
|
||||
rec = db.driver()->record(db.driver()->escapeIdentifier(tablename,QSqlDriver::TableName));
|
||||
QCOMPARE(rec.count(), 5);
|
||||
}
|
||||
|
||||
for (int i = 0; i < fields.size(); ++i)
|
||||
QCOMPARE(rec.fieldName(i), fields[i]);
|
||||
|
||||
if (dbType == QSqlDriver::Interbase || dbType == QSqlDriver::Oracle || dbType == QSqlDriver::DB2)
|
||||
tablename = tablename.toLower();
|
||||
else if (dbType == QSqlDriver::PostgreSQL)
|
||||
tablename = tablename.toUpper();
|
||||
|
||||
//check that we can't get records using incorrect tablename casing that's been quoted
|
||||
rec = db.driver()->record(db.driver()->escapeIdentifier(tablename,QSqlDriver::TableName));
|
||||
if (dbType == QSqlDriver::MySqlServer || dbType == QSqlDriver::SQLite || dbType == QSqlDriver::Sybase
|
||||
|| dbType == QSqlDriver::MSSqlServer || tst_Databases::isMSAccess(db))
|
||||
QCOMPARE(rec.count(), 5); //mysql, sqlite and tds will match
|
||||
else
|
||||
QCOMPARE(rec.count(), 0);
|
||||
|
||||
}
|
||||
|
||||
void tst_QSqlDriver::primaryIndex()
|
||||
{
|
||||
QFETCH_GLOBAL(QString, dbName);
|
||||
QSqlDatabase db = QSqlDatabase::database(dbName);
|
||||
CHECK_DATABASE(db);
|
||||
|
||||
QString tablename(qTableName("relTEST1", __FILE__, db));
|
||||
//check that we can get primary index using unquoted mixed case table name
|
||||
QSqlIndex index = db.driver()->primaryIndex(tablename);
|
||||
QCOMPARE(index.count(), 1);
|
||||
|
||||
QSqlDriver::DbmsType dbType = tst_Databases::getDatabaseType(db);
|
||||
if (dbType == QSqlDriver::Interbase || dbType == QSqlDriver::Oracle || dbType == QSqlDriver::DB2)
|
||||
QCOMPARE(index.fieldName(0), QString::fromLatin1("ID"));
|
||||
else
|
||||
QCOMPARE(index.fieldName(0), QString::fromLatin1("id"));
|
||||
|
||||
|
||||
//check that we can get the primary index using a quoted tablename
|
||||
if (dbType == QSqlDriver::Oracle || dbType == QSqlDriver::DB2)
|
||||
tablename = tablename.toUpper();
|
||||
else if (dbType == QSqlDriver::PostgreSQL)
|
||||
tablename = tablename.toLower();
|
||||
|
||||
if (dbType != QSqlDriver::PostgreSQL && !db.driverName().startsWith("QODBC")) {
|
||||
index = db.driver()->primaryIndex(db.driver()->escapeIdentifier(tablename, QSqlDriver::TableName));
|
||||
QCOMPARE(index.count(), 1);
|
||||
}
|
||||
if (dbType == QSqlDriver::Interbase || dbType == QSqlDriver::Oracle || dbType == QSqlDriver::DB2)
|
||||
QCOMPARE(index.fieldName(0), QString::fromLatin1("ID"));
|
||||
else
|
||||
QCOMPARE(index.fieldName(0), QString::fromLatin1("id"));
|
||||
|
||||
|
||||
|
||||
//check that we can not get the primary index using a quoted but incorrect table name casing
|
||||
if (dbType == QSqlDriver::Interbase || dbType == QSqlDriver::Oracle || dbType == QSqlDriver::DB2)
|
||||
tablename = tablename.toLower();
|
||||
else if (dbType == QSqlDriver::PostgreSQL)
|
||||
tablename = tablename.toUpper();
|
||||
|
||||
index = db.driver()->primaryIndex(db.driver()->escapeIdentifier(tablename, QSqlDriver::TableName));
|
||||
if (dbType == QSqlDriver::MySqlServer || dbType == QSqlDriver::SQLite || dbType == QSqlDriver::Sybase
|
||||
|| dbType == QSqlDriver::MSSqlServer || tst_Databases::isMSAccess(db))
|
||||
QCOMPARE(index.count(), 1); //mysql will always find the table name regardless of casing
|
||||
else
|
||||
QCOMPARE(index.count(), 0);
|
||||
|
||||
// Test getting a primary index for a table with a clob in it - QTBUG-64427
|
||||
if (dbType == QSqlDriver::Oracle) {
|
||||
const QString clobTable(qTableName("clobTable", __FILE__, db));
|
||||
QSqlQuery qry(db);
|
||||
QVERIFY_SQL(qry, exec("CREATE TABLE " + clobTable + " (id INTEGER, clobField CLOB)"));
|
||||
QVERIFY_SQL(qry, exec("CREATE UNIQUE INDEX " + clobTable + "IDX ON " + clobTable + " (id)"));
|
||||
QVERIFY_SQL(qry, exec("ALTER TABLE " + clobTable + " ADD CONSTRAINT " + clobTable +
|
||||
"PK PRIMARY KEY(id)"));
|
||||
QVERIFY_SQL(qry, exec("ALTER TABLE " + clobTable + " MODIFY (id NOT NULL ENABLE)"));
|
||||
const QSqlIndex primaryIndex = db.driver()->primaryIndex(clobTable);
|
||||
QCOMPARE(primaryIndex.count(), 1);
|
||||
QCOMPARE(primaryIndex.fieldName(0), QStringLiteral("ID"));
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QSqlDriver::formatValue()
|
||||
{
|
||||
QFETCH_GLOBAL(QString, dbName);
|
||||
QSqlDatabase db = QSqlDatabase::database(dbName);
|
||||
CHECK_DATABASE(db);
|
||||
QString tablename(qTableName("relTEST1", __FILE__, db));
|
||||
QSqlQuery qry(db);
|
||||
QVERIFY_SQL(qry, exec("SELECT * FROM " + tablename));
|
||||
qry.next();
|
||||
QSqlRecord rec = qry.record();
|
||||
QCOMPARE(db.driver()->formatValue(rec.field("id")), QString("1"));
|
||||
QCOMPARE(db.driver()->formatValue(rec.field("name")), QString("'harry'"));
|
||||
QCOMPARE(db.driver()->formatValue(rec.field("more_data")), QString("1.234567"));
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QSqlDriver)
|
||||
#include "tst_qsqldriver.moc"
|
13
tests/auto/sql/kernel/qsqlerror/CMakeLists.txt
Normal file
13
tests/auto/sql/kernel/qsqlerror/CMakeLists.txt
Normal file
@ -0,0 +1,13 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_qsqlerror Test:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_test(tst_qsqlerror
|
||||
SOURCES
|
||||
tst_qsqlerror.cpp
|
||||
LIBRARIES
|
||||
Qt::Sql
|
||||
)
|
143
tests/auto/sql/kernel/qsqlerror/tst_qsqlerror.cpp
Normal file
143
tests/auto/sql/kernel/qsqlerror/tst_qsqlerror.cpp
Normal file
@ -0,0 +1,143 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
|
||||
#include <QTest>
|
||||
|
||||
#include <qcoreapplication.h>
|
||||
#include <qdebug.h>
|
||||
#include <qsqlerror.h>
|
||||
|
||||
class tst_QSqlError : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
tst_QSqlError();
|
||||
virtual ~tst_QSqlError();
|
||||
|
||||
private slots:
|
||||
void construction();
|
||||
void moveOperator();
|
||||
void operators();
|
||||
void qtbug_74575();
|
||||
};
|
||||
|
||||
tst_QSqlError::tst_QSqlError()
|
||||
{
|
||||
}
|
||||
|
||||
tst_QSqlError::~tst_QSqlError()
|
||||
{
|
||||
}
|
||||
|
||||
void tst_QSqlError::construction()
|
||||
{
|
||||
QSqlError obj1("drivertext", "databasetext", QSqlError::UnknownError, QStringLiteral("123"));
|
||||
QCOMPARE(obj1.driverText(), QString("drivertext"));
|
||||
QCOMPARE(obj1.databaseText(), QString("databasetext"));
|
||||
QCOMPARE(obj1.type(), QSqlError::UnknownError);
|
||||
QCOMPARE(obj1.nativeErrorCode(), QStringLiteral("123"));
|
||||
QVERIFY(obj1.isValid());
|
||||
|
||||
QSqlError obj2(obj1);
|
||||
QCOMPARE(obj2.driverText(), obj1.driverText());
|
||||
QCOMPARE(obj2.databaseText(), obj1.databaseText());
|
||||
QCOMPARE(obj2.type(), obj1.type());
|
||||
QCOMPARE(obj2.nativeErrorCode(), obj1.nativeErrorCode());
|
||||
QVERIFY(obj2.isValid());
|
||||
|
||||
QSqlError obj3 = obj2;
|
||||
QCOMPARE(obj3.driverText(), obj2.driverText());
|
||||
QCOMPARE(obj3.databaseText(), obj2.databaseText());
|
||||
QCOMPARE(obj3.type(), obj2.type());
|
||||
QCOMPARE(obj3.nativeErrorCode(), obj2.nativeErrorCode());
|
||||
QVERIFY(obj3.isValid());
|
||||
|
||||
QSqlError obj4;
|
||||
QVERIFY(!obj4.isValid());
|
||||
QCOMPARE(obj4.driverText(), QString());
|
||||
QCOMPARE(obj4.databaseText(), QString());
|
||||
QCOMPARE(obj4.text(), QString());
|
||||
QCOMPARE(obj4.type(), QSqlError::NoError);
|
||||
QCOMPARE(obj4.nativeErrorCode(), QString());
|
||||
|
||||
QSqlError obj5(QStringLiteral("drivertext"), QStringLiteral("databasetext"),
|
||||
QSqlError::UnknownError, QStringLiteral("123"));
|
||||
QCOMPARE(obj5.driverText(), QString("drivertext"));
|
||||
QCOMPARE(obj5.databaseText(), QString("databasetext"));
|
||||
QCOMPARE(obj5.type(), QSqlError::UnknownError);
|
||||
QCOMPARE(obj5.nativeErrorCode(), QStringLiteral("123"));
|
||||
QVERIFY(obj5.isValid());
|
||||
|
||||
QSqlError obj6(QStringLiteral("drivertext"), QStringLiteral("databasetext"),
|
||||
QSqlError::UnknownError, QStringLiteral("Err123"));
|
||||
QCOMPARE(obj6.driverText(), QString("drivertext"));
|
||||
QCOMPARE(obj6.databaseText(), QString("databasetext"));
|
||||
QCOMPARE(obj6.type(), QSqlError::UnknownError);
|
||||
QCOMPARE(obj6.nativeErrorCode(), QStringLiteral("Err123"));
|
||||
QVERIFY(obj6.isValid());
|
||||
|
||||
// Default constructed object
|
||||
QSqlError obj7;
|
||||
QVERIFY(!obj7.isValid());
|
||||
QCOMPARE(obj7.driverText(), QString());
|
||||
QCOMPARE(obj7.databaseText(), QString());
|
||||
QCOMPARE(obj7.type(), QSqlError::NoError);
|
||||
QCOMPARE(obj7.nativeErrorCode(), QString());
|
||||
|
||||
// Move constructor
|
||||
QSqlError obj8(std::move(obj3));
|
||||
QCOMPARE(obj8.driverText(), obj2.driverText());
|
||||
QCOMPARE(obj8.databaseText(), obj2.databaseText());
|
||||
QCOMPARE(obj8.type(), obj2.type());
|
||||
QCOMPARE(obj8.nativeErrorCode(), obj2.nativeErrorCode());
|
||||
QVERIFY(obj8.isValid());
|
||||
}
|
||||
|
||||
void tst_QSqlError::moveOperator()
|
||||
{
|
||||
QSqlError obj1("drivertext", "databasetext", QSqlError::UnknownError, QStringLiteral("123")), obj2;
|
||||
obj2 = std::move(obj1);
|
||||
QCOMPARE(obj2.driverText(), QString("drivertext"));
|
||||
QCOMPARE(obj2.databaseText(), QString("databasetext"));
|
||||
QCOMPARE(obj2.type(), QSqlError::UnknownError);
|
||||
QCOMPARE(obj2.nativeErrorCode(), QStringLiteral("123"));
|
||||
QVERIFY(obj2.isValid());
|
||||
}
|
||||
|
||||
void tst_QSqlError::operators()
|
||||
{
|
||||
QSqlError error1(QString(), QString(), QSqlError::NoError);
|
||||
QSqlError error2(QString(), QString(), QSqlError::NoError);
|
||||
QSqlError error3(QString(), QString(), QSqlError::UnknownError);
|
||||
|
||||
QCOMPARE(error1, error2);
|
||||
QVERIFY(error1 != error3);
|
||||
}
|
||||
|
||||
void tst_QSqlError::qtbug_74575()
|
||||
{
|
||||
const QString driverText(QStringLiteral("drivertext"));
|
||||
const QString databaseText(QStringLiteral("databasetext"));
|
||||
const QString databaseTextNewline(QStringLiteral("databasetext\n"));
|
||||
|
||||
QSqlError error1(driverText, databaseText,
|
||||
QSqlError::UnknownError, QStringLiteral("123"));
|
||||
QCOMPARE(error1.text(), databaseText + QLatin1Char(' ') + driverText);
|
||||
|
||||
QSqlError error2(QString(), databaseText,
|
||||
QSqlError::UnknownError, QStringLiteral("123"));
|
||||
QCOMPARE(error2.text(), databaseText);
|
||||
|
||||
QSqlError error3(driverText, QString(),
|
||||
QSqlError::UnknownError, QStringLiteral("123"));
|
||||
QCOMPARE(error3.text(), driverText);
|
||||
|
||||
QSqlError error4(driverText, databaseTextNewline,
|
||||
QSqlError::UnknownError, QStringLiteral("123"));
|
||||
QCOMPARE(error4.text(), databaseTextNewline + driverText);
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QSqlError)
|
||||
#include "tst_qsqlerror.moc"
|
13
tests/auto/sql/kernel/qsqlfield/CMakeLists.txt
Normal file
13
tests/auto/sql/kernel/qsqlfield/CMakeLists.txt
Normal file
@ -0,0 +1,13 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_qsqlfield Test:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_test(tst_qsqlfield
|
||||
SOURCES
|
||||
tst_qsqlfield.cpp
|
||||
LIBRARIES
|
||||
Qt::Sql
|
||||
)
|
348
tests/auto/sql/kernel/qsqlfield/tst_qsqlfield.cpp
Normal file
348
tests/auto/sql/kernel/qsqlfield/tst_qsqlfield.cpp
Normal file
@ -0,0 +1,348 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
|
||||
#include <QTest>
|
||||
|
||||
#include <qsqlfield.h>
|
||||
#include <qvariant.h>
|
||||
#include <qsqlfield.h>
|
||||
|
||||
class tst_QSqlField : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
tst_QSqlField();
|
||||
virtual ~tst_QSqlField();
|
||||
|
||||
|
||||
public slots:
|
||||
void init();
|
||||
void cleanup();
|
||||
private slots:
|
||||
void getSetCheck();
|
||||
void type();
|
||||
void setValue_data();
|
||||
void setValue();
|
||||
void setReadOnly();
|
||||
void setNull();
|
||||
void setName_data();
|
||||
void setName();
|
||||
void operator_Equal();
|
||||
void operator_Assign();
|
||||
void name_data();
|
||||
void name();
|
||||
void isReadOnly();
|
||||
void isNull();
|
||||
void clear_data();
|
||||
void clear();
|
||||
void setTableName_data();
|
||||
void setTableName();
|
||||
};
|
||||
|
||||
// Testing get/set functions
|
||||
void tst_QSqlField::getSetCheck()
|
||||
{
|
||||
QSqlField obj1;
|
||||
// RequiredStatus QSqlField::requiredStatus()
|
||||
// void QSqlField::setRequiredStatus(RequiredStatus)
|
||||
obj1.setRequiredStatus(QSqlField::RequiredStatus(QSqlField::Unknown));
|
||||
QCOMPARE(QSqlField::RequiredStatus(QSqlField::Unknown), obj1.requiredStatus());
|
||||
obj1.setRequiredStatus(QSqlField::RequiredStatus(QSqlField::Optional));
|
||||
QCOMPARE(QSqlField::RequiredStatus(QSqlField::Optional), obj1.requiredStatus());
|
||||
obj1.setRequiredStatus(QSqlField::RequiredStatus(QSqlField::Required));
|
||||
QCOMPARE(QSqlField::RequiredStatus(QSqlField::Required), obj1.requiredStatus());
|
||||
|
||||
// int QSqlField::length()
|
||||
// void QSqlField::setLength(int)
|
||||
obj1.setLength(0);
|
||||
QCOMPARE(0, obj1.length());
|
||||
obj1.setLength(INT_MIN);
|
||||
QCOMPARE(INT_MIN, obj1.length());
|
||||
obj1.setLength(INT_MAX);
|
||||
QCOMPARE(INT_MAX, obj1.length());
|
||||
|
||||
// int QSqlField::precision()
|
||||
// void QSqlField::setPrecision(int)
|
||||
obj1.setPrecision(0);
|
||||
QCOMPARE(0, obj1.precision());
|
||||
obj1.setPrecision(INT_MIN);
|
||||
QCOMPARE(INT_MIN, obj1.precision());
|
||||
obj1.setPrecision(INT_MAX);
|
||||
QCOMPARE(INT_MAX, obj1.precision());
|
||||
}
|
||||
|
||||
tst_QSqlField::tst_QSqlField()
|
||||
{
|
||||
}
|
||||
|
||||
tst_QSqlField::~tst_QSqlField()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void tst_QSqlField::init()
|
||||
{
|
||||
// TODO: Add initialization code here.
|
||||
// This will be executed immediately before each test is run.
|
||||
}
|
||||
|
||||
void tst_QSqlField::cleanup()
|
||||
{
|
||||
// TODO: Add cleanup code here.
|
||||
// This will be executed immediately after each test is run.
|
||||
}
|
||||
|
||||
void tst_QSqlField::clear_data()
|
||||
{
|
||||
QTest::addColumn<int>("val");
|
||||
QTest::addColumn<bool>("bval");
|
||||
QTest::addColumn<QString>("strVal");
|
||||
QTest::addColumn<double>("fval");
|
||||
|
||||
//next we fill it with data
|
||||
QTest::newRow( "data0" ) << (int)5 << true << QString("Hallo") << (double)0;
|
||||
QTest::newRow( "data1" ) << -5 << false << QString("NULL") << (double)-4;
|
||||
QTest::newRow( "data2" ) << 0 << false << QString("0") << (double)0;
|
||||
}
|
||||
|
||||
void tst_QSqlField::clear()
|
||||
{
|
||||
QSqlField field( "Testfield", QMetaType(QMetaType::Int) );
|
||||
QFETCH( int, val );
|
||||
field.setValue( val );
|
||||
field.setReadOnly(true);
|
||||
field.clear();
|
||||
QVERIFY( field.value() == val );
|
||||
QVERIFY( !field.isNull() );
|
||||
|
||||
QSqlField bfield( "Testfield", QMetaType(QMetaType::Bool) );
|
||||
QFETCH( bool, bval );
|
||||
bfield.setValue( QVariant(bval) );
|
||||
bfield.setReadOnly(true);
|
||||
bfield.clear();
|
||||
|
||||
QVERIFY( bfield.value() == QVariant(bval) );
|
||||
QVERIFY( !bfield.isNull() );
|
||||
|
||||
QSqlField ffield( "Testfield", QMetaType(QMetaType::Double) );
|
||||
QFETCH( double, fval );
|
||||
ffield.setValue( fval );
|
||||
ffield.setReadOnly(true);
|
||||
ffield.clear();
|
||||
QVERIFY( ffield.value() == fval );
|
||||
QVERIFY( !ffield.isNull() );
|
||||
|
||||
QSqlField sfield( "Testfield", QMetaType(QMetaType::QString) );
|
||||
QFETCH( QString, strVal );
|
||||
sfield.setValue( strVal );
|
||||
sfield.setReadOnly(true);
|
||||
sfield.clear();
|
||||
QVERIFY( sfield.value() == strVal );
|
||||
QVERIFY( !sfield.isNull() );
|
||||
}
|
||||
|
||||
void tst_QSqlField::isNull()
|
||||
{
|
||||
QSqlField field( "test", QMetaType(QMetaType::QString) );
|
||||
QVERIFY( field.isNull() );
|
||||
}
|
||||
|
||||
void tst_QSqlField::isReadOnly()
|
||||
{
|
||||
QSqlField field( "test", QMetaType(QMetaType::QString) );
|
||||
QVERIFY( !field.isReadOnly() );
|
||||
field.setReadOnly( true );
|
||||
QVERIFY( field.isReadOnly() );
|
||||
field.setReadOnly( false );
|
||||
QVERIFY( !field.isReadOnly() );
|
||||
}
|
||||
|
||||
void tst_QSqlField::name_data()
|
||||
{
|
||||
QTest::addColumn<QString>("val");
|
||||
|
||||
//next we fill it with data
|
||||
QTest::newRow( "data0" ) << QString("test");
|
||||
QTest::newRow( "data1" ) << QString("Harry");
|
||||
QTest::newRow( "data2" ) << QString("");
|
||||
}
|
||||
|
||||
void tst_QSqlField::name()
|
||||
{
|
||||
QSqlField field( "test", QMetaType(QMetaType::QString) );
|
||||
QFETCH( QString, val );
|
||||
QCOMPARE(field.name(), QLatin1String("test"));
|
||||
field.setName( val );
|
||||
QCOMPARE(field.name(), val);
|
||||
}
|
||||
|
||||
void tst_QSqlField::operator_Assign()
|
||||
{
|
||||
QSqlField field1( "test", QMetaType(QMetaType::QString) );
|
||||
field1.setValue( "Harry" );
|
||||
field1.setReadOnly( true );
|
||||
QSqlField field2 = field1;
|
||||
QVERIFY( field1 == field2 );
|
||||
QSqlField field3( "test", QMetaType(QMetaType::Double) );
|
||||
field3.clear();
|
||||
field1 = field3;
|
||||
QVERIFY( field1 == field3 );
|
||||
QSqlField field4("test", QMetaType(QMetaType::QString), "ATable");
|
||||
field1 = field4;
|
||||
QVERIFY(field1 == field4);
|
||||
}
|
||||
|
||||
void tst_QSqlField::operator_Equal()
|
||||
{
|
||||
QSqlField field1( "test", QMetaType(QMetaType::QString) );
|
||||
QSqlField field2( "test2", QMetaType(QMetaType::QString) );
|
||||
QSqlField field3( "test", QMetaType(QMetaType::Int) );
|
||||
QSqlField field4("test", QMetaType(QMetaType::QString), QString("ATable"));
|
||||
QSqlField field5("test2", QMetaType(QMetaType::QString), QString("ATable"));
|
||||
QSqlField field6("test", QMetaType(QMetaType::QString), QString("BTable"));
|
||||
|
||||
QVERIFY( !(field1 == field2) );
|
||||
QVERIFY( !(field1 == field3) );
|
||||
QVERIFY(field1 != field4);
|
||||
QVERIFY(field1 != field5);
|
||||
QVERIFY(field1 != field6);
|
||||
QVERIFY(field4 != field5);
|
||||
QVERIFY(field4 != field6);
|
||||
|
||||
field2.setName( "test" );
|
||||
QVERIFY( field1 == field2 );
|
||||
QVERIFY( field1 == field2 );
|
||||
field1.setValue( "Harry" );
|
||||
QVERIFY( !(field1 == field2) );
|
||||
field2.setValue( "Harry" );
|
||||
QVERIFY( field1 == field2 );
|
||||
field1.setReadOnly( true );
|
||||
QVERIFY( !(field1 == field2) );
|
||||
field2.setReadOnly( true );
|
||||
QVERIFY( field1 == field2 );
|
||||
field4.setTableName("BTable");
|
||||
QCOMPARE(field4, field6);
|
||||
field6.setName("test3");
|
||||
QVERIFY(field4 != field6);
|
||||
}
|
||||
|
||||
void tst_QSqlField::setName_data()
|
||||
{
|
||||
QTest::addColumn<QString>("val");
|
||||
|
||||
//next we fill it with data
|
||||
QTest::newRow( "data0" ) << QString("test");
|
||||
QTest::newRow( "data1" ) << QString("Harry");
|
||||
QTest::newRow( "data2" ) << QString("");
|
||||
}
|
||||
|
||||
void tst_QSqlField::setName()
|
||||
{
|
||||
QSqlField field( "test", QMetaType(QMetaType::QString) );
|
||||
QFETCH( QString, val );
|
||||
QCOMPARE(field.name(), QLatin1String("test"));
|
||||
field.setName( val );
|
||||
QCOMPARE(field.name(), val);
|
||||
}
|
||||
|
||||
void tst_QSqlField::setNull()
|
||||
{
|
||||
QSqlField field( "test", QMetaType(QMetaType::QString) );
|
||||
field.setValue( "test" );
|
||||
field.clear();
|
||||
QVERIFY( field.value() == QVariant().toString() );
|
||||
QVERIFY( field.isNull() );
|
||||
}
|
||||
|
||||
void tst_QSqlField::setReadOnly()
|
||||
{
|
||||
QSqlField field( "test", QMetaType(QMetaType::QString) );
|
||||
field.setValue( "test" );
|
||||
field.setReadOnly( true );
|
||||
field.setValue( "Harry" );
|
||||
QCOMPARE(field.value().toString(), QLatin1String("test"));
|
||||
field.clear();
|
||||
QCOMPARE(field.value().toString(), QLatin1String("test"));
|
||||
QVERIFY( !field.isNull() );
|
||||
field.clear();
|
||||
QCOMPARE(field.value().toString(), QLatin1String("test"));
|
||||
QVERIFY( !field.isNull() );
|
||||
field.setReadOnly( false );
|
||||
field.setValue( "Harry" );
|
||||
QCOMPARE(field.value().toString(), QLatin1String("Harry"));
|
||||
field.clear();
|
||||
QVERIFY( field.value() == QVariant().toString() );
|
||||
QVERIFY( field.isNull() );
|
||||
}
|
||||
|
||||
void tst_QSqlField::setValue_data()
|
||||
{
|
||||
QTest::addColumn<int>("ival");
|
||||
QTest::addColumn<bool>("bval");
|
||||
QTest::addColumn<double>("dval");
|
||||
QTest::addColumn<QString>("sval");
|
||||
|
||||
//next we fill it with data
|
||||
QTest::newRow( "data0" ) << 0 << false << (double)223.232 << QString("");
|
||||
QTest::newRow( "data1" ) << 123 << true << (double)-232.232 << QString("Harry");
|
||||
QTest::newRow( "data2" ) << -123 << false << (double)232222.323223233338 << QString("Woipertinger");
|
||||
}
|
||||
|
||||
void tst_QSqlField::setValue()
|
||||
{
|
||||
QSqlField field1 ( "test", QMetaType(QMetaType::Int) );
|
||||
QSqlField field2 ( "test", QMetaType(QMetaType::QString) );
|
||||
QSqlField field3 ( "test", QMetaType(QMetaType::Bool) );
|
||||
QSqlField field4 ( "test", QMetaType(QMetaType::Double) );
|
||||
field1.clear();
|
||||
QFETCH( int, ival );
|
||||
QFETCH( QString, sval );
|
||||
QFETCH( double, dval );
|
||||
QFETCH( bool, bval );
|
||||
field1.setValue( ival );
|
||||
QCOMPARE( field1.value().toInt(), ival );
|
||||
// setValue should also reset the NULL flag
|
||||
QVERIFY( !field1.isNull() );
|
||||
|
||||
field2.setValue( sval );
|
||||
QCOMPARE( field2.value().toString(), sval );
|
||||
field3.setValue( QVariant( bval) );
|
||||
QVERIFY( field3.value().toBool() == bval );
|
||||
field4.setValue( dval );
|
||||
QCOMPARE( field4.value().toDouble(), dval );
|
||||
field4.setReadOnly( true );
|
||||
field4.setValue( "Something_that's_not_a_double" );
|
||||
QCOMPARE( field4.value().toDouble(), dval );
|
||||
}
|
||||
|
||||
void tst_QSqlField::type()
|
||||
{
|
||||
QSqlField field1( "string", QMetaType(QMetaType::QString) );
|
||||
QSqlField field2( "string", QMetaType(QMetaType::Bool) );
|
||||
QSqlField field3( "string", QMetaType(QMetaType::Double) );
|
||||
QVERIFY( field1.metaType() == QMetaType(QMetaType::QString) );
|
||||
QVERIFY( field2.metaType() == QMetaType(QMetaType::Bool) );
|
||||
QVERIFY( field3.metaType() == QMetaType(QMetaType::Double) );
|
||||
}
|
||||
|
||||
void tst_QSqlField::setTableName_data()
|
||||
{
|
||||
QTest::addColumn<QString>("tableName");
|
||||
|
||||
QTest::newRow("data0") << QString("");
|
||||
QTest::newRow("data1") << QString("tbl");
|
||||
}
|
||||
|
||||
void tst_QSqlField::setTableName()
|
||||
{
|
||||
QSqlField field("test", QMetaType(QMetaType::QString), "test");
|
||||
QFETCH(QString, tableName);
|
||||
QCOMPARE(field.tableName(), QLatin1String("test"));
|
||||
field.setTableName(tableName);
|
||||
QCOMPARE(field.tableName(), tableName);
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QSqlField)
|
||||
#include "tst_qsqlfield.moc"
|
15
tests/auto/sql/kernel/qsqlquery/CMakeLists.txt
Normal file
15
tests/auto/sql/kernel/qsqlquery/CMakeLists.txt
Normal file
@ -0,0 +1,15 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_qsqlquery Test:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_test(tst_qsqlquery
|
||||
SOURCES
|
||||
tst_qsqlquery.cpp
|
||||
LIBRARIES
|
||||
Qt::CorePrivate
|
||||
Qt::Sql
|
||||
Qt::SqlPrivate
|
||||
)
|
5072
tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp
Normal file
5072
tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp
Normal file
File diff suppressed because it is too large
Load Diff
13
tests/auto/sql/kernel/qsqlrecord/CMakeLists.txt
Normal file
13
tests/auto/sql/kernel/qsqlrecord/CMakeLists.txt
Normal file
@ -0,0 +1,13 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_qsqlrecord Test:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_test(tst_qsqlrecord
|
||||
SOURCES
|
||||
tst_qsqlrecord.cpp
|
||||
LIBRARIES
|
||||
Qt::Sql
|
||||
)
|
453
tests/auto/sql/kernel/qsqlrecord/tst_qsqlrecord.cpp
Normal file
453
tests/auto/sql/kernel/qsqlrecord/tst_qsqlrecord.cpp
Normal file
@ -0,0 +1,453 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
|
||||
#include <QTest>
|
||||
|
||||
#include "qsqlrecord.h"
|
||||
#include "qsqlfield.h"
|
||||
#include "qstringlist.h"
|
||||
|
||||
#include <qsqlrecord.h>
|
||||
|
||||
#define NUM_FIELDS 4
|
||||
|
||||
class tst_QSqlRecord : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public slots:
|
||||
void init();
|
||||
void cleanup();
|
||||
private slots:
|
||||
void value();
|
||||
void setValue_data();
|
||||
void setValue();
|
||||
void setNull();
|
||||
void setGenerated();
|
||||
void remove();
|
||||
void position();
|
||||
void operator_Assign();
|
||||
void isNull();
|
||||
void isGenerated();
|
||||
void isEmpty();
|
||||
void insert();
|
||||
void fieldName();
|
||||
void field();
|
||||
void count();
|
||||
void contains();
|
||||
void clearValues_data();
|
||||
void clearValues();
|
||||
void clear();
|
||||
void append();
|
||||
|
||||
private:
|
||||
std::unique_ptr<QSqlRecord> rec;
|
||||
std::array<std::unique_ptr<QSqlField>, NUM_FIELDS> fields;
|
||||
void createTestRecord();
|
||||
};
|
||||
|
||||
void tst_QSqlRecord::init()
|
||||
{
|
||||
cleanup();
|
||||
}
|
||||
|
||||
void tst_QSqlRecord::cleanup()
|
||||
{
|
||||
rec = nullptr;
|
||||
for (auto &field : fields)
|
||||
field = nullptr;
|
||||
}
|
||||
|
||||
void tst_QSqlRecord::createTestRecord()
|
||||
{
|
||||
rec = std::make_unique<QSqlRecord>();
|
||||
fields[0] = std::make_unique<QSqlField>(QStringLiteral("string"), QMetaType(QMetaType::QString), QStringLiteral("stringtable"));
|
||||
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));
|
||||
for (const auto &field : fields)
|
||||
rec->append(*field);
|
||||
}
|
||||
|
||||
|
||||
void tst_QSqlRecord::append()
|
||||
{
|
||||
rec = std::make_unique<QSqlRecord>();
|
||||
rec->append(QSqlField("string", QMetaType(QMetaType::QString), QStringLiteral("stringtable")));
|
||||
QCOMPARE( rec->field( 0 ).name(), (QString) "string" );
|
||||
QCOMPARE(rec->field(0).tableName(), QStringLiteral("stringtable"));
|
||||
QVERIFY( !rec->isEmpty() );
|
||||
QCOMPARE( (int)rec->count(), 1 );
|
||||
rec->append(QSqlField("int", QMetaType(QMetaType::Int), QStringLiteral("inttable")));
|
||||
QCOMPARE( rec->field( 1 ).name(), (QString) "int" );
|
||||
QCOMPARE(rec->field(1).tableName(), QStringLiteral("inttable"));
|
||||
QCOMPARE( (int)rec->count(), 2 );
|
||||
rec->append( QSqlField( "double", QMetaType(QMetaType::Double) ) );
|
||||
QCOMPARE( rec->field( 2 ).name(), (QString) "double" );
|
||||
QCOMPARE( (int)rec->count(), 3 );
|
||||
rec->append( QSqlField( "bool", QMetaType(QMetaType::Bool) ) );
|
||||
QCOMPARE( rec->field( 3 ).name(), (QString) "bool" );
|
||||
QCOMPARE( (int)rec->count(), 4 );
|
||||
QCOMPARE( rec->indexOf( "string" ), 0 );
|
||||
QCOMPARE( rec->indexOf( "int" ), 1 );
|
||||
QCOMPARE( rec->indexOf( "double" ), 2 );
|
||||
QCOMPARE( rec->indexOf( "bool" ), 3 );
|
||||
}
|
||||
|
||||
void tst_QSqlRecord::clear()
|
||||
{
|
||||
createTestRecord();
|
||||
|
||||
rec->clear();
|
||||
QCOMPARE( (int)rec->count(), 0 );
|
||||
QVERIFY( rec->isEmpty() );
|
||||
QVERIFY( !rec->contains( fields[0]->name() ) );
|
||||
}
|
||||
|
||||
void tst_QSqlRecord::clearValues_data()
|
||||
{
|
||||
QTest::addColumn<QString>("prefix");
|
||||
QTest::addColumn<QString>("sep");
|
||||
QTest::addColumn<int>("ival");
|
||||
QTest::addColumn<QString>("sval");
|
||||
QTest::addColumn<double>("dval");
|
||||
QTest::addColumn<int>("bval");
|
||||
|
||||
QTest::newRow( "data0" ) << QString::fromLatin1("tablename") << QString::fromLatin1(",") << 10
|
||||
<< QString::fromLatin1("Trond K.") << 2222.231234441 << 0;
|
||||
QTest::newRow( "data1" ) << QString::fromLatin1("mytable") << QString::fromLatin1(".") << 12
|
||||
<< QString::fromLatin1("Josten") << 544444444444423232.32334441 << 1;
|
||||
QTest::newRow( "data2" ) << QString::fromLatin1("tabby") << QString::fromLatin1("-") << 12
|
||||
<< QString::fromLatin1("Odvin") << 899129389283.32334441 << 1;
|
||||
QTest::newRow( "data3" ) << QString::fromLatin1("per") << QString::fromLatin1("00") << 12
|
||||
<< QString::fromLatin1("Brge") << 29382939182.99999919 << 0;
|
||||
}
|
||||
|
||||
void tst_QSqlRecord::clearValues()
|
||||
{
|
||||
int i;
|
||||
QFETCH( int, ival );
|
||||
QFETCH( QString, sval );
|
||||
QFETCH( double, dval );
|
||||
QFETCH( int, bval );
|
||||
|
||||
rec = std::make_unique<QSqlRecord>();
|
||||
rec->append( QSqlField( "string", QMetaType(QMetaType::QString) ) );
|
||||
QCOMPARE( rec->field(0).name(), (QString) "string" );
|
||||
QVERIFY( !rec->isEmpty() );
|
||||
QCOMPARE( (int)rec->count(), 1 );
|
||||
rec->append( QSqlField( "int", QMetaType(QMetaType::Int) ) );
|
||||
QCOMPARE( rec->field(1).name(), (QString) "int" );
|
||||
QCOMPARE( (int)rec->count(), 2 );
|
||||
rec->append( QSqlField( "double", QMetaType(QMetaType::Double) ) );
|
||||
QCOMPARE( rec->field(2).name(), (QString) "double" );
|
||||
QCOMPARE( (int)rec->count(), 3 );
|
||||
rec->append( QSqlField( "bool", QMetaType(QMetaType::Bool) ) );
|
||||
QCOMPARE( rec->field(3).name(), (QString) "bool" );
|
||||
QCOMPARE( (int)rec->count(), 4 );
|
||||
QCOMPARE( rec->indexOf( "string" ), 0 );
|
||||
QCOMPARE( rec->indexOf( "int" ), 1 );
|
||||
QCOMPARE( rec->indexOf( "double" ), 2 );
|
||||
QCOMPARE( rec->indexOf( "bool" ), 3 );
|
||||
for ( i = 0; i < 4; ++i )
|
||||
rec->setNull( i );
|
||||
|
||||
rec->setValue( 0, sval );
|
||||
rec->setValue( 1, ival );
|
||||
rec->setValue( 2, dval );
|
||||
rec->setValue( 3, QVariant(bval) );
|
||||
QVERIFY( rec->value( 0 ) == sval );
|
||||
QVERIFY( rec->value( 1 ) == ival );
|
||||
QVERIFY( rec->value( 2 ) == dval );
|
||||
QVERIFY( rec->value( 3 ) == QVariant(bval) );
|
||||
|
||||
rec->clearValues();
|
||||
|
||||
for ( i = 0; i < 4; ++i )
|
||||
QVERIFY( rec->isNull( i ) );
|
||||
|
||||
}
|
||||
|
||||
void tst_QSqlRecord::contains()
|
||||
{
|
||||
createTestRecord();
|
||||
for (const auto &field : fields)
|
||||
QVERIFY(rec->contains(field->name()));
|
||||
QVERIFY( !rec->contains( "__Harry__" ) );
|
||||
}
|
||||
|
||||
void tst_QSqlRecord::count()
|
||||
{
|
||||
createTestRecord();
|
||||
QCOMPARE( (int)rec->count(), NUM_FIELDS );
|
||||
rec->remove( 3 );
|
||||
QCOMPARE( (int)rec->count(), NUM_FIELDS - 1 );
|
||||
rec->clear();
|
||||
QCOMPARE( (int)rec->count(), 0 );
|
||||
QCOMPARE( (int)QSqlRecord().count(), 0 );
|
||||
}
|
||||
|
||||
void tst_QSqlRecord::field()
|
||||
{
|
||||
createTestRecord();
|
||||
|
||||
int i;
|
||||
for ( i = 0; i < NUM_FIELDS; ++i )
|
||||
QVERIFY( rec->field( i ) == *fields[ i ] );
|
||||
|
||||
for ( i = 0; i < NUM_FIELDS; ++i )
|
||||
QVERIFY( rec->field( (fields[ i ] )->name() ) == *( fields[ i ] ) );
|
||||
QVERIFY( rec->indexOf( "_This should give a warning!_" ) == -1 );
|
||||
}
|
||||
|
||||
void tst_QSqlRecord::fieldName()
|
||||
{
|
||||
createTestRecord();
|
||||
|
||||
for (const auto &field : fields)
|
||||
QVERIFY(rec->field(field->name()) == *field);
|
||||
QVERIFY( rec->fieldName( NUM_FIELDS ).isNull() );
|
||||
}
|
||||
|
||||
void tst_QSqlRecord::insert()
|
||||
{
|
||||
QSqlRecord iRec;
|
||||
int i;
|
||||
for ( i = 0; i <= 100; ++i ) {
|
||||
iRec.insert( i, QSqlField( QString::number( i ), QMetaType(QMetaType::Int) ) );
|
||||
}
|
||||
for ( i = 0; i <= 100; ++i ) {
|
||||
QCOMPARE( iRec.fieldName( i ), QString::number( i ) );
|
||||
}
|
||||
// iRec.insert( 505, QSqlField( "Harry", QMetaType(QMetaType::Double) ) );
|
||||
// QCOMPARE( iRec.fieldName( 505 ), (QString)"Harry" );
|
||||
// QVERIFY( iRec.field( 505 ).type() == QMetaType(QMetaType::Double) );
|
||||
|
||||
iRec.insert( 42, QSqlField( "Everything", QMetaType(QMetaType::QString) ) );
|
||||
QCOMPARE( iRec.fieldName( 42 ), (QString)"Everything" );
|
||||
QVERIFY( iRec.field( 42 ).metaType() == QMetaType(QMetaType::QString) );
|
||||
}
|
||||
|
||||
void tst_QSqlRecord::isEmpty()
|
||||
{
|
||||
QSqlRecord eRec;
|
||||
QVERIFY( eRec.isEmpty() );
|
||||
eRec.append( QSqlField( "Harry", QMetaType(QMetaType::QString) ) );
|
||||
QVERIFY( !eRec.isEmpty() );
|
||||
eRec.remove( 0 );
|
||||
QVERIFY( eRec.isEmpty() );
|
||||
eRec.insert( 0, QSqlField( "Harry", QMetaType(QMetaType::QString) ) );
|
||||
QVERIFY( !eRec.isEmpty() );
|
||||
eRec.clear();
|
||||
QVERIFY( eRec.isEmpty() );
|
||||
}
|
||||
|
||||
void tst_QSqlRecord::isGenerated()
|
||||
{
|
||||
createTestRecord();
|
||||
|
||||
int i;
|
||||
for ( i = 0; i < NUM_FIELDS; ++i )
|
||||
QVERIFY( rec->isGenerated( i ) );
|
||||
|
||||
for ( i = 0; i < NUM_FIELDS; ++i )
|
||||
QVERIFY( rec->isGenerated( fields[ i ]->name() ) );
|
||||
|
||||
for ( i = 0; i < NUM_FIELDS; ++i ) {
|
||||
if ( i % 2 )
|
||||
rec->setGenerated( i, false );
|
||||
}
|
||||
rec->setGenerated( NUM_FIELDS * 2, false ); // nothing should happen here
|
||||
|
||||
for ( i = 0; i < NUM_FIELDS; ++i ) {
|
||||
if ( i % 2 ) {
|
||||
QVERIFY( !rec->isGenerated( i ) );
|
||||
} else {
|
||||
QVERIFY( rec->isGenerated( i ) );
|
||||
}
|
||||
}
|
||||
|
||||
for ( i = 0; i < NUM_FIELDS; ++i )
|
||||
if ( i % 2 ) {
|
||||
QVERIFY( !rec->isGenerated( fields[ i ]->name() ) );
|
||||
} else {
|
||||
QVERIFY( rec->isGenerated( fields[ i ]->name() ) );
|
||||
}
|
||||
|
||||
rec->setGenerated( "_This should give a warning!_", false ); // nothing should happen here
|
||||
}
|
||||
|
||||
void tst_QSqlRecord::isNull()
|
||||
{
|
||||
createTestRecord();
|
||||
|
||||
int i;
|
||||
for ( i = 0; i < NUM_FIELDS; ++i ) {
|
||||
QVERIFY( rec->isNull( i ) );
|
||||
QVERIFY( rec->isNull( fields[ i ]->name() ) );
|
||||
}
|
||||
|
||||
for ( i = 0; i < NUM_FIELDS; ++i ) {
|
||||
if ( i % 2 )
|
||||
rec->setNull( i );
|
||||
}
|
||||
rec->setNull( NUM_FIELDS ); // nothing should happen here
|
||||
|
||||
for ( i = 0; i < NUM_FIELDS; ++i ) {
|
||||
if ( i % 2 ) {
|
||||
QVERIFY( rec->isNull( i ) );
|
||||
QVERIFY( rec->isNull( fields[ i ]->name() ) );
|
||||
}
|
||||
}
|
||||
|
||||
for ( i = 0; i < NUM_FIELDS; ++i ) {
|
||||
rec->setNull( fields[ i ]->name() );
|
||||
}
|
||||
rec->setNull( "_This should give a warning!_" ); // nothing should happen here
|
||||
|
||||
for ( i = 0; i < NUM_FIELDS; ++i ) {
|
||||
QVERIFY( rec->isNull( i ) );
|
||||
QVERIFY( rec->isNull( fields[ i ]->name() ) );
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QSqlRecord::operator_Assign()
|
||||
{
|
||||
createTestRecord();
|
||||
int i;
|
||||
QSqlRecord buf2, buf3, buf4; // since buffers are implicitely shared, we exaggerate a bit here
|
||||
buf2 = *rec;
|
||||
buf3 = *rec;
|
||||
buf4 = *rec;
|
||||
for ( i = 0; i < NUM_FIELDS; ++i ) {
|
||||
QVERIFY( buf2.field( i ) == *fields[ i ] );
|
||||
QVERIFY( buf3.field( i ) == *( fields[ i ] ) );
|
||||
QVERIFY( buf4.field( i ) == *( fields[ i ] ) );
|
||||
}
|
||||
for ( i = 0; i < NUM_FIELDS; ++i )
|
||||
buf3.setNull( i );
|
||||
buf3.remove( NUM_FIELDS - 1 );
|
||||
QSqlRecord buf5 = buf3;
|
||||
for ( i = 0; i < NUM_FIELDS - 1; ++i ) {
|
||||
QSqlField fi(fields[i]->name(), fields[i]->metaType(), fields[i]->tableName());
|
||||
fi.clear();
|
||||
QVERIFY( buf5.field( i ) == fi );
|
||||
QVERIFY( buf5.isGenerated( i ) );
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QSqlRecord::position()
|
||||
{
|
||||
createTestRecord();
|
||||
int i;
|
||||
for ( i = 0; i < NUM_FIELDS; ++i ) {
|
||||
QCOMPARE( rec->indexOf( fields[ i ]->name() ), i );
|
||||
if (!fields[i]->tableName().isEmpty())
|
||||
QCOMPARE(rec->indexOf(fields[i]->tableName() + QChar('.') + fields[i]->name()), i);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QSqlRecord::remove()
|
||||
{
|
||||
createTestRecord();
|
||||
int i;
|
||||
for ( i = 0; i < NUM_FIELDS; ++i ) {
|
||||
rec->setGenerated( i, false );
|
||||
QCOMPARE( (int)rec->count(), NUM_FIELDS - i );
|
||||
rec->remove( 0 );
|
||||
QCOMPARE( (int)rec->count(), NUM_FIELDS - i - 1 );
|
||||
}
|
||||
rec->remove( NUM_FIELDS * 2 ); // nothing should happen
|
||||
for ( i = 0; i < NUM_FIELDS; ++i ) {
|
||||
rec->insert( i, QSqlField( fields[ i ]->name(), fields[ i ]->metaType() ) );
|
||||
QVERIFY( rec->isGenerated( i ) );
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QSqlRecord::setGenerated()
|
||||
{
|
||||
isGenerated();
|
||||
}
|
||||
|
||||
void tst_QSqlRecord::setNull()
|
||||
{
|
||||
isNull();
|
||||
}
|
||||
|
||||
void tst_QSqlRecord::setValue_data()
|
||||
{
|
||||
clearValues_data();
|
||||
}
|
||||
|
||||
void tst_QSqlRecord::setValue()
|
||||
{
|
||||
int i;
|
||||
|
||||
rec = std::make_unique<QSqlRecord>();
|
||||
rec->append( QSqlField( "string", QMetaType(QMetaType::QString) ) );
|
||||
QCOMPARE( rec->field( 0 ).name(), (QString) "string" );
|
||||
QVERIFY( !rec->isEmpty() );
|
||||
QCOMPARE( (int)rec->count(), 1 );
|
||||
rec->append( QSqlField( "int", QMetaType(QMetaType::Int) ) );
|
||||
QCOMPARE( rec->field( 1 ).name(), (QString) "int" );
|
||||
QCOMPARE( (int)rec->count(), 2 );
|
||||
rec->append( QSqlField( "double", QMetaType(QMetaType::Double) ) );
|
||||
QCOMPARE( rec->field( 2 ).name(), (QString) "double" );
|
||||
QCOMPARE( (int)rec->count(), 3 );
|
||||
rec->append( QSqlField( "bool", QMetaType(QMetaType::Bool) ) );
|
||||
QCOMPARE( rec->field( 3 ).name(), (QString) "bool" );
|
||||
QCOMPARE( (int)rec->count(), 4 );
|
||||
QCOMPARE( rec->indexOf( "string" ), 0 );
|
||||
QCOMPARE( rec->indexOf( "int" ), 1 );
|
||||
QCOMPARE( rec->indexOf( "double" ), 2 );
|
||||
QCOMPARE( rec->indexOf( "bool" ), 3 );
|
||||
|
||||
QFETCH( int, ival );
|
||||
QFETCH( QString, sval );
|
||||
QFETCH( double, dval );
|
||||
QFETCH( int, bval );
|
||||
|
||||
for ( i = 0; i < 4; ++i )
|
||||
rec->setNull( i );
|
||||
|
||||
rec->setValue( 0, sval );
|
||||
rec->setValue( 1, ival );
|
||||
rec->setValue( 2, dval );
|
||||
rec->setValue( 3, QVariant(bval) );
|
||||
QVERIFY( rec->value( 0 ) == sval );
|
||||
QVERIFY( rec->value( 1 ) == ival );
|
||||
QVERIFY( rec->value( 2 ) == dval );
|
||||
QVERIFY( rec->value( 3 ) == QVariant(bval) );
|
||||
for ( i = 0; i < 4; ++i )
|
||||
QVERIFY( !rec->isNull( i ) );
|
||||
|
||||
QSqlRecord rec2 = *rec;
|
||||
QVERIFY( rec2.value( 0 ) == sval );
|
||||
QVERIFY( rec2.value( 1 ) == ival );
|
||||
QVERIFY( rec2.value( 2 ) == dval );
|
||||
QVERIFY( rec2.value( 3 ) == QVariant(bval) );
|
||||
|
||||
rec2.setValue( "string", "__Harry__" );
|
||||
QCOMPARE(rec2.value(0).toString(), QLatin1String("__Harry__"));
|
||||
|
||||
for ( i = 0; i < 4; ++i )
|
||||
QVERIFY( !rec2.isNull( i ) );
|
||||
|
||||
QCOMPARE( rec->value( 0 ).toString(), sval );
|
||||
QCOMPARE( rec->value( 1 ).toInt(), ival );
|
||||
QCOMPARE( rec->value( 2 ).toDouble(), dval );
|
||||
QCOMPARE( rec->value( 3 ), QVariant(bval) );
|
||||
}
|
||||
|
||||
void tst_QSqlRecord::value()
|
||||
{
|
||||
// this test is already covered in setValue()
|
||||
QSqlRecord rec2;
|
||||
rec2.append( QSqlField( "string", QMetaType(QMetaType::QString) ) );
|
||||
rec2.setValue( "string", "Harry" );
|
||||
QCOMPARE(rec2.value("string").toString(), QLatin1String("Harry"));
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QSqlRecord)
|
||||
#include "tst_qsqlrecord.moc"
|
16
tests/auto/sql/kernel/qsqlresult/CMakeLists.txt
Normal file
16
tests/auto/sql/kernel/qsqlresult/CMakeLists.txt
Normal file
@ -0,0 +1,16 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_qsqlresult Test:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_test(tst_qsqlresult
|
||||
SOURCES
|
||||
testsqldriver.h
|
||||
tst_qsqlresult.cpp
|
||||
LIBRARIES
|
||||
Qt::CorePrivate
|
||||
Qt::Sql
|
||||
Qt::SqlPrivate
|
||||
)
|
65
tests/auto/sql/kernel/qsqlresult/testsqldriver.h
Normal file
65
tests/auto/sql/kernel/qsqlresult/testsqldriver.h
Normal file
@ -0,0 +1,65 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#ifndef TESTSQLDRIVER_H
|
||||
#define TESTSQLDRIVER_H
|
||||
|
||||
#include <QtSql/QSqlResult>
|
||||
#include <QtSql/QSqlDriver>
|
||||
#include <QtSql/QSqlRecord>
|
||||
#include <private/qsqldriver_p.h>
|
||||
|
||||
class TestSqlDriverResult : public QSqlResult
|
||||
{
|
||||
public:
|
||||
TestSqlDriverResult(const QSqlDriver *driver)
|
||||
: QSqlResult(driver) {}
|
||||
~TestSqlDriverResult() {}
|
||||
|
||||
bool savePrepare(const QString& sqlquery) override
|
||||
{
|
||||
return QSqlResult::savePrepare(sqlquery);
|
||||
}
|
||||
|
||||
QList<QVariant> boundValues() const { return QSqlResult::boundValues(); }
|
||||
|
||||
protected:
|
||||
QVariant data(int /* index */) override { return QVariant(); }
|
||||
bool isNull(int /* index */) override { return false; }
|
||||
bool reset(const QString & /* query */) override { return false; }
|
||||
bool fetch(int /* index */) override { return false; }
|
||||
bool fetchFirst() override { return false; }
|
||||
bool fetchLast() override { return false; }
|
||||
int size() override { return 0; }
|
||||
int numRowsAffected() override { return 0; }
|
||||
QSqlRecord record() const override { return QSqlRecord(); }
|
||||
};
|
||||
|
||||
class TestSqlDriver : public QSqlDriver
|
||||
{
|
||||
Q_DECLARE_PRIVATE(QSqlDriver)
|
||||
|
||||
public:
|
||||
TestSqlDriver() {}
|
||||
~TestSqlDriver() {}
|
||||
|
||||
bool hasFeature(DriverFeature f) const override {
|
||||
switch (f) {
|
||||
case QSqlDriver::PreparedQueries:
|
||||
case QSqlDriver::NamedPlaceholders:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool open(const QString & /* db */, const QString & /* user */,
|
||||
const QString & /* password */, const QString & /* host */,
|
||||
int /* port */, const QString & /* options */) override
|
||||
{ return false; }
|
||||
void close() override {}
|
||||
|
||||
QSqlResult *createResult() const override { return new TestSqlDriverResult(this); }
|
||||
};
|
||||
|
||||
#endif // TESTSQLDRIVER_H
|
80
tests/auto/sql/kernel/qsqlresult/tst_qsqlresult.cpp
Normal file
80
tests/auto/sql/kernel/qsqlresult/tst_qsqlresult.cpp
Normal file
@ -0,0 +1,80 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include <QTest>
|
||||
#include <QtSql/QtSql>
|
||||
|
||||
#include "testsqldriver.h"
|
||||
|
||||
class tst_QSqlResult : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
tst_QSqlResult();
|
||||
|
||||
private slots:
|
||||
void positionalToNamedBinding();
|
||||
void parseOfBoundValues();
|
||||
|
||||
};
|
||||
|
||||
tst_QSqlResult::tst_QSqlResult()
|
||||
{
|
||||
}
|
||||
|
||||
void tst_QSqlResult::positionalToNamedBinding()
|
||||
{
|
||||
TestSqlDriver testDriver;
|
||||
TestSqlDriverResult result(&testDriver);
|
||||
QString query("INSERT INTO MYTABLE (ID, NAME, BIRTH) VALUES(?, ?, ?)");
|
||||
QVERIFY(result.savePrepare(query));
|
||||
QCOMPARE(result.boundValues().size(), 3);
|
||||
}
|
||||
|
||||
void tst_QSqlResult::parseOfBoundValues()
|
||||
{
|
||||
TestSqlDriver testDriver;
|
||||
TestSqlDriverResult result(&testDriver);
|
||||
QVERIFY(result.savePrepare("SELECT :1 AS \":2\""));
|
||||
QCOMPARE(result.boundValues().size(), 1);
|
||||
QVERIFY(result.savePrepare("SELECT :1 AS ':2'"));
|
||||
QCOMPARE(result.boundValues().size(), 1);
|
||||
QVERIFY(result.savePrepare("SELECT :1 AS [:2]"));
|
||||
if (testDriver.dbmsType() == QSqlDriver::PostgreSQL)
|
||||
QCOMPARE(result.boundValues().size(), 2);
|
||||
else
|
||||
QCOMPARE(result.boundValues().size(), 1);
|
||||
QVERIFY(result.savePrepare("SELECT :1 AS [:2]]]"));
|
||||
if (testDriver.dbmsType() == QSqlDriver::PostgreSQL)
|
||||
QCOMPARE(result.boundValues().size(), 2);
|
||||
else
|
||||
QCOMPARE(result.boundValues().size(), 1);
|
||||
QVERIFY(result.savePrepare("SELECT :1 AS [:2]]]]]"));
|
||||
if (testDriver.dbmsType() == QSqlDriver::PostgreSQL)
|
||||
QCOMPARE(result.boundValues().size(), 2);
|
||||
else
|
||||
QCOMPARE(result.boundValues().size(), 1);
|
||||
|
||||
QVERIFY(result.savePrepare("SELECT ? AS \"?\""));
|
||||
QCOMPARE(result.boundValues().size(), 1);
|
||||
QVERIFY(result.savePrepare("SELECT ? AS '?'"));
|
||||
QCOMPARE(result.boundValues().size(), 1);
|
||||
QVERIFY(result.savePrepare("SELECT ? AS [?]"));
|
||||
if (testDriver.dbmsType() == QSqlDriver::PostgreSQL)
|
||||
QCOMPARE(result.boundValues().size(), 2);
|
||||
else
|
||||
QCOMPARE(result.boundValues().size(), 1);
|
||||
|
||||
QVERIFY(result.savePrepare("SELECT ? AS \"'?\""));
|
||||
QCOMPARE(result.boundValues().size(), 1);
|
||||
QVERIFY(result.savePrepare("SELECT ? AS '?\"'"));
|
||||
QCOMPARE(result.boundValues().size(), 1);
|
||||
QVERIFY(result.savePrepare("SELECT ? AS '?''?'"));
|
||||
QCOMPARE(result.boundValues().size(), 1);
|
||||
QVERIFY(result.savePrepare("SELECT ? AS [\"?']"));
|
||||
QCOMPARE(result.boundValues().size(), 1);
|
||||
}
|
||||
|
||||
QTEST_MAIN( tst_QSqlResult )
|
||||
#include "tst_qsqlresult.moc"
|
15
tests/auto/sql/kernel/qsqlthread/CMakeLists.txt
Normal file
15
tests/auto/sql/kernel/qsqlthread/CMakeLists.txt
Normal file
@ -0,0 +1,15 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_qsqlthread Test:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_test(tst_qsqlthread
|
||||
SOURCES
|
||||
tst_qsqlthread.cpp
|
||||
LIBRARIES
|
||||
Qt::CorePrivate
|
||||
Qt::Sql
|
||||
Qt::SqlPrivate
|
||||
)
|
487
tests/auto/sql/kernel/qsqlthread/tst_qsqlthread.cpp
Normal file
487
tests/auto/sql/kernel/qsqlthread/tst_qsqlthread.cpp
Normal file
@ -0,0 +1,487 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
|
||||
#include <QTest>
|
||||
|
||||
|
||||
#include "../qsqldatabase/tst_databases.h"
|
||||
|
||||
#include <QtCore>
|
||||
#include <QtSql>
|
||||
#include "qdebug.h"
|
||||
|
||||
QString qtest;
|
||||
// set this define if Oracle is built with threading support
|
||||
//#define QOCI_THREADED
|
||||
|
||||
class tst_QSqlThread : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
tst_QSqlThread();
|
||||
virtual ~tst_QSqlThread();
|
||||
|
||||
|
||||
void dropTestTables();
|
||||
void createTestTables();
|
||||
void recreateTestTables();
|
||||
void repopulateTestTables();
|
||||
|
||||
void generic_data(const QString &engine=QString());
|
||||
tst_Databases dbs;
|
||||
|
||||
public slots:
|
||||
void initTestCase();
|
||||
void cleanupTestCase();
|
||||
void init();
|
||||
void cleanup();
|
||||
|
||||
protected slots:
|
||||
void threadFinished() {
|
||||
++threadFinishedCount;
|
||||
qDebug("Thread finished, total finished: %d", threadFinishedCount);
|
||||
}
|
||||
|
||||
private slots:
|
||||
void simpleThreading_data() { generic_data(); }
|
||||
void simpleThreading();
|
||||
void readWriteThreading_data() { generic_data(); }
|
||||
void readWriteThreading();
|
||||
void readFromSingleConnection_data() { generic_data(); }
|
||||
void readFromSingleConnection();
|
||||
void readWriteFromSingleConnection_data() { generic_data(); }
|
||||
void readWriteFromSingleConnection();
|
||||
void preparedReadWriteFromSingleConnection_data() { generic_data(); }
|
||||
void preparedReadWriteFromSingleConnection();
|
||||
void transactionsFromSingleConnection_data() { generic_data(); }
|
||||
void transactionsFromSingleConnection();
|
||||
|
||||
private:
|
||||
int threadFinishedCount;
|
||||
};
|
||||
|
||||
static QAtomicInt counter;
|
||||
|
||||
class QtTestSqlThread : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QtTestSqlThread(const QSqlDatabase &aDb, QObject *parent = nullptr)
|
||||
: QThread(parent), sourceDb(aDb) {}
|
||||
|
||||
void runHelper(const QString &dbName)
|
||||
{
|
||||
QSqlDatabase db = QSqlDatabase::cloneDatabase(sourceDb, dbName);
|
||||
QVERIFY_SQL(db, open());
|
||||
|
||||
int sum = 0;
|
||||
QSqlQuery q("select id from " + qtest, db);
|
||||
QVERIFY_SQL(q, isActive());
|
||||
while (q.next())
|
||||
sum += q.value(0).toInt();
|
||||
QCOMPARE(sum, 6);
|
||||
q.clear();
|
||||
}
|
||||
|
||||
void run() override
|
||||
{
|
||||
QString dbName = QString("QThreadDb%1").arg((size_t)currentThreadId());
|
||||
runHelper(dbName);
|
||||
|
||||
QSqlDatabase::database(dbName).close();
|
||||
QSqlDatabase::removeDatabase(dbName);
|
||||
}
|
||||
|
||||
private:
|
||||
QSqlDatabase sourceDb;
|
||||
};
|
||||
|
||||
enum { ProdConIterations = 10 };
|
||||
|
||||
class SqlProducer: public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SqlProducer(const QSqlDatabase &aDb, QObject *parent = nullptr)
|
||||
: QThread(parent), sourceDb(aDb) {}
|
||||
|
||||
void runHelper(const QString &dbName)
|
||||
{
|
||||
QSqlDatabase db = QSqlDatabase::cloneDatabase(sourceDb, dbName);
|
||||
QVERIFY_SQL(db, open());
|
||||
QSqlQuery q(db);
|
||||
QVERIFY_SQL(q, prepare("insert into " + qtest + " values (?, ?, ?)"));
|
||||
int id = 10;
|
||||
for (int i = 0; i < ProdConIterations; ++i) {
|
||||
q.bindValue(0, ++id);
|
||||
q.bindValue(1, "threaddy");
|
||||
q.bindValue(2, 10);
|
||||
QVERIFY_SQL(q, exec());
|
||||
QThread::yieldCurrentThread();
|
||||
}
|
||||
}
|
||||
|
||||
void run() override
|
||||
{
|
||||
QString dbName = QString("Producer%1").arg((size_t)currentThreadId());
|
||||
runHelper(dbName);
|
||||
QSqlDatabase::database(dbName).close();
|
||||
QSqlDatabase::removeDatabase(dbName);
|
||||
}
|
||||
private:
|
||||
QSqlDatabase sourceDb;
|
||||
};
|
||||
|
||||
class SqlConsumer: public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SqlConsumer(const QSqlDatabase &aDb, QObject *parent = nullptr)
|
||||
: QThread(parent), sourceDb(aDb) {}
|
||||
|
||||
void runHelper(const QString &dbName)
|
||||
{
|
||||
QSqlDatabase db = QSqlDatabase::cloneDatabase(sourceDb, dbName);
|
||||
QVERIFY_SQL(db, open());
|
||||
QSqlQuery q1(db), q2(db);
|
||||
QVERIFY_SQL(q2, prepare("delete from " + qtest + " where id = :id"));
|
||||
|
||||
for (int i = 0; i < ProdConIterations; ++i) {
|
||||
QVERIFY_SQL(q1, exec("select max(id) from " + qtest));
|
||||
q1.first();
|
||||
q2.bindValue(":id", q1.value(0));
|
||||
q1.clear();
|
||||
QVERIFY_SQL(q2, exec());
|
||||
QThread::yieldCurrentThread();
|
||||
}
|
||||
}
|
||||
|
||||
void run() override
|
||||
{
|
||||
QString dbName = QString("Consumer%1").arg((size_t)currentThreadId());
|
||||
runHelper(dbName);
|
||||
QSqlDatabase::database(dbName).close();
|
||||
QSqlDatabase::removeDatabase(dbName);
|
||||
}
|
||||
|
||||
private:
|
||||
QSqlDatabase sourceDb;
|
||||
};
|
||||
|
||||
class SqlThread: public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum Mode { SimpleReading, PreparedReading, SimpleWriting, PreparedWriting };
|
||||
|
||||
SqlThread(Mode m, const QSqlDatabase &db, QObject *parent = nullptr)
|
||||
: QThread(parent), sourceDb(db), mode(m) {}
|
||||
|
||||
void run() override
|
||||
{
|
||||
QSqlDatabase &db = sourceDb;
|
||||
switch (mode) {
|
||||
case SimpleReading: {
|
||||
// Executes a Query for reading, iterates over the first 4 results
|
||||
QSqlQuery q(sourceDb);
|
||||
for (int j = 0; j < ProdConIterations; ++j) {
|
||||
QVERIFY_SQL(q, exec("select id,name from " + qtest + " order by id"));
|
||||
for (int i = 1; i < 4; ++i) {
|
||||
QVERIFY_SQL(q, next());
|
||||
QCOMPARE(q.value(0).toInt(), i);
|
||||
}
|
||||
}
|
||||
break; }
|
||||
case SimpleWriting: {
|
||||
// Executes a query for writing (appends a new row)
|
||||
QSqlQuery q(sourceDb);
|
||||
for (int j = 0; j < ProdConIterations; ++j) {
|
||||
QVERIFY_SQL(q, exec(QString("insert into " + qtest
|
||||
+ " (id, name) values(%1, '%2')")
|
||||
.arg(counter.fetchAndAddRelaxed(1)).arg("Robert")));
|
||||
}
|
||||
break; }
|
||||
case PreparedReading: {
|
||||
// Prepares a query for reading and iterates over the results
|
||||
QSqlQuery q(sourceDb);
|
||||
QVERIFY_SQL(q, prepare("select id, name from " + qtest + " where id = ?"));
|
||||
for (int j = 0; j < ProdConIterations; ++j) {
|
||||
q.addBindValue(j % 3 + 1);
|
||||
QVERIFY_SQL(q, exec());
|
||||
QVERIFY_SQL(q, next());
|
||||
QCOMPARE(q.value(0).toInt(), j % 3 + 1);
|
||||
}
|
||||
break; }
|
||||
case PreparedWriting: {
|
||||
QSqlQuery q(sourceDb);
|
||||
QVERIFY_SQL(q, prepare("insert into " + qtest + " (id, name) "
|
||||
"values(?, ?)"));
|
||||
for (int i = 0; i < ProdConIterations; ++i) {
|
||||
q.addBindValue(counter.fetchAndAddRelaxed(1));
|
||||
q.addBindValue("Robert");
|
||||
QVERIFY_SQL(q, exec());
|
||||
}
|
||||
break; }
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
QSqlDatabase sourceDb;
|
||||
Mode mode;
|
||||
};
|
||||
|
||||
|
||||
tst_QSqlThread::tst_QSqlThread()
|
||||
: threadFinishedCount(0)
|
||||
{
|
||||
static QSqlDatabase static_qtest_db = QSqlDatabase();
|
||||
qtest = qTableName("qtest", __FILE__, static_qtest_db);
|
||||
}
|
||||
|
||||
tst_QSqlThread::~tst_QSqlThread()
|
||||
{
|
||||
}
|
||||
|
||||
void tst_QSqlThread::generic_data(const QString& engine)
|
||||
{
|
||||
if ( dbs.fillTestTable(engine) == 0 ) {
|
||||
if(engine.isEmpty())
|
||||
QSKIP( "No database drivers are available in this Qt configuration");
|
||||
else
|
||||
QSKIP( (QString("No database drivers of type %1 are available in this Qt configuration").arg(engine)).toLocal8Bit());
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QSqlThread::createTestTables()
|
||||
{
|
||||
for (int i = 0; i < dbs.dbNames.size(); ++i) {
|
||||
QSqlDatabase db = QSqlDatabase::database(dbs.dbNames.at(i));
|
||||
QSqlQuery q(db);
|
||||
|
||||
QVERIFY_SQL(q, exec("create table " + qtest
|
||||
+ "(id int NOT NULL primary key, name varchar(20), title int)"));
|
||||
|
||||
QVERIFY_SQL(q, exec("create table " + qTableName("qtest2", __FILE__, db)
|
||||
+ "(id int NOT NULL primary key, title varchar(20))"));
|
||||
|
||||
QVERIFY_SQL(q, exec("create table " + qTableName("emptytable", __FILE__, db)
|
||||
+ "(id int NOT NULL primary key)"));
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QSqlThread::repopulateTestTables()
|
||||
{
|
||||
for (int i = 0; i < dbs.dbNames.size(); ++i) {
|
||||
QSqlDatabase db = QSqlDatabase::database(dbs.dbNames.at(i));
|
||||
QSqlQuery q(db);
|
||||
|
||||
QVERIFY_SQL(q, exec("delete from " + qtest));
|
||||
QVERIFY_SQL(q, exec("insert into " + qtest + " values(1, 'harry', 1)"));
|
||||
QVERIFY_SQL(q, exec("insert into " + qtest + " values(2, 'trond', 2)"));
|
||||
QVERIFY_SQL(q, exec("insert into " + qtest + " values(3, 'vohi', 3)"));
|
||||
|
||||
QVERIFY_SQL(q, exec("delete from " + qTableName("qtest2", __FILE__, db)));
|
||||
QVERIFY_SQL(q, exec("insert into " + qTableName("qtest2", __FILE__, db) + " values(1, 'herr')"));
|
||||
QVERIFY_SQL(q, exec("insert into " + qTableName("qtest2", __FILE__, db) + " values(2, 'mister')"));
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QSqlThread::recreateTestTables()
|
||||
{
|
||||
dropTestTables();
|
||||
createTestTables();
|
||||
repopulateTestTables();
|
||||
}
|
||||
|
||||
void tst_QSqlThread::initTestCase()
|
||||
{
|
||||
QVERIFY(dbs.open());
|
||||
recreateTestTables();
|
||||
}
|
||||
|
||||
void tst_QSqlThread::cleanupTestCase()
|
||||
{
|
||||
dropTestTables();
|
||||
dbs.close();
|
||||
}
|
||||
|
||||
void tst_QSqlThread::init()
|
||||
{
|
||||
threadFinishedCount = 0;
|
||||
counter.storeRelaxed(4);
|
||||
}
|
||||
|
||||
void tst_QSqlThread::cleanup()
|
||||
{
|
||||
// repopulateTestTables();
|
||||
}
|
||||
|
||||
// This test creates two threads that clone their db connection and read
|
||||
// from it
|
||||
void tst_QSqlThread::simpleThreading()
|
||||
{
|
||||
QFETCH(QString, dbName);
|
||||
QSqlDatabase db = QSqlDatabase::database(dbName);
|
||||
CHECK_DATABASE(db);
|
||||
|
||||
if (db.databaseName() == ":memory:")
|
||||
QSKIP("does not work with in-memory databases");
|
||||
|
||||
QtTestSqlThread t1(db);
|
||||
QtTestSqlThread t2(db);
|
||||
|
||||
connect(&t1, SIGNAL(finished()), this, SLOT(threadFinished()), Qt::QueuedConnection);
|
||||
connect(&t2, SIGNAL(finished()), this, SLOT(threadFinished()), Qt::QueuedConnection);
|
||||
|
||||
t1.start();
|
||||
t2.start();
|
||||
|
||||
QTRY_VERIFY(threadFinishedCount >= 2);
|
||||
}
|
||||
|
||||
// This test creates two threads that clone their db connection and read
|
||||
// or write
|
||||
void tst_QSqlThread::readWriteThreading()
|
||||
{
|
||||
QFETCH(QString, dbName);
|
||||
QSqlDatabase db = QSqlDatabase::database(dbName);
|
||||
CHECK_DATABASE(db);
|
||||
|
||||
if (db.databaseName() == ":memory:")
|
||||
QSKIP("does not work with in-memory databases");
|
||||
else if (tst_Databases::isMSAccess(db))
|
||||
QSKIP("does not work with MS Access databases");
|
||||
|
||||
SqlProducer producer(db);
|
||||
SqlConsumer consumer(db);
|
||||
|
||||
connect(&producer, SIGNAL(finished()), this, SLOT(threadFinished()), Qt::QueuedConnection);
|
||||
connect(&consumer, SIGNAL(finished()), this, SLOT(threadFinished()), Qt::QueuedConnection);
|
||||
|
||||
producer.start();
|
||||
consumer.start();
|
||||
|
||||
QTRY_VERIFY_WITH_TIMEOUT(threadFinishedCount >= 2, 10000);
|
||||
}
|
||||
|
||||
#ifdef QOCI_THREADED
|
||||
// run with n threads in parallel. Change this constant to hammer the poor DB server even more
|
||||
static const int maxThreadCount = 4;
|
||||
#endif
|
||||
|
||||
void tst_QSqlThread::readFromSingleConnection()
|
||||
{
|
||||
#ifdef QOCI_THREADED
|
||||
QFETCH(QString, dbName);
|
||||
QSqlDatabase db = QSqlDatabase::database(dbName);
|
||||
CHECK_DATABASE(db);
|
||||
|
||||
if (db.databaseName() == ":memory:")
|
||||
QSKIP("does not work with in-memory databases");
|
||||
|
||||
QObject cleanupHelper; // make sure the threads die when we exit the scope
|
||||
for (int i = 0; i < maxThreadCount; ++i) {
|
||||
SqlThread *reader = new SqlThread(SqlThread::SimpleReading, db, &cleanupHelper);
|
||||
connect(reader, SIGNAL(finished()), this, SLOT(threadFinished()), Qt::QueuedConnection);
|
||||
reader->start();
|
||||
}
|
||||
|
||||
QTRY_VERIFY(threadFinishedCount >= maxThreadCount);
|
||||
#endif
|
||||
}
|
||||
|
||||
void tst_QSqlThread::readWriteFromSingleConnection()
|
||||
{
|
||||
#ifdef QOCI_THREADED
|
||||
QFETCH(QString, dbName);
|
||||
QSqlDatabase db = QSqlDatabase::database(dbName);
|
||||
CHECK_DATABASE(db);
|
||||
|
||||
if (db.databaseName() == ":memory:")
|
||||
QSKIP("does not work with in-memory databases");
|
||||
|
||||
QObject cleanupHelper;
|
||||
for (int i = 0; i < maxThreadCount; ++i) {
|
||||
SqlThread *reader = new SqlThread(SqlThread::SimpleReading, db, &cleanupHelper);
|
||||
connect(reader, SIGNAL(finished()), this, SLOT(threadFinished()), Qt::QueuedConnection);
|
||||
reader->start();
|
||||
|
||||
SqlThread *writer = new SqlThread(SqlThread::SimpleWriting, db, &cleanupHelper);
|
||||
connect(writer, SIGNAL(finished()), this, SLOT(threadFinished()), Qt::QueuedConnection);
|
||||
writer->start();
|
||||
}
|
||||
|
||||
QTRY_VERIFY(threadFinishedCount >= maxThreadCount * 2);
|
||||
#endif
|
||||
}
|
||||
|
||||
void tst_QSqlThread::preparedReadWriteFromSingleConnection()
|
||||
{
|
||||
#ifdef QOCI_THREADED
|
||||
QFETCH(QString, dbName);
|
||||
QSqlDatabase db = QSqlDatabase::database(dbName);
|
||||
CHECK_DATABASE(db);
|
||||
|
||||
if (db.databaseName() == ":memory:")
|
||||
QSKIP("does not work with in-memory databases");
|
||||
|
||||
QObject cleanupHelper;
|
||||
for (int i = 0; i < maxThreadCount; ++i) {
|
||||
SqlThread *reader = new SqlThread(SqlThread::PreparedReading, db, &cleanupHelper);
|
||||
connect(reader, SIGNAL(finished()), this, SLOT(threadFinished()), Qt::QueuedConnection);
|
||||
reader->start();
|
||||
|
||||
SqlThread *writer = new SqlThread(SqlThread::PreparedWriting, db, &cleanupHelper);
|
||||
connect(writer, SIGNAL(finished()), this, SLOT(threadFinished()), Qt::QueuedConnection);
|
||||
writer->start();
|
||||
}
|
||||
|
||||
QTRY_VERIFY(threadFinishedCount >= maxThreadCount * 2);
|
||||
#endif
|
||||
}
|
||||
|
||||
void tst_QSqlThread::transactionsFromSingleConnection()
|
||||
{
|
||||
#ifdef QOCI_THREADED
|
||||
QFETCH(QString, dbName);
|
||||
QSqlDatabase db = QSqlDatabase::database(dbName);
|
||||
CHECK_DATABASE(db);
|
||||
|
||||
if (db.databaseName() == ":memory:")
|
||||
QSKIP("does not work with in-memory databases");
|
||||
|
||||
// start and commit a transaction
|
||||
QVERIFY_SQL(db, db.transaction());
|
||||
preparedReadWriteFromSingleConnection(); // read and write from multiple threads
|
||||
if (QTest::currentTestFailed())
|
||||
return;
|
||||
QVERIFY_SQL(db, db.commit());
|
||||
|
||||
// reset test environment
|
||||
threadFinishedCount = 0;
|
||||
|
||||
// start and roll back a transaction
|
||||
QVERIFY_SQL(db, db.transaction());
|
||||
preparedReadWriteFromSingleConnection(); // read and write from multiple threads
|
||||
if (QTest::currentTestFailed())
|
||||
return;
|
||||
QVERIFY_SQL(db, db.rollback());
|
||||
#endif
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QSqlThread)
|
||||
#include "tst_qsqlthread.moc"
|
9
tests/auto/sql/models/CMakeLists.txt
Normal file
9
tests/auto/sql/models/CMakeLists.txt
Normal file
@ -0,0 +1,9 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
add_subdirectory(qsqlrelationaltablemodel)
|
||||
add_subdirectory(qsqltablemodel)
|
||||
if(TARGET Qt::Widgets)
|
||||
add_subdirectory(qsqlquerymodel)
|
||||
add_subdirectory(qsqlrelationaldelegate)
|
||||
endif()
|
17
tests/auto/sql/models/qsqlquerymodel/CMakeLists.txt
Normal file
17
tests/auto/sql/models/qsqlquerymodel/CMakeLists.txt
Normal file
@ -0,0 +1,17 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_qsqlquerymodel Test:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_test(tst_qsqlquerymodel
|
||||
SOURCES
|
||||
tst_qsqlquerymodel.cpp
|
||||
LIBRARIES
|
||||
Qt::CorePrivate
|
||||
Qt::Gui
|
||||
Qt::Sql
|
||||
Qt::SqlPrivate
|
||||
Qt::Widgets
|
||||
)
|
665
tests/auto/sql/models/qsqlquerymodel/tst_qsqlquerymodel.cpp
Normal file
665
tests/auto/sql/models/qsqlquerymodel/tst_qsqlquerymodel.cpp
Normal file
@ -0,0 +1,665 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
|
||||
#include <QTest>
|
||||
#include <QtGui>
|
||||
#include <QtWidgets>
|
||||
#include <QSignalSpy>
|
||||
|
||||
#include <qsqldriver.h>
|
||||
#include <qsqldatabase.h>
|
||||
#include <qsqlerror.h>
|
||||
#include <qsqlfield.h>
|
||||
#include <qsqlquery.h>
|
||||
#include <qsqlrecord.h>
|
||||
|
||||
#include <qsqlquerymodel.h>
|
||||
#include <qsortfilterproxymodel.h>
|
||||
|
||||
#include "../../kernel/qsqldatabase/tst_databases.h"
|
||||
|
||||
Q_DECLARE_METATYPE(Qt::Orientation)
|
||||
|
||||
class tst_QSqlQueryModel : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
tst_QSqlQueryModel();
|
||||
virtual ~tst_QSqlQueryModel();
|
||||
|
||||
public slots:
|
||||
void initTestCase();
|
||||
void cleanupTestCase();
|
||||
void init();
|
||||
void cleanup();
|
||||
|
||||
private slots:
|
||||
void insertColumn_data() { generic_data(); }
|
||||
void insertColumn();
|
||||
void removeColumn_data() { generic_data(); }
|
||||
void removeColumn();
|
||||
void record_data() { generic_data(); }
|
||||
void record();
|
||||
void setHeaderData_data() { generic_data(); }
|
||||
void setHeaderData();
|
||||
void fetchMore_data() { generic_data(); }
|
||||
void fetchMore();
|
||||
|
||||
//problem specific tests
|
||||
void withSortFilterProxyModel_data() { generic_data(); }
|
||||
void withSortFilterProxyModel();
|
||||
void setQuerySignalEmission_data() { generic_data(); }
|
||||
void setQuerySignalEmission();
|
||||
void setQueryWithNoRowsInResultSet_data() { generic_data(); }
|
||||
void setQueryWithNoRowsInResultSet();
|
||||
void nestedResets_data() { generic_data(); }
|
||||
void nestedResets();
|
||||
|
||||
void task_180617();
|
||||
void task_180617_data() { generic_data(); }
|
||||
void task_QTBUG_4963_setHeaderDataWithProxyModel();
|
||||
|
||||
private:
|
||||
void generic_data(const QString &engine=QString());
|
||||
void dropTestTables(QSqlDatabase db);
|
||||
void createTestTables(QSqlDatabase db);
|
||||
void populateTestTables(QSqlDatabase db);
|
||||
tst_Databases dbs;
|
||||
};
|
||||
|
||||
/* Stupid class that makes protected members public for testing */
|
||||
class DBTestModel: public QSqlQueryModel
|
||||
{
|
||||
public:
|
||||
DBTestModel(QObject *parent = nullptr): QSqlQueryModel(parent) {}
|
||||
QModelIndex indexInQuery(const QModelIndex &item) const override { return QSqlQueryModel::indexInQuery(item); }
|
||||
};
|
||||
|
||||
tst_QSqlQueryModel::tst_QSqlQueryModel()
|
||||
{
|
||||
}
|
||||
|
||||
tst_QSqlQueryModel::~tst_QSqlQueryModel()
|
||||
{
|
||||
}
|
||||
|
||||
void tst_QSqlQueryModel::initTestCase()
|
||||
{
|
||||
QVERIFY(dbs.open());
|
||||
for (QStringList::ConstIterator it = dbs.dbNames.begin(); it != dbs.dbNames.end(); ++it) {
|
||||
QSqlDatabase db = QSqlDatabase::database((*it));
|
||||
CHECK_DATABASE(db);
|
||||
dropTestTables(db); //in case of leftovers
|
||||
createTestTables(db);
|
||||
populateTestTables(db);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QSqlQueryModel::cleanupTestCase()
|
||||
{
|
||||
for (QStringList::ConstIterator it = dbs.dbNames.begin(); it != dbs.dbNames.end(); ++it) {
|
||||
QSqlDatabase db = QSqlDatabase::database((*it));
|
||||
CHECK_DATABASE(db);
|
||||
dropTestTables(db);
|
||||
}
|
||||
dbs.close();
|
||||
}
|
||||
|
||||
void tst_QSqlQueryModel::dropTestTables(QSqlDatabase db)
|
||||
{
|
||||
QStringList tableNames;
|
||||
tableNames << qTableName("test", __FILE__, db)
|
||||
<< qTableName("test2", __FILE__, db)
|
||||
<< qTableName("test3", __FILE__, db)
|
||||
<< qTableName("many", __FILE__, db);
|
||||
tst_Databases::safeDropTables(db, tableNames);
|
||||
}
|
||||
|
||||
void tst_QSqlQueryModel::createTestTables(QSqlDatabase db)
|
||||
{
|
||||
dropTestTables(db);
|
||||
QSqlQuery q(db);
|
||||
QSqlDriver::DbmsType dbType = tst_Databases::getDatabaseType(db);
|
||||
if (dbType == QSqlDriver::PostgreSQL)
|
||||
QVERIFY_SQL( q, exec("set client_min_messages='warning'"));
|
||||
QVERIFY_SQL( q, exec("create table " + qTableName("test", __FILE__, db) + "(id integer not null, name varchar(20), title integer, primary key (id))"));
|
||||
QVERIFY_SQL( q, exec("create table " + qTableName("test2", __FILE__, db) + "(id integer not null, title varchar(20), primary key (id))"));
|
||||
QVERIFY_SQL( q, exec("create table " + qTableName("test3", __FILE__, db) + "(id integer not null, primary key (id))"));
|
||||
QVERIFY_SQL( q, exec("create table " + qTableName("many", __FILE__, db) + "(id integer not null, name varchar(20), primary key (id))"));
|
||||
}
|
||||
|
||||
void tst_QSqlQueryModel::populateTestTables(QSqlDatabase db)
|
||||
{
|
||||
qWarning() << "Populating test tables, this can take quite a while... ZZZzzz...";
|
||||
bool hasTransactions = db.driver()->hasFeature(QSqlDriver::Transactions);
|
||||
|
||||
QSqlQuery q(db), q2(db);
|
||||
|
||||
tst_Databases::safeDropTables(db, QStringList() << qTableName("manytmp", __FILE__, db) << qTableName("test3tmp", __FILE__, db));
|
||||
QVERIFY_SQL(q, exec("create table " + qTableName("manytmp", __FILE__, db) + "(id integer not null, name varchar(20), primary key (id))"));
|
||||
QVERIFY_SQL(q, exec("create table " + qTableName("test3tmp", __FILE__, db) + "(id integer not null, primary key (id))"));
|
||||
|
||||
if (hasTransactions) QVERIFY_SQL(db, transaction());
|
||||
|
||||
QVERIFY_SQL(q, exec("insert into " + qTableName("test", __FILE__, db) + " values(1, 'harry', 1)"));
|
||||
QVERIFY_SQL(q, exec("insert into " + qTableName("test", __FILE__, db) + " values(2, 'trond', 2)"));
|
||||
QVERIFY_SQL(q, exec("insert into " + qTableName("test2", __FILE__, db) + " values(1, 'herr')"));
|
||||
QVERIFY_SQL(q, exec("insert into " + qTableName("test2", __FILE__, db) + " values(2, 'mister')"));
|
||||
|
||||
QVERIFY_SQL(q, exec(QString("insert into " + qTableName("test3", __FILE__, db) + " values(0)")));
|
||||
QVERIFY_SQL(q, prepare("insert into "+ qTableName("test3", __FILE__, db) + "(id) select id + ? from " + qTableName("test3tmp", __FILE__, db)));
|
||||
for (int i=1; i<260; i*=2) {
|
||||
q2.exec("delete from " + qTableName("test3tmp", __FILE__, db));
|
||||
QVERIFY_SQL(q2, exec("insert into " + qTableName("test3tmp", __FILE__, db) + "(id) select id from " + qTableName("test3", __FILE__, db)));
|
||||
q.bindValue(0, i);
|
||||
QVERIFY_SQL(q, exec());
|
||||
}
|
||||
|
||||
QVERIFY_SQL(q, exec(QString("insert into " + qTableName("many", __FILE__, db) + "(id, name) values (0, \'harry\')")));
|
||||
QVERIFY_SQL(q, prepare("insert into " + qTableName("many", __FILE__, db) + "(id, name) select id + ?, name from " + qTableName("manytmp", __FILE__, db)));
|
||||
for (int i=1; i < 2048; i*=2) {
|
||||
q2.exec("delete from " + qTableName("manytmp", __FILE__, db));
|
||||
QVERIFY_SQL(q2, exec("insert into " + qTableName("manytmp", __FILE__, db) + "(id, name) select id, name from " + qTableName("many", __FILE__, db)));
|
||||
q.bindValue(0, i);
|
||||
QVERIFY_SQL(q, exec());
|
||||
}
|
||||
|
||||
if (hasTransactions) QVERIFY_SQL(db, commit());
|
||||
|
||||
tst_Databases::safeDropTables(db, QStringList() << qTableName("manytmp", __FILE__, db) << qTableName("test3tmp", __FILE__, db));
|
||||
}
|
||||
|
||||
void tst_QSqlQueryModel::generic_data(const QString& engine)
|
||||
{
|
||||
if ( dbs.fillTestTable(engine) == 0 ) {
|
||||
if(engine.isEmpty())
|
||||
QSKIP( "No database drivers are available in this Qt configuration");
|
||||
else
|
||||
QSKIP( (QString("No database drivers of type %1 are available in this Qt configuration").arg(engine)).toLocal8Bit());
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QSqlQueryModel::init()
|
||||
{
|
||||
}
|
||||
|
||||
void tst_QSqlQueryModel::cleanup()
|
||||
{
|
||||
}
|
||||
|
||||
void tst_QSqlQueryModel::removeColumn()
|
||||
{
|
||||
QFETCH(QString, dbName);
|
||||
QSqlDatabase db = QSqlDatabase::database(dbName);
|
||||
CHECK_DATABASE(db);
|
||||
|
||||
DBTestModel model;
|
||||
model.setQuery(QSqlQuery("select * from " + qTableName("test", __FILE__, db), db));
|
||||
model.fetchMore();
|
||||
QSignalSpy spy(&model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)));
|
||||
|
||||
QCOMPARE(model.columnCount(), 3);
|
||||
QVERIFY(model.removeColumn(0));
|
||||
QCOMPARE(spy.size(), 1);
|
||||
QVERIFY(*(QModelIndex *)spy.at(0).at(0).constData() == QModelIndex());
|
||||
QCOMPARE(spy.at(0).at(1).toInt(), 0);
|
||||
QCOMPARE(spy.at(0).at(2).toInt(), 0);
|
||||
|
||||
QCOMPARE(model.columnCount(), 2);
|
||||
QCOMPARE(model.indexInQuery(model.index(0, 0)).column(), 1);
|
||||
QCOMPARE(model.indexInQuery(model.index(0, 1)).column(), 2);
|
||||
QCOMPARE(model.indexInQuery(model.index(0, 2)).column(), -1);
|
||||
QCOMPARE(model.indexInQuery(model.index(0, 3)).column(), -1);
|
||||
|
||||
QVERIFY(model.insertColumn(1));
|
||||
QCOMPARE(model.columnCount(), 3);
|
||||
QCOMPARE(model.indexInQuery(model.index(0, 0)).column(), 1);
|
||||
QCOMPARE(model.indexInQuery(model.index(0, 1)).column(), -1);
|
||||
QCOMPARE(model.indexInQuery(model.index(0, 2)).column(), 2);
|
||||
QCOMPARE(model.indexInQuery(model.index(0, 3)).column(), -1);
|
||||
|
||||
QCOMPARE(model.data(model.index(0, 0)).toString(), QString("harry"));
|
||||
QCOMPARE(model.data(model.index(0, 1)), QVariant());
|
||||
QCOMPARE(model.data(model.index(0, 2)).toInt(), 1);
|
||||
QCOMPARE(model.data(model.index(0, 3)), QVariant());
|
||||
|
||||
QVERIFY(!model.removeColumn(42));
|
||||
QVERIFY(!model.removeColumn(3));
|
||||
QVERIFY(!model.removeColumn(1, model.index(1, 2)));
|
||||
QCOMPARE(model.columnCount(), 3);
|
||||
|
||||
QVERIFY(model.removeColumn(2));
|
||||
|
||||
QCOMPARE(spy.size(), 2);
|
||||
QVERIFY(*(QModelIndex *)spy.at(1).at(0).constData() == QModelIndex());
|
||||
QCOMPARE(spy.at(1).at(1).toInt(), 2);
|
||||
QCOMPARE(spy.at(1).at(2).toInt(), 2);
|
||||
|
||||
QCOMPARE(model.columnCount(), 2);
|
||||
QCOMPARE(model.indexInQuery(model.index(0, 0)).column(), 1);
|
||||
QCOMPARE(model.indexInQuery(model.index(0, 1)).column(), -1);
|
||||
QCOMPARE(model.indexInQuery(model.index(0, 2)).column(), -1);
|
||||
QCOMPARE(model.indexInQuery(model.index(0, 3)).column(), -1);
|
||||
|
||||
QVERIFY(model.removeColumn(1));
|
||||
|
||||
QCOMPARE(spy.size(), 3);
|
||||
QVERIFY(*(QModelIndex *)spy.at(2).at(0).constData() == QModelIndex());
|
||||
QCOMPARE(spy.at(2).at(1).toInt(), 1);
|
||||
QCOMPARE(spy.at(2).at(2).toInt(), 1);
|
||||
|
||||
QCOMPARE(model.columnCount(), 1);
|
||||
QCOMPARE(model.indexInQuery(model.index(0, 0)).column(), 1);
|
||||
QCOMPARE(model.indexInQuery(model.index(0, 1)).column(), -1);
|
||||
QCOMPARE(model.indexInQuery(model.index(0, 2)).column(), -1);
|
||||
QCOMPARE(model.indexInQuery(model.index(0, 3)).column(), -1);
|
||||
QCOMPARE(model.data(model.index(0, 0)).toString(), QString("harry"));
|
||||
|
||||
QVERIFY(model.removeColumn(0));
|
||||
|
||||
QCOMPARE(spy.size(), 4);
|
||||
QVERIFY(*(QModelIndex *)spy.at(3).at(0).constData() == QModelIndex());
|
||||
QCOMPARE(spy.at(3).at(1).toInt(), 0);
|
||||
QCOMPARE(spy.at(3).at(2).toInt(), 0);
|
||||
|
||||
QCOMPARE(model.columnCount(), 0);
|
||||
QCOMPARE(model.indexInQuery(model.index(0, 0)).column(), -1);
|
||||
QCOMPARE(model.indexInQuery(model.index(0, 1)).column(), -1);
|
||||
QCOMPARE(model.indexInQuery(model.index(0, 2)).column(), -1);
|
||||
QCOMPARE(model.indexInQuery(model.index(0, 3)).column(), -1);
|
||||
}
|
||||
|
||||
void tst_QSqlQueryModel::insertColumn()
|
||||
{
|
||||
QFETCH(QString, dbName);
|
||||
QSqlDatabase db = QSqlDatabase::database(dbName);
|
||||
CHECK_DATABASE(db);
|
||||
const QSqlDriver::DbmsType dbType = tst_Databases::getDatabaseType(db);
|
||||
|
||||
DBTestModel model;
|
||||
model.setQuery(QSqlQuery("select * from " + qTableName("test", __FILE__, db), db));
|
||||
model.fetchMore(); // necessary???
|
||||
|
||||
bool isToUpper = (dbType == QSqlDriver::Interbase) || (dbType == QSqlDriver::Oracle) || (dbType == QSqlDriver::DB2);
|
||||
const QString idColumn(isToUpper ? "ID" : "id");
|
||||
const QString nameColumn(isToUpper ? "NAME" : "name");
|
||||
const QString titleColumn(isToUpper ? "TITLE" : "title");
|
||||
|
||||
QSignalSpy spy(&model, SIGNAL(columnsInserted(QModelIndex,int,int)));
|
||||
|
||||
QCOMPARE(model.data(model.index(0, 0)).toInt(), 1);
|
||||
QCOMPARE(model.data(model.index(0, 1)).toString(), QString("harry"));
|
||||
QCOMPARE(model.data(model.index(0, 2)).toInt(), 1);
|
||||
QCOMPARE(model.data(model.index(0, 3)), QVariant());
|
||||
|
||||
QCOMPARE(model.headerData(0, Qt::Horizontal).toString(), idColumn);
|
||||
QCOMPARE(model.headerData(1, Qt::Horizontal).toString(), nameColumn);
|
||||
QCOMPARE(model.headerData(2, Qt::Horizontal).toString(), titleColumn);
|
||||
QCOMPARE(model.headerData(3, Qt::Horizontal).toString(), QString("4"));
|
||||
|
||||
QVERIFY(model.insertColumn(1));
|
||||
|
||||
QCOMPARE(spy.size(), 1);
|
||||
QVERIFY(*(QModelIndex *)spy.at(0).at(0).constData() == QModelIndex());
|
||||
QCOMPARE(spy.at(0).at(1).toInt(), 1);
|
||||
QCOMPARE(spy.at(0).at(2).toInt(), 1);
|
||||
|
||||
QCOMPARE(model.indexInQuery(model.index(0, 0)).column(), 0);
|
||||
QCOMPARE(model.indexInQuery(model.index(0, 1)).column(), -1);
|
||||
QCOMPARE(model.indexInQuery(model.index(0, 2)).column(), 1);
|
||||
QCOMPARE(model.indexInQuery(model.index(0, 3)).column(), 2);
|
||||
QCOMPARE(model.indexInQuery(model.index(0, 4)).column(), -1);
|
||||
|
||||
QCOMPARE(model.data(model.index(0, 0)).toInt(), 1);
|
||||
QCOMPARE(model.data(model.index(0, 1)), QVariant());
|
||||
QCOMPARE(model.data(model.index(0, 2)).toString(), QString("harry"));
|
||||
QCOMPARE(model.data(model.index(0, 3)).toInt(), 1);
|
||||
QCOMPARE(model.data(model.index(0, 4)), QVariant());
|
||||
|
||||
QCOMPARE(model.headerData(0, Qt::Horizontal).toString(), idColumn);
|
||||
QCOMPARE(model.headerData(1, Qt::Horizontal).toString(), QString("2"));
|
||||
QCOMPARE(model.headerData(2, Qt::Horizontal).toString(), nameColumn);
|
||||
QCOMPARE(model.headerData(3, Qt::Horizontal).toString(), titleColumn);
|
||||
QCOMPARE(model.headerData(4, Qt::Horizontal).toString(), QString("5"));
|
||||
|
||||
QVERIFY(!model.insertColumn(-1));
|
||||
QVERIFY(!model.insertColumn(100));
|
||||
QVERIFY(!model.insertColumn(1, model.index(1, 1)));
|
||||
|
||||
QVERIFY(model.insertColumn(0));
|
||||
|
||||
QCOMPARE(spy.size(), 2);
|
||||
QVERIFY(*(QModelIndex *)spy.at(1).at(0).constData() == QModelIndex());
|
||||
QCOMPARE(spy.at(1).at(1).toInt(), 0);
|
||||
QCOMPARE(spy.at(1).at(2).toInt(), 0);
|
||||
|
||||
QCOMPARE(model.indexInQuery(model.index(0, 0)).column(), -1);
|
||||
QCOMPARE(model.indexInQuery(model.index(0, 1)).column(), 0);
|
||||
QCOMPARE(model.indexInQuery(model.index(0, 2)).column(), -1);
|
||||
QCOMPARE(model.indexInQuery(model.index(0, 3)).column(), 1);
|
||||
QCOMPARE(model.indexInQuery(model.index(0, 4)).column(), 2);
|
||||
QCOMPARE(model.indexInQuery(model.index(0, 5)).column(), -1);
|
||||
|
||||
QVERIFY(!model.insertColumn(6));
|
||||
QVERIFY(model.insertColumn(5));
|
||||
|
||||
QCOMPARE(spy.size(), 3);
|
||||
QVERIFY(*(QModelIndex *)spy.at(2).at(0).constData() == QModelIndex());
|
||||
QCOMPARE(spy.at(2).at(1).toInt(), 5);
|
||||
QCOMPARE(spy.at(2).at(2).toInt(), 5);
|
||||
|
||||
QCOMPARE(model.indexInQuery(model.index(0, 0)).column(), -1);
|
||||
QCOMPARE(model.indexInQuery(model.index(0, 1)).column(), 0);
|
||||
QCOMPARE(model.indexInQuery(model.index(0, 2)).column(), -1);
|
||||
QCOMPARE(model.indexInQuery(model.index(0, 3)).column(), 1);
|
||||
QCOMPARE(model.indexInQuery(model.index(0, 4)).column(), 2);
|
||||
QCOMPARE(model.indexInQuery(model.index(0, 5)).column(), -1);
|
||||
QCOMPARE(model.indexInQuery(model.index(0, 6)).column(), -1);
|
||||
|
||||
QCOMPARE(model.record().field(0).name(), QString());
|
||||
QCOMPARE(model.record().field(1).name(), idColumn);
|
||||
QCOMPARE(model.record().field(2).name(), QString());
|
||||
QCOMPARE(model.record().field(3).name(), nameColumn);
|
||||
QCOMPARE(model.record().field(4).name(), titleColumn);
|
||||
QCOMPARE(model.record().field(5).name(), QString());
|
||||
QCOMPARE(model.record().field(6).name(), QString());
|
||||
|
||||
QCOMPARE(model.headerData(0, Qt::Horizontal).toString(), QString("1"));
|
||||
QCOMPARE(model.headerData(1, Qt::Horizontal).toString(), idColumn);
|
||||
QCOMPARE(model.headerData(2, Qt::Horizontal).toString(), QString("3"));
|
||||
QCOMPARE(model.headerData(3, Qt::Horizontal).toString(), nameColumn);
|
||||
QCOMPARE(model.headerData(4, Qt::Horizontal).toString(), titleColumn);
|
||||
QCOMPARE(model.headerData(5, Qt::Horizontal).toString(), QString("6"));
|
||||
QCOMPARE(model.headerData(6, Qt::Horizontal).toString(), QString("7"));
|
||||
}
|
||||
|
||||
void tst_QSqlQueryModel::record()
|
||||
{
|
||||
QFETCH(QString, dbName);
|
||||
QSqlDatabase db = QSqlDatabase::database(dbName);
|
||||
CHECK_DATABASE(db);
|
||||
const QSqlDriver::DbmsType dbType = tst_Databases::getDatabaseType(db);
|
||||
|
||||
QSqlQueryModel model;
|
||||
model.setQuery(QSqlQuery("select * from " + qTableName("test", __FILE__, db), db));
|
||||
|
||||
QSqlRecord rec = model.record();
|
||||
|
||||
bool isToUpper = (dbType == QSqlDriver::Interbase) || (dbType == QSqlDriver::Oracle) || (dbType == QSqlDriver::DB2);
|
||||
|
||||
QCOMPARE(rec.count(), 3);
|
||||
QCOMPARE(rec.fieldName(0), isToUpper ? QString("ID") : QString("id"));
|
||||
QCOMPARE(rec.fieldName(1), isToUpper ? QString("NAME") : QString("name"));
|
||||
QCOMPARE(rec.fieldName(2), isToUpper ? QString("TITLE") : QString("title"));
|
||||
QCOMPARE(rec.value(0), QVariant(rec.field(0).metaType()));
|
||||
QCOMPARE(rec.value(1), QVariant(rec.field(1).metaType()));
|
||||
QCOMPARE(rec.value(2), QVariant(rec.field(2).metaType()));
|
||||
|
||||
rec = model.record(0);
|
||||
QCOMPARE(rec.fieldName(0), isToUpper ? QString("ID") : QString("id"));
|
||||
QCOMPARE(rec.fieldName(1), isToUpper ? QString("NAME") : QString("name"));
|
||||
QCOMPARE(rec.fieldName(2), isToUpper ? QString("TITLE") : QString("title"));
|
||||
QCOMPARE(rec.value(0).toString(), QString("1"));
|
||||
QCOMPARE(rec.value(1), QVariant("harry"));
|
||||
QCOMPARE(rec.value(2), QVariant(1));
|
||||
}
|
||||
|
||||
void tst_QSqlQueryModel::setHeaderData()
|
||||
{
|
||||
QFETCH(QString, dbName);
|
||||
QSqlDatabase db = QSqlDatabase::database(dbName);
|
||||
CHECK_DATABASE(db);
|
||||
const QSqlDriver::DbmsType dbType = tst_Databases::getDatabaseType(db);
|
||||
|
||||
QSqlQueryModel model;
|
||||
|
||||
QVERIFY(!model.setHeaderData(5, Qt::Vertical, "foo"));
|
||||
QVERIFY(model.headerData(5, Qt::Vertical).isValid());
|
||||
|
||||
model.setQuery(QSqlQuery("select * from " + qTableName("test", __FILE__, db), db));
|
||||
|
||||
qRegisterMetaType<Qt::Orientation>("Qt::Orientation");
|
||||
QSignalSpy spy(&model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)));
|
||||
QVERIFY(model.setHeaderData(2, Qt::Horizontal, "bar"));
|
||||
QCOMPARE(model.headerData(2, Qt::Horizontal).toString(), QString("bar"));
|
||||
QCOMPARE(spy.size(), 1);
|
||||
QCOMPARE(qvariant_cast<Qt::Orientation>(spy.value(0).value(0)), Qt::Horizontal);
|
||||
QCOMPARE(spy.value(0).value(1).toInt(), 2);
|
||||
QCOMPARE(spy.value(0).value(2).toInt(), 2);
|
||||
|
||||
QVERIFY(!model.setHeaderData(7, Qt::Horizontal, "foo", Qt::ToolTipRole));
|
||||
QVERIFY(!model.headerData(7, Qt::Horizontal, Qt::ToolTipRole).isValid());
|
||||
|
||||
bool isToUpper = (dbType == QSqlDriver::Interbase) || (dbType == QSqlDriver::Oracle) || (dbType == QSqlDriver::DB2);
|
||||
QCOMPARE(model.headerData(0, Qt::Horizontal).toString(), isToUpper ? QString("ID") : QString("id"));
|
||||
QCOMPARE(model.headerData(1, Qt::Horizontal).toString(), isToUpper ? QString("NAME") : QString("name"));
|
||||
QCOMPARE(model.headerData(2, Qt::Horizontal).toString(), QString("bar"));
|
||||
QVERIFY(model.headerData(3, Qt::Horizontal).isValid());
|
||||
}
|
||||
|
||||
void tst_QSqlQueryModel::fetchMore()
|
||||
{
|
||||
QFETCH(QString, dbName);
|
||||
QSqlDatabase db = QSqlDatabase::database(dbName);
|
||||
CHECK_DATABASE(db);
|
||||
|
||||
QSqlQueryModel model;
|
||||
QSignalSpy modelAboutToBeResetSpy(&model, SIGNAL(modelAboutToBeReset()));
|
||||
QSignalSpy modelResetSpy(&model, SIGNAL(modelReset()));
|
||||
|
||||
model.setQuery(QSqlQuery("select * from " + qTableName("many", __FILE__, db), db));
|
||||
int rowCount = model.rowCount();
|
||||
|
||||
QCOMPARE(modelAboutToBeResetSpy.size(), 1);
|
||||
QCOMPARE(modelResetSpy.size(), 1);
|
||||
|
||||
// If the driver doesn't return the query size fetchMore() causes the
|
||||
// model to grow and new signals are emitted
|
||||
QSignalSpy rowsInsertedSpy(&model, SIGNAL(rowsInserted(QModelIndex,int,int)));
|
||||
if (!db.driver()->hasFeature(QSqlDriver::QuerySize)) {
|
||||
model.fetchMore();
|
||||
int newRowCount = model.rowCount();
|
||||
QCOMPARE(rowsInsertedSpy.value(0).value(1).toInt(), rowCount);
|
||||
QCOMPARE(rowsInsertedSpy.value(0).value(2).toInt(), newRowCount - 1);
|
||||
}
|
||||
}
|
||||
|
||||
// For task 149491: When used with QSortFilterProxyModel, a view and a
|
||||
// database that doesn't support the QuerySize feature, blank rows was
|
||||
// appended if the query returned more than 256 rows and setQuery()
|
||||
// was called more than once. This because an insertion of rows was
|
||||
// triggered at the same time as the model was being cleared.
|
||||
void tst_QSqlQueryModel::withSortFilterProxyModel()
|
||||
{
|
||||
QFETCH(QString, dbName);
|
||||
QSqlDatabase db = QSqlDatabase::database(dbName);
|
||||
CHECK_DATABASE(db);
|
||||
|
||||
if (db.driver()->hasFeature(QSqlDriver::QuerySize))
|
||||
QSKIP("Test applies only for drivers not reporting the query size.");
|
||||
|
||||
QSqlQueryModel model;
|
||||
model.setQuery(QSqlQuery("SELECT * FROM " + qTableName("test3", __FILE__, db), db));
|
||||
QSortFilterProxyModel proxy;
|
||||
proxy.setSourceModel(&model);
|
||||
|
||||
QTableView view;
|
||||
view.setModel(&proxy);
|
||||
|
||||
QSignalSpy modelAboutToBeResetSpy(&model, SIGNAL(modelAboutToBeReset()));
|
||||
QSignalSpy modelResetSpy(&model, SIGNAL(modelReset()));
|
||||
QSignalSpy modelRowsInsertedSpy(&model, SIGNAL(rowsInserted(QModelIndex,int,int)));
|
||||
model.setQuery(QSqlQuery("SELECT * FROM " + qTableName("test3", __FILE__, db), db));
|
||||
view.scrollToBottom();
|
||||
|
||||
QTestEventLoop::instance().enterLoop(1);
|
||||
|
||||
QCOMPARE(proxy.rowCount(), 511);
|
||||
|
||||
// setQuery() resets the model accompanied by begin and end signals
|
||||
QCOMPARE(modelAboutToBeResetSpy.size(), 1);
|
||||
QCOMPARE(modelResetSpy.size(), 1);
|
||||
|
||||
// The call to scrollToBottom() forces the model to fetch additional rows.
|
||||
QCOMPARE(modelRowsInsertedSpy.size(), 1);
|
||||
QCOMPARE(modelRowsInsertedSpy.value(0).value(1).toInt(), 256);
|
||||
QCOMPARE(modelRowsInsertedSpy.value(0).value(2).toInt(), 510);
|
||||
}
|
||||
|
||||
// For task 155402: When the model is already empty when setQuery() is called
|
||||
// no rows have to be removed and rowsAboutToBeRemoved and rowsRemoved should
|
||||
// not be emitted.
|
||||
void tst_QSqlQueryModel::setQuerySignalEmission()
|
||||
{
|
||||
QFETCH(QString, dbName);
|
||||
QSqlDatabase db = QSqlDatabase::database(dbName);
|
||||
CHECK_DATABASE(db);
|
||||
|
||||
QSqlQueryModel model;
|
||||
QSignalSpy modelAboutToBeResetSpy(&model, SIGNAL(modelAboutToBeReset()));
|
||||
QSignalSpy modelResetSpy(&model, SIGNAL(modelReset()));
|
||||
|
||||
// First select, the model was empty and no rows had to be removed, but model resets anyway.
|
||||
model.setQuery(QSqlQuery("SELECT * FROM " + qTableName("test", __FILE__, db), db));
|
||||
QCOMPARE(modelAboutToBeResetSpy.size(), 1);
|
||||
QCOMPARE(modelResetSpy.size(), 1);
|
||||
|
||||
// Second select, the model wasn't empty and two rows had to be removed!
|
||||
// setQuery() resets the model accompanied by begin and end signals
|
||||
model.setQuery(QSqlQuery("SELECT * FROM " + qTableName("test", __FILE__, db), db));
|
||||
QCOMPARE(modelAboutToBeResetSpy.size(), 2);
|
||||
QCOMPARE(modelResetSpy.size(), 2);
|
||||
}
|
||||
|
||||
// For task 170783: When the query's result set is empty no rows should be inserted,
|
||||
// i.e. no rowsAboutToBeInserted or rowsInserted signals should be emitted.
|
||||
void tst_QSqlQueryModel::setQueryWithNoRowsInResultSet()
|
||||
{
|
||||
QFETCH(QString, dbName);
|
||||
QSqlDatabase db = QSqlDatabase::database(dbName);
|
||||
CHECK_DATABASE(db);
|
||||
|
||||
QSqlQueryModel model;
|
||||
QSignalSpy modelRowsAboutToBeInsertedSpy(&model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)));
|
||||
QSignalSpy modelRowsInsertedSpy(&model, SIGNAL(rowsInserted(QModelIndex,int,int)));
|
||||
|
||||
// The query's result set will be empty so no signals should be emitted!
|
||||
QSqlQuery query(db);
|
||||
QVERIFY_SQL(query, exec("SELECT * FROM " + qTableName("test", __FILE__, db) + " where 0 = 1"));
|
||||
model.setQuery(std::move(query));
|
||||
QCOMPARE(modelRowsAboutToBeInsertedSpy.size(), 0);
|
||||
QCOMPARE(modelRowsInsertedSpy.size(), 0);
|
||||
}
|
||||
|
||||
class NestedResetsTest: public QSqlQueryModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
NestedResetsTest(QObject *parent = nullptr) : QSqlQueryModel(parent), gotAboutToBeReset(false), gotReset(false)
|
||||
{
|
||||
connect(this, SIGNAL(modelAboutToBeReset()), this, SLOT(modelAboutToBeResetSlot()));
|
||||
connect(this, SIGNAL(modelReset()), this, SLOT(modelResetSlot()));
|
||||
}
|
||||
|
||||
void testNested()
|
||||
{
|
||||
// Only the outermost beginResetModel/endResetModel should
|
||||
// emit signals.
|
||||
gotAboutToBeReset = gotReset = false;
|
||||
beginResetModel();
|
||||
QCOMPARE(gotAboutToBeReset, true);
|
||||
QCOMPARE(gotReset, false);
|
||||
|
||||
gotAboutToBeReset = gotReset = false;
|
||||
beginResetModel();
|
||||
QCOMPARE(gotAboutToBeReset, false);
|
||||
QCOMPARE(gotReset, false);
|
||||
|
||||
gotAboutToBeReset = gotReset = false;
|
||||
endResetModel();
|
||||
QCOMPARE(gotAboutToBeReset, false);
|
||||
QCOMPARE(gotReset, false);
|
||||
|
||||
gotAboutToBeReset = gotReset = false;
|
||||
endResetModel();
|
||||
QCOMPARE(gotAboutToBeReset, false);
|
||||
QCOMPARE(gotReset, true);
|
||||
}
|
||||
|
||||
void testClear() // QTBUG-49404: Basic test whether clear() emits signals.
|
||||
{
|
||||
gotAboutToBeReset = gotReset = false;
|
||||
clear();
|
||||
QVERIFY(gotAboutToBeReset);
|
||||
QVERIFY(gotReset);
|
||||
}
|
||||
|
||||
private slots:
|
||||
void modelAboutToBeResetSlot() { gotAboutToBeReset = true; }
|
||||
void modelResetSlot() { gotReset = true; }
|
||||
|
||||
private:
|
||||
bool gotAboutToBeReset;
|
||||
bool gotReset;
|
||||
};
|
||||
|
||||
void tst_QSqlQueryModel::nestedResets()
|
||||
{
|
||||
QFETCH(QString, dbName);
|
||||
QSqlDatabase db = QSqlDatabase::database(dbName);
|
||||
CHECK_DATABASE(db);
|
||||
|
||||
NestedResetsTest t;
|
||||
t.testClear();
|
||||
t.testNested();
|
||||
}
|
||||
|
||||
// For task 180617
|
||||
// According to the task, several specific duplicate SQL queries would cause
|
||||
// multiple empty grid lines to be visible in the view
|
||||
void tst_QSqlQueryModel::task_180617()
|
||||
{
|
||||
QFETCH(QString, dbName);
|
||||
QSqlDatabase db = QSqlDatabase::database(dbName);
|
||||
CHECK_DATABASE(db);
|
||||
const QString test3(qTableName("test3", __FILE__, db));
|
||||
|
||||
QTableView view;
|
||||
QCOMPARE(view.columnAt(0), -1);
|
||||
QCOMPARE(view.rowAt(0), -1);
|
||||
|
||||
QSqlQueryModel model;
|
||||
model.setQuery( "SELECT TOP 0 * FROM " + test3, db );
|
||||
view.setModel(&model);
|
||||
|
||||
bool error = false;
|
||||
// Usually a syntax error
|
||||
if (model.lastError().isValid()) // usually a syntax error
|
||||
error = true;
|
||||
|
||||
QCOMPARE(view.columnAt(0), (error)?-1:0 );
|
||||
QCOMPARE(view.rowAt(0), -1);
|
||||
|
||||
model.setQuery( "SELECT TOP 0 * FROM " + test3, db );
|
||||
model.setQuery( "SELECT TOP 0 * FROM " + test3, db );
|
||||
model.setQuery( "SELECT TOP 0 * FROM " + test3, db );
|
||||
model.setQuery( "SELECT TOP 0 * FROM " + test3, db );
|
||||
|
||||
QCOMPARE(view.columnAt(0), (error)?-1:0 );
|
||||
QCOMPARE(view.rowAt(0), -1);
|
||||
}
|
||||
|
||||
void tst_QSqlQueryModel::task_QTBUG_4963_setHeaderDataWithProxyModel()
|
||||
{
|
||||
QSqlQueryModel plainModel;
|
||||
QSortFilterProxyModel proxyModel;
|
||||
proxyModel.setSourceModel(&plainModel);
|
||||
QVERIFY(!plainModel.setHeaderData(0, Qt::Horizontal, QObject::tr("ID")));
|
||||
// And it should not crash.
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QSqlQueryModel)
|
||||
#include "tst_qsqlquerymodel.moc"
|
16
tests/auto/sql/models/qsqlrelationaldelegate/CMakeLists.txt
Normal file
16
tests/auto/sql/models/qsqlrelationaldelegate/CMakeLists.txt
Normal file
@ -0,0 +1,16 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_qsqlrelationaldelegate Test:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_test(tst_qsqlrelationaldelegate
|
||||
SOURCES
|
||||
tst_qsqlrelationaldelegate.cpp
|
||||
LIBRARIES
|
||||
Qt::CorePrivate
|
||||
Qt::Sql
|
||||
Qt::SqlPrivate
|
||||
Qt::Widgets
|
||||
)
|
@ -0,0 +1,166 @@
|
||||
// Copyright (C) 2018 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
|
||||
#include <QTest>
|
||||
#include <QtSql/QtSql>
|
||||
#include <QTableView>
|
||||
#include <QComboBox>
|
||||
|
||||
#include "../../kernel/qsqldatabase/tst_databases.h"
|
||||
|
||||
class tst_QSqlRelationalDelegate : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
void recreateTestTables(QSqlDatabase);
|
||||
|
||||
tst_Databases dbs;
|
||||
tst_QSqlRelationalDelegate();
|
||||
|
||||
public slots:
|
||||
void initTestCase_data();
|
||||
void initTestCase();
|
||||
void cleanupTestCase();
|
||||
void init();
|
||||
void cleanup();
|
||||
|
||||
private slots:
|
||||
void comboBoxEditor();
|
||||
private:
|
||||
void dropTestTables(QSqlDatabase db);
|
||||
};
|
||||
|
||||
tst_QSqlRelationalDelegate::tst_QSqlRelationalDelegate()
|
||||
{
|
||||
}
|
||||
|
||||
void tst_QSqlRelationalDelegate::initTestCase_data()
|
||||
{
|
||||
QVERIFY(dbs.open());
|
||||
if (dbs.fillTestTable() == 0)
|
||||
QSKIP("No database drivers are available in this Qt configuration");
|
||||
}
|
||||
|
||||
void tst_QSqlRelationalDelegate::recreateTestTables(QSqlDatabase db)
|
||||
{
|
||||
const auto reltest1 = qTableName("reltest1", __FILE__, db);
|
||||
const auto reltest2 = qTableName("reltest2", __FILE__, db);
|
||||
|
||||
dropTestTables(db);
|
||||
|
||||
QSqlQuery q(db);
|
||||
const auto idField = db.driver()->escapeIdentifier(QLatin1String("id"), QSqlDriver::FieldName);
|
||||
const auto nameField = db.driver()->escapeIdentifier(QLatin1String("name"), QSqlDriver::FieldName);
|
||||
const auto titleKeyField = db.driver()->escapeIdentifier(QLatin1String("title_key"),
|
||||
QSqlDriver::FieldName);
|
||||
const auto anotherTitleField = db.driver()->escapeIdentifier(QLatin1String("another_title_key"),
|
||||
QSqlDriver::FieldName);
|
||||
const auto titleField = db.driver()->escapeIdentifier(QLatin1String("title"),
|
||||
QSqlDriver::FieldName);
|
||||
QVERIFY_SQL(q, exec("create table " + reltest1 +
|
||||
" (" + idField + " int not null primary key, " + nameField + " varchar(20), " +
|
||||
titleKeyField + " int, " + anotherTitleField + "int)"));
|
||||
QVERIFY_SQL(q, exec("insert into " + reltest1 + " values(1, 'harry', 1, 2)"));
|
||||
QVERIFY_SQL(q, exec("insert into " + reltest1 + " values(2, 'trond', 2, 1)"));
|
||||
QVERIFY_SQL(q, exec("insert into " + reltest1 + " values(3, 'vohi', 1, 2)"));
|
||||
QVERIFY_SQL(q, exec("insert into " + reltest1 + " values(4, 'boris', 2, 2)"));
|
||||
QVERIFY_SQL(q, exec("insert into " + reltest1 + " values(5, 'nat', NULL, NULL)"));
|
||||
QVERIFY_SQL(q, exec("insert into " + reltest1 + " values(6, 'ale', NULL, 2)"));
|
||||
|
||||
QVERIFY_SQL(q, exec("create table " + reltest2 + " (" + idField + " int not null primary key, "
|
||||
+ titleKeyField + " varchar(20))"));
|
||||
QVERIFY_SQL(q, exec("insert into " + reltest2 + " values(1, 'herr')"));
|
||||
QVERIFY_SQL(q, exec("insert into " + reltest2 + " values(2, 'mister')"));
|
||||
}
|
||||
|
||||
void tst_QSqlRelationalDelegate::initTestCase()
|
||||
{
|
||||
foreach (const QString &dbname, dbs.dbNames) {
|
||||
QSqlDatabase db=QSqlDatabase::database(dbname);
|
||||
QSqlDriver::DbmsType dbType = tst_Databases::getDatabaseType(db);
|
||||
if (dbType == QSqlDriver::Interbase) {
|
||||
db.exec("SET DIALECT 3");
|
||||
} else if (dbType == QSqlDriver::MSSqlServer) {
|
||||
db.exec("SET ANSI_DEFAULTS ON");
|
||||
db.exec("SET IMPLICIT_TRANSACTIONS OFF");
|
||||
} else if (dbType == QSqlDriver::PostgreSQL) {
|
||||
db.exec("set client_min_messages='warning'");
|
||||
}
|
||||
recreateTestTables(db);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QSqlRelationalDelegate::cleanupTestCase()
|
||||
{
|
||||
foreach (const QString &dbName, dbs.dbNames) {
|
||||
QSqlDatabase db = QSqlDatabase::database(dbName);
|
||||
CHECK_DATABASE(db);
|
||||
dropTestTables(QSqlDatabase::database(dbName));
|
||||
}
|
||||
dbs.close();
|
||||
}
|
||||
|
||||
void tst_QSqlRelationalDelegate::dropTestTables(QSqlDatabase db)
|
||||
{
|
||||
QStringList tableNames = { qTableName("reltest1", __FILE__, db), qTableName("reltest2", __FILE__, db) };
|
||||
tst_Databases::safeDropTables(db, tableNames);
|
||||
}
|
||||
|
||||
void tst_QSqlRelationalDelegate::init()
|
||||
{
|
||||
}
|
||||
|
||||
void tst_QSqlRelationalDelegate::cleanup()
|
||||
{
|
||||
}
|
||||
|
||||
void tst_QSqlRelationalDelegate::comboBoxEditor()
|
||||
{
|
||||
QFETCH_GLOBAL(QString, dbName);
|
||||
QSqlDatabase db = QSqlDatabase::database(dbName);
|
||||
CHECK_DATABASE(db);
|
||||
|
||||
const auto reltest1 = qTableName("reltest1", __FILE__, db);
|
||||
const auto reltest2 = qTableName("reltest2", __FILE__, db);
|
||||
const auto idField = db.driver()->escapeIdentifier(QLatin1String("id"), QSqlDriver::FieldName);
|
||||
const auto nameField = db.driver()->escapeIdentifier(QLatin1String("name"), QSqlDriver::FieldName);
|
||||
const auto titleKeyField = db.driver()->escapeIdentifier(QLatin1String("title_key"),
|
||||
QSqlDriver::FieldName);
|
||||
QTableView tv;
|
||||
QSqlRelationalTableModel model(0, db);
|
||||
model.setEditStrategy(QSqlTableModel::OnManualSubmit);
|
||||
model.setTable(reltest1);
|
||||
model.setRelation(2, QSqlRelation(reltest2, idField, titleKeyField));
|
||||
model.setRelation(3, QSqlRelation(reltest2, idField, titleKeyField));
|
||||
tv.setModel(&model);
|
||||
QVERIFY_SQL(model, select());
|
||||
|
||||
QSqlRelationalDelegate delegate;
|
||||
tv.setItemDelegate(&delegate);
|
||||
tv.show();
|
||||
QVERIFY(QTest::qWaitForWindowActive(&tv));
|
||||
|
||||
QModelIndex index = model.index(0, 2);
|
||||
tv.setCurrentIndex(index);
|
||||
tv.edit(index);
|
||||
QList<QComboBox*> comboBoxes = tv.viewport()->findChildren<QComboBox *>();
|
||||
QCOMPARE(comboBoxes.size(), 1);
|
||||
|
||||
QComboBox *editor = comboBoxes.at(0);
|
||||
QCOMPARE(editor->currentText(), "herr");
|
||||
QTest::keyClick(editor, Qt::Key_Down);
|
||||
QTest::keyClick(editor, Qt::Key_Enter);
|
||||
QCOMPARE(editor->currentText(), "mister");
|
||||
QTest::keyClick(tv.viewport(), Qt::Key_Tab);
|
||||
QVERIFY_SQL(model, submitAll());
|
||||
|
||||
QSqlQuery qry(db);
|
||||
QVERIFY_SQL(qry, exec("SELECT " + titleKeyField + " FROM " + reltest1 + " WHERE " + idField + "=1"));
|
||||
QVERIFY(qry.next());
|
||||
QCOMPARE(qry.value(0).toString(), "2");
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QSqlRelationalDelegate)
|
||||
#include "tst_qsqlrelationaldelegate.moc"
|
@ -0,0 +1,15 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_qsqlrelationaltablemodel Test:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_test(tst_qsqlrelationaltablemodel
|
||||
SOURCES
|
||||
tst_qsqlrelationaltablemodel.cpp
|
||||
LIBRARIES
|
||||
Qt::CorePrivate
|
||||
Qt::Sql
|
||||
Qt::SqlPrivate
|
||||
)
|
File diff suppressed because it is too large
Load Diff
15
tests/auto/sql/models/qsqltablemodel/CMakeLists.txt
Normal file
15
tests/auto/sql/models/qsqltablemodel/CMakeLists.txt
Normal file
@ -0,0 +1,15 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_qsqltablemodel Test:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_test(tst_qsqltablemodel
|
||||
SOURCES
|
||||
tst_qsqltablemodel.cpp
|
||||
LIBRARIES
|
||||
Qt::CorePrivate
|
||||
Qt::Sql
|
||||
Qt::SqlPrivate
|
||||
)
|
2190
tests/auto/sql/models/qsqltablemodel/tst_qsqltablemodel.cpp
Normal file
2190
tests/auto/sql/models/qsqltablemodel/tst_qsqltablemodel.cpp
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user