diff options
author | Lars Knoll <lars.knoll@nokia.com> | 2009-03-23 09:18:55 (GMT) |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2009-03-23 09:18:55 (GMT) |
commit | e5fcad302d86d316390c6b0f62759a067313e8a9 (patch) | |
tree | c2afbf6f1066b6ce261f14341cf6d310e5595bc1 /tests/auto/q3sqlcursor | |
download | Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.zip Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.tar.gz Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.tar.bz2 |
Long live Qt 4.5!
Diffstat (limited to 'tests/auto/q3sqlcursor')
-rw-r--r-- | tests/auto/q3sqlcursor/.gitignore | 1 | ||||
-rw-r--r-- | tests/auto/q3sqlcursor/q3sqlcursor.pro | 9 | ||||
-rw-r--r-- | tests/auto/q3sqlcursor/tst_q3sqlcursor.cpp | 779 |
3 files changed, 789 insertions, 0 deletions
diff --git a/tests/auto/q3sqlcursor/.gitignore b/tests/auto/q3sqlcursor/.gitignore new file mode 100644 index 0000000..5243db9 --- /dev/null +++ b/tests/auto/q3sqlcursor/.gitignore @@ -0,0 +1 @@ +tst_qsqlcursor diff --git a/tests/auto/q3sqlcursor/q3sqlcursor.pro b/tests/auto/q3sqlcursor/q3sqlcursor.pro new file mode 100644 index 0000000..2844540 --- /dev/null +++ b/tests/auto/q3sqlcursor/q3sqlcursor.pro @@ -0,0 +1,9 @@ +load(qttest_p4) +SOURCES += tst_q3sqlcursor.cpp + +QT += sql qt3support + +win32:LIBS += -lws2_32 + + + diff --git a/tests/auto/q3sqlcursor/tst_q3sqlcursor.cpp b/tests/auto/q3sqlcursor/tst_q3sqlcursor.cpp new file mode 100644 index 0000000..c06485d --- /dev/null +++ b/tests/auto/q3sqlcursor/tst_q3sqlcursor.cpp @@ -0,0 +1,779 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> +#include <q3sqlcursor.h> +#include <qsqlfield.h> +#include <qsqldriver.h> + + +#include "../qsqldatabase/tst_databases.h" + + +//TESTED_FILES= + +QT_FORWARD_DECLARE_CLASS(QSqlDatabase) + +class tst_Q3SqlCursor : public QObject +{ +Q_OBJECT + +public: + tst_Q3SqlCursor(); + virtual ~tst_Q3SqlCursor(); + + +public slots: + void initTestCase(); + void cleanupTestCase(); + void init(); + void cleanup(); +private slots: + void copyConstructor_data() { generic_data(); } + void copyConstructor(); + + void value_data() { generic_data(); } + void value(); + void primaryIndex_data() { generic_data(); } + void primaryIndex(); + void insert_data() { generic_data(); } + void insert(); + void select_data() { generic_data(); } + void select(); + void setFilter_data() { generic_data(); } + void setFilter(); + void setName_data() { generic_data(); } + void setName(); + + // problem specific tests + void unicode_data() { generic_data(); } + void unicode(); + void precision_data() { generic_data(); } + void precision(); + void insertORA_data(); + void insertORA(); + void batchInsert_data() { generic_data(); } + void batchInsert(); + void insertSpecial_data() { generic_data(); } + void insertSpecial(); + void updateNoPK_data() { generic_data(); } + void updateNoPK(); + void insertFieldNameContainsWS_data() { generic_data(); } + void insertFieldNameContainsWS(); // For task 117996 + +private: + void generic_data(); + void createTestTables( QSqlDatabase db ); + void dropTestTables( QSqlDatabase db ); + void populateTestTables( QSqlDatabase db ); + + tst_Databases dbs; +}; + +tst_Q3SqlCursor::tst_Q3SqlCursor() +{ +} + +tst_Q3SqlCursor::~tst_Q3SqlCursor() +{ +} + +void tst_Q3SqlCursor::generic_data() +{ + if ( dbs.fillTestTable() == 0 ) + QSKIP( "No database drivers are available in this Qt configuration", SkipAll ); +} + +void tst_Q3SqlCursor::createTestTables( QSqlDatabase db ) +{ + if ( !db.isValid() ) + return; + QSqlQuery q( db ); + // please never ever change this table; otherwise fix all tests ;) + if ( tst_Databases::isMSAccess( db ) ) { + QVERIFY_SQL(q, exec( "create table " + qTableName( "qtest" ) + " ( id int not null, t_varchar varchar(40) not null," + "t_char char(40), t_numeric number, primary key (id, t_varchar) )" )); + } else { + QVERIFY_SQL(q, exec( "create table " + qTableName( "qtest" ) + " ( id int not null, t_varchar varchar(40) not null," + "t_char char(40), t_numeric numeric(6, 3), primary key (id, t_varchar) )" )); + } + + if ( tst_Databases::isSqlServer( db ) ) { + //workaround for SQL SERVER since he can store unicode only in nvarchar fields + QVERIFY_SQL(q, exec("create table " + qTableName("qtest_unicode") + " (id int not null, " + "t_varchar nvarchar(40) not null, t_char nchar(40) )" )); + } else { + QVERIFY_SQL(q, exec("create table " + qTableName("qtest_unicode") + " (id int not null, " + "t_varchar varchar(40) not null," "t_char char(40))" )); + } + + if (tst_Databases::isMSAccess(db)) { + QVERIFY_SQL(q, exec("create table " + qTableName("qtest_precision") + " (col1 number)")); + } else if (db.driverName().startsWith("QIBASE")) { + QVERIFY_SQL(q, exec("create table " + qTableName("qtest_precision") + " (col1 numeric(15, 14))")); + } else { + QVERIFY_SQL(q, exec("create table " + qTableName("qtest_precision") + " (col1 numeric(15, 14))")); + } +} + +void tst_Q3SqlCursor::dropTestTables( QSqlDatabase db ) +{ + if ( !db.isValid() ) + return; + QStringList tableNames; + tableNames << qTableName( "qtest" ) + << qTableName( "qtest_unicode" ) + << qTableName( "qtest_precision" ) + << qTableName( "qtest_ovchar" ) + << qTableName( "qtest_onvchar" ) + << qTableName( "qtestPK" ); + tst_Databases::safeDropTables( db, tableNames ); +} + +void tst_Q3SqlCursor::populateTestTables( QSqlDatabase db ) +{ + if (!db.isValid()) + return; + QSqlQuery q( db ); + + q.exec( "delete from " + qTableName( "qtest" ) ); //not fatal + QVERIFY_SQL(q, prepare("insert into " + qTableName( "qtest" ) + " (id, t_varchar, t_char, t_numeric) values (?, ?, ?, ?)")); + q.addBindValue(QVariantList() << 0 << 1 << 2 << 3); + q.addBindValue(QVariantList() << "VarChar0" << "VarChar1" << "VarChar2" << "VarChar3"); + q.addBindValue(QVariantList() << "Char0" << "Char1" << "Char2" << "Char3"); + q.addBindValue(QVariantList() << 1.1 << 2.2 << 3.3 << 4.4); + QVERIFY_SQL(q, execBatch()); +} + +void tst_Q3SqlCursor::initTestCase() +{ + 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_Q3SqlCursor::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_Q3SqlCursor::init() +{ +} + +void tst_Q3SqlCursor::cleanup() +{ + QFETCH( QString, dbName ); + QSqlDatabase db = QSqlDatabase::database( dbName ); + CHECK_DATABASE( db ); + if ( QTest::currentTestFailed() ) { + //since Oracle ODBC totally craps out on error, we init again + db.close(); + db.open(); + } +} + +void tst_Q3SqlCursor::copyConstructor() +{ + QFETCH( QString, dbName ); + QSqlDatabase db = QSqlDatabase::database( dbName ); + CHECK_DATABASE( db ); + + Q3SqlCursor cur2; + { + Q3SqlCursor cur( qTableName( "qtest" ), true, db ); + QVERIFY_SQL(cur, select( cur.index( QString("id") ) )); + cur2 = Q3SqlCursor( cur ); + // let "cur" run out of scope... + } + + QSqlRecord* rec = cur2.primeUpdate(); + Q_ASSERT( rec ); + QCOMPARE( (int)rec->count(), 4 ); + + int i = 0; + while ( cur2.next() ) { + QVERIFY( cur2.value("id").toInt() == i ); + i++; + } +} + +void tst_Q3SqlCursor::value() +{ + QFETCH( QString, dbName ); + QSqlDatabase db = QSqlDatabase::database( dbName ); + CHECK_DATABASE( db ); + + Q3SqlCursor cur( qTableName( "qtest" ), true, db ); + QVERIFY_SQL(cur, select( cur.index( QString("id") ) )); + int i = 0; + while ( cur.next() ) { + QCOMPARE(cur.value("id").toInt(), i); + i++; + } +} + +void tst_Q3SqlCursor::primaryIndex() +{ + QFETCH( QString, dbName ); + QSqlDatabase db = QSqlDatabase::database( dbName ); + CHECK_DATABASE( db ); + + Q3SqlCursor cur( qTableName( "qtest" ), true, db ); + QSqlIndex index = cur.primaryIndex(); + if ( tst_Databases::isMSAccess( db ) ) { + QCOMPARE( index.fieldName(1).upper(), QString( "ID" ) ); + QCOMPARE( index.fieldName(0).upper(), QString( "T_VARCHAR" ) ); + } else { + QCOMPARE( index.fieldName(0).upper(), QString( "ID" ) ); + QCOMPARE( index.fieldName(1).upper(), QString( "T_VARCHAR" ) ); + } + QVERIFY(!index.isDescending(0)); + QVERIFY(!index.isDescending(1)); +} + +void tst_Q3SqlCursor::insert() +{ + QFETCH( QString, dbName ); + QSqlDatabase db = QSqlDatabase::database( dbName ); + CHECK_DATABASE( db ); + + Q3SqlCursor cur( qTableName( "qtest" ), true, db ); + QSqlRecord* irec = cur.primeInsert(); + QVERIFY( irec != 0 ); + + // check that primeInsert returns a valid QSqlRecord + QCOMPARE( (int)irec->count(), 4 ); + if ( ( irec->field( 0 ).type() != QVariant::Int ) && + ( irec->field( 0 ).type() != QVariant::String ) ) { + QFAIL( QString( "Wrong datatype %1 for field 'ID'" + " (expected Int or String)" ).arg( QVariant::typeToName( irec->field( 0 ).type() ) ) ); + } + QCOMPARE( QVariant::typeToName( irec->field( 1 ).type() ), QVariant::typeToName( QVariant::String ) ); + QCOMPARE( QVariant::typeToName( irec->field( 2 ).type() ), QVariant::typeToName( QVariant::String ) ); + QVERIFY((QVariant::typeToName(irec->field(3).type()) == QVariant::typeToName(QVariant::Double)) || + (QVariant::typeToName(irec->field(3).type()) == QVariant::typeToName(QVariant::String))); + QCOMPARE( irec->field( 0 ).name().upper(), QString( "ID" ) ); + QCOMPARE( irec->field( 1 ).name().upper(), QString( "T_VARCHAR" ) ); + QCOMPARE( irec->field( 2 ).name().upper(), QString( "T_CHAR" ) ); + QCOMPARE( irec->field( 3 ).name().upper(), QString( "T_NUMERIC" ) ); + + irec->setValue( "id", 400 ); + irec->setValue( "t_varchar", "SomeVarChar" ); + irec->setValue( "t_char", "SomeChar" ); + irec->setValue( "t_numeric", 400.400 ); + + QCOMPARE( cur.insert(), 1 ); + + // restore old test-tables + populateTestTables( db ); +} + +void tst_Q3SqlCursor::insertSpecial() +{ + QFETCH( QString, dbName ); + QSqlDatabase db = QSqlDatabase::database( dbName ); + CHECK_DATABASE( db ); + + Q3SqlCursor cur( qTableName( "qtest" ), true, db ); + QSqlRecord* irec = cur.primeInsert(); + QVERIFY( irec != 0 ); + + QStringList strings; + strings << "StringWith'ATick" << "StringWith\"Doublequote" << "StringWith\\Backslash" << "StringWith~Tilde"; + strings << "StringWith%Percent" << "StringWith_Underscore" << "StringWith[SquareBracket" << "StringWith{Brace"; + strings << "StringWith''DoubleTick" << "StringWith\\Lot\\of\\Backslash" << "StringWith\"lot\"of\"quotes\""; + strings << "'StartsAndEndsWithTick'" << "\"StartsAndEndsWithQuote\""; + strings << "StringWith\nCR" << "StringWith\n\rCRLF"; + + int i = 800; + + // INSERT the strings + QStringList::Iterator it; + for ( it = strings.begin(); it != strings.end(); ++it ) { + QSqlRecord* irec = cur.primeInsert(); + QVERIFY( irec != 0 ); + irec->setValue( "id", i ); + irec->setValue( "t_varchar", (*it) ); + irec->setValue( "t_char", (*it) ); + irec->setValue( "t_numeric", (double)i ); + ++i; + QCOMPARE( cur.insert(), 1 ); + } + + QVERIFY( cur.select( "id >= 800 and id < 900" ) ); + + int i2 = 800; + while( cur.next() ) { + QCOMPARE( cur.value( "id" ).toInt(), i2 ); + QCOMPARE( cur.value( "t_varchar" ).toString().stripWhiteSpace(), strings.at( i2 - 800 ) ); + QCOMPARE( cur.value( "t_char" ).toString().stripWhiteSpace(), strings.at( i2 - 800 ) ); + QCOMPARE( cur.value( "t_numeric" ).toDouble(), (double)i2 ); + ++i2; + } + QCOMPARE( i, i2 ); + + populateTestTables( db ); +} + +void tst_Q3SqlCursor::batchInsert() +{ + QFETCH( QString, dbName ); + QSqlDatabase db = QSqlDatabase::database( dbName ); + CHECK_DATABASE( db ); + + QSqlQuery q( db ); + q.exec( "delete from " + qTableName( "qtest" ) ); + + Q3SqlCursor cur( qTableName( "qtest" ), true, db ); + + int i = 0; + for ( ; i < 100; ++i ) { + QSqlRecord* irec = cur.primeInsert(); + Q_ASSERT( irec ); + irec->setValue( "id", i ); + irec->setValue( "t_varchar", "blah" ); + irec->setValue( "t_char", "blah" ); + irec->setValue( "t_numeric", 1.1 ); + if ( db.driverName().startsWith( "QSQLITE" ) ) { + QVERIFY( cur.insert( true ) ); + } else { + QCOMPARE( cur.insert( true ), 1 ); + } + } + + for ( ; i < 200; ++i ) { + QSqlRecord* irec = cur.primeInsert(); + Q_ASSERT( irec ); + irec->setValue( "id", i ); + irec->setValue( "t_varchar", "blah" ); + irec->setValue( "t_char", "blah" ); + irec->setValue( "t_numeric", 1.1 ); + if ( db.driverName().startsWith( "QSQLITE" ) ) { + QVERIFY( cur.insert( false ) ); + } else { + QCOMPARE( cur.insert( false ), 1 ); + } + } + + i = 0; + QVERIFY_SQL(q, exec( "select * from " + qTableName( "qtest" ) + " order by id" )); + while ( q.next() ) { + QCOMPARE( q.value( 0 ).toInt(), i ); + i++; + } + + QCOMPARE( i, 200 ); + + populateTestTables( db ); +} + +static QString dumpUtf8( const QString& str ) +{ + QString res; + for ( int i = 0; i < (int)str.length(); ++i ) { + res += "0x" + QString::number( str[ i ].unicode(), 16 ) + ' '; + } + return res; +} + +void tst_Q3SqlCursor::insertORA_data() +{ + if ( dbs.fillTestTable( "QOCI" ) == 0 ) + QSKIP( "No Oracle database drivers are available in this Qt configuration", SkipAll ); +} + +void tst_Q3SqlCursor::insertORA() +{ + QFETCH( QString, dbName ); + QSqlDatabase db = QSqlDatabase::database( dbName ); + CHECK_DATABASE( db ); + + if (tst_Databases::getOraVersion(db) < 9) + QSKIP("Need Oracle >= 9", SkipSingle); + + /****** CHARSET TEST ******/ + + QSqlQuery q( db ); + QVERIFY_SQL(q, exec( "create table " + qTableName( "qtest_ovchar" ) + " ( id int primary key, t_char varchar(40) )" )); + + static const QString val1( "blah1" ); + + Q3SqlCursor cur ( qTableName( "qtest_ovchar" ), true, db ); + QSqlRecord* irec = cur.primeInsert(); + irec->setValue( "id", 1 ); + irec->setValue( "t_char", val1 ); + QVERIFY( cur.insert() ); + + QVERIFY_SQL(cur, select()); + QVERIFY( cur.next() ); + if ( cur.value( "t_char" ).toString() != val1 ) + qDebug( QString( "Wrong value for t_char: expected '%1', got '%2'" ).arg( val1 ).arg( + cur.value( "t_char" ).toString() ) ); + + static const unsigned short utf8arr[] = { 0xd792,0xd79c,0xd792,0xd79c,0xd799,0x00 }; + static const QString utf8str = QString::fromUcs2( utf8arr ); + + irec = cur.primeInsert(); + irec->setValue( "id", 2 ); + irec->setValue( "t_char", utf8str ); + QVERIFY( cur.insert() ); + + QVERIFY_SQL(cur, select( "id=2" )); + QVERIFY( cur.next() ); + + // until qtest knows non-fatal errors we use qDebug instead + if ( cur.value( "t_char" ).toString() != utf8str ) + qDebug( QString( "Wrong value for t_char: expected '%1', got '%2'" ).arg( dumpUtf8 ( utf8str ) ).arg( + dumpUtf8( cur.value( "t_char" ).toString() ) ) ); + + /****** NCHARSET TEST ********/ + + QVERIFY_SQL(q, exec( "create table " + qTableName( "qtest_onvchar" ) + " ( id int primary key, t_nchar nvarchar2(40) )" )); + + Q3SqlCursor cur2 ( qTableName( "qtest_onvchar" ), true, db ); + irec = cur2.primeInsert(); + irec->setValue( "id", 1 ); + irec->setValue( "t_nchar", val1 ); + QVERIFY( cur2.insert() ); + + QVERIFY_SQL(cur2, select()); + QVERIFY( cur2.next() ); + if ( cur2.value( "t_nchar" ).toString() != val1 ) + qDebug( QString( "Wrong value for t_nchar: expected '%1', got '%2'" ).arg( val1 ).arg( + cur2.value( "t_nchar" ).toString() ) ); + + irec = cur2.primeInsert(); + irec->setValue( "id", 2 ); + irec->setValue( "t_nchar", utf8str ); + QVERIFY( cur2.insert() ); + + QVERIFY_SQL(cur2, select( "id=2" )); + QVERIFY( cur2.next() ); + + // until qtest knows non-fatal errors we use qDebug instead + if ( cur2.value( "t_nchar" ).toString() != utf8str ) + qDebug( QString( "Wrong value for t_nchar: expected '%1', got '%2'" ).arg( dumpUtf8( utf8str ) ).arg( + dumpUtf8( cur2.value( "t_nchar" ).toString() ) ) ); + +} + +void tst_Q3SqlCursor::unicode() +{ + QFETCH( QString, dbName ); + QSqlDatabase db = QSqlDatabase::database( dbName ); + CHECK_DATABASE( db ); + + static const unsigned short utf8arr[] = { 0xd792,0xd79c,0xd792,0xd79c,0xd799,0x20,0xd7a9,0xd799,0x00 }; + static const QString utf8str = QString::fromUcs2( utf8arr ); + if ( !db.driver()->hasFeature( QSqlDriver::Unicode ) ) { + QSKIP( "DBMS not Unicode capable", SkipSingle ); + } + + Q3SqlCursor cur( qTableName( "qtest_unicode" ), true, db ); + QSqlRecord* irec = cur.primeInsert(); + irec->setValue( 0, 500 ); + irec->setValue( 1, utf8str ); + irec->setValue( 2, utf8str ); + QVERIFY_SQL(cur, insert()); + QVERIFY_SQL(cur, select( "id=500" )); + QVERIFY_SQL(cur, next()); + QString res = cur.value( 1 ).asString(); + cur.primeDelete(); + cur.del(); + + if ( res != utf8str ) { + int i; + for ( i = 0; i < (int)res.length(); ++i ) { + if ( res[ i ] != utf8str[ i ] ) + break; + } + QFAIL( QString( "Strings differ at position %1: orig: %2, db: %3" ).arg( i ).arg( utf8str[ i ].unicode(), 0, 16 ).arg( res[ i ].unicode(), 0, 16 ) ); + } + QVERIFY( res == utf8str ); +} + +void tst_Q3SqlCursor::precision() +{ + static const QString precStr = "1.23456789012345"; + static const double precDbl = 2.23456789012345; + + QFETCH( QString, dbName ); + QSqlDatabase db = QSqlDatabase::database( dbName ); + CHECK_DATABASE( db ); + + Q3SqlCursor cur( qTableName( "qtest_precision" ), true, db ); + cur.setTrimmed( "col1", true ); + QSqlRecord* irec = cur.primeInsert(); + irec->setValue( 0, precStr ); + QVERIFY( cur.insert() ); + + irec = cur.primeInsert(); + irec->setValue( 0, precDbl ); + QVERIFY( cur.insert() ); + + QVERIFY_SQL(cur, select()); + QVERIFY( cur.next() ); + QCOMPARE( cur.value( 0 ).asString(), QString( precStr ) ); + QVERIFY( cur.next() ); + QCOMPARE( cur.value( 0 ).asDouble(), precDbl ); +} + +void tst_Q3SqlCursor::setFilter() +{ + QFETCH( QString, dbName ); + QSqlDatabase db = QSqlDatabase::database( dbName ); + CHECK_DATABASE( db ); + + Q3SqlCursor cur( qTableName( "qtest" ), true, db ); + cur.setFilter( "id = 2" ); + + QVERIFY_SQL(cur, select()); + QVERIFY( cur.next() ); + QCOMPARE( cur.value( "id" ).toInt(), 2 ); + QVERIFY( !cur.next() ); + + QVERIFY_SQL(cur, select()); + QVERIFY( cur.next() ); + QCOMPARE( cur.value( "id" ).toInt(), 2 ); + QVERIFY( !cur.next() ); + + QVERIFY_SQL(cur, select( "id = 3" )); + QVERIFY( cur.next() ); + QCOMPARE( cur.value( "id" ).toInt(), 3 ); + QVERIFY( !cur.next() ); + + QVERIFY_SQL(cur, select()); + QVERIFY( cur.next() ); + QCOMPARE( cur.value( "id" ).toInt(), 3 ); + QVERIFY( !cur.next() ); +} + +void tst_Q3SqlCursor::select() +{ + QFETCH( QString, dbName ); + QSqlDatabase db = QSqlDatabase::database( dbName ); + CHECK_DATABASE( db ); + + Q3SqlCursor cur( qTableName( "qtest" ), true, db ); + QVERIFY_SQL(cur, select()); + QVERIFY( cur.next() ); + QVERIFY( cur.next() ); + + Q3SqlCursor cur2( qTableName( "qtest" ), true, db ); + QVERIFY_SQL(cur2, select( "id = 1" )); + QVERIFY( cur2.next() ); + QCOMPARE( cur2.value( 0 ).toInt(), 1 ); + + Q3SqlCursor cur3( qTableName( "qtest" ), true, db ); + QVERIFY_SQL(cur3, select( cur3.primaryIndex( false ) )); + QVERIFY( cur3.next() ); + QVERIFY( cur3.next() ); + QCOMPARE( cur3.value( 0 ).toInt(), 1 ); + + Q3SqlCursor cur4( qTableName( "qtest" ), true, db ); + QSqlIndex idx = cur4.primaryIndex( false ); + QCOMPARE( (int)idx.count(), 2 ); + if ( tst_Databases::isMSAccess( db ) ) { + QCOMPARE( idx.field( 1 ).name().upper(), QString("ID") ); + QCOMPARE( idx.field( 0 ).name().upper(), QString("T_VARCHAR") ); + } else { + QCOMPARE( idx.field( 0 ).name().upper(), QString("ID") ); + QCOMPARE( idx.field( 1 ).name().upper(), QString("T_VARCHAR") ); + } + +#ifdef QT_DEBUG + // for people too stupid to read docs we had to insert this debugging message. + QTest::ignoreMessage(QtDebugMsg, "Q3SqlCursor::setValue(): This will not affect actual database values. Use primeInsert(), primeUpdate() or primeDelete()."); +#endif + cur4.setValue( "id", 1 ); +#ifdef QT_DEBUG + QTest::ignoreMessage(QtDebugMsg, "Q3SqlCursor::setValue(): This will not affect actual database values. Use primeInsert(), primeUpdate() or primeDelete()."); +#endif + cur4.setValue( "t_varchar", "VarChar1" ); + + QVERIFY_SQL(cur4, select( idx, cur4.primaryIndex( false ) )); + QVERIFY( cur4.next() ); + QCOMPARE( cur4.value( 0 ).toInt(), 1 ); +} + +void tst_Q3SqlCursor::setName() +{ + QFETCH( QString, dbName ); + QSqlDatabase db = QSqlDatabase::database( dbName ); + CHECK_DATABASE( db ); + + Q3SqlCursor c2( qTableName( "qtest" ), true, db ); + QCOMPARE( c2.name(), qTableName( "qtest" ) ); + QCOMPARE( c2.fieldName( 0 ).lower(), QString( "id" ) ); + + Q3SqlCursor c( QString(), true, db ); + c.setName( qTableName( "qtest" ) ); + QCOMPARE( c.name(), qTableName( "qtest" ) ); + QCOMPARE( c.fieldName( 0 ).lower(), QString( "id" ) ); + + c.setName( qTableName( "qtest_precision" ) ); + QCOMPARE( c.name(), qTableName( "qtest_precision" ) ); + QCOMPARE( c.fieldName( 0 ).lower(), QString( "col1" ) ); +} + +/* Database independent test */ +void tst_Q3SqlCursor::updateNoPK() +{ + QFETCH( QString, dbName ); + QSqlDatabase db = QSqlDatabase::database( dbName ); + CHECK_DATABASE( db ); + + QSqlQuery q(db); + QVERIFY_SQL(q, exec("create table " + qTableName( "qtestPK" ) + " (id int, name varchar(20), num numeric)")); + + Q3SqlCursor cur(qTableName("qtestPK"), true, db); + QSqlRecord* rec = cur.primeInsert(); + Q_ASSERT(rec); + rec->setNull(0); + rec->setNull(1); + rec->setNull(2); + QVERIFY_SQL(cur, insert() == 1); + if (!db.driver()->hasFeature(QSqlDriver::PreparedQueries)) { + + // Only QPSQL, QMYSQL, QODBC and QOCI drivers currently use escape identifiers for column names + if (db.driverName().startsWith("QPSQL") || + db.driverName().startsWith("QMYSQL") || + db.driverName().startsWith("QODBC") || + db.driverName().startsWith("QOCI")) { + QString query = QString::fromLatin1("insert into " + qTableName("qtestPK") + + " (" + db.driver()->escapeIdentifier("id", QSqlDriver::FieldName) + ',' + + db.driver()->escapeIdentifier("name", QSqlDriver::FieldName) + ',' + + db.driver()->escapeIdentifier("num", QSqlDriver::FieldName) + ')' + + " values (NULL,NULL,NULL)"); + QCOMPARE(cur.lastQuery(), query); + } else { + QCOMPARE(cur.lastQuery(), QString::fromLatin1("insert into " + qTableName("qtestPK") + + " (\"id\",\"name\",\"num\") values (NULL,NULL,NULL)")); + } + } + + rec = cur.primeUpdate(); + Q_ASSERT(rec); + rec->setValue(0, 1); + rec->setNull(1); + rec->setNull(2); + // Sqlite returns 2, don't ask why. + QVERIFY(cur.update() != 0); + QString expect = "update " + qTableName("qtestPK") + + " set id = 1 , name = NULL , num = NULL where " + qTableName("qtestPK") + ".id" + " IS NULL and " + qTableName("qtestPK") + ".name IS NULL and " + + qTableName("qtestPK") + ".num IS NULL"; + if (!db.driver()->hasFeature(QSqlDriver::PreparedQueries)) { + if (!db.driverName().startsWith("QSQLITE")) { + QCOMPARE(cur.lastQuery(), expect); + } + } + QVERIFY(cur.select(cur.index(QString("id")))); + QVERIFY(cur.next()); + QCOMPARE(cur.value("id").toInt(), 1); + QVERIFY(cur.isNull("name")); + QVERIFY(cur.isNull("num")); +} + +// For task 117996: Q3SqlCursor::insert() should not fail even if field names +// contain white spaces. +void tst_Q3SqlCursor::insertFieldNameContainsWS() { + + QFETCH( QString, dbName ); + QSqlDatabase db = QSqlDatabase::database( dbName ); + CHECK_DATABASE( db ); + + // The bugfix (and this test) depends on QSqlDriver::escapeIdentifier(...) + // to be implemented, which is currently only the case for the + // QPSQL, QODBC and QOCI drivers. + if (!db.driverName().startsWith("QPSQL") && + !db.driverName().startsWith("QODBC") && + !db.driverName().startsWith("QOCI")) { + QSKIP("PSQL, QODBC or QOCI specific test", SkipSingle); + return; + } + + QString tableName = qTableName("qtestws"); + + QSqlQuery q(db); + q.exec(QString("DROP TABLE %1").arg(tableName)); + QString query = QString("CREATE TABLE %1 (id int, \"first Name\" varchar(20), " + "lastName varchar(20))"); + QVERIFY_SQL(q, exec(query.arg(tableName))); + + Q3SqlCursor cur(QString("%1").arg(tableName), true, db); + cur.select(); + + QSqlRecord *r = cur.primeInsert(); + r->setValue("id", 1); + r->setValue("firsT NaMe", "Kong"); + r->setValue("lastNaMe", "Harald"); + + QVERIFY(cur.insert() == 1); + + cur.select(); + cur.next(); + + QVERIFY(cur.value(0) == 1); + QCOMPARE(cur.value(1).toString(), QString("Kong")); + QCOMPARE(cur.value(2).toString(), QString("Harald")); + + q.exec(QString("DROP TABLE %1").arg(tableName)); + +} + +QTEST_MAIN(tst_Q3SqlCursor) +#include "tst_q3sqlcursor.moc" |