From e1d82c315c76856911a6c944b530cad717b57019 Mon Sep 17 00:00:00 2001 From: daidai Date: Wed, 8 Apr 2026 10:39:11 +0800 Subject: [PATCH] branch-4.1: [fix](jdbc) Preserve query tvf column aliases across JDBC catalogs (#61939) (#62138) bp #61939 --- .../apache/doris/jdbc/BaseJdbcExecutor.java | 7 +- .../datasource/jdbc/util/JdbcFieldSchema.java | 5 +- .../jdbc/util/JdbcFieldSchemaTest.java | 74 +++++++++++++++++++ .../jdbc/test_jdbc_query_tvf.out | 6 ++ .../jdbc/test_jdbc_query_tvf.groovy | 5 +- 5 files changed, 92 insertions(+), 5 deletions(-) create mode 100644 fe/fe-core/src/test/java/org/apache/doris/datasource/jdbc/util/JdbcFieldSchemaTest.java diff --git a/fe/be-java-extensions/jdbc-scanner/src/main/java/org/apache/doris/jdbc/BaseJdbcExecutor.java b/fe/be-java-extensions/jdbc-scanner/src/main/java/org/apache/doris/jdbc/BaseJdbcExecutor.java index 0cf4136a461060..efebe6924136db 100644 --- a/fe/be-java-extensions/jdbc-scanner/src/main/java/org/apache/doris/jdbc/BaseJdbcExecutor.java +++ b/fe/be-java-extensions/jdbc-scanner/src/main/java/org/apache/doris/jdbc/BaseJdbcExecutor.java @@ -248,7 +248,10 @@ public long getBlockAddress(int batchSize, Map outputParams) thr this.resultSetColumnMap = new HashMap<>(); int resultSetColumnCount = resultSetMetaData.getColumnCount(); for (int i = 1; i <= resultSetColumnCount; i++) { - String columnName = resultSetMetaData.getColumnName(i).trim().toLowerCase(); + String columnLabel = resultSetMetaData.getColumnLabel(i); + String columnName = (columnLabel == null || columnLabel.isEmpty() + ? resultSetMetaData.getColumnName(i) + : columnLabel).trim().toLowerCase(); resultSetColumnMap.put(columnName, i); } } @@ -836,5 +839,3 @@ protected String defaultByteArrayToHexString(byte[] bytes) { } } - - diff --git a/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/util/JdbcFieldSchema.java b/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/util/JdbcFieldSchema.java index d91b06b46c93b7..5e1f0a87bbacb9 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/util/JdbcFieldSchema.java +++ b/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/util/JdbcFieldSchema.java @@ -99,7 +99,10 @@ public JdbcFieldSchema(ResultSet rs, Map dataTypeOverrides) thro } public JdbcFieldSchema(ResultSetMetaData metaData, int columnIndex) throws SQLException { - this.columnName = metaData.getColumnName(columnIndex); + String columnLabel = metaData.getColumnLabel(columnIndex); + this.columnName = columnLabel == null || columnLabel.isEmpty() + ? metaData.getColumnName(columnIndex) + : columnLabel; this.dataType = metaData.getColumnType(columnIndex); this.dataTypeName = Optional.ofNullable(metaData.getColumnTypeName(columnIndex)); this.columnSize = Optional.of(metaData.getPrecision(columnIndex)); diff --git a/fe/fe-core/src/test/java/org/apache/doris/datasource/jdbc/util/JdbcFieldSchemaTest.java b/fe/fe-core/src/test/java/org/apache/doris/datasource/jdbc/util/JdbcFieldSchemaTest.java new file mode 100644 index 00000000000000..5eda7393f99350 --- /dev/null +++ b/fe/fe-core/src/test/java/org/apache/doris/datasource/jdbc/util/JdbcFieldSchemaTest.java @@ -0,0 +1,74 @@ +// 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.datasource.jdbc.util; + +import mockit.Expectations; +import mockit.Mocked; +import org.junit.Assert; +import org.junit.Test; + +import java.sql.ResultSetMetaData; +import java.sql.Types; + +public class JdbcFieldSchemaTest { + + @Mocked + private ResultSetMetaData metaData; + + @Test + public void testUseColumnLabelForQueryAlias() throws Exception { + new Expectations() {{ + metaData.getColumnLabel(1); + result = "t1"; + metaData.getColumnType(1); + result = Types.VARCHAR; + metaData.getColumnTypeName(1); + result = "VARCHAR"; + metaData.getPrecision(1); + result = 64; + metaData.getScale(1); + result = 0; + }}; + + JdbcFieldSchema schema = new JdbcFieldSchema(metaData, 1); + + Assert.assertEquals("t1", schema.getColumnName()); + } + + @Test + public void testFallbackToColumnNameWhenLabelMissing() throws Exception { + new Expectations() {{ + metaData.getColumnLabel(1); + result = ""; + metaData.getColumnName(1); + result = "username"; + metaData.getColumnType(1); + result = Types.VARCHAR; + metaData.getColumnTypeName(1); + result = "VARCHAR"; + metaData.getPrecision(1); + result = 64; + metaData.getScale(1); + result = 0; + }}; + + JdbcFieldSchema schema = new JdbcFieldSchema(metaData, 1); + + Assert.assertEquals("username", schema.getColumnName()); + } +} diff --git a/regression-test/data/external_table_p0/jdbc/test_jdbc_query_tvf.out b/regression-test/data/external_table_p0/jdbc/test_jdbc_query_tvf.out index 76911221065061..8299d4e9678e9c 100644 --- a/regression-test/data/external_table_p0/jdbc/test_jdbc_query_tvf.out +++ b/regression-test/data/external_table_p0/jdbc/test_jdbc_query_tvf.out @@ -42,3 +42,9 @@ year smallint Yes true \N NONE -- !sql -- 4 +-- !sql -- +alias_smallint_u int Yes true \N NONE +alias_tinyint_u smallint Yes true \N NONE + +-- !sql -- +203 303 diff --git a/regression-test/suites/external_table_p0/jdbc/test_jdbc_query_tvf.groovy b/regression-test/suites/external_table_p0/jdbc/test_jdbc_query_tvf.groovy index bc4a552ebbe611..cb98df7b0d2a2b 100644 --- a/regression-test/suites/external_table_p0/jdbc/test_jdbc_query_tvf.groovy +++ b/regression-test/suites/external_table_p0/jdbc/test_jdbc_query_tvf.groovy @@ -43,8 +43,11 @@ suite("test_jdbc_query_tvf", "p0,external,external_docker") { order_qt_sql """desc function query('catalog' = '${catalog_name}', 'query' = 'select * from doris_test.all_types') """ order_qt_sql """select * from query('catalog' = '${catalog_name}', 'query' = 'select * from doris_test.all_types') """ order_qt_sql """select * from query('catalog' = '${catalog_name}', 'query' = 'select count(*) as cnt from doris_test.all_types') """ + order_qt_sql """desc function query('catalog' = '${catalog_name}', + 'query' = 'select tinyint_u as alias_tinyint_u, smallint_u as alias_smallint_u from doris_test.all_types where tinyint_u is not null') """ + order_qt_sql """select * from query('catalog' = '${catalog_name}', + 'query' = 'select tinyint_u as alias_tinyint_u, smallint_u as alias_smallint_u from doris_test.all_types where tinyint_u is not null') where alias_tinyint_u = 203 """ // sql """drop catalog if exists ${catalog_name} """ } } -