QtSQL: remove SQLite2 and TDS driver for Qt6

They were deprecated in Qt4 (TDS) and 5.14 (SQLITE2) so they can be
removed now in Qt6

[ChangeLog][QtSql] Removed obsolete TDS and Sqlite2 drivers

Change-Id: I55118fb03106564d519a99ab55f9b5cf528179f3
Reviewed-by: Andy Shaw <andy.shaw@qt.io>
This commit is contained in:
Christian Ehrlicher 2020-01-31 22:02:03 +01:00
parent e14e5e104d
commit 947d1eaaa4
20 changed files with 8 additions and 2112 deletions

View File

@ -320,6 +320,6 @@ Gui, printing, widget options:
Database options:
-sql-<driver> ........ Enable SQL <driver> plugin. Supported drivers:
db2 ibase mysql oci odbc psql sqlite2 sqlite tds
db2 ibase mysql oci odbc psql sqlite
[all auto]
-sqlite .............. Select used sqlite3 [system/qt]
-sqlite .............. Select used sqlite [system/qt]

View File

@ -1,4 +1,4 @@
Please note that the DB2, MySQL, Oracle and TDS client drivers are not
Please note that the DB2, MySQL and Oracle client drivers are not
distributed with the Qt Open Source Editions.
This is because the client libraries are distributed under a license which

View File

@ -7,9 +7,7 @@
"commandline": {
"assignments": {
"MYSQL_PATH": "mysql.prefix",
"SYBASE": "tds.prefix",
"SYBASE_LIBS": "tds.libs"
"MYSQL_PATH": "mysql.prefix"
},
"options": {
"mysql_config": "string",
@ -22,17 +20,13 @@
"sql-odbc": "boolean",
"sql-psql": "boolean",
"sql-sqlite": "boolean",
"sql-sqlite2": "boolean",
"sql-tds": "boolean",
"plugin-sql-db2": { "type": "void", "name": "sql-db2" },
"plugin-sql-ibase": { "type": "void", "name": "sql-ibase" },
"plugin-sql-mysql": { "type": "void", "name": "sql-mysql" },
"plugin-sql-oci": { "type": "void", "name": "sql-oci" },
"plugin-sql-odbc": { "type": "void", "name": "sql-odbc" },
"plugin-sql-psql": { "type": "void", "name": "sql-psql" },
"plugin-sql-sqlite": { "type": "void", "name": "sql-sqlite" },
"plugin-sql-sqlite2": { "type": "void", "name": "sql-sqlite2" },
"plugin-sql-tds": { "type": "void", "name": "sql-tds" }
"plugin-sql-sqlite": { "type": "void", "name": "sql-sqlite" }
}
},
@ -94,15 +88,6 @@
{ "type": "psqlEnv", "libs": "-lpq", "condition": "!config.win32" }
]
},
"tds": {
"label": "TDS (Sybase)",
"test": {},
"headers": [ "sybfront.h", "sybdb.h" ],
"sources": [
{ "type": "sybaseEnv", "libs": "-lNTWDBLIB", "condition": "config.win32" },
{ "type": "sybaseEnv", "libs": "-lsybdb", "condition": "!config.win32" }
]
},
"oci": {
"label": "OCI (Oracle)",
"test": {},
@ -132,14 +117,6 @@
{ "libs": "-lodbc", "condition": "!config.win32 && !config.darwin" }
]
},
"sqlite2": {
"label": "SQLite (version 2)",
"test": {},
"headers": "sqlite.h",
"sources": [
"-lsqlite"
]
},
"sqlite3": {
"label": "SQLite (version 3)",
"export": "sqlite",
@ -191,11 +168,6 @@
"condition": "libs.psql",
"output": [ "privateFeature" ]
},
"sql-sqlite2": {
"label": "SQLite2",
"condition": "libs.sqlite2",
"output": [ "privateFeature" ]
},
"sql-sqlite": {
"label": "SQLite",
"condition": "features.datestring",
@ -206,11 +178,6 @@
"autoDetect": false,
"condition": "features.sql-sqlite && libs.sqlite3",
"output": [ "privateFeature" ]
},
"sql-tds": {
"label": "TDS (Sybase)",
"condition": "features.datestring && libs.tds",
"output": [ "privateFeature" ]
}
},
@ -227,7 +194,7 @@
"section": "Qt Sql Drivers",
"entries": [
"sql-db2", "sql-ibase", "sql-mysql", "sql-oci", "sql-odbc", "sql-psql",
"sql-sqlite2", "sql-sqlite", "system-sqlite", "sql-tds"
"sql-sqlite", "system-sqlite"
]
}
]

View File

