?? qsql_odbc.cpp
字號:
/******************************************************************************** Copyright (C) 1992-2006 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://www.trolltech.com/products/qt/opensource.html**** If you are unsure which license is appropriate for your use, please** review the following information:** http://www.trolltech.com/products/qt/licensing.html or contact the** sales department at sales@trolltech.com.**** 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) { 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; bool checkDriver() const; void checkUnicode(); 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;};static QString qWarnODBCHandle(int handleType, SQLHANDLE handle, int *nativeCode = 0){ SQLINTEGER nativeCode_ = 0; SQLSMALLINT msgLen = 0; SQLRETURN r = SQL_ERROR; SQLTCHAR state_[SQL_SQLSTATE_SIZE+1]; SQLTCHAR description_[SQL_MAX_MESSAGE_LENGTH + 1]; description_[0] = 0; r = SQLGetDiagRec(handleType, handle, 1, (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_;#ifdef UNICODE return QString((const QChar*)description_, msgLen);#else return QString::fromLocal8Bit((const char*)description_);#endif } return QString();}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){ 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 = QVariant::Int; break; case SQL_BIGINT: type = QVariant::LongLong; 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); ulong read = 0; while (true) { r = SQLGetData(hStmt, column+1, SQL_C_BINARY, (SQLPOINTER)(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 > QSQLLEN(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){ SQLINTEGER intbuf = 0; QSQLLEN lengthIndicator = 0; SQLRETURN r = SQLGetData(hStmt, column+1, SQL_C_SLONG, (SQLPOINTER)&intbuf, 0, &lengthIndicator); if ((r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) || lengthIndicator == SQL_NULL_DATA) { return QVariant(QVariant::Int); } return QVariant(int(intbuf));}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -