diff options
Diffstat (limited to 'src/sql/drivers/odbc')
-rw-r--r-- | src/sql/drivers/odbc/qsql_odbc.cpp | 203 | ||||
-rw-r--r-- | src/sql/drivers/odbc/qsql_odbc_p.h | 14 |
2 files changed, 88 insertions, 129 deletions
diff --git a/src/sql/drivers/odbc/qsql_odbc.cpp b/src/sql/drivers/odbc/qsql_odbc.cpp index 2b14809943..e12764636a 100644 --- a/src/sql/drivers/odbc/qsql_odbc.cpp +++ b/src/sql/drivers/odbc/qsql_odbc.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ ** ** This file is part of the QtSql module of the Qt Toolkit. ** @@ -10,9 +10,9 @@ ** 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 Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser @@ -23,8 +23,8 @@ ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** $QT_END_LICENSE$ @@ -222,12 +222,7 @@ static QString qWarnODBCHandle(int handleType, SQLHANDLE handle, int *nativeCode if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) { if (nativeCode) *nativeCode = nativeCode_; - QString tmpstore; -#ifdef UNICODE - tmpstore = fromSQLTCHAR(description_, msgLen); -#else - tmpstore = QString::fromUtf8((const char*)description_.constData(), msgLen); -#endif + const QString tmpstore = fromSQLTCHAR(description_, msgLen); if(result != tmpstore) { if(!result.isEmpty()) result += QLatin1Char(' '); @@ -241,17 +236,39 @@ static QString qWarnODBCHandle(int handleType, SQLHANDLE handle, int *nativeCode 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 QODBCPrivate* odbc, int *nativeCode = 0) { - return QString(qWarnODBCHandle(SQL_HANDLE_ENV, odbc->dpEnv()) + QLatin1Char(' ') - + qWarnODBCHandle(SQL_HANDLE_DBC, odbc->dpDbc()) + QLatin1Char(' ') - + qWarnODBCHandle(SQL_HANDLE_STMT, odbc->hStmt, nativeCode)).simplified(); + return qODBCWarn(odbc->hStmt, odbc->dpEnv(), odbc->dpDbc(), nativeCode); } static QString qODBCWarn(const QODBCDriverPrivate* odbc, int *nativeCode = 0) { - return QString(qWarnODBCHandle(SQL_HANDLE_ENV, odbc->hEnv) + QLatin1Char(' ') - + qWarnODBCHandle(SQL_HANDLE_DBC, odbc->hDbc, nativeCode)).simplified(); + return qODBCWarn(0, odbc->hEnv, odbc->hDbc, nativeCode); } static void qSqlWarning(const QString& message, const QODBCPrivate* odbc) @@ -264,6 +281,11 @@ 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 QODBCPrivate* p) { int nativeCode = -1; @@ -279,10 +301,8 @@ static QSqlError qMakeError(const QString& err, QSqlError::ErrorType type, return QSqlError(QLatin1String("QODBC3: ") + err, qODBCWarn(p), type, nativeCode); } -template<class T> -static QVariant::Type qDecodeODBCType(SQLSMALLINT sqltype, const T* p, bool isSigned = true) +static QVariant::Type qDecodeODBCType(SQLSMALLINT sqltype, bool isSigned = true) { - Q_UNUSED(p); QVariant::Type type = QVariant::Invalid; switch (sqltype) { case SQL_DECIMAL: @@ -362,7 +382,7 @@ static QString qGetStringData(SQLHANDLE hStmt, int column, int colSize, bool uni 0, &lengthIndicator); if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && lengthIndicator > 0) - colSize = lengthIndicator/sizeof(SQLTCHAR) + 1; + colSize = int(lengthIndicator / sizeof(SQLTCHAR) + 1); QVarLengthArray<SQLTCHAR> buf(colSize); memset(buf.data(), 0, colSize*sizeof(SQLTCHAR)); while (true) { @@ -392,7 +412,7 @@ static QString qGetStringData(SQLHANDLE hStmt, int column, int colSize, bool uni // 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/sizeof(SQLTCHAR); + 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 @@ -569,6 +589,21 @@ static QVariant qGetBigIntData(SQLHANDLE hStmt, int column, bool isSigned = true 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) @@ -593,6 +628,15 @@ static QSqlField qMakeFieldInfo(const SQLHANDLE hStmt, const QODBCDriverPrivate* static QSqlField qMakeFieldInfo(const QODBCPrivate* 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; @@ -600,7 +644,8 @@ static QSqlField qMakeFieldInfo(const QODBCPrivate* p, int i ) SQLSMALLINT nullable; SQLRETURN r = SQL_ERROR; QVarLengthArray<SQLTCHAR> colName(COLNAMESIZE); - r = SQLDescribeCol(p->hStmt, + errorMessage->clear(); + r = SQLDescribeCol(hStmt, i+1, colName.data(), (SQLSMALLINT)COLNAMESIZE, @@ -611,12 +656,12 @@ static QSqlField qMakeFieldInfo(const QODBCPrivate* p, int i ) &nullable); if (r != SQL_SUCCESS) { - qSqlWarning(QString::fromLatin1("qMakeField: Unable to describe column %1").arg(i), p); + *errorMessage = QStringLiteral("qMakeField: Unable to describe column ") + QString::number(i); return QSqlField(); } SQLLEN unsignedFlag = SQL_FALSE; - r = SQLColAttribute (p->hStmt, + r = SQLColAttribute (hStmt, i + 1, SQL_DESC_UNSIGNED, 0, @@ -624,16 +669,13 @@ static QSqlField qMakeFieldInfo(const QODBCPrivate* p, int i ) 0, &unsignedFlag); if (r != SQL_SUCCESS) { - qSqlWarning(QString::fromLatin1("qMakeField: Unable to get column attributes for column %1").arg(i), p); + qSqlWarning(QStringLiteral("qMakeField: Unable to get column attributes for column ") + + QString::number(i), hStmt); } -#ifdef UNICODE - QString qColName(fromSQLTCHAR(colName, colNameLen)); -#else - QString qColName = QString::fromUtf8((const char *)colName.constData()); -#endif + const QString qColName(fromSQLTCHAR(colName, colNameLen)); // nullable can be SQL_NO_NULLS, SQL_NULLABLE or SQL_NULLABLE_UNKNOWN - QVariant::Type type = qDecodeODBCType(colType, p, unsignedFlag == SQL_FALSE); + QVariant::Type type = qDecodeODBCType(colType, unsignedFlag == SQL_FALSE); QSqlField f(qColName, type); f.setSqlType(colType); f.setLength(colSize == 0 ? -1 : int(colSize)); @@ -643,6 +685,7 @@ static QSqlField qMakeFieldInfo(const QODBCPrivate* p, int i ) else if (nullable == SQL_NULLABLE) f.setRequired(false); // else we don't know + f.setAutoValue(isAutoValue(hStmt, i)); return f; } @@ -664,11 +707,7 @@ QChar QODBCDriverPrivate::quoteChar() sizeof(driverResponse), &length); if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) -#ifdef UNICODE quote = QChar(driverResponse[0]); -#else - quote = QLatin1Char(driverResponse[0]); -#endif else quote = QLatin1Char('"'); isQuoteInitialized = true; @@ -713,11 +752,7 @@ bool QODBCDriverPrivate::setConnectionOptions(const QString& connOpts) } else if (opt.toUpper() == QLatin1String("SQL_ATTR_CURRENT_CATALOG")) { val.utf16(); // 0 terminate r = SQLSetConnectAttr(hDbc, SQL_ATTR_CURRENT_CATALOG, -#ifdef UNICODE toSQLTCHAR(val).data(), -#else - (SQLCHAR*) val.toUtf8().data(), -#endif val.length()*sizeof(SQLTCHAR)); } else if (opt.toUpper() == QLatin1String("SQL_ATTR_METADATA_ID")) { if (val.toUpper() == QLatin1String("SQL_TRUE")) { @@ -735,11 +770,7 @@ bool QODBCDriverPrivate::setConnectionOptions(const QString& connOpts) } else if (opt.toUpper() == QLatin1String("SQL_ATTR_TRACEFILE")) { val.utf16(); // 0 terminate r = SQLSetConnectAttr(hDbc, SQL_ATTR_TRACEFILE, -#ifdef UNICODE toSQLTCHAR(val).data(), -#else - (SQLCHAR*) val.toUtf8().data(), -#endif val.length()*sizeof(SQLTCHAR)); } else if (opt.toUpper() == QLatin1String("SQL_ATTR_TRACE")) { if (val.toUpper() == QLatin1String("SQL_OPT_TRACE_OFF")) { @@ -944,16 +975,9 @@ bool QODBCResult::reset (const QString& query) return false; } -#ifdef UNICODE r = SQLExecDirect(d->hStmt, toSQLTCHAR(query).data(), (SQLINTEGER) query.length()); -#else - QByteArray query8 = query.toUtf8(); - r = SQLExecDirect(d->hStmt, - (SQLCHAR*) query8.data(), - (SQLINTEGER) query8.length()); -#endif 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)); @@ -1290,16 +1314,9 @@ bool QODBCResult::prepare(const QString& query) return false; } -#ifdef UNICODE r = SQLPrepare(d->hStmt, toSQLTCHAR(query).data(), (SQLINTEGER) query.length()); -#else - QByteArray query8 = query.toUtf8(); - r = SQLPrepare(d->hStmt, - (SQLCHAR*) query8.data(), - (SQLINTEGER) query8.length()); -#endif if (r != SQL_SUCCESS) { setLastError(qMakeError(QCoreApplication::translate("QODBCResult", @@ -1889,11 +1906,7 @@ bool QODBCDriver::open(const QString & db, memset(connOut.data(), 0, connOut.size() * sizeof(SQLTCHAR)); r = SQLDriverConnect(d->hDbc, NULL, -#ifdef UNICODE toSQLTCHAR(connQStr).data(), -#else - (SQLCHAR*)connQStr.toUtf8().data(), -#endif (SQLSMALLINT)connQStr.length(), connOut.data(), 1024, @@ -2097,15 +2110,10 @@ void QODBCDriverPrivate::checkDBMS() r = SQLGetInfo(hDbc, SQL_DBMS_NAME, serverString.data(), - serverString.size() * sizeof(SQLTCHAR), + SQLSMALLINT(serverString.size() * sizeof(SQLTCHAR)), &t); if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) { - QString serverType; -#ifdef UNICODE - serverType = fromSQLTCHAR(serverString, t/sizeof(SQLTCHAR)); -#else - serverType = QString::fromUtf8((const char *)serverString.constData(), t); -#endif + 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)) @@ -2120,15 +2128,10 @@ void QODBCDriverPrivate::checkDBMS() r = SQLGetInfo(hDbc, SQL_DRIVER_NAME, serverString.data(), - serverString.size() * sizeof(SQLTCHAR), + SQLSMALLINT(serverString.size() * sizeof(SQLTCHAR)), &t); if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) { - QString serverType; -#ifdef UNICODE - serverType = fromSQLTCHAR(serverString, t/sizeof(SQLTCHAR)); -#else - serverType = QString::fromUtf8((const char *)serverString.constData(), t); -#endif + const QString serverType = fromSQLTCHAR(serverString, t / sizeof(SQLTCHAR)); isFreeTDSDriver = serverType.contains(QLatin1String("tdsodbc"), Qt::CaseInsensitive); unicode = unicode && !isFreeTDSDriver; } @@ -2151,14 +2154,10 @@ void QODBCDriverPrivate::checkHasMultiResults() SQLRETURN r = SQLGetInfo(hDbc, SQL_MULT_RESULT_SETS, driverResponse.data(), - driverResponse.size() * sizeof(SQLTCHAR), + SQLSMALLINT(driverResponse.size() * sizeof(SQLTCHAR)), &length); if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) -#ifdef UNICODE hasMultiResultSets = fromSQLTCHAR(driverResponse, length/sizeof(SQLTCHAR)).startsWith(QLatin1Char('Y')); -#else - hasMultiResultSets = QString::fromUtf8((const char *)driverResponse.constData(), length).startsWith(QLatin1Char('Y')); -#endif } void QODBCDriverPrivate::checkDateTimePrecision() @@ -2299,11 +2298,7 @@ QStringList QODBCDriver::tables(QSql::TableType type) const 0, NULL, 0, -#ifdef UNICODE toSQLTCHAR(joinedTableTypeString).data(), -#else - (SQLCHAR*)joinedTableTypeString.toUtf8().data(), -#endif joinedTableTypeString.length() /* characters, not bytes */); if (r != SQL_SUCCESS) @@ -2379,23 +2374,11 @@ QSqlIndex QODBCDriver::primaryIndex(const QString& tablename) const (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY, SQL_IS_UINTEGER); r = SQLPrimaryKeys(hStmt, -#ifdef UNICODE catalog.length() == 0 ? NULL : toSQLTCHAR(catalog).data(), -#else - catalog.length() == 0 ? NULL : (SQLCHAR*)catalog.toUtf8().data(), -#endif catalog.length(), -#ifdef UNICODE schema.length() == 0 ? NULL : toSQLTCHAR(schema).data(), -#else - schema.length() == 0 ? NULL : (SQLCHAR*)schema.toUtf8().data(), -#endif schema.length(), -#ifdef UNICODE toSQLTCHAR(table).data(), -#else - (SQLCHAR*)table.toUtf8().data(), -#endif table.length() /* in characters, not in bytes */); // if the SQLPrimaryKeys() call does not succeed (e.g the driver @@ -2404,23 +2387,11 @@ QSqlIndex QODBCDriver::primaryIndex(const QString& tablename) const if (r != SQL_SUCCESS) { r = SQLSpecialColumns(hStmt, SQL_BEST_ROWID, -#ifdef UNICODE catalog.length() == 0 ? NULL : toSQLTCHAR(catalog).data(), -#else - catalog.length() == 0 ? NULL : (SQLCHAR*)catalog.toUtf8().data(), -#endif catalog.length(), -#ifdef UNICODE schema.length() == 0 ? NULL : toSQLTCHAR(schema).data(), -#else - schema.length() == 0 ? NULL : (SQLCHAR*)schema.toUtf8().data(), -#endif schema.length(), -#ifdef UNICODE toSQLTCHAR(table).data(), -#else - (SQLCHAR*)table.toUtf8().data(), -#endif table.length(), SQL_SCOPE_CURROW, SQL_NULLABLE); @@ -2505,23 +2476,11 @@ QSqlRecord QODBCDriver::record(const QString& tablename) const (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY, SQL_IS_UINTEGER); r = SQLColumns(hStmt, -#ifdef UNICODE catalog.length() == 0 ? NULL : toSQLTCHAR(catalog).data(), -#else - catalog.length() == 0 ? NULL : (SQLCHAR*)catalog.toUtf8().data(), -#endif catalog.length(), -#ifdef UNICODE schema.length() == 0 ? NULL : toSQLTCHAR(schema).data(), -#else - schema.length() == 0 ? NULL : (SQLCHAR*)schema.toUtf8().data(), -#endif schema.length(), -#ifdef UNICODE toSQLTCHAR(table).data(), -#else - (SQLCHAR*)table.toUtf8().data(), -#endif table.length(), NULL, 0); diff --git a/src/sql/drivers/odbc/qsql_odbc_p.h b/src/sql/drivers/odbc/qsql_odbc_p.h index 56aebcb92e..96e7abd7dd 100644 --- a/src/sql/drivers/odbc/qsql_odbc_p.h +++ b/src/sql/drivers/odbc/qsql_odbc_p.h @@ -1,7 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ ** ** This file is part of the QtSql module of the Qt Toolkit. ** @@ -10,9 +10,9 @@ ** 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 Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser @@ -23,8 +23,8 @@ ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** $QT_END_LICENSE$ |