diff --git a/src/sql/drivers/odbc/qsql_odbc.cpp b/src/sql/drivers/odbc/qsql_odbc.cpp index c950d2c..ce47139 100644 --- a/src/sql/drivers/odbc/qsql_odbc.cpp +++ b/src/sql/drivers/odbc/qsql_odbc.cpp @@ -526,25 +526,95 @@ static QVariant qGetIntData(SQLHANDLE hStmt, int column, bool isSigned = true) return uint(intbuf); } -static QVariant qGetDoubleData(SQLHANDLE hStmt, int column) +long strtohextoval(SQL_NUMERIC_STRUCT NumStr) +{ + long val=0,value=0; + int i=1,last=1,current; + int a=0,b=0; + + for(i=0;i<=15;i++) + { + current = (int) NumStr.val[i]; + a= current % 16; //Obtain LSD + b= current / 16; //Obtain MSD + + value += last* a; + last = last * 16; + value += last* b; + last = last * 16; + } + return value; +} + +static QVariant qGetDoubleData(SQLHANDLE hStmt, int column, int precision, int length) { - SQLDOUBLE dblbuf; - SQLLEN lengthIndicator = 0; - SQLRETURN r = SQLGetData(hStmt, - column+1, - SQL_C_DOUBLE, - (SQLPOINTER) &dblbuf, - 0, - &lengthIndicator); - if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) { - return QVariant(QVariant::Invalid); + if (precision>0) + { + SQLHDESC hdesc = NULL; + SQL_NUMERIC_STRUCT NumStr; + SQLLEN lengthIndicator = 0; + + SQLGetStmtAttr(hStmt, SQL_ATTR_APP_ROW_DESC, &hdesc, 0, NULL); + + SQLSetDescField (hdesc, column+1, SQL_DESC_TYPE, (void*) SQL_C_NUMERIC, 0); + SQLSetDescField(hdesc, column+1, SQL_DESC_PRECISION, (void*) (length+precision), 0); + SQLSetDescField (hdesc, column+1, SQL_DESC_SCALE, (void*) precision, 0); + + SQLRETURN r = SQLGetData( + hStmt, + column+1, + SQL_ARD_TYPE, + &NumStr, + sizeof(NumStr), + &lengthIndicator + ); + + if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) + { + return QVariant(QVariant::Invalid); + } + + if(lengthIndicator == SQL_NULL_DATA) + return QVariant(QVariant::Double); + + double value = strtohextoval(NumStr); + + double divisor = 1; + if(NumStr.scale > 0) + { + for (int i=0;i< NumStr.scale; i++) + divisor = divisor * 10; + value = (double) value /(double) divisor; + } + + if (!NumStr.sign) + { + value = -value; + } + + return value; } - if(lengthIndicator == SQL_NULL_DATA) - return QVariant(QVariant::Double); + else + { + SQLDOUBLE dblbuf; + SQLLEN lengthIndicator = 0; + SQLRETURN r = SQLGetData(hStmt, + column+1, + SQL_C_DOUBLE, + (SQLPOINTER) &dblbuf, + 0, + &lengthIndicator); - return (double) dblbuf; -} + if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) + { + return QVariant(QVariant::Invalid); + } + if(lengthIndicator == SQL_NULL_DATA) + return QVariant(QVariant::Double); + return (double) dblbuf; + } +} static QVariant qGetBigIntData(SQLHANDLE hStmt, int column, bool isSigned = true) { @@ -1201,12 +1271,13 @@ QVariant QODBCResult::data(int field) d->fieldCache[i] = qGetBigIntData(d->hStmt, i); break; case QSql::LowPrecisionDouble: - d->fieldCache[i] = qGetDoubleData(d->hStmt, i); + d->fieldCache[i] = qGetDoubleData(d->hStmt, i, info.precision(), info.length()); break; case QSql::HighPrecision: d->fieldCache[i] = qGetStringData(d->hStmt, i, info.length(), false); break; } + break; default: d->fieldCache[i] = QVariant(qGetStringData(d->hStmt, i, info.length(), false));