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

morrysnow pushed a commit to branch branch-3.1
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/branch-3.1 by this push:
     new b79fc257395 branch-3.1: [fix](information_schema) The time type in 
tables under the information_schema should change according to the time_zone. 
#48462 (#52920)
b79fc257395 is described below

commit b79fc257395606c65d42b032a267012e5b795ffd
Author: Mingyu Chen (Rayner) <[email protected]>
AuthorDate: Tue Jul 8 17:44:07 2025 +0800

    branch-3.1: [fix](information_schema) The time type in tables under the 
information_schema should change according to the time_zone. #48462 (#52920)
    
    bp #48462
    
    Co-authored-by: Tiewei Fang <[email protected]>
---
 be/src/exec/schema_scanner.cpp                     |   3 +-
 be/src/exec/schema_scanner.h                       |   4 +-
 .../schema_active_queries_scanner.cpp              |   1 +
 .../schema_backend_kerberos_ticket_cache.cpp       |   1 -
 .../schema_backend_kerberos_ticket_cache.h         |   2 -
 .../schema_scanner/schema_partitions_scanner.cpp   |   1 +
 .../schema_scanner/schema_processlist_scanner.cpp  |   1 +
 .../exec/schema_scanner/schema_rowsets_scanner.cpp |   5 +-
 .../exec/schema_scanner/schema_tables_scanner.cpp  |   7 +-
 be/src/pipeline/exec/schema_scan_operator.cpp      |   2 +-
 .../org/apache/doris/common/util/TimeUtils.java    |  12 ++
 .../doris/httpv2/controller/SessionController.java |   3 +-
 .../plsql/functions/DorisFunctionRegistry.java     |   5 +-
 .../java/org/apache/doris/qe/ConnectContext.java   |   8 +-
 .../java/org/apache/doris/qe/ConnectPoolMgr.java   |   6 +-
 .../java/org/apache/doris/qe/ConnectScheduler.java |   8 +-
 .../java/org/apache/doris/qe/ShowExecutor.java     |   2 +-
 .../apache/doris/service/FrontendServiceImpl.java  |   7 +-
 .../doris/tablefunction/MetadataGenerator.java     |  33 ++--
 .../org/apache/doris/qe/ConnectContextTest.java    |   3 +-
 gensrc/thrift/FrontendService.thrift               |   2 +
 .../test_information_schema_timezone.out           | Bin 0 -> 415 bytes
 .../test_information_schema_timezone.groovy        | 218 +++++++++++++++++++++
 23 files changed, 297 insertions(+), 37 deletions(-)

diff --git a/be/src/exec/schema_scanner.cpp b/be/src/exec/schema_scanner.cpp
index 792bf044a59..9f977e33fbb 100644
--- a/be/src/exec/schema_scanner.cpp
+++ b/be/src/exec/schema_scanner.cpp
@@ -163,7 +163,7 @@ Status 
SchemaScanner::get_next_block_internal(vectorized::Block* block, bool* eo
     return Status::OK();
 }
 
-Status SchemaScanner::init(SchemaScannerParam* param, ObjectPool* pool) {
+Status SchemaScanner::init(RuntimeState* state, SchemaScannerParam* param, 
ObjectPool* pool) {
     if (_is_init) {
         return Status::OK();
     }
@@ -172,6 +172,7 @@ Status SchemaScanner::init(SchemaScannerParam* param, 
ObjectPool* pool) {
     }
 
     _param = param;
+    _timezone_obj = state->timezone_obj();
     _is_init = true;
 
     if (_param->profile) {
diff --git a/be/src/exec/schema_scanner.h b/be/src/exec/schema_scanner.h
index 35fc051511d..22a95c6cfd1 100644
--- a/be/src/exec/schema_scanner.h
+++ b/be/src/exec/schema_scanner.h
@@ -27,6 +27,7 @@
 #include <string>
 #include <vector>
 
+#include "cctz/time_zone.h"
 #include "common/factory_creator.h"
 #include "common/status.h"
 #include "runtime/define_primitive_type.h"
@@ -99,7 +100,7 @@ public:
     virtual ~SchemaScanner();
 
     // init object need information, schema etc.
-    virtual Status init(SchemaScannerParam* param, ObjectPool* pool);
+    virtual Status init(RuntimeState* state, SchemaScannerParam* param, 
ObjectPool* pool);
     Status get_next_block(RuntimeState* state, vectorized::Block* block, bool* 
eos);
     // Start to work
     virtual Status start(RuntimeState* state);
@@ -143,6 +144,7 @@ protected:
     std::atomic<bool> _eos = false;
     std::atomic<bool> _opened = false;
     std::atomic<bool> _async_thread_running = false;
+    cctz::time_zone _timezone_obj;
 };
 
 } // namespace doris
diff --git a/be/src/exec/schema_scanner/schema_active_queries_scanner.cpp 
b/be/src/exec/schema_scanner/schema_active_queries_scanner.cpp
index 98051638026..fa6c1ff1430 100644
--- a/be/src/exec/schema_scanner/schema_active_queries_scanner.cpp
+++ b/be/src/exec/schema_scanner/schema_active_queries_scanner.cpp
@@ -60,6 +60,7 @@ Status 
SchemaActiveQueriesScanner::_get_active_queries_block_from_fe() {
     }
     schema_table_params.replay_to_other_fe = true;
     schema_table_params.__isset.replay_to_other_fe = true;
+    schema_table_params.__set_time_zone(_timezone_obj.name());
 
     TFetchSchemaTableDataRequest request;
     request.__set_schema_table_name(TSchemaTableName::ACTIVE_QUERIES);
diff --git 
a/be/src/exec/schema_scanner/schema_backend_kerberos_ticket_cache.cpp 
b/be/src/exec/schema_scanner/schema_backend_kerberos_ticket_cache.cpp
index d318dec6970..85ab69d2798 100644
--- a/be/src/exec/schema_scanner/schema_backend_kerberos_ticket_cache.cpp
+++ b/be/src/exec/schema_scanner/schema_backend_kerberos_ticket_cache.cpp
@@ -49,7 +49,6 @@ 
SchemaBackendKerberosTicketCacheScanner::~SchemaBackendKerberosTicketCacheScanne
 
 Status SchemaBackendKerberosTicketCacheScanner::start(RuntimeState* state) {
     _block_rows_limit = state->batch_size();
-    _timezone_obj = state->timezone_obj();
     return Status::OK();
 }
 
diff --git a/be/src/exec/schema_scanner/schema_backend_kerberos_ticket_cache.h 
b/be/src/exec/schema_scanner/schema_backend_kerberos_ticket_cache.h
index ecb6110f561..19dac6f4c20 100644
--- a/be/src/exec/schema_scanner/schema_backend_kerberos_ticket_cache.h
+++ b/be/src/exec/schema_scanner/schema_backend_kerberos_ticket_cache.h
@@ -19,7 +19,6 @@
 
 #include <vector>
 
-#include "cctz/time_zone.h"
 #include "common/status.h"
 #include "exec/schema_scanner.h"
 
@@ -46,6 +45,5 @@ private:
     int _row_idx = 0;
     int _total_rows = 0;
     std::unique_ptr<vectorized::Block> _info_block = nullptr;
-    cctz::time_zone _timezone_obj;
 };
 }; // namespace doris
diff --git a/be/src/exec/schema_scanner/schema_partitions_scanner.cpp 
b/be/src/exec/schema_scanner/schema_partitions_scanner.cpp
index f2ba4abaddc..09beff234e6 100644
--- a/be/src/exec/schema_scanner/schema_partitions_scanner.cpp
+++ b/be/src/exec/schema_scanner/schema_partitions_scanner.cpp
@@ -124,6 +124,7 @@ Status 
SchemaPartitionsScanner::get_onedb_info_from_fe(int64_t dbId) {
     
schema_table_request_params.__set_current_user_ident(*_param->common_param->current_user_ident);
     schema_table_request_params.__set_catalog(*_param->common_param->catalog);
     schema_table_request_params.__set_dbId(dbId);
+    schema_table_request_params.__set_time_zone(_timezone_obj.name());
 
     TFetchSchemaTableDataRequest request;
     request.__set_schema_table_name(TSchemaTableName::PARTITIONS);
diff --git a/be/src/exec/schema_scanner/schema_processlist_scanner.cpp 
b/be/src/exec/schema_scanner/schema_processlist_scanner.cpp
index 185ef2ab442..0de1a252fbb 100644
--- a/be/src/exec/schema_scanner/schema_processlist_scanner.cpp
+++ b/be/src/exec/schema_scanner/schema_processlist_scanner.cpp
@@ -55,6 +55,7 @@ SchemaProcessListScanner::~SchemaProcessListScanner() = 
default;
 Status SchemaProcessListScanner::start(RuntimeState* state) {
     TShowProcessListRequest request;
     request.__set_show_full_sql(true);
+    request.__set_time_zone(state->timezone_obj().name());
 
     for (const auto& fe_addr : _param->common_param->fe_addr_list) {
         TShowProcessListResult tmp_ret;
diff --git a/be/src/exec/schema_scanner/schema_rowsets_scanner.cpp 
b/be/src/exec/schema_scanner/schema_rowsets_scanner.cpp
index 3aa0e944a82..23ae10198ae 100644
--- a/be/src/exec/schema_scanner/schema_rowsets_scanner.cpp
+++ b/be/src/exec/schema_scanner/schema_rowsets_scanner.cpp
@@ -242,7 +242,7 @@ Status 
SchemaRowsetsScanner::_fill_block_impl(vectorized::Block* block) {
         for (int i = fill_idx_begin; i < fill_idx_end; ++i) {
             RowsetSharedPtr rowset = rowsets_[i];
             int64_t creation_time = rowset->creation_time();
-            srcs[i - fill_idx_begin].from_unixtime(creation_time, 
TimezoneUtils::default_time_zone);
+            srcs[i - fill_idx_begin].from_unixtime(creation_time, 
_timezone_obj);
             datas[i - fill_idx_begin] = srcs.data() + i - fill_idx_begin;
         }
         RETURN_IF_ERROR(fill_dest_column_for_range(block, 10, datas));
@@ -253,8 +253,7 @@ Status 
SchemaRowsetsScanner::_fill_block_impl(vectorized::Block* block) {
         for (int i = fill_idx_begin; i < fill_idx_end; ++i) {
             RowsetSharedPtr rowset = rowsets_[i];
             int64_t newest_write_timestamp = rowset->newest_write_timestamp();
-            srcs[i - fill_idx_begin].from_unixtime(newest_write_timestamp,
-                                                   
TimezoneUtils::default_time_zone);
+            srcs[i - fill_idx_begin].from_unixtime(newest_write_timestamp, 
_timezone_obj);
             datas[i - fill_idx_begin] = srcs.data() + i - fill_idx_begin;
         }
         RETURN_IF_ERROR(fill_dest_column_for_range(block, 11, datas));
diff --git a/be/src/exec/schema_scanner/schema_tables_scanner.cpp 
b/be/src/exec/schema_scanner/schema_tables_scanner.cpp
index 23cef63815b..d6192bd8dd2 100644
--- a/be/src/exec/schema_scanner/schema_tables_scanner.cpp
+++ b/be/src/exec/schema_scanner/schema_tables_scanner.cpp
@@ -27,6 +27,7 @@
 #include "exec/schema_scanner/schema_helper.h"
 #include "runtime/decimalv2_value.h"
 #include "runtime/define_primitive_type.h"
+#include "runtime/runtime_state.h"
 #include "util/runtime_profile.h"
 #include "util/timezone_utils.h"
 #include "vec/common/string_ref.h"
@@ -278,7 +279,7 @@ Status 
SchemaTablesScanner::_fill_block_impl(vectorized::Block* block) {
                 if (create_time <= 0) {
                     datas[i] = nullptr;
                 } else {
-                    srcs[i].from_unixtime(create_time, 
TimezoneUtils::default_time_zone);
+                    srcs[i].from_unixtime(create_time, _timezone_obj);
                     datas[i] = srcs.data() + i;
                 }
             } else {
@@ -297,7 +298,7 @@ Status 
SchemaTablesScanner::_fill_block_impl(vectorized::Block* block) {
                 if (update_time <= 0) {
                     datas[i] = nullptr;
                 } else {
-                    srcs[i].from_unixtime(update_time, 
TimezoneUtils::default_time_zone);
+                    srcs[i].from_unixtime(update_time, _timezone_obj);
                     datas[i] = srcs.data() + i;
                 }
             } else {
@@ -316,7 +317,7 @@ Status 
SchemaTablesScanner::_fill_block_impl(vectorized::Block* block) {
                 if (check_time <= 0) {
                     datas[i] = nullptr;
                 } else {
-                    srcs[i].from_unixtime(check_time, 
TimezoneUtils::default_time_zone);
+                    srcs[i].from_unixtime(check_time, _timezone_obj);
                     datas[i] = srcs.data() + i;
                 }
             } else {
diff --git a/be/src/pipeline/exec/schema_scan_operator.cpp 
b/be/src/pipeline/exec/schema_scan_operator.cpp
index 8faee3ef581..f219a86d10d 100644
--- a/be/src/pipeline/exec/schema_scan_operator.cpp
+++ b/be/src/pipeline/exec/schema_scan_operator.cpp
@@ -53,7 +53,7 @@ Status SchemaScanLocalState::init(RuntimeState* state, 
LocalStateInfo& info) {
         return Status::InternalError("schema scanner get nullptr pointer.");
     }
 
-    return _schema_scanner->init(&_scanner_param, state->obj_pool());
+    return _schema_scanner->init(state, &_scanner_param, state->obj_pool());
 }
 
 Status SchemaScanLocalState::open(RuntimeState* state) {
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/common/util/TimeUtils.java 
b/fe/fe-core/src/main/java/org/apache/doris/common/util/TimeUtils.java
index d88971a6e72..8d019be68b7 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/common/util/TimeUtils.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/common/util/TimeUtils.java
@@ -86,6 +86,10 @@ public class TimeUtils {
         return DATETIME_FORMAT.withZone(getDorisZoneId());
     }
 
+    public static DateTimeFormatter getDatetimeFormatFromTimeZone(String 
timeZone) {
+        return 
DATETIME_FORMAT.withZone(getOrSystemTimeZone(timeZone).toZoneId());
+    }
+
     public static DateTimeFormatter getTimeFormatWithTimeZone() {
         return TIME_FORMAT.withZone(getDorisZoneId());
     }
@@ -178,6 +182,14 @@ public class TimeUtils {
         return longToTimeStringWithFormat(timeStamp, 
getDatetimeFormatWithTimeZone());
     }
 
+    public static String longToTimeStringWithTimeZone(Long timeStamp, String 
timeZone) {
+        if (timeStamp == null || timeStamp <= 0L) {
+            return FeConstants.null_string;
+        }
+        DateTimeFormatter dateFormat = getDatetimeFormatFromTimeZone(timeZone);
+        return 
dateFormat.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(timeStamp), 
dateFormat.getZone()));
+    }
+
     public static String longToTimeStringWithms(Long timeStamp) {
         return longToTimeStringWithFormat(timeStamp, 
getDatetimeMsFormatWithTimeZone());
     }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/httpv2/controller/SessionController.java
 
b/fe/fe-core/src/main/java/org/apache/doris/httpv2/controller/SessionController.java
index 090e8981495..8d9f791c0b0 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/httpv2/controller/SessionController.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/httpv2/controller/SessionController.java
@@ -44,6 +44,7 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Optional;
 import java.util.stream.Collectors;
 import javax.servlet.http.HttpServletRequest;
 
@@ -112,7 +113,7 @@ public class SessionController extends RestBaseController {
                 .listConnection("root", false);
         long nowMs = System.currentTimeMillis();
         return threadInfos.stream()
-                .map(info -> info.toRow(-1, nowMs))
+                .map(info -> info.toRow(-1, nowMs, Optional.empty()))
                 .map(row -> {
                     Map<String, String> record = new HashMap<>();
                     for (int i = 0; i < row.size(); i++) {
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/plsql/functions/DorisFunctionRegistry.java
 
b/fe/fe-core/src/main/java/org/apache/doris/plsql/functions/DorisFunctionRegistry.java
index 10b4807205b..88e7ddbb4aa 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/plsql/functions/DorisFunctionRegistry.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/plsql/functions/DorisFunctionRegistry.java
@@ -22,6 +22,7 @@ package org.apache.doris.plsql.functions;
 
 import org.apache.doris.catalog.DatabaseIf;
 import org.apache.doris.catalog.Env;
+import org.apache.doris.common.util.TimeUtils;
 import org.apache.doris.datasource.CatalogIf;
 import org.apache.doris.nereids.PLLexer;
 import org.apache.doris.nereids.PLParser;
@@ -43,7 +44,6 @@ import org.antlr.v4.runtime.CharStreams;
 import org.antlr.v4.runtime.CommonTokenStream;
 import org.antlr.v4.runtime.ParserRuleContext;
 
-import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.HashMap;
@@ -264,8 +264,7 @@ public class DorisFunctionRegistry implements 
FunctionRegistry {
     @Override
     public void save(FuncNameInfo procedureName, String source, boolean 
isForce) {
         try {
-            SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
-            String createTime = f.format(Calendar.getInstance().getTime());
+            String createTime = 
TimeUtils.longToTimeString(Calendar.getInstance().getTimeInMillis());
             String modifyTime = createTime;
             if (isForce) {
                 // need to get create time and use that.
diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectContext.java 
b/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectContext.java
index c0fe10998ec..b06a9594b6b 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectContext.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectContext.java
@@ -1188,7 +1188,7 @@ public class ConnectContext {
     public class ThreadInfo {
         public boolean isFull;
 
-        public List<String> toRow(int connId, long nowMs) {
+        public List<String> toRow(int connId, long nowMs, Optional<String> 
timeZone) {
             List<String> row = Lists.newArrayList();
             if (connId == connectionId) {
                 row.add("Yes");
@@ -1198,7 +1198,11 @@ public class ConnectContext {
             row.add("" + connectionId);
             row.add(ClusterNamespace.getNameFromFullName(qualifiedUser));
             row.add(getRemoteHostPortString());
-            row.add(TimeUtils.longToTimeString(loginTime));
+            if (timeZone.isPresent()) {
+                row.add(TimeUtils.longToTimeStringWithTimeZone(loginTime, 
timeZone.get()));
+            } else {
+                row.add(TimeUtils.longToTimeString(loginTime));
+            }
             row.add(defaultCatalog);
             row.add(ClusterNamespace.getNameFromFullName(currentDb));
             row.add(command.toString());
diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectPoolMgr.java 
b/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectPoolMgr.java
index 732263f244f..ce91ef09e37 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectPoolMgr.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectPoolMgr.java
@@ -33,6 +33,7 @@ import org.apache.logging.log4j.Logger;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.concurrent.atomic.AtomicInteger;
 
 public class ConnectPoolMgr {
@@ -130,7 +131,8 @@ public class ConnectPoolMgr {
     }
 
     // used for thrift
-    public List<List<String>> listConnectionForRpc(UserIdentity userIdentity, 
boolean isShowFullSql) {
+    public List<List<String>> listConnectionForRpc(UserIdentity userIdentity, 
boolean isShowFullSql,
+            Optional<String> timeZone) {
         List<List<String>> list = new ArrayList<>();
         long nowMs = System.currentTimeMillis();
         for (ConnectContext ctx : connectionMap.values()) {
@@ -139,7 +141,7 @@ public class ConnectPoolMgr {
                     .checkGlobalPriv(userIdentity, PrivPredicate.GRANT)) {
                 continue;
             }
-            list.add(ctx.toThreadInfo(isShowFullSql).toRow(-1, nowMs));
+            list.add(ctx.toThreadInfo(isShowFullSql).toRow(-1, nowMs, 
timeZone));
         }
         return list;
     }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectScheduler.java 
b/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectScheduler.java
index 7de6ce7b1a5..c8d27a23db6 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectScheduler.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectScheduler.java
@@ -33,6 +33,7 @@ import org.apache.logging.log4j.Logger;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.TimerTask;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
@@ -121,10 +122,11 @@ public class ConnectScheduler {
     }
 
     // used for thrift
-    public List<List<String>> listConnectionForRpc(UserIdentity userIdentity, 
boolean isShowFullSql) {
+    public List<List<String>> listConnectionForRpc(UserIdentity userIdentity, 
boolean isShowFullSql,
+            Optional<String> timeZone) {
         List<List<String>> list = new ArrayList<>();
-        list.addAll(connectPoolMgr.listConnectionForRpc(userIdentity, 
isShowFullSql));
-        list.addAll(flightSqlConnectPoolMgr.listConnectionForRpc(userIdentity, 
isShowFullSql));
+        list.addAll(connectPoolMgr.listConnectionForRpc(userIdentity, 
isShowFullSql, timeZone));
+        list.addAll(flightSqlConnectPoolMgr.listConnectionForRpc(userIdentity, 
isShowFullSql, timeZone));
         return list;
     }
 
diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/ShowExecutor.java 
b/fe/fe-core/src/main/java/org/apache/doris/qe/ShowExecutor.java
index 196ce304ee9..822d4b5646e 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/qe/ShowExecutor.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/qe/ShowExecutor.java
@@ -536,7 +536,7 @@ public class ShowExecutor {
                 .listConnection(ctx.getQualifiedUser(), isShowFullSql);
         long nowMs = System.currentTimeMillis();
         for (ConnectContext.ThreadInfo info : threadInfos) {
-            rowSet.add(info.toRow(ctx.getConnectionId(), nowMs));
+            rowSet.add(info.toRow(ctx.getConnectionId(), nowMs, 
Optional.empty()));
         }
 
         if (isShowAllFe) {
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/service/FrontendServiceImpl.java 
b/fe/fe-core/src/main/java/org/apache/doris/service/FrontendServiceImpl.java
index b4339023279..8eae599d0cc 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/service/FrontendServiceImpl.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/service/FrontendServiceImpl.java
@@ -299,6 +299,7 @@ import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ExecutionException;
@@ -4277,8 +4278,12 @@ public class FrontendServiceImpl implements 
FrontendService.Iface {
         if (request.isSetCurrentUserIdent()) {
             userIdentity = 
UserIdentity.fromThrift(request.getCurrentUserIdent());
         }
+        String timeZone = 
VariableMgr.getDefaultSessionVariable().getTimeZone();
+        if (request.isSetTimeZone()) {
+            timeZone = request.getTimeZone();
+        }
         List<List<String>> processList = 
ExecuteEnv.getInstance().getScheduler()
-                .listConnectionForRpc(userIdentity, isShowFullSql);
+                .listConnectionForRpc(userIdentity, isShowFullSql, 
Optional.of(timeZone));
         TShowProcessListResult result = new TShowProcessListResult();
         result.setProcessList(processList);
         return result;
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 468f7e0fe5f..82b5d01563e 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
@@ -75,6 +75,7 @@ import org.apache.doris.plsql.metastore.PlsqlStoredProcedure;
 import org.apache.doris.qe.ConnectContext;
 import org.apache.doris.qe.QeProcessorImpl;
 import org.apache.doris.qe.QeProcessorImpl.QueryInfo;
+import org.apache.doris.qe.VariableMgr;
 import org.apache.doris.resource.workloadgroup.WorkloadGroupMgr;
 import org.apache.doris.system.Backend;
 import org.apache.doris.system.SystemInfoService;
@@ -114,10 +115,8 @@ import org.apache.logging.log4j.Logger;
 import org.apache.thrift.TException;
 import org.jetbrains.annotations.NotNull;
 
-import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Date;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.TimeUnit;
@@ -647,7 +646,10 @@ public class MetadataGenerator {
 
         List<TRow> dataBatch = Lists.newArrayList();
         Map<String, QueryInfo> queryInfoMap = 
QeProcessorImpl.INSTANCE.getQueryInfoMap();
-        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        String timeZone = 
VariableMgr.getDefaultSessionVariable().getTimeZone();
+        if (tSchemaTableParams.isSetTimeZone()) {
+            timeZone = tSchemaTableParams.getTimeZone();
+        }
         for (Map.Entry<String, QueryInfo> entry : queryInfoMap.entrySet()) {
             String queryId = entry.getKey();
             QueryInfo queryInfo = entry.getValue();
@@ -657,7 +659,8 @@ public class MetadataGenerator {
 
             long queryStartTime = queryInfo.getStartExecTime();
             if (queryStartTime > 0) {
-                trow.addToColumnValue(new TCell().setStringVal(sdf.format(new 
Date(queryStartTime))));
+                trow.addToColumnValue(new TCell().setStringVal(
+                        TimeUtils.longToTimeStringWithTimeZone(queryStartTime, 
timeZone)));
                 trow.addToColumnValue(
                         new TCell().setLongVal(System.currentTimeMillis() - 
queryInfo.getStartExecTime()));
             } else {
@@ -681,14 +684,16 @@ public class MetadataGenerator {
 
             long queueStartTime = queryInfo.getQueueStartTime();
             if (queueStartTime > 0) {
-                trow.addToColumnValue(new TCell().setStringVal(sdf.format(new 
Date(queueStartTime))));
+                trow.addToColumnValue(new TCell().setStringVal(
+                        TimeUtils.longToTimeStringWithTimeZone(queueStartTime, 
timeZone)));
             } else {
                 trow.addToColumnValue(new TCell());
             }
 
             long queueEndTime = queryInfo.getQueueEndTime();
             if (queueEndTime > 0) {
-                trow.addToColumnValue(new TCell().setStringVal(sdf.format(new 
Date(queueEndTime))));
+                trow.addToColumnValue(new TCell().setStringVal(
+                        TimeUtils.longToTimeStringWithTimeZone(queueEndTime, 
timeZone)));
             } else {
                 trow.addToColumnValue(new TCell());
             }
@@ -1348,7 +1353,7 @@ public class MetadataGenerator {
     }
 
     private static void partitionsForInternalCatalog(UserIdentity 
currentUserIdentity,
-            CatalogIf catalog, DatabaseIf database, List<TableIf> tables, 
List<TRow> dataBatch) {
+            CatalogIf catalog, DatabaseIf database, List<TableIf> tables, 
List<TRow> dataBatch, String timeZone) {
         for (TableIf table : tables) {
             if (!(table instanceof OlapTable)) {
                 continue;
@@ -1401,8 +1406,9 @@ public class MetadataGenerator {
                     trow.addToColumnValue(new TCell().setIntVal(0)); // 
INDEX_LENGTH (not available)
                     trow.addToColumnValue(new TCell().setIntVal(0)); // 
DATA_FREE (not available)
                     trow.addToColumnValue(new TCell().setStringVal("NULL")); 
// CREATE_TIME (not available)
+                    // UPDATE_TIME
                     trow.addToColumnValue(new TCell().setStringVal(
-                            
TimeUtils.longToTimeString(partition.getVisibleVersionTime()))); // UPDATE_TIME
+                            
TimeUtils.longToTimeStringWithTimeZone(partition.getVisibleVersionTime(), 
timeZone)));
                     trow.addToColumnValue(new TCell().setStringVal("NULL")); 
// CHECK_TIME (not available)
                     trow.addToColumnValue(new TCell().setIntVal(0)); // 
CHECKSUM (not available)
                     trow.addToColumnValue(new TCell().setStringVal("")); // 
PARTITION_COMMENT (not available)
@@ -1474,7 +1480,7 @@ public class MetadataGenerator {
     }
 
     private static void partitionsForExternalCatalog(UserIdentity 
currentUserIdentity,
-            CatalogIf catalog, DatabaseIf database, List<TableIf> tables, 
List<TRow> dataBatch) {
+            CatalogIf catalog, DatabaseIf database, List<TableIf> tables, 
List<TRow> dataBatch, String timeZone) {
         for (TableIf table : tables) {
             if 
(!Env.getCurrentEnv().getAccessManager().checkTblPriv(currentUserIdentity, 
catalog.getName(),
                     database.getFullName(), table.getName(), 
PrivPredicate.SHOW)) {
@@ -1497,6 +1503,11 @@ public class MetadataGenerator {
             return errorResult("current catalog is not set.");
         }
 
+        String timezone = 
VariableMgr.getDefaultSessionVariable().getTimeZone();
+        if (params.isSetTimeZone()) {
+            timezone = params.getTimeZone();
+        }
+
         TUserIdentity tcurrentUserIdentity = params.getCurrentUserIdent();
         UserIdentity currentUserIdentity = 
UserIdentity.fromThrift(tcurrentUserIdentity);
         TFetchSchemaTableDataResult result = new TFetchSchemaTableDataResult();
@@ -1524,9 +1535,9 @@ public class MetadataGenerator {
         List<TableIf> tables = database.getTables();
         if (catalog instanceof InternalCatalog) {
             // only olap tables
-            partitionsForInternalCatalog(currentUserIdentity, catalog, 
database, tables, dataBatch);
+            partitionsForInternalCatalog(currentUserIdentity, catalog, 
database, tables, dataBatch, timezone);
         } else if (catalog instanceof ExternalCatalog) {
-            partitionsForExternalCatalog(currentUserIdentity, catalog, 
database, tables, dataBatch);
+            partitionsForExternalCatalog(currentUserIdentity, catalog, 
database, tables, dataBatch, timezone);
         }
         result.setDataBatch(dataBatch);
         result.setStatus(new TStatus(TStatusCode.OK));
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/qe/ConnectContextTest.java 
b/fe/fe-core/src/test/java/org/apache/doris/qe/ConnectContextTest.java
index 6ad9532a297..f16bc58a4fc 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/qe/ConnectContextTest.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/qe/ConnectContextTest.java
@@ -31,6 +31,7 @@ import org.junit.Test;
 
 import java.nio.channels.SocketChannel;
 import java.util.List;
+import java.util.Optional;
 
 public class ConnectContextTest {
     @Mocked
@@ -100,7 +101,7 @@ public class ConnectContextTest {
 
         // Thread info
         Assert.assertNotNull(ctx.toThreadInfo(false));
-        List<String> row = ctx.toThreadInfo(false).toRow(101, 1000);
+        List<String> row = ctx.toThreadInfo(false).toRow(101, 1000, 
Optional.empty());
         Assert.assertEquals(14, row.size());
         Assert.assertEquals("Yes", row.get(0));
         Assert.assertEquals("101", row.get(1));
diff --git a/gensrc/thrift/FrontendService.thrift 
b/gensrc/thrift/FrontendService.thrift
index b9f2847e168..fd367244691 100644
--- a/gensrc/thrift/FrontendService.thrift
+++ b/gensrc/thrift/FrontendService.thrift
@@ -1061,6 +1061,7 @@ struct TSchemaTableRequestParams {
     3: optional bool replay_to_other_fe
     4: optional string catalog  // use for table specific queries
     5: optional i64 dbId         // used for table specific queries
+    6: optional string time_zone // used for DATETIME field
 }
 
 struct TFetchSchemaTableDataRequest {
@@ -1717,6 +1718,7 @@ struct TGetColumnInfoResult {
 struct TShowProcessListRequest {
     1: optional bool show_full_sql
     2: optional Types.TUserIdentity current_user_ident
+    3: optional string time_zone
 }
 
 struct TShowProcessListResult {
diff --git 
a/regression-test/data/external_table_p0/info_schema_db/test_information_schema_timezone.out
 
b/regression-test/data/external_table_p0/info_schema_db/test_information_schema_timezone.out
new file mode 100644
index 00000000000..2f715922e84
Binary files /dev/null and 
b/regression-test/data/external_table_p0/info_schema_db/test_information_schema_timezone.out
 differ
diff --git 
a/regression-test/suites/external_table_p0/info_schema_db/test_information_schema_timezone.groovy
 
b/regression-test/suites/external_table_p0/info_schema_db/test_information_schema_timezone.groovy
new file mode 100644
index 00000000000..17b42303f7f
--- /dev/null
+++ 
b/regression-test/suites/external_table_p0/info_schema_db/test_information_schema_timezone.groovy
@@ -0,0 +1,218 @@
+// 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.
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+
+suite("test_information_schema_timezone", 
"p0,external,hive,kerberos,external_docker,external_docker_kerberos") {
+
+    def table_name = "test_information_schema_timezone"
+    sql """ DROP TABLE IF EXISTS ${table_name} """
+    sql """
+    CREATE TABLE IF NOT EXISTS ${table_name} (
+        `id` int(11) NULL,
+        `name` string NULL,
+        `age` int(11) NULL
+        )
+        PARTITION BY RANGE(id)
+        (
+            PARTITION less_than_20 VALUES LESS THAN ("20"),
+            PARTITION between_20_70 VALUES [("20"),("70")),
+            PARTITION more_than_70 VALUES LESS THAN ("151")
+        )
+        DISTRIBUTED BY HASH(id) BUCKETS 3
+        PROPERTIES("replication_num" = "1");
+    """
+    StringBuilder sb = new StringBuilder()
+    int i = 1
+    for (; i < 10; i ++) {
+        sb.append("""
+            (${i}, 'ftw-${i}', ${i + 18}),
+        """)
+    }
+    sb.append("""
+            (${i}, NULL, NULL)
+        """)
+    sql """ INSERT INTO ${table_name} VALUES
+            ${sb.toString()}
+        """
+    qt_select_export """ SELECT * FROM ${table_name} t ORDER BY id; """
+
+    def isEightHoursDiff = {LocalDateTime dateTime1, LocalDateTime dateTime2 
-> 
+        logger.info("dateTime1 = " + dateTime1 + " ; dateTime2 = " + dateTime2)
+        try {
+            int hour1 = dateTime1.getHour();
+            int hour2 = dateTime2.getHour();
+            logger.info("hour1 = " + hour1 + " ; hour2 = " + hour2)
+            
+
+            int difference = Math.abs(hour1 - hour2);
+            return difference == 8 || difference == 24 - 8;
+        } catch (Exception e) {
+            throw exception("Wrong datetime formatter: " + e.getMessage());
+        }
+    }
+
+    // 0. Assert the timezone
+    qt_session_time_zone_UTC """ show variables like "time_zone" """
+
+    // 1. tables
+    List<List<Object>> tables_res_1 = sql """ select CREATE_TIME, UPDATE_TIME 
from information_schema.tables where TABLE_NAME = "${table_name}" """
+    logger.info("tables_res_1 = " + tables_res_1);
+
+    // 2. routines
+    sql """DROP PROC test_information_schema_timezone1"""
+    def procedure_body = "BEGIN DECLARE a int = 1; print a; END;"
+    sql """ CREATE OR REPLACE PROCEDURE test_information_schema_timezone1() 
${procedure_body} """
+    List<List<Object>> routines_res_1 = sql """ select CREATED,LAST_ALTERED 
from information_schema.routines where 
ROUTINE_NAME="TEST_INFORMATION_SCHEMA_TIMEZONE1" """
+    logger.info("routines_res_1 = " + routines_res_1);
+    sql """DROP PROC test_information_schema_timezone1"""
+
+    // 3. partitions
+    List<List<Object>> partitions_res_1 = sql """ select UPDATE_TIME from 
information_schema.partitions where TABLE_NAME = "${table_name}" """
+    logger.info("partitions_res_1 = " + partitions_res_1);
+
+    // 4. processlist
+    List<List<Object>> processlist_res_1 = sql """ 
+            select LOGIN_TIME from information_schema.processlist where INFO 
like "%information_schema.processlist%"
+            """
+    logger.info("processlist_res_1 = " + processlist_res_1);
+    
+    // 5. rowsets
+    def rowsets_table_name_tablets = sql_return_maparray """ show tablets from 
${table_name}; """
+    def tablet_id = rowsets_table_name_tablets[0].TabletId
+    List<List<Object>> rowsets_res_1 = sql """ 
+            select CREATION_TIME, NEWEST_WRITE_TIMESTAMP from 
information_schema.rowsets where TABLET_ID = ${tablet_id}
+            """
+    logger.info("rowsets_res_1 = " + rowsets_res_1);
+    
+    // 6. backend_kerberos_ticket_cache
+    // TODO(ftw): Since there are some problems in kerveros case, we don't 
test this case tempraturely.
+    // String enabled = context.config.otherConfigs.get("enableKerberosTest")
+    String enabled = false 
+    String externalEnvIp = context.config.otherConfigs.get("externalEnvIp")
+    logger.info("enableKerberosTest = " + enabled + " ; externalEnvIp = " + 
externalEnvIp);
+    List<List<Object>> kerberos_cache_res_1 = null
+    if (enabled != null && enabled.equalsIgnoreCase("true")) {
+        sql """
+            CREATE CATALOG IF NOT EXISTS 
test_information_schema_timezone_catalog
+            PROPERTIES ( 
+                "type" = "hms",
+                "hive.metastore.uris" = "thrift://${externalEnvIp}:9583",
+                "fs.defaultFS" = "hdfs://${externalEnvIp}:8520",
+                "hadoop.kerberos.min.seconds.before.relogin" = "5",
+                "hadoop.security.authentication" = "kerberos",
+                
"hadoop.kerberos.principal"="hive/[email protected]",
+                "hadoop.kerberos.keytab" = 
"${keytab_root_dir}/hive-presto-master.keytab",
+                "hive.metastore.sasl.enabled " = "true",
+                "hive.metastore.kerberos.principal" = 
"hive/[email protected]"
+            );
+        """
+
+        sql """ DROP TABLE IF EXISTS 
test_information_schema_timezone_catalog.test_krb_hive_db.test_information_schema_table
 """
+        sql """ CREATE TABLE 
test_information_schema_timezone_catalog.test_krb_hive_db.test_information_schema_table
 (id int, str string, dd date) engine = hive; """
+        sql """ INSERT INTO 
test_information_schema_timezone_catalog.test_krb_hive_db.test_information_schema_table
 values(1, 'krb1', '2023-05-14') """
+        sql """ INSERT INTO 
test_information_schema_timezone_catalog.test_krb_hive_db.test_information_schema_table
 values(2, 'krb2', '2023-05-24') """
+
+        order_qt_select_kerberos """ select * from 
test_information_schema_timezone_catalog.test_krb_hive_db.test_information_schema_table;
 """
+
+        kerberos_cache_res_1 = sql """ 
+                    select START_TIME, EXPIRE_TIME, AUTH_TIME from 
information_schema.backend_kerberos_ticket_cache where 
PRINCIPAL="hive/[email protected]" and KEYTAB = 
"${keytab_root_dir}/hive-presto-master.keytab"
+                """
+        logger.info("kerberos_cache_res_1 = " + kerberos_cache_res_1);
+
+    }
+
+    // 7. active_queries
+    List<List<Object>> active_queries_res_1 = sql """ 
+                select QUERY_START_TIME from information_schema.active_queries 
where SQL like "%information_schema.active_queries%"
+            """
+    logger.info("active_queries_res_1 = " + active_queries_res_1);
+
+    // ------------------- change the time zone
+    sql """ SET time_zone = "UTC" """
+    qt_session_time_zone_UTC  """ show variables like "time_zone" """
+
+    // 1. tables
+    List<List<Object>> tables_res_2 = sql """ select CREATE_TIME, UPDATE_TIME 
from information_schema.tables where TABLE_NAME = "${table_name}" """
+    logger.info("tables_res_2 = " + tables_res_2);
+    assertEquals(true, isEightHoursDiff(tables_res_2[0][0], 
tables_res_1[0][0]))
+    assertEquals(true, isEightHoursDiff(tables_res_2[0][1], 
tables_res_1[0][1]))
+
+    // 2. routines
+    sql """DROP PROC test_information_schema_timezone2"""
+    def procedure_body2 = "BEGIN DECLARE a int = 1; print a; END;"
+    sql """ CREATE OR REPLACE PROCEDURE test_information_schema_timezone2() 
${procedure_body2} """
+    List<List<Object>> routines_res_2 = sql """ select CREATED,LAST_ALTERED 
from information_schema.routines where 
ROUTINE_NAME="TEST_INFORMATION_SCHEMA_TIMEZONE2"; """
+    logger.info("routines_res_2 = " + routines_res_2);
+    sql """DROP PROC test_information_schema_timezone2"""
+    assertEquals(true, isEightHoursDiff(routines_res_1[0][0], 
routines_res_2[0][0]))
+    assertEquals(true, isEightHoursDiff(routines_res_1[0][1], 
routines_res_2[0][1]))
+    
+    
+    // 3. partitions
+    List<List<Object>> partitions_res_2 = sql """ select UPDATE_TIME from 
information_schema.partitions where TABLE_NAME = "${table_name}" """
+    logger.info("partitions_res_2 = " + partitions_res_2);
+    assertEquals(true, isEightHoursDiff(partitions_res_1[0][0], 
partitions_res_2[0][0]))
+
+    // 4. processlist
+    List<List<Object>> processlist_res_2 = sql """ 
+            select LOGIN_TIME from information_schema.processlist where INFO 
like "%information_schema.processlist%"
+            """
+    logger.info("processlist_res_2 = " + processlist_res_2);
+    assertEquals(true, isEightHoursDiff(processlist_res_1[0][0], 
processlist_res_2[0][0]))
+
+    // 5. rowsets
+    List<List<Object>> rowsets_res_2 = sql """ 
+            select CREATION_TIME, NEWEST_WRITE_TIMESTAMP from 
information_schema.rowsets where TABLET_ID = ${tablet_id}
+            """
+    logger.info("rowsets_res_2 = " + rowsets_res_2);
+    assertEquals(true, isEightHoursDiff(rowsets_res_1[0][0], 
rowsets_res_2[0][0]))
+    assertEquals(true, isEightHoursDiff(rowsets_res_1[0][1], 
rowsets_res_2[0][1]))
+
+    // 6. backend_kerberos_ticket_cache
+    if (enabled != null && enabled.equalsIgnoreCase("true")) {
+        List<List<Object>> kerberos_cache_res_2 = sql """ 
+                select START_TIME, EXPIRE_TIME, AUTH_TIME from 
information_schema.backend_kerberos_ticket_cache where 
PRINCIPAL="hive/[email protected]" and KEYTAB = 
"${keytab_root_dir}/hive-presto-master.keytab"
+            """
+        logger.info("kerberos_cache_res_2 = " + kerberos_cache_res_2);
+
+        assertEquals(true, isEightHoursDiff(kerberos_cache_res_1[0][0], 
kerberos_cache_res_2[0][0]))
+        assertEquals(true, isEightHoursDiff(kerberos_cache_res_1[0][1], 
kerberos_cache_res_2[0][1]))
+        assertEquals(true, isEightHoursDiff(kerberos_cache_res_1[0][2], 
kerberos_cache_res_2[0][2]))
+    
+        sql """DROP CATALOG IF EXISTS 
test_information_schema_timezone_catalog"""
+    }
+
+    // 7. active_queries
+    List<List<Object>> active_queries_res_2 = sql """ 
+                select QUERY_START_TIME from information_schema.active_queries 
where SQL like "%information_schema.active_queries%"
+            """
+    logger.info("active_queries_res_2 = " + active_queries_res_2);
+
+    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd 
HH:mm:ss");
+    try {
+        LocalDateTime dateTime1 = 
LocalDateTime.parse(active_queries_res_1[0][0], formatter);
+        LocalDateTime dateTime2 = 
LocalDateTime.parse(active_queries_res_2[0][0], formatter);
+        assertEquals(true, isEightHoursDiff(dateTime1, dateTime2))
+    } catch (Exception e) {
+        throw exception("Wrong datetime formatter: " + e.getMessage())
+    }
+
+    // set time_zone back
+    sql """ SET time_zone = "Asia/Shanghai" """
+}


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


Reply via email to