diff options
author | Wastack <btomi96@gmail.com> | 2016-10-31 16:32:54 +0100 |
---|---|---|
committer | Lionel Elie Mamane <lionel@mamane.lu> | 2016-11-10 09:37:12 +0000 |
commit | 21cc1826c758bb71bb0cfa055b3bb51a38bc2acb (patch) | |
tree | 7142453461e05a9320d0f15de9dfb12dd336e8b3 /connectivity | |
parent | 9357e99450974a4bea5946129af126469199797b (diff) |
WiP tdf#74172 use DECIMAL and NUMERIC data types
Change-Id: I917cdf6e8d3ebfa7c9e4a52ca61adc5b8707ecfc
Reviewed-on: https://gerrit.libreoffice.org/30447
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Lionel Elie Mamane <lionel@mamane.lu>
Diffstat (limited to 'connectivity')
9 files changed, 324 insertions, 39 deletions
diff --git a/connectivity/source/drivers/firebird/Column.cxx b/connectivity/source/drivers/firebird/Column.cxx index 28ce9ac0edb8..38c367cfcc43 100644 --- a/connectivity/source/drivers/firebird/Column.cxx +++ b/connectivity/source/drivers/firebird/Column.cxx @@ -24,6 +24,7 @@ Column::Column() void Column::construct() { + OColumn::construct(); m_sAutoIncrement = "GENERATED BY DEFAULT AS IDENTITY"; registerProperty(OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_AUTOINCREMENTCREATION), diff --git a/connectivity/source/drivers/firebird/DatabaseMetaData.cxx b/connectivity/source/drivers/firebird/DatabaseMetaData.cxx index f5b1a7e977a5..bb26401b3f5d 100644 --- a/connectivity/source/drivers/firebird/DatabaseMetaData.cxx +++ b/connectivity/source/drivers/firebird/DatabaseMetaData.cxx @@ -34,6 +34,7 @@ #include <com/sun/star/sdbc/XRow.hpp> #include <com/sun/star/sdbc/KeyRule.hpp> #include <com/sun/star/sdbc/Deferrability.hpp> +#include <com/sun/star/sdbc/DataType.hpp> using namespace connectivity::firebird; using namespace com::sun::star; @@ -902,7 +903,7 @@ uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getTypeInfo() // SQL_TEXT aRow[1] = new ORowSetValueDecorator(OUString("CHAR")); - aRow[2] = new ORowSetValueDecorator(getColumnTypeFromFBType(SQL_TEXT)); + aRow[2] = new ORowSetValueDecorator(getColumnTypeFromFBType(SQL_TEXT, 0)); aRow[3] = new ORowSetValueDecorator(sal_Int16(32767)); // Prevision = max length aRow[6] = new ORowSetValueDecorator(OUString("length")); // Create Params aRow[9] = new ORowSetValueDecorator( @@ -914,7 +915,7 @@ uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getTypeInfo() // SQL_VARYING aRow[1] = new ORowSetValueDecorator(OUString("VARCHAR")); - aRow[2] = new ORowSetValueDecorator(getColumnTypeFromFBType(SQL_VARYING)); + aRow[2] = new ORowSetValueDecorator(getColumnTypeFromFBType(SQL_VARYING, 0)); aRow[3] = new ORowSetValueDecorator(sal_Int16(32767)); // Prevision = max length aRow[6] = new ORowSetValueDecorator(OUString("length")); // Create Params aRow[9] = new ORowSetValueDecorator( @@ -935,44 +936,62 @@ uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getTypeInfo() } // SQL_SHORT aRow[1] = new ORowSetValueDecorator(OUString("SMALLINT")); - aRow[2] = new ORowSetValueDecorator(getColumnTypeFromFBType(SQL_SHORT)); + aRow[2] = new ORowSetValueDecorator(getColumnTypeFromFBType(SQL_SHORT, 0)); aRow[3] = new ORowSetValueDecorator(sal_Int16(5)); // Prevision aResults.push_back(aRow); // SQL_LONG aRow[1] = new ORowSetValueDecorator(OUString("INTEGER")); - aRow[2] = new ORowSetValueDecorator(getColumnTypeFromFBType(SQL_LONG)); + aRow[2] = new ORowSetValueDecorator(getColumnTypeFromFBType(SQL_LONG, 0)); aRow[3] = new ORowSetValueDecorator(sal_Int16(10)); // Precision aResults.push_back(aRow); // SQL_INT64 aRow[1] = new ORowSetValueDecorator(OUString("BIGINT")); - aRow[2] = new ORowSetValueDecorator(getColumnTypeFromFBType(SQL_INT64)); + aRow[2] = new ORowSetValueDecorator(getColumnTypeFromFBType(SQL_INT64, 0)); aRow[3] = new ORowSetValueDecorator(sal_Int16(20)); // Precision aResults.push_back(aRow); // Decimal Types common { - aRow[6] = new ORowSetValueDecorator(); // Create Params aRow[9] = new ORowSetValueDecorator( sal_Int16(ColumnSearch::FULL)); // Searchable aRow[12] = new ORowSetValueDecorator(true); // Autoincrement } + + aRow[6] = new ORowSetValueDecorator(OUString("PRECISION,SCALE")); // Create params + // NUMERIC + aRow[1] = new ORowSetValueDecorator(OUString("NUMERIC")); + aRow[2] = new ORowSetValueDecorator(DataType::NUMERIC); + aRow[3] = new ORowSetValueDecorator(sal_Int16(15)); // Precision + aRow[14] = new ORowSetValueDecorator(sal_Int16(1)); // Minimum scale + aRow[15] = new ORowSetValueDecorator(sal_Int16(15)); // Max scale + aResults.push_back(aRow); + // DECIMAL + aRow[1] = new ORowSetValueDecorator(OUString("DECIMAL")); + aRow[2] = new ORowSetValueDecorator(DataType::DECIMAL); + aRow[3] = new ORowSetValueDecorator(sal_Int16(15)); // Precision + aRow[14] = new ORowSetValueDecorator(sal_Int16(1)); // Minimum scale + aRow[15] = new ORowSetValueDecorator(sal_Int16(15)); // Max scale + aResults.push_back(aRow); + + aRow[6] = new ORowSetValueDecorator(); // Create Params // SQL_FLOAT aRow[1] = new ORowSetValueDecorator(OUString("FLOAT")); - aRow[2] = new ORowSetValueDecorator(getColumnTypeFromFBType(SQL_FLOAT)); + aRow[2] = new ORowSetValueDecorator(getColumnTypeFromFBType(SQL_FLOAT, 0)); aRow[3] = new ORowSetValueDecorator(sal_Int16(7)); // Precision aRow[14] = new ORowSetValueDecorator(sal_Int16(1)); // Minimum scale aRow[15] = new ORowSetValueDecorator(sal_Int16(7)); // Max scale aResults.push_back(aRow); // SQL_DOUBLE aRow[1] = new ORowSetValueDecorator(OUString("DOUBLE PRECISION")); - aRow[2] = new ORowSetValueDecorator(getColumnTypeFromFBType(SQL_DOUBLE)); + aRow[2] = new ORowSetValueDecorator(getColumnTypeFromFBType(SQL_DOUBLE, 0)); aRow[3] = new ORowSetValueDecorator(sal_Int16(15)); // Precision aRow[14] = new ORowSetValueDecorator(sal_Int16(1)); // Minimum scale aRow[15] = new ORowSetValueDecorator(sal_Int16(15)); // Max scale aResults.push_back(aRow); + // // SQL_D_FLOAT -// aRow[1] = new ORowSetValueDecorator(getColumnTypeNameFromFBType(SQL_D_FLOAT)); -// aRow[2] = new ORowSetValueDecorator(getColumnTypeFromFBType(SQL_D_FLOAT)); +// aRow[1] = new ORowSetValueDecorator(getColumnTypeNameFromFBType(SQL_D_FLOAT, 0)); +// aRow[2] = new ORowSetValueDecorator(getColumnTypeFromFBType(SQL_D_FLOAT, 0)); // aRow[3] = new ORowSetValueDecorator(sal_Int16(15)); // Precision // aRow[14] = new ORowSetValueDecorator(sal_Int16(1)); // Minimum scale // aRow[15] = new ORowSetValueDecorator(sal_Int16(15)); // Max scale @@ -982,7 +1001,7 @@ uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getTypeInfo() // SQL_TIMESTAMP // TODO: precision? aRow[1] = new ORowSetValueDecorator(OUString("TIMESTAMP")); - aRow[2] = new ORowSetValueDecorator(getColumnTypeFromFBType(SQL_TIMESTAMP)); + aRow[2] = new ORowSetValueDecorator(getColumnTypeFromFBType(SQL_TIMESTAMP, 0)); aRow[3] = new ORowSetValueDecorator(sal_Int32(8)); // Prevision = max length aRow[6] = new ORowSetValueDecorator(); // Create Params aRow[9] = new ORowSetValueDecorator( @@ -995,7 +1014,7 @@ uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getTypeInfo() // SQL_TYPE_TIME // TODO: precision? aRow[1] = new ORowSetValueDecorator(OUString("TIME")); - aRow[2] = new ORowSetValueDecorator(getColumnTypeFromFBType(SQL_TYPE_TIME)); + aRow[2] = new ORowSetValueDecorator(getColumnTypeFromFBType(SQL_TYPE_TIME, 0)); aRow[3] = new ORowSetValueDecorator(sal_Int32(8)); // Prevision = max length aRow[6] = new ORowSetValueDecorator(); // Create Params aRow[9] = new ORowSetValueDecorator( @@ -1008,7 +1027,7 @@ uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getTypeInfo() // SQL_TYPE_DATE // TODO: precision? aRow[1] = new ORowSetValueDecorator(OUString("DATE")); - aRow[2] = new ORowSetValueDecorator(getColumnTypeFromFBType(SQL_TYPE_DATE)); + aRow[2] = new ORowSetValueDecorator(getColumnTypeFromFBType(SQL_TYPE_DATE, 0)); aRow[3] = new ORowSetValueDecorator(sal_Int32(8)); // Prevision = max length aRow[6] = new ORowSetValueDecorator(); // Create Params aRow[9] = new ORowSetValueDecorator( @@ -1021,7 +1040,7 @@ uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getTypeInfo() // SQL_BLOB // TODO: precision? aRow[1] = new ORowSetValueDecorator(OUString("BLOB")); - aRow[2] = new ORowSetValueDecorator(getColumnTypeFromFBType(SQL_BLOB)); + aRow[2] = new ORowSetValueDecorator(getColumnTypeFromFBType(SQL_BLOB, 0)); aRow[3] = new ORowSetValueDecorator(sal_Int32(0)); // Prevision = max length aRow[6] = new ORowSetValueDecorator(); // Create Params aRow[9] = new ORowSetValueDecorator( @@ -1133,13 +1152,15 @@ uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getColumns( "relfields.RDB$DEFAULT_VALUE, " // 4 "relfields.RDB$FIELD_POSITION, "// 5 "fields.RDB$FIELD_TYPE, " // 6 - "fields.RDB$FIELD_LENGTH, " // 7 - "fields.RDB$FIELD_PRECISION, " // 8 + "fields.RDB$FIELD_SUB_TYPE, " // 7 + "fields.RDB$FIELD_LENGTH, " // 8 + "fields.RDB$FIELD_PRECISION, " // 9 + "fields.RDB$FIELD_SCALE, " // 10 // Specifically use relfields null flag -- the one in fields is used // for domains, whether a specific field is nullable is set in relfields, // this is also the one we manually fiddle when changin NULL/NOT NULL // (see Table.cxx) - "relfields.RDB$NULL_FLAG " // 9 + "relfields.RDB$NULL_FLAG " // 11 "FROM RDB$RELATION_FIELDS relfields " "JOIN RDB$FIELDS fields " "on (fields.RDB$FIELD_NAME = relfields.RDB$FIELD_SOURCE) " @@ -1192,9 +1213,10 @@ uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getColumns( aCurrentRow[4] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(2))); // 5. Datatype short aType = getFBTypeFromBlrType(xRow->getShort(6)); - aCurrentRow[5] = new ORowSetValueDecorator(getColumnTypeFromFBType(aType)); + short aSubType = xRow->getShort(7); + aCurrentRow[5] = new ORowSetValueDecorator(getColumnTypeFromFBType(aType, aSubType)); // 6. Typename (SQL_*) - aCurrentRow[6] = new ORowSetValueDecorator(getColumnTypeNameFromFBType(aType)); + aCurrentRow[6] = new ORowSetValueDecorator(getColumnTypeNameFromFBType(aType, aSubType)); // 7. Column Sizes { @@ -1203,7 +1225,7 @@ uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getColumns( { case SQL_TEXT: case SQL_VARYING: - aColumnSize = xRow->getShort(7); + aColumnSize = xRow->getShort(8); break; case SQL_SHORT: case SQL_LONG: @@ -1212,7 +1234,7 @@ uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getColumns( case SQL_D_FLOAT: case SQL_INT64: case SQL_QUAD: - aColumnSize = xRow->getShort(8); + aColumnSize = xRow->getShort(9); break; case SQL_TIMESTAMP: case SQL_BLOB: @@ -1226,12 +1248,12 @@ uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getColumns( aCurrentRow[7] = new ORowSetValueDecorator(aColumnSize); } - // 9. Decimal Digits - // TODO: implement - aCurrentRow[9] = new ORowSetValueDecorator(sal_Int32(0)); + // 9. Decimal digits (scale) + // fb stores a negative number + aCurrentRow[9] = new ORowSetValueDecorator( (sal_Int16) -(xRow->getShort(10)) ); // 11. Nullable - if (xRow->getShort(9)) + if (xRow->getShort(11)) { aCurrentRow[11] = new ORowSetValueDecorator(ColumnValue::NO_NULLS); } @@ -1265,7 +1287,7 @@ uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getColumns( // 16. Bytes in Column for char if (aType == SQL_TEXT) { - aCurrentRow[16] = new ORowSetValueDecorator(xRow->getShort(7)); + aCurrentRow[16] = new ORowSetValueDecorator(xRow->getShort(8)); } else if (aType == SQL_VARYING) { diff --git a/connectivity/source/drivers/firebird/PreparedStatement.cxx b/connectivity/source/drivers/firebird/PreparedStatement.cxx index 13402b86d1dd..f9adc0bdb0fc 100644 --- a/connectivity/source/drivers/firebird/PreparedStatement.cxx +++ b/connectivity/source/drivers/firebird/PreparedStatement.cxx @@ -29,6 +29,7 @@ #include <osl/diagnose.h> #include <propertyids.hxx> #include <time.h> +#include <connectivity/dbtools.hxx> #include <com/sun/star/sdbc/DataType.hpp> #include <com/sun/star/lang/DisposedException.hpp> @@ -317,6 +318,32 @@ Reference< XResultSet > SAL_CALL OPreparedStatement::executeQuery() return m_xResultSet; } +sal_Int64 OPreparedStatement::toNumericWithoutDecimalPlace(const OUString& sSource) +{ + OUString sNumber(sSource); + + // cut off leading 0 eventually ( eg. 0.567 -> .567) + sSource.startsWith(OUString("0"), &sNumber); + + sal_Int32 nDotIndex = sNumber.indexOf((sal_Unicode)'.'); + + if( nDotIndex < 0) + { + return sNumber.toInt64(); // no dot -> it's an integer + } + else + { + // remove dot + OUStringBuffer sBuffer(15); + if(nDotIndex > 0) + { + sBuffer.append(sNumber.copy(0, nDotIndex)); + } + sBuffer.append(sNumber.copy(nDotIndex + 1)); + return sBuffer.makeStringAndClear().toInt64(); + } +} + //----- XParameters ----------------------------------------------------------- void SAL_CALL OPreparedStatement::setNull(sal_Int32 nIndex, sal_Int32 /*nSqlType*/) throw(SQLException, RuntimeException, std::exception) @@ -561,13 +588,81 @@ void SAL_CALL OPreparedStatement::setRef( sal_Int32 parameterIndex, const Refere void SAL_CALL OPreparedStatement::setObjectWithInfo( sal_Int32 parameterIndex, const Any& x, sal_Int32 sqlType, sal_Int32 scale ) throw(SQLException, RuntimeException, std::exception) { - (void) parameterIndex; - (void) x; - (void) sqlType; - (void) scale; checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed); ::osl::MutexGuard aGuard( m_aMutex ); + XSQLVAR* pVar = m_pInSqlda->sqlvar + (parameterIndex - 1); + int dType = (pVar->sqltype & ~1); // drop null flag + + if(sqlType == DataType::DECIMAL || sqlType == DataType::NUMERIC) + { + double myDouble=0.0; + OUString myString; + if( x >>= myDouble ) + { + myString = OUString::number( myDouble ); + } + else + { + x >>= myString; + } + + // fill in the number with nulls in fractional part. + // We need this because e.g. 0.450 != 0.045 despite + // their scale is equal + OUStringBuffer sBuffer(15); + sBuffer.append(myString); + if(myString.indexOf('.') != -1) // there is a dot + { + for(sal_Int32 i=myString.copy(myString.indexOf('.')+1).getLength(); i<scale;i++) + { + sBuffer.append('0'); + } + } + else + { + for (sal_Int32 i=0; i<scale; i++) + { + sBuffer.append('0'); + } + } + myString = sBuffer.makeStringAndClear(); + // set value depending on type + sal_Int16 n16Value = 0; + sal_Int32 n32Value = 0; + sal_Int64 n64Value = 0; + switch(dType) + { + case SQL_SHORT: + n16Value = (sal_Int16) toNumericWithoutDecimalPlace(myString); + setValue< sal_Int16 >(parameterIndex, + n16Value, + dType); + break; + case SQL_LONG: + case SQL_DOUBLE: // TODO FIXME 32 bits + n32Value = (sal_Int32) toNumericWithoutDecimalPlace(myString); + setValue< sal_Int32 >(parameterIndex, + n32Value, + dType); + break; + case SQL_INT64: + n64Value = (sal_Int64) toNumericWithoutDecimalPlace(myString); + setValue< sal_Int64 >(parameterIndex, + n64Value, + dType); + break; + default: + SAL_WARN("connectivity.firebird", + "No Firebird sql type found for numeric or decimal types"); + ::dbtools::setObjectWithInfo(this,parameterIndex,x,sqlType,scale); + } + } + else + { + ::dbtools::setObjectWithInfo(this,parameterIndex,x,sqlType,scale); + } + } diff --git a/connectivity/source/drivers/firebird/PreparedStatement.hxx b/connectivity/source/drivers/firebird/PreparedStatement.hxx index d98e46d2950c..04ba79227b90 100644 --- a/connectivity/source/drivers/firebird/PreparedStatement.hxx +++ b/connectivity/source/drivers/firebird/PreparedStatement.hxx @@ -79,6 +79,13 @@ namespace connectivity */ void closeBlobAfterWriting(isc_blob_handle& rBlobHandle); + /** + * Take out the number part of a fix point decimal without + * the information of where is the fracional part from a + * string representation of a number. (e.g. 54.654 -> 54654) + */ + sal_Int64 toNumericWithoutDecimalPlace(const OUString& sSource); + protected: virtual void SAL_CALL setFastPropertyValue_NoBroadcast(sal_Int32 nHandle, const css::uno::Any& rValue) diff --git a/connectivity/source/drivers/firebird/ResultSet.cxx b/connectivity/source/drivers/firebird/ResultSet.cxx index 916f7df49f69..71744187c8b0 100644 --- a/connectivity/source/drivers/firebird/ResultSet.cxx +++ b/connectivity/source/drivers/firebird/ResultSet.cxx @@ -377,6 +377,58 @@ bool OResultSet::isNull(const sal_Int32 nColumnIndex) } template <typename T> +OUString OResultSet::makeNumericString(const sal_Int32 nColumnIndex) +{ + // minus because firebird stores scale as a negative number + int nDecimalCount = -(m_pSqlda->sqlvar[nColumnIndex-1].sqlscale); + if(nDecimalCount < 0) + { + // scale should be always positive + assert(false); + return OUString(); + } + + OUStringBuffer sRetBuffer; + T nAllDigits = *reinterpret_cast<T*>(m_pSqlda->sqlvar[nColumnIndex-1].sqldata); + sal_Int64 nDecimalCountExp = pow10Integer(nDecimalCount); + + if(nAllDigits < 0) + { + sRetBuffer.append('-'); + nAllDigits = -nAllDigits; // abs + } + + sRetBuffer.append((sal_Int64) (nAllDigits / nDecimalCountExp) ); + if( nDecimalCount > 0) + { + sRetBuffer.append('.'); + + sal_Int64 nFractionalPart = nAllDigits % nDecimalCountExp; + + int iCount = 0; // digit count + sal_Int64 nFracTemp = nFractionalPart; + while(nFracTemp>0) + { + nFracTemp /= 10; + iCount++; + } + + int nMissingNulls = nDecimalCount - iCount; + + // append nulls after dot and before nFractionalPart + for(int i=0; i<nMissingNulls; i++) + { + sRetBuffer.append('0'); + } + + // the rest + sRetBuffer.append(nFractionalPart); + } + + return sRetBuffer.makeStringAndClear(); +} + +template <typename T> T OResultSet::retrieveValue(const sal_Int32 nColumnIndex, const ISC_SHORT nType) { if ((m_bWasNull = isNull(nColumnIndex))) @@ -398,18 +450,25 @@ ORowSetValue OResultSet::retrieveValue(const sal_Int32 nColumnIndex, const ISC_S // // Basically we just have to map to the correct direct request and // ORowSetValue does the rest for us here. + int nSqlSubType = m_pSqlda->sqlvar[nColumnIndex-1].sqlsubtype; switch (m_pSqlda->sqlvar[nColumnIndex-1].sqltype & ~1) { case SQL_TEXT: case SQL_VARYING: return getString(nColumnIndex); case SQL_SHORT: + if(nSqlSubType == 0 || nSqlSubType == 1) //numeric or decimal + return getString(nColumnIndex); return getShort(nColumnIndex); case SQL_LONG: + if(nSqlSubType == 0 || nSqlSubType == 1) //numeric or decimal + return getString(nColumnIndex); return getInt(nColumnIndex); case SQL_FLOAT: return getFloat(nColumnIndex); case SQL_DOUBLE: + if(nSqlSubType == 0 || nSqlSubType == 1) //numeric or decimal + return getString(nColumnIndex); return getDouble(nColumnIndex); case SQL_D_FLOAT: return getFloat(nColumnIndex); @@ -420,6 +479,8 @@ ORowSetValue OResultSet::retrieveValue(const sal_Int32 nColumnIndex, const ISC_S case SQL_TYPE_DATE: return getDate(nColumnIndex); case SQL_INT64: + if(nSqlSubType == 0 || nSqlSubType == 1) //numeric or decimal + return getString(nColumnIndex); return getLong(nColumnIndex); case SQL_BLOB: case SQL_NULL: @@ -502,6 +563,7 @@ OUString OResultSet::retrieveValue(const sal_Int32 nColumnIndex, const ISC_SHORT { // &~1 to remove the "can contain NULL" indicator int aSqlType = m_pSqlda->sqlvar[nColumnIndex-1].sqltype & ~1; + int aSqlSubType = m_pSqlda->sqlvar[nColumnIndex-1].sqlsubtype; if (aSqlType == SQL_TEXT ) { return OUString(m_pSqlda->sqlvar[nColumnIndex-1].sqldata, @@ -517,6 +579,26 @@ OUString OResultSet::retrieveValue(const sal_Int32 nColumnIndex, const ISC_SHORT aLength, RTL_TEXTENCODING_UTF8); } + else if ((aSqlType == SQL_SHORT || aSqlType == SQL_LONG + || aSqlType == SQL_DOUBLE || aSqlType == SQL_INT64) + && (aSqlSubType == 1 || aSqlSubType == 2)) + { + // decimal and numeric types + switch(aSqlType) + { + case SQL_SHORT: + return makeNumericString<sal_Int16>(nColumnIndex); + case SQL_LONG: + return makeNumericString<sal_Int32>(nColumnIndex); + case SQL_DOUBLE: + // TODO FIXME 64 bits? + case SQL_INT64: + return makeNumericString<sal_Int64>(nColumnIndex); + default: + assert(false); + return OUString(); // never reached + } + } else { return retrieveValue< ORowSetValue >(nColumnIndex, 0); diff --git a/connectivity/source/drivers/firebird/ResultSet.hxx b/connectivity/source/drivers/firebird/ResultSet.hxx index fb4d929a8cb7..347c7ea80f71 100644 --- a/connectivity/source/drivers/firebird/ResultSet.hxx +++ b/connectivity/source/drivers/firebird/ResultSet.hxx @@ -101,6 +101,9 @@ namespace connectivity bool isNull(const sal_Int32 nColumnIndex); + template <typename T> OUString makeNumericString( + const sal_Int32 nColumnIndex); + template <typename T> T retrieveValue(const sal_Int32 nColumnIndex, const ISC_SHORT nType); diff --git a/connectivity/source/drivers/firebird/ResultSetMetaData.cxx b/connectivity/source/drivers/firebird/ResultSetMetaData.cxx index 9baadab8fcce..c36148c6c2fa 100644 --- a/connectivity/source/drivers/firebird/ResultSetMetaData.cxx +++ b/connectivity/source/drivers/firebird/ResultSetMetaData.cxx @@ -23,6 +23,7 @@ #include <com/sun/star/sdbc/ColumnValue.hpp> #include <com/sun/star/sdbcx/XColumnsSupplier.hpp> #include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/DataType.hpp> using namespace connectivity::firebird; @@ -62,8 +63,9 @@ sal_Int32 SAL_CALL OResultSetMetaData::getColumnType(sal_Int32 column) verifyValidColumn(column); short aType = m_pSqlda->sqlvar[column-1].sqltype; + short aSubType = m_pSqlda->sqlvar[column-1].sqlsubtype; - return getColumnTypeFromFBType(aType); + return getColumnTypeFromFBType(aType, aSubType); } sal_Bool SAL_CALL OResultSetMetaData::isCaseSensitive(sal_Int32 column) @@ -118,8 +120,9 @@ OUString SAL_CALL OResultSetMetaData::getColumnTypeName(sal_Int32 column) verifyValidColumn(column); short aType = m_pSqlda->sqlvar[column-1].sqltype; + short aSubType = m_pSqlda->sqlvar[column-1].sqlsubtype; - return getColumnTypeNameFromFBType(aType); + return getColumnTypeNameFromFBType(aType, aSubType); } OUString SAL_CALL OResultSetMetaData::getColumnLabel(sal_Int32 column) @@ -191,15 +194,44 @@ sal_Bool SAL_CALL OResultSetMetaData::isSigned(sal_Int32 column) sal_Int32 SAL_CALL OResultSetMetaData::getPrecision(sal_Int32 column) throw(SQLException, RuntimeException, std::exception) { - // TODO: implement - (void) column; + sal_Int32 nType = getColumnType(column); + if( (nType == DataType::NUMERIC || nType == DataType::DECIMAL) + && !m_sTableName.isEmpty() ) + { + OUString sColumnName = getColumnName( column ); + + // RDB$FIELD_SOURCE is a unique name of column per database + OUString sSql = "SELECT RDB$FIELD_PRECISION FROM RDB$FIELDS " + " INNER JOIN RDB$RELATION_FIELDS " + " ON RDB$RELATION_FIELDS.RDB$FIELD_SOURCE = RDB$FIELDS.RDB$FIELD_NAME " + "WHERE RDB$RELATION_FIELDS.RDB$RELATION_NAME = '" + + escapeWith(getTableName(column), '\'', '\'') + "' AND " + "RDB$RELATION_FIELDS.RDB$FIELD_NAME = '" + + escapeWith(sColumnName, '\'', '\'') +"'"; + Reference<XStatement> xStmt= m_pConnection->createStatement(); + + Reference<XResultSet> xRes = + xStmt->executeQuery(sSql); + Reference<XRow> xRow ( xRes, UNO_QUERY); + if(xRes->next()) + { + return (sal_Int32) xRow->getShort(1); + } + else + { + SAL_WARN("connectivity.firebird","Column '" + << sColumnName + << "' not found in database"); + return 0; + } + } return 0; } sal_Int32 SAL_CALL OResultSetMetaData::getScale(sal_Int32 column) throw(css::sdbc::SQLException, css::uno::RuntimeException, std::exception) { - return m_pSqlda->sqlvar[column-1].sqlscale; + return -(m_pSqlda->sqlvar[column-1].sqlscale); // fb stores negative number } sal_Int32 SAL_CALL OResultSetMetaData::isNullable(sal_Int32 column) diff --git a/connectivity/source/drivers/firebird/Util.cxx b/connectivity/source/drivers/firebird/Util.cxx index ee5a9bd32481..318aa6d839b0 100644 --- a/connectivity/source/drivers/firebird/Util.cxx +++ b/connectivity/source/drivers/firebird/Util.cxx @@ -65,7 +65,7 @@ void firebird::evaluateStatusVector(const ISC_STATUS_ARRAY& rStatusVector, } } -sal_Int32 firebird::getColumnTypeFromFBType(short aType) +sal_Int32 firebird::getColumnTypeFromFBType(short aType, short aSubType) { aType &= ~1; // Remove last bit -- it is used to denote whether column // can store Null, not needed for type determination @@ -76,12 +76,24 @@ sal_Int32 firebird::getColumnTypeFromFBType(short aType) case SQL_VARYING: return DataType::VARCHAR; case SQL_SHORT: + if(aSubType == 1) + return DataType::NUMERIC; + if(aSubType == 2) + return DataType::DECIMAL; return DataType::SMALLINT; case SQL_LONG: + if(aSubType == 1) + return DataType::NUMERIC; + if(aSubType == 2) + return DataType::DECIMAL; return DataType::INTEGER; case SQL_FLOAT: return DataType::FLOAT; case SQL_DOUBLE: + if(aSubType == 1) + return DataType::NUMERIC; + if(aSubType == 2) + return DataType::DECIMAL; return DataType::DOUBLE; case SQL_D_FLOAT: return DataType::DOUBLE; @@ -96,6 +108,10 @@ sal_Int32 firebird::getColumnTypeFromFBType(short aType) case SQL_TYPE_DATE: return DataType::DATE; case SQL_INT64: + if(aSubType == 1) + return DataType::NUMERIC; + if(aSubType == 2) + return DataType::DECIMAL; return DataType::BIGINT; case SQL_NULL: return DataType::SQLNULL; @@ -107,7 +123,7 @@ sal_Int32 firebird::getColumnTypeFromFBType(short aType) } } -OUString firebird::getColumnTypeNameFromFBType(short aType) +OUString firebird::getColumnTypeNameFromFBType(short aType, short aSubType) { aType &= ~1; // Remove last bit -- it is used to denote whether column // can store Null, not needed for type determination @@ -118,12 +134,24 @@ OUString firebird::getColumnTypeNameFromFBType(short aType) case SQL_VARYING: return OUString("SQL_VARYING"); case SQL_SHORT: + if(aSubType == 1) + return OUString("SQL_NUMERIC"); + if(aSubType == 2) + return OUString("SQL_DECIMAL"); return OUString("SQL_SHORT"); case SQL_LONG: + if(aSubType == 1) + return OUString("SQL_NUMERIC"); + if(aSubType == 2) + return OUString("SQL_DECIMAL"); return OUString("SQL_LONG"); case SQL_FLOAT: return OUString("SQL_FLOAT"); case SQL_DOUBLE: + if(aSubType == 1) + return OUString("SQL_NUMERIC"); + if(aSubType == 2) + return OUString("SQL_DECIMAL"); return OUString("SQL_DOUBLE"); case SQL_D_FLOAT: return OUString("SQL_D_FLOAT"); @@ -138,6 +166,10 @@ OUString firebird::getColumnTypeNameFromFBType(short aType) case SQL_TYPE_DATE: return OUString("SQL_TYPE_DATE"); case SQL_INT64: + if(aSubType == 1) + return OUString("SQL_NUMERIC"); + if(aSubType == 2) + return OUString("SQL_DECIMAL"); return OUString("SQL_INT64"); case SQL_NULL: return OUString("SQL_NULL"); @@ -540,4 +572,14 @@ OUString firebird::escapeWith( const OUString& sText, const char aKey, const cha return sRet; } + +sal_Int64 firebird::pow10Integer(int nDecimalCount) +{ + sal_Int64 nRet = 1; + for(int i=0; i< nDecimalCount; i++) + { + nRet *= 10; + } + return nRet; +} /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/firebird/Util.hxx b/connectivity/source/drivers/firebird/Util.hxx index b957c808b37f..fa9af07c0b27 100644 --- a/connectivity/source/drivers/firebird/Util.hxx +++ b/connectivity/source/drivers/firebird/Util.hxx @@ -53,8 +53,8 @@ namespace connectivity const css::uno::Reference< css::uno::XInterface >& _rxContext) throw (css::sdbc::SQLException); - sal_Int32 getColumnTypeFromFBType(short aType); - ::rtl::OUString getColumnTypeNameFromFBType(short aType); + sal_Int32 getColumnTypeFromFBType(short aType, short aSubType); + ::rtl::OUString getColumnTypeNameFromFBType(short aType, short aSubType); /** * Internally (i.e. in RDB$FIELD_TYPE) firebird stores the data type @@ -73,6 +73,7 @@ namespace connectivity OString extractSingleTableFromSelect( const OStringVector &vec ); OUString escapeWith( const OUString& sText, const char aKey, const char aEscapeChar); + sal_Int64 pow10Integer( int nDecimalCount ); } } #endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_UTIL_HXX |