📄 qsql_odbc.cpp
字号:
/******************************************************************************** Copyright (C) 1992-2007 Trolltech ASA. All rights reserved.**** This file is part of the QtSql module of the Qt Toolkit.**** This file may be used under the terms of the GNU General Public** License version 2.0 as published by the Free Software Foundation** and appearing in the file LICENSE.GPL included in the packaging of** this file. Please review the following information to ensure GNU** General Public Licensing requirements will be met:** http://trolltech.com/products/qt/licenses/licensing/opensource/**** If you are unsure which license is appropriate for your use, please** review the following information:** http://trolltech.com/products/qt/licenses/licensing/licensingoverview** or contact the sales department at sales@trolltech.com.**** In addition, as a special exception, Trolltech gives you certain** additional rights. These rights are described in the Trolltech GPL** Exception version 1.0, which can be found at** http://www.trolltech.com/products/qt/gplexception/ and in the file** GPL_EXCEPTION.txt in this package.**** In addition, as a special exception, Trolltech, as the sole copyright** holder for Qt Designer, grants users of the Qt/Eclipse Integration** plug-in the right for the Qt/Eclipse Integration to link to** functionality provided by Qt Designer and its related libraries.**** Trolltech reserves all rights not expressly granted herein.**** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.******************************************************************************/#include "qsql_odbc.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 <string.h>// undefine this to prevent initial check of the ODBC driver#define ODBC_CHECK_DRIVER#if defined(Q_ODBC_VERSION_2)//crude hack to get non-unicode capable driver managers to work# undef UNICODE# define SQLTCHAR SQLCHAR# define SQL_C_WCHAR SQL_C_CHAR#endif// newer platform SDKs use SQLLEN instead of SQLINTEGER#if defined(SQLLEN) || defined(Q_OS_WIN64)# define QSQLLEN SQLLEN#else# define QSQLLEN SQLINTEGER#endif#if defined(SQLULEN) || defined(Q_OS_WIN64)# define QSQLULEN SQLULEN#else# define QSQLULEN SQLUINTEGER#endifstatic const int COLNAMESIZE = 256;//Map Qt parameter types to ODBC typesstatic const SQLSMALLINT qParamType[4] = { SQL_PARAM_INPUT, SQL_PARAM_INPUT, SQL_PARAM_OUTPUT, SQL_PARAM_INPUT_OUTPUT };class QODBCDriverPrivate{public: QODBCDriverPrivate() : hEnv(0), hDbc(0), useSchema(false), disconnectCount(0), isMySqlServer(false) { sql_char_type = sql_varchar_type = sql_longvarchar_type = QVariant::ByteArray; unicode = false; } SQLHANDLE hEnv; SQLHANDLE hDbc; uint unicode :1; uint useSchema :1; QVariant::Type sql_char_type; QVariant::Type sql_varchar_type; QVariant::Type sql_longvarchar_type; int disconnectCount; bool isMySqlServer; bool checkDriver() const; void checkUnicode(); void checkMySqlServer(); void checkSchemaUsage(); bool setConnectionOptions(const QString& connOpts); void splitTableQualifier(const QString &qualifier, QString &catalog, QString &schema, QString &table);};class QODBCPrivate{public: QODBCPrivate() : hEnv(0), hDbc(0), hStmt(0), useSchema(false) { sql_char_type = sql_varchar_type = sql_longvarchar_type = QVariant::ByteArray; unicode = false; } inline void clearValues() { fieldCache.fill(QVariant()); fieldCacheIdx = 0; } SQLHANDLE hEnv; SQLHANDLE hDbc; SQLHANDLE hStmt; uint unicode :1; uint useSchema :1; QVariant::Type sql_char_type; QVariant::Type sql_varchar_type; QVariant::Type sql_longvarchar_type; QSqlRecord rInf; QVector<QVariant> fieldCache; int fieldCacheIdx; int disconnectCount; bool isStmtHandleValid(const QSqlDriver *driver); void updateStmtHandleState(const QSqlDriver *driver);};bool QODBCPrivate::isStmtHandleValid(const QSqlDriver *driver){ const QODBCDriver *odbcdriver = static_cast<const QODBCDriver*> (driver); return disconnectCount == odbcdriver->d->disconnectCount;}void QODBCPrivate::updateStmtHandleState(const QSqlDriver *driver){ const QODBCDriver *odbcdriver = static_cast<const QODBCDriver*> (driver); disconnectCount = odbcdriver->d->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]; SQLTCHAR description_[SQL_MAX_MESSAGE_LENGTH + 1]; QString result; int i = 1; description_[0] = 0; do { r = SQLGetDiagRec(handleType, handle, i, (SQLTCHAR*)state_, &nativeCode_, (SQLTCHAR*)description_, SQL_MAX_MESSAGE_LENGTH, /* in bytes, not in characters */ &msgLen); description_[SQL_MAX_MESSAGE_LENGTH] = 0; if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) { if (nativeCode) *nativeCode = nativeCode_; if (i != 1) result += QLatin1Char(' ');#ifdef UNICODE result += QString((const QChar*)description_, msgLen);#else result += QString::fromLocal8Bit((const char*)description_);#endif } else if (r == SQL_ERROR || r == SQL_INVALID_HANDLE) { return result; } ++i; } while (r != SQL_NO_DATA); return result;}static QString qODBCWarn(const QODBCPrivate* odbc, int *nativeCode = 0){ return (qWarnODBCHandle(SQL_HANDLE_ENV, odbc->hEnv) + QLatin1String(" ") + qWarnODBCHandle(SQL_HANDLE_DBC, odbc->hDbc) + QLatin1String(" ") + qWarnODBCHandle(SQL_HANDLE_STMT, odbc->hStmt, nativeCode));}static QString qODBCWarn(const QODBCDriverPrivate* odbc, int *nativeCode = 0){ return (qWarnODBCHandle(SQL_HANDLE_ENV, odbc->hEnv) + QLatin1String(" ") + qWarnODBCHandle(SQL_HANDLE_DBC, odbc->hDbc, nativeCode));}static void qSqlWarning(const QString& message, const QODBCPrivate* odbc){ qWarning("%s\tError: %s", message.toLocal8Bit().constData(), qODBCWarn(odbc).toLocal8Bit().constData());}static void qSqlWarning(const QString &message, const QODBCDriverPrivate *odbc){ qWarning("%s\tError: %s", message.toLocal8Bit().constData(), qODBCWarn(odbc).toLocal8Bit().constData());}static QSqlError qMakeError(const QString& err, QSqlError::ErrorType type, const QODBCPrivate* 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);}template<class T>static QVariant::Type qDecodeODBCType(SQLSMALLINT sqltype, const T* p, 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: case SQL_TINYINT: type = isSigned ? QVariant::Int : 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;#ifndef Q_ODBC_VERSION_2 case SQL_WCHAR: case SQL_WVARCHAR: case SQL_WLONGVARCHAR: type = QVariant::String; break;#endif case SQL_CHAR: type = p->sql_char_type; break; case SQL_VARCHAR: type = p->sql_varchar_type; break; case SQL_LONGVARCHAR: type = p->sql_longvarchar_type; 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; QSQLLEN 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) { colSize *= 2; // a tiny bit faster, since it saves a SQLGetData() call } } char* buf = new char[colSize]; while (true) { r = SQLGetData(hStmt, column+1, unicode ? SQL_C_WCHAR : SQL_C_CHAR, (SQLPOINTER)buf, colSize, &lengthIndicator); if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) { if (lengthIndicator == SQL_NULL_DATA || lengthIndicator == SQL_NO_TOTAL) { fieldVal = QString(); 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) ? (unicode ? colSize-2 : colSize-1) : lengthIndicator; if (unicode) { fieldVal += QString((QChar*) buf, rSize / 2); } else { buf[rSize] = 0; fieldVal += QString::fromAscii(buf); } if (lengthIndicator < 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 (%d)", r); fieldVal = QString(); break; } } delete[] buf; return fieldVal;}static QVariant qGetBinaryData(SQLHANDLE hStmt, int column){ QByteArray fieldVal; SQLSMALLINT colNameLen; SQLSMALLINT colType; QSQLULEN colSize; SQLSMALLINT colScale; SQLSMALLINT nullable; QSQLLEN lengthIndicator = 0; SQLRETURN r = SQL_ERROR; SQLTCHAR colName[COLNAMESIZE]; r = SQLDescribeCol(hStmt, column + 1, colName, COLNAMESIZE, &colNameLen, &colType, &colSize, &colScale, &nullable); if (r != SQL_SUCCESS) qWarning("qGetBinaryData: Unable to describe column %d", column); // SQLDescribeCol may return 0 if size cannot be determined if (!colSize) colSize = 255; else if (colSize > 65536) // read the field in 64 KB chunks colSize = 65536; fieldVal.resize(colSize);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -