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

jackietien pushed a commit to branch force_ci/object_type
in repository https://gitbox.apache.org/repos/asf/iotdb.git

commit ec7d62751de65141daf4cab89d01e8dba3e994e4
Author: shuwenwei <[email protected]>
AuthorDate: Thu Nov 27 14:47:13 2025 +0800

    Add 'show available urls' (#16441)
    
    (cherry picked from commit c4114b95d94a127857706b45867d68c8a64712b3)
---
 .../org/apache/iotdb/db/it/auth/IoTDBAuthIT.java   |  2 +
 .../org/apache/iotdb/session/NodesSupplier.java    | 49 +++++++-------
 .../org/apache/iotdb/db/qp/sql/IdentifierParser.g4 |  2 +
 .../org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4   |  7 +-
 .../antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4  |  8 +++
 .../common/header/DatasetHeaderFactory.java        |  4 ++
 .../iotdb/db/queryengine/plan/Coordinator.java     |  2 +
 .../execution/config/TableConfigTaskVisitor.java   | 13 ++++
 .../execution/config/TreeConfigTaskVisitor.java    |  8 +++
 .../config/executor/ClusterConfigTaskExecutor.java | 21 ++++++
 .../config/executor/IConfigTaskExecutor.java       |  2 +
 .../config/metadata/ShowAvailableUrlsTask.java     | 74 ++++++++++++++++++++++
 .../db/queryengine/plan/parser/ASTVisitor.java     |  6 ++
 .../security/TreeAccessCheckVisitor.java           |  9 +++
 .../plan/relational/sql/ast/AstVisitor.java        |  4 ++
 .../plan/relational/sql/ast/ShowAvailableUrls.java | 61 ++++++++++++++++++
 .../plan/relational/sql/parser/AstBuilder.java     |  7 ++
 .../plan/statement/StatementVisitor.java           |  6 ++
 .../metadata/ShowAvailableUrlsStatement.java       | 43 +++++++++++++
 .../schema/column/ColumnHeaderConstant.java        |  5 ++
 .../db/relational/grammar/sql/RelationalSql.g4     | 11 +++-
 21 files changed, 316 insertions(+), 28 deletions(-)

diff --git 
a/integration-test/src/test/java/org/apache/iotdb/db/it/auth/IoTDBAuthIT.java 
b/integration-test/src/test/java/org/apache/iotdb/db/it/auth/IoTDBAuthIT.java
index bc77f5d3947..24204320f75 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/db/it/auth/IoTDBAuthIT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/db/it/auth/IoTDBAuthIT.java
@@ -54,6 +54,7 @@ import java.util.concurrent.Callable;
 import static org.apache.iotdb.commons.auth.entity.User.INTERNAL_USER_END_ID;
 import static org.apache.iotdb.db.audit.DNAuditLogger.PREFIX_PASSWORD_HISTORY;
 import static org.apache.iotdb.db.it.utils.TestUtils.createUser;
+import static org.apache.iotdb.db.it.utils.TestUtils.executeNonQuery;
 import static org.apache.iotdb.db.it.utils.TestUtils.resultSetEqualTest;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -1381,6 +1382,7 @@ public class IoTDBAuthIT {
           "tempuser,",
         };
     resultSetEqualTest("show current_user", expectedHeader, retArray, 
"tempuser", "temppw123456");
+    executeNonQuery("SHOW AVAILABLE URLS", "tempuser", "temppw123456");
   }
 
   @Ignore
diff --git 
a/iotdb-client/session/src/main/java/org/apache/iotdb/session/NodesSupplier.java
 
