diff --git a/be/src/exec/CMakeLists.txt b/be/src/exec/CMakeLists.txt index 916b3d5ce72392..044f82d507c370 100644 --- a/be/src/exec/CMakeLists.txt +++ b/be/src/exec/CMakeLists.txt @@ -84,6 +84,7 @@ set(EXEC_FILES schema_scanner/schema_charsets_scanner.cpp schema_scanner/schema_collations_scanner.cpp schema_scanner/schema_helper.cpp + schema_scanner/schema_views_scanner.cpp partitioned_hash_table.cc partitioned_hash_table_ir.cc partitioned_aggregation_node.cc diff --git a/be/src/exec/schema_scanner.cpp b/be/src/exec/schema_scanner.cpp index c2b99da6b13c8f..4c25f9c0c0dfbd 100644 --- a/be/src/exec/schema_scanner.cpp +++ b/be/src/exec/schema_scanner.cpp @@ -23,6 +23,7 @@ #include "exec/schema_scanner/schema_variables_scanner.h" #include "exec/schema_scanner/schema_charsets_scanner.h" #include "exec/schema_scanner/schema_collations_scanner.h" +#include "exec/schema_scanner/schema_views_scanner.h" namespace doris { @@ -93,6 +94,8 @@ SchemaScanner* SchemaScanner::create(TSchemaTableType::type type) { case TSchemaTableType::SCH_SESSION_VARIABLES: case TSchemaTableType::SCH_VARIABLES: return new(std::nothrow) SchemaVariablesScanner(TVarType::SESSION); + case TSchemaTableType::SCH_VIEWS: + return new(std::nothrow) SchemaViewsScanner(); default: return new(std::nothrow) SchemaDummyScanner(); break; diff --git a/be/src/exec/schema_scanner/schema_views_scanner.cpp b/be/src/exec/schema_scanner/schema_views_scanner.cpp new file mode 100644 index 00000000000000..ac41a45bc7f05c --- /dev/null +++ b/be/src/exec/schema_scanner/schema_views_scanner.cpp @@ -0,0 +1,240 @@ +// 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_helper.h" +#include "exec/schema_scanner/schema_views_scanner.h" +#include "runtime/primitive_type.h" +#include "runtime/string_value.h" +//#include "runtime/datetime_value.h" + +namespace doris +{ + +SchemaScanner::ColumnDesc SchemaViewsScanner::_s_tbls_columns[] = { + // name, type, size, is_null + { "TABLE_CATALOG", TYPE_VARCHAR, sizeof(StringValue), true}, + { "TABLE_SCHEMA", TYPE_VARCHAR, sizeof(StringValue), false}, + { "TABLE_NAME", TYPE_VARCHAR, sizeof(StringValue), false}, + { "VIEW_DEFINITION", TYPE_VARCHAR, sizeof(StringValue), true}, + { "CHECK_OPTION", TYPE_VARCHAR, sizeof(StringValue), true}, + { "IS_UPDATABLE", TYPE_VARCHAR, sizeof(StringValue), true}, + { "DEFINER", TYPE_VARCHAR, sizeof(StringValue), true}, + { "SECURITY_TYPE", TYPE_VARCHAR, sizeof(StringValue), true}, + { "CHARACTER_SET_CLIENT", TYPE_VARCHAR, sizeof(StringValue), true}, + { "COLLATION_CONNECTION", TYPE_VARCHAR, sizeof(StringValue), true}, +}; + +SchemaViewsScanner::SchemaViewsScanner() + : SchemaScanner(_s_tbls_columns, + sizeof(_s_tbls_columns) / sizeof(SchemaScanner::ColumnDesc)), + _db_index(0), + _table_index(0) { +} + +SchemaViewsScanner::~SchemaViewsScanner() { +} + +Status SchemaViewsScanner::start(RuntimeState *state) { + if (!_is_init) { + return Status::InternalError("used before initialized."); + } + TGetDbsParams db_params; + if (NULL != _param->db) { + db_params.__set_pattern(*(_param->db)); + } + if (NULL != _param->current_user_ident) { + db_params.__set_current_user_ident(*(_param->current_user_ident)); + } else { + if (NULL != _param->user) { + db_params.__set_user(*(_param->user)); + } + if (NULL != _param->user_ip) { + db_params.__set_user_ip(*(_param->user_ip)); + } + } + + if (NULL != _param->ip && 0 != _param->port) { + RETURN_IF_ERROR(SchemaHelper::get_db_names(*(_param->ip), + _param->port, db_params, &_db_result)); + } else { + return Status::InternalError("IP or port doesn't exists"); + } + return Status::OK(); +} + +Status SchemaViewsScanner::fill_one_row(Tuple *tuple, MemPool *pool) { + // set all bit to not null + memset((void *)tuple, 0, _tuple_desc->num_null_bytes()); + const TTableStatus& tbl_status = _table_result.tables[_table_index]; + // catalog + { + tuple->set_null(_tuple_desc->slots()[0]->null_indicator_offset()); + } + // schema + { + void *slot = tuple->get_slot(_tuple_desc->slots()[1]->tuple_offset()); + StringValue* str_slot = reinterpret_cast(slot); + std::string db_name = SchemaHelper::extract_db_name(_db_result.dbs[_db_index - 1]); + str_slot->ptr = (char *)pool->allocate(db_name.size()); + str_slot->len = db_name.size(); + memcpy(str_slot->ptr, db_name.c_str(), str_slot->len); + } + // name + { + void *slot = tuple->get_slot(_tuple_desc->slots()[2]->tuple_offset()); + StringValue* str_slot = reinterpret_cast(slot); + const std::string* src = &tbl_status.name; + str_slot->len = src->length(); + str_slot->ptr = (char *)pool->allocate(str_slot->len); + if (NULL == str_slot->ptr) { + return Status::InternalError("Allocate memcpy failed."); + } + memcpy(str_slot->ptr, src->c_str(), str_slot->len); + } + // definition + { + void *slot = tuple->get_slot(_tuple_desc->slots()[3]->tuple_offset()); + StringValue* str_slot = reinterpret_cast(slot); + const std::string* ddl_sql = &tbl_status.ddl_sql; + str_slot->len = ddl_sql->length(); + str_slot->ptr = (char *)pool->allocate(str_slot->len); + if (NULL == str_slot->ptr) { + return Status::InternalError("Allocate memcpy failed."); + } + memcpy(str_slot->ptr, ddl_sql->c_str(), str_slot->len); + } + // check_option + { + void *slot = tuple->get_slot(_tuple_desc->slots()[4]->tuple_offset()); + StringValue* str_slot = reinterpret_cast(slot); + // This is from views in mysql + const std::string check_option = "NONE"; + str_slot->len = check_option.length(); + str_slot->ptr = (char *)pool->allocate(str_slot->len); + if (NULL == str_slot->ptr) { + return Status::InternalError("Allocate memcpy failed."); + } + memcpy(str_slot->ptr, check_option.c_str(), str_slot->len); + } + // is_updatable + { + void *slot = tuple->get_slot(_tuple_desc->slots()[5]->tuple_offset()); + StringValue* str_slot = reinterpret_cast(slot); + // This is from views in mysql + const std::string is_updatable = "NO"; + str_slot->len = is_updatable.length(); + str_slot->ptr = (char *)pool->allocate(str_slot->len); + if (NULL == str_slot->ptr) { + return Status::InternalError("Allocate memcpy failed."); + } + memcpy(str_slot->ptr, is_updatable.c_str(), str_slot->len); + } + // definer + { + void *slot = tuple->get_slot(_tuple_desc->slots()[6]->tuple_offset()); + StringValue* str_slot = reinterpret_cast(slot); + // This is from views in mysql + const std::string definer = "root@%"; + str_slot->len = definer.length(); + str_slot->ptr = (char *)pool->allocate(str_slot->len); + if (NULL == str_slot->ptr) { + return Status::InternalError("Allocate memcpy failed."); + } + memcpy(str_slot->ptr, definer.c_str(), str_slot->len); + } + // security_type + { + void *slot = tuple->get_slot(_tuple_desc->slots()[7]->tuple_offset()); + StringValue* str_slot = reinterpret_cast(slot); + // This is from views in mysql + const std::string security_type = "DEFINER"; + str_slot->len = security_type.length(); + str_slot->ptr = (char *)pool->allocate(str_slot->len); + if (NULL == str_slot->ptr) { + return Status::InternalError("Allocate memcpy failed."); + } + memcpy(str_slot->ptr, security_type.c_str(), str_slot->len); + } + // character_set_client + { + void *slot = tuple->get_slot(_tuple_desc->slots()[8]->tuple_offset()); + StringValue* str_slot = reinterpret_cast(slot); + // This is from views in mysql + const std::string encoding = "utf8"; + str_slot->len = encoding.length(); + str_slot->ptr = (char *)pool->allocate(str_slot->len); + if (NULL == str_slot->ptr) { + return Status::InternalError("Allocate memcpy failed."); + } + memcpy(str_slot->ptr, encoding.c_str(), str_slot->len); + } + // collation_connection + { + tuple->set_null(_tuple_desc->slots()[9]->null_indicator_offset()); + } + _table_index++; + return Status::OK(); +} + +Status SchemaViewsScanner::get_new_table() { + TGetTablesParams table_params; + table_params.__set_db(_db_result.dbs[_db_index++]); + if (NULL != _param->wild) { + table_params.__set_pattern(*(_param->wild)); + } + if (NULL != _param->current_user_ident) { + table_params.__set_current_user_ident(*(_param->current_user_ident)); + } else { + if (NULL != _param->user) { + table_params.__set_user(*(_param->user)); + } + if (NULL != _param->user_ip) { + table_params.__set_user_ip(*(_param->user_ip)); + } + } + table_params.__set_type("VIEW"); + + if (NULL != _param->ip && 0 != _param->port) { + RETURN_IF_ERROR(SchemaHelper::list_table_status(*(_param->ip), + _param->port, table_params, &_table_result)); + } else { + return Status::InternalError("IP or port doesn't exists"); + } + _table_index = 0; + return Status::OK(); +} + +Status SchemaViewsScanner::get_next_row(Tuple *tuple, MemPool *pool, bool *eos) { + if (!_is_init) { + return Status::InternalError("Used before initialized."); + } + if (NULL == tuple || NULL == pool || NULL == eos) { + return Status::InternalError("input pointer is NULL."); + } + while (_table_index >= _table_result.tables.size()) { + if (_db_index < _db_result.dbs.size()) { + RETURN_IF_ERROR(get_new_table()); + } else { + *eos = true; + return Status::OK(); + } + } + *eos = false; + return fill_one_row(tuple, pool); +} + +} diff --git a/be/src/exec/schema_scanner/schema_views_scanner.h b/be/src/exec/schema_scanner/schema_views_scanner.h new file mode 100644 index 00000000000000..e674d5227a53a1 --- /dev/null +++ b/be/src/exec/schema_scanner/schema_views_scanner.h @@ -0,0 +1,47 @@ +// 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. + +#ifndef DORIS_BE_SRC_QUERY_EXEC_SCHEMA_SCANNER_SCHEMA_VIEWS_SCANNER_H +#define DORIS_BE_SRC_QUERY_EXEC_SCHEMA_SCANNER_SCHEMA_VIEWS_SCANNER_H + +#include "exec/schema_scanner.h" +#include "gen_cpp/FrontendService_types.h" + +namespace doris { + +class SchemaViewsScanner : public SchemaScanner { +public: + SchemaViewsScanner(); + virtual ~SchemaViewsScanner(); + + virtual Status start(RuntimeState *state); + virtual Status get_next_row(Tuple *tuple, MemPool *pool, bool *eos); + +private: + Status get_new_table(); + Status fill_one_row(Tuple *tuple, MemPool *pool); + + int _db_index; + int _table_index; + TGetDbsResult _db_result; + TListTableStatusResult _table_result; + static SchemaScanner::ColumnDesc _s_tbls_columns[]; +}; + +} + +#endif diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/Database.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/Database.java index bf3ed7a551f4e4..8db36e74562b0e 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/Database.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/Database.java @@ -342,6 +342,16 @@ public List getTables() { return new ArrayList
(idToTable.values()); } + public List
getViews() { + List
views = new ArrayList<>(); + for (Table table : idToTable.values()) { + if (table.getType() == TableType.VIEW) { + views.add(table); + } + } + return views; + } + public Set getTableNamesWithLock() { readLock(); try { 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 a3788e20c28093..97ec5be3144b0c 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 @@ -281,7 +281,25 @@ public static Builder builder() { .column("XA", ScalarType.createVarchar(3)) .column("SAVEPOINTS", ScalarType.createVarchar(3)) .build())) + .put("views", + new SchemaTable( + SystemIdGenerator.getNextId(), + "views", + TableType.SCHEMA, + builder() + .column("TABLE_CATALOG", ScalarType.createVarchar(512)) + .column("TABLE_SCHEMA", ScalarType.createVarchar(64)) + .column("TABLE_NAME", ScalarType.createVarchar(64)) + .column("VIEW_DEFINITION", ScalarType.createVarchar(8096)) + .column("CHECK_OPTION", ScalarType.createVarchar(8)) + .column("IS_UPDATABLE", ScalarType.createVarchar(3)) + .column("DEFINER", ScalarType.createVarchar(77)) + .column("SECURITY_TYPE", ScalarType.createVarchar(7)) + .column("CHARACTER_SET_CLIENT", ScalarType.createVarchar(32)) + .column("COLLATION_CONNECTION", ScalarType.createVarchar(32)) + .build())) .build(); + // views column is from show create table views in mysql: 5.5.6 public static class Builder { List columns; diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/Table.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/Table.java index 59c741432e948e..cda8491d31b04c 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/Table.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/Table.java @@ -94,6 +94,8 @@ public enum TableType { protected boolean isTypeRead = false; // table(view)'s comment protected String comment = ""; + // sql for creating this table, default is ""; + protected String ddlSql = ""; public Table(TableType type) { this.type = type; @@ -145,6 +147,10 @@ public List getFullSchema() { return fullSchema; } + public String getDdlSql() { + return ddlSql; + } + // should override in subclass if necessary public List getBaseSchema() { return getBaseSchema(Util.showHiddenColumns()); diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/View.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/View.java index 24a7c6a6f8e4a1..19f1efd4217cfc 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/View.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/View.java @@ -140,6 +140,11 @@ public String getInlineViewDef() { return inlineViewDef; } + @Override + public String getDdlSql() { + return inlineViewDef; + } + /** * Initializes the originalViewDef, inlineViewDef, and queryStmt members * by parsing the expanded view definition SQL-string. diff --git a/fe/fe-core/src/main/java/org/apache/doris/service/FrontendServiceImpl.java b/fe/fe-core/src/main/java/org/apache/doris/service/FrontendServiceImpl.java index 0f1a46770980e5..5ff844f3770965 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/service/FrontendServiceImpl.java +++ b/fe/fe-core/src/main/java/org/apache/doris/service/FrontendServiceImpl.java @@ -248,7 +248,19 @@ public TListTableStatusResult listTableStatus(TGetTablesParams params) throws TE if (db != null) { db.readLock(); try { - for (Table table : db.getTables()) { + List
tables = null; + if (!params.isSetType() || params.getType() == null || params.getType().isEmpty()) { + tables = db.getTables(); + } else { + switch (params.getType()) { + case "VIEW": + tables = db.getViews(); + break; + default: + tables = db.getTables(); + } + } + for (Table table : tables) { if (!Catalog.getCurrentCatalog().getAuth().checkTblPriv(currentUser, params.db, table.getName(), PrivPredicate.SHOW)) { continue; @@ -264,6 +276,7 @@ public TListTableStatusResult listTableStatus(TGetTablesParams params) throws TE status.setComment(table.getComment()); status.setCreateTime(table.getCreateTime()); status.setLastCheckTime(table.getLastCheckTime()); + status.setDdlSql(table.getDdlSql()); tablesResult.add(status); } diff --git a/gensrc/thrift/FrontendService.thrift b/gensrc/thrift/FrontendService.thrift index 69dccc5faad00b..71b969c79bb798 100644 --- a/gensrc/thrift/FrontendService.thrift +++ b/gensrc/thrift/FrontendService.thrift @@ -302,6 +302,7 @@ struct TGetTablesParams { 3: optional string user // deprecated 4: optional string user_ip // deprecated 5: optional Types.TUserIdentity current_user_ident // to replace the user and user ip + 6: optional string type } struct TTableStatus { @@ -311,6 +312,7 @@ struct TTableStatus { 4: optional string engine 5: optional i64 last_check_time 6: optional i64 create_time + 7: optional string ddl_sql } struct TListTableStatusResult {