A QtSql driver for Mimer SQL

The QtSql for Mimer SQL sqldriver makes it possible to work with the
Mimer SQL database on different plattforms. There are drivers for
several other databases in QtSql and a driver for Mimer SQL will
benefit many users.
To build the Mimer SQL driver, download Mimer SQL from
https://developer.mimer.com

[ChangeLog][QtSql]
Added a QtSql plugin to work with the Mimer SQL database

Fixes: QTBUG-111219
Change-Id: Id6ba5de4de01189d0516ffbfa89efcb0d013115f
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
This commit is contained in:
Fredrik Ålund 2022-09-15 22:04:23 +02:00 committed by Volker Hilsheimer
parent 360f69b74b
commit 0efd8854c4
22 changed files with 2071 additions and 29 deletions

54
cmake/FindMimer.cmake Normal file
View File

@ -0,0 +1,54 @@
# Copyright (C) 2022 The Qt Company Ltd.
# Copyright (C) 2022 Mimer Information Technology
# SPDX-License-Identifier: BSD-3-Clause
# FindMimer
# ---------
# Try to locate the Mimer SQL client library
find_package(PkgConfig QUIET)
pkg_check_modules(PC_Mimer QUIET mimctrl)
find_path(Mimer_INCLUDE_DIR
NAMES mimerapi.h
HINTS ${PC_Mimer_INCLUDEDIR})
if(WIN32)
if("$ENV{PROCESSOR_ARCHITECTURE}" STREQUAL "x86")
set(MIMER_LIBS_NAMES mimapi32)
else()
set(MIMER_LIBS_NAMES mimapi64)
endif()
else()
set(MIMER_LIBS_NAMES mimerapi)
endif()
find_library(Mimer_LIBRARIES
NAMES ${MIMER_LIBS_NAMES}
HINTS ${PC_Mimer_LIBDIR})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Mimer
REQUIRED_VARS Mimer_LIBRARIES Mimer_INCLUDE_DIR)
# Now try to get the include and library path.
if(Mimer_FOUND)
set(Mimer_INCLUDE_DIRS ${Mimer_INCLUDE_DIR})
set(Mimer_LIBRARY_DIRS ${Mimer_LIBRARIES})
if (NOT TARGET MimerSQL::MimerSQL)
add_library(MimerSQL::MimerSQL UNKNOWN IMPORTED)
set_target_properties(MimerSQL::MimerSQL PROPERTIES
IMPORTED_LOCATION "${Mimer_LIBRARY_DIRS}"
INTERFACE_INCLUDE_DIRECTORIES "${Mimer_INCLUDE_DIRS}")
endif ()
endif()
mark_as_advanced(Mimer_INCLUDE_DIR Mimer_LIBRARIES)
include(FeatureSummary)
set_package_properties(MimerSQL PROPERTIES
URL "https://www.mimer.com"
DESCRIPTION "Mimer client library")

View File

@ -64,6 +64,10 @@ if(QT_FEATURE_sql_ibase)
add_subdirectory(ibase)
endif()
if(QT_FEATURE_sql_mimer)
add_subdirectory(mimer)
endif()
if(NOT CMAKE_PROJECT_NAME STREQUAL "QtBase" AND NOT CMAKE_PROJECT_NAME STREQUAL "Qt")
qt_print_feature_summary()
endif()

View File

