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


##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/ComputeSignatureHelper.java:
##########
@@ -566,52 +569,363 @@ private static FunctionSignature 
defaultTimePrecisionPromotion(FunctionSignature
     }
 
     private static FunctionSignature defaultDecimalV3PrecisionPromotion(
-            FunctionSignature signature, List<Expression> arguments) {
-        DecimalV3Type finalType = null;
+            FunctionSignature signature, List<Expression> arguments, 
ComputeSignature computeSignature) {
+        // The wider type across all decimal slots, used for decimal slots 
that are not
+        // inside a MAP (keeping the original behavior), for the placeholder 
return type,
+        // and for MAP-nested leaves whose group has no concrete type 
information.
+        DecimalV3Type widerType = null;
+
+        // Decimal leaves inside 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 full structural path 
through nested
+        // containers (e.g. "key", "value", "value/array", "value/key") and 
the resolved
+        // leaf type, so the leaves of different (or repeated) MAP arguments 
on the same
+        // path aggregate while leaves on different paths stay independent.
+        Map<String, DecimalV3Type> groupWider = Maps.newHashMap();
+
+        // The template signature carrying the original Any/Follow slots that 
the resolved
+        // signature was derived from. It lets us link a top-level scalar slot 
with the MAP
+        // leaf it belongs to by the original Any/Follow group identity (the 
index) instead
+        // of the resolved concrete type, which can collide when independent 
slots resolve
+        // to the same type (e.g. the key and the value of a MAP both becoming 
DECIMAL(10,3)).
+        FunctionSignature template = findDecimalV3Template(computeSignature, 
signature);
+
+        // The outermost MAP leaf group of each Any/Follow index (from the 
template), used
+        // to link a top-level scalar slot (e.g. map_contains_value's probe, 
element_at's
+        // lookup) with the MAP leaf that carries the same index.
+        Map<Integer, String> indexToMapLeafGroup = Maps.newHashMap();
+
+        // Fallback used when the template can not be recovered: the outermost 
MAP leaf
+        // group of each resolved type, used to link a top-level scalar slot 
with the MAP
+        // leaf it was resolved from (after Any/Follow resolution both carry 
the same type).
+        Map<DecimalV3Type, String> mapLeafGroupByType = Maps.newHashMap();
+
+        // Top-level scalar decimal leaves with a concrete resolved type, 
whose promoted
+        // type must also be folded into the linked MAP leaf group.
+        List<DecimalLeaf> scalarLeaves = Lists.newArrayList();
+
+        // Top-level scalar decimal slots are independent logical type 
variables
+        // (e.g. the key/value of map_agg(k, v) are Any(0) and Any(1)); group 
them by
+        // the resolved type so the slots of one logical group aggregate while 
the slots
+        // of different groups keep their own precision/scale.
+        Map<DecimalV3Type, DecimalV3Type> scalarGroupWider = Maps.newHashMap();
+
+        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();
+            DataType targetType = getSignatureArgumentType(signature, i);
+            DataType templateType = template == null ? null : 
getSignatureArgumentType(template, i);
+            collectDecimalLeaf(targetType, arguments.get(i).getDataType(), 
arguments.get(i),
+                    "", templateType, indexToMapLeafGroup, mapLeafGroupByType, 
groupWider,
+                    scalarGroupWider, scalarLeaves, widerHolder);
+        }
+        widerType = widerHolder[0];
+        if (widerType == null) {
+            return signature;
+        }
+
+        // Fold the promoted type of every top-level scalar slot into the MAP 
leaf group it
+        // is linked with (by the original Any/Follow identity when available, 
otherwise by
+        // the resolved type), so the MAP leaf and the scalar slot linked with 
it are
+        // promoted to one type.
+        for (DecimalLeaf scalarLeaf : scalarLeaves) {
+            String linkedGroup;
+            if (scalarLeaf.index >= 0) {
+                linkedGroup = indexToMapLeafGroup.get(scalarLeaf.index);
             } else {
-                targetType = signature.getArgType(i);
+                linkedGroup = mapLeafGroupByType.get(scalarLeaf.resolvedType);
             }
-            List<DataType> argTypes = 
extractArgumentTypeBySignature(DecimalV3Type.class, targetType,
-                    arguments.get(i).getDataType());
-            if (argTypes.isEmpty()) {
-                continue;
+            if (linkedGroup != null) {
+                groupWider.merge(linkedGroup, scalarLeaf.promotedType,
+                        ComputeSignatureHelper::mergeDecimalV3Type);
             }
+        }
 
-            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);
+        List<DataType> newArgTypes = 
Lists.newArrayListWithCapacity(signature.argumentsTypes.size());
+        for (int i = 0; i < signature.argumentsTypes.size(); i++) {
+            DataType templateType = template == null ? null : 
getSignatureArgumentType(template, i);
+            
newArgTypes.add(replaceDecimalV3Leaf(signature.argumentsTypes.get(i), "", 
templateType,
+                    indexToMapLeafGroup, mapLeafGroupByType, groupWider, 
scalarGroupWider, widerType));
+        }
+        signature = signature.withArgumentTypes(signature.hasVarArgs, 
newArgTypes);
+        if (signature.returnType instanceof DecimalV3Type
+                && ((DecimalV3Type) signature.returnType).getPrecision() <= 0) 
{
+            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 path} is the full structural path through 
nested
+     * containers (empty for a top-level slot, {@link #MAP_KEY}/{@link 
#MAP_VALUE} for
+     * the key/value of a MAP, {@link #ARRAY_ITEM} for an ARRAY item), so an 
ARRAY nested
+     * in a MAP value (e.g. "value/array") or the key/value of a nested MAP 
(e.g.
+     * "value/key") keep the enclosing group instead of being merged with the 
outer
+     * leaves. {@code templateType} is the corresponding slot of the template 
signature
+     * that still carries the original Any/Follow identity of this leaf. 
{@code widerHolder}
+     * accumulates the wider type across all decimal leaves.
+     */
+    private static void collectDecimalLeaf(DataType sigType, DataType argType, 
Expression arg,
+            String path, DataType templateType, Map<Integer, String> 
indexToMapLeafGroup,
+            Map<DecimalV3Type, String> mapLeafGroupByType,
+            Map<String, DecimalV3Type> groupWider, Map<DecimalV3Type, 
DecimalV3Type> scalarGroupWider,
+            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 (path.isEmpty()) {
+                // top-level scalar slot: a concrete resolved type may be 
linked with a
+                // MAP leaf below by the original Any/Follow identity, and 
otherwise the
+                // slots of the same resolved type form one logical group 
(e.g. the two
+                // arguments of map_agg) and stay independent from the slots 
of other groups
+                if (promoted != null && sigDecimal.getPrecision() > 0) {
+                    scalarLeaves.add(new DecimalLeaf(sigDecimal, promoted, 
anyFollowIndex(templateType)));
+                    scalarGroupWider.merge(sigDecimal, promoted,
+                            ComputeSignatureHelper::mergeDecimalV3Type);
                 }
-                if (finalType == null) {
-                    finalType = decimalV3Type;
+            } else if (isMapNested(path) && promoted != null) {
+                String groupKey = path + ":" + sigDecimal;
+                groupWider.merge(groupKey, promoted, 
ComputeSignatureHelper::mergeDecimalV3Type);
+                int index = anyFollowIndex(templateType);
+                if (index >= 0) {
+                    // keep the outermost group (shortest path) for linking by 
the index
+                    indexToMapLeafGroup.putIfAbsent(index, groupKey);
                 } else {
-                    finalType = (DecimalV3Type) 
DecimalV3Type.widerDecimalV3Type(finalType, decimalV3Type, false);
+                    // fallback: keep the outermost group (shortest path, key 
before value)
+                    // for linking by the resolved type
+                    mapLeafGroupByType.putIfAbsent(sigDecimal, groupKey);
+                }
+            }
+            // other leaves (e.g. ARRAY items not nested in a MAP) keep the 
original
+            // behavior of the single wider type
+            return;
+        } else if (sigType instanceof MapType) {
+            MapType mapType = (MapType) sigType;
+            DataType templateKey = templateType instanceof MapType
+                    ? ((MapType) templateType).getKeyType() : null;
+            DataType templateValue = templateType instanceof MapType
+                    ? ((MapType) templateType).getValueType() : null;
+            if (argType instanceof MapType) {
+                MapType argMapType = (MapType) argType;
+                collectDecimalLeaf(mapType.getKeyType(), 
argMapType.getKeyType(), arg,
+                        appendPath(path, MAP_KEY), templateKey, 
indexToMapLeafGroup, mapLeafGroupByType,
+                        groupWider, scalarGroupWider, scalarLeaves, 
widerHolder);
+                collectDecimalLeaf(mapType.getValueType(), 
argMapType.getValueType(), arg,
+                        appendPath(path, MAP_VALUE), templateValue, 
indexToMapLeafGroup, mapLeafGroupByType,
+                        groupWider, scalarGroupWider, scalarLeaves, 
widerHolder);
+            } else if (argType instanceof NullType) {
+                collectDecimalLeaf(mapType.getKeyType(), argType, arg,
+                        appendPath(path, MAP_KEY), templateKey, 
indexToMapLeafGroup, mapLeafGroupByType,
+                        groupWider, scalarGroupWider, scalarLeaves, 
widerHolder);
+                collectDecimalLeaf(mapType.getValueType(), argType, arg,
+                        appendPath(path, MAP_VALUE), templateValue, 
indexToMapLeafGroup, mapLeafGroupByType,
+                        groupWider, scalarGroupWider, 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;
+            }
+            // carry the enclosing MAP path through the ARRAY so items nested 
in a MAP
+            // value stay in the value group
+            DataType templateItem = templateType instanceof ArrayType
+                    ? ((ArrayType) templateType).getItemType() : null;
+            collectDecimalLeaf(((ArrayType) sigType).getItemType(), 
itemArgType, arg,
+                    appendPath(path, ARRAY_ITEM), templateItem, 
indexToMapLeafGroup, mapLeafGroupByType,
+                    groupWider, scalarGroupWider, scalarLeaves, widerHolder);
+        }
+        // StructType and other types are not supported
+    }
+
+    /**
+     * Replace every decimal leaf in {@code sigType}: leaves inside a MAP use 
the wider
+     * type of their own structural group, top-level scalar slots use the 
wider type of
+     * their own logical group (slots of the same resolved type), and all 
other leaves
+     * (e.g. ARRAY items not nested in a MAP) keep the original behavior of 
using the
+     * single wider type across all decimal slots.
+     */
+    private static DataType replaceDecimalV3Leaf(DataType sigType, String 
path, DataType templateType,
+            Map<Integer, String> indexToMapLeafGroup, Map<DecimalV3Type, 
String> mapLeafGroupByType,
+            Map<String, DecimalV3Type> groupWider, Map<DecimalV3Type, 
DecimalV3Type> scalarGroupWider,
+            DecimalV3Type widerType) {
+        if (sigType instanceof DecimalV3Type) {
+            DecimalV3Type sigDecimal = (DecimalV3Type) sigType;
+            if (path.isEmpty()) {
+                // a top-level scalar slot linked with a MAP leaf keeps the 
type of that
+                // leaf (e.g. map_contains_value's probe / element_at's lookup 
must match
+                // the MAP value/key type). The link is resolved by the 
original Any/Follow
+                // identity, falling back to the resolved type when the 
template can not be
+                // recovered.
+                if (sigDecimal.getPrecision() > 0) {
+                    String linkedGroup = null;
+                    int index = anyFollowIndex(templateType);
+                    if (index >= 0) {
+                        linkedGroup = indexToMapLeafGroup.get(index);
+                    } else {
+                        linkedGroup = mapLeafGroupByType.get(sigDecimal);
+                    }
+                    if (linkedGroup != null) {
+                        DecimalV3Type linkedWider = 
groupWider.get(linkedGroup);
+                        if (linkedWider != null) {
+                            return linkedWider;
+                        }
+                    }
+                    // independent logical Any groups (e.g. the key/value 
arguments of
+                    // map_agg) keep their own precision/scale instead of 
being merged
+                    // into one wider type
+                    DecimalV3Type scalarWider = 
scalarGroupWider.get(sigDecimal);

Review Comment:
   [P1] Keep ARRAY leaves linked to their scalar Any group
   
   For signatures such as `array_contains(ARRAY<Any(0)>, Any(0))`, the earlier 
Any-resolution step can widen both slots to the array element type, but this 
pass records the ARRAY leaf only in global `widerType` while recording the 
scalar's narrower actual type in `scalarGroupWider`. Returning that scalar 
value here therefore splits one logical group again. For example, existing 
`ARRAY<DECIMAL(27,9)>` plus `DECIMAL(9,3)` calls leave the array as Decimal128 
and regress only the probe to Decimal32; BE array dispatch requires equal 
primitive types and returns an unsupported-types error. The same shape affects 
`array_position`, `array_remove`, `array_pushback/front`, `countequal`, and 
`array_apply`. Please retain the original Any/Follow group identity for non-MAP 
ARRAY leaves and add a reverse-widening array/scalar regression.



##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/ComputeSignatureHelper.java:
##########
@@ -566,52 +569,363 @@ private static FunctionSignature 
defaultTimePrecisionPromotion(FunctionSignature
     }
 
     private static FunctionSignature defaultDecimalV3PrecisionPromotion(
-            FunctionSignature signature, List<Expression> arguments) {
-        DecimalV3Type finalType = null;
+            FunctionSignature signature, List<Expression> arguments, 
ComputeSignature computeSignature) {
+        // The wider type across all decimal slots, used for decimal slots 
that are not
+        // inside a MAP (keeping the original behavior), for the placeholder 
return type,
+        // and for MAP-nested leaves whose group has no concrete type 
information.
+        DecimalV3Type widerType = null;
+
+        // Decimal leaves inside 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 full structural path 
through nested
+        // containers (e.g. "key", "value", "value/array", "value/key") and 
the resolved
+        // leaf type, so the leaves of different (or repeated) MAP arguments 
on the same
+        // path aggregate while leaves on different paths stay independent.
+        Map<String, DecimalV3Type> groupWider = Maps.newHashMap();
+
+        // The template signature carrying the original Any/Follow slots that 
the resolved
+        // signature was derived from. It lets us link a top-level scalar slot 
with the MAP
+        // leaf it belongs to by the original Any/Follow group identity (the 
index) instead
+        // of the resolved concrete type, which can collide when independent 
slots resolve
+        // to the same type (e.g. the key and the value of a MAP both becoming 
DECIMAL(10,3)).
+        FunctionSignature template = findDecimalV3Template(computeSignature, 
signature);
+
+        // The outermost MAP leaf group of each Any/Follow index (from the 
template), used
+        // to link a top-level scalar slot (e.g. map_contains_value's probe, 
element_at's
+        // lookup) with the MAP leaf that carries the same index.
+        Map<Integer, String> indexToMapLeafGroup = Maps.newHashMap();
+
+        // Fallback used when the template can not be recovered: the outermost 
MAP leaf
+        // group of each resolved type, used to link a top-level scalar slot 
with the MAP
+        // leaf it was resolved from (after Any/Follow resolution both carry 
the same type).
+        Map<DecimalV3Type, String> mapLeafGroupByType = Maps.newHashMap();
+
+        // Top-level scalar decimal leaves with a concrete resolved type, 
whose promoted
+        // type must also be folded into the linked MAP leaf group.
+        List<DecimalLeaf> scalarLeaves = Lists.newArrayList();
+
+        // Top-level scalar decimal slots are independent logical type 
variables
+        // (e.g. the key/value of map_agg(k, v) are Any(0) and Any(1)); group 
them by
+        // the resolved type so the slots of one logical group aggregate while 
the slots
+        // of different groups keep their own precision/scale.
+        Map<DecimalV3Type, DecimalV3Type> scalarGroupWider = Maps.newHashMap();
+
+        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();
+            DataType targetType = getSignatureArgumentType(signature, i);
+            DataType templateType = template == null ? null : 
getSignatureArgumentType(template, i);
+            collectDecimalLeaf(targetType, arguments.get(i).getDataType(), 
arguments.get(i),
+                    "", templateType, indexToMapLeafGroup, mapLeafGroupByType, 
groupWider,
+                    scalarGroupWider, scalarLeaves, widerHolder);
+        }
+        widerType = widerHolder[0];
+        if (widerType == null) {
+            return signature;
+        }
+
+        // Fold the promoted type of every top-level scalar slot into the MAP 
leaf group it
+        // is linked with (by the original Any/Follow identity when available, 
otherwise by
+        // the resolved type), so the MAP leaf and the scalar slot linked with 
it are
+        // promoted to one type.
+        for (DecimalLeaf scalarLeaf : scalarLeaves) {
+            String linkedGroup;
+            if (scalarLeaf.index >= 0) {
+                linkedGroup = indexToMapLeafGroup.get(scalarLeaf.index);
             } else {
-                targetType = signature.getArgType(i);
+                linkedGroup = mapLeafGroupByType.get(scalarLeaf.resolvedType);
             }
-            List<DataType> argTypes = 
extractArgumentTypeBySignature(DecimalV3Type.class, targetType,
-                    arguments.get(i).getDataType());
-            if (argTypes.isEmpty()) {
-                continue;
+            if (linkedGroup != null) {
+                groupWider.merge(linkedGroup, scalarLeaf.promotedType,
+                        ComputeSignatureHelper::mergeDecimalV3Type);
             }
+        }
 
-            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);
+        List<DataType> newArgTypes = 
Lists.newArrayListWithCapacity(signature.argumentsTypes.size());
+        for (int i = 0; i < signature.argumentsTypes.size(); i++) {
+            DataType templateType = template == null ? null : 
getSignatureArgumentType(template, i);
+            
newArgTypes.add(replaceDecimalV3Leaf(signature.argumentsTypes.get(i), "", 
templateType,
+                    indexToMapLeafGroup, mapLeafGroupByType, groupWider, 
scalarGroupWider, widerType));
+        }
+        signature = signature.withArgumentTypes(signature.hasVarArgs, 
newArgTypes);
+        if (signature.returnType instanceof DecimalV3Type
+                && ((DecimalV3Type) signature.returnType).getPrecision() <= 0) 
{
+            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 path} is the full structural path through 
nested
+     * containers (empty for a top-level slot, {@link #MAP_KEY}/{@link 
#MAP_VALUE} for
+     * the key/value of a MAP, {@link #ARRAY_ITEM} for an ARRAY item), so an 
ARRAY nested
+     * in a MAP value (e.g. "value/array") or the key/value of a nested MAP 
(e.g.
+     * "value/key") keep the enclosing group instead of being merged with the 
outer
+     * leaves. {@code templateType} is the corresponding slot of the template 
signature
+     * that still carries the original Any/Follow identity of this leaf. 
{@code widerHolder}
+     * accumulates the wider type across all decimal leaves.
+     */
+    private static void collectDecimalLeaf(DataType sigType, DataType argType, 
Expression arg,
+            String path, DataType templateType, Map<Integer, String> 
indexToMapLeafGroup,
+            Map<DecimalV3Type, String> mapLeafGroupByType,
+            Map<String, DecimalV3Type> groupWider, Map<DecimalV3Type, 
DecimalV3Type> scalarGroupWider,
+            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 (path.isEmpty()) {
+                // top-level scalar slot: a concrete resolved type may be 
linked with a
+                // MAP leaf below by the original Any/Follow identity, and 
otherwise the
+                // slots of the same resolved type form one logical group 
(e.g. the two
+                // arguments of map_agg) and stay independent from the slots 
of other groups
+                if (promoted != null && sigDecimal.getPrecision() > 0) {
+                    scalarLeaves.add(new DecimalLeaf(sigDecimal, promoted, 
anyFollowIndex(templateType)));
+                    scalarGroupWider.merge(sigDecimal, promoted,
+                            ComputeSignatureHelper::mergeDecimalV3Type);
                 }
-                if (finalType == null) {
-                    finalType = decimalV3Type;
+            } else if (isMapNested(path) && promoted != null) {
+                String groupKey = path + ":" + sigDecimal;
+                groupWider.merge(groupKey, promoted, 
ComputeSignatureHelper::mergeDecimalV3Type);
+                int index = anyFollowIndex(templateType);
+                if (index >= 0) {
+                    // keep the outermost group (shortest path) for linking by 
the index
+                    indexToMapLeafGroup.putIfAbsent(index, groupKey);
                 } else {
-                    finalType = (DecimalV3Type) 
DecimalV3Type.widerDecimalV3Type(finalType, decimalV3Type, false);
+                    // fallback: keep the outermost group (shortest path, key 
before value)
+                    // for linking by the resolved type
+                    mapLeafGroupByType.putIfAbsent(sigDecimal, groupKey);
+                }
+            }
+            // other leaves (e.g. ARRAY items not nested in a MAP) keep the 
original
+            // behavior of the single wider type
+            return;
+        } else if (sigType instanceof MapType) {
+            MapType mapType = (MapType) sigType;
+            DataType templateKey = templateType instanceof MapType

Review Comment:
   [P1] Preserve Any identity when it resolves to a MAP container
   
   An `AnyDataType` can own a whole complex value, not just a Decimal leaf. For 
`array_pushfront/back(ARRAY<Any(0)>, Any(0))` with ARRAY-of-MAP and MAP inputs, 
both occurrences first resolve to the same wider MAP. Here their template nodes 
are still `Any(0)`, so both key/value templates become null and the descendants 
are keyed by different absolute paths (`array/key` versus `key`). The pass 
consequently regresses the two slots to incompatible MAP types. BE builds the 
result from argument 0 and inserts argument 1; crossing Decimal widths reaches 
`Field::get`'s fatal type mismatch, and differing scales within one width 
insert the wrong raw value. Please propagate the container Any/Follow group 
into descendant-relative keys and cover ARRAY-of-MAP plus MAP column inputs.



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