connectivity/source/drivers/odbc/OPreparedStatement.cxx |   14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

New commits:
commit a03c481dcbbd595168ffbad017579f8fdf7a66e3
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Sun Jul 28 01:16:00 2024 +0500
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Mon Aug 5 12:25:58 2024 +0200

    tdf#162219: pass correct DecimalDigits value to SQLBindParameter
    
    ... when setting DECIMAL / NUMERIC.
    
    Passing 'scale' from setObjectWithInfo to SQLBindParameter was wrong
    anyway: in setObjectWithInfo, the scale is needed if it converts the
    object 'x' to the requested format before sending to the database.
    
    In this case, it mismatched with the actual count of decimals in the
    string sent to ODBC: it could be "1" or "1.2"; but 'scale' is always
    equal to the scale of the parameter in the database (4 in the bugdoc),
    which resulted in the error returned by driver.
    
    Note that there is code that truncates excessive decimals - it is in
    OKeySet::impl_convertValue_throw, implemented for i#106772; it would
    be best to remove that code, and let the database do its magic: e.g.,
    passing a string like "1.99999" to a DECIMAL(19,4) field in MS SQL
    Server would round it to 2, while our code truncates it to 1.9999.
    The ODBC driver can handle more digits itself. But that isn't in the
    scope here, and may need to tweak other database connectors.
    
    Change-Id: Ib50c6d78bfd0cbf5ecd59f46f300107076ec0037
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/171127
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>
    (cherry picked from commit 233af54afb6e493c3538efe7c93d0f53f1b4c3ab)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/171187
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>

diff --git a/connectivity/source/drivers/odbc/OPreparedStatement.cxx 
b/connectivity/source/drivers/odbc/OPreparedStatement.cxx
index f8bb5a6ad0b7..0478b03a4540 100644
--- a/connectivity/source/drivers/odbc/OPreparedStatement.cxx
+++ b/connectivity/source/drivers/odbc/OPreparedStatement.cxx
@@ -580,9 +580,21 @@ void SAL_CALL OPreparedStatement::setObjectWithInfo( 
sal_Int32 parameterIndex, c
         case DataType::NUMERIC:
             if(x.hasValue())
             {
+                // NB: sqlType and scale are not to be sent to the database, 
but to be used here.
+                // XParameters::setObjectWithInfo is required to convert the 
given object to the
+                // required type before being sent to the database; and scale 
may be needed for
+                // that conversion. But here we convert any object to a 
decimal string; and ODBC
+                // (or at least some drivers - see tdf#162219) needs 
DecimalDigits value passed
+                // to SQLBindParameter equal to the number of decimals in the 
string, otherwise
+                // the conversion from string to decimal fails. It may be not 
equal to the scale
+                // of the target parameter; ODBC driver handles that. 
Therefore, here we ignore
+                // the originally passed value of scale.
                 ORowSetValue aValue;
                 aValue.fill(x);
-                setParameter(parameterIndex, sqlType, scale, 
aValue.getString());
+                OUString number(aValue.getString());
+                sal_Int32 nIndex = number.indexOf('.');
+                sal_Int32 decimals = nIndex < 0 ? 0 : (number.getLength() - 
nIndex - 1);
+                setParameter(parameterIndex, sqlType, decimals, number);
             }
             else
                 setNull(parameterIndex,sqlType);

Reply via email to