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

morningman pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/master by this push:
     new abea4a6cf0c [Fix](udf) fix backends udf return rows incompatible with 
show backends command (#60210)
abea4a6cf0c is described below

commit abea4a6cf0cbeafd7c061c0c6d9aadc275c4f6e0
Author: heguanhui <[email protected]>
AuthorDate: Tue Feb 3 09:45:40 2026 +0800

    [Fix](udf) fix backends udf return rows incompatible with show backends 
command (#60210)
---
 .../apache/doris/common/proc/BackendsProcDir.java  | 17 ++---------
 .../trees/plans/commands/ShowBackendsCommand.java  |  3 +-
 .../tablefunction/BackendsTableValuedFunction.java | 15 ++++++++++
 .../doris/tablefunction/MetadataGenerator.java     | 11 +++++++
 .../plans/commands/ShowBackendsCommandTest.java    | 14 ++++++++-
 .../doris/utframe/DemoMultiBackendsTest.java       | 13 ++++----
 .../nereids_p0/ddl/describe/describe_command.out   |  4 +++
 .../external_table_p0/tvf/test_backends_tvf.groovy | 35 ++++++++++++++++++++--
 .../nereids_syntax_p0/information_schema.groovy    |  2 +-
 9 files changed, 89 insertions(+), 25 deletions(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/common/proc/BackendsProcDir.java 
b/fe/fe-core/src/main/java/org/apache/doris/common/proc/BackendsProcDir.java
index 92ef9f09e03..a7c59ec8c37 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/common/proc/BackendsProcDir.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/common/proc/BackendsProcDir.java
@@ -26,12 +26,12 @@ import org.apache.doris.common.util.ListComparator;
 import org.apache.doris.common.util.TimeUtils;
 import org.apache.doris.system.Backend;
 import org.apache.doris.system.SystemInfoService;
+import org.apache.doris.tablefunction.BackendsTableValuedFunction;
 import org.apache.doris.thrift.TUnit;
 
 import com.google.common.base.Preconditions;
 import com.google.common.base.Stopwatch;
 import com.google.common.base.Strings;
-import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
 import com.google.gson.Gson;
 import org.apache.logging.log4j.LogManager;
@@ -45,19 +45,6 @@ import java.util.concurrent.TimeUnit;
 public class BackendsProcDir implements ProcDirInterface {
     private static final Logger LOG = 
LogManager.getLogger(BackendsProcDir.class);
 
-    public static final ImmutableList<String> TITLE_NAMES = new 
ImmutableList.Builder<String>().add("BackendId")
-            
.add("Host").add("HeartbeatPort").add("BePort").add("HttpPort").add("BrpcPort").add("ArrowFlightSqlPort")
-            
.add("LastStartTime").add("LastHeartbeat").add("Alive").add("SystemDecommissioned").add("TabletNum")
-            
.add("DataUsedCapacity").add("TrashUsedCapacity").add("AvailCapacity").add("TotalCapacity").add("UsedPct")
-            
.add("MaxDiskUsedPct").add("RemoteUsedCapacity").add("Tag").add("ErrMsg").add("Version").add("Status")
-            
.add("HeartbeatFailureCounter").add("NodeRole").add("CpuCores").add("Memory").add("LiveSince")
-            .add("RunningTasks").build();
-
-    public static final ImmutableList<String> DISK_TITLE_NAMES = new 
ImmutableList.Builder<String>()
-            
.add("BackendId").add("Host").add("RootPath").add("DirType").add("DiskState")
-            
.add("TotalCapacity").add("UsedCapacity").add("AvailableCapacity").add("UsedPct")
-            .build();
-
     private SystemInfoService systemInfoService;
 
     public BackendsProcDir(SystemInfoService systemInfoService) {
@@ -69,7 +56,7 @@ public class BackendsProcDir implements ProcDirInterface {
         Preconditions.checkNotNull(systemInfoService);
 
         BaseProcResult result = new BaseProcResult();
-        result.setNames(TITLE_NAMES);
+        result.setNames(BackendsTableValuedFunction.getBackendsTitleNames());
 
         final List<List<String>> backendInfos = getBackendInfos();
         for (List<String> backendInfo : backendInfos) {
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowBackendsCommand.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowBackendsCommand.java
index 64cb8e282a2..ac73e5e3342 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowBackendsCommand.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowBackendsCommand.java
@@ -33,6 +33,7 @@ import org.apache.doris.qe.ConnectContext;
 import org.apache.doris.qe.ShowResultSet;
 import org.apache.doris.qe.ShowResultSetMetaData;
 import org.apache.doris.qe.StmtExecutor;
+import org.apache.doris.tablefunction.BackendsTableValuedFunction;
 
 import java.util.Comparator;
 import java.util.List;
@@ -51,7 +52,7 @@ public class ShowBackendsCommand extends ShowCommand {
 
     public ShowResultSetMetaData getMetaData() {
         ShowResultSetMetaData.Builder builder = 
ShowResultSetMetaData.builder();
-        for (String title : BackendsProcDir.TITLE_NAMES) {
+        for (String title : 
BackendsTableValuedFunction.getBackendsTitleNames()) {
             builder.addColumn(new Column(title, ScalarType.createVarchar(30)));
         }
         return builder.build();
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/tablefunction/BackendsTableValuedFunction.java
 
b/fe/fe-core/src/main/java/org/apache/doris/tablefunction/BackendsTableValuedFunction.java
index aca6779fc64..63a14a35e76 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/tablefunction/BackendsTableValuedFunction.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/tablefunction/BackendsTableValuedFunction.java
@@ -69,16 +69,24 @@ public class BackendsTableValuedFunction extends 
MetadataTableValuedFunction {
             new Column("Version", ScalarType.createStringType()),
             new Column("Status", ScalarType.createStringType()),
             new Column("HeartbeatFailureCounter", 
ScalarType.createType(PrimitiveType.INT)),
+            new Column("CpuCores", ScalarType.createType(PrimitiveType.INT)),
+            new Column("Memory", ScalarType.createStringType()),
+            new Column("LiveSince", ScalarType.createStringType()),
+            new Column("RunningTasks", 
ScalarType.createType(PrimitiveType.BIGINT)),
             new Column("NodeRole", ScalarType.createStringType()));
 
     private static final ImmutableMap<String, Integer> COLUMN_TO_INDEX;
+    private static final ImmutableList<String> TITLE_NAMES;
 
     static {
         ImmutableMap.Builder<String, Integer> builder = new 
ImmutableMap.Builder();
+        ImmutableList.Builder<String> immutableListBuilder = 
ImmutableList.builder();
         for (int i = 0; i < SCHEMA.size(); i++) {
             builder.put(SCHEMA.get(i).getName().toLowerCase(), i);
+            immutableListBuilder.add(SCHEMA.get(i).getName());
         }
         COLUMN_TO_INDEX = builder.build();
+        TITLE_NAMES = immutableListBuilder.build();
     }
 
     public static Integer getColumnIndexFromColumnName(String columnName) {
@@ -121,4 +129,11 @@ public class BackendsTableValuedFunction extends 
MetadataTableValuedFunction {
     public List<Column> getTableColumns() throws AnalysisException {
         return SCHEMA;
     }
+
+    /**
+     * unify title names for backends function and show backends command
+     */
+    public static ImmutableList<String> getBackendsTitleNames() {
+        return TITLE_NAMES;
+    }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/tablefunction/MetadataGenerator.java
 
b/fe/fe-core/src/main/java/org/apache/doris/tablefunction/MetadataGenerator.java
index 34d1afd60bd..fd70373fbdb 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/tablefunction/MetadataGenerator.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/tablefunction/MetadataGenerator.java
@@ -46,6 +46,7 @@ import org.apache.doris.common.ClientPool;
 import org.apache.doris.common.Pair;
 import org.apache.doris.common.proc.FrontendsProcNode;
 import org.apache.doris.common.proc.PartitionsProcDir;
+import org.apache.doris.common.profile.RuntimeProfile;
 import org.apache.doris.common.util.DebugUtil;
 import org.apache.doris.common.util.NetUtils;
 import org.apache.doris.common.util.TimeUtils;
@@ -106,6 +107,7 @@ import org.apache.doris.thrift.TSchemaTableRequestParams;
 import org.apache.doris.thrift.TStatus;
 import org.apache.doris.thrift.TStatusCode;
 import org.apache.doris.thrift.TTasksMetadataParams;
+import org.apache.doris.thrift.TUnit;
 import org.apache.doris.thrift.TUserIdentity;
 
 import com.codahale.metrics.Snapshot;
@@ -499,6 +501,15 @@ public class MetadataGenerator {
             trow.addToColumnValue(new TCell().setStringVal(new 
Gson().toJson(backend.getBackendStatus())));
             // heartbeat failure counter
             trow.addToColumnValue(new 
TCell().setIntVal(backend.getHeartbeatFailureCounter()));
+            // cpu cores
+            trow.addToColumnValue(new 
TCell().setIntVal(backend.getCputCores()));
+            // memory
+            trow.addToColumnValue(new TCell()
+                    
.setStringVal(RuntimeProfile.printCounter(backend.getBeMemory(), TUnit.BYTES)));
+            // live since
+            trow.addToColumnValue(new 
TCell().setStringVal(TimeUtils.longToTimeString(backend.getLiveSince())));
+            // running tasks
+            trow.addToColumnValue(new 
TCell().setLongVal(backend.getRunningTasks()));
 
             // node role, show the value only when backend is alive.
             trow.addToColumnValue(new TCell().setStringVal(backend.isAlive() ? 
backend.getNodeRoleTag().value : ""));
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/ShowBackendsCommandTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/ShowBackendsCommandTest.java
index 6e4b03d2cde..33c481094a5 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/ShowBackendsCommandTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/ShowBackendsCommandTest.java
@@ -17,6 +17,7 @@
 
 package org.apache.doris.nereids.trees.plans.commands;
 
+import org.apache.doris.catalog.Column;
 import org.apache.doris.catalog.Env;
 import org.apache.doris.catalog.InfoSchemaDb;
 import org.apache.doris.common.AnalysisException;
@@ -25,12 +26,17 @@ import org.apache.doris.datasource.InternalCatalog;
 import org.apache.doris.mysql.privilege.AccessControllerManager;
 import org.apache.doris.mysql.privilege.PrivPredicate;
 import org.apache.doris.qe.ConnectContext;
+import org.apache.doris.qe.ShowResultSet;
+import org.apache.doris.tablefunction.BackendsTableValuedFunction;
 
+import com.google.common.collect.ImmutableList;
 import mockit.Expectations;
 import mockit.Mocked;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
+import java.util.List;
+
 public class ShowBackendsCommandTest {
     private static final String internalCtl = 
InternalCatalog.INTERNAL_CATALOG_NAME;
     private static final String infoDB = InfoSchemaDb.DATABASE_NAME;
@@ -80,7 +86,13 @@ public class ShowBackendsCommandTest {
     public void testNormal() throws Exception {
         runBefore();
         ShowBackendsCommand command = new ShowBackendsCommand();
-        Assertions.assertDoesNotThrow(() -> command.doRun(ctx, null));
+        ShowResultSet showResultSet = command.doRun(ctx, null);
+        List<Column> columnList = showResultSet.getMetaData().getColumns();
+        ImmutableList<String> backendsTitleNames = 
BackendsTableValuedFunction.getBackendsTitleNames();
+        Assertions.assertTrue(!columnList.isEmpty() && columnList.size() == 
backendsTitleNames.size());
+        for (int i = 0; i < backendsTitleNames.size(); i++) {
+            
Assertions.assertTrue(columnList.get(i).getName().equalsIgnoreCase(backendsTitleNames.get(i)));
+        }
     }
 
     @Test
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/utframe/DemoMultiBackendsTest.java 
b/fe/fe-core/src/test/java/org/apache/doris/utframe/DemoMultiBackendsTest.java
index 800af43aaa1..fba2b882689 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/utframe/DemoMultiBackendsTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/utframe/DemoMultiBackendsTest.java
@@ -42,12 +42,14 @@ import org.apache.doris.qe.ConnectContext;
 import org.apache.doris.qe.StmtExecutor;
 import org.apache.doris.resource.Tag;
 import org.apache.doris.system.Backend;
+import org.apache.doris.tablefunction.BackendsTableValuedFunction;
 import org.apache.doris.thrift.TDisk;
 import org.apache.doris.thrift.TStorageMedium;
 import org.apache.doris.utframe.MockedFrontend.EnvVarNotSetException;
 import org.apache.doris.utframe.MockedFrontend.FeStartException;
 import org.apache.doris.utframe.MockedFrontend.NotInitException;
 
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
@@ -207,16 +209,17 @@ public class DemoMultiBackendsTest {
         // test show backends;
         BackendsProcDir dir = new BackendsProcDir(Env.getCurrentSystemInfo());
         ProcResult result = dir.fetchResult();
-        Assert.assertEquals(BackendsProcDir.TITLE_NAMES.size(), 
result.getColumnNames().size());
+        ImmutableList<String> backendsTitleNames = 
BackendsTableValuedFunction.getBackendsTitleNames();
+        Assert.assertEquals(backendsTitleNames.size(), 
result.getColumnNames().size());
         Assert.assertEquals("{\"location\" : \"default\"}",
-                result.getRows().get(0).get(BackendsProcDir.TITLE_NAMES.size() 
- 10));
+                result.getRows().get(0).get(backendsTitleNames.size() - 10));
         Assert.assertEquals(
                 
"{\"lastSuccessReportTabletsTime\":\"N/A\",\"lastStreamLoadTime\":-1,\"isQueryDisabled\":false,"
                         + 
"\"isLoadDisabled\":false,\"isActive\":true,\"isShutdown\":false,\"currentFragmentNum\":0,"
                         + "\"lastFragmentUpdateTime\":0}",
-                result.getRows().get(0).get(BackendsProcDir.TITLE_NAMES.size() 
- 7));
-        Assert.assertEquals("0", 
result.getRows().get(0).get(BackendsProcDir.TITLE_NAMES.size() - 6));
-        Assert.assertEquals(Tag.VALUE_MIX, 
result.getRows().get(0).get(BackendsProcDir.TITLE_NAMES.size() - 5));
+                result.getRows().get(0).get(backendsTitleNames.size() - 7));
+        Assert.assertEquals("0", 
result.getRows().get(0).get(backendsTitleNames.size() - 6));
+        Assert.assertEquals(Tag.VALUE_MIX, 
result.getRows().get(0).get(backendsTitleNames.size() - 5));
     }
 
     protected void alterTable(String sql, ConnectContext connectContext) 
throws Exception {
diff --git a/regression-test/data/nereids_p0/ddl/describe/describe_command.out 
b/regression-test/data/nereids_p0/ddl/describe/describe_command.out
index 9e27c418c4f..ba03c2bd56d 100644
--- a/regression-test/data/nereids_p0/ddl/describe/describe_command.out
+++ b/regression-test/data/nereids_p0/ddl/describe/describe_command.out
@@ -40,6 +40,10 @@ ErrMsg       text    No      false   \N      NONE
 Version        text    No      false   \N      NONE
 Status text    No      false   \N      NONE
 HeartbeatFailureCounter        int     No      false   \N      NONE
+CpuCores       int     No      false   \N      NONE
+Memory text    No      false   \N      NONE
+LiveSince      text    No      false   \N      NONE
+RunningTasks   bigint  No      false   \N      NONE
 NodeRole       text    No      false   \N      NONE
 
 -- !cmd --
diff --git 
a/regression-test/suites/external_table_p0/tvf/test_backends_tvf.groovy 
b/regression-test/suites/external_table_p0/tvf/test_backends_tvf.groovy
index 241e15d6f6a..fa001b6fdb8 100644
--- a/regression-test/suites/external_table_p0/tvf/test_backends_tvf.groovy
+++ b/regression-test/suites/external_table_p0/tvf/test_backends_tvf.groovy
@@ -19,7 +19,38 @@
 suite("test_backends_tvf","p0,external,tvf,external_docker") {
     List<List<Object>> table =  sql """ select * from backends(); """
     assertTrue(table.size() > 0)
-    assertEquals(25, table[0].size())
+    assertEquals(29, table[0].size())
+
+    List<List<Object>> titleNames = sql """ describe function backends(); """
+    assertTrue(titleNames[0][0] =="BackendId")
+    assertTrue(titleNames[1][0] =="Host")
+    assertTrue(titleNames[2][0] =="HeartbeatPort")
+    assertTrue(titleNames[3][0] =="BePort")
+    assertTrue(titleNames[4][0] =="HttpPort")
+    assertTrue(titleNames[5][0] =="BrpcPort")
+    assertTrue(titleNames[6][0] =="ArrowFlightSqlPort")
+    assertTrue(titleNames[7][0] =="LastStartTime")
+    assertTrue(titleNames[8][0] =="LastHeartbeat")
+    assertTrue(titleNames[9][0] =="Alive")
+    assertTrue(titleNames[10][0] =="SystemDecommissioned")
+    assertTrue(titleNames[11][0] =="TabletNum")
+    assertTrue(titleNames[12][0] =="DataUsedCapacity")
+    assertTrue(titleNames[13][0] =="TrashUsedCapacity")
+    assertTrue(titleNames[14][0] =="AvailCapacity")
+    assertTrue(titleNames[15][0] =="TotalCapacity")
+    assertTrue(titleNames[16][0] =="UsedPct")
+    assertTrue(titleNames[17][0] =="MaxDiskUsedPct")
+    assertTrue(titleNames[18][0] =="RemoteUsedCapacity")
+    assertTrue(titleNames[19][0] =="Tag")
+    assertTrue(titleNames[20][0] =="ErrMsg")
+    assertTrue(titleNames[21][0] =="Version")
+    assertTrue(titleNames[22][0] =="Status")
+    assertTrue(titleNames[23][0] =="HeartbeatFailureCounter")
+    assertTrue(titleNames[24][0] =="CpuCores")
+    assertTrue(titleNames[25][0] =="Memory")
+    assertTrue(titleNames[26][0] =="LiveSince")
+    assertTrue(titleNames[27][0] =="RunningTasks")
+    assertTrue(titleNames[28][0] =="NodeRole")
 
     // filter columns
     table = sql """ select BackendId, Host, Alive, TotalCapacity, Version, 
NodeRole from backends();"""
@@ -56,7 +87,7 @@ suite("test_backends_tvf","p0,external,tvf,external_docker") {
             SystemDecommissioned, tabletnum
             DataUsedCapacity, AvailCapacity, TotalCapacity, UsedPct
             MaxDiskUsedPct, RemoteUsedCapacity, Tag, ErrMsg, Version, Status
-            HeartbeatFailureCounter, NodeRole from backends();
+            HeartbeatFailureCounter, CpuCores, Memory, LiveSince, 
RunningTasks, NodeRole from backends();
     """
 
 
diff --git a/regression-test/suites/nereids_syntax_p0/information_schema.groovy 
b/regression-test/suites/nereids_syntax_p0/information_schema.groovy
index 477fc5c88be..2676142d28f 100644
--- a/regression-test/suites/nereids_syntax_p0/information_schema.groovy
+++ b/regression-test/suites/nereids_syntax_p0/information_schema.groovy
@@ -20,7 +20,7 @@ import java.util.regex.Pattern;
 suite("information_schema") {
     List<List<Object>> table =  sql """ select * from backends(); """
     assertTrue(table.size() > 0)
-    assertTrue(table[0].size() == 25)
+    assertTrue(table[0].size() == 29)
 
     sql "SELECT DATABASE();"
     sql "select USER();"


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to