tdf#123591: Firebird: Fix setting double values

Handle numerical and decimal values separately. In order to do that
we have to indentify the exact type first. That can be achieved using
sqltype and sqlsubtype in Firebird API.

Change-Id: Ie664dead51bae5522ee53009cda1cddbe0d64b16
Reviewed-on: https://gerrit.libreoffice.org/75525
Reviewed-by: Tamás Bunth <btomi96@gmail.com>
Tested-by: Tamás Bunth <btomi96@gmail.com>
diff --git a/connectivity/source/drivers/firebird/PreparedStatement.cxx b/connectivity/source/drivers/firebird/PreparedStatement.cxx
index 737875e..69ce91f 100644
--- a/connectivity/source/drivers/firebird/PreparedStatement.cxx
+++ b/connectivity/source/drivers/firebird/PreparedStatement.cxx
@@ -420,34 +420,44 @@ void SAL_CALL OPreparedStatement::setDouble(sal_Int32 nIndex, double nValue)
    ensurePrepared();

    XSQLVAR* pVar = m_pInSqlda->sqlvar + (nIndex - 1);
    int dType = (pVar->sqltype & ~1); // drop flag bit for now

    // take decimal places into account, later on they are removed in makeNumericString
    // minus because firebird stores scale as a negative number
    int nDecimalCount = -pVar->sqlscale;
    sal_Int64 nDecimalCountExp = pow10Integer(nDecimalCount);

    nValue = static_cast<double>(nValue * nDecimalCountExp);
    short dType = (pVar->sqltype & ~1); // drop flag bit for now
    short dSubType = pVar->sqlsubtype;
    // Assume it is a sub type of a number.
    if(dSubType < 0 || dSubType > 2)
    {
        ::dbtools::throwSQLException(
            "Incorrect number sub type",
            ::dbtools::StandardSQLState::INVALID_SQL_DATA_TYPE,
            *this);
    }
    // firebird stores scale as a negative number
    ColumnTypeInfo columnType{ dType, dSubType,
        static_cast<short>(-pVar->sqlscale) };

    // Caller might try to set an integer type here. It makes sense to convert
    // it instead of throwing an error.
    switch(dType)
    switch(columnType.getSdbcType())
    {
        case SQL_SHORT:
        case DataType::SMALLINT:
            setValue< sal_Int16 >(nIndex,
                    static_cast<sal_Int16>(nValue),
                    dType);
            break;
        case SQL_LONG:
        case DataType::INTEGER:
            setValue< sal_Int32 >(nIndex,
                    static_cast<sal_Int32>(nValue),
                    dType);
            break;
        case SQL_INT64:
        case DataType::BIGINT:
            setValue< sal_Int64 >(nIndex,
                    static_cast<sal_Int64>(nValue),
                    dType);
            break;
        case DataType::NUMERIC:
        case DataType::DECIMAL:
            // take decimal places into account, later on they are removed in makeNumericString
            setObjectWithInfo(nIndex,Any{nValue}, columnType.getSdbcType(), columnType.getScale());
            break;
        default:
            setValue< double >(nIndex, nValue, SQL_DOUBLE); // TODO: SQL_D_FLOAT?
    }
diff --git a/connectivity/source/drivers/firebird/Util.hxx b/connectivity/source/drivers/firebird/Util.hxx
index 26929a9..f380ab6 100644
--- a/connectivity/source/drivers/firebird/Util.hxx
+++ b/connectivity/source/drivers/firebird/Util.hxx
@@ -34,8 +34,10 @@ namespace connectivity
            Image = -9546
        };

        // Numeric and decimal types can be identified by their subtype
        // 1 for NUMERIC, 2 for DECIMAL
        /**
         * Numeric and decimal types can be identified by their subtype in
         * Firebird API. 1 for NUMERIC, 2 for DECIMAL.
         */
        enum class NumberSubType {
            Other = 0,
            Numeric = 1,
@@ -49,6 +51,16 @@ private:
            short m_nScale;
            OUString m_sCharsetName;
public:
            /**
             * @param tType SQL type of column defined by Firebird (e.g.
             * SQL_DOUBLE)
             * @param aSubType SQL sub type as in firebird API. See
             * NumberSubType.
             * @param scale: Scale of the number. It is ignored in case it's not
             * a number. Scale obtained from the Firebird API is negative, so
             * that should be negated before passing to this constructor.
             *
             */
            explicit ColumnTypeInfo( short aType, short aSubType = 0,
                    short nScale = 0, const OUString& sCharset = OUString() )
                : m_aType(aType)