From fc118515eee34d7a00ce363149bf85737607fed0 Mon Sep 17 00:00:00 2001 From: "Andrzej J.R. Hunt" Date: Thu, 19 Sep 2013 09:01:23 +0100 Subject: Implement implicit type conversion in ResultSet. (firebird-sdbc) Change-Id: I9faf9752556b7e0769d3a353e393924f5a1edb63 --- connectivity/source/drivers/firebird/ResultSet.cxx | 146 ++++++++++++++++----- connectivity/source/drivers/firebird/ResultSet.hxx | 25 ++++ 2 files changed, 139 insertions(+), 32 deletions(-) diff --git a/connectivity/source/drivers/firebird/ResultSet.cxx b/connectivity/source/drivers/firebird/ResultSet.cxx index e31e39ed7c01..c5af439ec9ba 100644 --- a/connectivity/source/drivers/firebird/ResultSet.cxx +++ b/connectivity/source/drivers/firebird/ResultSet.cxx @@ -368,22 +368,126 @@ bool OResultSet::isNull(const sal_Int32 nColumnIndex) return false; } +ORowSetValue OResultSet::retrieveConvertibleValue(const sal_Int32 nColumnIndex) +{ + // See http://wiki.openoffice.org/wiki/Documentation/DevGuide/Database/Using_the_getXXX_Methods + // (bottom of page) for a chart of possible conversions, we should allow all + // of these -- Blob/Clob will probably need some specialist handling especially + // w.r.t. to generating Strings for them. + // + // Basically we just have to map to the correct direct request and + // ORowSetValue does the rest for us here. + switch (m_pSqlda->sqlvar[nColumnIndex-1].sqltype & ~1) + { + case SQL_TEXT: + case SQL_VARYING: + return getString(nColumnIndex); + case SQL_SHORT: + return getShort(nColumnIndex); + case SQL_LONG: + return getInt(nColumnIndex); + case SQL_FLOAT: + return getFloat(nColumnIndex); + case SQL_DOUBLE: + return getDouble(nColumnIndex); + case SQL_D_FLOAT: + return getFloat(nColumnIndex); + case SQL_TIMESTAMP: + return getTimestamp(nColumnIndex); +// case SQL_BLOB: +// return DataType::BLOB; +// case SQL_ARRAY: +// return DataType::ARRAY; + case SQL_TYPE_TIME: + return getTime(nColumnIndex); + case SQL_TYPE_DATE: + return getTime(nColumnIndex); + case SQL_INT64: + return getLong(nColumnIndex); + case SQL_NULL: + assert(false); // We shouldn't really be returning this ever since + // detection is separate. +// case SQL_QUAD: // Is a "Blob ID" according to the docs +// return 0; // TODO: verify + default: + assert(false); + return ORowSetValue(); + } +} + template T OResultSet::retrieveValue(const sal_Int32 nColumnIndex, const ISC_SHORT nType) { - // TODO: check we have the right type. if ((m_bWasNull = isNull(nColumnIndex))) return T(); if ((m_pSqlda->sqlvar[nColumnIndex-1].sqltype & ~1) == nType) return *((T*) m_pSqlda->sqlvar[nColumnIndex-1].sqldata); else - return T(); - // TODO: fix + return retrieveConvertibleValue(nColumnIndex); +} + +template <> +Date OResultSet::retrieveValue(const sal_Int32 nColumnIndex, const ISC_SHORT /*nType*/) +{ + if ((m_pSqlda->sqlvar[nColumnIndex-1].sqltype & ~1) == SQL_TYPE_DATE) + { + ISC_DATE aISCDate = *((ISC_DATE*) m_pSqlda->sqlvar[nColumnIndex-1].sqldata); + + struct tm aCTime; + isc_decode_sql_date(&aISCDate, &aCTime); + + return Date(aCTime.tm_mday, aCTime.tm_mon, aCTime.tm_year); + } + else + { + return retrieveConvertibleValue(nColumnIndex); + } } template <> -OUString OResultSet::retrieveValue(const sal_Int32 nColumnIndex, const ISC_SHORT nType) +Time OResultSet::retrieveValue(const sal_Int32 nColumnIndex, const ISC_SHORT /*nType*/) +{ + if ((m_pSqlda->sqlvar[nColumnIndex-1].sqltype & ~1) == SQL_TYPE_TIME) + { + ISC_TIME aISCTime = *((ISC_TIME*) m_pSqlda->sqlvar[nColumnIndex-1].sqldata); + + struct tm aCTime; + isc_decode_sql_time(&aISCTime, &aCTime); + + // first field is nanoseconds -- not supported in firebird or struct tm. + // last field denotes UTC (true) or unknown (false) + return Time(0, aCTime.tm_sec, aCTime.tm_min, aCTime.tm_hour, false); + } + else + { + return retrieveConvertibleValue(nColumnIndex); + } +} + +template <> +DateTime OResultSet::retrieveValue(const sal_Int32 nColumnIndex, const ISC_SHORT /*nType*/) +{ + if ((m_pSqlda->sqlvar[nColumnIndex-1].sqltype & ~1) == SQL_TIMESTAMP) + { + ISC_TIMESTAMP aISCTimestamp = *((ISC_TIMESTAMP*) m_pSqlda->sqlvar[nColumnIndex-1].sqldata); + + struct tm aCTime; + isc_decode_timestamp(&aISCTimestamp, &aCTime); + + // first field is nanoseconds -- not supported in firebird or struct tm. + // last field denotes UTC (true) or unknown (false) + return DateTime(0, aCTime.tm_sec, aCTime.tm_min, aCTime.tm_hour, aCTime.tm_mday, + aCTime.tm_mon, aCTime.tm_year, false); + } + else + { + return retrieveConvertibleValue(nColumnIndex); + } +} + +template <> +OUString OResultSet::retrieveValue(const sal_Int32 nColumnIndex, const ISC_SHORT /*nType*/) { if ((m_bWasNull = isNull(nColumnIndex))) return OUString(); @@ -407,9 +511,7 @@ OUString OResultSet::retrieveValue(const sal_Int32 nColumnIndex, const ISC_SHORT } else { - (void) nType; - return OUString(); - // TODO: Possibly do some sort of type conversion? + return retrieveConvertibleValue(nColumnIndex); } } @@ -504,49 +606,29 @@ double SAL_CALL OResultSet::getDouble(sal_Int32 columnIndex) } // ---- XRow: More complex types ---------------------------------------------- -OUString SAL_CALL OResultSet::getString(sal_Int32 columnIndex) +OUString SAL_CALL OResultSet::getString(sal_Int32 nIndex) throw(SQLException, RuntimeException) { // TODO: special handling for char type? - return safelyRetrieveValue< OUString >(columnIndex, 0); + return safelyRetrieveValue< OUString >(nIndex, 0); } Date SAL_CALL OResultSet::getDate(sal_Int32 nIndex) throw(SQLException, RuntimeException) { - ISC_DATE aISCDate = safelyRetrieveValue< ISC_DATE >(nIndex, SQL_TYPE_DATE); - - struct tm aCTime; - isc_decode_sql_date(&aISCDate, &aCTime); - - return Date(aCTime.tm_mday, aCTime.tm_mon, aCTime.tm_year); + return safelyRetrieveValue< Date >(nIndex, SQL_TYPE_DATE); } Time SAL_CALL OResultSet::getTime(sal_Int32 nIndex) throw(SQLException, RuntimeException) { - ISC_TIME aISCTime = safelyRetrieveValue< ISC_TIME >(nIndex, SQL_TYPE_TIME); - - struct tm aCTime; - isc_decode_sql_time(&aISCTime, &aCTime); - - // first field is nanoseconds -- not supported in firebird or struct tm. - // last field denotes UTC (true) or unknown (false) - return Time(0, aCTime.tm_sec, aCTime.tm_min, aCTime.tm_hour, false); + return safelyRetrieveValue< Time >(nIndex, SQL_TYPE_TIME); } DateTime SAL_CALL OResultSet::getTimestamp(sal_Int32 nIndex) throw(SQLException, RuntimeException) { - ISC_TIMESTAMP aISCTimestamp = safelyRetrieveValue< ISC_TIMESTAMP >(nIndex, SQL_TIMESTAMP); - - struct tm aCTime; - isc_decode_timestamp(&aISCTimestamp, &aCTime); - - // first field is nanoseconds -- not supported in firebird or struct tm. - // last field denotes UTC (true) or unknown (false) - return DateTime(0, aCTime.tm_sec, aCTime.tm_min, aCTime.tm_hour, aCTime.tm_mday, - aCTime.tm_mon, aCTime.tm_year, false); + return safelyRetrieveValue< DateTime >(nIndex, SQL_TIMESTAMP); } // ------------------------------------------------------------------------- diff --git a/connectivity/source/drivers/firebird/ResultSet.hxx b/connectivity/source/drivers/firebird/ResultSet.hxx index c1dd9049a76a..fbaed5ae9ff1 100644 --- a/connectivity/source/drivers/firebird/ResultSet.hxx +++ b/connectivity/source/drivers/firebird/ResultSet.hxx @@ -24,6 +24,7 @@ #include +#include #include #include #include @@ -92,6 +93,14 @@ namespace connectivity ISC_STATUS_ARRAY m_statusVector; bool isNull(const sal_Int32 nColumnIndex); + + /** + * Retrieves a value to an ORowSetValue allowing for conversion + * at will. Should only be used if conversion is needed to avoid + * any performance hit otherwise. + */ + ORowSetValue retrieveConvertibleValue(const sal_Int32 nColumnIndex); + template T retrieveValue(const sal_Int32 nColumnIndex, const ISC_SHORT nType); @@ -194,6 +203,22 @@ namespace connectivity }; // Specialisations have to be in the namespace and can't be within the class. + template <> ::com::sun::star::util::Date + OResultSet::retrieveValue( + const sal_Int32 nColumnIndex, + const ISC_SHORT nType); + template <> ::com::sun::star::util::Time + OResultSet::retrieveValue( + const sal_Int32 nColumnIndex, + const ISC_SHORT nType); + template <> ::com::sun::star::util::DateTime + OResultSet::retrieveValue( + const sal_Int32 nColumnIndex, + const ISC_SHORT nType); + template <> ISC_QUAD* + OResultSet::retrieveValue( + const sal_Int32 nColumnIndex, + const ISC_SHORT nType); template <> ::rtl::OUString OResultSet::retrieveValue( const sal_Int32 nColumnIndex, -- cgit