summaryrefslogtreecommitdiffstats
path: root/tqtinterface/qt4/src/sql/drivers/odbc/tqsql_odbc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tqtinterface/qt4/src/sql/drivers/odbc/tqsql_odbc.cpp')
-rw-r--r--tqtinterface/qt4/src/sql/drivers/odbc/tqsql_odbc.cpp2035
1 files changed, 0 insertions, 2035 deletions
diff --git a/tqtinterface/qt4/src/sql/drivers/odbc/tqsql_odbc.cpp b/tqtinterface/qt4/src/sql/drivers/odbc/tqsql_odbc.cpp
deleted file mode 100644
index 8e75f90..0000000
--- a/tqtinterface/qt4/src/sql/drivers/odbc/tqsql_odbc.cpp
+++ /dev/null
@@ -1,2035 +0,0 @@
-/****************************************************************************
-**
-** Implementation of ODBC driver classes
-**
-** Created : 001103
-**
-** Copyright (C) 2010 Timothy Pearson and (C) 1992-2008 Trolltech ASA.
-**
-** This file is part of the sql module of the TQt GUI Toolkit.
-**
-** This file may be used under the terms of the GNU General
-** Public License versions 2.0 or 3.0 as published by the Free
-** Software Foundation and appearing in the files LICENSE.GPL2
-** and LICENSE.GPL3 included in the packaging of this file.
-** Alternatively you may (at your option) use any later version
-** of the GNU General Public License if such license has been
-** publicly approved by Trolltech ASA (or its successors, if any)
-** and the KDE Free TQt Foundation.
-**
-** 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.
-**
-** This file may be used under the terms of the Q Public License as
-** defined by Trolltech ASA and appearing in the file LICENSE.TQPL
-** included in the packaging of this file. Licensees holding valid TQt
-** Commercial licenses may use this file in accordance with the TQt
-** Commercial License Agreement provided with the Software.
-**
-** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
-** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
-** herein.
-**
-**********************************************************************/
-
-#include "tqsql_odbc.h"
-#include <tqsqlrecord.h>
-
-#if defined (TQ_OS_WIN32)
-#include <tqt_windows.h>
-#include <tqapplication.h>
-#endif
-#include <tqdatetime.h>
-#include <private/tqsqlextension_p.h>
-#include <private/tqinternal_p.h>
-#include <stdlib.h>
-
-// undefine this to prevent initial check of the ODBC driver
-#define ODBC_CHECK_DRIVER
-
-#if defined(TQ_ODBC_VERSION_2)
-//crude hack to get non-tqunicode capable driver managers to work
-# undef UNICODE
-# define STQLTCHAR STQLCHAR
-# define STQL_C_WCHAR STQL_C_CHAR
-#endif
-
-// newer platform SDKs use STQLLEN instead of STQLINTEGER
-#ifdef STQLLEN
-# define TQSTQLLEN STQLLEN
-#else
-# define TQSTQLLEN STQLINTEGER
-#endif
-
-#ifdef STQLULEN
-# define TQSQLULEN STQLULEN
-#else
-# define TQSQLULEN STQLUINTEGER
-#endif
-
-
-static const TQSTQLLEN COLNAMESIZE = 256;
-//Map TQt parameter types to ODBC types
-static const STQLSMALLINT qParamType[ 4 ] = { STQL_PARAM_INPUT, STQL_PARAM_INPUT, STQL_PARAM_OUTPUT, STQL_PARAM_INPUT_OUTPUT };
-
-class TQODBCPrivate
-{
-public:
- TQODBCPrivate()
- : hEnv(0), hDbc(0), hStmt(0), useSchema(FALSE)
- {
- sql_char_type = sql_varchar_type = sql_longvarchar_type = TQVariant::CString;
- tqunicode = FALSE;
- }
-
- STQLHANDLE hEnv;
- STQLHANDLE hDbc;
- STQLHANDLE hStmt;
-
- bool tqunicode;
- bool useSchema;
- TQVariant::Type sql_char_type;
- TQVariant::Type sql_varchar_type;
- TQVariant::Type sql_longvarchar_type;
-
- TQSqlRecordInfo rInf;
-
- bool checkDriver() const;
- void checkUnicode();
- void checkSchemaUsage();
- bool setConnectionOptions( const TQString& connOpts );
- void splitTableQualifier(const TQString &qualifier, TQString &catalog,
- TQString &schema, TQString &table);
-};
-
-class TQODBCPreparedExtension : public TQSqlExtension
-{
-public:
- TQODBCPreparedExtension( TQODBCResult * r )
- : result( r ) {}
-
- bool prepare( const TQString& query )
- {
- return result->prepare( query );
- }
-
- bool exec()
- {
- return result->exec();
- }
-
- TQODBCResult * result;
-};
-
-TQPtrDict<TQSqlOpenExtension> *qSqlOpenExtDict();
-
-class TQODBCOpenExtension : public TQSqlOpenExtension
-{
-public:
- TQODBCOpenExtension( TQODBCDriver *dri )
- : TQSqlOpenExtension(), driver(dri) {}
- ~TQODBCOpenExtension() {}
-
- bool open( const TQString& db,
- const TQString& user,
- const TQString& password,
- const TQString& host,
- int port,
- const TQString& connOpts );
-private:
- TQODBCDriver *driver;
-};
-
-bool TQODBCOpenExtension::open( const TQString& db,
- const TQString& user,
- const TQString& password,
- const TQString& host,
- int port,
- const TQString& connOpts )
-{
- return driver->open( db, user, password, host, port, connOpts );
-}
-
-static TQString qWarnODBCHandle(int handleType, STQLHANDLE handle)
-{
- STQLINTEGER nativeCode_;
- STQLSMALLINT msgLen;
- STQLRETURN r = STQL_ERROR;
- STQLTCHAR state_[STQL_STQLSTATE_SIZE+1];
- STQLTCHAR description_[STQL_MAX_MESSAGE_LENGTH];
- r = STQLGetDiagRec( handleType,
- handle,
- 1,
- (STQLTCHAR*)state_,
- &nativeCode_,
- (STQLTCHAR*)description_,
- STQL_MAX_MESSAGE_LENGTH-1, /* in bytes, not in characters */
- &msgLen);
- if ( r == STQL_SUCCESS || r == STQL_SUCCESS_WITH_INFO )
-#ifdef UNICODE
- return TQString( (const TQChar*)description_, (uint)msgLen );
-#else
- return TQString::fromLocal8Bit( (const char*)description_ );
-#endif
- return TQString::null;
-}
-
-static TQString qODBCWarn( const TQODBCPrivate* odbc)
-{
- return ( qWarnODBCHandle( STQL_HANDLE_ENV, odbc->hEnv ) + " "
- + qWarnODBCHandle( STQL_HANDLE_DBC, odbc->hDbc ) + " "
- + qWarnODBCHandle( STQL_HANDLE_STMT, odbc->hStmt ) );
-}
-
-static void qSqlWarning( const TQString& message, const TQODBCPrivate* odbc )
-{
-#ifdef TQT_CHECK_RANGE
- qWarning( "%s\tError: %s", message.local8Bit().data(), qODBCWarn( odbc ).local8Bit().data() );
-#endif
-}
-
-static TQSqlError qMakeError( const TQString& err, int type, const TQODBCPrivate* p )
-{
- return TQSqlError( "TQODBC3: " + err, qODBCWarn(p), type );
-}
-
-static TQVariant::Type qDecodeODBCType( STQLSMALLINT sqltype, const TQODBCPrivate* p )
-{
- TQVariant::Type type = TQVariant::Invalid;
- switch ( sqltype ) {
- case STQL_DECIMAL:
- case STQL_NUMERIC:
- case STQL_REAL:
- case STQL_FLOAT:
- case STQL_DOUBLE:
- type = TQVariant::Double;
- break;
- case STQL_SMALLINT:
- case STQL_INTEGER:
- case STQL_BIT:
- case STQL_TINYINT:
- type = TQVariant::Int;
- break;
- case STQL_BIGINT:
- type = TQVariant::LongLong;
- break;
- case STQL_BINARY:
- case STQL_VARBINARY:
- case STQL_LONGVARBINARY:
- type = TQVariant::ByteArray;
- break;
- case STQL_DATE:
- case STQL_TYPE_DATE:
- type = TQVariant::Date;
- break;
- case STQL_TIME:
- case STQL_TYPE_TIME:
- type = TQVariant::Time;
- break;
- case STQL_TIMESTAMP:
- case STQL_TYPE_TIMESTAMP:
- type = TQVariant::DateTime;
- break;
-#ifndef TQ_ODBC_VERSION_2
- case STQL_WCHAR:
- case STQL_WVARCHAR:
- case STQL_WLONGVARCHAR:
- type = TQVariant::String;
- break;
-#endif
- case STQL_CHAR:
- type = p->sql_char_type;
- break;
- case STQL_VARCHAR:
- type = p->sql_varchar_type;
- break;
- case STQL_LONGVARCHAR:
- type = p->sql_longvarchar_type;
- break;
- default:
- type = TQVariant::CString;
- break;
- }
- return type;
-}
-
-static TQString qGetStringData( STQLHANDLE hStmt, int column, int colSize, bool& isNull, bool tqunicode = FALSE )
-{
- TQString fieldVal;
- STQLRETURN r = STQL_ERROR;
- TQSTQLLEN lengthIndicator = 0;
-
- 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 ( tqunicode ) {
- colSize *= 2; // a tiny bit faster, since it saves a STQLGetData() call
- }
- }
- char* buf = new char[ colSize ];
- while ( TRUE ) {
- r = STQLGetData( hStmt,
- column+1,
- tqunicode ? STQL_C_WCHAR : STQL_C_CHAR,
- (STQLPOINTER)buf,
- (TQSTQLLEN)colSize,
- &lengthIndicator );
- if ( r == STQL_SUCCESS || r == STQL_SUCCESS_WITH_INFO ) {
- if ( lengthIndicator == STQL_NULL_DATA || lengthIndicator == STQL_NO_TOTAL ) {
- fieldVal = TQString::null;
- isNull = TRUE;
- break;
- }
- // if STQL_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 == STQL_SUCCESS_WITH_INFO) ? (tqunicode ? colSize-2 : colSize-1) : lengthIndicator;
- if ( tqunicode ) {
- fieldVal += TQString( (TQChar*) buf, rSize / 2 );
- } else {
- buf[ rSize ] = 0;
- fieldVal += buf;
- }
- if ( lengthIndicator < colSize ) {
- // workaround for Drivermanagers that don't return STQL_NO_DATA
- break;
- }
- } else if ( r == STQL_NO_DATA ) {
- break;
- } else {
-#ifdef TQT_CHECK_RANGE
- qWarning( "qGetStringData: Error while fetching data (%d)", r );
-#endif
- fieldVal = TQString::null;
- break;
- }
- }
- delete[] buf;
- return fieldVal;
-}
-
-static TQByteArray qGetBinaryData( STQLHANDLE hStmt, int column, TQSTQLLEN& lengthIndicator, bool& isNull )
-{
- TQByteArray fieldVal;
- STQLSMALLINT colNameLen;
- STQLSMALLINT colType;
- TQSQLULEN colSize;
- STQLSMALLINT colScale;
- STQLSMALLINT nullable;
- STQLRETURN r = STQL_ERROR;
-
- STQLTCHAR colName[COLNAMESIZE];
- r = STQLDescribeCol( hStmt,
- column+1,
- colName,
- COLNAMESIZE,
- &colNameLen,
- &colType,
- &colSize,
- &colScale,
- &nullable );
-#ifdef TQT_CHECK_RANGE
- if ( r != STQL_SUCCESS )
- qWarning( "qGetBinaryData: Unable to describe column %d", column );
-#endif
- // STQLDescribeCol may return 0 if size cannot be determined
- if (!colSize) {
- colSize = 256;
- }
- if ( colSize > 65536 ) { // read the field in 64 KB chunks
- colSize = 65536;
- }
- char * buf = new char[ colSize ];
- while ( TRUE ) {
- r = STQLGetData( hStmt,
- column+1,
- STQL_C_BINARY,
- (STQLPOINTER) buf,
- (TQSTQLLEN)colSize,
- &lengthIndicator );
- if ( r == STQL_SUCCESS || r == STQL_SUCCESS_WITH_INFO ) {
- if ( lengthIndicator == STQL_NULL_DATA ) {
- isNull = TRUE;
- break;
- } else {
- int rSize;
- r == STQL_SUCCESS ? rSize = lengthIndicator : rSize = colSize;
- if ( lengthIndicator == STQL_NO_TOTAL ) { // size cannot be determined
- rSize = colSize;
- }
- // NB! This is not a memleak - the mem will be deleted by TQByteArray 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 == STQL_SUCCESS ) { // the whole field was read in one chunk
- break;
- }
- }
- } else {
- break;
- }
- }
- delete [] buf;
- return fieldVal;
-}
-
-static int qGetIntData( STQLHANDLE hStmt, int column, bool& isNull )
-{
- TQSTQLLEN intbuf = 0;
- isNull = FALSE;
- TQSTQLLEN lengthIndicator = 0;
- STQLRETURN r = STQLGetData( hStmt,
- column+1,
- STQL_C_SLONG,
- (STQLPOINTER)&intbuf,
- (TQSTQLLEN)0,
- &lengthIndicator );
- if ( ( r != STQL_SUCCESS && r != STQL_SUCCESS_WITH_INFO ) || lengthIndicator == STQL_NULL_DATA ) {
- isNull = TRUE;
- return 0;
- }
- return (int)intbuf;
-}
-
-static double qGetDoubleData( STQLHANDLE hStmt, int column, bool& isNull )
-{
- STQLDOUBLE dblbuf;
- TQSTQLLEN lengthIndicator = 0;
- isNull = FALSE;
- STQLRETURN r = STQLGetData( hStmt,
- column+1,
- STQL_C_DOUBLE,
- (STQLPOINTER)&dblbuf,
- (TQSTQLLEN)0,
- &lengthIndicator );
- if ( ( r != STQL_SUCCESS && r != STQL_SUCCESS_WITH_INFO ) || lengthIndicator == STQL_NULL_DATA ) {
- isNull = TRUE;
- return 0.0;
- }
-
- return (double) dblbuf;
-}
-
-static STQLBIGINT qGetBigIntData( STQLHANDLE hStmt, int column, bool& isNull )
-{
- STQLBIGINT lngbuf = TQ_INT64_C( 0 );
- isNull = FALSE;
- TQSTQLLEN lengthIndicator = 0;
- STQLRETURN r = STQLGetData( hStmt,
- column+1,
- STQL_C_SBIGINT,
- (STQLPOINTER) &lngbuf,
- (TQSTQLLEN)0,
- &lengthIndicator );
- if ( ( r != STQL_SUCCESS && r != STQL_SUCCESS_WITH_INFO ) || lengthIndicator == STQL_NULL_DATA )
- isNull = TRUE;
-
- return lngbuf;
-}
-
-// creates a TQSqlFieldInfo from a valid hStmt generated
-// by STQLColumns. The hStmt has to point to a valid position.
-static TQSqlFieldInfo qMakeFieldInfo( const STQLHANDLE hStmt, const TQODBCPrivate* p )
-{
- bool isNull;
- TQString fname = qGetStringData( hStmt, 3, -1, isNull, p->tqunicode );
- int type = qGetIntData( hStmt, 4, isNull ); // column type
- int required = qGetIntData( hStmt, 10, isNull ); // nullable-flag
- // required can be STQL_NO_NULLS, STQL_NULLABLE or STQL_NULLABLE_UNKNOWN
- if ( required == STQL_NO_NULLS ) {
- required = 1;
- } else if ( required == STQL_NULLABLE ) {
- required = 0;
- } else {
- required = -1;
- }
- int size = qGetIntData( hStmt, 6, isNull ); // column size
- int prec = qGetIntData( hStmt, 8, isNull ); // precision
- return TQSqlFieldInfo( fname, qDecodeODBCType( type, p ), required, size, prec, TQVariant(), type );
-}
-
-static TQSqlFieldInfo qMakeFieldInfo( const TQODBCPrivate* p, int i )
-{
- STQLSMALLINT colNameLen;
- STQLSMALLINT colType;
- TQSQLULEN colSize;
- STQLSMALLINT colScale;
- STQLSMALLINT nullable;
- STQLRETURN r = STQL_ERROR;
- STQLTCHAR colName[ COLNAMESIZE ];
- r = STQLDescribeCol( p->hStmt,
- i+1,
- colName,
- (TQSQLULEN)COLNAMESIZE,
- &colNameLen,
- &colType,
- &colSize,
- &colScale,
- &nullable);
-
- if ( r != STQL_SUCCESS ) {
-#ifdef TQT_CHECK_RANGE
- qSqlWarning( TQString("qMakeField: Unable to describe column %1").arg(i), p );
-#endif
- return TQSqlFieldInfo();
- }
-#ifdef UNICODE
- TQString qColName( (const TQChar*)colName, (uint)colNameLen );
-#else
- TQString qColName = TQString::fromLocal8Bit( (const char*)colName );
-#endif
- // nullable can be STQL_NO_NULLS, STQL_NULLABLE or STQL_NULLABLE_UNKNOWN
- int required = -1;
- if ( nullable == STQL_NO_NULLS ) {
- required = 1;
- } else if ( nullable == STQL_NULLABLE ) {
- required = 0;
- }
- TQVariant::Type type = qDecodeODBCType( colType, p );
- return TQSqlFieldInfo( qColName,
- type,
- required,
- (int)colSize == 0 ? -1 : (int)colSize,
- (int)colScale == 0 ? -1 : (int)colScale,
- TQVariant(),
- (int)colType );
-}
-
-bool TQODBCPrivate::setConnectionOptions( const TQString& connOpts )
-{
- // Set any connection attributes
- TQStringList raw = TQStringList::split( ';', connOpts );
- TQStringList opts;
- STQLRETURN r = STQL_SUCCESS;
- TQMap<TQString, TQString> connMap;
- for ( TQStringList::ConstIterator it = raw.begin(); it != raw.end(); ++it ) {
- TQString tmp( *it );
- int idx;
- if ( (idx = tmp.find( '=' )) != -1 )
- connMap[ tmp.left( idx ) ] = tmp.mid( idx + 1 ).simplifyWhiteSpace();
- else
- qWarning( "TQODBCDriver::open: Illegal connect option value '%s'", tmp.latin1() );
- }
- if ( connMap.count() ) {
- TQMap<TQString, TQString>::ConstIterator it;
- TQString opt, val;
- STQLUINTEGER v = 0;
- for ( it = connMap.begin(); it != connMap.end(); ++it ) {
- opt = it.key().upper();
- val = it.data().upper();
- r = STQL_SUCCESS;
- if ( opt == "STQL_ATTR_ACCESS_MODE" ) {
- if ( val == "STQL_MODE_READ_ONLY" ) {
- v = STQL_MODE_READ_ONLY;
- } else if ( val == "STQL_MODE_READ_WRITE" ) {
- v = STQL_MODE_READ_WRITE;
- } else {
- qWarning( TQString( "TQODBCDriver::open: Unknown option value '%1'" ).arg( *it ) );
- break;
- }
- r = STQLSetConnectAttr( hDbc, STQL_ATTR_ACCESS_MODE, (STQLPOINTER) v, 0 );
- } else if ( opt == "STQL_ATTR_CONNECTION_TIMEOUT" ) {
- v = val.toUInt();
- r = STQLSetConnectAttr( hDbc, STQL_ATTR_CONNECTION_TIMEOUT, (STQLPOINTER) v, 0 );
- } else if ( opt == "STQL_ATTR_LOGIN_TIMEOUT" ) {
- v = val.toUInt();
- r = STQLSetConnectAttr( hDbc, STQL_ATTR_LOGIN_TIMEOUT, (STQLPOINTER) v, 0 );
- } else if ( opt == "STQL_ATTR_CURRENT_CATALOG" ) {
- val.ucs2(); // 0 terminate
- r = STQLSetConnectAttr( hDbc, STQL_ATTR_CURRENT_CATALOG,
-#ifdef UNICODE
- (STQLWCHAR*) val.tqunicode(),
-#else
- (STQLCHAR*) val.latin1(),
-#endif
- STQL_NTS );
- } else if ( opt == "STQL_ATTR_METADATA_ID" ) {
- if ( val == "STQL_TRUE" ) {
- v = STQL_TRUE;
- } else if ( val == "STQL_FALSE" ) {
- v = STQL_FALSE;
- } else {
- qWarning( TQString( "TQODBCDriver::open: Unknown option value '%1'" ).arg( *it ) );
- break;
- }
- r = STQLSetConnectAttr( hDbc, STQL_ATTR_METADATA_ID, (STQLPOINTER) v, 0 );
- } else if ( opt == "STQL_ATTR_PACKET_SIZE" ) {
- v = val.toUInt();
- r = STQLSetConnectAttr( hDbc, STQL_ATTR_PACKET_SIZE, (STQLPOINTER) v, 0 );
- } else if ( opt == "STQL_ATTR_TRACEFILE" ) {
- val.ucs2(); // 0 terminate
- r = STQLSetConnectAttr( hDbc, STQL_ATTR_TRACEFILE,
-#ifdef UNICODE
- (STQLWCHAR*) val.tqunicode(),
-#else
- (STQLCHAR*) val.latin1(),
-#endif
- STQL_NTS );
- } else if ( opt == "STQL_ATTR_TRACE" ) {
- if ( val == "STQL_OPT_TRACE_OFF" ) {
- v = STQL_OPT_TRACE_OFF;
- } else if ( val == "STQL_OPT_TRACE_ON" ) {
- v = STQL_OPT_TRACE_ON;
- } else {
- qWarning( TQString( "TQODBCDriver::open: Unknown option value '%1'" ).arg( *it ) );
- break;
- }
- r = STQLSetConnectAttr( hDbc, STQL_ATTR_TRACE, (STQLPOINTER) v, 0 );
- }
-#ifdef TQT_CHECK_RANGE
- else {
- qWarning( TQString("TQODBCDriver::open: Unknown connection attribute '%1'").arg( opt ) );
- }
-#endif
- if ( r != STQL_SUCCESS && r != STQL_SUCCESS_WITH_INFO ) {
-#ifdef TQT_CHECK_RANGE
- qSqlWarning( TQString("TQODBCDriver::open: Unable to set connection attribute '%1'").arg( opt ), this );
-#endif
- return FALSE;
- }
- }
- }
- return TRUE;
-}
-
-void TQODBCPrivate::splitTableQualifier(const TQString & qualifier, TQString &catalog,
- TQString &schema, TQString &table)
-{
- if (!useSchema) {
- table = qualifier;
- return;
- }
- TQStringList l = TQStringList::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 ( TQStringList::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++;
- }
- }
-}
-
-////////////////////////////////////////////////////////////////////////////
-
-TQODBCResult::TQODBCResult( const TQODBCDriver * db, TQODBCPrivate* p )
-: TQSqlResult(db)
-{
- d = new TQODBCPrivate();
- (*d) = (*p);
- setExtension( new TQODBCPreparedExtension( this ) );
-}
-
-TQODBCResult::~TQODBCResult()
-{
- if ( d->hStmt && driver()->isOpen() ) {
- STQLRETURN r = STQLFreeHandle( STQL_HANDLE_STMT, d->hStmt );
-#ifdef TQT_CHECK_RANGE
- if ( r != STQL_SUCCESS )
- qSqlWarning( "TQODBCDriver: Unable to free statement handle " + TQString::number(r), d );
-#endif
- }
-
- delete d;
-}
-
-bool TQODBCResult::reset ( const TQString& query )
-{
- setActive( FALSE );
- setAt( TQSql::BeforeFirst );
- STQLRETURN r;
-
- d->rInf.clear();
- // Always reallocate the statement handle - the statement attributes
- // are not reset if STQLFreeStmt() is called which causes some problems.
- if ( d->hStmt ) {
- r = STQLFreeHandle( STQL_HANDLE_STMT, d->hStmt );
- if ( r != STQL_SUCCESS ) {
-#ifdef TQT_CHECK_RANGE
- qSqlWarning( "TQODBCResult::reset: Unable to free statement handle", d );
-#endif
- return FALSE;
- }
- }
- r = STQLAllocHandle( STQL_HANDLE_STMT,
- d->hDbc,
- &d->hStmt );
- if ( r != STQL_SUCCESS ) {
-#ifdef TQT_CHECK_RANGE
- qSqlWarning( "TQODBCResult::reset: Unable to allocate statement handle", d );
-#endif
- return FALSE;
- }
-
- if ( isForwardOnly() ) {
- r = STQLSetStmtAttr( d->hStmt,
- STQL_ATTR_CURSOR_TYPE,
- (STQLPOINTER)STQL_CURSOR_FORWARD_ONLY,
- STQL_IS_UINTEGER );
- } else {
- r = STQLSetStmtAttr( d->hStmt,
- STQL_ATTR_CURSOR_TYPE,
- (STQLPOINTER)STQL_CURSOR_STATIC,
- STQL_IS_UINTEGER );
- }
- if ( r != STQL_SUCCESS && r != STQL_SUCCESS_WITH_INFO ) {
-#ifdef TQT_CHECK_RANGE
- qSqlWarning( "TQODBCResult::reset: Unable to set 'STQL_CURSOR_STATIC' as statement attribute. Please check your ODBC driver configuration", d );
-#endif
- return FALSE;
- }
-
-#ifdef UNICODE
- r = STQLExecDirect( d->hStmt,
- (STQLWCHAR*) query.tqunicode(),
- (STQLINTEGER) query.length() );
-#else
- TQCString query8 = query.local8Bit();
- r = STQLExecDirect( d->hStmt,
- (STQLCHAR*) query8.data(),
- (STQLINTEGER) query8.length() );
-#endif
- if ( r != STQL_SUCCESS && r != STQL_SUCCESS_WITH_INFO ) {
- setLastError( qMakeError( "Unable to execute statement", TQSqlError::Statement, d ) );
- return FALSE;
- }
- STQLSMALLINT count;
- r = STQLNumResultCols( 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 TQODBCResult::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( TQSql::BeforeFirst );
- return FALSE;
- }
- STQLRETURN r;
- if ( isForwardOnly() ) {
- bool ok = TRUE;
- while ( ok && i > at() )
- ok = fetchNext();
- return ok;
- } else {
- r = STQLFetchScroll( d->hStmt,
- STQL_FETCH_ABSOLUTE,
- actualIdx );
- }
- if ( r != STQL_SUCCESS ){
- return FALSE;
- }
- setAt( i );
- return TRUE;
-}
-
-bool TQODBCResult::fetchNext()
-{
- STQLRETURN r;
- fieldCache.clear();
- nullCache.clear();
- r = STQLFetchScroll( d->hStmt,
- STQL_FETCH_NEXT,
- 0 );
- if ( r != STQL_SUCCESS )
- return FALSE;
- setAt( at() + 1 );
- return TRUE;
-}
-
-bool TQODBCResult::fetchFirst()
-{
- if ( isForwardOnly() && at() != TQSql::BeforeFirst )
- return FALSE;
- STQLRETURN r;
- fieldCache.clear();
- nullCache.clear();
- if ( isForwardOnly() ) {
- return fetchNext();
- }
- r = STQLFetchScroll( d->hStmt,
- STQL_FETCH_FIRST,
- 0 );
- if ( r != STQL_SUCCESS )
- return FALSE;
- setAt( 0 );
- return TRUE;
-}
-
-bool TQODBCResult::fetchPrior()
-{
- if ( isForwardOnly() )
- return FALSE;
- STQLRETURN r;
- fieldCache.clear();
- nullCache.clear();
- r = STQLFetchScroll( d->hStmt,
- STQL_FETCH_PRIOR,
- 0 );
- if ( r != STQL_SUCCESS )
- return FALSE;
- setAt( at() - 1 );
- return TRUE;
-}
-
-bool TQODBCResult::fetchLast()
-{
- STQLRETURN r;
- fieldCache.clear();
- nullCache.clear();
-
- if ( isForwardOnly() ) {
- // cannot seek to last row in forwardOnly mode, so we have to use brute force
- int i = at();
- if ( i == TQSql::AfterLast )
- return FALSE;
- if ( i == TQSql::BeforeFirst )
- i = 0;
- while ( fetchNext() )
- ++i;
- setAt( i );
- return TRUE;
- }
-
- r = STQLFetchScroll( d->hStmt,
- STQL_FETCH_LAST,
- 0 );
- if ( r != STQL_SUCCESS ) {
- return FALSE;
- }
- STQLINTEGER currRow;
- r = STQLGetStmtAttr( d->hStmt,
- STQL_ROW_NUMBER,
- &currRow,
- STQL_IS_INTEGER,
- 0 );
- if ( r != STQL_SUCCESS )
- return FALSE;
- setAt( currRow-1 );
- return TRUE;
-}
-
-TQVariant TQODBCResult::data( int field )
-{
- if ( field >= (int) d->rInf.count() ) {
- qWarning( "TQODBCResult::data: column %d out of range", field );
- return TQVariant();
- }
- if ( fieldCache.contains( field ) )
- return fieldCache[ field ];
- STQLRETURN r(0);
- TQSTQLLEN lengthIndicator = 0;
- bool isNull = FALSE;
- int current = fieldCache.count();
- for ( ; current < (field + 1); ++current ) {
- const TQSqlFieldInfo info = d->rInf[ current ];
- switch ( info.type() ) {
- case TQVariant::LongLong:
- fieldCache[ current ] = TQVariant( (TQ_LLONG) qGetBigIntData( d->hStmt, current, isNull ) );
- nullCache[ current ] = isNull;
- break;
- case TQVariant::Int:
- fieldCache[ current ] = TQVariant( qGetIntData( d->hStmt, current, isNull ) );
- nullCache[ current ] = isNull;
- break;
- case TQVariant::Date:
- DATE_STRUCT dbuf;
- r = STQLGetData( d->hStmt,
- current+1,
- STQL_C_DATE,
- (STQLPOINTER)&dbuf,
- (TQSTQLLEN)0,
- &lengthIndicator );
- if ( ( r == STQL_SUCCESS || r == STQL_SUCCESS_WITH_INFO ) && ( lengthIndicator != STQL_NULL_DATA ) ) {
- fieldCache[ current ] = TQVariant( TQDate( dbuf.year, dbuf.month, dbuf.day ) );
- nullCache[ current ] = FALSE;
- } else {
- fieldCache[ current ] = TQVariant( TQDate() );
- nullCache[ current ] = TRUE;
- }
- break;
- case TQVariant::Time:
- TIME_STRUCT tbuf;
- r = STQLGetData( d->hStmt,
- current+1,
- STQL_C_TIME,
- (STQLPOINTER)&tbuf,
- (TQSTQLLEN)0,
- &lengthIndicator );
- if ( ( r == STQL_SUCCESS || r == STQL_SUCCESS_WITH_INFO ) && ( lengthIndicator != STQL_NULL_DATA ) ) {
- fieldCache[ current ] = TQVariant( TQTime( tbuf.hour, tbuf.minute, tbuf.second ) );
- nullCache[ current ] = FALSE;
- } else {
- fieldCache[ current ] = TQVariant( TQTime() );
- nullCache[ current ] = TRUE;
- }
- break;
- case TQVariant::DateTime:
- TIMESTAMP_STRUCT dtbuf;
- r = STQLGetData( d->hStmt,
- current+1,
- STQL_C_TIMESTAMP,
- (STQLPOINTER)&dtbuf,
- (TQSTQLLEN)0,
- &lengthIndicator );
- if ( ( r == STQL_SUCCESS || r == STQL_SUCCESS_WITH_INFO ) && ( lengthIndicator != STQL_NULL_DATA ) ) {
- fieldCache[ current ] = TQVariant( TQDateTime( TQDate( dtbuf.year, dtbuf.month, dtbuf.day ), TQTime( dtbuf.hour, dtbuf.minute, dtbuf.second, dtbuf.fraction / 1000000 ) ) );
- nullCache[ current ] = FALSE;
- } else {
- fieldCache[ current ] = TQVariant( TQDateTime() );
- nullCache[ current ] = TRUE;
- }
- break;
- case TQVariant::ByteArray: {
- isNull = FALSE;
- TQByteArray val = qGetBinaryData( d->hStmt, current, lengthIndicator, isNull );
- fieldCache[ current ] = TQVariant( val );
- nullCache[ current ] = isNull;
- break; }
- case TQVariant::String:
- isNull = FALSE;
- fieldCache[ current ] = TQVariant( qGetStringData( d->hStmt, current,
- info.length(), isNull, TRUE ) );
- nullCache[ current ] = isNull;
- break;
- case TQVariant::Double:
- if ( info.typeID() == STQL_DECIMAL || info.typeID() == STQL_NUMERIC )
- // bind Double values as string to prevent loss of precision
- fieldCache[ current ] = TQVariant( qGetStringData( d->hStmt, current,
- info.length() + 1, isNull, FALSE ) ); // length + 1 for the comma
- else
- fieldCache[ current ] = TQVariant( qGetDoubleData( d->hStmt, current, isNull ) );
- nullCache[ current ] = isNull;
- break;
- case TQVariant::CString:
- default:
- isNull = FALSE;
- fieldCache[ current ] = TQVariant( qGetStringData( d->hStmt, current,
- info.length(), isNull, FALSE ) );
- nullCache[ current ] = isNull;
- break;
- }
- }
- return fieldCache[ --current ];
-}
-
-bool TQODBCResult::isNull( int field )
-{
- if ( !fieldCache.contains( field ) ) {
- // since there is no good way to find out whether the value is NULL
- // without fetching the field we'll fetch it here.
- // (data() also sets the NULL flag)
- data( field );
- }
- return nullCache[ field ];
-}
-
-int TQODBCResult::size()
-{
- return -1;
-}
-
-int TQODBCResult::numRowsAffected()
-{
- TQSTQLLEN affectedRowCount(0);
- STQLRETURN r = STQLRowCount( d->hStmt, &affectedRowCount );
- if ( r == STQL_SUCCESS )
- return affectedRowCount;
-#ifdef TQT_CHECK_RANGE
- else
- qSqlWarning( "TQODBCResult::numRowsAffected: Unable to count affected rows", d );
-#endif
- return -1;
-}
-
-bool TQODBCResult::prepare( const TQString& query )
-{
- setActive( FALSE );
- setAt( TQSql::BeforeFirst );
- STQLRETURN r;
-
- d->rInf.clear();
- if ( d->hStmt ) {
- r = STQLFreeHandle( STQL_HANDLE_STMT, d->hStmt );
- if ( r != STQL_SUCCESS ) {
-#ifdef TQT_CHECK_RANGE
- qSqlWarning( "TQODBCResult::prepare: Unable to close statement", d );
-#endif
- return FALSE;
- }
- }
- r = STQLAllocHandle( STQL_HANDLE_STMT,
- d->hDbc,
- &d->hStmt );
- if ( r != STQL_SUCCESS ) {
-#ifdef TQT_CHECK_RANGE
- qSqlWarning( "TQODBCResult::prepare: Unable to allocate statement handle", d );
-#endif
- return FALSE;
- }
-
- if ( isForwardOnly() ) {
- r = STQLSetStmtAttr( d->hStmt,
- STQL_ATTR_CURSOR_TYPE,
- (STQLPOINTER)STQL_CURSOR_FORWARD_ONLY,
- STQL_IS_UINTEGER );
- } else {
- r = STQLSetStmtAttr( d->hStmt,
- STQL_ATTR_CURSOR_TYPE,
- (STQLPOINTER)STQL_CURSOR_STATIC,
- STQL_IS_UINTEGER );
- }
- if ( r != STQL_SUCCESS && r != STQL_SUCCESS_WITH_INFO ) {
-#ifdef TQT_CHECK_RANGE
- qSqlWarning( "TQODBCResult::prepare: Unable to set 'STQL_CURSOR_STATIC' as statement attribute. Please check your ODBC driver configuration", d );
-#endif
- return FALSE;
- }
-
-#ifdef UNICODE
- r = STQLPrepare( d->hStmt,
- (STQLWCHAR*) query.tqunicode(),
- (STQLINTEGER) query.length() );
-#else
- TQCString query8 = query.local8Bit();
- r = STQLPrepare( d->hStmt,
- (STQLCHAR*) query8.data(),
- (STQLINTEGER) query8.length() );
-#endif
-
- if ( r != STQL_SUCCESS ) {
-#ifdef TQT_CHECK_RANGE
- qSqlWarning( "TQODBCResult::prepare: Unable to prepare statement", d );
-#endif
- return FALSE;
- }
- return TRUE;
-}
-
-bool TQODBCResult::exec()
-{
- STQLRETURN r;
- TQPtrList<TQVirtualDestructor> tmpStorage; // holds temporary ptrs. which will be deleted on fu exit
- tmpStorage.setAutoDelete( TRUE );
-
- setActive( FALSE );
- setAt( TQSql::BeforeFirst );
- d->rInf.clear();
-
- if ( !d->hStmt ) {
-#ifdef TQT_CHECK_RANGE
- qSqlWarning( "TQODBCResult::exec: No statement handle available", d );
-#endif
- return FALSE;
- } else {
- r = STQLFreeStmt( d->hStmt, STQL_CLOSE );
- if ( r != STQL_SUCCESS ) {
- qSqlWarning( "TQODBCResult::exec: Unable to close statement handle", d );
- return FALSE;
- }
- }
-
- // bind parameters - only positional binding allowed
- if ( extension()->index.count() > 0 ) {
- TQMap<int, TQString>::Iterator it;
- int para = 1;
- TQVariant val;
- for ( it = extension()->index.begin(); it != extension()->index.end(); ++it ) {
- val = extension()->values[ it.data() ].value;
- TQSTQLLEN *ind = new TQSTQLLEN( STQL_NTS );
- tmpStorage.append( qAutoDeleter(ind) );
- if ( val.isNull() ) {
- *ind = STQL_NULL_DATA;
- }
- switch ( val.type() ) {
- case TQVariant::Date: {
- DATE_STRUCT * dt = new DATE_STRUCT;
- tmpStorage.append( qAutoDeleter(dt) );
- TQDate qdt = val.toDate();
- dt->year = qdt.year();
- dt->month = qdt.month();
- dt->day = qdt.day();
- r = STQLBindParameter( d->hStmt,
- para,
- qParamType[ (int)extension()->values[ it.data() ].typ ],
- STQL_C_DATE,
- STQL_DATE,
- 0,
- 0,
- (void *) dt,
- (TQSTQLLEN)0,
- *ind == STQL_NULL_DATA ? ind : NULL );
- break; }
- case TQVariant::Time: {
- TIME_STRUCT * dt = new TIME_STRUCT;
- tmpStorage.append( qAutoDeleter(dt) );
- TQTime qdt = val.toTime();
- dt->hour = qdt.hour();
- dt->minute = qdt.minute();
- dt->second = qdt.second();
- r = STQLBindParameter( d->hStmt,
- para,
- qParamType[ (int)extension()->values[ it.data() ].typ ],
- STQL_C_TIME,
- STQL_TIME,
- 0,
- 0,
- (void *) dt,
- (TQSTQLLEN)0,
- *ind == STQL_NULL_DATA ? ind : NULL );
- break; }
- case TQVariant::DateTime: {
- TIMESTAMP_STRUCT * dt = new TIMESTAMP_STRUCT;
- tmpStorage.append( qAutoDeleter(dt) );
- TQDateTime qdt = val.toDateTime();
- dt->year = qdt.date().year();
- dt->month = qdt.date().month();
- dt->day = qdt.date().day();
- dt->hour = qdt.time().hour();
- dt->minute = qdt.time().minute();
- dt->second = qdt.time().second();
- dt->fraction = 0;
- r = STQLBindParameter( d->hStmt,
- para,
- qParamType[ (int)extension()->values[ it.data() ].typ ],
- STQL_C_TIMESTAMP,
- STQL_TIMESTAMP,
- 0,
- 0,
- (void *) dt,
- (TQSTQLLEN)0,
- *ind == STQL_NULL_DATA ? ind : NULL );
- break; }
- case TQVariant::Int: {
- int * v = new int( val.toInt() );
- tmpStorage.append( qAutoDeleter(v) );
- r = STQLBindParameter( d->hStmt,
- para,
- qParamType[ (int)extension()->values[ it.data() ].typ ],
- STQL_C_SLONG,
- STQL_INTEGER,
- 0,
- 0,
- (void *) v,
- (TQSTQLLEN)0,
- *ind == STQL_NULL_DATA ? ind : NULL );
- break; }
- case TQVariant::Double: {
- double * v = new double( val.toDouble() );
- tmpStorage.append( qAutoDeleter(v) );
- r = STQLBindParameter( d->hStmt,
- para,
- qParamType[ (int)extension()->values[ it.data() ].typ ],
- STQL_C_DOUBLE,
- STQL_DOUBLE,
- 0,
- 0,
- (void *) v,
- (TQSTQLLEN)0,
- *ind == STQL_NULL_DATA ? ind : NULL );
- break; }
- case TQVariant::ByteArray: {
- if ( *ind != STQL_NULL_DATA ) {
- *ind = val.asByteArray().size();
- }
- r = STQLBindParameter( d->hStmt,
- para,
- qParamType[ (int)extension()->values[ it.data() ].typ ],
- STQL_C_BINARY,
- STQL_LONGVARBINARY,
- val.asByteArray().size(),
- 0,
- (void *) val.asByteArray().data(),
- (TQSTQLLEN)val.asByteArray().size(),
- ind );
- break; }
-#ifndef TQ_ODBC_VERSION_2
- case TQVariant::String:
- if ( d->tqunicode ) {
- TQString * str = new TQString( val.asString() );
- str->ucs2();
- int len = str->length()*2;
- tmpStorage.append( qAutoDeleter(str) );
- r = STQLBindParameter( d->hStmt,
- para,
- qParamType[ (int)extension()->values[ it.data() ].typ ],
- STQL_C_WCHAR,
- len > 8000 ? STQL_WLONGVARCHAR : STQL_WVARCHAR,
- len > 8000 ? len : 0,
- 0,
- (void *) str->tqunicode(),
- (TQSTQLLEN) len,
- ind );
- break;
- }
-#endif
- // fall through
- default: {
- TQCString * str = new TQCString( val.asString().local8Bit() );
- tmpStorage.append( qAutoDeleter(str) );
- r = STQLBindParameter( d->hStmt,
- para,
- qParamType[ (int)extension()->values[ it.data() ].typ ],
- STQL_C_CHAR,
- str->length() > 4000 ? STQL_LONGVARCHAR : STQL_VARCHAR,
- str->length() + 1,
- 0,
- (void *) str->data(),
- (TQSTQLLEN)(str->length() + 1),
- ind );
- break; }
- }
- para++;
- if ( r != STQL_SUCCESS ) {
-#ifdef TQT_CHECK_RANGE
- qWarning( "TQODBCResult::exec: unable to bind variable: %s", qODBCWarn( d ).local8Bit().data() );
-#endif
- setLastError( qMakeError( "Unable to bind variable", TQSqlError::Statement, d ) );
- return FALSE;
- }
- }
- }
- r = STQLExecute( d->hStmt );
- if ( r != STQL_SUCCESS && r != STQL_SUCCESS_WITH_INFO ) {
-#ifdef TQT_CHECK_RANGE
- qWarning( "TQODBCResult::exec: Unable to execute statement: %s", qODBCWarn( d ).local8Bit().data() );
-#endif
- setLastError( qMakeError( "Unable to execute statement", TQSqlError::Statement, d ) );
- return FALSE;
- }
- STQLSMALLINT count;
- r = STQLNumResultCols( 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 );
-
- //get out parameters
- if ( extension()->index.count() > 0 ) {
- TQMap<int, TQString>::Iterator it;
- for ( it = extension()->index.begin(); it != extension()->index.end(); ++it ) {
-
- STQLINTEGER* indPtr = qAutoDeleterData( (TQAutoDeleter<STQLINTEGER>*)tmpStorage.getFirst() );
- if ( !indPtr )
- return FALSE;
- bool isNull = (*indPtr == STQL_NULL_DATA);
- tmpStorage.removeFirst();
-
- TQVariant::Type type = extension()->values[ it.data() ].value.type();
- if ( isNull ) {
- TQVariant v;
- v.cast(type);
- extension()->values[ it.data() ].value = v;
- if (type != TQVariant::ByteArray)
- tmpStorage.removeFirst();
- continue;
- }
-
- switch (type) {
- case TQVariant::Date: {
- DATE_STRUCT * ds = qAutoDeleterData( (TQAutoDeleter<DATE_STRUCT>*)tmpStorage.getFirst() );
- extension()->values[ it.data() ].value = TQVariant( TQDate( ds->year, ds->month, ds->day ) );
- break; }
- case TQVariant::Time: {
- TIME_STRUCT * dt = qAutoDeleterData( (TQAutoDeleter<TIME_STRUCT>*)tmpStorage.getFirst() );
- extension()->values[ it.data() ].value = TQVariant( TQTime( dt->hour, dt->minute, dt->second ) );
- break; }
- case TQVariant::DateTime: {
- TIMESTAMP_STRUCT * dt = qAutoDeleterData( (TQAutoDeleter<TIMESTAMP_STRUCT>*)tmpStorage.getFirst() );
- extension()->values[ it.data() ].value = TQVariant( TQDateTime( TQDate( dt->year, dt->month, dt->day ),
- TQTime( dt->hour, dt->minute, dt->second ) ) );
- break; }
- case TQVariant::Int: {
- int * v = qAutoDeleterData( (TQAutoDeleter<int>*)tmpStorage.getFirst() );
- extension()->values[ it.data() ].value = TQVariant( *v );
- break; }
- case TQVariant::Double: {
- double * v = qAutoDeleterData( (TQAutoDeleter<double>*)tmpStorage.getFirst() );
- extension()->values[ it.data() ].value = TQVariant( *v );
- break; }
- case TQVariant::ByteArray:
- break;
- case TQVariant::String:
- if ( d->tqunicode ) {
- TQString * str = qAutoDeleterData( (TQAutoDeleter<TQString>*)tmpStorage.getFirst() );
- extension()->values[ it.data() ].value = TQVariant( *str );
- break;
- }
- // fall through
- default: {
- TQCString * str = qAutoDeleterData( (TQAutoDeleter<TQCString>*)tmpStorage.getFirst() );
- extension()->values[ it.data() ].value = TQVariant( *str );
- break; }
- }
- if (type != TQVariant::ByteArray)
- tmpStorage.removeFirst();
- }
- }
-
- return TRUE;
-}
-
-////////////////////////////////////////
-
-
-TQODBCDriver::TQODBCDriver( TQObject * parent, const char * name )
- : TQSqlDriver(parent,name ? name : "TQODBC")
-{
- init();
-}
-
-TQODBCDriver::TQODBCDriver( STQLHANDLE env, STQLHANDLE con, TQObject * parent, const char * name )
- : TQSqlDriver(parent,name ? name : "TQODBC")
-{
- init();
- d->hEnv = env;
- d->hDbc = con;
- if ( env && con ) {
- setOpen( TRUE );
- setOpenError( FALSE );
- }
-}
-
-void TQODBCDriver::init()
-{
- qSqlOpenExtDict()->insert( this, new TQODBCOpenExtension(this) );
- d = new TQODBCPrivate();
-}
-
-TQODBCDriver::~TQODBCDriver()
-{
- cleanup();
- delete d;
- if ( !qSqlOpenExtDict()->isEmpty() ) {
- TQSqlOpenExtension *ext = qSqlOpenExtDict()->take( this );
- delete ext;
- }
-}
-
-bool TQODBCDriver::hasFeature( DriverFeature f ) const
-{
- switch ( f ) {
- case Transactions: {
- if ( !d->hDbc )
- return FALSE;
- STQLUSMALLINT txn;
- STQLSMALLINT t;
- int r = STQLGetInfo( d->hDbc,
- (STQLUSMALLINT)STQL_TXN_CAPABLE,
- &txn,
- sizeof(txn),
- &t);
- if ( r != STQL_SUCCESS || txn == STQL_TC_NONE )
- return FALSE;
- else
- return TRUE;
- }
- case QuerySize:
- return FALSE;
- case BLOB:
- return TRUE;
- case Unicode:
- return d->tqunicode;
- case PreparedQueries:
- return TRUE;
- case PositionalPlaceholders:
- return TRUE;
- default:
- return FALSE;
- }
-}
-
-bool TQODBCDriver::open( const TQString&,
- const TQString&,
- const TQString&,
- const TQString&,
- int )
-{
- qWarning("TQODBCDriver::open(): This version of open() is no longer supported." );
- return FALSE;
-}
-
-bool TQODBCDriver::open( const TQString & db,
- const TQString & user,
- const TQString & password,
- const TQString &,
- int,
- const TQString& connOpts )
-{
- if ( isOpen() )
- close();
- STQLRETURN r;
- r = STQLAllocHandle( STQL_HANDLE_ENV,
- STQL_NULL_HANDLE,
- &d->hEnv);
- if ( r != STQL_SUCCESS && r != STQL_SUCCESS_WITH_INFO ) {
-#ifdef TQT_CHECK_RANGE
- qSqlWarning( "TQODBCDriver::open: Unable to allocate environment", d );
-#endif
- setOpenError( TRUE );
- return FALSE;
- }
- r = STQLSetEnvAttr( d->hEnv,
- STQL_ATTR_ODBC_VERSION,
- (STQLPOINTER)STQL_OV_ODBC2,
- STQL_IS_UINTEGER );
- r = STQLAllocHandle( STQL_HANDLE_DBC,
- d->hEnv,
- &d->hDbc);
- if ( r != STQL_SUCCESS && r != STQL_SUCCESS_WITH_INFO ) {
-#ifdef TQT_CHECK_RANGE
- qSqlWarning( "TQODBCDriver::open: Unable to allocate connection", d );
-#endif
- setOpenError( TRUE );
- return FALSE;
- }
-
- if ( !d->setConnectionOptions( connOpts ) )
- return FALSE;
-
- // Create the connection string
- TQString connTQStr;
- // support the "DRIVER={SQL SERVER};SERVER=blah" syntax
- if ( db.contains(".dsn") )
- connTQStr = "FILEDSN=" + db;
- else if ( db.contains( "DRIVER" ) || db.contains( "SERVER" ) )
- connTQStr = db;
- else
- connTQStr = "DSN=" + db;
- connTQStr += ";UID=" + user + ";PWD=" + password;
- STQLSMALLINT cb;
- STQLTCHAR connOut[1024];
- r = STQLDriverConnect( d->hDbc,
- NULL,
-#ifdef UNICODE
- (STQLWCHAR*)connTQStr.tqunicode(),
-#else
- (STQLCHAR*)connTQStr.latin1(),
-#endif
- (STQLSMALLINT)connTQStr.length(),
- connOut,
- 1024,
- &cb,
- STQL_DRIVER_NOPROMPT );
- if ( r != STQL_SUCCESS && r != STQL_SUCCESS_WITH_INFO ) {
- setLastError( qMakeError( "Unable to connect", TQSqlError::Connection, d ) );
- setOpenError( TRUE );
- return FALSE;
- }
-
- if ( !d->checkDriver() ) {
- setLastError( qMakeError( "Unable to connect - Driver doesn't support all needed functionality", TQSqlError::Connection, d ) );
- setOpenError( TRUE );
- return FALSE;
- }
-
- d->checkUnicode();
- d->checkSchemaUsage();
-
- setOpen( TRUE );
- setOpenError( FALSE );
- return TRUE;
-}
-
-void TQODBCDriver::close()
-{
- cleanup();
- setOpen( FALSE );
- setOpenError( FALSE );
-}
-
-void TQODBCDriver::cleanup()
-{
- STQLRETURN r;
- if ( !d )
- return;
-
- if( d->hDbc ) {
- // Open statements/descriptors handles are automatically cleaned up by STQLDisconnect
- if ( isOpen() ) {
- r = STQLDisconnect( d->hDbc );
-#ifdef TQT_CHECK_RANGE
- if ( r != STQL_SUCCESS )
- qSqlWarning( "TQODBCDriver::disconnect: Unable to disconnect datasource", d );
-#endif
- }
-
- r = STQLFreeHandle( STQL_HANDLE_DBC, d->hDbc );
-#ifdef TQT_CHECK_RANGE
- if ( r != STQL_SUCCESS )
- qSqlWarning( "TQODBCDriver::cleanup: Unable to free connection handle", d );
-#endif
- d->hDbc = 0;
- }
-
- if ( d->hEnv ) {
- r = STQLFreeHandle( STQL_HANDLE_ENV, d->hEnv );
-#ifdef TQT_CHECK_RANGE
- if ( r != STQL_SUCCESS )
- qSqlWarning( "TQODBCDriver::cleanup: Unable to free environment handle", d );
-#endif
- d->hEnv = 0;
- }
-}
-
-// checks whether the server can return char, varchar and longvarchar
-// as two byte tqunicode characters
-void TQODBCPrivate::checkUnicode()
-{
-#if defined(TQ_WS_WIN)
- if ( !qt_wintqunicode ) {
- tqunicode = FALSE;
- return;
- }
-#endif
- STQLRETURN r;
- STQLUINTEGER fFunc;
-
- tqunicode = FALSE;
- r = STQLGetInfo( hDbc,
- STQL_CONVERT_CHAR,
- (STQLPOINTER)&fFunc,
- sizeof(fFunc),
- NULL );
- if ( ( r == STQL_SUCCESS || r == STQL_SUCCESS_WITH_INFO ) && ( fFunc & STQL_CVT_WCHAR ) ) {
- sql_char_type = TQVariant::String;
- tqunicode = TRUE;
- }
-
- r = STQLGetInfo( hDbc,
- STQL_CONVERT_VARCHAR,
- (STQLPOINTER)&fFunc,
- sizeof(fFunc),
- NULL );
- if ( ( r == STQL_SUCCESS || r == STQL_SUCCESS_WITH_INFO ) && ( fFunc & STQL_CVT_WVARCHAR ) ) {
- sql_varchar_type = TQVariant::String;
- tqunicode = TRUE;
- }
-
- r = STQLGetInfo( hDbc,
- STQL_CONVERT_LONGVARCHAR,
- (STQLPOINTER)&fFunc,
- sizeof(fFunc),
- NULL );
- if ( ( r == STQL_SUCCESS || r == STQL_SUCCESS_WITH_INFO ) && ( fFunc & STQL_CVT_WLONGVARCHAR ) ) {
- sql_longvarchar_type = TQVariant::String;
- tqunicode = TRUE;
- }
-}
-
-bool TQODBCPrivate::checkDriver() const
-{
-#ifdef ODBC_CHECK_DRIVER
- // do not query for STQL_API_STQLFETCHSCROLL because it can't be used at this time
- static const STQLUSMALLINT reqFunc[] = {
- STQL_API_STQLDESCRIBECOL, STQL_API_STQLGETDATA, STQL_API_STQLCOLUMNS,
- STQL_API_STQLGETSTMTATTR, STQL_API_STQLGETDIAGREC, STQL_API_STQLEXECDIRECT,
- STQL_API_STQLGETINFO, STQL_API_STQLTABLES, 0
- };
-
- // these functions are optional
- static const STQLUSMALLINT optFunc[] = {
- STQL_API_STQLNUMRESULTCOLS, STQL_API_STQLROWCOUNT, 0
- };
-
- STQLRETURN r;
- STQLUSMALLINT sup;
-
-
- int i;
- // check the required functions
- for ( i = 0; reqFunc[ i ] != 0; ++i ) {
-
- r = STQLGetFunctions( hDbc, reqFunc[ i ], &sup );
-
-#ifdef TQT_CHECK_RANGE
- if ( r != STQL_SUCCESS ) {
- qSqlWarning( "TQODBCDriver::checkDriver: Cannot get list of supported functions", this );
- return FALSE;
- }
-#endif
- if ( sup == STQL_FALSE ) {
-#ifdef TQT_CHECK_RANGE
- qWarning ( "TQODBCDriver::open: Warning - Driver doesn't support all needed functionality (%d). "
- "Please look at the TQt SQL Module Driver documentation for more information.", reqFunc[ i ] );
-#endif
- return FALSE;
- }
- }
-
- // these functions are optional and just generate a warning
- for ( i = 0; optFunc[ i ] != 0; ++i ) {
-
- r = STQLGetFunctions( hDbc, optFunc[ i ], &sup );
-
-#ifdef TQT_CHECK_RANGE
- if ( r != STQL_SUCCESS ) {
- qSqlWarning( "TQODBCDriver::checkDriver: Cannot get list of supported functions", this );
- return FALSE;
- }
-#endif
- if ( sup == STQL_FALSE ) {
-#ifdef TQT_CHECK_RANGE
- qWarning( "TQODBCDriver::checkDriver: Warning - Driver doesn't support some non-critical functions (%d)", optFunc[ i ] );
-#endif
- return TRUE;
- }
- }
-#endif //ODBC_CHECK_DRIVER
-
- return TRUE;
-}
-
-void TQODBCPrivate::checkSchemaUsage()
-{
- STQLRETURN r;
- STQLUINTEGER val;
-
- r = STQLGetInfo(hDbc,
- STQL_SCHEMA_USAGE,
- (STQLPOINTER) &val,
- sizeof(val),
- NULL);
- if (r == STQL_SUCCESS || r == STQL_SUCCESS_WITH_INFO)
- useSchema = (val != 0);
-}
-
-TQSqlQuery TQODBCDriver::createQuery() const
-{
- return TQSqlQuery( new TQODBCResult( this, d ) );
-}
-
-bool TQODBCDriver::beginTransaction()
-{
- if ( !isOpen() ) {
-#ifdef TQT_CHECK_RANGE
- qWarning(" TQODBCDriver::beginTransaction: Database not open" );
-#endif
- return FALSE;
- }
- STQLUINTEGER ac(STQL_AUTOCOMMIT_OFF);
- STQLRETURN r = STQLSetConnectAttr( d->hDbc,
- STQL_ATTR_AUTOCOMMIT,
- (STQLPOINTER)ac,
- sizeof(ac) );
- if ( r != STQL_SUCCESS ) {
- setLastError( qMakeError( "Unable to disable autocommit", TQSqlError::Transaction, d ) );
- return FALSE;
- }
- return TRUE;
-}
-
-bool TQODBCDriver::commitTransaction()
-{
- if ( !isOpen() ) {
-#ifdef TQT_CHECK_RANGE
- qWarning(" TQODBCDriver::commitTransaction: Database not open" );
-#endif
- return FALSE;
- }
- STQLRETURN r = STQLEndTran( STQL_HANDLE_DBC,
- d->hDbc,
- STQL_COMMIT );
- if ( r != STQL_SUCCESS ) {
- setLastError( qMakeError("Unable to commit transaction", TQSqlError::Transaction, d ) );
- return FALSE;
- }
- return endTrans();
-}
-
-bool TQODBCDriver::rollbackTransaction()
-{
- if ( !isOpen() ) {
-#ifdef TQT_CHECK_RANGE
- qWarning(" TQODBCDriver::rollbackTransaction: Database not open" );
-#endif
- return FALSE;
- }
- STQLRETURN r = STQLEndTran( STQL_HANDLE_DBC,
- d->hDbc,
- STQL_ROLLBACK );
- if ( r != STQL_SUCCESS ) {
- setLastError( qMakeError( "Unable to rollback transaction", TQSqlError::Transaction, d ) );
- return FALSE;
- }
- return endTrans();
-}
-
-bool TQODBCDriver::endTrans()
-{
- STQLUINTEGER ac(STQL_AUTOCOMMIT_ON);
- STQLRETURN r = STQLSetConnectAttr( d->hDbc,
- STQL_ATTR_AUTOCOMMIT,
- (STQLPOINTER)ac,
- sizeof(ac));
- if ( r != STQL_SUCCESS ) {
- setLastError( qMakeError( "Unable to enable autocommit", TQSqlError::Transaction, d ) );
- return FALSE;
- }
- return TRUE;
-}
-
-TQStringList TQODBCDriver::tables( const TQString& typeName ) const
-{
- TQStringList tl;
- if ( !isOpen() )
- return tl;
- int type = typeName.toInt();
- STQLHANDLE hStmt;
-
- STQLRETURN r = STQLAllocHandle( STQL_HANDLE_STMT,
- d->hDbc,
- &hStmt );
- if ( r != STQL_SUCCESS ) {
-#ifdef TQT_CHECK_RANGE
- qSqlWarning( "TQODBCDriver::tables: Unable to allocate handle", d );
-#endif
- return tl;
- }
- r = STQLSetStmtAttr( hStmt,
- STQL_ATTR_CURSOR_TYPE,
- (STQLPOINTER)STQL_CURSOR_FORWARD_ONLY,
- STQL_IS_UINTEGER );
- TQString tableType;
- if ( typeName.isEmpty() || ((type & (int)TQSql::Tables) == (int)TQSql::Tables) )
- tableType += "TABLE,";
- if ( (type & (int)TQSql::Views) == (int)TQSql::Views )
- tableType += "VIEW,";
- if ( (type & (int)TQSql::SystemTables) == (int)TQSql::SystemTables )
- tableType += "SYSTEM TABLE,";
- if ( tableType.isEmpty() )
- return tl;
- tableType.truncate( tableType.length() - 1 );
-
- r = STQLTables( hStmt,
- NULL,
- 0,
- NULL,
- 0,
- NULL,
- 0,
-#ifdef UNICODE
- (STQLWCHAR*)tableType.tqunicode(),
-#else
- (STQLCHAR*)tableType.latin1(),
-#endif
- tableType.length() /* characters, not bytes */ );
-
-#ifdef TQT_CHECK_RANGE
- if ( r != STQL_SUCCESS )
- qSqlWarning( "TQODBCDriver::tables Unable to execute table list", d );
-#endif
- r = STQLFetchScroll( hStmt,
- STQL_FETCH_NEXT,
- 0);
- while ( r == STQL_SUCCESS ) {
- bool isNull;
- TQString fieldVal = qGetStringData( hStmt, 2, -1, isNull, d->tqunicode );
- tl.append( fieldVal );
- r = STQLFetchScroll( hStmt,
- STQL_FETCH_NEXT,
- 0);
- }
-
- r = STQLFreeHandle( STQL_HANDLE_STMT, hStmt );
- if ( r!= STQL_SUCCESS )
- qSqlWarning( "TQODBCDriver: Unable to free statement handle" + TQString::number(r), d );
- return tl;
-}
-
-TQSqlIndex TQODBCDriver::primaryIndex( const TQString& tablename ) const
-{
- TQSqlIndex index( tablename );
- if ( !isOpen() )
- return index;
- bool usingSpecialColumns = FALSE;
- TQSqlRecord rec = record( tablename );
-
- STQLHANDLE hStmt;
- STQLRETURN r = STQLAllocHandle( STQL_HANDLE_STMT,
- d->hDbc,
- &hStmt );
- if ( r != STQL_SUCCESS ) {
-#ifdef TQT_CHECK_RANGE
- qSqlWarning( "TQODBCDriver::primaryIndex: Unable to list primary key", d );
-#endif
- return index;
- }
- TQString catalog, schema, table;
- d->splitTableQualifier( tablename, catalog, schema, table );
- r = STQLSetStmtAttr( hStmt,
- STQL_ATTR_CURSOR_TYPE,
- (STQLPOINTER)STQL_CURSOR_FORWARD_ONLY,
- STQL_IS_UINTEGER );
- r = STQLPrimaryKeys( hStmt,
-#ifdef UNICODE
- catalog.length() == 0 ? NULL : (STQLWCHAR*)catalog.tqunicode(),
-#else
- catalog.length() == 0 ? NULL : (STQLCHAR*)catalog.latin1(),
-#endif
- catalog.length(),
-#ifdef UNICODE
- schema.length() == 0 ? NULL : (STQLWCHAR*)schema.tqunicode(),
-#else
- schema.length() == 0 ? NULL : (STQLCHAR*)schema.latin1(),
-#endif
- schema.length(),
-#ifdef UNICODE
- (STQLWCHAR*)table.tqunicode(),
-#else
- (STQLCHAR*)table.latin1(),
-#endif
- table.length() /* in characters, not in bytes */);
-
- // if the STQLPrimaryKeys() call does not succeed (e.g the driver
- // does not support it) - try an alternative method to get hold of
- // the primary index (e.g MS Access and FoxPro)
- if ( r != STQL_SUCCESS ) {
- r = STQLSpecialColumns( hStmt,
- STQL_BEST_ROWID,
-#ifdef UNICODE
- catalog.length() == 0 ? NULL : (STQLWCHAR*)catalog.tqunicode(),
-#else
- catalog.length() == 0 ? NULL : (STQLCHAR*)catalog.latin1(),
-#endif
- catalog.length(),
-#ifdef UNICODE
- schema.length() == 0 ? NULL : (STQLWCHAR*)schema.tqunicode(),
-#else
- schema.length() == 0 ? NULL : (STQLCHAR*)schema.latin1(),
-#endif
- schema.length(),
-#ifdef UNICODE
- (STQLWCHAR*)table.tqunicode(),
-#else
- (STQLCHAR*)table.latin1(),
-#endif
-
- table.length(),
- STQL_SCOPE_CURROW,
- STQL_NULLABLE );
-
- if ( r != STQL_SUCCESS ) {
-#ifdef TQT_CHECK_RANGE
- qSqlWarning( "TQODBCDriver::primaryIndex: Unable to execute primary key list", d );
-#endif
- } else {
- usingSpecialColumns = TRUE;
- }
- }
- r = STQLFetchScroll( hStmt,
- STQL_FETCH_NEXT,
- 0 );
- bool isNull;
- int fakeId = 0;
- TQString cName, idxName;
- // Store all fields in a StringList because some drivers can't detail fields in this FETCH loop
- while ( r == STQL_SUCCESS ) {
- if ( usingSpecialColumns ) {
- cName = qGetStringData( hStmt, 1, -1, isNull, d->tqunicode ); // column name
- idxName = TQString::number( fakeId++ ); // invent a fake index name
- } else {
- cName = qGetStringData( hStmt, 3, -1, isNull, d->tqunicode ); // column name
- idxName = qGetStringData( hStmt, 5, -1, isNull, d->tqunicode ); // pk index name
- }
- TQSqlField *fld = rec.field(cName);
- if (fld)
- index.append(*fld);
- index.setName( idxName );
- r = STQLFetchScroll( hStmt,
- STQL_FETCH_NEXT,
- 0 );
- }
- r = STQLFreeHandle( STQL_HANDLE_STMT, hStmt );
- if ( r!= STQL_SUCCESS )
- qSqlWarning( "TQODBCDriver: Unable to free statement handle" + TQString::number(r), d );
- return index;
-}
-
-TQSqlRecord TQODBCDriver::record( const TQString& tablename ) const
-{
- return recordInfo( tablename ).toRecord();
-}
-
-TQSqlRecord TQODBCDriver::record( const TQSqlQuery& query ) const
-{
- return recordInfo( query ).toRecord();
-}
-
-TQSqlRecordInfo TQODBCDriver::recordInfo( const TQString& tablename ) const
-{
- TQSqlRecordInfo fil;
- if ( !isOpen() )
- return fil;
-
- STQLHANDLE hStmt;
- TQString catalog, schema, table;
- d->splitTableQualifier( tablename, catalog, schema, table );
- STQLRETURN r = STQLAllocHandle( STQL_HANDLE_STMT,
- d->hDbc,
- &hStmt );
- if ( r != STQL_SUCCESS ) {
-#ifdef TQT_CHECK_RANGE
- qSqlWarning( "TQODBCDriver::record: Unable to allocate handle", d );
-#endif
- return fil;
- }
- r = STQLSetStmtAttr( hStmt,
- STQL_ATTR_CURSOR_TYPE,
- (STQLPOINTER)STQL_CURSOR_FORWARD_ONLY,
- STQL_IS_UINTEGER );
- r = STQLColumns( hStmt,
-#ifdef UNICODE
- catalog.length() == 0 ? NULL : (STQLWCHAR*)catalog.tqunicode(),
-#else
- catalog.length() == 0 ? NULL : (STQLCHAR*)catalog.latin1(),
-#endif
- catalog.length(),
-#ifdef UNICODE
- schema.length() == 0 ? NULL : (STQLWCHAR*)schema.tqunicode(),
-#else
- schema.length() == 0 ? NULL : (STQLCHAR*)schema.latin1(),
-#endif
- schema.length(),
-#ifdef UNICODE
- (STQLWCHAR*)table.tqunicode(),
-#else
- (STQLCHAR*)table.latin1(),
-#endif
- table.length(),
- NULL,
- 0 );
-#ifdef TQT_CHECK_RANGE
- if ( r != STQL_SUCCESS )
- qSqlWarning( "TQODBCDriver::record: Unable to execute column list", d );
-#endif
- r = STQLFetchScroll( hStmt,
- STQL_FETCH_NEXT,
- 0);
- // Store all fields in a StringList because some drivers can't detail fields in this FETCH loop
- while ( r == STQL_SUCCESS ) {
-
- fil.append( qMakeFieldInfo( hStmt, d ) );
-
- r = STQLFetchScroll( hStmt,
- STQL_FETCH_NEXT,
- 0);
- }
-
- r = STQLFreeHandle( STQL_HANDLE_STMT, hStmt );
- if ( r!= STQL_SUCCESS )
- qSqlWarning( "TQODBCDriver: Unable to free statement handle " + TQString::number(r), d );
-
- return fil;
-}
-
-TQSqlRecordInfo TQODBCDriver::recordInfo( const TQSqlQuery& query ) const
-{
- TQSqlRecordInfo fil;
- if ( !isOpen() )
- return fil;
- if ( query.isActive() && query.driver() == this ) {
- TQODBCResult* result = (TQODBCResult*)query.result();
- fil = result->d->rInf;
- }
- return fil;
-}
-
-STQLHANDLE TQODBCDriver::environment()
-{
- return d->hEnv;
-}
-
-STQLHANDLE TQODBCDriver::connection()
-{
- return d->hDbc;
-}
-
-TQString TQODBCDriver::formatValue( const TQSqlField* field,
- bool trimStrings ) const
-{
- TQString r;
- if ( field->isNull() ) {
- r = nullText();
- } else if ( field->type() == TQVariant::DateTime ) {
- // Use an escape sequence for the datetime fields
- if ( field->value().toDateTime().isValid() ){
- TQDate dt = field->value().toDateTime().date();
- TQTime tm = field->value().toDateTime().time();
- // Dateformat has to be "yyyy-MM-dd hh:mm:ss", with leading zeroes if month or day < 10
- r = "{ ts '" +
- TQString::number(dt.year()) + "-" +
- TQString::number(dt.month()).rightJustify( 2, '0', TRUE ) + "-" +
- TQString::number(dt.day()).rightJustify( 2, '0', TRUE ) + " " +
- tm.toString() +
- "' }";
- } else
- r = nullText();
- } else if ( field->type() == TQVariant::ByteArray ) {
- TQByteArray ba = field->value().toByteArray();
- TQString res;
- static const char hexchars[] = "0123456789abcdef";
- for ( uint i = 0; i < ba.size(); ++i ) {
- uchar s = (uchar) ba[(int)i];
- res += hexchars[s >> 4];
- res += hexchars[s & 0x0f];
- }
- r = "0x" + res;
- } else {
- r = TQSqlDriver::formatValue( field, trimStrings );
- }
- return r;
-}