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]