/** * Copyright (c) 2021 OceanBase * OceanBase CE is licensed under Mulan PubL v2. * You can use this software according to the terms and conditions of the Mulan PubL v2. * You may obtain a copy of Mulan PubL v2 at: * http://license.coscl.org.cn/MulanPubL-2.0 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PubL v2 for more details. */ #define USING_LOG_PREFIX SQL_RESV #include "sql/resolver/ddl/ob_create_view_resolver.h" #include "sql/resolver/ob_resolver_utils.h" #include "sql/resolver/ddl/ob_create_table_stmt.h" // share CREATE TABLE stmt #include "sql/resolver/dml/ob_select_stmt.h" // resolve select clause #include "sql/resolver/dml/ob_dml_stmt.h" // PartExprItem #include "sql/ob_sql_context.h" #include "sql/ob_select_stmt_printer.h" #include "sql/session/ob_sql_session_info.h" #include "sql/resolver/ddl/ob_create_table_resolver.h" #include "lib/json/ob_json_print_utils.h" // for SJ #include "lib/hash/ob_hashset.h" namespace oceanbase { using namespace common; using namespace obrpc; using namespace share::schema; namespace sql { ObCreateViewResolver::ObCreateViewResolver(ObResolverParams ¶ms) : ObDDLResolver(params) { } ObCreateViewResolver::~ObCreateViewResolver() { } int ObCreateViewResolver::resolve(const ParseNode &parse_tree) { int ret = OB_SUCCESS; ObCreateTableStmt *stmt = NULL; bool is_sync_ddl_user = false; if (OB_UNLIKELY(T_CREATE_VIEW != parse_tree.type_) || OB_UNLIKELY(ROOT_NUM_CHILD != parse_tree.num_child_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected parse_tree", K(parse_tree.type_), K(parse_tree.num_child_), K(ret)); } else if (OB_ISNULL(parse_tree.children_) || OB_ISNULL(parse_tree.children_[VIEW_NODE]) || OB_ISNULL(allocator_) || OB_ISNULL(session_info_) || OB_ISNULL(params_.query_ctx_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(parse_tree.children_), K(parse_tree.children_[VIEW_NODE]), K(allocator_), K(session_info_), K(params_.query_ctx_)); } else if (OB_FAIL(ObResolverUtils::check_sync_ddl_user(session_info_, is_sync_ddl_user))) { LOG_WARN("Failed to check sync_dll_user", K(ret)); } else if (OB_UNLIKELY(NULL == (stmt = create_stmt()))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_ERROR("create view stmt failed", K(ret)); } else { ObString db_name; ObString view_name; char *dblink_name_ptr = NULL; int32_t dblink_name_len = 0; ObString view_define; const bool is_force_view = NULL != parse_tree.children_[FORCE_VIEW_NODE]; stmt->set_allocator(*allocator_); stmt_ = stmt; stmt->set_is_view_stmt(true); ObCreateTableArg &create_arg = stmt->get_create_table_arg(); ObTableSchema &table_schema = create_arg.schema_; ObSelectStmt *select_stmt = NULL; // 原来兼容mysql,先resolve view_definition 再 resolve view_name // resolve view_name不依赖view_definition, 但是resolve view_definition检查循环依赖时需要view_name, // 因此交换两个resolve的位置 // resolve view name; create view [ or replace] view [column_list] [table_id] create_arg.if_not_exist_ = NULL != parse_tree.children_[IF_NOT_EXISTS_NODE] || 1 == parse_tree.reserved_; create_arg.is_alter_view_ = (1 == parse_tree.reserved_); table_schema.set_force_view(is_force_view); table_schema.set_tenant_id(session_info_->get_effective_tenant_id()); table_schema.set_tablegroup_id(OB_SYS_TABLEGROUP_ID); table_schema.set_define_user_id(session_info_->get_priv_user_id()); table_schema.set_view_created_method_flag((ObViewCreatedMethodFlag)(create_arg.if_not_exist_ || is_force_view)); ParseNode *table_id_node = parse_tree.children_[TABLE_ID_NODE]; const int64_t max_user_table_name_length = lib::is_oracle_mode() ? OB_MAX_USER_TABLE_NAME_LENGTH_ORACLE : OB_MAX_USER_TABLE_NAME_LENGTH_MYSQL; ObNameCaseMode mode = OB_NAME_CASE_INVALID; bool perserve_lettercase = false; // lib::is_oracle_mode() ? true : (mode != OB_LOWERCASE_AND_INSENSITIVE); ObArray column_list; if (OB_FAIL(resolve_table_relation_node(parse_tree.children_[VIEW_NODE], view_name, db_name, false, false, &dblink_name_ptr, &dblink_name_len))) { LOG_WARN("failed to resolve table relation node!", K(ret)); } else if (NULL != dblink_name_ptr) { //don't care about dblink_name_len ret = OB_ERR_MISSING_KEYWORD; LOG_WARN("missing keyword when create view", K(ret)); LOG_USER_ERROR(OB_ERR_MISSING_KEYWORD); } else if (OB_FAIL(normalize_table_or_database_names(view_name))) { LOG_WARN("fail to normalize table name", K(view_name), K(ret)); } else if (OB_FAIL(ob_write_string(*allocator_, db_name, stmt->get_non_const_db_name()))) { LOG_WARN("failed to deep copy database name", K(ret), K(db_name)); } else if (OB_FAIL(session_info_->get_name_case_mode(mode))) { LOG_WARN("fail to get name case mode", K(ret), K(mode)); } else if (FALSE_IT(perserve_lettercase = lib::is_oracle_mode() ? true : (mode != OB_LOWERCASE_AND_INSENSITIVE))) { } else if (OB_FAIL(ObSQLUtils::check_and_convert_table_name(CS_TYPE_UTF8MB4_GENERAL_CI, perserve_lettercase, view_name))) { LOG_WARN("fail to check and convert view_name", K(ret), K(view_name)); } else if (OB_FAIL(table_schema.set_table_name(view_name))) { LOG_WARN("fail to set table_name", K(view_name), K(ret)); } else if (OB_UNLIKELY(NULL != table_id_node && (T_TABLE_ID != table_id_node->type_ || 1 != table_id_node->num_child_))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("fail to resolve table_id", K(ret)); } else { table_schema.set_table_id(table_id_node ? static_cast(table_id_node->children_[0]->value_) : OB_INVALID_ID); } if (OB_SUCC(ret)) { // resolve select stmt: create ... as