summaryrefslogtreecommitdiffstats
path: root/src/sql/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'src/sql/drivers')
-rw-r--r--src/sql/drivers/db2/qsql_db2.cpp1700
-rw-r--r--src/sql/drivers/db2/qsql_db2.pri8
-rw-r--r--src/sql/drivers/db2/qsql_db2_p.h103
-rw-r--r--src/sql/drivers/drivers.pri11
-rw-r--r--src/sql/drivers/ibase/qsql_ibase.cpp1948
-rw-r--r--src/sql/drivers/ibase/qsql_ibase.pri10
-rw-r--r--src/sql/drivers/ibase/qsql_ibase_p.h114
-rw-r--r--src/sql/drivers/mysql/qsql_mysql.cpp1665
-rw-r--r--src/sql/drivers/mysql/qsql_mysql.pri16
-rw-r--r--src/sql/drivers/mysql/qsql_mysql_p.h110
-rw-r--r--src/sql/drivers/oci/qsql_oci.cpp2725
-rw-r--r--src/sql/drivers/oci/qsql_oci.pri9
-rw-r--r--src/sql/drivers/oci/qsql_oci_p.h106
-rw-r--r--src/sql/drivers/odbc/qsql_odbc.cpp2639
-rw-r--r--src/sql/drivers/odbc/qsql_odbc.pri12
-rw-r--r--src/sql/drivers/odbc/qsql_odbc_p.h127
-rw-r--r--src/sql/drivers/psql/qsql_psql.cpp1508
-rw-r--r--src/sql/drivers/psql/qsql_psql.pri10
-rw-r--r--src/sql/drivers/psql/qsql_psql_p.h128
-rw-r--r--src/sql/drivers/sqlite/qsql_sqlite.cpp828
-rw-r--r--src/sql/drivers/sqlite/qsql_sqlite.pri9
-rw-r--r--src/sql/drivers/sqlite/qsql_sqlite_p.h100
-rw-r--r--src/sql/drivers/sqlite2/qsql_sqlite2.cpp615
-rw-r--r--src/sql/drivers/sqlite2/qsql_sqlite2.pri4
-rw-r--r--src/sql/drivers/sqlite2/qsql_sqlite2_p.h109
-rw-r--r--src/sql/drivers/tds/qsql_tds.cpp881
-rw-r--r--src/sql/drivers/tds/qsql_tds.pri10
-rw-r--r--src/sql/drivers/tds/qsql_tds_p.h120
28 files changed, 0 insertions, 15625 deletions
diff --git a/src/sql/drivers/db2/qsql_db2.cpp b/src/sql/drivers/db2/qsql_db2.cpp
deleted file mode 100644
index 4ccc3aca9e..0000000000
--- a/src/sql/drivers/db2/qsql_db2.cpp
+++ /dev/null
@@ -1,1700 +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_db2_p.h"
-#include <qcoreapplication.h>
-#include <qdatetime.h>
-#include <qsqlfield.h>
-#include <qsqlerror.h>
-#include <qsqlindex.h>
-#include <qsqlrecord.h>
-#include <qstringlist.h>
-#include <qvarlengtharray.h>
-#include <qvector.h>
-#include <QDebug>
-#include <QtSql/private/qsqldriver_p.h>
-#include <QtSql/private/qsqlresult_p.h>
-
-#if defined(Q_CC_BOR)
-// DB2's sqlsystm.h (included through sqlcli1.h) defines the SQL_BIGINT_TYPE
-// and SQL_BIGUINT_TYPE to wrong the types for Borland; so do the defines to
-// the right type before including the header
-#define SQL_BIGINT_TYPE qint64
-#define SQL_BIGUINT_TYPE quint64
-#endif
-
-#define UNICODE
-
-#include <sqlcli1.h>
-
-#include <string.h>
-
-QT_BEGIN_NAMESPACE
-
-static const int COLNAMESIZE = 255;
-static const SQLSMALLINT qParamType[4] = { SQL_PARAM_INPUT, SQL_PARAM_INPUT, SQL_PARAM_OUTPUT, SQL_PARAM_INPUT_OUTPUT };
-
-class QDB2DriverPrivate : public QSqlDriverPrivate
-{
- Q_DECLARE_PUBLIC(QDB2Driver)
-
-public:
- QDB2DriverPrivate() : QSqlDriverPrivate(), hEnv(0), hDbc(0) { dbmsType = QSqlDriver::DB2; }
- SQLHANDLE hEnv;
- SQLHANDLE hDbc;
- QString user;
-};
-
-class QDB2ResultPrivate;
-
-class QDB2Result: public QSqlResult
-{
- Q_DECLARE_PRIVATE(QDB2Result)
-
-public:
- QDB2Result(const QDB2Driver *drv);
- ~QDB2Result();
- bool prepare(const QString &query) Q_DECL_OVERRIDE;
- bool exec() Q_DECL_OVERRIDE;
- QVariant handle() const Q_DECL_OVERRIDE;
-
-protected:
- QVariant data(int field) Q_DECL_OVERRIDE;
- bool reset(const QString &query) Q_DECL_OVERRIDE;
- bool fetch(int i) Q_DECL_OVERRIDE;
- bool fetchNext() Q_DECL_OVERRIDE;
- bool fetchFirst() Q_DECL_OVERRIDE;
- bool fetchLast() Q_DECL_OVERRIDE;
- bool isNull(int i) Q_DECL_OVERRIDE;
- int size() Q_DECL_OVERRIDE;
- int numRowsAffected() Q_DECL_OVERRIDE;
- QSqlRecord record() const Q_DECL_OVERRIDE;
- void virtual_hook(int id, void *data) Q_DECL_OVERRIDE;
- void detachFromResultSet() Q_DECL_OVERRIDE;
- bool nextResult() Q_DECL_OVERRIDE;
-};
-
-class QDB2ResultPrivate: public QSqlResultPrivate
-{
- Q_DECLARE_PUBLIC(QDB2Result)
-
-public:
- Q_DECLARE_SQLDRIVER_PRIVATE(QDB2Driver)
- QDB2ResultPrivate(QDB2Result *q, const QDB2Driver *drv)
- : QSqlResultPrivate(q, drv),
- hStmt(0)
- {}
- ~QDB2ResultPrivate()
- {
- emptyValueCache();
- }
- void clearValueCache()
- {
- for (int i = 0; i < valueCache.count(); ++i) {
- delete valueCache[i];
- valueCache[i] = NULL;
- }
- }
- void emptyValueCache()
- {
- clearValueCache();
- valueCache.clear();
- }
-
- SQLHANDLE hStmt;
- QSqlRecord recInf;
- QVector<QVariant*> valueCache;
-};
-
-static QString qFromTChar(SQLTCHAR* str)
-{
- return QString((const QChar *)str);
-}
-
-// dangerous!! (but fast). Don't use in functions that
-// require out parameters!
-static SQLTCHAR* qToTChar(const QString& str)
-{
- return (SQLTCHAR*)str.utf16();
-}
-
-static QString qWarnDB2Handle(int handleType, SQLHANDLE handle)
-{
- SQLINTEGER nativeCode;
- SQLSMALLINT msgLen;
- SQLRETURN r = SQL_ERROR;
- SQLTCHAR state[SQL_SQLSTATE_SIZE + 1];
- SQLTCHAR description[SQL_MAX_MESSAGE_LENGTH];
- r = SQLGetDiagRec(handleType,
- handle,
- 1,
- (SQLTCHAR*) state,
- &nativeCode,
- (SQLTCHAR*) description,
- SQL_MAX_MESSAGE_LENGTH - 1, /* in bytes, not in characters */
- &msgLen);
- if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO)
- return QString(qFromTChar(description));
- return QString();
-}
-
-static QString qDB2Warn(const QDB2DriverPrivate* d)
-{
- return (qWarnDB2Handle(SQL_HANDLE_ENV, d->hEnv) + QLatin1Char(' ')
- + qWarnDB2Handle(SQL_HANDLE_DBC, d->hDbc));
-}
-
-static QString qDB2Warn(const QDB2ResultPrivate* d)
-{
- return (qWarnDB2Handle(SQL_HANDLE_ENV, d->drv_d_func()->hEnv) + QLatin1Char(' ')
- + qWarnDB2Handle(SQL_HANDLE_DBC, d->drv_d_func()->hDbc)
- + qWarnDB2Handle(SQL_HANDLE_STMT, d->hStmt));
-}
-
-static void qSqlWarning(const QString& message, const QDB2DriverPrivate* d)
-{
- qWarning("%s\tError: %s", message.toLocal8Bit().constData(),
- qDB2Warn(d).toLocal8Bit().constData());
-}
-
-static void qSqlWarning(const QString& message, const QDB2ResultPrivate* d)
-{
- qWarning("%s\tError: %s", message.toLocal8Bit().constData(),
- qDB2Warn(d).toLocal8Bit().constData());
-}
-
-static QSqlError qMakeError(const QString& err, QSqlError::ErrorType type,
- const QDB2DriverPrivate* p)
-{
- return QSqlError(QLatin1String("QDB2: ") + err, qDB2Warn(p), type);
-}
-
-static QSqlError qMakeError(const QString& err, QSqlError::ErrorType type,
- const QDB2ResultPrivate* p)
-{
- return QSqlError(QLatin1String("QDB2: ") + err, qDB2Warn(p), type);
-}
-
-static QVariant::Type qDecodeDB2Type(SQLSMALLINT sqltype)
-{
- QVariant::Type type = QVariant::Invalid;
- switch (sqltype) {
- case SQL_REAL:
- case SQL_FLOAT:
- case SQL_DOUBLE:
- case SQL_DECIMAL:
- case SQL_NUMERIC:
- type = QVariant::Double;
- break;
- case SQL_SMALLINT:
- case SQL_INTEGER:
- case SQL_BIT:
- case SQL_TINYINT:
- type = QVariant::Int;
- break;
- case SQL_BIGINT:
- type = QVariant::LongLong;
- break;
- case SQL_BLOB:
- case SQL_BINARY:
- case SQL_VARBINARY:
- case SQL_LONGVARBINARY:
- case SQL_CLOB:
- case SQL_DBCLOB:
- type = QVariant::ByteArray;
- break;
- case SQL_DATE:
- case SQL_TYPE_DATE:
- type = QVariant::Date;
- break;
- case SQL_TIME:
- case SQL_TYPE_TIME:
- type = QVariant::Time;
- break;
- case SQL_TIMESTAMP:
- case SQL_TYPE_TIMESTAMP:
- type = QVariant::DateTime;
- break;
- case SQL_WCHAR:
- case SQL_WVARCHAR:
- case SQL_WLONGVARCHAR:
- case SQL_CHAR:
- case SQL_VARCHAR:
- case SQL_LONGVARCHAR:
- type = QVariant::String;
- break;
- default:
- type = QVariant::ByteArray;
- break;
- }
- return type;
-}
-
-static QSqlField qMakeFieldInfo(const QDB2ResultPrivate* d, int i)
-{
- SQLSMALLINT colNameLen;
- SQLSMALLINT colType;
- SQLUINTEGER colSize;
- SQLSMALLINT colScale;
- SQLSMALLINT nullable;
- SQLRETURN r = SQL_ERROR;
- SQLTCHAR colName[COLNAMESIZE];
- r = SQLDescribeCol(d->hStmt,
- i+1,
- colName,
- (SQLSMALLINT) COLNAMESIZE,
- &colNameLen,
- &colType,
- &colSize,
- &colScale,
- &nullable);
-
- if (r != SQL_SUCCESS) {
- qSqlWarning(QString::fromLatin1("qMakeFieldInfo: Unable to describe column %1").arg(i), d);
- return QSqlField();
- }
- QSqlField f(qFromTChar(colName), qDecodeDB2Type(colType));
- // nullable can be SQL_NO_NULLS, SQL_NULLABLE or SQL_NULLABLE_UNKNOWN
- if (nullable == SQL_NO_NULLS)
- f.setRequired(true);
- else if (nullable == SQL_NULLABLE)
- f.setRequired(false);
- // else required is unknown
- f.setLength(colSize == 0 ? -1 : int(colSize));
- f.setPrecision(colScale == 0 ? -1 : int(colScale));
- f.setSqlType(int(colType));
- return f;
-}
-
-static int qGetIntData(SQLHANDLE hStmt, int column, bool& isNull)
-{
- SQLINTEGER intbuf;
- isNull = false;
- SQLINTEGER lengthIndicator = 0;
- SQLRETURN r = SQLGetData(hStmt,
- column + 1,
- SQL_C_SLONG,
- (SQLPOINTER) &intbuf,
- 0,
- &lengthIndicator);
- if ((r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) || lengthIndicator == SQL_NULL_DATA) {
- isNull = true;
- return 0;
- }
- return int(intbuf);
-}
-
-static double qGetDoubleData(SQLHANDLE hStmt, int column, bool& isNull)
-{
- SQLDOUBLE dblbuf;
- isNull = false;
- SQLINTEGER lengthIndicator = 0;
- SQLRETURN r = SQLGetData(hStmt,
- column+1,
- SQL_C_DOUBLE,
- (SQLPOINTER) &dblbuf,
- 0,
- &lengthIndicator);
- if ((r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) || lengthIndicator == SQL_NULL_DATA) {
- isNull = true;
- return 0.0;
- }
-
- return (double) dblbuf;
-}
-
-static SQLBIGINT qGetBigIntData(SQLHANDLE hStmt, int column, bool& isNull)
-{
- SQLBIGINT lngbuf = Q_INT64_C(0);
- isNull = false;
- SQLINTEGER lengthIndicator = 0;
- SQLRETURN r = SQLGetData(hStmt,
- column+1,
- SQL_C_SBIGINT,
- (SQLPOINTER) &lngbuf,
- 0,
- &lengthIndicator);
- if ((r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) || lengthIndicator == SQL_NULL_DATA)
- isNull = true;
-
- return lngbuf;
-}
-
-static QString qGetStringData(SQLHANDLE hStmt, int column, int colSize, bool& isNull)
-{
- QString fieldVal;
- SQLRETURN r = SQL_ERROR;
- SQLINTEGER lengthIndicator = 0;
-
- if (colSize <= 0)
- colSize = 255;
- else if (colSize > 65536) // limit buffer size to 64 KB
- colSize = 65536;
- else
- colSize++; // make sure there is room for more than the 0 termination
- SQLTCHAR* buf = new SQLTCHAR[colSize];
-
- while (true) {
- r = SQLGetData(hStmt,
- column + 1,
- SQL_C_WCHAR,
- (SQLPOINTER)buf,
- colSize * sizeof(SQLTCHAR),
- &lengthIndicator);
- if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) {
- if (lengthIndicator == SQL_NULL_DATA || lengthIndicator == SQL_NO_TOTAL) {
- fieldVal.clear();
- isNull = true;
- break;
- }
- fieldVal += qFromTChar(buf);
- } else if (r == SQL_NO_DATA) {
- break;
- } else {
- qWarning("qGetStringData: Error while fetching data (%d)", r);
- fieldVal.clear();
- break;
- }
- }
- delete[] buf;
- return fieldVal;
-}
-
-static QByteArray qGetBinaryData(SQLHANDLE hStmt, int column, SQLINTEGER& lengthIndicator, bool& isNull)
-{
- QByteArray fieldVal;
- SQLSMALLINT colNameLen;
- SQLSMALLINT colType;
- SQLUINTEGER colSize;
- SQLSMALLINT colScale;
- SQLSMALLINT nullable;
- SQLRETURN r = SQL_ERROR;
-
- SQLTCHAR colName[COLNAMESIZE];
- r = SQLDescribeCol(hStmt,
- column+1,
- colName,
- COLNAMESIZE,
- &colNameLen,
- &colType,
- &colSize,
- &colScale,
- &nullable);
- if (r != SQL_SUCCESS)
- qWarning("qGetBinaryData: Unable to describe column %d", column);
- // SQLDescribeCol may return 0 if size cannot be determined
- if (!colSize)
- colSize = 255;
- else if (colSize > 65536) // read the field in 64 KB chunks
- colSize = 65536;
- char * buf = new char[colSize];
- while (true) {
- r = SQLGetData(hStmt,
- column+1,
- colType == SQL_DBCLOB ? SQL_C_CHAR : SQL_C_BINARY,
- (SQLPOINTER) buf,
- colSize,
- &lengthIndicator);
- if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) {
- if (lengthIndicator == SQL_NULL_DATA) {
- isNull = true;
- break;
- } else {
- int rSize;
- r == SQL_SUCCESS ? rSize = lengthIndicator : rSize = colSize;
- if (lengthIndicator == SQL_NO_TOTAL) // size cannot be determined
- rSize = colSize;
- fieldVal.append(QByteArray(buf, rSize));
- if (r == SQL_SUCCESS) // the whole field was read in one chunk
- break;
- }
- } else {
- break;
- }
- }
- delete [] buf;
- return fieldVal;
-}
-
-static void qSplitTableQualifier(const QString & qualifier, QString * catalog,
- QString * schema, QString * table)
-{
- if (!catalog || !schema || !table)
- return;
- QStringList l = qualifier.split(QLatin1Char('.'));
- if (l.count() > 3)
- return; // can't possibly be a valid table qualifier
- int i = 0, n = l.count();
- if (n == 1) {
- *table = qualifier;
- } else {
- for (QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
- if (n == 3) {
- if (i == 0)
- *catalog = *it;
- else if (i == 1)
- *schema = *it;
- else if (i == 2)
- *table = *it;
- } else if (n == 2) {
- if (i == 0)
- *schema = *it;
- else if (i == 1)
- *table = *it;
- }
- i++;
- }
- }
-}
-
-// creates a QSqlField from a valid hStmt generated
-// by SQLColumns. The hStmt has to point to a valid position.
-static QSqlField qMakeFieldInfo(const SQLHANDLE hStmt)
-{
- bool isNull;
- int type = qGetIntData(hStmt, 4, isNull);
- QSqlField f(qGetStringData(hStmt, 3, -1, isNull), qDecodeDB2Type(type));
- int required = qGetIntData(hStmt, 10, isNull); // nullable-flag
- // required can be SQL_NO_NULLS, SQL_NULLABLE or SQL_NULLABLE_UNKNOWN
- if (required == SQL_NO_NULLS)
- f.setRequired(true);
- else if (required == SQL_NULLABLE)
- f.setRequired(false);
- // else we don't know.
- f.setLength(qGetIntData(hStmt, 6, isNull)); // column size
- f.setPrecision(qGetIntData(hStmt, 8, isNull)); // precision
- f.setSqlType(type);
- return f;
-}
-
-static bool qMakeStatement(QDB2ResultPrivate* d, bool forwardOnly, bool setForwardOnly = true)
-{
- SQLRETURN r;
- if (!d->hStmt) {
- r = SQLAllocHandle(SQL_HANDLE_STMT,
- d->drv_d_func()->hDbc,
- &d->hStmt);
- if (r != SQL_SUCCESS) {
- qSqlWarning(QLatin1String("QDB2Result::reset: Unable to allocate statement handle"), d);
- return false;
- }
- } else {
- r = SQLFreeStmt(d->hStmt, SQL_CLOSE);
- if (r != SQL_SUCCESS) {
- qSqlWarning(QLatin1String("QDB2Result::reset: Unable to close statement handle"), d);
- return false;
- }
- }
-
- if (!setForwardOnly)
- return true;
-
- if (forwardOnly) {
- r = SQLSetStmtAttr(d->hStmt,
- SQL_ATTR_CURSOR_TYPE,
- (SQLPOINTER) SQL_CURSOR_FORWARD_ONLY,
- SQL_IS_UINTEGER);
- } else {
- r = SQLSetStmtAttr(d->hStmt,
- SQL_ATTR_CURSOR_TYPE,
- (SQLPOINTER) SQL_CURSOR_STATIC,
- SQL_IS_UINTEGER);
- }
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
- qSqlWarning(QString::fromLatin1("QDB2Result::reset: Unable to set %1 attribute.").arg(
- forwardOnly ? QLatin1String("SQL_CURSOR_FORWARD_ONLY")
- : QLatin1String("SQL_CURSOR_STATIC")), d);
- return false;
- }
- return true;
-}
-
-QVariant QDB2Result::handle() const
-{
- Q_D(const QDB2Result);
- return QVariant(qRegisterMetaType<SQLHANDLE>("SQLHANDLE"), &d->hStmt);
-}
-
-/************************************/
-
-QDB2Result::QDB2Result(const QDB2Driver *drv)
- : QSqlResult(*new QDB2ResultPrivate(this, drv))
-{
-}
-
-QDB2Result::~QDB2Result()
-{
- Q_D(const QDB2Result);
- if (d->hStmt) {
- SQLRETURN r = SQLFreeHandle(SQL_HANDLE_STMT, d->hStmt);
- if (r != SQL_SUCCESS)
- qSqlWarning(QLatin1String("QDB2Driver: Unable to free statement handle ")
- + QString::number(r), d);
- }
-}
-
-bool QDB2Result::reset (const QString& query)
-{
- Q_D(QDB2Result);
- setActive(false);
- setAt(QSql::BeforeFirstRow);
- SQLRETURN r;
-
- d->recInf.clear();
- d->emptyValueCache();
-
- if (!qMakeStatement(d, isForwardOnly()))
- return false;
-
- r = SQLExecDirect(d->hStmt,
- qToTChar(query),
- (SQLINTEGER) query.length());
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
- setLastError(qMakeError(QCoreApplication::translate("QDB2Result",
- "Unable to execute statement"), QSqlError::StatementError, d));
- return false;
- }
- SQLSMALLINT count = 0;
- r = SQLNumResultCols(d->hStmt, &count);
- if (count) {
- setSelect(true);
- for (int i = 0; i < count; ++i) {
- d->recInf.append(qMakeFieldInfo(d, i));
- }
- } else {
- setSelect(false);
- }
- d->valueCache.resize(count);
- d->valueCache.fill(NULL);
- setActive(true);
- return true;
-}
-
-bool QDB2Result::prepare(const QString& query)
-{
- Q_D(QDB2Result);
- setActive(false);
- setAt(QSql::BeforeFirstRow);
- SQLRETURN r;
-
- d->recInf.clear();
- d->emptyValueCache();
-
- if (!qMakeStatement(d, isForwardOnly()))
- return false;
-
- r = SQLPrepare(d->hStmt,
- qToTChar(query),
- (SQLINTEGER) query.length());
-
- if (r != SQL_SUCCESS) {
- setLastError(qMakeError(QCoreApplication::translate("QDB2Result",
- "Unable to prepare statement"), QSqlError::StatementError, d));
- return false;
- }
- return true;
-}
-
-bool QDB2Result::exec()
-{
- Q_D(QDB2Result);
- QList<QByteArray> tmpStorage; // holds temporary ptrs
- QVarLengthArray<SQLINTEGER, 32> indicators(boundValues().count());
-
- memset(indicators.data(), 0, indicators.size() * sizeof(SQLINTEGER));
- setActive(false);
- setAt(QSql::BeforeFirstRow);
- SQLRETURN r;
-
- d->recInf.clear();
- d->emptyValueCache();
-
- if (!qMakeStatement(d, isForwardOnly(), false))
- return false;
-
-
- QVector<QVariant> &values = boundValues();
- int i;
- for (i = 0; i < values.count(); ++i) {
- // bind parameters - only positional binding allowed
- SQLINTEGER *ind = &indicators[i];
- if (values.at(i).isNull())
- *ind = SQL_NULL_DATA;
- if (bindValueType(i) & QSql::Out)
- values[i].detach();
-
- switch (values.at(i).type()) {
- case QVariant::Date: {
- QByteArray ba;
- ba.resize(sizeof(DATE_STRUCT));
- DATE_STRUCT *dt = (DATE_STRUCT *)ba.constData();
- QDate qdt = values.at(i).toDate();
- dt->year = qdt.year();
- dt->month = qdt.month();
- dt->day = qdt.day();
- r = SQLBindParameter(d->hStmt,
- i + 1,
- qParamType[bindValueType(i) & 3],
- SQL_C_DATE,
- SQL_DATE,
- 0,
- 0,
- (void *) dt,
- 0,
- *ind == SQL_NULL_DATA ? ind : NULL);
- tmpStorage.append(ba);
- break; }
- case QVariant::Time: {
- QByteArray ba;
- ba.resize(sizeof(TIME_STRUCT));
- TIME_STRUCT *dt = (TIME_STRUCT *)ba.constData();
- QTime qdt = values.at(i).toTime();
- dt->hour = qdt.hour();
- dt->minute = qdt.minute();
- dt->second = qdt.second();
- r = SQLBindParameter(d->hStmt,
- i + 1,
- qParamType[bindValueType(i) & 3],
- SQL_C_TIME,
- SQL_TIME,
- 0,
- 0,
- (void *) dt,
- 0,
- *ind == SQL_NULL_DATA ? ind : NULL);
- tmpStorage.append(ba);
- break; }
- case QVariant::DateTime: {
- QByteArray ba;
- ba.resize(sizeof(TIMESTAMP_STRUCT));
- TIMESTAMP_STRUCT * dt = (TIMESTAMP_STRUCT *)ba.constData();
- QDateTime qdt = values.at(i).toDateTime();
- dt->year = qdt.date().year();
- dt->month = qdt.date().month();
- dt->day = qdt.date().day();
- dt->hour = qdt.time().hour();
- dt->minute = qdt.time().minute();
- dt->second = qdt.time().second();
- dt->fraction = qdt.time().msec() * 1000000;
- r = SQLBindParameter(d->hStmt,
- i + 1,
- qParamType[bindValueType(i) & 3],
- SQL_C_TIMESTAMP,
- SQL_TIMESTAMP,
- 0,
- 0,
- (void *) dt,
- 0,
- *ind == SQL_NULL_DATA ? ind : NULL);
- tmpStorage.append(ba);
- break; }
- case QVariant::Int:
- r = SQLBindParameter(d->hStmt,
- i + 1,
- qParamType[bindValueType(i) & 3],
- SQL_C_SLONG,
- SQL_INTEGER,
- 0,
- 0,
- (void *)values.at(i).constData(),
- 0,
- *ind == SQL_NULL_DATA ? ind : NULL);
- break;
- case QVariant::Double:
- r = SQLBindParameter(d->hStmt,
- i + 1,
- qParamType[bindValueType(i) & 3],
- SQL_C_DOUBLE,
- SQL_DOUBLE,
- 0,
- 0,
- (void *)values.at(i).constData(),
- 0,
- *ind == SQL_NULL_DATA ? ind : NULL);
- break;
- case QVariant::ByteArray: {
- int len = values.at(i).toByteArray().size();
- if (*ind != SQL_NULL_DATA)
- *ind = len;
- r = SQLBindParameter(d->hStmt,
- i + 1,
- qParamType[bindValueType(i) & 3],
- SQL_C_BINARY,
- SQL_LONGVARBINARY,
- len,
- 0,
- (void *)values.at(i).toByteArray().constData(),
- len,
- ind);
- break; }
- case QVariant::String:
- {
- QString str(values.at(i).toString());
- if (*ind != SQL_NULL_DATA)
- *ind = str.length() * sizeof(QChar);
- if (bindValueType(i) & QSql::Out) {
- QByteArray ba((char*)str.utf16(), str.capacity() * sizeof(QChar));
- r = SQLBindParameter(d->hStmt,
- i + 1,
- qParamType[bindValueType(i) & 3],
- SQL_C_WCHAR,
- SQL_WVARCHAR,
- str.length(),
- 0,
- (void *)ba.constData(),
- ba.size(),
- ind);
- tmpStorage.append(ba);
- } else {
- void *data = (void*)str.utf16();
- int len = str.length();
- r = SQLBindParameter(d->hStmt,
- i + 1,
- qParamType[bindValueType(i) & 3],
- SQL_C_WCHAR,
- SQL_WVARCHAR,
- len,
- 0,
- data,
- len * sizeof(QChar),
- ind);
- }
- break;
- }
- default: {
- QByteArray ba = values.at(i).toString().toLatin1();
- int len = ba.length() + 1;
- if (*ind != SQL_NULL_DATA)
- *ind = ba.length();
- r = SQLBindParameter(d->hStmt,
- i + 1,
- qParamType[bindValueType(i) & 3],
- SQL_C_CHAR,
- SQL_VARCHAR,
- len,
- 0,
- (void *) ba.constData(),
- len,
- ind);
- tmpStorage.append(ba);
- break; }
- }
- if (r != SQL_SUCCESS) {
- qWarning("QDB2Result::exec: unable to bind variable: %s",
- qDB2Warn(d).toLocal8Bit().constData());
- setLastError(qMakeError(QCoreApplication::translate("QDB2Result",
- "Unable to bind variable"), QSqlError::StatementError, d));
- return false;
- }
- }
-
- r = SQLExecute(d->hStmt);
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
- qWarning("QDB2Result::exec: Unable to execute statement: %s",
- qDB2Warn(d).toLocal8Bit().constData());
- setLastError(qMakeError(QCoreApplication::translate("QDB2Result",
- "Unable to execute statement"), QSqlError::StatementError, d));
- return false;
- }
- SQLSMALLINT count = 0;
- r = SQLNumResultCols(d->hStmt, &count);
- if (count) {
- setSelect(true);
- for (int i = 0; i < count; ++i) {
- d->recInf.append(qMakeFieldInfo(d, i));
- }
- } else {
- setSelect(false);
- }
- setActive(true);
- d->valueCache.resize(count);
- d->valueCache.fill(NULL);
-
- //get out parameters
- if (!hasOutValues())
- return true;
-
- for (i = 0; i < values.count(); ++i) {
- switch (values[i].type()) {
- case QVariant::Date: {
- DATE_STRUCT ds = *((DATE_STRUCT *)tmpStorage.takeFirst().constData());
- values[i] = QVariant(QDate(ds.year, ds.month, ds.day));
- break; }
- case QVariant::Time: {
- TIME_STRUCT dt = *((TIME_STRUCT *)tmpStorage.takeFirst().constData());
- values[i] = QVariant(QTime(dt.hour, dt.minute, dt.second));
- break; }
- case QVariant::DateTime: {
- TIMESTAMP_STRUCT dt = *((TIMESTAMP_STRUCT *)tmpStorage.takeFirst().constData());
- values[i] = QVariant(QDateTime(QDate(dt.year, dt.month, dt.day),
- QTime(dt.hour, dt.minute, dt.second, dt.fraction / 1000000)));
- break; }
- case QVariant::Int:
- case QVariant::Double:
- case QVariant::ByteArray:
- break;
- case QVariant::String:
- if (bindValueType(i) & QSql::Out)
- values[i] = QString((const QChar *)tmpStorage.takeFirst().constData());
- break;
- default: {
- values[i] = QString::fromLatin1(tmpStorage.takeFirst().constData());
- break; }
- }
- if (indicators[i] == SQL_NULL_DATA)
- values[i] = QVariant(values[i].type());
- }
- return true;
-}
-
-bool QDB2Result::fetch(int i)
-{
- Q_D(QDB2Result);
- if (isForwardOnly() && i < at())
- return false;
- if (i == at())
- return true;
- d->clearValueCache();
- int actualIdx = i + 1;
- if (actualIdx <= 0) {
- setAt(QSql::BeforeFirstRow);
- return false;
- }
- SQLRETURN r;
- if (isForwardOnly()) {
- bool ok = true;
- while (ok && i > at())
- ok = fetchNext();
- return ok;
- } else {
- r = SQLFetchScroll(d->hStmt,
- SQL_FETCH_ABSOLUTE,
- actualIdx);
- }
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO && r != SQL_NO_DATA) {
- setLastError(qMakeError(QCoreApplication::translate("QDB2Result",
- "Unable to fetch record %1").arg(i), QSqlError::StatementError, d));
- return false;
- }
- else if (r == SQL_NO_DATA)
- return false;
- setAt(i);
- return true;
-}
-
-bool QDB2Result::fetchNext()
-{
- Q_D(QDB2Result);
- SQLRETURN r;
- d->clearValueCache();
- r = SQLFetchScroll(d->hStmt,
- SQL_FETCH_NEXT,
- 0);
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
- if (r != SQL_NO_DATA)
- setLastError(qMakeError(QCoreApplication::translate("QDB2Result",
- "Unable to fetch next"), QSqlError::StatementError, d));
- return false;
- }
- setAt(at() + 1);
- return true;
-}
-
-bool QDB2Result::fetchFirst()
-{
- Q_D(QDB2Result);
- if (isForwardOnly() && at() != QSql::BeforeFirstRow)
- return false;
- if (isForwardOnly())
- return fetchNext();
- d->clearValueCache();
- SQLRETURN r;
- r = SQLFetchScroll(d->hStmt,
- SQL_FETCH_FIRST,
- 0);
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
- if(r!= SQL_NO_DATA)
- setLastError(qMakeError(QCoreApplication::translate("QDB2Result", "Unable to fetch first"),
- QSqlError::StatementError, d));
- return false;
- }
- setAt(0);
- return true;
-}
-
-bool QDB2Result::fetchLast()
-{
- Q_D(QDB2Result);
- d->clearValueCache();
-
- int i = at();
- if (i == QSql::AfterLastRow) {
- if (isForwardOnly()) {
- return false;
- } else {
- if (!fetch(0))
- return false;
- i = at();
- }
- }
-
- while (fetchNext())
- ++i;
-
- if (i == QSql::BeforeFirstRow) {
- setAt(QSql::AfterLastRow);
- return false;
- }
-
- if (!isForwardOnly())
- return fetch(i);
-
- setAt(i);
- return true;
-}
-
-
-QVariant QDB2Result::data(int field)
-{
- Q_D(QDB2Result);
- if (field >= d->recInf.count()) {
- qWarning("QDB2Result::data: column %d out of range", field);
- return QVariant();
- }
- SQLRETURN r = 0;
- SQLINTEGER lengthIndicator = 0;
- bool isNull = false;
- const QSqlField info = d->recInf.field(field);
-
- if (!info.isValid() || field >= d->valueCache.size())
- return QVariant();
-
- if (d->valueCache[field])
- return *d->valueCache[field];
-
-
- QVariant* v = 0;
- switch (info.type()) {
- case QVariant::LongLong:
- v = new QVariant((qint64) qGetBigIntData(d->hStmt, field, isNull));
- break;
- case QVariant::Int:
- v = new QVariant(qGetIntData(d->hStmt, field, isNull));
- break;
- case QVariant::Date: {
- DATE_STRUCT dbuf;
- r = SQLGetData(d->hStmt,
- field + 1,
- SQL_C_DATE,
- (SQLPOINTER) &dbuf,
- 0,
- &lengthIndicator);
- if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && (lengthIndicator != SQL_NULL_DATA)) {
- v = new QVariant(QDate(dbuf.year, dbuf.month, dbuf.day));
- } else {
- v = new QVariant(QDate());
- isNull = true;
- }
- break; }
- case QVariant::Time: {
- TIME_STRUCT tbuf;
- r = SQLGetData(d->hStmt,
- field + 1,
- SQL_C_TIME,
- (SQLPOINTER) &tbuf,
- 0,
- &lengthIndicator);
- if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && (lengthIndicator != SQL_NULL_DATA)) {
- v = new QVariant(QTime(tbuf.hour, tbuf.minute, tbuf.second));
- } else {
- v = new QVariant(QTime());
- isNull = true;
- }
- break; }
- case QVariant::DateTime: {
- TIMESTAMP_STRUCT dtbuf;
- r = SQLGetData(d->hStmt,
- field + 1,
- SQL_C_TIMESTAMP,
- (SQLPOINTER) &dtbuf,
- 0,
- &lengthIndicator);
- if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && (lengthIndicator != SQL_NULL_DATA)) {
- v = new QVariant(QDateTime(QDate(dtbuf.year, dtbuf.month, dtbuf.day),
- QTime(dtbuf.hour, dtbuf.minute, dtbuf.second, dtbuf.fraction / 1000000)));
- } else {
- v = new QVariant(QDateTime());
- isNull = true;
- }
- break; }
- case QVariant::ByteArray:
- v = new QVariant(qGetBinaryData(d->hStmt, field, lengthIndicator, isNull));
- break;
- case QVariant::Double:
- {
- switch(numericalPrecisionPolicy()) {
- case QSql::LowPrecisionInt32:
- v = new QVariant(qGetIntData(d->hStmt, field, isNull));
- break;
- case QSql::LowPrecisionInt64:
- v = new QVariant((qint64) qGetBigIntData(d->hStmt, field, isNull));
- break;
- case QSql::LowPrecisionDouble:
- v = new QVariant(qGetDoubleData(d->hStmt, field, isNull));
- break;
- case QSql::HighPrecision:
- default:
- // length + 1 for the comma
- v = new QVariant(qGetStringData(d->hStmt, field, info.length() + 1, isNull));
- break;
- }
- break;
- }
- case QVariant::String:
- default:
- v = new QVariant(qGetStringData(d->hStmt, field, info.length(), isNull));
- break;
- }
- if (isNull)
- *v = QVariant(info.type());
- d->valueCache[field] = v;
- return *v;
-}
-
-bool QDB2Result::isNull(int i)
-{
- Q_D(const QDB2Result);
- if (i >= d->valueCache.size())
- return true;
-
- if (d->valueCache[i])
- return d->valueCache[i]->isNull();
- return data(i).isNull();
-}
-
-int QDB2Result::numRowsAffected()
-{
- Q_D(const QDB2Result);
- SQLINTEGER affectedRowCount = 0;
- SQLRETURN r = SQLRowCount(d->hStmt, &affectedRowCount);
- if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO)
- return affectedRowCount;
- else
- qSqlWarning(QLatin1String("QDB2Result::numRowsAffected: Unable to count affected rows"), d);
- return -1;
-}
-
-int QDB2Result::size()
-{
- return -1;
-}
-
-QSqlRecord QDB2Result::record() const
-{
- Q_D(const QDB2Result);
- if (isActive())
- return d->recInf;
- return QSqlRecord();
-}
-
-bool QDB2Result::nextResult()
-{
- Q_D(QDB2Result);
- setActive(false);
- setAt(QSql::BeforeFirstRow);
- d->recInf.clear();
- d->emptyValueCache();
- setSelect(false);
-
- SQLRETURN r = SQLMoreResults(d->hStmt);
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
- if (r != SQL_NO_DATA) {
- setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
- "Unable to fetch last"), QSqlError::ConnectionError, d));
- }
- return false;
- }
-
- SQLSMALLINT fieldCount = 0;
- r = SQLNumResultCols(d->hStmt, &fieldCount);
- setSelect(fieldCount > 0);
- for (int i = 0; i < fieldCount; ++i)
- d->recInf.append(qMakeFieldInfo(d, i));
-
- d->valueCache.resize(fieldCount);
- d->valueCache.fill(NULL);
- setActive(true);
-
- return true;
-}
-
-void QDB2Result::virtual_hook(int id, void *data)
-{
- QSqlResult::virtual_hook(id, data);
-}
-
-void QDB2Result::detachFromResultSet()
-{
- Q_D(QDB2Result);
- if (d->hStmt)
- SQLCloseCursor(d->hStmt);
-}
-
-/************************************/
-
-QDB2Driver::QDB2Driver(QObject* parent)
- : QSqlDriver(*new QDB2DriverPrivate, parent)
-{
-}
-
-QDB2Driver::QDB2Driver(Qt::HANDLE env, Qt::HANDLE con, QObject* parent)
- : QSqlDriver(*new QDB2DriverPrivate, parent)
-{
- Q_D(QDB2Driver);
- d->hEnv = reinterpret_cast<intptr_t>(env);
- d->hDbc = reinterpret_cast<intptr_t>(con);
- if (env && con) {
- setOpen(true);
- setOpenError(false);
- }
-}
-
-QDB2Driver::~QDB2Driver()
-{
- close();
-}
-
-bool QDB2Driver::open(const QString& db, const QString& user, const QString& password, const QString& host, int port,
- const QString& connOpts)
-{
- Q_D(QDB2Driver);
- if (isOpen())
- close();
- SQLRETURN r;
- r = SQLAllocHandle(SQL_HANDLE_ENV,
- SQL_NULL_HANDLE,
- &d->hEnv);
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
- qSqlWarning(QLatin1String("QDB2Driver::open: Unable to allocate environment"), d);
- setOpenError(true);
- return false;
- }
-
- r = SQLAllocHandle(SQL_HANDLE_DBC,
- d->hEnv,
- &d->hDbc);
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
- qSqlWarning(QLatin1String("QDB2Driver::open: Unable to allocate connection"), d);
- setOpenError(true);
- return false;
- }
-
- QString protocol;
- // Set connection attributes
- const QStringList opts(connOpts.split(QLatin1Char(';'), QString::SkipEmptyParts));
- for (int i = 0; i < opts.count(); ++i) {
- const QString tmp(opts.at(i));
- int idx;
- if ((idx = tmp.indexOf(QLatin1Char('='))) == -1) {
- qWarning("QDB2Driver::open: Illegal connect option value '%s'",
- tmp.toLocal8Bit().constData());
- continue;
- }
-
- const QString opt(tmp.left(idx));
- const QString val(tmp.mid(idx + 1).simplified());
-
- SQLUINTEGER v = 0;
- r = SQL_SUCCESS;
- if (opt == QLatin1String("SQL_ATTR_ACCESS_MODE")) {
- if (val == QLatin1String("SQL_MODE_READ_ONLY")) {
- v = SQL_MODE_READ_ONLY;
- } else if (val == QLatin1String("SQL_MODE_READ_WRITE")) {
- v = SQL_MODE_READ_WRITE;
- } else {
- qWarning("QDB2Driver::open: Unknown option value '%s'",
- tmp.toLocal8Bit().constData());
- continue;
- }
- r = SQLSetConnectAttr(d->hDbc, SQL_ATTR_ACCESS_MODE, reinterpret_cast<SQLPOINTER>(v), 0);
- } else if (opt == QLatin1String("SQL_ATTR_LOGIN_TIMEOUT")) {
- v = val.toUInt();
- r = SQLSetConnectAttr(d->hDbc, SQL_ATTR_LOGIN_TIMEOUT, reinterpret_cast<SQLPOINTER>(v), 0);
- } else if (opt.compare(QLatin1String("PROTOCOL"), Qt::CaseInsensitive) == 0) {
- protocol = tmp;
- }
- else {
- qWarning("QDB2Driver::open: Unknown connection attribute '%s'",
- tmp.toLocal8Bit().constData());
- }
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO)
- qSqlWarning(QString::fromLatin1("QDB2Driver::open: "
- "Unable to set connection attribute '%1'").arg(opt), d);
- }
-
- if (protocol.isEmpty())
- protocol = QLatin1String("PROTOCOL=TCPIP");
-
- if (port < 0 )
- port = 50000;
-
- QString connQStr;
- connQStr = protocol + QLatin1String(";DATABASE=") + db + QLatin1String(";HOSTNAME=") + host
- + QLatin1String(";PORT=") + QString::number(port) + QLatin1String(";UID=") + user
- + QLatin1String(";PWD=") + password;
-
-
- SQLTCHAR connOut[SQL_MAX_OPTION_STRING_LENGTH];
- SQLSMALLINT cb;
-
- r = SQLDriverConnect(d->hDbc,
- NULL,
- qToTChar(connQStr),
- (SQLSMALLINT) connQStr.length(),
- connOut,
- SQL_MAX_OPTION_STRING_LENGTH,
- &cb,
- SQL_DRIVER_NOPROMPT);
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
- setLastError(qMakeError(tr("Unable to connect"),
- QSqlError::ConnectionError, d));
- setOpenError(true);
- return false;
- }
-
- d->user = user;
- setOpen(true);
- setOpenError(false);
- return true;
-}
-
-void QDB2Driver::close()
-{
- Q_D(QDB2Driver);
- SQLRETURN r;
- if (d->hDbc) {
- // Open statements/descriptors handles are automatically cleaned up by SQLDisconnect
- if (isOpen()) {
- r = SQLDisconnect(d->hDbc);
- if (r != SQL_SUCCESS)
- qSqlWarning(QLatin1String("QDB2Driver::close: Unable to disconnect datasource"), d);
- }
- r = SQLFreeHandle(SQL_HANDLE_DBC, d->hDbc);
- if (r != SQL_SUCCESS)
- qSqlWarning(QLatin1String("QDB2Driver::close: Unable to free connection handle"), d);
- d->hDbc = 0;
- }
-
- if (d->hEnv) {
- r = SQLFreeHandle(SQL_HANDLE_ENV, d->hEnv);
- if (r != SQL_SUCCESS)
- qSqlWarning(QLatin1String("QDB2Driver::close: Unable to free environment handle"), d);
- d->hEnv = 0;
- }
- setOpen(false);
- setOpenError(false);
-}
-
-QSqlResult *QDB2Driver::createResult() const
-{
- return new QDB2Result(this);
-}
-
-QSqlRecord QDB2Driver::record(const QString& tableName) const
-{
- Q_D(const QDB2Driver);
- QSqlRecord fil;
- if (!isOpen())
- return fil;
-
- SQLHANDLE hStmt;
- QString catalog, schema, table;
- qSplitTableQualifier(tableName, &catalog, &schema, &table);
- if (schema.isEmpty())
- schema = d->user;
-
- if (isIdentifierEscaped(catalog, QSqlDriver::TableName))
- catalog = stripDelimiters(catalog, QSqlDriver::TableName);
- else
- catalog = catalog.toUpper();
-
- if (isIdentifierEscaped(schema, QSqlDriver::TableName))
- schema = stripDelimiters(schema, QSqlDriver::TableName);
- else
- schema = schema.toUpper();
-
- if (isIdentifierEscaped(table, QSqlDriver::TableName))
- table = stripDelimiters(table, QSqlDriver::TableName);
- else
- table = table.toUpper();
-
- SQLRETURN r = SQLAllocHandle(SQL_HANDLE_STMT,
- d->hDbc,
- &hStmt);
- if (r != SQL_SUCCESS) {
- qSqlWarning(QLatin1String("QDB2Driver::record: Unable to allocate handle"), d);
- return fil;
- }
-
- r = SQLSetStmtAttr(hStmt,
- SQL_ATTR_CURSOR_TYPE,
- (SQLPOINTER) SQL_CURSOR_FORWARD_ONLY,
- SQL_IS_UINTEGER);
-
-
- //Aside: szSchemaName and szTableName parameters of SQLColumns
- //are case sensitive search patterns, so no escaping is used.
- r = SQLColumns(hStmt,
- NULL,
- 0,
- qToTChar(schema),
- schema.length(),
- qToTChar(table),
- table.length(),
- NULL,
- 0);
-
- if (r != SQL_SUCCESS)
- qSqlWarning(QLatin1String("QDB2Driver::record: Unable to execute column list"), d);
- r = SQLFetchScroll(hStmt,
- SQL_FETCH_NEXT,
- 0);
- while (r == SQL_SUCCESS) {
- fil.append(qMakeFieldInfo(hStmt));
- r = SQLFetchScroll(hStmt,
- SQL_FETCH_NEXT,
- 0);
- }
-
- r = SQLFreeHandle(SQL_HANDLE_STMT, hStmt);
- if (r != SQL_SUCCESS)
- qSqlWarning(QLatin1String("QDB2Driver: Unable to free statement handle ")
- + QString::number(r), d);
-
- return fil;
-}
-
-QStringList QDB2Driver::tables(QSql::TableType type) const
-{
- Q_D(const QDB2Driver);
- QStringList tl;
- if (!isOpen())
- return tl;
-
- SQLHANDLE hStmt;
-
- SQLRETURN r = SQLAllocHandle(SQL_HANDLE_STMT,
- d->hDbc,
- &hStmt);
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
- qSqlWarning(QLatin1String("QDB2Driver::tables: Unable to allocate handle"), d);
- return tl;
- }
- r = SQLSetStmtAttr(hStmt,
- SQL_ATTR_CURSOR_TYPE,
- (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY,
- SQL_IS_UINTEGER);
-
- QString tableType;
- if (type & QSql::Tables)
- tableType += QLatin1String("TABLE,");
- if (type & QSql::Views)
- tableType += QLatin1String("VIEW,");
- if (type & QSql::SystemTables)
- tableType += QLatin1String("SYSTEM TABLE,");
- if (tableType.isEmpty())
- return tl;
- tableType.chop(1);
-
- r = SQLTables(hStmt,
- NULL,
- 0,
- NULL,
- 0,
- NULL,
- 0,
- qToTChar(tableType),
- tableType.length());
-
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO)
- qSqlWarning(QLatin1String("QDB2Driver::tables: Unable to execute table list"), d);
- r = SQLFetchScroll(hStmt,
- SQL_FETCH_NEXT,
- 0);
- while (r == SQL_SUCCESS) {
- bool isNull;
- QString fieldVal = qGetStringData(hStmt, 2, -1, isNull);
- QString userVal = qGetStringData(hStmt, 1, -1, isNull);
- QString user = d->user;
- if ( isIdentifierEscaped(user, QSqlDriver::TableName))
- user = stripDelimiters(user, QSqlDriver::TableName);
- else
- user = user.toUpper();
-
- if (userVal != user)
- fieldVal = userVal + QLatin1Char('.') + fieldVal;
- tl.append(fieldVal);
- r = SQLFetchScroll(hStmt,
- SQL_FETCH_NEXT,
- 0);
- }
-
- r = SQLFreeHandle(SQL_HANDLE_STMT, hStmt);
- if (r != SQL_SUCCESS)
- qSqlWarning(QLatin1String("QDB2Driver::tables: Unable to free statement handle ")
- + QString::number(r), d);
- return tl;
-}
-
-QSqlIndex QDB2Driver::primaryIndex(const QString& tablename) const
-{
- Q_D(const QDB2Driver);
- QSqlIndex index(tablename);
- if (!isOpen())
- return index;
- QSqlRecord rec = record(tablename);
-
- SQLHANDLE hStmt;
- SQLRETURN r = SQLAllocHandle(SQL_HANDLE_STMT,
- d->hDbc,
- &hStmt);
- if (r != SQL_SUCCESS) {
- qSqlWarning(QLatin1String("QDB2Driver::primaryIndex: Unable to list primary key"), d);
- return index;
- }
- QString catalog, schema, table;
- qSplitTableQualifier(tablename, &catalog, &schema, &table);
-
- if (isIdentifierEscaped(catalog, QSqlDriver::TableName))
- catalog = stripDelimiters(catalog, QSqlDriver::TableName);
- else
- catalog = catalog.toUpper();
-
- if (isIdentifierEscaped(schema, QSqlDriver::TableName))
- schema = stripDelimiters(schema, QSqlDriver::TableName);
- else
- schema = schema.toUpper();
-
- if (isIdentifierEscaped(table, QSqlDriver::TableName))
- table = stripDelimiters(table, QSqlDriver::TableName);
- else
- table = table.toUpper();
-
- r = SQLSetStmtAttr(hStmt,
- SQL_ATTR_CURSOR_TYPE,
- (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY,
- SQL_IS_UINTEGER);
-
- r = SQLPrimaryKeys(hStmt,
- NULL,
- 0,
- qToTChar(schema),
- schema.length(),
- qToTChar(table),
- table.length());
- r = SQLFetchScroll(hStmt,
- SQL_FETCH_NEXT,
- 0);
-
- bool isNull;
- QString cName, idxName;
- // Store all fields in a StringList because the driver can't detail fields in this FETCH loop
- while (r == SQL_SUCCESS) {
- cName = qGetStringData(hStmt, 3, -1, isNull); // column name
- idxName = qGetStringData(hStmt, 5, -1, isNull); // pk index name
- index.append(rec.field(cName));
- index.setName(idxName);
- r = SQLFetchScroll(hStmt,
- SQL_FETCH_NEXT,
- 0);
- }
- r = SQLFreeHandle(SQL_HANDLE_STMT, hStmt);
- if (r!= SQL_SUCCESS)
- qSqlWarning(QLatin1String("QDB2Driver: Unable to free statement handle ")
- + QString::number(r), d);
- return index;
-}
-
-bool QDB2Driver::hasFeature(DriverFeature f) const
-{
- switch (f) {
- case QuerySize:
- case NamedPlaceholders:
- case BatchOperations:
- case LastInsertId:
- case SimpleLocking:
- case EventNotifications:
- case CancelQuery:
- return false;
- case BLOB:
- case Transactions:
- case MultipleResultSets:
- case PreparedQueries:
- case PositionalPlaceholders:
- case LowPrecisionNumbers:
- case FinishQuery:
- return true;
- case Unicode:
- return true;
- }
- return false;
-}
-
-bool QDB2Driver::beginTransaction()
-{
- if (!isOpen()) {
- qWarning("QDB2Driver::beginTransaction: Database not open");
- return false;
- }
- return setAutoCommit(false);
-}
-
-bool QDB2Driver::commitTransaction()
-{
- Q_D(QDB2Driver);
- if (!isOpen()) {
- qWarning("QDB2Driver::commitTransaction: Database not open");
- return false;
- }
- SQLRETURN r = SQLEndTran(SQL_HANDLE_DBC,
- d->hDbc,
- SQL_COMMIT);
- if (r != SQL_SUCCESS) {
- setLastError(qMakeError(tr("Unable to commit transaction"),
- QSqlError::TransactionError, d));
- return false;
- }
- return setAutoCommit(true);
-}
-
-bool QDB2Driver::rollbackTransaction()
-{
- Q_D(QDB2Driver);
- if (!isOpen()) {
- qWarning("QDB2Driver::rollbackTransaction: Database not open");
- return false;
- }
- SQLRETURN r = SQLEndTran(SQL_HANDLE_DBC,
- d->hDbc,
- SQL_ROLLBACK);
- if (r != SQL_SUCCESS) {
- setLastError(qMakeError(tr("Unable to rollback transaction"),
- QSqlError::TransactionError, d));
- return false;
- }
- return setAutoCommit(true);
-}
-
-bool QDB2Driver::setAutoCommit(bool autoCommit)
-{
- Q_D(QDB2Driver);
- SQLUINTEGER ac = autoCommit ? SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF;
- SQLRETURN r = SQLSetConnectAttr(d->hDbc,
- SQL_ATTR_AUTOCOMMIT,
- reinterpret_cast<SQLPOINTER>(ac),
- sizeof(ac));
- if (r != SQL_SUCCESS) {
- setLastError(qMakeError(tr("Unable to set autocommit"),
- QSqlError::TransactionError, d));
- return false;
- }
- return true;
-}
-
-QString QDB2Driver::formatValue(const QSqlField &field, bool trimStrings) const
-{
- if (field.isNull())
- return QLatin1String("NULL");
-
- switch (field.type()) {
- case QVariant::DateTime: {
- // Use an escape sequence for the datetime fields
- if (field.value().toDateTime().isValid()) {
- QDate dt = field.value().toDateTime().date();
- QTime tm = field.value().toDateTime().time();
- // Dateformat has to be "yyyy-MM-dd hh:mm:ss", with leading zeroes if month or day < 10
- return QLatin1Char('\'') + QString::number(dt.year()) + QLatin1Char('-')
- + QString::number(dt.month()) + QLatin1Char('-')
- + QString::number(dt.day()) + QLatin1Char('-')
- + QString::number(tm.hour()) + QLatin1Char('.')
- + QString::number(tm.minute()).rightJustified(2, QLatin1Char('0'), true)
- + QLatin1Char('.')
- + QString::number(tm.second()).rightJustified(2, QLatin1Char('0'), true)
- + QLatin1Char('.')
- + QString::number(tm.msec() * 1000).rightJustified(6, QLatin1Char('0'), true)
- + QLatin1Char('\'');
- } else {
- return QLatin1String("NULL");
- }
- }
- case QVariant::ByteArray: {
- QByteArray ba = field.value().toByteArray();
- QString res = QString::fromLatin1("BLOB(X'");
- 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]);
- }
- res += QLatin1String("')");
- return res;
- }
- default:
- return QSqlDriver::formatValue(field, trimStrings);
- }
-}
-
-QVariant QDB2Driver::handle() const
-{
- Q_D(const QDB2Driver);
- return QVariant(qRegisterMetaType<SQLHANDLE>("SQLHANDLE"), &d->hDbc);
-}
-
-QString QDB2Driver::escapeIdentifier(const QString &identifier, IdentifierType) const
-{
- QString res = identifier;
- if(!identifier.isEmpty() && !identifier.startsWith(QLatin1Char('"')) && !identifier.endsWith(QLatin1Char('"')) ) {
- res.replace(QLatin1Char('"'), QLatin1String("\"\""));
- res.prepend(QLatin1Char('"')).append(QLatin1Char('"'));
- res.replace(QLatin1Char('.'), QLatin1String("\".\""));
- }
- return res;
-}
-
-QT_END_NAMESPACE
diff --git a/src/sql/drivers/db2/qsql_db2.pri b/src/sql/drivers/db2/qsql_db2.pri
deleted file mode 100644
index c9e65e2c2e..0000000000
--- a/src/sql/drivers/db2/qsql_db2.pri
+++ /dev/null
@@ -1,8 +0,0 @@
-HEADERS += $$PWD/qsql_db2_p.h
-SOURCES += $$PWD/qsql_db2.cpp
-
-unix {
- !contains(LIBS, .*db2.*):LIBS += -ldb2
-} else {
- !contains(LIBS, .*db2.*):LIBS += -ldb2cli
-}
diff --git a/src/sql/drivers/db2/qsql_db2_p.h b/src/sql/drivers/db2/qsql_db2_p.h
deleted file mode 100644
index fa6d739479..0000000000
--- a/src/sql/drivers/db2/qsql_db2_p.h
+++ /dev/null
@@ -1,103 +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_DB2_H
-#define QSQL_DB2_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 <QtCore/qglobal.h>
-
-#ifdef QT_PLUGIN
-#define Q_EXPORT_SQLDRIVER_DB2
-#else
-#define Q_EXPORT_SQLDRIVER_DB2 Q_SQL_EXPORT
-#endif
-
-#include <QtSql/qsqldriver.h>
-
-QT_BEGIN_NAMESPACE
-
-class QDB2DriverPrivate;
-
-class Q_EXPORT_SQLDRIVER_DB2 QDB2Driver : public QSqlDriver
-{
- Q_DECLARE_PRIVATE(QDB2Driver)
- Q_OBJECT
- friend class QDB2ResultPrivate;
-
-public:
- explicit QDB2Driver(QObject* parent = 0);
- QDB2Driver(Qt::HANDLE env, Qt::HANDLE con, QObject* parent = 0);
- ~QDB2Driver();
- bool hasFeature(DriverFeature) const Q_DECL_OVERRIDE;
- void close() Q_DECL_OVERRIDE;
- QSqlRecord record(const QString &tableName) const Q_DECL_OVERRIDE;
- QStringList tables(QSql::TableType type) const Q_DECL_OVERRIDE;
- QSqlResult *createResult() const Q_DECL_OVERRIDE;
- QSqlIndex primaryIndex(const QString &tablename) const Q_DECL_OVERRIDE;
- bool beginTransaction() Q_DECL_OVERRIDE;
- bool commitTransaction() Q_DECL_OVERRIDE;
- bool rollbackTransaction() Q_DECL_OVERRIDE;
- QString formatValue(const QSqlField &field, bool trimStrings) const Q_DECL_OVERRIDE;
- QVariant handle() const Q_DECL_OVERRIDE;
- bool open(const QString &db,
- const QString &user,
- const QString &password,
- const QString &host,
- int port,
- const QString& connOpts) Q_DECL_OVERRIDE;
- QString escapeIdentifier(const QString &identifier, IdentifierType type) const Q_DECL_OVERRIDE;
-
-private:
- bool setAutoCommit(bool autoCommit);
-};
-
-QT_END_NAMESPACE
-
-#endif // QSQL_DB2_H
diff --git a/src/sql/drivers/drivers.pri b/src/sql/drivers/drivers.pri
deleted file mode 100644
index 87cc0b1d9e..0000000000
--- a/src/sql/drivers/drivers.pri
+++ /dev/null
@@ -1,11 +0,0 @@
-contains(sql-drivers, all):sql-driver += psql mysql odbc oci tds db2 sqlite ibase
-
-contains(sql-drivers, psql):include($$PWD/psql/qsql_psql.pri)
-contains(sql-drivers, mysql):include($$PWD/mysql/qsql_mysql.pri)
-contains(sql-drivers, odbc):include($$PWD/odbc/qsql_odbc.pri)
-contains(sql-drivers, oci):include($$PWD/oci/qsql_oci.pri)
-contains(sql-drivers, tds):include($$PWD/tds/qsql_tds.pri)
-contains(sql-drivers, db2):include($$PWD/db2/qsql_db2.pri)
-contains(sql-drivers, ibase):include($$PWD/ibase/qsql_ibase.pri)
-contains(sql-drivers, sqlite2):include($$PWD/sqlite2/qsql_sqlite2.pri)
-contains(sql-drivers, sqlite):include($$PWD/sqlite/qsql_sqlite.pri)
diff --git a/src/sql/drivers/ibase/qsql_ibase.cpp b/src/sql/drivers/ibase/qsql_ibase.cpp
deleted file mode 100644
index 6fd91b6b76..0000000000
--- a/src/sql/drivers/ibase/qsql_ibase.cpp
+++ /dev/null
@@ -1,1948 +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_ibase_p.h"
-#include <qcoreapplication.h>
-#include <qdatetime.h>
-#include <qvariant.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 <qlist.h>
-#include <qvector.h>
-#include <qtextcodec.h>
-#include <qmutex.h>
-#include <stdlib.h>
-#include <limits.h>
-#include <math.h>
-#include <qdebug.h>
-#include <QVarLengthArray>
-
-QT_BEGIN_NAMESPACE
-
-#define FBVERSION SQL_DIALECT_V6
-
-#ifndef SQLDA_CURRENT_VERSION
-#define SQLDA_CURRENT_VERSION SQLDA_VERSION1
-#endif
-
-enum { QIBaseChunkSize = SHRT_MAX / 2 };
-
-#if defined(FB_API_VER) && FB_API_VER >= 20
-static bool getIBaseError(QString& msg, const ISC_STATUS* status, ISC_LONG &sqlcode, QTextCodec *tc)
-#else
-static bool getIBaseError(QString& msg, ISC_STATUS* status, ISC_LONG &sqlcode, QTextCodec *tc)
-#endif
-{
- if (status[0] != 1 || status[1] <= 0)
- return false;
-
- msg.clear();
- sqlcode = isc_sqlcode(status);
- char buf[512];
-#if defined(FB_API_VER) && FB_API_VER >= 20
- while(fb_interpret(buf, 512, &status)) {
-#else
- while(isc_interprete(buf, &status)) {
-#endif
- if(!msg.isEmpty())
- msg += QLatin1String(" - ");
- if (tc)
- msg += tc->toUnicode(buf);
- else
- msg += QString::fromUtf8(buf);
- }
- return true;
-}
-
-static void createDA(XSQLDA *&sqlda)
-{
- sqlda = (XSQLDA *) malloc(XSQLDA_LENGTH(1));
- if (sqlda == (XSQLDA*)0) return;
- sqlda->sqln = 1;
- sqlda->sqld = 0;
- sqlda->version = SQLDA_CURRENT_VERSION;
- sqlda->sqlvar[0].sqlind = 0;
- sqlda->sqlvar[0].sqldata = 0;
-}
-
-static void enlargeDA(XSQLDA *&sqlda, int n)
-{
- if (sqlda != (XSQLDA*)0)
- free(sqlda);
- sqlda = (XSQLDA *) malloc(XSQLDA_LENGTH(n));
- if (sqlda == (XSQLDA*)0) return;
- sqlda->sqln = n;
- sqlda->version = SQLDA_CURRENT_VERSION;
-}
-
-static void initDA(XSQLDA *sqlda)
-{
- for (int i = 0; i < sqlda->sqld; ++i) {
- switch (sqlda->sqlvar[i].sqltype & ~1) {
- case SQL_INT64:
- case SQL_LONG:
- case SQL_SHORT:
- case SQL_FLOAT:
- case SQL_DOUBLE:
- case SQL_TIMESTAMP:
- case SQL_TYPE_TIME:
- case SQL_TYPE_DATE:
- case SQL_TEXT:
- case SQL_BLOB:
- sqlda->sqlvar[i].sqldata = new char[sqlda->sqlvar[i].sqllen];
- break;
- case SQL_ARRAY:
- sqlda->sqlvar[i].sqldata = new char[sizeof(ISC_QUAD)];
- memset(sqlda->sqlvar[i].sqldata, 0, sizeof(ISC_QUAD));
- break;
- case SQL_VARYING:
- sqlda->sqlvar[i].sqldata = new char[sqlda->sqlvar[i].sqllen + sizeof(short)];
- break;
- default:
- // not supported - do not bind.
- sqlda->sqlvar[i].sqldata = 0;
- break;
- }
- if (sqlda->sqlvar[i].sqltype & 1) {
- sqlda->sqlvar[i].sqlind = new short[1];
- *(sqlda->sqlvar[i].sqlind) = 0;
- } else {
- sqlda->sqlvar[i].sqlind = 0;
- }
- }
-}
-
-static void delDA(XSQLDA *&sqlda)
-{
- if (!sqlda)
- return;
- for (int i = 0; i < sqlda->sqld; ++i) {
- delete [] sqlda->sqlvar[i].sqlind;
- delete [] sqlda->sqlvar[i].sqldata;
- }
- free(sqlda);
- sqlda = 0;
-}
-
-static QVariant::Type qIBaseTypeName(int iType, bool hasScale)
-{
- switch (iType) {
- case blr_varying:
- case blr_varying2:
- case blr_text:
- case blr_cstring:
- case blr_cstring2:
- return QVariant::String;
- case blr_sql_time:
- return QVariant::Time;
- case blr_sql_date:
- return QVariant::Date;
- case blr_timestamp:
- return QVariant::DateTime;
- case blr_blob:
- return QVariant::ByteArray;
- case blr_quad:
- case blr_short:
- case blr_long:
- return (hasScale ? QVariant::Double : QVariant::Int);
- case blr_int64:
- return (hasScale ? QVariant::Double : QVariant::LongLong);
- case blr_float:
- case blr_d_float:
- case blr_double:
- return QVariant::Double;
- }
- qWarning("qIBaseTypeName: unknown datatype: %d", iType);
- return QVariant::Invalid;
-}
-
-static QVariant::Type qIBaseTypeName2(int iType, bool hasScale)
-{
- switch(iType & ~1) {
- case SQL_VARYING:
- case SQL_TEXT:
- return QVariant::String;
- case SQL_LONG:
- case SQL_SHORT:
- return (hasScale ? QVariant::Double : QVariant::Int);
- case SQL_INT64:
- return (hasScale ? QVariant::Double : QVariant::LongLong);
- case SQL_FLOAT:
- case SQL_DOUBLE:
- return QVariant::Double;
- case SQL_TIMESTAMP:
- return QVariant::DateTime;
- case SQL_TYPE_TIME:
- return QVariant::Time;
- case SQL_TYPE_DATE:
- return QVariant::Date;
- case SQL_ARRAY:
- return QVariant::List;
- case SQL_BLOB:
- return QVariant::ByteArray;
- default:
- return QVariant::Invalid;
- }
-}
-
-static ISC_TIMESTAMP toTimeStamp(const QDateTime &dt)
-{
- static const QTime midnight(0, 0, 0, 0);
- static const QDate basedate(1858, 11, 17);
- ISC_TIMESTAMP ts;
- ts.timestamp_time = midnight.msecsTo(dt.time()) * 10;
- ts.timestamp_date = basedate.daysTo(dt.date());
- return ts;
-}
-
-static QDateTime fromTimeStamp(char *buffer)
-{
- static const QDate bd(1858, 11, 17);
- QTime t(0, 0);
- QDate d;
-
- // have to demangle the structure ourselves because isc_decode_time
- // strips the msecs
- t = t.addMSecs(int(((ISC_TIMESTAMP*)buffer)->timestamp_time / 10));
- d = bd.addDays(int(((ISC_TIMESTAMP*)buffer)->timestamp_date));
-
- return QDateTime(d, t);
-}
-
-static ISC_TIME toTime(const QTime &t)
-{
- static const QTime midnight(0, 0, 0, 0);
- return (ISC_TIME)midnight.msecsTo(t) * 10;
-}
-
-static QTime fromTime(char *buffer)
-{
- QTime t(0, 0);
- // have to demangle the structure ourselves because isc_decode_time
- // strips the msecs
- t = t.addMSecs(int((*(ISC_TIME*)buffer) / 10));
-
- return t;
-}
-
-static ISC_DATE toDate(const QDate &t)
-{
- static const QDate basedate(1858, 11, 17);
- ISC_DATE date;
-
- date = basedate.daysTo(t);
- return date;
-}
-
-static QDate fromDate(char *buffer)
-{
- static const QDate bd(1858, 11, 17);
- QDate d;
-
- // have to demangle the structure ourselves because isc_decode_time
- // strips the msecs
- d = bd.addDays(int(((ISC_TIMESTAMP*)buffer)->timestamp_date));
-
- return d;
-}
-
-static QByteArray encodeString(QTextCodec *tc, const QString &str)
-{
- if (tc)
- return tc->fromUnicode(str);
- return str.toUtf8();
-}
-
-struct QIBaseEventBuffer {
-#if defined(FB_API_VER) && FB_API_VER >= 20
- ISC_UCHAR *eventBuffer;
- ISC_UCHAR *resultBuffer;
-#else
- char *eventBuffer;
- char *resultBuffer;
-#endif
- ISC_LONG bufferLength;
- ISC_LONG eventId;
-
- enum QIBaseSubscriptionState { Starting, Subscribed, Finished };
- QIBaseSubscriptionState subscriptionState;
-};
-
-class QIBaseDriverPrivate : public QSqlDriverPrivate
-{
- Q_DECLARE_PUBLIC(QIBaseDriver)
-public:
- QIBaseDriverPrivate() : QSqlDriverPrivate(), ibase(0), trans(0), tc(0) { dbmsType = QSqlDriver::Interbase; }
-
- bool isError(const char *msg, QSqlError::ErrorType typ = QSqlError::UnknownError)
- {
- Q_Q(QIBaseDriver);
- QString imsg;
- ISC_LONG sqlcode;
- if (!getIBaseError(imsg, status, sqlcode, tc))
- return false;
-
- q->setLastError(QSqlError(QCoreApplication::translate("QIBaseDriver", msg),
- imsg, typ, int(sqlcode)));
- return true;
- }
-
-public:
- isc_db_handle ibase;
- isc_tr_handle trans;
- QTextCodec *tc;
- ISC_STATUS status[20];
- QMap<QString, QIBaseEventBuffer*> eventBuffers;
-};
-
-typedef QMap<void *, QIBaseDriver *> QIBaseBufferDriverMap;
-Q_GLOBAL_STATIC(QIBaseBufferDriverMap, qBufferDriverMap)
-Q_GLOBAL_STATIC(QMutex, qMutex);
-
-static void qFreeEventBuffer(QIBaseEventBuffer* eBuffer)
-{
- qMutex()->lock();
- qBufferDriverMap()->remove(reinterpret_cast<void *>(eBuffer->resultBuffer));
- qMutex()->unlock();
- delete eBuffer;
-}
-
-class QIBaseResultPrivate;
-
-class QIBaseResult : public QSqlCachedResult
-{
- Q_DECLARE_PRIVATE(QIBaseResult)
-
-public:
- explicit QIBaseResult(const QIBaseDriver* db);
-
- bool prepare(const QString &query) Q_DECL_OVERRIDE;
- bool exec() Q_DECL_OVERRIDE;
- QVariant handle() const Q_DECL_OVERRIDE;
-
-protected:
- bool gotoNext(QSqlCachedResult::ValueCache& row, int rowIdx) Q_DECL_OVERRIDE;
- bool reset (const QString &query) Q_DECL_OVERRIDE;
- int size() Q_DECL_OVERRIDE;
- int numRowsAffected() Q_DECL_OVERRIDE;
- QSqlRecord record() const Q_DECL_OVERRIDE;
-};
-
-class QIBaseResultPrivate: public QSqlCachedResultPrivate
-{
- Q_DECLARE_PUBLIC(QIBaseResult)
-
-public:
- Q_DECLARE_SQLDRIVER_PRIVATE(QIBaseDriver)
-
- QIBaseResultPrivate(QIBaseResult *q, const QIBaseDriver *drv);
- ~QIBaseResultPrivate() { cleanup(); }
-
- void cleanup();
- bool isError(const char *msg, QSqlError::ErrorType typ = QSqlError::UnknownError)
- {
- Q_Q(QIBaseResult);
- QString imsg;
- ISC_LONG sqlcode;
- if (!getIBaseError(imsg, status, sqlcode, tc))
- return false;
-
- q->setLastError(QSqlError(QCoreApplication::translate("QIBaseResult", msg),
- imsg, typ, int(sqlcode)));
- return true;
- }
-
- bool transaction();
- bool commit();
-
- bool isSelect();
- QVariant fetchBlob(ISC_QUAD *bId);
- bool writeBlob(int i, const QByteArray &ba);
- QVariant fetchArray(int pos, ISC_QUAD *arr);
- bool writeArray(int i, const QList<QVariant> &list);
-
-public:
- ISC_STATUS status[20];
- isc_tr_handle trans;
- //indicator whether we have a local transaction or a transaction on driver level
- bool localTransaction;
- isc_stmt_handle stmt;
- isc_db_handle ibase;
- XSQLDA *sqlda; // output sqlda
- XSQLDA *inda; // input parameters
- int queryType;
- QTextCodec *tc;
-};
-
-
-QIBaseResultPrivate::QIBaseResultPrivate(QIBaseResult *q, const QIBaseDriver *drv)
- : QSqlCachedResultPrivate(q, drv),
- trans(0),
- localTransaction(!drv_d_func()->ibase),
- stmt(0),
- ibase(drv_d_func()->ibase),
- sqlda(0),
- inda(0),
- queryType(-1),
- tc(drv_d_func()->tc)
-{
-}
-
-void QIBaseResultPrivate::cleanup()
-{
- Q_Q(QIBaseResult);
- commit();
- if (!localTransaction)
- trans = 0;
-
- if (stmt) {
- isc_dsql_free_statement(status, &stmt, DSQL_drop);
- stmt = 0;
- }
-
- delDA(sqlda);
- delDA(inda);
-
- queryType = -1;
- q->cleanup();
-}
-
-bool QIBaseResultPrivate::writeBlob(int i, const QByteArray &ba)
-{
- isc_blob_handle handle = 0;
- ISC_QUAD *bId = (ISC_QUAD*)inda->sqlvar[i].sqldata;
- isc_create_blob2(status, &ibase, &trans, &handle, bId, 0, 0);
- if (!isError(QT_TRANSLATE_NOOP("QIBaseResult", "Unable to create BLOB"),
- QSqlError::StatementError)) {
- int i = 0;
- while (i < ba.size()) {
- isc_put_segment(status, &handle, qMin(ba.size() - i, int(QIBaseChunkSize)),
- const_cast<char*>(ba.data()) + i);
- if (isError(QT_TRANSLATE_NOOP("QIBaseResult", "Unable to write BLOB")))
- return false;
- i += qMin(ba.size() - i, int(QIBaseChunkSize));
- }
- }
- isc_close_blob(status, &handle);
- return true;
-}
-
-QVariant QIBaseResultPrivate::fetchBlob(ISC_QUAD *bId)
-{
- isc_blob_handle handle = 0;
-
- isc_open_blob2(status, &ibase, &trans, &handle, bId, 0, 0);
- if (isError(QT_TRANSLATE_NOOP("QIBaseResult", "Unable to open BLOB"),
- QSqlError::StatementError))
- return QVariant();
-
- unsigned short len = 0;
- QByteArray ba;
- int chunkSize = QIBaseChunkSize;
- ba.resize(chunkSize);
- int read = 0;
- while (isc_get_segment(status, &handle, &len, chunkSize, ba.data() + read) == 0 || status[1] == isc_segment) {
- read += len;
- ba.resize(read + chunkSize);
- }
- ba.resize(read);
-
- bool isErr = (status[1] == isc_segstr_eof ? false :
- isError(QT_TRANSLATE_NOOP("QIBaseResult",
- "Unable to read BLOB"),
- QSqlError::StatementError));
-
- isc_close_blob(status, &handle);
-
- if (isErr)
- return QVariant();
-
- ba.resize(read);
- return ba;
-}
-
-template<typename T>
-static QList<QVariant> toList(char** buf, int count, T* = 0)
-{
- QList<QVariant> res;
- for (int i = 0; i < count; ++i) {
- res.append(*(T*)(*buf));
- *buf += sizeof(T);
- }
- return res;
-}
-/* char** ? seems like bad influence from oracle ... */
-template<>
-QList<QVariant> toList<long>(char** buf, int count, long*)
-{
- QList<QVariant> res;
- for (int i = 0; i < count; ++i) {
- if (sizeof(int) == sizeof(long))
- res.append(int((*(long*)(*buf))));
- else
- res.append((qint64)(*(long*)(*buf)));
- *buf += sizeof(long);
- }
- return res;
-}
-
-static char* readArrayBuffer(QList<QVariant>& list, char *buffer, short curDim,
- short* numElements, ISC_ARRAY_DESC *arrayDesc,
- QTextCodec *tc)
-{
- const short dim = arrayDesc->array_desc_dimensions - 1;
- const unsigned char dataType = arrayDesc->array_desc_dtype;
- QList<QVariant> valList;
- unsigned short strLen = arrayDesc->array_desc_length;
-
- if (curDim != dim) {
- for(int i = 0; i < numElements[curDim]; ++i)
- buffer = readArrayBuffer(list, buffer, curDim + 1, numElements,
- arrayDesc, tc);
- } else {
- switch(dataType) {
- case blr_varying:
- case blr_varying2:
- strLen += 2; // for the two terminating null values
- case blr_text:
- case blr_text2: {
- int o;
- for (int i = 0; i < numElements[dim]; ++i) {
- for(o = 0; o < strLen && buffer[o]!=0; ++o )
- ;
-
- if (tc)
- valList.append(tc->toUnicode(buffer, o));
- else
- valList.append(QString::fromUtf8(buffer, o));
-
- buffer += strLen;
- }
- break; }
- case blr_long:
- valList = toList<long>(&buffer, numElements[dim], static_cast<long *>(0));
- break;
- case blr_short:
- valList = toList<short>(&buffer, numElements[dim]);
- break;
- case blr_int64:
- valList = toList<qint64>(&buffer, numElements[dim]);
- break;
- case blr_float:
- valList = toList<float>(&buffer, numElements[dim]);
- break;
- case blr_double:
- valList = toList<double>(&buffer, numElements[dim]);
- break;
- case blr_timestamp:
- for(int i = 0; i < numElements[dim]; ++i) {
- valList.append(fromTimeStamp(buffer));
- buffer += sizeof(ISC_TIMESTAMP);
- }
- break;
- case blr_sql_time:
- for(int i = 0; i < numElements[dim]; ++i) {
- valList.append(fromTime(buffer));
- buffer += sizeof(ISC_TIME);
- }
- break;
- case blr_sql_date:
- for(int i = 0; i < numElements[dim]; ++i) {
- valList.append(fromDate(buffer));
- buffer += sizeof(ISC_DATE);
- }
- break;
- }
- }
- if (dim > 0)
- list.append(valList);
- else
- list += valList;
- return buffer;
-}
-
-QVariant QIBaseResultPrivate::fetchArray(int pos, ISC_QUAD *arr)
-{
- QList<QVariant> list;
- ISC_ARRAY_DESC desc;
-
- if (!arr)
- return list;
-
- QByteArray relname(sqlda->sqlvar[pos].relname, sqlda->sqlvar[pos].relname_length);
- QByteArray sqlname(sqlda->sqlvar[pos].aliasname, sqlda->sqlvar[pos].aliasname_length);
-
- isc_array_lookup_bounds(status, &ibase, &trans, relname.data(), sqlname.data(), &desc);
- if (isError(QT_TRANSLATE_NOOP("QIBaseResult", "Could not find array"),
- QSqlError::StatementError))
- return list;
-
-
- int arraySize = 1, subArraySize;
- short dimensions = desc.array_desc_dimensions;
- QVarLengthArray<short> numElements(dimensions);
-
- for(int i = 0; i < dimensions; ++i) {
- subArraySize = (desc.array_desc_bounds[i].array_bound_upper -
- desc.array_desc_bounds[i].array_bound_lower + 1);
- numElements[i] = subArraySize;
- arraySize = subArraySize * arraySize;
- }
-
- ISC_LONG bufLen;
- QByteArray ba;
- /* varying arrayelements are stored with 2 trailing null bytes
- indicating the length of the string
- */
- if (desc.array_desc_dtype == blr_varying
- || desc.array_desc_dtype == blr_varying2) {
- desc.array_desc_length += 2;
- bufLen = desc.array_desc_length * arraySize * sizeof(short);
- } else {
- bufLen = desc.array_desc_length * arraySize;
- }
-
-
- ba.resize(int(bufLen));
- isc_array_get_slice(status, &ibase, &trans, arr, &desc, ba.data(), &bufLen);
- if (isError(QT_TRANSLATE_NOOP("QIBaseResult", "Could not get array data"),
- QSqlError::StatementError))
- return list;
-
- readArrayBuffer(list, ba.data(), 0, numElements.data(), &desc, tc);
-
- return QVariant(list);
-}
-
-template<typename T>
-static char* fillList(char *buffer, const QList<QVariant> &list, T* = 0)
-{
- for (int i = 0; i < list.size(); ++i) {
- T val;
- val = qvariant_cast<T>(list.at(i));
- memcpy(buffer, &val, sizeof(T));
- buffer += sizeof(T);
- }
- return buffer;
-}
-
-template<>
-char* fillList<float>(char *buffer, const QList<QVariant> &list, float*)
-{
- for (int i = 0; i < list.size(); ++i) {
- double val;
- float val2 = 0;
- val = qvariant_cast<double>(list.at(i));
- val2 = (float)val;
- memcpy(buffer, &val2, sizeof(float));
- buffer += sizeof(float);
- }
- return buffer;
-}
-
-static char* qFillBufferWithString(char *buffer, const QString& string,
- short buflen, bool varying, bool array,
- QTextCodec *tc)
-{
- QByteArray str = encodeString(tc, string); // keep a copy of the string alive in this scope
- if (varying) {
- short tmpBuflen = buflen;
- if (str.length() < buflen)
- buflen = str.length();
- if (array) { // interbase stores varying arrayelements different than normal varying elements
- memcpy(buffer, str.data(), buflen);
- memset(buffer + buflen, 0, tmpBuflen - buflen);
- } else {
- *(short*)buffer = buflen; // first two bytes is the length
- memcpy(buffer + sizeof(short), str.data(), buflen);
- }
- buffer += tmpBuflen;
- } else {
- str = str.leftJustified(buflen, ' ', true);
- memcpy(buffer, str.data(), buflen);
- buffer += buflen;
- }
- return buffer;
-}
-
-static char* createArrayBuffer(char *buffer, const QList<QVariant> &list,
- QVariant::Type type, short curDim, ISC_ARRAY_DESC *arrayDesc,
- QString& error, QTextCodec *tc)
-{
- int i;
- ISC_ARRAY_BOUND *bounds = arrayDesc->array_desc_bounds;
- short dim = arrayDesc->array_desc_dimensions - 1;
-
- int elements = (bounds[curDim].array_bound_upper -
- bounds[curDim].array_bound_lower + 1);
-
- if (list.size() != elements) { // size mismatch
- error = QLatin1String("Expected size: %1. Supplied size: %2");
- error = QLatin1String("Array size mismatch. Fieldname: %1 ")
- + error.arg(elements).arg(list.size());
- return 0;
- }
-
- if (curDim != dim) {
- for(i = 0; i < list.size(); ++i) {
-
- if (list.at(i).type() != QVariant::List) { // dimensions mismatch
- error = QLatin1String("Array dimensons mismatch. Fieldname: %1");
- return 0;
- }
-
- buffer = createArrayBuffer(buffer, list.at(i).toList(), type, curDim + 1,
- arrayDesc, error, tc);
- if (!buffer)
- return 0;
- }
- } else {
- switch(type) {
- case QVariant::Int:
- case QVariant::UInt:
- if (arrayDesc->array_desc_dtype == blr_short)
- buffer = fillList<short>(buffer, list);
- else
- buffer = fillList<int>(buffer, list);
- break;
- case QVariant::Double:
- if (arrayDesc->array_desc_dtype == blr_float)
- buffer = fillList<float>(buffer, list, static_cast<float *>(0));
- else
- buffer = fillList<double>(buffer, list);
- break;
- case QVariant::LongLong:
- buffer = fillList<qint64>(buffer, list);
- break;
- case QVariant::ULongLong:
- buffer = fillList<quint64>(buffer, list);
- break;
- case QVariant::String:
- for (i = 0; i < list.size(); ++i)
- buffer = qFillBufferWithString(buffer, list.at(i).toString(),
- arrayDesc->array_desc_length,
- arrayDesc->array_desc_dtype == blr_varying,
- true, tc);
- break;
- case QVariant::Date:
- for (i = 0; i < list.size(); ++i) {
- *((ISC_DATE*)buffer) = toDate(list.at(i).toDate());
- buffer += sizeof(ISC_DATE);
- }
- break;
- case QVariant::Time:
- for (i = 0; i < list.size(); ++i) {
- *((ISC_TIME*)buffer) = toTime(list.at(i).toTime());
- buffer += sizeof(ISC_TIME);
- }
- break;
-
- case QVariant::DateTime:
- for (i = 0; i < list.size(); ++i) {
- *((ISC_TIMESTAMP*)buffer) = toTimeStamp(list.at(i).toDateTime());
- buffer += sizeof(ISC_TIMESTAMP);
- }
- break;
- default:
- break;
- }
- }
- return buffer;
-}
-
-bool QIBaseResultPrivate::writeArray(int column, const QList<QVariant> &list)
-{
- Q_Q(QIBaseResult);
- QString error;
- ISC_QUAD *arrayId = (ISC_QUAD*) inda->sqlvar[column].sqldata;
- ISC_ARRAY_DESC desc;
-
- QByteArray relname(inda->sqlvar[column].relname, inda->sqlvar[column].relname_length);
- QByteArray sqlname(inda->sqlvar[column].aliasname, inda->sqlvar[column].aliasname_length);
-
- isc_array_lookup_bounds(status, &ibase, &trans, relname.data(), sqlname.data(), &desc);
- if (isError(QT_TRANSLATE_NOOP("QIBaseResult", "Could not find array"),
- QSqlError::StatementError))
- return false;
-
- short arraySize = 1;
- ISC_LONG bufLen;
- QList<QVariant> subList = list;
-
- short dimensions = desc.array_desc_dimensions;
- for(int i = 0; i < dimensions; ++i) {
- arraySize *= (desc.array_desc_bounds[i].array_bound_upper -
- desc.array_desc_bounds[i].array_bound_lower + 1);
- }
-
- /* varying arrayelements are stored with 2 trailing null bytes
- indicating the length of the string
- */
- if (desc.array_desc_dtype == blr_varying ||
- desc.array_desc_dtype == blr_varying2)
- desc.array_desc_length += 2;
-
- bufLen = desc.array_desc_length * arraySize;
- QByteArray ba;
- ba.resize(int(bufLen));
-
- if (list.size() > arraySize) {
- error = QLatin1String("Array size missmatch: size of %1 is %2, size of provided list is %3");
- error = error.arg(QLatin1String(sqlname)).arg(arraySize).arg(list.size());
- q->setLastError(QSqlError(error, QLatin1String(""), QSqlError::StatementError));
- return false;
- }
-
- if (!createArrayBuffer(ba.data(), list,
- qIBaseTypeName(desc.array_desc_dtype, inda->sqlvar[column].sqlscale < 0),
- 0, &desc, error, tc)) {
- q->setLastError(QSqlError(error.arg(QLatin1String(sqlname)), QLatin1String(""),
- QSqlError::StatementError));
- return false;
- }
-
- /* readjust the buffer size*/
- if (desc.array_desc_dtype == blr_varying
- || desc.array_desc_dtype == blr_varying2)
- desc.array_desc_length -= 2;
-
- isc_array_put_slice(status, &ibase, &trans, arrayId, &desc, ba.data(), &bufLen);
- return true;
-}
-
-
-bool QIBaseResultPrivate::isSelect()
-{
- char acBuffer[9];
- char qType = isc_info_sql_stmt_type;
- isc_dsql_sql_info(status, &stmt, 1, &qType, sizeof(acBuffer), acBuffer);
- if (isError(QT_TRANSLATE_NOOP("QIBaseResult", "Could not get query info"),
- QSqlError::StatementError))
- return false;
- int iLength = isc_vax_integer(&acBuffer[1], 2);
- queryType = isc_vax_integer(&acBuffer[3], iLength);
- return (queryType == isc_info_sql_stmt_select || queryType == isc_info_sql_stmt_exec_procedure);
-}
-
-bool QIBaseResultPrivate::transaction()
-{
- if (trans)
- return true;
- if (drv_d_func()->trans) {
- localTransaction = false;
- trans = drv_d_func()->trans;
- return true;
- }
- localTransaction = true;
-
- isc_start_transaction(status, &trans, 1, &ibase, 0, NULL);
- if (isError(QT_TRANSLATE_NOOP("QIBaseResult", "Could not start transaction"),
- QSqlError::TransactionError))
- return false;
-
- return true;
-}
-
-// does nothing if the transaction is on the
-// driver level
-bool QIBaseResultPrivate::commit()
-{
- if (!trans)
- return false;
- // don't commit driver's transaction, the driver will do it for us
- if (!localTransaction)
- return true;
-
- isc_commit_transaction(status, &trans);
- trans = 0;
- return !isError(QT_TRANSLATE_NOOP("QIBaseResult", "Unable to commit transaction"),
- QSqlError::TransactionError);
-}
-
-//////////
-
-QIBaseResult::QIBaseResult(const QIBaseDriver *db)
- : QSqlCachedResult(*new QIBaseResultPrivate(this, db))
-{
-}
-
-bool QIBaseResult::prepare(const QString& query)
-{
- Q_D(QIBaseResult);
-// qDebug("prepare: %s", qPrintable(query));
- if (!driver() || !driver()->isOpen() || driver()->isOpenError())
- return false;
- d->cleanup();
- setActive(false);
- setAt(QSql::BeforeFirstRow);
-
- createDA(d->sqlda);
- if (d->sqlda == (XSQLDA*)0) {
- qWarning()<<"QIOBaseResult: createDA(): failed to allocate memory";
- return false;
- }
-
- createDA(d->inda);
- if (d->inda == (XSQLDA*)0){
- qWarning()<<"QIOBaseResult: createDA(): failed to allocate memory";
- return false;
- }
-
- if (!d->transaction())
- return false;
-
- isc_dsql_allocate_statement(d->status, &d->ibase, &d->stmt);
- if (d->isError(QT_TRANSLATE_NOOP("QIBaseResult", "Could not allocate statement"),
- QSqlError::StatementError))
- return false;
- isc_dsql_prepare(d->status, &d->trans, &d->stmt, 0,
- const_cast<char*>(encodeString(d->tc, query).constData()), FBVERSION, d->sqlda);
- if (d->isError(QT_TRANSLATE_NOOP("QIBaseResult", "Could not prepare statement"),
- QSqlError::StatementError))
- return false;
-
- isc_dsql_describe_bind(d->status, &d->stmt, FBVERSION, d->inda);
- if (d->isError(QT_TRANSLATE_NOOP("QIBaseResult",
- "Could not describe input statement"), QSqlError::StatementError))
- return false;
- if (d->inda->sqld > d->inda->sqln) {
- enlargeDA(d->inda, d->inda->sqld);
- if (d->inda == (XSQLDA*)0) {
- qWarning()<<"QIOBaseResult: enlargeDA(): failed to allocate memory";
- return false;
- }
-
- isc_dsql_describe_bind(d->status, &d->stmt, FBVERSION, d->inda);
- if (d->isError(QT_TRANSLATE_NOOP("QIBaseResult",
- "Could not describe input statement"), QSqlError::StatementError))
- return false;
- }
- initDA(d->inda);
- if (d->sqlda->sqld > d->sqlda->sqln) {
- // need more field descriptors
- enlargeDA(d->sqlda, d->sqlda->sqld);
- if (d->sqlda == (XSQLDA*)0) {
- qWarning()<<"QIOBaseResult: enlargeDA(): failed to allocate memory";
- return false;
- }
-
- isc_dsql_describe(d->status, &d->stmt, FBVERSION, d->sqlda);
- if (d->isError(QT_TRANSLATE_NOOP("QIBaseResult", "Could not describe statement"),
- QSqlError::StatementError))
- return false;
- }
- initDA(d->sqlda);
-
- setSelect(d->isSelect());
- if (!isSelect()) {
- free(d->sqlda);
- d->sqlda = 0;
- }
-
- return true;
-}
-
-
-bool QIBaseResult::exec()
-{
- Q_D(QIBaseResult);
- bool ok = true;
-
- if (!d->trans)
- d->transaction();
-
- if (!driver() || !driver()->isOpen() || driver()->isOpenError())
- return false;
- setActive(false);
- setAt(QSql::BeforeFirstRow);
-
- if (d->inda) {
- QVector<QVariant>& values = boundValues();
- int i;
- if (values.count() > d->inda->sqld) {
- qWarning("QIBaseResult::exec: Parameter mismatch, expected %d, got %d parameters",
- d->inda->sqld, values.count());
- return false;
- }
- int para = 0;
- for (i = 0; i < values.count(); ++i) {
- para = i;
- if (!d->inda->sqlvar[para].sqldata)
- // skip unknown datatypes
- continue;
- const QVariant val(values[i]);
- if (d->inda->sqlvar[para].sqltype & 1) {
- if (val.isNull()) {
- // set null indicator
- *(d->inda->sqlvar[para].sqlind) = -1;
- // and set the value to 0, otherwise it would count as empty string.
- // it seems to be working with just setting sqlind to -1
- //*((char*)d->inda->sqlvar[para].sqldata) = 0;
- continue;
- }
- // a value of 0 means non-null.
- *(d->inda->sqlvar[para].sqlind) = 0;
- }
- switch(d->inda->sqlvar[para].sqltype & ~1) {
- case SQL_INT64:
- if (d->inda->sqlvar[para].sqlscale < 0)
- *((qint64*)d->inda->sqlvar[para].sqldata) =
- (qint64)floor(0.5 + val.toDouble() * pow(10.0, d->inda->sqlvar[para].sqlscale * -1));
- else
- *((qint64*)d->inda->sqlvar[para].sqldata) = val.toLongLong();
- break;
- case SQL_LONG:
- if (d->inda->sqlvar[para].sqllen == 4) {
- if (d->inda->sqlvar[para].sqlscale < 0)
- *((qint32*)d->inda->sqlvar[para].sqldata) =
- (qint32)floor(0.5 + val.toDouble() * pow(10.0, d->inda->sqlvar[para].sqlscale * -1));
- else
- *((qint32*)d->inda->sqlvar[para].sqldata) = (qint32)val.toInt();
- } else {
- *((qint64*)d->inda->sqlvar[para].sqldata) = val.toLongLong();
- }
- break;
- case SQL_SHORT:
- if (d->inda->sqlvar[para].sqlscale < 0)
- *((short*)d->inda->sqlvar[para].sqldata) =
- (short)floor(0.5 + val.toDouble() * pow(10.0, d->inda->sqlvar[para].sqlscale * -1));
- else
- *((short*)d->inda->sqlvar[para].sqldata) = (short)val.toInt();
- break;
- case SQL_FLOAT:
- *((float*)d->inda->sqlvar[para].sqldata) = (float)val.toDouble();
- break;
- case SQL_DOUBLE:
- *((double*)d->inda->sqlvar[para].sqldata) = val.toDouble();
- break;
- case SQL_TIMESTAMP:
- *((ISC_TIMESTAMP*)d->inda->sqlvar[para].sqldata) = toTimeStamp(val.toDateTime());
- break;
- case SQL_TYPE_TIME:
- *((ISC_TIME*)d->inda->sqlvar[para].sqldata) = toTime(val.toTime());
- break;
- case SQL_TYPE_DATE:
- *((ISC_DATE*)d->inda->sqlvar[para].sqldata) = toDate(val.toDate());
- break;
- case SQL_VARYING:
- case SQL_TEXT:
- qFillBufferWithString(d->inda->sqlvar[para].sqldata, val.toString(),
- d->inda->sqlvar[para].sqllen,
- (d->inda->sqlvar[para].sqltype & ~1) == SQL_VARYING, false, d->tc);
- break;
- case SQL_BLOB:
- ok &= d->writeBlob(para, val.toByteArray());
- break;
- case SQL_ARRAY:
- ok &= d->writeArray(para, val.toList());
- break;
- default:
- qWarning("QIBaseResult::exec: Unknown datatype %d",
- d->inda->sqlvar[para].sqltype & ~1);
- break;
- }
- }
- }
-
- if (ok) {
- if (colCount() && d->queryType != isc_info_sql_stmt_exec_procedure) {
- isc_dsql_free_statement(d->status, &d->stmt, DSQL_close);
- if (d->isError(QT_TRANSLATE_NOOP("QIBaseResult", "Unable to close statement")))
- return false;
- cleanup();
- }
- if (d->queryType == isc_info_sql_stmt_exec_procedure)
- isc_dsql_execute2(d->status, &d->trans, &d->stmt, FBVERSION, d->inda, d->sqlda);
- else
- isc_dsql_execute(d->status, &d->trans, &d->stmt, FBVERSION, d->inda);
- if (d->isError(QT_TRANSLATE_NOOP("QIBaseResult", "Unable to execute query")))
- return false;
-
- // Not all stored procedures necessarily return values.
- if (d->queryType == isc_info_sql_stmt_exec_procedure && d->sqlda && d->sqlda->sqld == 0)
- delDA(d->sqlda);
-
- if (d->sqlda)
- init(d->sqlda->sqld);
-
- if (!isSelect())
- d->commit();
-
- setActive(true);
- return true;
- }
- return false;
-}
-
-bool QIBaseResult::reset (const QString& query)
-{
- if (!prepare(query))
- return false;
- return exec();
-}
-
-bool QIBaseResult::gotoNext(QSqlCachedResult::ValueCache& row, int rowIdx)
-{
- Q_D(QIBaseResult);
- ISC_STATUS stat = 0;
-
- // Stored Procedures are special - they populate our d->sqlda when executing,
- // so we don't have to call isc_dsql_fetch
- if (d->queryType == isc_info_sql_stmt_exec_procedure) {
- // the first "fetch" shall succeed, all consecutive ones will fail since
- // we only have one row to fetch for stored procedures
- if (rowIdx != 0)
- stat = 100;
- } else {
- stat = isc_dsql_fetch(d->status, &d->stmt, FBVERSION, d->sqlda);
- }
-
- if (stat == 100) {
- // no more rows
- setAt(QSql::AfterLastRow);
- return false;
- }
- if (d->isError(QT_TRANSLATE_NOOP("QIBaseResult", "Could not fetch next item"),
- QSqlError::StatementError))
- return false;
- if (rowIdx < 0) // not interested in actual values
- return true;
-
- for (int i = 0; i < d->sqlda->sqld; ++i) {
- int idx = rowIdx + i;
- char *buf = d->sqlda->sqlvar[i].sqldata;
- int size = d->sqlda->sqlvar[i].sqllen;
- Q_ASSERT(buf);
-
- if ((d->sqlda->sqlvar[i].sqltype & 1) && *d->sqlda->sqlvar[i].sqlind) {
- // null value
- QVariant v;
- v.convert(qIBaseTypeName2(d->sqlda->sqlvar[i].sqltype, d->sqlda->sqlvar[i].sqlscale < 0));
- if(v.type() == QVariant::Double) {
- switch(numericalPrecisionPolicy()) {
- case QSql::LowPrecisionInt32:
- v.convert(QVariant::Int);
- break;
- case QSql::LowPrecisionInt64:
- v.convert(QVariant::LongLong);
- break;
- case QSql::HighPrecision:
- v.convert(QVariant::String);
- break;
- case QSql::LowPrecisionDouble:
- // no conversion
- break;
- }
- }
- row[idx] = v;
- continue;
- }
-
- switch(d->sqlda->sqlvar[i].sqltype & ~1) {
- case SQL_VARYING:
- // pascal strings - a short with a length information followed by the data
- if (d->tc)
- row[idx] = d->tc->toUnicode(buf + sizeof(short), *(short*)buf);
- else
- row[idx] = QString::fromUtf8(buf + sizeof(short), *(short*)buf);
- break;
- case SQL_INT64:
- if (d->sqlda->sqlvar[i].sqlscale < 0)
- row[idx] = *(qint64*)buf * pow(10.0, d->sqlda->sqlvar[i].sqlscale);
- else
- row[idx] = QVariant(*(qint64*)buf);
- break;
- case SQL_LONG:
- if (d->sqlda->sqlvar[i].sqllen == 4)
- if (d->sqlda->sqlvar[i].sqlscale < 0)
- row[idx] = QVariant(*(qint32*)buf * pow(10.0, d->sqlda->sqlvar[i].sqlscale));
- else
- row[idx] = QVariant(*(qint32*)buf);
- else
- row[idx] = QVariant(*(qint64*)buf);
- break;
- case SQL_SHORT:
- if (d->sqlda->sqlvar[i].sqlscale < 0)
- row[idx] = QVariant(long((*(short*)buf)) * pow(10.0, d->sqlda->sqlvar[i].sqlscale));
- else
- row[idx] = QVariant(int((*(short*)buf)));
- break;
- case SQL_FLOAT:
- row[idx] = QVariant(double((*(float*)buf)));
- break;
- case SQL_DOUBLE:
- row[idx] = QVariant(*(double*)buf);
- break;
- case SQL_TIMESTAMP:
- row[idx] = fromTimeStamp(buf);
- break;
- case SQL_TYPE_TIME:
- row[idx] = fromTime(buf);
- break;
- case SQL_TYPE_DATE:
- row[idx] = fromDate(buf);
- break;
- case SQL_TEXT:
- if (d->tc)
- row[idx] = d->tc->toUnicode(buf, size);
- else
- row[idx] = QString::fromUtf8(buf, size);
- break;
- case SQL_BLOB:
- row[idx] = d->fetchBlob((ISC_QUAD*)buf);
- break;
- case SQL_ARRAY:
- row[idx] = d->fetchArray(i, (ISC_QUAD*)buf);
- break;
- default:
- // unknown type - don't even try to fetch
- row[idx] = QVariant();
- break;
- }
- if (d->sqlda->sqlvar[i].sqlscale < 0) {
- QVariant v = row[idx];
- switch(numericalPrecisionPolicy()) {
- case QSql::LowPrecisionInt32:
- if(v.convert(QVariant::Int))
- row[idx]=v;
- break;
- case QSql::LowPrecisionInt64:
- if(v.convert(QVariant::LongLong))
- row[idx]=v;
- break;
- case QSql::LowPrecisionDouble:
- if(v.convert(QVariant::Double))
- row[idx]=v;
- break;
- case QSql::HighPrecision:
- if(v.convert(QVariant::String))
- row[idx]=v;
- break;
- }
- }
- }
-
- return true;
-}
-
-int QIBaseResult::size()
-{
- return -1;
-
-#if 0 /// ### FIXME
- static char sizeInfo[] = {isc_info_sql_records};
- char buf[64];
-
- //qDebug() << sizeInfo;
- if (!isActive() || !isSelect())
- return -1;
-
- char ct;
- short len;
- int val = 0;
-// while(val == 0) {
- isc_dsql_sql_info(d->status, &d->stmt, sizeof(sizeInfo), sizeInfo, sizeof(buf), buf);
-// isc_database_info(d->status, &d->ibase, sizeof(sizeInfo), sizeInfo, sizeof(buf), buf);
-
- for(int i = 0; i < 66; ++i)
- qDebug() << QString::number(buf[i]);
-
- for (char* c = buf + 3; *c != isc_info_end; /*nothing*/) {
- ct = *(c++);
- len = isc_vax_integer(c, 2);
- c += 2;
- val = isc_vax_integer(c, len);
- c += len;
- qDebug() << "size" << val;
- if (ct == isc_info_req_select_count)
- return val;
- }
- //qDebug("size -1");
- return -1;
-
- unsigned int i, result_size;
- if (buf[0] == isc_info_sql_records) {
- i = 3;
- result_size = isc_vax_integer(&buf[1],2);
- while (buf[i] != isc_info_end && i < result_size) {
- len = (short)isc_vax_integer(&buf[i+1],2);
- if (buf[i] == isc_info_req_select_count)
- return (isc_vax_integer(&buf[i+3],len));
- i += len+3;
- }
- }
-// }
- return -1;
-#endif
-}
-
-int QIBaseResult::numRowsAffected()
-{
- Q_D(QIBaseResult);
- static char acCountInfo[] = {isc_info_sql_records};
- char cCountType;
- bool bIsProcedure = false;
-
- switch (d->queryType) {
- case isc_info_sql_stmt_select:
- cCountType = isc_info_req_select_count;
- break;
- case isc_info_sql_stmt_update:
- cCountType = isc_info_req_update_count;
- break;
- case isc_info_sql_stmt_delete:
- cCountType = isc_info_req_delete_count;
- break;
- case isc_info_sql_stmt_insert:
- cCountType = isc_info_req_insert_count;
- break;
- case isc_info_sql_stmt_exec_procedure:
- bIsProcedure = true; // will sum all changes
- break;
- default:
- qWarning() << "numRowsAffected: Unknown statement type (" << d->queryType << ")";
- return -1;
- }
-
- char acBuffer[33];
- int iResult = -1;
- isc_dsql_sql_info(d->status, &d->stmt, sizeof(acCountInfo), acCountInfo, sizeof(acBuffer), acBuffer);
- if (d->isError(QT_TRANSLATE_NOOP("QIBaseResult", "Could not get statement info"),
- QSqlError::StatementError))
- return -1;
- for (char *pcBuf = acBuffer + 3; *pcBuf != isc_info_end; /*nothing*/) {
- char cType = *pcBuf++;
- short sLength = isc_vax_integer (pcBuf, 2);
- pcBuf += 2;
- int iValue = isc_vax_integer (pcBuf, sLength);
- pcBuf += sLength;
- if (bIsProcedure) {
- if (cType == isc_info_req_insert_count || cType == isc_info_req_update_count
- || cType == isc_info_req_delete_count) {
- if (iResult == -1)
- iResult = 0;
- iResult += iValue;
- }
- } else if (cType == cCountType) {
- iResult = iValue;
- break;
- }
- }
- return iResult;
-}
-
-QSqlRecord QIBaseResult::record() const
-{
- Q_D(const QIBaseResult);
- QSqlRecord rec;
- if (!isActive() || !d->sqlda)
- return rec;
-
- XSQLVAR v;
- for (int i = 0; i < d->sqlda->sqld; ++i) {
- v = d->sqlda->sqlvar[i];
- QSqlField f(QString::fromLatin1(v.aliasname, v.aliasname_length).simplified(),
- qIBaseTypeName2(v.sqltype, v.sqlscale < 0));
- f.setLength(v.sqllen);
- f.setPrecision(qAbs(v.sqlscale));
- f.setRequiredStatus((v.sqltype & 1) == 0 ? QSqlField::Required : QSqlField::Optional);
- if(v.sqlscale < 0) {
- QSqlQuery q(driver()->createResult());
- q.setForwardOnly(true);
- q.exec(QLatin1String("select b.RDB$FIELD_PRECISION, b.RDB$FIELD_SCALE, b.RDB$FIELD_LENGTH, a.RDB$NULL_FLAG "
- "FROM RDB$RELATION_FIELDS a, RDB$FIELDS b "
- "WHERE b.RDB$FIELD_NAME = a.RDB$FIELD_SOURCE "
- "AND a.RDB$RELATION_NAME = '") + QString::fromLatin1(v.relname, v.relname_length).toUpper() + QLatin1String("' "
- "AND a.RDB$FIELD_NAME = '") + QString::fromLatin1(v.sqlname, v.sqlname_length).toUpper() + QLatin1String("' "));
- if(q.first()) {
- if(v.sqlscale < 0) {
- f.setLength(q.value(0).toInt());
- f.setPrecision(qAbs(q.value(1).toInt()));
- } else {
- f.setLength(q.value(2).toInt());
- f.setPrecision(0);
- }
- f.setRequiredStatus(q.value(3).toBool() ? QSqlField::Required : QSqlField::Optional);
- }
- }
- f.setSqlType(v.sqltype);
- rec.append(f);
- }
- return rec;
-}
-
-QVariant QIBaseResult::handle() const
-{
- Q_D(const QIBaseResult);
- return QVariant(qRegisterMetaType<isc_stmt_handle>("isc_stmt_handle"), &d->stmt);
-}
-
-/*********************************/
-
-QIBaseDriver::QIBaseDriver(QObject * parent)
- : QSqlDriver(*new QIBaseDriverPrivate, parent)
-{
-}
-
-QIBaseDriver::QIBaseDriver(isc_db_handle connection, QObject *parent)
- : QSqlDriver(*new QIBaseDriverPrivate, parent)
-{
- Q_D(QIBaseDriver);
- d->ibase = connection;
- setOpen(true);
- setOpenError(false);
-}
-
-QIBaseDriver::~QIBaseDriver()
-{
-}
-
-bool QIBaseDriver::hasFeature(DriverFeature f) const
-{
- switch (f) {
- case QuerySize:
- case NamedPlaceholders:
- case LastInsertId:
- case BatchOperations:
- case SimpleLocking:
- case FinishQuery:
- case MultipleResultSets:
- case CancelQuery:
- return false;
- case Transactions:
- case PreparedQueries:
- case PositionalPlaceholders:
- case Unicode:
- case BLOB:
- case EventNotifications:
- case LowPrecisionNumbers:
- return true;
- }
- return false;
-}
-
-bool QIBaseDriver::open(const QString & db,
- const QString & user,
- const QString & password,
- const QString & host,
- int port,
- const QString & connOpts)
-{
- Q_D(QIBaseDriver);
- if (isOpen())
- close();
-
- const QStringList opts(connOpts.split(QLatin1Char(';'), QString::SkipEmptyParts));
-
- QString encString;
- QByteArray role;
- for (int i = 0; i < opts.count(); ++i) {
- QString tmp(opts.at(i).simplified());
- int idx;
- if ((idx = tmp.indexOf(QLatin1Char('='))) != -1) {
- QString val = tmp.mid(idx + 1).simplified();
- QString opt = tmp.left(idx).simplified();
- if (opt.toUpper() == QLatin1String("ISC_DPB_LC_CTYPE"))
- encString = val;
- else if (opt.toUpper() == QLatin1String("ISC_DPB_SQL_ROLE_NAME")) {
- role = val.toLocal8Bit();
- role.truncate(255);
- }
- }
- }
-
- // Use UNICODE_FSS when no ISC_DPB_LC_CTYPE is provided
- if (encString.isEmpty())
- encString = QLatin1String("UNICODE_FSS");
- else {
- d->tc = QTextCodec::codecForName(encString.toLocal8Bit());
- if (!d->tc) {
- qWarning("Unsupported encoding: %s. Using UNICODE_FFS for ISC_DPB_LC_CTYPE.", encString.toLocal8Bit().constData());
- encString = QLatin1String("UNICODE_FSS"); // Fallback to UNICODE_FSS
- }
- }
-
- QByteArray enc = encString.toLocal8Bit();
- QByteArray usr = user.toLocal8Bit();
- QByteArray pass = password.toLocal8Bit();
- enc.truncate(255);
- usr.truncate(255);
- pass.truncate(255);
-
- QByteArray ba;
- ba.reserve(usr.length() + pass.length() + enc.length() + role.length() + 9);
- ba.append(char(isc_dpb_version1));
- ba.append(char(isc_dpb_user_name));
- ba.append(char(usr.length()));
- ba.append(usr.data(), usr.length());
- ba.append(char(isc_dpb_password));
- ba.append(char(pass.length()));
- ba.append(pass.data(), pass.length());
- ba.append(char(isc_dpb_lc_ctype));
- ba.append(char(enc.length()));
- ba.append(enc.data(), enc.length());
-
- if (!role.isEmpty()) {
- ba.append(char(isc_dpb_sql_role_name));
- ba.append(char(role.length()));
- ba.append(role.data(), role.length());
- }
-
- QString portString;
- if (port != -1)
- portString = QStringLiteral("/%1").arg(port);
-
- QString ldb;
- if (!host.isEmpty())
- ldb += host + portString + QLatin1Char(':');
- ldb += db;
- isc_attach_database(d->status, 0, const_cast<char *>(ldb.toLocal8Bit().constData()),
- &d->ibase, ba.size(), ba.data());
- if (d->isError(QT_TRANSLATE_NOOP("QIBaseDriver", "Error opening database"),
- QSqlError::ConnectionError)) {
- setOpenError(true);
- return false;
- }
-
- setOpen(true);
- setOpenError(false);
- return true;
-}
-
-void QIBaseDriver::close()
-{
- Q_D(QIBaseDriver);
- if (isOpen()) {
-
- if (d->eventBuffers.size()) {
- ISC_STATUS status[20];
- QMap<QString, QIBaseEventBuffer *>::const_iterator i;
- for (i = d->eventBuffers.constBegin(); i != d->eventBuffers.constEnd(); ++i) {
- QIBaseEventBuffer *eBuffer = i.value();
- eBuffer->subscriptionState = QIBaseEventBuffer::Finished;
- isc_cancel_events(status, &d->ibase, &eBuffer->eventId);
- qFreeEventBuffer(eBuffer);
- }
- d->eventBuffers.clear();
-
-#if defined(FB_API_VER)
- // Workaround for Firebird crash
- QTime timer;
- timer.start();
- while (timer.elapsed() < 500)
- QCoreApplication::processEvents();
-#endif
- }
-
- isc_detach_database(d->status, &d->ibase);
- d->ibase = 0;
- setOpen(false);
- setOpenError(false);
- }
-}
-
-QSqlResult *QIBaseDriver::createResult() const
-{
- return new QIBaseResult(this);
-}
-
-bool QIBaseDriver::beginTransaction()
-{
- Q_D(QIBaseDriver);
- if (!isOpen() || isOpenError())
- return false;
- if (d->trans)
- return false;
-
- isc_start_transaction(d->status, &d->trans, 1, &d->ibase, 0, NULL);
- return !d->isError(QT_TRANSLATE_NOOP("QIBaseDriver", "Could not start transaction"),
- QSqlError::TransactionError);
-}
-
-bool QIBaseDriver::commitTransaction()
-{
- Q_D(QIBaseDriver);
- if (!isOpen() || isOpenError())
- return false;
- if (!d->trans)
- return false;
-
- isc_commit_transaction(d->status, &d->trans);
- d->trans = 0;
- return !d->isError(QT_TRANSLATE_NOOP("QIBaseDriver", "Unable to commit transaction"),
- QSqlError::TransactionError);
-}
-
-bool QIBaseDriver::rollbackTransaction()
-{
- Q_D(QIBaseDriver);
- if (!isOpen() || isOpenError())
- return false;
- if (!d->trans)
- return false;
-
- isc_rollback_transaction(d->status, &d->trans);
- d->trans = 0;
- return !d->isError(QT_TRANSLATE_NOOP("QIBaseDriver", "Unable to rollback transaction"),
- QSqlError::TransactionError);
-}
-
-QStringList QIBaseDriver::tables(QSql::TableType type) const
-{
- QStringList res;
- if (!isOpen())
- return res;
-
- QString typeFilter;
-
- if (type == QSql::SystemTables) {
- typeFilter += QLatin1String("RDB$SYSTEM_FLAG != 0");
- } else if (type == (QSql::SystemTables | QSql::Views)) {
- typeFilter += QLatin1String("RDB$SYSTEM_FLAG != 0 OR RDB$VIEW_BLR NOT NULL");
- } else {
- if (!(type & QSql::SystemTables))
- typeFilter += QLatin1String("RDB$SYSTEM_FLAG = 0 AND ");
- if (!(type & QSql::Views))
- typeFilter += QLatin1String("RDB$VIEW_BLR IS NULL AND ");
- if (!(type & QSql::Tables))
- typeFilter += QLatin1String("RDB$VIEW_BLR IS NOT NULL AND ");
- if (!typeFilter.isEmpty())
- typeFilter.chop(5);
- }
- if (!typeFilter.isEmpty())
- typeFilter.prepend(QLatin1String("where "));
-
- QSqlQuery q(createResult());
- q.setForwardOnly(true);
- if (!q.exec(QLatin1String("select rdb$relation_name from rdb$relations ") + typeFilter))
- return res;
- while(q.next())
- res << q.value(0).toString().simplified();
-
- return res;
-}
-
-QSqlRecord QIBaseDriver::record(const QString& tablename) const
-{
- QSqlRecord rec;
- if (!isOpen())
- return rec;
-
- QSqlQuery q(createResult());
- q.setForwardOnly(true);
- QString table = tablename;
- if (isIdentifierEscaped(table, QSqlDriver::TableName))
- table = stripDelimiters(table, QSqlDriver::TableName);
- else
- table = table.toUpper();
- q.exec(QLatin1String("SELECT a.RDB$FIELD_NAME, b.RDB$FIELD_TYPE, b.RDB$FIELD_LENGTH, "
- "b.RDB$FIELD_SCALE, b.RDB$FIELD_PRECISION, a.RDB$NULL_FLAG "
- "FROM RDB$RELATION_FIELDS a, RDB$FIELDS b "
- "WHERE b.RDB$FIELD_NAME = a.RDB$FIELD_SOURCE "
- "AND a.RDB$RELATION_NAME = '") + table + QLatin1String("' "
- "ORDER BY a.RDB$FIELD_POSITION"));
-
- while (q.next()) {
- int type = q.value(1).toInt();
- bool hasScale = q.value(3).toInt() < 0;
- QSqlField f(q.value(0).toString().simplified(), qIBaseTypeName(type, hasScale));
- if(hasScale) {
- f.setLength(q.value(4).toInt());
- f.setPrecision(qAbs(q.value(3).toInt()));
- } else {
- f.setLength(q.value(2).toInt());
- f.setPrecision(0);
- }
- f.setRequired(q.value(5).toInt() > 0);
- f.setSqlType(type);
-
- rec.append(f);
- }
- return rec;
-}
-
-QSqlIndex QIBaseDriver::primaryIndex(const QString &table) const
-{
- QSqlIndex index(table);
- if (!isOpen())
- return index;
-
- QString tablename = table;
- if (isIdentifierEscaped(tablename, QSqlDriver::TableName))
- tablename = stripDelimiters(tablename, QSqlDriver::TableName);
- else
- tablename = tablename.toUpper();
-
- QSqlQuery q(createResult());
- q.setForwardOnly(true);
- q.exec(QLatin1String("SELECT a.RDB$INDEX_NAME, b.RDB$FIELD_NAME, d.RDB$FIELD_TYPE, d.RDB$FIELD_SCALE "
- "FROM RDB$RELATION_CONSTRAINTS a, RDB$INDEX_SEGMENTS b, RDB$RELATION_FIELDS c, RDB$FIELDS d "
- "WHERE a.RDB$CONSTRAINT_TYPE = 'PRIMARY KEY' "
- "AND a.RDB$RELATION_NAME = '") + tablename +
- QLatin1String(" 'AND a.RDB$INDEX_NAME = b.RDB$INDEX_NAME "
- "AND c.RDB$RELATION_NAME = a.RDB$RELATION_NAME "
- "AND c.RDB$FIELD_NAME = b.RDB$FIELD_NAME "
- "AND d.RDB$FIELD_NAME = c.RDB$FIELD_SOURCE "
- "ORDER BY b.RDB$FIELD_POSITION"));
-
- while (q.next()) {
- QSqlField field(q.value(1).toString().simplified(), qIBaseTypeName(q.value(2).toInt(), q.value(3).toInt() < 0));
- index.append(field); //TODO: asc? desc?
- index.setName(q.value(0).toString());
- }
-
- return index;
-}
-
-QString QIBaseDriver::formatValue(const QSqlField &field, bool trimStrings) const
-{
- switch (field.type()) {
- case QVariant::DateTime: {
- QDateTime datetime = field.value().toDateTime();
- if (datetime.isValid())
- return QLatin1Char('\'') + QString::number(datetime.date().year()) + QLatin1Char('-') +
- QString::number(datetime.date().month()) + QLatin1Char('-') +
- QString::number(datetime.date().day()) + QLatin1Char(' ') +
- QString::number(datetime.time().hour()) + QLatin1Char(':') +
- QString::number(datetime.time().minute()) + QLatin1Char(':') +
- QString::number(datetime.time().second()) + QLatin1Char('.') +
- QString::number(datetime.time().msec()).rightJustified(3, QLatin1Char('0'), true) +
- QLatin1Char('\'');
- else
- return QLatin1String("NULL");
- }
- case QVariant::Time: {
- QTime time = field.value().toTime();
- if (time.isValid())
- return QLatin1Char('\'') + QString::number(time.hour()) + QLatin1Char(':') +
- QString::number(time.minute()) + QLatin1Char(':') +
- QString::number(time.second()) + QLatin1Char('.') +
- QString::number(time.msec()).rightJustified(3, QLatin1Char('0'), true) +
- QLatin1Char('\'');
- else
- return QLatin1String("NULL");
- }
- case QVariant::Date: {
- QDate date = field.value().toDate();
- if (date.isValid())
- return QLatin1Char('\'') + QString::number(date.year()) + QLatin1Char('-') +
- QString::number(date.month()) + QLatin1Char('-') +
- QString::number(date.day()) + QLatin1Char('\'');
- else
- return QLatin1String("NULL");
- }
- default:
- return QSqlDriver::formatValue(field, trimStrings);
- }
-}
-
-QVariant QIBaseDriver::handle() const
-{
- Q_D(const QIBaseDriver);
- return QVariant(qRegisterMetaType<isc_db_handle>("isc_db_handle"), &d->ibase);
-}
-
-#if defined(FB_API_VER) && FB_API_VER >= 20
-static ISC_EVENT_CALLBACK qEventCallback(char *result, ISC_USHORT length, const ISC_UCHAR *updated)
-#else
-static isc_callback qEventCallback(char *result, short length, char *updated)
-#endif
-{
- if (!updated)
- return 0;
-
-
- memcpy(result, updated, length);
- qMutex()->lock();
- QIBaseDriver *driver = qBufferDriverMap()->value(result);
- qMutex()->unlock();
-
- // We use an asynchronous call (i.e., queued connection) because the event callback
- // is executed in a different thread than the one in which the driver lives.
- if (driver)
- QMetaObject::invokeMethod(driver, "qHandleEventNotification", Qt::QueuedConnection, Q_ARG(void *, reinterpret_cast<void *>(result)));
-
- return 0;
-}
-
-bool QIBaseDriver::subscribeToNotification(const QString &name)
-{
- Q_D(QIBaseDriver);
- if (!isOpen()) {
- qWarning("QIBaseDriver::subscribeFromNotificationImplementation: database not open.");
- return false;
- }
-
- if (d->eventBuffers.contains(name)) {
- qWarning("QIBaseDriver::subscribeToNotificationImplementation: already subscribing to '%s'.",
- qPrintable(name));
- return false;
- }
-
- QIBaseEventBuffer *eBuffer = new QIBaseEventBuffer;
- eBuffer->subscriptionState = QIBaseEventBuffer::Starting;
- eBuffer->bufferLength = isc_event_block(&eBuffer->eventBuffer,
- &eBuffer->resultBuffer,
- 1,
- name.toLocal8Bit().constData());
-
- qMutex()->lock();
- qBufferDriverMap()->insert(eBuffer->resultBuffer, this);
- qMutex()->unlock();
-
- d->eventBuffers.insert(name, eBuffer);
-
- ISC_STATUS status[20];
- isc_que_events(status,
- &d->ibase,
- &eBuffer->eventId,
- eBuffer->bufferLength,
- eBuffer->eventBuffer,
-#if defined (FB_API_VER) && FB_API_VER >= 20
- (ISC_EVENT_CALLBACK)qEventCallback,
-#else
- (isc_callback)qEventCallback,
-#endif
- eBuffer->resultBuffer);
-
- if (status[0] == 1 && status[1]) {
- setLastError(QSqlError(QString::fromLatin1("Could not subscribe to event notifications for %1.").arg(name)));
- d->eventBuffers.remove(name);
- qFreeEventBuffer(eBuffer);
- return false;
- }
-
- return true;
-}
-
-bool QIBaseDriver::unsubscribeFromNotification(const QString &name)
-{
- Q_D(QIBaseDriver);
- if (!isOpen()) {
- qWarning("QIBaseDriver::unsubscribeFromNotificationImplementation: database not open.");
- return false;
- }
-
- if (!d->eventBuffers.contains(name)) {
- qWarning("QIBaseDriver::QIBaseSubscriptionState not subscribed to '%s'.",
- qPrintable(name));
- return false;
- }
-
- QIBaseEventBuffer *eBuffer = d->eventBuffers.value(name);
- ISC_STATUS status[20];
- eBuffer->subscriptionState = QIBaseEventBuffer::Finished;
- isc_cancel_events(status, &d->ibase, &eBuffer->eventId);
-
- if (status[0] == 1 && status[1]) {
- setLastError(QSqlError(QString::fromLatin1("Could not unsubscribe from event notifications for %1.").arg(name)));
- return false;
- }
-
- d->eventBuffers.remove(name);
- qFreeEventBuffer(eBuffer);
-
- return true;
-}
-
-QStringList QIBaseDriver::subscribedToNotifications() const
-{
- Q_D(const QIBaseDriver);
- return QStringList(d->eventBuffers.keys());
-}
-
-void QIBaseDriver::qHandleEventNotification(void *updatedResultBuffer)
-{
- Q_D(QIBaseDriver);
- QMap<QString, QIBaseEventBuffer *>::const_iterator i;
- for (i = d->eventBuffers.constBegin(); i != d->eventBuffers.constEnd(); ++i) {
- QIBaseEventBuffer* eBuffer = i.value();
- if (reinterpret_cast<void *>(eBuffer->resultBuffer) != updatedResultBuffer)
- continue;
-
- ISC_ULONG counts[20];
- memset(counts, 0, sizeof(counts));
- isc_event_counts(counts, eBuffer->bufferLength, eBuffer->eventBuffer, eBuffer->resultBuffer);
- if (counts[0]) {
-
- if (eBuffer->subscriptionState == QIBaseEventBuffer::Subscribed) {
- emit notification(i.key());
- emit notification(i.key(), QSqlDriver::UnknownSource, QVariant());
- }
- else if (eBuffer->subscriptionState == QIBaseEventBuffer::Starting)
- eBuffer->subscriptionState = QIBaseEventBuffer::Subscribed;
-
- ISC_STATUS status[20];
- isc_que_events(status,
- &d->ibase,
- &eBuffer->eventId,
- eBuffer->bufferLength,
- eBuffer->eventBuffer,
-#if defined (FB_API_VER) && FB_API_VER >= 20
- (ISC_EVENT_CALLBACK)qEventCallback,
-#else
- (isc_callback)qEventCallback,
-#endif
- eBuffer->resultBuffer);
- if (Q_UNLIKELY(status[0] == 1 && status[1])) {
- qCritical("QIBaseDriver::qHandleEventNotification: could not resubscribe to '%s'",
- qPrintable(i.key()));
- }
-
- return;
- }
- }
-}
-
-QString QIBaseDriver::escapeIdentifier(const QString &identifier, IdentifierType) const
-{
- QString res = identifier;
- if(!identifier.isEmpty() && !identifier.startsWith(QLatin1Char('"')) && !identifier.endsWith(QLatin1Char('"')) ) {
- res.replace(QLatin1Char('"'), QLatin1String("\"\""));
- res.prepend(QLatin1Char('"')).append(QLatin1Char('"'));
- res.replace(QLatin1Char('.'), QLatin1String("\".\""));
- }
- return res;
-}
-
-QT_END_NAMESPACE
diff --git a/src/sql/drivers/ibase/qsql_ibase.pri b/src/sql/drivers/ibase/qsql_ibase.pri
deleted file mode 100644
index ef3b68d34e..0000000000
--- a/src/sql/drivers/ibase/qsql_ibase.pri
+++ /dev/null
@@ -1,10 +0,0 @@
-HEADERS += $$PWD/qsql_ibase_p.h
-SOURCES += $$PWD/qsql_ibase.cpp
-
-unix {
- !contains(LIBS, .*gds.*):!contains(LIBS, .*libfb.*):LIBS += -lgds
-} else {
- !contains(LIBS, .*gds.*):!contains(LIBS, .*fbclient.*) {
- LIBS += -lgds32_ms
- }
-}
diff --git a/src/sql/drivers/ibase/qsql_ibase_p.h b/src/sql/drivers/ibase/qsql_ibase_p.h
deleted file mode 100644
index c7cee41462..0000000000
--- a/src/sql/drivers/ibase/qsql_ibase_p.h
+++ /dev/null
@@ -1,114 +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_IBASE_H
-#define QSQL_IBASE_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>
-#include <ibase.h>
-
-#ifdef QT_PLUGIN
-#define Q_EXPORT_SQLDRIVER_IBASE
-#else
-#define Q_EXPORT_SQLDRIVER_IBASE Q_SQL_EXPORT
-#endif
-
-QT_BEGIN_NAMESPACE
-
-class QSqlResult;
-class QIBaseDriverPrivate;
-
-class Q_EXPORT_SQLDRIVER_IBASE QIBaseDriver : public QSqlDriver
-{
- friend class QIBaseResultPrivate;
- Q_DECLARE_PRIVATE(QIBaseDriver)
- Q_OBJECT
-public:
- explicit QIBaseDriver(QObject *parent = 0);
- explicit QIBaseDriver(isc_db_handle connection, QObject *parent = 0);
- virtual ~QIBaseDriver();
- bool hasFeature(DriverFeature f) const Q_DECL_OVERRIDE;
- bool open(const QString &db,
- const QString &user,
- const QString &password,
- const QString &host,
- int port,
- const QString &connOpts) Q_DECL_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() Q_DECL_OVERRIDE;
- QSqlResult *createResult() const Q_DECL_OVERRIDE;
- bool beginTransaction() Q_DECL_OVERRIDE;
- bool commitTransaction() Q_DECL_OVERRIDE;
- bool rollbackTransaction() Q_DECL_OVERRIDE;
- QStringList tables(QSql::TableType) const Q_DECL_OVERRIDE;
-
- QSqlRecord record(const QString& tablename) const Q_DECL_OVERRIDE;
- QSqlIndex primaryIndex(const QString &table) const Q_DECL_OVERRIDE;
-
- QString formatValue(const QSqlField &field, bool trimStrings) const Q_DECL_OVERRIDE;
- QVariant handle() const Q_DECL_OVERRIDE;
-
- QString escapeIdentifier(const QString &identifier, IdentifierType type) const Q_DECL_OVERRIDE;
-
- bool subscribeToNotification(const QString &name) Q_DECL_OVERRIDE;
- bool unsubscribeFromNotification(const QString &name) Q_DECL_OVERRIDE;
- QStringList subscribedToNotifications() const Q_DECL_OVERRIDE;
-
-private Q_SLOTS:
- void qHandleEventNotification(void* updatedResultBuffer);
-};
-
-QT_END_NAMESPACE
-
-#endif // QSQL_IBASE_H
diff --git a/src/sql/drivers/mysql/qsql_mysql.cpp b/src/sql/drivers/mysql/qsql_mysql.cpp
deleted file mode 100644
index 56caf52dcb..0000000000
--- a/src/sql/drivers/mysql/qsql_mysql.cpp
+++ /dev/null
@@ -1,1665 +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_mysql_p.h"
-
-#include <qcoreapplication.h>
-#include <qvariant.h>
-#include <qdatetime.h>
-#include <qsqlerror.h>
-#include <qsqlfield.h>
-#include <qsqlindex.h>
-#include <qsqlquery.h>
-#include <qsqlrecord.h>
-#include <qstringlist.h>
-#include <qtextcodec.h>
-#include <qvector.h>
-#include <qfile.h>
-#include <qdebug.h>
-#include <QtSql/private/qsqldriver_p.h>
-#include <QtSql/private/qsqlresult_p.h>
-
-#ifdef Q_OS_WIN32
-// comment the next line out if you want to use MySQL/embedded on Win32 systems.
-// note that it will crash if you don't statically link to the mysql/e library!
-# define Q_NO_MYSQL_EMBEDDED
-#endif
-
-Q_DECLARE_METATYPE(MYSQL_RES*)
-Q_DECLARE_METATYPE(MYSQL*)
-
-#if MYSQL_VERSION_ID >= 40108
-Q_DECLARE_METATYPE(MYSQL_STMT*)
-#endif
-
-#if MYSQL_VERSION_ID >= 40100
-# define Q_CLIENT_MULTI_STATEMENTS CLIENT_MULTI_STATEMENTS
-#else
-# define Q_CLIENT_MULTI_STATEMENTS 0
-#endif
-
-QT_BEGIN_NAMESPACE
-
-class QMYSQLDriverPrivate : public QSqlDriverPrivate
-{
- Q_DECLARE_PUBLIC(QMYSQLDriver)
-
-public:
- QMYSQLDriverPrivate() : QSqlDriverPrivate(), mysql(0),
-#ifndef QT_NO_TEXTCODEC
- tc(QTextCodec::codecForLocale()),
-#else
- tc(0),
-#endif
- preparedQuerysEnabled(false) { dbmsType = QSqlDriver::MySqlServer; }
- MYSQL *mysql;
- QTextCodec *tc;
-
- bool preparedQuerysEnabled;
-};
-
-static inline QString toUnicode(QTextCodec *tc, const char *str)
-{
-#ifdef QT_NO_TEXTCODEC
- Q_UNUSED(tc);
- return QString::fromLatin1(str);
-#else
- return tc->toUnicode(str);
-#endif
-}
-
-static inline QString toUnicode(QTextCodec *tc, const char *str, int length)
-{
-#ifdef QT_NO_TEXTCODEC
- Q_UNUSED(tc);
- return QString::fromLatin1(str, length);
-#else
- return tc->toUnicode(str, length);
-#endif
-}
-
-static inline QByteArray fromUnicode(QTextCodec *tc, const QString &str)
-{
-#ifdef QT_NO_TEXTCODEC
- Q_UNUSED(tc);
- return str.toLatin1();
-#else
- return tc->fromUnicode(str);
-#endif
-}
-
-static inline QVariant qDateFromString(const QString &val)
-{
-#ifdef QT_NO_DATESTRING
- Q_UNUSED(val);
- return QVariant(val);
-#else
- if (val.isEmpty())
- return QVariant(QDate());
- return QVariant(QDate::fromString(val, Qt::ISODate));
-#endif
-}
-
-static inline QVariant qTimeFromString(const QString &val)
-{
-#ifdef QT_NO_DATESTRING
- Q_UNUSED(val);
- return QVariant(val);
-#else
- if (val.isEmpty())
- return QVariant(QTime());
- return QVariant(QTime::fromString(val, Qt::ISODate));
-#endif
-}
-
-static inline QVariant qDateTimeFromString(QString &val)
-{
-#ifdef QT_NO_DATESTRING
- Q_UNUSED(val);
- return QVariant(val);
-#else
- if (val.isEmpty())
- return QVariant(QDateTime());
- if (val.length() == 14)
- // TIMESTAMPS have the format yyyyMMddhhmmss
- val.insert(4, QLatin1Char('-')).insert(7, QLatin1Char('-')).insert(10,
- QLatin1Char('T')).insert(13, QLatin1Char(':')).insert(16, QLatin1Char(':'));
- return QVariant(QDateTime::fromString(val, Qt::ISODate));
-#endif
-}
-
-class QMYSQLResultPrivate;
-
-class QMYSQLResult : public QSqlResult
-{
- Q_DECLARE_PRIVATE(QMYSQLResult)
- friend class QMYSQLDriver;
-
-public:
- explicit QMYSQLResult(const QMYSQLDriver *db);
- ~QMYSQLResult();
-
- QVariant handle() const Q_DECL_OVERRIDE;
-protected:
- void cleanup();
- bool fetch(int i) Q_DECL_OVERRIDE;
- bool fetchNext() Q_DECL_OVERRIDE;
- bool fetchLast() Q_DECL_OVERRIDE;
- bool fetchFirst() Q_DECL_OVERRIDE;
- QVariant data(int field) Q_DECL_OVERRIDE;
- bool isNull(int field) Q_DECL_OVERRIDE;
- bool reset (const QString& query) Q_DECL_OVERRIDE;
- int size() Q_DECL_OVERRIDE;
- int numRowsAffected() Q_DECL_OVERRIDE;
- QVariant lastInsertId() const Q_DECL_OVERRIDE;
- QSqlRecord record() const Q_DECL_OVERRIDE;
- void virtual_hook(int id, void *data) Q_DECL_OVERRIDE;
- bool nextResult() Q_DECL_OVERRIDE;
-
-#if MYSQL_VERSION_ID >= 40108
- bool prepare(const QString &stmt) Q_DECL_OVERRIDE;
- bool exec() Q_DECL_OVERRIDE;
-#endif
-};
-
-class QMYSQLResultPrivate: public QSqlResultPrivate
-{
- Q_DECLARE_PUBLIC(QMYSQLResult)
-
-public:
- Q_DECLARE_SQLDRIVER_PRIVATE(QMYSQLDriver)
-
- QMYSQLResultPrivate(QMYSQLResult *q, const QMYSQLDriver *drv)
- : QSqlResultPrivate(q, drv),
- result(0),
- rowsAffected(0),
- hasBlobs(false)
-#if MYSQL_VERSION_ID >= 40108
- , stmt(0), meta(0), inBinds(0), outBinds(0)
-#endif
- , preparedQuery(false)
- { }
-
- MYSQL_RES *result;
- MYSQL_ROW row;
-
- int rowsAffected;
-
- bool bindInValues();
- void bindBlobs();
-
- bool hasBlobs;
- struct QMyField
- {
- QMyField()
- : outField(0), nullIndicator(false), bufLength(0ul),
- myField(0), type(QVariant::Invalid)
- {}
- char *outField;
- my_bool nullIndicator;
- ulong bufLength;
- MYSQL_FIELD *myField;
- QVariant::Type type;
- };
-
- QVector<QMyField> fields;
-
-#if MYSQL_VERSION_ID >= 40108
- MYSQL_STMT* stmt;
- MYSQL_RES* meta;
-
- MYSQL_BIND *inBinds;
- MYSQL_BIND *outBinds;
-#endif
-
- bool preparedQuery;
-};
-
-#ifndef QT_NO_TEXTCODEC
-static QTextCodec* codec(MYSQL* mysql)
-{
-#if MYSQL_VERSION_ID >= 32321
- QTextCodec* heuristicCodec = QTextCodec::codecForName(mysql_character_set_name(mysql));
- if (heuristicCodec)
- return heuristicCodec;
-#endif
- return QTextCodec::codecForLocale();
-}
-#endif // QT_NO_TEXTCODEC
-
-static QSqlError qMakeError(const QString& err, QSqlError::ErrorType type,
- const QMYSQLDriverPrivate* p)
-{
- const char *cerr = p->mysql ? mysql_error(p->mysql) : 0;
- return QSqlError(QLatin1String("QMYSQL: ") + err,
- p->tc ? toUnicode(p->tc, cerr) : QString::fromLatin1(cerr),
- type, mysql_errno(p->mysql));
-}
-
-
-static QVariant::Type qDecodeMYSQLType(int mysqltype, uint flags)
-{
- QVariant::Type type;
- switch (mysqltype) {
- case FIELD_TYPE_TINY :
- type = static_cast<QVariant::Type>((flags & UNSIGNED_FLAG) ? QMetaType::UChar : QMetaType::Char);
- break;
- case FIELD_TYPE_SHORT :
- type = static_cast<QVariant::Type>((flags & UNSIGNED_FLAG) ? QMetaType::UShort : QMetaType::Short);
- break;
- case FIELD_TYPE_LONG :
- case FIELD_TYPE_INT24 :
- type = (flags & UNSIGNED_FLAG) ? QVariant::UInt : QVariant::Int;
- break;
- case FIELD_TYPE_YEAR :
- type = QVariant::Int;
- break;
- case FIELD_TYPE_LONGLONG :
- type = (flags & UNSIGNED_FLAG) ? QVariant::ULongLong : QVariant::LongLong;
- break;
- case FIELD_TYPE_FLOAT :
- case FIELD_TYPE_DOUBLE :
- case FIELD_TYPE_DECIMAL :
-#if defined(FIELD_TYPE_NEWDECIMAL)
- case FIELD_TYPE_NEWDECIMAL:
-#endif
- type = QVariant::Double;
- break;
- case FIELD_TYPE_DATE :
- type = QVariant::Date;
- break;
- case FIELD_TYPE_TIME :
- type = QVariant::Time;
- break;
- case FIELD_TYPE_DATETIME :
- case FIELD_TYPE_TIMESTAMP :
- type = QVariant::DateTime;
- break;
- case FIELD_TYPE_STRING :
- case FIELD_TYPE_VAR_STRING :
- case FIELD_TYPE_BLOB :
- case FIELD_TYPE_TINY_BLOB :
- case FIELD_TYPE_MEDIUM_BLOB :
- case FIELD_TYPE_LONG_BLOB :
- type = (flags & BINARY_FLAG) ? QVariant::ByteArray : QVariant::String;
- break;
- default:
- case FIELD_TYPE_ENUM :
- case FIELD_TYPE_SET :
- type = QVariant::String;
- break;
- }
- return type;
-}
-
-static QSqlField qToField(MYSQL_FIELD *field, QTextCodec *tc)
-{
- QSqlField f(toUnicode(tc, field->name),
- qDecodeMYSQLType(int(field->type), field->flags));
- f.setRequired(IS_NOT_NULL(field->flags));
- f.setLength(field->length);
- f.setPrecision(field->decimals);
- f.setSqlType(field->type);
- f.setAutoValue(field->flags & AUTO_INCREMENT_FLAG);
- return f;
-}
-
-#if MYSQL_VERSION_ID >= 40108
-
-static QSqlError qMakeStmtError(const QString& err, QSqlError::ErrorType type,
- MYSQL_STMT* stmt)
-{
- const char *cerr = mysql_stmt_error(stmt);
- return QSqlError(QLatin1String("QMYSQL3: ") + err,
- QString::fromLatin1(cerr),
- type, mysql_stmt_errno(stmt));
-}
-
-static bool qIsBlob(int t)
-{
- return t == MYSQL_TYPE_TINY_BLOB
- || t == MYSQL_TYPE_BLOB
- || t == MYSQL_TYPE_MEDIUM_BLOB
- || t == MYSQL_TYPE_LONG_BLOB;
-}
-
-static bool qIsInteger(int t)
-{
- return t == QMetaType::Char || t == QMetaType::UChar
- || t == QMetaType::Short || t == QMetaType::UShort
- || t == QMetaType::Int || t == QMetaType::UInt
- || t == QMetaType::LongLong || t == QMetaType::ULongLong;
-}
-
-void QMYSQLResultPrivate::bindBlobs()
-{
- int i;
- MYSQL_FIELD *fieldInfo;
- MYSQL_BIND *bind;
-
- for(i = 0; i < fields.count(); ++i) {
- fieldInfo = fields.at(i).myField;
- if (qIsBlob(inBinds[i].buffer_type) && meta && fieldInfo) {
- bind = &inBinds[i];
- bind->buffer_length = fieldInfo->max_length;
- delete[] static_cast<char*>(bind->buffer);
- bind->buffer = new char[fieldInfo->max_length];
- fields[i].outField = static_cast<char*>(bind->buffer);
- }
- }
-}
-
-bool QMYSQLResultPrivate::bindInValues()
-{
- MYSQL_BIND *bind;
- char *field;
- int i = 0;
-
- if (!meta)
- meta = mysql_stmt_result_metadata(stmt);
- if (!meta)
- return false;
-
- fields.resize(mysql_num_fields(meta));
-
- inBinds = new MYSQL_BIND[fields.size()];
- memset(inBinds, 0, fields.size() * sizeof(MYSQL_BIND));
-
- MYSQL_FIELD *fieldInfo;
-
- while((fieldInfo = mysql_fetch_field(meta))) {
- QMyField &f = fields[i];
- f.myField = fieldInfo;
-
- f.type = qDecodeMYSQLType(fieldInfo->type, fieldInfo->flags);
- if (qIsBlob(fieldInfo->type)) {
- // the size of a blob-field is available as soon as we call
- // mysql_stmt_store_result()
- // after mysql_stmt_exec() in QMYSQLResult::exec()
- fieldInfo->length = 0;
- hasBlobs = true;
- } else if (qIsInteger(f.type)) {
- fieldInfo->length = 8;
- } else {
- fieldInfo->type = MYSQL_TYPE_STRING;
- }
- bind = &inBinds[i];
- field = new char[fieldInfo->length + 1];
- memset(field, 0, fieldInfo->length + 1);
-
- bind->buffer_type = fieldInfo->type;
- bind->buffer = field;
- bind->buffer_length = f.bufLength = fieldInfo->length + 1;
- bind->is_null = &f.nullIndicator;
- bind->length = &f.bufLength;
- f.outField=field;
-
- ++i;
- }
- return true;
-}
-#endif
-
-QMYSQLResult::QMYSQLResult(const QMYSQLDriver* db)
- : QSqlResult(*new QMYSQLResultPrivate(this, db))
-{
-}
-
-QMYSQLResult::~QMYSQLResult()
-{
- cleanup();
-}
-
-QVariant QMYSQLResult::handle() const
-{
- Q_D(const QMYSQLResult);
-#if MYSQL_VERSION_ID >= 40108
- if(d->preparedQuery)
- return d->meta ? QVariant::fromValue(d->meta) : QVariant::fromValue(d->stmt);
- else
-#endif
- return QVariant::fromValue(d->result);
-}
-
-void QMYSQLResult::cleanup()
-{
- Q_D(QMYSQLResult);
- if (d->result)
- mysql_free_result(d->result);
-
-// must iterate trough leftover result sets from multi-selects or stored procedures
-// if this isn't done subsequent queries will fail with "Commands out of sync"
-#if MYSQL_VERSION_ID >= 40100
- while (driver() && d->drv_d_func()->mysql && mysql_next_result(d->drv_d_func()->mysql) == 0) {
- MYSQL_RES *res = mysql_store_result(d->drv_d_func()->mysql);
- if (res)
- mysql_free_result(res);
- }
-#endif
-
-#if MYSQL_VERSION_ID >= 40108
- if (d->stmt) {
- if (mysql_stmt_close(d->stmt))
- qWarning("QMYSQLResult::cleanup: unable to free statement handle");
- d->stmt = 0;
- }
-
- if (d->meta) {
- mysql_free_result(d->meta);
- d->meta = 0;
- }
-
- int i;
- for (i = 0; i < d->fields.count(); ++i)
- delete[] d->fields[i].outField;
-
- if (d->outBinds) {
- delete[] d->outBinds;
- d->outBinds = 0;
- }
-
- if (d->inBinds) {
- delete[] d->inBinds;
- d->inBinds = 0;
- }
-#endif
-
- d->hasBlobs = false;
- d->fields.clear();
- d->result = NULL;
- d->row = NULL;
- setAt(-1);
- setActive(false);
-}
-
-bool QMYSQLResult::fetch(int i)
-{
- Q_D(QMYSQLResult);
- if (!driver())
- return false;
- if (isForwardOnly()) { // fake a forward seek
- if (at() < i) {
- int x = i - at();
- while (--x && fetchNext()) {};
- return fetchNext();
- } else {
- return false;
- }
- }
- if (at() == i)
- return true;
- if (d->preparedQuery) {
-#if MYSQL_VERSION_ID >= 40108
- mysql_stmt_data_seek(d->stmt, i);
-
- int nRC = mysql_stmt_fetch(d->stmt);
- if (nRC) {
-#ifdef MYSQL_DATA_TRUNCATED
- if (nRC == 1 || nRC == MYSQL_DATA_TRUNCATED)
-#else
- if (nRC == 1)
-#endif
- setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult",
- "Unable to fetch data"), QSqlError::StatementError, d->stmt));
- return false;
- }
-#else
- return false;
-#endif
- } else {
- mysql_data_seek(d->result, i);
- d->row = mysql_fetch_row(d->result);
- if (!d->row)
- return false;
- }
-
- setAt(i);
- return true;
-}
-
-bool QMYSQLResult::fetchNext()
-{
- Q_D(QMYSQLResult);
- if (!driver())
- return false;
- if (d->preparedQuery) {
-#if MYSQL_VERSION_ID >= 40108
- int nRC = mysql_stmt_fetch(d->stmt);
- if (nRC) {
-#ifdef MYSQL_DATA_TRUNCATED
- if (nRC == 1 || nRC == MYSQL_DATA_TRUNCATED)
-#else
- if (nRC == 1)
-#endif // MYSQL_DATA_TRUNCATED
- setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult",
- "Unable to fetch data"), QSqlError::StatementError, d->stmt));
- return false;
- }
-#else
- return false;
-#endif
- } else {
- d->row = mysql_fetch_row(d->result);
- if (!d->row)
- return false;
- }
- setAt(at() + 1);
- return true;
-}
-
-bool QMYSQLResult::fetchLast()
-{
- Q_D(QMYSQLResult);
- if (!driver())
- return false;
- if (isForwardOnly()) { // fake this since MySQL can't seek on forward only queries
- bool success = fetchNext(); // did we move at all?
- while (fetchNext()) {};
- return success;
- }
-
- my_ulonglong numRows;
- if (d->preparedQuery) {
-#if MYSQL_VERSION_ID >= 40108
- numRows = mysql_stmt_num_rows(d->stmt);
-#else
- numRows = 0;
-#endif
- } else {
- numRows = mysql_num_rows(d->result);
- }
- if (at() == int(numRows))
- return true;
- if (!numRows)
- return false;
- return fetch(numRows - 1);
-}
-
-bool QMYSQLResult::fetchFirst()
-{
- if (at() == 0)
- return true;
-
- if (isForwardOnly())
- return (at() == QSql::BeforeFirstRow) ? fetchNext() : false;
- return fetch(0);
-}
-
-QVariant QMYSQLResult::data(int field)
-{
- Q_D(QMYSQLResult);
- if (!isSelect() || field >= d->fields.count()) {
- qWarning("QMYSQLResult::data: column %d out of range", field);
- return QVariant();
- }
-
- if (!driver())
- return QVariant();
-
- int fieldLength = 0;
- const QMYSQLResultPrivate::QMyField &f = d->fields.at(field);
- QString val;
- if (d->preparedQuery) {
- if (f.nullIndicator)
- return QVariant(f.type);
-
- if (qIsInteger(f.type))
- return QVariant(f.type, f.outField);
-
- if (f.type != QVariant::ByteArray)
- val = toUnicode(d->drv_d_func()->tc, f.outField, f.bufLength);
- } else {
- if (d->row[field] == NULL) {
- // NULL value
- return QVariant(f.type);
- }
-
- fieldLength = mysql_fetch_lengths(d->result)[field];
-
- if (f.type != QVariant::ByteArray)
- val = toUnicode(d->drv_d_func()->tc, d->row[field], fieldLength);
- }
-
- switch (static_cast<int>(f.type)) {
- case QVariant::LongLong:
- return QVariant(val.toLongLong());
- case QVariant::ULongLong:
- return QVariant(val.toULongLong());
- case QMetaType::Char:
- case QMetaType::Short:
- case QVariant::Int:
- return QVariant(val.toInt());
- case QMetaType::UChar:
- case QMetaType::UShort:
- case QVariant::UInt:
- return QVariant(val.toUInt());
- case QVariant::Double: {
- QVariant v;
- bool ok=false;
- double dbl = val.toDouble(&ok);
- switch(numericalPrecisionPolicy()) {
- case QSql::LowPrecisionInt32:
- v=QVariant(dbl).toInt();
- break;
- case QSql::LowPrecisionInt64:
- v = QVariant(dbl).toLongLong();
- break;
- case QSql::LowPrecisionDouble:
- v = QVariant(dbl);
- break;
- case QSql::HighPrecision:
- default:
- v = val;
- ok = true;
- break;
- }
- if(ok)
- return v;
- else
- return QVariant();
- }
- return QVariant(val.toDouble());
- case QVariant::Date:
- return qDateFromString(val);
- case QVariant::Time:
- return qTimeFromString(val);
- case QVariant::DateTime:
- return qDateTimeFromString(val);
- case QVariant::ByteArray: {
-
- QByteArray ba;
- if (d->preparedQuery) {
- ba = QByteArray(f.outField, f.bufLength);
- } else {
- ba = QByteArray(d->row[field], fieldLength);
- }
- return QVariant(ba);
- }
- default:
- case QVariant::String:
- return QVariant(val);
- }
- qWarning("QMYSQLResult::data: unknown data type");
- return QVariant();
-}
-
-bool QMYSQLResult::isNull(int field)
-{
- Q_D(const QMYSQLResult);
- if (field < 0 || field >= d->fields.count())
- return true;
- if (d->preparedQuery)
- return d->fields.at(field).nullIndicator;
- else
- return d->row[field] == NULL;
-}
-
-bool QMYSQLResult::reset (const QString& query)
-{
- Q_D(QMYSQLResult);
- if (!driver() || !driver()->isOpen() || driver()->isOpenError())
- return false;
-
- d->preparedQuery = false;
-
- cleanup();
-
- const QByteArray encQuery(fromUnicode(d->drv_d_func()->tc, query));
- if (mysql_real_query(d->drv_d_func()->mysql, encQuery.data(), encQuery.length())) {
- setLastError(qMakeError(QCoreApplication::translate("QMYSQLResult", "Unable to execute query"),
- QSqlError::StatementError, d->drv_d_func()));
- return false;
- }
- d->result = mysql_store_result(d->drv_d_func()->mysql);
- if (!d->result && mysql_field_count(d->drv_d_func()->mysql) > 0) {
- setLastError(qMakeError(QCoreApplication::translate("QMYSQLResult", "Unable to store result"),
- QSqlError::StatementError, d->drv_d_func()));
- return false;
- }
- int numFields = mysql_field_count(d->drv_d_func()->mysql);
- setSelect(numFields != 0);
- d->fields.resize(numFields);
- d->rowsAffected = mysql_affected_rows(d->drv_d_func()->mysql);
-
- if (isSelect()) {
- for(int i = 0; i < numFields; i++) {
- MYSQL_FIELD* field = mysql_fetch_field_direct(d->result, i);
- d->fields[i].type = qDecodeMYSQLType(field->type, field->flags);
- }
- setAt(QSql::BeforeFirstRow);
- }
- setActive(true);
- return isActive();
-}
-
-int QMYSQLResult::size()
-{
- Q_D(const QMYSQLResult);
- if (driver() && isSelect())
- if (d->preparedQuery)
-#if MYSQL_VERSION_ID >= 40108
- return mysql_stmt_num_rows(d->stmt);
-#else
- return -1;
-#endif
- else
- return int(mysql_num_rows(d->result));
- else
- return -1;
-}
-
-int QMYSQLResult::numRowsAffected()
-{
- Q_D(const QMYSQLResult);
- return d->rowsAffected;
-}
-
-QVariant QMYSQLResult::lastInsertId() const
-{
- Q_D(const QMYSQLResult);
- if (!isActive() || !driver())
- return QVariant();
-
- if (d->preparedQuery) {
-#if MYSQL_VERSION_ID >= 40108
- quint64 id = mysql_stmt_insert_id(d->stmt);
- if (id)
- return QVariant(id);
-#endif
- } else {
- quint64 id = mysql_insert_id(d->drv_d_func()->mysql);
- if (id)
- return QVariant(id);
- }
- return QVariant();
-}
-
-QSqlRecord QMYSQLResult::record() const
-{
- Q_D(const QMYSQLResult);
- QSqlRecord info;
- MYSQL_RES *res;
- if (!isActive() || !isSelect() || !driver())
- return info;
-
-#if MYSQL_VERSION_ID >= 40108
- res = d->preparedQuery ? d->meta : d->result;
-#else
- res = d->result;
-#endif
-
- if (!mysql_errno(d->drv_d_func()->mysql)) {
- mysql_field_seek(res, 0);
- MYSQL_FIELD* field = mysql_fetch_field(res);
- while(field) {
- info.append(qToField(field, d->drv_d_func()->tc));
- field = mysql_fetch_field(res);
- }
- }
- mysql_field_seek(res, 0);
- return info;
-}
-
-bool QMYSQLResult::nextResult()
-{
- Q_D(QMYSQLResult);
- if (!driver())
- return false;
-#if MYSQL_VERSION_ID >= 40100
- setAt(-1);
- setActive(false);
-
- if (d->result && isSelect())
- mysql_free_result(d->result);
- d->result = 0;
- setSelect(false);
-
- for (int i = 0; i < d->fields.count(); ++i)
- delete[] d->fields[i].outField;
- d->fields.clear();
-
- int status = mysql_next_result(d->drv_d_func()->mysql);
- if (status > 0) {
- setLastError(qMakeError(QCoreApplication::translate("QMYSQLResult", "Unable to execute next query"),
- QSqlError::StatementError, d->drv_d_func()));
- return false;
- } else if (status == -1) {
- return false; // No more result sets
- }
-
- d->result = mysql_store_result(d->drv_d_func()->mysql);
- int numFields = mysql_field_count(d->drv_d_func()->mysql);
- if (!d->result && numFields > 0) {
- setLastError(qMakeError(QCoreApplication::translate("QMYSQLResult", "Unable to store next result"),
- QSqlError::StatementError, d->drv_d_func()));
- return false;
- }
-
- setSelect(numFields > 0);
- d->fields.resize(numFields);
- d->rowsAffected = mysql_affected_rows(d->drv_d_func()->mysql);
-
- if (isSelect()) {
- for (int i = 0; i < numFields; i++) {
- MYSQL_FIELD* field = mysql_fetch_field_direct(d->result, i);
- d->fields[i].type = qDecodeMYSQLType(field->type, field->flags);
- }
- }
-
- setActive(true);
- return true;
-#else
- return false;
-#endif
-}
-
-void QMYSQLResult::virtual_hook(int id, void *data)
-{
- QSqlResult::virtual_hook(id, data);
-}
-
-
-#if MYSQL_VERSION_ID >= 40108
-
-static MYSQL_TIME *toMySqlDate(QDate date, QTime time, QVariant::Type type)
-{
- Q_ASSERT(type == QVariant::Time || type == QVariant::Date
- || type == QVariant::DateTime);
-
- MYSQL_TIME *myTime = new MYSQL_TIME;
- memset(myTime, 0, sizeof(MYSQL_TIME));
-
- if (type == QVariant::Time || type == QVariant::DateTime) {
- myTime->hour = time.hour();
- myTime->minute = time.minute();
- myTime->second = time.second();
- myTime->second_part = time.msec() * 1000;
- }
- if (type == QVariant::Date || type == QVariant::DateTime) {
- myTime->year = date.year();
- myTime->month = date.month();
- myTime->day = date.day();
- }
-
- return myTime;
-}
-
-bool QMYSQLResult::prepare(const QString& query)
-{
- Q_D(QMYSQLResult);
- if (!driver())
- return false;
-#if MYSQL_VERSION_ID >= 40108
- cleanup();
- if (!d->drv_d_func()->preparedQuerysEnabled)
- return QSqlResult::prepare(query);
-
- int r;
-
- if (query.isEmpty())
- return false;
-
- if (!d->stmt)
- d->stmt = mysql_stmt_init(d->drv_d_func()->mysql);
- if (!d->stmt) {
- setLastError(qMakeError(QCoreApplication::translate("QMYSQLResult", "Unable to prepare statement"),
- QSqlError::StatementError, d->drv_d_func()));
- return false;
- }
-
- const QByteArray encQuery(fromUnicode(d->drv_d_func()->tc, query));
- r = mysql_stmt_prepare(d->stmt, encQuery.constData(), encQuery.length());
- if (r != 0) {
- setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult",
- "Unable to prepare statement"), QSqlError::StatementError, d->stmt));
- cleanup();
- return false;
- }
-
- if (mysql_stmt_param_count(d->stmt) > 0) {// allocate memory for outvalues
- d->outBinds = new MYSQL_BIND[mysql_stmt_param_count(d->stmt)];
- }
-
- setSelect(d->bindInValues());
- d->preparedQuery = true;
- return true;
-#else
- return false;
-#endif
-}
-
-bool QMYSQLResult::exec()
-{
- Q_D(QMYSQLResult);
- if (!driver())
- return false;
- if (!d->preparedQuery)
- return QSqlResult::exec();
- if (!d->stmt)
- return false;
-
- int r = 0;
- MYSQL_BIND* currBind;
- QVector<MYSQL_TIME *> timeVector;
- QVector<QByteArray> stringVector;
- QVector<my_bool> nullVector;
-
- const QVector<QVariant> values = boundValues();
-
- r = mysql_stmt_reset(d->stmt);
- if (r != 0) {
- setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult",
- "Unable to reset statement"), QSqlError::StatementError, d->stmt));
- return false;
- }
-
- if (mysql_stmt_param_count(d->stmt) > 0 &&
- mysql_stmt_param_count(d->stmt) == (uint)values.count()) {
-
- nullVector.resize(values.count());
- for (int i = 0; i < values.count(); ++i) {
- const QVariant &val = boundValues().at(i);
- void *data = const_cast<void *>(val.constData());
-
- currBind = &d->outBinds[i];
-
- nullVector[i] = static_cast<my_bool>(val.isNull());
- currBind->is_null = &nullVector[i];
- currBind->length = 0;
- currBind->is_unsigned = 0;
-
- switch (val.type()) {
- case QVariant::ByteArray:
- currBind->buffer_type = MYSQL_TYPE_BLOB;
- currBind->buffer = const_cast<char *>(val.toByteArray().constData());
- currBind->buffer_length = val.toByteArray().size();
- break;
-
- case QVariant::Time:
- case QVariant::Date:
- case QVariant::DateTime: {
- MYSQL_TIME *myTime = toMySqlDate(val.toDate(), val.toTime(), val.type());
- timeVector.append(myTime);
-
- currBind->buffer = myTime;
- switch(val.type()) {
- case QVariant::Time:
- currBind->buffer_type = MYSQL_TYPE_TIME;
- myTime->time_type = MYSQL_TIMESTAMP_TIME;
- break;
- case QVariant::Date:
- currBind->buffer_type = MYSQL_TYPE_DATE;
- myTime->time_type = MYSQL_TIMESTAMP_DATE;
- break;
- case QVariant::DateTime:
- currBind->buffer_type = MYSQL_TYPE_DATETIME;
- myTime->time_type = MYSQL_TIMESTAMP_DATETIME;
- break;
- default:
- break;
- }
- currBind->buffer_length = sizeof(MYSQL_TIME);
- currBind->length = 0;
- break; }
- case QVariant::UInt:
- case QVariant::Int:
- currBind->buffer_type = MYSQL_TYPE_LONG;
- currBind->buffer = data;
- currBind->buffer_length = sizeof(int);
- currBind->is_unsigned = (val.type() != QVariant::Int);
- break;
- case QVariant::Bool:
- currBind->buffer_type = MYSQL_TYPE_TINY;
- currBind->buffer = data;
- currBind->buffer_length = sizeof(bool);
- currBind->is_unsigned = false;
- break;
- case QVariant::Double:
- currBind->buffer_type = MYSQL_TYPE_DOUBLE;
- currBind->buffer = data;
- currBind->buffer_length = sizeof(double);
- break;
- case QVariant::LongLong:
- case QVariant::ULongLong:
- currBind->buffer_type = MYSQL_TYPE_LONGLONG;
- currBind->buffer = data;
- currBind->buffer_length = sizeof(qint64);
- currBind->is_unsigned = (val.type() == QVariant::ULongLong);
- break;
- case QVariant::String:
- default: {
- QByteArray ba = fromUnicode(d->drv_d_func()->tc, val.toString());
- stringVector.append(ba);
- currBind->buffer_type = MYSQL_TYPE_STRING;
- currBind->buffer = const_cast<char *>(ba.constData());
- currBind->buffer_length = ba.length();
- break; }
- }
- }
-
- r = mysql_stmt_bind_param(d->stmt, d->outBinds);
- if (r != 0) {
- setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult",
- "Unable to bind value"), QSqlError::StatementError, d->stmt));
- qDeleteAll(timeVector);
- return false;
- }
- }
- r = mysql_stmt_execute(d->stmt);
-
- qDeleteAll(timeVector);
-
- if (r != 0) {
- setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult",
- "Unable to execute statement"), QSqlError::StatementError, d->stmt));
- return false;
- }
- //if there is meta-data there is also data
- setSelect(d->meta);
-
- d->rowsAffected = mysql_stmt_affected_rows(d->stmt);
-
- if (isSelect()) {
- my_bool update_max_length = true;
-
- r = mysql_stmt_bind_result(d->stmt, d->inBinds);
- if (r != 0) {
- setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult",
- "Unable to bind outvalues"), QSqlError::StatementError, d->stmt));
- return false;
- }
- if (d->hasBlobs)
- mysql_stmt_attr_set(d->stmt, STMT_ATTR_UPDATE_MAX_LENGTH, &update_max_length);
-
- r = mysql_stmt_store_result(d->stmt);
- if (r != 0) {
- setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult",
- "Unable to store statement results"), QSqlError::StatementError, d->stmt));
- return false;
- }
-
- if (d->hasBlobs) {
- // mysql_stmt_store_result() with STMT_ATTR_UPDATE_MAX_LENGTH set to true crashes
- // when called without a preceding call to mysql_stmt_bind_result()
- // in versions < 4.1.8
- d->bindBlobs();
- r = mysql_stmt_bind_result(d->stmt, d->inBinds);
- if (r != 0) {
- setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult",
- "Unable to bind outvalues"), QSqlError::StatementError, d->stmt));
- return false;
- }
- }
- setAt(QSql::BeforeFirstRow);
- }
- setActive(true);
- return true;
-}
-#endif
-/////////////////////////////////////////////////////////
-
-static int qMySqlConnectionCount = 0;
-static bool qMySqlInitHandledByUser = false;
-
-static void qLibraryInit()
-{
-#ifndef Q_NO_MYSQL_EMBEDDED
-# if MYSQL_VERSION_ID >= 40000
- if (qMySqlInitHandledByUser || qMySqlConnectionCount > 1)
- return;
-
-# if (MYSQL_VERSION_ID >= 40110 && MYSQL_VERSION_ID < 50000) || MYSQL_VERSION_ID >= 50003
- if (mysql_library_init(0, 0, 0)) {
-# else
- if (mysql_server_init(0, 0, 0)) {
-# endif
- qWarning("QMYSQLDriver::qServerInit: unable to start server.");
- }
-# endif // MYSQL_VERSION_ID
-#endif // Q_NO_MYSQL_EMBEDDED
-}
-
-static void qLibraryEnd()
-{
-#ifndef Q_NO_MYSQL_EMBEDDED
-# if MYSQL_VERSION_ID > 40000
-# if (MYSQL_VERSION_ID >= 40110 && MYSQL_VERSION_ID < 50000) || MYSQL_VERSION_ID >= 50003
- mysql_library_end();
-# else
- mysql_server_end();
-# endif
-# endif
-#endif
-}
-
-QMYSQLDriver::QMYSQLDriver(QObject * parent)
- : QSqlDriver(*new QMYSQLDriverPrivate, parent)
-{
- init();
- qLibraryInit();
-}
-
-/*!
- Create a driver instance with the open connection handle, \a con.
- The instance's parent (owner) is \a parent.
-*/
-
-QMYSQLDriver::QMYSQLDriver(MYSQL * con, QObject * parent)
- : QSqlDriver(*new QMYSQLDriverPrivate, parent)
-{
- Q_D(QMYSQLDriver);
- init();
- if (con) {
- d->mysql = (MYSQL *) con;
-#ifndef QT_NO_TEXTCODEC
- d->tc = codec(con);
-#endif
- setOpen(true);
- setOpenError(false);
- if (qMySqlConnectionCount == 1)
- qMySqlInitHandledByUser = true;
- } else {
- qLibraryInit();
- }
-}
-
-void QMYSQLDriver::init()
-{
- Q_D(QMYSQLDriver);
- d->mysql = 0;
- qMySqlConnectionCount++;
-}
-
-QMYSQLDriver::~QMYSQLDriver()
-{
- qMySqlConnectionCount--;
- if (qMySqlConnectionCount == 0 && !qMySqlInitHandledByUser)
- qLibraryEnd();
-}
-
-bool QMYSQLDriver::hasFeature(DriverFeature f) const
-{
- Q_D(const QMYSQLDriver);
- switch (f) {
- case Transactions:
-// CLIENT_TRANSACTION should be defined in all recent mysql client libs > 3.23.34
-#ifdef CLIENT_TRANSACTIONS
- if (d->mysql) {
- if ((d->mysql->server_capabilities & CLIENT_TRANSACTIONS) == CLIENT_TRANSACTIONS)
- return true;
- }
-#endif
- return false;
- case NamedPlaceholders:
- case BatchOperations:
- case SimpleLocking:
- case EventNotifications:
- case FinishQuery:
- case CancelQuery:
- return false;
- case QuerySize:
- case BLOB:
- case LastInsertId:
- case Unicode:
- case LowPrecisionNumbers:
- return true;
- case PreparedQueries:
- case PositionalPlaceholders:
-#if MYSQL_VERSION_ID >= 40108
- return d->preparedQuerysEnabled;
-#else
- return false;
-#endif
- case MultipleResultSets:
-#if MYSQL_VERSION_ID >= 40100
- return true;
-#else
- return false;
-#endif
- }
- return false;
-}
-
-static void setOptionFlag(uint &optionFlags, const QString &opt)
-{
- if (opt == QLatin1String("CLIENT_COMPRESS"))
- optionFlags |= CLIENT_COMPRESS;
- else if (opt == QLatin1String("CLIENT_FOUND_ROWS"))
- optionFlags |= CLIENT_FOUND_ROWS;
- else if (opt == QLatin1String("CLIENT_IGNORE_SPACE"))
- optionFlags |= CLIENT_IGNORE_SPACE;
- else if (opt == QLatin1String("CLIENT_INTERACTIVE"))
- optionFlags |= CLIENT_INTERACTIVE;
- else if (opt == QLatin1String("CLIENT_NO_SCHEMA"))
- optionFlags |= CLIENT_NO_SCHEMA;
- else if (opt == QLatin1String("CLIENT_ODBC"))
- optionFlags |= CLIENT_ODBC;
- else if (opt == QLatin1String("CLIENT_SSL"))
- qWarning("QMYSQLDriver: SSL_KEY, SSL_CERT and SSL_CA should be used instead of CLIENT_SSL.");
- else
- qWarning("QMYSQLDriver::open: Unknown connect option '%s'", opt.toLocal8Bit().constData());
-}
-
-bool QMYSQLDriver::open(const QString& db,
- const QString& user,
- const QString& password,
- const QString& host,
- int port,
- const QString& connOpts)
-{
- Q_D(QMYSQLDriver);
- if (isOpen())
- close();
-
- /* This is a hack to get MySQL's stored procedure support working.
- Since a stored procedure _may_ return multiple result sets,
- we have to enable CLIEN_MULTI_STATEMENTS here, otherwise _any_
- stored procedure call will fail.
- */
- unsigned int optionFlags = Q_CLIENT_MULTI_STATEMENTS;
- const QStringList opts(connOpts.split(QLatin1Char(';'), QString::SkipEmptyParts));
- QString unixSocket;
- QString sslCert;
- QString sslCA;
- QString sslKey;
- QString sslCAPath;
- QString sslCipher;
-#if MYSQL_VERSION_ID >= 50000
- my_bool reconnect=false;
- uint connectTimeout = 0;
- uint readTimeout = 0;
- uint writeTimeout = 0;
-#endif
-
- // extract the real options from the string
- for (int i = 0; i < opts.count(); ++i) {
- QString tmp(opts.at(i).simplified());
- int idx;
- if ((idx = tmp.indexOf(QLatin1Char('='))) != -1) {
- QString val = tmp.mid(idx + 1).simplified();
- QString opt = tmp.left(idx).simplified();
- if (opt == QLatin1String("UNIX_SOCKET"))
- unixSocket = val;
-#if MYSQL_VERSION_ID >= 50000
- else if (opt == QLatin1String("MYSQL_OPT_RECONNECT")) {
- if (val == QLatin1String("TRUE") || val == QLatin1String("1") || val.isEmpty())
- reconnect = true;
- } else if (opt == QLatin1String("MYSQL_OPT_CONNECT_TIMEOUT")) {
- connectTimeout = val.toInt();
- } else if (opt == QLatin1String("MYSQL_OPT_READ_TIMEOUT")) {
- readTimeout = val.toInt();
- } else if (opt == QLatin1String("MYSQL_OPT_WRITE_TIMEOUT")) {
- writeTimeout = val.toInt();
- }
-#endif
- else if (opt == QLatin1String("SSL_KEY"))
- sslKey = val;
- else if (opt == QLatin1String("SSL_CERT"))
- sslCert = val;
- else if (opt == QLatin1String("SSL_CA"))
- sslCA = val;
- else if (opt == QLatin1String("SSL_CAPATH"))
- sslCAPath = val;
- else if (opt == QLatin1String("SSL_CIPHER"))
- sslCipher = val;
- else if (val == QLatin1String("TRUE") || val == QLatin1String("1"))
- setOptionFlag(optionFlags, tmp.left(idx).simplified());
- else
- qWarning("QMYSQLDriver::open: Illegal connect option value '%s'",
- tmp.toLocal8Bit().constData());
- } else {
- setOptionFlag(optionFlags, tmp);
- }
- }
-
- if (!(d->mysql = mysql_init((MYSQL*) 0))) {
- setLastError(qMakeError(tr("Unable to allocate a MYSQL object"),
- QSqlError::ConnectionError, d));
- setOpenError(true);
- return false;
- }
-
- if (!sslKey.isNull() || !sslCert.isNull() || !sslCA.isNull() ||
- !sslCAPath.isNull() || !sslCipher.isNull()) {
- mysql_ssl_set(d->mysql,
- sslKey.isNull() ? static_cast<const char *>(0)
- : QFile::encodeName(sslKey).constData(),
- sslCert.isNull() ? static_cast<const char *>(0)
- : QFile::encodeName(sslCert).constData(),
- sslCA.isNull() ? static_cast<const char *>(0)
- : QFile::encodeName(sslCA).constData(),
- sslCAPath.isNull() ? static_cast<const char *>(0)
- : QFile::encodeName(sslCAPath).constData(),
- sslCipher.isNull() ? static_cast<const char *>(0)
- : sslCipher.toLocal8Bit().constData());
- }
-
-#if MYSQL_VERSION_ID >= 50000
- if (connectTimeout != 0)
- mysql_options(d->mysql, MYSQL_OPT_CONNECT_TIMEOUT, &connectTimeout);
- if (readTimeout != 0)
- mysql_options(d->mysql, MYSQL_OPT_READ_TIMEOUT, &readTimeout);
- if (writeTimeout != 0)
- mysql_options(d->mysql, MYSQL_OPT_WRITE_TIMEOUT, &writeTimeout);
-#endif
- MYSQL *mysql = mysql_real_connect(d->mysql,
- host.isNull() ? static_cast<const char *>(0)
- : host.toLocal8Bit().constData(),
- user.isNull() ? static_cast<const char *>(0)
- : user.toLocal8Bit().constData(),
- password.isNull() ? static_cast<const char *>(0)
- : password.toLocal8Bit().constData(),
- db.isNull() ? static_cast<const char *>(0)
- : db.toLocal8Bit().constData(),
- (port > -1) ? port : 0,
- unixSocket.isNull() ? static_cast<const char *>(0)
- : unixSocket.toLocal8Bit().constData(),
- optionFlags);
-
- if (mysql == d->mysql) {
- if (!db.isEmpty() && mysql_select_db(d->mysql, db.toLocal8Bit().constData())) {
- setLastError(qMakeError(tr("Unable to open database '%1'").arg(db), QSqlError::ConnectionError, d));
- mysql_close(d->mysql);
- setOpenError(true);
- return false;
- }
-#if MYSQL_VERSION_ID >= 50000
- if (reconnect)
- mysql_options(d->mysql, MYSQL_OPT_RECONNECT, &reconnect);
-#endif
- } else {
- setLastError(qMakeError(tr("Unable to connect"),
- QSqlError::ConnectionError, d));
- mysql_close(d->mysql);
- d->mysql = NULL;
- setOpenError(true);
- return false;
- }
-
-#if (MYSQL_VERSION_ID >= 40113 && MYSQL_VERSION_ID < 50000) || MYSQL_VERSION_ID >= 50007
- // force the communication to be utf8
- mysql_set_character_set(d->mysql, "utf8");
-#endif
-#ifndef QT_NO_TEXTCODEC
- d->tc = codec(d->mysql);
-#endif
-
-#if MYSQL_VERSION_ID >= 40108
- d->preparedQuerysEnabled = mysql_get_client_version() >= 40108
- && mysql_get_server_version(d->mysql) >= 40100;
-#else
- d->preparedQuerysEnabled = false;
-#endif
-
-#ifndef QT_NO_THREAD
- mysql_thread_init();
-#endif
-
-
- setOpen(true);
- setOpenError(false);
- return true;
-}
-
-void QMYSQLDriver::close()
-{
- Q_D(QMYSQLDriver);
- if (isOpen()) {
-#ifndef QT_NO_THREAD
- mysql_thread_end();
-#endif
- mysql_close(d->mysql);
- d->mysql = NULL;
- setOpen(false);
- setOpenError(false);
- }
-}
-
-QSqlResult *QMYSQLDriver::createResult() const
-{
- return new QMYSQLResult(this);
-}
-
-QStringList QMYSQLDriver::tables(QSql::TableType type) const
-{
- Q_D(const QMYSQLDriver);
- QStringList tl;
-#if MYSQL_VERSION_ID >= 40100
- if( mysql_get_server_version(d->mysql) < 50000)
- {
-#endif
- if (!isOpen())
- return tl;
- if (!(type & QSql::Tables))
- return tl;
-
- MYSQL_RES* tableRes = mysql_list_tables(d->mysql, NULL);
- MYSQL_ROW row;
- int i = 0;
- while (tableRes) {
- mysql_data_seek(tableRes, i);
- row = mysql_fetch_row(tableRes);
- if (!row)
- break;
- tl.append(toUnicode(d->tc, row[0]));
- i++;
- }
- mysql_free_result(tableRes);
-#if MYSQL_VERSION_ID >= 40100
- } else {
- QSqlQuery q(createResult());
- if(type & QSql::Tables) {
- QString sql = QLatin1String("select table_name from information_schema.tables where table_schema = '") + QLatin1String(d->mysql->db) + QLatin1String("' and table_type = 'BASE TABLE'");
- q.exec(sql);
-
- while(q.next())
- tl.append(q.value(0).toString());
- }
- if(type & QSql::Views) {
- QString sql = QLatin1String("select table_name from information_schema.tables where table_schema = '") + QLatin1String(d->mysql->db) + QLatin1String("' and table_type = 'VIEW'");
- q.exec(sql);
-
- while(q.next())
- tl.append(q.value(0).toString());
- }
- }
-#endif
- return tl;
-}
-
-QSqlIndex QMYSQLDriver::primaryIndex(const QString& tablename) const
-{
- QSqlIndex idx;
- if (!isOpen())
- return idx;
-
- QSqlQuery i(createResult());
- QString stmt(QLatin1String("show index from %1;"));
- QSqlRecord fil = record(tablename);
- i.exec(stmt.arg(tablename));
- while (i.isActive() && i.next()) {
- if (i.value(2).toString() == QLatin1String("PRIMARY")) {
- idx.append(fil.field(i.value(4).toString()));
- idx.setCursorName(i.value(0).toString());
- idx.setName(i.value(2).toString());
- }
- }
-
- return idx;
-}
-
-QSqlRecord QMYSQLDriver::record(const QString& tablename) const
-{
- Q_D(const QMYSQLDriver);
- QString table=tablename;
- if(isIdentifierEscaped(table, QSqlDriver::TableName))
- table = stripDelimiters(table, QSqlDriver::TableName);
-
- QSqlRecord info;
- if (!isOpen())
- return info;
- MYSQL_RES* r = mysql_list_fields(d->mysql, table.toLocal8Bit().constData(), 0);
- if (!r) {
- return info;
- }
- MYSQL_FIELD* field;
-
- while ((field = mysql_fetch_field(r)))
- info.append(qToField(field, d->tc));
- mysql_free_result(r);
- return info;
-}
-
-QVariant QMYSQLDriver::handle() const
-{
- Q_D(const QMYSQLDriver);
- return QVariant::fromValue(d->mysql);
-}
-
-bool QMYSQLDriver::beginTransaction()
-{
- Q_D(QMYSQLDriver);
-#ifndef CLIENT_TRANSACTIONS
- return false;
-#endif
- if (!isOpen()) {
- qWarning("QMYSQLDriver::beginTransaction: Database not open");
- return false;
- }
- if (mysql_query(d->mysql, "BEGIN WORK")) {
- setLastError(qMakeError(tr("Unable to begin transaction"),
- QSqlError::StatementError, d));
- return false;
- }
- return true;
-}
-
-bool QMYSQLDriver::commitTransaction()
-{
- Q_D(QMYSQLDriver);
-#ifndef CLIENT_TRANSACTIONS
- return false;
-#endif
- if (!isOpen()) {
- qWarning("QMYSQLDriver::commitTransaction: Database not open");
- return false;
- }
- if (mysql_query(d->mysql, "COMMIT")) {
- setLastError(qMakeError(tr("Unable to commit transaction"),
- QSqlError::StatementError, d));
- return false;
- }
- return true;
-}
-
-bool QMYSQLDriver::rollbackTransaction()
-{
- Q_D(QMYSQLDriver);
-#ifndef CLIENT_TRANSACTIONS
- return false;
-#endif
- if (!isOpen()) {
- qWarning("QMYSQLDriver::rollbackTransaction: Database not open");
- return false;
- }
- if (mysql_query(d->mysql, "ROLLBACK")) {
- setLastError(qMakeError(tr("Unable to rollback transaction"),
- QSqlError::StatementError, d));
- return false;
- }
- return true;
-}
-
-QString QMYSQLDriver::formatValue(const QSqlField &field, bool trimStrings) const
-{
- Q_D(const QMYSQLDriver);
- QString r;
- if (field.isNull()) {
- r = QLatin1String("NULL");
- } else {
- switch(field.type()) {
- case QVariant::Double:
- r = QString::number(field.value().toDouble(), 'g', field.precision());
- break;
- case QVariant::String:
- // Escape '\' characters
- r = QSqlDriver::formatValue(field, trimStrings);
- r.replace(QLatin1String("\\"), QLatin1String("\\\\"));
- break;
- case QVariant::ByteArray:
- if (isOpen()) {
- const QByteArray ba = field.value().toByteArray();
- // buffer has to be at least length*2+1 bytes
- char* buffer = new char[ba.size() * 2 + 1];
- int escapedSize = int(mysql_real_escape_string(d->mysql, buffer,
- ba.data(), ba.size()));
- r.reserve(escapedSize + 3);
- r.append(QLatin1Char('\'')).append(toUnicode(d->tc, buffer)).append(QLatin1Char('\''));
- delete[] buffer;
- break;
- } else {
- qWarning("QMYSQLDriver::formatValue: Database not open");
- }
- // fall through
- default:
- r = QSqlDriver::formatValue(field, trimStrings);
- }
- }
- return r;
-}
-
-QString QMYSQLDriver::escapeIdentifier(const QString &identifier, IdentifierType) const
-{
- QString res = identifier;
- if(!identifier.isEmpty() && !identifier.startsWith(QLatin1Char('`')) && !identifier.endsWith(QLatin1Char('`')) ) {
- res.prepend(QLatin1Char('`')).append(QLatin1Char('`'));
- res.replace(QLatin1Char('.'), QLatin1String("`.`"));
- }
- return res;
-}
-
-bool QMYSQLDriver::isIdentifierEscaped(const QString &identifier, IdentifierType type) const
-{
- Q_UNUSED(type);
- return identifier.size() > 2
- && identifier.startsWith(QLatin1Char('`')) //left delimited
- && identifier.endsWith(QLatin1Char('`')); //right delimited
-}
-
-QT_END_NAMESPACE
diff --git a/src/sql/drivers/mysql/qsql_mysql.pri b/src/sql/drivers/mysql/qsql_mysql.pri
deleted file mode 100644
index 3cfb6144a1..0000000000
--- a/src/sql/drivers/mysql/qsql_mysql.pri
+++ /dev/null
@@ -1,16 +0,0 @@
-HEADERS += $$PWD/qsql_mysql_p.h
-SOURCES += $$PWD/qsql_mysql.cpp
-
-QMAKE_CXXFLAGS *= $$QT_CFLAGS_MYSQL
-LIBS += $$QT_LFLAGS_MYSQL
-
-unix {
- isEmpty(QT_LFLAGS_MYSQL) {
- !contains(LIBS, .*mysqlclient.*):!contains(LIBS, .*mysqld.*) {
- use_libmysqlclient_r:LIBS += -lmysqlclient_r
- else:LIBS += -lmysqlclient
- }
- }
-} else {
- !contains(LIBS, .*mysql.*):!contains(LIBS, .*mysqld.*):LIBS += -llibmysql
-}
diff --git a/src/sql/drivers/mysql/qsql_mysql_p.h b/src/sql/drivers/mysql/qsql_mysql_p.h
deleted file mode 100644
index 7641f9aa34..0000000000
--- a/src/sql/drivers/mysql/qsql_mysql_p.h
+++ /dev/null
@@ -1,110 +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_MYSQL_H
-#define QSQL_MYSQL_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
-
-#include <mysql.h>
-
-#ifdef QT_PLUGIN
-#define Q_EXPORT_SQLDRIVER_MYSQL
-#else
-#define Q_EXPORT_SQLDRIVER_MYSQL Q_SQL_EXPORT
-#endif
-
-QT_BEGIN_NAMESPACE
-
-class QMYSQLDriverPrivate;
-
-class Q_EXPORT_SQLDRIVER_MYSQL QMYSQLDriver : public QSqlDriver
-{
- friend class QMYSQLResultPrivate;
- Q_DECLARE_PRIVATE(QMYSQLDriver)
- Q_OBJECT
-public:
- explicit QMYSQLDriver(QObject *parent=0);
- explicit QMYSQLDriver(MYSQL *con, QObject * parent=0);
- ~QMYSQLDriver();
- bool hasFeature(DriverFeature f) const Q_DECL_OVERRIDE;
- bool open(const QString & db,
- const QString & user,
- const QString & password,
- const QString & host,
- int port,
- const QString& connOpts) Q_DECL_OVERRIDE;
- void close() Q_DECL_OVERRIDE;
- QSqlResult *createResult() const Q_DECL_OVERRIDE;
- QStringList tables(QSql::TableType) const Q_DECL_OVERRIDE;
- QSqlIndex primaryIndex(const QString& tablename) const Q_DECL_OVERRIDE;
- QSqlRecord record(const QString& tablename) const Q_DECL_OVERRIDE;
- QString formatValue(const QSqlField &field,
- bool trimStrings) const Q_DECL_OVERRIDE;
- QVariant handle() const Q_DECL_OVERRIDE;
- QString escapeIdentifier(const QString &identifier, IdentifierType type) const Q_DECL_OVERRIDE;
-
- bool isIdentifierEscaped(const QString &identifier, IdentifierType type) const Q_DECL_OVERRIDE;
-
-protected:
- bool beginTransaction() Q_DECL_OVERRIDE;
- bool commitTransaction() Q_DECL_OVERRIDE;
- bool rollbackTransaction() Q_DECL_OVERRIDE;
-private:
- void init();
-};
-
-QT_END_NAMESPACE
-
-#endif // QSQL_MYSQL_H
diff --git a/src/sql/drivers/oci/qsql_oci.cpp b/src/sql/drivers/oci/qsql_oci.cpp
deleted file mode 100644
index 47d6db7ea4..0000000000
--- a/src/sql/drivers/oci/qsql_oci.cpp
+++ /dev/null
@@ -1,2725 +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_oci_p.h"
-
-#include <qcoreapplication.h>
-#include <qvariant.h>
-#include <qdatetime.h>
-#include <qmetatype.h>
-#include <qregexp.h>
-#include <qshareddata.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 <qvarlengtharray.h>
-#include <qvector.h>
-#include <qdebug.h>
-
-// This is needed for oracle oci when compiling with mingw-w64 headers
-#if defined(__MINGW64_VERSION_MAJOR) && defined(_WIN64)
-#define _int64 __int64
-#endif
-
-
-#include <oci.h>
-#ifdef max
-#undef max
-#endif
-#ifdef min
-#undef min
-#endif
-
-#include <stdlib.h>
-
-#define QOCI_DYNAMIC_CHUNK_SIZE 65535
-#define QOCI_PREFETCH_MEM 10240
-
-// setting this define will allow using a query from a different
-// thread than its database connection.
-// warning - this is not fully tested and can lead to race conditions
-#define QOCI_THREADED
-
-//#define QOCI_DEBUG
-
-Q_DECLARE_OPAQUE_POINTER(OCIEnv*);
-Q_DECLARE_METATYPE(OCIEnv*)
-Q_DECLARE_OPAQUE_POINTER(OCIStmt*);
-Q_DECLARE_METATYPE(OCIStmt*)
-
-QT_BEGIN_NAMESPACE
-
-#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
-enum { QOCIEncoding = 2002 }; // AL16UTF16LE
-#else
-enum { QOCIEncoding = 2000 }; // AL16UTF16
-#endif
-
-#ifdef OCI_ATTR_CHARSET_FORM
-// Always set the OCI_ATTR_CHARSET_FORM to SQLCS_NCHAR is safe
-// because Oracle server will deal with the implicit Conversion
-// Between CHAR and NCHAR.
-// see: http://download.oracle.com/docs/cd/A91202_01/901_doc/appdev.901/a89857/oci05bnd.htm#422705
-static const ub1 qOraCharsetForm = SQLCS_NCHAR;
-#endif
-
-#if defined (OCI_UTF16ID)
-static const ub2 qOraCharset = OCI_UTF16ID;
-#else
-static const ub2 qOraCharset = OCI_UCS2ID;
-#endif
-
-typedef QVarLengthArray<sb2, 32> IndicatorArray;
-typedef QVarLengthArray<ub2, 32> SizeArray;
-
-static QByteArray qMakeOraDate(const QDateTime& dt);
-static QDateTime qMakeDate(const char* oraDate);
-
-static QByteArray qMakeOCINumber(const qlonglong &ll, OCIError *err);
-static QByteArray qMakeOCINumber(const qulonglong& ull, OCIError* err);
-
-static qlonglong qMakeLongLong(const char* ociNumber, OCIError* err);
-static qulonglong qMakeULongLong(const char* ociNumber, OCIError* err);
-
-static QString qOraWarn(OCIError *err, int *errorCode = 0);
-
-#ifndef Q_CC_SUN
-static // for some reason, Sun CC can't use qOraWarning when it's declared static
-#endif
-void qOraWarning(const char* msg, OCIError *err);
-static QSqlError qMakeError(const QString& errString, QSqlError::ErrorType type, OCIError *err);
-
-
-
-class QOCIRowId: public QSharedData
-{
-public:
- QOCIRowId(OCIEnv *env);
- ~QOCIRowId();
-
- OCIRowid *id;
-
-private:
- QOCIRowId(const QOCIRowId &other): QSharedData(other) { Q_ASSERT(false); }
-};
-
-QOCIRowId::QOCIRowId(OCIEnv *env)
- : id(0)
-{
- OCIDescriptorAlloc (env, reinterpret_cast<dvoid **>(&id),
- OCI_DTYPE_ROWID, 0, 0);
-}
-
-QOCIRowId::~QOCIRowId()
-{
- if (id)
- OCIDescriptorFree(id, OCI_DTYPE_ROWID);
-}
-
-typedef QSharedDataPointer<QOCIRowId> QOCIRowIdPointer;
-QT_BEGIN_INCLUDE_NAMESPACE
-Q_DECLARE_METATYPE(QOCIRowIdPointer)
-QT_END_INCLUDE_NAMESPACE
-
-class QOCIDriverPrivate : public QSqlDriverPrivate
-{
- Q_DECLARE_PUBLIC(QOCIDriver)
-
-public:
- QOCIDriverPrivate();
-
- OCIEnv *env;
- OCISvcCtx *svc;
- OCIServer *srvhp;
- OCISession *authp;
- OCIError *err;
- bool transaction;
- int serverVersion;
- int prefetchRows;
- int prefetchMem;
- QString user;
-
- void allocErrorHandle();
-};
-
-class QOCICols;
-class QOCIResultPrivate;
-
-class QOCIResult: public QSqlCachedResult
-{
- Q_DECLARE_PRIVATE(QOCIResult)
- friend class QOCIDriver;
- friend class QOCICols;
-public:
- QOCIResult(const QOCIDriver *db);
- ~QOCIResult();
- bool prepare(const QString &query) Q_DECL_OVERRIDE;
- bool exec() Q_DECL_OVERRIDE;
- QVariant handle() const Q_DECL_OVERRIDE;
-
-protected:
- bool gotoNext(ValueCache &values, int index) Q_DECL_OVERRIDE;
- bool reset(const QString &query) Q_DECL_OVERRIDE;
- int size() Q_DECL_OVERRIDE;
- int numRowsAffected() Q_DECL_OVERRIDE;
- QSqlRecord record() const Q_DECL_OVERRIDE;
- QVariant lastInsertId() const Q_DECL_OVERRIDE;
- bool execBatch(bool arrayBind = false) Q_DECL_OVERRIDE;
- void virtual_hook(int id, void *data) Q_DECL_OVERRIDE;
-};
-
-class QOCIResultPrivate: public QSqlCachedResultPrivate
-{
-public:
- Q_DECLARE_PUBLIC(QOCIResult)
- Q_DECLARE_SQLDRIVER_PRIVATE(QOCIDriver)
- QOCIResultPrivate(QOCIResult *q, const QOCIDriver *drv);
- ~QOCIResultPrivate();
-
- QOCICols *cols;
- OCIEnv *env;
- OCIError *err;
- OCISvcCtx *&svc;
- OCIStmt *sql;
- bool transaction;
- int serverVersion;
- int prefetchRows, prefetchMem;
-
- void setStatementAttributes();
- int bindValue(OCIStmt *sql, OCIBind **hbnd, OCIError *err, int pos,
- const QVariant &val, dvoid *indPtr, ub2 *tmpSize, QList<QByteArray> &tmpStorage);
- int bindValues(QVector<QVariant> &values, IndicatorArray &indicators, SizeArray &tmpSizes,
- QList<QByteArray> &tmpStorage);
- void outValues(QVector<QVariant> &values, IndicatorArray &indicators,
- QList<QByteArray> &tmpStorage);
- inline bool isOutValue(int i) const
- { Q_Q(const QOCIResult); return q->bindValueType(i) & QSql::Out; }
- inline bool isBinaryValue(int i) const
- { Q_Q(const QOCIResult); return q->bindValueType(i) & QSql::Binary; }
-
- void setCharset(dvoid* handle, ub4 type) const
- {
- int r = 0;
- Q_ASSERT(handle);
-
-#ifdef OCI_ATTR_CHARSET_FORM
- r = OCIAttrSet(handle,
- type,
- // this const cast is safe since OCI doesn't touch
- // the charset.
- const_cast<void *>(static_cast<const void *>(&qOraCharsetForm)),
- 0,
- OCI_ATTR_CHARSET_FORM,
- //Strange Oracle bug: some Oracle servers crash the server process with non-zero error handle (mostly for 10g).
- //So ignore the error message here.
- 0);
- #ifdef QOCI_DEBUG
- if (r != 0)
- qWarning("QOCIResultPrivate::setCharset: Couldn't set OCI_ATTR_CHARSET_FORM.");
- #endif
-#endif
-
- r = OCIAttrSet(handle,
- type,
- // this const cast is safe since OCI doesn't touch
- // the charset.
- const_cast<void *>(static_cast<const void *>(&qOraCharset)),
- 0,
- OCI_ATTR_CHARSET_ID,
- err);
- if (r != 0)
- qOraWarning("QOCIResultPrivate::setCharsetI Couldn't set OCI_ATTR_CHARSET_ID: ", err);
-
- }
-};
-
-void QOCIResultPrivate::setStatementAttributes()
-{
- Q_ASSERT(sql);
-
- int r = 0;
-
- if (prefetchRows >= 0) {
- r = OCIAttrSet(sql,
- OCI_HTYPE_STMT,
- &prefetchRows,
- 0,
- OCI_ATTR_PREFETCH_ROWS,
- err);
- if (r != 0)
- qOraWarning("QOCIResultPrivate::setStatementAttributes:"
- " Couldn't set OCI_ATTR_PREFETCH_ROWS: ", err);
- }
- if (prefetchMem >= 0) {
- r = OCIAttrSet(sql,
- OCI_HTYPE_STMT,
- &prefetchMem,
- 0,
- OCI_ATTR_PREFETCH_MEMORY,
- err);
- if (r != 0)
- qOraWarning("QOCIResultPrivate::setStatementAttributes:"
- " Couldn't set OCI_ATTR_PREFETCH_MEMORY: ", err);
- }
-}
-
-int QOCIResultPrivate::bindValue(OCIStmt *sql, OCIBind **hbnd, OCIError *err, int pos,
- const QVariant &val, dvoid *indPtr, ub2 *tmpSize, QList<QByteArray> &tmpStorage)
-{
- int r = OCI_SUCCESS;
- void *data = const_cast<void *>(val.constData());
-
- switch (val.type()) {
- case QVariant::ByteArray:
- r = OCIBindByPos(sql, hbnd, err,
- pos + 1,
- isOutValue(pos)
- ? const_cast<char *>(reinterpret_cast<QByteArray *>(data)->constData())
- : reinterpret_cast<QByteArray *>(data)->data(),
- reinterpret_cast<QByteArray *>(data)->size(),
- SQLT_BIN, indPtr, 0, 0, 0, 0, OCI_DEFAULT);
- break;
- case QVariant::Time:
- case QVariant::Date:
- case QVariant::DateTime: {
- QByteArray ba = qMakeOraDate(val.toDateTime());
- r = OCIBindByPos(sql, hbnd, err,
- pos + 1,
- ba.data(),
- ba.size(),
- SQLT_DAT, indPtr, 0, 0, 0, 0, OCI_DEFAULT);
- tmpStorage.append(ba);
- break; }
- case QVariant::Int:
- r = OCIBindByPos(sql, hbnd, err,
- pos + 1,
- // if it's an out value, the data is already detached
- // so the const cast is safe.
- const_cast<void *>(data),
- sizeof(int),
- SQLT_INT, indPtr, 0, 0, 0, 0, OCI_DEFAULT);
- break;
- case QVariant::UInt:
- r = OCIBindByPos(sql, hbnd, err,
- pos + 1,
- // if it's an out value, the data is already detached
- // so the const cast is safe.
- const_cast<void *>(data),
- sizeof(uint),
- SQLT_UIN, indPtr, 0, 0, 0, 0, OCI_DEFAULT);
- break;
- case QVariant::LongLong:
- {
- QByteArray ba = qMakeOCINumber(val.toLongLong(), err);
- r = OCIBindByPos(sql, hbnd, err,
- pos + 1,
- ba.data(),
- ba.size(),
- SQLT_VNU, indPtr, 0, 0, 0, 0, OCI_DEFAULT);
- tmpStorage.append(ba);
- break;
- }
- case QVariant::ULongLong:
- {
- QByteArray ba = qMakeOCINumber(val.toULongLong(), err);
- r = OCIBindByPos(sql, hbnd, err,
- pos + 1,
- ba.data(),
- ba.size(),
- SQLT_VNU, indPtr, 0, 0, 0, 0, OCI_DEFAULT);
- tmpStorage.append(ba);
- break;
- }
- case QVariant::Double:
- r = OCIBindByPos(sql, hbnd, err,
- pos + 1,
- // if it's an out value, the data is already detached
- // so the const cast is safe.
- const_cast<void *>(data),
- sizeof(double),
- SQLT_FLT, indPtr, 0, 0, 0, 0, OCI_DEFAULT);
- break;
- case QVariant::UserType:
- if (val.canConvert<QOCIRowIdPointer>() && !isOutValue(pos)) {
- // use a const pointer to prevent a detach
- const QOCIRowIdPointer rptr = qvariant_cast<QOCIRowIdPointer>(val);
- r = OCIBindByPos(sql, hbnd, err,
- pos + 1,
- // it's an IN value, so const_cast is ok
- const_cast<OCIRowid **>(&rptr->id),
- -1,
- SQLT_RDD, indPtr, 0, 0, 0, 0, OCI_DEFAULT);
- } else {
- qWarning("Unknown bind variable");
- r = OCI_ERROR;
- }
- break;
- case QVariant::String: {
- const QString s = val.toString();
- if (isBinaryValue(pos)) {
- r = OCIBindByPos(sql, hbnd, err,
- pos + 1,
- const_cast<ushort *>(s.utf16()),
- s.length() * sizeof(QChar),
- SQLT_LNG, indPtr, 0, 0, 0, 0, OCI_DEFAULT);
- break;
- } else if (!isOutValue(pos)) {
- // don't detach the string
- r = OCIBindByPos(sql, hbnd, err,
- pos + 1,
- // safe since oracle doesn't touch OUT values
- const_cast<ushort *>(s.utf16()),
- (s.length() + 1) * sizeof(QChar),
- SQLT_STR, indPtr, 0, 0, 0, 0, OCI_DEFAULT);
- if (r == OCI_SUCCESS)
- setCharset(*hbnd, OCI_HTYPE_BIND);
- break;
- }
- } // fall through for OUT values
- default: {
- const QString s = val.toString();
- // create a deep-copy
- QByteArray ba(reinterpret_cast<const char *>(s.utf16()), (s.length() + 1) * sizeof(QChar));
- if (isOutValue(pos)) {
- ba.reserve((s.capacity() + 1) * sizeof(QChar));
- *tmpSize = ba.size();
- r = OCIBindByPos(sql, hbnd, err,
- pos + 1,
- ba.data(),
- ba.capacity(),
- SQLT_STR, indPtr, tmpSize, 0, 0, 0, OCI_DEFAULT);
- } else {
- r = OCIBindByPos(sql, hbnd, err,
- pos + 1,
- ba.data(),
- ba.size(),
- SQLT_STR, indPtr, 0, 0, 0, 0, OCI_DEFAULT);
- }
- if (r == OCI_SUCCESS)
- setCharset(*hbnd, OCI_HTYPE_BIND);
- tmpStorage.append(ba);
- break;
- } // default case
- } // switch
- if (r != OCI_SUCCESS)
- qOraWarning("QOCIResultPrivate::bindValue:", err);
- return r;
-}
-
-int QOCIResultPrivate::bindValues(QVector<QVariant> &values, IndicatorArray &indicators,
- SizeArray &tmpSizes, QList<QByteArray> &tmpStorage)
-{
- int r = OCI_SUCCESS;
- for (int i = 0; i < values.count(); ++i) {
- if (isOutValue(i))
- values[i].detach();
- const QVariant &val = values.at(i);
-
- OCIBind * hbnd = 0; // Oracle handles these automatically
- sb2 *indPtr = &indicators[i];
- *indPtr = val.isNull() ? -1 : 0;
-
- bindValue(sql, &hbnd, err, i, val, indPtr, &tmpSizes[i], tmpStorage);
- }
- return r;
-}
-
-// will assign out value and remove its temp storage.
-static void qOraOutValue(QVariant &value, QList<QByteArray> &storage, OCIError* err)
-{
- switch (value.type()) {
- case QVariant::Time:
- value = qMakeDate(storage.takeFirst()).time();
- break;
- case QVariant::Date:
- value = qMakeDate(storage.takeFirst()).date();
- break;
- case QVariant::DateTime:
- value = qMakeDate(storage.takeFirst());
- break;
- case QVariant::LongLong:
- value = qMakeLongLong(storage.takeFirst(), err);
- break;
- case QVariant::ULongLong:
- value = qMakeULongLong(storage.takeFirst(), err);
- break;
- case QVariant::String:
- value = QString(
- reinterpret_cast<const QChar *>(storage.takeFirst().constData()));
- break;
- default:
- break; //nothing
- }
-}
-
-void QOCIResultPrivate::outValues(QVector<QVariant> &values, IndicatorArray &indicators,
- QList<QByteArray> &tmpStorage)
-{
- for (int i = 0; i < values.count(); ++i) {
-
- if (!isOutValue(i))
- continue;
-
- qOraOutValue(values[i], tmpStorage, err);
-
- QVariant::Type typ = values.at(i).type();
- if (indicators[i] == -1) // NULL
- values[i] = QVariant(typ);
- else
- values[i] = QVariant(typ, values.at(i).constData());
- }
-}
-
-
-QOCIDriverPrivate::QOCIDriverPrivate()
- : QSqlDriverPrivate(), env(0), svc(0), srvhp(0), authp(0), err(0), transaction(false),
- serverVersion(-1), prefetchRows(-1), prefetchMem(QOCI_PREFETCH_MEM)
-{
- dbmsType = QSqlDriver::Oracle;
-}
-
-void QOCIDriverPrivate::allocErrorHandle()
-{
- int r = OCIHandleAlloc(env,
- reinterpret_cast<void **>(&err),
- OCI_HTYPE_ERROR,
- 0,
- 0);
- if (r != 0)
- qWarning("QOCIDriver: unable to allocate error handle");
-}
-
-struct OraFieldInfo
-{
- QString name;
- QVariant::Type type;
- ub1 oraIsNull;
- ub4 oraType;
- sb1 oraScale;
- ub4 oraLength; // size in bytes
- ub4 oraFieldLength; // amount of characters
- sb2 oraPrecision;
-};
-
-QString qOraWarn(OCIError *err, int *errorCode)
-{
- sb4 errcode;
- text errbuf[1024];
- errbuf[0] = 0;
- errbuf[1] = 0;
-
- OCIErrorGet(err,
- 1,
- 0,
- &errcode,
- errbuf,
- sizeof(errbuf),
- OCI_HTYPE_ERROR);
- if (errorCode)
- *errorCode = errcode;
- return QString(reinterpret_cast<const QChar *>(errbuf));
-}
-
-void qOraWarning(const char* msg, OCIError *err)
-{
-#ifdef QOCI_DEBUG
- qWarning("%s %s", msg, qPrintable(qOraWarn(err)));
-#else
- Q_UNUSED(msg);
- Q_UNUSED(err);
-#endif
-}
-
-static int qOraErrorNumber(OCIError *err)
-{
- sb4 errcode;
- OCIErrorGet(err,
- 1,
- 0,
- &errcode,
- 0,
- 0,
- OCI_HTYPE_ERROR);
- return errcode;
-}
-
-QSqlError qMakeError(const QString& errString, QSqlError::ErrorType type, OCIError *err)
-{
- int errorCode = 0;
- const QString oraErrorString = qOraWarn(err, &errorCode);
- return QSqlError(errString, oraErrorString, type, errorCode);
-}
-
-QVariant::Type qDecodeOCIType(const QString& ocitype, QSql::NumericalPrecisionPolicy precisionPolicy)
-{
- QVariant::Type type = QVariant::Invalid;
- if (ocitype == QLatin1String("VARCHAR2") || ocitype == QLatin1String("VARCHAR")
- || ocitype.startsWith(QLatin1String("INTERVAL"))
- || ocitype == QLatin1String("CHAR") || ocitype == QLatin1String("NVARCHAR2")
- || ocitype == QLatin1String("NCHAR"))
- type = QVariant::String;
- else if (ocitype == QLatin1String("NUMBER")
- || ocitype == QLatin1String("FLOAT")
- || ocitype == QLatin1String("BINARY_FLOAT")
- || ocitype == QLatin1String("BINARY_DOUBLE")) {
- switch(precisionPolicy) {
- case QSql::LowPrecisionInt32:
- type = QVariant::Int;
- break;
- case QSql::LowPrecisionInt64:
- type = QVariant::LongLong;
- break;
- case QSql::LowPrecisionDouble:
- type = QVariant::Double;
- break;
- case QSql::HighPrecision:
- default:
- type = QVariant::String;
- break;
- }
- }
- else if (ocitype == QLatin1String("LONG") || ocitype == QLatin1String("NCLOB")
- || ocitype == QLatin1String("CLOB"))
- type = QVariant::ByteArray;
- else if (ocitype == QLatin1String("RAW") || ocitype == QLatin1String("LONG RAW")
- || ocitype == QLatin1String("ROWID") || ocitype == QLatin1String("BLOB")
- || ocitype == QLatin1String("CFILE") || ocitype == QLatin1String("BFILE"))
- type = QVariant::ByteArray;
- else if (ocitype == QLatin1String("DATE") || ocitype.startsWith(QLatin1String("TIME")))
- type = QVariant::DateTime;
- else if (ocitype == QLatin1String("UNDEFINED"))
- type = QVariant::Invalid;
- if (type == QVariant::Invalid)
- qWarning("qDecodeOCIType: unknown type: %s", ocitype.toLocal8Bit().constData());
- return type;
-}
-
-QVariant::Type qDecodeOCIType(int ocitype, QSql::NumericalPrecisionPolicy precisionPolicy)
-{
- QVariant::Type type = QVariant::Invalid;
- switch (ocitype) {
- case SQLT_STR:
- case SQLT_VST:
- case SQLT_CHR:
- case SQLT_AFC:
- case SQLT_VCS:
- case SQLT_AVC:
- case SQLT_RDD:
- case SQLT_LNG:
-#ifdef SQLT_INTERVAL_YM
- case SQLT_INTERVAL_YM:
-#endif
-#ifdef SQLT_INTERVAL_DS
- case SQLT_INTERVAL_DS:
-#endif
- type = QVariant::String;
- break;
- case SQLT_INT:
- type = QVariant::Int;
- break;
- case SQLT_FLT:
- case SQLT_NUM:
- case SQLT_VNU:
- case SQLT_UIN:
- switch(precisionPolicy) {
- case QSql::LowPrecisionInt32:
- type = QVariant::Int;
- break;
- case QSql::LowPrecisionInt64:
- type = QVariant::LongLong;
- break;
- case QSql::LowPrecisionDouble:
- type = QVariant::Double;
- break;
- case QSql::HighPrecision:
- default:
- type = QVariant::String;
- break;
- }
- break;
- case SQLT_VBI:
- case SQLT_BIN:
- case SQLT_LBI:
- case SQLT_LVC:
- case SQLT_LVB:
- case SQLT_BLOB:
- case SQLT_CLOB:
- case SQLT_FILE:
- case SQLT_NTY:
- case SQLT_REF:
- case SQLT_RID:
- type = QVariant::ByteArray;
- break;
- case SQLT_DAT:
- case SQLT_ODT:
-#ifdef SQLT_TIMESTAMP
- case SQLT_TIMESTAMP:
- case SQLT_TIMESTAMP_TZ:
- case SQLT_TIMESTAMP_LTZ:
-#endif
- type = QVariant::DateTime;
- break;
- default:
- type = QVariant::Invalid;
- qWarning("qDecodeOCIType: unknown OCI datatype: %d", ocitype);
- break;
- }
- return type;
-}
-
-static QSqlField qFromOraInf(const OraFieldInfo &ofi)
-{
- QSqlField f(ofi.name, ofi.type);
- f.setRequired(ofi.oraIsNull == 0);
-
- if (ofi.type == QVariant::String && ofi.oraType != SQLT_NUM && ofi.oraType != SQLT_VNU)
- f.setLength(ofi.oraFieldLength);
- else
- f.setLength(ofi.oraPrecision == 0 ? 38 : int(ofi.oraPrecision));
-
- f.setPrecision(ofi.oraScale);
- f.setSqlType(int(ofi.oraType));
- return f;
-}
-
-/*!
- \internal
-
- Convert QDateTime to the internal Oracle DATE format NB!
- It does not handle BCE dates.
-*/
-QByteArray qMakeOraDate(const QDateTime& dt)
-{
- QByteArray ba;
- ba.resize(7);
- int year = dt.date().year();
- ba[0]= (year / 100) + 100; // century
- ba[1]= (year % 100) + 100; // year
- ba[2]= dt.date().month();
- ba[3]= dt.date().day();
- ba[4]= dt.time().hour() + 1;
- ba[5]= dt.time().minute() + 1;
- ba[6]= dt.time().second() + 1;
- return ba;
-}
-
-/*!
- \internal
-
- Convert qlonglong to the internal Oracle OCINumber format.
- */
-QByteArray qMakeOCINumber(const qlonglong& ll, OCIError* err)
-{
- QByteArray ba(sizeof(OCINumber), 0);
-
- OCINumberFromInt(err,
- &ll,
- sizeof(qlonglong),
- OCI_NUMBER_SIGNED,
- reinterpret_cast<OCINumber*>(ba.data()));
- return ba;
-}
-
-/*!
- \internal
-
- Convert qulonglong to the internal Oracle OCINumber format.
- */
-QByteArray qMakeOCINumber(const qulonglong& ull, OCIError* err)
-{
- QByteArray ba(sizeof(OCINumber), 0);
-
- OCINumberFromInt(err,
- &ull,
- sizeof(qlonglong),
- OCI_NUMBER_UNSIGNED,
- reinterpret_cast<OCINumber*>(ba.data()));
- return ba;
-}
-
-qlonglong qMakeLongLong(const char* ociNumber, OCIError* err)
-{
- qlonglong qll = 0;
- OCINumberToInt(err, reinterpret_cast<const OCINumber *>(ociNumber), sizeof(qlonglong),
- OCI_NUMBER_SIGNED, &qll);
- return qll;
-}
-
-qulonglong qMakeULongLong(const char* ociNumber, OCIError* err)
-{
- qulonglong qull = 0;
- OCINumberToInt(err, reinterpret_cast<const OCINumber *>(ociNumber), sizeof(qulonglong),
- OCI_NUMBER_UNSIGNED, &qull);
- return qull;
-}
-
-QDateTime qMakeDate(const char* oraDate)
-{
- int century = uchar(oraDate[0]);
- if(century >= 100){
- int year = uchar(oraDate[1]);
- year = ((century-100)*100) + (year-100);
- int month = oraDate[2];
- int day = oraDate[3];
- int hour = oraDate[4] - 1;
- int min = oraDate[5] - 1;
- int sec = oraDate[6] - 1;
- return QDateTime(QDate(year,month,day), QTime(hour,min,sec));
- }
- return QDateTime();
-}
-
-class QOCICols
-{
-public:
- QOCICols(int size, QOCIResultPrivate* dp);
- ~QOCICols();
- int readPiecewise(QVector<QVariant> &values, int index = 0);
- int readLOBs(QVector<QVariant> &values, int index = 0);
- int fieldFromDefine(OCIDefine* d);
- void getValues(QVector<QVariant> &v, int index);
- inline int size() { return fieldInf.size(); }
- static bool execBatch(QOCIResultPrivate *d, QVector<QVariant> &boundValues, bool arrayBind);
-
- QSqlRecord rec;
-
-private:
- char* create(int position, int size);
- OCILobLocator ** createLobLocator(int position, OCIEnv* env);
- OraFieldInfo qMakeOraField(const QOCIResultPrivate* p, OCIParam* param) const;
-
- class OraFieldInf
- {
- public:
- OraFieldInf(): data(0), len(0), ind(0), typ(QVariant::Invalid), oraType(0), def(0), lob(0)
- {}
- ~OraFieldInf();
- char *data;
- int len;
- sb2 ind;
- QVariant::Type typ;
- ub4 oraType;
- OCIDefine *def;
- OCILobLocator *lob;
- };
-
- QVector<OraFieldInf> fieldInf;
- const QOCIResultPrivate *const d;
-};
-
-QOCICols::OraFieldInf::~OraFieldInf()
-{
- delete [] data;
- if (lob) {
- int r = OCIDescriptorFree(lob, OCI_DTYPE_LOB);
- if (r != 0)
- qWarning("QOCICols: Cannot free LOB descriptor");
- }
-}
-
-QOCICols::QOCICols(int size, QOCIResultPrivate* dp)
- : fieldInf(size), d(dp)
-{
- ub4 dataSize = 0;
- OCIDefine* dfn = 0;
- int r;
-
- OCIParam* param = 0;
- sb4 parmStatus = 0;
- ub4 count = 1;
- int idx = 0;
- parmStatus = OCIParamGet(d->sql,
- OCI_HTYPE_STMT,
- d->err,
- reinterpret_cast<void **>(&param),
- count);
-
- while (parmStatus == OCI_SUCCESS) {
- OraFieldInfo ofi = qMakeOraField(d, param);
- if (ofi.oraType == SQLT_RDD)
- dataSize = 50;
-#ifdef SQLT_INTERVAL_YM
-#ifdef SQLT_INTERVAL_DS
- else if (ofi.oraType == SQLT_INTERVAL_YM || ofi.oraType == SQLT_INTERVAL_DS)
- // since we are binding interval datatype as string,
- // we are not interested in the number of bytes but characters.
- dataSize = 50; // magic number
-#endif //SQLT_INTERVAL_DS
-#endif //SQLT_INTERVAL_YM
- else if (ofi.oraType == SQLT_NUM || ofi.oraType == SQLT_VNU){
- if (ofi.oraPrecision > 0)
- dataSize = (ofi.oraPrecision + 1) * sizeof(utext);
- else
- dataSize = (38 + 1) * sizeof(utext);
- }
- else
- dataSize = ofi.oraLength;
-
- fieldInf[idx].typ = ofi.type;
- fieldInf[idx].oraType = ofi.oraType;
- rec.append(qFromOraInf(ofi));
-
- switch (ofi.type) {
- case QVariant::DateTime:
- r = OCIDefineByPos(d->sql,
- &dfn,
- d->err,
- count,
- create(idx, dataSize+1),
- dataSize+1,
- SQLT_DAT,
- &(fieldInf[idx].ind),
- 0, 0, OCI_DEFAULT);
- break;
- case QVariant::Double:
- r = OCIDefineByPos(d->sql,
- &dfn,
- d->err,
- count,
- create(idx, sizeof(double) - 1),
- sizeof(double),
- SQLT_FLT,
- &(fieldInf[idx].ind),
- 0, 0, OCI_DEFAULT);
- break;
- case QVariant::Int:
- r = OCIDefineByPos(d->sql,
- &dfn,
- d->err,
- count,
- create(idx, sizeof(qint32) - 1),
- sizeof(qint32),
- SQLT_INT,
- &(fieldInf[idx].ind),
- 0, 0, OCI_DEFAULT);
- break;
- case QVariant::LongLong:
- r = OCIDefineByPos(d->sql,
- &dfn,
- d->err,
- count,
- create(idx, sizeof(OCINumber)),
- sizeof(OCINumber),
- SQLT_VNU,
- &(fieldInf[idx].ind),
- 0, 0, OCI_DEFAULT);
- break;
- case QVariant::ByteArray:
- // RAW and LONG RAW fields can't be bound to LOB locators
- if (ofi.oraType == SQLT_BIN) {
-// qDebug("binding SQLT_BIN");
- r = OCIDefineByPos(d->sql,
- &dfn,
- d->err,
- count,
- create(idx, dataSize),
- dataSize,
- SQLT_BIN,
- &(fieldInf[idx].ind),
- 0, 0, OCI_DYNAMIC_FETCH);
- } else if (ofi.oraType == SQLT_LBI) {
-// qDebug("binding SQLT_LBI");
- r = OCIDefineByPos(d->sql,
- &dfn,
- d->err,
- count,
- 0,
- SB4MAXVAL,
- SQLT_LBI,
- &(fieldInf[idx].ind),
- 0, 0, OCI_DYNAMIC_FETCH);
- } else if (ofi.oraType == SQLT_CLOB) {
- r = OCIDefineByPos(d->sql,
- &dfn,
- d->err,
- count,
- createLobLocator(idx, d->env),
- -1,
- SQLT_CLOB,
- &(fieldInf[idx].ind),
- 0, 0, OCI_DEFAULT);
- } else {
-// qDebug("binding SQLT_BLOB");
- r = OCIDefineByPos(d->sql,
- &dfn,
- d->err,
- count,
- createLobLocator(idx, d->env),
- -1,
- SQLT_BLOB,
- &(fieldInf[idx].ind),
- 0, 0, OCI_DEFAULT);
- }
- break;
- case QVariant::String:
- if (ofi.oraType == SQLT_LNG) {
- r = OCIDefineByPos(d->sql,
- &dfn,
- d->err,
- count,
- 0,
- SB4MAXVAL,
- SQLT_LNG,
- &(fieldInf[idx].ind),
- 0, 0, OCI_DYNAMIC_FETCH);
- } else {
- dataSize += dataSize + sizeof(QChar);
- //qDebug("OCIDefineByPosStr(%d): %d", count, dataSize);
- r = OCIDefineByPos(d->sql,
- &dfn,
- d->err,
- count,
- create(idx, dataSize),
- dataSize,
- SQLT_STR,
- &(fieldInf[idx].ind),
- 0, 0, OCI_DEFAULT);
- if (r == 0)
- d->setCharset(dfn, OCI_HTYPE_DEFINE);
- }
- break;
- default:
- // this should make enough space even with character encoding
- dataSize = (dataSize + 1) * sizeof(utext) ;
- //qDebug("OCIDefineByPosDef(%d): %d", count, dataSize);
- r = OCIDefineByPos(d->sql,
- &dfn,
- d->err,
- count,
- create(idx, dataSize),
- dataSize+1,
- SQLT_STR,
- &(fieldInf[idx].ind),
- 0, 0, OCI_DEFAULT);
- break;
- }
- if (r != 0)
- qOraWarning("QOCICols::bind:", d->err);
- fieldInf[idx].def = dfn;
- ++count;
- ++idx;
- parmStatus = OCIParamGet(d->sql,
- OCI_HTYPE_STMT,
- d->err,
- reinterpret_cast<void **>(&param),
- count);
- }
-}
-
-QOCICols::~QOCICols()
-{
-}
-
-char* QOCICols::create(int position, int size)
-{
- char* c = new char[size+1];
- // Oracle may not fill fixed width fields
- memset(c, 0, size+1);
- fieldInf[position].data = c;
- fieldInf[position].len = size;
- return c;
-}
-
-OCILobLocator **QOCICols::createLobLocator(int position, OCIEnv* env)
-{
- OCILobLocator *& lob = fieldInf[position].lob;
- int r = OCIDescriptorAlloc(env,
- reinterpret_cast<void **>(&lob),
- OCI_DTYPE_LOB,
- 0,
- 0);
- if (r != 0) {
- qWarning("QOCICols: Cannot create LOB locator");
- lob = 0;
- }
- return &lob;
-}
-
-int QOCICols::readPiecewise(QVector<QVariant> &values, int index)
-{
- OCIDefine* dfn;
- ub4 typep;
- ub1 in_outp;
- ub4 iterp;
- ub4 idxp;
- ub1 piecep;
- sword status;
- text col [QOCI_DYNAMIC_CHUNK_SIZE+1];
- int fieldNum = -1;
- int r = 0;
- bool nullField;
-
- do {
- r = OCIStmtGetPieceInfo(d->sql, d->err, reinterpret_cast<void **>(&dfn), &typep,
- &in_outp, &iterp, &idxp, &piecep);
- if (r != OCI_SUCCESS)
- qOraWarning("OCIResultPrivate::readPiecewise: unable to get piece info:", d->err);
- fieldNum = fieldFromDefine(dfn);
- bool isStringField = fieldInf.at(fieldNum).oraType == SQLT_LNG;
- ub4 chunkSize = QOCI_DYNAMIC_CHUNK_SIZE;
- nullField = false;
- r = OCIStmtSetPieceInfo(dfn, OCI_HTYPE_DEFINE,
- d->err, col,
- &chunkSize, piecep, NULL, NULL);
- if (r != OCI_SUCCESS)
- qOraWarning("OCIResultPrivate::readPiecewise: unable to set piece info:", d->err);
- status = OCIStmtFetch (d->sql, d->err, 1, OCI_FETCH_NEXT, OCI_DEFAULT);
- if (status == -1) {
- sb4 errcode;
- OCIErrorGet(d->err, 1, 0, &errcode, 0, 0,OCI_HTYPE_ERROR);
- switch (errcode) {
- case 1405: /* NULL */
- nullField = true;
- break;
- default:
- qOraWarning("OCIResultPrivate::readPiecewise: unable to fetch next:", d->err);
- break;
- }
- }
- if (status == OCI_NO_DATA)
- break;
- if (nullField || !chunkSize) {
- fieldInf[fieldNum].ind = -1;
- } else {
- if (isStringField) {
- QString str = values.at(fieldNum + index).toString();
- str += QString(reinterpret_cast<const QChar *>(col), chunkSize / 2);
- values[fieldNum + index] = str;
- fieldInf[fieldNum].ind = 0;
- } else {
- QByteArray ba = values.at(fieldNum + index).toByteArray();
- int sz = ba.size();
- ba.resize(sz + chunkSize);
- memcpy(ba.data() + sz, reinterpret_cast<char *>(col), chunkSize);
- values[fieldNum + index] = ba;
- fieldInf[fieldNum].ind = 0;
- }
- }
- } while (status == OCI_SUCCESS_WITH_INFO || status == OCI_NEED_DATA);
- return r;
-}
-
-OraFieldInfo QOCICols::qMakeOraField(const QOCIResultPrivate* p, OCIParam* param) const
-{
- OraFieldInfo ofi;
- ub2 colType(0);
- text *colName = 0;
- ub4 colNameLen(0);
- sb1 colScale(0);
- ub2 colLength(0);
- ub2 colFieldLength(0);
- sb2 colPrecision(0);
- ub1 colIsNull(0);
- int r(0);
- QVariant::Type type(QVariant::Invalid);
-
- r = OCIAttrGet(param,
- OCI_DTYPE_PARAM,
- &colType,
- 0,
- OCI_ATTR_DATA_TYPE,
- p->err);
- if (r != 0)
- qOraWarning("qMakeOraField:", p->err);
-
- r = OCIAttrGet(param,
- OCI_DTYPE_PARAM,
- &colName,
- &colNameLen,
- OCI_ATTR_NAME,
- p->err);
- if (r != 0)
- qOraWarning("qMakeOraField:", p->err);
-
- r = OCIAttrGet(param,
- OCI_DTYPE_PARAM,
- &colLength,
- 0,
- OCI_ATTR_DATA_SIZE, /* in bytes */
- p->err);
- if (r != 0)
- qOraWarning("qMakeOraField:", p->err);
-
-#ifdef OCI_ATTR_CHAR_SIZE
- r = OCIAttrGet(param,
- OCI_DTYPE_PARAM,
- &colFieldLength,
- 0,
- OCI_ATTR_CHAR_SIZE,
- p->err);
- if (r != 0)
- qOraWarning("qMakeOraField:", p->err);
-#else
- // for Oracle8.
- colFieldLength = colLength;
-#endif
-
- r = OCIAttrGet(param,
- OCI_DTYPE_PARAM,
- &colPrecision,
- 0,
- OCI_ATTR_PRECISION,
- p->err);
- if (r != 0)
- qOraWarning("qMakeOraField:", p->err);
-
- r = OCIAttrGet(param,
- OCI_DTYPE_PARAM,
- &colScale,
- 0,
- OCI_ATTR_SCALE,
- p->err);
- if (r != 0)
- qOraWarning("qMakeOraField:", p->err);
- r = OCIAttrGet(param,
- OCI_DTYPE_PARAM,
- &colType,
- 0,
- OCI_ATTR_DATA_TYPE,
- p->err);
- if (r != 0)
- qOraWarning("qMakeOraField:", p->err);
- r = OCIAttrGet(param,
- OCI_DTYPE_PARAM,
- &colIsNull,
- 0,
- OCI_ATTR_IS_NULL,
- p->err);
- if (r != 0)
- qOraWarning("qMakeOraField:", p->err);
-
- type = qDecodeOCIType(colType, p->q_func()->numericalPrecisionPolicy());
-
- if (type == QVariant::Int) {
- if (colLength == 22 && colPrecision == 0 && colScale == 0)
- type = QVariant::String;
- if (colScale > 0)
- type = QVariant::String;
- }
-
- // bind as double if the precision policy asks for it
- if (((colType == SQLT_FLT) || (colType == SQLT_NUM))
- && (p->q_func()->numericalPrecisionPolicy() == QSql::LowPrecisionDouble)) {
- type = QVariant::Double;
- }
-
- // bind as int32 or int64 if the precision policy asks for it
- if ((colType == SQLT_NUM) || (colType == SQLT_VNU) || (colType == SQLT_UIN)
- || (colType == SQLT_INT)) {
- if (p->q_func()->numericalPrecisionPolicy() == QSql::LowPrecisionInt64)
- type = QVariant::LongLong;
- else if (p->q_func()->numericalPrecisionPolicy() == QSql::LowPrecisionInt32)
- type = QVariant::Int;
- }
-
- if (colType == SQLT_BLOB)
- colLength = 0;
-
- // colNameLen is length in bytes
- ofi.name = QString(reinterpret_cast<const QChar*>(colName), colNameLen / 2);
- ofi.type = type;
- ofi.oraType = colType;
- ofi.oraFieldLength = colFieldLength;
- ofi.oraLength = colLength;
- ofi.oraScale = colScale;
- ofi.oraPrecision = colPrecision;
- ofi.oraIsNull = colIsNull;
-
- return ofi;
-}
-
-struct QOCIBatchColumn
-{
- inline QOCIBatchColumn()
- : bindh(0), bindAs(0), maxLen(0), recordCount(0),
- data(0), lengths(0), indicators(0), maxarr_len(0), curelep(0) {}
-
- OCIBind* bindh;
- ub2 bindAs;
- ub4 maxLen;
- ub4 recordCount;
- char* data;
- ub2* lengths;
- sb2* indicators;
- ub4 maxarr_len;
- ub4 curelep;
-};
-
-struct QOCIBatchCleanupHandler
-{
- inline QOCIBatchCleanupHandler(QVector<QOCIBatchColumn> &columns)
- : col(columns) {}
-
- ~QOCIBatchCleanupHandler()
- {
- // deleting storage, length and indicator arrays
- for ( int j = 0; j < col.count(); ++j){
- delete[] col[j].lengths;
- delete[] col[j].indicators;
- delete[] col[j].data;
- }
- }
-
- QVector<QOCIBatchColumn> &col;
-};
-
-bool QOCICols::execBatch(QOCIResultPrivate *d, QVector<QVariant> &boundValues, bool arrayBind)
-{
- int columnCount = boundValues.count();
- if (boundValues.isEmpty() || columnCount == 0)
- return false;
-
-#ifdef QOCI_DEBUG
- qDebug() << "columnCount:" << columnCount << boundValues;
-#endif
-
- int i;
- sword r;
-
- QVarLengthArray<QVariant::Type> fieldTypes;
- for (i = 0; i < columnCount; ++i) {
- QVariant::Type tp = boundValues.at(i).type();
- fieldTypes.append(tp == QVariant::List ? boundValues.at(i).toList().value(0).type()
- : tp);
- }
-
- QList<QByteArray> tmpStorage;
- SizeArray tmpSizes(columnCount);
- QVector<QOCIBatchColumn> columns(columnCount);
- QOCIBatchCleanupHandler cleaner(columns);
-
- // figuring out buffer sizes
- for (i = 0; i < columnCount; ++i) {
-
- if (boundValues.at(i).type() != QVariant::List) {
-
- // not a list - create a deep-copy of the single value
- QOCIBatchColumn &singleCol = columns[i];
- singleCol.indicators = new sb2[1];
- *singleCol.indicators = boundValues.at(i).isNull() ? -1 : 0;
-
- r = d->bindValue(d->sql, &singleCol.bindh, d->err, i,
- boundValues.at(i), singleCol.indicators, &tmpSizes[i], tmpStorage);
-
- if (r != OCI_SUCCESS && r != OCI_SUCCESS_WITH_INFO) {
- qOraWarning("QOCIPrivate::execBatch: unable to bind column:", d->err);
- d->q_func()->setLastError(qMakeError(QCoreApplication::translate("QOCIResult",
- "Unable to bind column for batch execute"),
- QSqlError::StatementError, d->err));
- return false;
- }
- continue;
- }
-
- QOCIBatchColumn &col = columns[i];
- col.recordCount = boundValues.at(i).toList().count();
-
- col.lengths = new ub2[col.recordCount];
- col.indicators = new sb2[col.recordCount];
- col.maxarr_len = col.recordCount;
- col.curelep = col.recordCount;
-
- switch (fieldTypes[i]) {
- case QVariant::Time:
- case QVariant::Date:
- case QVariant::DateTime:
- col.bindAs = SQLT_DAT;
- col.maxLen = 7;
- break;
-
- case QVariant::Int:
- col.bindAs = SQLT_INT;
- col.maxLen = sizeof(int);
- break;
-
- case QVariant::UInt:
- col.bindAs = SQLT_UIN;
- col.maxLen = sizeof(uint);
- break;
-
- case QVariant::LongLong:
- col.bindAs = SQLT_VNU;
- col.maxLen = sizeof(OCINumber);
- break;
-
- case QVariant::ULongLong:
- col.bindAs = SQLT_VNU;
- col.maxLen = sizeof(OCINumber);
- break;
-
- case QVariant::Double:
- col.bindAs = SQLT_FLT;
- col.maxLen = sizeof(double);
- break;
-
- case QVariant::UserType:
- col.bindAs = SQLT_RDD;
- col.maxLen = sizeof(OCIRowid*);
- break;
-
- case QVariant::String: {
- col.bindAs = SQLT_STR;
- for (uint j = 0; j < col.recordCount; ++j) {
- uint len;
- if(d->isOutValue(i))
- len = boundValues.at(i).toList().at(j).toString().capacity() + 1;
- else
- len = boundValues.at(i).toList().at(j).toString().length() + 1;
- if (len > col.maxLen)
- col.maxLen = len;
- }
- col.maxLen *= sizeof(QChar);
- break; }
-
- case QVariant::ByteArray:
- default: {
- col.bindAs = SQLT_LBI;
- for (uint j = 0; j < col.recordCount; ++j) {
- if(d->isOutValue(i))
- col.lengths[j] = boundValues.at(i).toList().at(j).toByteArray().capacity();
- else
- col.lengths[j] = boundValues.at(i).toList().at(j).toByteArray().size();
- if (col.lengths[j] > col.maxLen)
- col.maxLen = col.lengths[j];
- }
- break; }
- }
-
- col.data = new char[col.maxLen * col.recordCount];
- memset(col.data, 0, col.maxLen * col.recordCount);
-
- // we may now populate column with data
- for (uint row = 0; row < col.recordCount; ++row) {
- const QVariant &val = boundValues.at(i).toList().at(row);
-
- if (val.isNull()){
- columns[i].indicators[row] = -1;
- columns[i].lengths[row] = 0;
- } else {
- columns[i].indicators[row] = 0;
- char *dataPtr = columns[i].data + (columns[i].maxLen * row);
- switch (fieldTypes[i]) {
- case QVariant::Time:
- case QVariant::Date:
- case QVariant::DateTime:{
- columns[i].lengths[row] = columns[i].maxLen;
- const QByteArray ba = qMakeOraDate(val.toDateTime());
- Q_ASSERT(ba.size() == int(columns[i].maxLen));
- memcpy(dataPtr, ba.constData(), columns[i].maxLen);
- break;
- }
- case QVariant::Int:
- columns[i].lengths[row] = columns[i].maxLen;
- *reinterpret_cast<int*>(dataPtr) = val.toInt();
- break;
-
- case QVariant::UInt:
- columns[i].lengths[row] = columns[i].maxLen;
- *reinterpret_cast<uint*>(dataPtr) = val.toUInt();
- break;
-
- case QVariant::LongLong:
- {
- columns[i].lengths[row] = columns[i].maxLen;
- const QByteArray ba = qMakeOCINumber(val.toLongLong(), d->err);
- Q_ASSERT(ba.size() == int(columns[i].maxLen));
- memcpy(dataPtr, ba.constData(), columns[i].maxLen);
- break;
- }
- case QVariant::ULongLong:
- {
- columns[i].lengths[row] = columns[i].maxLen;
- const QByteArray ba = qMakeOCINumber(val.toULongLong(), d->err);
- Q_ASSERT(ba.size() == int(columns[i].maxLen));
- memcpy(dataPtr, ba.constData(), columns[i].maxLen);
- break;
- }
- case QVariant::Double:
- columns[i].lengths[row] = columns[i].maxLen;
- *reinterpret_cast<double*>(dataPtr) = val.toDouble();
- break;
-
- case QVariant::String: {
- const QString s = val.toString();
- columns[i].lengths[row] = (s.length() + 1) * sizeof(QChar);
- memcpy(dataPtr, s.utf16(), columns[i].lengths[row]);
- break;
- }
- case QVariant::UserType:
- if (val.canConvert<QOCIRowIdPointer>()) {
- const QOCIRowIdPointer rptr = qvariant_cast<QOCIRowIdPointer>(val);
- *reinterpret_cast<OCIRowid**>(dataPtr) = rptr->id;
- columns[i].lengths[row] = 0;
- break;
- }
- case QVariant::ByteArray:
- default: {
- const QByteArray ba = val.toByteArray();
- columns[i].lengths[row] = ba.size();
- memcpy(dataPtr, ba.constData(), ba.size());
- break;
- }
- }
- }
- }
-
- QOCIBatchColumn &bindColumn = columns[i];
-
-#ifdef QOCI_DEBUG
- qDebug("OCIBindByPos(%p, %p, %p, %d, %p, %d, %d, %p, %p, 0, %d, %p, OCI_DEFAULT)",
- d->sql, &bindColumn.bindh, d->err, i + 1, bindColumn.data,
- bindColumn.maxLen, bindColumn.bindAs, bindColumn.indicators, bindColumn.lengths,
- arrayBind ? bindColumn.maxarr_len : 0, arrayBind ? &bindColumn.curelep : 0);
-
- for (int ii = 0; ii < (int)bindColumn.recordCount; ++ii) {
- qDebug(" record %d: indicator %d, length %d", ii, bindColumn.indicators[ii],
- bindColumn.lengths[ii]);
- }
-#endif
-
-
- // binding the column
- r = OCIBindByPos(
- d->sql, &bindColumn.bindh, d->err, i + 1,
- bindColumn.data,
- bindColumn.maxLen,
- bindColumn.bindAs,
- bindColumn.indicators,
- bindColumn.lengths,
- 0,
- arrayBind ? bindColumn.maxarr_len : 0,
- arrayBind ? &bindColumn.curelep : 0,
- OCI_DEFAULT);
-
-#ifdef QOCI_DEBUG
- qDebug("After OCIBindByPos: r = %d, bindh = %p", r, bindColumn.bindh);
-#endif
-
- if (r != OCI_SUCCESS && r != OCI_SUCCESS_WITH_INFO) {
- qOraWarning("QOCIPrivate::execBatch: unable to bind column:", d->err);
- d->q_func()->setLastError(qMakeError(QCoreApplication::translate("QOCIResult",
- "Unable to bind column for batch execute"),
- QSqlError::StatementError, d->err));
- return false;
- }
-
- r = OCIBindArrayOfStruct (
- columns[i].bindh, d->err,
- columns[i].maxLen,
- sizeof(columns[i].indicators[0]),
- sizeof(columns[i].lengths[0]),
- 0);
-
- if (r != OCI_SUCCESS && r != OCI_SUCCESS_WITH_INFO) {
- qOraWarning("QOCIPrivate::execBatch: unable to bind column:", d->err);
- d->q_func()->setLastError(qMakeError(QCoreApplication::translate("QOCIResult",
- "Unable to bind column for batch execute"),
- QSqlError::StatementError, d->err));
- return false;
- }
- }
-
- //finaly we can execute
- r = OCIStmtExecute(d->svc, d->sql, d->err,
- arrayBind ? 1 : columns[0].recordCount,
- 0, NULL, NULL,
- d->transaction ? OCI_DEFAULT : OCI_COMMIT_ON_SUCCESS);
-
- if (r != OCI_SUCCESS && r != OCI_SUCCESS_WITH_INFO) {
- qOraWarning("QOCIPrivate::execBatch: unable to execute batch statement:", d->err);
- d->q_func()->setLastError(qMakeError(QCoreApplication::translate("QOCIResult",
- "Unable to execute batch statement"),
- QSqlError::StatementError, d->err));
- return false;
- }
-
- // for out parameters we copy data back to value vector
- for (i = 0; i < columnCount; ++i) {
-
- if (!d->isOutValue(i))
- continue;
-
- QVariant::Type tp = boundValues.at(i).type();
- if (tp != QVariant::List) {
- qOraOutValue(boundValues[i], tmpStorage, d->err);
- if (*columns[i].indicators == -1)
- boundValues[i] = QVariant(tp);
- continue;
- }
-
- QVariantList *list = static_cast<QVariantList *>(const_cast<void*>(boundValues.at(i).data()));
-
- char* data = columns[i].data;
- for (uint r = 0; r < columns[i].recordCount; ++r){
-
- if (columns[i].indicators[r] == -1) {
- (*list)[r] = QVariant();
- continue;
- }
-
- switch(columns[i].bindAs) {
-
- case SQLT_DAT:
- (*list)[r] = qMakeDate(data + r * columns[i].maxLen);
- break;
-
- case SQLT_INT:
- (*list)[r] = *reinterpret_cast<int*>(data + r * columns[i].maxLen);
- break;
-
- case SQLT_UIN:
- (*list)[r] = *reinterpret_cast<uint*>(data + r * columns[i].maxLen);
- break;
-
- case SQLT_VNU:
- {
- switch (boundValues.at(i).type()) {
- case QVariant::LongLong:
- (*list)[r] = qMakeLongLong(data + r * columns[i].maxLen, d->err);
- break;
- case QVariant::ULongLong:
- (*list)[r] = qMakeULongLong(data + r * columns[i].maxLen, d->err);
- break;
- default:
- break;
- }
- break;
- }
-
- case SQLT_FLT:
- (*list)[r] = *reinterpret_cast<double*>(data + r * columns[i].maxLen);
- break;
-
- case SQLT_STR:
- (*list)[r] = QString(reinterpret_cast<const QChar *>(data
- + r * columns[i].maxLen));
- break;
-
- default:
- (*list)[r] = QByteArray(data + r * columns[i].maxLen, columns[i].maxLen);
- break;
- }
- }
- }
-
- d->q_func()->setSelect(false);
- d->q_func()->setAt(QSql::BeforeFirstRow);
- d->q_func()->setActive(true);
-
- return true;
-}
-
-template<class T, int sz>
-int qReadLob(T &buf, const QOCIResultPrivate *d, OCILobLocator *lob)
-{
- ub1 csfrm;
- ub4 amount;
- int r;
-
- // Read this from the database, don't assume we know what it is set to
- r = OCILobCharSetForm(d->env, d->err, lob, &csfrm);
- if (r != OCI_SUCCESS) {
- qOraWarning("OCIResultPrivate::readLobs: Couldn't get LOB char set form: ", d->err);
- csfrm = 0;
- }
-
- // Get the length of the LOB (this is in characters)
- r = OCILobGetLength(d->svc, d->err, lob, &amount);
- if (r == OCI_SUCCESS) {
- if (amount == 0) {
- // Short cut for null LOBs
- buf.resize(0);
- return OCI_SUCCESS;
- }
- } else {
- qOraWarning("OCIResultPrivate::readLobs: Couldn't get LOB length: ", d->err);
- return r;
- }
-
- // Resize the buffer to hold the LOB contents
- buf.resize(amount);
-
- // Read the LOB into the buffer
- r = OCILobRead(d->svc,
- d->err,
- lob,
- &amount,
- 1,
- buf.data(),
- buf.size() * sz, // this argument is in bytes, not characters
- 0,
- 0,
- // Extract the data from a CLOB in UTF-16 (ie. what QString uses internally)
- sz == 1 ? ub2(0) : ub2(QOCIEncoding),
- csfrm);
-
- if (r != OCI_SUCCESS)
- qOraWarning("OCIResultPrivate::readLOBs: Cannot read LOB: ", d->err);
-
- return r;
-}
-
-int QOCICols::readLOBs(QVector<QVariant> &values, int index)
-{
- OCILobLocator *lob;
- int r = OCI_SUCCESS;
-
- for (int i = 0; i < size(); ++i) {
- const OraFieldInf &fi = fieldInf.at(i);
- if (fi.ind == -1 || !(lob = fi.lob))
- continue;
-
- bool isClob = fi.oraType == SQLT_CLOB;
- QVariant var;
-
- if (isClob) {
- QString str;
- r = qReadLob<QString, sizeof(QChar)>(str, d, lob);
- var = str;
- } else {
- QByteArray buf;
- r = qReadLob<QByteArray, sizeof(char)>(buf, d, lob);
- var = buf;
- }
- if (r == OCI_SUCCESS)
- values[index + i] = var;
- else
- break;
- }
- return r;
-}
-
-int QOCICols::fieldFromDefine(OCIDefine* d)
-{
- for (int i = 0; i < fieldInf.count(); ++i) {
- if (fieldInf.at(i).def == d)
- return i;
- }
- return -1;
-}
-
-void QOCICols::getValues(QVector<QVariant> &v, int index)
-{
- for (int i = 0; i < fieldInf.size(); ++i) {
- const OraFieldInf &fld = fieldInf.at(i);
-
- if (fld.ind == -1) {
- // got a NULL value
- v[index + i] = QVariant(fld.typ);
- continue;
- }
-
- if (fld.oraType == SQLT_BIN || fld.oraType == SQLT_LBI || fld.oraType == SQLT_LNG)
- continue; // already fetched piecewise
-
- switch (fld.typ) {
- case QVariant::DateTime:
- v[index + i] = QVariant(qMakeDate(fld.data));
- break;
- case QVariant::Double:
- case QVariant::Int:
- case QVariant::LongLong:
- if (d->q_func()->numericalPrecisionPolicy() != QSql::HighPrecision) {
- if ((d->q_func()->numericalPrecisionPolicy() == QSql::LowPrecisionDouble)
- && (fld.typ == QVariant::Double)) {
- v[index + i] = *reinterpret_cast<double *>(fld.data);
- break;
- } else if ((d->q_func()->numericalPrecisionPolicy() == QSql::LowPrecisionInt64)
- && (fld.typ == QVariant::LongLong)) {
- qint64 qll = 0;
- int r = OCINumberToInt(d->err, reinterpret_cast<OCINumber *>(fld.data), sizeof(qint64),
- OCI_NUMBER_SIGNED, &qll);
- if(r == OCI_SUCCESS)
- v[index + i] = qll;
- else
- v[index + i] = QVariant();
- break;
- } else if ((d->q_func()->numericalPrecisionPolicy() == QSql::LowPrecisionInt32)
- && (fld.typ == QVariant::Int)) {
- v[index + i] = *reinterpret_cast<int *>(fld.data);
- break;
- }
- }
- // else fall through
- case QVariant::String:
- v[index + i] = QString(reinterpret_cast<const QChar *>(fld.data));
- break;
- case QVariant::ByteArray:
- if (fld.len > 0)
- v[index + i] = QByteArray(fld.data, fld.len);
- else
- v[index + i] = QVariant(QVariant::ByteArray);
- break;
- default:
- qWarning("QOCICols::value: unknown data type");
- break;
- }
- }
-}
-
-QOCIResultPrivate::QOCIResultPrivate(QOCIResult *q, const QOCIDriver *drv)
- : QSqlCachedResultPrivate(q, drv),
- cols(0),
- env(drv_d_func()->env),
- err(0),
- svc(const_cast<OCISvcCtx*&>(drv_d_func()->svc)),
- sql(0),
- transaction(drv_d_func()->transaction),
- serverVersion(drv_d_func()->serverVersion),
- prefetchRows(drv_d_func()->prefetchRows),
- prefetchMem(drv_d_func()->prefetchMem)
-{
- int r = OCIHandleAlloc(env,
- reinterpret_cast<void **>(&err),
- OCI_HTYPE_ERROR,
- 0,
- 0);
- if (r != 0)
- qWarning("QOCIResult: unable to alloc error handle");
-}
-
-QOCIResultPrivate::~QOCIResultPrivate()
-{
- delete cols;
-
- int r = OCIHandleFree(err, OCI_HTYPE_ERROR);
- if (r != 0)
- qWarning("~QOCIResult: unable to free statement handle");
-}
-
-
-////////////////////////////////////////////////////////////////////////////
-
-QOCIResult::QOCIResult(const QOCIDriver *db)
- : QSqlCachedResult(*new QOCIResultPrivate(this, db))
-{
-}
-
-QOCIResult::~QOCIResult()
-{
- Q_D(QOCIResult);
- if (d->sql) {
- int r = OCIHandleFree(d->sql, OCI_HTYPE_STMT);
- if (r != 0)
- qWarning("~QOCIResult: unable to free statement handle");
- }
-}
-
-QVariant QOCIResult::handle() const
-{
- Q_D(const QOCIResult);
- return QVariant::fromValue(d->sql);
-}
-
-bool QOCIResult::reset (const QString& query)
-{
- if (!prepare(query))
- return false;
- return exec();
-}
-
-bool QOCIResult::gotoNext(QSqlCachedResult::ValueCache &values, int index)
-{
- Q_D(QOCIResult);
- if (at() == QSql::AfterLastRow)
- return false;
-
- bool piecewise = false;
- int r = OCI_SUCCESS;
- r = OCIStmtFetch(d->sql, d->err, 1, OCI_FETCH_NEXT, OCI_DEFAULT);
-
- if (index < 0) //not interested in values
- return r == OCI_SUCCESS || r == OCI_SUCCESS_WITH_INFO;
-
- switch (r) {
- case OCI_SUCCESS:
- break;
- case OCI_SUCCESS_WITH_INFO:
- qOraWarning("QOCIResult::gotoNext: SuccessWithInfo: ", d->err);
- r = OCI_SUCCESS; //ignore it
- break;
- case OCI_NO_DATA:
- // end of rowset
- return false;
- case OCI_NEED_DATA:
- piecewise = true;
- r = OCI_SUCCESS;
- break;
- case OCI_ERROR:
- if (qOraErrorNumber(d->err) == 1406) {
- qWarning("QOCI Warning: data truncated for %s", lastQuery().toLocal8Bit().constData());
- r = OCI_SUCCESS; /* ignore it */
- break;
- }
- // fall through
- default:
- qOraWarning("QOCIResult::gotoNext: ", d->err);
- setLastError(qMakeError(QCoreApplication::translate("QOCIResult",
- "Unable to goto next"),
- QSqlError::StatementError, d->err));
- break;
- }
-
- // need to read piecewise before assigning values
- if (r == OCI_SUCCESS && piecewise)
- r = d->cols->readPiecewise(values, index);
-
- if (r == OCI_SUCCESS)
- d->cols->getValues(values, index);
- if (r == OCI_SUCCESS)
- r = d->cols->readLOBs(values, index);
- if (r != OCI_SUCCESS)
- setAt(QSql::AfterLastRow);
- return r == OCI_SUCCESS || r == OCI_SUCCESS_WITH_INFO;
-}
-
-int QOCIResult::size()
-{
- return -1;
-}
-
-int QOCIResult::numRowsAffected()
-{
- Q_D(QOCIResult);
- int rowCount;
- OCIAttrGet(d->sql,
- OCI_HTYPE_STMT,
- &rowCount,
- NULL,
- OCI_ATTR_ROW_COUNT,
- d->err);
- return rowCount;
-}
-
-bool QOCIResult::prepare(const QString& query)
-{
- Q_D(QOCIResult);
- int r = 0;
- QSqlResult::prepare(query);
-
- delete d->cols;
- d->cols = 0;
- QSqlCachedResult::cleanup();
-
- if (d->sql) {
- r = OCIHandleFree(d->sql, OCI_HTYPE_STMT);
- if (r != OCI_SUCCESS)
- qOraWarning("QOCIResult::prepare: unable to free statement handle:", d->err);
- }
- if (query.isEmpty())
- return false;
- r = OCIHandleAlloc(d->env,
- reinterpret_cast<void **>(&d->sql),
- OCI_HTYPE_STMT,
- 0,
- 0);
- if (r != OCI_SUCCESS) {
- qOraWarning("QOCIResult::prepare: unable to alloc statement:", d->err);
- setLastError(qMakeError(QCoreApplication::translate("QOCIResult",
- "Unable to alloc statement"), QSqlError::StatementError, d->err));
- return false;
- }
- d->setStatementAttributes();
- const OraText *txt = reinterpret_cast<const OraText *>(query.utf16());
- const int len = query.length() * sizeof(QChar);
- r = OCIStmtPrepare(d->sql,
- d->err,
- txt,
- len,
- OCI_NTV_SYNTAX,
- OCI_DEFAULT);
- if (r != OCI_SUCCESS) {
- qOraWarning("QOCIResult::prepare: unable to prepare statement:", d->err);
- setLastError(qMakeError(QCoreApplication::translate("QOCIResult",
- "Unable to prepare statement"), QSqlError::StatementError, d->err));
- return false;
- }
- return true;
-}
-
-bool QOCIResult::exec()
-{
- Q_D(QOCIResult);
- int r = 0;
- ub2 stmtType=0;
- ub4 iters;
- ub4 mode;
- QList<QByteArray> tmpStorage;
- IndicatorArray indicators(boundValueCount());
- SizeArray tmpSizes(boundValueCount());
-
- r = OCIAttrGet(d->sql,
- OCI_HTYPE_STMT,
- &stmtType,
- NULL,
- OCI_ATTR_STMT_TYPE,
- d->err);
-
- if (r != OCI_SUCCESS && r != OCI_SUCCESS_WITH_INFO) {
- qOraWarning("QOCIResult::exec: Unable to get statement type:", d->err);
- setLastError(qMakeError(QCoreApplication::translate("QOCIResult",
- "Unable to get statement type"), QSqlError::StatementError, d->err));
-#ifdef QOCI_DEBUG
- qDebug() << "lastQuery()" << lastQuery();
-#endif
- return false;
- }
-
- iters = stmtType == OCI_STMT_SELECT ? 0 : 1;
- mode = d->transaction ? OCI_DEFAULT : OCI_COMMIT_ON_SUCCESS;
-
- // bind placeholders
- if (boundValueCount() > 0
- && d->bindValues(boundValues(), indicators, tmpSizes, tmpStorage) != OCI_SUCCESS) {
- qOraWarning("QOCIResult::exec: unable to bind value: ", d->err);
- setLastError(qMakeError(QCoreApplication::translate("QOCIResult", "Unable to bind value"),
- QSqlError::StatementError, d->err));
-#ifdef QOCI_DEBUG
- qDebug() << "lastQuery()" << lastQuery();
-#endif
- return false;
- }
-
- // execute
- r = OCIStmtExecute(d->svc,
- d->sql,
- d->err,
- iters,
- 0,
- 0,
- 0,
- mode);
- if (r != OCI_SUCCESS && r != OCI_SUCCESS_WITH_INFO) {
- qOraWarning("QOCIResult::exec: unable to execute statement:", d->err);
- setLastError(qMakeError(QCoreApplication::translate("QOCIResult",
- "Unable to execute statement"), QSqlError::StatementError, d->err));
-#ifdef QOCI_DEBUG
- qDebug() << "lastQuery()" << lastQuery();
-#endif
- return false;
- }
-
- if (stmtType == OCI_STMT_SELECT) {
- ub4 parmCount = 0;
- int r = OCIAttrGet(d->sql, OCI_HTYPE_STMT, reinterpret_cast<void **>(&parmCount),
- 0, OCI_ATTR_PARAM_COUNT, d->err);
- if (r == 0 && !d->cols)
- d->cols = new QOCICols(parmCount, d);
- setSelect(true);
- QSqlCachedResult::init(parmCount);
- } else { /* non-SELECT */
- setSelect(false);
- }
- setAt(QSql::BeforeFirstRow);
- setActive(true);
-
- if (hasOutValues())
- d->outValues(boundValues(), indicators, tmpStorage);
-
- return true;
-}
-
-QSqlRecord QOCIResult::record() const
-{
- Q_D(const QOCIResult);
- QSqlRecord inf;
- if (!isActive() || !isSelect() || !d->cols)
- return inf;
- return d->cols->rec;
-}
-
-QVariant QOCIResult::lastInsertId() const
-{
- Q_D(const QOCIResult);
- if (isActive()) {
- QOCIRowIdPointer ptr(new QOCIRowId(d->env));
-
- int r = OCIAttrGet(d->sql, OCI_HTYPE_STMT, ptr.constData()->id,
- 0, OCI_ATTR_ROWID, d->err);
- if (r == OCI_SUCCESS)
- return QVariant::fromValue(ptr);
- }
- return QVariant();
-}
-
-bool QOCIResult::execBatch(bool arrayBind)
-{
- Q_D(QOCIResult);
- QOCICols::execBatch(d, boundValues(), arrayBind);
- resetBindCount();
- return lastError().type() == QSqlError::NoError;
-}
-
-void QOCIResult::virtual_hook(int id, void *data)
-{
- Q_ASSERT(data);
-
- QSqlCachedResult::virtual_hook(id, data);
-}
-
-////////////////////////////////////////////////////////////////////////////
-
-
-QOCIDriver::QOCIDriver(QObject* parent)
- : QSqlDriver(*new QOCIDriverPrivate, parent)
-{
- Q_D(QOCIDriver);
-#ifdef QOCI_THREADED
- const ub4 mode = OCI_UTF16 | OCI_OBJECT | OCI_THREADED;
-#else
- const ub4 mode = OCI_UTF16 | OCI_OBJECT;
-#endif
- int r = OCIEnvCreate(&d->env,
- mode,
- NULL,
- NULL,
- NULL,
- NULL,
- 0,
- NULL);
- if (r != 0) {
- qWarning("QOCIDriver: unable to create environment");
- setLastError(qMakeError(tr("Unable to initialize", "QOCIDriver"),
- QSqlError::ConnectionError, d->err));
- return;
- }
-
- d->allocErrorHandle();
-}
-
-QOCIDriver::QOCIDriver(OCIEnv* env, OCISvcCtx* ctx, QObject* parent)
- : QSqlDriver(*new QOCIDriverPrivate, parent)
-{
- Q_D(QOCIDriver);
- d->env = env;
- d->svc = ctx;
-
- d->allocErrorHandle();
-
- if (env && ctx) {
- setOpen(true);
- setOpenError(false);
- }
-}
-
-QOCIDriver::~QOCIDriver()
-{
- Q_D(QOCIDriver);
- if (isOpen())
- close();
- int r = OCIHandleFree(d->err, OCI_HTYPE_ERROR);
- if (r != OCI_SUCCESS)
- qWarning("Unable to free Error handle: %d", r);
- r = OCIHandleFree(d->env, OCI_HTYPE_ENV);
- if (r != OCI_SUCCESS)
- qWarning("Unable to free Environment handle: %d", r);
-}
-
-bool QOCIDriver::hasFeature(DriverFeature f) const
-{
- Q_D(const QOCIDriver);
- switch (f) {
- case Transactions:
- case LastInsertId:
- case BLOB:
- case PreparedQueries:
- case NamedPlaceholders:
- case BatchOperations:
- case LowPrecisionNumbers:
- return true;
- case QuerySize:
- case PositionalPlaceholders:
- case SimpleLocking:
- case EventNotifications:
- case FinishQuery:
- case CancelQuery:
- case MultipleResultSets:
- return false;
- case Unicode:
- return d->serverVersion >= 9;
- }
- return false;
-}
-
-static void qParseOpts(const QString &options, QOCIDriverPrivate *d)
-{
- const QStringList opts(options.split(QLatin1Char(';'), QString::SkipEmptyParts));
- for (int i = 0; i < opts.count(); ++i) {
- const QString tmp(opts.at(i));
- int idx;
- if ((idx = tmp.indexOf(QLatin1Char('='))) == -1) {
- qWarning("QOCIDriver::parseArgs: Invalid parameter: '%s'",
- tmp.toLocal8Bit().constData());
- continue;
- }
- const QString opt = tmp.left(idx);
- const QString val = tmp.mid(idx + 1).simplified();
- bool ok;
- if (opt == QLatin1String("OCI_ATTR_PREFETCH_ROWS")) {
- d->prefetchRows = val.toInt(&ok);
- if (!ok)
- d->prefetchRows = -1;
- } else if (opt == QLatin1String("OCI_ATTR_PREFETCH_MEMORY")) {
- d->prefetchMem = val.toInt(&ok);
- if (!ok)
- d->prefetchMem = -1;
- } else {
- qWarning ("QOCIDriver::parseArgs: Invalid parameter: '%s'",
- opt.toLocal8Bit().constData());
- }
- }
-}
-
-bool QOCIDriver::open(const QString & db,
- const QString & user,
- const QString & password,
- const QString & hostname,
- int port,
- const QString &opts)
-{
- Q_D(QOCIDriver);
- int r;
-
- if (isOpen())
- close();
-
- qParseOpts(opts, d);
-
- // Connect without tnsnames.ora if a hostname is given
- QString connectionString = db;
- if (!hostname.isEmpty())
- connectionString =
- QString::fromLatin1("(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(Host=%1)(Port=%2))"
- "(CONNECT_DATA=(SID=%3)))").arg(hostname).arg((port > -1 ? port : 1521)).arg(db);
-
- r = OCIHandleAlloc(d->env, reinterpret_cast<void **>(&d->srvhp), OCI_HTYPE_SERVER, 0, 0);
- if (r == OCI_SUCCESS)
- r = OCIServerAttach(d->srvhp, d->err, reinterpret_cast<const OraText *>(connectionString.utf16()),
- connectionString.length() * sizeof(QChar), OCI_DEFAULT);
- if (r == OCI_SUCCESS || r == OCI_SUCCESS_WITH_INFO)
- r = OCIHandleAlloc(d->env, reinterpret_cast<void **>(&d->svc), OCI_HTYPE_SVCCTX, 0, 0);
- if (r == OCI_SUCCESS)
- r = OCIAttrSet(d->svc, OCI_HTYPE_SVCCTX, d->srvhp, 0, OCI_ATTR_SERVER, d->err);
- if (r == OCI_SUCCESS)
- r = OCIHandleAlloc(d->env, reinterpret_cast<void **>(&d->authp), OCI_HTYPE_SESSION, 0, 0);
- if (r == OCI_SUCCESS)
- r = OCIAttrSet(d->authp, OCI_HTYPE_SESSION, const_cast<ushort *>(user.utf16()),
- user.length() * sizeof(QChar), OCI_ATTR_USERNAME, d->err);
- if (r == OCI_SUCCESS)
- r = OCIAttrSet(d->authp, OCI_HTYPE_SESSION, const_cast<ushort *>(password.utf16()),
- password.length() * sizeof(QChar), OCI_ATTR_PASSWORD, d->err);
-
- OCITrans* trans;
- if (r == OCI_SUCCESS)
- r = OCIHandleAlloc(d->env, reinterpret_cast<void **>(&trans), OCI_HTYPE_TRANS, 0, 0);
- if (r == OCI_SUCCESS)
- r = OCIAttrSet(d->svc, OCI_HTYPE_SVCCTX, trans, 0, OCI_ATTR_TRANS, d->err);
-
- if (r == OCI_SUCCESS) {
- if (user.isEmpty() && password.isEmpty())
- r = OCISessionBegin(d->svc, d->err, d->authp, OCI_CRED_EXT, OCI_DEFAULT);
- else
- r = OCISessionBegin(d->svc, d->err, d->authp, OCI_CRED_RDBMS, OCI_DEFAULT);
- }
- if (r == OCI_SUCCESS || r == OCI_SUCCESS_WITH_INFO)
- r = OCIAttrSet(d->svc, OCI_HTYPE_SVCCTX, d->authp, 0, OCI_ATTR_SESSION, d->err);
-
- if (r != OCI_SUCCESS) {
- setLastError(qMakeError(tr("Unable to logon"), QSqlError::ConnectionError, d->err));
- setOpenError(true);
- if (d->authp)
- OCIHandleFree(d->authp, OCI_HTYPE_SESSION);
- d->authp = 0;
- if (d->srvhp)
- OCIHandleFree(d->srvhp, OCI_HTYPE_SERVER);
- d->srvhp = 0;
- return false;
- }
-
- // get server version
- char vertxt[512];
- r = OCIServerVersion(d->svc,
- d->err,
- reinterpret_cast<OraText *>(vertxt),
- sizeof(vertxt),
- OCI_HTYPE_SVCCTX);
- if (r != 0) {
- qWarning("QOCIDriver::open: could not get Oracle server version.");
- } else {
- QString versionStr;
- versionStr = QString(reinterpret_cast<const QChar *>(vertxt));
- QRegExp vers(QLatin1String("([0-9]+)\\.[0-9\\.]+[0-9]"));
- if (vers.indexIn(versionStr) >= 0)
- d->serverVersion = vers.cap(1).toInt();
- if (d->serverVersion == 0)
- d->serverVersion = -1;
- }
-
- setOpen(true);
- setOpenError(false);
- d->user = user;
-
- return true;
-}
-
-void QOCIDriver::close()
-{
- Q_D(QOCIDriver);
- if (!isOpen())
- return;
-
- OCISessionEnd(d->svc, d->err, d->authp, OCI_DEFAULT);
- OCIServerDetach(d->srvhp, d->err, OCI_DEFAULT);
- OCIHandleFree(d->authp, OCI_HTYPE_SESSION);
- d->authp = 0;
- OCIHandleFree(d->srvhp, OCI_HTYPE_SERVER);
- d->srvhp = 0;
- OCIHandleFree(d->svc, OCI_HTYPE_SVCCTX);
- d->svc = 0;
- setOpen(false);
- setOpenError(false);
-}
-
-QSqlResult *QOCIDriver::createResult() const
-{
- return new QOCIResult(this);
-}
-
-bool QOCIDriver::beginTransaction()
-{
- Q_D(QOCIDriver);
- if (!isOpen()) {
- qWarning("QOCIDriver::beginTransaction: Database not open");
- return false;
- }
- int r = OCITransStart(d->svc,
- d->err,
- 2,
- OCI_TRANS_READWRITE);
- if (r == OCI_ERROR) {
- qOraWarning("QOCIDriver::beginTransaction: ", d->err);
- setLastError(qMakeError(QCoreApplication::translate("QOCIDriver",
- "Unable to begin transaction"), QSqlError::TransactionError, d->err));
- return false;
- }
- d->transaction = true;
- return true;
-}
-
-bool QOCIDriver::commitTransaction()
-{
- Q_D(QOCIDriver);
- if (!isOpen()) {
- qWarning("QOCIDriver::commitTransaction: Database not open");
- return false;
- }
- int r = OCITransCommit(d->svc,
- d->err,
- 0);
- if (r == OCI_ERROR) {
- qOraWarning("QOCIDriver::commitTransaction:", d->err);
- setLastError(qMakeError(QCoreApplication::translate("QOCIDriver",
- "Unable to commit transaction"), QSqlError::TransactionError, d->err));
- return false;
- }
- d->transaction = false;
- return true;
-}
-
-bool QOCIDriver::rollbackTransaction()
-{
- Q_D(QOCIDriver);
- if (!isOpen()) {
- qWarning("QOCIDriver::rollbackTransaction: Database not open");
- return false;
- }
- int r = OCITransRollback(d->svc,
- d->err,
- 0);
- if (r == OCI_ERROR) {
- qOraWarning("QOCIDriver::rollbackTransaction:", d->err);
- setLastError(qMakeError(QCoreApplication::translate("QOCIDriver",
- "Unable to rollback transaction"), QSqlError::TransactionError, d->err));
- return false;
- }
- d->transaction = false;
- return true;
-}
-
-enum Expression {
- OrExpression,
- AndExpression
-};
-
-static QString make_where_clause(const QString &user, Expression e)
-{
- static const char sysUsers[][8] = {
- "MDSYS",
- "LBACSYS",
- "SYS",
- "SYSTEM",
- "WKSYS",
- "CTXSYS",
- "WMSYS",
- };
- static const char joinC[][4] = { "or" , "and" };
- static Q_CONSTEXPR QLatin1Char bang[] = { QLatin1Char(' '), QLatin1Char('!') };
-
- const QLatin1String join(joinC[e], -1); // -1: force strlen call
-
- QString result;
- result.reserve(sizeof sysUsers / sizeof *sysUsers *
- // max-sizeof(owner != <sysuser> and )
- (9 + sizeof *sysUsers + 5));
- for (const auto &sysUser : sysUsers) {
- const QLatin1String l1(sysUser, -1); // -1: force strlen call
- if (l1 != user)
- result += QLatin1String("owner ") + bang[e] + QLatin1String("= '") + l1 + QLatin1Char(' ') + join + QLatin1Char(' ');
- }
-
- result.chop(join.size() + 2); // remove final " <join> "
-
- return result;
-}
-
-QStringList QOCIDriver::tables(QSql::TableType type) const
-{
- Q_D(const QOCIDriver);
- QStringList tl;
-
- QString user = d->user;
- if ( isIdentifierEscaped(user, QSqlDriver::TableName))
- user = stripDelimiters(user, QSqlDriver::TableName);
- else
- user = user.toUpper();
-
- if (!isOpen())
- return tl;
-
- QSqlQuery t(createResult());
- t.setForwardOnly(true);
- if (type & QSql::Tables) {
- const QLatin1String tableQuery("select owner, table_name from all_tables where ");
- const QString where = make_where_clause(user, AndExpression);
- t.exec(tableQuery + where);
- while (t.next()) {
- if (t.value(0).toString().toUpper() != user.toUpper())
- tl.append(t.value(0).toString() + QLatin1Char('.') + t.value(1).toString());
- else
- tl.append(t.value(1).toString());
- }
-
- // list all table synonyms as well
- const QLatin1String synonymQuery("select owner, synonym_name from all_synonyms where ");
- t.exec(synonymQuery + where);
- while (t.next()) {
- if (t.value(0).toString() != d->user)
- tl.append(t.value(0).toString() + QLatin1Char('.') + t.value(1).toString());
- else
- tl.append(t.value(1).toString());
- }
- }
- if (type & QSql::Views) {
- const QLatin1String query("select owner, view_name from all_views where ");
- const QString where = make_where_clause(user, AndExpression);
- t.exec(query + where);
- while (t.next()) {
- if (t.value(0).toString().toUpper() != d->user.toUpper())
- tl.append(t.value(0).toString() + QLatin1Char('.') + t.value(1).toString());
- else
- tl.append(t.value(1).toString());
- }
- }
- if (type & QSql::SystemTables) {
- t.exec(QLatin1String("select table_name from dictionary"));
- while (t.next()) {
- tl.append(t.value(0).toString());
- }
- const QLatin1String tableQuery("select owner, table_name from all_tables where ");
- const QString where = make_where_clause(user, OrExpression);
- t.exec(tableQuery + where);
- while (t.next()) {
- if (t.value(0).toString().toUpper() != user.toUpper())
- tl.append(t.value(0).toString() + QLatin1Char('.') + t.value(1).toString());
- else
- tl.append(t.value(1).toString());
- }
-
- // list all table synonyms as well
- const QLatin1String synonymQuery("select owner, synonym_name from all_synonyms where ");
- t.exec(synonymQuery + where);
- while (t.next()) {
- if (t.value(0).toString() != d->user)
- tl.append(t.value(0).toString() + QLatin1Char('.') + t.value(1).toString());
- else
- tl.append(t.value(1).toString());
- }
- }
- return tl;
-}
-
-void qSplitTableAndOwner(const QString & tname, QString * tbl,
- QString * owner)
-{
- int i = tname.indexOf(QLatin1Char('.')); // prefixed with owner?
- if (i != -1) {
- *tbl = tname.right(tname.length() - i - 1);
- *owner = tname.left(i);
- } else {
- *tbl = tname;
- }
-}
-
-QSqlRecord QOCIDriver::record(const QString& tablename) const
-{
- Q_D(const QOCIDriver);
- QSqlRecord fil;
- if (!isOpen())
- return fil;
-
- QSqlQuery t(createResult());
- // using two separate queries for this is A LOT faster than using
- // eg. a sub-query on the sys.synonyms table
- QString stmt(QLatin1String("select column_name, data_type, data_length, "
- "data_precision, data_scale, nullable, data_default%1"
- "from all_tab_columns a "
- "where a.table_name=%2"));
- if (d->serverVersion >= 9)
- stmt = stmt.arg(QLatin1String(", char_length "));
- else
- stmt = stmt.arg(QLatin1String(" "));
- bool buildRecordInfo = false;
- QString table, owner, tmpStmt;
- qSplitTableAndOwner(tablename, &table, &owner);
-
- if (isIdentifierEscaped(table, QSqlDriver::TableName))
- table = stripDelimiters(table, QSqlDriver::TableName);
- else
- table = table.toUpper();
-
- tmpStmt = stmt.arg(QLatin1Char('\'') + table + QLatin1Char('\''));
- if (owner.isEmpty()) {
- owner = d->user;
- }
-
- if (isIdentifierEscaped(owner, QSqlDriver::TableName))
- owner = stripDelimiters(owner, QSqlDriver::TableName);
- else
- owner = owner.toUpper();
-
- tmpStmt += QLatin1String(" and a.owner='") + owner + QLatin1Char('\'');
- t.setForwardOnly(true);
- t.exec(tmpStmt);
- if (!t.next()) { // try and see if the tablename is a synonym
- stmt = stmt + QLatin1String(" join all_synonyms b "
- "on a.owner=b.table_owner and a.table_name=b.table_name "
- "where b.owner='") + owner +
- QLatin1String("' and b.synonym_name='") + table +
- QLatin1Char('\'');
- t.setForwardOnly(true);
- t.exec(stmt);
- if (t.next())
- buildRecordInfo = true;
- } else {
- buildRecordInfo = true;
- }
- QStringList keywords = QStringList() << QLatin1String("NUMBER") << QLatin1String("FLOAT") << QLatin1String("BINARY_FLOAT")
- << QLatin1String("BINARY_DOUBLE");
- if (buildRecordInfo) {
- do {
- QVariant::Type ty = qDecodeOCIType(t.value(1).toString(), t.numericalPrecisionPolicy());
- QSqlField f(t.value(0).toString(), ty);
- f.setRequired(t.value(5).toString() == QLatin1String("N"));
- f.setPrecision(t.value(4).toInt());
- if (d->serverVersion >= 9 && (ty == QVariant::String) && !t.isNull(3) && !keywords.contains(t.value(1).toString())) {
- // Oracle9: data_length == size in bytes, char_length == amount of characters
- f.setLength(t.value(7).toInt());
- } else {
- f.setLength(t.value(t.isNull(3) ? 2 : 3).toInt());
- }
- f.setDefaultValue(t.value(6));
- fil.append(f);
- } while (t.next());
- }
- return fil;
-}
-
-QSqlIndex QOCIDriver::primaryIndex(const QString& tablename) const
-{
- Q_D(const QOCIDriver);
- QSqlIndex idx(tablename);
- if (!isOpen())
- return idx;
- QSqlQuery t(createResult());
- QString stmt(QLatin1String("select b.column_name, b.index_name, a.table_name, a.owner "
- "from all_constraints a, all_ind_columns b "
- "where a.constraint_type='P' "
- "and b.index_name = a.constraint_name "
- "and b.index_owner = a.owner"));
-
- bool buildIndex = false;
- QString table, owner, tmpStmt;
- qSplitTableAndOwner(tablename, &table, &owner);
-
- if (isIdentifierEscaped(table, QSqlDriver::TableName))
- table = stripDelimiters(table, QSqlDriver::TableName);
- else
- table = table.toUpper();
-
- tmpStmt = stmt + QLatin1String(" and a.table_name='") + table + QLatin1Char('\'');
- if (owner.isEmpty()) {
- owner = d->user;
- }
-
- if (isIdentifierEscaped(owner, QSqlDriver::TableName))
- owner = stripDelimiters(owner, QSqlDriver::TableName);
- else
- owner = owner.toUpper();
-
- tmpStmt += QLatin1String(" and a.owner='") + owner + QLatin1Char('\'');
- t.setForwardOnly(true);
- t.exec(tmpStmt);
-
- if (!t.next()) {
- stmt += QLatin1String(" and a.table_name=(select tname from sys.synonyms "
- "where sname='") + table + QLatin1String("' and creator=a.owner)");
- t.setForwardOnly(true);
- t.exec(stmt);
- if (t.next()) {
- owner = t.value(3).toString();
- buildIndex = true;
- }
- } else {
- buildIndex = true;
- }
- if (buildIndex) {
- QSqlQuery tt(createResult());
- tt.setForwardOnly(true);
- idx.setName(t.value(1).toString());
- do {
- tt.exec(QLatin1String("select data_type from all_tab_columns where table_name='") +
- t.value(2).toString() + QLatin1String("' and column_name='") +
- t.value(0).toString() + QLatin1String("' and owner='") +
- owner + QLatin1Char('\''));
- if (!tt.next()) {
- return QSqlIndex();
- }
- QSqlField f(t.value(0).toString(), qDecodeOCIType(tt.value(0).toString(), t.numericalPrecisionPolicy()));
- idx.append(f);
- } while (t.next());
- return idx;
- }
- return QSqlIndex();
-}
-
-QString QOCIDriver::formatValue(const QSqlField &field, bool trimStrings) const
-{
- switch (field.type()) {
- case QVariant::DateTime: {
- QDateTime datetime = field.value().toDateTime();
- QString datestring;
- if (datetime.isValid()) {
- datestring = QLatin1String("TO_DATE('") + QString::number(datetime.date().year())
- + QLatin1Char('-')
- + QString::number(datetime.date().month()) + QLatin1Char('-')
- + QString::number(datetime.date().day()) + QLatin1Char(' ')
- + QString::number(datetime.time().hour()) + QLatin1Char(':')
- + QString::number(datetime.time().minute()) + QLatin1Char(':')
- + QString::number(datetime.time().second())
- + QLatin1String("','YYYY-MM-DD HH24:MI:SS')");
- } else {
- datestring = QLatin1String("NULL");
- }
- return datestring;
- }
- case QVariant::Time: {
- QDateTime datetime = field.value().toDateTime();
- QString datestring;
- if (datetime.isValid()) {
- datestring = QLatin1String("TO_DATE('")
- + QString::number(datetime.time().hour()) + QLatin1Char(':')
- + QString::number(datetime.time().minute()) + QLatin1Char(':')
- + QString::number(datetime.time().second())
- + QLatin1String("','HH24:MI:SS')");
- } else {
- datestring = QLatin1String("NULL");
- }
- return datestring;
- }
- case QVariant::Date: {
- QDate date = field.value().toDate();
- QString datestring;
- if (date.isValid()) {
- datestring = QLatin1String("TO_DATE('") + QString::number(date.year()) +
- QLatin1Char('-') +
- QString::number(date.month()) + QLatin1Char('-') +
- QString::number(date.day()) + QLatin1String("','YYYY-MM-DD')");
- } else {
- datestring = QLatin1String("NULL");
- }
- return datestring;
- }
- default:
- break;
- }
- return QSqlDriver::formatValue(field, trimStrings);
-}
-
-QVariant QOCIDriver::handle() const
-{
- Q_D(const QOCIDriver);
- return QVariant::fromValue(d->env);
-}
-
-QString QOCIDriver::escapeIdentifier(const QString &identifier, IdentifierType type) const
-{
- QString res = identifier;
- if(!identifier.isEmpty() && !isIdentifierEscaped(identifier, type)) {
- res.replace(QLatin1Char('"'), QLatin1String("\"\""));
- res.prepend(QLatin1Char('"')).append(QLatin1Char('"'));
- res.replace(QLatin1Char('.'), QLatin1String("\".\""));
- }
- return res;
-}
-
-QT_END_NAMESPACE
diff --git a/src/sql/drivers/oci/qsql_oci.pri b/src/sql/drivers/oci/qsql_oci.pri
deleted file mode 100644
index 66ccdb1abb..0000000000
--- a/src/sql/drivers/oci/qsql_oci.pri
+++ /dev/null
@@ -1,9 +0,0 @@
-HEADERS += $$PWD/qsql_oci_p.h
-SOURCES += $$PWD/qsql_oci.cpp
-
-unix {
- !contains(LIBS, .*clnts.*):LIBS += -lclntsh
-} else {
- LIBS *= -loci
-}
-mac:QMAKE_LFLAGS += -Wl,-flat_namespace,-U,_environ
diff --git a/src/sql/drivers/oci/qsql_oci_p.h b/src/sql/drivers/oci/qsql_oci_p.h
deleted file mode 100644
index 69911f4bee..0000000000
--- a/src/sql/drivers/oci/qsql_oci_p.h
+++ /dev/null
@@ -1,106 +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_OCI_H
-#define QSQL_OCI_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 QT_PLUGIN
-#define Q_EXPORT_SQLDRIVER_OCI
-#else
-#define Q_EXPORT_SQLDRIVER_OCI Q_SQL_EXPORT
-#endif
-
-typedef struct OCIEnv OCIEnv;
-typedef struct OCISvcCtx OCISvcCtx;
-
-QT_BEGIN_NAMESPACE
-
-class QSqlResult;
-class QOCIDriverPrivate;
-
-class Q_EXPORT_SQLDRIVER_OCI QOCIDriver : public QSqlDriver
-{
- Q_DECLARE_PRIVATE(QOCIDriver)
- Q_OBJECT
- friend class QOCICols;
- friend class QOCIResultPrivate;
-
-public:
- explicit QOCIDriver(QObject* parent = 0);
- QOCIDriver(OCIEnv* env, OCISvcCtx* ctx, QObject* parent = 0);
- ~QOCIDriver();
- bool hasFeature(DriverFeature f) const;
- bool open(const QString &db,
- const QString &user,
- const QString &password,
- const QString &host,
- int port,
- const QString &connOpts) Q_DECL_OVERRIDE;
- void close() Q_DECL_OVERRIDE;
- QSqlResult *createResult() const Q_DECL_OVERRIDE;
- QStringList tables(QSql::TableType) const Q_DECL_OVERRIDE;
- QSqlRecord record(const QString &tablename) const Q_DECL_OVERRIDE;
- QSqlIndex primaryIndex(const QString& tablename) const Q_DECL_OVERRIDE;
- QString formatValue(const QSqlField &field,
- bool trimStrings) const Q_DECL_OVERRIDE;
- QVariant handle() const Q_DECL_OVERRIDE;
- QString escapeIdentifier(const QString &identifier, IdentifierType) const Q_DECL_OVERRIDE;
-
-protected:
- bool beginTransaction() Q_DECL_OVERRIDE;
- bool commitTransaction() Q_DECL_OVERRIDE;
- bool rollbackTransaction() Q_DECL_OVERRIDE;
-};
-
-QT_END_NAMESPACE
-
-#endif // QSQL_OCI_H
diff --git a/src/sql/drivers/odbc/qsql_odbc.cpp b/src/sql/drivers/odbc/qsql_odbc.cpp
deleted file mode 100644
index 59ef42d609..0000000000
--- a/src/sql/drivers/odbc/qsql_odbc.cpp
+++ /dev/null
@@ -1,2639 +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_odbc_p.h"
-#include <qsqlrecord.h>
-
-#if defined (Q_OS_WIN32)
-#include <qt_windows.h>
-#endif
-#include <qcoreapplication.h>
-#include <qvariant.h>
-#include <qdatetime.h>
-#include <qsqlerror.h>
-#include <qsqlfield.h>
-#include <qsqlindex.h>
-#include <qstringlist.h>
-#include <qvarlengtharray.h>
-#include <qvector.h>
-#include <qmath.h>
-#include <QDebug>
-#include <QSqlQuery>
-#include <QtSql/private/qsqldriver_p.h>
-#include <QtSql/private/qsqlresult_p.h>
-
-QT_BEGIN_NAMESPACE
-
-// undefine this to prevent initial check of the ODBC driver
-#define ODBC_CHECK_DRIVER
-
-static const int COLNAMESIZE = 256;
-//Map Qt parameter types to ODBC types
-static const SQLSMALLINT qParamType[4] = { SQL_PARAM_INPUT, SQL_PARAM_INPUT, SQL_PARAM_OUTPUT, SQL_PARAM_INPUT_OUTPUT };
-
-inline static QString fromSQLTCHAR(const QVarLengthArray<SQLTCHAR>& input, int size=-1)
-{
- QString result;
-
- int realsize = qMin(size, input.size());
- if(realsize > 0 && input[realsize-1] == 0)
- realsize--;
- switch(sizeof(SQLTCHAR)) {
- case 1:
- result=QString::fromUtf8((const char *)input.constData(), realsize);
- break;
- case 2:
- result=QString::fromUtf16((const ushort *)input.constData(), realsize);
- break;
- case 4:
- result=QString::fromUcs4((const uint *)input.constData(), realsize);
- break;
- default:
- qCritical("sizeof(SQLTCHAR) is %d. Don't know how to handle this.", int(sizeof(SQLTCHAR)));
- }
- return result;
-}
-
-inline static QVarLengthArray<SQLTCHAR> toSQLTCHAR(const QString &input)
-{
- QVarLengthArray<SQLTCHAR> result;
- result.resize(input.size());
- switch(sizeof(SQLTCHAR)) {
- case 1:
- memcpy(result.data(), input.toUtf8().data(), input.size());
- break;
- case 2:
- memcpy(result.data(), input.unicode(), input.size() * 2);
- break;
- case 4:
- memcpy(result.data(), input.toUcs4().data(), input.size() * 4);
- break;
- default:
- qCritical("sizeof(SQLTCHAR) is %d. Don't know how to handle this.", int(sizeof(SQLTCHAR)));
- }
- result.append(0); // make sure it's null terminated, doesn't matter if it already is, it does if it isn't.
- return result;
-}
-
-class QODBCDriverPrivate : public QSqlDriverPrivate
-{
- Q_DECLARE_PUBLIC(QODBCDriver)
-
-public:
- enum DefaultCase{Lower, Mixed, Upper, Sensitive};
- QODBCDriverPrivate()
- : QSqlDriverPrivate(), hEnv(0), hDbc(0), unicode(false), useSchema(false), disconnectCount(0), datetime_precision(19),
- isFreeTDSDriver(false), hasSQLFetchScroll(true), hasMultiResultSets(false), isQuoteInitialized(false), quote(QLatin1Char('"'))
- {
- }
-
- SQLHANDLE hEnv;
- SQLHANDLE hDbc;
-
- bool unicode;
- bool useSchema;
- int disconnectCount;
- int datetime_precision;
- bool isFreeTDSDriver;
- bool hasSQLFetchScroll;
- bool hasMultiResultSets;
-
- bool checkDriver() const;
- void checkUnicode();
- void checkDBMS();
- void checkHasSQLFetchScroll();
- void checkHasMultiResults();
- void checkSchemaUsage();
- void checkDateTimePrecision();
- bool setConnectionOptions(const QString& connOpts);
- void splitTableQualifier(const QString &qualifier, QString &catalog,
- QString &schema, QString &table);
- DefaultCase defaultCase() const;
- QString adjustCase(const QString&) const;
- QChar quoteChar();
-private:
- bool isQuoteInitialized;
- QChar quote;
-};
-
-class QODBCResultPrivate;
-
-class QODBCResult: public QSqlResult
-{
- Q_DECLARE_PRIVATE(QODBCResult)
-
-public:
- QODBCResult(const QODBCDriver *db);
- virtual ~QODBCResult();
-
- bool prepare(const QString &query) Q_DECL_OVERRIDE;
- bool exec() Q_DECL_OVERRIDE;
-
- QVariant lastInsertId() const Q_DECL_OVERRIDE;
- QVariant handle() const Q_DECL_OVERRIDE;
-
-protected:
- bool fetchNext() Q_DECL_OVERRIDE;
- bool fetchFirst() Q_DECL_OVERRIDE;
- bool fetchLast() Q_DECL_OVERRIDE;
- bool fetchPrevious() Q_DECL_OVERRIDE;
- bool fetch(int i) Q_DECL_OVERRIDE;
- bool reset(const QString &query) Q_DECL_OVERRIDE;
- QVariant data(int field) Q_DECL_OVERRIDE;
- bool isNull(int field) Q_DECL_OVERRIDE;
- int size() Q_DECL_OVERRIDE;
- int numRowsAffected() Q_DECL_OVERRIDE;
- QSqlRecord record() const Q_DECL_OVERRIDE;
- void virtual_hook(int id, void *data) Q_DECL_OVERRIDE;
- void detachFromResultSet() Q_DECL_OVERRIDE;
- bool nextResult() Q_DECL_OVERRIDE;
-};
-
-class QODBCResultPrivate: public QSqlResultPrivate
-{
- Q_DECLARE_PUBLIC(QODBCResult)
-
-public:
- Q_DECLARE_SQLDRIVER_PRIVATE(QODBCDriver)
- QODBCResultPrivate(QODBCResult *q, const QODBCDriver *db)
- : QSqlResultPrivate(q, db),
- hStmt(0),
- useSchema(false),
- hasSQLFetchScroll(true)
- {
- unicode = drv_d_func()->unicode;
- useSchema = drv_d_func()->useSchema;
- disconnectCount = drv_d_func()->disconnectCount;
- hasSQLFetchScroll = drv_d_func()->hasSQLFetchScroll;
- }
-
- inline void clearValues()
- { fieldCache.fill(QVariant()); fieldCacheIdx = 0; }
-
- SQLHANDLE dpEnv() const { return drv_d_func() ? drv_d_func()->hEnv : 0;}
- SQLHANDLE dpDbc() const { return drv_d_func() ? drv_d_func()->hDbc : 0;}
- SQLHANDLE hStmt;
-
- bool unicode;
- bool useSchema;
-
- QSqlRecord rInf;
- QVector<QVariant> fieldCache;
- int fieldCacheIdx;
- int disconnectCount;
- bool hasSQLFetchScroll;
-
- bool isStmtHandleValid();
- void updateStmtHandleState();
-};
-
-bool QODBCResultPrivate::isStmtHandleValid()
-{
- return disconnectCount == drv_d_func()->disconnectCount;
-}
-
-void QODBCResultPrivate::updateStmtHandleState()
-{
- disconnectCount = drv_d_func()->disconnectCount;
-}
-
-static QString qWarnODBCHandle(int handleType, SQLHANDLE handle, int *nativeCode = 0)
-{
- SQLINTEGER nativeCode_ = 0;
- SQLSMALLINT msgLen = 0;
- SQLRETURN r = SQL_NO_DATA;
- SQLTCHAR state_[SQL_SQLSTATE_SIZE+1];
- QVarLengthArray<SQLTCHAR> description_(SQL_MAX_MESSAGE_LENGTH);
- QString result;
- int i = 1;
-
- description_[0] = 0;
- do {
- r = SQLGetDiagRec(handleType,
- handle,
- i,
- state_,
- &nativeCode_,
- 0,
- 0,
- &msgLen);
- if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && msgLen > 0)
- description_.resize(msgLen+1);
- r = SQLGetDiagRec(handleType,
- handle,
- i,
- state_,
- &nativeCode_,
- description_.data(),
- description_.size(),
- &msgLen);
- if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) {
- if (nativeCode)
- *nativeCode = nativeCode_;
- const QString tmpstore = fromSQLTCHAR(description_, msgLen);
- if(result != tmpstore) {
- if(!result.isEmpty())
- result += QLatin1Char(' ');
- result += tmpstore;
- }
- } else if (r == SQL_ERROR || r == SQL_INVALID_HANDLE) {
- return result;
- }
- ++i;
- } while (r != SQL_NO_DATA);
- return result;
-}
-
-static QString qODBCWarn(const SQLHANDLE hStmt, const SQLHANDLE envHandle = 0,
- const SQLHANDLE pDbC = 0, int *nativeCode = 0)
-{
- QString result;
- if (envHandle)
- result += qWarnODBCHandle(SQL_HANDLE_ENV, envHandle, nativeCode);
- if (pDbC) {
- const QString dMessage = qWarnODBCHandle(SQL_HANDLE_DBC, pDbC, nativeCode);
- if (!dMessage.isEmpty()) {
- if (!result.isEmpty())
- result += QLatin1Char(' ');
- result += dMessage;
- }
- }
- if (hStmt) {
- const QString hMessage = qWarnODBCHandle(SQL_HANDLE_STMT, hStmt, nativeCode);
- if (!hMessage.isEmpty()) {
- if (!result.isEmpty())
- result += QLatin1Char(' ');
- result += hMessage;
- }
- }
- return result;
-}
-
-static QString qODBCWarn(const QODBCResultPrivate* odbc, int *nativeCode = 0)
-{
- return qODBCWarn(odbc->hStmt, odbc->dpEnv(), odbc->dpDbc(), nativeCode);
-}
-
-static QString qODBCWarn(const QODBCDriverPrivate* odbc, int *nativeCode = 0)
-{
- return qODBCWarn(0, odbc->hEnv, odbc->hDbc, nativeCode);
-}
-
-static void qSqlWarning(const QString& message, const QODBCResultPrivate* odbc)
-{
- qWarning() << message << "\tError:" << qODBCWarn(odbc);
-}
-
-static void qSqlWarning(const QString &message, const QODBCDriverPrivate *odbc)
-{
- qWarning() << message << "\tError:" << qODBCWarn(odbc);
-}
-
-static void qSqlWarning(const QString &message, const SQLHANDLE hStmt)
-{
- qWarning() << message << "\tError:" << qODBCWarn(hStmt);
-}
-
-static QSqlError qMakeError(const QString& err, QSqlError::ErrorType type, const QODBCResultPrivate* p)
-{
- int nativeCode = -1;
- QString message = qODBCWarn(p, &nativeCode);
- return QSqlError(QLatin1String("QODBC3: ") + err, message, type, nativeCode);
-}
-
-static QSqlError qMakeError(const QString& err, QSqlError::ErrorType type,
- const QODBCDriverPrivate* p)
-{
- int nativeCode = -1;
- QString message = qODBCWarn(p, &nativeCode);
- return QSqlError(QLatin1String("QODBC3: ") + err, qODBCWarn(p), type, nativeCode);
-}
-
-static QVariant::Type qDecodeODBCType(SQLSMALLINT sqltype, bool isSigned = true)
-{
- QVariant::Type type = QVariant::Invalid;
- switch (sqltype) {
- case SQL_DECIMAL:
- case SQL_NUMERIC:
- case SQL_REAL:
- case SQL_FLOAT:
- case SQL_DOUBLE:
- type = QVariant::Double;
- break;
- case SQL_SMALLINT:
- case SQL_INTEGER:
- case SQL_BIT:
- type = isSigned ? QVariant::Int : QVariant::UInt;
- break;
- case SQL_TINYINT:
- type = QVariant::UInt;
- break;
- case SQL_BIGINT:
- type = isSigned ? QVariant::LongLong : QVariant::ULongLong;
- break;
- case SQL_BINARY:
- case SQL_VARBINARY:
- case SQL_LONGVARBINARY:
- type = QVariant::ByteArray;
- break;
- case SQL_DATE:
- case SQL_TYPE_DATE:
- type = QVariant::Date;
- break;
- case SQL_TIME:
- case SQL_TYPE_TIME:
- type = QVariant::Time;
- break;
- case SQL_TIMESTAMP:
- case SQL_TYPE_TIMESTAMP:
- type = QVariant::DateTime;
- break;
- case SQL_WCHAR:
- case SQL_WVARCHAR:
- case SQL_WLONGVARCHAR:
- type = QVariant::String;
- break;
- case SQL_CHAR:
- case SQL_VARCHAR:
-#if (ODBCVER >= 0x0350)
- case SQL_GUID:
-#endif
- case SQL_LONGVARCHAR:
- type = QVariant::String;
- break;
- default:
- type = QVariant::ByteArray;
- break;
- }
- return type;
-}
-
-static QString qGetStringData(SQLHANDLE hStmt, int column, int colSize, bool unicode = false)
-{
- QString fieldVal;
- SQLRETURN r = SQL_ERROR;
- SQLLEN lengthIndicator = 0;
-
- // NB! colSize must be a multiple of 2 for unicode enabled DBs
- if (colSize <= 0) {
- colSize = 256;
- } else if (colSize > 65536) { // limit buffer size to 64 KB
- colSize = 65536;
- } else {
- colSize++; // make sure there is room for more than the 0 termination
- }
- if(unicode) {
- r = SQLGetData(hStmt,
- column+1,
- SQL_C_TCHAR,
- NULL,
- 0,
- &lengthIndicator);
- if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && lengthIndicator > 0)
- colSize = int(lengthIndicator / sizeof(SQLTCHAR) + 1);
- QVarLengthArray<SQLTCHAR> buf(colSize);
- memset(buf.data(), 0, colSize*sizeof(SQLTCHAR));
- while (true) {
- r = SQLGetData(hStmt,
- column+1,
- SQL_C_TCHAR,
- (SQLPOINTER)buf.data(),
- colSize*sizeof(SQLTCHAR),
- &lengthIndicator);
- if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) {
- if (lengthIndicator == SQL_NULL_DATA) {
- fieldVal.clear();
- break;
- }
- // starting with ODBC Native Client 2012, SQL_NO_TOTAL is returned
- // instead of the length (which sometimes was wrong in older versions)
- // see link for more info: http://msdn.microsoft.com/en-us/library/jj219209.aspx
- // if length indicator equals SQL_NO_TOTAL, indicating that
- // more data can be fetched, but size not known, collect data
- // and fetch next block
- if (lengthIndicator == SQL_NO_TOTAL) {
- fieldVal += fromSQLTCHAR(buf, colSize);
- continue;
- }
- // if SQL_SUCCESS_WITH_INFO is returned, indicating that
- // more data can be fetched, the length indicator does NOT
- // contain the number of bytes returned - it contains the
- // total number of bytes that CAN be fetched
- // colSize-1: remove 0 termination when there is more data to fetch
- int rSize = (r == SQL_SUCCESS_WITH_INFO) ? colSize : int(lengthIndicator / sizeof(SQLTCHAR));
- fieldVal += fromSQLTCHAR(buf, rSize);
- if (lengthIndicator < SQLLEN(colSize*sizeof(SQLTCHAR))) {
- // workaround for Drivermanagers that don't return SQL_NO_DATA
- break;
- }
- } else if (r == SQL_NO_DATA) {
- break;
- } else {
- qWarning() << "qGetStringData: Error while fetching data (" << qWarnODBCHandle(SQL_HANDLE_STMT, hStmt) << ')';
- fieldVal.clear();
- break;
- }
- }
- } else {
- r = SQLGetData(hStmt,
- column+1,
- SQL_C_CHAR,
- NULL,
- 0,
- &lengthIndicator);
- if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && lengthIndicator > 0)
- colSize = lengthIndicator + 1;
- QVarLengthArray<SQLCHAR> buf(colSize);
- while (true) {
- r = SQLGetData(hStmt,
- column+1,
- SQL_C_CHAR,
- (SQLPOINTER)buf.data(),
- colSize,
- &lengthIndicator);
- if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) {
- if (lengthIndicator == SQL_NULL_DATA || lengthIndicator == SQL_NO_TOTAL) {
- fieldVal.clear();
- break;
- }
- // if SQL_SUCCESS_WITH_INFO is returned, indicating that
- // more data can be fetched, the length indicator does NOT
- // contain the number of bytes returned - it contains the
- // total number of bytes that CAN be fetched
- // colSize-1: remove 0 termination when there is more data to fetch
- int rSize = (r == SQL_SUCCESS_WITH_INFO) ? colSize : lengthIndicator;
- fieldVal += QString::fromUtf8((const char *)buf.constData(), rSize);
- if (lengthIndicator < SQLLEN(colSize)) {
- // workaround for Drivermanagers that don't return SQL_NO_DATA
- break;
- }
- } else if (r == SQL_NO_DATA) {
- break;
- } else {
- qWarning() << "qGetStringData: Error while fetching data (" << qWarnODBCHandle(SQL_HANDLE_STMT, hStmt) << ')';
- fieldVal.clear();
- break;
- }
- }
- }
- return fieldVal;
-}
-
-static QVariant qGetBinaryData(SQLHANDLE hStmt, int column)
-{
- QByteArray fieldVal;
- SQLSMALLINT colNameLen;
- SQLSMALLINT colType;
- SQLULEN colSize;
- SQLSMALLINT colScale;
- SQLSMALLINT nullable;
- SQLLEN lengthIndicator = 0;
- SQLRETURN r = SQL_ERROR;
-
- QVarLengthArray<SQLTCHAR> colName(COLNAMESIZE);
-
- r = SQLDescribeCol(hStmt,
- column + 1,
- colName.data(),
- COLNAMESIZE,
- &colNameLen,
- &colType,
- &colSize,
- &colScale,
- &nullable);
- if (r != SQL_SUCCESS)
- qWarning() << "qGetBinaryData: Unable to describe column" << column;
- // SQLDescribeCol may return 0 if size cannot be determined
- if (!colSize)
- colSize = 255;
- else if (colSize > 65536) // read the field in 64 KB chunks
- colSize = 65536;
- fieldVal.resize(colSize);
- ulong read = 0;
- while (true) {
- r = SQLGetData(hStmt,
- column+1,
- SQL_C_BINARY,
- const_cast<char *>(fieldVal.constData() + read),
- colSize,
- &lengthIndicator);
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO)
- break;
- if (lengthIndicator == SQL_NULL_DATA)
- return QVariant(QVariant::ByteArray);
- if (lengthIndicator > SQLLEN(colSize) || lengthIndicator == SQL_NO_TOTAL) {
- read += colSize;
- colSize = 65536;
- } else {
- read += lengthIndicator;
- }
- if (r == SQL_SUCCESS) { // the whole field was read in one chunk
- fieldVal.resize(read);
- break;
- }
- fieldVal.resize(fieldVal.size() + colSize);
- }
- return fieldVal;
-}
-
-static QVariant qGetIntData(SQLHANDLE hStmt, int column, bool isSigned = true)
-{
- SQLINTEGER intbuf = 0;
- SQLLEN lengthIndicator = 0;
- SQLRETURN r = SQLGetData(hStmt,
- column+1,
- isSigned ? SQL_C_SLONG : SQL_C_ULONG,
- (SQLPOINTER)&intbuf,
- sizeof(intbuf),
- &lengthIndicator);
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO)
- return QVariant(QVariant::Invalid);
- if (lengthIndicator == SQL_NULL_DATA)
- return QVariant(QVariant::Int);
- if (isSigned)
- return int(intbuf);
- else
- return uint(intbuf);
-}
-
-static QVariant qGetDoubleData(SQLHANDLE hStmt, int column)
-{
- SQLDOUBLE dblbuf;
- SQLLEN lengthIndicator = 0;
- SQLRETURN r = SQLGetData(hStmt,
- column+1,
- SQL_C_DOUBLE,
- (SQLPOINTER) &dblbuf,
- 0,
- &lengthIndicator);
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
- return QVariant(QVariant::Invalid);
- }
- if(lengthIndicator == SQL_NULL_DATA)
- return QVariant(QVariant::Double);
-
- return (double) dblbuf;
-}
-
-
-static QVariant qGetBigIntData(SQLHANDLE hStmt, int column, bool isSigned = true)
-{
- SQLBIGINT lngbuf = 0;
- SQLLEN lengthIndicator = 0;
- SQLRETURN r = SQLGetData(hStmt,
- column+1,
- isSigned ? SQL_C_SBIGINT : SQL_C_UBIGINT,
- (SQLPOINTER) &lngbuf,
- sizeof(lngbuf),
- &lengthIndicator);
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO)
- return QVariant(QVariant::Invalid);
- if (lengthIndicator == SQL_NULL_DATA)
- return QVariant(QVariant::LongLong);
-
- if (isSigned)
- return qint64(lngbuf);
- else
- return quint64(lngbuf);
-}
-
-static bool isAutoValue(const SQLHANDLE hStmt, int column)
-{
- SQLLEN nNumericAttribute = 0; // Check for auto-increment
- const SQLRETURN r = ::SQLColAttribute(hStmt, column + 1, SQL_DESC_AUTO_UNIQUE_VALUE,
- 0, 0, 0, &nNumericAttribute);
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
- qSqlWarning(QStringLiteral("qMakeField: Unable to get autovalue attribute for column ")
- + QString::number(column), hStmt);
- return false;
- }
- return nNumericAttribute != SQL_FALSE;
-}
-
-static QSqlField qMakeFieldInfo(const SQLHANDLE hStmt, int i, QString *errorMessage);
-
-// creates a QSqlField from a valid hStmt generated
-// by SQLColumns. The hStmt has to point to a valid position.
-static QSqlField qMakeFieldInfo(const SQLHANDLE hStmt, const QODBCDriverPrivate* p)
-{
- QString fname = qGetStringData(hStmt, 3, -1, p->unicode);
- int type = qGetIntData(hStmt, 4).toInt(); // column type
- QSqlField f(fname, qDecodeODBCType(type, p));
- QVariant var = qGetIntData(hStmt, 6);
- f.setLength(var.isNull() ? -1 : var.toInt()); // column size
- var = qGetIntData(hStmt, 8).toInt();
- f.setPrecision(var.isNull() ? -1 : var.toInt()); // precision
- f.setSqlType(type);
- int required = qGetIntData(hStmt, 10).toInt(); // nullable-flag
- // required can be SQL_NO_NULLS, SQL_NULLABLE or SQL_NULLABLE_UNKNOWN
- if (required == SQL_NO_NULLS)
- f.setRequired(true);
- else if (required == SQL_NULLABLE)
- f.setRequired(false);
- // else we don't know
- return f;
-}
-
-static QSqlField qMakeFieldInfo(const QODBCResultPrivate* p, int i )
-{
- QString errorMessage;
- const QSqlField result = qMakeFieldInfo(p->hStmt, i, &errorMessage);
- if (!errorMessage.isEmpty())
- qSqlWarning(errorMessage, p);
- return result;
-}
-
-static QSqlField qMakeFieldInfo(const SQLHANDLE hStmt, int i, QString *errorMessage)
-{
- SQLSMALLINT colNameLen;
- SQLSMALLINT colType;
- SQLULEN colSize;
- SQLSMALLINT colScale;
- SQLSMALLINT nullable;
- SQLRETURN r = SQL_ERROR;
- QVarLengthArray<SQLTCHAR> colName(COLNAMESIZE);
- errorMessage->clear();
- r = SQLDescribeCol(hStmt,
- i+1,
- colName.data(),
- (SQLSMALLINT)COLNAMESIZE,
- &colNameLen,
- &colType,
- &colSize,
- &colScale,
- &nullable);
-
- if (r != SQL_SUCCESS) {
- *errorMessage = QStringLiteral("qMakeField: Unable to describe column ") + QString::number(i);
- return QSqlField();
- }
-
- SQLLEN unsignedFlag = SQL_FALSE;
- r = SQLColAttribute (hStmt,
- i + 1,
- SQL_DESC_UNSIGNED,
- 0,
- 0,
- 0,
- &unsignedFlag);
- if (r != SQL_SUCCESS) {
- qSqlWarning(QStringLiteral("qMakeField: Unable to get column attributes for column ")
- + QString::number(i), hStmt);
- }
-
- const QString qColName(fromSQLTCHAR(colName, colNameLen));
- // nullable can be SQL_NO_NULLS, SQL_NULLABLE or SQL_NULLABLE_UNKNOWN
- QVariant::Type type = qDecodeODBCType(colType, unsignedFlag == SQL_FALSE);
- QSqlField f(qColName, type);
- f.setSqlType(colType);
- f.setLength(colSize == 0 ? -1 : int(colSize));
- f.setPrecision(colScale == 0 ? -1 : int(colScale));
- if (nullable == SQL_NO_NULLS)
- f.setRequired(true);
- else if (nullable == SQL_NULLABLE)
- f.setRequired(false);
- // else we don't know
- f.setAutoValue(isAutoValue(hStmt, i));
- return f;
-}
-
-static size_t qGetODBCVersion(const QString &connOpts)
-{
- if (connOpts.contains(QLatin1String("SQL_ATTR_ODBC_VERSION=SQL_OV_ODBC3"), Qt::CaseInsensitive))
- return SQL_OV_ODBC3;
- return SQL_OV_ODBC2;
-}
-
-QChar QODBCDriverPrivate::quoteChar()
-{
- if (!isQuoteInitialized) {
- SQLTCHAR driverResponse[4];
- SQLSMALLINT length;
- int r = SQLGetInfo(hDbc,
- SQL_IDENTIFIER_QUOTE_CHAR,
- &driverResponse,
- sizeof(driverResponse),
- &length);
- if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO)
- quote = QChar(driverResponse[0]);
- else
- quote = QLatin1Char('"');
- isQuoteInitialized = true;
- }
- return quote;
-}
-
-
-bool QODBCDriverPrivate::setConnectionOptions(const QString& connOpts)
-{
- // Set any connection attributes
- const QStringList opts(connOpts.split(QLatin1Char(';'), QString::SkipEmptyParts));
- SQLRETURN r = SQL_SUCCESS;
- for (int i = 0; i < opts.count(); ++i) {
- const QString tmp(opts.at(i));
- int idx;
- if ((idx = tmp.indexOf(QLatin1Char('='))) == -1) {
- qWarning() << "QODBCDriver::open: Illegal connect option value '" << tmp << '\'';
- continue;
- }
- const QString opt(tmp.left(idx));
- const QString val(tmp.mid(idx + 1).simplified());
- SQLUINTEGER v = 0;
-
- r = SQL_SUCCESS;
- if (opt.toUpper() == QLatin1String("SQL_ATTR_ACCESS_MODE")) {
- if (val.toUpper() == QLatin1String("SQL_MODE_READ_ONLY")) {
- v = SQL_MODE_READ_ONLY;
- } else if (val.toUpper() == QLatin1String("SQL_MODE_READ_WRITE")) {
- v = SQL_MODE_READ_WRITE;
- } else {
- qWarning() << "QODBCDriver::open: Unknown option value '" << val << '\'';
- continue;
- }
- r = SQLSetConnectAttr(hDbc, SQL_ATTR_ACCESS_MODE, (SQLPOINTER) size_t(v), 0);
- } else if (opt.toUpper() == QLatin1String("SQL_ATTR_CONNECTION_TIMEOUT")) {
- v = val.toUInt();
- r = SQLSetConnectAttr(hDbc, SQL_ATTR_CONNECTION_TIMEOUT, (SQLPOINTER) size_t(v), 0);
- } else if (opt.toUpper() == QLatin1String("SQL_ATTR_LOGIN_TIMEOUT")) {
- v = val.toUInt();
- r = SQLSetConnectAttr(hDbc, SQL_ATTR_LOGIN_TIMEOUT, (SQLPOINTER) size_t(v), 0);
- } else if (opt.toUpper() == QLatin1String("SQL_ATTR_CURRENT_CATALOG")) {
- val.utf16(); // 0 terminate
- r = SQLSetConnectAttr(hDbc, SQL_ATTR_CURRENT_CATALOG,
- toSQLTCHAR(val).data(),
- val.length()*sizeof(SQLTCHAR));
- } else if (opt.toUpper() == QLatin1String("SQL_ATTR_METADATA_ID")) {
- if (val.toUpper() == QLatin1String("SQL_TRUE")) {
- v = SQL_TRUE;
- } else if (val.toUpper() == QLatin1String("SQL_FALSE")) {
- v = SQL_FALSE;
- } else {
- qWarning() << "QODBCDriver::open: Unknown option value '" << val << '\'';
- continue;
- }
- r = SQLSetConnectAttr(hDbc, SQL_ATTR_METADATA_ID, (SQLPOINTER) size_t(v), 0);
- } else if (opt.toUpper() == QLatin1String("SQL_ATTR_PACKET_SIZE")) {
- v = val.toUInt();
- r = SQLSetConnectAttr(hDbc, SQL_ATTR_PACKET_SIZE, (SQLPOINTER) size_t(v), 0);
- } else if (opt.toUpper() == QLatin1String("SQL_ATTR_TRACEFILE")) {
- val.utf16(); // 0 terminate
- r = SQLSetConnectAttr(hDbc, SQL_ATTR_TRACEFILE,
- toSQLTCHAR(val).data(),
- val.length()*sizeof(SQLTCHAR));
- } else if (opt.toUpper() == QLatin1String("SQL_ATTR_TRACE")) {
- if (val.toUpper() == QLatin1String("SQL_OPT_TRACE_OFF")) {
- v = SQL_OPT_TRACE_OFF;
- } else if (val.toUpper() == QLatin1String("SQL_OPT_TRACE_ON")) {
- v = SQL_OPT_TRACE_ON;
- } else {
- qWarning() << "QODBCDriver::open: Unknown option value '" << val << '\'';
- continue;
- }
- r = SQLSetConnectAttr(hDbc, SQL_ATTR_TRACE, (SQLPOINTER) size_t(v), 0);
- } else if (opt.toUpper() == QLatin1String("SQL_ATTR_CONNECTION_POOLING")) {
- if (val == QLatin1String("SQL_CP_OFF"))
- v = SQL_CP_OFF;
- else if (val.toUpper() == QLatin1String("SQL_CP_ONE_PER_DRIVER"))
- v = SQL_CP_ONE_PER_DRIVER;
- else if (val.toUpper() == QLatin1String("SQL_CP_ONE_PER_HENV"))
- v = SQL_CP_ONE_PER_HENV;
- else if (val.toUpper() == QLatin1String("SQL_CP_DEFAULT"))
- v = SQL_CP_DEFAULT;
- else {
- qWarning() << "QODBCDriver::open: Unknown option value '" << val << '\'';
- continue;
- }
- r = SQLSetConnectAttr(hDbc, SQL_ATTR_CONNECTION_POOLING, (SQLPOINTER) size_t(v), 0);
- } else if (opt.toUpper() == QLatin1String("SQL_ATTR_CP_MATCH")) {
- if (val.toUpper() == QLatin1String("SQL_CP_STRICT_MATCH"))
- v = SQL_CP_STRICT_MATCH;
- else if (val.toUpper() == QLatin1String("SQL_CP_RELAXED_MATCH"))
- v = SQL_CP_RELAXED_MATCH;
- else if (val.toUpper() == QLatin1String("SQL_CP_MATCH_DEFAULT"))
- v = SQL_CP_MATCH_DEFAULT;
- else {
- qWarning() << "QODBCDriver::open: Unknown option value '" << val << '\'';
- continue;
- }
- r = SQLSetConnectAttr(hDbc, SQL_ATTR_CP_MATCH, (SQLPOINTER) size_t(v), 0);
- } else if (opt.toUpper() == QLatin1String("SQL_ATTR_ODBC_VERSION")) {
- // Already handled in QODBCDriver::open()
- continue;
- } else {
- qWarning() << "QODBCDriver::open: Unknown connection attribute '" << opt << '\'';
- }
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO)
- qSqlWarning(QString::fromLatin1("QODBCDriver::open: Unable to set connection attribute'%1'").arg(
- opt), this);
- }
- return true;
-}
-
-void QODBCDriverPrivate::splitTableQualifier(const QString & qualifier, QString &catalog,
- QString &schema, QString &table)
-{
- if (!useSchema) {
- table = qualifier;
- return;
- }
- QStringList l = qualifier.split(QLatin1Char('.'));
- if (l.count() > 3)
- return; // can't possibly be a valid table qualifier
- int i = 0, n = l.count();
- if (n == 1) {
- table = qualifier;
- } else {
- for (QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
- if (n == 3) {
- if (i == 0) {
- catalog = *it;
- } else if (i == 1) {
- schema = *it;
- } else if (i == 2) {
- table = *it;
- }
- } else if (n == 2) {
- if (i == 0) {
- schema = *it;
- } else if (i == 1) {
- table = *it;
- }
- }
- i++;
- }
- }
-}
-
-QODBCDriverPrivate::DefaultCase QODBCDriverPrivate::defaultCase() const
-{
- DefaultCase ret;
- SQLUSMALLINT casing;
- int r = SQLGetInfo(hDbc,
- SQL_IDENTIFIER_CASE,
- &casing,
- sizeof(casing),
- NULL);
- if ( r != SQL_SUCCESS)
- ret = Mixed;//arbitrary case if driver cannot be queried
- else {
- switch (casing) {
- case (SQL_IC_UPPER):
- ret = Upper;
- break;
- case (SQL_IC_LOWER):
- ret = Lower;
- break;
- case (SQL_IC_SENSITIVE):
- ret = Sensitive;
- break;
- case (SQL_IC_MIXED):
- default:
- ret = Mixed;
- break;
- }
- }
- return ret;
-}
-
-/*
- Adjust the casing of an identifier to match what the
- database engine would have done to it.
-*/
-QString QODBCDriverPrivate::adjustCase(const QString &identifier) const
-{
- QString ret = identifier;
- switch(defaultCase()) {
- case (Lower):
- ret = identifier.toLower();
- break;
- case (Upper):
- ret = identifier.toUpper();
- break;
- case(Mixed):
- case(Sensitive):
- default:
- ret = identifier;
- }
- return ret;
-}
-
-////////////////////////////////////////////////////////////////////////////
-
-QODBCResult::QODBCResult(const QODBCDriver *db)
- : QSqlResult(*new QODBCResultPrivate(this, db))
-{
-}
-
-QODBCResult::~QODBCResult()
-{
- Q_D(QODBCResult);
- if (d->hStmt && d->isStmtHandleValid() && driver()->isOpen()) {
- SQLRETURN r = SQLFreeHandle(SQL_HANDLE_STMT, d->hStmt);
- if (r != SQL_SUCCESS)
- qSqlWarning(QLatin1String("QODBCDriver: Unable to free statement handle ")
- + QString::number(r), d);
- }
-}
-
-bool QODBCResult::reset (const QString& query)
-{
- Q_D(QODBCResult);
- setActive(false);
- setAt(QSql::BeforeFirstRow);
- d->rInf.clear();
- d->fieldCache.clear();
- d->fieldCacheIdx = 0;
-
- // Always reallocate the statement handle - the statement attributes
- // are not reset if SQLFreeStmt() is called which causes some problems.
- SQLRETURN r;
- if (d->hStmt && d->isStmtHandleValid()) {
- r = SQLFreeHandle(SQL_HANDLE_STMT, d->hStmt);
- if (r != SQL_SUCCESS) {
- qSqlWarning(QLatin1String("QODBCResult::reset: Unable to free statement handle"), d);
- return false;
- }
- }
- r = SQLAllocHandle(SQL_HANDLE_STMT,
- d->dpDbc(),
- &d->hStmt);
- if (r != SQL_SUCCESS) {
- qSqlWarning(QLatin1String("QODBCResult::reset: Unable to allocate statement handle"), d);
- return false;
- }
-
- d->updateStmtHandleState();
-
- if (isForwardOnly()) {
- r = SQLSetStmtAttr(d->hStmt,
- SQL_ATTR_CURSOR_TYPE,
- (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY,
- SQL_IS_UINTEGER);
- } else {
- r = SQLSetStmtAttr(d->hStmt,
- SQL_ATTR_CURSOR_TYPE,
- (SQLPOINTER)SQL_CURSOR_STATIC,
- SQL_IS_UINTEGER);
- }
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
- setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
- "QODBCResult::reset: Unable to set 'SQL_CURSOR_STATIC' as statement attribute. "
- "Please check your ODBC driver configuration"), QSqlError::StatementError, d));
- return false;
- }
-
- r = SQLExecDirect(d->hStmt,
- toSQLTCHAR(query).data(),
- (SQLINTEGER) query.length());
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO && r!= SQL_NO_DATA) {
- setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
- "Unable to execute statement"), QSqlError::StatementError, d));
- return false;
- }
-
- SQLULEN isScrollable = 0;
- r = SQLGetStmtAttr(d->hStmt, SQL_ATTR_CURSOR_SCROLLABLE, &isScrollable, SQL_IS_INTEGER, 0);
- if(r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO)
- setForwardOnly(isScrollable == SQL_NONSCROLLABLE);
-
- SQLSMALLINT count = 0;
- SQLNumResultCols(d->hStmt, &count);
- if (count) {
- setSelect(true);
- for (int i = 0; i < count; ++i) {
- d->rInf.append(qMakeFieldInfo(d, i));
- }
- d->fieldCache.resize(count);
- } else {
- setSelect(false);
- }
- setActive(true);
-
- return true;
-}
-
-bool QODBCResult::fetch(int i)
-{
- Q_D(QODBCResult);
- if (!driver()->isOpen())
- return false;
-
- if (isForwardOnly() && i < at())
- return false;
- if (i == at())
- return true;
- d->clearValues();
- int actualIdx = i + 1;
- if (actualIdx <= 0) {
- setAt(QSql::BeforeFirstRow);
- return false;
- }
- SQLRETURN r;
- if (isForwardOnly()) {
- bool ok = true;
- while (ok && i > at())
- ok = fetchNext();
- return ok;
- } else {
- r = SQLFetchScroll(d->hStmt,
- SQL_FETCH_ABSOLUTE,
- actualIdx);
- }
- if (r != SQL_SUCCESS) {
- if (r != SQL_NO_DATA)
- setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
- "Unable to fetch"), QSqlError::ConnectionError, d));
- return false;
- }
- setAt(i);
- return true;
-}
-
-bool QODBCResult::fetchNext()
-{
- Q_D(QODBCResult);
- SQLRETURN r;
- d->clearValues();
-
- if (d->hasSQLFetchScroll)
- r = SQLFetchScroll(d->hStmt,
- SQL_FETCH_NEXT,
- 0);
- else
- r = SQLFetch(d->hStmt);
-
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
- if (r != SQL_NO_DATA)
- setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
- "Unable to fetch next"), QSqlError::ConnectionError, d));
- return false;
- }
- setAt(at() + 1);
- return true;
-}
-
-bool QODBCResult::fetchFirst()
-{
- Q_D(QODBCResult);
- if (isForwardOnly() && at() != QSql::BeforeFirstRow)
- return false;
- SQLRETURN r;
- d->clearValues();
- if (isForwardOnly()) {
- return fetchNext();
- }
- r = SQLFetchScroll(d->hStmt,
- SQL_FETCH_FIRST,
- 0);
- if (r != SQL_SUCCESS) {
- if (r != SQL_NO_DATA)
- setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
- "Unable to fetch first"), QSqlError::ConnectionError, d));
- return false;
- }
- setAt(0);
- return true;
-}
-
-bool QODBCResult::fetchPrevious()
-{
- Q_D(QODBCResult);
- if (isForwardOnly())
- return false;
- SQLRETURN r;
- d->clearValues();
- r = SQLFetchScroll(d->hStmt,
- SQL_FETCH_PRIOR,
- 0);
- if (r != SQL_SUCCESS) {
- if (r != SQL_NO_DATA)
- setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
- "Unable to fetch previous"), QSqlError::ConnectionError, d));
- return false;
- }
- setAt(at() - 1);
- return true;
-}
-
-bool QODBCResult::fetchLast()
-{
- Q_D(QODBCResult);
- SQLRETURN r;
- d->clearValues();
-
- if (isForwardOnly()) {
- // cannot seek to last row in forwardOnly mode, so we have to use brute force
- int i = at();
- if (i == QSql::AfterLastRow)
- return false;
- if (i == QSql::BeforeFirstRow)
- i = 0;
- while (fetchNext())
- ++i;
- setAt(i);
- return true;
- }
-
- r = SQLFetchScroll(d->hStmt,
- SQL_FETCH_LAST,
- 0);
- if (r != SQL_SUCCESS) {
- if (r != SQL_NO_DATA)
- setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
- "Unable to fetch last"), QSqlError::ConnectionError, d));
- return false;
- }
- SQLULEN currRow = 0;
- r = SQLGetStmtAttr(d->hStmt,
- SQL_ROW_NUMBER,
- &currRow,
- SQL_IS_INTEGER,
- 0);
- if (r != SQL_SUCCESS)
- return false;
- setAt(currRow-1);
- return true;
-}
-
-QVariant QODBCResult::data(int field)
-{
- Q_D(QODBCResult);
- if (field >= d->rInf.count() || field < 0) {
- qWarning() << "QODBCResult::data: column" << field << "out of range";
- return QVariant();
- }
- if (field < d->fieldCacheIdx)
- return d->fieldCache.at(field);
-
- SQLRETURN r(0);
- SQLLEN lengthIndicator = 0;
-
- for (int i = d->fieldCacheIdx; i <= field; ++i) {
- // some servers do not support fetching column n after we already
- // fetched column n+1, so cache all previous columns here
- const QSqlField info = d->rInf.field(i);
- switch (info.type()) {
- case QVariant::LongLong:
- d->fieldCache[i] = qGetBigIntData(d->hStmt, i);
- break;
- case QVariant::ULongLong:
- d->fieldCache[i] = qGetBigIntData(d->hStmt, i, false);
- break;
- case QVariant::Int:
- d->fieldCache[i] = qGetIntData(d->hStmt, i);
- break;
- case QVariant::UInt:
- d->fieldCache[i] = qGetIntData(d->hStmt, i, false);
- break;
- case QVariant::Date:
- DATE_STRUCT dbuf;
- r = SQLGetData(d->hStmt,
- i + 1,
- SQL_C_DATE,
- (SQLPOINTER)&dbuf,
- 0,
- &lengthIndicator);
- if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && (lengthIndicator != SQL_NULL_DATA))
- d->fieldCache[i] = QVariant(QDate(dbuf.year, dbuf.month, dbuf.day));
- else
- d->fieldCache[i] = QVariant(QVariant::Date);
- break;
- case QVariant::Time:
- TIME_STRUCT tbuf;
- r = SQLGetData(d->hStmt,
- i + 1,
- SQL_C_TIME,
- (SQLPOINTER)&tbuf,
- 0,
- &lengthIndicator);
- if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && (lengthIndicator != SQL_NULL_DATA))
- d->fieldCache[i] = QVariant(QTime(tbuf.hour, tbuf.minute, tbuf.second));
- else
- d->fieldCache[i] = QVariant(QVariant::Time);
- break;
- case QVariant::DateTime:
- TIMESTAMP_STRUCT dtbuf;
- r = SQLGetData(d->hStmt,
- i + 1,
- SQL_C_TIMESTAMP,
- (SQLPOINTER)&dtbuf,
- 0,
- &lengthIndicator);
- if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && (lengthIndicator != SQL_NULL_DATA))
- d->fieldCache[i] = QVariant(QDateTime(QDate(dtbuf.year, dtbuf.month, dtbuf.day),
- QTime(dtbuf.hour, dtbuf.minute, dtbuf.second, dtbuf.fraction / 1000000)));
- else
- d->fieldCache[i] = QVariant(QVariant::DateTime);
- break;
- case QVariant::ByteArray:
- d->fieldCache[i] = qGetBinaryData(d->hStmt, i);
- break;
- case QVariant::String:
- d->fieldCache[i] = qGetStringData(d->hStmt, i, info.length(), d->unicode);
- break;
- case QVariant::Double:
- switch(numericalPrecisionPolicy()) {
- case QSql::LowPrecisionInt32:
- d->fieldCache[i] = qGetIntData(d->hStmt, i);
- break;
- case QSql::LowPrecisionInt64:
- d->fieldCache[i] = qGetBigIntData(d->hStmt, i);
- break;
- case QSql::LowPrecisionDouble:
- d->fieldCache[i] = qGetDoubleData(d->hStmt, i);
- break;
- case QSql::HighPrecision:
- d->fieldCache[i] = qGetStringData(d->hStmt, i, info.length(), false);
- break;
- }
- break;
- default:
- d->fieldCache[i] = QVariant(qGetStringData(d->hStmt, i, info.length(), false));
- break;
- }
- d->fieldCacheIdx = field + 1;
- }
- return d->fieldCache[field];
-}
-
-bool QODBCResult::isNull(int field)
-{
- Q_D(const QODBCResult);
- if (field < 0 || field > d->fieldCache.size())
- return true;
- if (field <= d->fieldCacheIdx) {
- // since there is no good way to find out whether the value is NULL
- // without fetching the field we'll fetch it here.
- // (data() also sets the NULL flag)
- data(field);
- }
- return d->fieldCache.at(field).isNull();
-}
-
-int QODBCResult::size()
-{
- return -1;
-}
-
-int QODBCResult::numRowsAffected()
-{
- Q_D(QODBCResult);
- SQLLEN affectedRowCount = 0;
- SQLRETURN r = SQLRowCount(d->hStmt, &affectedRowCount);
- if (r == SQL_SUCCESS)
- return affectedRowCount;
- else
- qSqlWarning(QLatin1String("QODBCResult::numRowsAffected: Unable to count affected rows"), d);
- return -1;
-}
-
-bool QODBCResult::prepare(const QString& query)
-{
- Q_D(QODBCResult);
- setActive(false);
- setAt(QSql::BeforeFirstRow);
- SQLRETURN r;
-
- d->rInf.clear();
- if (d->hStmt && d->isStmtHandleValid()) {
- r = SQLFreeHandle(SQL_HANDLE_STMT, d->hStmt);
- if (r != SQL_SUCCESS) {
- qSqlWarning(QLatin1String("QODBCResult::prepare: Unable to close statement"), d);
- return false;
- }
- }
- r = SQLAllocHandle(SQL_HANDLE_STMT,
- d->dpDbc(),
- &d->hStmt);
- if (r != SQL_SUCCESS) {
- qSqlWarning(QLatin1String("QODBCResult::prepare: Unable to allocate statement handle"), d);
- return false;
- }
-
- d->updateStmtHandleState();
-
- if (isForwardOnly()) {
- r = SQLSetStmtAttr(d->hStmt,
- SQL_ATTR_CURSOR_TYPE,
- (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY,
- SQL_IS_UINTEGER);
- } else {
- r = SQLSetStmtAttr(d->hStmt,
- SQL_ATTR_CURSOR_TYPE,
- (SQLPOINTER)SQL_CURSOR_STATIC,
- SQL_IS_UINTEGER);
- }
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
- setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
- "QODBCResult::reset: Unable to set 'SQL_CURSOR_STATIC' as statement attribute. "
- "Please check your ODBC driver configuration"), QSqlError::StatementError, d));
- return false;
- }
-
- r = SQLPrepare(d->hStmt,
- toSQLTCHAR(query).data(),
- (SQLINTEGER) query.length());
-
- if (r != SQL_SUCCESS) {
- setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
- "Unable to prepare statement"), QSqlError::StatementError, d));
- return false;
- }
- return true;
-}
-
-bool QODBCResult::exec()
-{
- Q_D(QODBCResult);
- setActive(false);
- setAt(QSql::BeforeFirstRow);
- d->rInf.clear();
- d->fieldCache.clear();
- d->fieldCacheIdx = 0;
-
- if (!d->hStmt) {
- qSqlWarning(QLatin1String("QODBCResult::exec: No statement handle available"), d);
- return false;
- }
-
- if (isSelect())
- SQLCloseCursor(d->hStmt);
-
- QVector<QVariant>& values = boundValues();
- QVector<QByteArray> tmpStorage(values.count(), QByteArray()); // holds temporary buffers
- QVarLengthArray<SQLLEN, 32> indicators(values.count());
- memset(indicators.data(), 0, indicators.size() * sizeof(SQLLEN));
-
- // bind parameters - only positional binding allowed
- int i;
- SQLRETURN r;
- for (i = 0; i < values.count(); ++i) {
- if (bindValueType(i) & QSql::Out)
- values[i].detach();
- const QVariant &val = values.at(i);
- SQLLEN *ind = &indicators[i];
- if (val.isNull())
- *ind = SQL_NULL_DATA;
- switch (val.type()) {
- case QVariant::Date: {
- QByteArray &ba = tmpStorage[i];
- ba.resize(sizeof(DATE_STRUCT));
- DATE_STRUCT *dt = (DATE_STRUCT *)const_cast<char *>(ba.constData());
- QDate qdt = val.toDate();
- dt->year = qdt.year();
- dt->month = qdt.month();
- dt->day = qdt.day();
- r = SQLBindParameter(d->hStmt,
- i + 1,
- qParamType[bindValueType(i) & QSql::InOut],
- SQL_C_DATE,
- SQL_DATE,
- 0,
- 0,
- (void *) dt,
- 0,
- *ind == SQL_NULL_DATA ? ind : NULL);
- break; }
- case QVariant::Time: {
- QByteArray &ba = tmpStorage[i];
- ba.resize(sizeof(TIME_STRUCT));
- TIME_STRUCT *dt = (TIME_STRUCT *)const_cast<char *>(ba.constData());
- QTime qdt = val.toTime();
- dt->hour = qdt.hour();
- dt->minute = qdt.minute();
- dt->second = qdt.second();
- r = SQLBindParameter(d->hStmt,
- i + 1,
- qParamType[bindValueType(i) & QSql::InOut],
- SQL_C_TIME,
- SQL_TIME,
- 0,
- 0,
- (void *) dt,
- 0,
- *ind == SQL_NULL_DATA ? ind : NULL);
- break; }
- case QVariant::DateTime: {
- QByteArray &ba = tmpStorage[i];
- ba.resize(sizeof(TIMESTAMP_STRUCT));
- TIMESTAMP_STRUCT * dt = (TIMESTAMP_STRUCT *)const_cast<char *>(ba.constData());
- QDateTime qdt = val.toDateTime();
- dt->year = qdt.date().year();
- dt->month = qdt.date().month();
- dt->day = qdt.date().day();
- dt->hour = qdt.time().hour();
- dt->minute = qdt.time().minute();
- dt->second = qdt.time().second();
-
- int precision = d->drv_d_func()->datetime_precision - 20; // (20 includes a separating period)
- if (precision <= 0) {
- dt->fraction = 0;
- } else {
- dt->fraction = qdt.time().msec() * 1000000;
-
- // (How many leading digits do we want to keep? With SQL Server 2005, this should be 3: 123000000)
- int keep = (int)qPow(10.0, 9 - qMin(9, precision));
- dt->fraction = (dt->fraction / keep) * keep;
- }
-
- r = SQLBindParameter(d->hStmt,
- i + 1,
- qParamType[bindValueType(i) & QSql::InOut],
- SQL_C_TIMESTAMP,
- SQL_TIMESTAMP,
- d->drv_d_func()->datetime_precision,
- precision,
- (void *) dt,
- 0,
- *ind == SQL_NULL_DATA ? ind : NULL);
- break; }
- case QVariant::Int:
- r = SQLBindParameter(d->hStmt,
- i + 1,
- qParamType[bindValueType(i) & QSql::InOut],
- SQL_C_SLONG,
- SQL_INTEGER,
- 0,
- 0,
- const_cast<void *>(val.constData()),
- 0,
- *ind == SQL_NULL_DATA ? ind : NULL);
- break;
- case QVariant::UInt:
- r = SQLBindParameter(d->hStmt,
- i + 1,
- qParamType[bindValueType(i) & QSql::InOut],
- SQL_C_ULONG,
- SQL_NUMERIC,
- 15,
- 0,
- const_cast<void *>(val.constData()),
- 0,
- *ind == SQL_NULL_DATA ? ind : NULL);
- break;
- case QVariant::Double:
- r = SQLBindParameter(d->hStmt,
- i + 1,
- qParamType[bindValueType(i) & QSql::InOut],
- SQL_C_DOUBLE,
- SQL_DOUBLE,
- 0,
- 0,
- const_cast<void *>(val.constData()),
- 0,
- *ind == SQL_NULL_DATA ? ind : NULL);
- break;
- case QVariant::LongLong:
- r = SQLBindParameter(d->hStmt,
- i + 1,
- qParamType[bindValueType(i) & QSql::InOut],
- SQL_C_SBIGINT,
- SQL_BIGINT,
- 0,
- 0,
- const_cast<void *>(val.constData()),
- 0,
- *ind == SQL_NULL_DATA ? ind : NULL);
- break;
- case QVariant::ULongLong:
- r = SQLBindParameter(d->hStmt,
- i + 1,
- qParamType[bindValueType(i) & QSql::InOut],
- SQL_C_UBIGINT,
- SQL_BIGINT,
- 0,
- 0,
- const_cast<void *>(val.constData()),
- 0,
- *ind == SQL_NULL_DATA ? ind : NULL);
- break;
- case QVariant::ByteArray:
- if (*ind != SQL_NULL_DATA) {
- *ind = val.toByteArray().size();
- }
- r = SQLBindParameter(d->hStmt,
- i + 1,
- qParamType[bindValueType(i) & QSql::InOut],
- SQL_C_BINARY,
- SQL_LONGVARBINARY,
- val.toByteArray().size(),
- 0,
- const_cast<char *>(val.toByteArray().constData()),
- val.toByteArray().size(),
- ind);
- break;
- case QVariant::Bool:
- r = SQLBindParameter(d->hStmt,
- i + 1,
- qParamType[bindValueType(i) & QSql::InOut],
- SQL_C_BIT,
- SQL_BIT,
- 0,
- 0,
- const_cast<void *>(val.constData()),
- 0,
- *ind == SQL_NULL_DATA ? ind : NULL);
- break;
- case QVariant::String:
- if (d->unicode) {
- QByteArray &ba = tmpStorage[i];
- QString str = val.toString();
- if (*ind != SQL_NULL_DATA)
- *ind = str.length() * sizeof(SQLTCHAR);
- int strSize = str.length() * sizeof(SQLTCHAR);
-
- if (bindValueType(i) & QSql::Out) {
- const QVarLengthArray<SQLTCHAR> a(toSQLTCHAR(str));
- ba = QByteArray((const char *)a.constData(), a.size() * sizeof(SQLTCHAR));
- r = SQLBindParameter(d->hStmt,
- i + 1,
- qParamType[bindValueType(i) & QSql::InOut],
- SQL_C_TCHAR,
- strSize > 254 ? SQL_WLONGVARCHAR : SQL_WVARCHAR,
- 0, // god knows... don't change this!
- 0,
- ba.data(),
- ba.size(),
- ind);
- break;
- }
- ba = QByteArray ((const char *)toSQLTCHAR(str).constData(), str.size()*sizeof(SQLTCHAR));
- r = SQLBindParameter(d->hStmt,
- i + 1,
- qParamType[bindValueType(i) & QSql::InOut],
- SQL_C_TCHAR,
- strSize > 254 ? SQL_WLONGVARCHAR : SQL_WVARCHAR,
- strSize,
- 0,
- const_cast<char *>(ba.constData()),
- ba.size(),
- ind);
- break;
- }
- else
- {
- QByteArray &str = tmpStorage[i];
- str = val.toString().toUtf8();
- if (*ind != SQL_NULL_DATA)
- *ind = str.length();
- int strSize = str.length();
-
- r = SQLBindParameter(d->hStmt,
- i + 1,
- qParamType[bindValueType(i) & QSql::InOut],
- SQL_C_CHAR,
- strSize > 254 ? SQL_LONGVARCHAR : SQL_VARCHAR,
- strSize,
- 0,
- const_cast<char *>(str.constData()),
- strSize,
- ind);
- break;
- }
- // fall through
- default: {
- QByteArray &ba = tmpStorage[i];
- if (*ind != SQL_NULL_DATA)
- *ind = ba.size();
- r = SQLBindParameter(d->hStmt,
- i + 1,
- qParamType[bindValueType(i) & QSql::InOut],
- SQL_C_BINARY,
- SQL_VARBINARY,
- ba.length() + 1,
- 0,
- const_cast<char *>(ba.constData()),
- ba.length() + 1,
- ind);
- break; }
- }
- if (r != SQL_SUCCESS) {
- qWarning() << "QODBCResult::exec: unable to bind variable:" << qODBCWarn(d);
- setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
- "Unable to bind variable"), QSqlError::StatementError, d));
- return false;
- }
- }
- r = SQLExecute(d->hStmt);
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO && r != SQL_NO_DATA) {
- qWarning() << "QODBCResult::exec: Unable to execute statement:" << qODBCWarn(d);
- setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
- "Unable to execute statement"), QSqlError::StatementError, d));
- return false;
- }
-
- SQLULEN isScrollable = 0;
- r = SQLGetStmtAttr(d->hStmt, SQL_ATTR_CURSOR_SCROLLABLE, &isScrollable, SQL_IS_INTEGER, 0);
- if(r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO)
- setForwardOnly(isScrollable == SQL_NONSCROLLABLE);
-
- SQLSMALLINT count = 0;
- SQLNumResultCols(d->hStmt, &count);
- if (count) {
- setSelect(true);
- for (int i = 0; i < count; ++i) {
- d->rInf.append(qMakeFieldInfo(d, i));
- }
- d->fieldCache.resize(count);
- } else {
- setSelect(false);
- }
- setActive(true);
-
-
- //get out parameters
- if (!hasOutValues())
- return true;
-
- for (i = 0; i < values.count(); ++i) {
- switch (values.at(i).type()) {
- case QVariant::Date: {
- DATE_STRUCT ds = *((DATE_STRUCT *)const_cast<char *>(tmpStorage.at(i).constData()));
- values[i] = QVariant(QDate(ds.year, ds.month, ds.day));
- break; }
- case QVariant::Time: {
- TIME_STRUCT dt = *((TIME_STRUCT *)const_cast<char *>(tmpStorage.at(i).constData()));
- values[i] = QVariant(QTime(dt.hour, dt.minute, dt.second));
- break; }
- case QVariant::DateTime: {
- TIMESTAMP_STRUCT dt = *((TIMESTAMP_STRUCT*)
- const_cast<char *>(tmpStorage.at(i).constData()));
- values[i] = QVariant(QDateTime(QDate(dt.year, dt.month, dt.day),
- QTime(dt.hour, dt.minute, dt.second, dt.fraction / 1000000)));
- break; }
- case QVariant::Bool:
- case QVariant::Int:
- case QVariant::UInt:
- case QVariant::Double:
- case QVariant::ByteArray:
- case QVariant::LongLong:
- case QVariant::ULongLong:
- //nothing to do
- break;
- case QVariant::String:
- if (d->unicode) {
- if (bindValueType(i) & QSql::Out) {
- const QByteArray &first = tmpStorage.at(i);
- QVarLengthArray<SQLTCHAR> array;
- array.append((const SQLTCHAR *)first.constData(), first.size());
- values[i] = fromSQLTCHAR(array, first.size()/sizeof(SQLTCHAR));
- }
- break;
- }
- // fall through
- default: {
- if (bindValueType(i) & QSql::Out)
- values[i] = tmpStorage.at(i);
- break; }
- }
- if (indicators[i] == SQL_NULL_DATA)
- values[i] = QVariant(values[i].type());
- }
- return true;
-}
-
-QSqlRecord QODBCResult::record() const
-{
- Q_D(const QODBCResult);
- if (!isActive() || !isSelect())
- return QSqlRecord();
- return d->rInf;
-}
-
-QVariant QODBCResult::lastInsertId() const
-{
- Q_D(const QODBCResult);
- QString sql;
-
- switch (driver()->dbmsType()) {
- case QSqlDriver::MSSqlServer:
- case QSqlDriver::Sybase:
- sql = QLatin1String("SELECT @@IDENTITY;");
- break;
- case QSqlDriver::MySqlServer:
- sql = QLatin1String("SELECT LAST_INSERT_ID();");
- break;
- case QSqlDriver::PostgreSQL:
- sql = QLatin1String("SELECT lastval();");
- break;
- default:
- break;
- }
-
- if (!sql.isEmpty()) {
- QSqlQuery qry(driver()->createResult());
- if (qry.exec(sql) && qry.next())
- return qry.value(0);
-
- qSqlWarning(QLatin1String("QODBCResult::lastInsertId: Unable to get lastInsertId"), d);
- } else {
- qSqlWarning(QLatin1String("QODBCResult::lastInsertId: not implemented for this DBMS"), d);
- }
-
- return QVariant();
-}
-
-QVariant QODBCResult::handle() const
-{
- Q_D(const QODBCResult);
- return QVariant(qRegisterMetaType<SQLHANDLE>("SQLHANDLE"), &d->hStmt);
-}
-
-bool QODBCResult::nextResult()
-{
- Q_D(QODBCResult);
- setActive(false);
- setAt(QSql::BeforeFirstRow);
- d->rInf.clear();
- d->fieldCache.clear();
- d->fieldCacheIdx = 0;
- setSelect(false);
-
- SQLRETURN r = SQLMoreResults(d->hStmt);
- if (r != SQL_SUCCESS) {
- if (r == SQL_SUCCESS_WITH_INFO) {
- int nativeCode = -1;
- QString message = qODBCWarn(d, &nativeCode);
- qWarning() << "QODBCResult::nextResult():" << message;
- } else {
- if (r != SQL_NO_DATA)
- setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
- "Unable to fetch last"), QSqlError::ConnectionError, d));
- return false;
- }
- }
-
- SQLSMALLINT count = 0;
- SQLNumResultCols(d->hStmt, &count);
- if (count) {
- setSelect(true);
- for (int i = 0; i < count; ++i) {
- d->rInf.append(qMakeFieldInfo(d, i));
- }
- d->fieldCache.resize(count);
- } else {
- setSelect(false);
- }
- setActive(true);
-
- return true;
-}
-
-void QODBCResult::virtual_hook(int id, void *data)
-{
- QSqlResult::virtual_hook(id, data);
-}
-
-void QODBCResult::detachFromResultSet()
-{
- Q_D(QODBCResult);
- if (d->hStmt)
- SQLCloseCursor(d->hStmt);
-}
-
-////////////////////////////////////////
-
-
-QODBCDriver::QODBCDriver(QObject *parent)
- : QSqlDriver(*new QODBCDriverPrivate, parent)
-{
-}
-
-QODBCDriver::QODBCDriver(SQLHANDLE env, SQLHANDLE con, QObject *parent)
- : QSqlDriver(*new QODBCDriverPrivate, parent)
-{
- Q_D(QODBCDriver);
- d->hEnv = env;
- d->hDbc = con;
- if (env && con) {
- setOpen(true);
- setOpenError(false);
- }
-}
-
-QODBCDriver::~QODBCDriver()
-{
- cleanup();
-}
-
-bool QODBCDriver::hasFeature(DriverFeature f) const
-{
- Q_D(const QODBCDriver);
- switch (f) {
- case Transactions: {
- if (!d->hDbc)
- return false;
- SQLUSMALLINT txn;
- SQLSMALLINT t;
- int r = SQLGetInfo(d->hDbc,
- (SQLUSMALLINT)SQL_TXN_CAPABLE,
- &txn,
- sizeof(txn),
- &t);
- if (r != SQL_SUCCESS || txn == SQL_TC_NONE)
- return false;
- else
- return true;
- }
- case Unicode:
- return d->unicode;
- case PreparedQueries:
- case PositionalPlaceholders:
- case FinishQuery:
- case LowPrecisionNumbers:
- return true;
- case QuerySize:
- case NamedPlaceholders:
- case BatchOperations:
- case SimpleLocking:
- case EventNotifications:
- case CancelQuery:
- return false;
- case LastInsertId:
- return (d->dbmsType == MSSqlServer)
- || (d->dbmsType == Sybase)
- || (d->dbmsType == MySqlServer)
- || (d->dbmsType == PostgreSQL);
- case MultipleResultSets:
- return d->hasMultiResultSets;
- case BLOB: {
- if (d->dbmsType == MySqlServer)
- return true;
- else
- return false;
- }
- }
- return false;
-}
-
-bool QODBCDriver::open(const QString & db,
- const QString & user,
- const QString & password,
- const QString &,
- int,
- const QString& connOpts)
-{
- Q_D(QODBCDriver);
- if (isOpen())
- close();
- SQLRETURN r;
- r = SQLAllocHandle(SQL_HANDLE_ENV,
- SQL_NULL_HANDLE,
- &d->hEnv);
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
- qSqlWarning(QLatin1String("QODBCDriver::open: Unable to allocate environment"), d);
- setOpenError(true);
- return false;
- }
- r = SQLSetEnvAttr(d->hEnv,
- SQL_ATTR_ODBC_VERSION,
- (SQLPOINTER)qGetODBCVersion(connOpts),
- SQL_IS_UINTEGER);
- r = SQLAllocHandle(SQL_HANDLE_DBC,
- d->hEnv,
- &d->hDbc);
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
- qSqlWarning(QLatin1String("QODBCDriver::open: Unable to allocate connection"), d);
- setOpenError(true);
- cleanup();
- return false;
- }
-
- if (!d->setConnectionOptions(connOpts)) {
- cleanup();
- return false;
- }
-
- // Create the connection string
- QString connQStr;
- // support the "DRIVER={SQL SERVER};SERVER=blah" syntax
- if (db.contains(QLatin1String(".dsn"), Qt::CaseInsensitive))
- connQStr = QLatin1String("FILEDSN=") + db;
- else if (db.contains(QLatin1String("DRIVER="), Qt::CaseInsensitive)
- || db.contains(QLatin1String("SERVER="), Qt::CaseInsensitive))
- connQStr = db;
- else
- connQStr = QLatin1String("DSN=") + db;
-
- if (!user.isEmpty())
- connQStr += QLatin1String(";UID=") + user;
- if (!password.isEmpty())
- connQStr += QLatin1String(";PWD=") + password;
-
- SQLSMALLINT cb;
- QVarLengthArray<SQLTCHAR> connOut(1024);
- memset(connOut.data(), 0, connOut.size() * sizeof(SQLTCHAR));
- r = SQLDriverConnect(d->hDbc,
- NULL,
- toSQLTCHAR(connQStr).data(),
- (SQLSMALLINT)connQStr.length(),
- connOut.data(),
- 1024,
- &cb,
- /*SQL_DRIVER_NOPROMPT*/0);
-
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
- setLastError(qMakeError(tr("Unable to connect"), QSqlError::ConnectionError, d));
- setOpenError(true);
- cleanup();
- return false;
- }
-
- if (!d->checkDriver()) {
- setLastError(qMakeError(tr("Unable to connect - Driver doesn't support all "
- "functionality required"), QSqlError::ConnectionError, d));
- setOpenError(true);
- cleanup();
- return false;
- }
-
- d->checkUnicode();
- d->checkSchemaUsage();
- d->checkDBMS();
- d->checkHasSQLFetchScroll();
- d->checkHasMultiResults();
- d->checkDateTimePrecision();
- setOpen(true);
- setOpenError(false);
- if (d->dbmsType == MSSqlServer) {
- QSqlQuery i(createResult());
- i.exec(QLatin1String("SET QUOTED_IDENTIFIER ON"));
- }
- return true;
-}
-
-void QODBCDriver::close()
-{
- cleanup();
- setOpen(false);
- setOpenError(false);
-}
-
-void QODBCDriver::cleanup()
-{
- Q_D(QODBCDriver);
- SQLRETURN r;
-
- if(d->hDbc) {
- // Open statements/descriptors handles are automatically cleaned up by SQLDisconnect
- if (isOpen()) {
- r = SQLDisconnect(d->hDbc);
- if (r != SQL_SUCCESS)
- qSqlWarning(QLatin1String("QODBCDriver::disconnect: Unable to disconnect datasource"), d);
- else
- d->disconnectCount++;
- }
-
- r = SQLFreeHandle(SQL_HANDLE_DBC, d->hDbc);
- if (r != SQL_SUCCESS)
- qSqlWarning(QLatin1String("QODBCDriver::cleanup: Unable to free connection handle"), d);
- d->hDbc = 0;
- }
-
- if (d->hEnv) {
- r = SQLFreeHandle(SQL_HANDLE_ENV, d->hEnv);
- if (r != SQL_SUCCESS)
- qSqlWarning(QLatin1String("QODBCDriver::cleanup: Unable to free environment handle"), d);
- d->hEnv = 0;
- }
-}
-
-// checks whether the server can return char, varchar and longvarchar
-// as two byte unicode characters
-void QODBCDriverPrivate::checkUnicode()
-{
- SQLRETURN r;
- SQLUINTEGER fFunc;
-
- unicode = false;
- r = SQLGetInfo(hDbc,
- SQL_CONVERT_CHAR,
- (SQLPOINTER)&fFunc,
- sizeof(fFunc),
- NULL);
- if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && (fFunc & SQL_CVT_WCHAR)) {
- unicode = true;
- return;
- }
-
- r = SQLGetInfo(hDbc,
- SQL_CONVERT_VARCHAR,
- (SQLPOINTER)&fFunc,
- sizeof(fFunc),
- NULL);
- if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && (fFunc & SQL_CVT_WVARCHAR)) {
- unicode = true;
- return;
- }
-
- r = SQLGetInfo(hDbc,
- SQL_CONVERT_LONGVARCHAR,
- (SQLPOINTER)&fFunc,
- sizeof(fFunc),
- NULL);
- if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && (fFunc & SQL_CVT_WLONGVARCHAR)) {
- unicode = true;
- return;
- }
- SQLHANDLE hStmt;
- r = SQLAllocHandle(SQL_HANDLE_STMT,
- hDbc,
- &hStmt);
-
- r = SQLExecDirect(hStmt, toSQLTCHAR(QLatin1String("select 'test'")).data(), SQL_NTS);
- if(r == SQL_SUCCESS) {
- r = SQLFetch(hStmt);
- if(r == SQL_SUCCESS) {
- QVarLengthArray<SQLWCHAR> buffer(10);
- r = SQLGetData(hStmt, 1, SQL_C_WCHAR, buffer.data(), buffer.size() * sizeof(SQLWCHAR), NULL);
- if(r == SQL_SUCCESS && fromSQLTCHAR(buffer) == QLatin1String("test")) {
- unicode = true;
- }
- }
- }
- r = SQLFreeHandle(SQL_HANDLE_STMT, hStmt);
-}
-
-bool QODBCDriverPrivate::checkDriver() const
-{
-#ifdef ODBC_CHECK_DRIVER
- static const SQLUSMALLINT reqFunc[] = {
- SQL_API_SQLDESCRIBECOL, SQL_API_SQLGETDATA, SQL_API_SQLCOLUMNS,
- SQL_API_SQLGETSTMTATTR, SQL_API_SQLGETDIAGREC, SQL_API_SQLEXECDIRECT,
- SQL_API_SQLGETINFO, SQL_API_SQLTABLES, 0
- };
-
- // these functions are optional
- static const SQLUSMALLINT optFunc[] = {
- SQL_API_SQLNUMRESULTCOLS, SQL_API_SQLROWCOUNT, 0
- };
-
- SQLRETURN r;
- SQLUSMALLINT sup;
-
- int i;
- // check the required functions
- for (i = 0; reqFunc[i] != 0; ++i) {
-
- r = SQLGetFunctions(hDbc, reqFunc[i], &sup);
-
- if (r != SQL_SUCCESS) {
- qSqlWarning(QLatin1String("QODBCDriver::checkDriver: Cannot get list of supported functions"), this);
- return false;
- }
- if (sup == SQL_FALSE) {
- qWarning () << "QODBCDriver::open: Warning - Driver doesn't support all needed functionality (" << reqFunc[i] <<
- ").\nPlease look at the Qt SQL Module Driver documentation for more information.";
- return false;
- }
- }
-
- // these functions are optional and just generate a warning
- for (i = 0; optFunc[i] != 0; ++i) {
-
- r = SQLGetFunctions(hDbc, optFunc[i], &sup);
-
- if (r != SQL_SUCCESS) {
- qSqlWarning(QLatin1String("QODBCDriver::checkDriver: Cannot get list of supported functions"), this);
- return false;
- }
- if (sup == SQL_FALSE) {
- qWarning() << "QODBCDriver::checkDriver: Warning - Driver doesn't support some non-critical functions (" << optFunc[i] << ')';
- return true;
- }
- }
-#endif //ODBC_CHECK_DRIVER
-
- return true;
-}
-
-void QODBCDriverPrivate::checkSchemaUsage()
-{
- SQLRETURN r;
- SQLUINTEGER val;
-
- r = SQLGetInfo(hDbc,
- SQL_SCHEMA_USAGE,
- (SQLPOINTER) &val,
- sizeof(val),
- NULL);
- if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO)
- useSchema = (val != 0);
-}
-
-void QODBCDriverPrivate::checkDBMS()
-{
- SQLRETURN r;
- QVarLengthArray<SQLTCHAR> serverString(200);
- SQLSMALLINT t;
- memset(serverString.data(), 0, serverString.size() * sizeof(SQLTCHAR));
-
- r = SQLGetInfo(hDbc,
- SQL_DBMS_NAME,
- serverString.data(),
- SQLSMALLINT(serverString.size() * sizeof(SQLTCHAR)),
- &t);
- if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) {
- const QString serverType = fromSQLTCHAR(serverString, t / sizeof(SQLTCHAR));
- if (serverType.contains(QLatin1String("PostgreSQL"), Qt::CaseInsensitive))
- dbmsType = QSqlDriver::PostgreSQL;
- else if (serverType.contains(QLatin1String("Oracle"), Qt::CaseInsensitive))
- dbmsType = QSqlDriver::Oracle;
- else if (serverType.contains(QLatin1String("MySql"), Qt::CaseInsensitive))
- dbmsType = QSqlDriver::MySqlServer;
- else if (serverType.contains(QLatin1String("Microsoft SQL Server"), Qt::CaseInsensitive))
- dbmsType = QSqlDriver::MSSqlServer;
- else if (serverType.contains(QLatin1String("Sybase"), Qt::CaseInsensitive))
- dbmsType = QSqlDriver::Sybase;
- }
- r = SQLGetInfo(hDbc,
- SQL_DRIVER_NAME,
- serverString.data(),
- SQLSMALLINT(serverString.size() * sizeof(SQLTCHAR)),
- &t);
- if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) {
- const QString serverType = fromSQLTCHAR(serverString, t / sizeof(SQLTCHAR));
- isFreeTDSDriver = serverType.contains(QLatin1String("tdsodbc"), Qt::CaseInsensitive);
- unicode = unicode && !isFreeTDSDriver;
- }
-}
-
-void QODBCDriverPrivate::checkHasSQLFetchScroll()
-{
- SQLUSMALLINT sup;
- SQLRETURN r = SQLGetFunctions(hDbc, SQL_API_SQLFETCHSCROLL, &sup);
- if ((r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) || sup != SQL_TRUE) {
- hasSQLFetchScroll = false;
- qWarning("QODBCDriver::checkHasSQLFetchScroll: Warning - Driver doesn't support scrollable result sets, use forward only mode for queries");
- }
-}
-
-void QODBCDriverPrivate::checkHasMultiResults()
-{
- QVarLengthArray<SQLTCHAR> driverResponse(2);
- SQLSMALLINT length;
- SQLRETURN r = SQLGetInfo(hDbc,
- SQL_MULT_RESULT_SETS,
- driverResponse.data(),
- SQLSMALLINT(driverResponse.size() * sizeof(SQLTCHAR)),
- &length);
- if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO)
- hasMultiResultSets = fromSQLTCHAR(driverResponse, length/sizeof(SQLTCHAR)).startsWith(QLatin1Char('Y'));
-}
-
-void QODBCDriverPrivate::checkDateTimePrecision()
-{
- SQLINTEGER columnSize;
- SQLHANDLE hStmt;
-
- SQLRETURN r = SQLAllocHandle(SQL_HANDLE_STMT, hDbc, &hStmt);
- if (r != SQL_SUCCESS) {
- return;
- }
-
- r = SQLGetTypeInfo(hStmt, SQL_TIMESTAMP);
- if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) {
- r = SQLFetch(hStmt);
- if ( r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO )
- {
- if (SQLGetData(hStmt, 3, SQL_INTEGER, &columnSize, sizeof(columnSize), 0) == SQL_SUCCESS) {
- datetime_precision = (int)columnSize;
- }
- }
- }
- SQLFreeHandle(SQL_HANDLE_STMT, hStmt);
-}
-
-QSqlResult *QODBCDriver::createResult() const
-{
- return new QODBCResult(this);
-}
-
-bool QODBCDriver::beginTransaction()
-{
- Q_D(QODBCDriver);
- if (!isOpen()) {
- qWarning("QODBCDriver::beginTransaction: Database not open");
- return false;
- }
- SQLUINTEGER ac(SQL_AUTOCOMMIT_OFF);
- SQLRETURN r = SQLSetConnectAttr(d->hDbc,
- SQL_ATTR_AUTOCOMMIT,
- (SQLPOINTER)size_t(ac),
- sizeof(ac));
- if (r != SQL_SUCCESS) {
- setLastError(qMakeError(tr("Unable to disable autocommit"),
- QSqlError::TransactionError, d));
- return false;
- }
- return true;
-}
-
-bool QODBCDriver::commitTransaction()
-{
- Q_D(QODBCDriver);
- if (!isOpen()) {
- qWarning("QODBCDriver::commitTransaction: Database not open");
- return false;
- }
- SQLRETURN r = SQLEndTran(SQL_HANDLE_DBC,
- d->hDbc,
- SQL_COMMIT);
- if (r != SQL_SUCCESS) {
- setLastError(qMakeError(tr("Unable to commit transaction"),
- QSqlError::TransactionError, d));
- return false;
- }
- return endTrans();
-}
-
-bool QODBCDriver::rollbackTransaction()
-{
- Q_D(QODBCDriver);
- if (!isOpen()) {
- qWarning("QODBCDriver::rollbackTransaction: Database not open");
- return false;
- }
- SQLRETURN r = SQLEndTran(SQL_HANDLE_DBC,
- d->hDbc,
- SQL_ROLLBACK);
- if (r != SQL_SUCCESS) {
- setLastError(qMakeError(tr("Unable to rollback transaction"),
- QSqlError::TransactionError, d));
- return false;
- }
- return endTrans();
-}
-
-bool QODBCDriver::endTrans()
-{
- Q_D(QODBCDriver);
- SQLUINTEGER ac(SQL_AUTOCOMMIT_ON);
- SQLRETURN r = SQLSetConnectAttr(d->hDbc,
- SQL_ATTR_AUTOCOMMIT,
- (SQLPOINTER)size_t(ac),
- sizeof(ac));
- if (r != SQL_SUCCESS) {
- setLastError(qMakeError(tr("Unable to enable autocommit"), QSqlError::TransactionError, d));
- return false;
- }
- return true;
-}
-
-QStringList QODBCDriver::tables(QSql::TableType type) const
-{
- Q_D(const QODBCDriver);
- QStringList tl;
- if (!isOpen())
- return tl;
- SQLHANDLE hStmt;
-
- SQLRETURN r = SQLAllocHandle(SQL_HANDLE_STMT,
- d->hDbc,
- &hStmt);
- if (r != SQL_SUCCESS) {
- qSqlWarning(QLatin1String("QODBCDriver::tables: Unable to allocate handle"), d);
- return tl;
- }
- r = SQLSetStmtAttr(hStmt,
- SQL_ATTR_CURSOR_TYPE,
- (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY,
- SQL_IS_UINTEGER);
- QStringList tableType;
- if (type & QSql::Tables)
- tableType += QLatin1String("TABLE");
- if (type & QSql::Views)
- tableType += QLatin1String("VIEW");
- if (type & QSql::SystemTables)
- tableType += QLatin1String("SYSTEM TABLE");
- if (tableType.isEmpty())
- return tl;
-
- QString joinedTableTypeString = tableType.join(QLatin1Char(','));
-
- r = SQLTables(hStmt,
- NULL,
- 0,
- NULL,
- 0,
- NULL,
- 0,
- toSQLTCHAR(joinedTableTypeString).data(),
- joinedTableTypeString.length() /* characters, not bytes */);
-
- if (r != SQL_SUCCESS)
- qSqlWarning(QLatin1String("QODBCDriver::tables Unable to execute table list"), d);
-
- if (d->hasSQLFetchScroll)
- r = SQLFetchScroll(hStmt,
- SQL_FETCH_NEXT,
- 0);
- else
- r = SQLFetch(hStmt);
-
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO && r != SQL_NO_DATA) {
- qWarning() << "QODBCDriver::tables failed to retrieve table/view list: (" << r << "," << qWarnODBCHandle(SQL_HANDLE_STMT, hStmt) << ")";
- return QStringList();
- }
-
- while (r == SQL_SUCCESS) {
- QString fieldVal = qGetStringData(hStmt, 2, -1, false);
- tl.append(fieldVal);
-
- if (d->hasSQLFetchScroll)
- r = SQLFetchScroll(hStmt,
- SQL_FETCH_NEXT,
- 0);
- else
- r = SQLFetch(hStmt);
- }
-
- r = SQLFreeHandle(SQL_HANDLE_STMT, hStmt);
- if (r!= SQL_SUCCESS)
- qSqlWarning(QLatin1String("QODBCDriver: Unable to free statement handle") + QString::number(r), d);
- return tl;
-}
-
-QSqlIndex QODBCDriver::primaryIndex(const QString& tablename) const
-{
- Q_D(const QODBCDriver);
- QSqlIndex index(tablename);
- if (!isOpen())
- return index;
- bool usingSpecialColumns = false;
- QSqlRecord rec = record(tablename);
-
- SQLHANDLE hStmt;
- SQLRETURN r = SQLAllocHandle(SQL_HANDLE_STMT,
- d->hDbc,
- &hStmt);
- if (r != SQL_SUCCESS) {
- qSqlWarning(QLatin1String("QODBCDriver::primaryIndex: Unable to list primary key"), d);
- return index;
- }
- QString catalog, schema, table;
- const_cast<QODBCDriverPrivate*>(d)->splitTableQualifier(tablename, catalog, schema, table);
-
- if (isIdentifierEscaped(catalog, QSqlDriver::TableName))
- catalog = stripDelimiters(catalog, QSqlDriver::TableName);
- else
- catalog = d->adjustCase(catalog);
-
- if (isIdentifierEscaped(schema, QSqlDriver::TableName))
- schema = stripDelimiters(schema, QSqlDriver::TableName);
- else
- schema = d->adjustCase(schema);
-
- if (isIdentifierEscaped(table, QSqlDriver::TableName))
- table = stripDelimiters(table, QSqlDriver::TableName);
- else
- table = d->adjustCase(table);
-
- r = SQLSetStmtAttr(hStmt,
- SQL_ATTR_CURSOR_TYPE,
- (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY,
- SQL_IS_UINTEGER);
- r = SQLPrimaryKeys(hStmt,
- catalog.length() == 0 ? NULL : toSQLTCHAR(catalog).data(),
- catalog.length(),
- schema.length() == 0 ? NULL : toSQLTCHAR(schema).data(),
- schema.length(),
- toSQLTCHAR(table).data(),
- table.length() /* in characters, not in bytes */);
-
- // if the SQLPrimaryKeys() call does not succeed (e.g the driver
- // does not support it) - try an alternative method to get hold of
- // the primary index (e.g MS Access and FoxPro)
- if (r != SQL_SUCCESS) {
- r = SQLSpecialColumns(hStmt,
- SQL_BEST_ROWID,
- catalog.length() == 0 ? NULL : toSQLTCHAR(catalog).data(),
- catalog.length(),
- schema.length() == 0 ? NULL : toSQLTCHAR(schema).data(),
- schema.length(),
- toSQLTCHAR(table).data(),
- table.length(),
- SQL_SCOPE_CURROW,
- SQL_NULLABLE);
-
- if (r != SQL_SUCCESS) {
- qSqlWarning(QLatin1String("QODBCDriver::primaryIndex: Unable to execute primary key list"), d);
- } else {
- usingSpecialColumns = true;
- }
- }
-
- if (d->hasSQLFetchScroll)
- r = SQLFetchScroll(hStmt,
- SQL_FETCH_NEXT,
- 0);
- else
- r = SQLFetch(hStmt);
-
- int fakeId = 0;
- QString cName, idxName;
- // Store all fields in a StringList because some drivers can't detail fields in this FETCH loop
- while (r == SQL_SUCCESS) {
- if (usingSpecialColumns) {
- cName = qGetStringData(hStmt, 1, -1, d->unicode); // column name
- idxName = QString::number(fakeId++); // invent a fake index name
- } else {
- cName = qGetStringData(hStmt, 3, -1, d->unicode); // column name
- idxName = qGetStringData(hStmt, 5, -1, d->unicode); // pk index name
- }
- index.append(rec.field(cName));
- index.setName(idxName);
-
- if (d->hasSQLFetchScroll)
- r = SQLFetchScroll(hStmt,
- SQL_FETCH_NEXT,
- 0);
- else
- r = SQLFetch(hStmt);
-
- }
- r = SQLFreeHandle(SQL_HANDLE_STMT, hStmt);
- if (r!= SQL_SUCCESS)
- qSqlWarning(QLatin1String("QODBCDriver: Unable to free statement handle") + QString::number(r), d);
- return index;
-}
-
-QSqlRecord QODBCDriver::record(const QString& tablename) const
-{
- Q_D(const QODBCDriver);
- QSqlRecord fil;
- if (!isOpen())
- return fil;
-
- SQLHANDLE hStmt;
- QString catalog, schema, table;
- const_cast<QODBCDriverPrivate*>(d)->splitTableQualifier(tablename, catalog, schema, table);
-
- if (isIdentifierEscaped(catalog, QSqlDriver::TableName))
- catalog = stripDelimiters(catalog, QSqlDriver::TableName);
- else
- catalog = d->adjustCase(catalog);
-
- if (isIdentifierEscaped(schema, QSqlDriver::TableName))
- schema = stripDelimiters(schema, QSqlDriver::TableName);
- else
- schema = d->adjustCase(schema);
-
- if (isIdentifierEscaped(table, QSqlDriver::TableName))
- table = stripDelimiters(table, QSqlDriver::TableName);
- else
- table = d->adjustCase(table);
-
- SQLRETURN r = SQLAllocHandle(SQL_HANDLE_STMT,
- d->hDbc,
- &hStmt);
- if (r != SQL_SUCCESS) {
- qSqlWarning(QLatin1String("QODBCDriver::record: Unable to allocate handle"), d);
- return fil;
- }
- r = SQLSetStmtAttr(hStmt,
- SQL_ATTR_CURSOR_TYPE,
- (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY,
- SQL_IS_UINTEGER);
- r = SQLColumns(hStmt,
- catalog.length() == 0 ? NULL : toSQLTCHAR(catalog).data(),
- catalog.length(),
- schema.length() == 0 ? NULL : toSQLTCHAR(schema).data(),
- schema.length(),
- toSQLTCHAR(table).data(),
- table.length(),
- NULL,
- 0);
- if (r != SQL_SUCCESS)
- qSqlWarning(QLatin1String("QODBCDriver::record: Unable to execute column list"), d);
-
- if (d->hasSQLFetchScroll)
- r = SQLFetchScroll(hStmt,
- SQL_FETCH_NEXT,
- 0);
- else
- r = SQLFetch(hStmt);
-
- // Store all fields in a StringList because some drivers can't detail fields in this FETCH loop
- while (r == SQL_SUCCESS) {
-
- fil.append(qMakeFieldInfo(hStmt, d));
-
- if (d->hasSQLFetchScroll)
- r = SQLFetchScroll(hStmt,
- SQL_FETCH_NEXT,
- 0);
- else
- r = SQLFetch(hStmt);
- }
-
- r = SQLFreeHandle(SQL_HANDLE_STMT, hStmt);
- if (r!= SQL_SUCCESS)
- qSqlWarning(QLatin1String("QODBCDriver: Unable to free statement handle ") + QString::number(r), d);
-
- return fil;
-}
-
-QString QODBCDriver::formatValue(const QSqlField &field,
- bool trimStrings) const
-{
- QString r;
- if (field.isNull()) {
- r = QLatin1String("NULL");
- } else if (field.type() == QVariant::DateTime) {
- // Use an escape sequence for the datetime fields
- if (field.value().toDateTime().isValid()){
- QDate dt = field.value().toDateTime().date();
- QTime tm = field.value().toDateTime().time();
- // Dateformat has to be "yyyy-MM-dd hh:mm:ss", with leading zeroes if month or day < 10
- r = QLatin1String("{ ts '") +
- QString::number(dt.year()) + QLatin1Char('-') +
- QString::number(dt.month()).rightJustified(2, QLatin1Char('0'), true) +
- QLatin1Char('-') +
- QString::number(dt.day()).rightJustified(2, QLatin1Char('0'), true) +
- QLatin1Char(' ') +
- tm.toString() +
- 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, trimStrings);
- }
- return r;
-}
-
-QVariant QODBCDriver::handle() const
-{
- Q_D(const QODBCDriver);
- return QVariant(qRegisterMetaType<SQLHANDLE>("SQLHANDLE"), &d->hDbc);
-}
-
-QString QODBCDriver::escapeIdentifier(const QString &identifier, IdentifierType) const
-{
- Q_D(const QODBCDriver);
- QChar quote = const_cast<QODBCDriverPrivate*>(d)->quoteChar();
- QString res = identifier;
- if(!identifier.isEmpty() && !identifier.startsWith(quote) && !identifier.endsWith(quote) ) {
- res.replace(quote, QString(quote)+QString(quote));
- res.prepend(quote).append(quote);
- res.replace(QLatin1Char('.'), QString(quote)+QLatin1Char('.')+QString(quote));
- }
- return res;
-}
-
-bool QODBCDriver::isIdentifierEscaped(const QString &identifier, IdentifierType) const
-{
- Q_D(const QODBCDriver);
- QChar quote = const_cast<QODBCDriverPrivate*>(d)->quoteChar();
- return identifier.size() > 2
- && identifier.startsWith(quote) //left delimited
- && identifier.endsWith(quote); //right delimited
-}
-
-QT_END_NAMESPACE
diff --git a/src/sql/drivers/odbc/qsql_odbc.pri b/src/sql/drivers/odbc/qsql_odbc.pri
deleted file mode 100644
index b206df37c3..0000000000
--- a/src/sql/drivers/odbc/qsql_odbc.pri
+++ /dev/null
@@ -1,12 +0,0 @@
-HEADERS += $$PWD/qsql_odbc_p.h
-SOURCES += $$PWD/qsql_odbc.cpp
-
-unix {
- DEFINES += UNICODE
- !contains(LIBS, .*odbc.*) {
- macx:LIBS += -liodbc
- else:LIBS += $$QT_LFLAGS_ODBC
- }
-} else {
- LIBS *= -lodbc32
-}
diff --git a/src/sql/drivers/odbc/qsql_odbc_p.h b/src/sql/drivers/odbc/qsql_odbc_p.h
deleted file mode 100644
index f4ce8bc243..0000000000
--- a/src/sql/drivers/odbc/qsql_odbc_p.h
+++ /dev/null
@@ -1,127 +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_ODBC_H
-#define QSQL_ODBC_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
-
-#ifdef QT_PLUGIN
-#define Q_EXPORT_SQLDRIVER_ODBC
-#else
-#define Q_EXPORT_SQLDRIVER_ODBC Q_SQL_EXPORT
-#endif
-
-#ifdef Q_OS_UNIX
-#define HAVE_LONG_LONG 1 // force UnixODBC NOT to fall back to a struct for BIGINTs
-#endif
-
-#if defined(Q_CC_BOR)
-// workaround for Borland to make sure that SQLBIGINT is defined
-# define _MSC_VER 900
-#endif
-#include <sql.h>
-#if defined(Q_CC_BOR)
-# undef _MSC_VER
-#endif
-
-#include <sqlext.h>
-
-QT_BEGIN_NAMESPACE
-
-class QODBCDriverPrivate;
-
-class Q_EXPORT_SQLDRIVER_ODBC QODBCDriver : public QSqlDriver
-{
- Q_DECLARE_PRIVATE(QODBCDriver)
- Q_OBJECT
- friend class QODBCResultPrivate;
-
-public:
- explicit QODBCDriver(QObject *parent=0);
- QODBCDriver(SQLHANDLE env, SQLHANDLE con, QObject * parent=0);
- virtual ~QODBCDriver();
- bool hasFeature(DriverFeature f) const Q_DECL_OVERRIDE;
- void close() Q_DECL_OVERRIDE;
- QSqlResult *createResult() const Q_DECL_OVERRIDE;
- QStringList tables(QSql::TableType) const Q_DECL_OVERRIDE;
- QSqlRecord record(const QString &tablename) const Q_DECL_OVERRIDE;
- QSqlIndex primaryIndex(const QString &tablename) const Q_DECL_OVERRIDE;
- QVariant handle() const Q_DECL_OVERRIDE;
- QString formatValue(const QSqlField &field,
- bool trimStrings) const Q_DECL_OVERRIDE;
- bool open(const QString &db,
- const QString &user,
- const QString &password,
- const QString &host,
- int port,
- const QString &connOpts) Q_DECL_OVERRIDE;
-
- QString escapeIdentifier(const QString &identifier, IdentifierType type) const Q_DECL_OVERRIDE;
-
- bool isIdentifierEscaped(const QString &identifier, IdentifierType type) const Q_DECL_OVERRIDE;
-
-protected:
- bool beginTransaction() Q_DECL_OVERRIDE;
- bool commitTransaction() Q_DECL_OVERRIDE;
- bool rollbackTransaction() Q_DECL_OVERRIDE;
-
-private:
- bool endTrans();
- void cleanup();
-};
-
-QT_END_NAMESPACE
-
-#endif // QSQL_ODBC_H
diff --git a/src/sql/drivers/psql/qsql_psql.cpp b/src/sql/drivers/psql/qsql_psql.cpp
deleted file mode 100644
index fcf75af298..0000000000
--- a/src/sql/drivers/psql/qsql_psql.cpp
+++ /dev/null
@@ -1,1508 +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_psql_p.h"
-
-#include <qcoreapplication.h>
-#include <qvariant.h>
-#include <qdatetime.h>
-#include <qregexp.h>
-#include <qsqlerror.h>
-#include <qsqlfield.h>
-#include <qsqlindex.h>
-#include <qsqlrecord.h>
-#include <qsqlquery.h>
-#include <qsocketnotifier.h>
-#include <qstringlist.h>
-#include <qmutex.h>
-#include <QtSql/private/qsqlresult_p.h>
-#include <QtSql/private/qsqldriver_p.h>
-
-#include <libpq-fe.h>
-#include <pg_config.h>
-
-#include <stdlib.h>
-#include <math.h>
-// below code taken from an example at http://www.gnu.org/software/hello/manual/autoconf/Function-Portability.html
-#ifndef isnan
- # define isnan(x) \
- (sizeof (x) == sizeof (long double) ? isnan_ld (x) \
- : sizeof (x) == sizeof (double) ? isnan_d (x) \
- : isnan_f (x))
- static inline int isnan_f (float x) { return x != x; }
- static inline int isnan_d (double x) { return x != x; }
- static inline int isnan_ld (long double x) { return x != x; }
-#endif
-
-#ifndef isinf
- # define isinf(x) \
- (sizeof (x) == sizeof (long double) ? isinf_ld (x) \
- : sizeof (x) == sizeof (double) ? isinf_d (x) \
- : isinf_f (x))
- static inline int isinf_f (float x) { return isnan (x - x); }
- static inline int isinf_d (double x) { return isnan (x - x); }
- static inline int isinf_ld (long double x) { return isnan (x - x); }
-#endif
-
-
-// workaround for postgres defining their OIDs in a private header file
-#define QBOOLOID 16
-#define QINT8OID 20
-#define QINT2OID 21
-#define QINT4OID 23
-#define QNUMERICOID 1700
-#define QFLOAT4OID 700
-#define QFLOAT8OID 701
-#define QABSTIMEOID 702
-#define QRELTIMEOID 703
-#define QDATEOID 1082
-#define QTIMEOID 1083
-#define QTIMETZOID 1266
-#define QTIMESTAMPOID 1114
-#define QTIMESTAMPTZOID 1184
-#define QOIDOID 2278
-#define QBYTEAOID 17
-#define QREGPROCOID 24
-#define QXIDOID 28
-#define QCIDOID 29
-
-#define QBITOID 1560
-#define QVARBITOID 1562
-
-#define VARHDRSZ 4
-
-/* This is a compile time switch - if PQfreemem is declared, the compiler will use that one,
- otherwise it'll run in this template */
-template <typename T>
-inline void PQfreemem(T *t, int = 0) { free(t); }
-
-Q_DECLARE_OPAQUE_POINTER(PGconn*)
-Q_DECLARE_METATYPE(PGconn*)
-
-Q_DECLARE_OPAQUE_POINTER(PGresult*)
-Q_DECLARE_METATYPE(PGresult*)
-
-QT_BEGIN_NAMESPACE
-
-inline void qPQfreemem(void *buffer)
-{
- PQfreemem(buffer);
-}
-
-class QPSQLResultPrivate;
-
-class QPSQLResult: public QSqlResult
-{
- Q_DECLARE_PRIVATE(QPSQLResult)
-
-public:
- QPSQLResult(const QPSQLDriver *db);
- ~QPSQLResult();
-
- QVariant handle() const Q_DECL_OVERRIDE;
- void virtual_hook(int id, void *data) Q_DECL_OVERRIDE;
-
-protected:
- void cleanup();
- bool fetch(int i) Q_DECL_OVERRIDE;
- bool fetchFirst() Q_DECL_OVERRIDE;
- bool fetchLast() Q_DECL_OVERRIDE;
- QVariant data(int i) Q_DECL_OVERRIDE;
- bool isNull(int field) Q_DECL_OVERRIDE;
- bool reset (const QString &query) Q_DECL_OVERRIDE;
- int size() Q_DECL_OVERRIDE;
- int numRowsAffected() Q_DECL_OVERRIDE;
- QSqlRecord record() const Q_DECL_OVERRIDE;
- QVariant lastInsertId() const Q_DECL_OVERRIDE;
- bool prepare(const QString &query) Q_DECL_OVERRIDE;
- bool exec() Q_DECL_OVERRIDE;
-};
-
-class QPSQLDriverPrivate : public QSqlDriverPrivate
-{
- Q_DECLARE_PUBLIC(QPSQLDriver)
-public:
- QPSQLDriverPrivate() : QSqlDriverPrivate(),
- connection(0),
- isUtf8(false),
- pro(QPSQLDriver::Version6),
- sn(0),
- pendingNotifyCheck(false),
- hasBackslashEscape(false)
- { dbmsType = QSqlDriver::PostgreSQL; }
-
- PGconn *connection;
- bool isUtf8;
- QPSQLDriver::Protocol pro;
- QSocketNotifier *sn;
- QStringList seid;
- mutable bool pendingNotifyCheck;
- bool hasBackslashEscape;
-
- void appendTables(QStringList &tl, QSqlQuery &t, QChar type);
- PGresult * exec(const char * stmt) const;
- PGresult * exec(const QString & stmt) const;
- QPSQLDriver::Protocol getPSQLVersion();
- bool setEncodingUtf8();
- void setDatestyle();
- void detectBackslashEscape();
-};
-
-void QPSQLDriverPrivate::appendTables(QStringList &tl, QSqlQuery &t, QChar type)
-{
- QString query;
- if (pro >= QPSQLDriver::Version73) {
- query = QString::fromLatin1("select pg_class.relname, pg_namespace.nspname from pg_class "
- "left join pg_namespace on (pg_class.relnamespace = pg_namespace.oid) "
- "where (pg_class.relkind = '%1') and (pg_class.relname !~ '^Inv') "
- "and (pg_class.relname !~ '^pg_') "
- "and (pg_namespace.nspname != 'information_schema') ").arg(type);
- } else {
- query = QString::fromLatin1("select relname, null from pg_class where (relkind = '%1') "
- "and (relname !~ '^Inv') "
- "and (relname !~ '^pg_') ").arg(type);
- }
- t.exec(query);
- while (t.next()) {
- QString schema = t.value(1).toString();
- if (schema.isEmpty() || schema == QLatin1String("public"))
- tl.append(t.value(0).toString());
- else
- tl.append(t.value(0).toString().prepend(QLatin1Char('.')).prepend(schema));
- }
-}
-
-PGresult * QPSQLDriverPrivate::exec(const char * stmt) const
-{
- Q_Q(const QPSQLDriver);
- PGresult *result = PQexec(connection, stmt);
- if (seid.size() && !pendingNotifyCheck) {
- pendingNotifyCheck = true;
- QMetaObject::invokeMethod(const_cast<QPSQLDriver*>(q), "_q_handleNotification", Qt::QueuedConnection, Q_ARG(int,0));
- }
- return result;
-}
-
-PGresult * QPSQLDriverPrivate::exec(const QString & stmt) const
-{
- return exec(isUtf8 ? stmt.toUtf8().constData() : stmt.toLocal8Bit().constData());
-}
-
-class QPSQLResultPrivate : public QSqlResultPrivate
-{
- Q_DECLARE_PUBLIC(QPSQLResult)
-public:
- Q_DECLARE_SQLDRIVER_PRIVATE(QPSQLDriver);
- QPSQLResultPrivate(QPSQLResult *q, const QPSQLDriver *drv)
- : QSqlResultPrivate(q, drv),
- result(0),
- currentSize(-1),
- preparedQueriesEnabled(false)
- { }
-
- QString fieldSerial(int i) const Q_DECL_OVERRIDE { return QLatin1Char('$') + QString::number(i + 1); }
- void deallocatePreparedStmt();
-
- PGresult *result;
- int currentSize;
- bool preparedQueriesEnabled;
- QString preparedStmtId;
-
- bool processResults();
-};
-
-static QSqlError qMakeError(const QString& err, QSqlError::ErrorType type,
- const QPSQLDriverPrivate *p, PGresult* result = 0)
-{
- const char *s = PQerrorMessage(p->connection);
- QString msg = p->isUtf8 ? QString::fromUtf8(s) : QString::fromLocal8Bit(s);
- QString errorCode;
- if (result) {
- errorCode = QString::fromLatin1(PQresultErrorField(result, PG_DIAG_SQLSTATE));
- msg += QString::fromLatin1("(%1)").arg(errorCode);
- }
- return QSqlError(QLatin1String("QPSQL: ") + err, msg, type, errorCode);
-}
-
-bool QPSQLResultPrivate::processResults()
-{
- Q_Q(QPSQLResult);
- if (!result)
- return false;
-
- int status = PQresultStatus(result);
- if (status == PGRES_TUPLES_OK) {
- q->setSelect(true);
- q->setActive(true);
- currentSize = PQntuples(result);
- return true;
- } else if (status == PGRES_COMMAND_OK) {
- q->setSelect(false);
- q->setActive(true);
- currentSize = -1;
- return true;
- }
- q->setLastError(qMakeError(QCoreApplication::translate("QPSQLResult",
- "Unable to create query"), QSqlError::StatementError, drv_d_func(), result));
- return false;
-}
-
-static QVariant::Type qDecodePSQLType(int t)
-{
- QVariant::Type type = QVariant::Invalid;
- switch (t) {
- case QBOOLOID:
- type = QVariant::Bool;
- break;
- case QINT8OID:
- type = QVariant::LongLong;
- break;
- case QINT2OID:
- case QINT4OID:
- case QOIDOID:
- case QREGPROCOID:
- case QXIDOID:
- case QCIDOID:
- type = QVariant::Int;
- break;
- case QNUMERICOID:
- case QFLOAT4OID:
- case QFLOAT8OID:
- type = QVariant::Double;
- break;
- case QABSTIMEOID:
- case QRELTIMEOID:
- case QDATEOID:
- type = QVariant::Date;
- break;
- case QTIMEOID:
- case QTIMETZOID:
- type = QVariant::Time;
- break;
- case QTIMESTAMPOID:
- case QTIMESTAMPTZOID:
- type = QVariant::DateTime;
- break;
- case QBYTEAOID:
- type = QVariant::ByteArray;
- break;
- default:
- type = QVariant::String;
- break;
- }
- return type;
-}
-
-void QPSQLResultPrivate::deallocatePreparedStmt()
-{
- const QString stmt = QLatin1String("DEALLOCATE ") + preparedStmtId;
- PGresult *result = drv_d_func()->exec(stmt);
-
- if (PQresultStatus(result) != PGRES_COMMAND_OK)
- qWarning("Unable to free statement: %s", PQerrorMessage(drv_d_func()->connection));
- PQclear(result);
- preparedStmtId.clear();
-}
-
-QPSQLResult::QPSQLResult(const QPSQLDriver* db)
- : QSqlResult(*new QPSQLResultPrivate(this, db))
-{
- Q_D(QPSQLResult);
- d->preparedQueriesEnabled = db->hasFeature(QSqlDriver::PreparedQueries);
-}
-
-QPSQLResult::~QPSQLResult()
-{
- Q_D(QPSQLResult);
- cleanup();
-
- if (d->preparedQueriesEnabled && !d->preparedStmtId.isNull())
- d->deallocatePreparedStmt();
-}
-
-QVariant QPSQLResult::handle() const
-{
- Q_D(const QPSQLResult);
- return QVariant::fromValue(d->result);
-}
-
-void QPSQLResult::cleanup()
-{
- Q_D(QPSQLResult);
- if (d->result)
- PQclear(d->result);
- d->result = 0;
- setAt(QSql::BeforeFirstRow);
- d->currentSize = -1;
- setActive(false);
-}
-
-bool QPSQLResult::fetch(int i)
-{
- Q_D(const QPSQLResult);
- if (!isActive())
- return false;
- if (i < 0)
- return false;
- if (i >= d->currentSize)
- return false;
- if (at() == i)
- return true;
- setAt(i);
- return true;
-}
-
-bool QPSQLResult::fetchFirst()
-{
- return fetch(0);
-}
-
-bool QPSQLResult::fetchLast()
-{
- Q_D(const QPSQLResult);
- return fetch(PQntuples(d->result) - 1);
-}
-
-QVariant QPSQLResult::data(int i)
-{
- Q_D(const QPSQLResult);
- if (i >= PQnfields(d->result)) {
- qWarning("QPSQLResult::data: column %d out of range", i);
- return QVariant();
- }
- int ptype = PQftype(d->result, i);
- QVariant::Type type = qDecodePSQLType(ptype);
- const char *val = PQgetvalue(d->result, at(), i);
- if (PQgetisnull(d->result, at(), i))
- return QVariant(type);
- switch (type) {
- case QVariant::Bool:
- return QVariant((bool)(val[0] == 't'));
- case QVariant::String:
- return d->drv_d_func()->isUtf8 ? QString::fromUtf8(val) : QString::fromLatin1(val);
- case QVariant::LongLong:
- if (val[0] == '-')
- return QString::fromLatin1(val).toLongLong();
- else
- return QString::fromLatin1(val).toULongLong();
- case QVariant::Int:
- return atoi(val);
- case QVariant::Double:
- if (ptype == QNUMERICOID) {
- if (numericalPrecisionPolicy() != QSql::HighPrecision) {
- QVariant retval;
- bool convert;
- double dbl=QString::fromLatin1(val).toDouble(&convert);
- if (numericalPrecisionPolicy() == QSql::LowPrecisionInt64)
- retval = (qlonglong)dbl;
- else if (numericalPrecisionPolicy() == QSql::LowPrecisionInt32)
- retval = (int)dbl;
- else if (numericalPrecisionPolicy() == QSql::LowPrecisionDouble)
- retval = dbl;
- if (!convert)
- return QVariant();
- return retval;
- }
- return QString::fromLatin1(val);
- }
- return QString::fromLatin1(val).toDouble();
- case QVariant::Date:
- if (val[0] == '\0') {
- return QVariant(QDate());
- } else {
-#ifndef QT_NO_DATESTRING
- return QVariant(QDate::fromString(QString::fromLatin1(val), Qt::ISODate));
-#else
- return QVariant(QString::fromLatin1(val));
-#endif
- }
- case QVariant::Time: {
- const QString str = QString::fromLatin1(val);
-#ifndef QT_NO_DATESTRING
- if (str.isEmpty())
- return QVariant(QTime());
- else
- return QVariant(QTime::fromString(str, Qt::ISODate));
-#else
- return QVariant(str);
-#endif
- }
- case QVariant::DateTime: {
- QString dtval = QString::fromLatin1(val);
-#ifndef QT_NO_DATESTRING
- if (dtval.length() < 10) {
- return QVariant(QDateTime());
- } else {
- QChar sign = dtval[dtval.size() - 3];
- if (sign == QLatin1Char('-') || sign == QLatin1Char('+')) dtval += QLatin1String(":00");
- return QVariant(QDateTime::fromString(dtval, Qt::ISODate).toLocalTime());
- }
-#else
- return QVariant(dtval);
-#endif
- }
- case QVariant::ByteArray: {
- size_t len;
- unsigned char *data = PQunescapeBytea((const unsigned char*)val, &len);
- QByteArray ba(reinterpret_cast<const char *>(data), int(len));
- qPQfreemem(data);
- return QVariant(ba);
- }
- default:
- case QVariant::Invalid:
- qWarning("QPSQLResult::data: unknown data type");
- }
- return QVariant();
-}
-
-bool QPSQLResult::isNull(int field)
-{
- Q_D(const QPSQLResult);
- PQgetvalue(d->result, at(), field);
- return PQgetisnull(d->result, at(), field);
-}
-
-bool QPSQLResult::reset (const QString& query)
-{
- Q_D(QPSQLResult);
- cleanup();
- if (!driver())
- return false;
- if (!driver()->isOpen() || driver()->isOpenError())
- return false;
- d->result = d->drv_d_func()->exec(query);
- return d->processResults();
-}
-
-int QPSQLResult::size()
-{
- Q_D(const QPSQLResult);
- return d->currentSize;
-}
-
-int QPSQLResult::numRowsAffected()
-{
- Q_D(const QPSQLResult);
- return QString::fromLatin1(PQcmdTuples(d->result)).toInt();
-}
-
-QVariant QPSQLResult::lastInsertId() const
-{
- Q_D(const QPSQLResult);
- if (d->drv_d_func()->pro >= QPSQLDriver::Version81) {
- QSqlQuery qry(driver()->createResult());
- // Most recent sequence value obtained from nextval
- if (qry.exec(QLatin1String("SELECT lastval();")) && qry.next())
- return qry.value(0);
- } else if (isActive()) {
- Oid id = PQoidValue(d->result);
- if (id != InvalidOid)
- return QVariant(id);
- }
- return QVariant();
-}
-
-QSqlRecord QPSQLResult::record() const
-{
- Q_D(const QPSQLResult);
- QSqlRecord info;
- if (!isActive() || !isSelect())
- return info;
-
- int count = PQnfields(d->result);
- for (int i = 0; i < count; ++i) {
- QSqlField f;
- if (d->drv_d_func()->isUtf8)
- f.setName(QString::fromUtf8(PQfname(d->result, i)));
- else
- f.setName(QString::fromLocal8Bit(PQfname(d->result, i)));
- int ptype = PQftype(d->result, i);
- f.setType(qDecodePSQLType(ptype));
- int len = PQfsize(d->result, i);
- int precision = PQfmod(d->result, i);
-
- switch (ptype) {
- case QTIMESTAMPOID:
- case QTIMESTAMPTZOID:
- precision = 3;
- break;
-
- case QNUMERICOID:
- if (precision != -1) {
- len = (precision >> 16);
- precision = ((precision - VARHDRSZ) & 0xffff);
- }
- break;
- case QBITOID:
- case QVARBITOID:
- len = precision;
- precision = -1;
- break;
- default:
- if (len == -1 && precision >= VARHDRSZ) {
- len = precision - VARHDRSZ;
- precision = -1;
- }
- }
-
- f.setLength(len);
- f.setPrecision(precision);
- f.setSqlType(ptype);
- info.append(f);
- }
- return info;
-}
-
-void QPSQLResult::virtual_hook(int id, void *data)
-{
- Q_ASSERT(data);
-
- QSqlResult::virtual_hook(id, data);
-}
-
-static QString qCreateParamString(const QVector<QVariant> &boundValues, const QSqlDriver *driver)
-{
- if (boundValues.isEmpty())
- return QString();
-
- QString params;
- QSqlField f;
- for (int i = 0; i < boundValues.count(); ++i) {
- const QVariant &val = boundValues.at(i);
-
- f.setType(val.type());
- if (val.isNull())
- f.clear();
- else
- f.setValue(val);
- if(!params.isNull())
- params.append(QLatin1String(", "));
- params.append(driver->formatValue(f));
- }
- return params;
-}
-
-Q_GLOBAL_STATIC(QMutex, qMutex)
-QString qMakePreparedStmtId()
-{
- qMutex()->lock();
- static unsigned int qPreparedStmtCount = 0;
- QString id = QLatin1String("qpsqlpstmt_") + QString::number(++qPreparedStmtCount, 16);
- qMutex()->unlock();
- return id;
-}
-
-bool QPSQLResult::prepare(const QString &query)
-{
- Q_D(QPSQLResult);
- if (!d->preparedQueriesEnabled)
- return QSqlResult::prepare(query);
-
- cleanup();
-
- if (!d->preparedStmtId.isEmpty())
- d->deallocatePreparedStmt();
-
- const QString stmtId = qMakePreparedStmtId();
- const QString stmt = QString::fromLatin1("PREPARE %1 AS ").arg(stmtId).append(d->positionalToNamedBinding(query));
-
- PGresult *result = d->drv_d_func()->exec(stmt);
-
- if (PQresultStatus(result) != PGRES_COMMAND_OK) {
- setLastError(qMakeError(QCoreApplication::translate("QPSQLResult",
- "Unable to prepare statement"), QSqlError::StatementError, d->drv_d_func(), result));
- PQclear(result);
- d->preparedStmtId.clear();
- return false;
- }
-
- PQclear(result);
- d->preparedStmtId = stmtId;
- return true;
-}
-
-bool QPSQLResult::exec()
-{
- Q_D(QPSQLResult);
- if (!d->preparedQueriesEnabled)
- return QSqlResult::exec();
-
- cleanup();
-
- QString stmt;
- const QString params = qCreateParamString(boundValues(), driver());
- if (params.isEmpty())
- stmt = QString::fromLatin1("EXECUTE %1").arg(d->preparedStmtId);
- else
- stmt = QString::fromLatin1("EXECUTE %1 (%2)").arg(d->preparedStmtId).arg(params);
-
- d->result = d->drv_d_func()->exec(stmt);
-
- return d->processResults();
-}
-
-///////////////////////////////////////////////////////////////////
-
-bool QPSQLDriverPrivate::setEncodingUtf8()
-{
- PGresult* result = exec("SET CLIENT_ENCODING TO 'UNICODE'");
- int status = PQresultStatus(result);
- PQclear(result);
- return status == PGRES_COMMAND_OK;
-}
-
-void QPSQLDriverPrivate::setDatestyle()
-{
- PGresult* result = exec("SET DATESTYLE TO 'ISO'");
- int status = PQresultStatus(result);
- if (status != PGRES_COMMAND_OK)
- qWarning("%s", PQerrorMessage(connection));
- PQclear(result);
-}
-
-void QPSQLDriverPrivate::detectBackslashEscape()
-{
- // standard_conforming_strings option introduced in 8.2
- // http://www.postgresql.org/docs/8.2/static/runtime-config-compatible.html
- if (pro < QPSQLDriver::Version82) {
- hasBackslashEscape = true;
- } else {
- hasBackslashEscape = false;
- PGresult* result = exec(QLatin1Literal("SELECT '\\\\' x"));
- int status = PQresultStatus(result);
- if (status == PGRES_COMMAND_OK || status == PGRES_TUPLES_OK)
- if (QString::fromLatin1(PQgetvalue(result, 0, 0)) == QLatin1Literal("\\"))
- hasBackslashEscape = true;
- PQclear(result);
- }
-}
-
-static QPSQLDriver::Protocol qMakePSQLVersion(int vMaj, int vMin)
-{
- switch (vMaj) {
- case 6:
- return QPSQLDriver::Version6;
- case 7:
- {
- switch (vMin) {
- case 1:
- return QPSQLDriver::Version71;
- case 3:
- return QPSQLDriver::Version73;
- case 4:
- return QPSQLDriver::Version74;
- default:
- return QPSQLDriver::Version7;
- }
- break;
- }
- case 8:
- {
- switch (vMin) {
- case 1:
- return QPSQLDriver::Version81;
- case 2:
- return QPSQLDriver::Version82;
- case 3:
- return QPSQLDriver::Version83;
- case 4:
- return QPSQLDriver::Version84;
- default:
- return QPSQLDriver::Version8;
- }
- break;
- }
- case 9:
- return QPSQLDriver::Version9;
- break;
- default:
- break;
- }
- return QPSQLDriver::VersionUnknown;
-}
-
-QPSQLDriver::Protocol QPSQLDriverPrivate::getPSQLVersion()
-{
- QPSQLDriver::Protocol serverVersion = QPSQLDriver::Version6;
- PGresult* result = exec("select version()");
- int status = PQresultStatus(result);
- if (status == PGRES_COMMAND_OK || status == PGRES_TUPLES_OK) {
- QString val = QString::fromLatin1(PQgetvalue(result, 0, 0));
-
- QRegExp rx(QLatin1String("(\\d+)\\.(\\d+)"));
- rx.setMinimal(true); // enforce non-greedy RegExp
-
- if (rx.indexIn(val) != -1) {
- int vMaj = rx.cap(1).toInt();
- int vMin = rx.cap(2).toInt();
- serverVersion = qMakePSQLVersion(vMaj, vMin);
-#if defined(PG_MAJORVERSION)
- if (rx.indexIn(QLatin1String(PG_MAJORVERSION)) != -1)
-#elif defined(PG_VERSION)
- if (rx.indexIn(QLatin1String(PG_VERSION)) != -1)
-#else
- if (0)
-#endif
- {
- vMaj = rx.cap(1).toInt();
- vMin = rx.cap(2).toInt();
- QPSQLDriver::Protocol clientVersion = qMakePSQLVersion(vMaj, vMin);
-
- if (serverVersion >= QPSQLDriver::Version9 && clientVersion < QPSQLDriver::Version9) {
- //Client version before QPSQLDriver::Version9 only supports escape mode for bytea type,
- //but bytea format is set to hex by default in PSQL 9 and above. So need to force the
- //server use the old escape mode when connects to the new server with old client library.
- PQclear(result);
- result = exec("SET bytea_output=escape; ");
- status = PQresultStatus(result);
- } else if (serverVersion == QPSQLDriver::VersionUnknown) {
- serverVersion = clientVersion;
- if (serverVersion != QPSQLDriver::VersionUnknown)
- qWarning("The server version of this PostgreSQL is unknown, falling back to the client version.");
- }
- }
- }
- }
- PQclear(result);
-
- //keep the old behavior unchanged
- if (serverVersion == QPSQLDriver::VersionUnknown)
- serverVersion = QPSQLDriver::Version6;
-
- if (serverVersion < QPSQLDriver::Version71) {
- qWarning("This version of PostgreSQL is not supported and may not work.");
- }
-
- return serverVersion;
-}
-
-QPSQLDriver::QPSQLDriver(QObject *parent)
- : QSqlDriver(*new QPSQLDriverPrivate, parent)
-{
-}
-
-QPSQLDriver::QPSQLDriver(PGconn *conn, QObject *parent)
- : QSqlDriver(*new QPSQLDriverPrivate, parent)
-{
- Q_D(QPSQLDriver);
- d->connection = conn;
- if (conn) {
- d->pro = d->getPSQLVersion();
- d->detectBackslashEscape();
- setOpen(true);
- setOpenError(false);
- }
-}
-
-QPSQLDriver::~QPSQLDriver()
-{
- Q_D(QPSQLDriver);
- if (d->connection)
- PQfinish(d->connection);
-}
-
-QVariant QPSQLDriver::handle() const
-{
- Q_D(const QPSQLDriver);
- return QVariant::fromValue(d->connection);
-}
-
-bool QPSQLDriver::hasFeature(DriverFeature f) const
-{
- Q_D(const QPSQLDriver);
- switch (f) {
- case Transactions:
- case QuerySize:
- case LastInsertId:
- case LowPrecisionNumbers:
- case EventNotifications:
- return true;
- case PreparedQueries:
- case PositionalPlaceholders:
- return d->pro >= QPSQLDriver::Version82;
- case BatchOperations:
- case NamedPlaceholders:
- case SimpleLocking:
- case FinishQuery:
- case MultipleResultSets:
- case CancelQuery:
- return false;
- case BLOB:
- return d->pro >= QPSQLDriver::Version71;
- case Unicode:
- return d->isUtf8;
- }
- return false;
-}
-
-/*
- Quote a string for inclusion into the connection string
- \ -> \\
- ' -> \'
- surround string by single quotes
- */
-static QString qQuote(QString s)
-{
- s.replace(QLatin1Char('\\'), QLatin1String("\\\\"));
- s.replace(QLatin1Char('\''), QLatin1String("\\'"));
- s.append(QLatin1Char('\'')).prepend(QLatin1Char('\''));
- return s;
-}
-
-bool QPSQLDriver::open(const QString & db,
- const QString & user,
- const QString & password,
- const QString & host,
- int port,
- const QString& connOpts)
-{
- Q_D(QPSQLDriver);
- if (isOpen())
- close();
- QString connectString;
- if (!host.isEmpty())
- connectString.append(QLatin1String("host=")).append(qQuote(host));
- if (!db.isEmpty())
- connectString.append(QLatin1String(" dbname=")).append(qQuote(db));
- if (!user.isEmpty())
- connectString.append(QLatin1String(" user=")).append(qQuote(user));
- if (!password.isEmpty())
- connectString.append(QLatin1String(" password=")).append(qQuote(password));
- if (port != -1)
- connectString.append(QLatin1String(" port=")).append(qQuote(QString::number(port)));
-
- // add any connect options - the server will handle error detection
- if (!connOpts.isEmpty()) {
- QString opt = connOpts;
- opt.replace(QLatin1Char(';'), QLatin1Char(' '), Qt::CaseInsensitive);
- connectString.append(QLatin1Char(' ')).append(opt);
- }
-
- d->connection = PQconnectdb(connectString.toLocal8Bit().constData());
- if (PQstatus(d->connection) == CONNECTION_BAD) {
- setLastError(qMakeError(tr("Unable to connect"), QSqlError::ConnectionError, d));
- setOpenError(true);
- PQfinish(d->connection);
- d->connection = 0;
- return false;
- }
-
- d->pro = d->getPSQLVersion();
- d->detectBackslashEscape();
- d->isUtf8 = d->setEncodingUtf8();
- d->setDatestyle();
-
- setOpen(true);
- setOpenError(false);
- return true;
-}
-
-void QPSQLDriver::close()
-{
- Q_D(QPSQLDriver);
- if (isOpen()) {
-
- d->seid.clear();
- if (d->sn) {
- disconnect(d->sn, SIGNAL(activated(int)), this, SLOT(_q_handleNotification(int)));
- delete d->sn;
- d->sn = 0;
- }
-
- if (d->connection)
- PQfinish(d->connection);
- d->connection = 0;
- setOpen(false);
- setOpenError(false);
- }
-}
-
-QSqlResult *QPSQLDriver::createResult() const
-{
- return new QPSQLResult(this);
-}
-
-bool QPSQLDriver::beginTransaction()
-{
- Q_D(const QPSQLDriver);
- if (!isOpen()) {
- qWarning("QPSQLDriver::beginTransaction: Database not open");
- return false;
- }
- PGresult* res = d->exec("BEGIN");
- if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) {
- setLastError(qMakeError(tr("Could not begin transaction"),
- QSqlError::TransactionError, d, res));
- PQclear(res);
- return false;
- }
- PQclear(res);
- return true;
-}
-
-bool QPSQLDriver::commitTransaction()
-{
- Q_D(QPSQLDriver);
- if (!isOpen()) {
- qWarning("QPSQLDriver::commitTransaction: Database not open");
- return false;
- }
- PGresult* res = d->exec("COMMIT");
-
- bool transaction_failed = false;
-
- // XXX
- // This hack is used to tell if the transaction has succeeded for the protocol versions of
- // PostgreSQL below. For 7.x and other protocol versions we are left in the dark.
- // This hack can dissapear once there is an API to query this sort of information.
- if (d->pro == QPSQLDriver::Version8 ||
- d->pro == QPSQLDriver::Version81 ||
- d->pro == QPSQLDriver::Version82 ||
- d->pro == QPSQLDriver::Version83 ||
- d->pro == QPSQLDriver::Version84 ||
- d->pro == QPSQLDriver::Version9) {
- transaction_failed = qstrcmp(PQcmdStatus(res), "ROLLBACK") == 0;
- }
-
- if (!res || PQresultStatus(res) != PGRES_COMMAND_OK || transaction_failed) {
- setLastError(qMakeError(tr("Could not commit transaction"),
- QSqlError::TransactionError, d, res));
- PQclear(res);
- return false;
- }
- PQclear(res);
- return true;
-}
-
-bool QPSQLDriver::rollbackTransaction()
-{
- Q_D(QPSQLDriver);
- if (!isOpen()) {
- qWarning("QPSQLDriver::rollbackTransaction: Database not open");
- return false;
- }
- PGresult* res = d->exec("ROLLBACK");
- if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) {
- setLastError(qMakeError(tr("Could not rollback transaction"),
- QSqlError::TransactionError, d, res));
- PQclear(res);
- return false;
- }
- PQclear(res);
- return true;
-}
-
-QStringList QPSQLDriver::tables(QSql::TableType type) const
-{
- Q_D(const QPSQLDriver);
- QStringList tl;
- if (!isOpen())
- return tl;
- QSqlQuery t(createResult());
- t.setForwardOnly(true);
-
- if (type & QSql::Tables)
- const_cast<QPSQLDriverPrivate*>(d)->appendTables(tl, t, QLatin1Char('r'));
- if (type & QSql::Views)
- const_cast<QPSQLDriverPrivate*>(d)->appendTables(tl, t, QLatin1Char('v'));
- if (type & QSql::SystemTables) {
- t.exec(QLatin1String("select relname from pg_class where (relkind = 'r') "
- "and (relname like 'pg_%') "));
- while (t.next())
- tl.append(t.value(0).toString());
- }
-
- return tl;
-}
-
-static void qSplitTableName(QString &tablename, QString &schema)
-{
- int dot = tablename.indexOf(QLatin1Char('.'));
- if (dot == -1)
- return;
- schema = tablename.left(dot);
- tablename = tablename.mid(dot + 1);
-}
-
-QSqlIndex QPSQLDriver::primaryIndex(const QString& tablename) const
-{
- Q_D(const QPSQLDriver);
- QSqlIndex idx(tablename);
- if (!isOpen())
- return idx;
- QSqlQuery i(createResult());
- QString stmt;
-
- QString tbl = tablename;
- QString schema;
- qSplitTableName(tbl, schema);
-
- if (isIdentifierEscaped(tbl, QSqlDriver::TableName))
- tbl = stripDelimiters(tbl, QSqlDriver::TableName);
- else
- tbl = tbl.toLower();
-
- if (isIdentifierEscaped(schema, QSqlDriver::TableName))
- schema = stripDelimiters(schema, QSqlDriver::TableName);
- else
- schema = schema.toLower();
-
- switch(d->pro) {
- case QPSQLDriver::Version6:
- stmt = QLatin1String("select pg_att1.attname, int(pg_att1.atttypid), pg_cl.relname "
- "from pg_attribute pg_att1, pg_attribute pg_att2, pg_class pg_cl, pg_index pg_ind "
- "where pg_cl.relname = '%1_pkey' "
- "and pg_cl.oid = pg_ind.indexrelid "
- "and pg_att2.attrelid = pg_ind.indexrelid "
- "and pg_att1.attrelid = pg_ind.indrelid "
- "and pg_att1.attnum = pg_ind.indkey[pg_att2.attnum-1] "
- "order by pg_att2.attnum");
- break;
- case QPSQLDriver::Version7:
- case QPSQLDriver::Version71:
- stmt = QLatin1String("select pg_att1.attname, pg_att1.atttypid::int, pg_cl.relname "
- "from pg_attribute pg_att1, pg_attribute pg_att2, pg_class pg_cl, pg_index pg_ind "
- "where pg_cl.relname = '%1_pkey' "
- "and pg_cl.oid = pg_ind.indexrelid "
- "and pg_att2.attrelid = pg_ind.indexrelid "
- "and pg_att1.attrelid = pg_ind.indrelid "
- "and pg_att1.attnum = pg_ind.indkey[pg_att2.attnum-1] "
- "order by pg_att2.attnum");
- break;
- case QPSQLDriver::Version73:
- case QPSQLDriver::Version74:
- case QPSQLDriver::Version8:
- case QPSQLDriver::Version81:
- case QPSQLDriver::Version82:
- case QPSQLDriver::Version83:
- case QPSQLDriver::Version84:
- case QPSQLDriver::Version9:
- stmt = QLatin1String("SELECT pg_attribute.attname, pg_attribute.atttypid::int, "
- "pg_class.relname "
- "FROM pg_attribute, pg_class "
- "WHERE %1 pg_class.oid IN "
- "(SELECT indexrelid FROM pg_index WHERE indisprimary = true AND indrelid IN "
- " (SELECT oid FROM pg_class WHERE relname = '%2')) "
- "AND pg_attribute.attrelid = pg_class.oid "
- "AND pg_attribute.attisdropped = false "
- "ORDER BY pg_attribute.attnum");
- if (schema.isEmpty())
- stmt = stmt.arg(QLatin1String("pg_table_is_visible(pg_class.oid) AND"));
- else
- stmt = stmt.arg(QString::fromLatin1("pg_class.relnamespace = (select oid from "
- "pg_namespace where pg_namespace.nspname = '%1') AND ").arg(schema));
- break;
- case QPSQLDriver::VersionUnknown:
- qFatal("PSQL version is unknown");
- break;
- }
-
- i.exec(stmt.arg(tbl));
- while (i.isActive() && i.next()) {
- QSqlField f(i.value(0).toString(), qDecodePSQLType(i.value(1).toInt()));
- idx.append(f);
- idx.setName(i.value(2).toString());
- }
- return idx;
-}
-
-QSqlRecord QPSQLDriver::record(const QString& tablename) const
-{
- Q_D(const QPSQLDriver);
- QSqlRecord info;
- if (!isOpen())
- return info;
-
- QString tbl = tablename;
- QString schema;
- qSplitTableName(tbl, schema);
-
- if (isIdentifierEscaped(tbl, QSqlDriver::TableName))
- tbl = stripDelimiters(tbl, QSqlDriver::TableName);
- else
- tbl = tbl.toLower();
-
- if (isIdentifierEscaped(schema, QSqlDriver::TableName))
- schema = stripDelimiters(schema, QSqlDriver::TableName);
- else
- schema = schema.toLower();
-
- QString stmt;
- switch(d->pro) {
- case QPSQLDriver::Version6:
- stmt = QLatin1String("select pg_attribute.attname, int(pg_attribute.atttypid), "
- "pg_attribute.attnotnull, pg_attribute.attlen, pg_attribute.atttypmod, "
- "int(pg_attribute.attrelid), pg_attribute.attnum "
- "from pg_class, pg_attribute "
- "where pg_class.relname = '%1' "
- "and pg_attribute.attnum > 0 "
- "and pg_attribute.attrelid = pg_class.oid ");
- break;
- case QPSQLDriver::Version7:
- stmt = QLatin1String("select pg_attribute.attname, pg_attribute.atttypid::int, "
- "pg_attribute.attnotnull, pg_attribute.attlen, pg_attribute.atttypmod, "
- "pg_attribute.attrelid::int, pg_attribute.attnum "
- "from pg_class, pg_attribute "
- "where pg_class.relname = '%1' "
- "and pg_attribute.attnum > 0 "
- "and pg_attribute.attrelid = pg_class.oid ");
- break;
- case QPSQLDriver::Version71:
- stmt = QLatin1String("select pg_attribute.attname, pg_attribute.atttypid::int, "
- "pg_attribute.attnotnull, pg_attribute.attlen, pg_attribute.atttypmod, "
- "pg_attrdef.adsrc "
- "from pg_class, pg_attribute "
- "left join pg_attrdef on (pg_attrdef.adrelid = "
- "pg_attribute.attrelid and pg_attrdef.adnum = pg_attribute.attnum) "
- "where pg_class.relname = '%1' "
- "and pg_attribute.attnum > 0 "
- "and pg_attribute.attrelid = pg_class.oid "
- "order by pg_attribute.attnum ");
- break;
- case QPSQLDriver::Version73:
- case QPSQLDriver::Version74:
- case QPSQLDriver::Version8:
- case QPSQLDriver::Version81:
- case QPSQLDriver::Version82:
- case QPSQLDriver::Version83:
- case QPSQLDriver::Version84:
- case QPSQLDriver::Version9:
- stmt = QLatin1String("select pg_attribute.attname, pg_attribute.atttypid::int, "
- "pg_attribute.attnotnull, pg_attribute.attlen, pg_attribute.atttypmod, "
- "pg_attrdef.adsrc "
- "from pg_class, pg_attribute "
- "left join pg_attrdef on (pg_attrdef.adrelid = "
- "pg_attribute.attrelid and pg_attrdef.adnum = pg_attribute.attnum) "
- "where %1 "
- "and pg_class.relname = '%2' "
- "and pg_attribute.attnum > 0 "
- "and pg_attribute.attrelid = pg_class.oid "
- "and pg_attribute.attisdropped = false "
- "order by pg_attribute.attnum ");
- if (schema.isEmpty())
- stmt = stmt.arg(QLatin1String("pg_table_is_visible(pg_class.oid)"));
- else
- stmt = stmt.arg(QString::fromLatin1("pg_class.relnamespace = (select oid from "
- "pg_namespace where pg_namespace.nspname = '%1')").arg(schema));
- break;
- case QPSQLDriver::VersionUnknown:
- qFatal("PSQL version is unknown");
- break;
- }
-
- QSqlQuery query(createResult());
- query.exec(stmt.arg(tbl));
- if (d->pro >= QPSQLDriver::Version71) {
- while (query.next()) {
- int len = query.value(3).toInt();
- int precision = query.value(4).toInt();
- // swap length and precision if length == -1
- if (len == -1 && precision > -1) {
- len = precision - 4;
- precision = -1;
- }
- QString defVal = query.value(5).toString();
- if (!defVal.isEmpty() && defVal.at(0) == QLatin1Char('\''))
- defVal = defVal.mid(1, defVal.length() - 2);
- QSqlField f(query.value(0).toString(), qDecodePSQLType(query.value(1).toInt()));
- f.setRequired(query.value(2).toBool());
- f.setLength(len);
- f.setPrecision(precision);
- f.setDefaultValue(defVal);
- f.setSqlType(query.value(1).toInt());
- info.append(f);
- }
- } else {
- // Postgres < 7.1 cannot handle outer joins
- while (query.next()) {
- QString defVal;
- QString stmt2 = QLatin1String("select pg_attrdef.adsrc from pg_attrdef where "
- "pg_attrdef.adrelid = %1 and pg_attrdef.adnum = %2 ");
- QSqlQuery query2(createResult());
- query2.exec(stmt2.arg(query.value(5).toInt()).arg(query.value(6).toInt()));
- if (query2.isActive() && query2.next())
- defVal = query2.value(0).toString();
- if (!defVal.isEmpty() && defVal.at(0) == QLatin1Char('\''))
- defVal = defVal.mid(1, defVal.length() - 2);
- int len = query.value(3).toInt();
- int precision = query.value(4).toInt();
- // swap length and precision if length == -1
- if (len == -1 && precision > -1) {
- len = precision - 4;
- precision = -1;
- }
- QSqlField f(query.value(0).toString(), qDecodePSQLType(query.value(1).toInt()));
- f.setRequired(query.value(2).toBool());
- f.setLength(len);
- f.setPrecision(precision);
- f.setDefaultValue(defVal);
- f.setSqlType(query.value(1).toInt());
- info.append(f);
- }
- }
-
- return info;
-}
-
-template <class FloatType>
-inline void assignSpecialPsqlFloatValue(FloatType val, QString *target)
-{
- if (isnan(val)) {
- *target = QLatin1String("'NaN'");
- } else {
- switch (isinf(val)) {
- case 1:
- *target = QLatin1String("'Infinity'");
- break;
- case -1:
- *target = QLatin1String("'-Infinity'");
- break;
- }
- }
-}
-
-QString QPSQLDriver::formatValue(const QSqlField &field, bool trimStrings) const
-{
- Q_D(const QPSQLDriver);
- QString r;
- if (field.isNull()) {
- r = QLatin1String("NULL");
- } else {
- switch (int(field.type())) {
- case QVariant::DateTime:
-#ifndef QT_NO_DATESTRING
- if (field.value().toDateTime().isValid()) {
- // we force the value to be considered with a timezone information, and we force it to be UTC
- // this is safe since postgresql stores only the UTC value and not the timezone offset (only used
- // while parsing), so we have correct behavior in both case of with timezone and without tz
- r = QLatin1String("TIMESTAMP WITH TIME ZONE ") + QLatin1Char('\'') + field.value().toDateTime().toUTC().toString(QLatin1String("yyyy-MM-ddThh:mm:ss.zzz")) + QLatin1Char('Z') + QLatin1Char('\'');
- } else {
- r = QLatin1String("NULL");
- }
-#else
- r = QLatin1String("NULL");
-#endif // QT_NO_DATESTRING
- break;
- case QVariant::Time:
-#ifndef QT_NO_DATESTRING
- if (field.value().toTime().isValid()) {
- r = QLatin1Char('\'') + field.value().toTime().toString(QLatin1String("hh:mm:ss.zzz")) + QLatin1Char('\'');
- } else
-#endif
- {
- r = QLatin1String("NULL");
- }
- break;
- case QVariant::String:
- r = QSqlDriver::formatValue(field, trimStrings);
- if (d->hasBackslashEscape)
- r.replace(QLatin1String("\\"), QLatin1String("\\\\"));
- break;
- case QVariant::Bool:
- if (field.value().toBool())
- r = QLatin1String("TRUE");
- else
- r = QLatin1String("FALSE");
- break;
- case QVariant::ByteArray: {
- QByteArray ba(field.value().toByteArray());
- size_t len;
-#if defined PG_VERSION_NUM && PG_VERSION_NUM-0 >= 80200
- unsigned char *data = PQescapeByteaConn(d->connection, (const unsigned char*)ba.constData(), ba.size(), &len);
-#else
- unsigned char *data = PQescapeBytea((const unsigned char*)ba.constData(), ba.size(), &len);
-#endif
- r += QLatin1Char('\'');
- r += QLatin1String((const char*)data);
- r += QLatin1Char('\'');
- qPQfreemem(data);
- break;
- }
- case QMetaType::Float:
- assignSpecialPsqlFloatValue(field.value().toFloat(), &r);
- if (r.isEmpty())
- r = QSqlDriver::formatValue(field, trimStrings);
- break;
- case QVariant::Double:
- assignSpecialPsqlFloatValue(field.value().toDouble(), &r);
- if (r.isEmpty())
- r = QSqlDriver::formatValue(field, trimStrings);
- break;
- case QVariant::Uuid:
- r = QLatin1Char('\'') + field.value().toString() + QLatin1Char('\'');
- break;
- default:
- r = QSqlDriver::formatValue(field, trimStrings);
- break;
- }
- }
- return r;
-}
-
-QString QPSQLDriver::escapeIdentifier(const QString &identifier, IdentifierType) const
-{
- QString res = identifier;
- if(!identifier.isEmpty() && !identifier.startsWith(QLatin1Char('"')) && !identifier.endsWith(QLatin1Char('"')) ) {
- res.replace(QLatin1Char('"'), QLatin1String("\"\""));
- res.prepend(QLatin1Char('"')).append(QLatin1Char('"'));
- res.replace(QLatin1Char('.'), QLatin1String("\".\""));
- }
- return res;
-}
-
-bool QPSQLDriver::isOpen() const
-{
- Q_D(const QPSQLDriver);
- return PQstatus(d->connection) == CONNECTION_OK;
-}
-
-QPSQLDriver::Protocol QPSQLDriver::protocol() const
-{
- Q_D(const QPSQLDriver);
- return d->pro;
-}
-
-bool QPSQLDriver::subscribeToNotification(const QString &name)
-{
- Q_D(QPSQLDriver);
- if (!isOpen()) {
- qWarning("QPSQLDriver::subscribeToNotificationImplementation: database not open.");
- return false;
- }
-
- if (d->seid.contains(name)) {
- qWarning("QPSQLDriver::subscribeToNotificationImplementation: already subscribing to '%s'.",
- qPrintable(name));
- return false;
- }
-
- int socket = PQsocket(d->connection);
- if (socket) {
- // Add the name to the list of subscriptions here so that QSQLDriverPrivate::exec knows
- // to check for notifications immediately after executing the LISTEN
- d->seid << name;
- QString query = QLatin1String("LISTEN ") + escapeIdentifier(name, QSqlDriver::TableName);
- PGresult *result = d->exec(query);
- if (PQresultStatus(result) != PGRES_COMMAND_OK) {
- setLastError(qMakeError(tr("Unable to subscribe"), QSqlError::StatementError, d, result));
- PQclear(result);
- return false;
- }
- PQclear(result);
-
- if (!d->sn) {
- d->sn = new QSocketNotifier(socket, QSocketNotifier::Read);
- connect(d->sn, SIGNAL(activated(int)), this, SLOT(_q_handleNotification(int)));
- }
- } else {
- qWarning("QPSQLDriver::subscribeToNotificationImplementation: PQsocket didn't return a valid socket to listen on");
- return false;
- }
-
- return true;
-}
-
-bool QPSQLDriver::unsubscribeFromNotification(const QString &name)
-{
- Q_D(QPSQLDriver);
- if (!isOpen()) {
- qWarning("QPSQLDriver::unsubscribeFromNotificationImplementation: database not open.");
- return false;
- }
-
- if (!d->seid.contains(name)) {
- qWarning("QPSQLDriver::unsubscribeFromNotificationImplementation: not subscribed to '%s'.",
- qPrintable(name));
- return false;
- }
-
- QString query = QLatin1String("UNLISTEN ") + escapeIdentifier(name, QSqlDriver::TableName);
- PGresult *result = d->exec(query);
- if (PQresultStatus(result) != PGRES_COMMAND_OK) {
- setLastError(qMakeError(tr("Unable to unsubscribe"), QSqlError::StatementError, d, result));
- PQclear(result);
- return false;
- }
- PQclear(result);
-
- d->seid.removeAll(name);
-
- if (d->seid.isEmpty()) {
- disconnect(d->sn, SIGNAL(activated(int)), this, SLOT(_q_handleNotification(int)));
- delete d->sn;
- d->sn = 0;
- }
-
- return true;
-}
-
-QStringList QPSQLDriver::subscribedToNotifications() const
-{
- Q_D(const QPSQLDriver);
- return d->seid;
-}
-
-void QPSQLDriver::_q_handleNotification(int)
-{
- Q_D(QPSQLDriver);
- d->pendingNotifyCheck = false;
- PQconsumeInput(d->connection);
-
- PGnotify *notify = 0;
- while((notify = PQnotifies(d->connection)) != 0) {
- QString name(QLatin1String(notify->relname));
- if (d->seid.contains(name)) {
- QString payload;
-#if defined PG_VERSION_NUM && PG_VERSION_NUM-0 >= 70400
- if (notify->extra)
- payload = d->isUtf8 ? QString::fromUtf8(notify->extra) : QString::fromLatin1(notify->extra);
-#endif
- emit notification(name);
- QSqlDriver::NotificationSource source = (notify->be_pid == PQbackendPID(d->connection)) ? QSqlDriver::SelfSource : QSqlDriver::OtherSource;
- emit notification(name, source, payload);
- }
- else
- qWarning("QPSQLDriver: received notification for '%s' which isn't subscribed to.",
- qPrintable(name));
-
- qPQfreemem(notify);
- }
-}
-
-QT_END_NAMESPACE
diff --git a/src/sql/drivers/psql/qsql_psql.pri b/src/sql/drivers/psql/qsql_psql.pri
deleted file mode 100644
index 867be3edb8..0000000000
--- a/src/sql/drivers/psql/qsql_psql.pri
+++ /dev/null
@@ -1,10 +0,0 @@
-HEADERS += $$PWD/qsql_psql_p.h
-SOURCES += $$PWD/qsql_psql.cpp
-
-unix|mingw {
- LIBS += $$QT_LFLAGS_PSQL
- !contains(LIBS, .*pq.*):LIBS += -lpq
- QMAKE_CXXFLAGS *= $$QT_CFLAGS_PSQL
-} else {
- !contains(LIBS, .*pq.*):LIBS += -llibpq -lws2_32 -ladvapi32
-}
diff --git a/src/sql/drivers/psql/qsql_psql_p.h b/src/sql/drivers/psql/qsql_psql_p.h
deleted file mode 100644
index 8468b9af93..0000000000
--- a/src/sql/drivers/psql/qsql_psql_p.h
+++ /dev/null
@@ -1,128 +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_PSQL_H
-#define QSQL_PSQL_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 QT_PLUGIN
-#define Q_EXPORT_SQLDRIVER_PSQL
-#else
-#define Q_EXPORT_SQLDRIVER_PSQL Q_SQL_EXPORT
-#endif
-
-typedef struct pg_conn PGconn;
-typedef struct pg_result PGresult;
-
-QT_BEGIN_NAMESPACE
-
-class QPSQLDriverPrivate;
-
-class Q_EXPORT_SQLDRIVER_PSQL QPSQLDriver : public QSqlDriver
-{
- friend class QPSQLResultPrivate;
- Q_DECLARE_PRIVATE(QPSQLDriver)
- Q_OBJECT
-public:
- enum Protocol {
- VersionUnknown = -1,
- Version6 = 6,
- Version7 = 7,
- Version71 = 8,
- Version73 = 9,
- Version74 = 10,
- Version8 = 11,
- Version81 = 12,
- Version82 = 13,
- Version83 = 14,
- Version84 = 15,
- Version9 = 16
- };
-
- explicit QPSQLDriver(QObject *parent=0);
- explicit QPSQLDriver(PGconn *conn, QObject *parent=0);
- ~QPSQLDriver();
- bool hasFeature(DriverFeature f) const Q_DECL_OVERRIDE;
- bool open(const QString & db,
- const QString & user,
- const QString & password,
- const QString & host,
- int port,
- const QString& connOpts) Q_DECL_OVERRIDE;
- bool isOpen() const Q_DECL_OVERRIDE;
- void close() Q_DECL_OVERRIDE;
- QSqlResult *createResult() const Q_DECL_OVERRIDE;
- QStringList tables(QSql::TableType) const Q_DECL_OVERRIDE;
- QSqlIndex primaryIndex(const QString& tablename) const Q_DECL_OVERRIDE;
- QSqlRecord record(const QString& tablename) const Q_DECL_OVERRIDE;
-
- Protocol protocol() const;
- QVariant handle() const Q_DECL_OVERRIDE;
-
- QString escapeIdentifier(const QString &identifier, IdentifierType type) const Q_DECL_OVERRIDE;
- QString formatValue(const QSqlField &field, bool trimStrings) const Q_DECL_OVERRIDE;
-
- bool subscribeToNotification(const QString &name) Q_DECL_OVERRIDE;
- bool unsubscribeFromNotification(const QString &name) Q_DECL_OVERRIDE;
- QStringList subscribedToNotifications() const Q_DECL_OVERRIDE;
-
-protected:
- bool beginTransaction() Q_DECL_OVERRIDE;
- bool commitTransaction() Q_DECL_OVERRIDE;
- bool rollbackTransaction() Q_DECL_OVERRIDE;
-
-private Q_SLOTS:
- void _q_handleNotification(int);
-};
-
-QT_END_NAMESPACE
-
-#endif // QSQL_PSQL_H
diff --git a/src/sql/drivers/sqlite/qsql_sqlite.cpp b/src/sql/drivers/sqlite/qsql_sqlite.cpp
deleted file mode 100644
index 2a45b73d14..0000000000
--- a/src/sql/drivers/sqlite/qsql_sqlite.cpp
+++ /dev/null
@@ -1,828 +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_sqlite_p.h"
-
-#include <qcoreapplication.h>
-#include <qdatetime.h>
-#include <qvariant.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 <qdebug.h>
-
-#if defined Q_OS_WIN
-# include <qt_windows.h>
-#else
-# include <unistd.h>
-#endif
-
-#include <sqlite3.h>
-
-Q_DECLARE_OPAQUE_POINTER(sqlite3*)
-Q_DECLARE_METATYPE(sqlite3*)
-
-Q_DECLARE_OPAQUE_POINTER(sqlite3_stmt*)
-Q_DECLARE_METATYPE(sqlite3_stmt*)
-
-QT_BEGIN_NAMESPACE
-
-static QString _q_escapeIdentifier(const QString &identifier)
-{
- QString res = identifier;
- if(!identifier.isEmpty() && identifier.left(1) != QString(QLatin1Char('"')) && identifier.right(1) != QString(QLatin1Char('"')) ) {
- res.replace(QLatin1Char('"'), QLatin1String("\"\""));
- res.prepend(QLatin1Char('"')).append(QLatin1Char('"'));
- res.replace(QLatin1Char('.'), QLatin1String("\".\""));
- }
- return res;
-}
-
-static QVariant::Type qGetColumnType(const QString &tpName)
-{
- const QString typeName = tpName.toLower();
-
- if (typeName == QLatin1String("integer")
- || typeName == QLatin1String("int"))
- return QVariant::Int;
- if (typeName == QLatin1String("double")
- || typeName == QLatin1String("float")
- || typeName == QLatin1String("real")
- || typeName.startsWith(QLatin1String("numeric")))
- return QVariant::Double;
- if (typeName == QLatin1String("blob"))
- return QVariant::ByteArray;
- if (typeName == QLatin1String("boolean")
- || typeName == QLatin1String("bool"))
- return QVariant::Bool;
- return QVariant::String;
-}
-
-static QSqlError qMakeError(sqlite3 *access, const QString &descr, QSqlError::ErrorType type,
- int errorCode = -1)
-{
- return QSqlError(descr,
- QString(reinterpret_cast<const QChar *>(sqlite3_errmsg16(access))),
- type, QString::number(errorCode));
-}
-
-class QSQLiteResultPrivate;
-
-class QSQLiteResult : public QSqlCachedResult
-{
- Q_DECLARE_PRIVATE(QSQLiteResult)
- friend class QSQLiteDriver;
-
-public:
- explicit QSQLiteResult(const QSQLiteDriver* db);
- ~QSQLiteResult();
- QVariant handle() const Q_DECL_OVERRIDE;
-
-protected:
- bool gotoNext(QSqlCachedResult::ValueCache& row, int idx) Q_DECL_OVERRIDE;
- bool reset(const QString &query) Q_DECL_OVERRIDE;
- bool prepare(const QString &query) Q_DECL_OVERRIDE;
- bool exec() Q_DECL_OVERRIDE;
- int size() Q_DECL_OVERRIDE;
- int numRowsAffected() Q_DECL_OVERRIDE;
- QVariant lastInsertId() const Q_DECL_OVERRIDE;
- QSqlRecord record() const Q_DECL_OVERRIDE;
- void detachFromResultSet() Q_DECL_OVERRIDE;
- void virtual_hook(int id, void *data) Q_DECL_OVERRIDE;
-};
-
-class QSQLiteDriverPrivate : public QSqlDriverPrivate
-{
- Q_DECLARE_PUBLIC(QSQLiteDriver)
-
-public:
- inline QSQLiteDriverPrivate() : QSqlDriverPrivate(), access(0) { dbmsType = QSqlDriver::SQLite; }
- sqlite3 *access;
- QList <QSQLiteResult *> results;
-};
-
-
-class QSQLiteResultPrivate: public QSqlCachedResultPrivate
-{
- Q_DECLARE_PUBLIC(QSQLiteResult)
-
-public:
- Q_DECLARE_SQLDRIVER_PRIVATE(QSQLiteDriver)
- QSQLiteResultPrivate(QSQLiteResult *q, const QSQLiteDriver *drv);
- void cleanup();
- bool fetchNext(QSqlCachedResult::ValueCache &values, int idx, bool initialFetch);
- // initializes the recordInfo and the cache
- void initColumns(bool emptyResultset);
- void finalize();
-
- sqlite3_stmt *stmt;
-
- bool skippedStatus; // the status of the fetchNext() that's skipped
- bool skipRow; // skip the next fetchNext()?
- QSqlRecord rInf;
- QVector<QVariant> firstRow;
-};
-
-QSQLiteResultPrivate::QSQLiteResultPrivate(QSQLiteResult *q, const QSQLiteDriver *drv)
- : QSqlCachedResultPrivate(q, drv),
- stmt(0),
- skippedStatus(false),
- skipRow(false)
-{
-}
-
-void QSQLiteResultPrivate::cleanup()
-{
- Q_Q(QSQLiteResult);
- finalize();
- rInf.clear();
- skippedStatus = false;
- skipRow = false;
- q->setAt(QSql::BeforeFirstRow);
- q->setActive(false);
- q->cleanup();
-}
-
-void QSQLiteResultPrivate::finalize()
-{
- if (!stmt)
- return;
-
- sqlite3_finalize(stmt);
- stmt = 0;
-}
-
-void QSQLiteResultPrivate::initColumns(bool emptyResultset)
-{
- Q_Q(QSQLiteResult);
- int nCols = sqlite3_column_count(stmt);
- if (nCols <= 0)
- return;
-
- q->init(nCols);
-
- for (int i = 0; i < nCols; ++i) {
- QString colName = QString(reinterpret_cast<const QChar *>(
- sqlite3_column_name16(stmt, i))
- ).remove(QLatin1Char('"'));
-
- // must use typeName for resolving the type to match QSqliteDriver::record
- QString typeName = QString(reinterpret_cast<const QChar *>(
- sqlite3_column_decltype16(stmt, i)));
- // sqlite3_column_type is documented to have undefined behavior if the result set is empty
- int stp = emptyResultset ? -1 : sqlite3_column_type(stmt, i);
-
- QVariant::Type fieldType;
-
- if (!typeName.isEmpty()) {
- fieldType = qGetColumnType(typeName);
- } else {
- // Get the proper type for the field based on stp value
- switch (stp) {
- case SQLITE_INTEGER:
- fieldType = QVariant::Int;
- break;
- case SQLITE_FLOAT:
- fieldType = QVariant::Double;
- break;
- case SQLITE_BLOB:
- fieldType = QVariant::ByteArray;
- break;
- case SQLITE_TEXT:
- fieldType = QVariant::String;
- break;
- case SQLITE_NULL:
- default:
- fieldType = QVariant::Invalid;
- break;
- }
- }
-
- QSqlField fld(colName, fieldType);
- fld.setSqlType(stp);
- rInf.append(fld);
- }
-}
-
-bool QSQLiteResultPrivate::fetchNext(QSqlCachedResult::ValueCache &values, int idx, bool initialFetch)
-{
- Q_Q(QSQLiteResult);
- 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(initialFetch) {
- firstRow.clear();
- firstRow.resize(sqlite3_column_count(stmt));
- }
-
- if (!stmt) {
- q->setLastError(QSqlError(QCoreApplication::translate("QSQLiteResult", "Unable to fetch row"),
- QCoreApplication::translate("QSQLiteResult", "No query"), QSqlError::ConnectionError));
- q->setAt(QSql::AfterLastRow);
- return false;
- }
- res = sqlite3_step(stmt);
-
- switch(res) {
- case SQLITE_ROW:
- // check to see if should fill out columns
- if (rInf.isEmpty())
- // must be first call.
- initColumns(false);
- if (idx < 0 && !initialFetch)
- return true;
- for (i = 0; i < rInf.count(); ++i) {
- switch (sqlite3_column_type(stmt, i)) {
- case SQLITE_BLOB:
- values[i + idx] = QByteArray(static_cast<const char *>(
- sqlite3_column_blob(stmt, i)),
- sqlite3_column_bytes(stmt, i));
- break;
- case SQLITE_INTEGER:
- values[i + idx] = sqlite3_column_int64(stmt, i);
- break;
- case SQLITE_FLOAT:
- switch(q->numericalPrecisionPolicy()) {
- case QSql::LowPrecisionInt32:
- values[i + idx] = sqlite3_column_int(stmt, i);
- break;
- case QSql::LowPrecisionInt64:
- values[i + idx] = sqlite3_column_int64(stmt, i);
- break;
- case QSql::LowPrecisionDouble:
- case QSql::HighPrecision:
- default:
- values[i + idx] = sqlite3_column_double(stmt, i);
- break;
- };
- break;
- case SQLITE_NULL:
- values[i + idx] = QVariant(QVariant::String);
- break;
- default:
- values[i + idx] = QString(reinterpret_cast<const QChar *>(
- sqlite3_column_text16(stmt, i)),
- sqlite3_column_bytes16(stmt, i) / sizeof(QChar));
- break;
- }
- }
- return true;
- case SQLITE_DONE:
- if (rInf.isEmpty())
- // must be first call.
- initColumns(true);
- q->setAt(QSql::AfterLastRow);
- sqlite3_reset(stmt);
- return false;
- case SQLITE_CONSTRAINT:
- case SQLITE_ERROR:
- // SQLITE_ERROR is a generic error code and we must call sqlite3_reset()
- // to get the specific error message.
- res = sqlite3_reset(stmt);
- q->setLastError(qMakeError(drv_d_func()->access, QCoreApplication::translate("QSQLiteResult",
- "Unable to fetch row"), QSqlError::ConnectionError, res));
- q->setAt(QSql::AfterLastRow);
- return false;
- case SQLITE_MISUSE:
- case SQLITE_BUSY:
- default:
- // something wrong, don't get col info, but still return false
- q->setLastError(qMakeError(drv_d_func()->access, QCoreApplication::translate("QSQLiteResult",
- "Unable to fetch row"), QSqlError::ConnectionError, res));
- sqlite3_reset(stmt);
- q->setAt(QSql::AfterLastRow);
- return false;
- }
- return false;
-}
-
-QSQLiteResult::QSQLiteResult(const QSQLiteDriver* db)
- : QSqlCachedResult(*new QSQLiteResultPrivate(this, db))
-{
- Q_D(QSQLiteResult);
- const_cast<QSQLiteDriverPrivate*>(d->drv_d_func())->results.append(this);
-}
-
-QSQLiteResult::~QSQLiteResult()
-{
- Q_D(QSQLiteResult);
- if (d->drv_d_func())
- const_cast<QSQLiteDriverPrivate*>(d->drv_d_func())->results.removeOne(this);
- d->cleanup();
-}
-
-void QSQLiteResult::virtual_hook(int id, void *data)
-{
- QSqlCachedResult::virtual_hook(id, data);
-}
-
-bool QSQLiteResult::reset(const QString &query)
-{
- if (!prepare(query))
- return false;
- return exec();
-}
-
-bool QSQLiteResult::prepare(const QString &query)
-{
- Q_D(QSQLiteResult);
- if (!driver() || !driver()->isOpen() || driver()->isOpenError())
- return false;
-
- d->cleanup();
-
- setSelect(false);
-
- const void *pzTail = NULL;
-
-#if (SQLITE_VERSION_NUMBER >= 3003011)
- int res = sqlite3_prepare16_v2(d->drv_d_func()->access, query.constData(), (query.size() + 1) * sizeof(QChar),
- &d->stmt, &pzTail);
-#else
- int res = sqlite3_prepare16(d->access, query.constData(), (query.size() + 1) * sizeof(QChar),
- &d->stmt, &pzTail);
-#endif
-
- if (res != SQLITE_OK) {
- setLastError(qMakeError(d->drv_d_func()->access, QCoreApplication::translate("QSQLiteResult",
- "Unable to execute statement"), QSqlError::StatementError, res));
- d->finalize();
- return false;
- } else if (pzTail && !QString(reinterpret_cast<const QChar *>(pzTail)).trimmed().isEmpty()) {
- setLastError(qMakeError(d->drv_d_func()->access, QCoreApplication::translate("QSQLiteResult",
- "Unable to execute multiple statements at a time"), QSqlError::StatementError, SQLITE_MISUSE));
- d->finalize();
- return false;
- }
- return true;
-}
-
-bool QSQLiteResult::exec()
-{
- Q_D(QSQLiteResult);
- const QVector<QVariant> values = boundValues();
-
- d->skippedStatus = false;
- d->skipRow = false;
- d->rInf.clear();
- clearValues();
- setLastError(QSqlError());
-
- int res = sqlite3_reset(d->stmt);
- if (res != SQLITE_OK) {
- setLastError(qMakeError(d->drv_d_func()->access, QCoreApplication::translate("QSQLiteResult",
- "Unable to reset statement"), QSqlError::StatementError, res));
- d->finalize();
- return false;
- }
- int paramCount = sqlite3_bind_parameter_count(d->stmt);
- if (paramCount == values.count()) {
- for (int i = 0; i < paramCount; ++i) {
- res = SQLITE_OK;
- const QVariant value = values.at(i);
-
- if (value.isNull()) {
- res = sqlite3_bind_null(d->stmt, i + 1);
- } else {
- switch (value.type()) {
- case QVariant::ByteArray: {
- const QByteArray *ba = static_cast<const QByteArray*>(value.constData());
- res = sqlite3_bind_blob(d->stmt, i + 1, ba->constData(),
- ba->size(), SQLITE_STATIC);
- break; }
- case QVariant::Int:
- case QVariant::Bool:
- res = sqlite3_bind_int(d->stmt, i + 1, value.toInt());
- break;
- case QVariant::Double:
- res = sqlite3_bind_double(d->stmt, i + 1, value.toDouble());
- break;
- case QVariant::UInt:
- case QVariant::LongLong:
- res = sqlite3_bind_int64(d->stmt, i + 1, value.toLongLong());
- break;
- case QVariant::DateTime: {
- const QDateTime dateTime = value.toDateTime();
- const QString str = dateTime.toString(QStringLiteral("yyyy-MM-ddThh:mm:ss.zzz"));
- res = sqlite3_bind_text16(d->stmt, i + 1, str.utf16(),
- str.size() * sizeof(ushort), SQLITE_TRANSIENT);
- break;
- }
- case QVariant::Time: {
- const QTime time = value.toTime();
- const QString str = time.toString(QStringLiteral("hh:mm:ss.zzz"));
- res = sqlite3_bind_text16(d->stmt, i + 1, str.utf16(),
- str.size() * sizeof(ushort), SQLITE_TRANSIENT);
- break;
- }
- case QVariant::String: {
- // lifetime of string == lifetime of its qvariant
- const QString *str = static_cast<const QString*>(value.constData());
- res = sqlite3_bind_text16(d->stmt, i + 1, str->utf16(),
- (str->size()) * sizeof(QChar), SQLITE_STATIC);
- break; }
- default: {
- QString str = value.toString();
- // SQLITE_TRANSIENT makes sure that sqlite buffers the data
- res = sqlite3_bind_text16(d->stmt, i + 1, str.utf16(),
- (str.size()) * sizeof(QChar), SQLITE_TRANSIENT);
- break; }
- }
- }
- if (res != SQLITE_OK) {
- setLastError(qMakeError(d->drv_d_func()->access, QCoreApplication::translate("QSQLiteResult",
- "Unable to bind parameters"), QSqlError::StatementError, res));
- d->finalize();
- return false;
- }
- }
- } else {
- setLastError(QSqlError(QCoreApplication::translate("QSQLiteResult",
- "Parameter count mismatch"), QString(), QSqlError::StatementError));
- return false;
- }
- 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 QSQLiteResult::gotoNext(QSqlCachedResult::ValueCache& row, int idx)
-{
- Q_D(QSQLiteResult);
- return d->fetchNext(row, idx, false);
-}
-
-int QSQLiteResult::size()
-{
- return -1;
-}
-
-int QSQLiteResult::numRowsAffected()
-{
- Q_D(const QSQLiteResult);
- return sqlite3_changes(d->drv_d_func()->access);
-}
-
-QVariant QSQLiteResult::lastInsertId() const
-{
- Q_D(const QSQLiteResult);
- if (isActive()) {
- qint64 id = sqlite3_last_insert_rowid(d->drv_d_func()->access);
- if (id)
- return id;
- }
- return QVariant();
-}
-
-QSqlRecord QSQLiteResult::record() const
-{
- Q_D(const QSQLiteResult);
- if (!isActive() || !isSelect())
- return QSqlRecord();
- return d->rInf;
-}
-
-void QSQLiteResult::detachFromResultSet()
-{
- Q_D(QSQLiteResult);
- if (d->stmt)
- sqlite3_reset(d->stmt);
-}
-
-QVariant QSQLiteResult::handle() const
-{
- Q_D(const QSQLiteResult);
- return QVariant::fromValue(d->stmt);
-}
-
-/////////////////////////////////////////////////////////
-
-QSQLiteDriver::QSQLiteDriver(QObject * parent)
- : QSqlDriver(*new QSQLiteDriverPrivate, parent)
-{
-}
-
-QSQLiteDriver::QSQLiteDriver(sqlite3 *connection, QObject *parent)
- : QSqlDriver(*new QSQLiteDriverPrivate, parent)
-{
- Q_D(QSQLiteDriver);
- d->access = connection;
- setOpen(true);
- setOpenError(false);
-}
-
-
-QSQLiteDriver::~QSQLiteDriver()
-{
-}
-
-bool QSQLiteDriver::hasFeature(DriverFeature f) const
-{
- switch (f) {
- case BLOB:
- case Transactions:
- case Unicode:
- case LastInsertId:
- case PreparedQueries:
- case PositionalPlaceholders:
- case SimpleLocking:
- case FinishQuery:
- case LowPrecisionNumbers:
- return true;
- case QuerySize:
- case NamedPlaceholders:
- case BatchOperations:
- case EventNotifications:
- case MultipleResultSets:
- case CancelQuery:
- return false;
- }
- return false;
-}
-
-/*
- SQLite dbs have no user name, passwords, hosts or ports.
- just file names.
-*/
-bool QSQLiteDriver::open(const QString & db, const QString &, const QString &, const QString &, int, const QString &conOpts)
-{
- Q_D(QSQLiteDriver);
- if (isOpen())
- close();
-
-
- int timeOut = 5000;
- bool sharedCache = false;
- bool openReadOnlyOption = false;
- bool openUriOption = false;
-
- const auto opts = conOpts.splitRef(QLatin1Char(';'));
- for (auto option : opts) {
- option = option.trimmed();
- if (option.startsWith(QLatin1String("QSQLITE_BUSY_TIMEOUT"))) {
- option = option.mid(20).trimmed();
- if (option.startsWith(QLatin1Char('='))) {
- bool ok;
- const int nt = option.mid(1).trimmed().toInt(&ok);
- if (ok)
- timeOut = nt;
- }
- } else if (option == QLatin1String("QSQLITE_OPEN_READONLY")) {
- openReadOnlyOption = true;
- } else if (option == QLatin1String("QSQLITE_OPEN_URI")) {
- openUriOption = true;
- } else if (option == QLatin1String("QSQLITE_ENABLE_SHARED_CACHE")) {
- sharedCache = true;
- }
- }
-
- int openMode = (openReadOnlyOption ? SQLITE_OPEN_READONLY : (SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE));
- if (openUriOption)
- openMode |= SQLITE_OPEN_URI;
-
- sqlite3_enable_shared_cache(sharedCache);
-
- if (sqlite3_open_v2(db.toUtf8().constData(), &d->access, openMode, NULL) == SQLITE_OK) {
- sqlite3_busy_timeout(d->access, timeOut);
- setOpen(true);
- setOpenError(false);
- return true;
- } else {
- if (d->access) {
- sqlite3_close(d->access);
- d->access = 0;
- }
-
- setLastError(qMakeError(d->access, tr("Error opening database"),
- QSqlError::ConnectionError));
- setOpenError(true);
- return false;
- }
-}
-
-void QSQLiteDriver::close()
-{
- Q_D(QSQLiteDriver);
- if (isOpen()) {
- for (QSQLiteResult *result : qAsConst(d->results))
- result->d_func()->finalize();
-
- if (sqlite3_close(d->access) != SQLITE_OK)
- setLastError(qMakeError(d->access, tr("Error closing database"),
- QSqlError::ConnectionError));
- d->access = 0;
- setOpen(false);
- setOpenError(false);
- }
-}
-
-QSqlResult *QSQLiteDriver::createResult() const
-{
- return new QSQLiteResult(this);
-}
-
-bool QSQLiteDriver::beginTransaction()
-{
- if (!isOpen() || isOpenError())
- return false;
-
- QSqlQuery q(createResult());
- if (!q.exec(QLatin1String("BEGIN"))) {
- setLastError(QSqlError(tr("Unable to begin transaction"),
- q.lastError().databaseText(), QSqlError::TransactionError));
- return false;
- }
-
- return true;
-}
-
-bool QSQLiteDriver::commitTransaction()
-{
- if (!isOpen() || isOpenError())
- return false;
-
- QSqlQuery q(createResult());
- if (!q.exec(QLatin1String("COMMIT"))) {
- setLastError(QSqlError(tr("Unable to commit transaction"),
- q.lastError().databaseText(), QSqlError::TransactionError));
- return false;
- }
-
- return true;
-}
-
-bool QSQLiteDriver::rollbackTransaction()
-{
- if (!isOpen() || isOpenError())
- return false;
-
- QSqlQuery q(createResult());
- if (!q.exec(QLatin1String("ROLLBACK"))) {
- setLastError(QSqlError(tr("Unable to rollback transaction"),
- q.lastError().databaseText(), QSqlError::TransactionError));
- return false;
- }
-
- return true;
-}
-
-QStringList QSQLiteDriver::tables(QSql::TableType type) const
-{
- QStringList res;
- if (!isOpen())
- return res;
-
- QSqlQuery q(createResult());
- q.setForwardOnly(true);
-
- QString sql = QLatin1String("SELECT name FROM sqlite_master WHERE %1 "
- "UNION ALL SELECT name FROM sqlite_temp_master WHERE %1");
- if ((type & QSql::Tables) && (type & QSql::Views))
- sql = sql.arg(QLatin1String("type='table' OR type='view'"));
- else if (type & QSql::Tables)
- sql = sql.arg(QLatin1String("type='table'"));
- else if (type & QSql::Views)
- sql = sql.arg(QLatin1String("type='view'"));
- else
- sql.clear();
-
- if (!sql.isEmpty() && q.exec(sql)) {
- 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;
-}
-
-static QSqlIndex qGetTableInfo(QSqlQuery &q, const QString &tableName, bool onlyPIndex = false)
-{
- QString schema;
- QString table(tableName);
- int indexOfSeparator = tableName.indexOf(QLatin1Char('.'));
- if (indexOfSeparator > -1) {
- schema = tableName.left(indexOfSeparator).append(QLatin1Char('.'));
- table = tableName.mid(indexOfSeparator + 1);
- }
- q.exec(QLatin1String("PRAGMA ") + schema + QLatin1String("table_info (") + _q_escapeIdentifier(table) + QLatin1Char(')'));
-
- QSqlIndex ind;
- while (q.next()) {
- bool isPk = q.value(5).toInt();
- if (onlyPIndex && !isPk)
- continue;
- QString typeName = q.value(2).toString().toLower();
- QSqlField fld(q.value(1).toString(), qGetColumnType(typeName));
- if (isPk && (typeName == QLatin1String("integer")))
- // INTEGER PRIMARY KEY fields are auto-generated in sqlite
- // INT PRIMARY KEY is not the same as INTEGER PRIMARY KEY!
- fld.setAutoValue(true);
- fld.setRequired(q.value(3).toInt() != 0);
- fld.setDefaultValue(q.value(4));
- ind.append(fld);
- }
- return ind;
-}
-
-QSqlIndex QSQLiteDriver::primaryIndex(const QString &tblname) const
-{
- if (!isOpen())
- return QSqlIndex();
-
- QString table = tblname;
- if (isIdentifierEscaped(table, QSqlDriver::TableName))
- table = stripDelimiters(table, QSqlDriver::TableName);
-
- QSqlQuery q(createResult());
- q.setForwardOnly(true);
- return qGetTableInfo(q, table, true);
-}
-
-QSqlRecord QSQLiteDriver::record(const QString &tbl) const
-{
- if (!isOpen())
- return QSqlRecord();
-
- QString table = tbl;
- if (isIdentifierEscaped(table, QSqlDriver::TableName))
- table = stripDelimiters(table, QSqlDriver::TableName);
-
- QSqlQuery q(createResult());
- q.setForwardOnly(true);
- return qGetTableInfo(q, table);
-}
-
-QVariant QSQLiteDriver::handle() const
-{
- Q_D(const QSQLiteDriver);
- return QVariant::fromValue(d->access);
-}
-
-QString QSQLiteDriver::escapeIdentifier(const QString &identifier, IdentifierType type) const
-{
- Q_UNUSED(type);
- return _q_escapeIdentifier(identifier);
-}
-
-QT_END_NAMESPACE
diff --git a/src/sql/drivers/sqlite/qsql_sqlite.pri b/src/sql/drivers/sqlite/qsql_sqlite.pri
deleted file mode 100644
index e323f2eba5..0000000000
--- a/src/sql/drivers/sqlite/qsql_sqlite.pri
+++ /dev/null
@@ -1,9 +0,0 @@
-HEADERS += $$PWD/qsql_sqlite_p.h
-SOURCES += $$PWD/qsql_sqlite.cpp
-
-!system-sqlite:!contains(LIBS, .*sqlite3.*) {
- include($$PWD/../../../3rdparty/sqlite.pri)
-} else {
- LIBS += $$QT_LFLAGS_SQLITE
- QMAKE_CXXFLAGS *= $$QT_CFLAGS_SQLITE
-}
diff --git a/src/sql/drivers/sqlite/qsql_sqlite_p.h b/src/sql/drivers/sqlite/qsql_sqlite_p.h
deleted file mode 100644
index c9b7708698..0000000000
--- a/src/sql/drivers/sqlite/qsql_sqlite_p.h
+++ /dev/null
@@ -1,100 +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_SQLITE_H
-#define QSQL_SQLITE_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>
-
-struct sqlite3;
-
-#ifdef QT_PLUGIN
-#define Q_EXPORT_SQLDRIVER_SQLITE
-#else
-#define Q_EXPORT_SQLDRIVER_SQLITE Q_SQL_EXPORT
-#endif
-
-QT_BEGIN_NAMESPACE
-
-class QSqlResult;
-class QSQLiteDriverPrivate;
-
-class Q_EXPORT_SQLDRIVER_SQLITE QSQLiteDriver : public QSqlDriver
-{
- Q_DECLARE_PRIVATE(QSQLiteDriver)
- Q_OBJECT
- friend class QSQLiteResultPrivate;
-public:
- explicit QSQLiteDriver(QObject *parent = 0);
- explicit QSQLiteDriver(sqlite3 *connection, QObject *parent = 0);
- ~QSQLiteDriver();
- bool hasFeature(DriverFeature f) const Q_DECL_OVERRIDE;
- bool open(const QString & db,
- const QString & user,
- const QString & password,
- const QString & host,
- int port,
- const QString & connOpts) Q_DECL_OVERRIDE;
- void close() Q_DECL_OVERRIDE;
- QSqlResult *createResult() const Q_DECL_OVERRIDE;
- bool beginTransaction() Q_DECL_OVERRIDE;
- bool commitTransaction() Q_DECL_OVERRIDE;
- bool rollbackTransaction() Q_DECL_OVERRIDE;
- QStringList tables(QSql::TableType) const Q_DECL_OVERRIDE;
-
- QSqlRecord record(const QString& tablename) const Q_DECL_OVERRIDE;
- QSqlIndex primaryIndex(const QString &table) const Q_DECL_OVERRIDE;
- QVariant handle() const Q_DECL_OVERRIDE;
- QString escapeIdentifier(const QString &identifier, IdentifierType) const Q_DECL_OVERRIDE;
-};
-
-QT_END_NAMESPACE
-
-#endif // QSQL_SQLITE_H
diff --git a/src/sql/drivers/sqlite2/qsql_sqlite2.cpp b/src/sql/drivers/sqlite2/qsql_sqlite2.cpp
deleted file mode 100644
index 67c24e4168..0000000000
--- a/src/sql/drivers/sqlite2/qsql_sqlite2.cpp
+++ /dev/null
@@ -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 <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>
-
-#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 Q_DECL_OVERRIDE;
-
-protected:
- bool gotoNext(QSqlCachedResult::ValueCache &row, int idx) Q_DECL_OVERRIDE;
- bool reset(const QString &query) Q_DECL_OVERRIDE;
- int size() Q_DECL_OVERRIDE;
- int numRowsAffected() Q_DECL_OVERRIDE;
- QSqlRecord record() const Q_DECL_OVERRIDE;
- void detachFromResultSet() Q_DECL_OVERRIDE;
- void virtual_hook(int id, void *data) Q_DECL_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));
- 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));
- }
- 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
diff --git a/src/sql/drivers/sqlite2/qsql_sqlite2.pri b/src/sql/drivers/sqlite2/qsql_sqlite2.pri
deleted file mode 100644
index 5baba30db0..0000000000
--- a/src/sql/drivers/sqlite2/qsql_sqlite2.pri
+++ /dev/null
@@ -1,4 +0,0 @@
-HEADERS += $$PWD/qsql_sqlite2_p.h
-SOURCES += $$PWD/qsql_sqlite2.cpp
-
-!contains(LIBS, .*sqlite.*):LIBS += -lsqlite
diff --git a/src/sql/drivers/sqlite2/qsql_sqlite2_p.h b/src/sql/drivers/sqlite2/qsql_sqlite2_p.h
deleted file mode 100644
index 83b248ec6a..0000000000
--- a/src/sql/drivers/sqlite2/qsql_sqlite2_p.h
+++ /dev/null
@@ -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 = 0);
- explicit QSQLite2Driver(sqlite *connection, QObject *parent = 0);
- ~QSQLite2Driver();
- bool hasFeature(DriverFeature f) const Q_DECL_OVERRIDE;
- bool open(const QString &db,
- const QString &user,
- const QString &password,
- const QString &host,
- int port,
- const QString &connOpts) Q_DECL_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() Q_DECL_OVERRIDE;
- QSqlResult *createResult() const Q_DECL_OVERRIDE;
- bool beginTransaction() Q_DECL_OVERRIDE;
- bool commitTransaction() Q_DECL_OVERRIDE;
- bool rollbackTransaction() Q_DECL_OVERRIDE;
- QStringList tables(QSql::TableType) const Q_DECL_OVERRIDE;
-
- QSqlRecord record(const QString &tablename) const Q_DECL_OVERRIDE;
- QSqlIndex primaryIndex(const QString &table) const Q_DECL_OVERRIDE;
- QVariant handle() const Q_DECL_OVERRIDE;
- QString escapeIdentifier(const QString &identifier, IdentifierType) const Q_DECL_OVERRIDE;
-};
-
-QT_END_NAMESPACE
-
-#endif // QSQL_SQLITE2_H
diff --git a/src/sql/drivers/tds/qsql_tds.cpp b/src/sql/drivers/tds/qsql_tds.cpp
deleted file mode 100644
index 10d9fe7298..0000000000
--- a/src/sql/drivers/tds/qsql_tds.cpp
+++ /dev/null
@@ -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);
-}
-
-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;
-
-protected:
- void cleanup();
- bool reset(const QString &query) Q_DECL_OVERRIDE;
- int size() Q_DECL_OVERRIDE;
- int numRowsAffected() Q_DECL_OVERRIDE;
- bool gotoNext(QSqlCachedResult::ValueCache &values, int index) Q_DECL_OVERRIDE;
- QSqlRecord record() const Q_DECL_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;
- }
-
-
- QString errMsg = QString::fromLatin1("%1 %2\n").arg(QLatin1String(dberrstr)).arg(
- QLatin1String(oserrstr));
- errMsg += 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()));
- 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(QLatin1String("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());
- 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
diff --git a/src/sql/drivers/tds/qsql_tds.pri b/src/sql/drivers/tds/qsql_tds.pri
deleted file mode 100644
index 8c528c154d..0000000000
--- a/src/sql/drivers/tds/qsql_tds.pri
+++ /dev/null
@@ -1,10 +0,0 @@
-HEADERS += $$PWD/qsql_tds_p.h
-SOURCES += $$PWD/qsql_tds.cpp
-
-unix|mingw: {
- LIBS += $$QT_LFLAGS_TDS
- !contains(LIBS, .*sybdb.*):LIBS += -lsybdb
- QMAKE_CXXFLAGS *= $$QT_CFLAGS_TDS
-} else {
- LIBS *= -lNTWDBLIB
-}
diff --git a/src/sql/drivers/tds/qsql_tds_p.h b/src/sql/drivers/tds/qsql_tds_p.h
deleted file mode 100644
index d0914455a2..0000000000
--- a/src/sql/drivers/tds/qsql_tds_p.h
+++ /dev/null
@@ -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 = 0);
- QTDSDriver(LOGINREC* rec, const QString& host, const QString &db, QObject* parent = 0);
- ~QTDSDriver();
- bool hasFeature(DriverFeature f) const Q_DECL_OVERRIDE;
- bool open(const QString &db,
- const QString &user,
- const QString &password,
- const QString &host,
- int port,
- const QString &connOpts) Q_DECL_OVERRIDE;
- void close() Q_DECL_OVERRIDE;
- QStringList tables(QSql::TableType) const Q_DECL_OVERRIDE;
- QSqlResult *createResult() const Q_DECL_OVERRIDE;
- QSqlRecord record(const QString &tablename) const Q_DECL_OVERRIDE;
- QSqlIndex primaryIndex(const QString &tablename) const Q_DECL_OVERRIDE;
-
- QString formatValue(const QSqlField &field,
- bool trimStrings) const Q_DECL_OVERRIDE;
- QVariant handle() const Q_DECL_OVERRIDE;
-
- QString escapeIdentifier(const QString &identifier, IdentifierType type) const Q_DECL_OVERRIDE;
-
-protected:
- bool beginTransaction() Q_DECL_OVERRIDE;
- bool commitTransaction() Q_DECL_OVERRIDE;
- bool rollbackTransaction() Q_DECL_OVERRIDE;
-private:
- void init();
-};
-
-QT_END_NAMESPACE
-
-#endif // QSQL_TDS_H