summaryrefslogtreecommitdiffstats
path: root/tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp')
-rw-r--r--tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp418
1 files changed, 401 insertions, 17 deletions
diff --git a/tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp b/tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp
index 1a0340f153..baf2551dfb 100644
--- a/tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp
+++ b/tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp
@@ -94,6 +94,10 @@ private slots:
// forwardOnly mode need special treatment
void forwardOnly_data() { generic_data(); }
void forwardOnly();
+ void forwardOnlyMultipleResultSet_data() { generic_data(); }
+ void forwardOnlyMultipleResultSet();
+ void psql_forwardOnlyQueryResultsLost_data() { generic_data("QPSQL"); }
+ void psql_forwardOnlyQueryResultsLost();
// bug specific tests
void tds_bitField_data() { generic_data("QTDS"); }
@@ -248,6 +252,9 @@ private slots:
void QTBUG_57138_data() { generic_data("QSQLITE"); }
void QTBUG_57138();
+ void dateTime_data();
+ void dateTime();
+
private:
// returns all database connections
void generic_data(const QString &engine=QString());
@@ -724,6 +731,30 @@ void tst_QSqlQuery::oraOutValues()
q.addBindValue( out, QSql::Out );
QVERIFY_SQL( q, exec() );
QCOMPARE( q.boundValue( 1 ).toString(), QString( "fifibubulalakikikokololo" ) );
+
+ /*** in/outvalue date ***/
+ QVERIFY_SQL(q, exec("create or replace procedure " + tst_outValues + "(x in date, y out date) is\n"
+ "begin\n"
+ " y := x;\n"
+ "end;\n"));
+ QVERIFY(q.prepare("call " + tst_outValues + "(?, ?)"));
+ const QDate date = QDate::currentDate();
+ q.addBindValue(date, QSql::In);
+ q.addBindValue(QVariant(QDate()), QSql::Out);
+ QVERIFY_SQL(q, exec());
+ QCOMPARE(q.boundValue(1).toDate(), date);
+
+ /*** in/outvalue timestamp ***/
+ QVERIFY_SQL(q, exec("create or replace procedure " + tst_outValues + "(x in timestamp, y out timestamp) is\n"
+ "begin\n"
+ " y := x;\n"
+ "end;\n"));
+ QVERIFY(q.prepare("call " + tst_outValues + "(?, ?)"));
+ const QDateTime dt = QDateTime::currentDateTime();
+ q.addBindValue(dt, QSql::In);
+ q.addBindValue(QVariant(QVariant::DateTime), QSql::Out);
+ QVERIFY_SQL(q, exec());
+ QCOMPARE(q.boundValue(1).toDateTime(), dt);
}
void tst_QSqlQuery::oraClob()
@@ -1332,6 +1363,8 @@ void tst_QSqlQuery::forwardOnly()
QVERIFY( q.isForwardOnly() );
QVERIFY( q.at() == QSql::BeforeFirstRow );
QVERIFY_SQL( q, exec( "select * from " + qtest + " order by id" ) );
+ if (!q.isForwardOnly())
+ QSKIP("DBMS doesn't support forward-only queries");
QVERIFY( q.at() == QSql::BeforeFirstRow );
QVERIFY( q.first() );
QCOMPARE( q.at(), 0 );
@@ -1405,6 +1438,209 @@ void tst_QSqlQuery::forwardOnly()
QCOMPARE( q.at(), int( QSql::AfterLastRow ) );
}
+void tst_QSqlQuery::forwardOnlyMultipleResultSet()
+{
+ QFETCH(QString, dbName);
+ QSqlDatabase db = QSqlDatabase::database(dbName);
+ CHECK_DATABASE(db);
+
+ QSqlDriver::DbmsType dbType = tst_Databases::getDatabaseType(db);
+
+ if (!db.driver()->hasFeature(QSqlDriver::MultipleResultSets))
+ QSKIP("DBMS doesn't support multiple result sets");
+
+ QSqlQuery q(db);
+ q.setForwardOnly(true);
+ QVERIFY_SQL(q, exec("select id, t_varchar from " + qtest + " order by id;" // 1.
+ "select id, t_varchar, t_char from " + qtest + " where id<4 order by id;" // 2.
+ "update " + qtest + " set t_varchar='VarChar555' where id=5;" // 3.
+ "select * from " + qtest + " order by id;" // 4.
+ "select * from " + qtest + " where id=5 order by id;" // 5.
+ "select * from " + qtest + " where id=-1 order by id;" // 6.
+ "select * from " + qtest + " order by id")); // 7.
+
+ if (!q.isForwardOnly())
+ QSKIP("DBMS doesn't support forward-only queries");
+
+ // 1. Result set with 2 columns and 5 rows
+ QVERIFY(q.at() == QSql::BeforeFirstRow);
+ QCOMPARE(q.isActive(), true);
+ QCOMPARE(q.isSelect(), true);
+
+ // Test record() of first result set
+ QSqlRecord record = q.record();
+ QCOMPARE(record.count(), 2);
+ QCOMPARE(record.indexOf("id"), 0);
+ QCOMPARE(record.indexOf("t_varchar"), 1);
+ if (dbType != QSqlDriver::PostgreSQL) { // tableName() is not available in forward-only mode of QPSQL
+ QCOMPARE(record.field(0).tableName(), qtest); // BUG: This fails for Microsoft SQL Server 2016 (QODBC), need fix
+ QCOMPARE(record.field(1).tableName(), qtest);
+ }
+
+ // Test navigation
+ QVERIFY(q.first());
+ QCOMPARE(q.at(), 0);
+ QCOMPARE(q.value(0).toInt(), 1);
+
+ QVERIFY(q.next());
+ QCOMPARE(q.at(), 1);
+ QCOMPARE(q.value(0).toInt(), 2);
+
+ QVERIFY(q.seek(3));
+ QCOMPARE(q.at(), 3);
+ QCOMPARE(q.value(0).toInt(), 4);
+
+ QTest::ignoreMessage(QtWarningMsg, "QSqlQuery::seek: cannot seek backwards in a forward only query");
+ QVERIFY(q.first() == false);
+ QCOMPARE(q.at(), 3);
+ QCOMPARE(q.value(0).toInt(), 4);
+
+ QTest::ignoreMessage(QtWarningMsg, "QSqlQuery::seek: cannot seek backwards in a forward only query");
+ QVERIFY(q.previous() == false);
+ QCOMPARE(q.at(), 3);
+ QCOMPARE(q.value(0).toInt(), 4);
+
+ QTest::ignoreMessage(QtWarningMsg, "QSqlQuery::seek: cannot seek backwards in a forward only query");
+ QVERIFY(q.seek(1) == false);
+ QCOMPARE(q.at(), 3);
+ QCOMPARE(q.value(0).toInt(), 4);
+
+ QVERIFY(q.last());
+ QCOMPARE(q.at(), 4);
+
+ // Try move after last row
+ QVERIFY(q.next() == false);
+ QCOMPARE(q.at(), QSql::AfterLastRow);
+ QCOMPARE(q.isActive(), true);
+
+ // 2. Result set with 3 columns and 3 rows
+ QVERIFY(q.nextResult());
+ QVERIFY(q.at() == QSql::BeforeFirstRow);
+ QCOMPARE(q.isActive(), true);
+ QCOMPARE(q.isSelect(), true);
+
+ // Test record() of second result set
+ record = q.record();
+ QCOMPARE(record.count(), 3);
+ QCOMPARE(record.indexOf("id"), 0);
+ QCOMPARE(record.indexOf("t_varchar"), 1);
+ QCOMPARE(record.indexOf("t_char"), 2);
+
+ // Test iteration
+ QVERIFY(q.at() == QSql::BeforeFirstRow);
+ int index = 0;
+ while (q.next()) {
+ QCOMPARE(q.at(), index);
+ QCOMPARE(q.value(0).toInt(), index+1);
+ index++;
+ }
+ QVERIFY(q.at() == QSql::AfterLastRow);
+ QCOMPARE(index, 3);
+
+ // 3. Update statement
+ QVERIFY(q.nextResult());
+ QVERIFY(q.at() == QSql::BeforeFirstRow);
+ QCOMPARE(q.isActive(), true);
+ QCOMPARE(q.isSelect(), false);
+ QCOMPARE(q.numRowsAffected(), 1);
+
+ // 4. Result set with 5 rows
+ QVERIFY(q.nextResult());
+ QVERIFY(q.at() == QSql::BeforeFirstRow);
+ QCOMPARE(q.isActive(), true);
+ QCOMPARE(q.isSelect(), true);
+
+ // Test forward seek(n)
+ QVERIFY(q.seek(2));
+ QCOMPARE(q.at(), 2);
+ QCOMPARE(q.value(0).toInt(), 3);
+
+ // Test value(string)
+ QCOMPARE(q.value("id").toInt(), 3);
+ QCOMPARE(q.value("t_varchar").toString(), "VarChar3");
+ QCOMPARE(q.value("t_char").toString().trimmed(), "Char3");
+
+ // Next 2 rows of current result set will be
+ // discarded by next call of nextResult()
+
+ // 5. Result set with 1 row
+ QVERIFY(q.nextResult());
+ QVERIFY(q.at() == QSql::BeforeFirstRow);
+ QCOMPARE(q.isActive(), true);
+ QCOMPARE(q.isSelect(), true);
+ QVERIFY(q.first());
+ QCOMPARE(q.at(), 0);
+ QCOMPARE(q.value(0).toInt(), 5);
+ QVERIFY(q.next() == false);
+ QVERIFY(q.at() == QSql::AfterLastRow);
+
+ // 6. Result set without rows
+ QVERIFY(q.nextResult());
+ QVERIFY(q.at() == QSql::BeforeFirstRow);
+ QCOMPARE(q.isActive(), true);
+ QCOMPARE(q.isSelect(), true);
+ QVERIFY(q.next() == false);
+
+ // 7. Result set with 5 rows
+ QVERIFY(q.nextResult());
+ QVERIFY(q.at() == QSql::BeforeFirstRow);
+ QCOMPARE(q.isActive(), true);
+ QCOMPARE(q.isSelect(), true);
+
+ // Just skip it, so we move after last result set.
+ QVERIFY(q.nextResult() == false);
+ QVERIFY(q.at() == QSql::BeforeFirstRow);
+ QCOMPARE(q.isActive(), false);
+
+ // See if we can execute another query
+ QVERIFY_SQL(q, exec("select id from " + qtest + " where id=5"));
+ QVERIFY(q.at() == QSql::BeforeFirstRow);
+ QCOMPARE(q.isActive(), true);
+ QCOMPARE(q.isSelect(), true);
+ QVERIFY(q.first());
+ QCOMPARE(q.at(), 0);
+ QCOMPARE(q.value("id").toInt(), 5);
+ QCOMPARE(q.record().count(), 1);
+ QCOMPARE(q.record().indexOf("id"), 0);
+}
+
+void tst_QSqlQuery::psql_forwardOnlyQueryResultsLost()
+{
+ QFETCH(QString, dbName);
+ QSqlDatabase db = QSqlDatabase::database(dbName);
+ CHECK_DATABASE(db);
+
+ QSqlQuery q1(db);
+ q1.setForwardOnly(true);
+ QVERIFY_SQL(q1, exec("select * from " + qtest + " where id<=3 order by id"));
+ if (!q1.isForwardOnly())
+ QSKIP("DBMS doesn't support forward-only queries");
+
+ // Read first row of q1
+ QVERIFY(q1.next());
+ QCOMPARE(q1.at(), 0);
+ QCOMPARE(q1.value(0).toInt(), 1);
+
+ // Executing another query on the same db connection
+ // will cause the query results of q1 to be lost.
+ QSqlQuery q2(db);
+ q2.setForwardOnly(true);
+ QVERIFY_SQL(q2, exec("select * from " + qtest + " where id>3 order by id"));
+
+ QTest::ignoreMessage(QtWarningMsg, "QPSQLDriver::getResult: Query results lost - "
+ "probably discarded on executing another SQL query.");
+
+ // Reading next row of q1 will not possible.
+ QVERIFY(!q1.next());
+ QCOMPARE(q1.at(), QSql::AfterLastRow);
+ QVERIFY(q1.lastError().type() != QSqlError::NoError);
+
+ // See if we can read rows from q2
+ QVERIFY(q2.seek(1));
+ QCOMPARE(q2.at(), 1);
+ QCOMPARE(q2.value(0).toInt(), 5);
+}
+
void tst_QSqlQuery::query_exec()
{
QFETCH( QString, dbName );
@@ -2163,8 +2399,8 @@ void tst_QSqlQuery::batchExec()
QSqlQuery q( db );
const QString tableName = qTableName("qtest_batch", __FILE__, db);
- QVERIFY_SQL( q, exec( "create table " + tableName + " (id int, name varchar(20), dt date, num numeric(8, 4))" ) );
- QVERIFY_SQL( q, prepare( "insert into " + tableName + " (id, name, dt, num) values (?, ?, ?, ?)" ) );
+ QVERIFY_SQL(q, exec("create table " + tableName + " (id int, name varchar(20), dt date, num numeric(8, 4), dtstamp TIMESTAMP(3))"));
+ QVERIFY_SQL(q, prepare("insert into " + tableName + " (id, name, dt, num, dtstamp) values (?, ?, ?, ?, ?)"));
QVariantList intCol;
intCol << 1 << 2 << QVariant( QVariant::Int );
@@ -2179,31 +2415,54 @@ void tst_QSqlQuery::batchExec()
QVariantList numCol;
numCol << 2.3 << 3.4 << QVariant( QVariant::Double );
- q.addBindValue( intCol );
+ QVariantList timeStampCol;
+ const QDateTime dtStamp = QDateTime(QDate::currentDate(), QTime(1, 2, 3, 4));
+ timeStampCol << dtStamp << dtStamp.addDays(-1) << QVariant(QVariant::DateTime);
+
+ q.addBindValue(intCol);
q.addBindValue( charCol );
q.addBindValue( dateCol );
q.addBindValue( numCol );
+ q.addBindValue(timeStampCol);
QVERIFY_SQL( q, execBatch() );
- QVERIFY_SQL( q, exec( "select id, name, dt, num from " + tableName + " order by id" ) );
+ QVERIFY_SQL(q, exec("select id, name, dt, num, dtstamp from " + tableName + " order by id"));
QVERIFY( q.next() );
QCOMPARE( q.value( 0 ).toInt(), 1 );
QCOMPARE( q.value( 1 ).toString(), QString( "harald" ) );
QCOMPARE( q.value( 2 ).toDateTime(), dt );
QCOMPARE( q.value( 3 ).toDouble(), 2.3 );
+ QCOMPARE(q.value(4).toDateTime(), dtStamp);
QVERIFY( q.next() );
QCOMPARE( q.value( 0 ).toInt(), 2 );
QCOMPARE( q.value( 1 ).toString(), QString( "boris" ) );
QCOMPARE( q.value( 2 ).toDateTime(), dt.addDays( -1 ) );
QCOMPARE( q.value( 3 ).toDouble(), 3.4 );
+ QCOMPARE(q.value(4).toDateTime(), dtStamp.addDays(-1));
QVERIFY( q.next() );
QVERIFY( q.value( 0 ).isNull() );
QVERIFY( q.value( 1 ).isNull() );
QVERIFY( q.value( 2 ).isNull() );
QVERIFY( q.value( 3 ).isNull() );
+ QVERIFY(q.value(4).isNull());
+
+ const QString procName = qTableName("qtest_batch_proc", __FILE__, db);
+ QVERIFY_SQL(q, exec("create or replace procedure " + procName + " (x in timestamp, y out timestamp) is\n"
+ "begin\n"
+ " y := x;\n"
+ "end;\n"));
+ QVERIFY(q.prepare("call " + procName + "(?, ?)"));
+ q.addBindValue(timeStampCol, QSql::In);
+ QVariantList emptyDateTimes;
+ emptyDateTimes.reserve(timeStampCol.size());
+ for (int i = 0; i < timeStampCol.size(); i++)
+ emptyDateTimes << QVariant(QDateTime());
+ q.addBindValue(emptyDateTimes, QSql::Out);
+ QVERIFY_SQL(q, execBatch());
+ QCOMPARE(q.boundValue(1).toList(), timeStampCol);
}
void tst_QSqlQuery::QTBUG_43874()
@@ -2658,8 +2917,8 @@ void tst_QSqlQuery::nextResult()
QSqlDatabase db = QSqlDatabase::database( dbName );
CHECK_DATABASE( db );
const QSqlDriver::DbmsType dbType = tst_Databases::getDatabaseType(db);
- if ( !db.driver()->hasFeature( QSqlDriver::MultipleResultSets ) || !db.driver()->hasFeature( QSqlDriver::BatchOperations ) )
- QSKIP( "DBMS does not support multiple result sets or batch operations");
+ if (!db.driver()->hasFeature(QSqlDriver::MultipleResultSets))
+ QSKIP("DBMS does not support multiple result sets");
QSqlQuery q( db );
@@ -2772,7 +3031,10 @@ void tst_QSqlQuery::nextResult()
// Stored procedure with multiple result sets
const QString procName(qTableName("proc_more_res", __FILE__, db));
- q.exec( QString( "DROP PROCEDURE %1;" ).arg( procName ) );
+ if (dbType == QSqlDriver::PostgreSQL)
+ q.exec(QString("DROP FUNCTION %1(refcursor, refcursor);").arg(procName));
+ else
+ q.exec(QString("DROP PROCEDURE %1;").arg(procName));
if (dbType == QSqlDriver::MySqlServer)
QVERIFY_SQL( q, exec( QString( "CREATE PROCEDURE %1()"
@@ -2790,6 +3052,16 @@ void tst_QSqlQuery::nextResult()
"\nOPEN cursor1;"
"\nOPEN cursor2;"
"\nEND p1" ).arg( procName ).arg( tableName ).arg( tableName ) ) );
+ else if (dbType == QSqlDriver::PostgreSQL)
+ QVERIFY_SQL(q, exec(QString("CREATE FUNCTION %1(ref1 refcursor, ref2 refcursor)"
+ "\nRETURNS SETOF refcursor AS $$"
+ "\nBEGIN"
+ "\nOPEN ref1 FOR SELECT id, text FROM %2;"
+ "\nRETURN NEXT ref1;"
+ "\nOPEN ref2 FOR SELECT empty, num, text, id FROM %2;"
+ "\nRETURN NEXT ref2;"
+ "\nEND;"
+ "\n$$ LANGUAGE plpgsql").arg(procName).arg(tableName)));
else
QVERIFY_SQL( q, exec( QString( "CREATE PROCEDURE %1"
"\nAS"
@@ -2799,10 +3071,32 @@ void tst_QSqlQuery::nextResult()
if (dbType == QSqlDriver::MySqlServer || dbType == QSqlDriver::DB2) {
q.setForwardOnly( true );
QVERIFY_SQL( q, exec( QString( "CALL %1()" ).arg( procName ) ) );
+ } else if (dbType == QSqlDriver::PostgreSQL) {
+ // Returning multiple result sets from PostgreSQL stored procedure:
+ // http://sqlines.com/postgresql/how-to/return_result_set_from_stored_procedure
+ QVERIFY_SQL(q, exec(QString("BEGIN;"
+ "SELECT %1('cur1', 'cur2');"
+ "FETCH ALL IN cur1;"
+ "FETCH ALL IN cur2;"
+ "COMMIT;").arg(procName)));
} else {
QVERIFY_SQL( q, exec( QString( "EXEC %1" ).arg( procName ) ) );
}
+ if (dbType == QSqlDriver::PostgreSQL) {
+ // First result set - start of transaction
+ QVERIFY(!q.isSelect());
+ QCOMPARE(q.numRowsAffected(), 0);
+ QVERIFY(q.nextResult());
+ // Second result set contains cursor names
+ QVERIFY(q.isSelect());
+ QVERIFY(q.next());
+ QCOMPARE(q.value(0).toString(), "cur1");
+ QVERIFY(q.next());
+ QCOMPARE(q.value(0).toString(), "cur2");
+ QVERIFY(q.nextResult());
+ }
+
for ( int i = 0; i < 4; i++ ) {
QVERIFY_SQL( q, next() );
QCOMPARE( q.value( 0 ).toInt(), i+1 );
@@ -2827,12 +3121,21 @@ void tst_QSqlQuery::nextResult()
QVERIFY( !q.isSelect() ); // ... but it's not a select
QCOMPARE( q.numRowsAffected(), 0 ); // ... and no rows are affected (at least not with this procedure)
}
+ if (dbType == QSqlDriver::PostgreSQL) {
+ // Last result set - commit transaction
+ QVERIFY(q.nextResult());
+ QVERIFY(!q.isSelect());
+ QCOMPARE(q.numRowsAffected(), 0);
+ }
QVERIFY( !q.nextResult() );
QVERIFY( !q.isActive() );
- q.exec( QString( "DROP PROCEDURE %1;" ).arg( procName ) );
+ if (dbType == QSqlDriver::PostgreSQL)
+ q.exec(QString("DROP FUNCTION %1(refcursor, refcursor);").arg(procName));
+ else
+ q.exec(QString("DROP PROCEDURE %1;").arg(procName));
}
@@ -2919,16 +3222,14 @@ void tst_QSqlQuery::timeStampParsing()
QFETCH(QString, dbName);
QSqlDatabase db = QSqlDatabase::database(dbName);
CHECK_DATABASE(db);
+ const QString tableName(qTableName("timeStampParsing", __FILE__, db));
+ tst_Databases::safeDropTable(db, tableName);
QSqlQuery q(db);
- QVERIFY_SQL(q, exec(
- "CREATE TABLE \"main\".\"datetest\" ("
- "\"id\" integer NOT NULL PRIMARY KEY AUTOINCREMENT,"
- "\"datefield\" timestamp);"
- ));
- QVERIFY_SQL(q, exec(
- "INSERT INTO datetest (datefield) VALUES (current_timestamp);"
- ));
- QVERIFY_SQL(q, exec("SELECT * FROM datetest;"));
+ QVERIFY_SQL(q, exec(QStringLiteral("CREATE TABLE ") + tableName
+ + QStringLiteral(" (id integer, datefield timestamp)")));
+ QVERIFY_SQL(q, exec(QStringLiteral("INSERT INTO ") + tableName
+ + QStringLiteral(" (datefield) VALUES (current_timestamp)")));
+ QVERIFY_SQL(q, exec(QStringLiteral("SELECT * FROM ") + tableName));
while (q.next())
QVERIFY(q.value(1).toDateTime().isValid());
}
@@ -4167,5 +4468,88 @@ void tst_QSqlQuery::QTBUG_57138()
QCOMPARE(q.value(2).toDateTime(), tzoffset);
}
+void tst_QSqlQuery::dateTime_data()
+{
+ QTest::addColumn<QString>("dbName");
+ QTest::addColumn<QString>("tableName");
+ QTest::addColumn<QString>("createTableString");
+ QTest::addColumn<QList<QDateTime> >("initialDateTimes");
+ QTest::addColumn<QList<QDateTime> >("expectedDateTimes");
+
+ // Using time zones which are highly unlikely to be the same as the testing machine's one
+ // as it could pass as a result despite it.
+ // +8.5 hours from UTC to North Korea
+ const QTimeZone afterUTCTimeZone(30600);
+ // -8 hours from UTC to Belize
+ const QTimeZone beforeUTCTimeZone(-28800);
+ const QTimeZone utcTimeZone("UTC");
+ const QDateTime dt(QDate(2015, 5, 18), QTime(4, 26, 30));
+ const QDateTime dtWithMS(QDate(2015, 5, 18), QTime(4, 26, 30, 500));
+ const QDateTime dtWithAfterTZ(QDate(2015, 5, 18), QTime(4, 26, 30, 500), afterUTCTimeZone);
+ const QDateTime dtWithBeforeTZ(QDate(2015, 5, 18), QTime(4, 26, 30, 500), beforeUTCTimeZone);
+ const QDateTime dtWithUTCTZ(QDate(2015, 5, 18), QTime(4, 26, 30, 500), utcTimeZone);
+ const QList<QDateTime> dateTimes = { dt, dtWithMS, dtWithAfterTZ, dtWithBeforeTZ, dtWithUTCTZ };
+ const QList<QDateTime> expectedDateTimesLocalTZ = { dt, dtWithMS, dtWithAfterTZ.toLocalTime(),
+ dtWithBeforeTZ.toLocalTime(),
+ dtWithUTCTZ.toLocalTime() };
+ const QList<QDateTime> expectedTimeStampDateTimes = { dt, dtWithMS, dtWithMS, dtWithMS, dtWithMS };
+ const QList<QDateTime> expectedDateTimes = { dt, dt, dt, dt, dt };
+
+ for (const QString &dbName : qAsConst(dbs.dbNames)) {
+ QSqlDatabase db = QSqlDatabase::database(dbName);
+ if (!db.isValid())
+ continue;
+ const QString tableNameTSWithTimeZone(qTableName("dateTimeTSWithTimeZone", __FILE__, db));
+ const QString tableNameTSWithLocalTimeZone(qTableName("dateTimeTSWithLocalTimeZone", __FILE__, db));
+ const QString tableNameTS(qTableName("dateTimeTS", __FILE__, db));
+ const QString tableNameDate(qTableName("dateTimeDate", __FILE__, db));
+ QTest::newRow(QString(dbName + " timestamp with time zone").toLatin1())
+ << dbName << tableNameTSWithTimeZone
+ << QStringLiteral(" (dt TIMESTAMP WITH TIME ZONE)")
+ << dateTimes << dateTimes;
+ QTest::newRow(QString(dbName + " timestamp with local time zone").toLatin1())
+ << dbName << tableNameTSWithTimeZone
+ << QStringLiteral(" (dt TIMESTAMP WITH LOCAL TIME ZONE)")
+ << dateTimes << expectedDateTimesLocalTZ;
+ QTest::newRow(QString(dbName + "timestamp").toLatin1())
+ << dbName << tableNameTS << QStringLiteral(" (dt TIMESTAMP(3))")
+ << dateTimes << expectedTimeStampDateTimes;
+ QTest::newRow(QString(dbName + "date").toLatin1())
+ << dbName << tableNameDate << QStringLiteral(" (dt DATE)")
+ << dateTimes << expectedDateTimes;
+ }
+}
+
+void tst_QSqlQuery::dateTime()
+{
+ QFETCH(QString, dbName);
+ QSqlDatabase db = QSqlDatabase::database(dbName);
+ CHECK_DATABASE(db);
+
+ QSqlDriver::DbmsType dbType = tst_Databases::getDatabaseType(db);
+ if (dbType != QSqlDriver::Oracle)
+ QSKIP("Implemented only for Oracle");
+
+ QFETCH(QString, tableName);
+ QFETCH(QString, createTableString);
+ QFETCH(QList<QDateTime>, initialDateTimes);
+ QFETCH(QList<QDateTime>, expectedDateTimes);
+
+ tst_Databases::safeDropTable(db, tableName);
+
+ QSqlQuery q(db);
+ QVERIFY_SQL(q, exec("CREATE TABLE " + tableName + createTableString));
+ for (const QDateTime &dt : qAsConst(initialDateTimes)) {
+ QVERIFY_SQL(q, prepare("INSERT INTO " + tableName + " values(:dt)"));
+ q.bindValue(":dt", dt);
+ QVERIFY_SQL(q, exec());
+ }
+ QVERIFY_SQL(q, exec("SELECT * FROM " + tableName));
+ for (const QDateTime &dt : qAsConst(expectedDateTimes)) {
+ QVERIFY(q.next());
+ QCOMPARE(q.value(0).toDateTime(), dt);
+ }
+}
+
QTEST_MAIN( tst_QSqlQuery )
#include "tst_qsqlquery.moc"