This is an automated email from the ASF dual-hosted git repository.
sollhui 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 31e3606b265 [fix](load) Fix Arrow stream load with uppercase columns
(#65127)
31e3606b265 is described below
commit 31e3606b2655f2f42d864b3e3263350cbfac8deb
Author: hui lai <[email protected]>
AuthorDate: Mon Jul 13 10:16:50 2026 +0800
[fix](load) Fix Arrow stream load with uppercase columns (#65127)
### What problem does this PR solve?
Issue Number: None
Related PR: None
Problem Summary: Arrow Stream Load through the Nereids load planner
lowercased source column names even though Arrow schema field names are
case-sensitive. For tables with uppercase target columns, the Arrow
scan-slot path could resolve the source name through a case-sensitive
type map and fail planning with a null type or construct a scan slot
whose name no longer matched the Arrow field. This change preserves
source column names for Arrow load format, including non-lowercase Arrow
format spellings, and resolves Arrow scan slot types through the target
table's case-insensitive column lookup.
---
.../org/apache/doris/analysis/DataDescription.java | 14 +-
.../java/org/apache/doris/common/util/Util.java | 10 ++
.../doris/nereids/load/NereidsDataDescription.java | 19 +-
.../nereids/load/NereidsLoadScanProvider.java | 13 +-
.../doris/nereids/load/NereidsLoadUtils.java | 10 ++
.../nereids/load/NereidsLoadingTaskPlanner.java | 18 +-
.../nereids/load/NereidsStreamLoadPlanner.java | 26 ++-
.../nereids/load/NereidsLoadScanProviderTest.java | 192 +++++++++++++++++++++
.../stream_load/arrow_uppercase_column.arrow | Bin 0 -> 456 bytes
.../test_arrow_stream_load_uppercase_column.out | 8 +
.../test_arrow_stream_load_uppercase_column.groovy | 89 ++++++++++
11 files changed, 358 insertions(+), 41 deletions(-)
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/analysis/DataDescription.java
b/fe/fe-core/src/main/java/org/apache/doris/analysis/DataDescription.java
index be306098077..b59288d4442 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/analysis/DataDescription.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/DataDescription.java
@@ -29,6 +29,7 @@ import org.apache.doris.common.ErrorCode;
import org.apache.doris.common.ErrorReport;
import org.apache.doris.common.Pair;
import org.apache.doris.common.UserException;
+import org.apache.doris.common.util.Util;
import org.apache.doris.datasource.property.fileformat.CsvFileFormatProperties;
import org.apache.doris.datasource.property.fileformat.FileFormatProperties;
import
org.apache.doris.datasource.property.fileformat.JsonFileFormatProperties;
@@ -231,7 +232,7 @@ public class DataDescription {
putAnalysisMapIfNonNull(FileFormatProperties.PROP_FORMAT, fileFormat);
putAnalysisMapIfNonNull(FileFormatProperties.PROP_COMPRESS_TYPE,
compressType);
- columnsNameToLowerCase(fileFieldNames);
+ fileFieldNamesToLowerCase(fileFieldNames);
columnsNameToLowerCase(columnsFromPath);
this.isHadoopLoad = isHadoopLoad;
@@ -297,7 +298,7 @@ public class DataDescription {
putAnalysisMapIfNonNull(FileFormatProperties.PROP_FORMAT, fileFormat);
putAnalysisMapIfNonNull(FileFormatProperties.PROP_COMPRESS_TYPE,
compressType);
- columnsNameToLowerCase(fileFieldNames);
+ fileFieldNamesToLowerCase(fileFieldNames);
columnsNameToLowerCase(columnsFromPath);
}
@@ -652,9 +653,16 @@ public class DataDescription {
}
}
+ private void fileFieldNamesToLowerCase(List<String> columns) {
+ if
(Util.isCasePreservingFormat(analysisMap.get(FileFormatProperties.PROP_FORMAT)))
{
+ return;
+ }
+ columnsNameToLowerCase(columns);
+ }
+
// Change all the columns name to lower case, because Doris column is
case-insensitive.
private void columnsNameToLowerCase(List<String> columns) {
- if (columns == null || columns.isEmpty() ||
"json".equals(analysisMap.get(FileFormatProperties.PROP_FORMAT))) {
+ if (columns == null || columns.isEmpty()) {
return;
}
for (int i = 0; i < columns.size(); i++) {
diff --git a/fe/fe-core/src/main/java/org/apache/doris/common/util/Util.java
b/fe/fe-core/src/main/java/org/apache/doris/common/util/Util.java
index 25c0d81295b..0a4e8f967e3 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/common/util/Util.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/common/util/Util.java
@@ -505,6 +505,16 @@ public class Util {
|| fileFormatType == TFileFormatType.FORMAT_CSV_PLAIN;
}
+ public static boolean isCasePreservingFormat(String formatName) {
+ return !Strings.isNullOrEmpty(formatName)
+ &&
isCasePreservingFormat(getFileFormatTypeFromName(formatName));
+ }
+
+ public static boolean isCasePreservingFormat(TFileFormatType
fileFormatType) {
+ return fileFormatType == TFileFormatType.FORMAT_JSON
+ || fileFormatType == TFileFormatType.FORMAT_ARROW;
+ }
+
public static void logAndThrowRuntimeException(Logger logger, String msg,
Throwable e) {
logger.warn(msg, e);
throw new RuntimeException(msg, e);
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/load/NereidsDataDescription.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/load/NereidsDataDescription.java
index 8e7b45f48c2..7c0c4b2fd97 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/load/NereidsDataDescription.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/load/NereidsDataDescription.java
@@ -241,7 +241,7 @@ public class NereidsDataDescription {
}
putAnalysisMapIfNonNull(FileFormatProperties.PROP_FORMAT, fileFormat);
putAnalysisMapIfNonNull(FileFormatProperties.PROP_COMPRESS_TYPE,
compressType);
- columnsNameToLowerCase(fileFieldNames);
+ fileFieldNamesToLowerCase(fileFieldNames);
columnsNameToLowerCase(columnsFromPath);
}
@@ -294,7 +294,7 @@ public class NereidsDataDescription {
}
putAnalysisMapIfNonNull(FileFormatProperties.PROP_FORMAT, fileFormat);
putAnalysisMapIfNonNull(FileFormatProperties.PROP_COMPRESS_TYPE,
compressType);
- columnsNameToLowerCase(fileFieldNames);
+ fileFieldNamesToLowerCase(fileFieldNames);
columnsNameToLowerCase(columnsFromPath);
}
@@ -375,7 +375,7 @@ public class NereidsDataDescription {
}
putAnalysisMapIfNonNull(CsvFileFormatProperties.PROP_SKIP_LINES,
String.valueOf(skipLines));
this.isMysqlLoad = true;
- columnsNameToLowerCase(fileFieldNames);
+ fileFieldNamesToLowerCase(fileFieldNames);
}
/**
@@ -437,7 +437,7 @@ public class NereidsDataDescription {
String.valueOf(taskInfo.isReadJsonByLine()));
putAnalysisMapIfNonNull(JsonFileFormatProperties.PROP_NUM_AS_STRING,
String.valueOf(taskInfo.isNumAsString()));
this.uniquekeyUpdateMode = taskInfo.getUniqueKeyUpdateMode();
- columnsNameToLowerCase(fileFieldNames);
+ fileFieldNamesToLowerCase(fileFieldNames);
}
private String getFileFormat(NereidsLoadTaskInfo taskInfo) {
@@ -990,9 +990,16 @@ public class NereidsDataDescription {
}
}
- // Change all the columns name to lower case, because Doris column is
case-insensitive.
+ private void fileFieldNamesToLowerCase(List<String> columns) {
+ if
(Util.isCasePreservingFormat(analysisMap.get(FileFormatProperties.PROP_FORMAT)))
{
+ return;
+ }
+ columnsNameToLowerCase(columns);
+ }
+
+ // Change column names to lower case, because Doris column is
case-insensitive.
private void columnsNameToLowerCase(List<String> columns) {
- if (columns == null || columns.isEmpty() ||
"json".equals(analysisMap.get(FileFormatProperties.PROP_FORMAT))) {
+ if (columns == null || columns.isEmpty()) {
return;
}
for (int i = 0; i < columns.size(); i++) {
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/load/NereidsLoadScanProvider.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/load/NereidsLoadScanProvider.java
index b9949a825b1..42bc039f694 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/load/NereidsLoadScanProvider.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/load/NereidsLoadScanProvider.java
@@ -23,7 +23,6 @@ import org.apache.doris.catalog.OlapTable;
import org.apache.doris.catalog.PrimitiveType;
import org.apache.doris.catalog.Table;
import org.apache.doris.catalog.TableIf;
-import org.apache.doris.catalog.Type;
import org.apache.doris.common.AnalysisException;
import org.apache.doris.common.DdlException;
import org.apache.doris.common.IdGenerator;
@@ -59,7 +58,6 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@@ -204,7 +202,8 @@ public class NereidsLoadScanProvider {
continue;
}
NereidsImportColumnDesc columnDesc;
- if (fileGroup.getFileFormatProperties().getFileFormatType() ==
TFileFormatType.FORMAT_JSON) {
+ TFileFormatType fileFormatType =
fileGroup.getFileFormatProperties().getFileFormatType();
+ if (Util.isCasePreservingFormat(fileFormatType)) {
columnDesc = new NereidsImportColumnDesc(column.getName());
} else {
columnDesc = new
NereidsImportColumnDesc(column.getName().toLowerCase());
@@ -281,7 +280,6 @@ public class NereidsLoadScanProvider {
}
}
- HashMap<String, Type> colToType = new HashMap<>();
// check default value and auto-increment column
for (Column column : tbl.getBaseSchema()) {
if (fileGroupInfo.getUniqueKeyUpdateMode() ==
TUniqueKeyUpdateMode.UPDATE_FIXED_COLUMNS
@@ -289,7 +287,6 @@ public class NereidsLoadScanProvider {
continue;
}
String columnName = column.getName();
- colToType.put(columnName, column.getType());
Expression expression = null;
if (column.getGeneratedColumnInfo() != null) {
// the generated column will be handled by bindSink
@@ -372,7 +369,11 @@ public class NereidsLoadScanProvider {
// Use real column type for arrow/native format, other formats
read as varchar first
if (fileFormatType == TFileFormatType.FORMAT_ARROW
|| fileFormatType == TFileFormatType.FORMAT_NATIVE) {
- slotColumn = new Column(realColName,
colToType.get(realColName), true);
+ if (tblColumn == null) {
+ throw new AnalysisException("Unknown column " +
realColName + " in table " + tbl.getName()
+ + " for " + fileFormatType + " load");
+ }
+ slotColumn = new Column(realColName, tblColumn.getType(),
true);
} else {
if (fileGroupInfo.getUniqueKeyUpdateMode() ==
TUniqueKeyUpdateMode.UPDATE_FLEXIBLE_COLUMNS
&& hasSkipBitmapColumn) {
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/load/NereidsLoadUtils.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/load/NereidsLoadUtils.java
index 10d48cee510..2b1148a253c 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/load/NereidsLoadUtils.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/load/NereidsLoadUtils.java
@@ -81,6 +81,16 @@ import java.util.TreeSet;
* NereidsLoadUtils
*/
public class NereidsLoadUtils {
+ static boolean hasImportColumn(List<NereidsImportColumnDesc>
importColumnDescs, Column tableColumn) {
+ for (NereidsImportColumnDesc importColumnDesc : importColumnDescs) {
+ if (importColumnDesc.getColumnName() != null
+ &&
importColumnDesc.getColumnName().equalsIgnoreCase(tableColumn.getName())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/**
* parse a expression list as 'select expr1, expr2,... exprn' into a
nereids Expression List
*/
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/load/NereidsLoadingTaskPlanner.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/load/NereidsLoadingTaskPlanner.java
index 001ede1fbcc..924cc43c1d8 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/load/NereidsLoadingTaskPlanner.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/load/NereidsLoadingTaskPlanner.java
@@ -124,19 +124,15 @@ public class NereidsLoadingTaskPlanner {
HashSet<String> partialUpdateInputColumns = new HashSet<>();
if (isPartialUpdate) {
+ List<NereidsImportColumnDesc> importColumnDescs =
fileGroups.get(0).getColumnExprList();
for (Column col : table.getFullSchema()) {
- boolean existInExpr = false;
- for (NereidsImportColumnDesc importColumnDesc :
fileGroups.get(0).getColumnExprList()) {
- if (importColumnDesc.getColumnName() != null
- &&
importColumnDesc.getColumnName().equals(col.getName())) {
- if (!col.isVisible() &&
!Column.DELETE_SIGN.equals(col.getName())) {
- throw new UserException("Partial update should not
include invisible column except"
- + " delete sign column: " + col.getName());
- }
- partialUpdateInputColumns.add(col.getName());
- existInExpr = true;
- break;
+ boolean existInExpr =
NereidsLoadUtils.hasImportColumn(importColumnDescs, col);
+ if (existInExpr) {
+ if (!col.isVisible() &&
!Column.DELETE_SIGN.equals(col.getName())) {
+ throw new UserException("Partial update should not
include invisible column except"
+ + " delete sign column: " + col.getName());
}
+ partialUpdateInputColumns.add(col.getName());
}
if (col.isKey() && !existInExpr) {
throw new UserException("Partial update should include all
key columns, missing: " + col.getName());
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/load/NereidsStreamLoadPlanner.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/load/NereidsStreamLoadPlanner.java
index 69d68365189..6bc4a4974e9 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/load/NereidsStreamLoadPlanner.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/load/NereidsStreamLoadPlanner.java
@@ -159,21 +159,17 @@ public class NereidsStreamLoadPlanner {
if (col.hasOnUpdateDefaultValue()) {
partialUpdateInputColumns.add(col.getName());
}
- for (NereidsImportColumnDesc importColumnDesc :
taskInfo.getColumnExprDescs().descs) {
- if (importColumnDesc.getColumnName() != null
- &&
importColumnDesc.getColumnName().equals(col.getName())) {
- if (!col.isVisible() &&
!Column.DELETE_SIGN.equals(col.getName())) {
- throw new UserException("Partial update should not
include invisible column except"
- + " delete sign column: " + col.getName());
- }
- partialUpdateInputColumns.add(col.getName());
- if (destTable.hasSequenceCol()
- && (taskInfo.hasSequenceCol() ||
(destTable.getSequenceMapCol() != null
- &&
destTable.getSequenceMapCol().equalsIgnoreCase(col.getName())))) {
- partialUpdateInputColumns.add(Column.SEQUENCE_COL);
- }
- existInExpr = true;
- break;
+ existInExpr =
NereidsLoadUtils.hasImportColumn(taskInfo.getColumnExprDescs().descs, col);
+ if (existInExpr) {
+ if (!col.isVisible() &&
!Column.DELETE_SIGN.equals(col.getName())) {
+ throw new UserException("Partial update should not
include invisible column except"
+ + " delete sign column: " + col.getName());
+ }
+ partialUpdateInputColumns.add(col.getName());
+ if (destTable.hasSequenceCol()
+ && (taskInfo.hasSequenceCol() ||
(destTable.getSequenceMapCol() != null
+ &&
destTable.getSequenceMapCol().equalsIgnoreCase(col.getName())))) {
+ partialUpdateInputColumns.add(Column.SEQUENCE_COL);
}
}
if (!existInExpr) {
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/nereids/load/NereidsLoadScanProviderTest.java
b/fe/fe-core/src/test/java/org/apache/doris/nereids/load/NereidsLoadScanProviderTest.java
new file mode 100644
index 00000000000..95d469a4a93
--- /dev/null
+++
b/fe/fe-core/src/test/java/org/apache/doris/nereids/load/NereidsLoadScanProviderTest.java
@@ -0,0 +1,192 @@
+// 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.
+
+package org.apache.doris.nereids.load;
+
+import org.apache.doris.analysis.BrokerDesc;
+import org.apache.doris.catalog.Column;
+import org.apache.doris.catalog.KeysType;
+import org.apache.doris.catalog.OlapTable;
+import org.apache.doris.catalog.PrimitiveType;
+import org.apache.doris.common.UserException;
+import
org.apache.doris.datasource.property.fileformat.ArrowFileFormatProperties;
+import org.apache.doris.datasource.property.fileformat.FileFormatProperties;
+import
org.apache.doris.datasource.property.fileformat.NativeFileFormatProperties;
+import org.apache.doris.load.loadv2.LoadTask;
+import org.apache.doris.nereids.trees.expressions.SlotReference;
+import org.apache.doris.thrift.TBrokerFileStatus;
+import org.apache.doris.thrift.TFileCompressType;
+import org.apache.doris.thrift.TFileFormatType;
+import org.apache.doris.thrift.TFileType;
+import org.apache.doris.thrift.TStreamLoadPutRequest;
+import org.apache.doris.thrift.TUniqueId;
+import org.apache.doris.thrift.TUniqueKeyUpdateMode;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+public class NereidsLoadScanProviderTest {
+
+ @Test
+ public void testArrowStreamLoadKeepsExplicitColumnCase() throws Exception {
+ TStreamLoadPutRequest request = new TStreamLoadPutRequest();
+ request.setLoadId(new TUniqueId(1, 2));
+ request.setTxnId(3);
+ request.setFileType(TFileType.FILE_STREAM);
+ request.setFormatType(TFileFormatType.FORMAT_ARROW);
+ request.setCompressType(TFileCompressType.UNKNOWN);
+ request.setColumns("time,securityid,EV");
+
+ NereidsStreamLoadTask task =
NereidsStreamLoadTask.fromTStreamLoadPutRequest(request);
+ NereidsDataDescription dataDescription = new
NereidsDataDescription("t_upper", task);
+
+ Assertions.assertEquals(Lists.newArrayList("time", "securityid", "EV"),
+ dataDescription.getFileFieldNames());
+ }
+
+ @Test
+ public void
testArrowBrokerLoadKeepsExplicitColumnCaseForNonLowercaseFormat() {
+ NereidsDataDescription dataDescription = new
NereidsDataDescription("t_upper", null,
+ Lists.newArrayList("dummy"), Lists.newArrayList("time",
"securityid", "EV"),
+ null, null, "ARROW", null, null, false,
Collections.emptyList(), null, null,
+ LoadTask.MergeType.APPEND, null, null, null);
+
+ Assertions.assertEquals(Lists.newArrayList("time", "securityid", "EV"),
+ dataDescription.getFileFieldNames());
+ }
+
+ @Test
+ public void testArrowBrokerLoadLowersColumnsFromPath() {
+ NereidsDataDescription dataDescription = new
NereidsDataDescription("t_upper", null,
+ Lists.newArrayList("dummy"), Lists.newArrayList("time",
"securityid", "EV"),
+ null, null, "ARROW", null, Lists.newArrayList("DT"), false,
Collections.emptyList(), null, null,
+ LoadTask.MergeType.APPEND, null, null, null);
+
+ Assertions.assertEquals(Lists.newArrayList("time", "securityid", "EV"),
+ dataDescription.getFileFieldNames());
+ Assertions.assertEquals(Lists.newArrayList("dt"),
dataDescription.getColumnsFromPath());
+ }
+
+ @Test
+ public void testArrowAutoGeneratedSlotsKeepUppercaseTableColumn() throws
Exception {
+ OlapTable table = mockTable();
+ NereidsParamCreateContext context = createArrowLoadContext(table,
ImmutableList.of());
+
+ assertSlot(context, "time", PrimitiveType.DATETIME);
+ assertSlot(context, "securityid", PrimitiveType.INT);
+ assertSlot(context, "EV", PrimitiveType.DOUBLE);
+ Assertions.assertFalse(context.scanSlots.stream().anyMatch(slot ->
slot.getName().equals("ev")));
+ }
+
+ @Test
+ public void testArrowSourceColumnUsesCaseInsensitiveTableType() throws
Exception {
+ OlapTable table = mockTable();
+ NereidsParamCreateContext context = createArrowLoadContext(table,
+ ImmutableList.of(new NereidsImportColumnDesc("time"),
+ new NereidsImportColumnDesc("securityid"),
+ new NereidsImportColumnDesc("ev")));
+
+ assertSlot(context, "ev", PrimitiveType.DOUBLE);
+ }
+
+ @Test
+ public void testNativeSourceColumnUsesCaseInsensitiveTableType() throws
Exception {
+ OlapTable table = mockTable();
+ NereidsParamCreateContext context = createLoadContext(table,
+ ImmutableList.of(new NereidsImportColumnDesc("time"),
+ new NereidsImportColumnDesc("securityid"),
+ new NereidsImportColumnDesc("ev")),
+ new NativeFileFormatProperties());
+
+ assertSlot(context, "ev", PrimitiveType.DOUBLE);
+ }
+
+ @Test
+ public void testImportColumnMatchesTableColumnCaseInsensitive() {
+ Column tableColumn = new Column("EV", PrimitiveType.DOUBLE, true);
+
+ Assertions.assertTrue(NereidsLoadUtils.hasImportColumn(
+ ImmutableList.of(new NereidsImportColumnDesc("ev")),
tableColumn));
+ Assertions.assertTrue(NereidsLoadUtils.hasImportColumn(
+ ImmutableList.of(new NereidsImportColumnDesc("EV")),
tableColumn));
+ Assertions.assertFalse(NereidsLoadUtils.hasImportColumn(
+ ImmutableList.of(new NereidsImportColumnDesc("other")),
tableColumn));
+ }
+
+ private NereidsParamCreateContext createArrowLoadContext(
+ OlapTable table, List<NereidsImportColumnDesc> columnExprList)
throws UserException {
+ return createLoadContext(table, columnExprList, new
ArrowFileFormatProperties());
+ }
+
+ private NereidsParamCreateContext createLoadContext(OlapTable table,
List<NereidsImportColumnDesc> columnExprList,
+ FileFormatProperties fileFormatProperties)
+ throws UserException {
+ NereidsBrokerFileGroup fileGroup = new NereidsBrokerFileGroup(1L,
false, null,
+ Lists.newArrayList("dummy"), null, null, null, columnExprList,
null, null, null, null,
+ LoadTask.MergeType.APPEND, null, -1L, false, false,
fileFormatProperties);
+ TBrokerFileStatus fileStatus = new TBrokerFileStatus();
+ fileStatus.setPath("");
+ fileStatus.setIsDir(false);
+ fileStatus.setSize(-1);
+ NereidsFileGroupInfo fileGroupInfo = new NereidsFileGroupInfo(new
TUniqueId(1, 2), 3L, table,
+ BrokerDesc.createForStreamLoad(), fileGroup, fileStatus,
false, TFileType.FILE_STREAM, null,
+ TUniqueKeyUpdateMode.UPSERT, null);
+ return new NereidsLoadScanProvider(fileGroupInfo,
Collections.emptySet()).createLoadContext();
+ }
+
+ private OlapTable mockTable() {
+ List<Column> schema = Arrays.asList(
+ new Column("time", PrimitiveType.DATETIME, true),
+ new Column("securityid", PrimitiveType.INT, true),
+ new Column("EV", PrimitiveType.DOUBLE, true));
+ Map<String, Column> nameToColumn = new
TreeMap<>(String.CASE_INSENSITIVE_ORDER);
+ for (Column column : schema) {
+ nameToColumn.put(column.getName(), column);
+ }
+
+ OlapTable table = Mockito.mock(OlapTable.class);
+ Mockito.when(table.getName()).thenReturn("t_upper");
+ Mockito.when(table.getBaseSchema()).thenReturn(schema);
+ Mockito.when(table.getBaseSchema(false)).thenReturn(schema);
+ Mockito.when(table.getBaseSchema(true)).thenReturn(schema);
+ Mockito.when(table.getColumn(Mockito.anyString()))
+ .thenAnswer(invocation ->
nameToColumn.get(invocation.getArgument(0)));
+ Mockito.when(table.hasSequenceCol()).thenReturn(false);
+ Mockito.when(table.getSequenceMapCol()).thenReturn(null);
+ Mockito.when(table.hasSkipBitmapColumn()).thenReturn(false);
+ Mockito.when(table.getKeysType()).thenReturn(KeysType.UNIQUE_KEYS);
+
Mockito.when(table.getFullQualifiers()).thenReturn(ImmutableList.of("internal",
"db", "t_upper"));
+ return table;
+ }
+
+ private void assertSlot(NereidsParamCreateContext context, String name,
PrimitiveType type) {
+ SlotReference slot = context.scanSlots.stream()
+ .filter(scanSlot -> scanSlot.getName().equals(name))
+ .findFirst()
+ .orElseThrow(() -> new AssertionError("missing scan slot " +
name));
+ Assertions.assertEquals(type,
slot.getOriginalColumn().get().getDataType());
+ }
+}
diff --git
a/regression-test/data/load_p0/stream_load/arrow_uppercase_column.arrow
b/regression-test/data/load_p0/stream_load/arrow_uppercase_column.arrow
new file mode 100644
index 00000000000..b8bebcf3d3e
Binary files /dev/null and
b/regression-test/data/load_p0/stream_load/arrow_uppercase_column.arrow differ
diff --git
a/regression-test/data/load_p0/stream_load/test_arrow_stream_load_uppercase_column.out
b/regression-test/data/load_p0/stream_load/test_arrow_stream_load_uppercase_column.out
new file mode 100644
index 00000000000..31344c45f9d
--- /dev/null
+++
b/regression-test/data/load_p0/stream_load/test_arrow_stream_load_uppercase_column.out
@@ -0,0 +1,8 @@
+-- This file is automatically generated. You should know what you did if you
want to edit this
+-- !explicit --
+1:2.5
+2:3.5
+
+-- !auto --
+1:2.5
+2:3.5
diff --git
a/regression-test/suites/load_p0/stream_load/test_arrow_stream_load_uppercase_column.groovy
b/regression-test/suites/load_p0/stream_load/test_arrow_stream_load_uppercase_column.groovy
new file mode 100644
index 00000000000..16e3fe4c861
--- /dev/null
+++
b/regression-test/suites/load_p0/stream_load/test_arrow_stream_load_uppercase_column.groovy
@@ -0,0 +1,89 @@
+// 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_arrow_stream_load_uppercase_column", "p0") {
+ sql """DROP TABLE IF EXISTS
test_arrow_stream_load_uppercase_column_explicit"""
+ sql """
+ CREATE TABLE test_arrow_stream_load_uppercase_column_explicit (
+ `id` INT,
+ `EV` DOUBLE
+ ) ENGINE=OLAP
+ DUPLICATE KEY(`id`)
+ DISTRIBUTED BY HASH(`id`) BUCKETS 1
+ PROPERTIES ("replication_allocation" = "tag.location.default: 1");
+ """
+
+ streamLoad {
+ table "test_arrow_stream_load_uppercase_column_explicit"
+ set 'format', 'arrow'
+ set 'columns', 'id,EV'
+ file 'arrow_uppercase_column.arrow'
+ time 10000
+ check { result, exception, startTime, endTime ->
+ if (exception != null) {
+ throw exception
+ }
+ log.info("Stream load result: ${result}".toString())
+ def json = parseJson(result)
+ assertEquals("success", json.Status.toLowerCase())
+ assertEquals(2, json.NumberTotalRows)
+ assertEquals(0, json.NumberFilteredRows)
+ }
+ }
+
+ sql "sync"
+ order_qt_explicit """
+ SELECT concat(cast(id AS STRING), ':', cast(EV AS STRING))
+ FROM test_arrow_stream_load_uppercase_column_explicit
+ ORDER BY id
+ """
+
+ sql """DROP TABLE IF EXISTS test_arrow_stream_load_uppercase_column_auto"""
+ sql """
+ CREATE TABLE test_arrow_stream_load_uppercase_column_auto (
+ `id` INT,
+ `EV` DOUBLE
+ ) ENGINE=OLAP
+ DUPLICATE KEY(`id`)
+ DISTRIBUTED BY HASH(`id`) BUCKETS 1
+ PROPERTIES ("replication_allocation" = "tag.location.default: 1");
+ """
+
+ streamLoad {
+ table "test_arrow_stream_load_uppercase_column_auto"
+ set 'format', 'arrow'
+ file 'arrow_uppercase_column.arrow'
+ time 10000
+ check { result, exception, startTime, endTime ->
+ if (exception != null) {
+ throw exception
+ }
+ log.info("Stream load result: ${result}".toString())
+ def json = parseJson(result)
+ assertEquals("success", json.Status.toLowerCase())
+ assertEquals(2, json.NumberTotalRows)
+ assertEquals(0, json.NumberFilteredRows)
+ }
+ }
+
+ sql "sync"
+ order_qt_auto """
+ SELECT concat(cast(id AS STRING), ':', cast(EV AS STRING))
+ FROM test_arrow_stream_load_uppercase_column_auto
+ ORDER BY id
+ """
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]