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:
|
Database options:
|
||||||
|
|
||||||
-sql-<driver> ........ Enable SQL <driver> plugin. Supported drivers:
|
-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]
|
[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.
|
distributed with the Qt Open Source Editions.
|
||||||
|
|
||||||
This is because the client libraries are distributed under a license which
|
This is because the client libraries are distributed under a license which
|
||||||
|
@ -7,9 +7,7 @@
|
|||||||
|
|
||||||
"commandline": {
|
"commandline": {
|
||||||
"assignments": {
|
"assignments": {
|
||||||
"MYSQL_PATH": "mysql.prefix",
|
"MYSQL_PATH": "mysql.prefix"
|
||||||
"SYBASE": "tds.prefix",
|
|
||||||
"SYBASE_LIBS": "tds.libs"
|
|
||||||
},
|
},
|
||||||
"options": {
|
"options": {
|
||||||
"mysql_config": "string",
|
"mysql_config": "string",
|
||||||
@ -22,17 +20,13 @@
|
|||||||
"sql-odbc": "boolean",
|
"sql-odbc": "boolean",
|
||||||
"sql-psql": "boolean",
|
"sql-psql": "boolean",
|
||||||
"sql-sqlite": "boolean",
|
"sql-sqlite": "boolean",
|
||||||
"sql-sqlite2": "boolean",
|
|
||||||
"sql-tds": "boolean",
|
|
||||||
"plugin-sql-db2": { "type": "void", "name": "sql-db2" },
|
"plugin-sql-db2": { "type": "void", "name": "sql-db2" },
|
||||||
"plugin-sql-ibase": { "type": "void", "name": "sql-ibase" },
|
"plugin-sql-ibase": { "type": "void", "name": "sql-ibase" },
|
||||||
"plugin-sql-mysql": { "type": "void", "name": "sql-mysql" },
|
"plugin-sql-mysql": { "type": "void", "name": "sql-mysql" },
|
||||||
"plugin-sql-oci": { "type": "void", "name": "sql-oci" },
|
"plugin-sql-oci": { "type": "void", "name": "sql-oci" },
|
||||||
"plugin-sql-odbc": { "type": "void", "name": "sql-odbc" },
|
"plugin-sql-odbc": { "type": "void", "name": "sql-odbc" },
|
||||||
"plugin-sql-psql": { "type": "void", "name": "sql-psql" },
|
"plugin-sql-psql": { "type": "void", "name": "sql-psql" },
|
||||||
"plugin-sql-sqlite": { "type": "void", "name": "sql-sqlite" },
|
"plugin-sql-sqlite": { "type": "void", "name": "sql-sqlite" }
|
||||||
"plugin-sql-sqlite2": { "type": "void", "name": "sql-sqlite2" },
|
|
||||||
"plugin-sql-tds": { "type": "void", "name": "sql-tds" }
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -94,15 +88,6 @@
|
|||||||
{ "type": "psqlEnv", "libs": "-lpq", "condition": "!config.win32" }
|
{ "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": {
|
"oci": {
|
||||||
"label": "OCI (Oracle)",
|
"label": "OCI (Oracle)",
|
||||||
"test": {},
|
"test": {},
|
||||||
@ -132,14 +117,6 @@
|
|||||||
{ "libs": "-lodbc", "condition": "!config.win32 && !config.darwin" }
|
{ "libs": "-lodbc", "condition": "!config.win32 && !config.darwin" }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"sqlite2": {
|
|
||||||
"label": "SQLite (version 2)",
|
|
||||||
"test": {},
|
|
||||||
"headers": "sqlite.h",
|
|
||||||
"sources": [
|
|
||||||
"-lsqlite"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"sqlite3": {
|
"sqlite3": {
|
||||||
"label": "SQLite (version 3)",
|
"label": "SQLite (version 3)",
|
||||||
"export": "sqlite",
|
"export": "sqlite",
|
||||||
@ -191,11 +168,6 @@
|
|||||||
"condition": "libs.psql",
|
"condition": "libs.psql",
|
||||||
"output": [ "privateFeature" ]
|
"output": [ "privateFeature" ]
|
||||||
},
|
},
|
||||||
"sql-sqlite2": {
|
|
||||||
"label": "SQLite2",
|
|
||||||
"condition": "libs.sqlite2",
|
|
||||||
"output": [ "privateFeature" ]
|
|
||||||
},
|
|
||||||
"sql-sqlite": {
|
"sql-sqlite": {
|
||||||
"label": "SQLite",
|
"label": "SQLite",
|
||||||
"condition": "features.datestring",
|
"condition": "features.datestring",
|
||||||
@ -206,11 +178,6 @@
|
|||||||
"autoDetect": false,
|
"autoDetect": false,
|
||||||
"condition": "features.sql-sqlite && libs.sqlite3",
|
"condition": "features.sql-sqlite && libs.sqlite3",
|
||||||
"output": [ "privateFeature" ]
|
"output": [ "privateFeature" ]
|
||||||
},
|
|
||||||
"sql-tds": {
|
|
||||||
"label": "TDS (Sybase)",
|
|
||||||
"condition": "features.datestring && libs.tds",
|
|
||||||
"output": [ "privateFeature" ]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -227,7 +194,7 @@
|
|||||||
"section": "Qt Sql Drivers",
|
"section": "Qt Sql Drivers",
|
||||||
"entries": [
|
"entries": [
|
||||||
"sql-db2", "sql-ibase", "sql-mysql", "sql-oci", "sql-odbc", "sql-psql",
|
"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-psql) : SUBDIRS += psql
|
||||||
qtConfig(sql-mysql) : SUBDIRS += mysql
|
qtConfig(sql-mysql) : SUBDIRS += mysql
|
||||||
qtConfig(sql-odbc) : SUBDIRS += odbc
|
qtConfig(sql-odbc) : SUBDIRS += odbc
|
||||||
qtConfig(sql-tds) : SUBDIRS += tds
|
|
||||||
qtConfig(sql-oci) : SUBDIRS += oci
|
qtConfig(sql-oci) : SUBDIRS += oci
|
||||||
qtConfig(sql-db2) : SUBDIRS += db2
|
qtConfig(sql-db2) : SUBDIRS += db2
|
||||||
qtConfig(sql-sqlite) : SUBDIRS += sqlite
|
qtConfig(sql-sqlite) : SUBDIRS += sqlite
|
||||||
qtConfig(sql-sqlite2) : SUBDIRS += sqlite2
|
|
||||||
qtConfig(sql-ibase) : SUBDIRS += ibase
|
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:
|
Database options:
|
||||||
|
|
||||||
-sql-<driver> ........ Enable SQL <driver> plugin. Supported drivers:
|
-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]
|
[all auto]
|
||||||
-sqlite .............. Select used sqlite3 [system/qt]
|
-sqlite .............. Select used sqlite3 [system/qt]
|
||||||
|
|
||||||
@ -146,21 +146,6 @@ nmake install
|
|||||||
//! [15]
|
//! [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]
|
//! [18]
|
||||||
cd $QTDIR/qtbase/src/plugins/sqldrivers
|
cd $QTDIR/qtbase/src/plugins/sqldrivers
|
||||||
qmake -- DB2_PREFIX=$DB2DIR
|
qmake -- DB2_PREFIX=$DB2DIR
|
||||||
@ -271,8 +256,6 @@ Checking for MySQL... yes
|
|||||||
Checking for OCI (Oracle)... no
|
Checking for OCI (Oracle)... no
|
||||||
Checking for ODBC... yes
|
Checking for ODBC... yes
|
||||||
Checking for PostgreSQL... no
|
Checking for PostgreSQL... no
|
||||||
Checking for SQLite (version 2)... no
|
|
||||||
Checking for TDS (Sybase)... no
|
|
||||||
Done running configuration tests.
|
Done running configuration tests.
|
||||||
|
|
||||||
Configure summary:
|
Configure summary:
|
||||||
@ -284,10 +267,8 @@ Qt Sql Drivers:
|
|||||||
OCI (Oracle) ........................... no
|
OCI (Oracle) ........................... no
|
||||||
ODBC ................................... yes
|
ODBC ................................... yes
|
||||||
PostgreSQL ............................. no
|
PostgreSQL ............................. no
|
||||||
SQLite2 ................................ no
|
|
||||||
SQLite ................................. yes
|
SQLite ................................. yes
|
||||||
Using system provided SQLite ......... no
|
Using system provided SQLite ......... no
|
||||||
TDS (Sybase) ........................... no
|
|
||||||
|
|
||||||
Qt is now configured for building. Just run 'mingw32-make'.
|
Qt is now configured for building. Just run 'mingw32-make'.
|
||||||
Once everything is built, you must run 'mingw32-make install'.
|
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 The value is a BLOB of data, stored exactly as it was input.
|
||||||
\li Mapped to QByteArray
|
\li Mapped to QByteArray
|
||||||
\endtable
|
\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
|
\li Open Database Connectivity (ODBC) - Microsoft SQL Server and other
|
||||||
ODBC-compliant databases
|
ODBC-compliant databases
|
||||||
\row \li \l{#QPSQL}{QPSQL} \li PostgreSQL (versions 7.3 and above)
|
\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{#QSQLITE}{QSQLITE} \li SQLite version 3
|
||||||
\row \li \l{#QTDS}{QTDS} \li Sybase Adaptive Server \note obsolete since Qt 4.7
|
|
||||||
\endtable
|
\endtable
|
||||||
|
|
||||||
SQLite is the in-process database system with the best test coverage
|
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
|
in your installation package. It must be placed in the same folder
|
||||||
as the application executable.
|
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
|
\target QDB2
|
||||||
\section2 QDB2 for IBM DB2 (Version 7.1 and Above)
|
\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
|
If you are not using a Microsoft compiler, replace \c nmake
|
||||||
with \c mingw32-make in the line above.
|
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
|
\target QSQLITE
|
||||||
\section2 QSQLITE for SQLite (Version 3 and Above)
|
\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 QODBC \li ODBC Driver (includes Microsoft SQL Server)
|
||||||
\row \li QPSQL \li PostgreSQL Driver
|
\row \li QPSQL \li PostgreSQL Driver
|
||||||
\row \li QSQLITE \li SQLite version 3 or above
|
\row \li QSQLITE \li SQLite version 3 or above
|
||||||
\row \li QSQLITE2 \li SQLite version 2
|
|
||||||
\row \li QTDS \li Sybase Adaptive Server
|
|
||||||
\endtable
|
\endtable
|
||||||
|
|
||||||
Additional third party drivers, including your own custom
|
Additional third party drivers, including your own custom
|
||||||
@ -1185,7 +1183,7 @@ QSqlRecord QSqlDatabase::record(const QString& tablename) const
|
|||||||
\li service
|
\li service
|
||||||
\endlist
|
\endlist
|
||||||
|
|
||||||
\header \li DB2 \li OCI \li TDS
|
\header \li DB2 \li OCI
|
||||||
\row
|
\row
|
||||||
|
|
||||||
\li
|
\li
|
||||||
@ -1200,9 +1198,6 @@ QSqlRecord QSqlDatabase::record(const QString& tablename) const
|
|||||||
\li OCI_ATTR_PREFETCH_MEMORY
|
\li OCI_ATTR_PREFETCH_MEMORY
|
||||||
\endlist
|
\endlist
|
||||||
|
|
||||||
\li
|
|
||||||
\e none
|
|
||||||
|
|
||||||
\header \li SQLite \li Interbase
|
\header \li SQLite \li Interbase
|
||||||
\row
|
\row
|
||||||
|
|
||||||
@ -1327,11 +1322,6 @@ bool QSqlDatabase::isDriverAvailable(const QString& name)
|
|||||||
\li SQLHANDLE environment, SQLHANDLE connection
|
\li SQLHANDLE environment, SQLHANDLE connection
|
||||||
\li \c qsql_db2.cpp
|
\li \c qsql_db2.cpp
|
||||||
\row
|
\row
|
||||||
\li QTDS
|
|
||||||
\li QTDSDriver
|
|
||||||
\li LOGINREC *loginRecord, DBPROCESS *dbProcess, const QString &hostName
|
|
||||||
\li \c qsql_tds.cpp
|
|
||||||
\row
|
|
||||||
\li QSQLITE
|
\li QSQLITE
|
||||||
\li QSQLiteDriver
|
\li QSQLiteDriver
|
||||||
\li sqlite *connection
|
\li sqlite *connection
|
||||||
@ -1343,11 +1333,6 @@ bool QSqlDatabase::isDriverAvailable(const QString& name)
|
|||||||
\li \c qsql_ibase.cpp
|
\li \c qsql_ibase.cpp
|
||||||
\endtable
|
\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
|
\warning Adding a database connection with the same connection
|
||||||
name as an existing connection, causes the existing connection to
|
name as an existing connection, causes the existing connection to
|
||||||
be replaced by the new one.
|
be replaced by the new one.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user