summaryrefslogtreecommitdiffstats
path: root/src/sql/drivers/odbc
diff options
context:
space:
mode:
Diffstat (limited to 'src/sql/drivers/odbc')
-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
3 files changed, 0 insertions, 2778 deletions
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