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);