@ -8,9 +8,7 @@ sqldrivers_standalone {
qtConfig(sql-psql) : SUBDIRS += psql
qtConfig(sql-mysql) : SUBDIRS += mysql
qtConfig(sql-odbc) : SUBDIRS += odbc
qtConfig(sql-tds) : SUBDIRS += tds
qtConfig(sql-oci) : SUBDIRS += oci
qtConfig(sql-db2) : SUBDIRS += db2
qtConfig(sql-sqlite) : SUBDIRS += sqlite
qtConfig(sql-sqlite2) : SUBDIRS += sqlite2
qtConfig(sql-ibase) : SUBDIRS += ibase

View File

@ -1,6 +0,0 @@
You will need the SQLite development headers and libraries installed
before compiling this plugin.
See the Qt SQL documentation for more information on compiling Qt SQL
driver plugins (sql-driver.html).

View File

@ -1,615 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtSql module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qsql_sqlite2_p.h"
#include <qcoreapplication.h>
#include <qvariant.h>
#include <qdatetime.h>
#include <qfile.h>
#include <qsqlerror.h>
#include <qsqlfield.h>
#include <qsqlindex.h>
#include <qsqlquery.h>
#include <QtSql/private/qsqlcachedresult_p.h>
#include <QtSql/private/qsqldriver_p.h>
#include <qstringlist.h>
#include <qvector.h>
#if !defined Q_OS_WIN
# include <unistd.h>
#endif
#include <sqlite.h>
typedef struct sqlite_vm sqlite_vm;
Q_DECLARE_OPAQUE_POINTER(sqlite_vm*)
Q_DECLARE_METATYPE(sqlite_vm*)
Q_DECLARE_OPAQUE_POINTER(sqlite*)
Q_DECLARE_METATYPE(sqlite*)
QT_BEGIN_NAMESPACE
static QVariant::Type nameToType(const QString& typeName)
{
QString tName = typeName.toUpper();
if (tName.startsWith(QLatin1String("INT")))
return QVariant::Int;
if (tName.startsWith(QLatin1String("FLOAT")) || tName.startsWith(QLatin1String("NUMERIC")))
return QVariant::Double;
if (tName.startsWith(QLatin1String("BOOL")))
return QVariant::Bool;
// SQLite is typeless - consider everything else as string
return QVariant::String;
}
class QSQLite2DriverPrivate : public QSqlDriverPrivate
{
Q_DECLARE_PUBLIC(QSQLite2Driver)
public:
QSQLite2DriverPrivate();
sqlite *access;
bool utf8;
};
QSQLite2DriverPrivate::QSQLite2DriverPrivate() : QSqlDriverPrivate(), access(0)
{
utf8 = (qstrcmp(sqlite_encoding, "UTF-8") == 0);
dbmsType = QSqlDriver::SQLite;
}
class QSQLite2ResultPrivate;
class QSQLite2Result : public QSqlCachedResult
{
Q_DECLARE_PRIVATE(QSQLite2Result)
friend class QSQLite2Driver;
public:
explicit QSQLite2Result(const QSQLite2Driver* db);
~QSQLite2Result();
QVariant handle() const override;
protected:
bool gotoNext(QSqlCachedResult::ValueCache &row, int idx) override;
bool reset(const QString &query) override;
int size() override;
int numRowsAffected() override;
QSqlRecord record() const override;
void detachFromResultSet() override;
void virtual_hook(int id, void *data) override;
};
class QSQLite2ResultPrivate: public QSqlCachedResultPrivate
{
Q_DECLARE_PUBLIC(QSQLite2Result)
public:
Q_DECLARE_SQLDRIVER_PRIVATE(QSQLite2Driver);
QSQLite2ResultPrivate(QSQLite2Result *q, const QSQLite2Driver *drv);
void cleanup();
bool fetchNext(QSqlCachedResult::ValueCache &values, int idx, bool initialFetch);
bool isSelect();
// initializes the recordInfo and the cache
void init(const char **cnames, int numCols);
void finalize();
// and we have too keep our own struct for the data (sqlite works via
// callback.
const char *currentTail;
sqlite_vm *currentMachine;
bool skippedStatus; // the status of the fetchNext() that's skipped
bool skipRow; // skip the next fetchNext()?
QSqlRecord rInf;
QVector<QVariant> firstRow;
};
QSQLite2ResultPrivate::QSQLite2ResultPrivate(QSQLite2Result *q, const QSQLite2Driver *drv)
: QSqlCachedResultPrivate(q, drv),
currentTail(0),
currentMachine(0),
skippedStatus(false),
skipRow(false)
{
}
void QSQLite2ResultPrivate::cleanup()
{
Q_Q(QSQLite2Result);
finalize();
rInf.clear();
currentTail = 0;
currentMachine = 0;
skippedStatus = false;
skipRow = false;
q->setAt(QSql::BeforeFirstRow);
q->setActive(false);
q->cleanup();
}
void QSQLite2ResultPrivate::finalize()
{
Q_Q(QSQLite2Result);
if (!currentMachine)
return;
char* err = 0;
int res = sqlite_finalize(currentMachine, &err);
if (err) {
q->setLastError(QSqlError(QCoreApplication::translate("QSQLite2Result",
"Unable to fetch results"), QString::fromLatin1(err),
QSqlError::StatementError,
res != -1 ? QString::number(res) : QString()));
sqlite_freemem(err);
}
currentMachine = 0;
}
// called on first fetch
void QSQLite2ResultPrivate::init(const char **cnames, int numCols)
{
Q_Q(QSQLite2Result);
if (!cnames)
return;
rInf.clear();
if (numCols <= 0)
return;
q->init(numCols);
for (int i = 0; i < numCols; ++i) {
const char* lastDot = strrchr(cnames[i], '.');
const char* fieldName = lastDot ? lastDot + 1 : cnames[i];
//remove quotations around the field name if any
QString fieldStr = QString::fromLatin1(fieldName);
QLatin1Char quote('\"');
if ( fieldStr.length() > 2 && fieldStr.startsWith(quote) && fieldStr.endsWith(quote)) {
fieldStr = fieldStr.mid(1);
fieldStr.chop(1);
}
rInf.append(QSqlField(fieldStr,
nameToType(QString::fromLatin1(cnames[i+numCols]))));
}
}
bool QSQLite2ResultPrivate::fetchNext(QSqlCachedResult::ValueCache &values, int idx, bool initialFetch)
{
Q_Q(QSQLite2Result);
// may be caching.
const char **fvals;
const char **cnames;
int colNum;
int res;
int i;
if (skipRow) {
// already fetched
Q_ASSERT(!initialFetch);
skipRow = false;
for(int i=0;i<firstRow.count(); i++)
values[i] = firstRow[i];
return skippedStatus;
}
skipRow = initialFetch;
if (!currentMachine)
return false;
// keep trying while busy, wish I could implement this better.
while ((res = sqlite_step(currentMachine, &colNum, &fvals, &cnames)) == SQLITE_BUSY) {
// sleep instead requesting result again immidiately.
#if defined Q_OS_WIN
Sleep(1000);
#else
sleep(1);
#endif
}
if(initialFetch) {
firstRow.clear();
firstRow.resize(colNum);
}
switch(res) {
case SQLITE_ROW:
// check to see if should fill out columns
if (rInf.isEmpty())
// must be first call.
init(cnames, colNum);
if (!fvals)
return false;
if (idx < 0 && !initialFetch)
return true;
for (i = 0; i < colNum; ++i)
values[i + idx] = drv_d_func()->utf8 ? QString::fromUtf8(fvals[i]) : QString::fromLatin1(fvals[i]);
return true;
case SQLITE_DONE:
if (rInf.isEmpty())
// must be first call.
init(cnames, colNum);
q->setAt(QSql::AfterLastRow);
return false;
case SQLITE_ERROR:
case SQLITE_MISUSE:
default:
// something wrong, don't get col info, but still return false
finalize(); // finalize to get the error message.
q->setAt(QSql::AfterLastRow);
return false;
}
return false;
}
QSQLite2Result::QSQLite2Result(const QSQLite2Driver* db)
: QSqlCachedResult(*new QSQLite2ResultPrivate(this, db))
{
}
QSQLite2Result::~QSQLite2Result()
{
Q_D(QSQLite2Result);
d->cleanup();
}
void QSQLite2Result::virtual_hook(int id, void *data)
{
QSqlCachedResult::virtual_hook(id, data);
}
/*
Execute \a query.
*/
bool QSQLite2Result::reset (const QString& query)
{
Q_D(QSQLite2Result);
// this is where we build a query.
if (!driver())
return false;
if (!driver()-> isOpen() || driver()->isOpenError())
return false;
d->cleanup();
// Um, ok. callback based so.... pass private static function for this.
setSelect(false);
char *err = 0;
int res = sqlite_compile(d->drv_d_func()->access,
d->drv_d_func()->utf8 ? query.toUtf8().constData()
: query.toLatin1().constData(),
&(d->currentTail),
&(d->currentMachine),
&err);
if (res != SQLITE_OK || err) {
setLastError(QSqlError(QCoreApplication::translate("QSQLite2Result",
"Unable to execute statement"), QString::fromLatin1(err),
QSqlError::StatementError, res));
sqlite_freemem(err);
}
//if (*d->currentTail != '\000' then there is more sql to eval
if (!d->currentMachine) {
setActive(false);
return false;
}
// we have to fetch one row to find out about
// the structure of the result set
d->skippedStatus = d->fetchNext(d->firstRow, 0, true);
if (lastError().isValid()) {
setSelect(false);
setActive(false);
return false;
}
setSelect(!d->rInf.isEmpty());
setActive(true);
return true;
}
bool QSQLite2Result::gotoNext(QSqlCachedResult::ValueCache& row, int idx)
{
Q_D(QSQLite2Result);
return d->fetchNext(row, idx, false);
}
int QSQLite2Result::size()
{
return -1;
}
int QSQLite2Result::numRowsAffected()
{
Q_D(QSQLite2Result);
return sqlite_changes(d->drv_d_func()->access);
}
QSqlRecord QSQLite2Result::record() const
{
Q_D(const QSQLite2Result);
if (!isActive() || !isSelect())
return QSqlRecord();
return d->rInf;
}
void QSQLite2Result::detachFromResultSet()
{
Q_D(QSQLite2Result);
d->finalize();
}
QVariant QSQLite2Result::handle() const
{
Q_D(const QSQLite2Result);
return QVariant::fromValue(d->currentMachine);
}
/////////////////////////////////////////////////////////
QSQLite2Driver::QSQLite2Driver(QObject *parent)
: QSqlDriver(*new QSQLite2DriverPrivate, parent)
{
}
QSQLite2Driver::QSQLite2Driver(sqlite *connection, QObject *parent)
: QSqlDriver(*new QSQLite2DriverPrivate, parent)
{
Q_D(QSQLite2Driver);
d->access = connection;
setOpen(true);
setOpenError(false);
}
QSQLite2Driver::~QSQLite2Driver()
{
}
bool QSQLite2Driver::hasFeature(DriverFeature f) const
{
Q_D(const QSQLite2Driver);
switch (f) {
case Transactions:
case SimpleLocking:
return true;
case Unicode:
return d->utf8;
default:
return false;
}
}
/*
SQLite dbs have no user name, passwords, hosts or ports.
just file names.
*/
bool QSQLite2Driver::open(const QString & db, const QString &, const QString &, const QString &, int, const QString &)
{
Q_D(QSQLite2Driver);
if (isOpen())
close();
if (db.isEmpty())
return false;
char* err = 0;
d->access = sqlite_open(QFile::encodeName(db), 0, &err);
if (err) {
setLastError(QSqlError(tr("Error opening database"), QString::fromLatin1(err),
QSqlError::ConnectionError));
sqlite_freemem(err);
err = 0;
}
if (d->access) {
setOpen(true);
setOpenError(false);
return true;
}
setOpenError(true);
return false;
}
void QSQLite2Driver::close()
{
Q_D(QSQLite2Driver);
if (isOpen()) {
sqlite_close(d->access);
d->access = 0;
setOpen(false);
setOpenError(false);
}
}
QSqlResult *QSQLite2Driver::createResult() const
{
return new QSQLite2Result(this);
}
bool QSQLite2Driver::beginTransaction()
{
Q_D(QSQLite2Driver);
if (!isOpen() || isOpenError())
return false;
char* err;
int res = sqlite_exec(d->access, "BEGIN", 0, this, &err);
if (res == SQLITE_OK)
return true;
setLastError(QSqlError(tr("Unable to begin transaction"),
QString::fromLatin1(err), QSqlError::TransactionError, res));
sqlite_freemem(err);
return false;
}
bool QSQLite2Driver::commitTransaction()
{
Q_D(QSQLite2Driver);
if (!isOpen() || isOpenError())
return false;
char* err;
int res = sqlite_exec(d->access, "COMMIT", 0, this, &err);
if (res == SQLITE_OK)
return true;
setLastError(QSqlError(tr("Unable to commit transaction"),
QString::fromLatin1(err), QSqlError::TransactionError, res));
sqlite_freemem(err);
return false;
}
bool QSQLite2Driver::rollbackTransaction()
{
Q_D(QSQLite2Driver);
if (!isOpen() || isOpenError())
return false;
char* err;
int res = sqlite_exec(d->access, "ROLLBACK", 0, this, &err);
if (res == SQLITE_OK)
return true;
setLastError(QSqlError(tr("Unable to rollback transaction"),
QString::fromLatin1(err), QSqlError::TransactionError, res));
sqlite_freemem(err);
return false;
}
QStringList QSQLite2Driver::tables(QSql::TableType type) const
{
QStringList res;
if (!isOpen())
return res;
QSqlQuery q(createResult());
q.setForwardOnly(true);
if ((type & QSql::Tables) && (type & QSql::Views))
q.exec(QLatin1String("SELECT name FROM sqlite_master WHERE type='table' OR type='view'"));
else if (type & QSql::Tables)
q.exec(QLatin1String("SELECT name FROM sqlite_master WHERE type='table'"));
else if (type & QSql::Views)
q.exec(QLatin1String("SELECT name FROM sqlite_master WHERE type='view'"));
if (q.isActive()) {
while(q.next())
res.append(q.value(0).toString());
}
if (type & QSql::SystemTables) {
// there are no internal tables beside this one:
res.append(QLatin1String("sqlite_master"));
}
return res;
}
QSqlIndex QSQLite2Driver::primaryIndex(const QString &tblname) const
{
QSqlRecord rec(record(tblname)); // expensive :(
if (!isOpen())
return QSqlIndex();
QSqlQuery q(createResult());
q.setForwardOnly(true);
QString table = tblname;
if (isIdentifierEscaped(table, QSqlDriver::TableName))
table = stripDelimiters(table, QSqlDriver::TableName);
// finrst find a UNIQUE INDEX
q.exec(QLatin1String("PRAGMA index_list('") + table + QLatin1String("');"));
QString indexname;
while(q.next()) {
if (q.value(2).toInt()==1) {
indexname = q.value(1).toString();
break;
}
}
if (indexname.isEmpty())
return QSqlIndex();
q.exec(QLatin1String("PRAGMA index_info('") + indexname + QLatin1String("');"));
QSqlIndex index(table, indexname);
while(q.next()) {
QString name = q.value(2).toString();
QVariant::Type type = QVariant::Invalid;
if (rec.contains(name))
type = rec.field(name).type();
index.append(QSqlField(name, type, tblname));
}
return index;
}
QSqlRecord QSQLite2Driver::record(const QString &tbl) const
{
if (!isOpen())
return QSqlRecord();
QString table = tbl;
if (isIdentifierEscaped(tbl, QSqlDriver::TableName))
table = stripDelimiters(table, QSqlDriver::TableName);
QSqlQuery q(createResult());
q.setForwardOnly(true);
q.exec(QLatin1String("SELECT * FROM ") + tbl + QLatin1String(" LIMIT 1"));
return q.record();
}
QVariant QSQLite2Driver::handle() const
{
Q_D(const QSQLite2Driver);
return QVariant::fromValue(d->access);
}
QString QSQLite2Driver::escapeIdentifier(const QString &identifier, IdentifierType /*type*/) 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;
}
QT_END_NAMESPACE

