You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iotdb.apache.org by ju...@apache.org on 2026/05/18 04:27:49 UTC

(iotdb) branch count-db created (now 14d2d0b7455)

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

Caideyipi pushed a change to branch count-db
in repository https://gitbox.apache.org/repos/asf/iotdb.git


      at 14d2d0b7455 fix

This branch includes the following new commits:

     new 148250ece42 count database
     new 14d2d0b7455 fix

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



(iotdb) 01/02: count database

Posted by ju...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

Caideyipi pushed a commit to branch count-db
in repository https://gitbox.apache.org/repos/asf/iotdb.git

commit 148250ece420ae679fb49b80ab313a23c01cb41e
Author: Caideyipi <87...@users.noreply.github.com>
AuthorDate: Mon May 18 11:24:42 2026 +0800

    count database
---
 .../relational/it/schema/IoTDBDatabaseIT.java      | 35 ++++++++++
 .../iotdb/db/queryengine/plan/Coordinator.java     |  2 +
 .../execution/config/TableConfigTaskVisitor.java   | 11 +++
 .../config/executor/ClusterConfigTaskExecutor.java | 20 ++++++
 .../config/executor/IConfigTaskExecutor.java       |  4 ++
 .../config/metadata/relational/CountDBTask.java    | 78 ++++++++++++++++++++++
 .../plan/relational/sql/ast/AstVisitor.java        |  4 ++
 .../plan/relational/sql/ast/CountDB.java           | 77 +++++++++++++++++++++
 .../plan/relational/sql/parser/AstBuilder.java     |  7 ++
 .../relational/sql/util/DataNodeSqlFormatter.java  |  9 ++-
 .../db/relational/grammar/sql/RelationalSql.g4     |  5 ++
 11 files changed, 251 insertions(+), 1 deletion(-)

diff --git a/integration-test/src/test/java/org/apache/iotdb/relational/it/schema/IoTDBDatabaseIT.java b/integration-test/src/test/java/org/apache/iotdb/relational/it/schema/IoTDBDatabaseIT.java
index 2b367b70b22..d52036ba75b 100644
--- a/integration-test/src/test/java/org/apache/iotdb/relational/it/schema/IoTDBDatabaseIT.java
+++ b/integration-test/src/test/java/org/apache/iotdb/relational/it/schema/IoTDBDatabaseIT.java
@@ -825,6 +825,29 @@ public class IoTDBDatabaseIT {
     }
   }
 
