[Libreoffice-commits] core.git: connectivity/source

Wastack btomi96 at gmail.com
Thu Nov 10 09:37:42 UTC 2016


 connectivity/source/drivers/firebird/Column.cxx            |    1 
 connectivity/source/drivers/firebird/DatabaseMetaData.cxx  |   74 ++++++---
 connectivity/source/drivers/firebird/PreparedStatement.cxx |  103 ++++++++++++-
 connectivity/source/drivers/firebird/PreparedStatement.hxx |    7 
 connectivity/source/drivers/firebird/ResultSet.cxx         |   82 ++++++++++
 connectivity/source/drivers/firebird/ResultSet.hxx         |    3 
 connectivity/source/drivers/firebird/ResultSetMetaData.cxx |   42 ++++-
 connectivity/source/drivers/firebird/Util.cxx              |   46 +++++
 connectivity/source/drivers/firebird/Util.hxx              |    5 
 9 files changed, 324 insertions(+), 39 deletions(-)

New commits:
commit 21cc1826c758bb71bb0cfa055b3bb51a38bc2acb
Author: Wastack <btomi96 at gmail.com>
Date:   Mon Oct 31 16:32:54 2016 +0100

    WiP tdf#74172 use DECIMAL and NUMERIC data types
    
    Change-Id: I917cdf6e8d3ebfa7c9e4a52ca61adc5b8707ecfc
    Reviewed-on: https://gerrit.libreoffice.org/30447
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Lionel Elie Mamane <lionel at mamane.lu>

diff --git a/connectivity/source/drivers/firebird/Column.cxx b/connectivity/source/drivers/firebird/Column.cxx
index 28ce9ac..38c367c 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 f5b1a7e..bb26401 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 13402b8..f9adc0b 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 d98e46d..04ba792 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 916f7df..7174418 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 fb4d929..347c7ea 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 9baadab..c36148c 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 ee5a9bd..318aa6d 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 b957c80..fa9af07 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


More information about the Libreoffice-commits mailing list