This is an automated email from the ASF dual-hosted git repository.
yiguolei pushed a commit to branch branch-4.1
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/branch-4.1 by this push:
new 9782738437f branch-4.1:[fix](fe) Improve MaxCompute catalog validation
(#64119) (#66157)
9782738437f is described below
commit 9782738437f7d5d61f20cd215288bd48a78a75f9
Author: daidai <[email protected]>
AuthorDate: Thu Jul 30 08:54:04 2026 +0800
branch-4.1:[fix](fe) Improve MaxCompute catalog validation (#64119) (#66157)
### What problem does this PR solve?
bp #64119
Problem Summary:
Use the `test_connection` catalog parameter, to perform ak-sk、 project
、schema validation when creating a maxcompute catalog.
### Release note
None
### Check List (For Author)
- Test <!-- At least one of them must be included. -->
- [ ] Regression test
- [ ] Unit Test
- [ ] Manual test (add detailed scripts or steps below)
- [ ] No need to test or manual test. Explain why:
- [ ] This is a refactor/code format and no logic has been changed.
- [ ] Previous test can cover this change.
- [ ] No code files have been changed.
- [ ] Other reason <!-- Add your reason? -->
- Behavior changed:
- [ ] No.
- [ ] Yes. <!-- Explain the behavior change -->
- Does this need documentation?
- [ ] No.
- [ ] Yes. <!-- Add document PR link here. eg:
https://github.com/apache/doris-website/pull/1214 -->
### Check List (For Reviewer who merge this PR)
- [ ] Confirm the release note
- [ ] Confirm test cases
- [ ] Confirm document
- [ ] Add branch pick label <!-- Add branch pick label that this PR
should merge into -->
---
.../doris/datasource/maxcompute/MCTransaction.java | 4 +
.../maxcompute/MaxComputeExternalCatalog.java | 70 +++++++++-
.../maxcompute/MaxComputeExternalTable.java | 11 ++
.../maxcompute/source/MaxComputeScanNode.java | 5 +
.../datasource/maxcompute/MCTransactionTest.java | 54 ++++++++
.../maxcompute/MaxComputeExternalCatalogTest.java | 146 +++++++++++++++++++++
.../maxcompute/source/MaxComputeScanNodeTest.java | 79 +++++++++++
fe/pom.xml | 2 +-
.../test_external_catalog_maxcompute.groovy | 6 +-
.../maxcompute/test_max_compute_schema.groovy | 5 +-
.../test_max_compute_validate_connection.groovy | 102 ++++++++++++++
11 files changed, 477 insertions(+), 7 deletions(-)
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/datasource/maxcompute/MCTransaction.java
b/fe/fe-core/src/main/java/org/apache/doris/datasource/maxcompute/MCTransaction.java
index 9f1c61ddf24..6d5a6c9112f 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/datasource/maxcompute/MCTransaction.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/datasource/maxcompute/MCTransaction.java
@@ -71,6 +71,10 @@ public class MCTransaction implements Transaction {
public void beginInsert(ExternalTable dorisTable,
Optional<InsertCommandContext> ctx) throws UserException {
this.table = (MaxComputeExternalTable) dorisTable;
+ if (table.isUnsupportedOdpsTable()) {
+ throw new UserException("Writing MaxCompute external table or
logical view is not supported: "
+ + table.getDbName() + "." + table.getName());
+ }
try {
TableIdentifier tableId =
catalog.getOdpsTableIdentifier(table.getDbName(), table.getName());
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/datasource/maxcompute/MaxComputeExternalCatalog.java
b/fe/fe-core/src/main/java/org/apache/doris/datasource/maxcompute/MaxComputeExternalCatalog.java
index 1292746cc25..33de9d0e1f4 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/datasource/maxcompute/MaxComputeExternalCatalog.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/datasource/maxcompute/MaxComputeExternalCatalog.java
@@ -29,6 +29,7 @@ import
org.apache.doris.datasource.operations.ExternalMetadataOperations;
import org.apache.doris.transaction.TransactionManagerFactory;
import com.aliyun.odps.Odps;
+import com.aliyun.odps.OdpsException;
import com.aliyun.odps.Partition;
import com.aliyun.odps.account.AccountFormat;
import com.aliyun.odps.table.TableIdentifier;
@@ -53,7 +54,6 @@ public class MaxComputeExternalCatalog extends
ExternalCatalog {
// you can ref : https://help.aliyun.com/zh/maxcompute/user-guide/endpoints
private static final String endpointTemplate =
"http://service.{}.maxcompute.aliyun-inc.com/api";
-
private Map<String, String> props;
private Odps odps;
private String endpoint;
@@ -207,6 +207,9 @@ public class MaxComputeExternalCatalog extends
ExternalCatalog {
odps = MCUtils.createMcClient(props);
odps.setDefaultProject(defaultProject);
odps.setEndpoint(endpoint);
+ odps.getRestClient().setConnectTimeout(connectTimeout);
+ odps.getRestClient().setReadTimeout(readTimeout);
+ odps.getRestClient().setRetryTimes(retryTimes);
String accountFormatProp =
props.getOrDefault(MCProperties.ACCOUNT_FORMAT,
MCProperties.DEFAULT_ACCOUNT_FORMAT);
if (accountFormatProp.equals(MCProperties.ACCOUNT_FORMAT_NAME)) {
@@ -234,6 +237,69 @@ public class MaxComputeExternalCatalog extends
ExternalCatalog {
transactionManager =
TransactionManagerFactory.createMCTransactionManager(this);
}
+ @Override
+ public void checkWhenCreating() throws DdlException {
+ boolean testConnection =
Boolean.parseBoolean(catalogProperty.getOrDefault(TEST_CONNECTION,
+ String.valueOf(DEFAULT_TEST_CONNECTION)));
+ if (!testConnection) {
+ return;
+ }
+ // MaxCompute has no MetastoreProperties-backed connectivity tester
yet,
+ // so run its catalog-specific test directly under the common
test_connection switch.
+ boolean enableNamespaceSchema = Boolean.parseBoolean(
+
catalogProperty.getOrDefault(MCProperties.ENABLE_NAMESPACE_SCHEMA,
+ MCProperties.DEFAULT_ENABLE_NAMESPACE_SCHEMA));
+ try {
+ initLocalObjects();
+ validateMaxComputeConnection(enableNamespaceSchema);
+ } catch (Exception e) {
+ throw new DdlException(e.getMessage(), e);
+ }
+ }
+
+ protected void validateMaxComputeConnection(boolean enableNamespaceSchema)
{
+ if (enableNamespaceSchema) {
+ validateMaxComputeProjectAndNamespaceSchema();
+ } else {
+ validateMaxComputeProject();
+ }
+ }
+
+ private void validateMaxComputeProject() {
+ boolean projectExists;
+ try {
+ projectExists = maxComputeProjectExists(defaultProject);
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to validate MaxCompute project
'" + defaultProject
+ + "'. Check " + MCProperties.PROJECT + ", " +
MCProperties.ENDPOINT
+ + " and credentials. Cause: " + e.getMessage(), e);
+ }
+ if (!projectExists) {
+ throw new RuntimeException("Failed to validate MaxCompute project
'" + defaultProject
+ + "'. Check " + MCProperties.PROJECT + ", " +
MCProperties.ENDPOINT
+ + " and credentials. Cause: project does not exist or is
not accessible");
+ }
+ }
+
+ private void validateMaxComputeProjectAndNamespaceSchema() {
+ try {
+ validateMaxComputeNamespaceSchemaAccess(defaultProject);
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to validate MaxCompute project
'" + defaultProject
+ + "' with namespace schema. Check " + MCProperties.PROJECT
+ ", " + MCProperties.ENDPOINT
+ + ", credentials, and whether the schema list is
accessible for the namespace schema "
+ + "configuration. Cause: " + e.getMessage(), e);
+ }
+ }
+
+ protected boolean maxComputeProjectExists(String projectName) throws
OdpsException {
+ return odps.projects().exists(projectName);
+ }
+
+ protected void validateMaxComputeNamespaceSchemaAccess(String projectName)
throws OdpsException {
+ odps.schemas().iterator(projectName).hasNext();
+ }
+
public Odps getClient() {
makeSureInitialized();
return odps;
@@ -402,7 +468,7 @@ public class MaxComputeExternalCatalog extends
ExternalCatalog {
MCProperties.DEFAULT_SPLIT_BYTE_SIZE));
if (splitByteSize < 10485760L) {
- throw new DdlException(MCProperties.SPLIT_ROW_COUNT + "
must be greater than or equal to 10485760");
+ throw new DdlException(MCProperties.SPLIT_BYTE_SIZE + "
must be greater than or equal to 10485760");
}
} else if
(splitStrategy.equals(MCProperties.SPLIT_BY_ROW_COUNT_STRATEGY)) {
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/datasource/maxcompute/MaxComputeExternalTable.java
b/fe/fe-core/src/main/java/org/apache/doris/datasource/maxcompute/MaxComputeExternalTable.java
index 85e592b6f3d..1ca1e42b0c7 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/datasource/maxcompute/MaxComputeExternalTable.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/datasource/maxcompute/MaxComputeExternalTable.java
@@ -54,6 +54,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
@@ -347,6 +348,16 @@ public class MaxComputeExternalTable extends ExternalTable
{
.orElse(null);
}
+ public boolean isUnsupportedOdpsTable() {
+ Table odpsTable = getOdpsTable();
+ return isUnsupportedOdpsTable(odpsTable);
+ }
+
+ public static boolean isUnsupportedOdpsTable(Table odpsTable) {
+ Objects.requireNonNull(odpsTable, "MaxCompute table metadata is not
initialized");
+ return odpsTable.isExternalTable() || odpsTable.isVirtualView();
+ }
+
@Override
public boolean isPartitionedTable() {
makeSureInitialized();
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/datasource/maxcompute/source/MaxComputeScanNode.java
b/fe/fe-core/src/main/java/org/apache/doris/datasource/maxcompute/source/MaxComputeScanNode.java
index bf09288be98..3c71e1ad856 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/datasource/maxcompute/source/MaxComputeScanNode.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/datasource/maxcompute/source/MaxComputeScanNode.java
@@ -633,6 +633,11 @@ public class MaxComputeScanNode extends FileQueryScanNode {
public List<Split> getSplits(int numBackends) throws UserException {
List<Split> result = new ArrayList<>();
com.aliyun.odps.Table odpsTable = table.getOdpsTable();
+ if (MaxComputeExternalTable.isUnsupportedOdpsTable(odpsTable)) {
+ throw new UserException("Reading MaxCompute external table or
logical view is not supported: "
+ + table.getDbName() + "." + table.getName());
+ }
+
if (desc.getSlots().isEmpty() || odpsTable.getFileNum() <= 0) {
return result;
}
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/datasource/maxcompute/MCTransactionTest.java
b/fe/fe-core/src/test/java/org/apache/doris/datasource/maxcompute/MCTransactionTest.java
new file mode 100644
index 00000000000..e76f192a858
--- /dev/null
+++
b/fe/fe-core/src/test/java/org/apache/doris/datasource/maxcompute/MCTransactionTest.java
@@ -0,0 +1,54 @@
+// 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.maxcompute;
+
+import org.apache.doris.common.UserException;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import java.util.Optional;
+
+public class MCTransactionTest {
+ @Test
+ public void testBeginInsertRejectsOdpsExternalTable() {
+ assertBeginInsertRejectsUnsupportedOdpsTable("mc_external_table");
+ }
+
+ @Test
+ public void testBeginInsertRejectsOdpsLogicalView() {
+ assertBeginInsertRejectsUnsupportedOdpsTable("mc_logical_view");
+ }
+
+ private void assertBeginInsertRejectsUnsupportedOdpsTable(String
tableName) {
+ MaxComputeExternalCatalog catalog =
Mockito.mock(MaxComputeExternalCatalog.class);
+ MaxComputeExternalTable table =
Mockito.mock(MaxComputeExternalTable.class);
+ Mockito.when(table.isUnsupportedOdpsTable()).thenReturn(true);
+ Mockito.when(table.getDbName()).thenReturn("default");
+ Mockito.when(table.getName()).thenReturn(tableName);
+
+ MCTransaction transaction = new MCTransaction(catalog);
+
+ UserException exception = Assert.assertThrows(UserException.class,
+ () -> transaction.beginInsert(table, Optional.empty()));
+ Assert.assertTrue(exception.getMessage().contains(
+ "Writing MaxCompute external table or logical view is not
supported: default." + tableName));
+ Mockito.verify(catalog,
Mockito.never()).getOdpsTableIdentifier(Mockito.anyString(),
Mockito.anyString());
+ }
+}
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/datasource/maxcompute/MaxComputeExternalCatalogTest.java
b/fe/fe-core/src/test/java/org/apache/doris/datasource/maxcompute/MaxComputeExternalCatalogTest.java
new file mode 100644
index 00000000000..dfe22f136b5
--- /dev/null
+++
b/fe/fe-core/src/test/java/org/apache/doris/datasource/maxcompute/MaxComputeExternalCatalogTest.java
@@ -0,0 +1,146 @@
+// 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.maxcompute;
+
+import org.apache.doris.common.DdlException;
+import org.apache.doris.common.maxcompute.MCProperties;
+import org.apache.doris.datasource.ExternalCatalog;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class MaxComputeExternalCatalogTest {
+ @Test
+ public void testSplitByteSizeErrorMessage() {
+ Map<String, String> props = new HashMap<>();
+ addRequiredProperties(props);
+ props.put(MCProperties.SPLIT_STRATEGY,
MCProperties.SPLIT_BY_BYTE_SIZE_STRATEGY);
+ props.put(MCProperties.SPLIT_BYTE_SIZE, "1048576");
+
+ MaxComputeExternalCatalog catalog = new MaxComputeExternalCatalog(1L,
"mc_catalog", null, props, "");
+
+ DdlException exception = Assert.assertThrows(DdlException.class,
catalog::checkProperties);
+ Assert.assertTrue(exception.getMessage().contains(
+ MCProperties.SPLIT_BYTE_SIZE + " must be greater than or equal
to 10485760"));
+
Assert.assertFalse(exception.getMessage().contains(MCProperties.SPLIT_ROW_COUNT));
+ }
+
+ @Test
+ public void testCheckWhenCreatingSkipsValidationByDefault() throws
DdlException {
+ Map<String, String> props = createRequiredProperties(true);
+ TestMaxComputeExternalCatalog catalog = new
TestMaxComputeExternalCatalog(props);
+
+ catalog.checkWhenCreating();
+
+ Assert.assertNull(catalog.checkedProjectName);
+ Assert.assertNull(catalog.checkedNamespaceSchemaProjectName);
+ }
+
+ @Test
+ public void testCheckWhenCreatingValidatesProjectWhenValidationEnabled()
throws DdlException {
+ Map<String, String> props = createRequiredProperties(false);
+ props.put(ExternalCatalog.TEST_CONNECTION, "true");
+ TestMaxComputeExternalCatalog catalog = new
TestMaxComputeExternalCatalog(props);
+
+ catalog.checkWhenCreating();
+
+ Assert.assertEquals("mc_project", catalog.checkedProjectName);
+ Assert.assertNull(catalog.checkedNamespaceSchemaProjectName);
+ }
+
+ @Test
+ public void
testCheckWhenCreatingValidatesSchemaWhenNamespaceSchemaEnabled() throws
DdlException {
+ Map<String, String> props = createRequiredProperties(true);
+ props.put(ExternalCatalog.TEST_CONNECTION, "true");
+ TestMaxComputeExternalCatalog catalog = new
TestMaxComputeExternalCatalog(props);
+
+ catalog.checkWhenCreating();
+
+ Assert.assertNull(catalog.checkedProjectName);
+ Assert.assertEquals("mc_project",
catalog.checkedNamespaceSchemaProjectName);
+ }
+
+ @Test
+ public void testCheckWhenCreatingReportsInaccessibleProject() {
+ Map<String, String> props = createRequiredProperties(false);
+ props.put(ExternalCatalog.TEST_CONNECTION, "true");
+ TestMaxComputeExternalCatalog catalog = new
TestMaxComputeExternalCatalog(props);
+ catalog.projectExists = false;
+
+ DdlException exception = Assert.assertThrows(DdlException.class,
catalog::checkWhenCreating);
+
+ Assert.assertTrue(exception.getMessage().contains("Failed to validate
MaxCompute project 'mc_project'"));
+ Assert.assertTrue(exception.getMessage().contains("does not exist or
is not accessible"));
+ Assert.assertNull(catalog.checkedNamespaceSchemaProjectName);
+ }
+
+ @Test
+ public void testCheckWhenCreatingReportsInaccessibleNamespaceSchema() {
+ Map<String, String> props = createRequiredProperties(true);
+ props.put(ExternalCatalog.TEST_CONNECTION, "true");
+ TestMaxComputeExternalCatalog catalog = new
TestMaxComputeExternalCatalog(props);
+ catalog.threeTierModel = false;
+
+ DdlException exception = Assert.assertThrows(DdlException.class,
catalog::checkWhenCreating);
+
+ Assert.assertTrue(exception.getMessage().contains("Failed to validate
MaxCompute project 'mc_project'"));
+ Assert.assertTrue(exception.getMessage().contains("schema list is
accessible"));
+ }
+
+ private static Map<String, String> createRequiredProperties(boolean
enableNamespaceSchema) {
+ Map<String, String> props = new HashMap<>();
+ addRequiredProperties(props);
+ props.put(MCProperties.ENABLE_NAMESPACE_SCHEMA,
Boolean.toString(enableNamespaceSchema));
+ return props;
+ }
+
+ private static void addRequiredProperties(Map<String, String> props) {
+ props.put(MCProperties.PROJECT, "mc_project");
+ props.put(MCProperties.ENDPOINT,
"http://service.cn-beijing.maxcompute.aliyun-inc.com/api");
+ props.put(MCProperties.ACCESS_KEY, "access_key");
+ props.put(MCProperties.SECRET_KEY, "secret_key");
+ }
+
+ private static class TestMaxComputeExternalCatalog extends
MaxComputeExternalCatalog {
+ private boolean projectExists = true;
+ private boolean threeTierModel = true;
+ private String checkedProjectName;
+ private String checkedNamespaceSchemaProjectName;
+
+ private TestMaxComputeExternalCatalog(Map<String, String> props) {
+ super(1L, "mc_catalog", null, props, "");
+ }
+
+ @Override
+ protected boolean maxComputeProjectExists(String projectName) {
+ checkedProjectName = projectName;
+ return projectExists;
+ }
+
+ @Override
+ protected void validateMaxComputeNamespaceSchemaAccess(String
projectName) {
+ checkedNamespaceSchemaProjectName = projectName;
+ if (!threeTierModel) {
+ throw new RuntimeException("schema list is not accessible");
+ }
+ }
+ }
+}
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/datasource/maxcompute/source/MaxComputeScanNodeTest.java
b/fe/fe-core/src/test/java/org/apache/doris/datasource/maxcompute/source/MaxComputeScanNodeTest.java
new file mode 100644
index 00000000000..192bb301483
--- /dev/null
+++
b/fe/fe-core/src/test/java/org/apache/doris/datasource/maxcompute/source/MaxComputeScanNodeTest.java
@@ -0,0 +1,79 @@
+// 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.maxcompute.source;
+
+import org.apache.doris.analysis.TupleDescriptor;
+import org.apache.doris.analysis.TupleId;
+import org.apache.doris.common.UserException;
+import org.apache.doris.datasource.maxcompute.MaxComputeExternalTable;
+import
org.apache.doris.nereids.trees.plans.logical.LogicalFileScan.SelectedPartitions;
+import org.apache.doris.planner.PlanNodeId;
+import org.apache.doris.planner.ScanContext;
+import org.apache.doris.qe.SessionVariable;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class MaxComputeScanNodeTest {
+ @Mock
+ private MaxComputeExternalTable table;
+ @Mock
+ private com.aliyun.odps.Table odpsTable;
+ @Mock
+ private TupleDescriptor desc;
+
+ private MaxComputeScanNode node;
+
+ @Before
+ public void setUp() {
+ Mockito.when(table.getOdpsTable()).thenReturn(odpsTable);
+ Mockito.when(desc.getTable()).thenReturn(table);
+ Mockito.when(desc.getId()).thenReturn(new TupleId(0));
+ node = new MaxComputeScanNode(new PlanNodeId(0), desc,
+ SelectedPartitions.NOT_PRUNED, false, new SessionVariable(),
ScanContext.EMPTY);
+ }
+
+ @Test
+ public void testGetSplitsRejectsOdpsExternalTable() {
+ assertGetSplitsRejectsUnsupportedOdpsTable(true, false,
"mc_external_table");
+ }
+
+ @Test
+ public void testGetSplitsRejectsOdpsLogicalView() {
+ assertGetSplitsRejectsUnsupportedOdpsTable(false, true,
"mc_logical_view");
+ }
+
+ private void assertGetSplitsRejectsUnsupportedOdpsTable(boolean
isExternalTable, boolean isVirtualView,
+ String tableName) {
+ Mockito.when(odpsTable.isExternalTable()).thenReturn(isExternalTable);
+ Mockito.when(odpsTable.isVirtualView()).thenReturn(isVirtualView);
+ Mockito.when(table.getDbName()).thenReturn("default");
+ Mockito.when(table.getName()).thenReturn(tableName);
+
+ UserException exception = Assert.assertThrows(UserException.class, ()
-> node.getSplits(1));
+ Assert.assertTrue(exception.getMessage().contains(
+ "Reading MaxCompute external table or logical view is not
supported: default." + tableName));
+ Mockito.verify(odpsTable, Mockito.never()).getFileNum();
+ }
+}
diff --git a/fe/pom.xml b/fe/pom.xml
index 0d0dbc0bf81..e8dc5655cec 100644
--- a/fe/pom.xml
+++ b/fe/pom.xml
@@ -1389,7 +1389,7 @@ under the License.
</exclusions>
</dependency>
<dependency>
- <!-- This is a dependency chain: odps-sdk-core:0.53.2-public →
credentials-java:0.3.12 → com.aliyun:tea:[1.1.14,2.0.0)-->
+ <!-- Keep tea pinned for Alibaba SDK dependency chains that
allow com.aliyun:tea:[1.1.14,2.0.0). -->
<groupId>com.aliyun</groupId>
<artifactId>tea</artifactId>
<version>1.4.1</version>
diff --git
a/regression-test/suites/external_table_p2/maxcompute/test_external_catalog_maxcompute.groovy
b/regression-test/suites/external_table_p2/maxcompute/test_external_catalog_maxcompute.groovy
index 827ed963873..474abf4b8ea 100644
---
a/regression-test/suites/external_table_p2/maxcompute/test_external_catalog_maxcompute.groovy
+++
b/regression-test/suites/external_table_p2/maxcompute/test_external_catalog_maxcompute.groovy
@@ -341,7 +341,8 @@ suite("test_external_catalog_maxcompute",
"p2,external,maxcompute,external_remot
"mc.default.project" = "${mc_db}",
"mc.access_key" = "${ak}",
"mc.secret_key" = "${sk}",
- "mc.endpoint" =
"http://service.cn-beijing-vpc.maxcompute.aliyun-inc.com/api"
+ "mc.endpoint" =
"http://service.cn-beijing-vpc.maxcompute.aliyun-inc.com/api",
+ "test_connection" = "true"
);
"""
@@ -379,7 +380,8 @@ suite("test_external_catalog_maxcompute",
"p2,external,maxcompute,external_remot
"mc.default.project" = "${mc_db}",
"mc.access_key" = "${ak}",
"mc.secret_key" = "${sk}",
- "mc.endpoint" =
"http://service.cn-beijing-vpc.maxcompute.aliyun-inc.com/api"
+ "mc.endpoint" =
"http://service.cn-beijing-vpc.maxcompute.aliyun-inc.com/api",
+ "test_connection" = "true"
);
"""
sql """ switch `${mc_catalog_name}`; """
diff --git
a/regression-test/suites/external_table_p2/maxcompute/test_max_compute_schema.groovy
b/regression-test/suites/external_table_p2/maxcompute/test_max_compute_schema.groovy
index d317c43da21..19580a7df13 100644
---
a/regression-test/suites/external_table_p2/maxcompute/test_max_compute_schema.groovy
+++
b/regression-test/suites/external_table_p2/maxcompute/test_max_compute_schema.groovy
@@ -106,7 +106,8 @@ suite("test_max_compute_schema",
"p2,external,maxcompute,external_remote,externa
"mc.access_key" = "${ak}",
"mc.secret_key" = "${sk}",
"mc.endpoint" =
"http://service.cn-beijing-vpc.maxcompute.aliyun-inc.com/api",
- "mc.enable.namespace.schema" = "true"
+ "mc.enable.namespace.schema" = "true",
+ "test_connection" = "true"
);
"""
@@ -251,4 +252,4 @@ suite("test_max_compute_schema",
"p2,external,maxcompute,external_remote,externa
qt_mc_join_q34 """SELECT p.product_name, e.department, e.salary FROM
analytics.product_sales p JOIN iot.employee_salary e ON p.id=e.id ORDER BY
p.id;"""
qt_mc_join_q35 """SELECT o.order_id, p.product_name, e.emp_name FROM
`default`.order_detail o JOIN analytics.product_sales p ON o.id=p.id JOIN
iot.employee_salary e ON o.id=e.id WHERE o.ds1='202510' ORDER BY o.id;"""
}
-}
\ No newline at end of file
+}
diff --git
a/regression-test/suites/external_table_p2/maxcompute/test_max_compute_validate_connection.groovy
b/regression-test/suites/external_table_p2/maxcompute/test_max_compute_validate_connection.groovy
new file mode 100644
index 00000000000..d88e65a2340
--- /dev/null
+++
b/regression-test/suites/external_table_p2/maxcompute/test_max_compute_validate_connection.groovy
@@ -0,0 +1,102 @@
+// 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_max_compute_validate_connection", "p2,external") {
+ String enabled = context.config.otherConfigs.get("enableMaxComputeTest")
+ if (enabled == null || !enabled.equalsIgnoreCase("true")) {
+ logger.info("disable MaxCompute test.")
+ return
+ }
+
+ String ak = context.config.otherConfigs.get("ak")
+ String sk = context.config.otherConfigs.get("sk")
+ String defaultProject = "mc_datalake"
+ String invalidEndpoint = "http://127.0.0.1:1/api"
+ String catalogDefaultFalse = "test_mc_validate_default_false"
+ String catalogExplicitFalse = "test_mc_validate_explicit_false"
+ String catalogValidateProject = "test_mc_validate_project"
+ String catalogValidateSchema = "test_mc_validate_schema"
+
+ sql """drop catalog if exists ${catalogDefaultFalse}"""
+ sql """drop catalog if exists ${catalogExplicitFalse}"""
+ sql """drop catalog if exists ${catalogValidateProject}"""
+ sql """drop catalog if exists ${catalogValidateSchema}"""
+
+ sql """
+ create catalog ${catalogDefaultFalse} properties (
+ "type" = "max_compute",
+ "mc.default.project" = "${defaultProject}",
+ "mc.access_key" = "${ak}",
+ "mc.secret_key" = "${sk}",
+ "mc.endpoint" = "${invalidEndpoint}",
+ "mc.connect_timeout" = "1",
+ "mc.read_timeout" = "1",
+ "mc.retry_count" = "1"
+ );
+ """
+ sql """drop catalog if exists ${catalogDefaultFalse}"""
+
+ sql """
+ create catalog ${catalogExplicitFalse} properties (
+ "type" = "max_compute",
+ "mc.default.project" = "${defaultProject}",
+ "mc.access_key" = "${ak}",
+ "mc.secret_key" = "${sk}",
+ "mc.endpoint" = "${invalidEndpoint}",
+ "mc.connect_timeout" = "1",
+ "mc.read_timeout" = "1",
+ "mc.retry_count" = "1",
+ "test_connection" = "false"
+ );
+ """
+ sql """drop catalog if exists ${catalogExplicitFalse}"""
+
+ test {
+ sql """
+ create catalog ${catalogValidateProject} properties (
+ "type" = "max_compute",
+ "mc.default.project" = "${defaultProject}",
+ "mc.access_key" = "${ak}",
+ "mc.secret_key" = "${sk}",
+ "mc.endpoint" = "${invalidEndpoint}",
+ "mc.connect_timeout" = "1",
+ "mc.read_timeout" = "1",
+ "mc.retry_count" = "1",
+ "test_connection" = "true"
+ );
+ """
+ exception "Failed to validate MaxCompute project"
+ }
+
+ test {
+ sql """
+ create catalog ${catalogValidateSchema} properties (
+ "type" = "max_compute",
+ "mc.default.project" = "${defaultProject}",
+ "mc.access_key" = "${ak}",
+ "mc.secret_key" = "${sk}",
+ "mc.endpoint" = "${invalidEndpoint}",
+ "mc.connect_timeout" = "1",
+ "mc.read_timeout" = "1",
+ "mc.retry_count" = "1",
+ "mc.enable.namespace.schema" = "true",
+ "test_connection" = "true"
+ );
+ """
+ exception "with namespace schema"
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]