Files
doris/regression-test/data/correctness
Mryange 4c6df9062e [fix](DECIMALV3)fix cumulative precision when literal and DECIMALV3 operations in Legacy (#20354)
The precision handling for division with DECIMALV3 is as follows (excluding cases where division increases precision):

(p1, s1) / (p2, s2) ----> (p1 + s2, s1)

However, due to precision loss in division, it is considered to increase the precision of the left operand:

(p1, s1) / (p2, s2) =====> (p1 + s2, s1 + s2) / (p2, s2) ----> (p1 + s2, s1)

However, the legacy optimizer repeats the analyze and substitute steps for an expression, which can result in the accumulation of precision:

(p1, s1) / (p2, s2) =====> (p1 + s2, s1 + s2) / (p2, s2) =====> (p1 + s2 + s2, s1 + s2 + s2) / (p2, s2)

To address this, the previous approach was to forcibly convert the left operand of DECIMALV3 calculations. This results in rewriting the expression as:

(p1, s1) / (p2, s2) =====> cast((p1, s1) as (p1 + s2, s1 + s2)) / (p2, s2)

Then, during the substitution step, a check is performed. If it is a cast expression, the expression modified by the cast is extracted:

cast((p1, s1) as (p1 + s2, s1 + s2)) =====> (p1, s1)

protected Expr substituteImpl(ExprSubstitutionMap smap, ExprSubstitutionMap disjunctsMap, Analyzer analyzer) {
        if (isImplicitCast()) {
            return getChild(0).substituteImpl(smap, disjunctsMap, analyzer);
        }
This way, there won't be repeated analysis, preventing the continuous increase in precision. However, if the left expression is a constant (literal), theoretically, the precision would continue to increase. Unfortunately, the code that was removed in this PR (#19926) obscured this issue.

for (Expr child : children) {
    if (child instanceof DecimalLiteral && child.getType().isDecimalV3()) {
      ((DecimalLiteral)child).tryToReduceType();
    }
}
An attempt will be made to reduce the precision of literals in the expressions. However, this code snippet can cause such a bug.

mysql [test]>select cast(1 as DECIMALV3(16, 2)) /  cast(3 as DECIMALV3(16, 2));
+-----------------------------------------------------------+
| CAST(1 AS DECIMALV3(16, 2)) / CAST(3 AS DECIMALV3(16, 2)) |
+-----------------------------------------------------------+
|                                                      0.00 |
+-----------------------------------------------------------+
1.00 / 3.00, due to reduced precision, becomes 1 / 3.
<--Describe your changes.-->
2023-06-09 08:58:55 +08:00
..