tdf#167591: Convert date string to date early

To insert a default value, ODatabaseForm gets its value from column
properties, and passes to XColumnUpdate. The problem appeared when
the default was a localized date string, like "20/07/25".

The string was set as the value of a ORowSetValue; then, when its
value was requested, its getDate() called DBTypeConversion::toDate,
which only handles ISO date strings. But for correct conversion, not
only the string is needed, but also its format key. This information
is already lost at that point. The conversion failed, and the result
date was invalid, somewhere in the beginning of CE.

Try to overcome this problem by converting the default value from
date string to date(time) where all the information is available.

Change-Id: I73e96e433895da18cbf6145ffc26b16fa4844452
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/188093
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
Tested-by: Jenkins
This commit is contained in:
Mike Kaganski
2025-07-21 08:18:23 +02:00
parent 5b808448dc
commit 3b22e7c3aa
2 changed files with 86 additions and 12 deletions
+82 -12
View File
@@ -53,11 +53,13 @@
#include <com/sun/star/sdbc/XRowSet.hpp>
#include <com/sun/star/sdbcx/Privilege.hpp>
#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
#include <com/sun/star/util/NumberFormatter.hpp>
#include <com/sun/star/util/URLTransformer.hpp>
#include <com/sun/star/util/XURLTransformer.hpp>
#include <com/sun/star/util/XModifiable2.hpp>
#include <comphelper/basicio.hxx>
#include <comphelper/numbers.hxx>
#include <comphelper/property.hxx>
#include <comphelper/seqstream.hxx>
#include <comphelper/sequence.hxx>
@@ -68,6 +70,7 @@
#include <rtl/math.hxx>
#include <rtl/tencinfo.h>
#include <svl/inettype.hxx>
#include <svl/numformat.hxx>
#include <tools/datetime.hxx>
#include <tools/debug.hxx>
#include <comphelper/diagnose_ex.hxx>
@@ -1923,6 +1926,70 @@ void SAL_CALL ODatabaseForm::reset()
}
}
Reference<XNumberFormatter> ODatabaseForm::getFormatter()
{
if (auto xSupplier = dbtools::getNumberFormats(getConnection(), true, m_xContext))
{
auto result = NumberFormatter::create(m_xContext);
result->attachNumberFormatsSupplier(xSupplier);
return result;
}
return {};
}
static void maybeConvertDefaultStringToDate(Any& def, const auto& getFieldPropOrDefault,
const auto& getFormatter)
{
OUString sDefault;
if (!(def >>= sDefault))
return;
sal_Int32 dataType = getFieldPropOrDefault(PROPERTY_FIELDTYPE, sal_Int32());
if (dataType != css::sdbc::DataType::DATE && dataType != css::sdbc::DataType::TIMESTAMP)
return;
Reference<XNumberFormatter> xFormatter = getFormatter();
if (!xFormatter)
return;
// Convert to a date
sal_uInt32 nFormatKey = xFormatter->detectNumberFormat(
getFieldPropOrDefault(PROPERTY_FORMATKEY, sal_uInt32()), sDefault);
sal_Int16 nType = comphelper::getNumberFormatType(xFormatter, nFormatKey);
if ((nType & css::util::NumberFormat::DATE) == 0)
return;
Reference<XNumberFormatsSupplier> xSupplier = xFormatter->getNumberFormatsSupplier();
css::util::Date aNull;
try
{
if (!(xSupplier->getNumberFormatSettings()->getPropertyValue(u"NullDate"_ustr) >>= aNull))
return;
}
catch (const Exception&)
{
return;
}
::Date d(aNull);
double value = xFormatter->convertStringToNumber(nFormatKey, sDefault);
switch (dataType)
{
case css::sdbc::DataType::DATE:
{
d.AddDays(value);
def <<= d.GetUNODate();
break;
}
case css::sdbc::DataType::TIMESTAMP:
{
::DateTime dt(d);
dt.AddTime(value);
def <<= dt.GetUNODateTime();
break;
}
}
}
void ODatabaseForm::reset_impl(bool _bApproveByListeners)
{
@@ -1956,24 +2023,27 @@ void ODatabaseForm::reset_impl(bool _bApproveByListeners)
if ( !xColUpdate.is() )
continue;
Reference< XPropertySetInfo > xPSI;
if ( xColProps.is() )
xPSI = xColProps->getPropertySetInfo( );
auto getPropValOrDefault = [&xColProps, xPSI = xColProps->getPropertySetInfo()](
const OUString& propname, auto default_value)
{
if (xPSI && xPSI->hasPropertyByName(propname))
fromAny(xColProps->getPropertyValue(propname), &default_value);
return default_value;
};
static constexpr OUString PROPERTY_CONTROLDEFAULT = u"ControlDefault"_ustr;
if (!xPSI || !xPSI->hasPropertyByName(PROPERTY_CONTROLDEFAULT))
continue;
Any aDefault = xColProps->getPropertyValue( PROPERTY_CONTROLDEFAULT );
Any aDefault = getPropValOrDefault(u"ControlDefault"_ustr, Any());
if (!aDefault.hasValue())
continue;
bool bReadOnly = false;
if ( xPSI->hasPropertyByName( PROPERTY_ISREADONLY ) )
xColProps->getPropertyValue( PROPERTY_ISREADONLY ) >>= bReadOnly;
if (bReadOnly)
if (getPropValOrDefault(PROPERTY_ISREADONLY, false))
continue;
// If the column is a date, and the default is a string, it may be
// impossible to convert the string to date at a later stage (namely, in
// DBTypeConversion::getValue, where the column formatting is unknown).
maybeConvertDefaultStringToDate(aDefault, getPropValOrDefault,
[this]() { return getFormatter(); });
try
{
xColUpdate->updateObject( aDefault );
+4
View File
@@ -54,6 +54,7 @@
#include <com/sun/star/beans/XPropertyContainer.hpp>
#include <com/sun/star/beans/XPropertyAccess.hpp>
#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
#include <com/sun/star/util/XNumberFormatter.hpp>
#include <tools/link.hxx>
@@ -518,6 +519,9 @@ private:
void impl_construct();
DECL_LINK( OnTimeout, Timer*, void );
css::uno::Reference<css::util::XNumberFormatter> getFormatter();
protected:
using OPropertySetHelper::getPropertyValues;
};