github-actions[bot] commented on code in PR #67154:
URL: https://github.com/apache/doris/pull/67154#discussion_r3863354589


##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/ComputeSignatureHelper.java:
##########
@@ -567,53 +569,211 @@ private static FunctionSignature 
defaultTimePrecisionPromotion(FunctionSignature
 
     private static FunctionSignature defaultDecimalV3PrecisionPromotion(
             FunctionSignature signature, List<Expression> arguments) {
-        DecimalV3Type finalType = null;
+        // The wider type across all decimal slots, used for decimal slots 
that are not
+        // the key/value of a MAP (keeping the original behavior), for the 
placeholder
+        // return type, and for MAP leaves whose group has no concrete type 
information.
+        DecimalV3Type widerType = null;
+
+        // The KEY leaves and the VALUE leaves of a MAP are independent type 
variables:
+        // they must keep their own precision/scale instead of being merged 
into one wider
+        // type, otherwise widening one leaf (e.g. the scale of a big integral 
key) may
+        // overflow the other leaf. They are grouped by the resolved leaf 
type, so the
+        // corresponding leaves of different (or repeated) MAP arguments 
aggregate while
+        // the key leaves and the value leaves stay independent.
+        Map<DecimalV3Type, DecimalV3Type> mapKeyWider = Maps.newHashMap();
+        Map<DecimalV3Type, DecimalV3Type> mapValueWider = Maps.newHashMap();
+
+        // Top-level scalar decimal leaves with a concrete resolved type. After
+        // Any/Follow resolution such a slot carries the same concrete type as 
the MAP
+        // key/value leaf it was resolved from (e.g. the lookup argument of 
element_at
+        // follows the MAP key type). It must be promoted together with that 
MAP leaf,
+        // otherwise the BE compares columns of different concrete decimal 
classes.
+        List<DecimalLeaf> scalarLeaves = Lists.newArrayList();
+
+        DecimalV3Type[] widerHolder = new DecimalV3Type[1];
         for (int i = 0; i < arguments.size(); i++) {
-            DataType targetType;
-            if (i >= signature.argumentsTypes.size()) {
-                Preconditions.checkState(signature.getVarArgType().isPresent(),
-                        "argument size larger than signature");
-                targetType = signature.getVarArgType().get();
-            } else {
-                targetType = signature.getArgType(i);
-            }
-            List<DataType> argTypes = 
extractArgumentTypeBySignature(DecimalV3Type.class, targetType,
-                    arguments.get(i).getDataType());
-            if (argTypes.isEmpty()) {
-                continue;
-            }
+            DataType targetType = getSignatureArgumentType(signature, i);
+            collectDecimalLeaf(targetType, arguments.get(i).getDataType(), 
arguments.get(i),
+                    null, true, mapKeyWider, mapValueWider, scalarLeaves, 
widerHolder);
+        }
+        widerType = widerHolder[0];
+        if (widerType == null) {
+            return signature;
+        }
 
-            for (DataType argType : argTypes) {
-                Expression arg = arguments.get(i);
-                DecimalV3Type decimalV3Type;
-                if (arg.isLiteral() && arg.getDataType().isIntegralType()) {
-                    // create decimalV3 with minimum scale enough to hold the 
integral literal
-                    decimalV3Type = DecimalV3Type.createDecimalV3Type(new 
BigDecimal(((Literal) arg).getStringValue()));
-                } else {
-                    decimalV3Type = DecimalV3Type.forType(argType);
-                }
-                if (finalType == null) {
-                    finalType = decimalV3Type;
-                } else {
-                    finalType = (DecimalV3Type) 
DecimalV3Type.widerDecimalV3Type(finalType, decimalV3Type, false);
+        // Fold the promoted type of every top-level scalar slot into the MAP 
leaf group
+        // of the same resolved type (if any), so the MAP key/value and the 
scalar slot
+        // linked with it are promoted to one type.
+        for (DecimalLeaf scalarLeaf : scalarLeaves) {
+            DecimalV3Type linkedWider = 
mapKeyWider.get(scalarLeaf.resolvedType);
+            if (linkedWider == null) {
+                linkedWider = mapValueWider.get(scalarLeaf.resolvedType);
+                if (linkedWider != null) {
+                    mapValueWider.put(scalarLeaf.resolvedType,
+                            mergeDecimalV3Type(linkedWider, 
scalarLeaf.promotedType));
                 }
+            } else {
+                mapKeyWider.put(scalarLeaf.resolvedType,
+                        mergeDecimalV3Type(linkedWider, 
scalarLeaf.promotedType));
             }
         }
-        DecimalV3Type argType = finalType;
-        if (finalType == null) {
-            return signature;
+
+        List<DataType> newArgTypes = 
Lists.newArrayListWithCapacity(signature.argumentsTypes.size());
+        for (int i = 0; i < signature.argumentsTypes.size(); i++) {
+            
newArgTypes.add(replaceDecimalV3Leaf(signature.argumentsTypes.get(i), null, 
true,
+                    mapKeyWider, mapValueWider, widerType));
         }
-        List<DataType> newArgTypes = signature.argumentsTypes.stream()
-                .map(at -> TypeCoercionUtils.replaceDecimalV3WithTarget(at, 
argType))
-                .collect(Collectors.toList());
         signature = signature.withArgumentTypes(signature.hasVarArgs, 
newArgTypes);
         if (signature.returnType instanceof DecimalV3Type
                 && ((DecimalV3Type) signature.returnType).getPrecision() <= 0) 
{
-            signature = signature.withReturnType(argType);
+            signature = signature.withReturnType(widerType);
         }
         return signature;
     }
 
+    private static DataType getSignatureArgumentType(FunctionSignature 
signature, int index) {
+        if (index >= signature.argumentsTypes.size()) {
+            Preconditions.checkState(signature.getVarArgType().isPresent(),
+                    "argument size larger than signature");
+            return signature.getVarArgType().get();
+        }
+        return signature.getArgType(index);
+    }
+
+    /**
+     * Compute the promoted DecimalV3Type for one decimal slot from its 
argument type.
+     */
+    private static DecimalV3Type promotedDecimalV3Type(Expression arg, 
DataType argType) {
+        if (arg.isLiteral() && arg.getDataType().isIntegralType()) {
+            // create decimalV3 with minimum scale enough to hold the integral 
literal
+            return DecimalV3Type.createDecimalV3Type(new BigDecimal(((Literal) 
arg).getStringValue()));
+        }
+        return DecimalV3Type.forType(argType);
+    }
+
+    /**
+     * Collect every decimal leaf of one argument and fold its promoted type 
into the
+     * corresponding group. {@code mapSide} is {@link #MAP_KEY} or {@link 
#MAP_VALUE}
+     * when the leaf is directly the key/value of a MAP (possibly nested in a 
MAP),
+     * otherwise {@code null}. {@code linkable} indicates the leaf is a 
top-level scalar
+     * slot (not nested in any MAP or ARRAY), which may be linked to a MAP 
key/value leaf
+     * of the same resolved type. {@code widerHolder} accumulates the wider 
type across
+     * all decimal leaves.
+     */
+    private static void collectDecimalLeaf(DataType sigType, DataType argType, 
Expression arg,
+            String mapSide, boolean linkable, Map<DecimalV3Type, 
DecimalV3Type> mapKeyWider,
+            Map<DecimalV3Type, DecimalV3Type> mapValueWider, List<DecimalLeaf> 
scalarLeaves,
+            DecimalV3Type[] widerHolder) {
+        if (sigType instanceof DecimalV3Type) {
+            DecimalV3Type sigDecimal = (DecimalV3Type) sigType;
+            DecimalV3Type promoted = null;
+            if (!(argType instanceof NullType)) {
+                promoted = promotedDecimalV3Type(arg, argType);
+                widerHolder[0] = mergeDecimalV3Type(widerHolder[0], promoted);
+            }
+            if (mapSide == null) {
+                if (linkable && promoted != null && sigDecimal.getPrecision() 
> 0) {
+                    // top-level scalar slot with a concrete resolved type may 
be linked
+                    // with a MAP key/value leaf of the same type below
+                    scalarLeaves.add(new DecimalLeaf(sigDecimal, promoted));
+                }
+            } else if (promoted != null) {
+                if (mapSide == MAP_KEY) {
+                    mapKeyWider.merge(sigDecimal, promoted, 
ComputeSignatureHelper::mergeDecimalV3Type);
+                } else {
+                    mapValueWider.merge(sigDecimal, promoted, 
ComputeSignatureHelper::mergeDecimalV3Type);
+                }
+            }
+            return;
+        } else if (sigType instanceof MapType) {
+            MapType mapType = (MapType) sigType;
+            if (argType instanceof MapType) {
+                MapType argMapType = (MapType) argType;
+                collectDecimalLeaf(mapType.getKeyType(), 
argMapType.getKeyType(), arg,
+                        MAP_KEY, false, mapKeyWider, mapValueWider, 
scalarLeaves, widerHolder);
+                collectDecimalLeaf(mapType.getValueType(), 
argMapType.getValueType(), arg,
+                        MAP_VALUE, false, mapKeyWider, mapValueWider, 
scalarLeaves, widerHolder);
+            } else if (argType instanceof NullType) {
+                collectDecimalLeaf(mapType.getKeyType(), argType, arg,
+                        MAP_KEY, false, mapKeyWider, mapValueWider, 
scalarLeaves, widerHolder);
+                collectDecimalLeaf(mapType.getValueType(), argType, arg,
+                        MAP_VALUE, false, mapKeyWider, mapValueWider, 
scalarLeaves, widerHolder);
+            }
+            return;
+        } else if (sigType instanceof ArrayType) {
+            DataType itemArgType;
+            if (argType instanceof ArrayType) {
+                itemArgType = ((ArrayType) argType).getItemType();
+            } else if (argType instanceof NullType) {
+                itemArgType = argType;
+            } else {
+                return;
+            }
+            // ARRAY items are not MAP key/value leaves, keep the original 
behavior

Review Comment:
   [P1] Preserve the enclosing MAP path through nested containers
   
   For a nonconstant `m MAP<DECIMAL(38,0), ARRAY<DECIMAL(38,18)>>`, this 
recursion drops the incoming `MAP_VALUE`. The array leaf is therefore merged 
globally with the key and becomes `DECIMAL(38,6)` under the default overflow 
scale, so `expectedInputTypes()` inserts a lossy cast and discards low-order 
fractional digits before `map_values(m)` executes. Nested MAP recursion 
similarly overwrites the outer branch and can apply an outer-key lookup 
promotion to an unrelated inner key. Please carry the full structural/logical 
group path through ARRAY/MAP recursion and cover a nonconstant nested-container 
case. This is distinct from the existing direct key/value and scalar-link 
threads.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


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

Reply via email to