List:Commits« Previous MessageNext Message »
From:jbalint Date:March 19 2007 6:50pm
Subject:Connector/ODBC 5 commit: r817 - trunk/SDK/MYSQLPlus/Library
View as plain text  
Modified:
   trunk/SDK/MYSQLPlus/Library/MDataConvert.cpp
   trunk/SDK/MYSQLPlus/Library/MDataConvert.h
   trunk/SDK/MYSQLPlus/Library/MResult.h
   trunk/SDK/MYSQLPlus/Library/MResult_data_toC.cpp
   trunk/SDK/MYSQLPlus/Library/MStatement.cpp
Log:
re-arranged and cleaned up data conversions for "toC"

Modified: trunk/SDK/MYSQLPlus/Library/MDataConvert.cpp
===================================================================
--- trunk/SDK/MYSQLPlus/Library/MDataConvert.cpp	2007-03-16 03:23:33 UTC (rev 816)
+++ trunk/SDK/MYSQLPlus/Library/MDataConvert.cpp	2007-03-19 17:50:12 UTC (rev 817)
@@ -212,12 +212,10 @@
 }
 
 /*!
-    \brief Map an ODBC type constant to a QVariant::Type value.
+    \brief Map an ODBC SQL type constant to a QVariant::Type value.
 */
 QVariant::Type MDataConvert::qtypeForSqlType(SQLSMALLINT type)
 {
-    QVariant::Type t = QVariant::Invalid;
-
     switch ( type )
     {
         case SQL_CHAR:
@@ -226,46 +224,37 @@
         case SQL_WCHAR:
         case SQL_WVARCHAR:
         case SQL_WLONGVARCHAR:
-            t = QVariant::String;
-            break;
+            return QVariant::String;
         case SQL_BINARY:
         case SQL_VARBINARY:
         case SQL_LONGVARBINARY:
-            t = QVariant::ByteArray;
-            break;
+            return QVariant::ByteArray;
         case SQL_DECIMAL:
         case SQL_NUMERIC:
         case SQL_REAL:
         case SQL_FLOAT:
         case SQL_DOUBLE:
-            t = QVariant::Double;
-            break;
+            return QVariant::Double;
         case SQL_TINYINT:
         case SQL_SMALLINT:
         case SQL_INTEGER:
-            t = QVariant::Int;
-            break;
+            return QVariant::Int;
         case SQL_BIGINT:
-            t = QVariant::LongLong;
-            break;
+            return QVariant::LongLong;
         case SQL_BIT:
-            t = QVariant::Int;
-            break;
+            return QVariant::Int;
         case SQL_TYPE_DATE:
         case SQL_DATE:
-            t = QVariant::Date;
-            break;
+            return QVariant::Date;
         case SQL_TYPE_TIME:
         case SQL_TIME:
-            t = QVariant::Time;
-            break;
+            return QVariant::Time;
         case SQL_TYPE_TIMESTAMP:
         case SQL_TIMESTAMP:
-            t = QVariant::DateTime;
-            break;
+            return QVariant::DateTime;
     }
 
-    return t;
+    return QVariant::Invalid;
 }
 
 /*!
@@ -329,3 +318,205 @@
     return 0;
 }
 
+/*!
+    \brief Map an ODBC C type constant to a QVariant::Type value.
+*/
+QVariant::Type MDataConvert::qtypeForCType(SQLSMALLINT type)
+{
+    switch ( type )
+    {
+        case SQL_C_CHAR:
+        case SQL_C_BINARY:
+            return QVariant::ByteArray;
+        case SQL_C_WCHAR:
+            return QVariant::String;
+        /* TODO unsigned separately */
+        case SQL_C_TINYINT:
+        case SQL_C_STINYINT:
+        case SQL_C_UTINYINT:
+        case SQL_C_SHORT:
+        case SQL_C_SSHORT:
+        case SQL_C_USHORT:
+        case SQL_C_LONG:
+        case SQL_C_SLONG:
+        case SQL_C_ULONG:
+        case SQL_C_BIT:
+            return QVariant::Int;
+        case SQL_C_SBIGINT:
+        case SQL_C_UBIGINT:
+            return QVariant::LongLong;
+        case SQL_C_NUMERIC:
+        case SQL_C_FLOAT:
+        case SQL_C_DOUBLE:
+            return QVariant::Double;
+        case SQL_C_GUID:
+        case SQL_C_TYPE_DATE:
+        case SQL_C_DATE:
+            return QVariant::Date;
+        case SQL_C_TYPE_TIME:
+        case SQL_C_TIME:
+            return QVariant::Time;
+        case SQL_C_TYPE_TIMESTAMP:
+        case SQL_C_TIMESTAMP:
+            return QVariant::DateTime;
+        /* TODO int? */
+        case SQL_C_INTERVAL_MONTH:
+        case SQL_C_INTERVAL_YEAR:
+        case SQL_C_INTERVAL_YEAR_TO_MONTH:
+        case SQL_C_INTERVAL_DAY:
+        case SQL_C_INTERVAL_HOUR:
+        case SQL_C_INTERVAL_MINUTE:
+        case SQL_C_INTERVAL_SECOND:
+        case SQL_C_INTERVAL_DAY_TO_HOUR:
+        case SQL_C_INTERVAL_DAY_TO_MINUTE:
+        case SQL_C_INTERVAL_DAY_TO_SECOND:
+        case SQL_C_INTERVAL_HOUR_TO_MINUTE:
+        case SQL_C_INTERVAL_HOUR_TO_SECOND:
+        case SQL_C_INTERVAL_MINUTE_TO_SECOND:
+            break;
+    }
+
+    return QVariant::Invalid;
+}
+
+/*!
+    \brief Check if a given C type is an integer type.
+*/
+int MDataConvert::isIntegerCType(SQLSMALLINT type)
+{
+    switch(type)
+    {
+        case SQL_C_TINYINT:
+        case SQL_C_STINYINT:
+        case SQL_C_UTINYINT:
+        case SQL_C_SHORT:
+        case SQL_C_SSHORT:
+        case SQL_C_USHORT:
+        case SQL_C_LONG:
+        case SQL_C_SLONG:
+        case SQL_C_ULONG:
+        case SQL_C_SBIGINT:
+        case SQL_C_UBIGINT:
+        case SQL_C_BIT:
+            return 1;
+    }
+
+    return 0;
+}
+
+/*!
+    \brief Check if a given C type is an var-len / long type.
+*/
+int MDataConvert::isVarLengthCType(SQLSMALLINT type)
+{
+    switch(type)
+    {
+        case SQL_C_CHAR:
+        case SQL_C_WCHAR:
+        case SQL_C_BINARY:
+            return 1;
+    }
+
+    return 0;
+}
+
+/*!
+    \brief Return the size of a fixed-length C type.
+*/
+int MDataConvert::fixedLengthForCType(SQLSMALLINT type)
+{
+    switch(type)
+    {
+        case SQL_C_BIT:
+        case SQL_C_TINYINT:
+        case SQL_C_STINYINT:
+        case SQL_C_UTINYINT:
+            return sizeof(SQLCHAR);
+        case SQL_C_SHORT:
+        case SQL_C_SSHORT:
+        case SQL_C_USHORT:
+            return sizeof(SQLSMALLINT);
+        case SQL_C_LONG:
+        case SQL_C_SLONG:
+        case SQL_C_ULONG:
+            return sizeof(SQLINTEGER);
+        case SQL_C_FLOAT:
+            return sizeof(SQLREAL);
+        case SQL_C_DOUBLE:
+            return sizeof(SQLFLOAT);
+        case SQL_C_SBIGINT:
+        case SQL_C_UBIGINT:
+            return sizeof(SQLBIGINT);
+        case SQL_C_NUMERIC:
+            return sizeof(SQL_NUMERIC_STRUCT);
+        case SQL_C_GUID:
+            return sizeof(SQLGUID);
+        case SQL_C_TYPE_DATE:
+        case SQL_C_DATE:
+            return sizeof(SQL_DATE_STRUCT);
+        case SQL_C_TYPE_TIME:
+        case SQL_C_TIME:
+            return sizeof(SQL_TIME_STRUCT);
+        case SQL_C_TYPE_TIMESTAMP:
+        case SQL_C_TIMESTAMP:
+            return sizeof(SQL_TIMESTAMP_STRUCT);
+        case SQL_C_INTERVAL_MONTH:
+        case SQL_C_INTERVAL_YEAR:
+        case SQL_C_INTERVAL_YEAR_TO_MONTH:
+        case SQL_C_INTERVAL_DAY:
+        case SQL_C_INTERVAL_HOUR:
+        case SQL_C_INTERVAL_MINUTE:
+        case SQL_C_INTERVAL_SECOND:
+        case SQL_C_INTERVAL_DAY_TO_HOUR:
+        case SQL_C_INTERVAL_DAY_TO_MINUTE:
+        case SQL_C_INTERVAL_DAY_TO_SECOND:
+        case SQL_C_INTERVAL_HOUR_TO_MINUTE:
+        case SQL_C_INTERVAL_HOUR_TO_SECOND:
+        case SQL_C_INTERVAL_MINUTE_TO_SECOND:
+            return sizeof(SQL_INTERVAL_STRUCT);
+    }
+
+    return 0;
+}
+
+/*!
+    \brief Check the given integer value is the range for it's C type.
+*/
+int MDataConvert::isInRange(SQLSMALLINT type, QVariant v)
+{
+    SQLINTEGER i = v.toInt();
+    SQLUINTEGER ui = v.toUInt();
+
+    switch(type)
+    {
+        case SQL_C_TINYINT:
+        case SQL_C_STINYINT:
+            return (i >= SCHAR_MIN) && (i <= SCHAR_MAX);
+        case SQL_C_UTINYINT:
+        case SQL_C_BIT:
+            return ui <= UCHAR_MAX;
+        case SQL_C_SHORT:
+        case SQL_C_SSHORT:
+            return (i >= SHRT_MIN) && (i <= SHRT_MAX);
+        case SQL_C_USHORT:
+            return ui <= USHRT_MAX;
+        case SQL_C_LONG:
+        case SQL_C_SLONG:
+            return (i >= INT_MIN) && (i <= INT_MAX);
+        case SQL_C_ULONG:
+            return ui <= UINT_MAX;
+        case SQL_C_SBIGINT:
+        {
+            qlonglong l = v.toLongLong();
+            return (l >= LLONG_MIN) && (l <= LLONG_MAX);
+        }
+        case SQL_C_UBIGINT:
+        {
+            qulonglong ul = v.toULongLong();
+            return ul <= ULLONG_MAX;
+        }
+    }
+
+    return 0;
+}
+

Modified: trunk/SDK/MYSQLPlus/Library/MDataConvert.h
===================================================================
--- trunk/SDK/MYSQLPlus/Library/MDataConvert.h	2007-03-16 03:23:33 UTC (rev 816)
+++ trunk/SDK/MYSQLPlus/Library/MDataConvert.h	2007-03-19 17:50:12 UTC (rev 817)
@@ -2,15 +2,23 @@
 #define MDATACONVERT_H
 
 #include "MInternal.h"
+#include <limits.h>
 
 class MDataConvert {
 public:
 
+    /* to-SQL related */
     static int cToQVariant(SQLSMALLINT type, SQLPOINTER data,
             SQLINTEGER len, QVariant &v);
     static QVariant::Type qtypeForSqlType(SQLSMALLINT type);
     static int qvariantToSql(SQLSMALLINT type, QVariant &v); 
 
+    /* to-C related */
+    static QVariant::Type qtypeForCType(SQLSMALLINT type);
+    static int isIntegerCType(SQLSMALLINT type);
+    static int isVarLengthCType(SQLSMALLINT type);
+    static int fixedLengthForCType(SQLSMALLINT type);
+    static int isInRange(SQLSMALLINT type, QVariant v);
 };
 
 #endif /* MDATACONVERT_H */

Modified: trunk/SDK/MYSQLPlus/Library/MResult.h
===================================================================
--- trunk/SDK/MYSQLPlus/Library/MResult.h	2007-03-16 03:23:33 UTC (rev 816)
+++ trunk/SDK/MYSQLPlus/Library/MResult.h	2007-03-19 17:50:12 UTC (rev 817)
@@ -49,6 +49,7 @@
     MDescriptorRecordIRD *  pImpRowDescRec;         /*!< descriptor describing the
resultset column                         */
     MDescriptorRecordARD *  pAppRowDescRec;         /*!< set if nTargetType ==
SQL_ARD_TYPE - otherwise this is null        */
     SQLINTEGER              nBytesRemaining;        /*!< bytes or chars remaining in
cell (possibly at end of last getData) */
+    SQLUINTEGER pos; /*!< position into data of current field */
 
     /* we use these to avoid repeatedly converting data during chunking (optimize this -
particularly when we are chunking over the wire) */
     QString                 stringData;