+  @Test
+  public void testCountDatabases() throws SQLException {
+    try (final Connection connection =
+            EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
+        final Statement statement = connection.createStatement()) {
+      statement.execute("create database db1");
+      statement.execute("create database db2");
+
+      TestUtils.assertResultSetEqual(
+          statement.executeQuery("count databases"),
+          "count,",
+          Collections.singleton("3,"));
+      TestUtils.assertResultSetEqual(
+          statement.executeQuery("count database"),
+          "count,",
+          Collections.singleton("3,"));
+      TestUtils.assertResultSetEqual(
+          statement.executeQuery("select count(*) from information_schema.databases"),
+          "_col0,",
+          Collections.singleton("3,"));
+    }
+  }
+
   @Test
   public void testDBAuth() throws SQLException {
     try (final Connection adminCon = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
@@ -838,6 +861,14 @@ public class IoTDBDatabaseIT {
     try (final Connection userCon =
             EnvFactory.getEnv().getConnection("test", "password123456", BaseEnv.TABLE_SQL_DIALECT);
         final Statement userStmt = userCon.createStatement()) {
+      TestUtils.assertResultSetEqual(
+          userStmt.executeQuery("count databases"),
+          "count,",
+          Collections.singleton("1,"));
+      TestUtils.assertResultSetEqual(
+          userStmt.executeQuery("count database"),
+          "count,",
+          Collections.singleton("1,"));
       TestUtils.assertResultSetEqual(
           userStmt.executeQuery("show databases"),
           "Database,TTL(ms),SchemaReplicationFactor,DataReplicationFactor,TimePartitionInterval,",
@@ -869,6 +900,10 @@ public class IoTDBDatabaseIT {
     try (final Connection userCon =
             EnvFactory.getEnv().getConnection("test", "password123456", BaseEnv.TABLE_SQL_DIALECT);
         final Statement userStmt = userCon.createStatement()) {
+      TestUtils.assertResultSetEqual(
+          userStmt.executeQuery("count databases"),
+          "count,",
+          Collections.singleton("2,"));
       try (final ResultSet resultSet = userStmt.executeQuery("SHOW DATABASES")) {
         final ResultSetMetaData metaData = resultSet.getMetaData();
         assertEquals(showDBColumnHeaders.size(), metaData.getColumnCount());
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 d2e76b218b1..bd1512aa428 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
@@ -78,6 +78,7 @@ import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.AddColumn;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.AlterColumnDataType;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.AlterDB;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ClearCache;
+import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.CountDB;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.CreateDB;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.CreateExternalService;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.CreateFunction;
@@ -610,6 +611,7 @@ public class Coordinator {
     queryContext.setTimeOut(timeOut);
     queryContext.setStartTime(startTime);
     if (statement instanceof DropDB
+        || statement instanceof CountDB
         || statement instanceof ShowDB
         || statement instanceof CreateDB
         || statement instanceof AlterDB
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 e07bc920313..827590e86a0 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
@@ -99,6 +99,7 @@ import org.apache.iotdb.db.queryengine.plan.execution.config.metadata.relational
 import org.apache.iotdb.db.queryengine.plan.execution.config.metadata.relational.AlterTableRenameTableTask;
 import org.apache.iotdb.db.queryengine.plan.execution.config.metadata.relational.AlterTableSetPropertiesTask;
 import org.apache.iotdb.db.queryengine.plan.execution.config.metadata.relational.ClearCacheTask;
+import org.apache.iotdb.db.queryengine.plan.execution.config.metadata.relational.CountDBTask;
 import org.apache.iotdb.db.queryengine.plan.execution.config.metadata.relational.CreateDBTask;
 import org.apache.iotdb.db.queryengine.plan.execution.config.metadata.relational.CreateTableTask;
 import org.apache.iotdb.db.queryengine.plan.execution.config.metadata.relational.CreateTableViewTask;
@@ -156,6 +157,7 @@ import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.AlterPipe;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.AstVisitor;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ClearCache;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ColumnDefinition;
+import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.CountDB;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.CreateDB;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.CreateExternalService;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.CreateFunction;
@@ -424,6 +426,15 @@ public class TableConfigTaskVisitor implements AstVisitor<IConfigTask, MPPQueryC
             canShowDB(accessControl, context.getSession().getUserName(), databaseName, context));
   }
 
+  @Override
+  public IConfigTask visitCountDB(final CountDB node, final MPPQueryContext context) {
+    context.setQueryType(QueryType.READ);
+    return new CountDBTask(
+        node,
+        databaseName ->
+            canShowDB(accessControl, context.getSession().getUserName(), databaseName, context));
+  }
+
   public static boolean canShowDB(
       final AccessControl accessControl,
       final String userName,
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 3f632c9a987..ae4168eb132 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
@@ -229,6 +229,7 @@ import org.apache.iotdb.db.queryengine.plan.execution.config.metadata.region.Ext
 import org.apache.iotdb.db.queryengine.plan.execution.config.metadata.region.MigrateRegionTask;
 import org.apache.iotdb.db.queryengine.plan.execution.config.metadata.region.ReconstructRegionTask;
 import org.apache.iotdb.db.queryengine.plan.execution.config.metadata.region.RemoveRegionTask;
+import org.apache.iotdb.db.queryengine.plan.execution.config.metadata.relational.CountDBTask;
 import org.apache.iotdb.db.queryengine.plan.execution.config.metadata.relational.DeleteDeviceTask;
 import org.apache.iotdb.db.queryengine.plan.execution.config.metadata.relational.DescribeTableDetailsTask;
 import org.apache.iotdb.db.queryengine.plan.execution.config.metadata.relational.DescribeTableTask;
@@ -255,6 +256,7 @@ import org.apache.iotdb.db.queryengine.plan.execution.config.sys.subscription.Sh
 import org.apache.iotdb.db.queryengine.plan.expression.Expression;
 import org.apache.iotdb.db.queryengine.plan.expression.visitor.TransformToViewExpressionVisitor;
 import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metadata.write.view.AlterLogicalViewNode;
+import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.CountDB;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.DeleteDevice;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.DropDB;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowCluster;
@@ -4140,6 +4142,24 @@ public class ClusterConfigTaskExecutor implements IConfigTaskExecutor {
     return future;
   }
 
+  @Override
+  public SettableFuture<ConfigTaskResult> countDatabases(
+      final CountDB countDB, final Predicate<String> canSeenDB) {
+    final SettableFuture<ConfigTaskResult> future = SettableFuture.create();
+    final List<String> databasePathPattern = Arrays.asList(ALL_RESULT_NODES);
+    try (final ConfigNodeClient client =
+        CONFIG_NODE_CLIENT_MANAGER.borrowClient(ConfigNodeInfo.CONFIG_REGION_ID)) {
+      final TGetDatabaseReq req =
+          new TGetDatabaseReq(databasePathPattern, ALL_MATCH_SCOPE.serialize())
+              .setIsTableModel(true);
+      final TShowDatabaseResp resp = client.showDatabase(req);
+      CountDBTask.buildTSBlock(resp.getDatabaseInfoMap(), future, canSeenDB);
+    } catch (final IOException | ClientManagerException | TException e) {
+      future.setException(e);
+    }
+    return future;
+  }
+
   @Override
   public SettableFuture<ConfigTaskResult> showCluster(final ShowCluster showCluster) {
     // As the implementation is identical, we'll simply translate to the
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 b4b928ba0b6..42caa6cd92e 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
@@ -41,6 +41,7 @@ import org.apache.iotdb.db.queryengine.plan.execution.config.metadata.region.Mig
 import org.apache.iotdb.db.queryengine.plan.execution.config.metadata.region.ReconstructRegionTask;
 import org.apache.iotdb.db.queryengine.plan.execution.config.metadata.region.RemoveRegionTask;
 import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metadata.write.view.AlterLogicalViewNode;
+import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.CountDB;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.DeleteDevice;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.DropDB;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowCluster;
@@ -333,6 +334,9 @@ public interface IConfigTaskExecutor {
   SettableFuture<ConfigTaskResult> showDatabases(
       final ShowDB showDB, final Predicate<String> canSeenDB);
 
+  SettableFuture<ConfigTaskResult> countDatabases(
+      final CountDB countDB, final Predicate<String> canSeenDB);
+
   SettableFuture<ConfigTaskResult> showCluster(ShowCluster showCluster);
 
   SettableFuture<ConfigTaskResult> useDatabase(final Use useDB, final IClientSession clientSession);
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/relational/CountDBTask.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/relational/CountDBTask.java
new file mode 100644
index 00000000000..0b6e2864e2e
--- /dev/null
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/relational/CountDBTask.java
@@ -0,0 +1,78 @@
+/*
+ * 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.relational;
+
+import org.apache.iotdb.commons.conf.IoTDBConstant;
+import org.apache.iotdb.commons.schema.column.ColumnHeader;
+import org.apache.iotdb.db.queryengine.common.header.DatasetHeader;
+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.db.queryengine.plan.relational.sql.ast.CountDB;
+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 java.util.Collections;
+import java.util.Map;
+import java.util.function.Predicate;
+
+import static org.apache.iotdb.commons.schema.table.InformationSchema.INFORMATION_DATABASE;
+
+public class CountDBTask implements IConfigTask {
+
+  private final CountDB node;
+  private final Predicate<String> canSeenDB;
+
+  public CountDBTask(final CountDB node, final Predicate<String> canSeenDB) {
+    this.node = node;
+    this.canSeenDB = canSeenDB;
+  }
+
+  @Override
+  public ListenableFuture<ConfigTaskResult> execute(final IConfigTaskExecutor configTaskExecutor)
+      throws InterruptedException {
+    return configTaskExecutor.countDatabases(node, canSeenDB);
+  }
+
+  public static void buildTSBlock(
+      final Map<String, ?> databaseInfoMap,
+      final SettableFuture<ConfigTaskResult> future,
+      final Predicate<String> canSeenDB) {
+    final long databaseCount =
+        databaseInfoMap.keySet().stream().filter(canSeenDB::test).count()
+            + (canSeenDB.test(INFORMATION_DATABASE) ? 1 : 0);
+
+    final TsBlockBuilder builder = new TsBlockBuilder(Collections.singletonList(TSDataType.INT32));
+    builder.getTimeColumnBuilder().writeLong(0L);
+    builder.getColumnBuilder(0).writeInt((int) databaseCount);
+    builder.declarePosition();
+
+    final DatasetHeader datasetHeader =
+        new DatasetHeader(
+            Collections.singletonList(
+                new ColumnHeader(IoTDBConstant.COLUMN_COUNT, TSDataType.INT32)),
+            true);
+    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/relational/sql/ast/AstVisitor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/AstVisitor.java
index 2e236e116e8..7c311fa7f62 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
@@ -79,6 +79,10 @@ public interface AstVisitor<R, C> extends CommonQueryAstVisitor<R, C> {
     return visitStatement(node, context);
   }
 
+  default R visitCountDB(final CountDB node, final C context) {
+    return visitStatement(node, context);
+  }
+
   default R visitCreateTable(final CreateTable node, final C context) {
     return visitStatement(node, context);
   }
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/CountDB.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/CountDB.java
new file mode 100644
index 00000000000..49f113421b2
--- /dev/null
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/CountDB.java
@@ -0,0 +1,77 @@
+/*
+ * 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 org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.AstMemoryEstimationHelper;
+import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.IAstVisitor;
+import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.Node;
+import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.NodeLocation;
+import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.Statement;
+
+import com.google.common.collect.ImmutableList;
+import org.apache.tsfile.utils.RamUsageEstimator;
+
+import java.util.List;
+
+import static java.util.Objects.requireNonNull;
+
+public class CountDB extends Statement {
+
+  private static final long INSTANCE_SIZE = RamUsageEstimator.shallowSizeOfInstance(CountDB.class);
+
+  public CountDB(final NodeLocation location) {
+    super(requireNonNull(location, "location is null"));
+  }
+
+  @Override
+  public <R, C> R accept(final IAstVisitor<R, C> visitor, final C context) {
+    return ((AstVisitor<R, C>) visitor).visitCountDB(this, context);
+  }
+
+  @Override
+  public List<Node> getChildren() {
+    return ImmutableList.of();
+  }
+
+  @Override
+  public int hashCode() {
+    return getClass().hashCode();
+  }
+
+  @Override
+  public boolean equals(final Object obj) {
+    if (this == obj) {
+      return true;
+    }
+    return (obj != null) && (getClass() == obj.getClass());
+  }
+
+  @Override
+  public String toString() {
+    return "COUNT DATABASES";
+  }
+
+  @Override
+  public long ramBytesUsed() {
+    long size = INSTANCE_SIZE;
+    size += AstMemoryEstimationHelper.getEstimatedSizeOfNodeLocation(getLocationInternal());
+    return size;
+  }
+}
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 768a05689e8..25d68eba6be 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
@@ -162,6 +162,7 @@ import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.AsofJoinOn;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ClearCache;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ColumnDefinition;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.CopyTo;
+import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.CountDB;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.CountDevice;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.CountStatement;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.CreateDB;
@@ -406,6 +407,12 @@ public class AstBuilder extends RelationalSqlBaseVisitor<Node> {
     return new ShowDB(getLocation(ctx), Objects.nonNull(ctx.DETAILS()));
   }
 
+  @Override
+  public Node visitCountDatabasesStatement(
+      final RelationalSqlParser.CountDatabasesStatementContext ctx) {
+    return new CountDB(getLocation(ctx));
+  }
+
   @Override
   public Node visitCreateDbStatement(final RelationalSqlParser.CreateDbStatementContext ctx) {
     List<Property> properties = ImmutableList.of();
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/util/DataNodeSqlFormatter.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/util/DataNodeSqlFormatter.java
index 4797d43cf21..b806fd72592 100644
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/util/DataNodeSqlFormatter.java
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/util/DataNodeSqlFormatter.java
@@ -32,6 +32,7 @@ import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.AlterPipe;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.AstVisitor;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ColumnDefinition;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.CopyTo;
+import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.CountDB;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.CreateDB;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.CreateFunction;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.CreatePipe;
@@ -134,7 +135,13 @@ public final class DataNodeSqlFormatter extends CommonQuerySqlFormatter
 
   @Override
   public Void visitShowDB(ShowDB node, Integer indent) {
-    builder.append("SHOW DATABASE");
+    builder.append("SHOW DATABASES");
+    return null;
+  }
+
+  @Override
+  public Void visitCountDB(CountDB node, Integer indent) {
+    builder.append("COUNT DATABASES");
     return null;
   }
 
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 ca766464686..9263323b8f6 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
@@ -49,6 +49,7 @@ statement
     // Database Statement
     | useDatabaseStatement
     | showDatabasesStatement
+    | countDatabasesStatement
     | createDbStatement
     | alterDbStatement
     | dropDbStatement
@@ -203,6 +204,10 @@ showDatabasesStatement
     : SHOW DATABASES (DETAILS)?
     ;
 
+countDatabasesStatement
+    : COUNT (DATABASE | DATABASES)
+    ;
+
 createDbStatement
     : CREATE DATABASE (IF NOT EXISTS)? database=identifier (WITH properties)?
     ;


(iotdb) 02/02: fix

Posted by ju...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

Caideyipi pushed a commit to branch count-db
in repository https://gitbox.apache.org/repos/asf/iotdb.git

commit 14d2d0b74553665e40ec2a6ba1e5c2b251f99159
Author: Caideyipi <87...@users.noreply.github.com>
AuthorDate: Mon May 18 12:27:29 2026 +0800

    fix
---
 .../config/metadata/relational/CountDBTask.java    |   6 +-
 .../metadata/relational/CountDBTaskTest.java       | 107 +++++++++++++++++++++
 .../sql/parser/CountDBStatementTest.java           |  66 +++++++++++++
 3 files changed, 178 insertions(+), 1 deletion(-)

diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/relational/CountDBTask.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/relational/CountDBTask.java
index 0b6e2864e2e..293d216856c 100644
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/relational/CountDBTask.java
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/relational/CountDBTask.java
@@ -59,8 +59,12 @@ public class CountDBTask implements IConfigTask {
       final Map<String, ?> databaseInfoMap,
       final SettableFuture<ConfigTaskResult> future,
       final Predicate<String> canSeenDB) {
+    // information_schema is synthesized in table model rather than returned from ConfigNode.
     final long databaseCount =
-        databaseInfoMap.keySet().stream().filter(canSeenDB::test).count()
+        databaseInfoMap.keySet().stream()
+                .filter(databaseName -> !INFORMATION_DATABASE.equals(databaseName))
+                .filter(canSeenDB::test)
+                .count()
             + (canSeenDB.test(INFORMATION_DATABASE) ? 1 : 0);
 
     final TsBlockBuilder builder = new TsBlockBuilder(Collections.singletonList(TSDataType.INT32));
diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/relational/CountDBTaskTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/relational/CountDBTaskTest.java
new file mode 100644
index 00000000000..b29c11c2a91
--- /dev/null
+++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/relational/CountDBTaskTest.java
@@ -0,0 +1,107 @@
+/*
+ * 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.relational;
+
+import org.apache.iotdb.commons.conf.IoTDBConstant;
+import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.NodeLocation;
+import org.apache.iotdb.db.queryengine.plan.execution.config.ConfigTaskResult;
+import org.apache.iotdb.db.queryengine.plan.execution.config.executor.IConfigTaskExecutor;
+import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.CountDB;
+import org.apache.iotdb.rpc.TSStatusCode;
+
+import com.google.common.util.concurrent.SettableFuture;
+import org.apache.tsfile.read.common.block.TsBlock;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.Predicate;
+
+import static org.apache.iotdb.commons.schema.table.InformationSchema.INFORMATION_DATABASE;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+import static org.mockito.ArgumentMatchers.same;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class CountDBTaskTest {
+
+  @Test
+  public void testBuildTSBlockCountsVisibleDatabases() throws Exception {
+    final Map<String, Object> databaseInfoMap = new HashMap<>();
+    databaseInfoMap.put("db1", new Object());
+    databaseInfoMap.put("db2", new Object());
+
+    final SettableFuture<ConfigTaskResult> future = SettableFuture.create();
+    CountDBTask.buildTSBlock(databaseInfoMap, future, databaseName -> !"db2".equals(databaseName));
+
+    final ConfigTaskResult result = future.get();
+    final TsBlock resultSet = result.getResultSet();
+
+    assertEquals(TSStatusCode.SUCCESS_STATUS, result.getStatusCode());
+    assertEquals(
+        Collections.singletonList(IoTDBConstant.COLUMN_COUNT),
+        result.getResultSetHeader().getRespColumns());
+    assertEquals(1, resultSet.getPositionCount());
+    assertEquals(2, resultSet.getColumn(0).getInt(0));
+  }
+
+  @Test
+  public void testBuildTSBlockCanHideInformationSchema() throws Exception {
+    final Map<String, Object> databaseInfoMap = new HashMap<>();
+    databaseInfoMap.put("db1", new Object());
+    databaseInfoMap.put("db2", new Object());
+
+    final SettableFuture<ConfigTaskResult> future = SettableFuture.create();
+    CountDBTask.buildTSBlock(databaseInfoMap, future, databaseName -> "db1".equals(databaseName));
+
+    final ConfigTaskResult result = future.get();
+    assertEquals(1, result.getResultSet().getColumn(0).getInt(0));
+  }
+
+  @Test
+  public void testBuildTSBlockDoesNotDoubleCountInformationSchema() throws Exception {
+    final Map<String, Object> databaseInfoMap = new HashMap<>();
+    databaseInfoMap.put("db1", new Object());
+    databaseInfoMap.put(INFORMATION_DATABASE, new Object());
+
+    final SettableFuture<ConfigTaskResult> future = SettableFuture.create();
+    CountDBTask.buildTSBlock(databaseInfoMap, future, databaseName -> true);
+
+    final ConfigTaskResult result = future.get();
+    assertEquals(2, result.getResultSet().getColumn(0).getInt(0));
+  }
+
+  @Test
+  public void testExecuteDelegatesToExecutor() throws Exception {
+    final CountDB node = new CountDB(new NodeLocation(1, 1));
+    final Predicate<String> canSeenDB = databaseName -> true;
+    final CountDBTask task = new CountDBTask(node, canSeenDB);
+    final IConfigTaskExecutor executor = Mockito.mock(IConfigTaskExecutor.class);
+    final SettableFuture<ConfigTaskResult> future = SettableFuture.create();
+
+    when(executor.countDatabases(same(node), same(canSeenDB))).thenReturn(future);
+
+    assertSame(future, task.execute(executor));
+    verify(executor).countDatabases(same(node), same(canSeenDB));
+  }
+}
diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/sql/parser/CountDBStatementTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/sql/parser/CountDBStatementTest.java
new file mode 100644
index 00000000000..6d3dcc6bf52
--- /dev/null
+++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/sql/parser/CountDBStatementTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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.parser;
+
+import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.Statement;
+import org.apache.iotdb.db.protocol.session.IClientSession;
+import org.apache.iotdb.db.protocol.session.InternalClientSession;
+import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.CountDB;
+import org.apache.iotdb.db.queryengine.plan.relational.sql.util.DataNodeSqlFormatter;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.time.ZoneId;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class CountDBStatementTest {
+
+  private SqlParser sqlParser;
+  private IClientSession clientSession;
+
+  @Before
+  public void setUp() {
+    sqlParser = new SqlParser();
+    clientSession = new InternalClientSession("testClient");
+  }
+
+  @Test
+  public void testCountDatabaseStatement() {
+    final Statement statement =
+        sqlParser.createStatement("count database", ZoneId.systemDefault(), clientSession);
+
+    assertTrue(statement instanceof CountDB);
+    assertEquals("COUNT DATABASES", statement.toString());
+    assertEquals("COUNT DATABASES", DataNodeSqlFormatter.formatDataNodeSql(statement));
+  }
+
+  @Test
+  public void testCountDatabasesStatement() {
+    final Statement statement =
+        sqlParser.createStatement("count databases", ZoneId.systemDefault(), clientSession);
+
+    assertTrue(statement instanceof CountDB);
+    assertEquals("COUNT DATABASES", statement.toString());
+    assertEquals("COUNT DATABASES", DataNodeSqlFormatter.formatDataNodeSql(statement));
+  }
+}