@ -20,6 +20,7 @@ qt_find_package(Oracle PROVIDED_TARGETS Oracle::OCI MODULE_NAME sqldrivers QMAKE
qt_find_package(ODBC PROVIDED_TARGETS ODBC::ODBC MODULE_NAME sqldrivers QMAKE_LIB odbc)
qt_find_package(SQLite3 PROVIDED_TARGETS SQLite::SQLite3 MODULE_NAME sqldrivers QMAKE_LIB sqlite3)
qt_find_package(Interbase PROVIDED_TARGETS Interbase::Interbase MODULE_NAME sqldrivers QMAKE_LIB ibase) # special case
qt_find_package(Mimer PROVIDED_TARGETS MimerSQL::MimerSQL MODULE_NAME sqldrivers QMAKE_LIB mimer)
if(NOT WIN32 AND QT_FEATURE_system_zlib)
qt_add_qmake_lib_dependency(sqlite3 zlib)
endif()
@ -64,6 +65,11 @@ qt_feature("system-sqlite" PRIVATE
AUTODETECT OFF
CONDITION QT_FEATURE_sql_sqlite AND SQLite3_FOUND
)
qt_feature("sql-mimer" PRIVATE
LABEL "Mimer"
CONDITION Mimer_FOUND
)
qt_configure_add_summary_section(NAME "Qt Sql Drivers")
qt_configure_add_summary_entry(ARGS "sql-db2")
qt_configure_add_summary_entry(ARGS "sql-ibase")
@ -73,6 +79,7 @@ qt_configure_add_summary_entry(ARGS "sql-odbc")
qt_configure_add_summary_entry(ARGS "sql-psql")
qt_configure_add_summary_entry(ARGS "sql-sqlite")
qt_configure_add_summary_entry(ARGS "system-sqlite")
qt_configure_add_summary_entry(ARGS "sql-mimer")
qt_configure_end_summary_section() # end of "Qt Sql Drivers" section
qt_configure_add_report_entry(
TYPE WARNING

View File

@ -0,0 +1,23 @@
# Generated from mimer.pro.
#####################################################################
## MIMERSQLDriverPlugin Plugin:
#####################################################################
qt_internal_add_plugin(QMimerSQLDriverPlugin
OUTPUT_NAME qsqlmimer
PLUGIN_TYPE sqldrivers
SOURCES
main.cpp
qsql_mimer.cpp qsql_mimer.h
DEFINES
QT_NO_CAST_FROM_ASCII
QT_NO_CAST_TO_ASCII
LIBRARIES
MimerSQL::MimerSQL
Qt::Core
Qt::SqlPrivate
)
#### Keys ignored in scope 1:.:.:mimer.pro:<TRUE>:
# OTHER_FILES = "mimer.json"

View File

@ -0,0 +1,6 @@
You will need the Mimer SQL development headers and libraries installed before
compiling this plugin. qsql_mimer.h contains an include to mimerapi.h that is
needed for the driver to compile.
See the Qt SQL documentation for more information on compiling Qt SQL driver
plugins.

View File

@ -0,0 +1,33 @@
// Copyright (C) 2022 The Qt Company Ltd.
// Copyright (C) 2022 Mimer Information Technology
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qsql_mimer.h"
#include <qsqldriverplugin.h>
#include <qstringlist.h>
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
class QMimerSQLDriverPlugin : public QSqlDriverPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QSqlDriverFactoryInterface" FILE "mimer.json")
public:
QMimerSQLDriverPlugin();
QSqlDriver *create(const QString &) override;
};
QMimerSQLDriverPlugin::QMimerSQLDriverPlugin() : QSqlDriverPlugin() { }
QSqlDriver *QMimerSQLDriverPlugin::create(const QString &name)
{
if (name == "QMIMER"_L1)
return new QMimerSQLDriver;
return nullptr;
}
QT_END_NAMESPACE
#include "main.moc"

View File

@ -0,0 +1,5 @@
{
"Keys": [
"QMIMER"
]
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,50 @@
// Copyright (C) 2022 The Qt Company Ltd.
// Copyright (C) 2022 Mimer Information Technology
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSQL_MIMER_H
#define QSQL_MIMER_H
#include <QtSql/qsqldriver.h>
#include <QUuid>
#include <mimerapi.h>
#ifdef QT_PLUGIN
# define Q_EXPORT_SQLDRIVER_MIMER
#else
# define Q_EXPORT_SQLDRIVER_MIMER Q_SQL_EXPORT
#endif
QT_BEGIN_NAMESPACE
class QMimerSQLDriverPrivate;
class Q_EXPORT_SQLDRIVER_MIMER QMimerSQLDriver : public QSqlDriver
{
friend class QMimerSQLResultPrivate;
Q_DECLARE_PRIVATE(QMimerSQLDriver)
Q_OBJECT
public:
explicit QMimerSQLDriver(QObject *parent = nullptr);
explicit QMimerSQLDriver(MimerSession *conn, QObject *parent = nullptr);
~QMimerSQLDriver() override;
bool hasFeature(DriverFeature f) const override;
bool open(const QString &db, const QString &user, const QString &password, const QString &host,
int port, const QString &connOpts) override;
void close() override;
QSqlResult *createResult() const override;
QStringList tables(QSql::TableType type) const override;
QSqlIndex primaryIndex(const QString &tablename) const override;
QSqlRecord record(const QString &tablename) const override;
QVariant handle() const override;
QString escapeIdentifier(const QString &identifier, IdentifierType type) const override;
protected:
bool beginTransaction() override;
bool commitTransaction() override;
bool rollbackTransaction() override;
private:
};
QT_END_NAMESPACE
#endif // QSQL_MIMER

View File

@ -11,6 +11,7 @@ qt_commandline_option(sql-oci TYPE boolean)
qt_commandline_option(sql-odbc TYPE boolean)
qt_commandline_option(sql-psql TYPE boolean)
qt_commandline_option(sql-sqlite TYPE boolean)
qt_commandline_option(sql-mimer TYPE boolean)
qt_commandline_option(plugin-sql-db2 TYPE void NAME sql-db2)
qt_commandline_option(plugin-sql-ibase TYPE void NAME sql-ibase)
qt_commandline_option(plugin-sql-mysql TYPE void NAME sql-mysql)
@ -18,3 +19,4 @@ qt_commandline_option(plugin-sql-oci TYPE void NAME sql-oci)
qt_commandline_option(plugin-sql-odbc TYPE void NAME sql-odbc)
qt_commandline_option(plugin-sql-psql TYPE void NAME sql-psql)
qt_commandline_option(plugin-sql-sqlite TYPE void NAME sql-sqlite)
qt_commandline_option(plugin-sql-mimer TYPE void NAME sql-mimer)

View File

@ -79,3 +79,16 @@ while (query1.next()) {
}
//! [37]
}
void callOutProc()
{
//! [40]
QSqlDatabase db;
QSqlQuery query;
int i1 = 10, i2 = 0;
query.prepare("call qtestproc(?, ?)");
query.bindValue(0, i1, QSql::InOut);
query.bindValue(1, i2, QSql::Out);
query.exec();
//! [40]
}

View File

@ -173,6 +173,23 @@ cmake --build .
cmake --install .
//! [30]
//! [31]
mkdir build-sqldrivers
cd build-sqldrivers
qt-cmake -G Ninja <qt_installation_path>\Src\qtbase\src\plugins\sqldrivers -DCMAKE_INSTALL_PREFIX=<qt_installation_path>\<platform> -DMimer_INCLUDE_DIR="/usr/include" -DMimer_LIBRARIES="/usr/lib/libmimer.so"
cmake --build .
cmake --install .
//! [31]
//! [32]
mkdir build-sqldrivers
cd build-sqldrivers
qt-cmake -G Ninja <qt_installation_path>\Src\qtbase\src\plugins\sqldrivers -DCMAKE_INSTALL_PREFIX=<qt_installation_path>\<platform> -DMimer_INCLUDE_DIR="C:\Program Files\Mimer SQL Experience 11.0\dev\include" -DMimer_LIBRARIES="C:\Program Files\Mimer SQL Experience 11.0\dev\lib\amd64\mimapi64.lib|C:\Program Files\Mimer SQL Experience 11.0\dev\lib\x86\mimapi32.lib"
cmake --build .
cmake --install .
//! [32]
//! [35]
QSqlDatabase: QPSQL driver not loaded
@ -205,6 +222,7 @@ Configure summary:
Qt Sql Drivers:
DB2 (IBM) .............................. no
InterBase .............................. no
Mimer SQL .............................. yes
MySql .................................. yes
OCI (Oracle) ........................... no
ODBC ................................... yes
@ -225,6 +243,7 @@ Configure summary:
Qt Sql Drivers:
DB2 (IBM) .............................. no
InterBase .............................. no
Mimer SQL .............................. yes
MySql .................................. yes
OCI (Oracle) ........................... no
ODBC ................................... yes
@ -242,6 +261,7 @@ Configure summary:
Qt Sql Drivers:
DB2 (IBM) .............................. no
InterBase .............................. no
Mimer SQL .............................. yes
MySql .................................. yes
OCI (Oracle) ........................... no
ODBC ................................... yes
@ -250,3 +270,11 @@ Qt Sql Drivers:
Using system provided SQLite ......... no
...
//! [43]
//! [44]
create procedure inout_proc (INOUT param1 INT, OUT param2 INT)
BEGIN
set param1 = param1 * 2;
set param2 = param1 * param1;
END
//! [44]

View File

@ -269,7 +269,7 @@
\row
\li NUMBER(p,s)
\li NUMERIC(p,s) DECIMAL(p,s)a
\li By default mapping to QString
\li Mapped to QString
\row
\li NVARCHAR2(n)
\li Character string (NATIONAL CHARACTER VARYING(n) NATIONAL
@ -478,4 +478,90 @@
\li The value is a BLOB of data, stored exactly as it was input.
\li Mapped to QByteArray
\endtable
\section2 Mimer SQL Data Types
\table 90%
\header
\li Mimer SQL type
\li SQL type description
\li Recommended input (C++ or Qt data type)
\row
\li SMALLINT
\li 16-bit signed integer
\li typedef qint16
\row
\li INTEGER
\li 32-bit signed integer
\li typedef qint32
\row
\li BIGINT
\li 64-bit signed integer
\li typedef qint64
\row
\li REAL
\li 32-bit Single-precision floating point
\li typedef qreal
\row
\li DOUBLE PRECISION
\li 64-bit Double-precision floating point
\li Mapped to QString for high precision doubles, otherwise qreal
\row
\li FLOAT
\li 64-bit Double-precision floating point
\li typedef qreal
\row
\li CHAR
\li Fixed-length, null-terminated character string
\li Mapped to QString
\row
\li VARCHAR
\li Null-terminated varying length string
\li Mapped to QString
\row
\li NCHAR
\li Fixed-length, null-terminated Unicode character string
\li Mapped to QString
\row
\li NVARCHAR
\li Null-terminated varying length Unicode string
\li Mapped to QString
\row
\li BLOB
\li Not null-terminated varying binary string with 4-byte string
length indicator
\li Mapped to QByteArray
\row
\li CLOB
\li Character large string object
\li Mapped to QString
\row
\li NCLOB
\li National Character large string object
\li Mapped to QString
\row
\li DATE
\li Null-terminated character string of the following format:
yyyy-mm-dd
\li Mapped to QDate
\row
\li TIME
\li Null-terminated character string of the following format: hh.mm.ss
\li Mapped to QTime
\row
\li TIMESTAMP
\li Null-terminated character string of the following format: yyyy-mm-dd-hh.mm.ss.nnnnnn
\li Mapped to QDateTime
\row
\li BUILTIN.UUID
\li Universally unique identifier
\li Mapped to QUuid
\row
\li BOOLEAN
\li Boolean
\li bool
\row
\li DECIMAL(p,s)
\li By default mapping to QString
\endtable
*/

View File

@ -30,6 +30,7 @@
ODBC-compliant databases
\row \li \l{#QPSQL}{QPSQL} \li PostgreSQL (versions 7.3 and above)
\row \li \l{#QSQLITE}{QSQLITE} \li SQLite version 3
\row \li \l{#QMIMER}{QMIMER} \li Mimer SQL (version 11 and above)
\endtable
SQLite is the in-process database system with the best test coverage
@ -791,6 +792,47 @@
Some versions of SQLite can be forced to write a specific file format by setting
the \c{SQLITE_DEFAULT_FILE_FORMAT} define when building SQLite.
\target QMIMER
\section2 QMIMER for Mimer SQL version 11 and higher
The Qt Mimer SQL plugin makes it possible to work with the Mimer SQL RDBMS.
Mimer SQL provides small footprint, scalable and robust relational database
solutions that conform to international ISO SQL standards. Mimer SQL is available
on Windows, Linux, \macos, and OpenVMS as well as several embedded platforms like QNX, Android,
and embedded Linux.
Mimer SQL fully support Unicode. To work with Unicode data the column types National Character (NCHAR),
National Character Varying (NVARCHAR), or National Character Large Object (NCLOB) must be used.
For more information about Mimer SQL and unicode, see \l{https://developer.mimer.com/features/multilingual-support}
\section3 QMIMER Stored Procedure Support
Mimer SQL have stored procedures according to the SQL standard (PSM) and
the plugin fully support IN, OUT, INOUT parameters as well as resultset procedures.
Example stored procedure with INOUT and OUT parameters:
\snippet code/doc_src_sql-driver.qdoc 44
Source code to access the INOUT and OUT values:
\snippet code/doc_src_sql-driver.cpp 40
\section3 How to Build the QMIMER Plugin on Unix and \macos
You need the Mimer SQL header files and shared libraries. Get them by installing
any of the Mimer SQL variants found at \l{https://developer.mimer.com}.
\snippet code/doc_src_sql-driver.qdoc 31
\section3 How to Build the QMIMER Plugin on Windows
You need the Mimer SQL header files and shared libraries. Get them by installing
any of the Mimer SQL variants found at \l{https://developer.mimer.com}.
\snippet code/doc_src_sql-driver.qdoc 32
\target QIBASE
\section2 QIBASE for Borland InterBase

View File

@ -580,6 +580,7 @@ QStringList QSqlDatabase::connectionNames()
\row \li QODBC \li ODBC Driver (includes Microsoft SQL Server)
\row \li QPSQL \li PostgreSQL Driver
\row \li QSQLITE \li SQLite version 3 or above
\row \li QMIMER \li Mimer SQL 11 or above
\endtable
Additional third party drivers, including your own custom
@ -1205,6 +1206,11 @@ bool QSqlDatabase::isDriverAvailable(const QString& name)
\li sqlite *connection
\li \c qsql_sqlite.cpp
\row
\li QMIMER
\li QMimerSQLDriver
\li MimerSession *connection
\li \c qsql_mimer.cpp
\row
\li QIBASE
\li QIBaseDriver
\li isc_db_handle connection

View File

@ -215,6 +215,7 @@ bool QSqlDriver::isOpenError() const
\value SQLite
\value Interbase
\value DB2
\value MimerSQL
*/
/*!

View File

@ -50,7 +50,8 @@ public:
Sybase,
SQLite,
Interbase,
DB2
DB2,
MimerSQL
};
explicit QSqlDriver(QObject *parent = nullptr);

View File

@ -332,7 +332,7 @@ public:
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)
if (dbType == QSqlDriver::PostgreSQL || dbType == QSqlDriver::MimerSQL)
wasDropped = q.exec( "drop table " + table + " cascade");
else
wasDropped = q.exec( "drop table " + table);
@ -426,7 +426,7 @@ public:
return QLatin1String("timestamptz");
if (dbType == QSqlDriver::Oracle && getOraVersion(db) >= 9)
return QLatin1String("timestamp(0)");
if (dbType == QSqlDriver::Interbase)
if (dbType == QSqlDriver::Interbase || dbType == QSqlDriver::MimerSQL)
return QLatin1String("timestamp");
return QLatin1String("datetime");
}

View File

@ -1146,9 +1146,8 @@ void tst_QSqlDatabase::bigIntField()
if (dbType == QSqlDriver::MySqlServer) {
QVERIFY_SQL(q, exec("create table " + qtest_bigint + " (id int, t_s64bit bigint, t_u64bit bigint unsigned)"));
} else if (dbType == QSqlDriver::PostgreSQL
|| dbType == QSqlDriver::DB2
|| dbType == QSqlDriver::MSSqlServer) {
} else if (dbType == QSqlDriver::PostgreSQL || dbType == QSqlDriver::DB2
|| dbType == QSqlDriver::MSSqlServer || dbType == QSqlDriver::MimerSQL) {
QVERIFY_SQL(q, exec("create table " + qtest_bigint + "(id int, t_s64bit bigint, t_u64bit bigint)"));
} else if (dbType == QSqlDriver::Oracle) {
QVERIFY_SQL(q, exec("create table " + qtest_bigint + " (id int, t_s64bit int, t_u64bit int)"));

View File

@ -64,7 +64,7 @@ void tst_QSqlDriver::recreateTestTables(QSqlDatabase db)
doubleField = "more_data double";
else if (dbType == QSqlDriver::Oracle)
doubleField = "more_data number(8,7)";
else if (dbType == QSqlDriver::PostgreSQL)
else if (dbType == QSqlDriver::PostgreSQL || dbType == QSqlDriver::MimerSQL)
doubleField = "more_data double precision";
else if (dbType == QSqlDriver::Interbase)
doubleField = "more_data numeric(8,7)";
@ -155,8 +155,9 @@ void tst_QSqlDriver::record()
//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))
if (dbType == QSqlDriver::MySqlServer || dbType == QSqlDriver::SQLite
|| dbType == QSqlDriver::Sybase || dbType == QSqlDriver::MSSqlServer
|| tst_Databases::isMSAccess(db) || dbType == QSqlDriver::MimerSQL)
QCOMPARE(rec.count(), 5); //mysql, sqlite and tds will match
else
QCOMPARE(rec.count(), 0);
@ -205,8 +206,9 @@ void tst_QSqlDriver::primaryIndex()
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))
if (dbType == QSqlDriver::MySqlServer || dbType == QSqlDriver::SQLite
|| dbType == QSqlDriver::Sybase || dbType == QSqlDriver::MSSqlServer
|| tst_Databases::isMSAccess(db) || dbType == QSqlDriver::MimerSQL)
QCOMPARE(index.count(), 1); //mysql will always find the table name regardless of casing
else
QCOMPARE(index.count(), 0);

View File

@ -486,6 +486,7 @@ void tst_QSqlQuery::char1SelectUnicode()
const QString char1SelectUnicode(qTableName("char1SU", __FILE__, db));
switch (dbType) {
case QSqlDriver::MimerSQL:
case QSqlDriver::MSSqlServer:
createQuery = QLatin1String("create table %1(id nchar(1))");
break;
@ -1113,8 +1114,9 @@ void tst_QSqlQuery::record()
QCOMPARE(q.record().fieldName(0).toLower(), u"id");
QCOMPARE(q.value(0).toInt(), 2);
if (tst_Databases::getDatabaseType(db) == QSqlDriver::Oracle)
QSKIP("Getting the tablename is not supported in Oracle");
if (tst_Databases::getDatabaseType(db) == QSqlDriver::Oracle
|| tst_Databases::getDatabaseType(db) == QSqlDriver::MimerSQL)
QSKIP("Getting the tablename is not supported in Oracle and Mimer SQL");
const auto lowerQTest = qtest.toLower();
for (int i = 0; i < 3; ++i)
@ -1786,17 +1788,19 @@ void tst_QSqlQuery::writeNull()
const QString tableName = qTableName("qtest_writenull", __FILE__, db);
// The test data table is already used, so use a local hash to exercise the various
// cases from the QSqlResultPrivate::isVariantNull helper. Only PostgreSQL supports
// QUuid.
// cases from the QSqlResultPrivate::isVariantNull helper. Only PostgreSQL and Mimer SQL
// supports QUuid.
QMultiHash<QString, QVariant> nullableTypes = {
{"varchar(20)", u"not null"_s},
{"varchar(20)", "not null"_ba},
{tst_Databases::dateTimeTypeName(db), QDateTime::currentDateTime()},
{tst_Databases::dateTypeName(db), QDate::currentDate()},
{tst_Databases::timeTypeName(db), QTime::currentTime()},
{ "varchar(20)", u"not null"_s },
{ "varchar(20)", "not null"_ba },
{ tst_Databases::dateTimeTypeName(db), QDateTime::currentDateTime() },
{ tst_Databases::dateTypeName(db), QDate::currentDate() },
{ tst_Databases::timeTypeName(db), QTime::currentTime() },
};
if (dbType == QSqlDriver::PostgreSQL)
nullableTypes["uuid"] = QUuid::createUuid();
if (dbType == QSqlDriver::MimerSQL)
nullableTypes["builtin.uuid"] = QUuid::createUuid();
// Helper to count rows with null values in the data column.
// Since QSqlDriver::QuerySize might not be supported, we have to count anyway
@ -2191,6 +2195,7 @@ void tst_QSqlQuery::prepare_bind_exec()
switch (dbType) {
case QSqlDriver::MSSqlServer:
case QSqlDriver::Sybase:
case QSqlDriver::MimerSQL:
createQuery = QLatin1String("create table %1 (id int primary key, "
"name nvarchar(200) null, name2 nvarchar(200) null)");
break;
@ -2675,8 +2680,9 @@ void tst_QSqlQuery::batchExec()
}
// Only test the prepared stored procedure approach where the driver has support
// for batch operations as this will not work without it
if (db.driver()->hasFeature(QSqlDriver::BatchOperations)) {
// for batch operations as this will not work without it.
// Currently Mimer SQL cannot use output parameters with procedures in batch operations.
if (dbType != QSqlDriver::MimerSQL && db.driver()->hasFeature(QSqlDriver::BatchOperations)) {
const QString procName = qTableName("qtest_batch_proc", __FILE__, db);
QVERIFY_SQL(q, exec(QLatin1String(
"create or replace procedure %1 (x in timestamp, y out timestamp) "
@ -3533,6 +3539,13 @@ void tst_QSqlQuery::timeStampParsing()
// Since there is no auto-increment feature in Interbase we allow it to be null
creator = QLatin1String("CREATE TABLE %1(id integer, datefield timestamp);");
break;
case QSqlDriver::MimerSQL:
creator = QLatin1String("CREATE UNIQUE SEQUENCE timeStampParsing_seq");
QVERIFY_SQL(q, exec(creator));
creator = QLatin1String("CREATE TABLE %1(id integer NOT NULL default next value "
"for timeStampParsing_seq, "
"datefield timestamp, primary key(id));");
break;
default:
creator = QLatin1String("CREATE TABLE %1("
"\"id\" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "
@ -3540,8 +3553,15 @@ void tst_QSqlQuery::timeStampParsing()
break;
}
QVERIFY_SQL(q, exec(creator.arg(tableName)));
QVERIFY_SQL(q, exec(QLatin1String("INSERT INTO %1 (datefield) VALUES (current_timestamp);")
.arg(tableName)));
QLatin1String currentTimestamp;
if (tst_Databases::getDatabaseType(db) == QSqlDriver::MimerSQL)
currentTimestamp = QLatin1String("localtimestamp");
else
currentTimestamp = QLatin1String("current_timestamp");
QVERIFY_SQL(q,
exec(QLatin1String("INSERT INTO %1 (datefield) VALUES (%2);")
.arg(tableName)
.arg(currentTimestamp)));
QVERIFY_SQL(q, exec(QLatin1String("SELECT * FROM ") + tableName));
while (q.next())
QVERIFY(q.value(1).toDateTime().isValid());
@ -4485,7 +4505,8 @@ void tst_QSqlQuery::aggregateFunctionTypes()
int countType = intType;
// QPSQL uses LongLong for manipulation of integers
const QSqlDriver::DbmsType dbType = tst_Databases::getDatabaseType(db);
if (dbType == QSqlDriver::PostgreSQL || dbType == QSqlDriver::Interbase) {
if (dbType == QSqlDriver::PostgreSQL || dbType == QSqlDriver::Interbase
|| dbType == QSqlDriver::MimerSQL) {
sumType = countType = QMetaType::LongLong;
} else if (dbType == QSqlDriver::Oracle) {
intType = sumType = countType = QMetaType::Double;

View File

@ -784,7 +784,7 @@ void tst_QSqlRelationalTableModel::sort()
QStringList stringsInDatabaseOrder;
// PostgreSQL puts the null ones (from the table with the original value) first in descending order
// which translate to empty strings in the related table
if (dbType == QSqlDriver::PostgreSQL)
if (dbType == QSqlDriver::PostgreSQL || dbType == QSqlDriver::MimerSQL)
stringsInDatabaseOrder << "" << "" << "mister" << "mister" << "herr" << "herr";
else
stringsInDatabaseOrder << "mister" << "mister" << "herr" << "herr" << "" << "";
@ -797,7 +797,7 @@ void tst_QSqlRelationalTableModel::sort()
// PostgreSQL puts the null ones (from the table with the original value) first in descending order
// which translate to empty strings in the related table
stringsInDatabaseOrder.clear();
if (dbType == QSqlDriver::PostgreSQL)
if (dbType == QSqlDriver::PostgreSQL || dbType == QSqlDriver::MimerSQL)
stringsInDatabaseOrder << "herr" << "mister" << "mister" << "mister" << "mister" << "";
else if (dbType != QSqlDriver::Sybase)
stringsInDatabaseOrder << "" << "herr" << "mister" << "mister" << "mister" << "mister";
@ -1520,7 +1520,14 @@ void tst_QSqlRelationalTableModel::relationOnFirstColumn()
QVERIFY_SQL(q, exec("INSERT INTO " + testTable1 + " (id1, val1) VALUES(3, 30);"));
//prepare test2 table
QVERIFY_SQL(q, exec("CREATE TABLE " + testTable2 + " (id INTEGER PRIMARY KEY, name TEXT);"));
if (tst_Databases::getDatabaseType(db) == QSqlDriver::MimerSQL) {
QVERIFY_SQL(q,
exec("CREATE TABLE " + testTable2
+ " (id INTEGER PRIMARY KEY, name NVARCHAR(100));"));
} else {
QVERIFY_SQL(q,
exec("CREATE TABLE " + testTable2 + " (id INTEGER PRIMARY KEY, name TEXT);"));
}
QVERIFY_SQL(q, exec("DELETE FROM " + testTable2 + QLatin1Char(';')));
QVERIFY_SQL(q, exec("INSERT INTO " + testTable2 + " (id, name) VALUES (10, 'Hervanta');"));
QVERIFY_SQL(q, exec("INSERT INTO " + testTable2 + " (id, name) VALUES (20, 'Keskusta');"));