View File

@ -1,109 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtSql module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QSQL_SQLITE2_H
#define QSQL_SQLITE2_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <QtSql/qsqldriver.h>
#if defined (Q_OS_WIN32)
# include <QtCore/qt_windows.h>
#endif
struct sqlite;
#ifdef QT_PLUGIN
#define Q_EXPORT_SQLDRIVER_SQLITE2
#else
#define Q_EXPORT_SQLDRIVER_SQLITE2 Q_SQL_EXPORT
#endif
QT_BEGIN_NAMESPACE
class QSqlResult;
class QSQLite2DriverPrivate;
class Q_EXPORT_SQLDRIVER_SQLITE2 QSQLite2Driver : public QSqlDriver
{
friend class QSQLite2ResultPrivate;
Q_DECLARE_PRIVATE(QSQLite2Driver)
Q_OBJECT
public:
explicit QSQLite2Driver(QObject *parent = nullptr);
explicit QSQLite2Driver(sqlite *connection, QObject *parent = nullptr);
~QSQLite2Driver();
bool hasFeature(DriverFeature f) const override;
bool open(const QString &db,
const QString &user,
const QString &password,
const QString &host,
int port,
const QString &connOpts) override;
bool open(const QString &db,
const QString &user,
const QString &password,
const QString &host,
int port) { return open(db, user, password, host, port, QString()); }
void close() override;
QSqlResult *createResult() const override;
bool beginTransaction() override;
bool commitTransaction() override;
bool rollbackTransaction() override;
QStringList tables(QSql::TableType) const override;
QSqlRecord record(const QString &tablename) const override;
QSqlIndex primaryIndex(const QString &table) const override;
QVariant handle() const override;
QString escapeIdentifier(const QString &identifier, IdentifierType) const override;
};
QT_END_NAMESPACE
#endif // QSQL_SQLITE2_H

View File