b/iotdb-client/session/src/main/java/org/apache/iotdb/session/NodesSupplier.java
index 9284171eade..aa28b9bc0c7 100644
--- 
a/iotdb-client/session/src/main/java/org/apache/iotdb/session/NodesSupplier.java
+++ 
b/iotdb-client/session/src/main/java/org/apache/iotdb/session/NodesSupplier.java
@@ -40,16 +40,12 @@ public class NodesSupplier implements INodeSupplier, 
Runnable {
   private static final Logger LOGGER = 
LoggerFactory.getLogger(NodesSupplier.class);
 
   private static final long UPDATE_PERIOD_IN_S = 60;
-  private static final String SHOW_DATA_NODES_COMMAND = "SHOW DATANODES";
-
-  private static final String STATUS_COLUMN_NAME = "Status";
+  private static final String SHOW_AVAILABLE_URLS_COMMAND = "SHOW AVAILABLE 
URLS";
 
   private static final String IP_COLUMN_NAME = "RpcAddress";
 
   private static final String PORT_COLUMN_NAME = "RpcPort";
 
-  private static final String REMOVING_STATUS = "Removing";
-
   // it's ok that TIMEOUT_IN_MS is larger than UPDATE_PERIOD_IN_S, because the 
next update request
   // won't be scheduled until last time is done.
   private static final long TIMEOUT_IN_MS = 60_000;
@@ -228,28 +224,31 @@ public class NodesSupplier implements INodeSupplier, 
Runnable {
 
   private boolean updateDataNodeList() {
     try (SessionDataSet sessionDataSet =
-        client.executeQueryStatement(SHOW_DATA_NODES_COMMAND, TIMEOUT_IN_MS, 
FETCH_SIZE)) {
-      SessionDataSet.DataIterator iterator = sessionDataSet.iterator();
-      List<TEndPoint> res = new ArrayList<>();
-      while (iterator.next()) {
-        String ip = iterator.getString(IP_COLUMN_NAME);
-        // ignore 0.0.0.0 and removing DN
-        if (!REMOVING_STATUS.equals(iterator.getString(STATUS_COLUMN_NAME))
-            && !"0.0.0.0".equals(ip)) {
-          String port = iterator.getString(PORT_COLUMN_NAME);
-          if (ip != null && port != null) {
-            res.add(new TEndPoint(ip, Integer.parseInt(port)));
-          }
-        }
-      }
-      // replace the older ones.
-      if (!res.isEmpty()) {
-        availableNodes = res;
-      }
-      return true;
-    } catch (Exception e) {
+        client.executeQueryStatement(SHOW_AVAILABLE_URLS_COMMAND, 
TIMEOUT_IN_MS, FETCH_SIZE)) {
+      updateAvailableNodes(sessionDataSet);
+    } catch (Exception e1) {
       LOGGER.warn("Failed to fetch data node list from {}.", client.endPoint);
       return false;
     }
+    return true;
+  }
+
+  private void updateAvailableNodes(SessionDataSet sessionDataSet) throws 
Exception {
+    SessionDataSet.DataIterator iterator = sessionDataSet.iterator();
+    List<TEndPoint> res = new ArrayList<>();
+    while (iterator.next()) {
+      String ip = iterator.getString(IP_COLUMN_NAME);
+      // ignore 0.0.0.0
+      if (!"0.0.0.0".equals(ip)) {
+        String port = iterator.getString(PORT_COLUMN_NAME);
+        if (ip != null && port != null) {
+          res.add(new TEndPoint(ip, Integer.parseInt(port)));
+        }
+      }
+    }
+    // replace the older ones.
+    if (!res.isEmpty()) {
+      availableNodes = res;
+    }
   }
 }
diff --git 
a/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IdentifierParser.g4
 
b/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IdentifierParser.g4
index 0cc5e6faf8b..4a01b352384 100644
--- 
a/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IdentifierParser.g4
+++ 
b/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IdentifierParser.g4
@@ -47,6 +47,7 @@ keyWords
     | AS
     | ASC
     | ATTRIBUTES
+    | AVAILABLE
     | BEFORE
     | BEGIN
     | BETWEEN
@@ -267,6 +268,7 @@ keyWords
     | UPDATE
     | UPSERT
     | URI
+    | URLS
     | USED
     | USER
     | USING
diff --git 
a/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4 
b/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
index 8a1a0f5468f..bd49f38ec3c 100644
--- 
a/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
+++ 
b/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
@@ -61,7 +61,7 @@ ddlStatement
     // CQ
     | createContinuousQuery | dropContinuousQuery | showContinuousQueries
     // Cluster
-    | showVariables | showCluster | showRegions | showDataNodes | 
showConfigNodes | showClusterId
+    | showVariables | showCluster | showRegions | showDataNodes | 
showAvailableUrls | showConfigNodes | showClusterId
     | getRegionId | getTimeSlotList | countTimeSlotList | getSeriesSlotList
     | migrateRegion | reconstructRegion | extendRegion | removeRegion  | 
removeDataNode | removeConfigNode | removeAINode
     | verifyConnection
@@ -491,6 +491,11 @@ showDataNodes
     : SHOW DATANODES
     ;
 
+// ---- Show Available Urls
+showAvailableUrls
+    : SHOW AVAILABLE URLS
+    ;
+
 // ---- Show Config Nodes
 showConfigNodes
     : SHOW CONFIGNODES
diff --git 
a/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4 
b/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4
index f63fd211149..5696d5da32a 100644
--- a/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4
+++ b/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4
@@ -254,6 +254,14 @@ DATANODES
     : D A T A N O D E S
     ;
 
+AVAILABLE
+    : A V A I L A B L E
+    ;
+
+URLS
+    : U R L S
+    ;
+
 DATASET
     : D A T A S E T
     ;
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/header/DatasetHeaderFactory.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/header/DatasetHeaderFactory.java
index a9e737ac06e..d7fd3e071c6 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/header/DatasetHeaderFactory.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/header/DatasetHeaderFactory.java
@@ -129,6 +129,10 @@ public class DatasetHeaderFactory {
     return new DatasetHeader(ColumnHeaderConstant.showDataNodesColumnHeaders, 
true);
   }
 
+  public static DatasetHeader getShowAvailableUrlsHeader() {
+    return new 
DatasetHeader(ColumnHeaderConstant.showAvailableUrlsColumnHeaders, true);
+  }
+
   public static DatasetHeader getShowConfigNodesHeader() {
     return new 
DatasetHeader(ColumnHeaderConstant.showConfigNodesColumnHeaders, true);
   }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/Coordinator.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/Coordinator.java
index c2f9639de8e..3a900b4bc12 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/Coordinator.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/Coordinator.java
@@ -94,6 +94,7 @@ import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.SetSystemStatus;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.SetTableComment;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowAIDevices;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowAINodes;
+import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowAvailableUrls;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowCluster;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowClusterId;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowConfigNodes;
@@ -432,6 +433,7 @@ public class Coordinator {
         || statement instanceof ShowCluster
         || statement instanceof ShowRegions
         || statement instanceof ShowDataNodes
+        || statement instanceof ShowAvailableUrls
         || statement instanceof ShowConfigNodes
         || statement instanceof ShowAINodes
         || statement instanceof Flush
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/TableConfigTaskVisitor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/TableConfigTaskVisitor.java
index 32b964ec584..417e65d4fe4 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/TableConfigTaskVisitor.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/TableConfigTaskVisitor.java
@@ -21,6 +21,7 @@ package org.apache.iotdb.db.queryengine.plan.execution.config;
 
 import org.apache.iotdb.common.rpc.thrift.Model;
 import org.apache.iotdb.common.rpc.thrift.TSStatus;
+import org.apache.iotdb.commons.audit.AuditLogOperation;
 import org.apache.iotdb.commons.audit.IAuditEntity;
 import org.apache.iotdb.commons.audit.UserEntity;
 import org.apache.iotdb.commons.auth.entity.PrivilegeType;
@@ -53,6 +54,7 @@ import 
org.apache.iotdb.db.queryengine.plan.execution.config.metadata.DropPipePl
 import 
org.apache.iotdb.db.queryengine.plan.execution.config.metadata.RemoveAINodeTask;
 import 
org.apache.iotdb.db.queryengine.plan.execution.config.metadata.RemoveConfigNodeTask;
 import 
org.apache.iotdb.db.queryengine.plan.execution.config.metadata.RemoveDataNodeTask;
+import 
org.apache.iotdb.db.queryengine.plan.execution.config.metadata.ShowAvailableUrlsTask;
 import 
org.apache.iotdb.db.queryengine.plan.execution.config.metadata.ShowClusterIdTask;
 import 
org.apache.iotdb.db.queryengine.plan.execution.config.metadata.ShowClusterTask;
 import 
org.apache.iotdb.db.queryengine.plan.execution.config.metadata.ShowFunctionsTask;
@@ -129,6 +131,7 @@ import 
org.apache.iotdb.db.queryengine.plan.relational.metadata.Metadata;
 import 
org.apache.iotdb.db.queryengine.plan.relational.metadata.QualifiedObjectName;
 import 
org.apache.iotdb.db.queryengine.plan.relational.metadata.fetcher.TableHeaderSchemaValidator;
 import org.apache.iotdb.db.queryengine.plan.relational.security.AccessControl;
+import 
org.apache.iotdb.db.queryengine.plan.relational.security.ITableAuthCheckerImpl;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.AddColumn;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.AlterDB;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.AlterPipe;
@@ -185,6 +188,7 @@ import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.SetSystemStatus;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.SetTableComment;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowAIDevices;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowAINodes;
+import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowAvailableUrls;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowCluster;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowClusterId;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowConfigNodes;
@@ -482,6 +486,15 @@ public class TableConfigTaskVisitor extends 
AstVisitor<IConfigTask, MPPQueryCont
     return new ShowDataNodesTask();
   }
 
+  @Override
+  protected IConfigTask visitShowAvailableUrls(
+      final ShowAvailableUrls showAvailableUrls, final MPPQueryContext 
context) {
+    context.setQueryType(QueryType.READ);
+    ITableAuthCheckerImpl.recordAuditLog(
+        context.setAuditLogOperation(AuditLogOperation.QUERY).setResult(true), 
() -> "");
+    return new ShowAvailableUrlsTask();
+  }
+
   @Override
   protected IConfigTask visitShowConfigNodes(
       final ShowConfigNodes showConfigNodesStatement, final MPPQueryContext 
context) {
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/TreeConfigTaskVisitor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/TreeConfigTaskVisitor.java
index 40724d4df15..cb4d05f1b99 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/TreeConfigTaskVisitor.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/TreeConfigTaskVisitor.java
@@ -52,6 +52,7 @@ import 
org.apache.iotdb.db.queryengine.plan.execution.config.metadata.RemoveConf
 import 
org.apache.iotdb.db.queryengine.plan.execution.config.metadata.RemoveDataNodeTask;
 import 
org.apache.iotdb.db.queryengine.plan.execution.config.metadata.SetTTLTask;
 import 
org.apache.iotdb.db.queryengine.plan.execution.config.metadata.ShowAINodesTask;
+import 
org.apache.iotdb.db.queryengine.plan.execution.config.metadata.ShowAvailableUrlsTask;
 import 
org.apache.iotdb.db.queryengine.plan.execution.config.metadata.ShowClusterDetailsTask;
 import 
org.apache.iotdb.db.queryengine.plan.execution.config.metadata.ShowClusterIdTask;
 import 
org.apache.iotdb.db.queryengine.plan.execution.config.metadata.ShowClusterTask;
@@ -143,6 +144,7 @@ import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.RemoveAINodeState
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.RemoveConfigNodeStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.RemoveDataNodeStatement;
 import org.apache.iotdb.db.queryengine.plan.statement.metadata.SetTTLStatement;
+import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowAvailableUrlsStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowClusterIdStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowClusterStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowConfigNodesStatement;
@@ -550,6 +552,12 @@ public class TreeConfigTaskVisitor extends 
StatementVisitor<IConfigTask, MPPQuer
     return new ShowDataNodesTask(showDataNodesStatement);
   }
 
+  @Override
+  public IConfigTask visitShowAvailableUrls(
+      ShowAvailableUrlsStatement showAvailableUrlsStatement, MPPQueryContext 
context) {
+    return new ShowAvailableUrlsTask();
+  }
+
   @Override
   public IConfigTask visitShowConfigNodes(
       ShowConfigNodesStatement showConfigNodesStatement, MPPQueryContext 
context) {
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/executor/ClusterConfigTaskExecutor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/executor/ClusterConfigTaskExecutor.java
index beba9896f0b..8292fd9d623 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/executor/ClusterConfigTaskExecutor.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/executor/ClusterConfigTaskExecutor.java
@@ -196,6 +196,7 @@ import 
org.apache.iotdb.db.queryengine.plan.execution.config.metadata.GetRegionI
 import 
org.apache.iotdb.db.queryengine.plan.execution.config.metadata.GetSeriesSlotListTask;
 import 
org.apache.iotdb.db.queryengine.plan.execution.config.metadata.GetTimeSlotListTask;
 import 
org.apache.iotdb.db.queryengine.plan.execution.config.metadata.ShowAINodesTask;
+import 
org.apache.iotdb.db.queryengine.plan.execution.config.metadata.ShowAvailableUrlsTask;
 import 
org.apache.iotdb.db.queryengine.plan.execution.config.metadata.ShowClusterDetailsTask;
 import 
org.apache.iotdb.db.queryengine.plan.execution.config.metadata.ShowClusterIdTask;
 import 
org.apache.iotdb.db.queryengine.plan.execution.config.metadata.ShowClusterTask;
@@ -1747,6 +1748,26 @@ public class ClusterConfigTaskExecutor implements 
IConfigTaskExecutor {
     return future;
   }
 
+  @Override
+  public SettableFuture<ConfigTaskResult> showAvailableUrls() {
+    final SettableFuture<ConfigTaskResult> future = SettableFuture.create();
+    TShowDataNodesResp showDataNodesResp = new TShowDataNodesResp();
+    try (final ConfigNodeClient client =
+        
CONFIG_NODE_CLIENT_MANAGER.borrowClient(ConfigNodeInfo.CONFIG_REGION_ID)) {
+      showDataNodesResp = client.showDataNodes();
+      if (showDataNodesResp.getStatus().getCode() != 
TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
+        future.setException(
+            new IoTDBException(
+                showDataNodesResp.getStatus().message, 
showDataNodesResp.getStatus().code));
+        return future;
+      }
+    } catch (final ClientManagerException | TException e) {
+      future.setException(e);
+    }
+    ShowAvailableUrlsTask.buildTsBlock(showDataNodesResp, future);
+    return future;
+  }
+
   @Override
   public SettableFuture<ConfigTaskResult> showConfigNodes() {
     final SettableFuture<ConfigTaskResult> future = SettableFuture.create();
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/executor/IConfigTaskExecutor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/executor/IConfigTaskExecutor.java
index 926fd37cf3a..85455756b05 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/executor/IConfigTaskExecutor.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/executor/IConfigTaskExecutor.java
@@ -183,6 +183,8 @@ public interface IConfigTaskExecutor {
 
   SettableFuture<ConfigTaskResult> showDataNodes();
 
+  SettableFuture<ConfigTaskResult> showAvailableUrls();
+
   SettableFuture<ConfigTaskResult> showConfigNodes();
 
   SettableFuture<ConfigTaskResult> showAINodes();
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/ShowAvailableUrlsTask.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/ShowAvailableUrlsTask.java
new file mode 100644
index 00000000000..6d957769b44
--- /dev/null
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/ShowAvailableUrlsTask.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.iotdb.db.queryengine.plan.execution.config.metadata;
+
+import org.apache.iotdb.commons.cluster.RegionStatus;
+import org.apache.iotdb.commons.schema.column.ColumnHeader;
+import org.apache.iotdb.commons.schema.column.ColumnHeaderConstant;
+import org.apache.iotdb.confignode.rpc.thrift.TDataNodeInfo;
+import org.apache.iotdb.confignode.rpc.thrift.TShowDataNodesResp;
+import org.apache.iotdb.db.queryengine.common.header.DatasetHeader;
+import org.apache.iotdb.db.queryengine.common.header.DatasetHeaderFactory;
+import org.apache.iotdb.db.queryengine.plan.execution.config.ConfigTaskResult;
+import org.apache.iotdb.db.queryengine.plan.execution.config.IConfigTask;
+import 
org.apache.iotdb.db.queryengine.plan.execution.config.executor.IConfigTaskExecutor;
+import org.apache.iotdb.rpc.TSStatusCode;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.SettableFuture;
+import org.apache.tsfile.enums.TSDataType;
+import org.apache.tsfile.read.common.block.TsBlockBuilder;
+import org.apache.tsfile.utils.BytesUtils;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class ShowAvailableUrlsTask implements IConfigTask {
+
+  @Override
+  public ListenableFuture<ConfigTaskResult> execute(IConfigTaskExecutor 
configTaskExecutor)
+      throws InterruptedException {
+    return configTaskExecutor.showAvailableUrls();
+  }
+
+  public static void buildTsBlock(
+      TShowDataNodesResp showDataNodesResp, SettableFuture<ConfigTaskResult> 
future) {
+    List<TSDataType> outputDataTypes =
+        ColumnHeaderConstant.showAvailableUrlsColumnHeaders.stream()
+            .map(ColumnHeader::getColumnType)
+            .collect(Collectors.toList());
+    TsBlockBuilder builder = new TsBlockBuilder(outputDataTypes);
+    if (showDataNodesResp.getDataNodesInfoList() != null) {
+      for (TDataNodeInfo dataNodeInfo : 
showDataNodesResp.getDataNodesInfoList()) {
+        String status = dataNodeInfo.getStatus();
+        if (RegionStatus.Removing.getStatus().equals(status)) {
+          continue;
+        }
+        builder.getTimeColumnBuilder().writeLong(0L);
+
+        
builder.getColumnBuilder(0).writeBinary(BytesUtils.valueOf(dataNodeInfo.getRpcAddresss()));
+        builder.getColumnBuilder(1).writeInt(dataNodeInfo.getRpcPort());
+        builder.declarePosition();
+      }
+    }
+    DatasetHeader datasetHeader = 
DatasetHeaderFactory.getShowAvailableUrlsHeader();
+    future.set(new ConfigTaskResult(TSStatusCode.SUCCESS_STATUS, 
builder.build(), datasetHeader));
+  }
+}
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/ASTVisitor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/ASTVisitor.java
index be30b4e1b37..7f3936af511 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/ASTVisitor.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/ASTVisitor.java
@@ -170,6 +170,7 @@ import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.RemoveAINodeState
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.RemoveConfigNodeStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.RemoveDataNodeStatement;
 import org.apache.iotdb.db.queryengine.plan.statement.metadata.SetTTLStatement;
+import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowAvailableUrlsStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowChildNodesStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowChildPathsStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowClusterIdStatement;
@@ -3781,6 +3782,11 @@ public class ASTVisitor extends 
IoTDBSqlParserBaseVisitor<Statement> {
     return new ShowDataNodesStatement();
   }
 
+  @Override
+  public Statement 
visitShowAvailableUrls(IoTDBSqlParser.ShowAvailableUrlsContext ctx) {
+    return new ShowAvailableUrlsStatement();
+  }
+
   // show confignodes
 
   @Override
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/TreeAccessCheckVisitor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/TreeAccessCheckVisitor.java
index aa8c4d0ed80..89daafccfbb 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/TreeAccessCheckVisitor.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/TreeAccessCheckVisitor.java
@@ -72,6 +72,7 @@ import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.RemoveAINodeState
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.RemoveConfigNodeStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.RemoveDataNodeStatement;
 import org.apache.iotdb.db.queryengine.plan.statement.metadata.SetTTLStatement;
+import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowAvailableUrlsStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowChildNodesStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowChildPathsStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowClusterIdStatement;
@@ -1661,6 +1662,14 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
     return checkGlobalAuth(context, PrivilegeType.MAINTAIN, () -> "");
   }
 
+  @Override
+  public TSStatus visitShowAvailableUrls(
+      ShowAvailableUrlsStatement showAvailableUrlsStatement, 
TreeAccessCheckContext context) {
+    recordObjectAuthenticationAuditLog(
+        context.setAuditLogOperation(AuditLogOperation.QUERY).setResult(true), 
() -> "");
+    return SUCCEED;
+  }
+
   @Override
   public TSStatus visitShowConfigNodes(
       ShowConfigNodesStatement statement, TreeAccessCheckContext context) {
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/AstVisitor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/AstVisitor.java
index 5b43b467a36..54802a1d2f6 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/AstVisitor.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/AstVisitor.java
@@ -393,6 +393,10 @@ public abstract class AstVisitor<R, C> {
     return visitStatement(node, context);
   }
 
+  protected R visitShowAvailableUrls(ShowAvailableUrls node, C context) {
+    return visitStatement(node, context);
+  }
+
   protected R visitShowConfigNodes(ShowConfigNodes node, C context) {
     return visitStatement(node, context);
   }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/ShowAvailableUrls.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/ShowAvailableUrls.java
new file mode 100644
index 00000000000..2117cdfdac2
--- /dev/null
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/ShowAvailableUrls.java
@@ -0,0 +1,61 @@
+/*
+ * 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.iotdb.db.queryengine.plan.relational.sql.ast;
+
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+public class ShowAvailableUrls extends Statement {
+
+  public ShowAvailableUrls() {
+    super(null);
+  }
+
+  @Override
+  public <R, C> R accept(AstVisitor<R, C> visitor, C context) {
+    return visitor.visitShowAvailableUrls(this, context);
+  }
+
+  @Override
+  public List<Node> getChildren() {
+    return ImmutableList.of();
+  }
+
+  @Override
+  public int hashCode() {
+    return 0;
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    if (this == obj) {
+      return true;
+    }
+    return (obj != null) && (getClass() == obj.getClass());
+  }
+
+  @Override
+  public String toString() {
+    return toStringHelper(this).toString();
+  }
+}
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/parser/AstBuilder.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/parser/AstBuilder.java
index 76107bfa30e..f62b45d8b8a 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/parser/AstBuilder.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/parser/AstBuilder.java
@@ -176,6 +176,7 @@ import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.SetSystemStatus;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.SetTableComment;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowAIDevices;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowAINodes;
+import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowAvailableUrls;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowCluster;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowClusterId;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowConfigNodes;
@@ -1384,6 +1385,12 @@ public class AstBuilder extends 
RelationalSqlBaseVisitor<Node> {
     return new ShowDataNodes();
   }
 
+  @Override
+  public Node visitShowAvailableUrlsStatement(
+      RelationalSqlParser.ShowAvailableUrlsStatementContext ctx) {
+    return new ShowAvailableUrls();
+  }
+
   @Override
   public Node visitShowConfigNodesStatement(
       RelationalSqlParser.ShowConfigNodesStatementContext ctx) {
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/StatementVisitor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/StatementVisitor.java
index 3f8bb158c09..eb38d9ba390 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/StatementVisitor.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/StatementVisitor.java
@@ -61,6 +61,7 @@ import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.RemoveAINodeState
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.RemoveConfigNodeStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.RemoveDataNodeStatement;
 import org.apache.iotdb.db.queryengine.plan.statement.metadata.SetTTLStatement;
+import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowAvailableUrlsStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowChildNodesStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowChildPathsStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowClusterIdStatement;
@@ -506,6 +507,11 @@ public abstract class StatementVisitor<R, C> {
     return visitStatement(showDataNodesStatement, context);
   }
 
+  public R visitShowAvailableUrls(
+      ShowAvailableUrlsStatement showAvailableUrlsStatement, C context) {
+    return visitStatement(showAvailableUrlsStatement, context);
+  }
+
   public R visitShowConfigNodes(ShowConfigNodesStatement 
showConfigNodesStatement, C context) {
     return visitStatement(showConfigNodesStatement, context);
   }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/ShowAvailableUrlsStatement.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/ShowAvailableUrlsStatement.java
new file mode 100644
index 00000000000..5427a3200ea
--- /dev/null
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/ShowAvailableUrlsStatement.java
@@ -0,0 +1,43 @@
+/*
+ * 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.iotdb.db.queryengine.plan.statement.metadata;
+
+import org.apache.iotdb.db.queryengine.plan.analyze.QueryType;
+import org.apache.iotdb.db.queryengine.plan.statement.IConfigStatement;
+import org.apache.iotdb.db.queryengine.plan.statement.StatementType;
+import org.apache.iotdb.db.queryengine.plan.statement.StatementVisitor;
+
+public class ShowAvailableUrlsStatement extends ShowStatement implements 
IConfigStatement {
+
+  public ShowAvailableUrlsStatement() {
+    super();
+    this.statementType = StatementType.SHOW;
+  }
+
+  @Override
+  public QueryType getQueryType() {
+    return QueryType.READ;
+  }
+
+  @Override
+  public <R, C> R accept(StatementVisitor<R, C> visitor, C context) {
+    return visitor.visitShowAvailableUrls(this, context);
+  }
+}
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/column/ColumnHeaderConstant.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/column/ColumnHeaderConstant.java
index 30997db31e1..4f78ad9d5ea 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/column/ColumnHeaderConstant.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/column/ColumnHeaderConstant.java
@@ -461,6 +461,11 @@ public class ColumnHeaderConstant {
           new ColumnHeader(DATA_REGION_NUM, TSDataType.INT32),
           new ColumnHeader(SCHEMA_REGION_NUM, TSDataType.INT32));
 
+  public static final List<ColumnHeader> showAvailableUrlsColumnHeaders =
+      ImmutableList.of(
+          new ColumnHeader(RPC_ADDRESS, TSDataType.TEXT),
+          new ColumnHeader(RPC_PORT, TSDataType.INT32));
+
   public static final List<ColumnHeader> showConfigNodesColumnHeaders =
       ImmutableList.of(
           new ColumnHeader(NODE_ID, TSDataType.INT32),
diff --git 
a/iotdb-core/relational-grammar/src/main/antlr4/org/apache/iotdb/db/relational/grammar/sql/RelationalSql.g4
 
b/iotdb-core/relational-grammar/src/main/antlr4/org/apache/iotdb/db/relational/grammar/sql/RelationalSql.g4
index 7357196219f..4bd8a2b0bd7 100644
--- 
a/iotdb-core/relational-grammar/src/main/antlr4/org/apache/iotdb/db/relational/grammar/sql/RelationalSql.g4
+++ 
b/iotdb-core/relational-grammar/src/main/antlr4/org/apache/iotdb/db/relational/grammar/sql/RelationalSql.g4
@@ -113,6 +113,7 @@ statement
     | showClusterStatement
     | showRegionsStatement
     | showDataNodesStatement
+    | showAvailableUrlsStatement
     | showConfigNodesStatement
     | showAINodesStatement
     | showClusterIdStatement
@@ -547,6 +548,10 @@ showDataNodesStatement
     : SHOW DATANODES
     ;
 
+showAvailableUrlsStatement
+    : SHOW AVAILABLE URLS
+    ;
+
 showConfigNodesStatement
     : SHOW CONFIGNODES
     ;
@@ -1394,7 +1399,7 @@ authorizationUser
 
 nonReserved
     // IMPORTANT: this rule must only contain tokens. Nested rules are not 
supported. See SqlParser.exitNonReserved
-    : ABSENT | ADD | ADMIN | AFTER | ALL | ANALYZE | ANY | ARRAY | ASC | AT | 
ATTRIBUTE | AUDIT | AUTHORIZATION
+    : ABSENT | ADD | ADMIN | AFTER | ALL | ANALYZE | ANY | ARRAY | ASC | AT | 
ATTRIBUTE | AUDIT | AUTHORIZATION | AVAILABLE
     | BEGIN | BERNOULLI | BOTH
     | CACHE | CALL | CALLED | CASCADE | CATALOG | CATALOGS | CHAR | CHARACTER 
| CHARSET | CLEAR | CLUSTER | CLUSTERID | COLUMN | COLUMNS | COMMENT | COMMIT | 
COMMITTED | CONDITION | CONDITIONAL | CONFIGNODES | CONFIGNODE | CONFIGURATION 
| CONNECTOR | CONSTANT | COPARTITION | COUNT | CURRENT
     | DATA | DATABASE | DATABASES | DATANODE | DATANODES | DATASET | DATE | 
DAY | DECLARE | DEFAULT | DEFINE | DEFINER | DENY | DESC | DESCRIPTOR | 
DETAILS| DETERMINISTIC | DEVICES | DISTRIBUTED | DO | DOUBLE
@@ -1415,7 +1420,7 @@ nonReserved
     | SERIESSLOTID | SCALAR | SCHEMA | SCHEMAS | SECOND | SECURITY | SEEK | 
SERIALIZABLE | SESSION | SET | SETS
     | SECURITY | SHOW | SINK | SOME | SOURCE | START | STATS | STOP | 
SUBSCRIPTION | SUBSCRIPTIONS | SUBSET | SUBSTRING | SYSTEM
     | TABLES | TABLESAMPLE | TAG | TEXT | TEXT_STRING | TIES | TIME | 
TIMEPARTITION | TIMER | TIMER_XL | TIMESERIES | TIMESLOTID | TIMESTAMP | TO | 
TOPIC | TOPICS | TRAILING | TRANSACTION | TRUNCATE | TRY_CAST | TYPE
-    | UNBOUNDED | UNCOMMITTED | UNCONDITIONAL | UNIQUE | UNKNOWN | UNMATCHED | 
UNTIL | UPDATE | URI | USE | USED | USER | UTF16 | UTF32 | UTF8
+    | UNBOUNDED | UNCOMMITTED | UNCONDITIONAL | UNIQUE | UNKNOWN | UNMATCHED | 
UNTIL | UPDATE | URI | URLS | USE | USED | USER | UTF16 | UTF32 | UTF8
     | VALIDATE | VALUE | VARIABLES | VARIATION | VERBOSE | VERSION | VIEW
     | WEEK | WHILE | WINDOW | WITHIN | WITHOUT | WORK | WRAPPER | WRITE
     | YEAR
@@ -1496,6 +1501,8 @@ DATABASE: 'DATABASE';
 DATABASES: 'DATABASES';
 DATANODE: 'DATANODE';
 DATANODES: 'DATANODES';
+AVAILABLE: 'AVAILABLE';
+URLS: 'URLS';
 DATASET: 'DATASET';
 DATE: 'DATE';
 DATE_BIN: 'DATE_BIN';


Reply via email to