From 4209a57e8ad94abdf07d5ef7473dfc0b66f91f95 Mon Sep 17 00:00:00 2001 From: Ivailo Monev Date: Fri, 10 Sep 2021 05:03:08 +0300 Subject: [PATCH] drop support for PostgreSQL and MySQL databases Signed-off-by: Ivailo Monev --- CMakeLists.txt | 24 - README | 1 + appveyor.yml | 6 +- cmake/modules/FindMySQL.cmake | 48 - cmake/modules/FindPostgreSQL.cmake | 33 - package/archlinux/PKGBUILD | 6 +- package/debian/control | 5 +- package/fedora/katie.spec | 2 +- package/freebsd/Makefile | 11 +- package/freebsd/pkg-plist | 2 - package/netbsd/Makefile | 2 - package/netbsd/PLIST | 2 - package/netbsd/options.mk | 25 - scripts/minsize.sh | 4 +- src/plugins/CMakeLists.txt | 6 - src/plugins/sqldrivers/mysql/CMakeLists.txt | 24 - src/plugins/sqldrivers/mysql/mysqlmain.cpp | 61 - src/plugins/sqldrivers/mysql/qsql_mysql.cpp | 1396 ----------------- src/plugins/sqldrivers/mysql/qsql_mysql.h | 106 -- src/plugins/sqldrivers/psql/CMakeLists.txt | 24 - src/plugins/sqldrivers/psql/psqlmain.cpp | 61 - src/plugins/sqldrivers/psql/qsql_psql.cpp | 1245 --------------- src/plugins/sqldrivers/psql/qsql_psql.h | 124 -- src/sql/kernel/qsqldatabase.cpp | 98 +- tests/auto/qsqldatabase/tst_databases.h | 74 +- tests/auto/qsqldatabase/tst_qsqldatabase.cpp | 453 +----- tests/auto/qsqldriver/tst_qsqldriver.cpp | 13 - tests/auto/qsqlquery/tst_qsqlquery.cpp | 361 +---- .../qsqltablemodel/tst_qsqltablemodel.cpp | 27 - .../benchmarks/sql/kernel/qsqlquery/main.cpp | 15 +- translations/qt.pot | 119 +- translations/qt_tools.pot | 2 +- 32 files changed, 64 insertions(+), 4316 deletions(-) delete mode 100644 cmake/modules/FindMySQL.cmake delete mode 100644 cmake/modules/FindPostgreSQL.cmake delete mode 100644 package/netbsd/options.mk delete mode 100644 src/plugins/sqldrivers/mysql/CMakeLists.txt delete mode 100644 src/plugins/sqldrivers/mysql/mysqlmain.cpp delete mode 100644 src/plugins/sqldrivers/mysql/qsql_mysql.cpp delete mode 100644 src/plugins/sqldrivers/mysql/qsql_mysql.h delete mode 100644 src/plugins/sqldrivers/psql/CMakeLists.txt delete mode 100644 src/plugins/sqldrivers/psql/psqlmain.cpp delete mode 100644 src/plugins/sqldrivers/psql/qsql_psql.cpp delete mode 100644 src/plugins/sqldrivers/psql/qsql_psql.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 19e7bd91a..e9484097e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -161,12 +161,6 @@ add_feature_info(fontconfig WITH_FONTCONFIG "build Fontconfig support") option(WITH_ODBC "Build ODBC database plugin" ON) add_feature_info(odbc WITH_ODBC "build ODBC support") -option(WITH_POSTGRESQL "Build PostgreSQL database plugin" ON) -add_feature_info(postgresql WITH_POSTGRESQL "build PostgreSQL support") - -option(WITH_MYSQL "Build MySQL database plugin" ON) -add_feature_info(mysql WITH_MYSQL "build MySQL support") - option(WITH_INTL "Build Intl support" ON) add_feature_info(intl WITH_INTL "build Intl support") @@ -336,24 +330,6 @@ set_package_properties(ODBC PROPERTIES TYPE RECOMMENDED ) -# v7.4+ required for PQresultErrorField() -find_package(PostgreSQL 7.4) -set_package_properties(PostgreSQL PROPERTIES - PURPOSE "Required for PostgreSQL database support" - DESCRIPTION "The world's most advanced open source database" - URL "https://www.postgresql.org/" - TYPE RECOMMENDED -) - -# v4.1.13+ required for multiple statements query and UTF-8 support -find_package(MySQL 4.1.13) -set_package_properties(MySQL PROPERTIES - PURPOSE "Required for MySQL database support" - DESCRIPTION "The world's most popular open source database" - URL "https://www.mysql.com/" - TYPE RECOMMENDED -) - find_package(Intl) set_package_properties(Intl PROPERTIES PURPOSE "Required for translations support" diff --git a/README b/README index d40b4c9c6..5bed62234 100644 --- a/README +++ b/README @@ -33,6 +33,7 @@ There are several things you should be aware before considering Katie: - no SIMD, zero performance impact with decent compiler - state machine is no more - removed non-open source DB2, OCI, TDS and InterBase database drivers + - removed PostgreSQL and MySQL database drivers - removed 3rd party sources that are very common nowdays - dropped non-open source and discontinued platforms support - dropped dnotify filesystem watcher support diff --git a/appveyor.yml b/appveyor.yml index 27d133d47..0841e5b42 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,9 +1,6 @@ version: 4.11.0-{branch}-{build} image: Ubuntu2004 clone_depth: 1 -services: - - mysql - - postgresql cache: - /home/appveyor/.ccache @@ -17,8 +14,7 @@ build_script: sudo apt-get install -qq libpcre3-dev libssl-dev zlib1g-dev libzstd-dev libc6-dev libpng-dev \ libjpeg-dev libtiff-dev libcups2-dev libfreetype6-dev libfontconfig1-dev libdbus-1-dev \ - libicu-dev unixodbc-dev libpq-dev libmariadbclient-dev libmariadbd-dev liblz4-dev \ - libsqlite3-dev xorg-dev dbus-x11 libjansson-dev ccache + libicu-dev unixodbc-dev libsqlite3-dev xorg-dev dbus-x11 libjansson-dev ccache export PATH="/usr/lib/ccache/:$PATH" diff --git a/cmake/modules/FindMySQL.cmake b/cmake/modules/FindMySQL.cmake deleted file mode 100644 index b4fa7ac79..000000000 --- a/cmake/modules/FindMySQL.cmake +++ /dev/null @@ -1,48 +0,0 @@ -# - Try to find MySQL -# Once done this will define -# -# MYSQL_FOUND - system has MySQL -# MYSQL_INCLUDES - the MySQL include directory -# MYSQL_LIBRARIES - the libraries needed to use MySQL -# -# Copyright (C) 2015, Ivailo Monev, -# -# Redistribution and use is allowed according to the terms of the BSD license. - -include(FindPkgConfig) -include(FindPackageHandleStandardArgs) - -# Only MariaDB provides pkg-config files and only in recent versions -pkg_check_modules(PC_MYSQL QUIET libmariadb) - -# However, both provide config program -find_program(MYSQL_CONFIG - NAMES mariadb_config mysql_config - HINTS $ENV{MYSQLDIR}/bin -) - -if(MYSQL_CONFIG) - execute_process( - COMMAND ${MYSQL_CONFIG} --version - OUTPUT_VARIABLE MYSQL_VERSION - OUTPUT_STRIP_TRAILING_WHITESPACE - ) -endif() - -find_path(MYSQL_INCLUDES - NAMES mysql.h - PATH_SUFFIXES mariadb mysql - HINTS $ENV{MYSQLDIR}/include ${PC_MYSQL_INCLUDEDIR} -) - -find_library(MYSQL_LIBRARIES - NAMES mariadbd mysqld - HINTS $ENV{MYSQLDIR}/lib ${PC_MYSQL_LIBDIR} -) - -find_package_handle_standard_args(MySQL - VERSION_VAR MYSQL_VERSION - REQUIRED_VARS MYSQL_LIBRARIES MYSQL_INCLUDES -) - -mark_as_advanced(MYSQL_INCLUDES MYSQL_LIBRARIES) diff --git a/cmake/modules/FindPostgreSQL.cmake b/cmake/modules/FindPostgreSQL.cmake deleted file mode 100644 index d5233a261..000000000 --- a/cmake/modules/FindPostgreSQL.cmake +++ /dev/null @@ -1,33 +0,0 @@ -# - Try to find PostgreSQL database engine -# Once done this will define -# -# POSTGRESQL_FOUND - system has PostgreSQL database engine -# POSTGRESQL_INCLUDES - the PostgreSQL database engine include directory -# POSTGRESQL_LIBRARIES - the libraries needed to use PostgreSQL database engine -# -# Copyright (C) 2020, Ivailo Monev, -# -# Redistribution and use is allowed according to the terms of the BSD license. - -include(FindPkgConfig) -include(FindPackageHandleStandardArgs) - -pkg_check_modules(PC_POSTGRESQL QUIET libpq) - -find_path(POSTGRESQL_INCLUDES - NAMES libpq-fe.h - PATH_SUFFIXES postgresql - HINTS $ENV{POSTGRESQLDIR}/include ${PC_POSTGRESQL_INCLUDEDIR} -) - -find_library(POSTGRESQL_LIBRARIES - NAMES pq - HINTS $ENV{POSTGRESQLDIR}/lib ${PC_POSTGRESQL_LIBDIR} -) - -find_package_handle_standard_args(PostgreSQL - VERSION_VAR PC_POSTGRESQL_VERSION - REQUIRED_VARS POSTGRESQL_LIBRARIES POSTGRESQL_INCLUDES -) - -mark_as_advanced(POSTGRESQL_INCLUDES POSTGRESQL_LIBRARIES) diff --git a/package/archlinux/PKGBUILD b/package/archlinux/PKGBUILD index c70019db8..d2fb48c9f 100644 --- a/package/archlinux/PKGBUILD +++ b/package/archlinux/PKGBUILD @@ -12,10 +12,8 @@ url='https://github.com/fluxer/katie' license=('LGPL' 'BSD') depends=('libsm' 'libxcursor' 'libxinerama' 'icu' 'libcups' 'libxrandr' 'sqlite' 'fontconfig' 'xdg-utils' 'jansson') -makedepends=('cmake' 'git' 'postgresql' 'mariadb-libs' 'unixodbc' 'unifdef') -optdepends=('postgresql-libs: PostgreSQL driver' - 'mariadb-libs: MariaDB driver' - 'unixodbc: ODBC driver') +makedepends=('cmake' 'git' 'unixodbc' 'unifdef') +optdepends=('unixodbc: ODBC driver') source=("git+https://github.com/fluxer/katie") sha1sums=('SKIP') conflicts=('katie') diff --git a/package/debian/control b/package/debian/control index f8294c91a..465fc120a 100644 --- a/package/debian/control +++ b/package/debian/control @@ -10,14 +10,13 @@ Build-Depends: debhelper (>= 9~), libssl-dev, zlib1g-dev, libzstd-dev, libcups2-dev, libfreetype6-dev, libfontconfig1-dev, libpcre3-dev, libdbus-1-dev, unixodbc-dev, libicu-dev, libsqlite3-dev, cmake, git, xserver-xorg-dev, libxinerama-dev, libxrandr-dev, libxrender-dev, - libxcursor-dev, libsm-dev, libpq-dev, libmariadbclient-dev, libmariadbd-dev, - unifdef | dpkg + libxcursor-dev, libsm-dev, unifdef | dpkg Package: katie-runtime Architecture: amd64 arm64 armel armhf i386 mips mips64el mipsel ppc64el s390x hurd-i386 Section: x11 Depends: ${shlibs:Depends}, ${misc:Depends}, xdg-utils -Recommends: unixodbc, libpq5, libmariadbclient, xserver-xorg-core +Recommends: unixodbc, xserver-xorg-core Description: C++ toolkit derived from the Qt 4.8 framework Katie is continuation of the Qt4 C++ toolkit with the goal to keep it alive, clean it up, fix some bugs and backport some features from Qt5. It is based diff --git a/package/fedora/katie.spec b/package/fedora/katie.spec index 6bd8310fd..6757cfc69 100644 --- a/package/fedora/katie.spec +++ b/package/fedora/katie.spec @@ -7,7 +7,7 @@ Summary: C++ toolkit derived from the Qt 4.8 framework License: BSD and LGPLv2+ URL: https://github.com/fluxer/katie -BuildRequires: gcc-c++ cmake libicu-devel libzstd-devel jansson-devel zlib-devel libsq3-devel libpng-devel freetype-devel pcre-devel openssl-devel libX11-devel libXinerama-devel libXrandr-devel libXrender-devel libXfixes-devel libXcursor-devel libSM-devel libICE-devel dbus-devel libtiff-devel libjpeg-turbo-devel fontconfig-devel cups-devel libiodbc-devel libpq-devel mariadb-embedded-devel unifdef +BuildRequires: gcc-c++ cmake libicu-devel libzstd-devel jansson-devel zlib-devel libsq3-devel libpng-devel freetype-devel pcre-devel openssl-devel libX11-devel libXinerama-devel libXrandr-devel libXrender-devel libXfixes-devel libXcursor-devel libSM-devel libICE-devel dbus-devel libtiff-devel libjpeg-turbo-devel fontconfig-devel cups-devel libiodbc-devel unifdef Requires: xdg-utils Requires(post): /sbin/ldconfig Requires(postun): /sbin/ldconfig diff --git a/package/freebsd/Makefile b/package/freebsd/Makefile index 4243381db..f8bdb40f5 100644 --- a/package/freebsd/Makefile +++ b/package/freebsd/Makefile @@ -25,20 +25,11 @@ LIB_DEPENDS = libzstd.so:archivers/zstd libicuuc.so:devel/icu \ libcups.so:print/cups libiodbc.so:databases/libiodbc CMAKE_ARGS = -DKATIE_TOOLS_SUFFIX="-katie" -OPTIONS_DEFINE = NLS MYSQL PGSQL +OPTIONS_DEFINE = NLS OPTIONS_SUB = yes NLS_DESC = Build translator and translations NLS_USES = gettext NLS_CMAKE_ON = -DWITH_INTL=TRUE NLS_CMAKE_OFF = -DWITH_INTL=FALSE -MYSQL_DESC = Build MySQL database plugin -MYSQL_USES = mysql -MYSQL_CMAKE_ON = -DWITH_MYSQL=TRUE -MYSQL_CMAKE_OFF = -DWITH_MYSQL=FALSE -PGSQL_DESC = Build PostgreSQL database plugin -PGSQL_USES = pgsql -WANT_PGSQL = client -PGSQL_CMAKE_ON = -DWITH_POSTGRESQL=TRUE -PGSQL_CMAKE_OFF = -DWITH_POSTGRESQL=FALSE .include diff --git a/package/freebsd/pkg-plist b/package/freebsd/pkg-plist index f720f75a3..c10bd2a93 100644 --- a/package/freebsd/pkg-plist +++ b/package/freebsd/pkg-plist @@ -1459,8 +1459,6 @@ lib/katie/plugins/imageformats/libqtga.so lib/katie/plugins/imageformats/libqtiff.so lib/katie/plugins/script/libqtscriptdbus.so lib/katie/plugins/sqldrivers/libqsqlodbc.so -%%MYSQL%%lib/katie/plugins/sqldrivers/libqsqlmysql.so -%%PGSQL%%lib/katie/plugins/sqldrivers/libqsqlpsql.so lib/libKtCore.so lib/libKtCore.so.4.11 lib/libKtCore.so.4.11.0 diff --git a/package/netbsd/Makefile b/package/netbsd/Makefile index dd3819f93..0a5fd8d18 100644 --- a/package/netbsd/Makefile +++ b/package/netbsd/Makefile @@ -23,8 +23,6 @@ DL_AUTO_VARS = yes DEPENDS = xdg-utils-[0-9]*:../../misc/xdg-utils -.include "options.mk" - .include "../../sysutils/desktop-file-utils/desktopdb.mk" .include "../../archivers/zstd/buildlink3.mk" .include "../../textproc/jansson/buildlink3.mk" diff --git a/package/netbsd/PLIST b/package/netbsd/PLIST index 4ef58e4a3..aeae55d87 100644 --- a/package/netbsd/PLIST +++ b/package/netbsd/PLIST @@ -1461,9 +1461,7 @@ lib/katie/plugins/imageformats/libqsvg.so lib/katie/plugins/imageformats/libqtga.so lib/katie/plugins/imageformats/libqtiff.so lib/katie/plugins/script/libqtscriptdbus.so -${PLIST.mysql}lib/katie/plugins/sqldrivers/libqsqlmysql.so lib/katie/plugins/sqldrivers/libqsqlodbc.so -${PLIST.pgsql}lib/katie/plugins/sqldrivers/libqsqlpsql.so lib/libKtCore.so lib/libKtCore.so.4.11 lib/libKtCore.so.4.11.0 diff --git a/package/netbsd/options.mk b/package/netbsd/options.mk deleted file mode 100644 index ba469ddf5..000000000 --- a/package/netbsd/options.mk +++ /dev/null @@ -1,25 +0,0 @@ -# $NetBSD$ - -PKG_OPTIONS_VAR = PKG_OPTIONS.katie -PKG_SUPPORTED_OPTIONS = mysql pgsql -PKG_SUGGESTED_OPTIONS = - -.include "../../mk/bsd.options.mk" - -PLIST_VARS += mysql pgsql - -.if !empty(PKG_OPTIONS:Mmysql) -CMAKE_ARGS += -DWITH_MYSQL=TRUE -PLIST.mysql = yes -. include "../../mk/mysql.buildlink3.mk" -.else -CMAKE_ARGS += -DWITH_MYSQL=FALSE -.endif - -.if !empty(PKG_OPTIONS:Mpgsql) -CMAKE_ARGS += -DWITH_POSTGRESQL=TRUE -PLIST.pgsql = yes -. include "../../mk/pgsql.buildlink3.mk" -.else -CMAKE_ARGS += -DWITH_POSTGRESQL=FALSE -.endif diff --git a/scripts/minsize.sh b/scripts/minsize.sh index 790320b95..e112407f9 100755 --- a/scripts/minsize.sh +++ b/scripts/minsize.sh @@ -8,8 +8,8 @@ rm -rf "$cwd/../minsize" mkdir -p "$cwd/../minsize" cd "$cwd/../minsize" -export CFLAGS="$CFLAGS -flto" -export CXXFLAGS="$CXXFLAGS -flto -fno-exceptions" +# export CFLAGS="$CFLAGS -flto" +# export CXXFLAGS="$CXXFLAGS -flto -fno-exceptions" cmake ../ -DCMAKE_BUILD_TYPE=MinSizeRel \ -DCMAKE_INSTALL_PREFIX=/usr $@ diff --git a/src/plugins/CMakeLists.txt b/src/plugins/CMakeLists.txt index 6778ad4be..099b54c0b 100644 --- a/src/plugins/CMakeLists.txt +++ b/src/plugins/CMakeLists.txt @@ -49,15 +49,9 @@ endif() set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/plugins/sqldrivers") set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/plugins/sqldrivers") -if(WITH_MYSQL AND MYSQL_FOUND) - add_subdirectory(sqldrivers/mysql) -endif() if(WITH_ODBC AND ODBC_FOUND) add_subdirectory(sqldrivers/odbc) endif() -if(WITH_POSTGRESQL AND POSTGRESQL_FOUND) - add_subdirectory(sqldrivers/psql) -endif() set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/plugins/designer") diff --git a/src/plugins/sqldrivers/mysql/CMakeLists.txt b/src/plugins/sqldrivers/mysql/CMakeLists.txt deleted file mode 100644 index 88cde056c..000000000 --- a/src/plugins/sqldrivers/mysql/CMakeLists.txt +++ /dev/null @@ -1,24 +0,0 @@ -set(MYSQLCDRIVER_HEADERS - ${CMAKE_CURRENT_SOURCE_DIR}/qsql_mysql.h -) - -set(MYSQLCDRIVER_SOURCES - ${CMAKE_CURRENT_SOURCE_DIR}/mysqlmain.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/qsql_mysql.cpp -) - -include_directories(${MYSQL_INCLUDES}) - -katie_setup_target(qsqlmysqlplugin ${MYSQLCDRIVER_SOURCES} ${MYSQLCDRIVER_HEADERS}) - -add_library(qsqlmysqlplugin MODULE ${qsqlmysqlplugin_SOURCES}) -target_link_libraries(qsqlmysqlplugin KtSql ${MYSQL_LIBRARIES}) -set_target_properties(qsqlmysqlplugin PROPERTIES OUTPUT_NAME qsqlmysql) - -katie_setup_plugin(qsqlmysqlplugin) - -install( - TARGETS qsqlmysqlplugin - DESTINATION ${KATIE_PLUGINS_PATH}/sqldrivers - COMPONENT Runtime -) diff --git a/src/plugins/sqldrivers/mysql/mysqlmain.cpp b/src/plugins/sqldrivers/mysql/mysqlmain.cpp deleted file mode 100644 index c7aebd4da..000000000 --- a/src/plugins/sqldrivers/mysql/mysqlmain.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Copyright (C) 2016 Ivailo Monev -** -** This file is part of the plugins of the Katie Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** -** GNU Lesser General Public License Usage -** 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. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qsqldriverplugin.h" -#include "qstringlist.h" -#include "qsql_mysql.h" - -QT_BEGIN_NAMESPACE - -class QMYSQLDriverPlugin : public QSqlDriverPlugin -{ -public: - QMYSQLDriverPlugin(); - - QSqlDriver* create(const QString &); - QStringList keys() const; -}; - -QMYSQLDriverPlugin::QMYSQLDriverPlugin() - : QSqlDriverPlugin() -{ -} - -QSqlDriver* QMYSQLDriverPlugin::create(const QString &name) -{ - if (name == QLatin1String("QMYSQL") || name == QLatin1String("QMYSQL3")) { - QMYSQLDriver* driver = new QMYSQLDriver(); - return driver; - } - return 0; -} - -QStringList QMYSQLDriverPlugin::keys() const -{ - static const QStringList list = QStringList() - << QLatin1String("QMYSQL3") - << QLatin1String("QMYSQL"); - return list; -} - -Q_EXPORT_PLUGIN2(qsqlmysql, QMYSQLDriverPlugin) - -QT_END_NAMESPACE diff --git a/src/plugins/sqldrivers/mysql/qsql_mysql.cpp b/src/plugins/sqldrivers/mysql/qsql_mysql.cpp deleted file mode 100644 index 6d44e7451..000000000 --- a/src/plugins/sqldrivers/mysql/qsql_mysql.cpp +++ /dev/null @@ -1,1396 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Copyright (C) 2016 Ivailo Monev -** -** This file is part of the QtSql module of the Katie Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** -** GNU Lesser General Public License Usage -** 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. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qsql_mysql.h" - -#include "qcoreapplication.h" -#include "qvariant.h" -#include "qdatetime.h" -#include "qsqlerror.h" -#include "qsqlfield.h" -#include "qsqlindex.h" -#include "qsqlquery.h" -#include "qsqlrecord.h" -#include "qstringlist.h" -#include "qtextcodec.h" -#include "qvector.h" -#include "qdebug.h" - -// comment the next line out if you want to use MySQL/embedded. -// note that it will crash if you don't link to the mysql/e library! -// #define Q_NO_MYSQL_EMBEDDED - -Q_DECLARE_METATYPE(MYSQL_RES*) -Q_DECLARE_METATYPE(MYSQL*) -Q_DECLARE_METATYPE(MYSQL_STMT*) - -QT_BEGIN_NAMESPACE - -class QMYSQLDriverPrivate -{ -public: - QMYSQLDriverPrivate() : mysql(nullptr), -#ifndef QT_NO_TEXTCODEC - tc(QTextCodec::codecForLocale()) -#else - tc(nullptr) -#endif - { } - MYSQL *mysql; - QTextCodec *tc; -}; - -static inline QString toUnicode(QTextCodec *tc, const char *str) -{ -#ifdef QT_NO_TEXTCODEC - Q_UNUSED(tc); - return QString::fromLatin1(str); -#else - return tc->toUnicode(str); -#endif -} - -static inline QString toUnicode(QTextCodec *tc, const char *str, int length) -{ -#ifdef QT_NO_TEXTCODEC - Q_UNUSED(tc); - return QString::fromLatin1(str, length); -#else - return tc->toUnicode(str, length); -#endif -} - -static inline QByteArray fromUnicode(QTextCodec *tc, const QString &str) -{ -#ifdef QT_NO_TEXTCODEC - Q_UNUSED(tc); - return str.toLatin1(); -#else - return tc->fromUnicode(str); -#endif -} - -static inline QVariant qDateFromString(const QString &val) -{ -#ifdef QT_NO_DATESTRING - Q_UNUSED(val); - return QVariant(val); -#else - if (val.isEmpty()) - return QVariant(QDate()); - return QVariant(QDate::fromString(val, Qt::ISODate)); -#endif -} - -static inline QVariant qTimeFromString(const QString &val) -{ -#ifdef QT_NO_DATESTRING - Q_UNUSED(val); - return QVariant(val); -#else - if (val.isEmpty()) - return QVariant(QTime()); - return QVariant(QTime::fromString(val, Qt::ISODate)); -#endif -} - -static inline QVariant qDateTimeFromString(QString &val) -{ -#ifdef QT_NO_DATESTRING - Q_UNUSED(val); - return QVariant(val); -#else - if (val.isEmpty()) - return QVariant(QDateTime()); - if (val.length() == 14) - // TIMESTAMPS have the format yyyyMMddhhmmss - val.insert(4, QLatin1Char('-')).insert(7, QLatin1Char('-')).insert(10, - QLatin1Char('T')).insert(13, QLatin1Char(':')).insert(16, QLatin1Char(':')); - return QVariant(QDateTime::fromString(val, Qt::ISODate)); -#endif -} - -class QMYSQLResultPrivate : public QObject -{ - Q_OBJECT -public: - QMYSQLResultPrivate(const QMYSQLDriver* dp, const QMYSQLResult* d) : driver(dp), result(nullptr), - q(d), rowsAffected(0), hasBlobs(false) - , stmt(nullptr), meta(nullptr), inBinds(nullptr), outBinds(nullptr) - , preparedQuery(false) - { - connect(dp, SIGNAL(destroyed()), this, SLOT(driverDestroyed())); - } - - const QMYSQLDriver* driver; - MYSQL_RES *result; - MYSQL_ROW row; - const QMYSQLResult* q; - - int rowsAffected; - - bool bindInValues(); - void bindBlobs(); - - bool hasBlobs; - struct QMyField - { - QMyField() - : outField(nullptr), nullIndicator(false), bufLength(0ul), - myField(nullptr), type(QVariant::Invalid) - {} - char *outField; - my_bool nullIndicator; - ulong bufLength; - MYSQL_FIELD *myField; - QVariant::Type type; - }; - - QVector fields; - - MYSQL_STMT* stmt; - MYSQL_RES* meta; - - MYSQL_BIND *inBinds; - MYSQL_BIND *outBinds; - - bool preparedQuery; - -private Q_SLOTS: - void driverDestroyed() { driver = NULL; } -}; - -#ifndef QT_NO_TEXTCODEC -static QTextCodec* codec(MYSQL* mysql) -{ - QTextCodec* heuristicCodec = QTextCodec::codecForName(mysql_character_set_name(mysql)); - if (heuristicCodec) - return heuristicCodec; - return QTextCodec::codecForLocale(); -} -#endif // QT_NO_TEXTCODEC - -static QSqlError qMakeError(const QString& err, QSqlError::ErrorType type, - const QMYSQLDriverPrivate* p) -{ - const char *cerr = p->mysql ? mysql_error(p->mysql) : 0; - return QSqlError(QLatin1String("QMYSQL: ") + err, - p->tc ? toUnicode(p->tc, cerr) : QString::fromLatin1(cerr), - type, mysql_errno(p->mysql)); -} - - -static QVariant::Type qDecodeMYSQLType(int mysqltype, uint flags) -{ - QVariant::Type type; - switch (mysqltype) { - case FIELD_TYPE_TINY : - case FIELD_TYPE_SHORT : - case FIELD_TYPE_LONG : - case FIELD_TYPE_INT24 : - type = (flags & UNSIGNED_FLAG) ? QVariant::UInt : QVariant::Int; - break; - case FIELD_TYPE_YEAR : - type = QVariant::Int; - break; - case FIELD_TYPE_LONGLONG : - type = (flags & UNSIGNED_FLAG) ? QVariant::ULongLong : QVariant::LongLong; - break; - case FIELD_TYPE_FLOAT : - case FIELD_TYPE_DOUBLE : - case FIELD_TYPE_DECIMAL : -#if defined(FIELD_TYPE_NEWDECIMAL) - case FIELD_TYPE_NEWDECIMAL: -#endif - type = QVariant::Double; - break; - case FIELD_TYPE_DATE : - type = QVariant::Date; - break; - case FIELD_TYPE_TIME : - type = QVariant::Time; - break; - case FIELD_TYPE_DATETIME : - case FIELD_TYPE_TIMESTAMP : - type = QVariant::DateTime; - break; - case FIELD_TYPE_STRING : - case FIELD_TYPE_VAR_STRING : - case FIELD_TYPE_BLOB : - case FIELD_TYPE_TINY_BLOB : - case FIELD_TYPE_MEDIUM_BLOB : - case FIELD_TYPE_LONG_BLOB : - type = (flags & BINARY_FLAG) ? QVariant::ByteArray : QVariant::String; - break; - default: - case FIELD_TYPE_ENUM : - case FIELD_TYPE_SET : - type = QVariant::String; - break; - } - return type; -} - -static QSqlField qToField(MYSQL_FIELD *field, QTextCodec *tc) -{ - QSqlField f(toUnicode(tc, field->name), - qDecodeMYSQLType(int(field->type), field->flags)); - f.setRequired(IS_NOT_NULL(field->flags)); - f.setLength(field->length); - f.setPrecision(field->decimals); - f.setSqlType(field->type); - f.setAutoValue(field->flags & AUTO_INCREMENT_FLAG); - return f; -} - -static QSqlError qMakeStmtError(const QString& err, QSqlError::ErrorType type, - MYSQL_STMT* stmt) -{ - const char *cerr = mysql_stmt_error(stmt); - return QSqlError(QLatin1String("QMYSQL3: ") + err, - QString::fromLatin1(cerr), - type, mysql_stmt_errno(stmt)); -} - -static bool qIsBlob(int t) -{ - return t == MYSQL_TYPE_TINY_BLOB - || t == MYSQL_TYPE_BLOB - || t == MYSQL_TYPE_MEDIUM_BLOB - || t == MYSQL_TYPE_LONG_BLOB; -} - -static bool qIsInteger(int t) -{ - return t == MYSQL_TYPE_TINY - || t == MYSQL_TYPE_SHORT - || t == MYSQL_TYPE_LONG - || t == MYSQL_TYPE_LONGLONG - || t == MYSQL_TYPE_INT24; -} - - -void QMYSQLResultPrivate::bindBlobs() -{ - for(int i = 0; i < fields.count(); ++i) { - MYSQL_FIELD *fieldInfo = fields.at(i).myField; - if (qIsBlob(inBinds[i].buffer_type) && meta && fieldInfo) { - MYSQL_BIND *bind = &inBinds[i]; - bind->buffer_length = fieldInfo->max_length; - delete[] static_cast(bind->buffer); - bind->buffer = new char[fieldInfo->max_length]; - fields[i].outField = static_cast(bind->buffer); - } - } -} - -bool QMYSQLResultPrivate::bindInValues() -{ - if (!meta) - meta = mysql_stmt_result_metadata(stmt); - if (!meta) - return false; - - fields.resize(mysql_num_fields(meta)); - - inBinds = new MYSQL_BIND[fields.size()]; - memset(inBinds, 0, fields.size() * sizeof(MYSQL_BIND)); - - int i = 0; - MYSQL_FIELD *fieldInfo; - while((fieldInfo = mysql_fetch_field(meta))) { - QMyField &f = fields[i]; - f.myField = fieldInfo; - - f.type = qDecodeMYSQLType(fieldInfo->type, fieldInfo->flags); - if (qIsBlob(fieldInfo->type)) { - // the size of a blob-field is available as soon as we call - // mysql_stmt_store_result() - // after mysql_stmt_exec() in QMYSQLResult::exec() - fieldInfo->length = 0; - hasBlobs = true; - } else { - // fieldInfo->length specifies the display width, which may be too - // small to hold valid integer values (see - // http://dev.mysql.com/doc/refman/5.0/en/numeric-types.html ), so - // always use the MAX_BIGINT_WIDTH for integer types - if (qIsInteger(fieldInfo->type)) { - fieldInfo->length = MAX_BIGINT_WIDTH; - } - fieldInfo->type = MYSQL_TYPE_STRING; - } - MYSQL_BIND *bind = &inBinds[i]; - char *field = new char[fieldInfo->length + 1]; - memset(field, 0, fieldInfo->length + 1); - - bind->buffer_type = fieldInfo->type; - bind->buffer = field; - bind->buffer_length = f.bufLength = fieldInfo->length + 1; - bind->is_null = &f.nullIndicator; - bind->length = &f.bufLength; - f.outField=field; - - ++i; - } - return true; -} - -QMYSQLResult::QMYSQLResult(const QMYSQLDriver* db) -: QSqlResult(db), d(new QMYSQLResultPrivate(db, this)) -{ -} - -QMYSQLResult::~QMYSQLResult() -{ - cleanup(); - delete d; -} - -QVariant QMYSQLResult::handle() const -{ - if(d->preparedQuery) - return d->meta ? QVariant::fromValue(d->meta) : qVariantFromValue(d->stmt); - return QVariant::fromValue(d->result); -} - -void QMYSQLResult::cleanup() -{ - if (d->result) - mysql_free_result(d->result); - -// must iterate trough leftover result sets from multi-selects or stored procedures -// if this isn't done subsequent queries will fail with "Commands out of sync" - while (d->driver && d->driver->d->mysql && mysql_next_result(d->driver->d->mysql) == 0) { - MYSQL_RES *res = mysql_store_result(d->driver->d->mysql); - if (res) - mysql_free_result(res); - } - - if (d->stmt) { - if (mysql_stmt_close(d->stmt)) - qWarning("QMYSQLResult::cleanup: unable to free statement handle"); - d->stmt = 0; - } - - if (d->meta) { - mysql_free_result(d->meta); - d->meta = 0; - } - - for (int i = 0; i < d->fields.count(); ++i) - delete[] d->fields[i].outField; - - if (d->outBinds) { - delete[] d->outBinds; - d->outBinds = 0; - } - - if (d->inBinds) { - delete[] d->inBinds; - d->inBinds = 0; - } - - d->hasBlobs = false; - d->fields.clear(); - d->result = NULL; - d->row = NULL; - setAt(-1); - setActive(false); -} - -bool QMYSQLResult::fetch(int i) -{ - if(!d->driver) - return false; - if (isForwardOnly()) { // fake a forward seek - if (at() < i) { - int x = i - at(); - while (--x && fetchNext()) {}; - return fetchNext(); - } else { - return false; - } - } - if (at() == i) - return true; - if (d->preparedQuery) { - mysql_stmt_data_seek(d->stmt, i); - - int rc = mysql_stmt_fetch(d->stmt); - if (rc) { -#ifdef MYSQL_DATA_TRUNCATED - if (rc == 1 || rc == MYSQL_DATA_TRUNCATED) -#else - if (rc == 1) -#endif - setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult", - "Unable to fetch data"), QSqlError::StatementError, d->stmt)); - return false; - } - } else { - mysql_data_seek(d->result, i); - d->row = mysql_fetch_row(d->result); - if (!d->row) - return false; - } - - setAt(i); - return true; -} - -bool QMYSQLResult::fetchNext() -{ - if(!d->driver) - return false; - if (d->preparedQuery) { - int rc = mysql_stmt_fetch(d->stmt); - if (rc) { -#ifdef MYSQL_DATA_TRUNCATED - if (rc == 1 || rc == MYSQL_DATA_TRUNCATED) -#else - if (rc == 1) -#endif // MYSQL_DATA_TRUNCATED - setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult", - "Unable to fetch data"), QSqlError::StatementError, d->stmt)); - return false; - } - } else { - d->row = mysql_fetch_row(d->result); - if (!d->row) - return false; - } - setAt(at() + 1); - return true; -} - -bool QMYSQLResult::fetchLast() -{ - if(!d->driver) - return false; - if (isForwardOnly()) { // fake this since MySQL can't seek on forward only queries - bool success = fetchNext(); // did we move at all? - while (fetchNext()) {}; - return success; - } - - my_ulonglong numRows; - if (d->preparedQuery) { - numRows = mysql_stmt_num_rows(d->stmt); - } else { - numRows = mysql_num_rows(d->result); - } - if (at() == int(numRows)) - return true; - if (!numRows) - return false; - return fetch(numRows - 1); -} - -bool QMYSQLResult::fetchFirst() -{ - if (at() == 0) - return true; - - if (isForwardOnly()) - return (at() == QSql::BeforeFirstRow) ? fetchNext() : false; - return fetch(0); -} - -QVariant QMYSQLResult::data(int field) const -{ - - if (!isSelect() || field >= d->fields.count()) { - qWarning("QMYSQLResult::data: column %d out of range", field); - return QVariant(); - } - - if (!d->driver) - return QVariant(); - - int fieldLength = 0; - const QMYSQLResultPrivate::QMyField &f = d->fields.at(field); - QString val; - if (d->preparedQuery) { - if (f.nullIndicator) - return QVariant(f.type); - - if (f.type != QVariant::ByteArray) - val = toUnicode(d->driver->d->tc, f.outField, f.bufLength); - } else { - if (d->row[field] == NULL) { - // NULL value - return QVariant(f.type); - } - fieldLength = mysql_fetch_lengths(d->result)[field]; - if (f.type != QVariant::ByteArray) - val = toUnicode(d->driver->d->tc, d->row[field], fieldLength); - } - - switch(f.type) { - case QVariant::LongLong: - return QVariant(val.toLongLong()); - case QVariant::ULongLong: - return QVariant(val.toULongLong()); - case QVariant::Int: - return QVariant(val.toInt()); - case QVariant::UInt: - return QVariant(val.toUInt()); - case QVariant::Double: { - QVariant v; - bool ok=false; - double dbl = val.toDouble(&ok); - switch(numericalPrecisionPolicy()) { - case QSql::LowPrecisionInt32: - v=QVariant(dbl).toInt(); - break; - case QSql::LowPrecisionInt64: - v = QVariant(dbl).toLongLong(); - break; - case QSql::LowPrecisionDouble: - v = QVariant(dbl); - break; - case QSql::HighPrecision: - default: - v = val; - ok = true; - break; - } - if(ok) - return v; - else - return QVariant(); - } - return QVariant(val.toDouble()); - case QVariant::Date: - return qDateFromString(val); - case QVariant::Time: - return qTimeFromString(val); - case QVariant::DateTime: - return qDateTimeFromString(val); - case QVariant::ByteArray: { - - QByteArray ba; - if (d->preparedQuery) { - ba = QByteArray(f.outField, f.bufLength); - } else { - ba = QByteArray(d->row[field], fieldLength); - } - return QVariant(ba); - } - default: - case QVariant::String: - return QVariant(val); - } - qWarning("QMYSQLResult::data: unknown data type"); - return QVariant(); -} - -bool QMYSQLResult::isNull(int field) const -{ - if (d->preparedQuery) - return d->fields.at(field).nullIndicator; - return d->row[field] == NULL; -} - -bool QMYSQLResult::reset (const QString& query) -{ - if (!driver() || !driver()->isOpen() || driver()->isOpenError() || !d->driver) - return false; - - d->preparedQuery = false; - - cleanup(); - - const QByteArray encQuery(fromUnicode(d->driver->d->tc, query)); - if (mysql_real_query(d->driver->d->mysql, encQuery.data(), encQuery.length())) { - setLastError(qMakeError(QCoreApplication::translate("QMYSQLResult", "Unable to execute query"), - QSqlError::StatementError, d->driver->d)); - return false; - } - d->result = mysql_store_result(d->driver->d->mysql); - if (!d->result && mysql_field_count(d->driver->d->mysql) > 0) { - setLastError(qMakeError(QCoreApplication::translate("QMYSQLResult", "Unable to store result"), - QSqlError::StatementError, d->driver->d)); - return false; - } - int numFields = mysql_field_count(d->driver->d->mysql); - setSelect(numFields != 0); - d->fields.resize(numFields); - d->rowsAffected = mysql_affected_rows(d->driver->d->mysql); - - if (isSelect()) { - for(int i = 0; i < numFields; i++) { - MYSQL_FIELD* field = mysql_fetch_field_direct(d->result, i); - d->fields[i].type = qDecodeMYSQLType(field->type, field->flags); - } - setAt(QSql::BeforeFirstRow); - } - setActive(true); - return isActive(); -} - -int QMYSQLResult::size() const -{ - if (d->driver && isSelect()) { - if (d->preparedQuery) { - return mysql_stmt_num_rows(d->stmt); - } - return int(mysql_num_rows(d->result)); - } - return -1; -} - -int QMYSQLResult::numRowsAffected() const -{ - return d->rowsAffected; -} - -QVariant QMYSQLResult::lastInsertId() const -{ - if (!isActive() || !d->driver) - return QVariant(); - - if (d->preparedQuery) { - quint64 id = mysql_stmt_insert_id(d->stmt); - if (id) - return QVariant(id); - } else { - quint64 id = mysql_insert_id(d->driver->d->mysql); - if (id) - return QVariant(id); - } - return QVariant(); -} - -QSqlRecord QMYSQLResult::record() const -{ - QSqlRecord info; - if (!isActive() || !isSelect() || !d->driver) - return info; - - MYSQL_RES *res = d->preparedQuery ? d->meta : d->result; - - if (!mysql_errno(d->driver->d->mysql)) { - mysql_field_seek(res, 0); - MYSQL_FIELD* field = mysql_fetch_field(res); - while(field) { - info.append(qToField(field, d->driver->d->tc)); - field = mysql_fetch_field(res); - } - } - mysql_field_seek(res, 0); - return info; -} - -bool QMYSQLResult::nextResult() -{ - if (!d->driver) - return false; - - setAt(-1); - setActive(false); - - if (d->result && isSelect()) - mysql_free_result(d->result); - d->result = nullptr; - setSelect(false); - - for (int i = 0; i < d->fields.count(); ++i) - delete[] d->fields[i].outField; - d->fields.clear(); - - int status = mysql_next_result(d->driver->d->mysql); - if (status > 0) { - setLastError(qMakeError(QCoreApplication::translate("QMYSQLResult", "Unable to execute next query"), - QSqlError::StatementError, d->driver->d)); - return false; - } else if (status == -1) { - return false; // No more result sets - } - - d->result = mysql_store_result(d->driver->d->mysql); - int numFields = mysql_field_count(d->driver->d->mysql); - if (!d->result && numFields > 0) { - setLastError(qMakeError(QCoreApplication::translate("QMYSQLResult", "Unable to store next result"), - QSqlError::StatementError, d->driver->d)); - return false; - } - - setSelect(numFields > 0); - d->fields.resize(numFields); - d->rowsAffected = mysql_affected_rows(d->driver->d->mysql); - - if (isSelect()) { - for (int i = 0; i < numFields; i++) { - MYSQL_FIELD* field = mysql_fetch_field_direct(d->result, i); - d->fields[i].type = qDecodeMYSQLType(field->type, field->flags); - } - } - - setActive(true); - return true; -} - -void QMYSQLResult::virtual_hook(int id, void *data) -{ - switch (id) { - case QSqlResult::NextResult: - Q_ASSERT(data); - *static_cast(data) = nextResult(); - break; - default: - QSqlResult::virtual_hook(id, data); - } -} - -static MYSQL_TIME *toMySqlDate(QDate date, QTime time, QVariant::Type type) -{ - Q_ASSERT(type == QVariant::Time || type == QVariant::Date - || type == QVariant::DateTime); - - MYSQL_TIME *myTime = new MYSQL_TIME; - memset(myTime, 0, sizeof(MYSQL_TIME)); - - if (type == QVariant::Time || type == QVariant::DateTime) { - myTime->hour = time.hour(); - myTime->minute = time.minute(); - myTime->second = time.second(); - myTime->second_part = time.msec(); - } - if (type == QVariant::Date || type == QVariant::DateTime) { - myTime->year = date.year(); - myTime->month = date.month(); - myTime->day = date.day(); - } - - return myTime; -} - -bool QMYSQLResult::prepare(const QString& query) -{ - if(!d->driver) - return false; - cleanup(); - - if (query.isEmpty()) - return false; - - if (!d->stmt) - d->stmt = mysql_stmt_init(d->driver->d->mysql); - if (!d->stmt) { - setLastError(qMakeError(QCoreApplication::translate("QMYSQLResult", "Unable to prepare statement"), - QSqlError::StatementError, d->driver->d)); - return false; - } - - const QByteArray encQuery(fromUnicode(d->driver->d->tc, query)); - int rc = mysql_stmt_prepare(d->stmt, encQuery.constData(), encQuery.length()); - if (rc != 0) { - setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult", - "Unable to prepare statement"), QSqlError::StatementError, d->stmt)); - cleanup(); - return false; - } - - if (mysql_stmt_param_count(d->stmt) > 0) {// allocate memory for outvalues - d->outBinds = new MYSQL_BIND[mysql_stmt_param_count(d->stmt)]; - } - - setSelect(d->bindInValues()); - d->preparedQuery = true; - return true; -} - -bool QMYSQLResult::exec() -{ - if (!d->driver) - return false; - if (!d->preparedQuery) - return QSqlResult::exec(); - if (!d->stmt) - return false; - - QVector timeVector; - QVector stringVector; - QVector nullVector; - - const QVector values = boundValues(); - - int rc = mysql_stmt_reset(d->stmt); - if (rc != 0) { - setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult", - "Unable to reset statement"), QSqlError::StatementError, d->stmt)); - return false; - } - - if (mysql_stmt_param_count(d->stmt) > 0 && - mysql_stmt_param_count(d->stmt) == (uint)values.count()) { - - nullVector.resize(values.count()); - for (int i = 0; i < values.count(); ++i) { - const QVariant &val = boundValues().at(i); - void *data = const_cast(val.constData()); - - MYSQL_BIND *currBind = &d->outBinds[i]; - - nullVector[i] = static_cast(val.isNull()); - currBind->is_null = &nullVector[i]; - currBind->length = 0; - currBind->is_unsigned = 0; - - switch (val.type()) { - case QVariant::ByteArray: - currBind->buffer_type = MYSQL_TYPE_BLOB; - currBind->buffer = const_cast(val.toByteArray().constData()); - currBind->buffer_length = val.toByteArray().size(); - break; - - case QVariant::Time: - case QVariant::Date: - case QVariant::DateTime: { - MYSQL_TIME *myTime = toMySqlDate(val.toDate(), val.toTime(), val.type()); - timeVector.append(myTime); - - currBind->buffer = myTime; - switch(val.type()) { - case QVariant::Time: - currBind->buffer_type = MYSQL_TYPE_TIME; - myTime->time_type = MYSQL_TIMESTAMP_TIME; - break; - case QVariant::Date: - currBind->buffer_type = MYSQL_TYPE_DATE; - myTime->time_type = MYSQL_TIMESTAMP_DATE; - break; - case QVariant::DateTime: - currBind->buffer_type = MYSQL_TYPE_DATETIME; - myTime->time_type = MYSQL_TIMESTAMP_DATETIME; - break; - default: - break; - } - currBind->buffer_length = sizeof(MYSQL_TIME); - currBind->length = 0; - break; } - case QVariant::UInt: - case QVariant::Int: - currBind->buffer_type = MYSQL_TYPE_LONG; - currBind->buffer = data; - currBind->buffer_length = sizeof(int); - currBind->is_unsigned = (val.type() != QVariant::Int); - break; - case QVariant::Bool: - currBind->buffer_type = MYSQL_TYPE_TINY; - currBind->buffer = data; - currBind->buffer_length = sizeof(bool); - currBind->is_unsigned = false; - break; - case QVariant::Double: - currBind->buffer_type = MYSQL_TYPE_DOUBLE; - currBind->buffer = data; - currBind->buffer_length = sizeof(double); - break; - case QVariant::LongLong: - case QVariant::ULongLong: - currBind->buffer_type = MYSQL_TYPE_LONGLONG; - currBind->buffer = data; - currBind->buffer_length = sizeof(qint64); - currBind->is_unsigned = (val.type() == QVariant::ULongLong); - break; - case QVariant::String: - default: { - QByteArray ba = fromUnicode(d->driver->d->tc, val.toString()); - stringVector.append(ba); - currBind->buffer_type = MYSQL_TYPE_STRING; - currBind->buffer = const_cast(ba.constData()); - currBind->buffer_length = ba.length(); - break; } - } - } - - rc = mysql_stmt_bind_param(d->stmt, d->outBinds); - if (rc != 0) { - setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult", - "Unable to bind value"), QSqlError::StatementError, d->stmt)); - qDeleteAll(timeVector); - return false; - } - } - rc = mysql_stmt_execute(d->stmt); - - qDeleteAll(timeVector); - - if (rc != 0) { - setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult", - "Unable to execute statement"), QSqlError::StatementError, d->stmt)); - return false; - } - //if there is meta-data there is also data - setSelect(d->meta); - - d->rowsAffected = mysql_stmt_affected_rows(d->stmt); - - if (isSelect()) { - my_bool update_max_length = true; - - rc = mysql_stmt_bind_result(d->stmt, d->inBinds); - if (rc != 0) { - setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult", - "Unable to bind outvalues"), QSqlError::StatementError, d->stmt)); - return false; - } - if (d->hasBlobs) - mysql_stmt_attr_set(d->stmt, STMT_ATTR_UPDATE_MAX_LENGTH, &update_max_length); - - rc = mysql_stmt_store_result(d->stmt); - if (rc != 0) { - setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult", - "Unable to store statement results"), QSqlError::StatementError, d->stmt)); - return false; - } - - if (d->hasBlobs) { - // mysql_stmt_store_result() with STMT_ATTR_UPDATE_MAX_LENGTH set to true crashes - // when called without a preceding call to mysql_stmt_bind_result() - // in versions < 4.1.8 - d->bindBlobs(); - rc = mysql_stmt_bind_result(d->stmt, d->inBinds); - if (rc != 0) { - setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult", - "Unable to bind outvalues"), QSqlError::StatementError, d->stmt)); - return false; - } - } - setAt(QSql::BeforeFirstRow); - } - setActive(true); - return true; -} - -///////////////////////////////////////////////////////// - -static int qMySqlConnectionCount = 0; - -static inline void qLibraryInit() -{ -#if !defined(Q_NO_MYSQL_EMBEDDED) - if (qMySqlConnectionCount > 1) - return; - -# if MYSQL_VERSION_ID < 50000 || MYSQL_VERSION_ID >= 50003 - if (mysql_library_init(0, nullptr, nullptr)) { -# else - if (mysql_server_init(0, nullptr, nullptr)) { -# endif - qWarning("QMYSQLDriver::qServerInit: unable to start server."); - } -#endif // Q_NO_MYSQL_EMBEDDED - -#ifdef MARIADB_BASE_VERSION - qAddPostRoutine(mysql_server_end); -#endif -} - -static inline void qLibraryEnd() -{ -#if !defined(Q_NO_MYSQL_EMBEDDED) && !defined(MARIADB_BASE_VERSION) -# if MYSQL_VERSION_ID < 50000 || MYSQL_VERSION_ID >= 50003 - mysql_library_end(); -# else - mysql_server_end(); -# endif -#endif -} - -QMYSQLDriver::QMYSQLDriver(QObject * parent) - : QSqlDriver(parent), d(new QMYSQLDriverPrivate()) -{ - qMySqlConnectionCount++; - qLibraryInit(); -} - -QMYSQLDriver::~QMYSQLDriver() -{ - qMySqlConnectionCount--; - if (qMySqlConnectionCount == 0) - qLibraryEnd(); - delete d; -} - -bool QMYSQLDriver::hasFeature(DriverFeature f) const -{ - switch (f) { - case Transactions: -// CLIENT_TRANSACTION should be defined in all recent mysql client libs > 3.23.34 -#ifdef CLIENT_TRANSACTIONS - if (d->mysql) { - if ((d->mysql->server_capabilities & CLIENT_TRANSACTIONS) == CLIENT_TRANSACTIONS) - return true; - } -#endif - return false; - case NamedPlaceholders: - case BatchOperations: - case SimpleLocking: - case EventNotifications: - case FinishQuery: - return false; - case QuerySize: - case BLOB: - case LastInsertId: - case Unicode: - case LowPrecisionNumbers: - return true; - case PreparedQueries: - case PositionalPlaceholders: - return true; - case MultipleResultSets: - return true; - } - return false; -} - -static void setOptionFlag(uint &optionFlags, const QString &opt) -{ - if (opt == QLatin1String("CLIENT_COMPRESS")) - optionFlags |= CLIENT_COMPRESS; - else if (opt == QLatin1String("CLIENT_FOUND_ROWS")) - optionFlags |= CLIENT_FOUND_ROWS; - else if (opt == QLatin1String("CLIENT_IGNORE_SPACE")) - optionFlags |= CLIENT_IGNORE_SPACE; - else if (opt == QLatin1String("CLIENT_INTERACTIVE")) - optionFlags |= CLIENT_INTERACTIVE; - else if (opt == QLatin1String("CLIENT_NO_SCHEMA")) - optionFlags |= CLIENT_NO_SCHEMA; - else if (opt == QLatin1String("CLIENT_ODBC")) - optionFlags |= CLIENT_ODBC; - else if (opt == QLatin1String("CLIENT_SSL")) - optionFlags |= CLIENT_SSL; - else - qWarning("QMYSQLDriver::open: Unknown connect option '%s'", opt.toLocal8Bit().constData()); -} - -bool QMYSQLDriver::open(const QString& db, - const QString& user, - const QString& password, - const QString& host, - int port, - const QString& connOpts) -{ - if (isOpen()) - close(); - - /* This is a hack to get MySQL's stored procedure support working. - Since a stored procedure _may_ return multiple result sets, - we have to enable CLIEN_MULTI_STATEMENTS here, otherwise _any_ - stored procedure call will fail. - */ - unsigned int optionFlags = CLIENT_MULTI_STATEMENTS; - const QStringList opts(connOpts.split(QLatin1Char(';'), QString::SkipEmptyParts)); - QString unixSocket; -#if MYSQL_VERSION_ID >= 50000 - my_bool reconnect=false; -#endif - - // extract the real options from the string - for (int i = 0; i < opts.count(); ++i) { - QString tmp(opts.at(i).simplified()); - int idx = tmp.indexOf(QLatin1Char('=')); - if (idx != -1) { - QString val = tmp.mid(idx + 1).simplified(); - QString opt = tmp.left(idx).simplified(); - if (opt == QLatin1String("UNIX_SOCKET")) - unixSocket = val; -#if MYSQL_VERSION_ID >= 50000 - else if (opt == QLatin1String("MYSQL_OPT_RECONNECT")) { - if (val == QLatin1String("TRUE") || val == QLatin1String("1") || val.isEmpty()) - reconnect = true; - } -#endif - else if (val == QLatin1String("TRUE") || val == QLatin1String("1")) - setOptionFlag(optionFlags, tmp.left(idx).simplified()); - else - qWarning("QMYSQLDriver::open: Illegal connect option value '%s'", - tmp.toLocal8Bit().constData()); - } else { - setOptionFlag(optionFlags, tmp); - } - } - - if ((d->mysql = mysql_init(nullptr)) && - mysql_real_connect(d->mysql, - host.isNull() ? static_cast(0) - : host.toLocal8Bit().constData(), - user.isNull() ? static_cast(0) - : user.toLocal8Bit().constData(), - password.isNull() ? static_cast(0) - : password.toLocal8Bit().constData(), - db.isNull() ? static_cast(0) - : db.toLocal8Bit().constData(), - (port > -1) ? port : 0, - unixSocket.isNull() ? static_cast(0) - : unixSocket.toLocal8Bit().constData(), - optionFlags)) - { - if (!db.isEmpty() && mysql_select_db(d->mysql, db.toLocal8Bit().constData())) { - setLastError(qMakeError(tr("Unable to open database '") + db + - QLatin1Char('\''), QSqlError::ConnectionError, d)); - mysql_close(d->mysql); - setOpenError(true); - return false; - } -#if MYSQL_VERSION_ID >= 50000 - if(reconnect) - mysql_options(d->mysql, MYSQL_OPT_RECONNECT, &reconnect); -#endif - } else { - setLastError(qMakeError(tr("Unable to connect"), - QSqlError::ConnectionError, d)); - mysql_close(d->mysql); - d->mysql = NULL; - setOpenError(true); - return false; - } - -#if MYSQL_VERSION_ID < 50000 || MYSQL_VERSION_ID >= 50007 - // force the communication to be utf8 - mysql_set_character_set(d->mysql, "utf8"); -#endif -#ifndef QT_NO_TEXTCODEC - d->tc = codec(d->mysql); -#endif - - mysql_thread_init(); - - - setOpen(true); - setOpenError(false); - return true; -} - -void QMYSQLDriver::close() -{ - if (isOpen()) { - mysql_thread_end(); - mysql_close(d->mysql); - d->mysql = nullptr; - setOpen(false); - setOpenError(false); - } -} - -QSqlResult *QMYSQLDriver::createResult() const -{ - return new QMYSQLResult(this); -} - -QStringList QMYSQLDriver::tables(QSql::TableType type) const -{ - QStringList tl; - if (mysql_get_server_version(d->mysql) < 50000) { - if (!isOpen()) - return tl; - if (!(type & QSql::Tables)) - return tl; - - MYSQL_RES* tableRes = mysql_list_tables(d->mysql, NULL); - int i = 0; - while (tableRes) { - mysql_data_seek(tableRes, i); - MYSQL_ROW row = mysql_fetch_row(tableRes); - if (!row) - break; - tl.append(toUnicode(d->tc, row[0])); - i++; - } - mysql_free_result(tableRes); - } else { - QSqlQuery q(createResult()); - if(type & QSql::Tables) { - QString sql = QLatin1String("select table_name from information_schema.tables where table_schema = '") + QLatin1String(d->mysql->db) + QLatin1String("' and table_type = 'BASE TABLE'"); - q.exec(sql); - - while(q.next()) - tl.append(q.value(0).toString()); - } - if(type & QSql::Views) { - QString sql = QLatin1String("select table_name from information_schema.tables where table_schema = '") + QLatin1String(d->mysql->db) + QLatin1String("' and table_type = 'VIEW'"); - q.exec(sql); - - while(q.next()) - tl.append(q.value(0).toString()); - } - } - return tl; -} - -QSqlIndex QMYSQLDriver::primaryIndex(const QString& tablename) const -{ - QSqlIndex idx; - if (!isOpen()) - return idx; - - QSqlQuery query(createResult()); - QString stmt(QLatin1String("show index from %1;")); - QSqlRecord fil = record(tablename); - query.exec(stmt.arg(tablename)); - while (query.isActive() && query.next()) { - if (query.value(2).toString() == QLatin1String("PRIMARY")) { - idx.append(fil.field(query.value(4).toString())); - idx.setCursorName(query.value(0).toString()); - idx.setName(query.value(2).toString()); - } - } - - return idx; -} - -QSqlRecord QMYSQLDriver::record(const QString& tablename) const -{ - QString table=tablename; - if(isIdentifierEscaped(table, QSqlDriver::TableName)) - table = stripDelimiters(table, QSqlDriver::TableName); - - QSqlRecord info; - if (!isOpen()) - return info; - MYSQL_RES* r = mysql_list_fields(d->mysql, table.toLocal8Bit().constData(), 0); - if (!r) { - return info; - } - - MYSQL_FIELD* field; - while ((field = mysql_fetch_field(r))) - info.append(qToField(field, d->tc)); - mysql_free_result(r); - return info; -} - -QVariant QMYSQLDriver::handle() const -{ - return QVariant::fromValue(d->mysql); -} - -bool QMYSQLDriver::beginTransaction() -{ -#ifndef CLIENT_TRANSACTIONS - return false; -#endif - if (!isOpen()) { - qWarning("QMYSQLDriver::beginTransaction: Database not open"); - return false; - } - if (mysql_query(d->mysql, "BEGIN WORK")) { - setLastError(qMakeError(tr("Unable to begin transaction"), - QSqlError::StatementError, d)); - return false; - } - return true; -} - -bool QMYSQLDriver::commitTransaction() -{ -#ifndef CLIENT_TRANSACTIONS - return false; -#endif - if (!isOpen()) { - qWarning("QMYSQLDriver::commitTransaction: Database not open"); - return false; - } - if (mysql_query(d->mysql, "COMMIT")) { - setLastError(qMakeError(tr("Unable to commit transaction"), - QSqlError::StatementError, d)); - return false; - } - return true; -} - -bool QMYSQLDriver::rollbackTransaction() -{ -#ifndef CLIENT_TRANSACTIONS - return false; -#endif - if (!isOpen()) { - qWarning("QMYSQLDriver::rollbackTransaction: Database not open"); - return false; - } - if (mysql_query(d->mysql, "ROLLBACK")) { - setLastError(qMakeError(tr("Unable to rollback transaction"), - QSqlError::StatementError, d)); - return false; - } - return true; -} - -QString QMYSQLDriver::formatValue(const QSqlField &field, bool trimStrings) const -{ - if (field.isNull()) - return QLatin1String("NULL"); - - QString r; - switch(field.type()) { - case QVariant::String: - // Escape '\' characters - r = QSqlDriver::formatValue(field, trimStrings); - r.replace(QLatin1String("\\"), QLatin1String("\\\\")); - break; - case QVariant::ByteArray: - if (isOpen()) { - const QByteArray ba = field.value().toByteArray(); - // buffer has to be at least length*2+1 bytes - char* buffer = new char[ba.size() * 2 + 1]; - int escapedSize = int(mysql_real_escape_string(d->mysql, buffer, - ba.data(), ba.size())); - r.reserve(escapedSize + 3); - r.append(QLatin1Char('\'')).append(toUnicode(d->tc, buffer)).append(QLatin1Char('\'')); - delete[] buffer; - break; - } else { - qWarning("QMYSQLDriver::formatValue: Database not open"); - } - // fall through - default: - r = QSqlDriver::formatValue(field, trimStrings); - } - return r; -} - -QString QMYSQLDriver::escapeIdentifier(const QString &identifier, IdentifierType) const -{ - QString res = identifier; - if(!identifier.isEmpty() && !identifier.startsWith(QLatin1Char('`')) && !identifier.endsWith(QLatin1Char('`')) ) { - res.prepend(QLatin1Char('`')).append(QLatin1Char('`')); - res.replace(QLatin1Char('.'), QLatin1String("`.`")); - } - return res; -} - -bool QMYSQLDriver::isIdentifierEscaped(const QString &identifier, IdentifierType type) const -{ - Q_UNUSED(type); - return identifier.size() > 2 - && identifier.startsWith(QLatin1Char('`')) //left delimited - && identifier.endsWith(QLatin1Char('`')); //right delimited -} - -QT_END_NAMESPACE - -#include "moc_qsql_mysql.cpp" -#include "moc_qsql_mysql.h" diff --git a/src/plugins/sqldrivers/mysql/qsql_mysql.h b/src/plugins/sqldrivers/mysql/qsql_mysql.h deleted file mode 100644 index 69360320e..000000000 --- a/src/plugins/sqldrivers/mysql/qsql_mysql.h +++ /dev/null @@ -1,106 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Copyright (C) 2016 Ivailo Monev -** -** This file is part of the QtSql module of the Katie Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** -** GNU Lesser General Public License Usage -** 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. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QSQL_MYSQL_H -#define QSQL_MYSQL_H - -#include -#include - -#include - - -QT_BEGIN_NAMESPACE - -class QMYSQLDriverPrivate; -class QMYSQLResultPrivate; -class QMYSQLDriver; -class QSqlRecordInfo; - -class QMYSQLResult : public QSqlResult -{ - friend class QMYSQLDriver; - friend class QMYSQLResultPrivate; -public: - explicit QMYSQLResult(const QMYSQLDriver* db); - ~QMYSQLResult(); - - QVariant handle() const; -protected: - void cleanup(); - bool fetch(int i); - bool fetchNext(); - bool fetchLast(); - bool fetchFirst(); - QVariant data(int field) const; - bool isNull(int field) const; - bool reset (const QString& query); - int size() const; - int numRowsAffected() const; - QVariant lastInsertId() const; - QSqlRecord record() const; - void virtual_hook(int id, void *data); - bool nextResult(); - - bool prepare(const QString& stmt); - bool exec(); -private: - QMYSQLResultPrivate* d; -}; - -class QMYSQLDriver : public QSqlDriver -{ - Q_OBJECT - friend class QMYSQLResult; -public: - explicit QMYSQLDriver(QObject *parent=0); - ~QMYSQLDriver(); - bool hasFeature(DriverFeature f) const; - bool open(const QString & db, - const QString & user, - const QString & password, - const QString & host, - int port, - const QString& connOpts); - void close(); - QSqlResult *createResult() const; - QStringList tables(QSql::TableType) const; - QSqlIndex primaryIndex(const QString& tablename) const; - QSqlRecord record(const QString& tablename) const; - QString formatValue(const QSqlField &field, - bool trimStrings) const; - QVariant handle() const; - QString escapeIdentifier(const QString &identifier, IdentifierType type) const; - - bool isIdentifierEscaped(const QString &identifier, IdentifierType type) const; - -protected: - bool beginTransaction(); - bool commitTransaction(); - bool rollbackTransaction(); -private: - QMYSQLDriverPrivate* d; -}; - -QT_END_NAMESPACE - - -#endif // QSQL_MYSQL_H diff --git a/src/plugins/sqldrivers/psql/CMakeLists.txt b/src/plugins/sqldrivers/psql/CMakeLists.txt deleted file mode 100644 index ff0f05a15..000000000 --- a/src/plugins/sqldrivers/psql/CMakeLists.txt +++ /dev/null @@ -1,24 +0,0 @@ -set(PSQLDRIVER_HEADERS - ${CMAKE_CURRENT_SOURCE_DIR}/qsql_psql.h -) - -set(PSQLDRIVER_SOURCES - ${CMAKE_CURRENT_SOURCE_DIR}/psqlmain.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/qsql_psql.cpp -) - -include_directories(${POSTGRESQL_INCLUDES}) - -katie_setup_target(qsqlpsqlplugin ${PSQLDRIVER_SOURCES} ${PSQLDRIVER_HEADERS}) - -add_library(qsqlpsqlplugin MODULE ${qsqlpsqlplugin_SOURCES}) -target_link_libraries(qsqlpsqlplugin KtSql ${POSTGRESQL_LIBRARIES}) -set_target_properties(qsqlpsqlplugin PROPERTIES OUTPUT_NAME qsqlpsql) - -katie_setup_plugin(qsqlpsqlplugin) - -install( - TARGETS qsqlpsqlplugin - DESTINATION ${KATIE_PLUGINS_PATH}/sqldrivers - COMPONENT Runtime -) diff --git a/src/plugins/sqldrivers/psql/psqlmain.cpp b/src/plugins/sqldrivers/psql/psqlmain.cpp deleted file mode 100644 index 9cfb8cb83..000000000 --- a/src/plugins/sqldrivers/psql/psqlmain.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Copyright (C) 2016 Ivailo Monev -** -** This file is part of the plugins of the Katie Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** -** GNU Lesser General Public License Usage -** 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. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qsqldriverplugin.h" -#include "qstringlist.h" -#include "qsql_psql.h" - -QT_BEGIN_NAMESPACE - -class QPSQLDriverPlugin : public QSqlDriverPlugin -{ -public: - QPSQLDriverPlugin(); - - QSqlDriver* create(const QString &); - QStringList keys() const; -}; - -QPSQLDriverPlugin::QPSQLDriverPlugin() - : QSqlDriverPlugin() -{ -} - -QSqlDriver* QPSQLDriverPlugin::create(const QString &name) -{ - if (name == QLatin1String("QPSQL") || name == QLatin1String("QPSQL7")) { - QPSQLDriver* driver = new QPSQLDriver(); - return driver; - } - return 0; -} - -QStringList QPSQLDriverPlugin::keys() const -{ - static const QStringList list = QStringList() - << QLatin1String("QPSQL7") - << QLatin1String("QPSQL"); - return list; -} - -Q_EXPORT_PLUGIN2(qsqlpsql, QPSQLDriverPlugin) - -QT_END_NAMESPACE diff --git a/src/plugins/sqldrivers/psql/qsql_psql.cpp b/src/plugins/sqldrivers/psql/qsql_psql.cpp deleted file mode 100644 index 72da469b9..000000000 --- a/src/plugins/sqldrivers/psql/qsql_psql.cpp +++ /dev/null @@ -1,1245 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Copyright (C) 2016 Ivailo Monev -** -** This file is part of the QtSql module of the Katie Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** -** GNU Lesser General Public License Usage -** 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. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qsql_psql.h" - -#include "qcoreapplication.h" -#include "qvariant.h" -#include "qdatetime.h" -#include "qregexp.h" -#include "qsqlerror.h" -#include "qsqlfield.h" -#include "qsqlindex.h" -#include "qsqlrecord.h" -#include "qsqlquery.h" -#include "qsocketnotifier.h" -#include "qstringlist.h" -#include "qmutex.h" -#include "qnumeric.h" - -#include - -// workaround for postgres defining their OIDs in a private header file -#define QBOOLOID 16 -#define QINT8OID 20 -#define QINT2OID 21 -#define QINT4OID 23 -#define QNUMERICOID 1700 -#define QFLOAT4OID 700 -#define QFLOAT8OID 701 -#define QABSTIMEOID 702 -#define QRELTIMEOID 703 -#define QDATEOID 1082 -#define QTIMEOID 1083 -#define QTIMETZOID 1266 -#define QTIMESTAMPOID 1114 -#define QTIMESTAMPTZOID 1184 -#define QOIDOID 2278 -#define QBYTEAOID 17 -#define QREGPROCOID 24 -#define QXIDOID 28 -#define QCIDOID 29 - -/* This is a compile time switch - if PQfreemem is declared, the compiler will use that one, - otherwise it'll run in this template */ -template -inline void PQfreemem(T *t, int = 0) { free(t); } - -Q_DECLARE_METATYPE(PGconn*) -Q_DECLARE_METATYPE(PGresult*) - -QT_BEGIN_NAMESPACE - -inline void qPQfreemem(void *buffer) -{ - PQfreemem(buffer); -} - -class QPSQLDriverPrivate -{ -public: - QPSQLDriverPrivate(QPSQLDriver *qq) - : q(qq), - connection(0), - isUtf8(false), - pro(QPSQLDriver::Version74), - sn(0), - pendingNotifyCheck(false), - hasBackslashEscape(false) - { } - - QPSQLDriver *q; - PGconn *connection; - bool isUtf8; - QPSQLDriver::Protocol pro; - QSocketNotifier *sn; - QStringList seid; - mutable bool pendingNotifyCheck; - bool hasBackslashEscape; - - void appendTables(QStringList &tl, QSqlQuery &t, QChar type); - PGresult * exec(const char * stmt) const; - PGresult * exec(const QString & stmt) const; - QPSQLDriver::Protocol getPSQLVersion(); - bool setEncodingUtf8(); - void setDatestyle(); - void detectBackslashEscape(); -}; - -void QPSQLDriverPrivate::appendTables(QStringList &tl, QSqlQuery &t, QChar type) -{ - QString query = QString::fromLatin1("select pg_class.relname, pg_namespace.nspname from pg_class " - "left join pg_namespace on (pg_class.relnamespace = pg_namespace.oid) " - "where (pg_class.relkind = '%1') and (pg_class.relname !~ '^Inv') " - "and (pg_class.relname !~ '^pg_') " - "and (pg_namespace.nspname != 'information_schema') ").arg(type); - t.exec(query); - while (t.next()) { - QString schema = t.value(1).toString(); - if (schema.isEmpty() || schema == QLatin1String("public")) - tl.append(t.value(0).toString()); - else - tl.append(t.value(0).toString().prepend(QLatin1Char('.')).prepend(schema)); - } -} - -PGresult * QPSQLDriverPrivate::exec(const char * stmt) const -{ - PGresult *result = PQexec(connection, stmt); - if (seid.size() && !pendingNotifyCheck) { - pendingNotifyCheck = true; - QMetaObject::invokeMethod(q, "_q_handleNotification", Qt::QueuedConnection, Q_ARG(int,0)); - } - return result; -} - -PGresult * QPSQLDriverPrivate::exec(const QString & stmt) const -{ - return exec(isUtf8 ? stmt.toUtf8().constData() : stmt.toLocal8Bit().constData()); -} - -class QPSQLResultPrivate -{ -public: - QPSQLResultPrivate(QPSQLResult *qq): q(qq), driver(0), result(0), currentSize(-1), preparedQueriesEnabled(false) {} - - QPSQLResult *q; - const QPSQLDriverPrivate *driver; - PGresult *result; - int currentSize; - bool preparedQueriesEnabled; - QString preparedStmtId; - - bool processResults(); -}; - -static QSqlError qMakeError(const QString& err, QSqlError::ErrorType type, - const QPSQLDriverPrivate *p, PGresult* result = 0) -{ - const char *s = PQerrorMessage(p->connection); - QString msg = p->isUtf8 ? QString::fromUtf8(s) : QString::fromLocal8Bit(s); - if (result) { - const char *sCode = PQresultErrorField(result, PG_DIAG_SQLSTATE); - msg += QString::fromLatin1("(%1)").arg(QString::fromLatin1(sCode)); - } - return QSqlError(QLatin1String("QPSQL: ") + err, msg, type); -} - -bool QPSQLResultPrivate::processResults() -{ - if (!result) - return false; - - int status = PQresultStatus(result); - if (status == PGRES_TUPLES_OK) { - q->setSelect(true); - q->setActive(true); - currentSize = PQntuples(result); - return true; - } else if (status == PGRES_COMMAND_OK) { - q->setSelect(false); - q->setActive(true); - currentSize = -1; - return true; - } - q->setLastError(qMakeError(QCoreApplication::translate("QPSQLResult", - "Unable to create query"), QSqlError::StatementError, driver, result)); - return false; -} - -static QVariant::Type qDecodePSQLType(int t) -{ - QVariant::Type type = QVariant::Invalid; - switch (t) { - case QBOOLOID: - type = QVariant::Bool; - break; - case QINT8OID: - type = QVariant::LongLong; - break; - case QINT2OID: - case QINT4OID: - case QOIDOID: - case QREGPROCOID: - case QXIDOID: - case QCIDOID: - type = QVariant::Int; - break; - case QNUMERICOID: - case QFLOAT4OID: - case QFLOAT8OID: - type = QVariant::Double; - break; - case QABSTIMEOID: - case QRELTIMEOID: - case QDATEOID: - type = QVariant::Date; - break; - case QTIMEOID: - case QTIMETZOID: - type = QVariant::Time; - break; - case QTIMESTAMPOID: - case QTIMESTAMPTZOID: - type = QVariant::DateTime; - break; - case QBYTEAOID: - type = QVariant::ByteArray; - break; - default: - type = QVariant::String; - break; - } - return type; -} - -static void qDeallocatePreparedStmt(QPSQLResultPrivate *d) -{ - const QString stmt = QLatin1String("DEALLOCATE ") + d->preparedStmtId; - PGresult *result = d->driver->exec(stmt); - - if (PQresultStatus(result) != PGRES_COMMAND_OK) - qWarning("Unable to free statement: %s", PQerrorMessage(d->driver->connection)); - PQclear(result); - d->preparedStmtId.clear(); -} - -QPSQLResult::QPSQLResult(const QPSQLDriver* db, const QPSQLDriverPrivate* p) - : QSqlResult(db) -{ - d = new QPSQLResultPrivate(this); - d->driver = p; - d->preparedQueriesEnabled = db->hasFeature(QSqlDriver::PreparedQueries); -} - -QPSQLResult::~QPSQLResult() -{ - cleanup(); - - if (d->preparedQueriesEnabled && !d->preparedStmtId.isNull()) - qDeallocatePreparedStmt(d); - - delete d; -} - -QVariant QPSQLResult::handle() const -{ - return QVariant::fromValue(d->result); -} - -void QPSQLResult::cleanup() -{ - if (d->result) - PQclear(d->result); - d->result = 0; - setAt(QSql::BeforeFirstRow); - d->currentSize = -1; - setActive(false); -} - -bool QPSQLResult::fetch(int i) -{ - if (!isActive()) - return false; - if (i < 0) - return false; - if (i >= d->currentSize) - return false; - if (at() == i) - return true; - setAt(i); - return true; -} - -bool QPSQLResult::fetchFirst() -{ - return fetch(0); -} - -bool QPSQLResult::fetchLast() -{ - return fetch(PQntuples(d->result) - 1); -} - -QVariant QPSQLResult::data(int i) const -{ - if (i >= PQnfields(d->result)) { - qWarning("QPSQLResult::data: column %d out of range", i); - return QVariant(); - } - int ptype = PQftype(d->result, i); - QVariant::Type type = qDecodePSQLType(ptype); - const char *val = PQgetvalue(d->result, at(), i); - if (PQgetisnull(d->result, at(), i)) - return QVariant(type); - switch (type) { - case QVariant::Bool: { - return QVariant((bool)(val[0] == 't')); - } - case QVariant::String: { - return d->driver->isUtf8 ? QString::fromUtf8(val) : QString::fromAscii(val); - } - case QVariant::LongLong: { - if (val[0] == '-') - return QString::fromLatin1(val).toLongLong(); - else - return QString::fromLatin1(val).toULongLong(); - } - case QVariant::Int: { - return atoi(val); - } - case QVariant::Double: { - if (ptype == QNUMERICOID) { - if (numericalPrecisionPolicy() != QSql::HighPrecision) { - QVariant retval; - bool convert; - double dbl=QString::fromAscii(val).toDouble(&convert); - if (numericalPrecisionPolicy() == QSql::LowPrecisionInt64) - retval = (qlonglong)dbl; - else if (numericalPrecisionPolicy() == QSql::LowPrecisionInt32) - retval = (int)dbl; - else if (numericalPrecisionPolicy() == QSql::LowPrecisionDouble) - retval = dbl; - if (!convert) - return QVariant(); - return retval; - } - return QString::fromAscii(val); - } - if (qstricmp(val, "Infinity") == 0) - return qInf(); - if (qstricmp(val, "-Infinity") == 0) - return -qInf(); - return QString::fromAscii(val).toDouble(); - } - case QVariant::Date: { - if (val[0] == '\0') { - return QVariant(QDate()); - } else { -#ifndef QT_NO_DATESTRING - return QVariant(QDate::fromString(QString::fromLatin1(val), Qt::ISODate)); -#else - return QVariant(QString::fromLatin1(val)); -#endif - } - } - case QVariant::Time: { - const QString str = QString::fromLatin1(val); -#ifndef QT_NO_DATESTRING - if (str.isEmpty()) - return QVariant(QTime()); - if (str.at(str.length() - 3) == QLatin1Char('+') || str.at(str.length() - 3) == QLatin1Char('-')) - // strip the timezone - // TODO: fix this when timestamp support comes into QDateTime - return QVariant(QTime::fromString(str.left(str.length() - 3), Qt::ISODate)); - return QVariant(QTime::fromString(str, Qt::ISODate)); -#else - return QVariant(str); -#endif - } - case QVariant::DateTime: { - QString dtval = QString::fromLatin1(val); -#ifndef QT_NO_DATESTRING - if (dtval.length() < 10) - return QVariant(QDateTime()); - // remove the timezone - // TODO: fix this when timestamp support comes into QDateTime - if (dtval.at(dtval.length() - 3) == QLatin1Char('+') || dtval.at(dtval.length() - 3) == QLatin1Char('-')) - dtval.chop(3); - // milliseconds are sometimes returned with 2 digits only - if (dtval.at(dtval.length() - 3).isPunct()) - dtval += QLatin1Char('0'); - if (dtval.isEmpty()) - return QVariant(QDateTime()); - else - return QVariant(QDateTime::fromString(dtval, Qt::ISODate)); -#else - return QVariant(dtval); -#endif - } - case QVariant::ByteArray: { - size_t len; - unsigned char *data = PQunescapeBytea((unsigned char*)val, &len); - QByteArray ba((const char*)data, len); - qPQfreemem(data); - return QVariant(ba); - } - default: - case QVariant::Invalid: - qWarning("QPSQLResult::data: unknown data type"); - } - return QVariant(); -} - -bool QPSQLResult::isNull(int field) const -{ - PQgetvalue(d->result, at(), field); - return PQgetisnull(d->result, at(), field); -} - -bool QPSQLResult::reset(const QString& query) -{ - cleanup(); - if (!driver()) - return false; - if (!driver()->isOpen() || driver()->isOpenError()) - return false; - d->result = d->driver->exec(query); - return d->processResults(); -} - -int QPSQLResult::size() const -{ - return d->currentSize; -} - -int QPSQLResult::numRowsAffected() const -{ - return QString::fromLatin1(PQcmdTuples(d->result)).toInt(); -} - -QVariant QPSQLResult::lastInsertId() const -{ - if (isActive()) { - Oid id = PQoidValue(d->result); - if (id != InvalidOid) - return QVariant(id); - } - return QVariant(); -} - -QSqlRecord QPSQLResult::record() const -{ - QSqlRecord info; - if (!isActive() || !isSelect()) - return info; - - int count = PQnfields(d->result); - for (int i = 0; i < count; ++i) { - QSqlField f; - if (d->driver->isUtf8) - f.setName(QString::fromUtf8(PQfname(d->result, i))); - else - f.setName(QString::fromLocal8Bit(PQfname(d->result, i))); - f.setType(qDecodePSQLType(PQftype(d->result, i))); - int len = PQfsize(d->result, i); - int precision = PQfmod(d->result, i); - // swap length and precision if length == -1 - if (len == -1 && precision > -1) { - len = precision - 4; - precision = -1; - } - f.setLength(len); - f.setPrecision(precision); - f.setSqlType(PQftype(d->result, i)); - info.append(f); - } - return info; -} - -static QString qReplacePlaceholderMarkers(const QString &query) -{ - const int originalLength = query.length(); - bool inQuote = false; - int markerIdx = 0; - QString result; - result.reserve(originalLength + 23); - for (int i = 0; i < originalLength; ++i) { - const QChar ch = query.at(i); - if (ch == QLatin1Char('?') && !inQuote) { - result += QLatin1Char('$'); - result += QString::number(++markerIdx); - } else { - if (ch == QLatin1Char('\'')) - inQuote = !inQuote; - result += ch; - } - } - - result.squeeze(); - return result; -} - -static QString qCreateParamString(const QVector &boundValues, const QSqlDriver *driver) -{ - if (boundValues.isEmpty()) - return QString(); - - QString params; - QSqlField f; - for (int i = 0; i < boundValues.count(); ++i) { - const QVariant &val = boundValues.at(i); - - f.setType(val.type()); - if (val.isNull()) - f.clear(); - else - f.setValue(val); - if(!params.isNull()) - params.append(QLatin1String(", ")); - params.append(driver->formatValue(f)); - } - return params; -} - -Q_GLOBAL_STATIC(QMutex, qPSqlMutex) -QString qMakePreparedStmtId() -{ - QMutexLocker locker(qPSqlMutex()); - static unsigned int qPreparedStmtCount = 0; - return QString::fromLatin1("qpsqlpstmt_%1").arg(QString::number(++qPreparedStmtCount, 16)); -} - -bool QPSQLResult::prepare(const QString &query) -{ - if (!d->preparedQueriesEnabled) - return QSqlResult::prepare(query); - - cleanup(); - - if (!d->preparedStmtId.isEmpty()) - qDeallocatePreparedStmt(d); - - const QString stmtId = qMakePreparedStmtId(); - const QString stmt = QString::fromLatin1("PREPARE %1 AS ").arg(stmtId).append(qReplacePlaceholderMarkers(query)); - - PGresult *result = d->driver->exec(stmt); - - if (PQresultStatus(result) != PGRES_COMMAND_OK) { - setLastError(qMakeError(QCoreApplication::translate("QPSQLResult", - "Unable to prepare statement"), QSqlError::StatementError, d->driver, result)); - PQclear(result); - d->preparedStmtId.clear(); - return false; - } - - PQclear(result); - d->preparedStmtId = stmtId; - return true; -} - -bool QPSQLResult::exec() -{ - if (!d->preparedQueriesEnabled) - return QSqlResult::exec(); - - cleanup(); - - QString stmt; - const QString params = qCreateParamString(boundValues(), d->q->driver()); - if (params.isEmpty()) - stmt = QString::fromLatin1("EXECUTE %1").arg(d->preparedStmtId); - else - stmt = QString::fromLatin1("EXECUTE %1 (%2)").arg(d->preparedStmtId).arg(params); - - d->result = d->driver->exec(stmt); - - return d->processResults(); -} - -/////////////////////////////////////////////////////////////////// - -bool QPSQLDriverPrivate::setEncodingUtf8() -{ - PGresult* result = exec("SET CLIENT_ENCODING TO 'UNICODE'"); - int status = PQresultStatus(result); - PQclear(result); - return status == PGRES_COMMAND_OK; -} - -void QPSQLDriverPrivate::setDatestyle() -{ - PGresult* result = exec("SET DATESTYLE TO 'ISO'"); - int status = PQresultStatus(result); - if (status != PGRES_COMMAND_OK) - qWarning("%s", PQerrorMessage(connection)); - PQclear(result); -} - -void QPSQLDriverPrivate::detectBackslashEscape() -{ - // standard_conforming_strings option introduced in 8.2 - // http://www.postgresql.org/docs/8.2/static/runtime-config-compatible.html - if (pro < QPSQLDriver::Version82) { - hasBackslashEscape = true; - } else { - hasBackslashEscape = false; - PGresult* result = exec(QLatin1String("SELECT '\\\\' x")); - int status = PQresultStatus(result); - if (status == PGRES_COMMAND_OK || status == PGRES_TUPLES_OK) - if (QString::fromLatin1(PQgetvalue(result, 0, 0)) == QLatin1String("\\")) - hasBackslashEscape = true; - PQclear(result); - } -} - -static QPSQLDriver::Protocol qMakePSQLVersion(int vMaj, int vMin) -{ - switch (vMaj) { - case 7: { - switch (vMin) { - case 4: { - return QPSQLDriver::Version74; - } - default: { - return QPSQLDriver::VersionUnknown; - } - } - } - case 8: { - switch (vMin) { - case 1: { - return QPSQLDriver::Version81; - } - case 2: { - return QPSQLDriver::Version82; - } - case 3: { - return QPSQLDriver::Version83; - } - case 4: { - return QPSQLDriver::Version84; - } - default: { - return QPSQLDriver::Version8; - } - } - } - case 9: { - return QPSQLDriver::Version9; - } - default: { - if (vMaj >= 10) { - return QPSQLDriver::VersionMaybeCompatible; - } - return QPSQLDriver::VersionUnknown; - } - } - Q_UNREACHABLE(); -} - -QPSQLDriver::Protocol QPSQLDriverPrivate::getPSQLVersion() -{ - QPSQLDriver::Protocol serverVersion = QPSQLDriver::Version74; - PGresult* result = exec("select version()"); - int status = PQresultStatus(result); - if (status == PGRES_COMMAND_OK || status == PGRES_TUPLES_OK) { - QString val = QString::fromAscii(PQgetvalue(result, 0, 0)); - - QRegExp rx(QLatin1String("(\\d+)\\.(\\d+)")); - rx.setMinimal(true); // enforce non-greedy RegExp - - if (rx.indexIn(val) != -1) { - int vMaj = rx.cap(1).toInt(); - int vMin = rx.cap(2).toInt(); - serverVersion = qMakePSQLVersion(vMaj, vMin); -#ifdef PG_MAJORVERSION - if (rx.indexIn(QLatin1String(PG_MAJORVERSION)) != -1) { - vMaj = rx.cap(1).toInt(); - vMin = rx.cap(2).toInt(); - } - QPSQLDriver::Protocol clientVersion = qMakePSQLVersion(vMaj, vMin); - - if (serverVersion >= QPSQLDriver::Version9 && clientVersion < QPSQLDriver::Version9) { - //Client version before QPSQLDriver::Version9 only supports escape mode for bytea type, - //but bytea format is set to hex by default in PSQL 9 and above. So need to force the - //server use the old escape mode when connects to the new server with old client library. - result = exec("SET bytea_output=escape; "); - } else if (serverVersion == QPSQLDriver::VersionUnknown) { - serverVersion = clientVersion; - if (serverVersion != QPSQLDriver::VersionUnknown) - qWarning("The server version of this PostgreSQL is unknown, falling back to the client version."); - } -#endif - } - } - PQclear(result); - - //keep the old behavior unchanged - if (serverVersion == QPSQLDriver::VersionUnknown) - serverVersion = QPSQLDriver::Version74; - - if (serverVersion < QPSQLDriver::Version74) { - qWarning("This version of PostgreSQL is not supported and may not work."); - } - - return serverVersion; -} - -QPSQLDriver::QPSQLDriver(QObject *parent) - : QSqlDriver(parent), d(new QPSQLDriverPrivate(this)) -{ -} - -QPSQLDriver::~QPSQLDriver() -{ - if (d->connection) - PQfinish(d->connection); - delete d; -} - -QVariant QPSQLDriver::handle() const -{ - return QVariant::fromValue(d->connection); -} - -bool QPSQLDriver::hasFeature(DriverFeature f) const -{ - switch (f) { - case Transactions: - case QuerySize: - case LastInsertId: - case LowPrecisionNumbers: - case EventNotifications: - return true; - case PreparedQueries: - case PositionalPlaceholders: - return (d->pro >= QPSQLDriver::Version82); - case BatchOperations: - case NamedPlaceholders: - case SimpleLocking: - case FinishQuery: - case MultipleResultSets: - return false; - case BLOB: - return true; - case Unicode: - return d->isUtf8; - } - return false; -} - -/* - Quote a string for inclusion into the connection string - \ -> \\ - ' -> \' - surround string by single quotes - */ -static QString qQuote(QString s) -{ - s.replace(QLatin1Char('\\'), QLatin1String("\\\\")); - s.replace(QLatin1Char('\''), QLatin1String("\\'")); - s.append(QLatin1Char('\'')).prepend(QLatin1Char('\'')); - return s; -} - -bool QPSQLDriver::open(const QString & db, - const QString & user, - const QString & password, - const QString & host, - int port, - const QString& connOpts) -{ - if (isOpen()) - close(); - QString connectString; - if (!host.isEmpty()) - connectString.append(QLatin1String("host=")).append(qQuote(host)); - if (!db.isEmpty()) - connectString.append(QLatin1String(" dbname=")).append(qQuote(db)); - if (!user.isEmpty()) - connectString.append(QLatin1String(" user=")).append(qQuote(user)); - if (!password.isEmpty()) - connectString.append(QLatin1String(" password=")).append(qQuote(password)); - if (port != -1) - connectString.append(QLatin1String(" port=")).append(qQuote(QString::number(port))); - - // add any connect options - the server will handle error detection - if (!connOpts.isEmpty()) { - QString opt = connOpts; - opt.replace(QLatin1Char(';'), QLatin1Char(' '), Qt::CaseInsensitive); - connectString.append(QLatin1Char(' ')).append(opt); - } - - d->connection = PQconnectdb(connectString.toLocal8Bit().constData()); - if (PQstatus(d->connection) == CONNECTION_BAD) { - setLastError(qMakeError(tr("Unable to connect"), QSqlError::ConnectionError, d)); - setOpenError(true); - PQfinish(d->connection); - d->connection = 0; - return false; - } - - d->pro = d->getPSQLVersion(); - d->detectBackslashEscape(); - d->isUtf8 = d->setEncodingUtf8(); - d->setDatestyle(); - - setOpen(true); - setOpenError(false); - return true; -} - -void QPSQLDriver::close() -{ - if (isOpen()) { - - d->seid.clear(); - if (d->sn) { - disconnect(d->sn, SIGNAL(activated(int)), this, SLOT(_q_handleNotification(int))); - delete d->sn; - d->sn = 0; - } - - if (d->connection) - PQfinish(d->connection); - d->connection = 0; - setOpen(false); - setOpenError(false); - } -} - -QSqlResult *QPSQLDriver::createResult() const -{ - return new QPSQLResult(this, d); -} - -bool QPSQLDriver::beginTransaction() -{ - if (!isOpen()) { - qWarning("QPSQLDriver::beginTransaction: Database not open"); - return false; - } - PGresult* res = d->exec("BEGIN"); - if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) { - setLastError(qMakeError(tr("Could not begin transaction"), - QSqlError::TransactionError, d, res)); - PQclear(res); - return false; - } - PQclear(res); - return true; -} - -bool QPSQLDriver::commitTransaction() -{ - if (!isOpen()) { - qWarning("QPSQLDriver::commitTransaction: Database not open"); - return false; - } - PGresult* res = d->exec("COMMIT"); - - bool transaction_failed = false; - - // XXX - // This hack is used to tell if the transaction has succeeded for the protocol versions of - // PostgreSQL below. For 7.x and other protocol versions we are left in the dark. - // This hack can dissapear once there is an API to query this sort of information. - if (d->pro >= QPSQLDriver::Version8) { - transaction_failed = qstrcmp(PQcmdStatus(res), "ROLLBACK") == 0; - } - - if (!res || PQresultStatus(res) != PGRES_COMMAND_OK || transaction_failed) { - setLastError(qMakeError(tr("Could not commit transaction"), - QSqlError::TransactionError, d, res)); - PQclear(res); - return false; - } - PQclear(res); - return true; -} - -bool QPSQLDriver::rollbackTransaction() -{ - if (!isOpen()) { - qWarning("QPSQLDriver::rollbackTransaction: Database not open"); - return false; - } - PGresult* res = d->exec("ROLLBACK"); - if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) { - setLastError(qMakeError(tr("Could not rollback transaction"), - QSqlError::TransactionError, d, res)); - PQclear(res); - return false; - } - PQclear(res); - return true; -} - -QStringList QPSQLDriver::tables(QSql::TableType type) const -{ - QStringList tl; - if (!isOpen()) - return tl; - QSqlQuery t(createResult()); - t.setForwardOnly(true); - - if (type & QSql::Tables) - d->appendTables(tl, t, QLatin1Char('r')); - if (type & QSql::Views) - d->appendTables(tl, t, QLatin1Char('v')); - if (type & QSql::SystemTables) { - t.exec(QLatin1String("select relname from pg_class where (relkind = 'r') " - "and (relname like 'pg_%') ")); - while (t.next()) - tl.append(t.value(0).toString()); - } - - return tl; -} - -static void qSplitTableName(QString &tablename, QString &schema) -{ - int dot = tablename.indexOf(QLatin1Char('.')); - if (dot == -1) - return; - schema = tablename.left(dot); - tablename = tablename.mid(dot + 1); -} - -QSqlIndex QPSQLDriver::primaryIndex(const QString& tablename) const -{ - QSqlIndex idx(tablename); - if (!isOpen()) - return idx; - QSqlQuery i(createResult()); - - QString tbl = tablename; - QString schema; - qSplitTableName(tbl, schema); - - if (isIdentifierEscaped(tbl, QSqlDriver::TableName)) - tbl = stripDelimiters(tbl, QSqlDriver::TableName); - else - tbl = tbl.toLower(); - - if (isIdentifierEscaped(schema, QSqlDriver::TableName)) - schema = stripDelimiters(schema, QSqlDriver::TableName); - else - schema = schema.toLower(); - - if (d->pro == QPSQLDriver::VersionUnknown) { - qFatal("PSQL version is unknown"); - } - - QString stmt = QLatin1String( - "SELECT pg_attribute.attname, pg_attribute.atttypid::int, " - "pg_class.relname " - "FROM pg_attribute, pg_class " - "WHERE %1 pg_class.oid IN " - "(SELECT indexrelid FROM pg_index WHERE indisprimary = true AND indrelid IN " - " (SELECT oid FROM pg_class WHERE relname = '%2')) " - "AND pg_attribute.attrelid = pg_class.oid " - "AND pg_attribute.attisdropped = false " - "ORDER BY pg_attribute.attnum" - ); - if (schema.isEmpty()) - stmt = stmt.arg(QLatin1String("pg_table_is_visible(pg_class.oid) AND")); - else - stmt = stmt.arg(QString::fromLatin1("pg_class.relnamespace = (select oid from " - "pg_namespace where pg_namespace.nspname = '%1') AND ").arg(schema)); - - i.exec(stmt.arg(tbl)); - while (i.isActive() && i.next()) { - QSqlField f(i.value(0).toString(), qDecodePSQLType(i.value(1).toInt())); - idx.append(f); - idx.setName(i.value(2).toString()); - } - return idx; -} - -QSqlRecord QPSQLDriver::record(const QString& tablename) const -{ - QSqlRecord info; - if (!isOpen()) - return info; - - QString tbl = tablename; - QString schema; - qSplitTableName(tbl, schema); - - if (isIdentifierEscaped(tbl, QSqlDriver::TableName)) - tbl = stripDelimiters(tbl, QSqlDriver::TableName); - else - tbl = tbl.toLower(); - - if (isIdentifierEscaped(schema, QSqlDriver::TableName)) - schema = stripDelimiters(schema, QSqlDriver::TableName); - else - schema = schema.toLower(); - - - if (d->pro == QPSQLDriver::VersionUnknown) { - qFatal("PSQL version is unknown"); - } - - QString stmt = QLatin1String( - "select pg_attribute.attname, pg_attribute.atttypid::int, " - "pg_attribute.attnotnull, pg_attribute.attlen, pg_attribute.atttypmod, " - "pg_attrdef.adsrc " - "from pg_class, pg_attribute " - "left join pg_attrdef on (pg_attrdef.adrelid = " - "pg_attribute.attrelid and pg_attrdef.adnum = pg_attribute.attnum) " - "where %1 " - "and pg_class.relname = '%2' " - "and pg_attribute.attnum > 0 " - "and pg_attribute.attrelid = pg_class.oid " - "and pg_attribute.attisdropped = false " - "order by pg_attribute.attnum " - ); - if (schema.isEmpty()) - stmt = stmt.arg(QLatin1String("pg_table_is_visible(pg_class.oid)")); - else - stmt = stmt.arg(QString::fromLatin1("pg_class.relnamespace = (select oid from " - "pg_namespace where pg_namespace.nspname = '%1')").arg(schema)); - - QSqlQuery query(createResult()); - query.exec(stmt.arg(tbl)); - while (query.next()) { - int len = query.value(3).toInt(); - int precision = query.value(4).toInt(); - // swap length and precision if length == -1 - if (len == -1 && precision > -1) { - len = precision - 4; - precision = -1; - } - QString defVal = query.value(5).toString(); - if (!defVal.isEmpty() && defVal.at(0) == QLatin1Char('\'')) - defVal = defVal.mid(1, defVal.length() - 2); - QSqlField f(query.value(0).toString(), qDecodePSQLType(query.value(1).toInt())); - f.setRequired(query.value(2).toBool()); - f.setLength(len); - f.setPrecision(precision); - f.setDefaultValue(defVal); - f.setSqlType(query.value(1).toInt()); - info.append(f); - } - - return info; -} - -QString QPSQLDriver::formatValue(const QSqlField &field, bool trimStrings) const -{ - QString r; - if (field.isNull()) { - r = QLatin1String("NULL"); - } else { - switch (field.type()) { - case QVariant::DateTime: -#ifndef QT_NO_DATESTRING - if (field.value().toDateTime().isValid()) { - QDate dt = field.value().toDateTime().date(); - QTime tm = field.value().toDateTime().time(); - // msecs need to be right aligned otherwise psql - // interpretes them wrong - r = QLatin1Char('\'') + QString::number(dt.year()) + QLatin1Char('-') - + QString::number(dt.month()).rightJustified(2, QLatin1Char('0')) + QLatin1Char('-') - + QString::number(dt.day()).rightJustified(2, QLatin1Char('0')) + QLatin1Char(' ') - + tm.toString() + QLatin1Char('.') - + QString::number(tm.msec()).rightJustified(3, QLatin1Char('0')) - + QLatin1Char('\''); - } else { - r = QLatin1String("NULL"); - } -#else - r = QLatin1String("NULL"); -#endif // QT_NO_DATESTRING - break; - case QVariant::Time: -#ifndef QT_NO_DATESTRING - if (field.value().toTime().isValid()) { - r = QLatin1Char('\'') + field.value().toTime().toString(QLatin1String("hh:mm:ss.zzz")) + QLatin1Char('\''); - } else -#endif - { - r = QLatin1String("NULL"); - } - break; - case QVariant::String: - r = QSqlDriver::formatValue(field, trimStrings); - if (d->hasBackslashEscape) - r.replace(QLatin1String("\\"), QLatin1String("\\\\")); - break; - case QVariant::Bool: - if (field.value().toBool()) - r = QLatin1String("TRUE"); - else - r = QLatin1String("FALSE"); - break; - case QVariant::ByteArray: { - QByteArray ba(field.value().toByteArray()); - size_t len; -#if defined PG_VERSION_NUM && PG_VERSION_NUM-0 >= 80200 - unsigned char *data = PQescapeByteaConn(d->connection, (unsigned char*)ba.constData(), ba.size(), &len); -#else - unsigned char *data = PQescapeBytea((unsigned char*)ba.constData(), ba.size(), &len); -#endif - r += QLatin1Char('\''); - r += QLatin1String((const char*)data); - r += QLatin1Char('\''); - qPQfreemem(data); - break; - } - case QVariant::Double: { - double val = field.value().toDouble(); - if (qIsNaN(val)) { - r = QLatin1String("'NaN'"); - } else if (qIsInf(val)) { - r = (val < 0) ? QLatin1String("'-Infinity'") : QLatin1String("'Infinity'"); - } else { - r = QSqlDriver::formatValue(field, trimStrings); - } - break; - } - default: - r = QSqlDriver::formatValue(field, trimStrings); - break; - } - } - return r; -} - -QString QPSQLDriver::escapeIdentifier(const QString &identifier, IdentifierType) const -{ - QString res = identifier; - if(!identifier.isEmpty() && !identifier.startsWith(QLatin1Char('"')) && !identifier.endsWith(QLatin1Char('"')) ) { - res.replace(QLatin1Char('"'), QLatin1String("\"\"")); - res.prepend(QLatin1Char('"')).append(QLatin1Char('"')); - res.replace(QLatin1Char('.'), QLatin1String("\".\"")); - } - return res; -} - -bool QPSQLDriver::isOpen() const -{ - return PQstatus(d->connection) == CONNECTION_OK; -} - -QPSQLDriver::Protocol QPSQLDriver::protocol() const -{ - return d->pro; -} - -bool QPSQLDriver::subscribeToNotification(const QString &name) -{ - if (!isOpen()) { - qWarning("QPSQLDriver::subscribeToNotification: database not open."); - return false; - } - - if (d->seid.contains(name)) { - qWarning("QPSQLDriver::subscribeToNotification: already subscribing to '%s'.", - qPrintable(name)); - return false; - } - - int socket = PQsocket(d->connection); - if (socket) { - // Add the name to the list of subscriptions here so that QSQLDriverPrivate::exec knows - // to check for notifications immediately after executing the LISTEN - d->seid << name; - QString query = QLatin1String("LISTEN ") + escapeIdentifier(name, QSqlDriver::TableName); - PGresult *result = d->exec(query); - if (PQresultStatus(result) != PGRES_COMMAND_OK) { - setLastError(qMakeError(tr("Unable to subscribe"), QSqlError::StatementError, d, result)); - return false; - } - - if (!d->sn) { - d->sn = new QSocketNotifier(socket, QSocketNotifier::Read); - connect(d->sn, SIGNAL(activated(int)), this, SLOT(_q_handleNotification(int))); - } - } else { - qWarning("QPSQLDriver::subscribeToNotification: PQsocket didn't return a valid socket to listen on"); - return false; - } - - return true; -} - -bool QPSQLDriver::unsubscribeFromNotification(const QString &name) -{ - if (!isOpen()) { - qWarning("QPSQLDriver::unsubscribeFromNotification: database not open."); - return false; - } - - if (!d->seid.contains(name)) { - qWarning("QPSQLDriver::unsubscribeFromNotification: not subscribed to '%s'.", - qPrintable(name)); - return false; - } - - QString query = QLatin1String("UNLISTEN ") + escapeIdentifier(name, QSqlDriver::TableName); - PGresult *result = d->exec(query); - if (PQresultStatus(result) != PGRES_COMMAND_OK) { - setLastError(qMakeError(tr("Unable to unsubscribe"), QSqlError::StatementError, d, result)); - return false; - } - - d->seid.removeAll(name); - - if (d->seid.isEmpty()) { - disconnect(d->sn, SIGNAL(activated(int)), this, SLOT(_q_handleNotification(int))); - delete d->sn; - d->sn = 0; - } - - return true; -} - -QStringList QPSQLDriver::subscribedToNotifications() const -{ - return d->seid; -} - -void QPSQLDriver::_q_handleNotification(int) -{ - d->pendingNotifyCheck = false; - PQconsumeInput(d->connection); - - PGnotify *notify = 0; - while((notify = PQnotifies(d->connection)) != 0) { - QString name(QLatin1String(notify->relname)); - if (d->seid.contains(name)) - emit notification(name); - else - qWarning("QPSQLDriver: received notification for '%s' which isn't subscribed to.", - qPrintable(name)); - - qPQfreemem(notify); - } -} - -QT_END_NAMESPACE - -#include "moc_qsql_psql.h" - diff --git a/src/plugins/sqldrivers/psql/qsql_psql.h b/src/plugins/sqldrivers/psql/qsql_psql.h deleted file mode 100644 index 01aed7f7a..000000000 --- a/src/plugins/sqldrivers/psql/qsql_psql.h +++ /dev/null @@ -1,124 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Copyright (C) 2016 Ivailo Monev -** -** This file is part of the QtSql module of the Katie Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** -** GNU Lesser General Public License Usage -** 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. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QSQL_PSQL_H -#define QSQL_PSQL_H - -#include -#include - -#include -#include - - -QT_BEGIN_NAMESPACE - -class QPSQLResultPrivate; -class QPSQLDriverPrivate; -class QPSQLDriver; -class QSqlRecordInfo; - -class QPSQLResult : public QSqlResult -{ - friend class QPSQLResultPrivate; -public: - QPSQLResult(const QPSQLDriver* db, const QPSQLDriverPrivate* p); - ~QPSQLResult(); - - QVariant handle() const; - -protected: - void cleanup(); - bool fetch(int i); - bool fetchFirst(); - bool fetchLast(); - QVariant data(int i) const; - bool isNull(int field) const; - bool reset (const QString& query); - int size() const; - int numRowsAffected() const; - QSqlRecord record() const; - QVariant lastInsertId() const; - bool prepare(const QString& query); - bool exec(); - -private: - QPSQLResultPrivate *d; -}; - -class QPSQLDriver : public QSqlDriver -{ - Q_OBJECT -public: - enum Protocol { - VersionUnknown = -1, - Version74 = 1, - Version8 = 2, - Version81 = 3, - Version82 = 4, - Version83 = 5, - Version84 = 6, - Version9 = 7, - VersionMaybeCompatible = 32 - }; - - explicit QPSQLDriver(QObject *parent=0); - ~QPSQLDriver(); - bool hasFeature(DriverFeature f) const; - bool open(const QString & db, - const QString & user, - const QString & password, - const QString & host, - int port, - const QString& connOpts); - bool isOpen() const; - void close(); - QSqlResult *createResult() const; - QStringList tables(QSql::TableType) const; - QSqlIndex primaryIndex(const QString& tablename) const; - QSqlRecord record(const QString& tablename) const; - - Protocol protocol() const; - QVariant handle() const; - - QString escapeIdentifier(const QString &identifier, IdentifierType type) const; - QString formatValue(const QSqlField &field, bool trimStrings) const; - - bool subscribeToNotification(const QString &name); - bool unsubscribeFromNotification(const QString &name); - QStringList subscribedToNotifications() const; - -protected: - bool beginTransaction(); - bool commitTransaction(); - bool rollbackTransaction(); - -private Q_SLOTS: - void _q_handleNotification(int); - -private: - QPSQLDriverPrivate *d; -}; - -QT_END_NAMESPACE - - -#endif // QSQL_PSQL_H diff --git a/src/sql/kernel/qsqldatabase.cpp b/src/sql/kernel/qsqldatabase.cpp index 76419ab9c..856bc8bfa 100644 --- a/src/sql/kernel/qsqldatabase.cpp +++ b/src/sql/kernel/qsqldatabase.cpp @@ -457,9 +457,7 @@ QStringList QSqlDatabase::connectionNames() \table \header \i Driver Type \i Description - \row \i QMYSQL \i MySQL Driver - \row \i QODBC \i ODBC Driver (includes Microsoft SQL Server) - \row \i QPSQL \i PostgreSQL Driver + \row \i QODBC \i ODBC version 3 or above \row \i QSQLITE \i SQLite version 3 or above \endtable @@ -957,7 +955,7 @@ QSqlRecord QSqlDatabase::record(const QString& tablename) const database client used: \table - \header \i ODBC \i MySQL \i PostgreSQL + \header \i ODBC \row \i @@ -973,47 +971,10 @@ QSqlRecord QSqlDatabase::record(const QString& tablename) const \i SQL_ATTR_CONNECTION_POOLING \endlist - \i - \list - \i CLIENT_COMPRESS - \i CLIENT_FOUND_ROWS - \i CLIENT_IGNORE_SPACE - \i CLIENT_SSL - \i CLIENT_ODBC - \i CLIENT_NO_SCHEMA - \i CLIENT_INTERACTIVE - \i UNIX_SOCKET - \i MYSQL_OPT_RECONNECT - \endlist - - \i - \list - \i connect_timeout - \i options - \i tty - \i requiressl - \i service - \endlist - - \header \i DB2 \i OCI \i TDS - \row - - \i - \list - \i SQL_ATTR_ACCESS_MODE - \i SQL_ATTR_LOGIN_TIMEOUT - \endlist - - \i - \list - \i OCI_ATTR_PREFETCH_ROWS - \i OCI_ATTR_PREFETCH_MEMORY - \endlist - \i \e none - \header \i SQLite \i Interbase + \header \i SQLite \row \i @@ -1023,12 +984,6 @@ QSqlRecord QSqlDatabase::record(const QString& tablename) const \i QSQLITE_ENABLE_SHARED_CACHE \endlist - \i - \list - \i ISC_DPB_LC_CTYPE - \i ISC_DPB_SQL_ROLE_NAME - \endlist - \endtable Examples: @@ -1076,50 +1031,14 @@ bool QSqlDatabase::isDriverAvailable(const QString& name) yourself. It might be your own database driver, or you might just need to instantiate one of the Qt drivers yourself. If you do this, it is recommended that you include the driver code in your - application. For example, you can create a PostgreSQL connection - with your own QPSQL driver like this: + application. - \snippet doc/src/snippets/code/src_sql_kernel_qsqldatabase.cpp 5 - \codeline - \snippet doc/src/snippets/code/src_sql_kernel_qsqldatabase.cpp 6 - - The above code sets up a PostgreSQL connection and instantiates a - QPSQLDriver object. Next, addDatabase() is called to add the - connection to the known connections so that it can be used by the - Qt SQL classes. When a driver is instantiated with a connection - handle (or set of handles), Qt assumes that you have already - opened the database connection. - - \note We assume that \c qtdir is the directory where Qt is - installed. This will pull in the code that is needed to use the - PostgreSQL client library and to instantiate a QPSQLDriver object, - assuming that you have the PostgreSQL headers somewhere in your - include search path. - - Remember that you must link your application against the database - client library. Make sure the client library is in your linker's - search path, and add lines like these to your \c{.pro} file: - - \snippet doc/src/snippets/code/src_sql_kernel_qsqldatabase.cpp 7 - - The method described works for all the supplied drivers. The only - difference will be in the driver constructor arguments. Here is a - table of the drivers included with Qt, their source code files, - and their constructor arguments: + Here is a table of the drivers included with Qt, their name and + their constructor arguments: \table \header \i Driver \i Class name \i Constructor arguments \i File to include \row - \i QPSQL - \i QPSQLDriver - \i PGconn *connection - \i \c qsql_psql.cpp - \row - \i QMYSQL - \i QMYSQLDriver - \i MYSQL *connection - \i \c qsql_mysql.cpp - \row \i QODBC \i QODBCDriver \i SQLHANDLE environment, SQLHANDLE connection @@ -1132,11 +1051,6 @@ bool QSqlDatabase::isDriverAvailable(const QString& name) \row \endtable - The host name (or service name) is needed when constructing the - QTDSDriver for creating new connections for internal queries. This - is to prevent blocking when several QSqlQuery objects are used - simultaneously. - \warning Adding a database connection with the same connection name as an existing connection, causes the existing connection to be replaced by the new one. diff --git a/tests/auto/qsqldatabase/tst_databases.h b/tests/auto/qsqldatabase/tst_databases.h index 6d52eeb34..656c1c6ed 100644 --- a/tests/auto/qsqldatabase/tst_databases.h +++ b/tests/auto/qsqldatabase/tst_databases.h @@ -76,10 +76,8 @@ inline static QString qTableName( const QString& prefix, QSqlDriver* driver ) inline static bool testWhiteSpaceNames( const QString &name ) { - return name.startsWith( QLatin1String("QPSQL") ) - || name.startsWith( QLatin1String("QODBC") ) - || name.startsWith( QLatin1String("QSQLITE") ) - || name.startsWith( QLatin1String("QMYSQL") ); + return name.startsWith( QLatin1String("QODBC") ) + || name.startsWith( QLatin1String("QSQLITE") ); } class tst_Databases @@ -189,34 +187,6 @@ public: void addDbs() { -// This requires a local ODBC data source to be configured( pointing to a MySql database ) -// addDb( "QODBC", "mysqlodbc", "troll", "trond" ); -// addDb( "QODBC", "SqlServer", "troll", "trond" ); -// addDb( "QODBC", "silencetestdb", "troll", "trond", "silence" ); -// addDb( "QODBC", "horseheadtestdb", "troll", "trondk", "horsehead" ); - -// addDb( "QMYSQL3", "testdb", "troll", "trond", "horsehead.nokia.troll.no" ); -// addDb( "QMYSQL3", "testdb", "troll", "trond", "horsehead.nokia.troll.no", 3307 ); -// addDb( "QMYSQL3", "testdb", "troll", "trond", "horsehead.nokia.troll.no", 3308, "CLIENT_COMPRESS=1;CLIENT_SSL=1" ); // MySQL 4.1.1 -// addDb( "QMYSQL3", "testdb", "troll", "trond", "horsehead.nokia.troll.no", 3309, "CLIENT_COMPRESS=1;CLIENT_SSL=1" ); // MySQL 5.0.18 Linux -// addDb( "QMYSQL3", "testdb", "troll", "trond", "silence.nokia.troll.no" ); // MySQL 5.1.36 Windows - -// addDb( "QMYSQL3", "testdb", "testuser", "Ee4Gabf6_", "bq-mysql41.apac.nokia.com" ); // MySQL 4.1.22-2.el4 linux -// addDb( "QMYSQL3", "testdb", "testuser", "Ee4Gabf6_", "bq-mysql50.apac.nokia.com" ); // MySQL 5.0.45-7.el5 linux -// addDb( "QMYSQL3", "testdb", "testuser", "Ee4Gabf6_", "bq-mysql51.apac.nokia.com" ); // MySQL 5.1.36-6.7.2.i586 linux - -// addDb( "QPSQL7", "testdb", "troll", "trond", "horsehead.nokia.troll.no" ); // V7.2 NOT SUPPORTED! -// addDb( "QPSQL7", "testdb", "troll", "trond", "horsehead.nokia.troll.no", 5434 ); // V7.2 NOT SUPPORTED! Multi-byte -// addDb( "QPSQL7", "testdb", "troll", "trond", "horsehead.nokia.troll.no", 5435 ); // V7.3 -// addDb( "QPSQL7", "testdb", "troll", "trond", "horsehead.nokia.troll.no", 5436 ); // V7.4 -// addDb( "QPSQL7", "testdb", "troll", "trond", "horsehead.nokia.troll.no", 5437 ); // V8.0.3 -// addDb( "QPSQL7", "testdb", "troll", "trond", "silence.nokia.troll.no" ); // V8.2.1, UTF-8 - -// addDb( "QPSQL7", "testdb", "testuser", "Ee4Gabf6_", "bq-postgres74.apac.nokia.com" ); // Version 7.4.19-1.el4_6.1 -// addDb( "QPSQL7", "testdb", "testuser", "Ee4Gabf6_", "bq-pgsql81.apac.nokia.com" ); // Version 8.1.11-1.el5_1.1 -// addDb( "QPSQL7", "testdb", "testuser", "Ee4Gabf6_", "bq-pgsql84.apac.nokia.com" ); // Version 8.4.1-2.1.i586 -// addDb( "QPSQL7", "testdb", "testuser", "Ee4Gabf6_", "bq-pgsql90.apac.nokia.com" ); // Version 9.0.0 - // use in-memory database to prevent local files // addDb("QSQLITE", ":memory:"); addDb( QLatin1String("QSQLITE"), QDir::toNativeSeparators(sqLiteFileName())); @@ -370,12 +340,6 @@ public: // blobSize is only used if the db doesn't have a generic blob type static QString blobTypeName( QSqlDatabase db, int blobSize = 10000 ) { - if ( db.driverName().startsWith( QLatin1String("QMYSQL") ) ) - return QLatin1String( "longblob" ); - - if ( db.driverName().startsWith( QLatin1String("QPSQL") ) ) - return QLatin1String( "bytea" ); - if ( db.driverName().startsWith( QLatin1String("QSQLITE") ) ) return QLatin1String( "blob" ); @@ -384,16 +348,6 @@ public: return QLatin1String( "blob" ); } - static QString autoFieldName( QSqlDatabase db ) - { - if ( db.driverName().startsWith( QLatin1String("QMYSQL") ) ) - return QLatin1String( "AUTO_INCREMENT" ); -/* if ( db.driverName().startsWith( QLatin1String("QPSQL") ) ) - return QLatin1String( "SERIAL" );*/ - - return QString(); - } - static QByteArray printError( const QSqlError& err ) { QString result; @@ -434,12 +388,12 @@ public: static bool isPostgreSQL( QSqlDatabase db ) { - return db.driverName().startsWith(QLatin1String("QPSQL")) || (db.driverName().startsWith(QLatin1String("QODBC")) && ( db.databaseName().contains(QLatin1String("PostgreSQL"), Qt::CaseInsensitive) || db.databaseName().contains(QLatin1String("pgsql"), Qt::CaseInsensitive) ) ); + return db.driverName().startsWith(QLatin1String("QODBC")) && ( db.databaseName().contains(QLatin1String("PostgreSQL"), Qt::CaseInsensitive) || db.databaseName().contains(QLatin1String("pgsql"), Qt::CaseInsensitive) ); } static bool isMySQL( QSqlDatabase db ) { - return db.driverName().startsWith(QLatin1String("QMYSQL")) || (db.driverName().startsWith(QLatin1String("QODBC")) && db.databaseName().contains(QLatin1String("MySQL"), Qt::CaseInsensitive) ); + return db.driverName().startsWith(QLatin1String("QODBC")) && db.databaseName().contains(QLatin1String("MySQL"), Qt::CaseInsensitive); } // -1 on fail, else Oracle version @@ -462,26 +416,6 @@ public: return ver; } - static QString getMySqlVersion( const QSqlDatabase &db ) - { - QSqlQuery q(db); - q.exec( QLatin1String("select version()") ); - if(q.next()) - return q.value( 0 ).toString(); - else - return QString(); - } - - static QString getPSQLVersion( const QSqlDatabase &db ) - { - QSqlQuery q(db); - q.exec( QLatin1String("select version()") ); - if(q.next()) - return q.value( 0 ).toString(); - else - return QString(); - } - QString sqLiteFileName() // Return a temporary file name for SQLite DB { const QString newFileName = m_sqLitePrefix + QLatin1Char('_') diff --git a/tests/auto/qsqldatabase/tst_qsqldatabase.cpp b/tests/auto/qsqldatabase/tst_qsqldatabase.cpp index fc1c5518b..db3a88b29 100644 --- a/tests/auto/qsqldatabase/tst_qsqldatabase.cpp +++ b/tests/auto/qsqldatabase/tst_qsqldatabase.cpp @@ -67,14 +67,8 @@ private slots: void eventNotification_data() { generic_data(); } void eventNotification(); void addDatabase(); - void errorReporting_data(); - void errorReporting(); //database specific tests - void recordMySQL_data() { generic_data("QMYSQL"); } - void recordMySQL(); - void recordPSQL_data() { generic_data("QPSQL"); } - void recordPSQL(); void recordSQLite_data() { generic_data("QSQLITE"); } void recordSQLite(); void recordAccess_data() { generic_data("QODBC"); } @@ -82,9 +76,6 @@ private slots: void recordSQLServer_data() { generic_data("QODBC"); } void recordSQLServer(); - void eventNotificationPSQL_data() { generic_data("QPSQL"); } - void eventNotificationPSQL(); - //database specific 64 bit integer test void bigIntField_data() { generic_data(); } void bigIntField(); @@ -107,21 +98,8 @@ private slots: void precisionPolicy_data() { generic_data(); } void precisionPolicy(); - void psql_schemas_data() { generic_data("QPSQL"); } - void psql_schemas(); - void psql_escapedIdentifiers_data() { generic_data("QPSQL"); } - void psql_escapedIdentifiers(); - void psql_escapeBytea_data() { generic_data("QPSQL"); } - void psql_escapeBytea(); - void bug_249059_data() { generic_data("QPSQL"); } - void bug_249059(); - void mysqlOdbc_unsignedIntegers_data() { generic_data(); } void mysqlOdbc_unsignedIntegers(); - void mysql_multiselect_data() { generic_data("QMYSQL"); } - void mysql_multiselect(); // For task 144331 - void mysql_savepointtest_data() { generic_data("QMYSQL"); } - void mysql_savepointtest(); void accessOdbc_strings_data() { generic_data(); } void accessOdbc_strings(); @@ -194,13 +172,12 @@ static int createFieldTable(const FieldDef fieldDefs[], QSqlDatabase db) QSqlQuery q(db); // construct a create table statement consisting of all fieldtypes QString qs = "create table " + qTableName("qtestfields", __FILE__); - QString autoName = tst_Databases::autoFieldName(db); if (tst_Databases::isMSAccess(db)) qs.append(" (id int not null"); else if (tst_Databases::isPostgreSQL(db)) qs.append(" (id serial not null"); else - qs.append(QString("(id integer not null %1 primary key").arg(autoName)); + qs.append(QString("(id integer not null primary key")); int i = 0; for (i = 0; !fieldDefs[ i ].typeName.isNull(); ++i) { @@ -235,11 +212,7 @@ void tst_QSqlDatabase::createTestTables(QSqlDatabase db) if (!db.isValid()) return; QSqlQuery q(db); - if (db.driverName().startsWith("QMYSQL")) - // ### stupid workaround until we find a way to hardcode this - // in the MySQL server startup script - q.exec("set table_type=innodb"); - else if (tst_Databases::isSqlServer(db)) { + if (tst_Databases::isSqlServer(db)) { QVERIFY_SQL(q, exec("SET ANSI_DEFAULTS ON")); QVERIFY_SQL(q, exec("SET IMPLICIT_TRANSACTIONS OFF")); } else if(tst_Databases::isPostgreSQL(db)) @@ -297,14 +270,7 @@ void tst_QSqlDatabase::dropTestTables(QSqlDatabase db) << qTableName("testqGetString", __FILE__) << qTableName("qtest_sqlguid", __FILE__) << qTableName("uint_table", __FILE__) - << qTableName("uint_test", __FILE__) - << qTableName("bug_249059", __FILE__); - - QSqlQuery q(QString(), db); - if (db.driverName().startsWith("QPSQL")) { - q.exec("drop schema " + qTableName("qtestschema", __FILE__) + " cascade"); - q.exec("drop schema " + qTableName("qtestScHeMa", __FILE__) + " cascade"); - } + << qTableName("uint_test", __FILE__); if (testWhiteSpaceNames(db.driverName())) tableNames << db.driver()->escapeIdentifier(qTableName("qtest", __FILE__) + " test", QSqlDriver::TableName); @@ -383,36 +349,6 @@ void tst_QSqlDatabase::addDatabase() QVERIFY(!QSqlDatabase::contains("INVALID_CONNECTION")); } -void tst_QSqlDatabase::errorReporting_data() -{ - QTest::addColumn("driver"); - - QTest::newRow("QMYSQL") << QString::fromLatin1("QMYSQL"); - QTest::newRow("QPSQL") << QString::fromLatin1("QPSQL"); -} - -void tst_QSqlDatabase::errorReporting() -{ - QFETCH(QString, driver); - - if (!QSqlDatabase::drivers().contains(driver)) - QSKIP(QString::fromLatin1("Database driver %1 not available").arg(driver).toLocal8Bit().constData(), SkipSingle); - - const QString dbName = QLatin1String("errorReportingDb-") + driver; - QSqlDatabase db = QSqlDatabase::addDatabase(driver, dbName); - - db.setHostName(QLatin1String("127.0.0.1")); - db.setDatabaseName(QLatin1String("NonExistantDatabase")); - db.setUserName(QLatin1String("InvalidUser")); - db.setPassword(QLatin1String("IncorrectPassword")); - - QVERIFY(!db.open()); - - db = QSqlDatabase(); - - QSqlDatabase::removeDatabase(dbName); -} - void tst_QSqlDatabase::open() { QFETCH(QString, dbName); @@ -447,9 +383,6 @@ void tst_QSqlDatabase::tables() bool tempTables = false; QSqlQuery q(db); - if ( db.driverName().startsWith( "QMYSQL" ) && tst_Databases::getMySqlVersion( db ).section( QChar('.'), 0, 0 ).toInt()<5 ) - QSKIP( "Test requires MySQL >= 5.0", SkipSingle ); - if (!q.exec("CREATE VIEW " + qtest_view + " as select * from " + qtest)) { qDebug() << "DBMS '" << tst_Databases::dbToString(db) << "' cannot handle VIEWs:" @@ -492,10 +425,6 @@ void tst_QSqlDatabase::tables() if (tempTables) QVERIFY(tables.contains(temp_tab, Qt::CaseInsensitive)); QVERIFY(tables.contains(qtest, Qt::CaseInsensitive)); - - if (db.driverName().startsWith("QPSQL")) { - QVERIFY(tables.contains(qtest + " test")); - } } void tst_QSqlDatabase::whitespaceInIdentifiers() @@ -581,8 +510,6 @@ void tst_QSqlDatabase::record() void tst_QSqlDatabase::testRecord(const FieldDef fieldDefs[], const QSqlRecord& inf, QSqlDatabase db) { int i = 0; - if (!tst_Databases::autoFieldName(db).isEmpty()) // Currently only MySQL is tested - QVERIFY2(inf.field(i).isAutoValue(), qPrintable(inf.field(i).name() + " should be reporting as an autovalue")); for (i = 0; !fieldDefs[ i ].typeName.isNull(); ++i) { QCOMPARE(inf.field(i+1).name().toUpper(), fieldDefs[ i ].fieldName().toUpper()); if (inf.field(i+1).type() != fieldDefs[ i ].type) { @@ -611,146 +538,6 @@ void tst_QSqlDatabase::commonFieldTest(const FieldDef fieldDefs[], QSqlDatabase QVERIFY_SQL(q, exec("select * from " + qTableName("qtestfields", __FILE__))); } -void tst_QSqlDatabase::recordPSQL() -{ - QFETCH(QString, dbName); - QSqlDatabase db = QSqlDatabase::database(dbName); - CHECK_DATABASE(db); - - FieldDef byteadef; - if (db.driver()->hasFeature(QSqlDriver::BLOB)) - byteadef = FieldDef("bytea", QVariant::ByteArray, QByteArray("bl\\ah")); - static FieldDef fieldDefs[] = { - FieldDef("bigint", QVariant::LongLong, Q_INT64_C(9223372036854775807)), - FieldDef("bigserial", QVariant::LongLong, 100, false), - FieldDef("bit", QVariant::String, "1"), // a bit in postgres is a bit-string - FieldDef("box", QVariant::String, "(5,6),(1,2)"), - FieldDef("char(20)", QVariant::String, "blah5678901234567890"), - FieldDef("varchar(20)", QVariant::String, "blah5678901234567890"), - FieldDef("cidr", QVariant::String, "12.123.0.0/24"), - FieldDef("circle", QVariant::String, "<(1,2),3>"), - FieldDef("date", QVariant::Date, QDate::currentDate()), - FieldDef("float8", QVariant::Double, 1.12345678912), - FieldDef("inet", QVariant::String, "12.123.12.23"), - FieldDef("integer", QVariant::Int, 2147483647), - FieldDef("interval", QVariant::String, "1 day 12:59:10"), -// LOL... you can create a "line" datatype in PostgreSQL <= 7.2.x but -// as soon as you want to insert data you get a "not implemented yet" error -// FieldDef("line", QVariant::Polygon, QPolygon(QRect(1, 2, 3, 4))), - FieldDef("lseg", QVariant::String, "[(1,1),(2,2)]"), - FieldDef("macaddr", QVariant::String, "08:00:2b:01:02:03"), - FieldDef("money", QVariant::String, "$12.23"), - FieldDef("numeric", QVariant::Double, 1.2345678912), - FieldDef("path", QVariant::String, "((1,2),(3,2),(3,5),(1,5))"), - FieldDef("point", QVariant::String, "(1,2)"), - FieldDef("polygon", QVariant::String, "((1,2),(3,2),(3,5),(1,5))"), - FieldDef("real", QVariant::Double, 1.1234), - FieldDef("smallint", QVariant::Int, 32767), - FieldDef("serial", QVariant::Int, 100, false), - FieldDef("text", QVariant::String, "blah"), - FieldDef("time(6)", QVariant::Time, QTime(1, 2, 3)), - FieldDef("timetz", QVariant::Time, QTime(1, 2, 3)), - FieldDef("timestamp(6)", QVariant::DateTime, QDateTime::currentDateTime()), - FieldDef("timestamptz", QVariant::DateTime, QDateTime::currentDateTime()), - byteadef, - - FieldDef() - }; - - QSqlQuery q(db); - - if(tst_Databases::isPostgreSQL(db)) - QVERIFY_SQL( q, exec("set client_min_messages='warning'")); - - q.exec("drop sequence " + qTableName("qtestfields", __FILE__) + "_t_bigserial_seq"); - q.exec("drop sequence " + qTableName("qtestfields", __FILE__) + "_t_serial_seq"); - // older psql cut off the table name - q.exec("drop sequence " + qTableName("qtestfields", __FILE__).left(15) + "_t_bigserial_seq"); - q.exec("drop sequence " + qTableName("qtestfields", __FILE__).left(18) + "_t_serial_seq"); - - const int fieldCount = createFieldTable(fieldDefs, db); - QVERIFY(fieldCount > 0); - - commonFieldTest(fieldDefs, db, fieldCount); - for (int i = 0; i < ITERATION_COUNT; ++i) { - // increase serial values - for (int i2 = 0; !fieldDefs[ i2 ].typeName.isNull(); ++i2) { - if (fieldDefs[ i2 ].typeName == "serial" || - fieldDefs[ i2 ].typeName == "bigserial") { - - FieldDef def = fieldDefs[ i2 ]; - def.val = def.val.toInt() + 1; - fieldDefs[ i2 ] = def; - } - } - } -} - -void tst_QSqlDatabase::recordMySQL() -{ - QFETCH(QString, dbName); - QSqlDatabase db = QSqlDatabase::database(dbName); - CHECK_DATABASE(db); - - FieldDef bin10, varbin10; - int major = tst_Databases::getMySqlVersion( db ).section( QChar('.'), 0, 0 ).toInt(); - int minor = tst_Databases::getMySqlVersion( db ).section( QChar('.'), 1, 1 ).toInt(); - int revision = tst_Databases::getMySqlVersion( db ).section( QChar('.'), 2, 2 ).toInt(); - int vernum = (major << 16) + (minor << 8) + revision; - - /* The below is broken in mysql below 5.0.15 - see http://dev.mysql.com/doc/refman/5.0/en/binary-varbinary.html - specifically: Before MySQL 5.0.15, the pad value is space. Values are right-padded - with space on insert, and trailing spaces are removed on select. - */ - if( vernum >= ((5 << 16) + 15) ) { - bin10 = FieldDef("binary(10)", QVariant::ByteArray, QString("123abc ")); - varbin10 = FieldDef("varbinary(10)", QVariant::ByteArray, QString("123abcv ")); - } - - static QDateTime dt(QDate::currentDate(), QTime(1, 2, 3, 0)); - static const FieldDef fieldDefs[] = { - FieldDef("tinyint", QVariant::Int, 127), - FieldDef("tinyint unsigned", QVariant::UInt, 255), - FieldDef("smallint", QVariant::Int, 32767), - FieldDef("smallint unsigned", QVariant::UInt, 65535), - FieldDef("mediumint", QVariant::Int, 8388607), - FieldDef("mediumint unsigned", QVariant::UInt, 16777215), - FieldDef("integer", QVariant::Int, 2147483647), - FieldDef("integer unsigned", QVariant::UInt, 4294967295u), - FieldDef("bigint", QVariant::LongLong, Q_INT64_C(9223372036854775807)), - FieldDef("bigint unsigned", QVariant::ULongLong, Q_UINT64_C(18446744073709551615)), - FieldDef("float", QVariant::Double, 1.12345), - FieldDef("double", QVariant::Double, 1.123456789), - FieldDef("decimal(10, 9)", QVariant::Double,1.123456789), - FieldDef("numeric(5, 2)", QVariant::Double, 123.67), - FieldDef("date", QVariant::Date, QDate::currentDate()), - FieldDef("datetime", QVariant::DateTime, dt), - FieldDef("timestamp", QVariant::DateTime, dt, false), - FieldDef("time", QVariant::Time, dt.time()), - FieldDef("year", QVariant::Int, 2003), - FieldDef("char(20)", QVariant::String, "Blah"), - FieldDef("varchar(20)", QVariant::String, "BlahBlah"), - FieldDef("tinytext", QVariant::String, QString("blah5")), - FieldDef("text", QVariant::String, QString("blah6")), - FieldDef("mediumtext", QVariant::String, QString("blah7")), - FieldDef("longtext", QVariant::String, QString("blah8")), - // SET OF? - - FieldDef() - }; - - const int fieldCount = createFieldTable(fieldDefs, db); - QVERIFY(fieldCount > 0); - - commonFieldTest(fieldDefs, db, fieldCount); - - QSqlQuery q(db); - QVERIFY_SQL(q, exec("SELECT DATE_SUB(CURDATE(), INTERVAL 2 DAY)")); - QVERIFY(q.next()); - QCOMPARE(q.value(0).toDateTime().date(), QDate::currentDate().addDays(-2)); -} - void tst_QSqlDatabase::recordSQLite() { QFETCH(QString, dbName); @@ -876,12 +663,7 @@ void tst_QSqlDatabase::transaction() QCOMPARE(q.value(0).toInt(), 41); q.clear(); // for SQLite which does not allow any references on rows that shall be rolled back if (!db.rollback()) { - if (db.driverName().startsWith("QMYSQL")) { - qDebug() << "MySQL:" << tst_Databases::printError(db.lastError()); - QSKIP("MySQL transaction failed ", SkipSingle); //non-fatal - } else { - QFAIL("Could not rollback transaction: " + tst_Databases::printError(db.lastError())); - } + QFAIL("Could not rollback transaction: " + tst_Databases::printError(db.lastError())); } QVERIFY_SQL(q, exec("select * from " + qtest + " where id = 41")); @@ -903,9 +685,7 @@ void tst_QSqlDatabase::bigIntField() QSqlQuery q(db); q.setForwardOnly(true); - if (drvName.startsWith("QMYSQL")) { - QVERIFY_SQL(q, exec("create table " + qtest_bigint + " (id int, t_s64bit bigint, t_u64bit bigint unsigned)")); - } else if (drvName.startsWith("QPSQL") || tst_Databases::isSqlServer(db)) { + if (tst_Databases::isSqlServer(db)) { QVERIFY_SQL(q, exec("create table " + qtest_bigint + "(id int, t_s64bit bigint, t_u64bit bigint)")); } else { QSKIP("no 64 bit integer support", SkipAll); @@ -914,26 +694,16 @@ void tst_QSqlDatabase::bigIntField() qlonglong ll = Q_INT64_C(9223372036854775807); qulonglong ull = Q_UINT64_C(18446744073709551615); - if (drvName.startsWith("QMYSQL")) { - q.bindValue(0, 0); - q.bindValue(1, ll); - q.bindValue(2, ull); - QVERIFY_SQL(q, exec()); - q.bindValue(0, 1); - q.bindValue(1, -ll); - q.bindValue(2, ull); - QVERIFY_SQL(q, exec()); - } else { - // usinged bigint fields not supported - a cast is necessary - q.bindValue(0, 0); - q.bindValue(1, ll); - q.bindValue(2, (qlonglong) ull); - QVERIFY_SQL(q, exec()); - q.bindValue(0, 1); - q.bindValue(1, -ll); - q.bindValue(2, (qlonglong) ull); - QVERIFY_SQL(q, exec()); - } + + // usinged bigint fields not supported - a cast is necessary + q.bindValue(0, 0); + q.bindValue(1, ll); + q.bindValue(2, (qlonglong) ull); + QVERIFY_SQL(q, exec()); + q.bindValue(0, 1); + q.bindValue(1, -ll); + q.bindValue(2, (qlonglong) ull); + QVERIFY_SQL(q, exec()); QVERIFY(q.exec("select * from " + qtest_bigint + " order by id")); QVERIFY(q.next()); QCOMPARE(q.value(1).toDouble(), (double)ll); @@ -951,9 +721,7 @@ void tst_QSqlDatabase::caseSensivity() CHECK_DATABASE(db); bool cs = false; - if (db.driverName().startsWith("QMYSQL") - || db.driverName().startsWith("QSQLITE") - || db.driverName().startsWith("QTDS") + if (db.driverName().startsWith("QSQLITE") || db.driverName().startsWith("QODBC")) cs = true; @@ -990,146 +758,6 @@ void tst_QSqlDatabase::noEscapedFieldNamesInRecord() QCOMPARE(q.record().fieldName(0), fieldname); } -void tst_QSqlDatabase::psql_schemas() -{ - QFETCH(QString, dbName); - QSqlDatabase db = QSqlDatabase::database(dbName); - CHECK_DATABASE(db); - - if (!db.tables(QSql::SystemTables).contains("pg_namespace")) - QSKIP("server does not support schemas", SkipSingle); - - QSqlQuery q(db); - - if(tst_Databases::isPostgreSQL(db)) { - QVERIFY_SQL( q, exec("set client_min_messages='warning'")); - } - - QVERIFY_SQL(q, exec("CREATE SCHEMA " + qTableName("qtestschema", __FILE__))); - - QString table = qTableName("qtestschema", __FILE__) + '.' + qTableName("qtesttable", __FILE__); - QVERIFY_SQL(q, exec("CREATE TABLE " + table + " (id int primary key, name varchar(20))")); - - QVERIFY(db.tables().contains(table)); - - QSqlRecord rec = db.record(table); - QCOMPARE(rec.count(), 2); - QCOMPARE(rec.fieldName(0), QString("id")); - QCOMPARE(rec.fieldName(1), QString("name")); - - QSqlIndex idx = db.primaryIndex(table); - QCOMPARE(idx.count(), 1); - QCOMPARE(idx.fieldName(0), QString("id")); -} - -void tst_QSqlDatabase::psql_escapedIdentifiers() -{ - QFETCH(QString, dbName); - QSqlDatabase db = QSqlDatabase::database(dbName); - QSqlDriver* drv = db.driver(); - CHECK_DATABASE(db); - - if (!db.tables(QSql::SystemTables).contains("pg_namespace")) - QSKIP("server does not support schemas", SkipSingle); - - QSqlQuery q(db); - - if(tst_Databases::isPostgreSQL(db)) - QVERIFY_SQL( q, exec("set client_min_messages='warning'")); - - const QString schemaName(qTableName("qtestScHeMa", __FILE__)), - tableName(qTableName("qtest", __FILE__)), - field1Name(QLatin1String("fIeLdNaMe")), - field2Name(QLatin1String("ZuLu")); - - q.exec(QString("DROP SCHEMA \"%1\" CASCADE").arg(schemaName)); - QString createSchema = QString("CREATE SCHEMA \"%1\"").arg(schemaName); - QVERIFY_SQL(q, exec(createSchema)); - QString createTable = QString("CREATE TABLE \"%1\".\"%2\" (\"%3\" int PRIMARY KEY, \"%4\" varchar(20))").arg(schemaName).arg(tableName).arg(field1Name).arg(field2Name); - QVERIFY_SQL(q, exec(createTable)); - - QVERIFY(db.tables().contains(schemaName + '.' + tableName, Qt::CaseSensitive)); - - QSqlField fld1(field1Name, QVariant::Int); - QSqlField fld2(field2Name, QVariant::String); - QSqlRecord rec; - rec.append(fld1); - rec.append(fld2); - - QVERIFY_SQL(q, exec(drv->sqlStatement(QSqlDriver::SelectStatement, db.driver()->escapeIdentifier(schemaName, QSqlDriver::TableName) + '.' + db.driver()->escapeIdentifier(tableName, QSqlDriver::TableName), rec, false))); - - rec = q.record(); - QCOMPARE(rec.count(), 2); - QCOMPARE(rec.fieldName(0), field1Name); - QCOMPARE(rec.fieldName(1), field2Name); - QCOMPARE(rec.field(0).type(), QVariant::Int); - - q.exec(QString("DROP SCHEMA \"%1\" CASCADE").arg(schemaName)); -} - -void tst_QSqlDatabase::psql_escapeBytea() -{ - QFETCH(QString, dbName); - QSqlDatabase db = QSqlDatabase::database(dbName); - CHECK_DATABASE(db); - - const char dta[4] = {'\x71', '\x14', '\x32', '\x81'}; - QByteArray ba(dta, 4); - - QSqlQuery q(db); - const QString tableName(qTableName("batable", __FILE__)); - QVERIFY_SQL(q, exec(QString("CREATE TABLE %1 (ba bytea)").arg(tableName))); - - QSqlQuery iq(db); - QVERIFY_SQL(iq, prepare(QString("INSERT INTO %1 VALUES (?)").arg(tableName))); - iq.bindValue(0, QVariant(ba)); - QVERIFY_SQL(iq, exec()); - - QVERIFY_SQL(q, exec(QString("SELECT ba FROM %1").arg(tableName))); - QVERIFY_SQL(q, next()); - - QByteArray res = q.value(0).toByteArray(); - int i = 0; - for (; i < ba.size(); ++i){ - if (ba[i] != res[i]) - break; - } - - QCOMPARE(i, 4); -} - -void tst_QSqlDatabase::bug_249059() -{ - QFETCH(QString, dbName); - QSqlDatabase db = QSqlDatabase::database(dbName); - CHECK_DATABASE(db); - - QSqlQuery q(db); - const QString tableName(qTableName("bug_249059", __FILE__)); - QVERIFY_SQL(q, exec(QString("CREATE TABLE %1 (dt timestamp, t time)").arg(tableName))); - - QSqlQuery iq(db); - QVERIFY_SQL(iq, prepare(QString("INSERT INTO %1 VALUES (?, ?)").arg(tableName))); - iq.bindValue(0, QVariant(QString("2001-09-09 04:05:06.789 -5:00"))); - iq.bindValue(1, QVariant(QString("04:05:06.789 -5:00"))); - QVERIFY_SQL(iq, exec()); - iq.bindValue(0, QVariant(QString("2001-09-09 04:05:06.789 +5:00"))); - iq.bindValue(1, QVariant(QString("04:05:06.789 +5:00"))); - QVERIFY_SQL(iq, exec()); - - QVERIFY_SQL(q, exec(QString("SELECT dt, t FROM %1").arg(tableName))); - QVERIFY_SQL(q, next()); - QDateTime dt1=q.value(0).toDateTime(); - QTime t1=q.value(1).toTime(); - QVERIFY_SQL(q, next()); - QDateTime dt2=q.value(0).toDateTime(); - QTime t2=q.value(1).toTime(); - - // These will fail when timezone support is added, when that's the case, set the second record to 14:05:06.789 and it should work correctly - QCOMPARE(dt1, dt2); - QCOMPARE(t1, t2); -} - // This test should be rewritten to work with Oracle as well - or the Oracle driver // should be fixed to make this test pass (handle overflows) void tst_QSqlDatabase::precisionPolicy() @@ -1137,7 +765,6 @@ void tst_QSqlDatabase::precisionPolicy() QFETCH(QString, dbName); QSqlDatabase db = QSqlDatabase::database(dbName); CHECK_DATABASE(db); -// DBMS_SPECIFIC(db, "QPSQL"); QSqlQuery q(db); const QString tableName(qTableName("qtest_prec", __FILE__)); @@ -1410,22 +1037,6 @@ void tst_QSqlDatabase::odbc_testqGetString() QCOMPARE(q.value(1).toString().length(), 65538); } - -void tst_QSqlDatabase::mysql_multiselect() -{ - QFETCH(QString, dbName); - QSqlDatabase db = QSqlDatabase::database(dbName); - CHECK_DATABASE(db); - const QString qtest(qTableName("qtest", __FILE__)); - - QSqlQuery q(db); - QVERIFY_SQL(q, exec("SELECT * FROM " + qtest + "; SELECT * FROM " + qtest)); - QVERIFY_SQL(q, next()); - QVERIFY_SQL(q, exec("SELECT * FROM " + qtest + "; SELECT * FROM " + qtest)); - QVERIFY_SQL(q, next()); - QVERIFY_SQL(q, exec("SELECT * FROM " + qtest)); -} - // This test isn't really necessary as SQL_GUID / uniqueidentifier is // already tested in recordSQLServer(). void tst_QSqlDatabase::odbc_uniqueidentifier() @@ -1539,26 +1150,6 @@ void tst_QSqlDatabase::eventNotification() db.open(); } -void tst_QSqlDatabase::eventNotificationPSQL() -{ - QFETCH(QString, dbName); - QSqlDatabase db = QSqlDatabase::database(dbName); - CHECK_DATABASE(db); - - QSqlQuery query(db); - QString procedureName = qTableName("posteventProc", __FILE__); - - QSqlDriver &driver=*(db.driver()); - QVERIFY_SQL(driver, subscribeToNotification(procedureName)); - QSignalSpy spy(db.driver(), SIGNAL(notification(const QString&))); - query.exec(QString("NOTIFY \"%1\"").arg(procedureName)); - QCoreApplication::processEvents(); - QCOMPARE(spy.count(), 1); - QList arguments = spy.takeFirst(); - QVERIFY(arguments.at(0).toString() == procedureName); - QVERIFY_SQL(driver, unsubscribeFromNotification(procedureName)); -} - void tst_QSqlDatabase::sqlite_bindAndFetchUInt() { QFETCH(QString, dbName); @@ -1602,18 +1193,6 @@ void tst_QSqlDatabase::sqlStatementUseIsNull_189093() QCOMPARE(statment.count("IS NULL", Qt::CaseInsensitive), 2); } -void tst_QSqlDatabase::mysql_savepointtest() -{ - QFETCH(QString, dbName); - QSqlDatabase db = QSqlDatabase::database(dbName); - CHECK_DATABASE(db); - - QSqlQuery q(db); - QVERIFY_SQL(q, exec("begin")); - QVERIFY_SQL(q, exec("insert into "+qTableName("qtest", __FILE__)+" VALUES (54, 'foo', 'foo', 54.54)")); - QVERIFY_SQL(q, exec("savepoint foo")); -} - void tst_QSqlDatabase::sqlite_enable_cache_mode() { QFETCH(QString, dbName); diff --git a/tests/auto/qsqldriver/tst_qsqldriver.cpp b/tests/auto/qsqldriver/tst_qsqldriver.cpp index 25a9129c3..4443bd66d 100644 --- a/tests/auto/qsqldriver/tst_qsqldriver.cpp +++ b/tests/auto/qsqldriver/tst_qsqldriver.cpp @@ -119,9 +119,6 @@ void tst_QSqlDriver::record() for (int i = 0; i < fields.count(); ++i) QCOMPARE(rec.fieldName(i), fields[i]); - if (db.driverName().startsWith("QPSQL")) - tablename = tablename.toLower(); - if(!db.driverName().startsWith("QODBC") && !db.databaseName().contains("PostgreSql")) { //check we can get records using a properly quoted table name rec = db.driver()->record(db.driver()->escapeIdentifier(tablename,QSqlDriver::TableName)); @@ -131,9 +128,6 @@ void tst_QSqlDriver::record() for (int i = 0; i < fields.count(); ++i) QCOMPARE(rec.fieldName(i), fields[i]); - if (db.driverName().startsWith("QPSQL")) - 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 (tst_Databases::isMySQL(db) @@ -161,9 +155,6 @@ void tst_QSqlDriver::primaryIndex() //check that we can get the primary index using a quoted tablename - if (db.driverName().startsWith("QPSQL")) - tablename = tablename.toLower(); - if(!db.driverName().startsWith("QODBC") && !db.databaseName().contains("PostgreSql")) { index = db.driver()->primaryIndex(db.driver()->escapeIdentifier(tablename, QSqlDriver::TableName)); QCOMPARE(index.count(), 1); @@ -173,13 +164,9 @@ void tst_QSqlDriver::primaryIndex() //check that we can not get the primary index using a quoted but incorrect table name casing - if (db.driverName().startsWith("QPSQL")) - tablename = tablename.toUpper(); - index = db.driver()->primaryIndex(db.driver()->escapeIdentifier(tablename, QSqlDriver::TableName)); if (tst_Databases::isMySQL(db) || db.driverName().startsWith("QSQLITE") - || db.driverName().startsWith("QTDS") || tst_Databases::isSqlServer(db) || tst_Databases::isMSAccess(db)) QCOMPARE(index.count(), 1); //mysql will always find the table name regardless of casing diff --git a/tests/auto/qsqlquery/tst_qsqlquery.cpp b/tests/auto/qsqlquery/tst_qsqlquery.cpp index 4c412762f..574f1ef74 100644 --- a/tests/auto/qsqlquery/tst_qsqlquery.cpp +++ b/tests/auto/qsqlquery/tst_qsqlquery.cpp @@ -105,8 +105,6 @@ private slots: void char1SelectUnicode(); void synonyms_data() { generic_data(); } void synonyms(); - void mysqlOutValues_data() { generic_data("QMYSQL"); } - void mysqlOutValues(); void prepare_bind_exec_data() { generic_data(); } void prepare_bind_exec(); void prepared_select_data() { generic_data(); } @@ -125,12 +123,8 @@ private slots: void lastQuery(); void bindBool_data() { generic_data(); } void bindBool(); - void bindWithDoubleColonCastOperator_data() { generic_data(); } - void bindWithDoubleColonCastOperator(); void queryOnInvalidDatabase_data() { generic_data(); } void queryOnInvalidDatabase(); - void createQueryOnClosedDatabase_data() { generic_data(); } - void createQueryOnClosedDatabase(); void seekForwardOnlyQuery_data() { generic_data(); } void seekForwardOnlyQuery(); void reExecutePreparedForwardOnlyQuery_data() { generic_data(); } @@ -151,23 +145,12 @@ private slots: void task_250026_data() { generic_data("QODBC"); } void task_250026(); - void task_205701_data() { generic_data("QMYSQL"); } - void task_205701(); - - void task_233829_data() { generic_data("QPSQL"); } - void task_233829(); void sqlServerReturn0_data() { generic_data(); } void sqlServerReturn0(); - void QTBUG_5251_data() { generic_data("QPSQL"); } - void QTBUG_5251(); void QTBUG_6618_data() { generic_data("QODBC"); } void QTBUG_6618(); - void QTBUG_6852_data() { generic_data("QMYSQL"); } - void QTBUG_6852(); - void QTBUG_5765_data() { generic_data("QMYSQL"); } - void QTBUG_5765(); void QTBUG_21884_data() { generic_data("QSQLITE"); } void QTBUG_21884(); void QTBUG_16967_data() { generic_data("QSQLITE"); } @@ -297,9 +280,6 @@ void tst_QSqlQuery::dropTestTables( QSqlDatabase db ) << qTableName("test141895", __FILE__) << qTableName( "bug2192", __FILE__); - if ( db.driverName().startsWith("QPSQL") ) - tablenames << qTableName("task_233829", __FILE__); - if ( db.driverName().startsWith("QSQLITE") ) tablenames << qTableName( "record_sqlite", __FILE__ ); @@ -319,17 +299,13 @@ void tst_QSqlQuery::createTestTables( QSqlDatabase db ) { QSqlQuery q( db ); - if ( db.driverName().startsWith( "QMYSQL" ) ) - // ### stupid workaround until we find a way to hardcode this - // in the MySQL server startup script - q.exec( "set table_type=innodb" ); - else if(tst_Databases::isPostgreSQL(db)) + if(tst_Databases::isPostgreSQL(db)) QVERIFY_SQL( q, exec("set client_min_messages='warning'")); if(tst_Databases::isPostgreSQL(db)) QVERIFY_SQL( q, exec( "create table " + qtest + " (id serial NOT NULL, t_varchar varchar(20), t_char char(20), primary key(id)) WITH OIDS" ) ); else - QVERIFY_SQL( q, exec( "create table " + qtest + " (id int "+tst_Databases::autoFieldName(db) +" NOT NULL, t_varchar varchar(20), t_char char(20), primary key(id))" ) ); + QVERIFY_SQL( q, exec( "create table " + qtest + " (id int NOT NULL, t_varchar varchar(20), t_char char(20), primary key(id))" ) ); if ( tst_Databases::isSqlServer( db ) ) QVERIFY_SQL( q, exec( "create table " + qTableName( "qtest_null", __FILE__ ) + " (id int null, t_varchar varchar(20) null)" ) ); @@ -385,19 +361,11 @@ void tst_QSqlQuery::char1SelectUnicode() QString uniStr( QChar(0x0915) ); // DEVANAGARI LETTER KA QSqlQuery q( db ); - if ( db.driverName().startsWith( "QMYSQL" ) && tst_Databases::getMySqlVersion( db ).section( QChar('.'), 0, 0 ).toInt()<5 ) - QSKIP( "Test requires MySQL >= 5.0", SkipSingle ); - QString createQuery; const QString char1SelectUnicode(qTableName( "char1SU", __FILE__ )); if ( tst_Databases::isSqlServer( db ) ) createQuery = "create table " + char1SelectUnicode + "(id nchar(1))"; - else if ( db.driverName().startsWith( "QPSQL" ) ) - createQuery = "create table " + char1SelectUnicode + " (id char(3))"; - else if ( db.driverName().startsWith( "QMYSQL" ) ) - createQuery = "create table " + char1SelectUnicode + " (id char(1)) " - "default character set 'utf8'"; else createQuery = "create table " + char1SelectUnicode + " (id char(1))"; @@ -424,57 +392,6 @@ void tst_QSqlQuery::char1SelectUnicode() QSKIP( "Database not unicode capable", SkipSingle ); } -void tst_QSqlQuery::mysqlOutValues() -{ - QFETCH( QString, dbName ); - QSqlDatabase db = QSqlDatabase::database( dbName ); - CHECK_DATABASE( db ); - const QString hello(qTableName( "hello", __FILE__ )), qtestproc(qTableName( "qtestproc", __FILE__ )); - - QSqlQuery q( db ); - - if ( db.driverName().startsWith( "QMYSQL" ) && tst_Databases::getMySqlVersion( db ).section( QChar('.'), 0, 0 ).toInt()<5 ) - QSKIP( "Test requires MySQL >= 5.0", SkipSingle ); - - q.exec( "drop function " + hello ); - - QVERIFY_SQL( q, exec( "create function " + hello + " (s char(20)) returns varchar(50) return concat('Hello ', s)" ) ); - - QVERIFY_SQL( q, exec( "select " + hello + "('world')" ) ); - QVERIFY_SQL( q, next() ); - - QCOMPARE( q.value( 0 ).toString(), QString( "Hello world" ) ); - - QVERIFY_SQL( q, prepare( "select " + hello + "('harald')" ) ); - QVERIFY_SQL( q, exec() ); - QVERIFY_SQL( q, next() ); - - QCOMPARE( q.value( 0 ).toString(), QString( "Hello harald" ) ); - - QVERIFY_SQL( q, exec( "drop function " + hello ) ); - - q.exec( "drop procedure " + qtestproc ); - - QVERIFY_SQL( q, exec( "create procedure " + qtestproc + " () " - "BEGIN select * from " + qtest + " order by id; END" ) ); - QVERIFY_SQL( q, exec( "call " + qtestproc + "()" ) ); - QVERIFY_SQL( q, next() ); - QCOMPARE( q.value( 1 ).toString(), QString( "VarChar1" ) ); - - QVERIFY_SQL( q, exec( "drop procedure " + qtestproc ) ); - - QVERIFY_SQL( q, exec( "create procedure " + qtestproc + " (OUT param1 INT) " - "BEGIN set param1 = 42; END" ) ); - - QVERIFY_SQL( q, exec( "call " + qtestproc + " (@out)" ) ); - QVERIFY_SQL( q, exec( "select @out" ) ); - QCOMPARE( q.record().fieldName( 0 ), QString( "@out" ) ); - QVERIFY_SQL( q, next() ); - QCOMPARE( q.value( 0 ).toInt(), 42 ); - - QVERIFY_SQL( q, exec( "drop procedure " + qtestproc ) ); -} - void tst_QSqlQuery::bindBool() { // QTBUG-27763: bool value got converted to int 127 by mysql driver becuase sizeof(bool) < sizeof(int). @@ -1086,14 +1003,8 @@ void tst_QSqlQuery::precision() while ( precStr[i] != 0 && *( precStr + i ) == val[i].toLatin1() ) i++; - // MySQL and TDS have crappy precisions by default - if ( db.driverName().startsWith( "QMYSQL" ) ) { - if ( i < 17 ) - QWARN( "MySQL didn't return the right precision" ); - } else { - QWARN( QString( tst_Databases::dbToString( db ) + " didn't return the right precision (" + - QString::number( i ) + " out of 21), " + val ).toLatin1() ); - } + QWARN( QString( tst_Databases::dbToString( db ) + " didn't return the right precision (" + + QString::number( i ) + " out of 21), " + val ).toLatin1() ); } } // SQLITE scope } @@ -1136,9 +1047,6 @@ void tst_QSqlQuery::transaction() // this is the standard SQL QString startTransactionStr( "start transaction" ); - if ( db.driverName().startsWith( "QMYSQL" ) ) - startTransactionStr = "begin work"; - QSqlQuery q( db ); QSqlQuery q2( db ); @@ -1174,11 +1082,7 @@ void tst_QSqlQuery::transaction() QCOMPARE( q.value( 0 ).toInt(), 41 ); if ( !q.exec( "rollback" ) ) { - if ( db.driverName().startsWith( "QMYSQL" ) ) { - qDebug( "MySQL: %s", qPrintable(tst_Databases::printError( q.lastError() ) ) ); - QSKIP( "MySQL transaction failed ", SkipSingle ); //non-fatal - } else - QFAIL( "Could not rollback transaction: " + tst_Databases::printError( q.lastError() ) ); + QFAIL( "Could not rollback transaction: " + tst_Databases::printError( q.lastError() ) ); } QVERIFY_SQL( q, exec( "select * from" + qtest + " where id = 41" ) ); @@ -1283,9 +1187,6 @@ void tst_QSqlQuery::prepare_bind_exec() QSqlQuery q( db ); - if ( db.driverName().startsWith( "QMYSQL" ) && tst_Databases::getMySqlVersion( db ).section( QChar('.'), 0, 0 ).toInt()<5 ) - useUnicode = false; - QString createQuery; if(tst_Databases::isPostgreSQL(db)) @@ -1793,40 +1694,6 @@ void tst_QSqlQuery::lastQuery() QCOMPARE( q.executedQuery(), sql ); } -void tst_QSqlQuery::bindWithDoubleColonCastOperator() -{ - QFETCH( QString, dbName ); - QSqlDatabase db = QSqlDatabase::database( dbName ); - CHECK_DATABASE( db ); - - // Only PostgreSQL support the double-colon cast operator - - if ( !db.driverName().startsWith( "QPSQL" ) ) { - QSKIP( "Test requires PostgreSQL", SkipSingle ); - return; - } - - const QString tablename(qTableName( "bindtest", __FILE__ )); - - QSqlQuery q( db ); - - QVERIFY_SQL( q, exec( "create table " + tablename + " (id1 int, id2 int, id3 int, fld1 int, fld2 int)" ) ); - QVERIFY_SQL( q, exec( "insert into " + tablename + " values (1, 2, 3, 10, 5)" ) ); - - QVERIFY_SQL( q, prepare( "select sum((fld1 - fld2)::int) from " + tablename + " where id1 = :myid1 and id2 =:myid2 and id3=:myid3" ) ); - q.bindValue( ":myid1", 1 ); - q.bindValue( ":myid2", 2 ); - q.bindValue( ":myid3", 3 ); - - QVERIFY_SQL( q, exec() ); - QVERIFY_SQL( q, next() ); - - if ( db.driver()->hasFeature( QSqlDriver::PreparedQueries ) ) - QCOMPARE( q.executedQuery(), QString( "select sum((fld1 - fld2)::int) from " + tablename + " where id1 = ? and id2 =? and id3=?" ) ); - else - QCOMPARE( q.executedQuery(), QString( "select sum((fld1 - fld2)::int) from " + tablename + " where id1 = 1 and id2 =2 and id3=3" ) ); -} - /* For task 157397: Using QSqlQuery with an invalid QSqlDatabase does not set the last error of the query. This test function will output some warnings, that's ok. @@ -1856,40 +1723,6 @@ void tst_QSqlQuery::queryOnInvalidDatabase() } } -/* For task 159138: Error on instantiating a sql-query before explicitly - opening the database. This is something we don't support, so this isn't - really a bug. However some of the drivers are nice enough to support it. -*/ -void tst_QSqlQuery::createQueryOnClosedDatabase() -{ - QFETCH( QString, dbName ); - QSqlDatabase db = QSqlDatabase::database( dbName ); - CHECK_DATABASE( db ); - - // Only supported by these drivers - - if ( !db.driverName().startsWith( "QPSQL" ) - && !db.driverName().startsWith( "QMYSQL" ) ) { - QSKIP( "Test is specific for PostgreSQL and MySql", SkipSingle ); - return; - } - - db.close(); - - QSqlQuery q( db ); - db.open(); - QVERIFY_SQL( q, exec( QString( "select * from %1 where id = 1" ).arg( qtest ) ) ); - - QVERIFY_SQL( q, next() ); - QCOMPARE( q.value( 0 ).toInt(), 1 ); - QCOMPARE( q.value( 1 ).toString().trimmed(), QLatin1String( "VarChar1" ) ); - QCOMPARE( q.value( 2 ).toString().trimmed(), QLatin1String( "Char1" ) ); - - db.close(); - QVERIFY2( !q.exec( QString( "select * from %1 where id = 1" ).arg( qtest ) ), - qPrintable( QString( "This can't happen! The query should not have been executed!" ) ) ); -} - void tst_QSqlQuery::reExecutePreparedForwardOnlyQuery() { QFETCH( QString, dbName ); @@ -2009,15 +1842,6 @@ void tst_QSqlQuery::nextResult() QSqlQuery q( db ); - if ( db.driverName().startsWith( "QMYSQL" ) && tst_Databases::getMySqlVersion( db ).section( QChar('.'), 0, 0 ).toInt()<5 ) - QSKIP( "Test requires MySQL >= 5.0", SkipSingle ); - - enum DriverType { ODBC, MYSQL }; - DriverType driverType = ODBC; - - if ( db.driverName().startsWith( "QMYSQL" ) ) - driverType = MYSQL; - const QString tableName(qTableName( "more_results", __FILE__ )); QVERIFY_SQL( q, exec( "CREATE TABLE " + tableName + " (id integer, text varchar(20), num numeric(6, 3), empty varchar(10));" ) ); @@ -2049,8 +1873,7 @@ void tst_QSqlQuery::nextResult() // Query that returns two result sets (batch sql) // When working with multiple result sets SQL Server insists on non-scrollable cursors - if ( driverType == ODBC ) - q.setForwardOnly( true ); + q.setForwardOnly( true ); QVERIFY_SQL( q, exec( "SELECT id FROM " + tableName + "; SELECT text, num FROM " + tableName + ';' ) ); @@ -2070,10 +1893,7 @@ void tst_QSqlQuery::nextResult() QCOMPARE( q.record().field( 1 ).name().toUpper(), QString( "NUM" ) ); - if ( driverType == MYSQL ) - QCOMPARE( q.record().field( 1 ).type(), QVariant::String ); - else - QCOMPARE( q.record().field( 1 ).type(), QVariant::Double ); + QCOMPARE( q.record().field( 1 ).type(), QVariant::Double ); QVERIFY( q.next() ); // Move to first row of the second result set @@ -2126,24 +1946,12 @@ void tst_QSqlQuery::nextResult() q.exec( QString( "DROP PROCEDURE %1;" ).arg( procName ) ); - if ( driverType == MYSQL ) - QVERIFY_SQL( q, exec( QString( "CREATE PROCEDURE %1()" - "\nBEGIN" - "\nSELECT id, text FROM %2;" - "\nSELECT empty, num, text, id FROM %3;" - "\nEND" ).arg( procName ).arg( tableName ).arg( tableName ) ) ); - else - QVERIFY_SQL( q, exec( QString( "CREATE PROCEDURE %1" - "\nAS" - "\nSELECT id, text FROM %2" - "\nSELECT empty, num, text, id FROM %3" ).arg( procName ).arg( tableName ).arg( tableName ) ) ); + QVERIFY_SQL( q, exec( QString( "CREATE PROCEDURE %1" + "\nAS" + "\nSELECT id, text FROM %2" + "\nSELECT empty, num, text, id FROM %3" ).arg( procName ).arg( tableName ).arg( tableName ) ) ); - if ( driverType == MYSQL ) { - q.setForwardOnly( true ); - QVERIFY_SQL( q, exec( QString( "CALL %1()" ).arg( procName ) ) ); - } else { - QVERIFY_SQL( q, exec( QString( "EXEC %1" ).arg( procName ) ) ); - } + QVERIFY_SQL( q, exec( QString( "EXEC %1" ).arg( procName ) ) ); for ( int i = 0; i < 4; i++ ) { QVERIFY_SQL( q, next() ); @@ -2163,13 +1971,6 @@ void tst_QSqlQuery::nextResult() QCOMPARE( q.value( 3 ).toInt(), 1+i ); } - // MySQL also counts the CALL itself as a result - if ( driverType == MYSQL ) { - QVERIFY( q.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) - } - QVERIFY( !q.nextResult() ); QVERIFY( !q.isActive() ); @@ -2200,9 +2001,7 @@ void tst_QSqlQuery::blobsPreparedQuery() // In PostgreSQL a BLOB is not called a BLOB, but a BYTEA! :-) // ... and in SQL Server it can be called a lot, but IMAGE will do. QString typeName( "BLOB" ); - if ( db.driverName().startsWith( "QPSQL" ) ) - typeName = "BYTEA"; - else if ( db.driverName().startsWith( "QODBC" ) && tst_Databases::isSqlServer( db )) + if ( db.driverName().startsWith( "QODBC" ) && tst_Databases::isSqlServer( db )) typeName = "IMAGE"; QVERIFY_SQL( q, exec( QString( "CREATE TABLE %1(id INTEGER, data %2)" ).arg( tableName ).arg( typeName ) ) ); @@ -2310,21 +2109,6 @@ void tst_QSqlQuery::task_250026() QCOMPARE( q.value( 0 ).toString().length(), data1026.length() ); } -void tst_QSqlQuery::task_205701() -{ - QSqlDatabase qsdb = QSqlDatabase::addDatabase("QMYSQL", "atest"); - qsdb.setHostName("test"); - qsdb.setDatabaseName("test"); - qsdb.setUserName("test"); - qsdb.setPassword("test"); - qsdb.open(); - -// { - QSqlQuery query(qsdb); -// } - QSqlDatabase::removeDatabase("atest"); -} - #ifdef NOT_READY_YET // For task: 229811 void tst_QSqlQuery::task_229811() @@ -2409,25 +2193,6 @@ void tst_QSqlQuery::task_234422() #endif -void tst_QSqlQuery::task_233829() -{ - QFETCH( QString, dbName ); - QSqlDatabase db = QSqlDatabase::database( dbName ); - CHECK_DATABASE( db ); - - QSqlQuery q( db ); - const QString tableName(qTableName("task_233829", __FILE__)); - QVERIFY_SQL(q,exec("CREATE TABLE " + tableName + "(dbl1 double precision,dbl2 double precision) without oids;")); - - QString queryString("INSERT INTO " + tableName +"(dbl1, dbl2) VALUES(?,?)"); - - double k = 0.0; - QVERIFY_SQL(q,prepare(queryString)); - q.bindValue(0,0.0 / k); // nan - q.bindValue(1,0.0 / k); // nan - QVERIFY_SQL(q,exec()); -} - void tst_QSqlQuery::sqlServerReturn0() { QFETCH( QString, dbName ); @@ -2456,37 +2221,6 @@ void tst_QSqlQuery::sqlServerReturn0() QVERIFY_SQL(q, next()); } -void tst_QSqlQuery::QTBUG_5251() -{ - QFETCH( QString, dbName ); - QSqlDatabase db = QSqlDatabase::database( dbName ); - CHECK_DATABASE( db ); - const QString timetest(qTableName("timetest", __FILE__)); - - if (!db.driverName().startsWith( "QPSQL" )) return; - - QSqlQuery q(db); - q.exec("DROP TABLE " + timetest); - QVERIFY_SQL(q, exec("CREATE TABLE " + timetest + " (t TIME)")); - QVERIFY_SQL(q, exec("INSERT INTO " + timetest + " VALUES ('1:2:3.666')")); - - QSqlTableModel timetestModel(0,db); - timetestModel.setEditStrategy(QSqlTableModel::OnManualSubmit); - timetestModel.setTable(timetest); - QVERIFY_SQL(timetestModel, select()); - - QCOMPARE(timetestModel.record(0).field(0).value().toTime().toString("HH:mm:ss.zzz"), QString("01:02:03.666")); - QVERIFY_SQL(timetestModel,setData(timetestModel.index(0, 0), QTime(0,12,34,500))); - QCOMPARE(timetestModel.record(0).field(0).value().toTime().toString("HH:mm:ss.zzz"), QString("00:12:34.500")); - QVERIFY_SQL(timetestModel, submitAll()); - QCOMPARE(timetestModel.record(0).field(0).value().toTime().toString("HH:mm:ss.zzz"), QString("00:12:34.500")); - - QVERIFY_SQL(q, exec("UPDATE " + timetest + " SET t = '0:11:22.33'")); - QVERIFY_SQL(timetestModel, select()); - QCOMPARE(timetestModel.record(0).field(0).value().toTime().toString("HH:mm:ss.zzz"), QString("00:11:22.330")); - -} - void tst_QSqlQuery::QTBUG_6618() { QFETCH( QString, dbName ); @@ -2509,75 +2243,6 @@ void tst_QSqlQuery::QTBUG_6618() QVERIFY(q.lastError().text().contains(errorString)); } -void tst_QSqlQuery::QTBUG_6852() -{ - QFETCH( QString, dbName ); - QSqlDatabase db = QSqlDatabase::database( dbName ); - CHECK_DATABASE( db ); - if ( tst_Databases::getMySqlVersion( db ).section( QChar('.'), 0, 0 ).toInt()<5 ) - QSKIP( "Test requires MySQL >= 5.0", SkipSingle ); - - QSqlQuery q(db); - const QString tableName(qTableName("bug6852", __FILE__)), procName(qTableName("bug6852_proc", __FILE__)); - - QVERIFY_SQL(q, exec("DROP PROCEDURE IF EXISTS "+procName)); - QVERIFY_SQL(q, exec("CREATE TABLE "+tableName+"(\n" - "MainKey INT NOT NULL,\n" - "OtherTextCol VARCHAR(45) NOT NULL,\n" - "PRIMARY KEY(`MainKey`))")); - QVERIFY_SQL(q, exec("INSERT INTO "+tableName+" VALUES(0, \"Disabled\")")); - QVERIFY_SQL(q, exec("INSERT INTO "+tableName+" VALUES(5, \"Error Only\")")); - QVERIFY_SQL(q, exec("INSERT INTO "+tableName+" VALUES(10, \"Enabled\")")); - QVERIFY_SQL(q, exec("INSERT INTO "+tableName+" VALUES(15, \"Always\")")); - QVERIFY_SQL(q, exec("CREATE PROCEDURE "+procName+"()\n" - "READS SQL DATA\n" - "BEGIN\n" - " SET @st = 'SELECT MainKey, OtherTextCol from "+tableName+"';\n" - " PREPARE stmt from @st;\n" - " EXECUTE stmt;\n" - "END;")); - - QVERIFY_SQL(q, exec("CALL "+procName+"()")); - QVERIFY_SQL(q, next()); - QCOMPARE(q.value(0).toInt(), 0); - QCOMPARE(q.value(1).toString(), QLatin1String("Disabled")); -} - -void tst_QSqlQuery::QTBUG_5765() -{ - QFETCH( QString, dbName ); - QSqlDatabase db = QSqlDatabase::database( dbName ); - CHECK_DATABASE( db ); - - QSqlQuery q(db); - const QString tableName(qTableName("bug5765", __FILE__)); - - QVERIFY_SQL(q, exec("CREATE TABLE "+tableName+"(testval TINYINT(1) DEFAULT 0)")); - q.prepare("INSERT INTO "+tableName+" SET testval = :VALUE"); - q.bindValue(":VALUE", 1); - QVERIFY_SQL(q, exec()); - q.bindValue(":VALUE", 12); - QVERIFY_SQL(q, exec()); - q.bindValue(":VALUE", 123); - QVERIFY_SQL(q, exec()); - QString sql="select testval from "+tableName; - QVERIFY_SQL(q, exec(sql)); - QVERIFY_SQL(q, next()); - QCOMPARE(q.value(0).toInt(), 1); - QVERIFY_SQL(q, next()); - QCOMPARE(q.value(0).toInt(), 12); - QVERIFY_SQL(q, next()); - QCOMPARE(q.value(0).toInt(), 123); - QVERIFY_SQL(q, prepare(sql)); - QVERIFY_SQL(q, exec()); - QVERIFY_SQL(q, next()); - QCOMPARE(q.value(0).toInt(), 1); - QVERIFY_SQL(q, next()); - QCOMPARE(q.value(0).toInt(), 12); - QVERIFY_SQL(q, next()); - QCOMPARE(q.value(0).toInt(), 123); -} - /** * This test case tests multiple statements in one execution. * Sqlite driver doesn't support multiple statement at one time. diff --git a/tests/auto/qsqltablemodel/tst_qsqltablemodel.cpp b/tests/auto/qsqltablemodel/tst_qsqltablemodel.cpp index 29185c28b..83cad816a 100644 --- a/tests/auto/qsqltablemodel/tst_qsqltablemodel.cpp +++ b/tests/auto/qsqltablemodel/tst_qsqltablemodel.cpp @@ -86,8 +86,6 @@ private slots: void emptyTable_data() { generic_data(); } void emptyTable(); - void tablesAndSchemas_data() { generic_data("QPSQL"); } - void tablesAndSchemas(); void whitespaceInIdentifiers_data() { generic_data(); } void whitespaceInIdentifiers(); void primaryKeyOrder_data() { generic_data("QSQLITE"); } @@ -148,10 +146,6 @@ void tst_QSqlTableModel::dropTestTables() tableNames << qTableName("qtestw hitespace", db.driver()); tst_Databases::safeDropTables(db, tableNames); - - if (db.driverName().startsWith("QPSQL")) { - q.exec("DROP SCHEMA " + qTableName("testschema", __FILE__) + " CASCADE"); - } } } @@ -950,27 +944,6 @@ void tst_QSqlTableModel::emptyTable() QCOMPARE(model.columnCount(), 1); } -void tst_QSqlTableModel::tablesAndSchemas() -{ - QFETCH(QString, dbName); - QSqlDatabase db = QSqlDatabase::database(dbName); - CHECK_DATABASE(db); - - QSqlQuery q(db); - q.exec("DROP SCHEMA " + qTableName("testschema", __FILE__) + " CASCADE"); - QVERIFY_SQL( q, exec("create schema " + qTableName("testschema", __FILE__))); - QString tableName = qTableName("testschema", __FILE__) + '.' + qTableName("testtable", __FILE__); - QVERIFY_SQL( q, exec("create table " + tableName + "(id int)")); - QVERIFY_SQL( q, exec("insert into " + tableName + " values(1)")); - QVERIFY_SQL( q, exec("insert into " + tableName + " values(2)")); - - QSqlTableModel model(0, db); - model.setTable(tableName); - QVERIFY_SQL(model, select()); - QCOMPARE(model.rowCount(), 2); - QCOMPARE(model.columnCount(), 1); -} - void tst_QSqlTableModel::whitespaceInIdentifiers() { QFETCH(QString, dbName); diff --git a/tests/benchmarks/sql/kernel/qsqlquery/main.cpp b/tests/benchmarks/sql/kernel/qsqlquery/main.cpp index 6a3c3fbef..33a70c7ea 100644 --- a/tests/benchmarks/sql/kernel/qsqlquery/main.cpp +++ b/tests/benchmarks/sql/kernel/qsqlquery/main.cpp @@ -158,9 +158,6 @@ void tst_QSqlQuery::dropTestTables( QSqlDatabase db ) << qTableName( QLatin1String("test141895"), __FILE__) << qTableName( QLatin1String("qtest_oraOCINumber"), __FILE__); - if ( db.driverName().startsWith( QLatin1String("QPSQL") ) ) - tablenames << qTableName( QLatin1String("task_233829"), __FILE__); - if ( db.driverName().startsWith( QLatin1String("QSQLITE") ) ) tablenames << qTableName( QLatin1String("record_sqlite"), __FILE__ ); @@ -180,19 +177,15 @@ void tst_QSqlQuery::createTestTables( QSqlDatabase db ) { QSqlQuery q( db ); - if ( db.driverName().startsWith( QLatin1String("QMYSQL") ) ) - // ### stupid workaround until we find a way to hardcode this - // in the MySQL server startup script - q.exec( QLatin1String("set table_type=innodb") ); - else if (tst_Databases::isPostgreSQL(db)) + if (tst_Databases::isPostgreSQL(db)) QVERIFY_SQL( q, exec( QLatin1String("set client_min_messages='warning'") )); if (tst_Databases::isPostgreSQL(db)) QVERIFY_SQL( q, exec( QLatin1String("create table ") + qtest + QLatin1String(" (id serial NOT NULL, t_varchar varchar(20), t_char char(20), primary key(id)) WITH OIDS") ) ); else - QVERIFY_SQL( q, exec( QLatin1String("create table ") + qtest + QLatin1String(" (id int ") + tst_Databases::autoFieldName(db) + QLatin1String(" NOT NULL, t_varchar varchar(20), t_char char(20), primary key(id))") ) ); + QVERIFY_SQL( q, exec( QLatin1String("create table ") + qtest + QLatin1String(" (id int NOT NULL, t_varchar varchar(20), t_char char(20), primary key(id))") ) ); - if ( tst_Databases::isSqlServer( db ) || db.driverName().startsWith( QLatin1String("QTDS") ) ) + if ( tst_Databases::isSqlServer( db ) ) QVERIFY_SQL( q, exec( QLatin1String("create table ") + qTableName( QLatin1String( "qtest_null"), __FILE__ ) + QLatin1String(" (id int null, t_varchar varchar(20) null)") ) ); else QVERIFY_SQL( q, exec( QLatin1String("create table ") + qTableName( QLatin1String("qtest_null"), __FILE__ ) + QLatin1String(" (id int, t_varchar varchar(20))") ) ); @@ -221,8 +214,6 @@ void tst_QSqlQuery::benchmark() QFETCH( QString, dbName ); QSqlDatabase db = QSqlDatabase::database( dbName ); CHECK_DATABASE( db ); - if ( tst_Databases::getMySqlVersion( db ).section( QLatin1Char('.'), 0, 0 ).toInt()<5 ) - QSKIP( "Test requires MySQL >= 5.0", SkipSingle ); QSqlQuery q(db); const QString tableName(qTableName(QLatin1String("benchmark"), __FILE__)); diff --git a/translations/qt.pot b/translations/qt.pot index d4152871c..cd4dc4350 100644 --- a/translations/qt.pot +++ b/translations/qt.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-09-07 01:25+0300\n" +"POT-Creation-Date: 2021-09-10 05:02+0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -38,11 +38,11 @@ msgstr "" msgid "The file '%1' is not a valid Katie plugin." msgstr "" -#: src/core/plugin/qlibrary.cpp:464 +#: src/core/plugin/qlibrary.cpp:463 msgid "The plugin uses incompatible Katie library: %1 (%2, %3)" msgstr "" -#: src/core/plugin/qlibrary.cpp:796 src/core/plugin/qpluginloader.cpp:279 +#: src/core/plugin/qlibrary.cpp:795 src/core/plugin/qpluginloader.cpp:279 #: src/core/io/qiodevice.cpp:1519 src/network/ssl/qsslerror.cpp:249 #: src/network/socket/qnativesocketengine.cpp:250 #: src/network/access/qftp.cpp:1414 src/uitools/formscriptrunner.cpp:104 @@ -5501,42 +5501,6 @@ msgstr "" msgid "Could not reset to start position" msgstr "" -#: src/plugins/sqldrivers/psql/qsql_psql.cpp:184 -msgctxt "QPSQLResult" -msgid "Unable to create query" -msgstr "" - -#: src/plugins/sqldrivers/psql/qsql_psql.cpp:548 -msgctxt "QPSQLResult" -msgid "Unable to prepare statement" -msgstr "" - -#: src/plugins/sqldrivers/psql/qsql_psql.cpp:794 -#: src/plugins/sqldrivers/odbc/qsql_odbc.cpp:1786 -#: src/plugins/sqldrivers/mysql/qsql_mysql.cpp:1164 -msgid "Unable to connect" -msgstr "" - -#: src/plugins/sqldrivers/psql/qsql_psql.cpp:843 -msgid "Could not begin transaction" -msgstr "" - -#: src/plugins/sqldrivers/psql/qsql_psql.cpp:871 -msgid "Could not commit transaction" -msgstr "" - -#: src/plugins/sqldrivers/psql/qsql_psql.cpp:888 -msgid "Could not rollback transaction" -msgstr "" - -#: src/plugins/sqldrivers/psql/qsql_psql.cpp:1172 -msgid "Unable to subscribe" -msgstr "" - -#: src/plugins/sqldrivers/psql/qsql_psql.cpp:1204 -msgid "Unable to unsubscribe" -msgstr "" - #: src/plugins/sqldrivers/odbc/qsql_odbc.cpp:887 #: src/plugins/sqldrivers/odbc/qsql_odbc.cpp:1226 msgctxt "QODBCResult" @@ -5587,6 +5551,10 @@ msgctxt "QODBCResult" msgid "Unable to bind variable" msgstr "" +#: src/plugins/sqldrivers/odbc/qsql_odbc.cpp:1786 +msgid "Unable to connect" +msgstr "" + #: src/plugins/sqldrivers/odbc/qsql_odbc.cpp:1792 msgid "Unable to connect - Driver doesn't support all functionality required" msgstr "" @@ -5596,13 +5564,11 @@ msgid "Unable to disable autocommit" msgstr "" #: src/plugins/sqldrivers/odbc/qsql_odbc.cpp:2082 -#: src/plugins/sqldrivers/mysql/qsql_mysql.cpp:1318 #: src/sql/drivers/qsql_sqlite.cpp:633 msgid "Unable to commit transaction" msgstr "" #: src/plugins/sqldrivers/odbc/qsql_odbc.cpp:2099 -#: src/plugins/sqldrivers/mysql/qsql_mysql.cpp:1335 #: src/sql/drivers/qsql_sqlite.cpp:648 msgid "Unable to rollback transaction" msgstr "" @@ -5611,73 +5577,6 @@ msgstr "" msgid "Unable to enable autocommit" msgstr "" -#: src/plugins/sqldrivers/mysql/qsql_mysql.cpp:445 -#: src/plugins/sqldrivers/mysql/qsql_mysql.cpp:472 -msgctxt "QMYSQLResult" -msgid "Unable to fetch data" -msgstr "" - -#: src/plugins/sqldrivers/mysql/qsql_mysql.cpp:624 -msgctxt "QMYSQLResult" -msgid "Unable to execute query" -msgstr "" - -#: src/plugins/sqldrivers/mysql/qsql_mysql.cpp:630 -msgctxt "QMYSQLResult" -msgid "Unable to store result" -msgstr "" - -#: src/plugins/sqldrivers/mysql/qsql_mysql.cpp:722 -msgctxt "QMYSQLResult" -msgid "Unable to execute next query" -msgstr "" - -#: src/plugins/sqldrivers/mysql/qsql_mysql.cpp:732 -msgctxt "QMYSQLResult" -msgid "Unable to store next result" -msgstr "" - -#: src/plugins/sqldrivers/mysql/qsql_mysql.cpp:799 -#: src/plugins/sqldrivers/mysql/qsql_mysql.cpp:808 -msgctxt "QMYSQLResult" -msgid "Unable to prepare statement" -msgstr "" - -#: src/plugins/sqldrivers/mysql/qsql_mysql.cpp:840 -msgctxt "QMYSQLResult" -msgid "Unable to reset statement" -msgstr "" - -#: src/plugins/sqldrivers/mysql/qsql_mysql.cpp:931 -msgctxt "QMYSQLResult" -msgid "Unable to bind value" -msgstr "" - -#: src/plugins/sqldrivers/mysql/qsql_mysql.cpp:942 -msgctxt "QMYSQLResult" -msgid "Unable to execute statement" -msgstr "" - -#: src/plugins/sqldrivers/mysql/qsql_mysql.cpp:956 -#: src/plugins/sqldrivers/mysql/qsql_mysql.cpp:977 -msgctxt "QMYSQLResult" -msgid "Unable to bind outvalues" -msgstr "" - -#: src/plugins/sqldrivers/mysql/qsql_mysql.cpp:965 -msgctxt "QMYSQLResult" -msgid "Unable to store statement results" -msgstr "" - -#: src/plugins/sqldrivers/mysql/qsql_mysql.cpp:1153 -msgid "Unable to open database '" -msgstr "" - -#: src/plugins/sqldrivers/mysql/qsql_mysql.cpp:1301 -#: src/sql/drivers/qsql_sqlite.cpp:618 -msgid "Unable to begin transaction" -msgstr "" - #: src/scripttools/debugging/qscriptedit.cpp:391 #: src/scripttools/debugging/qscriptdebugger.cpp:1768 msgid "Toggle Breakpoint" @@ -5964,6 +5863,10 @@ msgstr "" msgid "Error closing database" msgstr "" +#: src/sql/drivers/qsql_sqlite.cpp:618 +msgid "Unable to begin transaction" +msgstr "" + #: src/uitools/formbuilderextra.cpp:349 msgctxt "FormBuilder" msgid "Invalid stretch value for '%1': '%2'" diff --git a/translations/qt_tools.pot b/translations/qt_tools.pot index 64a53e3e3..05f87eca3 100644 --- a/translations/qt_tools.pot +++ b/translations/qt_tools.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-09-07 01:25+0300\n" +"POT-Creation-Date: 2021-09-10 05:02+0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n"