@@ -553,79 +554,6 @@
     /*@}*/
 
     /*!
-        \name   from*SQL
-
-        These are used to convert/copy data into an initialized MStateGetData. These
methods also enforce ODBC rules 
-        generalized based upon SQL type - hence fewer methods than SQL types.
-
-        \sa 
-
-        "Converting Data from SQL to C Data Types"
http://msdn.microsoft.com/library/en-us/odbc/htm/odbcconverting_data_from_sql_to_c_data_types.asp
-    */
-    /*@{*/
-    SQLRETURN       fromCharacterSQL( MStateGetData *pResultGetData );
-    SQLRETURN       fromNumericSQL( MStateGetData *pResultGetData );
-    SQLRETURN       fromBitSQL( MStateGetData *pResultGetData );
-    SQLRETURN       fromBinarySQL( MStateGetData *pResultGetData );
-    SQLRETURN       fromDateSQL( MStateGetData *pResultGetData );
-    SQLRETURN       fromGuidSQL( MStateGetData *pResultGetData );
-    SQLRETURN       fromTimeSQL( MStateGetData *pResultGetData );
-    SQLRETURN       fromTimeStampSQL( MStateGetData *pResultGetData );
-    SQLRETURN       fromIntervalYearMonthSQL( MStateGetData *pResultGetData );
-    SQLRETURN       fromIntervalDayTimeSQL( MStateGetData *pResultGetData );
-    /*@}*/
-
-    /*!
-        \name   to*C
-
-        These correspond to the "C type identifier" column in the "C Data Types" table.
These are 
-        used to support from*SQL methods.
-
-        We are using a 'hub' and 'spoke' data conversion method. The Variant cell value
is our data 
-        conversion 'hub' - these are our outgoing 'spokes'.
-
-        \sa
-        
-        "C Data Types"
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/odbc/htm/odbcc_data_types.asp
-    */
-    /*@{*/
-    SQLRETURN       toCharC( MStateGetData  *pResultGetData );                        
/*!< SQL_C_CHAR 	        SQLCHAR * 	            unsigned char *     */
-    SQLRETURN       toWCharC( MStateGetData  *pResultGetData );                       
/*!< SQL_C_WCHAR 	        SQLWCHAR * 	            wchar_t *           */
-    SQLRETURN       toSShortC( MStateGetData  *pResultGetData );                      
/*!< SQL_C_SSHORT 	        SQLSMALLINT 	        short int           */
-    SQLRETURN       toUShortC( MStateGetData  *pResultGetData );                      
/*!< SQL_C_USHORT 	        SQLUSMALLINT 	        unsigned short int  */
-    SQLRETURN       toSLongC( MStateGetData  *pResultGetData );                       
/*!< SQL_C_SLONG 	        SQLINTEGER 	            long int            */
-    SQLRETURN       toULongC( MStateGetData  *pResultGetData );                       
/*!< SQL_C_ULONG 	        SQLUINTEGER	            unsigned long int   */
-    SQLRETURN       toFloatC( MStateGetData  *pResultGetData );                       
/*!< SQL_C_FLOAT 	        SQLREAL 	            float               */
-    SQLRETURN       toDoubleC( MStateGetData  *pResultGetData );                      
/*!< SQL_C_DOUBLE 	        SQLDOUBLE,SQLFLOAT      double              */
-    SQLRETURN       toBitC( MStateGetData  *pResultGetData );                         
/*!< SQL_C_BIT 	            SQLCHAR 	            unsigned char       */
-    SQLRETURN       toSTinyIntC( MStateGetData  *pResultGetData );                    
/*!< SQL_C_STINYINT	        SQLSCHAR 	            signed char         */
-    SQLRETURN       toUTinyIntC( MStateGetData  *pResultGetData );                    
/*!< SQL_C_UTINYINT	        SQLCHAR 	            unsigned char       */
-    SQLRETURN       toSBigIntC( MStateGetData  *pResultGetData );                     
/*!< SQL_C_SBIGINT 	        SQLBIGINT 	            _int64              */
-    SQLRETURN       toUBigIntC( MStateGetData  *pResultGetData );                     
/*!< SQL_C_UBIGINT 	        SQLUBIGINT 	            unsigned _int64     */
-    SQLRETURN       toBinaryC( MStateGetData  *pResultGetData );                      
/*!< SQL_C_BINARY 	        SQLCHAR * 	            unsigned char *     */
-    SQLRETURN       toVarBookmarkC( MStateGetData  *pResultGetData );                 
/*!< SQL_C_VARBOOKMARK 	    SQLCHAR * 	            unsigned char *     */
-    SQLRETURN       toTypeDateC( MStateGetData  *pResultGetData );                    
/*!< SQL_C_TYPE_DATE 	    SQL_DATE_STRUCT         DATE_STRUCT         */
-    SQLRETURN       toTypeTimeC( MStateGetData  *pResultGetData );                    
/*!< SQL_C_TYPE_TIME 	    SQL_TIME_STRUCT         TIME_STRUCT         */
-    SQLRETURN       toTypeTimestampC( MStateGetData  *pResultGetData );               
/*!< SQL_C_TYPE_TIMESTAMP 	SQL_TIMESTAMP_STRUCT    TIMESTAMP_STRUCT    */
-    SQLRETURN       toNumericC( MStateGetData  *pResultGetData );                     
/*!< SQL_C_NUMERIC 	        SQL_NUMERIC_STRUCT      SQL_NUMERIC_STRUCT  */
-    SQLRETURN       toGuidC( MStateGetData  *pResultGetData );                        
/*!< SQL_C_GUID 	        SQLGUID                 SQLGUID             */
-    SQLRETURN       toIntervalMonthC( MStateGetData  *pResultGetData );               
/*!< interval type          SQL_INTERVAL_STRUCT     SQL_INTERVAL_STRUCT */
-    SQLRETURN       toIntervalYearC( MStateGetData  *pResultGetData );
-    SQLRETURN       toIntervalYearToMonthC( MStateGetData  *pResultGetData );
-    SQLRETURN       toIntervalDayC( MStateGetData  *pResultGetData );
-    SQLRETURN       toIntervalHourC( MStateGetData  *pResultGetData );
-    SQLRETURN       toIntervalMinuteC( MStateGetData  *pResultGetData );
-    SQLRETURN       toIntervalSecondC( MStateGetData  *pResultGetData );
-    SQLRETURN       toIntervalDayToHourC( MStateGetData  *pResultGetData );
-    SQLRETURN       toIntervalDayToMinuteC( MStateGetData  *pResultGetData );
-    SQLRETURN       toIntervalDayToSecondC( MStateGetData  *pResultGetData );
-    SQLRETURN       toIntervalHourToMinuteC( MStateGetData  *pResultGetData );
-    SQLRETURN       toIntervalHourToSecondC( MStateGetData  *pResultGetData );
-    SQLRETURN       toIntervalMinuteToSecondC( MStateGetData  *pResultGetData );
-    /*@}*/
-
-
-    /*!
         \name   fromC
 
         Convert/copy data into an initialized MStatePutData.

Modified: trunk/SDK/MYSQLPlus/Library/MResult_data_toC.cpp
===================================================================
--- trunk/SDK/MYSQLPlus/Library/MResult_data_toC.cpp	2007-03-16 03:23:33 UTC (rev 816)
+++ trunk/SDK/MYSQLPlus/Library/MResult_data_toC.cpp	2007-03-19 17:50:12 UTC (rev 817)
@@ -6,6 +6,8 @@
 
 #include "MInternal.h"
 
+#include "MDataConvert.h"
+
 MStateGetData::MStateGetData()
 {
     MYODBCDbgEnter();
@@ -38,6 +40,7 @@
     pImpRowDescRec          = NULL;
     pAppRowDescRec          = NULL;
     nBytesRemaining         = 0;
+    pos = 0;
 
     stringData.clear();
     bytearrayData.clear();
@@ -49,7 +52,7 @@
 {
     MYODBCDbgEnter();
 
-    if ( this->nRow == nRow && this->nColumn == nColumn && bInUse )

+    if ( this->nRow == nRow && this->nColumn == nColumn && bInUse )
     {
         MYODBCDbgReturn3( "%d", true );
     }
@@ -99,9 +102,9 @@
     /*!
         \internal ODBC RULE (DM)
 
-        The argument TargetType was neither a valid data type, SQL_C_DEFAULT, nor
SQL_ARD_TYPE. 
-    */ 
-    if ( !MYODBCC::isConciseTypeC( nTargetType, getEnvironment()->getODBCVersion() )
&& 
+        The argument TargetType was neither a valid data type, SQL_C_DEFAULT, nor
SQL_ARD_TYPE.
+    */
+    if ( !MYODBCC::isConciseTypeC( nTargetType, getEnvironment()->getODBCVersion() )
&&
          nTargetType != SQL_C_DEFAULT &&
          nTargetType != SQL_ARD_TYPE )
     {
@@ -117,1966 +120,503 @@
 /*!
     \brief  Get column data from ResultSet/RowSet.
 
-            This supports the getData() which operates on RowSetRow AND doRefresh()
(bound array or single row). 
+            This supports the getData() which operates on RowSetRow AND doRefresh()
(bound array or single row).
 
     \param  nRowsIndex      Index into vectorRows. 0-based.
     \param  nColumn         Index into vectorRows[nRow]. 1-based.
     \param  nTargetType
     \param  pTarget
     \param  nBufferLength
-    \param  pnLength        ODBC RULE: "For data being retrieved from the data source,
this is the byte length of the data 
+    \param  pnLength        ODBC RULE: "For data being retrieved from the data source,
this is the byte length of the data
                             after conversion to the data buffer's type and before any
truncation is done."
 
-                            ODBC RULE: "If the byte length of the data is greater than
the byte length of the buffer, the driver truncates 
-                            fetched data to the byte length of the buffer and returns
SQL_SUCCESS_WITH_INFO with SQLSTATE 01004 
+                            ODBC RULE: "If the byte length of the data is greater than
the byte length of the buffer, the driver truncates
+                            fetched data to the byte length of the buffer and returns
SQL_SUCCESS_WITH_INFO with SQLSTATE 01004
                             (Data truncated). However, the returned byte length is the
length of the untruncated data."
-    \param  pnIndicator     
+    \param  pnIndicator
 
 */
 SQLRETURN MResult::getData( SQLUINTEGER nRowsIndex, SQLUSMALLINT nColumn, SQLSMALLINT
nTargetType, SQLPOINTER pTarget, SQLINTEGER nBufferLength, SQLINTEGER *pnLength,
SQLINTEGER *pnIndicator )
 {
     MYODBCDbgEnter();
 
-    SQLRETURN nReturn = SQL_SUCCESS;
+    /* defaults for SQL_NUMERIC_STRUCT */
+    SQLCHAR precision = 10;
+    SQLCHAR scale = 0;
 
-    /*!
-        \internal
-        \todo
+    QVariant val = vectorRows[nRowsIndex][nColumn - 1];
+    MDescriptorRecordIRD *pImpRowDescRec =
+        (MDescriptorRecordIRD*)getImpRowDesc()->getRecord( nColumn );
 
-        Account for SQL_ATTR_MAX_LENGTH/getMaxLength() (limits the amount of data to be
found in a column - for optimization - limits
-        the amount of data pulled from server).
-
-        \note
-
-        The SQL_ATTR_MAX_LENGTH statement attribute is intended to reduce network
traffic. It is generally implemented by the data source, 
-        which truncates the data before returning it across the network. Drivers and data
sources are not required to support it. Therefore, 
-        to guarantee that data is truncated to a particular size, an application should
allocate a buffer of that size and specify the size 
-        in the BufferLength argument.
-    */
-
-    /*!
-        \internal ODBC RULE (implied)
-
-        We are chunking data when we get the same row & column being used for more
than 1 successive call
-        to here.
-    */
-    if ( stateGetData.isChunkingRequest( nRowsIndex, nColumn ) )
-    {
-        if ( MDescriptorRecordIRD::isVariableLength(
stateGetData.pImpRowDescRec->getConciseType() ) )
-        {
-            if ( vectorRows[stateGetData.nRow][stateGetData.nColumn - 1].isNull() )
-                MYODBCDbgReturn( SQL_NO_DATA );
-
-            /* reset var-len data for next read if previous read is complete */
-            /* TODO enable this as a data-source option?
-             * It causes ADO problems, and fixes others,
-             * see bug#26213 and bug#26164 */
-            /*
-            if ( stateGetData.nBytesRemaining == 0 )
-            {
-                stateGetData.stringData.clear();
-                stateGetData.bytearrayData.clear();
-            }
-            */
-            if ( stateGetData.nBytesRemaining == 0 )
-            {
-                MYODBCDbgReturn( SQL_NO_DATA );
-            }
-
-            /*!
-                \internal
-                \note
-
-                We assume that nTargetType has not changed!!! In this way we *avoid*
having to convert
-                data & recalc length after the first call.
-            */
-            stateGetData.pTarget       = pTarget;
-            stateGetData.nBytesMax     = nBufferLength;
-            stateGetData.pnLength      = pnLength;
-            stateGetData.pnIndicator   = pnIndicator;
-        }
-        else
-        {
-            /*!
-                \internal ODBC RULE
-
-                If SQLGetData is called more than one time in a row for a column
containing 
-                fixed-length data, it returns SQL_NO_DATA for all calls after the first.
-            */
-            MYODBCDbgReturn( SQL_NO_DATA );
-        }
-    }
-    else
-    {
-        /* init our get data state (beyond doClear()) */
-        stateGetData.doClear();
-        stateGetData.bInUse                = true;
-        stateGetData.nBytesMax             = nBufferLength;
-        stateGetData.nColumn               = nColumn;
-        stateGetData.nTargetType           = nTargetType;
-        stateGetData.nTargetTypeAdjusted   = nTargetType;
-        stateGetData.pImpRowDescRec        =
(MDescriptorRecordIRD*)getImpRowDesc()->getRecord( nColumn );
-        stateGetData.pnLength              = pnLength;
-        stateGetData.pnIndicator           = pnIndicator;
-        stateGetData.pTarget               = pTarget;
-        stateGetData.nRow                  = nRowsIndex;
-        MYODBCCSet( stateGetData.pnIndicator, stateGetData.nIndicator );
-
-        /* get indicator value; no need to process further if we are null */
-        if ( vectorRows[stateGetData.nRow][stateGetData.nColumn - 1].isNull() )
-        {
-            stateGetData.nIndicator = SQL_NULL_DATA;
-
-            MYODBCCSet( stateGetData.pnLength, 0 );
-
-            if ( stateGetData.pnIndicator ) 
-            {
-                MYODBCCSet( stateGetData.pnIndicator, stateGetData.nIndicator );
-                MYODBCDbgReturn( SQL_SUCCESS );
-            }
-            else
-                MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_22002 )
);
-        }
-
-        /*!
-            \internal
-            \note
-
-            Have we been told to use ARD (bound column) info? Most common reason for this
is to adjust 
-            precision and scale for SQL_C_NUMERIC 
-        */
-        if ( nTargetType == SQL_ARD_TYPE )
-        {
-            /*!
-                \internal ODBC RULE
-
-                The TargetType argument was SQL_ARD_TYPE, and the value in the
SQL_DESC_COUNT 
-                field of the ARD was less than the ColumnNumber argument.
-            */
-            if ( nColumn > getAppRowDesc()->getCount() )
-                MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_07009A
) );
-
-            /*!
-                \internal ODBC RULE
-
-                If TargetType is SQL_ARD_TYPE, the driver uses the type identifier
specified in the 
-                SQL_DESC_CONCISE_TYPE field of the ARD.
-
-                The precision and scale fields of the SQL_C_NUMERIC data type are never
used for input from 
-                an application, only for output from the driver to the application. When
the driver writes a 
-                numeric value into the SQL_NUMERIC_STRUCT, it will use its own
driver-specific default as the 
-                value for the precision field, and it will use the value in the
SQL_DESC_SCALE field of the 
-                application descriptor (which defaults to 0) for the scale field. An
application can provide 
-                its own values for precision and scale by setting the SQL_DESC_PRECISION
and SQL_DESC_SCALE 
-                fields of the application descriptor.
-
-                If any default precision or scale is not appropriate, the application
should explicitly 
-                set the appropriate descriptor field by a call to SQLSetDescField or
SQLSetDescRec. It 
-                can set the SQL_DESC_CONCISE_TYPE field to SQL_C_NUMERIC and call
SQLGetData with a 
-                TargetType argument of SQL_ARD_TYPE, which will cause the precision and
scale values in 
-                the descriptor fields to be used.
-            */
-            stateGetData.pAppRowDescRec        =
(MDescriptorRecordARD*)getAppRowDesc()->getRecord( nColumn );
-            stateGetData.nTargetTypeAdjusted   =
stateGetData.pAppRowDescRec->getConciseType();
-
-            /* sanity check to prevent 'looping' */
-            if ( stateGetData.nTargetTypeAdjusted == SQL_ARD_TYPE )
-                MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_HY000,
0, tr("SQL_ARD_TYPE is invalid target type for ARD") ) );
-        }
-        /*!
-            \internal
-            \note
-
-            Have we been told to use a default type/conversion? The default calc is
spelled out in the ODBC
-            specification. 
-
-            This is probably not used much.
-        */
-        else if ( nTargetType == SQL_C_DEFAULT )
-        {
-            /*!
-                \internal ODBC RULE
-    
-                If it is SQL_C_DEFAULT, the driver selects the default C data type based
on the SQL 
-                data type of the source.        
-    
-                \note
-    
-                The logic for selecting the C data type is spelled out in the ODBC
specification.
-            */
-            stateGetData.nTargetTypeAdjusted = MYODBCC::getCDefault(
-                    getEnvironment()->getODBCVersion(),
-                    stateGetData.pImpRowDescRec->getConciseType(),
-                    stateGetData.pImpRowDescRec->getUnsigned() );
-        }
-    }
-
 #if MYODBC_DBG > 1
-    MYODBCDbgInfo( QString( "cell data (1st 50 chars)=%1" )
-            .arg( vectorRows[stateGetData.nRow][stateGetData.nColumn -
1].toString().left( 50 ) ) );
-    MYODBCDbgInfo( QString( "stateGetData.pImpRowDescRec->getConciseType()=%1=%2" )
-            .arg( stateGetData.pImpRowDescRec->getConciseType() )
-            .arg( MYODBCC::getConciseTypeStringSQL(
-                    stateGetData.pImpRowDescRec->getConciseType(),
-                    getEnvironment()->getODBCVersion() ) ) );
-    MYODBCDbgInfo( QString( "stateGetData.nTargetTypeAdjusted=%1=%2" )
-            .arg( stateGetData.nTargetTypeAdjusted )
-            .arg( MYODBCC::getConciseTypeStringC(
-                    stateGetData.nTargetTypeAdjusted,
-                    getEnvironment()->getODBCVersion() ) ) );
+    MYODBCDbgInfo( QString( "adjusted nTargetType=%1" )
+            .arg( nTargetType ) );
+    MYODBCDbgInfo( QString( "initial nTargetType=%1" )
+            .arg( nTargetType ) );
 #endif
 
-    /*!
-        \internal
-        \note
-
-        Ok - we have handled special conditions and we have ensured that we have a viable
-        get data state in stateGetData - including cell data in our variant (data
conversion 'hub'). 
-        Now lets convert the data (select a 'spoke to head out on').
-    */
-    switch ( stateGetData.pImpRowDescRec->getConciseType() )
+    /* clear "GetData" state if we're on a new field */
+    if ( stateGetData.nColumn != nColumn || stateGetData.nRow != nRowsIndex )
     {
-        case SQL_CHAR:
-        case SQL_VARCHAR:
-        case SQL_LONGVARCHAR:
-        case SQL_WCHAR:
-        case SQL_WVARCHAR:
-        case SQL_WLONGVARCHAR:
-            nReturn = fromCharacterSQL( &stateGetData );
-            break;
-
-        case SQL_DECIMAL:
-        case SQL_NUMERIC:
-        case SQL_TINYINT:
-        case SQL_SMALLINT:
-        case SQL_INTEGER:
-        case SQL_BIGINT:
-        case SQL_REAL:
-        case SQL_FLOAT:
-        case SQL_DOUBLE:
-            nReturn = fromNumericSQL( &stateGetData );
-            break;
-
-        case SQL_BIT:
-            nReturn = fromBitSQL( &stateGetData );
-            break;
-
-        case SQL_BINARY:
-        case SQL_VARBINARY:
-        case SQL_LONGVARBINARY:
-            nReturn = fromBinarySQL( &stateGetData );
-            break;
-
-        case SQL_GUID:
-            nReturn = fromGuidSQL( &stateGetData );
-            break;
-
-        case SQL_TYPE_DATE:
-            if ( getEnvironment()->getODBCVersion() == SQL_OV_ODBC2 )
-                MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_HY003 )
);
-            nReturn = fromDateSQL( &stateGetData );
-            break;
-
-        case SQL_TYPE_TIME:
-            if ( getEnvironment()->getODBCVersion() == SQL_OV_ODBC2 )
-                MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_HY003 )
);
-            nReturn = fromTimeSQL( &stateGetData );
-            break;
-
-        case SQL_TYPE_TIMESTAMP:
-            if ( getEnvironment()->getODBCVersion() == SQL_OV_ODBC2 )
-                MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_HY003 )
);
-            nReturn = fromTimeStampSQL( &stateGetData );
-            break;
-
-        case SQL_INTERVAL_YEAR:
-        case SQL_INTERVAL_MONTH:
-        case SQL_INTERVAL_YEAR_TO_MONTH:
-            nReturn = fromIntervalYearMonthSQL( &stateGetData );
-            break;
-
-        case SQL_INTERVAL_DAY:
-        case SQL_INTERVAL_HOUR:
-        case SQL_INTERVAL_MINUTE:
-        case SQL_INTERVAL_SECOND:
-        case SQL_INTERVAL_DAY_TO_HOUR:
-        case SQL_INTERVAL_DAY_TO_MINUTE:
-        case SQL_INTERVAL_DAY_TO_SECOND:
-        case SQL_INTERVAL_HOUR_TO_MINUTE:
-        case SQL_INTERVAL_HOUR_TO_SECOND:
-        case SQL_INTERVAL_MINUTE_TO_SECOND:
-            nReturn = fromIntervalDayTimeSQL( &stateGetData );
-            break;
-
-        case SQL_DATE:
-            if ( getEnvironment()->getODBCVersion() == SQL_OV_ODBC3 )
-                MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_HY003 )
);
-            nReturn = fromDateSQL( &stateGetData );
-            break;
-
-        case SQL_TIME:
-            if ( getEnvironment()->getODBCVersion() == SQL_OV_ODBC3 )
-                MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_HY003 )
);
-            nReturn = fromTimeSQL( &stateGetData );
-            break;
-
-        case SQL_TIMESTAMP:
-            if ( getEnvironment()->getODBCVersion() == SQL_OV_ODBC3 )
-                MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_HY003 )
);
-            nReturn = fromTimeStampSQL( &stateGetData );
-            break;
-
-        default:
-            MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_HY003 ) );
+        stateGetData.doClear();
     }
+    stateGetData.nColumn = nColumn;
+    stateGetData.nRow = nRowsIndex;
 
-    /* if its retrieved in chunks,
-     * we need to send whats available before getData() */
-    if ( stateGetData.nBytesPrev )
+    /* make sure v3 types are not used in v2 API */
+    if ( getEnvironment()->getODBCVersion() == SQL_OV_ODBC2 )
     {
-        MYODBCCSet( pnLength, stateGetData.nBytesPrev );
-        /* adjust for data taken */
-        stateGetData.nBytesPrev -=
-            (stateGetData.nBytesPrev - stateGetData.nBytesRemaining);
+        switch ( pImpRowDescRec->getConciseType() )
+        {
+            case SQL_TYPE_DATE:
+            case SQL_TYPE_TIME:
+            case SQL_TYPE_TIMESTAMP:
+                MYODBCDbgReturn( getDiagnostic()->doAppend(
+                            MDiagnostic::STATE_HY003 ) );
+        }
     }
-    else
-    {
-        MYODBCCSet( pnLength, stateGetData.nBytesTotal );
-    }
 
-    MYODBCDbgReturn( nReturn );
-}
-
-/*!
-    \brief  Get character cell data. 
-
-            This enforces the rules from the ODBC specification in a section name "SQL to
C: Character"
-            while attempting to get the column data.
-
-            Converts type as required.
-
-    \param  pResultGetData  Reference to a MStateGetData. This should be initialized with
cell data etc.
-
-    \return SQLRETURN
-
-    \sa     getData()
-            "SQL to C: Character"
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/odbc/htm/odbcconverting_data_from_sql_to_c_data_types.asp
-*/
-SQLRETURN MResult::fromCharacterSQL( MStateGetData *pResultGetData )
-{
-    MYODBCDbgEnter();
-
-    /*!
-        \internal ODBC RULE
-
-        The following table shows the ODBC C data types to which character SQL data may
be converted.
-    */
-    switch ( pResultGetData->nTargetTypeAdjusted )
+    /* make sure v2 types are not used in v3 API */
+    if ( getEnvironment()->getODBCVersion() == SQL_OV_ODBC3 )
     {
-        case SQL_C_CHAR:
-            MYODBCDbgReturn( toCharC( pResultGetData ) );
-        case SQL_C_WCHAR:
-            MYODBCDbgReturn( toWCharC( pResultGetData ) );
-        case SQL_C_TINYINT:
-        case SQL_C_STINYINT:
-            MYODBCDbgReturn( toSTinyIntC( pResultGetData ) );
-        case SQL_C_UTINYINT:
-            MYODBCDbgReturn( toUTinyIntC( pResultGetData ) );
-        case SQL_C_SBIGINT:
-            MYODBCDbgReturn( toSBigIntC( pResultGetData ) );
-        case SQL_C_UBIGINT:
-            MYODBCDbgReturn( toUBigIntC( pResultGetData ) );
-        case SQL_C_SHORT:
-        case SQL_C_SSHORT:
-            MYODBCDbgReturn( toSShortC( pResultGetData ) );
-        case SQL_C_USHORT:
-            MYODBCDbgReturn( toUShortC( pResultGetData ) );
-        case SQL_C_LONG:
-        case SQL_C_SLONG:
-            MYODBCDbgReturn( toSLongC( pResultGetData ) );
-        case SQL_C_ULONG:
-            MYODBCDbgReturn( toULongC( pResultGetData ) );
-        case SQL_C_NUMERIC:
-            MYODBCDbgReturn( toNumericC( pResultGetData ) );
-        case SQL_C_FLOAT:
-            MYODBCDbgReturn( toFloatC( pResultGetData ) );
-        case SQL_C_DOUBLE:
-            MYODBCDbgReturn( toDoubleC( pResultGetData ) );
-        case SQL_C_BIT:
-            MYODBCDbgReturn( toBitC( pResultGetData ) );
-        case SQL_C_BINARY:
-            MYODBCDbgReturn( toBinaryC( pResultGetData ) );
-        case SQL_C_TYPE_DATE:
-        case SQL_C_DATE:        /* ODBC v2 - validation should already have occured */
-            MYODBCDbgReturn( toTypeDateC( pResultGetData ) );
-        case SQL_C_TYPE_TIME:
-        case SQL_C_TIME:        /* ODBC v2 - validation should already have occured */
-            MYODBCDbgReturn( toTypeTimeC( pResultGetData ) );
-        case SQL_C_TYPE_TIMESTAMP:
-        case SQL_C_TIMESTAMP:   /* ODBC v2 - validation should already have occured */
-            MYODBCDbgReturn( toTypeTimestampC( pResultGetData ) );
-        case SQL_C_INTERVAL_MONTH:
-            MYODBCDbgReturn( toIntervalMonthC( pResultGetData ) );
-        case SQL_C_INTERVAL_YEAR:
-            MYODBCDbgReturn( toIntervalYearC( pResultGetData ) );
-        case SQL_C_INTERVAL_YEAR_TO_MONTH:
-            MYODBCDbgReturn( toIntervalYearToMonthC( pResultGetData ) );
-        case SQL_C_INTERVAL_DAY:
-            MYODBCDbgReturn( toIntervalDayC( pResultGetData ) );
-        case SQL_C_INTERVAL_HOUR:
-            MYODBCDbgReturn( toIntervalHourC( pResultGetData ) );
-        case SQL_C_INTERVAL_MINUTE:
-            MYODBCDbgReturn( toIntervalMinuteC( pResultGetData ) );
-        case SQL_C_INTERVAL_SECOND:
-            MYODBCDbgReturn( toIntervalSecondC( pResultGetData ) );
-        case SQL_C_INTERVAL_DAY_TO_HOUR:
-            MYODBCDbgReturn( toIntervalDayToHourC( pResultGetData ) );
-        case SQL_C_INTERVAL_DAY_TO_MINUTE:
-            MYODBCDbgReturn( toIntervalDayToMinuteC( pResultGetData ) );
-        case SQL_C_INTERVAL_DAY_TO_SECOND:
-            MYODBCDbgReturn( toIntervalDayToSecondC( pResultGetData ) );
-        case SQL_C_INTERVAL_HOUR_TO_MINUTE:
-            MYODBCDbgReturn( toIntervalHourToMinuteC( pResultGetData ) );
-        case SQL_C_INTERVAL_HOUR_TO_SECOND:
-            MYODBCDbgReturn( toIntervalHourToSecondC( pResultGetData ) );
-        case SQL_C_INTERVAL_MINUTE_TO_SECOND:
-            MYODBCDbgReturn( toIntervalMinuteToSecondC( pResultGetData ) );
+        switch ( pImpRowDescRec->getConciseType() )
+        {
+            case SQL_DATE:
+            case SQL_TIME:
+            case SQL_TIMESTAMP:
+                MYODBCDbgReturn( getDiagnostic()->doAppend(
+                            MDiagnostic::STATE_HY003 ) );
+        }
     }
 
-    MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_07006 ) );
-}
-
-/*!
-    \brief  Get numeric cell data. 
-
-            This enforces the rules from the ODBC specification in a section name "SQL to
C: Numeric"
-            while attempting to get the column data.
-
-            Converts type as required.
-
-    \param  pResultGetData  Reference to a MStateGetData. This should be initialized with
cell data etc.
-
-    \return SQLRETURN
-
-    \sa     getData()
-            "SQL to C: Numeric"
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/odbc/htm/odbcconverting_data_from_sql_to_c_data_types.asp
-*/
-SQLRETURN MResult::fromNumericSQL( MStateGetData *pResultGetData )
-{
-    MYODBCDbgEnter();
-
-    /*!
-        \internal ODBC RULE
-
-        The following table shows the ODBC C data types to which numeric SQL data may be
converted.
-    */
-    switch ( pResultGetData->nTargetTypeAdjusted )
+    /* set ind and return if null */
+    if ( val.isNull() )
     {
-        case SQL_C_CHAR:
-            MYODBCDbgReturn( toCharC( pResultGetData ) );
-        case SQL_C_WCHAR:
-            MYODBCDbgReturn( toWCharC( pResultGetData ) );
-        case SQL_C_TINYINT:
-        case SQL_C_STINYINT:
-            MYODBCDbgReturn( toSTinyIntC( pResultGetData ) );
-        case SQL_C_UTINYINT:
-            MYODBCDbgReturn( toUTinyIntC( pResultGetData ) );
-        case SQL_C_BIT:
-            MYODBCDbgReturn( toBitC( pResultGetData ) );
-        case SQL_C_SBIGINT:
-            MYODBCDbgReturn( toSBigIntC( pResultGetData ) );
-        case SQL_C_UBIGINT:
-            MYODBCDbgReturn( toUBigIntC( pResultGetData ) );
-        case SQL_C_SHORT:
-        case SQL_C_SSHORT:
-            MYODBCDbgReturn( toSShortC( pResultGetData ) );
-        case SQL_C_USHORT:
-            MYODBCDbgReturn( toUShortC( pResultGetData ) );
-        case SQL_C_LONG:
-        case SQL_C_SLONG:
-            MYODBCDbgReturn( toSLongC( pResultGetData ) );
-        case SQL_C_ULONG:
-            MYODBCDbgReturn( toULongC( pResultGetData ) );
-        case SQL_C_NUMERIC:
-            MYODBCDbgReturn( toNumericC( pResultGetData ) );
-        case SQL_C_FLOAT:
-            MYODBCDbgReturn( toFloatC( pResultGetData ) );
-        case SQL_C_DOUBLE:
-            MYODBCDbgReturn( toDoubleC( pResultGetData ) );
-        case SQL_C_BINARY:
-            MYODBCDbgReturn( toBinaryC( pResultGetData ) );
-        case SQL_C_INTERVAL_MONTH:
-            MYODBCDbgReturn( toIntervalMonthC( pResultGetData ) );
-        case SQL_C_INTERVAL_YEAR:
-            MYODBCDbgReturn( toIntervalYearC( pResultGetData ) );
-        case SQL_C_INTERVAL_YEAR_TO_MONTH:
-            /*!
-                \internal
-                \note
-
-                We are expected to load SQL_INTERVAL_STRUCT -> SQL_YEAR_MONTH_STRUCT
from
-                a numeric. 
-            */
-            MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_HY000, 0,
tr("Loading SQL_INTERVAL_STRUCT/SQL_YEAR_MONTH_STRUCT from numeric not supported.") ) );
-        case SQL_C_INTERVAL_DAY:
-        case SQL_C_INTERVAL_HOUR:
-        case SQL_C_INTERVAL_MINUTE:
-        case SQL_C_INTERVAL_SECOND:
-        case SQL_C_INTERVAL_DAY_TO_HOUR:
-        case SQL_C_INTERVAL_DAY_TO_MINUTE:
-        case SQL_C_INTERVAL_DAY_TO_SECOND:
-        case SQL_C_INTERVAL_HOUR_TO_MINUTE:
-        case SQL_C_INTERVAL_HOUR_TO_SECOND:
-            /*!
-                \internal
-                \note
-
-                We are expected to load SQL_INTERVAL_STRUCT -> SQL_DAY_SECOND_STRUCT
from
-                a numeric. 
-            */
-            MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_HY000, 0,
tr("Loading SQL_INTERVAL_STRUCT/SQL_DAY_SECOND_STRUCT from numeric not supported.") ) );
+        if ( pnIndicator )
+        {
+            *pnIndicator = SQL_NULL_DATA;
+            MYODBCDbgReturn( SQL_SUCCESS );
+        }
+        else
+            MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_22002 ) );
     }
 
-    MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_07006 ) );
-}
-
-/*!
-    \brief  Get bit cell data. 
-
-            This enforces the rules from the ODBC specification in a section name "SQL to
C: Bit"
-            while attempting to get the column data.
-
-            Converts type as required.
-
-    \param  pResultGetData  Reference to a MStateGetData. This should be initialized with
cell data etc.
-
-    \return SQLRETURN
-
-    \sa     getData()
-            "SQL to C: Bit"
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/odbc/htm/odbcconverting_data_from_sql_to_c_data_types.asp
-*/
-SQLRETURN MResult::fromBitSQL( MStateGetData *pResultGetData )
-{
-    MYODBCDbgEnter();
-
-    /*!
-        \internal ODBC RULE
-
-        The following table shows the ODBC C data types to which bit SQL data may be
converted.
-    */
-    switch ( pResultGetData->nTargetTypeAdjusted )
+    /* alter target type to concrete if asked for default */
+    if ( nTargetType == SQL_C_DEFAULT )
     {
-        case SQL_C_CHAR:
-            MYODBCDbgReturn( toCharC( pResultGetData ) );
-        case SQL_C_WCHAR:
-            MYODBCDbgReturn( toWCharC( pResultGetData ) );
-        case SQL_C_TINYINT:
-        case SQL_C_STINYINT:
-            MYODBCDbgReturn( toSTinyIntC( pResultGetData ) );
-        case SQL_C_UTINYINT:
-            MYODBCDbgReturn( toUTinyIntC( pResultGetData ) );
-        case SQL_C_SBIGINT:
-            MYODBCDbgReturn( toSBigIntC( pResultGetData ) );
-        case SQL_C_UBIGINT:
-            MYODBCDbgReturn( toUBigIntC( pResultGetData ) );
-        case SQL_C_SHORT:
-        case SQL_C_SSHORT:
-            MYODBCDbgReturn( toSShortC( pResultGetData ) );
-        case SQL_C_USHORT:
-            MYODBCDbgReturn( toUShortC( pResultGetData ) );
-        case SQL_C_LONG:
-        case SQL_C_SLONG:
-            MYODBCDbgReturn( toSLongC( pResultGetData ) );
-        case SQL_C_ULONG:
-            MYODBCDbgReturn( toULongC( pResultGetData ) );
-        case SQL_C_FLOAT:
-            MYODBCDbgReturn( toFloatC( pResultGetData ) );
-        case SQL_C_DOUBLE:
-            MYODBCDbgReturn( toDoubleC( pResultGetData ) );
-        case SQL_C_NUMERIC:
-            MYODBCDbgReturn( toNumericC( pResultGetData ) );
-        case SQL_C_BIT:
-            MYODBCDbgReturn( toBitC( pResultGetData ) );
-        case SQL_C_BINARY:
-            MYODBCDbgReturn( toBinaryC( pResultGetData ) );
+        nTargetType = MYODBCC::getCDefault(
+                getEnvironment()->getODBCVersion(),
+                pImpRowDescRec->getConciseType(),
+                pImpRowDescRec->getUnsigned() );
     }
-
-    MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_07006 ) );
-}
-
-/*!
-    \brief  Get binary cell data. 
-
-            This enforces the rules from the ODBC specification in a section name "SQL to
C: Binary"
-            while attempting to get the column data.
-
-            Converts type as required.
-
-    \param  pResultGetData  Reference to a MStateGetData. This should be initialized with
cell data etc.
-
-    \return SQLRETURN
-
-    \sa     getData()
-            "SQL to C: Binary"
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/odbc/htm/odbcconverting_data_from_sql_to_c_data_types.asp
-*/
-SQLRETURN MResult::fromBinarySQL( MStateGetData *pResultGetData )
-{
-    MYODBCDbgEnter();
-
-    /*!
-        \internal ODBC RULE
-
-        The following table shows the ODBC C data types to which binary SQL data may be
converted.
-    */
-    switch ( pResultGetData->nTargetTypeAdjusted )
+    else if ( nTargetType == SQL_ARD_TYPE )
     {
-        case SQL_C_CHAR:
-            MYODBCDbgReturn( toCharC( pResultGetData ) );
-        case SQL_C_WCHAR:
-            MYODBCDbgReturn( toWCharC( pResultGetData ) );
-        case SQL_C_BINARY:
-            MYODBCDbgReturn( toBinaryC( pResultGetData ) );
-    }
+        MDescriptorRecordARD *desc = (MDescriptorRecordARD*)
+            getAppRowDesc()->getRecord( nColumn );
 
-    MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_07006 ) );
-}
+        /*! Usually to adjust precision and scale for SQL_C_NUMERIC */
+        nTargetType = desc->getConciseType();
 
-/*!
-    \brief  Get date cell data. 
+        /* sanity check to prevent 'looping' */
+        if ( nTargetType == SQL_ARD_TYPE )
+            MYODBCDbgReturn( getDiagnostic()->doAppend(
+                        MDiagnostic::STATE_HY000, 0,
+                        tr("SQL_ARD_TYPE is invalid target type for ARD") ) );
 
-            This enforces the rules from the ODBC specification in a section name "SQL to
C: Date"
-            while attempting to get the column data.
-
-            Converts type as required.
-
-    \param  pResultGetData  Reference to a MStateGetData. This should be initialized with
cell data etc.
-
-    \return SQLRETURN
-
-    \sa     getData()
-            "SQL to C: Date"
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/odbc/htm/odbcconverting_data_from_sql_to_c_data_types.asp
-*/
-SQLRETURN MResult::fromDateSQL( MStateGetData *pResultGetData )
-{
-    MYODBCDbgEnter();
-
-    /*!
-        \internal ODBC RULE
-
-        The following table shows the ODBC C data types to which date SQL data may be
converted. 
-    */
-    switch ( pResultGetData->nTargetTypeAdjusted )
-    {
-        case SQL_C_CHAR:
-            MYODBCDbgReturn( toCharC( pResultGetData ) );
-        case SQL_C_WCHAR:
-            MYODBCDbgReturn( toWCharC( pResultGetData ) );
-        case SQL_C_BINARY:
-            MYODBCDbgReturn( toBinaryC( pResultGetData ) );
-        case SQL_C_TYPE_DATE:
-        case SQL_C_DATE:        /* ODBC v2 - validation should already have occured */
-            MYODBCDbgReturn( toTypeDateC( pResultGetData ) );
-        case SQL_C_TYPE_TIMESTAMP:
-        case SQL_C_TIMESTAMP:   /* ODBC v2 - validation should already have occured */
-            MYODBCDbgReturn( toTypeTimestampC( pResultGetData ) );
+        /* get prec+scale if using numeric struct */
+        if ( nTargetType == SQL_C_NUMERIC )
+        {
+            precision = desc->getPrecision();
+            scale     = desc->getScale();
+        }
     }
 
-    MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_07006 ) );
-}
+#if MYODBC_DBG > 1
+    MYODBCDbgInfo( QString( "cell data (1st 50 chars)=%1" )
+            .arg( val.toString().left( 50 ) ) );
+#endif
 
-/*!
-    \brief  Get guid cell data (in case we support it in future). 
+    QVariant::Type destType = MDataConvert::qtypeForCType( nTargetType );
 
-            This enforces the rules from the ODBC specification in a section name "SQL to
C: GUID"
-            while attempting to get the column data.
-
-            Converts type as required.
-
-    \param  pResultGetData  Reference to a MStateGetData. This should be initialized with
cell data etc.
-
-    \return SQLRETURN
-
-    \sa     getData()
-            "SQL to C: GUID"
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/odbc/htm/odbcconverting_data_from_sql_to_c_data_types.asp
-*/
-SQLRETURN MResult::fromGuidSQL( MStateGetData *pResultGetData )
-{
-    MYODBCDbgEnter();
-
-    /*!
-        \internal ODBC RULE
-
-        The following table shows the ODBC C data types to which GUID SQL data may be
converted.
-    */
-    /*!
-        \internal MYODBC RULE
-
-        We do not have a GUID type to support here - so this method should not get
called. We are just
-        a stub.
-    */
-    switch ( pResultGetData->nTargetTypeAdjusted )
+    /* invalid application buffer type (DM responsibility) */
+    if ( destType == QVariant::Invalid )
     {
-        case SQL_C_CHAR:
-        case SQL_C_WCHAR:
-        case SQL_C_BINARY:
-        case SQL_C_GUID:
-            ;
+        MYODBCDbgReturn( getDiagnostic()->doAppend(
+                    MDiagnostic::STATE_HY003 ) );
     }
 
-    MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_07006 ) );
-}
-
-/*!
-    \brief  Get time cell data. 
-
-            This enforces the rules from the ODBC specification in a section name "SQL to
C: Time"
-            while attempting to get the column data.
-
-            Converts type as required.
-
-    \param  pResultGetData  Reference to a MStateGetData. This should be initialized with
cell data etc.
-
-    \return SQLRETURN
-
-    \sa     getData()
-            "SQL to C: Time"
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/odbc/htm/odbcconverting_data_from_sql_to_c_data_types.asp
-*/
-SQLRETURN MResult::fromTimeSQL( MStateGetData *pResultGetData )
-{
-    MYODBCDbgEnter();
-
-    /*!
-        \internal ODBC RULE
-
-        The following table shows the ODBC C data types to which time SQL data may be
converted.
-    */
-    switch ( pResultGetData->nTargetTypeAdjusted )
+    /* make sure we can convert to the requested type */
+    if ( !val.canConvert( destType ) )
     {
-        case SQL_C_CHAR:
-            MYODBCDbgReturn( toCharC( pResultGetData ) );
-        case SQL_C_WCHAR:
-            MYODBCDbgReturn( toWCharC( pResultGetData ) );
-        case SQL_C_BINARY:
-            MYODBCDbgReturn( toBinaryC( pResultGetData ) );
-        case SQL_C_TYPE_TIME:
-        case SQL_C_TIME:        /* ODBC v2 - validation should already have occured */
-            MYODBCDbgReturn( toTypeTimeC( pResultGetData ) );
-        case SQL_C_TYPE_TIMESTAMP:
-        case SQL_C_TIMESTAMP:   /* ODBC v2 - validation should already have occured */
-            MYODBCDbgReturn( toTypeTimestampC( pResultGetData ) );
+        switch( nTargetType )
+        {
+            /* per spec, these are validated separately */
+            case SQL_C_TYPE_DATE:
+            case SQL_C_DATE:
+            case SQL_C_TYPE_TIME:
+            case SQL_C_TIME:
+            case SQL_C_TYPE_TIMESTAMP:
+            case SQL_C_TIMESTAMP:
+                break;
+            default:
+                MYODBCDbgReturn( getDiagnostic()->doAppend(
+                            MDiagnostic::STATE_07006 ) );
+        }
     }
 
-    MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_07006 ) );
-}
-
-/*!
-    \brief  Get timestamp cell data. 
-
-            This enforces the rules from the ODBC specification in a section name "SQL to
C: Timestamp"
-            while attempting to get the column data.
-
-            Converts type as required.
-
-    \param  pResultGetData  Reference to a MStateGetData. This should be initialized with
cell data etc.
-
-    \return SQLRETURN
-
-    \sa     getData()
-            "SQL to C: Timestamp"
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/odbc/htm/odbcconverting_data_from_sql_to_c_data_types.asp
-*/
-SQLRETURN MResult::fromTimeStampSQL( MStateGetData *pResultGetData )
-{
-    MYODBCDbgEnter();
-
-    /*!
-        \internal ODBC RULE
-
-        The following table shows the ODBC C data types to which timestamp SQL data may
be converted.
-    */
-    switch ( pResultGetData->nTargetTypeAdjusted )
+    /* assign length for fixed size data (only?) */
+    if ( !MDataConvert::isVarLengthCType( nTargetType ) )
     {
-        case SQL_C_CHAR:
-            MYODBCDbgReturn( toCharC( pResultGetData ) );
-        case SQL_C_WCHAR:
-            MYODBCDbgReturn( toWCharC( pResultGetData ) );
-        case SQL_C_BINARY:
-            MYODBCDbgReturn( toBinaryC( pResultGetData ) );
-        case SQL_C_TYPE_DATE:
-        case SQL_C_DATE:        /* ODBC v2 - validation should already have occured */
-            MYODBCDbgReturn( toTypeDateC( pResultGetData ) );
-        case SQL_C_TYPE_TIME:
-        case SQL_C_TIME:        /* ODBC v2 - validation should already have occured */
-            MYODBCDbgReturn( toTypeTimeC( pResultGetData ) );
-        case SQL_C_TYPE_TIMESTAMP:
-        case SQL_C_TIMESTAMP:   /* ODBC v2 - validation should already have occured */
-            MYODBCDbgReturn( toTypeTimestampC( pResultGetData ) );
-    }
+        MYODBCCSet( pnIndicator, MDataConvert::fixedLengthForCType( nTargetType ) );
 
-    MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_07006 ) );
-}
-
-/*!
-    \brief  Get Year-Month Intervals cell data. 
-
-            This enforces the rules from the ODBC specification in a section name "SQL to
C: Year-Month Intervals"
-            while attempting to get the column data.
-
-            Converts type as required.
-
-    \param  pResultGetData  Reference to a MStateGetData. This should be initialized with
cell data etc.
-
-    \return SQLRETURN
-
-    \sa     getData()
-            "SQL to C: Year-Month Intervals"
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/odbc/htm/odbcconverting_data_from_sql_to_c_data_types.asp
-*/
-SQLRETURN MResult::fromIntervalYearMonthSQL( MStateGetData *pResultGetData )
-{
-    MYODBCDbgEnter();
-
-    /*!
-        \internal ODBC RULE
-
-        The following table shows the ODBC C data types to which year-month interval SQL
data may be converted.
-    */
-    /*!
-        \internal MYODBC RULE
-
-        We do not have an interval type to support here - so this method should not get
called. We are just
-        a stub.
-    */
-    switch ( pResultGetData->nTargetTypeAdjusted )
-    {
-        case SQL_C_CHAR:
-        case SQL_C_WCHAR:
-        case SQL_C_INTERVAL_MONTH:
-        case SQL_C_INTERVAL_YEAR:
-        case SQL_C_INTERVAL_YEAR_TO_MONTH:
-        case SQL_C_STINYINT:
-        case SQL_C_UTINYINT:
-        case SQL_C_USHORT:
-        case SQL_C_SHORT:
-        case SQL_C_SLONG:
-        case SQL_C_ULONG:
-        case SQL_C_NUMERIC:
-        case SQL_C_SBIGINT:
-        case SQL_C_UBIGINT:
-        case SQL_C_BINARY:
-            ;
+        /* if pTarget is NULL, return */
+        if ( !pTarget )
+            MYODBCDbgReturn( SQL_SUCCESS );
     }
 
-    MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_07006 ) );
-}
-
-/*!
-    \brief  Get Day-Time Intervals cell data. 
-
-            This enforces the rules from the ODBC specification in a section name "SQL to
C: Day-Time Intervals"
-            while attempting to get the column data.
-
-            Converts type as required.
-
-    \param  pResultGetData  Reference to a MStateGetData. This should be initialized with
cell data etc.
-
-    \return SQLRETURN
-
-    \sa     getData()
-            "SQL to C: Day-Time Intervals"
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/odbc/htm/odbcconverting_data_from_sql_to_c_data_types.asp
-*/
-SQLRETURN MResult::fromIntervalDayTimeSQL( MStateGetData *pResultGetData )
-{
-    MYODBCDbgEnter();
-
-    /*!
-        \internal ODBC RULE
-
-        The following table shows the ODBC C data types to which day-time interval SQL
data may be converted.
-    */
-    /*!
-        \internal MYODBC RULE
-
-        We do not have an interval type to support here - so this method should not get
called. We are just
-        a stub.
-    */
-    switch ( pResultGetData->nTargetTypeAdjusted )
+    if ( MDataConvert::isIntegerCType( nTargetType ) )
     {
-        case SQL_C_CHAR:
-        case SQL_C_WCHAR:
-        case SQL_C_STINYINT:
-        case SQL_C_UTINYINT:
-        case SQL_C_SBIGINT:
-        case SQL_C_USHORT:
-        case SQL_C_SHORT:
-        case SQL_C_SLONG:
-        case SQL_C_ULONG:
-        case SQL_C_NUMERIC:
-        case SQL_C_BINARY:
-        case SQL_C_INTERVAL_MONTH:
-        case SQL_C_INTERVAL_YEAR:
-        case SQL_C_INTERVAL_YEAR_TO_MONTH:
-        case SQL_C_INTERVAL_DAY:
-        case SQL_C_INTERVAL_HOUR:
-        case SQL_C_INTERVAL_MINUTE:
-        case SQL_C_INTERVAL_SECOND:
-        case SQL_C_INTERVAL_DAY_TO_HOUR:
-        case SQL_C_INTERVAL_DAY_TO_MINUTE:
-        case SQL_C_INTERVAL_DAY_TO_SECOND:
-        case SQL_C_INTERVAL_HOUR_TO_MINUTE:
-        case SQL_C_INTERVAL_HOUR_TO_SECOND:
-        case SQL_C_INTERVAL_MINUTE_TO_SECOND:
-            ;
-    }
-
-    MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_07006 ) );
-}
-
-/*!
-    \brief  Converts data to SQL_C_CHAR.
-
-            This method uses information provided in MStateGetData to fill a target
buffer with the 
-            specified cell data - converted as needed.
-
-    \param  pResultGetData  Reference to a MStateGetData. This should be initialized with
cell data etc.
-
-    \return SQLRETURN
-
-    \sa getData()
-*/
-SQLRETURN MResult::toCharC( MStateGetData *pResultGetData )
-{
-    MYODBCDbgEnter();
-
-    /*!
-        \internal ODBC RULE
-
-       
+-------------+-------------------------------------+-----------------+-------------------------+----------+
-        | C Type      | Test                                | TargetValuePtr  |
StrLen_or_IndPtr        | SQLSTATE |
-       
+-------------+-------------------------------------+-----------------+-------------------------+----------+
-        | SQL_C_CHAR  | Byte length of data < BufferLength  | Data            | Length
of data in bytes | n/a      |
-        |             | Byte length of data >= BufferLength | Truncated data  | Length
of data in bytes | 01004    |
-       
+-------------+-------------------------------------+-----------------+-------------------------+----------+
-
-        When character data is returned from the driver to the application, the driver
must always null-terminate it. 
-        This gives the application the choice of whether to handle the data as a string
or a character array. If the 
-        application buffer is not large enough to return all of the character data, the
driver truncates it to the byte 
-        length of the buffer less the number of bytes required by the null-termination
character, null-terminates the 
-        truncated data, and stores it in the buffer. Therefore, applications must always
allocate extra space for the 
-        null-termination character in buffers used to retrieve character data. For
example, a 51-byte buffer is needed 
-        to retrieve 50 characters of data.
-    */
-
-    /* convert to string (if possible) */
-    if ( pResultGetData->stringData.isEmpty() )
-    {
-        if ( !vectorRows[pResultGetData->nRow][pResultGetData->nColumn -
1].canConvert( QVariant::String ) )
-            MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_07006 ) );
-        /* make a copy we can easily work with (avoid re-convert) in case of chunking
(optimize this later) */
-        pResultGetData->stringData  =
vectorRows[pResultGetData->nRow][pResultGetData->nColumn - 1].toString();
-        /* make sure we have the ACTUAL length of the result */
-        pResultGetData->nBytesTotal =
-            pResultGetData->stringData.toUtf8().length();
-        pResultGetData->nBytesPrev = pResultGetData->nBytesTotal; /* init
prev-bytes */
-    }
-
-    /* do we even need to do the data bit (or just looking for len)? */
-    if ( pResultGetData->pTarget && pResultGetData->nBytesMax )
-    {
-        if ( MYODBCC::doStringCopyOut( (SQLCHAR*)pResultGetData->pTarget,
-                    pResultGetData->nBytesMax,
-                    (SQLCHAR*)pResultGetData->stringData.toUtf8().data() ) )
+        /* integer range check */
+        if ( !MDataConvert::isInRange( nTargetType, val ) )
         {
-            pResultGetData->nBytesRemaining = 0;
+            MYODBCDbgReturn( getDiagnostic()->doAppend(
+                        MDiagnostic::STATE_22003 ) );
         }
-        else
+
+        /* actual assignment */
+        switch ( nTargetType )
         {
-            /* remove chars returned thus far from our working copy */
-            pResultGetData->nBytesRemaining =
-                pResultGetData->stringData.length() -
-                (pResultGetData->nBytesMax - 1);
-            pResultGetData->stringData.remove( 0,
-                    pResultGetData->nBytesMax - 1);
-            MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_01004 ) );
+            case SQL_C_TINYINT:
+            case SQL_C_STINYINT:
+                *(SCHAR *)pTarget = val.toInt();
+                break;
+            case SQL_C_BIT:
+                if ( val.toUInt() & ~1 )
+                {
+                    *(SQLCHAR *)pTarget = 1;
+                    getDiagnostic()->doAppend( MDiagnostic::STATE_01000, 0,
+                            tr("value out of range for a bit - has been forced to 1") );
+                }
+            case SQL_C_UTINYINT:
+                *(SQLCHAR *)pTarget = val.toUInt();
+                break;
+            case SQL_C_SHORT:
+            case SQL_C_SSHORT:
+                *(SQLSMALLINT *)pTarget = val.toInt();
+                break;
+            case SQL_C_USHORT:
+                *(SQLUSMALLINT *)pTarget = val.toUInt();
+                break;
+            case SQL_C_LONG:
+            case SQL_C_SLONG:
+                *(SQLINTEGER *)pTarget = val.toInt();
+                break;
+            case SQL_C_ULONG:
+                *(SQLUINTEGER *)pTarget = val.toUInt();
+                break;
+            case SQL_C_SBIGINT:
+                *(SQLBIGINT *)pTarget = val.toLongLong();
+                break;
+            case SQL_C_UBIGINT:
+                *(SQLBIGINT *)pTarget = val.toULongLong();
+                break;
         }
     }
-    else 
+    else if ( MDataConvert::isVarLengthCType( nTargetType ) )
     {
-        pResultGetData->nBytesRemaining = pResultGetData->stringData.length();
-        MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_01004 ) );
-    }
+        int copysize = nBufferLength;
+        QByteArray data = val.toByteArray();
 
-    MYODBCDbgReturn( SQL_SUCCESS );
-}
+        /* save extra byte(s) for NULL */
+        if ( nTargetType == SQL_C_CHAR )
+            copysize--;
+        else if ( nTargetType == SQL_C_WCHAR )
+            copysize -= sizeof(SQLWCHAR);
 
-/*!
-    \brief  Converts data to SQL_C_WCHAR.
+        /* convert to SQLWCHAR if requested and initial call */
+        if ( nTargetType == SQL_C_WCHAR )
+        {
+            if ( stateGetData.bytearrayData.isEmpty() )
+            {
+                QString s = QString::fromUtf8( data.constData() );
+                stateGetData.bytearrayData.reserve(
+                        s.length() * sizeof(SQLWCHAR) );
+                int len = s.toWCharArray(
+                        (wchar_t *)stateGetData.bytearrayData.data() );
+                stateGetData.bytearrayData.resize( len * sizeof(SQLWCHAR) );
+            }
 
-            This method uses information provided in MStateGetData to fill a target
buffer with the 
-            specified cell data - converted as needed.
+            data = stateGetData.bytearrayData;
+        }
 
-    \param  pResultGetData  Reference to a MStateGetData. This should be initialized with
cell data etc.
+        const char *cdata = data.constData();
+        SQLUINTEGER datalen = data.length();
 
-    \return SQLRETURN
-
-    \sa getData()
-*/
-SQLRETURN MResult::toWCharC( MStateGetData *pResultGetData )
-{
-    MYODBCDbgEnter();
-
-    /*!
-        \internal ODBC RULE
-
-       
+-------------+------------------------------------------+-----------------+------------------------------+----------+
-        | C Type      | Test                                     | TargetValuePtr  |
StrLen_or_IndPtr             | SQLSTATE |
-       
+-------------+------------------------------------------+-----------------+------------------------------+----------+
-        | SQL_C_WCHAR | Character length of data < BufferLength  | Data            |
Length of data in characters | n/a      |
-        |             | Character length of data >= BufferLength | Truncated data  |
Length of data in characters | 01004    |
-       
+-------------+------------------------------------------+-----------------+------------------------------+----------+
-
-        When character data is returned from the driver to the application, the driver
must always null-terminate it. 
-        This gives the application the choice of whether to handle the data as a string
or a character array. If the 
-        application buffer is not large enough to return all of the character data, the
driver truncates it to the byte 
-        length of the buffer less the number of bytes required by the null-termination
character, null-terminates the 
-        truncated data, and stores it in the buffer. Therefore, applications must always
allocate extra space for the 
-        null-termination character in buffers used to retrieve character data. For
example, a 51-byte buffer is needed 
-        to retrieve 50 characters of data.
-    */
-
-    /* convert to string (if possible) */
-    if ( pResultGetData->stringData.isEmpty() )
-    {
-        if ( !vectorRows[pResultGetData->nRow][pResultGetData->nColumn -
1].canConvert( QVariant::String ) )
-            MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_07006 ) );
-        /* make a copy we can easily work with (avoid re-convert) in case of chunking
(optimize this later) */
-        pResultGetData->stringData  =
vectorRows[pResultGetData->nRow][pResultGetData->nColumn - 1].toString();
-        pResultGetData->nBytesTotal = pResultGetData->stringData.length() *
sizeof(SQLWCHAR); /* >1 bytes = char in this case */
-        pResultGetData->nBytesPrev = pResultGetData->nBytesTotal; /* init
prev-bytes */
-    }
-
-    /* do we even need to do the data bit (or just looking for len)? */
-    if ( pResultGetData->pTarget && pResultGetData->nBytesMax )
-    {
-        if ( MYODBCC::doStringCopyOut( (SQLWCHAR*)pResultGetData->pTarget,
-                    pResultGetData->nBytesMax / sizeof(SQLWCHAR),
-                    pResultGetData->stringData ) )
+        /* short-circuit return SQL_NO_DATA if we're done */
+        if ( datalen && datalen == stateGetData.pos )
         {
-            pResultGetData->nBytesRemaining = 0;
+            MYODBCDbgReturn( SQL_NO_DATA );
         }
-        else
-        {
-            /* remove chars returned thus far from our working copy */
-            pResultGetData->nBytesRemaining = pResultGetData->stringData.length() *
sizeof(SQLWCHAR) - pResultGetData->nBytesMax;
-            pResultGetData->stringData.remove( 0, pResultGetData->nBytesMax  /
sizeof(SQLWCHAR) );
-            MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_01004 ) );
-        }
-    }
-    else 
-    {
-        pResultGetData->nBytesRemaining = pResultGetData->stringData.length() *
sizeof(SQLWCHAR);
-        MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_01004 ) );
-    }
 
-    MYODBCDbgReturn( SQL_SUCCESS );
-}
+        /* limit to whats available */
+        if ( stateGetData.pos + copysize > datalen )
+            copysize = data.length() - stateGetData.pos;
 
-/*!
-    \brief  Converts data to SQL_C_SSHORT.
+        /* assign len/ind ptr with data available BEFORE this call */
+        MYODBCCSet( pnIndicator, datalen - stateGetData.pos );
 
-            This method uses information provided in MStateGetData to fill a target
buffer with the 
-            specified cell data - converted as needed.
+        /* fill the buffer if given */
+        if ( pTarget )
+        {
+            memcpy( pTarget, cdata + stateGetData.pos, copysize );
 
-    \param  pResultGetData  Reference to a MStateGetData. This should be initialized with
cell data etc.
+            /* NULL-term string */
+            if ( nTargetType == SQL_C_CHAR )
+                *((SQLCHAR *)pTarget + copysize) = 0;
+            else if ( nTargetType == SQL_C_WCHAR )
+            {
+                int i;
+                SQLCHAR *p = (SQLCHAR *)pTarget + copysize;
+                for(i = 0; i < sizeof(SQLWCHAR); ++i)
+                    p[i] = 0;
+            }
 
-    \return SQLRETURN
+            /* advance position */
+            stateGetData.pos += copysize;
+        }
 
-    \sa getData()
-*/
-SQLRETURN MResult::toSShortC( MStateGetData *pResultGetData )
-{
-    MYODBCDbgEnter();
-
-    /*!
-        \internal ODBC RULE
-
-        +--------------+
-        | C Type       |
-        +--------------+
-        | SQL_C_SSHORT |
-        +--------------+
-    */
-
-    pResultGetData->nBytesTotal     = sizeof(short);
-    pResultGetData->nBytesRemaining = 0;
-
-    /*!
-        \internal ODBC RULE
-
-        The TargetValuePtr argument was a null pointer, and more data was available to
return.
-    */
-    if ( !pResultGetData->pTarget )
-        MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_01004 ) );
-
-    if ( !vectorRows[pResultGetData->nRow][pResultGetData->nColumn - 1].canConvert(
QVariant::Int ) ) 
-        MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_07006 ) );
-
-    *((short *)(pResultGetData->pTarget)) =
(short)vectorRows[pResultGetData->nRow][pResultGetData->nColumn - 1].toInt();
-
-    MYODBCDbgReturn( SQL_SUCCESS );
-}
-
-/*!
-    \brief  Converts data to SQL_C_USHORT.
-
-            This method uses information provided in MStateGetData to fill a target
buffer with the 
-            specified cell data - converted as needed.
-
-    \param  pResultGetData  Reference to a MStateGetData. This should be initialized with
cell data etc.
-
-    \return SQLRETURN
-
-    \sa getData()
-*/
-SQLRETURN MResult::toUShortC( MStateGetData *pResultGetData )
-{
-    MYODBCDbgEnter();
-
-    pResultGetData->nBytesTotal     = sizeof(unsigned short);
-    pResultGetData->nBytesRemaining = 0;
-
-    /*!
-        \internal ODBC RULE
-
-        The TargetValuePtr argument was a null pointer, and more data was available to
return.
-    */
-    if ( !pResultGetData->pTarget )
-        MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_01004 ) );
-
-    if ( !vectorRows[pResultGetData->nRow][pResultGetData->nColumn - 1].canConvert(
QVariant::UInt ) ) 
-        MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_07006 ) );
-
-    *((unsigned short *)pResultGetData->pTarget) = (unsigned
short)vectorRows[pResultGetData->nRow][pResultGetData->nColumn - 1].toUInt();
-
-    MYODBCDbgReturn( SQL_SUCCESS );
-}
-
-/*!
-    \brief  Converts data to SQL_C_SLONG.
-
-            This method uses information provided in MStateGetData to fill a target
buffer with the 
-            specified cell data - converted as needed.
-
-    \param  pResultGetData  Reference to a MStateGetData. This should be initialized with
cell data etc.
-
-    \return SQLRETURN
-
-    \sa getData()
-*/
-SQLRETURN MResult::toSLongC( MStateGetData *pResultGetData )
-{
-    MYODBCDbgEnter();
-
-    pResultGetData->nBytesTotal     = sizeof(long);
-    pResultGetData->nBytesRemaining = 0;
-
-    /*!
-        \internal ODBC RULE
-
-        The TargetValuePtr argument was a null pointer, and more data was available to
return.
-    */
-    if ( !pResultGetData->pTarget )
-        MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_01004 ) );
-
-    /*!
-        \internal MYODBC RULE
-
-        Try to be smart about dates and times. We probably could do this for all numeric
types but
-        for now do it here so we are compat. with v3.
-    */
-    if ( MYODBCC::isDateTimeTypeSQL(
pResultGetData->pImpRowDescRec->getConciseType(),
getEnvironment()->getODBCVersion() ) )
-    {
-        if ( !vectorRows[pResultGetData->nRow][pResultGetData->nColumn -
1].canConvert( QVariant::DateTime ) ) 
-            MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_07006 ) );
-
-        *((unsigned long *)pResultGetData->pTarget) = (unsigned
long)vectorRows[pResultGetData->nRow][pResultGetData->nColumn -
1].toDateTime().toTime_t();
-        
-    }
-    else
-    {
-        if ( !vectorRows[pResultGetData->nRow][pResultGetData->nColumn -
1].canConvert( QVariant::Int ) ) 
-            MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_07006 ) );
-        *((long *)pResultGetData->pTarget) =
(long)vectorRows[pResultGetData->nRow][pResultGetData->nColumn - 1].toInt();
-    }
-
-    MYODBCDbgReturn( SQL_SUCCESS );
-}
-
-/*!
-    \brief  Converts data to SQL_C_ULONG.
-
-            This method uses information provided in MStateGetData to fill a target
buffer with the 
-            specified cell data - converted as needed.
-
-    \param  pResultGetData  Reference to a MStateGetData. This should be initialized with
cell data etc.
-
-    \return SQLRETURN
-
-    \sa getData()
-*/
-SQLRETURN MResult::toULongC( MStateGetData *pResultGetData )
-{
-    MYODBCDbgEnter();
-
-    pResultGetData->nBytesTotal     = sizeof(unsigned long);
-    pResultGetData->nBytesRemaining = 0;
-
-    /*!
-        \internal ODBC RULE
-
-        The TargetValuePtr argument was a null pointer, and more data was available to
return.
-    */
-    if ( !pResultGetData->pTarget )
-        MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_01004 ) );
-
-    if ( !vectorRows[pResultGetData->nRow][pResultGetData->nColumn - 1].canConvert(
QVariant::UInt ) ) 
-        MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_07006 ) );
-
-    *((unsigned long *)pResultGetData->pTarget) = (unsigned
long)vectorRows[pResultGetData->nRow][pResultGetData->nColumn - 1].toUInt();
-
-    MYODBCDbgReturn( SQL_SUCCESS );
-}
-
-/*!
-    \brief  Converts data to SQL_C_FLOAT.
-
-            This method uses information provided in MStateGetData to fill a target
buffer with the 
-            specified cell data - converted as needed.
-
-    \param  pResultGetData  Reference to a MStateGetData. This should be initialized with
cell data etc.
-
-    \return SQLRETURN
-
-    \sa getData()
-*/
-SQLRETURN MResult::toFloatC( MStateGetData *pResultGetData )
-{
-    MYODBCDbgEnter();
-
-    pResultGetData->nBytesTotal     = sizeof(float);
-    pResultGetData->nBytesRemaining = 0;
-
-    /*!
-        \internal ODBC RULE
-
-        The TargetValuePtr argument was a null pointer, and more data was available to
return.
-    */
-    if ( !pResultGetData->pTarget )
-        MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_01004 ) );
-
-    if ( !vectorRows[pResultGetData->nRow][pResultGetData->nColumn - 1].canConvert(
QVariant::Double ) ) 
-        MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_07006 ) );
-
-    *((float *)pResultGetData->pTarget) =
(float)vectorRows[pResultGetData->nRow][pResultGetData->nColumn - 1].toDouble();
-
-    MYODBCDbgReturn( SQL_SUCCESS );
-}
-
-/*!
-    \brief  Converts data to SQL_C_DOUBLE.
-
-            This method uses information provided in MStateGetData to fill a target
buffer with the 
-            specified cell data - converted as needed.
-
-    \param  pResultGetData  Reference to a MStateGetData. This should be initialized with
cell data etc.
-
-    \return SQLRETURN
-
-    \sa getData()
-*/
-SQLRETURN MResult::toDoubleC( MStateGetData *pResultGetData )
-{
-    MYODBCDbgEnter();
-
-    pResultGetData->nBytesTotal     = sizeof(double);
-    pResultGetData->nBytesRemaining = 0;
-
-    /*!
-        \internal ODBC RULE
-
-        The TargetValuePtr argument was a null pointer, and more data was available to
return.
-    */
-    if ( !pResultGetData->pTarget )
-        MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_01004 ) );
-
-    if ( !vectorRows[pResultGetData->nRow][pResultGetData->nColumn - 1].canConvert(
QVariant::Double ) ) 
-        MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_07006 ) );
-
-    *((double *)pResultGetData->pTarget) =
(double)vectorRows[pResultGetData->nRow][pResultGetData->nColumn - 1].toDouble();
-
-    MYODBCDbgReturn( SQL_SUCCESS );
-}
-
-/*!
-    \brief  Converts data to SQL_C_BIT.
-
-            This method uses information provided in MStateGetData to fill a target
buffer with the 
-            specified cell data - converted as needed.
-
-    \param  pResultGetData  Reference to a MStateGetData. This should be initialized with
cell data etc.
-
-    \return SQLRETURN
-
-    \sa getData()
-*/
-SQLRETURN MResult::toBitC( MStateGetData *pResultGetData )
-{
-    MYODBCDbgEnter();
-
-    pResultGetData->nBytesTotal     = sizeof(unsigned char);
-    pResultGetData->nBytesRemaining = 0;
-
-    /*!
-        \internal ODBC RULE
-
-        The TargetValuePtr argument was a null pointer, and more data was available to
return.
-    */
-    if ( !pResultGetData->pTarget )
-        MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_01004 ) );
-
-    if ( !vectorRows[pResultGetData->nRow][pResultGetData->nColumn - 1].canConvert(
QVariant::Int ) ) 
-        MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_07006 ) );
-
-    /*!
-        \internal MYODBC RULE
-
-        We silently change bogus values to 1.
-
-        This rule is for compat with v3 - but we issue a warning.
-    */
-    if ( vectorRows[pResultGetData->nRow][pResultGetData->nColumn - 1].toInt() == 0
)
-        *((unsigned char *)pResultGetData->pTarget) = 0;
-    else if ( vectorRows[pResultGetData->nRow][pResultGetData->nColumn - 1].toInt()
== 1 )
-        *((unsigned char *)pResultGetData->pTarget) = 1;
-    else
-    {
-        *((unsigned char *)pResultGetData->pTarget) = 1;
-        getDiagnostic()->doAppend( MDiagnostic::STATE_01000, 0, tr("value out of range
for a bit - has been forced to 1") );
-    }
-
-    MYODBCDbgReturn( SQL_SUCCESS );
-}
-
-/*!
-    \brief  Converts data to SQL_C_STINYINT.
-
-            This method uses information provided in MStateGetData to fill a target
buffer with the 
-            specified cell data - converted as needed.
-
-    \param  pResultGetData  Reference to a MStateGetData. This should be initialized with
cell data etc.
-
-    \return SQLRETURN
-
-    \sa getData()
-*/
-SQLRETURN MResult::toSTinyIntC( MStateGetData *pResultGetData )
-{
-    MYODBCDbgEnter();
-
-    pResultGetData->nBytesTotal     = sizeof(char);
-    pResultGetData->nBytesRemaining = 0;
-
-    /*!
-        \internal ODBC RULE
-
-        The TargetValuePtr argument was a null pointer, and more data was available to
return.
-    */
-    if ( !pResultGetData->pTarget )
-        MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_01004 ) );
-
-    if ( !vectorRows[pResultGetData->nRow][pResultGetData->nColumn - 1].canConvert(
QVariant::Int ) ) 
-        MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_07006 ) );
-
-    *((char *)pResultGetData->pTarget) =
vectorRows[pResultGetData->nRow][pResultGetData->nColumn - 1].toInt();
-
-    MYODBCDbgReturn( SQL_SUCCESS );
-}
-
-/*!
-    \brief  Converts data to SQL_C_UTINYINT.
-
-            This method uses information provided in MStateGetData to fill a target
buffer with the 
-            specified cell data - converted as needed.
-
-    \param  pResultGetData  Reference to a MStateGetData. This should be initialized with
cell data etc.
-
-    \return SQLRETURN
-
-    \sa getData()
-*/
-SQLRETURN MResult::toUTinyIntC( MStateGetData *pResultGetData )
-{
-    MYODBCDbgEnter();
-
-    pResultGetData->nBytesTotal     = sizeof(unsigned char);
-    pResultGetData->nBytesRemaining = 0;
-
-    /*!
-        \internal ODBC RULE
-
-        The TargetValuePtr argument was a null pointer, and more data was available to
return.
-    */
-    if ( !pResultGetData->pTarget )
-        MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_01004 ) );
-
-    if ( !vectorRows[pResultGetData->nRow][pResultGetData->nColumn - 1].canConvert(
QVariant::UInt ) ) 
-        MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_07006 ) );
-
-    *((unsigned char *)pResultGetData->pTarget) =
vectorRows[pResultGetData->nRow][pResultGetData->nColumn - 1].toUInt();
-
-    MYODBCDbgReturn( SQL_SUCCESS );
-}
-
-/*!
-    \brief  Converts data to SQL_C_SBIGINT.
-
-            This method uses information provided in MStateGetData to fill a target
buffer with the 
-            specified cell data - converted as needed.
-
-    \param  pResultGetData  Reference to a MStateGetData. This should be initialized with
cell data etc.
-
-    \return SQLRETURN
-
-    \sa getData()
-*/
-SQLRETURN MResult::toSBigIntC( MStateGetData *pResultGetData )
-{
-    MYODBCDbgEnter();
-
-    pResultGetData->nBytesTotal     = sizeof(qint64);
-    pResultGetData->nBytesRemaining = 0;
-
-    /*!
-        \internal ODBC RULE
-
-        The TargetValuePtr argument was a null pointer, and more data was available to
return.
-    */
-    if ( !pResultGetData->pTarget )
-        MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_01004 ) );
-
-    if ( !vectorRows[pResultGetData->nRow][pResultGetData->nColumn - 1].canConvert(
QVariant::LongLong ) ) 
-        MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_07006 ) );
-
-    *((qint64 *)pResultGetData->pTarget) =
(qint64)vectorRows[pResultGetData->nRow][pResultGetData->nColumn - 1].toLongLong();
-
-    MYODBCDbgReturn( SQL_SUCCESS );
-}
-
-/*!
-    \brief  Converts data to SQL_C_UBIGINT.
-
-            This method uses information provided in MStateGetData to fill a target
buffer with the 
-            specified cell data - converted as needed.
-
-    \param  pResultGetData  Reference to a MStateGetData. This should be initialized with
cell data etc.
-
-    \return SQLRETURN
-
-    \sa getData()
-*/
-SQLRETURN MResult::toUBigIntC( MStateGetData *pResultGetData )
-{
-    MYODBCDbgEnter();
-
-    pResultGetData->nBytesTotal     = sizeof(quint64);
-    pResultGetData->nBytesRemaining = 0;
-
-    /*!
-        \internal ODBC RULE
-
-        The TargetValuePtr argument was a null pointer, and more data was available to
return.
-    */
-    if ( !pResultGetData->pTarget )
-        MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_01004 ) );
-
-    if ( !vectorRows[pResultGetData->nRow][pResultGetData->nColumn - 1].canConvert(
QVariant::ULongLong ) ) 
-        MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_07006 ) );
-
-    *((quint64 *)pResultGetData->pTarget) =
(quint64)vectorRows[pResultGetData->nRow][pResultGetData->nColumn -
1].toULongLong();
-
-    MYODBCDbgReturn( SQL_SUCCESS );
-}
-
-/*!
-    \brief  Converts data to SQL_C_BINARY.
-
-            This method uses information provided in MStateGetData to fill a target
buffer with the 
-            specified cell data - converted as needed.
-
-    \param  pResultGetData  Reference to a MStateGetData. This should be initialized with
cell data etc.
-
-    \return SQLRETURN
-
-    \sa getData()
-*/
-SQLRETURN MResult::toBinaryC( MStateGetData *pResultGetData )
-{
-    MYODBCDbgEnter();
-
-    /* convert to bytearray */
-    if ( pResultGetData->bytearrayData.isEmpty() )
-    {
-        if ( !vectorRows[pResultGetData->nRow][pResultGetData->nColumn -
1].canConvert( QVariant::ByteArray ) )
-            MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_07006 ) );
-        /* make a copy we can easily work with (avoid re-convert) in case of chunking
(optimize this later) */
-        pResultGetData->bytearrayData =
vectorRows[pResultGetData->nRow][pResultGetData->nColumn - 1].toByteArray();
-        pResultGetData->nBytesTotal   = pResultGetData->bytearrayData.size();
-        pResultGetData->nBytesPrev = pResultGetData->nBytesTotal; /* init
prev-bytes */
-    }
-
-    /* do we even need to do the data bit (or just looking for len)? */
-    if ( pResultGetData->pTarget && pResultGetData->nBytesMax )
-    {
-        MYODBCC::doMemCpy( pResultGetData->pTarget,
-                pResultGetData->bytearrayData.constData(),
-                std::min( pResultGetData->nBytesMax,
-                    (SQLINTEGER)pResultGetData->bytearrayData.size() ) );
-        if ( pResultGetData->bytearrayData.size() < pResultGetData->nBytesMax )
+        /* determine return */
+        if ( stateGetData.pos < datalen )
         {
-            pResultGetData->nBytesRemaining = 0;
+            MYODBCDbgReturn( getDiagnostic()->doAppend(
+                        MDiagnostic::STATE_01004 ) );
         }
         else
         {
-            /* remove chars returned thus far from our working copy */
-            pResultGetData->nBytesRemaining = pResultGetData->bytearrayData.size()
- pResultGetData->nBytesMax;
-            pResultGetData->bytearrayData.remove( 0, pResultGetData->nBytesMax );
-            MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_01004 ) );
+            MYODBCDbgReturn( SQL_SUCCESS );
         }
     }
-    else 
-    {
-        pResultGetData->nBytesRemaining = pResultGetData->bytearrayData.size();
-        MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_01004 ) );
-    }
-
-    MYODBCDbgReturn( SQL_SUCCESS );
-}
-
-/*!
-    \brief  Converts data to SQL_C_VARBOOKMARK.
-
-            This method uses information provided in MStateGetData to fill a target
buffer with the 
-            specified cell data - converted as needed.
-
-    \note   We may never really use this as bookmark requests will likely get intercepted
higher up
-            the 'food chain'. But doing this allows us to put a bookmark into the result
set and 
-            subsequently in our data conversion 'hub' - the Variant cell value.
-
-    \param  pResultGetData  Reference to a MStateGetData. This should be initialized with
cell data etc.
-
-    \return SQLRETURN
-
-    \sa getData()
-*/
-SQLRETURN MResult::toVarBookmarkC( MStateGetData *pResultGetData )
-{
-    MYODBCDbgEnter();
-    MYODBCDbgReturn( toBinaryC( pResultGetData ) );
-}
-
-/*!
-    \brief  Converts data to SQL_C_TYPE_DATE.
-
-            This method uses information provided in MStateGetData to fill a target
buffer with the 
-            specified cell data - converted as needed.
-
-    \param  pResultGetData  Reference to a MStateGetData. This should be initialized with
cell data etc.
-
-    \return SQLRETURN
-
-    \sa getData()
-*/
-SQLRETURN MResult::toTypeDateC( MStateGetData *pResultGetData )
-{
-    MYODBCDbgEnter();
-
-    pResultGetData->nBytesTotal     = sizeof(SQL_DATE_STRUCT);
-    pResultGetData->nBytesRemaining = 0;
-
-    /*!
-        \internal ODBC RULE
-
-        The TargetValuePtr argument was a null pointer, and more data was available to
return.
-    */
-    if ( !pResultGetData->pTarget )
-        MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_01004 ) );
-
-    SQL_DATE_STRUCT *pDateTarget = (SQL_DATE_STRUCT *)pResultGetData->pTarget;
-
-    if ( !vectorRows[pResultGetData->nRow][pResultGetData->nColumn - 1].canConvert(
QVariant::Date ) ) 
-        MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_07006 ) );
-
-    QDate d = vectorRows[pResultGetData->nRow][pResultGetData->nColumn -
1].toDate();
-
-    if ( d.isNull() || !d.isValid() )
-    {
-        MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_22007 ) );
-    }
     else
     {
-        pDateTarget->day    = d.day();
-        pDateTarget->month  = d.month();
-        pDateTarget->year   = d.year();
-    }
+        switch( nTargetType )
+        {
+            /***** float *****/
+            case SQL_C_FLOAT:
+                *((SQLREAL *)pTarget) = val.toDouble();
+                break;
+            case SQL_C_DOUBLE:
+                *((SQLFLOAT *)pTarget) = val.toDouble();
+                break;
+            case SQL_C_NUMERIC:
+            {
+                QString  stringData = val.toString().trimmed();
 
-    MYODBCDbgReturn( SQL_SUCCESS );
-}
+                SQL_NUMERIC_STRUCT *pNumericTarget = (SQL_NUMERIC_STRUCT *)pTarget;
 
-/*!
-    \brief  Converts data to SQL_C_TYPE_TIME.
+                pNumericTarget->sign = 1;
+                pNumericTarget->precision = precision;
+                pNumericTarget->scale = scale;
 
-            This method uses information provided in MStateGetData to fill a target
buffer with the 
-            specified cell data - converted as needed.
+                /*!
+                    \internal ODBC RULE
 
-    \param  pResultGetData  Reference to a MStateGetData. This should be initialized with
cell data etc.
+                    The sign field is 1 if positive, 0 if negative.
 
-    \return SQLRETURN
+                    \note
 
-    \sa getData()
-*/
-SQLRETURN MResult::toTypeTimeC( MStateGetData *pResultGetData )
-{
-    MYODBCDbgEnter();
+                    The ODBC 3.0 spec required drivers to return the sign as 1 for
positive numbers and 2 for
+                    negative number. This was changed in the ODBC 3.5 spec to return 0
for negative instead of 2.
+                */
+                if ( stringData[0] == QChar( '-' ) )
+                {
+                    stringData.remove( 1, 1 );
+                    pNumericTarget->sign = 0;
+                }
+                else if ( stringData[0] == QChar( '+' ) )
+                {
+                    stringData.remove( 1, 1 );
+                    pNumericTarget->sign = 1;
+                }
 
-    pResultGetData->nBytesTotal     = sizeof(SQL_TIME_STRUCT);
-    pResultGetData->nBytesRemaining = 0;
+                /* get precision & scale strings */
+                int nWhole = 0;
+                int nDecimal = 0;
 
-    /*!
-        \internal ODBC RULE
+                QStringList stringlistData = stringData.split( '.' );
 
-        The TargetValuePtr argument was a null pointer, and more data was available to
return.
-    */
-    if ( !pResultGetData->pTarget )
-        MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_01004 ) );
+                if ( stringlistData.count() > 2 )
+                    MYODBCDbgReturn( getDiagnostic()->doAppend(
+                                MDiagnostic::STATE_07006, 0,
+                                tr("Data was converted to string but then had too many
decimal points.") ) );
+                if ( stringlistData.count() > 1 )
+                     nDecimal = stringlistData[1].length();
+                if ( stringlistData.count() > 0 )
+                     nWhole = stringlistData[0].length();
 
-    SQL_TIME_STRUCT *pTimeTarget = (SQL_TIME_STRUCT *)pResultGetData->pTarget;
+                int nPrecision = nWhole + nDecimal;
 
-    if ( !vectorRows[pResultGetData->nRow][pResultGetData->nColumn - 1].canConvert(
QVariant::Time ) ) 
-        MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_07006 ) );
+                /* check for truncation */
+                BOOL bFractionalTruncation = false;
 
-    QTime t             = vectorRows[pResultGetData->nRow][pResultGetData->nColumn
- 1].toTime();
-    pTimeTarget->hour   = t.hour();
-    pTimeTarget->minute = t.minute();
-    pTimeTarget->second = t.second();
+                if ( nPrecision > pNumericTarget->precision )
+                    MYODBCDbgReturn( getDiagnostic()->doAppend(
MDiagnostic::STATE_22003 ) );
 
-    MYODBCDbgReturn( SQL_SUCCESS );
-}
+                if ( nDecimal > pNumericTarget->scale )
+                {
+                    if ( pNumericTarget->scale == 0 )
+                        stringlistData[1] = QString::null;
+                    else
+                        stringlistData[1].truncate( pNumericTarget->scale );
+                    bFractionalTruncation = true;
+                    nDecimal = stringlistData[1].length();
+                }
 
-/*!
-    \brief  Converts data to SQL_C_TYPE_TIMESTAMP.
+                QString stringValueToPack;
+                if ( stringlistData.size() == 2 )
+                    stringValueToPack = QString( stringlistData[0] + stringlistData[1] );
+                else
+                    stringValueToPack = stringlistData[0];
+                ulonglong nValueToPack = stringValueToPack.toULongLong();
 
-            This method uses information provided in MStateGetData to fill a target
buffer with the 
-            specified cell data - converted as needed.
+                /*!
+                    \internal ODBC RULE
 
-    \param  pResultGetData  Reference to a MStateGetData. This should be initialized with
cell data etc.
+                    A number is stored in the val field of the SQL_NUMERIC_STRUCT
structure as a scaled integer,
+                    in little endian mode (the leftmost byte being the least-significant
byte). For example, the
+                    number 10.001 base 10, with a scale of 4, is scaled to an integer of
100010. Because this is
+                    186AA in hexadecimal format, the value in SQL_NUMERIC_STRUCT would be
"AA 86 01 00 00 ... 00",
+                    with the number of bytes defined by the SQL_MAX_NUMERIC_LEN #define.
+                */
 
-    \return SQLRETURN
+#if MYODBC_DBG > 1
+                MYODBCDbgInfo( QString( "stringlistData[0]  =%1" ).arg( stringlistData[0]
) );
+                MYODBCDbgInfo( QString( "stringlistData[1]  =%1" ).arg( stringlistData[1]
) );
+                MYODBCDbgInfo( QString( "stringValueToPack  =%1" ).arg( stringValueToPack
) );
+                MYODBCDbgInfo( QString( "stringData         =%1" ).arg( stringData ) );
+                MYODBCDbgInfo( QString( "nValueToPack       =%1" ).arg( nValueToPack ) );
+#endif
 
-    \sa getData()
-*/
-SQLRETURN MResult::toTypeTimestampC( MStateGetData *pResultGetData )
-{
-    MYODBCDbgEnter();
+                MYODBCC::num_pack( pNumericTarget->val, (int)nValueToPack );
 
-    pResultGetData->nBytesTotal     = sizeof(SQL_TIMESTAMP_STRUCT);
-    pResultGetData->nBytesRemaining = 0;
+                if ( bFractionalTruncation )
+                    MYODBCDbgReturn( getDiagnostic()->doAppend(
MDiagnostic::STATE_01S07 ) );
 
-    QVariant val = vectorRows[pResultGetData->nRow][pResultGetData->nColumn - 1];
+                break;
+            }
+            /***** date & time *****/
+            case SQL_C_TYPE_DATE:
+            case SQL_C_DATE:
+            {
+                SQL_DATE_STRUCT *pDate = (SQL_DATE_STRUCT *)pTarget;
+                QDate d = val.toDate();
 
-    /*!
-        \internal ODBC RULE
+                if ( d.isNull() || !d.isValid() )
+                {
+                    MYODBCDbgReturn( getDiagnostic()->doAppend(
+                                MDiagnostic::STATE_22007 ) );
+                }
+                else
+                {
+                    pDate->day    = d.day();
+                    pDate->month  = d.month();
+                    pDate->year   = d.year();
+                }
+                break;
+            }
+            case SQL_C_TYPE_TIME:
+            case SQL_C_TIME:
+            {
+                SQL_TIME_STRUCT *pTime= (SQL_TIME_STRUCT *)pTarget;
 
-        The TargetValuePtr argument was a null pointer, and more data was available to
return.
-    */
-    if ( !pResultGetData->pTarget )
-        MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_01004 ) );
+                /* validity check, allowed by spec to be zero (but not Qt) */
+                if ( !val.canConvert( QVariant::Time ) &&
+                        !(val.toString() == QString( "00:00:00" )) )
+                {
+                    MYODBCDbgReturn( getDiagnostic()->doAppend(
+                                MDiagnostic::STATE_22007 ) );
+                }
 
