This is an automated email from the ASF dual-hosted git repository.

jacktengg pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/master by this push:
     new f194151a444 [fix](be) Correct rounding and bounds in floating-point 
decimal casts (#67965)
f194151a444 is described below

commit f194151a4448e28d0962d340ce4b96b429add51d
Author: TengJianPing <[email protected]>
AuthorDate: Thu Sep 17 11:01:36 2026 +0800

    [fix](be) Correct rounding and bounds in floating-point decimal casts 
(#67965)
    
    ### What problem does this PR solve?
    
    Issue Number: None
    
    Related PR: None
    
    Problem Summary: Float/double casts reject valid decimal endpoints and
    values that round to them. Adding 0.5 before truncation also changes
    exactly representable large integers, and Decimal256 loses intermediate
    precision by narrowing long double back to double. For example, casting
    DOUBLE 4503599627370497 to DECIMAL(16,0) produces 4503599627370498, and
    casting DOUBLE 9007199254740991 to DECIMAL(39,1) produces
    9007199254740990.4.
    
    Share the DecimalV2/V3 conversion, round explicitly, preserve
    Decimal256's intermediate precision with integer limbs, and check
    inclusive bounds in integer arithmetic. Also check the original integer
    part so high-scale multiplication cannot round an overflowing input such
    as 10 into DECIMAL(38,37) back into range. Use decimal parsing to derive
    existing unit-test expectations independently of floating-to-integer
    casts. Add focused unit and regression coverage for signed endpoints,
    rounding, high-scale overflow, Decimal256, and strict/non-strict casts.
    
    ### Release note
    
    Fix valid floating-point decimal casts being rejected, incorrect
    rounding of large integers, and loss of Decimal256 intermediate
    precision. Preserve overflow errors in strict mode and NULL results in
    non-strict mode.
    
    ### Check List (For Author)
    
    - Test: Unit Test / Regression test / Manual test
        - ASAN BE build: ./build.sh --be -j32
    - 21 targeted FunctionCastToDecimalTest unit tests passed via
    run-be-ut.sh.
    - 18 regression suites passed in cast_double_to_decimal and
    function_p2/cast/to_decimal/from_float.
    - Regression output generated by run-regression-test.sh and verified by
    a subsequent comparison run.
        - clang-format 16 and build hygiene checks passed.
    - clang-tidy changed-line checks passed using the toolchain resource
    directory and a temporary VFS overlay omitting an existing unmatched
    NOLINTEND comment in core/types.h; that source file is unchanged.
    - Behavior changed: Yes, correct decimal boundary acceptance, rounding,
    and Decimal256 precision.
    - Does this need documentation: No
    
    ### What problem does this PR solve?
    
    Issue Number: close #xxx
    
    Related PR: #xxx
    
    Problem Summary:
    
    ### Release note
    
    None
    
    ### Check List (For Author)
    
    - Test <!-- At least one of them must be included. -->
        - [ ] Regression test
        - [ ] Unit Test
        - [ ] Manual test (add detailed scripts or steps below)
        - [ ] No need to test or manual test. Explain why:
    - [ ] This is a refactor/code format and no logic has been changed.
            - [ ] Previous test can cover this change.
            - [ ] No code files have been changed.
            - [ ] Other reason <!-- Add your reason?  -->
    
    - Behavior changed:
        - [ ] No.
        - [ ] Yes. <!-- Explain the behavior change -->
    
    - Does this need documentation?
        - [ ] No.
    - [ ] Yes. <!-- Add document PR link here. eg:
    https://github.com/apache/doris-website/pull/1214 -->
    
    ### Check List (For Reviewer who merge this PR)
    
    - [ ] Confirm the release note
    - [ ] Confirm test cases
    - [ ] Confirm document
    - [ ] Add branch pick label <!-- Add branch pick label that this PR
    should merge into -->
---
 be/src/exprs/function/cast/cast_to_decimal.h       |  65 ++++++------
 be/test/exprs/function/cast/cast_to_decimal.cpp    | 116 +++++++++++++++++++++
 be/test/exprs/function/cast/cast_to_decimal_test.h |  36 ++++---
 .../test_cast_float_decimal_rounding.out           | 106 +++++++++++++++++++
 .../test_cast_float_decimal_rounding.groovy        | 116 +++++++++++++++++++++
 5 files changed, 393 insertions(+), 46 deletions(-)

diff --git a/be/src/exprs/function/cast/cast_to_decimal.h 
b/be/src/exprs/function/cast/cast_to_decimal.h
index 8dc4c6b4aea..1ee8cbee5ab 100644
--- a/be/src/exprs/function/cast/cast_to_decimal.h
+++ b/be/src/exprs/function/cast/cast_to_decimal.h
@@ -233,7 +233,7 @@ struct CastToDecimal {
     }
 
     template <typename FromCppT, typename ToCppT>
-        requires(IsDecimalNumber<ToCppT> && IsCppTypeFloat<FromCppT> && 
!IsDecimal128V2<ToCppT>)
+        requires(IsDecimalNumber<ToCppT> && IsCppTypeFloat<FromCppT>)
     static inline bool _from_float(const FromCppT& from, ToCppT& to, UInt32 
to_precision,
                                    UInt32 to_scale,
                                    const typename ToCppT::NativeType& 
scale_multiplier,
@@ -246,45 +246,48 @@ struct CastToDecimal {
                                    "to decimal");
             return false;
         }
-        using DoubleType = std::conditional_t<IsDecimal256<ToCppT>, long 
double, double>;
-        DoubleType tmp = from * static_cast<DoubleType>(scale_multiplier);
-        if (tmp <= DoubleType(min_result) || tmp >= DoubleType(max_result)) {
+        auto overflow = [&]() {
             if (params.is_strict) {
                 params.status = DECIMAL_CONVERT_OVERFLOW_ERROR(from, 
"float/double", to_precision,
                                                                to_scale);
             }
             return false;
+        };
+        // Use binary64 arithmetic for every decimal backing type. This also 
matches FE constant
+        // folding for halfway cases such as +/-0.15 at scale 1.
+        // Round before checking the inclusive decimal bounds. Adding 0.5 
would itself round
+        // exactly representable odd integers above 2^52 to the next even 
integer in double.
+        const double tmp =
+                std::round(static_cast<double>(from) * 
static_cast<double>(scale_multiplier));
+        if (tmp < static_cast<double>(min_result) || tmp > 
static_cast<double>(max_result)) {
+            return overflow();
         }
-        to.value = static_cast<typename 
ToCppT::NativeType>(static_cast<double>(
-                from * static_cast<DoubleType>(scale_multiplier) + ((from >= 
0) ? 0.5 : -0.5)));
-        return true;
-    }
 
-    template <typename FromCppT, typename ToCppT>
-        requires(IsDecimal128V2<ToCppT> && IsCppTypeFloat<FromCppT>)
-    static inline bool _from_float(const FromCppT& from, ToCppT& to, UInt32 
to_precision,
-                                   UInt32 to_scale,
-                                   const typename ToCppT::NativeType& 
scale_multiplier,
-                                   const typename ToCppT::NativeType& 
min_result,
-                                   const typename ToCppT::NativeType& 
max_result,
-                                   CastParameters& params) {
-        if (!std::isfinite(from)) {
-            params.status = Status(ErrorCode::ARITHMETIC_OVERFLOW_ERRROR,
-                                   "Decimal convert overflow. Cannot convert 
infinity or NaN "
-                                   "to decimal");
-            return false;
-        }
-        using DoubleType = std::conditional_t<IsDecimal256<ToCppT>, long 
double, double>;
-        DoubleType tmp = from * static_cast<DoubleType>(scale_multiplier);
-        if (tmp <= DoubleType(min_result) || tmp >= DoubleType(max_result)) {
-            if (params.is_strict) {
-                params.status = DECIMAL_CONVERT_OVERFLOW_ERROR(from, 
"float/double", to_precision,
-                                                               to_scale);
+        using NativeType = typename ToCppT::NativeType;
+        if (to_scale > 0) {
+            // Scaling can round an out-of-range integer back inside the 
decimal bounds:
+            // double(10 * 10^37) is below 10^38. Check the original integer 
part exactly.
+            const NativeType integral_limit =
+                    
DataTypeDecimal<ToCppT::PType>::get_scale_multiplier(to_precision - to_scale);
+            const auto integral = static_cast<NativeType>(from);
+            if (integral <= -integral_limit || integral >= integral_limit) {
+                return overflow();
             }
-            return false;
         }
-        to = DecimalV2Value(static_cast<typename 
ToCppT::NativeType>(static_cast<double>(
-                from * static_cast<DoubleType>(scale_multiplier) + ((from >= 
0) ? 0.5 : -0.5))));
+        // Every supported decimal precision leaves room below the native 
integer limit, even when
+        // converting max_result to floating point rounds it up. Int256 
reconstructs the binary64
+        // significand directly, so this also preserves every integer bit 
represented by tmp.
+        auto result = static_cast<NativeType>(tmp);
+        // Floating point cannot represent all decimal bounds exactly. Recheck 
in integer
+        // arithmetic to reject a rounded-up bound such as double(10^18 - 1) 
== 10^18.
+        if (result < min_result || result > max_result) {
+            return overflow();
+        }
+        if constexpr (IsDecimal128V2<ToCppT>) {
+            to = DecimalV2Value(result);
+        } else {
+            to.value = result;
+        }
         return true;
     }
 
diff --git a/be/test/exprs/function/cast/cast_to_decimal.cpp 
b/be/test/exprs/function/cast/cast_to_decimal.cpp
index b8e1bef4825..980d1569863 100644
--- a/be/test/exprs/function/cast/cast_to_decimal.cpp
+++ b/be/test/exprs/function/cast/cast_to_decimal.cpp
@@ -15,6 +15,8 @@
 // specific language governing permissions and limitations
 // under the License.
 
+#include "exprs/function/cast/cast_to_decimal.h"
+
 #include <fstream>
 #include <memory>
 
@@ -119,6 +121,120 @@ TEST_F(FunctionCastToDecimalTest, 
string_parser_scientific_rounding) {
     EXPECT_EQ(parse_decimal128("0.00000000000000005"), 0);
 }
 
+namespace {
+template <typename T, typename F>
+void check_float_decimal_value(F input, typename T::NativeType expected, 
UInt32 precision,
+                               UInt32 scale, bool strict) {
+    CastParameters params;
+    params.is_strict = strict;
+    T result;
+    ASSERT_TRUE(CastToDecimal::from_float(input, result, precision, scale, 
params));
+    EXPECT_EQ(result.value, expected);
+}
+
+template <typename T>
+void check_float_decimal_overflow(double input, UInt32 precision, bool strict, 
UInt32 scale = 0) {
+    CastParameters params;
+    params.is_strict = strict;
+    T result;
+    EXPECT_FALSE(CastToDecimal::from_float(input, result, precision, scale, 
params));
+    EXPECT_EQ(params.status.ok(), !strict);
+}
+} // namespace
+
+TEST_F(FunctionCastToDecimalTest, float_rounding_and_bounds) {
+    auto check = []<typename T>() {
+        for (bool strict : {false, true}) {
+            for (double sign : {-1.0, 1.0}) {
+                for (double input : {9.0, 9.25, std::nextafter(9.5, 0.0)}) {
+                    check_float_decimal_value<T>(sign * input, typename 
T::NativeType(sign * 9), 1,
+                                                 0, strict);
+                }
+                for (double input : {9.5, 10.0, 
std::numeric_limits<double>::max()}) {
+                    check_float_decimal_overflow<T>(sign * input, 1, strict);
+                }
+                check_float_decimal_value<T>(sign * std::nextafter(0.5, 0.0),
+                                             typename T::NativeType(0), 1, 0, 
strict);
+                check_float_decimal_value<T>(sign * 0.5, typename 
T::NativeType(sign), 1, 0,
+                                             strict);
+                check_float_decimal_value<T>(static_cast<float>(sign * 9.25),
+                                             typename T::NativeType(sign * 9), 
1, 0, strict);
+            }
+        }
+    };
+    check.operator()<Decimal32>();
+    check.operator()<Decimal64>();
+    check.operator()<Decimal128V3>();
+    check.operator()<Decimal256>();
+}
+
+TEST_F(FunctionCastToDecimalTest, float_rounding_large_integers) {
+    auto check = []<typename T>() {
+        for (bool strict : {false, true}) {
+            for (int64_t input : {4503599627370497LL, -4503599627370497LL}) {
+                check_float_decimal_value<T>(static_cast<double>(input),
+                                             typename T::NativeType(input), 
16, 0, strict);
+            }
+            // The floating representation of the bound 10^18 - 1 rounds up to 
10^18.
+            for (double input : {1e18, -1e18}) {
+                check_float_decimal_overflow<T>(input, 18, strict);
+            }
+        }
+    };
+    check.operator()<Decimal64>();
+    check.operator()<Decimal128V3>();
+    check.operator()<Decimal256>();
+}
+
+TEST_F(FunctionCastToDecimalTest, float_rounding_independent_of_backing_width) 
{
+    for (bool strict : {false, true}) {
+        for (int64_t sign : {-1, 1}) {
+            check_float_decimal_value<Decimal128V3>(sign * 0.15, int128_t(sign 
* 2), 38, 1, strict);
+            check_float_decimal_value<Decimal256>(sign * 0.15, 
wide::Int256(sign * 2), 39, 1,
+                                                  strict);
+        }
+    }
+}
+
+TEST_F(FunctionCastToDecimalTest, float_rounding_decimal256_large_values) {
+    CastParameters params;
+    Decimal256 result;
+    for (int64_t sign : {-1, 1}) {
+        ASSERT_TRUE(CastToDecimal::from_float(sign * 9007199254740991.0, 
result, 39, 1, params));
+        EXPECT_EQ(result.value, wide::Int256(sign) * 90071992547409904LL);
+        // Exercise both 128-bit limbs, as well as a value with only the high 
limb set.
+        ASSERT_TRUE(CastToDecimal::from_float(sign * (0x1p128 + 0x1p76), 
result, 76, 0, params));
+        EXPECT_EQ(result.value, sign * ((wide::Int256(1) << 128) + 
(wide::Int256(1) << 76)));
+        ASSERT_TRUE(CastToDecimal::from_float(sign * 0x1p200, result, 76, 0, 
params));
+        EXPECT_EQ(result.value, sign * (wide::Int256(1) << 200));
+    }
+}
+
+TEST_F(FunctionCastToDecimalTest, float_rounding_high_scale_overflow) {
+    auto check = []<typename T>(UInt32 precision) {
+        for (bool strict : {false, true}) {
+            for (double sign : {-1.0, 1.0}) {
+                check_float_decimal_overflow<T>(sign * 10, precision, strict, 
precision - 1);
+                check_float_decimal_overflow<T>(sign, precision, strict, 
precision);
+            }
+        }
+    };
+    check.operator()<Decimal128V3>(38);
+    check.operator()<Decimal256>(76);
+}
+
+TEST_F(FunctionCastToDecimalTest, float_rounding_decimalv2) {
+    CastParameters params;
+    DecimalV2Value result;
+    for (int64_t sign : {-1, 1}) {
+        ASSERT_TRUE(CastToDecimal::from_float(sign * 4503599.627370497, 
result, 27, 9, params));
+        EXPECT_EQ(result.value(), sign * int128_t(4503599627370497LL));
+        ASSERT_TRUE(CastToDecimal::from_float(sign * std::nextafter(0.5e-9, 
0.0), result, 27, 9,
+                                              params));
+        EXPECT_EQ(result.value(), 0);
+    }
+}
+
 TEST_F(FunctionCastToDecimalTest, test_from_bool) {
     from_bool_test_func<Decimal32>(9, 0);
     from_bool_test_func<Decimal32>(9, 1);
diff --git a/be/test/exprs/function/cast/cast_to_decimal_test.h 
b/be/test/exprs/function/cast/cast_to_decimal_test.h
index 55e4eb5a17a..4c7635b8c77 100644
--- a/be/test/exprs/function/cast/cast_to_decimal_test.h
+++ b/be/test/exprs/function/cast/cast_to_decimal_test.h
@@ -1395,9 +1395,6 @@ struct FunctionCastToDecimalTest : public 
FunctionCastTest {
             fractional_part.emplace(large_fractional2);
             fractional_part.emplace(large_fractional3);
         }
-        auto max_result = dt_to.get_max_digits_number(precision);
-        auto min_result = -max_result;
-
         auto multiplier = dt_to.get_scale_multiplier(scale);
 
         std::vector<std::string> const_test_strs;
@@ -1447,18 +1444,27 @@ struct FunctionCastToDecimalTest : public 
FunctionCastTest {
                         float_value = std::strtod(v_str.c_str(), &end);
                     }
                     // float_value = is_negative ? -float_value : float_value;
-                    using DoubleType = std::conditional_t<IsDecimal256<T>, 
long double, double>;
-                    DoubleType expect_value = float_value * 
DoubleType(multiplier);
-                    if (expect_value <= DoubleType(min_result) ||
-                        expect_value >= DoubleType(max_result)) {
-                        // std::cerr << fmt::format("{:f} overflow\n", 
expect_value);
-                    } else {
-                        T v {};
-                        // v.value = typename T::NativeType(FromT(float_value 
* multiplier +
-                        //                                        (float_value 
>= 0 ? 0.5 : -0.5)));
-                        v.value = typename T::NativeType(static_cast<double>(
-                                float_value * 
static_cast<DoubleType>(multiplier) +
-                                ((float_value >= 0) ? 0.5 : -0.5)));
+                    // The original integer part must fit even when floating 
scaling rounds
+                    // an overflowing value down (for example, 10 into 
decimal(38, 37)).
+                    const auto integral_str = fmt::format("{:.0f}", 
std::trunc(float_value));
+                    StringParser::ParseResult integral_result;
+                    
static_cast<void>(StringParser::string_to_decimal<T::PType>(
+                            integral_str.data(), integral_str.size(), 
precision, scale,
+                            &integral_result));
+                    if (integral_result != StringParser::PARSE_SUCCESS) {
+                        continue;
+                    }
+                    // Keep the rounding rule independent of the target 
decimal backing type.
+                    const auto rounded = 
std::round(static_cast<double>(float_value) *
+                                                    
static_cast<double>(multiplier));
+                    // Derive the expected integer through decimal text 
parsing, independently
+                    // of the cast implementation's floating-to-integer 
conversion and bounds.
+                    const auto integer_str = fmt::format("{:.0f}", rounded);
+                    StringParser::ParseResult parse_result;
+                    T v {};
+                    v.value = StringParser::string_to_decimal<T::PType>(
+                            integer_str.data(), integer_str.size(), precision, 
0, &parse_result);
+                    if (parse_result == StringParser::PARSE_SUCCESS) {
                         data_set.push_back({{float_value}, v});
                         // dbg_str += fmt::format("({:f}, {})|", float_value, 
dt_to.to_string(v));
 
diff --git 
a/regression-test/data/cast_double_to_decimal/test_cast_float_decimal_rounding.out
 
b/regression-test/data/cast_double_to_decimal/test_cast_float_decimal_rounding.out
new file mode 100644
index 00000000000..5819bb69fbf
--- /dev/null
+++ 
b/regression-test/data/cast_double_to_decimal/test_cast_float_decimal_rounding.out
@@ -0,0 +1,106 @@
+-- This file is automatically generated. You should know what you did if you 
want to edit this
+-- !bounds_false --
+1      9       9
+2      -9      -9
+3      9       9
+4      -9      -9
+5      0       0
+6      0       0
+7      1       1
+8      -1      -1
+9      3       3
+10     -3      -3
+
+-- !scaled_bounds_false --
+16     9.99
+17     -9.99
+18     9.99
+19     -9.99
+
+-- !large_false --
+20     4503599627370497        4503599627370497        4503599627370496.8
+21     -4503599627370497       -4503599627370497       -4503599627370496.8
+22     9007199254740991        9007199254740991        9007199254740990.4
+23     -9007199254740991       -9007199254740991       -9007199254740990.4
+
+-- !decimal32_false --
+24     999999999
+25     -999999999
+
+-- !decimal256_false --
+28     340282366920938539021238333346091630592
+29     -340282366920938539021238333346091630592
+
+-- !decimalv2_false --
+30     4503599.627370497
+31     -4503599.627370497
+
+-- !constants_false --
+9      -9      4503599627370497        9007199254740991.0
+
+-- !backing_width_false --
+34     0.2     0.2     0.2     0.2
+35     -0.2    -0.2    -0.2    -0.2
+
+-- !bounds_true --
+1      9       9
+2      -9      -9
+3      9       9
+4      -9      -9
+5      0       0
+6      0       0
+7      1       1
+8      -1      -1
+9      3       3
+10     -3      -3
+
+-- !scaled_bounds_true --
+16     9.99
+17     -9.99
+18     9.99
+19     -9.99
+
+-- !large_true --
+20     4503599627370497        4503599627370497        4503599627370496.8
+21     -4503599627370497       -4503599627370497       -4503599627370496.8
+22     9007199254740991        9007199254740991        9007199254740990.4
+23     -9007199254740991       -9007199254740991       -9007199254740990.4
+
+-- !decimal32_true --
+24     999999999
+25     -999999999
+
+-- !decimal256_true --
+28     340282366920938539021238333346091630592
+29     -340282366920938539021238333346091630592
+
+-- !decimalv2_true --
+30     4503599.627370497
+31     -4503599.627370497
+
+-- !constants_true --
+9      -9      4503599627370497        9007199254740991.0
+
+-- !backing_width_true --
+34     0.2     0.2     0.2     0.2
+35     -0.2    -0.2    -0.2    -0.2
+
+-- !overflow --
+11     \N      \N
+12     \N      \N
+13     \N      \N
+14     \N      \N
+15     \N      \N
+
+-- !rounded_bound --
+26     \N
+27     \N
+
+-- !high_scale_overflow --
+13     \N      \N
+14     \N      \N
+
+-- !full_scale_overflow --
+32     \N      \N
+33     \N      \N
+
diff --git 
a/regression-test/suites/cast_double_to_decimal/test_cast_float_decimal_rounding.groovy
 
b/regression-test/suites/cast_double_to_decimal/test_cast_float_decimal_rounding.groovy
new file mode 100644
index 00000000000..2a208c43a2f
--- /dev/null
+++ 
b/regression-test/suites/cast_double_to_decimal/test_cast_float_decimal_rounding.groovy
@@ -0,0 +1,116 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+suite("test_cast_float_decimal_rounding") {
+    sql "set enable_decimal256 = true"
+    sql "drop table if exists test_cast_float_decimal_rounding"
+    sql """create table test_cast_float_decimal_rounding (
+        id int, d double, f float
+    ) distributed by hash(id) buckets 1 properties("replication_num" = "1")"""
+    sql """insert into test_cast_float_decimal_rounding values
+        (1, 9, 9), (2, -9, -9), (3, 9.25, 9.25), (4, -9.25, -9.25),
+        (5, 0.49999999999999994, 0.49999997),
+        (6, -0.49999999999999994, -0.49999997),
+        (7, 0.5, 0.5), (8, -0.5, -0.5), (9, 2.5, 2.5), (10, -2.5, -2.5),
+        (11, 9.5, 9.5), (12, -9.5, -9.5), (13, 10, 10), (14, -10, -10),
+        (15, null, null),
+        (16, 9.99, 0), (17, -9.99, 0),
+        (18, 9.9921875, 0), (19, -9.9921875, 0),
+        (20, 4503599627370497, 0), (21, -4503599627370497, 0),
+        (22, 9007199254740991, 0), (23, -9007199254740991, 0),
+        (24, 999999999, 0), (25, -999999999, 0),
+        (26, 1000000000000000000, 0), (27, -1000000000000000000, 0),
+        (28, cast('340282366920938539021238333346091630592' as double), 0),
+        (29, cast('-340282366920938539021238333346091630592' as double), 0),
+        (30, 4503599.627370497, 0), (31, -4503599.627370497, 0),
+        (32, 1, 1), (33, -1, -1), (34, 0.15, 0), (35, -0.15, 0)
+    """
+
+    for (def strict : [false, true]) {
+        sql "set enable_strict_cast = ${strict}"
+        "qt_bounds_${strict}" """select id, cast(d as decimalv3(1,0)), cast(f 
as decimalv3(1,0))
+            from test_cast_float_decimal_rounding where id <= 10 order by id"""
+        "qt_scaled_bounds_${strict}" """select id, cast(d as decimalv3(3,2))
+            from test_cast_float_decimal_rounding where id between 16 and 19 
order by id"""
+        "qt_large_${strict}" """select id, cast(d as decimalv3(16,0)), cast(d 
as decimalv3(38,0)),
+            cast(d as decimalv3(39,1)) from test_cast_float_decimal_rounding
+            where id between 20 and 23 order by id"""
+        "qt_decimal32_${strict}" """select id, cast(d as decimalv3(9,0))
+            from test_cast_float_decimal_rounding where id in (24,25) order by 
id"""
+        "qt_decimal256_${strict}" """select id, cast(d as decimalv3(76,0))
+            from test_cast_float_decimal_rounding where id in (28,29) order by 
id"""
+        "qt_decimalv2_${strict}" """select id, cast(d as decimalv2(27,9))
+            from test_cast_float_decimal_rounding where id in (30,31) order by 
id"""
+        "qt_constants_${strict}" """select cast(cast('9.25' as double) as 
decimalv3(1,0)),
+            cast(cast('-9' as float) as decimalv3(1,0)),
+            cast(cast('4503599627370497' as double) as decimalv3(16,0)),
+            cast(cast('9007199254740991' as double) as decimalv3(39,1))"""
+        "qt_backing_width_${strict}" """select * from (
+            select id, cast(d as decimalv3(38,1)), cast(d as decimalv3(39,1)),
+                cast(cast('0.15' as double) as decimalv3(38,1)),
+                cast(cast('0.15' as double) as decimalv3(39,1))
+                from test_cast_float_decimal_rounding where id = 34
+            union all
+            select id, cast(d as decimalv3(38,1)), cast(d as decimalv3(39,1)),
+                cast(cast('-0.15' as double) as decimalv3(38,1)),
+                cast(cast('-0.15' as double) as decimalv3(39,1))
+                from test_cast_float_decimal_rounding where id = 35
+            ) t order by id"""
+    }
+    sql "set enable_strict_cast = false"
+    qt_overflow """select id, cast(d as decimalv3(1,0)), cast(f as 
decimalv3(1,0))
+        from test_cast_float_decimal_rounding where id between 11 and 15 order 
by id"""
+    qt_rounded_bound """select id, cast(d as decimalv3(18,0))
+        from test_cast_float_decimal_rounding where id in (26,27) order by 
id"""
+    qt_high_scale_overflow """select id, cast(d as decimalv3(38,37)), cast(d 
as decimalv3(76,75))
+        from test_cast_float_decimal_rounding where id in (13,14) order by 
id"""
+    qt_full_scale_overflow """select id, cast(d as decimalv3(38,38)), cast(d 
as decimalv3(76,76))
+        from test_cast_float_decimal_rounding where id in (32,33) order by 
id"""
+    sql "set enable_strict_cast = true"
+    for (def type : ["decimalv3(38,37)", "decimalv3(76,75)"]) {
+        for (def id : [13,14]) {
+            test {
+                sql "select cast(d as ${type}) from 
test_cast_float_decimal_rounding where id = ${id}"
+                exception "Arithmetic overflow"
+            }
+        }
+    }
+    for (def type : ["decimalv3(38,38)", "decimalv3(76,76)"]) {
+        for (def id : [32,33]) {
+            test {
+                sql "select cast(d as ${type}) from 
test_cast_float_decimal_rounding where id = ${id}"
+                exception "Arithmetic overflow"
+            }
+        }
+    }
+    for (def id : [11, 12, 13, 14]) {
+        test {
+            sql "select cast(d as decimalv3(1,0)) from 
test_cast_float_decimal_rounding where id = ${id}"
+            exception "Arithmetic overflow"
+        }
+        test {
+            sql "select cast(f as decimalv3(1,0)) from 
test_cast_float_decimal_rounding where id = ${id}"
+            exception "Arithmetic overflow"
+        }
+    }
+    for (def id : [26, 27]) {
+        test {
+            sql "select cast(d as decimalv3(18,0)) from 
test_cast_float_decimal_rounding where id = ${id}"
+            exception "Arithmetic overflow"
+        }
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to