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/Library | jbalint | 19 Mar |