📄 qsql_odbc.cpp
字号:
/******************************************************************************** Implementation of ODBC driver classes**** Created : 001103**** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.**** This file is part of the sql module of the Qt GUI Toolkit.**** This file may be distributed under the terms of the Q Public License** as defined by Trolltech AS of Norway and appearing in the file** LICENSE.QPL included in the packaging of this file.**** This file may be distributed and/or modified under the terms of the** GNU General Public License version 2 as published by the Free Software** Foundation and appearing in the file LICENSE.GPL included in the** packaging of this file.**** Licensees holding valid Qt Enterprise Edition licenses may use this** file in accordance with the Qt Commercial License Agreement provided** with the Software.**** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.**** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for** information about Qt Commercial License Agreements.** See http://www.trolltech.com/qpl/ for QPL licensing information.** See http://www.trolltech.com/gpl/ for GPL licensing information.**** Contact info@trolltech.com if any conditions of this licensing are** not clear to you.************************************************************************/#include "qsql_odbc.h"#include <qsqlrecord.h>#if defined (Q_OS_WIN32)#include <qt_windows.h>#include <qapplication.h>#endif#include <qdatetime.h>// undefine this to prevent initial check of the ODBC driver #define ODBC_CHECK_DRIVERclass QODBCPrivate{public: QODBCPrivate() : hEnv(0), hDbc(0), hStmt(0) {} SQLHANDLE hEnv; SQLHANDLE hDbc; SQLHANDLE hStmt; bool checkDriver() const;};QString qWarnODBCHandle(int handleType, SQLHANDLE handle){ SQLINTEGER nativeCode_; SQLSMALLINT tmp; SQLRETURN r = SQL_ERROR; SQLCHAR state_[SQL_SQLSTATE_SIZE+1]; SQLCHAR description_[SQL_MAX_MESSAGE_LENGTH]; r = SQLGetDiagRec( handleType, handle, 1, (SQLCHAR*)state_, &nativeCode_, (SQLCHAR*)description_, SQL_MAX_MESSAGE_LENGTH-1, &tmp); if ( r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO ) return QString( (const char*)description_ ); return QString::null;}QString qODBCWarn( const QODBCPrivate* odbc){ return ( qWarnODBCHandle( SQL_HANDLE_ENV, odbc->hEnv ) + " " \ + qWarnODBCHandle( SQL_HANDLE_DBC, odbc->hDbc ) + " " \ + qWarnODBCHandle( SQL_HANDLE_STMT, odbc->hStmt ) );}void qSqlWarning( const QString& message, const QODBCPrivate* odbc ){#ifdef QT_CHECK_RANGE qWarning( message + "\tError:" + qODBCWarn( odbc ) );#endif}QSqlError qMakeError( const QString& err, int type, const QODBCPrivate* p ){ return QSqlError( "QODBC3: " + err, qODBCWarn(p), type );}QVariant::Type qDecodeODBCType( SQLSMALLINT sqltype ){ 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: case SQL_BIGINT: type = QVariant::Int; break;// case SQL_BINARY:// case SQL_VARBINARY:// case SQL_LONGVARBINARY:// type = QSqlFieldInfo::Binary;// 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; default: case SQL_CHAR: case SQL_VARCHAR: case SQL_LONGVARCHAR: type = QVariant::String; break; } return type;}QSqlFieldInfo qMakeFieldInfo( const QODBCPrivate* p, int i ){ SQLSMALLINT colNameLen; SQLSMALLINT colType; SQLUINTEGER colSize; SQLSMALLINT colScale; SQLSMALLINT nullable; SQLRETURN r = SQL_ERROR; QString qColName; SQLCHAR colName[255]; r = SQLDescribeCol( p->hStmt, i+1, colName, sizeof(colName), &colNameLen, &colType, &colSize, &colScale, &nullable); if ( r != SQL_SUCCESS ) {#ifdef QT_CHECK_RANGE qSqlWarning( QString("qMakeField: Unable to describe column %1").arg(i), p );#endif return QSqlFieldInfo(); } qColName = qstrdup((const char*)colName); // nullable can be SQL_NO_NULLS, SQL_NULLABLE or SQL_NULLABLE_UNKNOWN int required = -1; if ( nullable == SQL_NO_NULLS ) { required = 1; } else if ( nullable == SQL_NULLABLE ) { required = 0; } QVariant::Type type = qDecodeODBCType( colType ); return QSqlFieldInfo( qColName, type, required, (int)colSize == 0 ? -1 : (int)colSize, (int)colScale == 0 ? -1 : (int)colScale, QVariant(), (int)colType );}QString qGetStringData( SQLHANDLE hStmt, int column, SQLINTEGER& lengthIndicator, bool& isNull ){ QString fieldVal; SQLSMALLINT colNameLen; SQLSMALLINT colType; SQLUINTEGER colSize; SQLSMALLINT colScale; SQLSMALLINT nullable; SQLRETURN r = SQL_ERROR; QString qColName; SQLCHAR colName[255]; r = SQLDescribeCol( hStmt, column+1, colName, sizeof(colName), &colNameLen, &colType, &colSize, &colScale, &nullable); qColName = qstrdup( (const char*)colName );#ifdef QT_CHECK_RANGE if ( r != SQL_SUCCESS ) qWarning( QString("qGetStringData: Unable to describe column %1").arg(column) );#endif // SQLDescribeCol may return 0 if size cannot be determined if (!colSize) { colSize = 255; } SQLCHAR* buf = new SQLTCHAR[ colSize + 1 ]; while ( TRUE ) { r = SQLGetData( hStmt, column+1, SQL_C_CHAR, (SQLPOINTER)buf, colSize + 1, &lengthIndicator ); if ( r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO ) { if ( lengthIndicator == SQL_NO_TOTAL ){ fieldVal += QString( (char*)buf ); // keep going } else if ( lengthIndicator == SQL_NULL_DATA ) { fieldVal = QString::null; isNull = TRUE; break; } else { if ( r == SQL_SUCCESS ) { fieldVal += QString( (char*)buf ); break; } else { if( (int)fieldVal.length() >= lengthIndicator ) // ### HACK - remove asap break; fieldVal += QString( (char*)buf ); } } } else { fieldVal += QString::null; break; } } delete buf; return fieldVal;}int qGetIntData( SQLHANDLE hStmt, int column, bool& isNull ){ SQLINTEGER intbuf; isNull = FALSE; SQLINTEGER lengthIndicator = 0; SQLRETURN r = SQLGetData( hStmt, column+1, SQL_C_SLONG, (SQLPOINTER)&intbuf, 0, &lengthIndicator ); if ( r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO ) { if ( lengthIndicator == SQL_NULL_DATA ) isNull = TRUE; } return (int)intbuf;}QSqlFieldInfo qMakeFieldInfo( const QODBCPrivate* d, const QString& tablename, const QString& fieldname ){ QSqlFieldInfo fi; SQLHANDLE hStmt; SQLRETURN r = SQLAllocHandle( SQL_HANDLE_STMT, d->hDbc, &hStmt ); if ( r != SQL_SUCCESS ) {#ifdef QT_CHECK_RANGE qSqlWarning( "qMakeField: Unable to alloc handle", d );#endif return fi; } r = SQLSetStmtAttr( hStmt, SQL_ATTR_CURSOR_TYPE, (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY, SQL_IS_UINTEGER ); r = SQLColumns( hStmt, NULL, 0, NULL, 0, (SQLCHAR*)tablename.local8Bit().data(), tablename.length(), (SQLCHAR*)fieldname.local8Bit().data(), fieldname.length() ); if ( r != SQL_SUCCESS ) {#ifdef QT_CHECK_RANGE qSqlWarning( "qMakeField: Unable to execute column list", d );#endif return fi; } r = SQLFetchScroll( hStmt, SQL_FETCH_NEXT, 0); if ( r == SQL_SUCCESS ) { bool isNull; int type = qGetIntData( hStmt, 4, isNull ); // column type int required = qGetIntData( hStmt, 10, isNull ); // nullable-flag // required can be SQL_NO_NULLS, SQL_NULLABLE or SQL_NULLABLE_UNKNOWN if ( required == SQL_NO_NULLS ) { required = 1; } else if ( required == SQL_NULLABLE ) { required = 0; } else { required = -1; } int size = qGetIntData( hStmt, 6, isNull ); // column size int prec = qGetIntData( hStmt, 8, isNull ); // precision fi = QSqlFieldInfo( fieldname, qDecodeODBCType( type ), required, size, prec, QVariant(), type ); } r = SQLFreeHandle( SQL_HANDLE_STMT, hStmt );#ifdef QT_CHECK_RANGE if ( r != SQL_SUCCESS ) qSqlWarning( "QODBCDriver: Unable to free statement handle " + QString::number(r), d );#endif return fi;}QSqlField qMakeField( const QODBCPrivate* d, const QString& tablename, const QString& fieldname ){ QSqlFieldInfo info = qMakeFieldInfo( d, tablename, fieldname ); return QSqlField( info.name(), info.type() );}QSqlField qMakeField( const QODBCPrivate* p, int i ){ QSqlFieldInfo info = qMakeFieldInfo( p, i ); return QSqlField( info.name(), info.type() );}////////////////////////////////////////////////////////////////////////////QODBCResult::QODBCResult( const QODBCDriver * db, QODBCPrivate* p ): QSqlResult(db){ d = new QODBCPrivate(); (*d) = (*p);}QODBCResult::~QODBCResult(){ if ( d->hStmt && driver()->isOpen() ) { SQLRETURN r = SQLFreeHandle( SQL_HANDLE_STMT, d->hStmt );#ifdef QT_CHECK_RANGE if ( r!= SQL_SUCCESS ) qSqlWarning( "QODBCDriver: Unable to free statement handle" + QString::number(r), d );#endif } delete d;}bool QODBCResult::reset ( const QString& query ){ setActive( FALSE ); setAt( QSql::BeforeFirst ); SQLRETURN r; // If a statement handle exists - reuse it if ( d->hStmt ) { r = SQLFreeStmt( d->hStmt, SQL_CLOSE ); if ( r != SQL_SUCCESS ) {#ifdef QT_CHECK_RANGE qSqlWarning( "QODBCResult::reset: Unable to close statement", d );#endif return FALSE; } } else { r = SQLAllocHandle( SQL_HANDLE_STMT, d->hDbc, &d->hStmt ); if ( r != SQL_SUCCESS ) {#ifdef QT_CHECK_RANGE qSqlWarning( "QODBCResult::reset: Unable to allocate statement handle", d );#endif return FALSE; } r = SQLSetStmtAttr( d->hStmt, SQL_ATTR_CURSOR_TYPE, (SQLPOINTER)SQL_CURSOR_STATIC, SQL_IS_UINTEGER ); if ( r != SQL_SUCCESS ) {#ifdef QT_CHECK_RANGE qSqlWarning( "QODBCResult::reset: Unable to set statement attribute", d );#endif return FALSE; } } r = SQLExecDirect( d->hStmt, (SQLCHAR*)query.local8Bit().data(), SQL_NTS ); if ( r != SQL_SUCCESS ) { setLastError( qMakeError( "Unable to execute statement", QSqlError::Statement, d ) ); return FALSE; } SQLSMALLINT count; r = SQLNumResultCols( d->hStmt, &count );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -