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:
parent
e14e5e104d
commit
947d1eaaa4
@ -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]
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
]
|
||||
}
|
||||
]
|
||||
|
@ -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
|
||||
|
@ -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).
|
||||
|
@ -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
|
@ -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
|
@ -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"
|
@ -1,3 +0,0 @@
|
||||
{
|
||||
"Keys": [ "QSQLITE2" ]
|
||||
}
|
@ -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)
|
@ -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).
|
||||
|
@ -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"
|
@ -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
|
@ -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
|
@ -1,3 +0,0 @@
|
||||
{
|
||||
"Keys": [ "QTDS7", "QTDS" ]
|
||||
}
|
@ -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)
|
@ -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'.
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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.
|
||||
|
Loading…
x
Reference in New Issue
Block a user