@ -1,74 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <qsqldriverplugin.h>
#include <qstringlist.h>
#include "qsql_sqlite2_p.h"
QT_BEGIN_NAMESPACE
// ### Qt6: remove, obsolete since 5.14
class QSQLite2DriverPlugin : public QSqlDriverPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QSqlDriverFactoryInterface" FILE "sqlite2.json")
public:
QSQLite2DriverPlugin();
QSqlDriver* create(const QString &);
};
QSQLite2DriverPlugin::QSQLite2DriverPlugin()
: QSqlDriverPlugin()
{
}
QSqlDriver* QSQLite2DriverPlugin::create(const QString &name)
{
if (name == QLatin1String("QSQLITE2")) {
QSQLite2Driver* driver = new QSQLite2Driver();
return driver;
}
return 0;
}
QT_END_NAMESPACE
#include "smain.moc"

View File

@ -1,3 +0,0 @@
{
"Keys": [ "QSQLITE2" ]
}

View File

@ -1,11 +0,0 @@
TARGET = qsqlite2
HEADERS += $$PWD/qsql_sqlite2_p.h
SOURCES += $$PWD/qsql_sqlite2.cpp $$PWD/smain.cpp
QMAKE_USE += sqlite2
OTHER_FILES += sqlite2.json
PLUGIN_CLASS_NAME = QSQLite2DriverPlugin
include(../qsqldriverbase.pri)

View File

@ -1,6 +0,0 @@
You will need the dblib development headers and libraries installed before
compiling this plugin.
See the Qt SQL documentation for more information on compiling Qt SQL
driver plugins (sql-driver.html).

View File

@ -1,81 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#define Q_UUIDIMPL
#include <qsqldriverplugin.h>
#include <qstringlist.h>
#ifdef Q_OS_WIN32 // We assume that MS SQL Server is used. Set Q_USE_SYBASE to force Sybase.
// Conflicting declarations of LPCBYTE in sqlfront.h and winscard.h
#define _WINSCARD_H_
#include <windows.h>
#endif
#include "qsql_tds_p.h"
QT_BEGIN_NAMESPACE
// ### Qt6: remove, obsolete since 4.7
class QTDSDriverPlugin : public QSqlDriverPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QSqlDriverFactoryInterface" FILE "tds.json")
public:
QTDSDriverPlugin();
QSqlDriver* create(const QString &);
};
QTDSDriverPlugin::QTDSDriverPlugin()
: QSqlDriverPlugin()
{
}
QSqlDriver* QTDSDriverPlugin::create(const QString &name)
{
if (name == QLatin1String("QTDS") || name == QLatin1String("QTDS7")) {
QTDSDriver* driver = new QTDSDriver();
return driver;
}
return 0;
}
QT_END_NAMESPACE
#include "main.moc"

View File

