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

hello-stephen 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 7a84ab67c23 [fix](fe) Preserve inferred JSON column name casing 
(#67411)
7a84ab67c23 is described below

commit 7a84ab67c23d714bc6280f42011e0e0d8b1c226c
Author: Refrain <[email protected]>
AuthorDate: Wed Oct 21 17:06:02 2026 +0800

    [fix](fe) Preserve inferred JSON column name casing (#67411)
    
    Problem Summary: JSON schema inference lowercased field names before
    creating the table-valued function schema, while JSON readers match
    object keys case-sensitively. Uppercase keys therefore appeared as
    queryable lowercase columns but were silently materialized as NULL.
    Preserve the inferred key casing for JSON only, while retaining
    case-insensitive duplicate detection and the existing lowercase behavior
    for other file formats.
    
    ### Release note
    
    JSON table-valued functions now read inferred mixed-case and uppercase
    keys without silently producing NULL values.
---
 .../ExternalFileTableValuedFunction.java           | 11 +++--
 .../tvf/test_json_uppercase_keys.out               |  9 ++++
 .../tvf/test_json_uppercase_keys/case_keys.jsonl   |  2 +
 .../tvf/test_json_uppercase_keys.groovy            | 49 ++++++++++++++++++++++
 4 files changed, 67 insertions(+), 4 deletions(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/tablefunction/ExternalFileTableValuedFunction.java
 
b/fe/fe-core/src/main/java/org/apache/doris/tablefunction/ExternalFileTableValuedFunction.java
index 2f4495ab643..3f15a190ccd 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/tablefunction/ExternalFileTableValuedFunction.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/tablefunction/ExternalFileTableValuedFunction.java
@@ -477,15 +477,18 @@ public abstract class ExternalFileTableValuedFunction 
extends TableValuedFunctio
         }
         // add fetched file columns
         Set<String> columnLowerNames = new HashSet<>();
+        boolean preserveColumnCase = fileFormatProperties.getFileFormatType() 
== TFileFormatType.FORMAT_JSON;
         for (int idx = 0; idx < result.getColumnNums(); ++idx) {
             PTypeDesc type = result.getColumnTypes(idx);
-            String colName = result.getColumnNames(idx).toLowerCase();
+            String originalColName = result.getColumnNames(idx);
+            String colLowerName = originalColName.toLowerCase();
             // Since doris does not distinguish between upper and lower case 
columns when querying, in order to avoid
             // query ambiguity, two columns with the same name but different 
capitalization are not allowed.
-            if (columnLowerNames.contains(colName)) {
-                throw new NotSupportedException("Repeated lowercase column 
names: " + colName);
+            if (columnLowerNames.contains(colLowerName)) {
+                throw new NotSupportedException("Repeated lowercase column 
names: " + colLowerName);
             } else {
-                columnLowerNames.add(colName);
+                columnLowerNames.add(colLowerName);
+                String colName = preserveColumnCase ? originalColName : 
colLowerName;
                 columns.add(new Column(colName, 
getColumnType(type.getTypesList(), 0).key(), true));
             }
         }
diff --git 
a/regression-test/data/external_table_p0/tvf/test_json_uppercase_keys.out 
b/regression-test/data/external_table_p0/tvf/test_json_uppercase_keys.out
new file mode 100644
index 00000000000..1dba9bb2590
--- /dev/null
+++ b/regression-test/data/external_table_p0/tvf/test_json_uppercase_keys.out
@@ -0,0 +1,9 @@
+-- This file is automatically generated. You should know what you did if you 
want to edit this
+-- !json_uppercase_keys --
+1      Beijing 12.5
+2      Shanghai        7.75
+
+-- !json_uppercase_keys_with_jsonpaths --
+1      Beijing 12.5
+2      Shanghai        7.75
+
diff --git 
a/regression-test/data/external_table_p0/tvf/test_json_uppercase_keys/case_keys.jsonl
 
b/regression-test/data/external_table_p0/tvf/test_json_uppercase_keys/case_keys.jsonl
new file mode 100644
index 00000000000..8b1e11f4b33
--- /dev/null
+++ 
b/regression-test/data/external_table_p0/tvf/test_json_uppercase_keys/case_keys.jsonl
@@ -0,0 +1,2 @@
+{"ID":1,"City":"Beijing","Metric":12.5}
+{"ID":2,"City":"Shanghai","Metric":7.75}
diff --git 
a/regression-test/suites/external_table_p0/tvf/test_json_uppercase_keys.groovy 
b/regression-test/suites/external_table_p0/tvf/test_json_uppercase_keys.groovy
new file mode 100644
index 00000000000..9953855e883
--- /dev/null
+++ 
b/regression-test/suites/external_table_p0/tvf/test_json_uppercase_keys.groovy
@@ -0,0 +1,49 @@
+// 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_json_uppercase_keys", "p0,external") {
+    String ak = getS3AK()
+    String sk = getS3SK()
+    String s3Endpoint = getS3Endpoint()
+    String bucket = context.config.otherConfigs.get("s3BucketName")
+    String uri = 
"https://${bucket}.${s3Endpoint}/regression/tvf/test_json_uppercase_keys/case_keys.jsonl";
+
+    order_qt_json_uppercase_keys """
+        select id, city, metric from
+        s3(
+            "URI" = "${uri}",
+            "s3.access_key" = "${ak}",
+            "s3.secret_key" = "${sk}",
+            "FORMAT" = "json",
+            "read_json_by_line" = "true",
+            "fuzzy_parse" = "true",
+            "use_path_style" = "false") order by id;
+    """
+
+    order_qt_json_uppercase_keys_with_jsonpaths """
+        select id, city, metric from
+        s3(
+            "URI" = "${uri}",
+            "s3.access_key" = "${ak}",
+            "s3.secret_key" = "${sk}",
+            "FORMAT" = "json",
+            "read_json_by_line" = "true",
+            "fuzzy_parse" = "true",
+            "jsonpaths" = '["\$.ID", "\$.City", "\$.Metric"]',
+            "use_path_style" = "false") order by id;
+    """
+}


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

Reply via email to