-    SQL_TIMESTAMP_STRUCT *pTimeStampTarget = (SQL_TIMESTAMP_STRUCT
*)pResultGetData->pTarget;
+                QTime t = val.toTime();
+                pTime->hour = t.hour();
+                pTime->minute = t.minute();
+                pTime->second = t.second();
+                break;
+            }
+            case SQL_C_TYPE_TIMESTAMP:
+            case SQL_C_TIMESTAMP:
+            {
+                QDateTime t;
 
-    if ( !val.canConvert( QVariant::DateTime ) ) 
-        MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_07006 ) );
+                int len = val.toString().size();
 
-    QDateTime t;
+                /* if we only have the time, use today's date per spec */
+                if ( pImpRowDescRec->getConciseType() == SQL_TYPE_TIME ||
+                        /* strings that LOOK like time 12:30 or 12:30:00 */
+                        len == 5 || len == 8)
+                {
+                    QTime time;
+                    if ( len == 8 )
+                        time = QTime::fromString( val.toString(), "hh:mm:ss" );
+                    else if ( len == 5 )
+                        time = QTime::fromString( val.toString(), "hh:mm" );
 
-    int len = val.toString().size();
+                    if ( time.isValid() )
+                    {
+                        t = QDateTime::currentDateTime();
+                        t.setTime( time );
+                    }
+                }
+                else
+                {
+                    if ( val.canConvert( QVariant::DateTime ) )
+                        t = val.toDateTime();
+                }
 
-    /* if we only have the time, use today's date per spec */
-    if ( pResultGetData->pImpRowDescRec->getConciseType() == SQL_TYPE_TIME ||
-            /* strings that LOOK like time 12:30 or 12:30:00 */
-            len == 5 || len == 8)
-    {
-        t = QDateTime::currentDateTime();
-        t.setTime( val.toTime() );
-    }
-    else
-    {
-        t = val.toDateTime();
-    }
+                /* we can only return valid dates */
+                if ( t.isNull() || !t.isValid() )
+                {
+                    MYODBCDbgReturn( getDiagnostic()->doAppend(
+                                MDiagnostic::STATE_22007 ) );
+                }
 
-    /* we can only return valid dates */
-    if ( t.isNull() || !t.isValid() )
-    {
-        MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_22007 ) );
-    }
-    else
-    {
-        pTimeStampTarget->year       = t.date().year();
-        pTimeStampTarget->month      = t.date().month();
-        pTimeStampTarget->day        = t.date().day();
-        pTimeStampTarget->hour       = t.time().hour();
-        pTimeStampTarget->minute     = t.time().minute();
-        pTimeStampTarget->second     = t.time().second();
-        pTimeStampTarget->fraction   = t.time().msec() * 1000000;
-    }
+                SQL_TIMESTAMP_STRUCT *pTimeStamp=
+                    (SQL_TIMESTAMP_STRUCT *)pTarget;
+                pTimeStamp->year       = t.date().year();
+                pTimeStamp->month      = t.date().month();
+                pTimeStamp->day        = t.date().day();
+                pTimeStamp->hour       = t.time().hour();
+                pTimeStamp->minute     = t.time().minute();
+                pTimeStamp->second     = t.time().second();
+                /* fractions not supported */
+                pTimeStamp->fraction   = 0;
+                break;
+            }
 
-    MYODBCDbgReturn( SQL_SUCCESS );
-}
+            /***** TODO date time interval *****/
+            /*
+            case SQL_C_INTERVAL_MONTH:
+            case SQL_C_INTERVAL_YEAR:
+            case SQL_C_INTERVAL_YEAR_TO_MONTH:
 
-/*!
-    \brief          Attempts to get the data into a SQL_NUMERIC_STRUCT.
-
-                    The precision and scale fields of SQL_NUMERIC_STRUCT are for output
only. In other
-                    words the app can not set them and expect it to mean anything. This
is according to
-                    the ODBC specification. But we are an internal method used to support
higher-level
-                    versions of getData() and as such we expect precision and scale
fields to hold viable
-                    values as per (other) ODBC rules.
-
-    \note           Not all source data can be converted to a SQL_NUMERIC_STRUCT. There
are ODBC rules
-                    which govern this - most of which may have been applied before
getting here.
-
-    \param  pResultGetData  Reference to a MStateGetData. This should be initialized with
cell data etc.
-
-    \return SQLRETURN
-
-    \sa getData()
-*/
-SQLRETURN MResult::toNumericC( MStateGetData *pResultGetData )
-{
-    MYODBCDbgEnter();
-
-    pResultGetData->nBytesTotal     = sizeof(SQL_NUMERIC_STRUCT);
-    pResultGetData->nBytesRemaining = 0;
-
-    /* our high precision stuff (DECIMAL) is stored as a string and all other numerics
can be turned into a string 
-       so lets use a string as our starting point - in this way we hope to catch &
report any possible loss of 
-       precision/scale :) */
-    if ( !vectorRows[pResultGetData->nRow][pResultGetData->nColumn - 1].canConvert(
QVariant::String ) )
-        MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_07006, 0,
tr("Variant (data conversion hub) could not convert to a string.") ) );
-
-    /*!
-        \internal ODBC RULE
-
-        The TargetValuePtr argument was a null pointer, and more data was available to
return.
-    */
-    if ( !pResultGetData->pTarget )
-        MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_01004 ) );
-
-    QString  stringData = vectorRows[pResultGetData->nRow][pResultGetData->nColumn
- 1].toString().trimmed();
-
-    /*!
-        \internal ODBC RULE
-
-        The precision and scale fields of the SQL_C_NUMERIC data type are never used for
input from 
-        an application, only for output from the driver to the application. When the
driver writes a 
-        numeric value into the SQL_NUMERIC_STRUCT, it will use its own driver-specific
default as the 
-        value for the precision field, and it will use the value in the SQL_DESC_SCALE
field of the 
-        application descriptor (which defaults to 0) for the scale field. An application
can provide 
-        its own values for precision and scale by setting the SQL_DESC_PRECISION and
SQL_DESC_SCALE 
-        fields of the application descriptor.
-
-        \sa SQL_ARD_TYPE
-    */
-    SQL_NUMERIC_STRUCT *pNumericTarget = (SQL_NUMERIC_STRUCT
*)pResultGetData->pTarget;
-
-    pNumericTarget->sign = 1;
-
-    /* is default being overidden with ARD? */
-    if ( pResultGetData->pAppRowDescRec )
-    {
-        pNumericTarget->precision =
pResultGetData->pAppRowDescRec->getPrecision();
-        pNumericTarget->scale     = pResultGetData->pAppRowDescRec->getScale();
+            case SQL_C_INTERVAL_DAY:
+            case SQL_C_INTERVAL_HOUR:
+            case SQL_C_INTERVAL_MINUTE:
+            case SQL_C_INTERVAL_SECOND:
+            case SQL_C_INTERVAL_DAY_TO_HOUR:
+            case SQL_C_INTERVAL_DAY_TO_MINUTE:
+            case SQL_C_INTERVAL_DAY_TO_SECOND:
+            case SQL_C_INTERVAL_HOUR_TO_MINUTE:
+            case SQL_C_INTERVAL_HOUR_TO_SECOND:
+            case SQL_C_INTERVAL_MINUTE_TO_SECOND:
+            */
+            /***** TODO guid *****/
+            /*
+            case SQL_C_GUID:
+            */
+        }
     }
-    else
-    {
-        pNumericTarget->precision = 10;   /* default precision    */
-        pNumericTarget->scale     = 0;    /* default scale        */
-    }
 
-    /*!
-        \internal ODBC RULE
-
-        The sign field is 1 if positive, 0 if negative.
-
-        \note 
-
-        The ODBC 3.0 spec required drivers to return the sign as 1 for positive numbers
and 2 for 
-        negative number. This was changed in the ODBC 3.5 spec to return 0 for negative
instead of 2.
-    */
-    if ( stringData[0] == QChar( '-' ) )
-    {
-        stringData.remove( 1, 1 );
-        pNumericTarget->sign = 0;
-    }
-    else if ( stringData[0] == QChar( '+' ) )
-    {
-        stringData.remove( 1, 1 );
-        pNumericTarget->sign = 1;
-    }
-
-    /* get precision & scale strings */
-    int nWhole = 0;
-    int nDecimal = 0;
-
-    QStringList stringlistData = stringData.split( '.' );
-
-    if ( stringlistData.count() > 2 )
-        MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_07006, 0,
tr("Data was converted to string but then had too many decimal points.") ) );
-    if ( stringlistData.count() > 1 )
-         nDecimal = stringlistData[1].length();
-    if ( stringlistData.count() > 0 )
-         nWhole = stringlistData[0].length();
-
-    int nPrecision = nWhole + nDecimal;
-
-
-    /* check for truncation */
-    BOOL bFractionalTruncation = false;
-
-    if ( nPrecision > pNumericTarget->precision )
-        MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_22003 ) );
-
-    if ( nDecimal > pNumericTarget->scale )
-    {
-        if ( pNumericTarget->scale == 0 )
-            stringlistData[1] = QString::null;
-        else
-            stringlistData[1].truncate( pNumericTarget->scale );
-        bFractionalTruncation = true;
-        nDecimal = stringlistData[1].length();
-    }
-
-    QString stringValueToPack;
-    if ( stringlistData.size() == 2 )
-        stringValueToPack = QString( stringlistData[0] + stringlistData[1] );
-    else
-        stringValueToPack = stringlistData[0];
-    ulonglong nValueToPack = stringValueToPack.toULongLong();
-
-    /*!
-        \internal ODBC RULE
-
-        A number is stored in the val field of the SQL_NUMERIC_STRUCT structure as a
scaled integer, 
-        in little endian mode (the leftmost byte being the least-significant byte). For
example, the 
-        number 10.001 base 10, with a scale of 4, is scaled to an integer of 100010.
Because this is 
-        186AA in hexadecimal format, the value in SQL_NUMERIC_STRUCT would be "AA 86 01
00 00 ... 00", 
-        with the number of bytes defined by the SQL_MAX_NUMERIC_LEN #define.
-    */
-
-#if MYODBC_DBG > 1
-    MYODBCDbgInfo( QString( "stringlistData[0]  =%1" ).arg( stringlistData[0] ) );
-    MYODBCDbgInfo( QString( "stringlistData[1]  =%1" ).arg( stringlistData[1] ) );
-    MYODBCDbgInfo( QString( "stringValueToPack  =%1" ).arg( stringValueToPack ) );
-    MYODBCDbgInfo( QString( "stringData         =%1" ).arg( stringData ) );
-    MYODBCDbgInfo( QString( "nValueToPack       =%1" ).arg( nValueToPack ) );
-#endif
-
-    MYODBCC::num_pack( pNumericTarget->val, (int)nValueToPack );
-
-    if ( bFractionalTruncation )
-        MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::STATE_01S07 ) );
-
     MYODBCDbgReturn( SQL_SUCCESS );
-}
 
-SQLRETURN MResult::toGuidC( MStateGetData * )
-{
-    MYODBCDbgEnter();
-    MYODBCDbgReturn( SQL_ERROR );
 }
 
-SQLRETURN MResult::toIntervalMonthC( MStateGetData * )
-{
-    MYODBCDbgEnter();
-    MYODBCDbgReturn( SQL_ERROR );
-}
-
-SQLRETURN MResult::toIntervalYearC( MStateGetData * )
-{
-    MYODBCDbgEnter();
-    MYODBCDbgReturn( SQL_ERROR );
-}
-
-SQLRETURN MResult::toIntervalYearToMonthC( MStateGetData * )
-{
-    MYODBCDbgEnter();
-    MYODBCDbgReturn( SQL_ERROR );
-}
-
-SQLRETURN MResult::toIntervalDayC( MStateGetData * )
-{
-    MYODBCDbgEnter();
-    MYODBCDbgReturn( SQL_ERROR );
-}
-
-SQLRETURN MResult::toIntervalHourC( MStateGetData * )
-{
-    MYODBCDbgEnter();
-    MYODBCDbgReturn( SQL_ERROR );
-}
-
-SQLRETURN MResult::toIntervalMinuteC( MStateGetData * )
-{
-    MYODBCDbgEnter();
-    MYODBCDbgReturn( SQL_ERROR );
-}
-
-SQLRETURN MResult::toIntervalSecondC( MStateGetData * )
-{
-    MYODBCDbgEnter();
-    MYODBCDbgReturn( SQL_ERROR );
-}
-
-SQLRETURN MResult::toIntervalDayToHourC( MStateGetData * )
-{
-    MYODBCDbgEnter();
-    MYODBCDbgReturn( SQL_ERROR );
-}
-
-SQLRETURN MResult::toIntervalDayToMinuteC( MStateGetData * )
-{
-    MYODBCDbgEnter();
-    MYODBCDbgReturn( SQL_ERROR );
-}
-
-SQLRETURN MResult::toIntervalDayToSecondC( MStateGetData * )
-{
-    MYODBCDbgEnter();
-    MYODBCDbgReturn( SQL_ERROR );
-}
-
-SQLRETURN MResult::toIntervalHourToMinuteC( MStateGetData * )
-{
-    MYODBCDbgEnter();
-    MYODBCDbgReturn( SQL_ERROR );
-}
-
-SQLRETURN MResult::toIntervalHourToSecondC( MStateGetData * )
-{
-    MYODBCDbgEnter();
-    MYODBCDbgReturn( SQL_ERROR );
-}
-
-SQLRETURN MResult::toIntervalMinuteToSecondC( MStateGetData * )
-{
-    MYODBCDbgEnter();
-    MYODBCDbgReturn( SQL_ERROR );
-}
-

Modified: trunk/SDK/MYSQLPlus/Library/MStatement.cpp
===================================================================
--- trunk/SDK/MYSQLPlus/Library/MStatement.cpp	2007-03-16 03:23:33 UTC (rev 816)
+++ trunk/SDK/MYSQLPlus/Library/MStatement.cpp	2007-03-19 17:50:12 UTC (rev 817)
@@ -470,15 +470,6 @@
     SQLINTEGER  nLength;
     SQLRETURN   nReturn = pResult->getData( nColumnNumber, nTargetType, pTargetValue,
nBufferLength, &nLength, pnStrLenOrInd );
 
-    if ( !SQL_SUCCEEDED(nReturn) )
-        MYODBCDbgReturn( nReturn );
-
-    /* merge length if not an indicator value */
-    if ( pnStrLenOrInd &&
-            *pnStrLenOrInd != SQL_NULL_DATA &&
-            *pnStrLenOrInd != SQL_NO_TOTAL )
-        *pnStrLenOrInd = nLength;
-
     MYODBCDbgReturn( nReturn );
 }
 

Thread
Connector/ODBC 5 commit: r817 - trunk/SDK/MYSQLPlus/Libraryjbalint19 Mar