@ -1,881 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtSql module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qsql_tds_p.h"
#include <qglobal.h>
#ifdef Q_OS_WIN32 // We assume that MS SQL Server is used. Set Q_USE_SYBASE to force Sybase.
// Conflicting declarations of LPCBYTE in sqlfront.h and winscard.h
#define _WINSCARD_H_
#include <windows.h>
#else
#define Q_USE_SYBASE
#endif
#include <qvariant.h>
#include <qdatetime.h>
#include <qhash.h>
#include <qregexp.h>
#include <qsqlerror.h>
#include <qsqlfield.h>
#include <qsqlindex.h>
#include <qsqlquery.h>
#include <QtSql/private/qsqlcachedresult_p.h>
#include <QtSql/private/qsqldriver_p.h>
#include <qstringlist.h>
#include <qvector.h>
#include <stdlib.h>
Q_DECLARE_OPAQUE_POINTER(LOGINREC*)
Q_DECLARE_OPAQUE_POINTER(DBPROCESS*)
QT_BEGIN_NAMESPACE
#ifdef DBNTWIN32
#define QMSGHANDLE DBMSGHANDLE_PROC
#define QERRHANDLE DBERRHANDLE_PROC
#define QTDSCHAR SQLCHAR
#define QTDSDATETIME4 SQLDATETIM4
#define QTDSDATETIME SQLDATETIME
#define QTDSDATETIME_N SQLDATETIMN
#define QTDSDECIMAL SQLDECIMAL
#define QTDSFLT4 SQLFLT4
#define QTDSFLT8 SQLFLT8
#define QTDSFLT8_N SQLFLTN
#define QTDSINT1 SQLINT1
#define QTDSINT2 SQLINT2
#define QTDSINT4 SQLINT4
#define QTDSINT4_N SQLINTN
#define QTDSMONEY4 SQLMONEY4
#define QTDSMONEY SQLMONEY
#define QTDSMONEY_N SQLMONEYN
#define QTDSNUMERIC SQLNUMERIC
#define QTDSTEXT SQLTEXT
#define QTDSVARCHAR SQLVARCHAR
#define QTDSBIT SQLBIT
#define QTDSBINARY SQLBINARY
#define QTDSVARBINARY SQLVARBINARY
#define QTDSIMAGE SQLIMAGE
#else
#define QMSGHANDLE MHANDLEFUNC
#define QERRHANDLE EHANDLEFUNC
#define QTDSCHAR SYBCHAR
#define QTDSDATETIME4 SYBDATETIME4
#define QTDSDATETIME SYBDATETIME
#define QTDSDATETIME_N SYBDATETIMN
#define QTDSDECIMAL SYBDECIMAL
#define QTDSFLT8 SYBFLT8
#define QTDSFLT8_N SYBFLTN
#define QTDSFLT4 SYBREAL
#define QTDSINT1 SYBINT1
#define QTDSINT2 SYBINT2
#define QTDSINT4 SYBINT4
#define QTDSINT4_N SYBINTN
#define QTDSMONEY4 SYBMONEY4
#define QTDSMONEY SYBMONEY
#define QTDSMONEY_N SYBMONEYN
#define QTDSNUMERIC SYBNUMERIC
#define QTDSTEXT SYBTEXT
#define QTDSVARCHAR SYBVARCHAR
#define QTDSBIT SYBBIT
#define QTDSBINARY SYBBINARY
#define QTDSVARBINARY SYBVARBINARY
#define QTDSIMAGE SYBIMAGE
// magic numbers not defined anywhere in Sybase headers
#define QTDSDECIMAL_2 55
#define QTDSNUMERIC_2 63
#endif //DBNTWIN32
#define TDS_CURSOR_SIZE 50
// workaround for FreeTDS
#ifndef CS_PUBLIC
#define CS_PUBLIC
#endif
QSqlError qMakeError(const QString& err, QSqlError::ErrorType type, int errNo = -1)
{
return QSqlError(QLatin1String("QTDS: ") + err, QString(), type,
errNo != -1 ? QString::number(errNo) : QString());
}
class QTDSDriverPrivate : public QSqlDriverPrivate
{
Q_DECLARE_PUBLIC(QTDSDriver)
public:
QTDSDriverPrivate() : QSqlDriverPrivate(), login(0), initialized(false) { dbmsType = QSqlDriver::Sybase; }
LOGINREC* login; // login information
QString hostName;
QString db;
bool initialized;
};
struct QTDSColumnData
{
void *data;
DBINT nullbind;
};
Q_DECLARE_TYPEINFO(QTDSColumnData, Q_MOVABLE_TYPE);
class QTDSResultPrivate;
class QTDSResult : public QSqlCachedResult
{
Q_DECLARE_PRIVATE(QTDSResult)
public:
explicit QTDSResult(const QTDSDriver* db);
~QTDSResult();
QVariant handle() const override;
protected:
void cleanup();
bool reset(const QString &query) override;
int size() override;
int numRowsAffected() override;
bool gotoNext(QSqlCachedResult::ValueCache &values, int index) override;
QSqlRecord record() const override;
};
class QTDSResultPrivate: public QSqlCachedResultPrivate
{
Q_DECLARE_PUBLIC(QTDSResult)
public:
Q_DECLARE_SQLDRIVER_PRIVATE(QTDSDriver)
QTDSResultPrivate(QTDSResult *q, const QTDSDriver *drv)
: QSqlCachedResultPrivate(q, drv),
login(0),
dbproc(0) {}
LOGINREC* login; // login information
DBPROCESS* dbproc; // connection from app to server
QSqlError lastError;
void addErrorMsg(QString& errMsg) { errorMsgs.append(errMsg); }
QString getErrorMsgs() { return errorMsgs.join(QLatin1String("\n")); }
void clearErrorMsgs() { errorMsgs.clear(); }
QVector<QTDSColumnData> buffer;
QSqlRecord rec;
private:
QStringList errorMsgs;
};
typedef QHash<DBPROCESS *, QTDSResultPrivate *> QTDSErrorHash;
Q_GLOBAL_STATIC(QTDSErrorHash, errs)
extern "C" {
static int CS_PUBLIC qTdsMsgHandler (DBPROCESS* dbproc,
DBINT msgno,
int msgstate,
int severity,
char* msgtext,
char* srvname,
char* /*procname*/,
int line)
{
QTDSResultPrivate* p = errs()->value(dbproc);
if (!p) {
// ### umm... temporary disabled since this throws a lot of warnings...
// qWarning("QTDSDriver warning (%d): [%s] from server [%s]", msgstate, msgtext, srvname);
return INT_CANCEL;
}
if (severity > 0) {
QString errMsg = QString::fromLatin1("%1 (Msg %2, Level %3, State %4, Server %5, Line %6)")
.arg(QString::fromLatin1(msgtext))
.arg(msgno)
.arg(severity)
.arg(msgstate)
.arg(QString::fromLatin1(srvname))
.arg(line);
p->addErrorMsg(errMsg);
if (severity > 10) {
// Severe messages are really errors in the sense of lastError
errMsg = p->getErrorMsgs();
p->lastError = qMakeError(errMsg, QSqlError::UnknownError, msgno);
p->clearErrorMsgs();
}
}
return INT_CANCEL;
}
static int CS_PUBLIC qTdsErrHandler(DBPROCESS* dbproc,
int /*severity*/,
int dberr,
int /*oserr*/,
char* dberrstr,
char* oserrstr)
{
QTDSResultPrivate* p = errs()->value(dbproc);
if (!p) {
qWarning("QTDSDriver error (%d): [%s] [%s]", dberr, dberrstr, oserrstr);
return INT_CANCEL;
}
/*
* If the process is dead or NULL and
* we are not in the middle of logging in...
*/
if((dbproc == NULL || DBDEAD(dbproc))) {
qWarning("QTDSDriver error (%d): [%s] [%s]", dberr, dberrstr, oserrstr);
return INT_CANCEL;
}
const QString errMsg = QLatin1String(dberrstr) + QLatin1Char(' ')
+ QLatin1String(oserrstr) + QLatin1Char('\n')
+ p->getErrorMsgs();
p->lastError = qMakeError(errMsg, QSqlError::UnknownError, dberr);
p->clearErrorMsgs();
return INT_CANCEL ;
}
} //extern "C"
QVariant::Type qDecodeTDSType(int type)
{
QVariant::Type t = QVariant::Invalid;
switch (type) {
case QTDSCHAR:
case QTDSTEXT:
case QTDSVARCHAR:
t = QVariant::String;
break;
case QTDSINT1:
case QTDSINT2:
case QTDSINT4:
case QTDSINT4_N:
case QTDSBIT:
t = QVariant::Int;
break;
case QTDSFLT4:
case QTDSFLT8:
case QTDSFLT8_N:
case QTDSMONEY4:
case QTDSMONEY:
case QTDSDECIMAL:
case QTDSNUMERIC:
#ifdef QTDSNUMERIC_2
case QTDSNUMERIC_2:
#endif
#ifdef QTDSDECIMAL_2
case QTDSDECIMAL_2:
#endif
case QTDSMONEY_N:
t = QVariant::Double;
break;
case QTDSDATETIME4:
case QTDSDATETIME:
case QTDSDATETIME_N:
t = QVariant::DateTime;
break;
case QTDSBINARY:
case QTDSVARBINARY:
case QTDSIMAGE:
t = QVariant::ByteArray;
break;
default:
t = QVariant::Invalid;
break;
}
return t;
}
QVariant::Type qFieldType(QTDSResultPrivate* d, int i)
{
QVariant::Type type = qDecodeTDSType(dbcoltype(d->dbproc, i+1));
return type;
}
QTDSResult::QTDSResult(const QTDSDriver* db)
: QSqlCachedResult(*new QTDSResultPrivate(this, db))
{
Q_D(QTDSResult);
d->login = d->drv_d_func()->login;
d->dbproc = dbopen(d->login, const_cast<char*>(d->drv_d_func()->hostName.toLatin1().constData()));
if (!d->dbproc)
return;
if (dbuse(d->dbproc, const_cast<char*>(d->drv_d_func()->db.toLatin1().constData())) == FAIL)
return;
// insert d in error handler dict
errs()->insert(d->dbproc, d);
dbcmd(d->dbproc, "set quoted_identifier on");
dbsqlexec(d->dbproc);
}
QTDSResult::~QTDSResult()
{
Q_D(QTDSResult);
cleanup();
if (d->dbproc)
dbclose(d->dbproc);
errs()->remove(d->dbproc);
}
void QTDSResult::cleanup()
{
Q_D(QTDSResult);
d->clearErrorMsgs();
d->rec.clear();
for (int i = 0; i < d->buffer.size(); ++i)
free(d->buffer.at(i).data);
d->buffer.clear();
// "can" stands for "cancel"... very clever.
dbcanquery(d->dbproc);
dbfreebuf(d->dbproc);
QSqlCachedResult::cleanup();
}
QVariant QTDSResult::handle() const
{
Q_D(const QTDSResult);
return QVariant(qRegisterMetaType<DBPROCESS *>("DBPROCESS*"), &d->dbproc);
}
static inline bool qIsNull(const QTDSColumnData &p)
{
return p.nullbind == -1;
}
bool QTDSResult::gotoNext(QSqlCachedResult::ValueCache &values, int index)
{
Q_D(QTDSResult);
STATUS stat = dbnextrow(d->dbproc);
if (stat == NO_MORE_ROWS) {
setAt(QSql::AfterLastRow);
return false;
}
if ((stat == FAIL) || (stat == BUF_FULL)) {
setLastError(d->lastError);
return false;
}
if (index < 0)
return true;
for (int i = 0; i < d->rec.count(); ++i) {
int idx = index + i;
switch (d->rec.field(i).type()) {
case QVariant::DateTime:
if (qIsNull(d->buffer.at(i))) {
values[idx] = QVariant(QVariant::DateTime);
} else {
DBDATETIME *bdt = (DBDATETIME*) d->buffer.at(i).data;
QDate date = QDate::fromString(QLatin1String("1900-01-01"), Qt::ISODate);
QTime time = QTime::fromString(QLatin1String("00:00:00"), Qt::ISODate);
values[idx] = QDateTime(date.addDays(bdt->dtdays), time.addMSecs(int(bdt->dttime / 0.3)));
}
break;
case QVariant::Int:
if (qIsNull(d->buffer.at(i)))
values[idx] = QVariant(QVariant::Int);
else
values[idx] = *((int*)d->buffer.at(i).data);
break;
case QVariant::Double:
case QVariant::String:
if (qIsNull(d->buffer.at(i)))
values[idx] = QVariant(QVariant::String);
else
values[idx] = QString::fromLocal8Bit((const char*)d->buffer.at(i).data).trimmed();
break;
case QVariant::ByteArray: {
if (qIsNull(d->buffer.at(i)))
values[idx] = QVariant(QVariant::ByteArray);
else
values[idx] = QByteArray((const char*)d->buffer.at(i).data);
break;
}
default:
// should never happen, and we already fired
// a warning while binding.
values[idx] = QVariant();
break;
}
}
return true;
}
bool QTDSResult::reset (const QString& query)
{
Q_D(QTDSResult);
cleanup();
if (!driver() || !driver()-> isOpen() || driver()->isOpenError())
return false;
setActive(false);
setAt(QSql::BeforeFirstRow);
if (dbcmd(d->dbproc, const_cast<char*>(query.toLocal8Bit().constData())) == FAIL) {
setLastError(d->lastError);
return false;
}
if (dbsqlexec(d->dbproc) == FAIL) {
setLastError(d->lastError);
dbfreebuf(d->dbproc);
return false;
}
if (dbresults(d->dbproc) != SUCCEED) {
setLastError(d->lastError);
dbfreebuf(d->dbproc);
return false;
}
setSelect((DBCMDROW(d->dbproc) == SUCCEED)); // decide whether or not we are dealing with a SELECT query
int numCols = dbnumcols(d->dbproc);
if (numCols > 0) {
d->buffer.resize(numCols);
init(numCols);
}
for (int i = 0; i < numCols; ++i) {
int dbType = dbcoltype(d->dbproc, i+1);
QVariant::Type vType = qDecodeTDSType(dbType);
QSqlField f(QString::fromLatin1(dbcolname(d->dbproc, i+1)), vType);
f.setSqlType(dbType);
f.setLength(dbcollen(d->dbproc, i+1));
d->rec.append(f);
RETCODE ret = -1;
void* p = 0;
switch (vType) {
case QVariant::Int:
p = malloc(4);
ret = dbbind(d->dbproc, i+1, INTBIND, (DBINT) 4, (unsigned char *)p);
break;
case QVariant::Double:
// use string binding to prevent loss of precision
p = malloc(50);
ret = dbbind(d->dbproc, i+1, STRINGBIND, 50, (unsigned char *)p);
break;
case QVariant::String:
p = malloc(dbcollen(d->dbproc, i+1) + 1);
ret = dbbind(d->dbproc, i+1, STRINGBIND, DBINT(dbcollen(d->dbproc, i+1) + 1), (unsigned char *)p);
break;
case QVariant::DateTime:
p = malloc(8);
ret = dbbind(d->dbproc, i+1, DATETIMEBIND, (DBINT) 8, (unsigned char *)p);
break;
case QVariant::ByteArray:
p = malloc(dbcollen(d->dbproc, i+1) + 1);
ret = dbbind(d->dbproc, i+1, BINARYBIND, DBINT(dbcollen(d->dbproc, i+1) + 1), (unsigned char *)p);
break;
default: //don't bind the field since we do not support it
qWarning("QTDSResult::reset: Unsupported type for field \"%s\"", dbcolname(d->dbproc, i+1));
break;
}
if (ret == SUCCEED) {
d->buffer[i].data = p;
ret = dbnullbind(d->dbproc, i+1, &d->buffer[i].nullbind);
} else {
d->buffer[i].data = 0;
d->buffer[i].nullbind = 0;
free(p);
}
if ((ret != SUCCEED) && (ret != -1)) {
setLastError(d->lastError);
return false;
}
}
setActive(true);
return true;
}
int QTDSResult::size()
{
return -1;
}
int QTDSResult::numRowsAffected()
{
Q_D(const QTDSResult);
#ifdef DBNTWIN32
if (dbiscount(d->dbproc)) {
return DBCOUNT(d->dbproc);
}
return -1;
#else
return DBCOUNT(d->dbproc);
#endif
}
QSqlRecord QTDSResult::record() const
{
Q_D(const QTDSResult);
return d->rec;
}
///////////////////////////////////////////////////////////////////
QTDSDriver::QTDSDriver(QObject* parent)
: QSqlDriver(*new QTDSDriverPrivate, parent)
{
init();
}
QTDSDriver::QTDSDriver(LOGINREC* rec, const QString& host, const QString &db, QObject* parent)
: QSqlDriver(*new QTDSDriverPrivate, parent)
{
Q_D(QTDSDriver);
init();
d->login = rec;
d->hostName = host;
d->db = db;
if (rec) {
setOpen(true);
setOpenError(false);
}
}
QVariant QTDSDriver::handle() const
{
Q_D(const QTDSDriver);
return QVariant(qRegisterMetaType<LOGINREC *>("LOGINREC*"), &d->login);
}
void QTDSDriver::init()
{
Q_D(QTDSDriver);
d->initialized = (dbinit() == SUCCEED);
// the following two code-lines will fail compilation on some FreeTDS versions
// just comment them out if you have FreeTDS (you won't get any errors and warnings then)
dberrhandle((QERRHANDLE)qTdsErrHandler);
dbmsghandle((QMSGHANDLE)qTdsMsgHandler);
}
QTDSDriver::~QTDSDriver()
{
dberrhandle(0);
dbmsghandle(0);
// dbexit also calls dbclose if necessary
dbexit();
}
bool QTDSDriver::hasFeature(DriverFeature f) const
{
switch (f) {
case Transactions:
case QuerySize:
case Unicode:
case SimpleLocking:
case EventNotifications:
case MultipleResultSets:
return false;
case BLOB:
return true;
default:
return false;
}
}
bool QTDSDriver::open(const QString & db,
const QString & user,
const QString & password,
const QString & host,
int /*port*/,
const QString& /*connOpts*/)
{
Q_D(QTDSDriver);
if (isOpen())
close();
if (!d->initialized) {
setOpenError(true);
return false;
}
d->login = dblogin();
if (!d->login) {
setOpenError(true);
return false;
}
DBSETLPWD(d->login, const_cast<char*>(password.toLocal8Bit().constData()));
DBSETLUSER(d->login, const_cast<char*>(user.toLocal8Bit().constData()));
// Now, try to open and use the database. If this fails, return false.
DBPROCESS* dbproc;
dbproc = dbopen(d->login, const_cast<char*>(host.toLatin1().constData()));
if (!dbproc) {
setLastError(qMakeError(tr("Unable to open connection"), QSqlError::ConnectionError, -1));
setOpenError(true);
return false;
}
if (dbuse(dbproc, const_cast<char*>(db.toLatin1().constData())) == FAIL) {
setLastError(qMakeError(tr("Unable to use database"), QSqlError::ConnectionError, -1));
setOpenError(true);
return false;
}
dbclose( dbproc );
setOpen(true);
setOpenError(false);
d->hostName = host;
d->db = db;
return true;
}
void QTDSDriver::close()
{
Q_D(QTDSDriver);
if (isOpen()) {
#ifdef Q_USE_SYBASE
dbloginfree(d->login);
#else
dbfreelogin(d->login);
#endif
d->login = 0;
setOpen(false);
setOpenError(false);
}
}
QSqlResult *QTDSDriver::createResult() const
{
return new QTDSResult(this);
}
bool QTDSDriver::beginTransaction()
{
return false;
/*
if (!isOpen()) {
qWarning("QTDSDriver::beginTransaction: Database not open");
return false;
}
if (dbcmd(d->dbproc, "BEGIN TRANSACTION") == FAIL) {
setLastError(d->lastError);
dbfreebuf(d->dbproc);
return false;
}
if (dbsqlexec(d->dbproc) == FAIL) {
setLastError(d->lastError);
dbfreebuf(d->dbproc);
return false;
}
while(dbresults(d->dbproc) == NO_MORE_RESULTS) {}
dbfreebuf(d->dbproc);
inTransaction = true;
return true;
*/
}
bool QTDSDriver::commitTransaction()
{
return false;
/*
if (!isOpen()) {
qWarning("QTDSDriver::commitTransaction: Database not open");
return false;
}
if (dbcmd(d->dbproc, "COMMIT TRANSACTION") == FAIL) {
setLastError(d->lastError);
dbfreebuf(d->dbproc);
return false;
}
if (dbsqlexec(d->dbproc) == FAIL) {
setLastError(d->lastError);
dbfreebuf(d->dbproc);
return false;
}
while(dbresults(d->dbproc) == NO_MORE_RESULTS) {}
dbfreebuf(d->dbproc);
inTransaction = false;
return true;
*/
}
bool QTDSDriver::rollbackTransaction()
{
return false;
/*
if (!isOpen()) {
qWarning("QTDSDriver::rollbackTransaction: Database not open");
return false;
}
if (dbcmd(d->dbproc, "ROLLBACK TRANSACTION") == FAIL) {
setLastError(d->lastError);
dbfreebuf(d->dbproc);
return false;
}
if (dbsqlexec(d->dbproc) == FAIL) {
setLastError(d->lastError);
dbfreebuf(d->dbproc);
return false;
}
while(dbresults(d->dbproc) == NO_MORE_RESULTS) {}
dbfreebuf(d->dbproc);
inTransaction = false;
return true;
*/
}
QSqlRecord QTDSDriver::record(const QString& tablename) const
{
QSqlRecord info;
if (!isOpen())
return info;
QSqlQuery t(createResult());
t.setForwardOnly(true);
QString table = tablename;
if (isIdentifierEscaped(table, QSqlDriver::TableName))
table = stripDelimiters(table, QSqlDriver::TableName);
QString stmt (QLatin1String("select name, type, length, prec from syscolumns "
"where id = (select id from sysobjects where name = '%1')"));
t.exec(stmt.arg(table));
while (t.next()) {
QSqlField f(t.value(0).toString().simplified(), qDecodeTDSType(t.value(1).toInt()), tablename);
f.setLength(t.value(2).toInt());
f.setPrecision(t.value(3).toInt());
f.setSqlType(t.value(1).toInt());
info.append(f);
}
return info;
}
QStringList QTDSDriver::tables(QSql::TableType type) const
{
QStringList list;
if (!isOpen())
return list;
QStringList typeFilter;
if (type & QSql::Tables)
typeFilter += QLatin1String("type='U'");
if (type & QSql::SystemTables)
typeFilter += QLatin1String("type='S'");
if (type & QSql::Views)
typeFilter += QLatin1String("type='V'");
if (typeFilter.isEmpty())
return list;
QSqlQuery t(createResult());
t.setForwardOnly(true);
t.exec(QLatin1String("select name from sysobjects where ") + typeFilter.join(QLatin1String(" or ")));
while (t.next())
list.append(t.value(0).toString().simplified());
return list;
}
QString QTDSDriver::formatValue(const QSqlField &field,
bool trim) const
{
QString r;
if (field.isNull())
r = QLatin1String("NULL");
else if (field.type() == QVariant::DateTime) {
if (field.value().toDateTime().isValid()){
r = field.value().toDateTime().toString(u"yyyyMMdd hh:mm:ss");
r.prepend(QLatin1String("'"));
r.append(QLatin1String("'"));
} else
r = QLatin1String("NULL");
} else if (field.type() == QVariant::ByteArray) {
QByteArray ba = field.value().toByteArray();
QString res;
static const char hexchars[] = "0123456789abcdef";
for (int i = 0; i < ba.size(); ++i) {
uchar s = (uchar) ba[i];
res += QLatin1Char(hexchars[s >> 4]);
res += QLatin1Char(hexchars[s & 0x0f]);
}
r = QLatin1String("0x") + res;
} else {
r = QSqlDriver::formatValue(field, trim);
}
return r;
}
QSqlIndex QTDSDriver::primaryIndex(const QString& tablename) const
{
QSqlRecord rec = record(tablename);
QString table = tablename;
if (isIdentifierEscaped(table, QSqlDriver::TableName))
table = stripDelimiters(table, QSqlDriver::TableName);
QSqlIndex idx(table);
if ((!isOpen()) || (table.isEmpty()))
return QSqlIndex();
QSqlQuery t(createResult());
t.setForwardOnly(true);
t.exec(QString::fromLatin1("sp_helpindex '%1'").arg(table));
if (t.next()) {
QStringList fNames = t.value(2).toString().simplified().split(QLatin1Char(','));
QRegExp regx(QLatin1String("\\s*(\\S+)(?:\\s+(DESC|desc))?\\s*"));
for(QStringList::Iterator it = fNames.begin(); it != fNames.end(); ++it) {
regx.indexIn(*it);
QSqlField f(regx.cap(1), rec.field(regx.cap(1)).type(), tablename);
if (regx.cap(2).toLower() == QLatin1String("desc")) {
idx.append(f, true);
} else {
idx.append(f, false);
}
}
idx.setName(t.value(0).toString().simplified());
}
return idx;
}
QString QTDSDriver::escapeIdentifier(const QString &identifier, IdentifierType type) const
{
Q_UNUSED(type)
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;
}
QT_END_NAMESPACE

View File

@ -1,120 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtSql module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QSQL_TDS_H
#define QSQL_TDS_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <QtSql/qsqldriver.h>
#ifdef Q_OS_WIN32
#define WIN32_LEAN_AND_MEAN
#ifndef Q_USE_SYBASE
#define DBNTWIN32 // indicates 32bit windows dblib
#endif
#include <winsock2.h>
#include <QtCore/qt_windows.h>
#include <sqlfront.h>
#include <sqldb.h>
#define CS_PUBLIC
#else
#include <sybfront.h>
#include <sybdb.h>
#endif //Q_OS_WIN32
#ifdef QT_PLUGIN
#define Q_EXPORT_SQLDRIVER_TDS
#else
#define Q_EXPORT_SQLDRIVER_TDS Q_SQL_EXPORT
#endif
QT_BEGIN_NAMESPACE
class QSqlResult;
class QTDSDriverPrivate;
class Q_EXPORT_SQLDRIVER_TDS QTDSDriver : public QSqlDriver
{
Q_DECLARE_PRIVATE(QTDSDriver)
Q_OBJECT
friend class QTDSResultPrivate;
public:
explicit QTDSDriver(QObject* parent = nullptr);
QTDSDriver(LOGINREC* rec, const QString& host, const QString &db, QObject* parent = nullptr);
~QTDSDriver();
bool hasFeature(DriverFeature f) const override;
bool open(const QString &db,
const QString &user,
const QString &password,
const QString &host,
int port,
const QString &connOpts) override;
void close() override;
QStringList tables(QSql::TableType) const override;
QSqlResult *createResult() const override;
QSqlRecord record(const QString &tablename) const override;
QSqlIndex primaryIndex(const QString &tablename) const override;
QString formatValue(const QSqlField &field,
bool trimStrings) const override;
QVariant handle() const override;
QString escapeIdentifier(const QString &identifier, IdentifierType type) const override;
protected:
bool beginTransaction() override;
bool commitTransaction() override;
bool rollbackTransaction() override;
private:
void init();
};
QT_END_NAMESPACE
#endif // QSQL_TDS_H

