This is an automated email from the ASF dual-hosted git repository.
morrySnow 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 a8216b532fe [fix](fe) Fix Type.exceedsMaxNestingDepth skipping MAP
keyType recursion (#63201)
a8216b532fe is described below
commit a8216b532febf3f0635b036a1b2ac6e562eede02
Author: morrySnow <[email protected]>
AuthorDate: Wed May 13 16:38:42 2026 +0800
[fix](fe) Fix Type.exceedsMaxNestingDepth skipping MAP keyType recursion
(#63201)
## Summary
`Type.exceedsMaxNestingDepth` in the MAP branch only recursed into
`valueType` and silently skipped `keyType`. A user could construct
arbitrarily deep types via the MAP key path, bypassing the 9-layer
nesting limit.
### What problem does this PR solve?
Problem Summary:
```java
// Before fix — MAP branch:
} else if (isMapType()) {
MapType mapType = (MapType) this;
return mapType.getValueType().exceedsMaxNestingDepth(d + 1); //
keyType never checked
}
```
ARRAY and STRUCT branches recursed correctly; only MAP missed the
keyType path.
### Fix
```java
} else if (isMapType()) {
MapType mapType = (MapType) this;
if (mapType.getKeyType().exceedsMaxNestingDepth(d + 1)) {
return true;
}
return mapType.getValueType().exceedsMaxNestingDepth(d + 1);
}
```
### Tests
Three new FE unit tests added to `TypeTest`:
- `testMapKeyPathNestingWithinLimit` — `MAX_NESTING_DEPTH` levels via
keyType → allowed (assertFalse)
- `testMapKeyPathDeepNestingDetected` — `MAX_NESTING_DEPTH + 1` levels
via keyType → rejected (assertTrue)
- `testMapValuePathDeepNestingDetected` — regression guard: valueType
path still detected (assertTrue)
All 11 tests in `TypeTest` pass.
### Release note
Fix MAP key-type nesting-depth check bypass: deeply-nested MAP key types
are now correctly rejected with "Type exceeds the maximum nesting
depth".
Co-authored-by: Copilot <[email protected]>
---
.../java/org/apache/doris/catalog/TypeTest.java | 40 ++++++++++++++++++++++
.../main/java/org/apache/doris/catalog/Type.java | 3 ++
2 files changed, 43 insertions(+)
diff --git a/fe/fe-core/src/test/java/org/apache/doris/catalog/TypeTest.java
b/fe/fe-core/src/test/java/org/apache/doris/catalog/TypeTest.java
index 29353ae6c50..cb544d3d01c 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/catalog/TypeTest.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/catalog/TypeTest.java
@@ -185,6 +185,46 @@ public class TypeTest {
Assert.assertFalse(Type.matchExactType(d20s1, d38s1, false));
}
+ // ===================== exceedsMaxNestingDepth =====================
+
+ /**
+ * Builds a MAP<MAP<...<MAP<STRING, STRING>>...>, STRING> with the given
number of outer MAP wrappers.
+ * This tests the keyType recursion path of exceedsMaxNestingDepth().
+ */
+ private static Type buildMapKeyNestedType(int depth) {
+ // innermost: MAP<STRING, STRING> counts as depth 1 (from the caller's
perspective we start at d=0)
+ Type current = new MapType(Type.STRING, Type.STRING, true, true);
+ for (int i = 1; i < depth; i++) {
+ current = new MapType(current, Type.STRING, true, true);
+ }
+ return current;
+ }
+
+ @Test
+ public void testMapKeyPathNestingWithinLimit() {
+ // MAP < MAP < ... STRING ...>, STRING > with total nesting ==
MAX_NESTING_DEPTH should be allowed
+ Type t = buildMapKeyNestedType(Type.MAX_NESTING_DEPTH);
+ Assert.assertFalse(t.exceedsMaxNestingDepth());
+ }
+
+ @Test
+ public void testMapKeyPathDeepNestingDetected() {
+ // Nesting depth of MAX_NESTING_DEPTH + 1 via keyType path must be
rejected
+ Type t = buildMapKeyNestedType(Type.MAX_NESTING_DEPTH + 1);
+ Assert.assertTrue(t.exceedsMaxNestingDepth());
+ }
+
+ @Test
+ public void testMapValuePathDeepNestingDetected() {
+ // Existing valueType path should still be detected (regression guard).
+ // Need MAX_NESTING_DEPTH + 1 wraps so the innermost reaches d =
MAX_NESTING_DEPTH + 1.
+ Type current = Type.STRING;
+ for (int i = 0; i <= Type.MAX_NESTING_DEPTH; i++) {
+ current = new MapType(Type.STRING, current, true, true);
+ }
+ Assert.assertTrue(current.exceedsMaxNestingDepth());
+ }
+
@Test
public void testDatetimeV2ScaleMatching() {
ScalarType dtv2s3 = ScalarType.createDatetimeV2Type(3);
diff --git a/fe/fe-type/src/main/java/org/apache/doris/catalog/Type.java
b/fe/fe-type/src/main/java/org/apache/doris/catalog/Type.java
index 6af6a174766..8a544cade38 100644
--- a/fe/fe-type/src/main/java/org/apache/doris/catalog/Type.java
+++ b/fe/fe-type/src/main/java/org/apache/doris/catalog/Type.java
@@ -797,6 +797,9 @@ public abstract class Type {
return itemType.exceedsMaxNestingDepth(d + 1);
} else if (isMapType()) {
MapType mapType = (MapType) this;
+ if (mapType.getKeyType().exceedsMaxNestingDepth(d + 1)) {
+ return true;
+ }
return mapType.getValueType().exceedsMaxNestingDepth(d + 1);
} else {
Preconditions.checkState(isScalarType() || isAggStateType());
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]