⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 qsql_odbc.cpp

📁 Linux下的基于X11的图形开发环境。
💻 CPP
📖 第 1 页 / 共 3 页
字号:
/******************************************************************************** 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>#include <private/qsqlextension_p.h>#include <private/qinternal_p.h>#include <stdlib.h>// undefine this to prevent initial check of the ODBC driver #define ODBC_CHECK_DRIVERstatic const int COLNAMESIZE = 255;class QODBCPrivate{public:    QODBCPrivate()    : hEnv(0), hDbc(0), hStmt(0)    {	sql_char_type = sql_varchar_type = sql_longvarchar_type = QVariant::CString;	unicode = FALSE;    }    SQLHANDLE hEnv;    SQLHANDLE hDbc;    SQLHANDLE hStmt;    bool unicode;    QVariant::Type sql_char_type;    QVariant::Type sql_varchar_type;    QVariant::Type sql_longvarchar_type;    QSqlRecordInfo rInf;    bool checkDriver() const;    void checkUnicode();};class QODBCPreparedExtension : public QSqlExtension{public:    QODBCPreparedExtension( QODBCResult * r )	: result( r ) {}    bool prepare( const QString& query )    {	return result->prepare( query );    }    bool exec()    {	return result->exec();    }        QODBCResult * result;};QString qWarnODBCHandle(int handleType, SQLHANDLE handle){    SQLINTEGER nativeCode_;    SQLSMALLINT msgLen;    SQLRETURN r = SQL_ERROR;    SQLTCHAR state_[SQL_SQLSTATE_SIZE+1];    SQLTCHAR description_[SQL_MAX_MESSAGE_LENGTH];    r = SQLGetDiagRec( handleType,			 handle,			 1,			 (SQLTCHAR*)state_,			 &nativeCode_,			 (SQLTCHAR*)description_,			 SQL_MAX_MESSAGE_LENGTH-1, /* in bytes, not in characters */			 &msgLen);    if ( r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO )#ifdef UNICODE	return QString( (const QChar*)description_, (uint)msgLen );#else	return QString::fromLocal8Bit( (const char*)description_ );#endif    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, const QODBCPrivate* p ){    QVariant::Type type = QVariant::Invalid;    switch ( sqltype ) {    case SQL_DECIMAL:    case SQL_NUMERIC:    case SQL_REAL:    case SQL_FLOAT:    case SQL_DOUBLE:    case SQL_BIGINT: //use high precision binding	type = QVariant::Double;	break;    case SQL_SMALLINT:    case SQL_INTEGER:    case SQL_BIT:    case SQL_TINYINT:	type = QVariant::Int;	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:	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::CString;	break;    }    return type;}QString qGetStringData( SQLHANDLE hStmt, int column, int colSize, bool& isNull, bool unicode = FALSE ){    QString     fieldVal;    SQLRETURN   r = SQL_ERROR;    SQLINTEGER  lengthIndicator = 0;    if ( colSize <= 0 ) {	colSize = 255;    } 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::null;		isNull = TRUE;		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 += buf;	    }	    if ( lengthIndicator < colSize ) {		// workaround for Drivermanagers that don't return SQL_NO_DATA		break;	    }	} else if ( r == SQL_NO_DATA ) {	    break;	} else {#ifdef QT_CHECK_RANGE	    qWarning( "qGetStringData: Error while fetching data (%d)", r );#endif	    fieldVal = QString::null;	    break;	}    }    delete[] buf;    return fieldVal;}QByteArray qGetBinaryData( SQLHANDLE hStmt, int column, SQLINTEGER& lengthIndicator, bool& isNull ){    QByteArray fieldVal;    SQLSMALLINT colNameLen;    SQLSMALLINT colType;    SQLUINTEGER colSize;    SQLSMALLINT colScale;    SQLSMALLINT nullable;    SQLRETURN r = SQL_ERROR;    SQLTCHAR colName[COLNAMESIZE];    r = SQLDescribeCol( hStmt,			column+1,			colName,			COLNAMESIZE,			&colNameLen,			&colType,			&colSize,			&colScale,			&nullable );#ifdef QT_CHECK_RANGE    if ( r != SQL_SUCCESS )	qWarning( QString("qGetBinaryData: Unable to describe column %1").arg(column) );#endif    // SQLDescribeCol may return 0 if size cannot be determined    if (!colSize) {	colSize = 255;    }    if ( colSize > 65536 ) { // read the field in 64 KB chunks	colSize = 65536;    }    char * buf = new char[ colSize ];    while ( TRUE ) {	r = SQLGetData( hStmt,			column+1,			SQL_C_BINARY,			(SQLPOINTER) buf,			colSize,			&lengthIndicator );	if ( r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO ) {	    if ( lengthIndicator == SQL_NULL_DATA ) { 		isNull = TRUE;		break;	    } else {		int rSize;		r == SQL_SUCCESS ? rSize = lengthIndicator : rSize = colSize;		if ( lengthIndicator == SQL_NO_TOTAL ) { // size cannot be determined		    rSize = colSize;		}		// NB! This is not a memleak - the mem will be deleted by QByteArray when		// no longer ref'd		char * tmp = (char *) malloc( rSize + fieldVal.size() );		if ( fieldVal.size() ) {		    memcpy( tmp, fieldVal.data(), fieldVal.size() );		}		memcpy( tmp + fieldVal.size(), buf, rSize );		fieldVal = fieldVal.assign( tmp, fieldVal.size() + rSize );		if ( r == SQL_SUCCESS ) { // the whole field was read in one chunk		    break;		}	    }	} else {	    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;}// creates a QSqlFieldInfo from a valid hStmt generated// by SQLColumns. The hStmt has to point to a valid position.QSqlFieldInfo qMakeFieldInfo( const SQLHANDLE hStmt, const QODBCPrivate* p ){    bool isNull;    QString fname = qGetStringData( hStmt, 3, -1, isNull, p->unicode );    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    return QSqlFieldInfo( fname, qDecodeODBCType( type, p ), required, size, prec, QVariant(), type );}QSqlFieldInfo qMakeFieldInfo( const QODBCPrivate* p, int i  ){    SQLSMALLINT colNameLen;    SQLSMALLINT colType;    SQLUINTEGER colSize;    SQLSMALLINT colScale;    SQLSMALLINT nullable;    SQLRETURN r = SQL_ERROR;    SQLTCHAR colName[ COLNAMESIZE ];    r = SQLDescribeCol( p->hStmt,			i+1,			colName,			(SQLSMALLINT)COLNAMESIZE,			&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();    }#ifdef UNICODE    QString qColName( (const QChar*)colName, (uint)colNameLen );#else    QString qColName = QString::fromLocal8Bit( (const char*)colName );#endif    // 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, p );    return QSqlFieldInfo( qColName,    			  type,    			  required,    			  (int)colSize == 0 ? -1 : (int)colSize,    			  (int)colScale == 0 ? -1 : (int)colScale,    			  QVariant(),    			  (int)colType );}void qSplitTableQualifier( const QString & qualifier, QString * catalog,			   QString * schema, QString * table ){    if ( !catalog || !schema || !table )	return;    QStringList l = QStringList::split( ".", qualifier, TRUE );    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++;	}    }}////////////////////////////////////////////////////////////////////////////QODBCResult::QODBCResult( const QODBCDriver * db, QODBCPrivate* p ): QSqlResult(db){    d = new QODBCPrivate();    (*d) = (*p);    setExtension( new QODBCPreparedExtension( this ) );}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;    d->rInf.clear();    // Always reallocate the statement handle - the statement attributes    // are not reset if SQLFreeStmt() is called which causes some problems.    if ( d->hStmt ) {	r = SQLFreeHandle( SQL_HANDLE_STMT, d->hStmt );	if ( r != SQL_SUCCESS ) {#ifdef QT_CHECK_RANGE	    qSqlWarning( "QODBCResult::reset: Unable to free statement handle", d );#endif	    return FALSE;	}    }    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;    }    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 ) {#ifdef QT_CHECK_RANGE			qSqlWarning( "QODBCResult::reset: Unable to set 'SQL_CURSOR_STATIC' as statement attribute. Please check your ODBC driver configuration", d );#endif	return FALSE;    }#ifdef UNICODE    r = SQLExecDirect( d->hStmt,		       (SQLWCHAR*) query.unicode(),		       (SQLINTEGER) query.length() );#else    QCString query8 = query.local8Bit();    r = SQLExecDirect( d->hStmt,                       (SQLCHAR*) query8.data(),                       (SQLINTEGER) query8.length() );#endif    if ( r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO ) {	setLastError( qMakeError( "Unable to execute statement", QSqlError::Statement, d ) );	return FALSE;    }    SQLSMALLINT count;    r = SQLNumResultCols( d->hStmt, &count );    if ( count ) {	setSelect( TRUE );	for ( int i = 0; i < count; ++i ) {	    d->rInf.append( qMakeFieldInfo( d, i ) );	}    } else {	setSelect( FALSE );    }    setActive( TRUE );    return TRUE;}bool QODBCResult::fetch(int i){    if ( isForwardOnly() && i < at() )	return FALSE;    if ( i == at() )	return TRUE;    fieldCache.clear();    nullCache.clear();    int actualIdx = i + 1;    if ( actualIdx <= 0 ) {	setAt( QSql::BeforeFirst );	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 ){ 	return FALSE;    }    setAt( i );    return TRUE;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -