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

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


The following commit(s) were added to refs/heads/branch-2.1 by this push:
     new 3604d63184f [Branch 2.1] backport systable PR 
(#34384,#40153,#40456,#40455,#40568) (#40687)
3604d63184f is described below

commit 3604d63184f431371bfc610a012a9e65d355f3ea
Author: Vallish Pai <vallish...@gmail.com>
AuthorDate: Thu Sep 12 09:20:09 2024 +0530

    [Branch 2.1] backport systable PR (#34384,#40153,#40456,#40455,#40568) 
(#40687)
    
    backport
    https://github.com/apache/doris/pull/40568
    https://github.com/apache/doris/pull/40455
    https://github.com/apache/doris/pull/40456
    https://github.com/apache/doris/pull/40153
    https://github.com/apache/doris/pull/34384
    
    Test result:
    2024-09-11 11:00:45.618 INFO [suite-thread-1] (SuiteContext.groovy:309)
    - Recover original connection
    2024-09-11 11:00:45.619 INFO [suite-thread-1] (Suite.groovy:359) -
    Execute sql: REVOKE SELECT_PRIV ON
    test_partitions_schema_db.duplicate_table FROM partitions_user
    2024-09-11 11:00:45.625 INFO [suite-thread-1] (SuiteContext.groovy:299)
    - Create new connection for user 'partitions_user'
    2024-09-11 11:00:45.632 INFO [suite-thread-1] (Suite.groovy:1162) -
    Execute tag: select_check_5, sql: select
    
TABLE_CATALOG,TABLE_SCHEMA,TABLE_NAME,PARTITION_NAME,SUBPARTITION_NAME,PARTITION_ORDINAL_POSITION,SUBPARTITION_ORDINAL_POSITION,PARTITION_METHOD,SUBPARTITION_METHOD,PARTITION_EXPRESSION,SUBPARTITION_EXPRESSION,PARTITION_DESCRIPTION,TABLE_ROWS,AVG_ROW_LENGTH,DATA_LENGTH,MAX_DATA_LENGTH,INDEX_LENGTH,DATA_FREE,CHECKSUM,PARTITION_COMMENT,NODEGROUP,TABLESPACE_NAME
    from information_schema.partitions where
    table_schema="test_partitions_schema_db" order by
    
TABLE_CATALOG,TABLE_SCHEMA,TABLE_NAME,PARTITION_NAME,SUBPARTITION_NAME,PARTITION_ORDINAL_POSITION,SUBPARTITION_ORDINAL_POSITION,PARTITION_METHOD,SUBPARTITION_METHOD,PARTITION_EXPRESSION,SUBPARTITION_EXPRESSION,PARTITION_DESCRIPTION,TABLE_ROWS,AVG_ROW_LENGTH,DATA_LENGTH,MAX_DATA_LENGTH,INDEX_LENGTH,DATA_FREE,CHECKSUM,PARTITION_COMMENT,NODEGROUP,TABLESPACE_NAME
    2024-09-11 11:00:45.644 INFO [suite-thread-1] (SuiteContext.groovy:309)
    - Recover original connection
    2024-09-11 11:00:45.645 INFO [suite-thread-1] (ScriptContext.groovy:120)
    - Run test_partitions_schema in
    
/root/doris/workspace/doris/regression-test/suites/query_p0/system/test_partitions_schema.groovy
    succeed
    2024-09-11 11:00:45.652 INFO [main] (RegressionTest.groovy:259) - Start
    to run single scripts
    2024-09-11 11:01:10.321 INFO [main] (RegressionTest.groovy:380) -
    Success suites:
    
    
/root/doris/workspace/doris/regression-test/suites/query_p0/system/test_partitions_schema.groovy:
    group=default,p0, name=test_partitions_schema
    2024-09-11 11:01:10.322 INFO [main] (RegressionTest.groovy:459) - All
    suites success.
     ____   _    ____ ____  _____ ____
    |  _ \ / \  / ___/ ___|| ____|  _ \
    | |_) / _ \ \___ \___ \|  _| | | | |
    |  __/ ___ \ ___) |__) | |___| |_| |
    |_| /_/   \_\____/____/|_____|____/
    
    2024-09-11 11:01:10.322 INFO [main] (RegressionTest.groovy:410) - Test 1
    suites, failed 0 suites, fatal 0 scripts, skipped 0 scripts
    2024-09-11 11:01:10.322 INFO [main] (RegressionTest.groovy:119) - Test
    finished
    
    
    2024-09-11 11:03:00.712 INFO [suite-thread-1] (Suite.groovy:1162) -
    Execute tag: select_check_5, sql: select * from
    information_schema.table_options ORDER BY
    
TABLE_CATALOG,TABLE_SCHEMA,TABLE_NAME,TABLE_MODEL,TABLE_MODEL_KEY,DISTRIBUTE_KEY,DISTRIBUTE_TYPE,BUCKETS_NUM,PARTITION_NUM;
    2024-09-11 11:03:00.729 INFO [suite-thread-1] (SuiteContext.groovy:309)
    - Recover original connection
    2024-09-11 11:03:00.731 INFO [suite-thread-1] (ScriptContext.groovy:120)
    - Run test_table_options in
    
/root/doris/workspace/doris/regression-test/suites/query_p0/system/test_table_options.groovy
    succeed
    2024-09-11 11:03:04.817 INFO [main] (RegressionTest.groovy:259) - Start
    to run single scripts
    2024-09-11 11:03:28.741 INFO [main] (RegressionTest.groovy:380) -
    Success suites:
    
    
/root/doris/workspace/doris/regression-test/suites/query_p0/system/test_table_options.groovy:
    group=default,p0, name=test_table_options
    2024-09-11 11:03:28.742 INFO [main] (RegressionTest.groovy:459) - All
    suites success.
     ____   _    ____ ____  _____ ____
    |  _ \ / \  / ___/ ___|| ____|  _ \
    | |_) / _ \ \___ \___ \|  _| | | | |
    |  __/ ___ \ ___) |__) | |___| |_| |
    |_| /_/   \_\____/____/|_____|____/
    
    2024-09-11 11:03:28.742 INFO [main] (RegressionTest.groovy:410) - Test 1
    suites, failed 0 suites, fatal 0 scripts, skipped 0 scripts
    2024-09-11 11:03:28.742 INFO [main] (RegressionTest.groovy:119) - Test
    finished
    
    
    *************************** 7. row ***************************
                 PartitionId: 18035
               PartitionName: p100
              VisibleVersion: 2
          VisibleVersionTime: 2024-09-11 10:59:28
                       State: NORMAL
                PartitionKey: col_1
    Range: [types: [INT]; keys: [83647]; ..types: [INT]; keys: [2147483647];
    )
             DistributionKey: pk
                     Buckets: 10
              ReplicationNum: 1
               StorageMedium: HDD
                CooldownTime: 9999-12-31 15:59:59
         RemoteStoragePolicy:
    LastConsistencyCheckTime: NULL
                    DataSize: 2.872 KB
                  IsInMemory: false
           ReplicaAllocation: tag.location.default: 1
                   IsMutable: true
          SyncWithBaseTables: true
                UnsyncTables: NULL
            CommittedVersion: 2
                    RowCount: 4
    7 rows in set (0.01 sec)
    
    ---------
    
    Co-authored-by: Mingyu Chen <morningman....@gmail.com>
---
 be/src/exec/schema_scanner.cpp                     |  14 ++
 .../schema_active_queries_scanner.cpp              |  37 +--
 .../schema_scanner/schema_partitions_scanner.cpp   | 120 +++++++--
 .../schema_scanner/schema_partitions_scanner.h     |  15 +-
 .../exec/schema_scanner/schema_routine_scanner.cpp |  35 +--
 .../exec/schema_scanner/schema_scanner_helper.cpp  |  73 ++++++
 ...artitions_scanner.h => schema_scanner_helper.h} |  33 +--
 .../schema_table_options_scanner.cpp               | 173 +++++++++++++
 ...ns_scanner.h => schema_table_options_scanner.h} |  27 +-
 be/src/runtime/runtime_query_statistics_mgr.cpp    |  47 +---
 be/src/runtime/workload_group/workload_group.cpp   |   1 +
 .../workload_group/workload_group_manager.cpp      |  35 +--
 .../org/apache/doris/analysis/SchemaTableType.java |   5 +-
 .../apache/doris/catalog/ListPartitionItem.java    |   8 +
 .../java/org/apache/doris/catalog/OlapTable.java   |  14 ++
 .../java/org/apache/doris/catalog/Partition.java   |  19 ++
 .../org/apache/doris/catalog/PartitionInfo.java    |  13 +
 .../org/apache/doris/catalog/PartitionItem.java    |   4 +
 .../apache/doris/catalog/RangePartitionItem.java   |   8 +
 .../java/org/apache/doris/catalog/SchemaTable.java |  12 +
 .../org/apache/doris/catalog/TableProperty.java    |  11 +
 .../doris/common/proc/PartitionsProcDir.java       |   4 +
 .../doris/tablefunction/MetadataGenerator.java     | 275 ++++++++++++++++++++-
 gensrc/thrift/FrontendService.thrift               |   1 +
 .../query_p0/system/test_partitions_schema.out     |  48 ++++
 .../data/query_p0/system/test_query_sys_tables.out |   2 -
 .../data/query_p0/system/test_table_options.out    |  27 ++
 .../query_p0/system/test_partitions_schema.groovy  | 195 +++++++++++++++
 .../query_p0/system/test_query_sys_tables.groovy   |   6 +-
 .../query_p0/system/test_table_options.groovy      | 217 ++++++++++++++++
 30 files changed, 1291 insertions(+), 188 deletions(-)

diff --git a/be/src/exec/schema_scanner.cpp b/be/src/exec/schema_scanner.cpp
index 933de634350..ce75c6d0cd1 100644
--- a/be/src/exec/schema_scanner.cpp
+++ b/be/src/exec/schema_scanner.cpp
@@ -43,6 +43,7 @@
 #include "exec/schema_scanner/schema_rowsets_scanner.h"
 #include "exec/schema_scanner/schema_schema_privileges_scanner.h"
 #include "exec/schema_scanner/schema_schemata_scanner.h"
+#include "exec/schema_scanner/schema_table_options_scanner.h"
 #include "exec/schema_scanner/schema_table_privileges_scanner.h"
 #include "exec/schema_scanner/schema_table_properties_scanner.h"
 #include "exec/schema_scanner/schema_tables_scanner.h"
@@ -239,6 +240,8 @@ std::unique_ptr<SchemaScanner> 
SchemaScanner::create(TSchemaTableType::type type
         return SchemaTablePropertiesScanner::create_unique();
     case TSchemaTableType::SCH_CATALOG_META_CACHE_STATISTICS:
         return SchemaCatalogMetaCacheStatsScanner::create_unique();
+    case TSchemaTableType::SCH_TABLE_OPTIONS:
+        return SchemaTableOptionsScanner::create_unique();
     default:
         return SchemaDummyScanner::create_unique();
         break;
@@ -449,6 +452,17 @@ Status SchemaScanner::insert_block_column(TCell cell, int 
col_index, vectorized:
         break;
     }
 
+    case TYPE_DATETIME: {
+        std::vector<void*> datas(1);
+        VecDateTimeValue src[1];
+        src[0].from_date_str(cell.stringVal.data(), cell.stringVal.size());
+        datas[0] = src;
+        auto data = datas[0];
+        
reinterpret_cast<vectorized::ColumnVector<vectorized::Int64>*>(col_ptr)->insert_data(
+                reinterpret_cast<char*>(data), 0);
+        nullable_column->get_null_map_data().emplace_back(0);
+        break;
+    }
     default: {
         std::stringstream ss;
         ss << "unsupported column type:" << type;
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 46522a36242..6aa6e758999 100644
--- a/be/src/exec/schema_scanner/schema_active_queries_scanner.cpp
+++ b/be/src/exec/schema_scanner/schema_active_queries_scanner.cpp
@@ -98,41 +98,12 @@ Status 
SchemaActiveQueriesScanner::_get_active_queries_block_from_fe() {
         }
     }
 
-    // todo(wb) reuse this callback function
-    auto insert_string_value = [&](int col_index, std::string str_val, 
vectorized::Block* block) {
-        vectorized::MutableColumnPtr mutable_col_ptr;
-        mutable_col_ptr = 
std::move(*block->get_by_position(col_index).column).assume_mutable();
-        auto* nullable_column =
-                
reinterpret_cast<vectorized::ColumnNullable*>(mutable_col_ptr.get());
-        vectorized::IColumn* col_ptr = &nullable_column->get_nested_column();
-        
reinterpret_cast<vectorized::ColumnString*>(col_ptr)->insert_data(str_val.data(),
-                                                                          
str_val.size());
-        nullable_column->get_null_map_data().emplace_back(0);
-    };
-    auto insert_int_value = [&](int col_index, int64_t int_val, 
vectorized::Block* block) {
-        vectorized::MutableColumnPtr mutable_col_ptr;
-        mutable_col_ptr = 
std::move(*block->get_by_position(col_index).column).assume_mutable();
-        auto* nullable_column =
-                
reinterpret_cast<vectorized::ColumnNullable*>(mutable_col_ptr.get());
-        vectorized::IColumn* col_ptr = &nullable_column->get_nested_column();
-        
reinterpret_cast<vectorized::ColumnVector<vectorized::Int64>*>(col_ptr)->insert_value(
-                int_val);
-        nullable_column->get_null_map_data().emplace_back(0);
-    };
-
     for (int i = 0; i < result_data.size(); i++) {
         TRow row = result_data[i];
-
-        insert_string_value(0, row.column_value[0].stringVal, 
_active_query_block.get());
-        insert_string_value(1, row.column_value[1].stringVal, 
_active_query_block.get());
-        insert_int_value(2, row.column_value[2].longVal, 
_active_query_block.get());
-        insert_int_value(3, row.column_value[3].longVal, 
_active_query_block.get());
-        insert_string_value(4, row.column_value[4].stringVal, 
_active_query_block.get());
-        insert_string_value(5, row.column_value[5].stringVal, 
_active_query_block.get());
-        insert_string_value(6, row.column_value[6].stringVal, 
_active_query_block.get());
-        insert_string_value(7, row.column_value[7].stringVal, 
_active_query_block.get());
-        insert_string_value(8, row.column_value[8].stringVal, 
_active_query_block.get());
-        insert_string_value(9, row.column_value[9].stringVal, 
_active_query_block.get());
+        for (int j = 0; j < _s_tbls_columns.size(); j++) {
+            RETURN_IF_ERROR(insert_block_column(row.column_value[j], j, 
_active_query_block.get(),
+                                                _s_tbls_columns[j].type));
+        }
     }
     return Status::OK();
 }
diff --git a/be/src/exec/schema_scanner/schema_partitions_scanner.cpp 
b/be/src/exec/schema_scanner/schema_partitions_scanner.cpp
index ea7394e15e1..ebe2bd3b70e 100644
--- a/be/src/exec/schema_scanner/schema_partitions_scanner.cpp
+++ b/be/src/exec/schema_scanner/schema_partitions_scanner.cpp
@@ -22,10 +22,13 @@
 #include <stdint.h>
 
 #include "exec/schema_scanner/schema_helper.h"
-#include "runtime/decimalv2_value.h"
-#include "runtime/define_primitive_type.h"
-#include "util/runtime_profile.h"
+#include "runtime/client_cache.h"
+#include "runtime/exec_env.h"
+#include "runtime/runtime_state.h"
+#include "util/thrift_rpc_helper.h"
 #include "vec/common/string_ref.h"
+#include "vec/core/block.h"
+#include "vec/data_types/data_type_factory.hpp"
 
 namespace doris {
 class RuntimeState;
@@ -63,9 +66,7 @@ std::vector<SchemaScanner::ColumnDesc> 
SchemaPartitionsScanner::_s_tbls_columns
 };
 
 SchemaPartitionsScanner::SchemaPartitionsScanner()
-        : SchemaScanner(_s_tbls_columns, TSchemaTableType::SCH_PARTITIONS),
-          _db_index(0),
-          _table_index(0) {}
+        : SchemaScanner(_s_tbls_columns, TSchemaTableType::SCH_PARTITIONS) {}
 
 SchemaPartitionsScanner::~SchemaPartitionsScanner() {}
 
@@ -75,21 +76,14 @@ Status SchemaPartitionsScanner::start(RuntimeState* state) {
     }
     SCOPED_TIMER(_get_db_timer);
     TGetDbsParams db_params;
-    if (nullptr != _param->common_param->db) {
+    if (_param->common_param->db) {
         db_params.__set_pattern(*(_param->common_param->db));
     }
-    if (nullptr != _param->common_param->catalog) {
+    if (_param->common_param->catalog) {
         db_params.__set_catalog(*(_param->common_param->catalog));
     }
-    if (nullptr != _param->common_param->current_user_ident) {
+    if (_param->common_param->current_user_ident) {
         
db_params.__set_current_user_ident(*(_param->common_param->current_user_ident));
-    } else {
-        if (nullptr != _param->common_param->user) {
-            db_params.__set_user(*(_param->common_param->user));
-        }
-        if (nullptr != _param->common_param->user_ip) {
-            db_params.__set_user_ip(*(_param->common_param->user_ip));
-        }
     }
 
     if (nullptr != _param->common_param->ip && 0 != 
_param->common_param->port) {
@@ -98,17 +92,109 @@ Status SchemaPartitionsScanner::start(RuntimeState* state) 
{
     } else {
         return Status::InternalError("IP or port doesn't exists");
     }
+    _block_rows_limit = state->batch_size();
+    _rpc_timeout_ms = state->execution_timeout() * 1000;
     return Status::OK();
 }
 
+Status SchemaPartitionsScanner::get_onedb_info_from_fe(int64_t dbId) {
+    TNetworkAddress master_addr = 
ExecEnv::GetInstance()->master_info()->network_address;
+
+    TSchemaTableRequestParams schema_table_request_params;
+    for (int i = 0; i < _s_tbls_columns.size(); i++) {
+        schema_table_request_params.__isset.columns_name = true;
+        
schema_table_request_params.columns_name.emplace_back(_s_tbls_columns[i].name);
+    }
+    
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);
+
+    TFetchSchemaTableDataRequest request;
+    request.__set_schema_table_name(TSchemaTableName::PARTITIONS);
+    request.__set_schema_table_params(schema_table_request_params);
+
+    TFetchSchemaTableDataResult result;
+
+    RETURN_IF_ERROR(ThriftRpcHelper::rpc<FrontendServiceClient>(
+            master_addr.hostname, master_addr.port,
+            [&request, &result](FrontendServiceConnection& client) {
+                client->fetchSchemaTableData(result, request);
+            },
+            _rpc_timeout_ms));
+
+    Status status(Status::create(result.status));
+    if (!status.ok()) {
+        LOG(WARNING) << "fetch table options from FE failed, errmsg=" << 
status;
+        return status;
+    }
+    std::vector<TRow> result_data = result.data_batch;
+
+    _partitions_block = vectorized::Block::create_unique();
+    for (int i = 0; i < _s_tbls_columns.size(); ++i) {
+        TypeDescriptor descriptor(_s_tbls_columns[i].type);
+        auto data_type = 
vectorized::DataTypeFactory::instance().create_data_type(descriptor, true);
+        _partitions_block->insert(vectorized::ColumnWithTypeAndName(
+                data_type->create_column(), data_type, 
_s_tbls_columns[i].name));
+    }
+    _partitions_block->reserve(_block_rows_limit);
+    if (result_data.size() > 0) {
+        int col_size = result_data[0].column_value.size();
+        if (col_size != _s_tbls_columns.size()) {
+            return Status::InternalError<false>("table options schema is not 
match for FE and BE");
+        }
+    }
+
+    for (int i = 0; i < result_data.size(); i++) {
+        TRow row = result_data[i];
+        for (int j = 0; j < _s_tbls_columns.size(); j++) {
+            RETURN_IF_ERROR(insert_block_column(row.column_value[j], j, 
_partitions_block.get(),
+                                                _s_tbls_columns[j].type));
+        }
+    }
+    return Status::OK();
+}
+
+bool SchemaPartitionsScanner::check_and_mark_eos(bool* eos) const {
+    if (_row_idx == _total_rows) {
+        *eos = true;
+        if (_db_index < _db_result.db_ids.size()) {
+            *eos = false;
+        }
+        return true;
+    }
+    return false;
+}
+
 Status SchemaPartitionsScanner::get_next_block_internal(vectorized::Block* 
block, bool* eos) {
     if (!_is_init) {
         return Status::InternalError("Used before initialized.");
     }
+
     if (nullptr == block || nullptr == eos) {
         return Status::InternalError("input pointer is nullptr.");
     }
-    *eos = true;
+
+    if ((_partitions_block == nullptr) || (_row_idx == _total_rows)) {
+        if (_db_index < _db_result.db_ids.size()) {
+            
RETURN_IF_ERROR(get_onedb_info_from_fe(_db_result.db_ids[_db_index]));
+            _row_idx = 0; // reset row index so that it start filling for next 
block.
+            _total_rows = _partitions_block->rows();
+            _db_index++;
+        }
+    }
+
+    if (check_and_mark_eos(eos)) {
+        return Status::OK();
+    }
+
+    int current_batch_rows = std::min(_block_rows_limit, _total_rows - 
_row_idx);
+    vectorized::MutableBlock mblock = 
vectorized::MutableBlock::build_mutable_block(block);
+    RETURN_IF_ERROR(mblock.add_rows(_partitions_block.get(), _row_idx, 
current_batch_rows));
+    _row_idx += current_batch_rows;
+
+    if (!check_and_mark_eos(eos)) {
+        *eos = false;
+    }
     return Status::OK();
 }
 
diff --git a/be/src/exec/schema_scanner/schema_partitions_scanner.h 
b/be/src/exec/schema_scanner/schema_partitions_scanner.h
index 87e55db984a..3c246f36eec 100644
--- a/be/src/exec/schema_scanner/schema_partitions_scanner.h
+++ b/be/src/exec/schema_scanner/schema_partitions_scanner.h
@@ -40,11 +40,18 @@ public:
     Status start(RuntimeState* state) override;
     Status get_next_block_internal(vectorized::Block* block, bool* eos) 
override;
 
-    int _db_index;
-    int _table_index;
-    TGetDbsResult _db_result;
-    TListTableStatusResult _table_result;
     static std::vector<SchemaScanner::ColumnDesc> _s_tbls_columns;
+
+private:
+    Status get_onedb_info_from_fe(int64_t dbId);
+    bool check_and_mark_eos(bool* eos) const;
+    int _block_rows_limit = 4096;
+    int _db_index = 0;
+    TGetDbsResult _db_result;
+    int _row_idx = 0;
+    int _total_rows = 0;
+    std::unique_ptr<vectorized::Block> _partitions_block = nullptr;
+    int _rpc_timeout_ms = 3000;
 };
 
 } // namespace doris
diff --git a/be/src/exec/schema_scanner/schema_routine_scanner.cpp 
b/be/src/exec/schema_scanner/schema_routine_scanner.cpp
index 8c263c99d2d..e8d95f0abd6 100644
--- a/be/src/exec/schema_scanner/schema_routine_scanner.cpp
+++ b/be/src/exec/schema_scanner/schema_routine_scanner.cpp
@@ -99,43 +99,12 @@ Status SchemaRoutinesScanner::get_block_from_fe() {
             return Status::InternalError<false>("routine table schema is not 
match for FE and BE");
         }
     }
-    auto insert_string_value = [&](int col_index, std::string str_val, 
vectorized::Block* block) {
-        vectorized::MutableColumnPtr mutable_col_ptr;
-        mutable_col_ptr = 
std::move(*block->get_by_position(col_index).column).assume_mutable();
-        auto* nullable_column =
-                
reinterpret_cast<vectorized::ColumnNullable*>(mutable_col_ptr.get());
-        vectorized::IColumn* col_ptr = &nullable_column->get_nested_column();
-        
reinterpret_cast<vectorized::ColumnString*>(col_ptr)->insert_data(str_val.data(),
-                                                                          
str_val.size());
-        nullable_column->get_null_map_data().emplace_back(0);
-    };
-    auto insert_datetime_value = [&](int col_index, const std::vector<void*>& 
datas,
-                                     vectorized::Block* block) {
-        vectorized::MutableColumnPtr mutable_col_ptr;
-        mutable_col_ptr = 
std::move(*block->get_by_position(col_index).column).assume_mutable();
-        auto* nullable_column =
-                
reinterpret_cast<vectorized::ColumnNullable*>(mutable_col_ptr.get());
-        vectorized::IColumn* col_ptr = &nullable_column->get_nested_column();
-        auto data = datas[0];
-        
reinterpret_cast<vectorized::ColumnVector<vectorized::Int64>*>(col_ptr)->insert_data(
-                reinterpret_cast<char*>(data), 0);
-        nullable_column->get_null_map_data().emplace_back(0);
-    };
 
     for (int i = 0; i < result_data.size(); i++) {
         TRow row = result_data[i];
-
         for (int j = 0; j < _s_tbls_columns.size(); j++) {
-            if (_s_tbls_columns[j].type == TYPE_DATETIME) {
-                std::vector<void*> datas(1);
-                VecDateTimeValue src[1];
-                src[0].from_date_str(row.column_value[j].stringVal.data(),
-                                     row.column_value[j].stringVal.size());
-                datas[0] = src;
-                insert_datetime_value(j, datas, _routines_block.get());
-            } else {
-                insert_string_value(j, row.column_value[j].stringVal, 
_routines_block.get());
-            }
+            RETURN_IF_ERROR(insert_block_column(row.column_value[j], j, 
_routines_block.get(),
+                                                _s_tbls_columns[j].type));
         }
     }
     return Status::OK();
diff --git a/be/src/exec/schema_scanner/schema_scanner_helper.cpp 
b/be/src/exec/schema_scanner/schema_scanner_helper.cpp
new file mode 100644
index 00000000000..fc42044a29c
--- /dev/null
+++ b/be/src/exec/schema_scanner/schema_scanner_helper.cpp
@@ -0,0 +1,73 @@
+// 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.
+
+#include "exec/schema_scanner/schema_scanner_helper.h"
+
+#include "runtime/client_cache.h"
+#include "runtime/exec_env.h"
+#include "runtime/runtime_state.h"
+#include "util/thrift_rpc_helper.h"
+#include "vec/common/string_ref.h"
+#include "vec/core/block.h"
+#include "vec/data_types/data_type_factory.hpp"
+
+namespace doris {
+
+void SchemaScannerHelper::insert_string_value(int col_index, std::string 
str_val,
+                                              vectorized::Block* block) {
+    vectorized::MutableColumnPtr mutable_col_ptr;
+    mutable_col_ptr = 
std::move(*block->get_by_position(col_index).column).assume_mutable();
+    auto* nullable_column = 
reinterpret_cast<vectorized::ColumnNullable*>(mutable_col_ptr.get());
+    vectorized::IColumn* col_ptr = &nullable_column->get_nested_column();
+    
reinterpret_cast<vectorized::ColumnString*>(col_ptr)->insert_data(str_val.data(),
+                                                                      
str_val.size());
+    nullable_column->get_null_map_data().emplace_back(0);
+}
+
+void SchemaScannerHelper::insert_datetime_value(int col_index, const 
std::vector<void*>& datas,
+                                                vectorized::Block* block) {
+    vectorized::MutableColumnPtr mutable_col_ptr;
+    mutable_col_ptr = 
std::move(*block->get_by_position(col_index).column).assume_mutable();
+    auto* nullable_column = 
reinterpret_cast<vectorized::ColumnNullable*>(mutable_col_ptr.get());
+    vectorized::IColumn* col_ptr = &nullable_column->get_nested_column();
+    auto data = datas[0];
+    
reinterpret_cast<vectorized::ColumnVector<vectorized::Int64>*>(col_ptr)->insert_data(
+            reinterpret_cast<char*>(data), 0);
+    nullable_column->get_null_map_data().emplace_back(0);
+}
+
+void SchemaScannerHelper::insert_int_value(int col_index, int64_t int_val,
+                                           vectorized::Block* block) {
+    vectorized::MutableColumnPtr mutable_col_ptr;
+    mutable_col_ptr = 
std::move(*block->get_by_position(col_index).column).assume_mutable();
+    auto* nullable_column = 
reinterpret_cast<vectorized::ColumnNullable*>(mutable_col_ptr.get());
+    vectorized::IColumn* col_ptr = &nullable_column->get_nested_column();
+    
reinterpret_cast<vectorized::ColumnVector<vectorized::Int64>*>(col_ptr)->insert_value(int_val);
+    nullable_column->get_null_map_data().emplace_back(0);
+}
+
+void SchemaScannerHelper::insert_double_value(int col_index, double double_val,
+                                              vectorized::Block* block) {
+    vectorized::MutableColumnPtr mutable_col_ptr;
+    mutable_col_ptr = 
std::move(*block->get_by_position(col_index).column).assume_mutable();
+    auto* nullable_column = 
reinterpret_cast<vectorized::ColumnNullable*>(mutable_col_ptr.get());
+    vectorized::IColumn* col_ptr = &nullable_column->get_nested_column();
+    
reinterpret_cast<vectorized::ColumnVector<vectorized::Float64>*>(col_ptr)->insert_value(
+            double_val);
+    nullable_column->get_null_map_data().emplace_back(0);
+}
+} // namespace doris
diff --git a/be/src/exec/schema_scanner/schema_partitions_scanner.h 
b/be/src/exec/schema_scanner/schema_scanner_helper.h
similarity index 58%
copy from be/src/exec/schema_scanner/schema_partitions_scanner.h
copy to be/src/exec/schema_scanner/schema_scanner_helper.h
index 87e55db984a..c9fe8881ddb 100644
--- a/be/src/exec/schema_scanner/schema_partitions_scanner.h
+++ b/be/src/exec/schema_scanner/schema_scanner_helper.h
@@ -15,36 +15,29 @@
 // specific language governing permissions and limitations
 // under the License.
 
-#pragma once
+#ifndef _SCHEMA_SCANNER_HELPER_H_
 
-#include <gen_cpp/FrontendService_types.h>
+#include <stdint.h>
 
+#include <string>
 #include <vector>
 
-#include "common/status.h"
-#include "exec/schema_scanner.h"
-
+// this is a util class which can be used by all shema scanner
+// all common functions are added in this class.
 namespace doris {
-class RuntimeState;
+
 namespace vectorized {
 class Block;
 } // namespace vectorized
-
-class SchemaPartitionsScanner : public SchemaScanner {
-    ENABLE_FACTORY_CREATOR(SchemaPartitionsScanner);
-
+class SchemaScannerHelper {
 public:
-    SchemaPartitionsScanner();
-    ~SchemaPartitionsScanner() override;
-
-    Status start(RuntimeState* state) override;
-    Status get_next_block_internal(vectorized::Block* block, bool* eos) 
override;
+    static void insert_string_value(int col_index, std::string str_val, 
vectorized::Block* block);
+    static void insert_datetime_value(int col_index, const std::vector<void*>& 
datas,
+                                      vectorized::Block* block);
 
-    int _db_index;
-    int _table_index;
-    TGetDbsResult _db_result;
-    TListTableStatusResult _table_result;
-    static std::vector<SchemaScanner::ColumnDesc> _s_tbls_columns;
+    static void insert_int_value(int col_index, int64_t int_val, 
vectorized::Block* block);
+    static void insert_double_value(int col_index, double double_val, 
vectorized::Block* block);
 };
 
 } // namespace doris
+#endif
diff --git a/be/src/exec/schema_scanner/schema_table_options_scanner.cpp 
b/be/src/exec/schema_scanner/schema_table_options_scanner.cpp
new file mode 100644
index 00000000000..7465d9fe7ae
--- /dev/null
+++ b/be/src/exec/schema_scanner/schema_table_options_scanner.cpp
@@ -0,0 +1,173 @@
+// 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.
+
+#include "exec/schema_scanner/schema_table_options_scanner.h"
+
+#include "exec/schema_scanner/schema_helper.h"
+#include "runtime/client_cache.h"
+#include "runtime/exec_env.h"
+#include "runtime/runtime_state.h"
+#include "util/thrift_rpc_helper.h"
+#include "vec/common/string_ref.h"
+#include "vec/core/block.h"
+#include "vec/data_types/data_type_factory.hpp"
+
+namespace doris {
+std::vector<SchemaScanner::ColumnDesc> 
SchemaTableOptionsScanner::_s_tbls_columns = {
+        {"TABLE_CATALOG", TYPE_VARCHAR, sizeof(StringRef), true},
+        {"TABLE_SCHEMA", TYPE_VARCHAR, sizeof(StringRef), true},
+        {"TABLE_NAME", TYPE_VARCHAR, sizeof(StringRef), true},
+        {"TABLE_MODEL", TYPE_STRING, sizeof(StringRef), true},
+        {"TABLE_MODEL_KEY", TYPE_STRING, sizeof(StringRef), true},
+        {"DISTRIBUTE_KEY", TYPE_STRING, sizeof(StringRef), true},
+        {"DISTRIBUTE_TYPE", TYPE_STRING, sizeof(StringRef), true},
+        {"BUCKETS_NUM", TYPE_INT, sizeof(int32_t), true},
+        {"PARTITION_NUM", TYPE_INT, sizeof(int32_t), true},
+};
+
+SchemaTableOptionsScanner::SchemaTableOptionsScanner()
+        : SchemaScanner(_s_tbls_columns, TSchemaTableType::SCH_TABLE_OPTIONS) 
{}
+
+Status SchemaTableOptionsScanner::start(RuntimeState* state) {
+    if (!_is_init) {
+        return Status::InternalError("used before initialized.");
+    }
+
+    // first get the all the database specific to current catalog
+    SCOPED_TIMER(_get_db_timer);
+    TGetDbsParams db_params;
+
+    if (_param->common_param->catalog) {
+        db_params.__set_catalog(*(_param->common_param->catalog));
+    }
+    if (_param->common_param->current_user_ident) {
+        
db_params.__set_current_user_ident(*(_param->common_param->current_user_ident));
+    }
+
+    if (_param->common_param->ip && 0 != _param->common_param->port) {
+        RETURN_IF_ERROR(SchemaHelper::get_db_names(
+                *(_param->common_param->ip), _param->common_param->port, 
db_params, &_db_result));
+    } else {
+        return Status::InternalError("IP or port doesn't exists");
+    }
+    _block_rows_limit = state->batch_size();
+    _rpc_timeout_ms = state->execution_timeout() * 1000;
+    return Status::OK();
+}
+
+Status SchemaTableOptionsScanner::get_onedb_info_from_fe(int64_t dbId) {
+    TNetworkAddress master_addr = 
ExecEnv::GetInstance()->master_info()->network_address;
+
+    TSchemaTableRequestParams schema_table_request_params;
+    for (int i = 0; i < _s_tbls_columns.size(); i++) {
+        schema_table_request_params.__isset.columns_name = true;
+        
schema_table_request_params.columns_name.emplace_back(_s_tbls_columns[i].name);
+    }
+    
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);
+
+    TFetchSchemaTableDataRequest request;
+    request.__set_schema_table_name(TSchemaTableName::TABLE_OPTIONS);
+    request.__set_schema_table_params(schema_table_request_params);
+
+    TFetchSchemaTableDataResult result;
+
+    RETURN_IF_ERROR(ThriftRpcHelper::rpc<FrontendServiceClient>(
+            master_addr.hostname, master_addr.port,
+            [&request, &result](FrontendServiceConnection& client) {
+                client->fetchSchemaTableData(result, request);
+            },
+            _rpc_timeout_ms));
+
+    Status status(Status::create(result.status));
+    if (!status.ok()) {
+        LOG(WARNING) << "fetch table options from FE failed, errmsg=" << 
status;
+        return status;
+    }
+    std::vector<TRow> result_data = result.data_batch;
+
+    _tableoptions_block = vectorized::Block::create_unique();
+    for (int i = 0; i < _s_tbls_columns.size(); ++i) {
+        TypeDescriptor descriptor(_s_tbls_columns[i].type);
+        auto data_type = 
vectorized::DataTypeFactory::instance().create_data_type(descriptor, true);
+        _tableoptions_block->insert(vectorized::ColumnWithTypeAndName(
+                data_type->create_column(), data_type, 
_s_tbls_columns[i].name));
+    }
+    _tableoptions_block->reserve(_block_rows_limit);
+    if (result_data.size() > 0) {
+        int col_size = result_data[0].column_value.size();
+        if (col_size != _s_tbls_columns.size()) {
+            return Status::InternalError<false>("table options schema is not 
match for FE and BE");
+        }
+    }
+
+    for (int i = 0; i < result_data.size(); i++) {
+        TRow row = result_data[i];
+        for (int j = 0; j < _s_tbls_columns.size(); j++) {
+            RETURN_IF_ERROR(insert_block_column(row.column_value[j], j, 
_tableoptions_block.get(),
+                                                _s_tbls_columns[j].type));
+        }
+    }
+    return Status::OK();
+}
+
+bool SchemaTableOptionsScanner::check_and_mark_eos(bool* eos) const {
+    if (_row_idx == _total_rows) {
+        *eos = true;
+        if (_db_index < _db_result.db_ids.size()) {
+            *eos = false;
+        }
+        return true;
+    }
+    return false;
+}
+
+Status SchemaTableOptionsScanner::get_next_block_internal(vectorized::Block* 
block, bool* eos) {
+    if (!_is_init) {
+        return Status::InternalError("Used before initialized.");
+    }
+
+    if (nullptr == block || nullptr == eos) {
+        return Status::InternalError("input pointer is nullptr.");
+    }
+
+    if ((_tableoptions_block == nullptr) || (_row_idx == _total_rows)) {
+        if (_db_index < _db_result.db_ids.size()) {
+            
RETURN_IF_ERROR(get_onedb_info_from_fe(_db_result.db_ids[_db_index]));
+            _row_idx = 0; // reset row index so that it start filling for next 
block.
+            _total_rows = _tableoptions_block->rows();
+            _db_index++;
+        }
+    }
+
+    if (check_and_mark_eos(eos)) {
+        return Status::OK();
+    }
+
+    int current_batch_rows = std::min(_block_rows_limit, _total_rows - 
_row_idx);
+    vectorized::MutableBlock mblock = 
vectorized::MutableBlock::build_mutable_block(block);
+    RETURN_IF_ERROR(mblock.add_rows(_tableoptions_block.get(), _row_idx, 
current_batch_rows));
+    _row_idx += current_batch_rows;
+
+    if (!check_and_mark_eos(eos)) {
+        *eos = false;
+    }
+    return Status::OK();
+}
+
+} // namespace doris
\ No newline at end of file
diff --git a/be/src/exec/schema_scanner/schema_partitions_scanner.h 
b/be/src/exec/schema_scanner/schema_table_options_scanner.h
similarity index 70%
copy from be/src/exec/schema_scanner/schema_partitions_scanner.h
copy to be/src/exec/schema_scanner/schema_table_options_scanner.h
index 87e55db984a..631bd3b07ee 100644
--- a/be/src/exec/schema_scanner/schema_partitions_scanner.h
+++ b/be/src/exec/schema_scanner/schema_table_options_scanner.h
@@ -16,7 +16,6 @@
 // under the License.
 
 #pragma once
-
 #include <gen_cpp/FrontendService_types.h>
 
 #include <vector>
@@ -30,21 +29,27 @@ namespace vectorized {
 class Block;
 } // namespace vectorized
 
-class SchemaPartitionsScanner : public SchemaScanner {
-    ENABLE_FACTORY_CREATOR(SchemaPartitionsScanner);
+class SchemaTableOptionsScanner : public SchemaScanner {
+    ENABLE_FACTORY_CREATOR(SchemaTableOptionsScanner);
 
 public:
-    SchemaPartitionsScanner();
-    ~SchemaPartitionsScanner() override;
+    SchemaTableOptionsScanner();
+    ~SchemaTableOptionsScanner() override = default;
 
     Status start(RuntimeState* state) override;
     Status get_next_block_internal(vectorized::Block* block, bool* eos) 
override;
 
-    int _db_index;
-    int _table_index;
-    TGetDbsResult _db_result;
-    TListTableStatusResult _table_result;
     static std::vector<SchemaScanner::ColumnDesc> _s_tbls_columns;
-};
 
-} // namespace doris
+private:
+    Status get_onedb_info_from_fe(int64_t dbId);
+    bool check_and_mark_eos(bool* eos) const;
+    int _block_rows_limit = 4096;
+    int _db_index = 0;
+    TGetDbsResult _db_result;
+    int _row_idx = 0;
+    int _total_rows = 0;
+    std::unique_ptr<vectorized::Block> _tableoptions_block = nullptr;
+    int _rpc_timeout_ms = 3000;
+};
+}; // namespace doris
\ No newline at end of file
diff --git a/be/src/runtime/runtime_query_statistics_mgr.cpp 
b/be/src/runtime/runtime_query_statistics_mgr.cpp
index d55bbed9761..7e6a34ad1b5 100644
--- a/be/src/runtime/runtime_query_statistics_mgr.cpp
+++ b/be/src/runtime/runtime_query_statistics_mgr.cpp
@@ -17,6 +17,7 @@
 
 #include "runtime/runtime_query_statistics_mgr.h"
 
+#include "exec/schema_scanner/schema_scanner_helper.h"
 #include "runtime/client_cache.h"
 #include "runtime/exec_env.h"
 #include "util/debug_util.h"
@@ -223,51 +224,29 @@ void 
RuntimeQueryStatiticsMgr::get_active_be_tasks_block(vectorized::Block* bloc
     std::shared_lock<std::shared_mutex> read_lock(_qs_ctx_map_lock);
     int64_t be_id = ExecEnv::GetInstance()->master_info()->backend_id;
 
-    auto insert_int_value = [&](int col_index, int64_t int_val, 
vectorized::Block* block) {
-        vectorized::MutableColumnPtr mutable_col_ptr;
-        mutable_col_ptr = 
std::move(*block->get_by_position(col_index).column).assume_mutable();
-        auto* nullable_column =
-                
reinterpret_cast<vectorized::ColumnNullable*>(mutable_col_ptr.get());
-        vectorized::IColumn* col_ptr = &nullable_column->get_nested_column();
-        
reinterpret_cast<vectorized::ColumnVector<vectorized::Int64>*>(col_ptr)->insert_value(
-                int_val);
-        nullable_column->get_null_map_data().emplace_back(0);
-    };
-
-    auto insert_string_value = [&](int col_index, std::string str_val, 
vectorized::Block* block) {
-        vectorized::MutableColumnPtr mutable_col_ptr;
-        mutable_col_ptr = 
std::move(*block->get_by_position(col_index).column).assume_mutable();
-        auto* nullable_column =
-                
reinterpret_cast<vectorized::ColumnNullable*>(mutable_col_ptr.get());
-        vectorized::IColumn* col_ptr = &nullable_column->get_nested_column();
-        
reinterpret_cast<vectorized::ColumnString*>(col_ptr)->insert_data(str_val.data(),
-                                                                          
str_val.size());
-        nullable_column->get_null_map_data().emplace_back(0);
-    };
-
     // block's schema come from 
SchemaBackendActiveTasksScanner::_s_tbls_columns
     for (auto& [query_id, qs_ctx_ptr] : _query_statistics_ctx_map) {
         TQueryStatistics tqs;
         qs_ctx_ptr->collect_query_statistics(&tqs);
-        insert_int_value(0, be_id, block);
-        insert_string_value(1, qs_ctx_ptr->_fe_addr.hostname, block);
-        insert_string_value(2, query_id, block);
+        SchemaScannerHelper::insert_int_value(0, be_id, block);
+        SchemaScannerHelper::insert_string_value(1, 
qs_ctx_ptr->_fe_addr.hostname, block);
+        SchemaScannerHelper::insert_string_value(2, query_id, block);
 
         int64_t task_time = qs_ctx_ptr->_is_query_finished
                                     ? qs_ctx_ptr->_query_finish_time - 
qs_ctx_ptr->_query_start_time
                                     : MonotonicMillis() - 
qs_ctx_ptr->_query_start_time;
-        insert_int_value(3, task_time, block);
-        insert_int_value(4, tqs.cpu_ms, block);
-        insert_int_value(5, tqs.scan_rows, block);
-        insert_int_value(6, tqs.scan_bytes, block);
-        insert_int_value(7, tqs.max_peak_memory_bytes, block);
-        insert_int_value(8, tqs.current_used_memory_bytes, block);
-        insert_int_value(9, tqs.shuffle_send_bytes, block);
-        insert_int_value(10, tqs.shuffle_send_rows, block);
+        SchemaScannerHelper::insert_int_value(3, task_time, block);
+        SchemaScannerHelper::insert_int_value(4, tqs.cpu_ms, block);
+        SchemaScannerHelper::insert_int_value(5, tqs.scan_rows, block);
+        SchemaScannerHelper::insert_int_value(6, tqs.scan_bytes, block);
+        SchemaScannerHelper::insert_int_value(7, tqs.max_peak_memory_bytes, 
block);
+        SchemaScannerHelper::insert_int_value(8, 
tqs.current_used_memory_bytes, block);
+        SchemaScannerHelper::insert_int_value(9, tqs.shuffle_send_bytes, 
block);
+        SchemaScannerHelper::insert_int_value(10, tqs.shuffle_send_rows, 
block);
 
         std::stringstream ss;
         ss << qs_ctx_ptr->_query_type;
-        insert_string_value(11, ss.str(), block);
+        SchemaScannerHelper::insert_string_value(11, ss.str(), block);
     }
 }
 
diff --git a/be/src/runtime/workload_group/workload_group.cpp 
b/be/src/runtime/workload_group/workload_group.cpp
index 63295563699..8b0985d4ecf 100644
--- a/be/src/runtime/workload_group/workload_group.cpp
+++ b/be/src/runtime/workload_group/workload_group.cpp
@@ -27,6 +27,7 @@
 #include <utility>
 
 #include "common/logging.h"
+#include "exec/schema_scanner/schema_scanner_helper.h"
 #include "io/fs/local_file_reader.h"
 #include "olap/storage_engine.h"
 #include "pipeline/task_queue.h"
diff --git a/be/src/runtime/workload_group/workload_group_manager.cpp 
b/be/src/runtime/workload_group/workload_group_manager.cpp
index 1df0dcc3a46..62fcf0aad23 100644
--- a/be/src/runtime/workload_group/workload_group_manager.cpp
+++ b/be/src/runtime/workload_group/workload_group_manager.cpp
@@ -21,6 +21,7 @@
 #include <mutex>
 #include <unordered_map>
 
+#include "exec/schema_scanner/schema_scanner_helper.h"
 #include "pipeline/task_scheduler.h"
 #include "runtime/memory/mem_tracker_limiter.h"
 #include "runtime/workload_group/workload_group.h"
@@ -258,28 +259,6 @@ void WorkloadGroupMgr::refresh_wg_weighted_memory_limit() {
 }
 
 void WorkloadGroupMgr::get_wg_resource_usage(vectorized::Block* block) {
-    auto insert_int_value = [&](int col_index, int64_t int_val, 
vectorized::Block* block) {
-        vectorized::MutableColumnPtr mutable_col_ptr;
-        mutable_col_ptr = 
std::move(*block->get_by_position(col_index).column).assume_mutable();
-        auto* nullable_column =
-                
reinterpret_cast<vectorized::ColumnNullable*>(mutable_col_ptr.get());
-        vectorized::IColumn* col_ptr = &nullable_column->get_nested_column();
-        
reinterpret_cast<vectorized::ColumnVector<vectorized::Int64>*>(col_ptr)->insert_value(
-                int_val);
-        nullable_column->get_null_map_data().emplace_back(0);
-    };
-
-    auto insert_double_value = [&](int col_index, double double_val, 
vectorized::Block* block) {
-        vectorized::MutableColumnPtr mutable_col_ptr;
-        mutable_col_ptr = 
std::move(*block->get_by_position(col_index).column).assume_mutable();
-        auto* nullable_column =
-                
reinterpret_cast<vectorized::ColumnNullable*>(mutable_col_ptr.get());
-        vectorized::IColumn* col_ptr = &nullable_column->get_nested_column();
-        
reinterpret_cast<vectorized::ColumnVector<vectorized::Float64>*>(col_ptr)->insert_value(
-                double_val);
-        nullable_column->get_null_map_data().emplace_back(0);
-    };
-
     int64_t be_id = ExecEnv::GetInstance()->master_info()->backend_id;
     int cpu_num = CpuInfo::num_cores();
     cpu_num = cpu_num <= 0 ? 1 : cpu_num;
@@ -288,18 +267,18 @@ void 
WorkloadGroupMgr::get_wg_resource_usage(vectorized::Block* block) {
     std::shared_lock<std::shared_mutex> r_lock(_group_mutex);
     block->reserve(_workload_groups.size());
     for (const auto& [id, wg] : _workload_groups) {
-        insert_int_value(0, be_id, block);
-        insert_int_value(1, wg->id(), block);
-        insert_int_value(2, wg->get_mem_used(), block);
+        SchemaScannerHelper::insert_int_value(0, be_id, block);
+        SchemaScannerHelper::insert_int_value(1, wg->id(), block);
+        SchemaScannerHelper::insert_int_value(2, wg->get_mem_used(), block);
 
         double cpu_usage_p =
                 (double)wg->get_cpu_usage() / 
(double)total_cpu_time_ns_per_second * 100;
         cpu_usage_p = std::round(cpu_usage_p * 100.0) / 100.0;
 
-        insert_double_value(3, cpu_usage_p, block);
+        SchemaScannerHelper::insert_double_value(3, cpu_usage_p, block);
 
-        insert_int_value(4, wg->get_local_scan_bytes_per_second(), block);
-        insert_int_value(5, wg->get_remote_scan_bytes_per_second(), block);
+        SchemaScannerHelper::insert_int_value(4, 
wg->get_local_scan_bytes_per_second(), block);
+        SchemaScannerHelper::insert_int_value(5, 
wg->get_remote_scan_bytes_per_second(), block);
     }
 }
 
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/analysis/SchemaTableType.java 
b/fe/fe-core/src/main/java/org/apache/doris/analysis/SchemaTableType.java
index 2b6bd0f089e..69787463bc7 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/analysis/SchemaTableType.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/SchemaTableType.java
@@ -75,7 +75,6 @@ public enum SchemaTableType {
     SCH_WORKLOAD_GROUPS("WORKLOAD_GROUPS", "WORKLOAD_GROUPS", 
TSchemaTableType.SCH_WORKLOAD_GROUPS),
     SCHE_USER("user", "user", TSchemaTableType.SCH_USER),
     SCH_PROCS_PRIV("procs_priv", "procs_priv", 
TSchemaTableType.SCH_PROCS_PRIV),
-
     SCH_WORKLOAD_POLICY("WORKLOAD_POLICY", "WORKLOAD_POLICY",
             TSchemaTableType.SCH_WORKLOAD_POLICY),
     SCH_FILE_CACHE_STATISTICS("FILE_CACHE_STATISTICS", "FILE_CACHE_STATISTICS",
@@ -87,7 +86,9 @@ public enum SchemaTableType {
     SCH_TABLE_PROPERTIES("TABLE_PROPERTIES", "TABLE_PROPERTIES",
             TSchemaTableType.SCH_TABLE_PROPERTIES),
     SCH_CATALOG_META_CACHE_STATISTICS("CATALOG_META_CACHE_STATISTICS", 
"CATALOG_META_CACHE_STATISTICS",
-            TSchemaTableType.SCH_CATALOG_META_CACHE_STATISTICS);
+            TSchemaTableType.SCH_CATALOG_META_CACHE_STATISTICS),
+    SCH_TABLE_OPTIONS("TABLE_OPTIONS", "TABLE_OPTIONS",
+            TSchemaTableType.SCH_TABLE_OPTIONS);
 
     private static final String dbName = "INFORMATION_SCHEMA";
     private static SelectList fullSelectLists;
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/catalog/ListPartitionItem.java 
b/fe/fe-core/src/main/java/org/apache/doris/catalog/ListPartitionItem.java
index dafdcdc49f5..2db1531de9b 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/catalog/ListPartitionItem.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/ListPartitionItem.java
@@ -58,6 +58,14 @@ public class ListPartitionItem extends PartitionItem {
         return partitionKeys;
     }
 
+    public String getItemsString() {
+        return toString();
+    }
+
+    public String getItemsSql() {
+        return toSql();
+    }
+
     @Override
     public boolean isDefaultPartition() {
         return isDefaultPartition;
diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/OlapTable.java 
b/fe/fe-core/src/main/java/org/apache/doris/catalog/OlapTable.java
index e048ae8ede8..0d4e12cfdd6 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/catalog/OlapTable.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/OlapTable.java
@@ -2025,6 +2025,20 @@ public class OlapTable extends Table implements 
MTMVRelatedTableIf {
         return keysNum;
     }
 
+    public String getKeyColAsString() {
+        StringBuilder str = new StringBuilder();
+        str.append("");
+        for (Column column : getBaseSchema()) {
+            if (column.isKey()) {
+                if (str.length() != 0) {
+                    str.append(",");
+                }
+                str.append(column.getName());
+            }
+        }
+        return str.toString();
+    }
+
     public boolean convertHashDistributionToRandomDistribution() {
         boolean hasChanged = false;
         if (defaultDistributionInfo.getType() == DistributionInfoType.HASH) {
diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/Partition.java 
b/fe/fe-core/src/main/java/org/apache/doris/catalog/Partition.java
index a21ba68f0dd..aad35071952 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/catalog/Partition.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/Partition.java
@@ -478,4 +478,23 @@ public class Partition extends MetaObject implements 
Writable {
     public boolean isRollupIndex(long id) {
         return idToVisibleRollupIndex.containsKey(id);
     }
+
+
+    public long getRowCount() {
+        return getBaseIndex().getRowCount();
+    }
+
+    public long getAvgRowLength() {
+        long rowCount = getBaseIndex().getRowCount();
+        long dataSize = getBaseIndex().getDataSize(false);
+        if (rowCount > 0) {
+            return dataSize / rowCount;
+        } else {
+            return 0;
+        }
+    }
+
+    public long getDataLength() {
+        return getBaseIndex().getDataSize(false);
+    }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/catalog/PartitionInfo.java 
b/fe/fe-core/src/main/java/org/apache/doris/catalog/PartitionInfo.java
index 434812b07d3..8f148188a5a 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/catalog/PartitionInfo.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/PartitionInfo.java
@@ -122,6 +122,19 @@ public class PartitionInfo implements Writable {
         return partitionColumns;
     }
 
+    public String getDisplayPartitionColumns() {
+        StringBuilder sb = new StringBuilder();
+        int index = 0;
+        for (Column c : partitionColumns) {
+            if (index  != 0) {
+                sb.append(", ");
+            }
+            sb.append(c.getDisplayName());
+            index++;
+        }
+        return sb.toString();
+    }
+
     public Map<Long, PartitionItem> getIdToItem(boolean isTemp) {
         if (isTemp) {
             return idToTempItem;
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/catalog/PartitionItem.java 
b/fe/fe-core/src/main/java/org/apache/doris/catalog/PartitionItem.java
index af1bbc9d0e2..386f7537b03 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/catalog/PartitionItem.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/PartitionItem.java
@@ -60,4 +60,8 @@ public abstract class PartitionItem implements 
Comparable<PartitionItem>, Writab
     public abstract boolean isGreaterThanSpecifiedTime(int pos, 
Optional<String> dateFormatOptional,
             long nowTruncSubSec)
             throws AnalysisException;
+
+
+    //get the unique string of the partition item in sql format
+    public abstract String getItemsSql();
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/catalog/RangePartitionItem.java 
b/fe/fe-core/src/main/java/org/apache/doris/catalog/RangePartitionItem.java
index bb7ddabbaa4..e7f2a9cab5d 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/catalog/RangePartitionItem.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/RangePartitionItem.java
@@ -46,6 +46,14 @@ public class RangePartitionItem extends PartitionItem {
         return partitionKeyRange;
     }
 
+    public String getItemsString() {
+        return toString();
+    }
+
+    public String getItemsSql() {
+        return toPartitionKeyDesc().toSql();
+    }
+
     @Override
     public boolean isDefaultPartition() {
         return false;
diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/SchemaTable.java 
b/fe/fe-core/src/main/java/org/apache/doris/catalog/SchemaTable.java
index eeff956658f..5d6c01ea2a0 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/catalog/SchemaTable.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/SchemaTable.java
@@ -558,6 +558,18 @@ public class SchemaTable extends Table {
                                     .column("METRIC_VALUE", 
ScalarType.createStringType())
                                     .build())
             )
+            .put("table_options",
+                    new SchemaTable(SystemIdGenerator.getNextId(), 
"table_options", TableType.SCHEMA,
+                            builder().column("TABLE_CATALOG", 
ScalarType.createVarchar(NAME_CHAR_LEN))
+                                    .column("TABLE_SCHEMA", 
ScalarType.createVarchar(NAME_CHAR_LEN))
+                                    .column("TABLE_NAME", 
ScalarType.createVarchar(NAME_CHAR_LEN))
+                                    .column("TABLE_MODEL", 
ScalarType.createStringType())
+                                    .column("TABLE_MODEL_KEY", 
ScalarType.createStringType())
+                                    .column("DISTRIBUTE_KEY", 
ScalarType.createStringType())
+                                    .column("DISTRIBUTE_TYPE", 
ScalarType.createStringType())
+                                    .column("BUCKETS_NUM", 
ScalarType.createType(PrimitiveType.INT))
+                                    .column("PARTITION_NUM", 
ScalarType.createType(PrimitiveType.INT))
+                                    .build()))
             .build();
 
     private boolean fetchAllFe = false;
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/catalog/TableProperty.java 
b/fe/fe-core/src/main/java/org/apache/doris/catalog/TableProperty.java
index 2ede77a6180..0d58aabea08 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/catalog/TableProperty.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/TableProperty.java
@@ -657,4 +657,15 @@ public class TableProperty implements Writable {
             properties.remove(DynamicPartitionProperty.REPLICATION_NUM);
         }
     }
+
+    public String getPropertiesString() {
+        StringBuilder str = new StringBuilder("");
+        for (Map.Entry<String, String> entry : properties.entrySet()) {
+            if (str.length() != 0) {
+                str.append(", ");
+            }
+            str.append(entry.getKey() + " = " + entry.getValue());
+        }
+        return str.toString();
+    }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/common/proc/PartitionsProcDir.java 
b/fe/fe-core/src/main/java/org/apache/doris/common/proc/PartitionsProcDir.java
index 7a2acf64154..d0771f3be1c 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/common/proc/PartitionsProcDir.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/common/proc/PartitionsProcDir.java
@@ -76,6 +76,7 @@ public class PartitionsProcDir implements ProcDirInterface {
             
.add("Buckets").add("ReplicationNum").add("StorageMedium").add("CooldownTime").add("RemoteStoragePolicy")
             
.add("LastConsistencyCheckTime").add("DataSize").add("IsInMemory").add("ReplicaAllocation")
             
.add("IsMutable").add("SyncWithBaseTables").add("UnsyncTables").add("CommittedVersion")
+            .add("RowCount")
             .build();
 
     private Database db;
@@ -383,6 +384,9 @@ public class PartitionsProcDir implements ProcDirInterface {
                 partitionInfo.add(partition.getCommittedVersion());
                 trow.addToColumnValue(new 
TCell().setLongVal(partition.getCommittedVersion()));
 
+                partitionInfo.add(partition.getRowCount());
+                trow.addToColumnValue(new 
TCell().setLongVal(partition.getRowCount()));
+
                 partitionInfos.add(Pair.of(partitionInfo, trow));
             }
         } finally {
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 929497cbaab..a08b49ccada 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
@@ -21,9 +21,15 @@ import org.apache.doris.analysis.UserIdentity;
 import org.apache.doris.catalog.Column;
 import org.apache.doris.catalog.Database;
 import org.apache.doris.catalog.DatabaseIf;
+import org.apache.doris.catalog.DistributionInfo;
+import org.apache.doris.catalog.DistributionInfo.DistributionInfoType;
 import org.apache.doris.catalog.Env;
+import org.apache.doris.catalog.HashDistributionInfo;
 import org.apache.doris.catalog.MTMV;
 import org.apache.doris.catalog.OlapTable;
+import org.apache.doris.catalog.Partition;
+import org.apache.doris.catalog.PartitionItem;
+import org.apache.doris.catalog.PartitionType;
 import org.apache.doris.catalog.SchemaTable;
 import org.apache.doris.catalog.Table;
 import org.apache.doris.catalog.TableIf;
@@ -96,6 +102,7 @@ import java.text.SimpleDateFormat;
 import java.time.Instant;
 import java.time.LocalDateTime;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Date;
 import java.util.List;
 import java.util.Map;
@@ -112,12 +119,16 @@ public class MetadataGenerator {
 
     private static final ImmutableMap<String, Integer> 
WORKLOAD_SCHED_POLICY_COLUMN_TO_INDEX;
 
+    private static final ImmutableMap<String, Integer> 
TABLE_OPTIONS_COLUMN_TO_INDEX;
+
     private static final ImmutableMap<String, Integer> 
WORKLOAD_GROUP_PRIVILEGES_COLUMN_TO_INDEX;
 
     private static final ImmutableMap<String, Integer> 
TABLE_PROPERTIES_COLUMN_TO_INDEX;
 
     private static final ImmutableMap<String, Integer> 
META_CACHE_STATS_COLUMN_TO_INDEX;
 
+    private static final ImmutableMap<String, Integer> 
PARTITIONS_COLUMN_TO_INDEX;
+
     static {
         ImmutableMap.Builder<String, Integer> activeQueriesbuilder = new 
ImmutableMap.Builder();
         List<Column> activeQueriesColList = 
SchemaTable.TABLE_MAP.get("active_queries").getFullSchema();
@@ -145,6 +156,13 @@ public class MetadataGenerator {
         }
         WORKLOAD_SCHED_POLICY_COLUMN_TO_INDEX = policyBuilder.build();
 
+        ImmutableMap.Builder<String, Integer> optionBuilder = new 
ImmutableMap.Builder();
+        List<Column> optionColList = 
SchemaTable.TABLE_MAP.get("table_options").getFullSchema();
+        for (int i = 0; i < optionColList.size(); i++) {
+            optionBuilder.put(optionColList.get(i).getName().toLowerCase(), i);
+        }
+        TABLE_OPTIONS_COLUMN_TO_INDEX = optionBuilder.build();
+
         ImmutableMap.Builder<String, Integer> wgPrivsBuilder = new 
ImmutableMap.Builder();
         List<Column> wgPrivsColList = 
SchemaTable.TABLE_MAP.get("workload_group_privileges").getFullSchema();
         for (int i = 0; i < wgPrivsColList.size(); i++) {
@@ -165,6 +183,13 @@ public class MetadataGenerator {
             
metaCacheBuilder.put(metaCacheColList.get(i).getName().toLowerCase(), i);
         }
         META_CACHE_STATS_COLUMN_TO_INDEX = metaCacheBuilder.build();
+
+        ImmutableMap.Builder<String, Integer> partitionsBuilder = new 
ImmutableMap.Builder();
+        List<Column> partitionsColList = 
SchemaTable.TABLE_MAP.get("partitions").getFullSchema();
+        for (int i = 0; i < partitionsColList.size(); i++) {
+            
partitionsBuilder.put(partitionsColList.get(i).getName().toLowerCase(), i);
+        }
+        PARTITIONS_COLUMN_TO_INDEX = partitionsBuilder.build();
     }
 
     public static TFetchSchemaTableDataResult 
getMetadataTable(TFetchSchemaTableDataRequest request) throws TException {
@@ -244,6 +269,10 @@ public class MetadataGenerator {
                 result = workloadSchedPolicyMetadataResult(schemaTableParams);
                 columnIndex = WORKLOAD_SCHED_POLICY_COLUMN_TO_INDEX;
                 break;
+            case TABLE_OPTIONS:
+                result = tableOptionsMetadataResult(schemaTableParams);
+                columnIndex = TABLE_OPTIONS_COLUMN_TO_INDEX;
+                break;
             case WORKLOAD_GROUP_PRIVILEGES:
                 result = workloadGroupPrivsMetadataResult(schemaTableParams);
                 columnIndex = WORKLOAD_GROUP_PRIVILEGES_COLUMN_TO_INDEX;
@@ -256,6 +285,10 @@ public class MetadataGenerator {
                 result = metaCacheStatsMetadataResult(schemaTableParams);
                 columnIndex = META_CACHE_STATS_COLUMN_TO_INDEX;
                 break;
+            case PARTITIONS:
+                result = partitionsMetadataResult(schemaTableParams);
+                columnIndex = PARTITIONS_COLUMN_TO_INDEX;
+                break;
             default:
                 return errorResult("invalid schema table name.");
         }
@@ -1046,6 +1079,123 @@ public class MetadataGenerator {
         return result;
     }
 
+    private static void tableOptionsForInternalCatalog(UserIdentity 
currentUserIdentity,
+                    CatalogIf catalog, DatabaseIf database, List<TableIf> 
tables, List<TRow> dataBatch) {
+        for (TableIf table : tables) {
+            if (!(table instanceof OlapTable)) {
+                continue;
+            }
+            if 
(!Env.getCurrentEnv().getAccessManager().checkTblPriv(currentUserIdentity, 
catalog.getName(),
+                    database.getFullName(), table.getName(), 
PrivPredicate.SHOW)) {
+                continue;
+            }
+            OlapTable olapTable = (OlapTable) table;
+            TRow trow = new TRow();
+            trow.addToColumnValue(new 
TCell().setStringVal(catalog.getName())); // TABLE_CATALOG
+            trow.addToColumnValue(new 
TCell().setStringVal(database.getFullName())); // TABLE_SCHEMA
+            trow.addToColumnValue(new TCell().setStringVal(table.getName())); 
// TABLE_NAME
+            trow.addToColumnValue(
+                    new 
TCell().setStringVal(olapTable.getKeysType().toMetadata())); // TABLE_MODEL
+            trow.addToColumnValue(
+                    new TCell().setStringVal(olapTable.getKeyColAsString())); 
// key columTypes
+
+            DistributionInfo distributionInfo = 
olapTable.getDefaultDistributionInfo();
+            if (distributionInfo.getType() == DistributionInfoType.HASH) {
+                HashDistributionInfo hashDistributionInfo = 
(HashDistributionInfo) distributionInfo;
+                List<Column> distributionColumns = 
hashDistributionInfo.getDistributionColumns();
+                StringBuilder distributeKey = new StringBuilder();
+                for (Column c : distributionColumns) {
+                    if (distributeKey.length() != 0) {
+                        distributeKey.append(",");
+                    }
+                    distributeKey.append(c.getName());
+                }
+                if (distributeKey.length() == 0) {
+                    trow.addToColumnValue(new TCell().setStringVal(""));
+                } else {
+                    trow.addToColumnValue(
+                            new 
TCell().setStringVal(distributeKey.toString()));
+                }
+                trow.addToColumnValue(new TCell().setStringVal("HASH")); // 
DISTRIBUTE_TYPE
+            } else {
+                trow.addToColumnValue(new TCell().setStringVal("RANDOM")); // 
DISTRIBUTE_KEY
+                trow.addToColumnValue(new TCell().setStringVal("RANDOM")); // 
DISTRIBUTE_TYPE
+            }
+            trow.addToColumnValue(new 
TCell().setIntVal(distributionInfo.getBucketNum())); // BUCKETS_NUM
+            trow.addToColumnValue(new 
TCell().setIntVal(olapTable.getPartitionNum())); // PARTITION_NUM
+            dataBatch.add(trow);
+        }
+    }
+
+    private static void tableOptionsForExternalCatalog(UserIdentity 
currentUserIdentity,
+                    CatalogIf catalog, DatabaseIf database, List<TableIf> 
tables, List<TRow> dataBatch) {
+        for (TableIf table : tables) {
+            if 
(!Env.getCurrentEnv().getAccessManager().checkTblPriv(currentUserIdentity, 
catalog.getName(),
+                    database.getFullName(), table.getName(), 
PrivPredicate.SHOW)) {
+                continue;
+            }
+            TRow trow = new TRow();
+            trow.addToColumnValue(new 
TCell().setStringVal(catalog.getName())); // TABLE_CATALOG
+            trow.addToColumnValue(new 
TCell().setStringVal(database.getFullName())); // TABLE_SCHEMA
+            trow.addToColumnValue(new TCell().setStringVal(table.getName())); 
// TABLE_NAME
+            trow.addToColumnValue(
+                    new TCell().setStringVal("")); // TABLE_MODEL
+            trow.addToColumnValue(
+                    new TCell().setStringVal("")); // key columTypes
+            trow.addToColumnValue(new TCell().setStringVal("")); // 
DISTRIBUTE_KEY
+            trow.addToColumnValue(new TCell().setStringVal("")); // 
DISTRIBUTE_TYPE
+            trow.addToColumnValue(new TCell().setIntVal(0)); // BUCKETS_NUM
+            trow.addToColumnValue(new TCell().setIntVal(0)); // PARTITION_NUM
+            dataBatch.add(trow);
+        }
+    }
+
+    private static TFetchSchemaTableDataResult 
tableOptionsMetadataResult(TSchemaTableRequestParams params) {
+        if (!params.isSetCurrentUserIdent()) {
+            return errorResult("current user ident is not set.");
+        }
+        if (!params.isSetDbId()) {
+            return errorResult("current db id is not set.");
+        }
+
+        if (!params.isSetCatalog()) {
+            return errorResult("current catalog is not set.");
+        }
+
+        TUserIdentity tcurrentUserIdentity = params.getCurrentUserIdent();
+        UserIdentity currentUserIdentity = 
UserIdentity.fromThrift(tcurrentUserIdentity);
+        TFetchSchemaTableDataResult result = new TFetchSchemaTableDataResult();
+        List<TRow> dataBatch = Lists.newArrayList();
+        Long dbId = params.getDbId();
+        String clg = params.getCatalog();
+        CatalogIf catalog = 
Env.getCurrentEnv().getCatalogMgr().getCatalog(clg);
+        if (catalog == null) {
+            // catalog is NULL  let return empty to BE
+            result.setDataBatch(dataBatch);
+            result.setStatus(new TStatus(TStatusCode.OK));
+            return result;
+        }
+        DatabaseIf database = catalog.getDbNullable(dbId);
+        if (database == null) {
+            // BE gets the database id list from FE and then invokes this 
interface
+            // per database. there is a chance that in between database can be 
dropped.
+            // so need to handle database not exist case and return ok so that 
BE continue the
+            // loop with next database.
+            result.setDataBatch(dataBatch);
+            result.setStatus(new TStatus(TStatusCode.OK));
+            return result;
+        }
+        List<TableIf> tables = database.getTables();
+        if (catalog instanceof InternalCatalog) {
+            tableOptionsForInternalCatalog(currentUserIdentity, catalog, 
database, tables, dataBatch);
+        } else if (catalog instanceof ExternalCatalog) {
+            tableOptionsForExternalCatalog(currentUserIdentity, catalog, 
database, tables, dataBatch);
+        }
+        result.setDataBatch(dataBatch);
+        result.setStatus(new TStatus(TStatusCode.OK));
+        return result;
+    }
+
     private static void tablePropertiesForInternalCatalog(UserIdentity 
currentUserIdentity,
                 CatalogIf catalog, DatabaseIf database, List<TableIf> tables, 
List<TRow> dataBatch) {
         for (TableIf table : tables) {
@@ -1119,8 +1269,14 @@ public class MetadataGenerator {
         TFetchSchemaTableDataResult result = new TFetchSchemaTableDataResult();
         Long dbId = params.getDbId();
         String clg = params.getCatalog();
-        CatalogIf catalog = 
Env.getCurrentEnv().getCatalogMgr().getCatalog(clg);
         List<TRow> dataBatch = Lists.newArrayList();
+        CatalogIf catalog = 
Env.getCurrentEnv().getCatalogMgr().getCatalog(clg);
+        if (catalog == null) {
+            // catalog is NULL  let return empty to BE
+            result.setDataBatch(dataBatch);
+            result.setStatus(new TStatus(TStatusCode.OK));
+            return result;
+        }
         DatabaseIf database = catalog.getDbNullable(dbId);
         if (database == null) {
             // BE gets the database id list from FE and then invokes this 
interface
@@ -1164,7 +1320,124 @@ public class MetadataGenerator {
                 fillBatch(dataBatch, icebergCache.getCacheStats(), 
catalogIf.getName());
             }
         }
+        result.setDataBatch(dataBatch);
+        result.setStatus(new TStatus(TStatusCode.OK));
+        return result;
+    }
+
+    private static void partitionsForInternalCatalog(UserIdentity 
currentUserIdentity,
+                CatalogIf catalog, DatabaseIf database, List<TableIf> tables, 
List<TRow> dataBatch) {
+        for (TableIf table : tables) {
+            if (!(table instanceof OlapTable)) {
+                continue;
+            }
+            if 
(!Env.getCurrentEnv().getAccessManager().checkTblPriv(currentUserIdentity, 
catalog.getName(),
+                    database.getFullName(), table.getName(), 
PrivPredicate.SHOW)) {
+                continue;
+            }
+
+            OlapTable olapTable = (OlapTable) table;
+            Collection<Partition> allPartitions = olapTable.getAllPartitions();
+
+            for (Partition partition : allPartitions) {
+                TRow trow = new TRow();
+                trow.addToColumnValue(new 
TCell().setStringVal(catalog.getName())); // TABLE_CATALOG
+                trow.addToColumnValue(new 
TCell().setStringVal(database.getFullName())); // TABLE_SCHEMA
+                trow.addToColumnValue(new 
TCell().setStringVal(table.getName())); // TABLE_NAME
+                trow.addToColumnValue(new 
TCell().setStringVal(partition.getName())); // PARTITION_NAME
+                trow.addToColumnValue(new TCell().setStringVal("NULL")); // 
SUBPARTITION_NAME (always null)
+
+                trow.addToColumnValue(new TCell().setIntVal(0)); 
//PARTITION_ORDINAL_POSITION (not available)
+                trow.addToColumnValue(new TCell().setIntVal(0)); 
//SUBPARTITION_ORDINAL_POSITION (not available)
+                trow.addToColumnValue(new TCell().setStringVal(
+                        olapTable.getPartitionInfo().getType().toString())); 
// PARTITION_METHOD
+                trow.addToColumnValue(new TCell().setStringVal("NULL")); // 
SUBPARTITION_METHOD(always null)
+                PartitionItem item = 
olapTable.getPartitionInfo().getItem(partition.getId());
+                if ((olapTable.getPartitionInfo().getType() == 
PartitionType.UNPARTITIONED) || (item == null)) {
+                    trow.addToColumnValue(new TCell().setStringVal("NULL")); 
// if unpartitioned, its null
+                    trow.addToColumnValue(new TCell().setStringVal("NULL")); 
// SUBPARTITION_EXPRESSION (always null)
+                    trow.addToColumnValue(new TCell().setStringVal("NULL")); 
// PARITION DESC, its null
+                } else {
+                    trow.addToColumnValue(new TCell().setStringVal(
+                            olapTable.getPartitionInfo()
+                                .getDisplayPartitionColumns().toString())); // 
PARTITION_EXPRESSION
+                    trow.addToColumnValue(new TCell().setStringVal("NULL")); 
// SUBPARTITION_EXPRESSION (always null)
+                    trow.addToColumnValue(new TCell().setStringVal(
+                            item.getItemsSql())); // PARITION DESC
+                }
+                trow.addToColumnValue(new 
TCell().setLongVal(partition.getRowCount())); //TABLE_ROWS (PARTITION row)
+                trow.addToColumnValue(new 
TCell().setLongVal(partition.getAvgRowLength())); //AVG_ROW_LENGTH
+                trow.addToColumnValue(new 
TCell().setLongVal(partition.getDataLength())); //DATA_LENGTH
+                trow.addToColumnValue(new TCell().setIntVal(0)); 
//MAX_DATA_LENGTH (not available)
+                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)
+                trow.addToColumnValue(new TCell().setStringVal(
+                        
TimeUtils.longToTimeString(partition.getVisibleVersionTime()))); //UPDATE_TIME
+                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)
+                trow.addToColumnValue(new TCell().setStringVal("")); // 
NODEGROUP (not available)
+                trow.addToColumnValue(new TCell().setStringVal("")); // 
TABLESPACE_NAME (not available)
+                dataBatch.add(trow);
+            }
+        } // for table
+    }
+
+    private static void partitionsForExternalCatalog(UserIdentity 
currentUserIdentity,
+            CatalogIf catalog, DatabaseIf database, List<TableIf> tables, 
List<TRow> dataBatch) {
+        for (TableIf table : tables) {
+            if 
(!Env.getCurrentEnv().getAccessManager().checkTblPriv(currentUserIdentity, 
catalog.getName(),
+                    database.getFullName(), table.getName(), 
PrivPredicate.SHOW)) {
+                continue;
+            }
+            // TODO
+        } // for table
+    }
+
+    private static TFetchSchemaTableDataResult 
partitionsMetadataResult(TSchemaTableRequestParams params) {
+        if (!params.isSetCurrentUserIdent()) {
+            return errorResult("current user ident is not set.");
+        }
 
+        if (!params.isSetDbId()) {
+            return errorResult("current db id is not set.");
+        }
+
+        if (!params.isSetCatalog()) {
+            return errorResult("current catalog is not set.");
+        }
+
+        TUserIdentity tcurrentUserIdentity = params.getCurrentUserIdent();
+        UserIdentity currentUserIdentity = 
UserIdentity.fromThrift(tcurrentUserIdentity);
+        TFetchSchemaTableDataResult result = new TFetchSchemaTableDataResult();
+        Long dbId = params.getDbId();
+        String clg = params.getCatalog();
+        List<TRow> dataBatch = Lists.newArrayList();
+        CatalogIf catalog = 
Env.getCurrentEnv().getCatalogMgr().getCatalog(clg);
+        if (catalog == null) {
+            // catalog is NULL  let return empty to BE
+            result.setDataBatch(dataBatch);
+            result.setStatus(new TStatus(TStatusCode.OK));
+            return result;
+        }
+        DatabaseIf database = catalog.getDbNullable(dbId);
+        if (database == null) {
+            // BE gets the database id list from FE and then invokes this 
interface
+            // per database. there is a chance that in between database can be 
dropped.
+            // so need to handle database not exist case and return ok so that 
BE continue the
+            // loop with next database.
+            result.setDataBatch(dataBatch);
+            result.setStatus(new TStatus(TStatusCode.OK));
+            return result;
+        }
+        List<TableIf> tables = database.getTables();
+        if (catalog instanceof InternalCatalog) {
+            // only olap tables
+            partitionsForInternalCatalog(currentUserIdentity, catalog, 
database, tables, dataBatch);
+        } else if (catalog instanceof ExternalCatalog) {
+            partitionsForExternalCatalog(currentUserIdentity, catalog, 
database, tables, dataBatch);
+        }
         result.setDataBatch(dataBatch);
         result.setStatus(new TStatus(TStatusCode.OK));
         return result;
diff --git a/gensrc/thrift/FrontendService.thrift 
b/gensrc/thrift/FrontendService.thrift
index cda2392be07..61dce73400b 100644
--- a/gensrc/thrift/FrontendService.thrift
+++ b/gensrc/thrift/FrontendService.thrift
@@ -958,6 +958,7 @@ enum TSchemaTableName {
   WORKLOAD_GROUP_PRIVILEGES = 7,
   TABLE_PROPERTIES = 8,
   CATALOG_META_CACHE_STATS = 9,
+  PARTITIONS = 10,
 }
 
 struct TMetadataTableRequestParams {
diff --git a/regression-test/data/query_p0/system/test_partitions_schema.out 
b/regression-test/data/query_p0/system/test_partitions_schema.out
new file mode 100644
index 00000000000..ffe2a9cb667
--- /dev/null
+++ b/regression-test/data/query_p0/system/test_partitions_schema.out
@@ -0,0 +1,48 @@
+-- This file is automatically generated. You should know what you did if you 
want to edit this
+-- !select_check_0 --
+test_range_table       p0      9
+test_range_table       p1      2
+test_range_table       p100    4
+test_range_table       p2      1
+test_range_table       p3      1
+test_range_table       p4      3
+test_range_table       p5      0
+
+-- !select_check_1 --
+internal       test_partitions_schema_db       duplicate_table duplicate_table 
NULL    0       0       UNPARTITIONED   NULL    NULL    NULL    NULL    0       
0       0       0       0       0       0                       
+internal       test_partitions_schema_db       listtable       p1_city NULL    
0       0       LIST    NULL    user_id, city   NULL    (("1", "Beijing"),("1", 
"Shanghai"))    0       0       0       0       0       0       0               
        
+internal       test_partitions_schema_db       listtable       p2_city NULL    
0       0       LIST    NULL    user_id, city   NULL    (("2", "Beijing"),("2", 
"Shanghai"))    0       0       0       0       0       0       0               
        
+internal       test_partitions_schema_db       listtable       p3_city NULL    
0       0       LIST    NULL    user_id, city   NULL    (("3", "Beijing"),("3", 
"Shanghai"))    0       0       0       0       0       0       0               
        
+internal       test_partitions_schema_db       randomtable     randomtable     
NULL    0       0       UNPARTITIONED   NULL    NULL    NULL    NULL    0       
0       0       0       0       0       0                       
+internal       test_partitions_schema_db       test_range_table        p0      
NULL    0       0       RANGE   NULL    col_1   NULL    [('-2147483648'), 
('4'))        9       636     5728    0       0       0       0                 
      
+internal       test_partitions_schema_db       test_range_table        p1      
NULL    0       0       RANGE   NULL    col_1   NULL    [('4'), ('6'))  2       
959     1919    0       0       0       0                       
+internal       test_partitions_schema_db       test_range_table        p100    
NULL    0       0       RANGE   NULL    col_1   NULL    [('83647'), 
('2147483647'))     4       735     2941    0       0       0       0           
            
+internal       test_partitions_schema_db       test_range_table        p2      
NULL    0       0       RANGE   NULL    col_1   NULL    [('6'), ('7'))  1       
975     975     0       0       0       0                       
+internal       test_partitions_schema_db       test_range_table        p3      
NULL    0       0       RANGE   NULL    col_1   NULL    [('7'), ('8'))  1       
959     959     0       0       0       0                       
+internal       test_partitions_schema_db       test_range_table        p4      
NULL    0       0       RANGE   NULL    col_1   NULL    [('8'), ('10')) 3       
948     2846    0       0       0       0                       
+internal       test_partitions_schema_db       test_range_table        p5      
NULL    0       0       RANGE   NULL    col_1   NULL    [('10'), ('83647'))     
0       0       0       0       0       0       0                       
+internal       test_partitions_schema_db       test_row_column_page_size1      
test_row_column_page_size1      NULL    0       0       UNPARTITIONED   NULL    
NULL    NULL    NULL    0       0       0       0       0       0       0       
                
+internal       test_partitions_schema_db       test_row_column_page_size2      
test_row_column_page_size2      NULL    0       0       UNPARTITIONED   NULL    
NULL    NULL    NULL    0       0       0       0       0       0       0       
                
+
+-- !select_check_2 --
+internal       test_partitions_schema_db       duplicate_table duplicate_table 
NULL    0       0       UNPARTITIONED   NULL    NULL    NULL    NULL    0       
0       0       0       0       0       0                       
+internal       test_partitions_schema_db       listtable       p1_city NULL    
0       0       LIST    NULL    user_id, city   NULL    (("1", "Beijing"),("1", 
"Shanghai"))    0       0       0       0       0       0       0               
        
+internal       test_partitions_schema_db       listtable       p2_city NULL    
0       0       LIST    NULL    user_id, city   NULL    (("2", "Beijing"),("2", 
"Shanghai"))    0       0       0       0       0       0       0               
        
+internal       test_partitions_schema_db       listtable       p3_city NULL    
0       0       LIST    NULL    user_id, city   NULL    (("3", "Beijing"),("3", 
"Shanghai"))    0       0       0       0       0       0       0               
        
+internal       test_partitions_schema_db       randomtable     randomtable     
NULL    0       0       UNPARTITIONED   NULL    NULL    NULL    NULL    0       
0       0       0       0       0       0                       
+internal       test_partitions_schema_db       test_range_table        p0      
NULL    0       0       RANGE   NULL    col_1   NULL    [('-2147483648'), 
('4'))        9       636     5728    0       0       0       0                 
      
+internal       test_partitions_schema_db       test_range_table        p1      
NULL    0       0       RANGE   NULL    col_1   NULL    [('4'), ('6'))  2       
959     1919    0       0       0       0                       
+internal       test_partitions_schema_db       test_range_table        p100    
NULL    0       0       RANGE   NULL    col_1   NULL    [('83647'), 
('2147483647'))     4       735     2941    0       0       0       0           
            
+internal       test_partitions_schema_db       test_range_table        p2      
NULL    0       0       RANGE   NULL    col_1   NULL    [('6'), ('7'))  1       
975     975     0       0       0       0                       
+internal       test_partitions_schema_db       test_range_table        p3      
NULL    0       0       RANGE   NULL    col_1   NULL    [('7'), ('8'))  1       
959     959     0       0       0       0                       
+internal       test_partitions_schema_db       test_range_table        p4      
NULL    0       0       RANGE   NULL    col_1   NULL    [('8'), ('10')) 3       
948     2846    0       0       0       0                       
+internal       test_partitions_schema_db       test_range_table        p5      
NULL    0       0       RANGE   NULL    col_1   NULL    [('10'), ('83647'))     
0       0       0       0       0       0       0                       
+internal       test_partitions_schema_db       test_row_column_page_size1      
test_row_column_page_size1      NULL    0       0       UNPARTITIONED   NULL    
NULL    NULL    NULL    0       0       0       0       0       0       0       
                
+
+-- !select_check_3 --
+
+-- !select_check_4 --
+internal       test_partitions_schema_db       duplicate_table duplicate_table 
NULL    0       0       UNPARTITIONED   NULL    NULL    NULL    NULL    0       
0       0       0       0       0       0                       
+
+-- !select_check_5 --
+
diff --git a/regression-test/data/query_p0/system/test_query_sys_tables.out 
b/regression-test/data/query_p0/system/test_query_sys_tables.out
index d3a4ef5a57c..215a3d5f1c6 100644
--- a/regression-test/data/query_p0/system/test_query_sys_tables.out
+++ b/regression-test/data/query_p0/system/test_query_sys_tables.out
@@ -152,8 +152,6 @@ PARTITION_COMMENT   text    Yes     false   \N
 NODEGROUP      varchar(256)    Yes     false   \N      
 TABLESPACE_NAME        varchar(268)    Yes     false   \N      
 
--- !select_partitions --
-
 -- !desc_rowsets --
 BACKEND_ID     bigint  Yes     false   \N      
 ROWSET_ID      varchar(64)     Yes     false   \N      
diff --git a/regression-test/data/query_p0/system/test_table_options.out 
b/regression-test/data/query_p0/system/test_table_options.out
new file mode 100644
index 00000000000..0e94265c23f
--- /dev/null
+++ b/regression-test/data/query_p0/system/test_table_options.out
@@ -0,0 +1,27 @@
+-- This file is automatically generated. You should know what you did if you 
want to edit this
+-- !select_check_1 --
+internal       test_table_options_db   aggregate_table AGG     
user_id,date,city,age,sex       user_id HASH    1       1
+internal       test_table_options_db   duplicate_table DUP     
timestamp,type,error_code       type    HASH    1       1
+internal       test_table_options_db   listtable       AGG     
user_id,date,timestamp,city,age,sex     user_id HASH    16      3
+internal       test_table_options_db   randomtable     DUP     
user_id,date,timestamp  RANDOM  RANDOM  16      1
+internal       test_table_options_db   rangetable      AGG     
user_id,date,timestamp,city,age,sex     user_id HASH    8       3
+internal       test_table_options_db   test_row_column_page_size1      DUP     
aaa     aaa     HASH    1       1
+internal       test_table_options_db   test_row_column_page_size2      DUP     
aaa     aaa     HASH    1       1
+internal       test_table_options_db   unique_table    UNI     
user_id,username        user_id HASH    1       1
+
+-- !select_check_2 --
+internal       test_table_options_db   aggregate_table AGG     
user_id,date,city,age,sex       user_id HASH    1       1
+internal       test_table_options_db   duplicate_table DUP     
timestamp,type,error_code       type    HASH    1       1
+internal       test_table_options_db   listtable       AGG     
user_id,date,timestamp,city,age,sex     user_id HASH    16      3
+internal       test_table_options_db   randomtable     DUP     
user_id,date,timestamp  RANDOM  RANDOM  16      1
+internal       test_table_options_db   rangetable      AGG     
user_id,date,timestamp,city,age,sex     user_id HASH    8       3
+internal       test_table_options_db   test_row_column_page_size1      DUP     
aaa     aaa     HASH    1       1
+internal       test_table_options_db   unique_table    UNI     
user_id,username        user_id HASH    1       1
+
+-- !select_check_3 --
+
+-- !select_check_4 --
+internal       test_table_options_db   duplicate_table DUP     
timestamp,type,error_code       type    HASH    1       1
+
+-- !select_check_5 --
+
diff --git 
a/regression-test/suites/query_p0/system/test_partitions_schema.groovy 
b/regression-test/suites/query_p0/system/test_partitions_schema.groovy
new file mode 100644
index 00000000000..ac73d3315d0
--- /dev/null
+++ b/regression-test/suites/query_p0/system/test_partitions_schema.groovy
@@ -0,0 +1,195 @@
+// 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 org.awaitility.Awaitility
+import static java.util.concurrent.TimeUnit.SECONDS
+
+suite("test_partitions_schema") {
+    def dbName = "test_partitions_schema_db"
+    def listOfColum = 
"TABLE_CATALOG,TABLE_SCHEMA,TABLE_NAME,PARTITION_NAME,SUBPARTITION_NAME,PARTITION_ORDINAL_POSITION,SUBPARTITION_ORDINAL_POSITION,PARTITION_METHOD,SUBPARTITION_METHOD,PARTITION_EXPRESSION,SUBPARTITION_EXPRESSION,PARTITION_DESCRIPTION,TABLE_ROWS,AVG_ROW_LENGTH,DATA_LENGTH,MAX_DATA_LENGTH,INDEX_LENGTH,DATA_FREE,CHECKSUM,PARTITION_COMMENT,NODEGROUP,TABLESPACE_NAME";
+    sql "drop database if exists ${dbName}"
+    sql "CREATE DATABASE IF NOT EXISTS ${dbName}"
+    sql "use ${dbName}"
+ 
+     def checkRowCount = { expectedRowCount ->
+        Awaitility.await().atMost(180, SECONDS).pollInterval(1, SECONDS).until(
+            {
+                def result = sql "select table_rows from  
information_schema.partitions where table_name='test_range_table' and 
partition_name='p0'"
+                logger.info("table: table_name, rowCount: ${result}")
+                return result[0][0] == expectedRowCount
+            }
+        )
+    }
+    
+    sql """
+        create table test_range_table (
+        col_1 int,
+        col_2 int,
+        col_3 int,
+        col_4 int,
+        pk int
+        ) engine=olap
+        DUPLICATE KEY(col_1, col_2)
+        PARTITION BY             RANGE(col_1) (
+                        PARTITION p0 VALUES LESS THAN ('4'),
+                        PARTITION p1 VALUES LESS THAN ('6'),
+                        PARTITION p2 VALUES LESS THAN ('7'),
+                        PARTITION p3 VALUES LESS THAN ('8'),
+                        PARTITION p4 VALUES LESS THAN ('10'),
+                        PARTITION p5 VALUES LESS THAN ('83647'),
+                        PARTITION p100 VALUES LESS THAN ('2147483647')
+                    )
+                
+        distributed by hash(pk) buckets 10
+        properties("replication_num" = "1");
+    """
+    sql """
+        insert into test_range_table(pk,col_1,col_2,col_3,col_4) values 
(0,6,-179064,5213411,5),(1,3,5,2,6),(2,4226261,7,null,3),(3,9,null,4,4),(4,-1003770,2,1,1),(5,8,7,null,8176864),(6,3388266,5,8,8),(7,5,1,2,null),(8,9,2064412,0,null),(9,1489553,8,-446412,6),(10,1,3,0,1),(11,null,3,4621304,null),(12,null,-3058026,-262645,9),(13,null,null,9,3),(14,null,null,5037128,7),(15,299896,-1444893,8,1480339),(16,7,7,0,1470826),(17,-7378014,5,null,5),(18,0,3,6,5),(19,5,3,-4403612,-3103249);
+    """
+    sql """
+        sync
+    """
+    checkRowCount(9);
+ 
+    qt_select_check_0 """select  table_name,partition_name,table_rows from 
information_schema.partitions where table_schema=\"${dbName}\" order by 
$listOfColum"""
+    sql """
+    CREATE TABLE IF NOT EXISTS listtable
+       (
+         `user_id` LARGEINT NOT NULL COMMENT "User id",
+         `date` DATE NOT NULL COMMENT "Data fill in date time",
+         `timestamp` DATETIME NOT NULL COMMENT "Timestamp of data being 
poured",
+          `city` VARCHAR(20) COMMENT "The city where the user is located",
+          `age` SMALLINT COMMENT "User Age",
+          `sex` TINYINT COMMENT "User gender",
+          `last_visit_date` DATETIME REPLACE DEFAULT "1970-01-01 00:00:00" 
COMMENT "User last visit time",
+          `cost` BIGINT SUM DEFAULT "0" COMMENT "Total user consumption",
+          `max_dwell_time` INT MAX DEFAULT "0" COMMENT "User maximum dwell 
time",
+          `min_dwell_time` INT MIN DEFAULT "99999" COMMENT "User minimum dwell 
time"
+        )
+       ENGINE=olap
+       AGGREGATE KEY(`user_id`, `date`, `timestamp`, `city`, `age`, `sex`)
+    PARTITION BY LIST(user_id, city)
+    (
+        PARTITION p1_city VALUES IN (("1", "Beijing"), ("1", "Shanghai")),
+        PARTITION p2_city VALUES IN (("2", "Beijing"), ("2", "Shanghai")),
+        PARTITION p3_city VALUES IN (("3", "Beijing"), ("3", "Shanghai"))
+    )
+       DISTRIBUTED BY HASH(`user_id`) BUCKETS 16
+       PROPERTIES
+       (
+               "replication_num" = "1"
+       );
+    """
+    sql """
+        CREATE TABLE IF NOT EXISTS randomtable
+       (
+               `user_id` LARGEINT NOT NULL COMMENT "User id",
+               `date` DATE NOT NULL COMMENT "Data fill in date time",
+               `timestamp` DATETIME NOT NULL COMMENT "Timestamp of data being 
poured",
+               `city` VARCHAR(20) COMMENT "The city where the user is located",
+               `age` SMALLINT COMMENT "User Age",
+               `sex` TINYINT COMMENT "User gender"
+       )
+       ENGINE=olap
+       DISTRIBUTED BY RANDOM BUCKETS 16
+       PROPERTIES
+       (
+               "replication_num" = "1"
+       );
+        """
+    sql """
+       CREATE TABLE IF NOT EXISTS duplicate_table
+       (
+           `timestamp` DATETIME NOT NULL COMMENT "Log time",
+           `type` INT NOT NULL COMMENT "Log type",
+           `error_code` INT COMMENT "Error code",
+           `error_msg` VARCHAR(1024) COMMENT "Error detail message",
+           `op_id` BIGINT COMMENT "Operator ID",
+           `op_time` DATETIME COMMENT "Operation time"
+       )
+       DISTRIBUTED BY HASH(`type`) BUCKETS 1
+       PROPERTIES (
+       "replication_allocation" = "tag.location.default: 1"
+       );
+        """
+       
+    // test row column page size
+    sql """
+        CREATE TABLE IF NOT EXISTS test_row_column_page_size1 (
+            `aaa` varchar(170) NOT NULL COMMENT "",
+            `bbb` varchar(20) NOT NULL COMMENT "",
+            `ccc` INT NULL COMMENT "",
+            `ddd` SMALLINT NULL COMMENT ""
+        )
+        DISTRIBUTED BY HASH(`aaa`) BUCKETS 1
+        PROPERTIES (
+            "replication_num" = "1",
+            "store_row_column" = "true"
+        );
+    """
+
+    sql """
+        CREATE TABLE IF NOT EXISTS test_row_column_page_size2 (
+            `aaa` varchar(170) NOT NULL COMMENT "",
+            `bbb` varchar(20) NOT NULL COMMENT "",
+            `ccc` INT NULL COMMENT "",
+            `ddd` SMALLINT NULL COMMENT ""
+        )
+        DISTRIBUTED BY HASH(`aaa`) BUCKETS 1
+        PROPERTIES (
+            "replication_num" = "1",
+            "store_row_column" = "true",
+            "row_store_page_size" = "8190"
+        );
+    """
+    qt_select_check_1 """select  $listOfColum from 
information_schema.partitions where table_schema=\"${dbName}\" order by 
$listOfColum"""
+    sql """
+        drop table test_row_column_page_size2;
+    """    
+    qt_select_check_2 """select  $listOfColum from 
information_schema.partitions where table_schema=\"${dbName}\" order by 
$listOfColum"""
+
+    def user = "partitions_user"
+    sql "DROP USER IF EXISTS ${user}"
+    sql "CREATE USER ${user} IDENTIFIED BY '123abc!@#'"
+    //cloud-mode
+    if (isCloudMode()) {
+        def clusters = sql " SHOW CLUSTERS; "
+        assertTrue(!clusters.isEmpty())
+        def validCluster = clusters[0][0]
+        sql """GRANT USAGE_PRIV ON CLUSTER ${validCluster} TO ${user}""";
+    }
+
+    sql "GRANT SELECT_PRIV ON information_schema.partitions  TO ${user}"
+
+    def tokens = context.config.jdbcUrl.split('/')
+    def url=tokens[0] + "//" + tokens[2] + "/" + "information_schema" + "?"
+
+    connect(user=user, password='123abc!@#', url=url) {
+           qt_select_check_3 """select  $listOfColum from 
information_schema.partitions where table_schema=\"${dbName}\" order by 
$listOfColum"""
+    }
+
+    sql "GRANT SELECT_PRIV ON ${dbName}.duplicate_table  TO ${user}"
+    connect(user=user, password='123abc!@#', url=url) {
+        qt_select_check_4 """select  $listOfColum from 
information_schema.partitions where table_schema=\"${dbName}\" order by 
$listOfColum"""
+    }
+    
+    sql "REVOKE SELECT_PRIV ON ${dbName}.duplicate_table  FROM ${user}"
+    connect(user=user, password='123abc!@#', url=url) {
+        qt_select_check_5 """select  $listOfColum from 
information_schema.partitions where table_schema=\"${dbName}\" order by 
$listOfColum"""
+    }
+
+}
diff --git 
a/regression-test/suites/query_p0/system/test_query_sys_tables.groovy 
b/regression-test/suites/query_p0/system/test_query_sys_tables.groovy
index 7d943894168..dd069816fd3 100644
--- a/regression-test/suites/query_p0/system/test_query_sys_tables.groovy
+++ b/regression-test/suites/query_p0/system/test_query_sys_tables.groovy
@@ -135,9 +135,9 @@ suite("test_query_sys_tables", "query,p0") {
 
 
     // test partitions
-    // have no impl
+    // have  impl now, partition based on time and date so not doing data 
validation.
+    // data validation taken care in another regression test.
     qt_desc_partitions """ desc `information_schema`.`partitions` """ 
-    order_qt_select_partitions """ select * from  
`information_schema`.`partitions`; """ 
 
 
     // test rowsets
@@ -280,4 +280,4 @@ suite("test_query_sys_tables", "query,p0") {
     qt_sql "select * from triggers"
     qt_sql "select * from parameters"
     qt_sql "select * from profiling"
-}
\ No newline at end of file
+}
diff --git a/regression-test/suites/query_p0/system/test_table_options.groovy 
b/regression-test/suites/query_p0/system/test_table_options.groovy
new file mode 100644
index 00000000000..9d2e99ab974
--- /dev/null
+++ b/regression-test/suites/query_p0/system/test_table_options.groovy
@@ -0,0 +1,217 @@
+// 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.
+
+suite("test_table_options") {
+    def dbName = "test_table_options_db"
+    sql "drop database if exists ${dbName}"
+    sql "CREATE DATABASE IF NOT EXISTS ${dbName}"
+    sql "use ${dbName}"
+
+    sql """
+       CREATE TABLE IF NOT EXISTS rangetable
+       (
+               `user_id` LARGEINT NOT NULL COMMENT "User id",
+               `date` DATE NOT NULL COMMENT "Data fill in date time",
+               `timestamp` DATETIME NOT NULL COMMENT "Timestamp of data being 
poured",
+               `city` VARCHAR(20) COMMENT "The city where the user is located",
+               `age` SMALLINT COMMENT "User age",
+               `sex` TINYINT COMMENT "User gender",
+               `last_visit_date` DATETIME REPLACE DEFAULT "1970-01-01 
00:00:00" COMMENT "User last visit time",
+               `cost` BIGINT SUM DEFAULT "0" COMMENT "Total user consumption",
+               `max_dwell_time` INT MAX DEFAULT "0" COMMENT "User maximum 
dwell time",
+               `min_dwell_time` INT MIN DEFAULT "99999" COMMENT "User minimum 
dwell time"
+       )
+       ENGINE=olap
+       AGGREGATE KEY(`user_id`, `date`, `timestamp`, `city`, `age`, `sex`)
+       PARTITION BY RANGE(`date`)
+       (
+               PARTITION `p201701` VALUES LESS THAN ("2017-02-01"),
+               PARTITION `p201702` VALUES LESS THAN ("2017-03-01"),
+               PARTITION `p201703` VALUES LESS THAN ("2017-04-01")
+       )
+       DISTRIBUTED BY HASH(`user_id`) BUCKETS 8
+       PROPERTIES
+       (
+               "replication_num" = "1"
+       );
+       """    
+    sql """
+    CREATE TABLE IF NOT EXISTS listtable
+       (
+         `user_id` LARGEINT NOT NULL COMMENT "User id",
+         `date` DATE NOT NULL COMMENT "Data fill in date time",
+         `timestamp` DATETIME NOT NULL COMMENT "Timestamp of data being 
poured",
+          `city` VARCHAR(20) COMMENT "The city where the user is located",
+          `age` SMALLINT COMMENT "User Age",
+          `sex` TINYINT COMMENT "User gender",
+          `last_visit_date` DATETIME REPLACE DEFAULT "1970-01-01 00:00:00" 
COMMENT "User last visit time",
+          `cost` BIGINT SUM DEFAULT "0" COMMENT "Total user consumption",
+          `max_dwell_time` INT MAX DEFAULT "0" COMMENT "User maximum dwell 
time",
+          `min_dwell_time` INT MIN DEFAULT "99999" COMMENT "User minimum dwell 
time"
+        )
+       ENGINE=olap
+       AGGREGATE KEY(`user_id`, `date`, `timestamp`, `city`, `age`, `sex`)
+       PARTITION BY LIST(`city`)
+       (
+               PARTITION `p_cn` VALUES IN ("Beijing", "Shanghai", "Hong Kong"),
+               PARTITION `p_usa` VALUES IN ("New York", "San Francisco"),
+               PARTITION `p_jp` VALUES IN ("Tokyo")
+       )
+       DISTRIBUTED BY HASH(`user_id`) BUCKETS 16
+       PROPERTIES
+       (
+               "replication_num" = "1"
+       );
+    """
+    sql """
+        CREATE TABLE IF NOT EXISTS randomtable
+       (
+               `user_id` LARGEINT NOT NULL COMMENT "User id",
+               `date` DATE NOT NULL COMMENT "Data fill in date time",
+               `timestamp` DATETIME NOT NULL COMMENT "Timestamp of data being 
poured",
+               `city` VARCHAR(20) COMMENT "The city where the user is located",
+               `age` SMALLINT COMMENT "User Age",
+               `sex` TINYINT COMMENT "User gender"
+       )
+       ENGINE=olap
+       DISTRIBUTED BY RANDOM BUCKETS 16
+       PROPERTIES
+       (
+               "replication_num" = "1"
+       );
+        """
+    sql """
+       CREATE TABLE IF NOT EXISTS aggregate_table
+       (
+           `user_id` LARGEINT NOT NULL COMMENT "user id",
+           `date` DATE NOT NULL COMMENT "data import time",
+           `city` VARCHAR(20) COMMENT "city",
+           `age` SMALLINT COMMENT "age",
+           `sex` TINYINT COMMENT "gender",
+           `last_visit_date` DATETIME REPLACE DEFAULT "1970-01-01 00:00:00" 
COMMENT "last visit date time",
+           `cost` BIGINT SUM DEFAULT "0" COMMENT "user total cost",
+           `max_dwell_time` INT MAX DEFAULT "0" COMMENT "user max dwell time",
+           `min_dwell_time` INT MIN DEFAULT "99999" COMMENT "user min dwell 
time"
+       )
+       AGGREGATE KEY(`user_id`, `date`, `city`, `age`, `sex`)
+       DISTRIBUTED BY HASH(`user_id`) BUCKETS 1
+       PROPERTIES (
+       "replication_allocation" = "tag.location.default: 1"
+       );
+        """
+    sql """
+       CREATE TABLE IF NOT EXISTS unique_table
+       (
+           `user_id` LARGEINT NOT NULL COMMENT "User ID",
+           `username` VARCHAR(50) NOT NULL COMMENT "Username",
+           `city` VARCHAR(20) COMMENT "User location city",
+           `age` SMALLINT COMMENT "User age",
+           `sex` TINYINT COMMENT "User gender",
+           `phone` LARGEINT COMMENT "User phone number",
+           `address` VARCHAR(500) COMMENT "User address",
+           `register_time` DATETIME COMMENT "User registration time"
+       )
+       UNIQUE KEY(`user_id`, `username`)
+       DISTRIBUTED BY HASH(`user_id`) BUCKETS 1
+       PROPERTIES (
+       "replication_allocation" = "tag.location.default: 1"
+       );
+        """
+    sql """
+       CREATE TABLE IF NOT EXISTS duplicate_table
+       (
+           `timestamp` DATETIME NOT NULL COMMENT "Log time",
+           `type` INT NOT NULL COMMENT "Log type",
+           `error_code` INT COMMENT "Error code",
+           `error_msg` VARCHAR(1024) COMMENT "Error detail message",
+           `op_id` BIGINT COMMENT "Operator ID",
+           `op_time` DATETIME COMMENT "Operation time"
+       )
+       DISTRIBUTED BY HASH(`type`) BUCKETS 1
+       PROPERTIES (
+       "replication_allocation" = "tag.location.default: 1"
+       );
+        """
+       
+    // test row column page size
+    sql """
+        CREATE TABLE IF NOT EXISTS test_row_column_page_size1 (
+            `aaa` varchar(170) NOT NULL COMMENT "",
+            `bbb` varchar(20) NOT NULL COMMENT "",
+            `ccc` INT NULL COMMENT "",
+            `ddd` SMALLINT NULL COMMENT ""
+        )
+        DISTRIBUTED BY HASH(`aaa`) BUCKETS 1
+        PROPERTIES (
+            "replication_num" = "1",
+            "store_row_column" = "true"
+        );
+    """
+
+    sql """
+        CREATE TABLE IF NOT EXISTS test_row_column_page_size2 (
+            `aaa` varchar(170) NOT NULL COMMENT "",
+            `bbb` varchar(20) NOT NULL COMMENT "",
+            `ccc` INT NULL COMMENT "",
+            `ddd` SMALLINT NULL COMMENT ""
+        )
+        DISTRIBUTED BY HASH(`aaa`) BUCKETS 1
+        PROPERTIES (
+            "replication_num" = "1",
+            "store_row_column" = "true",
+            "row_store_page_size" = "8190"
+        );
+    """
+
+    qt_select_check_1 """select * from information_schema.table_options where 
table_schema=\"${dbName}\" order by 
TABLE_CATALOG,TABLE_SCHEMA,TABLE_NAME,TABLE_MODEL,TABLE_MODEL_KEY,DISTRIBUTE_KEY,DISTRIBUTE_TYPE,BUCKETS_NUM,PARTITION_NUM;
 """
+    sql """
+        drop table test_row_column_page_size2;
+    """    
+    qt_select_check_2 """select * from information_schema.table_options where 
table_schema=\"${dbName}\" order by 
TABLE_CATALOG,TABLE_SCHEMA,TABLE_NAME,TABLE_MODEL,TABLE_MODEL_KEY,DISTRIBUTE_KEY,DISTRIBUTE_TYPE,BUCKETS_NUM,PARTITION_NUM;
 """
+
+    def user = "table_options_user"
+    sql "DROP USER IF EXISTS ${user}"
+    sql "CREATE USER ${user} IDENTIFIED BY '123abc!@#'"
+    //cloud-mode
+    if (isCloudMode()) {
+        def clusters = sql " SHOW CLUSTERS; "
+        assertTrue(!clusters.isEmpty())
+        def validCluster = clusters[0][0]
+        sql """GRANT USAGE_PRIV ON CLUSTER ${validCluster} TO ${user}""";
+    }
+
+    sql "GRANT SELECT_PRIV ON information_schema.table_properties  TO ${user}"
+
+    def tokens = context.config.jdbcUrl.split('/')
+    def url=tokens[0] + "//" + tokens[2] + "/" + "information_schema" + "?"
+
+    connect(user=user, password='123abc!@#', url=url) {
+       qt_select_check_3 """select * from information_schema.table_options 
ORDER BY 
TABLE_CATALOG,TABLE_SCHEMA,TABLE_NAME,TABLE_MODEL,TABLE_MODEL_KEY,DISTRIBUTE_KEY,DISTRIBUTE_TYPE,BUCKETS_NUM,PARTITION_NUM;
 """
+    }
+
+    sql "GRANT SELECT_PRIV ON ${dbName}.duplicate_table  TO ${user}"
+    connect(user=user, password='123abc!@#', url=url) {
+       qt_select_check_4 """select * from information_schema.table_options 
ORDER BY 
TABLE_CATALOG,TABLE_SCHEMA,TABLE_NAME,TABLE_MODEL,TABLE_MODEL_KEY,DISTRIBUTE_KEY,DISTRIBUTE_TYPE,BUCKETS_NUM,PARTITION_NUM;
 """
+    }
+    
+    sql "REVOKE SELECT_PRIV ON ${dbName}.duplicate_table  FROM ${user}"
+    connect(user=user, password='123abc!@#', url=url) {
+       qt_select_check_5 """select * from information_schema.table_options 
ORDER BY 
TABLE_CATALOG,TABLE_SCHEMA,TABLE_NAME,TABLE_MODEL,TABLE_MODEL_KEY,DISTRIBUTE_KEY,DISTRIBUTE_TYPE,BUCKETS_NUM,PARTITION_NUM;
 """
+    }
+
+
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org
For additional commands, e-mail: commits-h...@doris.apache.org

Reply via email to