View File

@ -1,3 +0,0 @@
{
"Keys": [ "QTDS7", "QTDS" ]
}

View File

@ -1,11 +0,0 @@
TARGET = qsqltds
HEADERS += $$PWD/qsql_tds_p.h
SOURCES += $$PWD/qsql_tds.cpp $$PWD/main.cpp
QMAKE_USE += tds
OTHER_FILES += tds.json
PLUGIN_CLASS_NAME = QTDSDriverPlugin
include(../qsqldriverbase.pri)

View File

@ -54,7 +54,7 @@
Database options:
-sql-<driver> ........ Enable SQL <driver> plugin. Supported drivers:
db2 ibase mysql oci odbc psql sqlite2 sqlite tds
db2 ibase mysql oci odbc psql sqlite
[all auto]
-sqlite .............. Select used sqlite3 [system/qt]
@ -146,21 +146,6 @@ nmake install
//! [15]
//! [16]
cd $QTDIR/qtbase/src/plugins/sqldrivers
qmake -- TDS_PREFIX=$SYBASE
make sub-tds
//! [16]
//! [17]
cd %QTDIR%\qtbase\src\plugins\sqldrivers
qmake
nmake sub-tds
nmake install
//! [17]
//! [18]
cd $QTDIR/qtbase/src/plugins/sqldrivers
qmake -- DB2_PREFIX=$DB2DIR
@ -271,8 +256,6 @@ Checking for MySQL... yes
Checking for OCI (Oracle)... no
Checking for ODBC... yes
Checking for PostgreSQL... no
Checking for SQLite (version 2)... no
Checking for TDS (Sybase)... no
Done running configuration tests.
Configure summary:
@ -284,10 +267,8 @@ Qt Sql Drivers:
OCI (Oracle) ........................... no
ODBC ................................... yes
PostgreSQL ............................. no
SQLite2 ................................ no
SQLite ................................. yes
Using system provided SQLite ......... no
TDS (Sybase) ........................... no
Qt is now configured for building. Just run 'mingw32-make'.
Once everything is built, you must run 'mingw32-make install'.

View File

@ -502,67 +502,4 @@
\li The value is a BLOB of data, stored exactly as it was input.
\li Mapped to QByteArray
\endtable
\section2 Sybase Adaptive Server Data Types
\table 90%
\header
\li Sybase Adaptive Server data type
\li SQL type description
\li Recommended input (C++ or Qt data type)
\row
\li BINARY
\li Describes a fixed-length binary value up to 255 bytes in size.
\li Mapped to QByteArray
\row
\li CHAR
\li Character String
\li Mapped to QString
\row
\li DATETIME
\li Date and time. Range: 1753-01-01 00:00:00 through 9999-12-31 23:59:59.
\li Mapped to QDateTime
\row
\li NCHAR
\li Character String of fixed length
\li Mapped to QString
\row
\li NVARACHAR
\li Character String of variable length
\li Mapped to QString
\row
\li VARCHAR
\li Character String of fixed length
\li Mapped to QString
\row
\li CLOB
\li Character large string object
\li Mapped to QString
\row
\li TIMESTAMP
\li A unique number within a database
\li Mapped to QString
\row
\li SMALLDATETIME
\li Date and time. Range: 1900-01-01 00:00 through 2079-12-31 23:59
\li Mapped to QDateTime
\row
\li UNICHAR
\li Character String of fixed length.(Unicode)
\li Mapped to QString
\row
\li UNIVARCHAR
\li Character String of variable length.(Unicode)
\li Mapped to QString
\row
\li VARBINARY
\li Describes a variable-length binary value up to 255 bytes in size
\li Mapped to QByteArray
\endtable
\section2 SQLite Version 2
SQLite version 2 is "typeless". This means that you can store any kind of
data you want in any column of any table, regardless of the declared
data type of that column. We recommend that you map the data to QString.
*/

View File

@ -54,9 +54,7 @@
\li Open Database Connectivity (ODBC) - Microsoft SQL Server and other
ODBC-compliant databases
\row \li \l{#QPSQL}{QPSQL} \li PostgreSQL (versions 7.3 and above)
\row \li \l{#QSQLITE2}{QSQLITE2} \li SQLite version 2 \note obsolete since Qt 5.14
\row \li \l{#QSQLITE}{QSQLITE} \li SQLite version 3
\row \li \l{#QTDS}{QTDS} \li Sybase Adaptive Server \note obsolete since Qt 4.7
\endtable
SQLite is the in-process database system with the best test coverage
@ -500,49 +498,6 @@
in your installation package. It must be placed in the same folder
as the application executable.
\target QTDS
\section2 QTDS for Sybase Adaptive Server
\note TDS is no longer used by MS Sql Server, and is superseded by
\l{QODBC}{ODBC}. QTDS is obsolete from Qt 4.7.
It is not possible to set the port with QSqlDatabase::setPort() due to limitations in the
Sybase client library. Refer to the Sybase documentation for information on how to set up
a Sybase client configuration file to enable connections to databases on non-default ports.
\section3 How to Build the QTDS Plugin on Unix and \macos
Under Unix, two libraries are available which support the TDS protocol:
\list
\li FreeTDS, a free implementation of the TDS protocol
(\l{http://www.freetds.org}).
\li Sybase Open Client, available from \l{https://support.sap.com}.
\endlist
Regardless of which library you use, the shared object file
\c{libsybdb.so} is needed. Set the \c SYBASE environment variable to
point to the directory where you installed the client library and
execute \c{qmake}:
\snippet code/doc_src_sql-driver.qdoc 16
\section3 How to Build the QDTS Plugin on Windows
You can either use the DB-Library supplied by Microsoft or the Sybase
Open Client (\l{https://support.sap.com}). Configure will try to find
NTWDBLIB.LIB to build the plugin:
\snippet code/doc_src_sql-driver.qdoc 17
By default, the Microsoft library is used on Windows. If you want to
force the use of the Sybase Open Client, you must define \c
Q_USE_SYBASE in \c{%QTDIR%\qtbase\src\plugins\sqldrivers\tds\qsql_tds.cpp}.
If you are not using a Microsoft compiler, replace \c nmake
with \c mingw32-make in the line above.
\target QDB2
\section2 QDB2 for IBM DB2 (Version 7.1 and Above)
@ -571,13 +526,6 @@
If you are not using a Microsoft compiler, replace \c nmake
with \c mingw32-make in the line above.
\target QSQLITE2
\section2 QSQLITE2 for SQLite Version 2
The Qt SQLite 2 plugin is offered for compatibility. Whenever
possible, use the \l{#QSQLITE}{version 3 plugin} instead. The
build instructions for version 3 apply to version 2 as well.
\target QSQLITE
\section2 QSQLITE for SQLite (Version 3 and Above)

View File

@ -619,8 +619,6 @@ QStringList QSqlDatabase::connectionNames()
\row \li QODBC \li ODBC Driver (includes Microsoft SQL Server)
\row \li QPSQL \li PostgreSQL Driver
\row \li QSQLITE \li SQLite version 3 or above
\row \li QSQLITE2 \li SQLite version 2
\row \li QTDS \li Sybase Adaptive Server
\endtable
Additional third party drivers, including your own custom
@ -1185,7 +1183,7 @@ QSqlRecord QSqlDatabase::record(const QString& tablename) const
\li service
\endlist
\header \li DB2 \li OCI \li TDS
\header \li DB2 \li OCI
\row
\li
@ -1200,9 +1198,6 @@ QSqlRecord QSqlDatabase::record(const QString& tablename) const
\li OCI_ATTR_PREFETCH_MEMORY
\endlist
\li
\e none
\header \li SQLite \li Interbase
\row
@ -1327,11 +1322,6 @@ bool QSqlDatabase::isDriverAvailable(const QString& name)
\li SQLHANDLE environment, SQLHANDLE connection
\li \c qsql_db2.cpp
\row
\li QTDS
\li QTDSDriver
\li LOGINREC *loginRecord, DBPROCESS *dbProcess, const QString &hostName
\li \c qsql_tds.cpp
\row
\li QSQLITE
\li QSQLiteDriver
\li sqlite *connection
@ -1343,11 +1333,6 @@ bool QSqlDatabase::isDriverAvailable(const QString& name)
\li \c qsql_ibase.cpp
\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.