/** * 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 SERVER #include "sql/resolver/ddl/ob_alter_tablegroup_resolver.h" #include "sql/resolver/ddl/ob_tablegroup_resolver.h" #include "share/ob_define.h" #include "share/ob_rpc_struct.h" #include "sql/session/ob_sql_session_info.h" namespace oceanbase { using namespace share::schema; using namespace common; namespace sql { using share::schema::AlterColumnSchema; ObAlterTablegroupResolver::ObAlterTablegroupResolver(ObResolverParams ¶ms) : ObTableGroupResolver(params) { } ObAlterTablegroupResolver::~ObAlterTablegroupResolver() { } int ObAlterTablegroupResolver::resolve(const ParseNode &parser_tree) { int ret = OB_SUCCESS; ParseNode *node = const_cast(&parser_tree); if (OB_ISNULL(session_info_) || OB_ISNULL(node) || T_ALTER_TABLEGROUP != node->type_ || OB_ISNULL(node->children_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("session_info_ is null or parser error", K(ret)); } ObAlterTablegroupStmt *alter_tablegroup_stmt = NULL; if (OB_SUCC(ret)) { //create alter table stmt if (NULL == (alter_tablegroup_stmt = create_stmt())) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_ERROR("failed to create alter table stmt", K(ret)); } else { stmt_ = alter_tablegroup_stmt; } if (OB_SUCC(ret)) { if (NULL != node->children_[TG_NAME] && T_IDENT == node->children_[TG_NAME]->type_) { ObString tablegroup_name; tablegroup_name.assign_ptr(node->children_[TG_NAME]->str_value_, static_cast(node->children_[TG_NAME]->str_len_)); alter_tablegroup_stmt->set_tenant_id(session_info_->get_effective_tenant_id()); alter_tablegroup_stmt->set_tablegroup_name(tablegroup_name); } else { ret = OB_ERR_UNEXPECTED; LOG_WARN("node is null or node type is not T_IDENT", K(ret)); } } if (OB_FAIL(ret)) { } else if (OB_ISNULL(node->children_[1])) { ret = OB_ERR_UNEXPECTED; LOG_WARN("node is null", K(ret)); } else if (T_TABLE_LIST == node->children_[1]->type_) { ParseNode *table_list_node = node->children_[TABLE_LIST]; for(int32_t i = 0; OB_SUCC(ret) && i < table_list_node->num_child_; ++i) { ParseNode *relation_node = table_list_node->children_[i]; if (NULL != relation_node) { ObString table_name; ObString database_name; obrpc::ObTableItem table_item; if (OB_FAIL(resolve_table_relation_node(relation_node, table_name, database_name))) { LOG_WARN("failed to resolve table name", K(ret), K(table_item)); } else { table_item.table_name_ = table_name; table_item.database_name_ = database_name; if (OB_FAIL(alter_tablegroup_stmt->add_table_item(table_item))) { LOG_WARN("failed to add table item!", K(ret), K(table_item)); } } } else { ret = OB_ERR_UNEXPECTED; LOG_WARN("node is null", K(ret)); } } //end for } else if (T_ALTER_TABLEGROUP_ACTION_LIST == node->children_[1]->type_) { if (OB_FAIL(resolve_tablegroup_option(alter_tablegroup_stmt, node->children_[1]))) { LOG_WARN("fail to resolve tablegroup option", K(ret)); } else { alter_tablegroup_stmt->set_alter_option_set(get_alter_option_bitset()); } } else if (T_ALTER_PARTITION_OPTION == node->children_[1]->type_) { if (OB_FAIL(resolve_partition_options(*(node->children_[1])))) { LOG_WARN("fail to resolve tablegroup partition option", K(ret)); } else { // partition_array是否序列化依赖part_level,由于resolver端不获取schema, // 为避免序列化时丢失数据,可设置part_level为PARTITION_LEVEL_ONE // (目前仅能动态增删一级range/range column分区) alter_tablegroup_stmt->get_alter_tablegroup_arg() .alter_tablegroup_schema_.set_part_level(PARTITION_LEVEL_ONE); } } else { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid node type", K(ret), K(node->children_[1]->type_)); } } return ret; } int ObAlterTablegroupResolver::resolve_partition_options(const ParseNode &node) { int ret = OB_SUCCESS; if (OB_UNLIKELY(T_ALTER_PARTITION_OPTION != node.type_ || 0 >= node.num_child_ || OB_ISNULL(node.children_) || OB_ISNULL(node.children_[0]))) { ret = OB_ERR_UNEXPECTED; SQL_RESV_LOG(WARN, "invalid parse tree!", K(ret)); } else if (OB_ISNULL(session_info_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("session info is null", K(ret)); } else { ObAlterTablegroupStmt *alter_tablegroup_stmt = get_alter_tablegroup_stmt(); if (OB_SUCC(ret)) { obrpc::ObAlterTablegroupArg &arg = alter_tablegroup_stmt->get_alter_tablegroup_arg(); switch(node.children_[0]->type_) { case T_ALTER_PARTITION_ADD: { ParseNode *partition_node = node.children_[0]; if (OB_FAIL(resolve_add_partition(*partition_node))) { SQL_RESV_LOG(WARN, "Resolve add partition error!", K(ret)); } else if (OB_FAIL(arg.alter_option_bitset_.add_member(obrpc::ObAlterTablegroupArg::ADD_PARTITION))) { LOG_WARN("failed to add member", K(ret)); } break; } case T_ALTER_PARTITION_DROP: { ParseNode *partition_node = node.children_[0]; if (OB_FAIL(resolve_drop_partition(*partition_node))) { SQL_RESV_LOG(WARN, "Resolve drop partition error!", K(ret)); } else if (OB_FAIL(arg.alter_option_bitset_.add_member(obrpc::ObAlterTablegroupArg::DROP_PARTITION))) { LOG_WARN("failed to add member", K(ret)); } break; } case T_ALTER_PARTITION_PARTITIONED: { ParseNode *partition_node = node.children_[0]; bool enable_split_partition = false; if (OB_ISNULL(partition_node) || 1 != partition_node->num_child_ || OB_ISNULL(partition_node->children_[0])) { ret = OB_INVALID_ARGUMENT; SQL_RESV_LOG(WARN, "invalid partition node", K(ret), K(partition_node)); } else if (OB_FAIL(get_enable_split_partition(session_info_->get_effective_tenant_id(), enable_split_partition))) { LOG_WARN("failed to get enable split partition config", K(ret), "tenant_id", session_info_->get_effective_tenant_id()); } else if (!enable_split_partition) { ret = OB_OP_NOT_ALLOW; LOG_WARN("partitioned table not allow", K(ret)); LOG_USER_ERROR(OB_OP_NOT_ALLOW, "partition table"); } else if (OB_FAIL(resolve_partition_table_option(alter_tablegroup_stmt, partition_node->children_[0], arg.alter_tablegroup_schema_))) { LOG_WARN("fail to resolve partition node", K(ret), K(partition_node)); } else if (OB_FAIL(arg.alter_option_bitset_.add_member(obrpc::ObAlterTablegroupArg::PARTITIONED_TABLE))) { LOG_WARN("failed to add member", K(ret)); } break; } case T_ALTER_PARTITION_REORGANIZE: { ParseNode *partition_node = node.children_[0]; bool enable_split_partition = false; if (OB_ISNULL(partition_node) || 2 != partition_node->num_child_ || OB_ISNULL(partition_node->children_[0]) || OB_ISNULL(partition_node->children_[1])) { ret = OB_INVALID_ARGUMENT; SQL_RESV_LOG(WARN, "invalid partition node", K(ret), K(partition_node)); } else if (OB_FAIL(get_enable_split_partition(session_info_->get_effective_tenant_id(), enable_split_partition))) { LOG_WARN("failed to get enable split partition config", K(ret), "tenant_id", session_info_->get_effective_tenant_id()); } else if (!enable_split_partition) { ret = OB_OP_NOT_ALLOW; LOG_WARN("reorganize partition not allow", K(ret)); LOG_USER_ERROR(OB_OP_NOT_ALLOW, "reorganize partition"); } else if (OB_FAIL(resolve_reorganize_partition(*partition_node))) { LOG_WARN("failed to reorganize partition", K(ret)); } else if (OB_FAIL(arg.alter_option_bitset_.add_member(obrpc::ObAlterTablegroupArg::REORGANIZE_PARTITION))) { LOG_WARN("failed to add member", K(ret)); } break; } case T_ALTER_PARTITION_SPLIT: { ParseNode *partition_node = node.children_[0]; bool enable_split_partition = false; if (OB_ISNULL(partition_node) || 2 != partition_node->num_child_ || OB_ISNULL(partition_node->children_[0]) || OB_ISNULL(partition_node->children_[1])) { ret = OB_INVALID_ARGUMENT; SQL_RESV_LOG(WARN, "invalid partition node", K(ret), K(partition_node)); } else if (OB_FAIL(get_enable_split_partition(session_info_->get_effective_tenant_id(), enable_split_partition))) { LOG_WARN("failed to get enable split partition config", K(ret), "tenant_id", session_info_->get_effective_tenant_id()); } else if (!enable_split_partition) { ret = OB_OP_NOT_ALLOW; LOG_WARN("split partition not allow", K(ret)); LOG_USER_ERROR(OB_OP_NOT_ALLOW, "split partition"); } else if (OB_FAIL(resolve_split_partition(*partition_node))) { LOG_WARN("failed to reorganize partition", K(ret)); } else if (OB_FAIL(arg.alter_option_bitset_.add_member(obrpc::ObAlterTablegroupArg::SPLIT_PARTITION))) { LOG_WARN("failed to add member", K(ret)); } break; } default: { ret = OB_ERR_UNEXPECTED; SQL_RESV_LOG(WARN, "Unknown alter partition option %d!", "option type", node.children_[0]->type_, K(ret)); break; } } } } return ret; } int ObAlterTablegroupResolver::resolve_add_partition(const ParseNode &node) { int ret = OB_SUCCESS; int64_t expr_num = OB_INVALID_INDEX; ParseNode *range_part_elements_node = NULL; PartitionInfo part_info; bool in_tablegroup = true; ObAlterTablegroupStmt *alter_tablegroup_stmt = get_alter_tablegroup_stmt(); const ObTablegroupSchema *tablegroup_schema = NULL; if (OB_ISNULL(schema_checker_) || OB_ISNULL(alter_tablegroup_stmt) || OB_ISNULL(node.children_[0])) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid schema, stmt or node ", K(ret), KP(schema_checker_), KP(alter_tablegroup_stmt), "node", node.children_[0]); } else if (OB_FAIL(schema_checker_->get_tablegroup_schema(session_info_->get_effective_tenant_id(), alter_tablegroup_stmt->get_tablegroup_name(), tablegroup_schema))) { LOG_WARN("fail to get tablegroup schema", K(ret)); } else if (OB_ISNULL(tablegroup_schema)) { ret = OB_TABLEGROUP_NOT_EXIST; LOG_WARN("invalid tablegroup schema", K(ret)); } else if (OB_ISNULL(range_part_elements_node = node.children_[0]->children_[0])) { ret = OB_ERR_UNEXPECTED; LOG_WARN("NULL ptr", K(ret)); } else if (tablegroup_schema->is_range_part()) { // resolver端放宽对value类型的检查,由rs端检查range分区的value是否为int const ObPartitionFuncType part_type = ObPartitionFuncType::PARTITION_FUNC_TYPE_RANGE_COLUMNS; // 此处expr_num由resolver解析所得,不代表tablegroup实际的expr_num if (OB_FAIL(resolve_range_partition_elements(range_part_elements_node, false, // is_subpartition part_type, part_info.range_value_exprs_, part_info.parts_, part_info.subparts_, expr_num, in_tablegroup))) { LOG_WARN("resolve range partition elements fail", K(ret)); } else if (OB_FAIL(alter_tablegroup_stmt->get_part_values_exprs().assign( part_info.range_value_exprs_))) { LOG_WARN("assign faield", K(ret)); } } else if (tablegroup_schema->is_list_part()) { const ObPartitionFuncType part_type = ObPartitionFuncType::PARTITION_FUNC_TYPE_LIST_COLUMNS; if (OB_FAIL(resolve_list_partition_elements(range_part_elements_node, false, part_type, expr_num, part_info.list_value_exprs_, part_info.parts_, part_info.subparts_, in_tablegroup))) { LOG_WARN("resolve list partition elememts fail", K(ret)); } else if (OB_FAIL(alter_tablegroup_stmt->get_part_values_exprs().assign(part_info.list_value_exprs_))) { LOG_WARN("assign list values failed", K(ret)); } } if (OB_FAIL(ret)) { } else { share::schema::ObPartition *part = NULL; ObTablegroupSchema &alter_tablegroup_schema = get_alter_tablegroup_stmt()->get_alter_tablegroup_arg().alter_tablegroup_schema_; for (int64_t i = 0; OB_SUCC(ret) && i < part_info.parts_.count(); ++i) { part = &(part_info.parts_.at(i)); if (!part->get_part_name().empty()) { if (OB_FAIL(alter_tablegroup_schema.check_part_name(*part))) { LOG_WARN("check part name failed", K(ret)); } } if (OB_FAIL(ret)) { } else if (OB_FAIL(alter_tablegroup_schema.add_partition(*part))) { LOG_WARN("add partition failed", K(ret)); } } if (OB_SUCC(ret)) { alter_tablegroup_stmt->set_part_func_expr_num(expr_num); alter_tablegroup_schema.get_part_option().set_part_func_type(tablegroup_schema->get_part_option().get_part_func_type()); alter_tablegroup_schema.get_part_option().set_part_num(alter_tablegroup_schema.get_partition_num()); } } return ret; } int ObAlterTablegroupResolver::resolve_drop_partition(const ParseNode &node) { int ret = OB_SUCCESS; if (OB_ISNULL(node.children_) || (T_ALTER_PARTITION_DROP != node.type_ && T_ALTER_PARTITION_TRUNCATE != node.type_ )) { ret = OB_ERR_UNEXPECTED; SQL_RESV_LOG(WARN, "invalid parse tree", K(ret), "type", node.type_); } else { const ParseNode *name_list = node.children_[0]; if (OB_ISNULL(name_list)) { ret = OB_ERR_UNEXPECTED; SQL_RESV_LOG(WARN, "invalid parse tree", K(ret)); } else { ObAlterTablegroupStmt *alter_tablegroup_stmt = get_alter_tablegroup_stmt(); if (OB_ISNULL(alter_tablegroup_stmt)) { ret = OB_ERR_UNEXPECTED; SQL_RESV_LOG(WARN, "alter tablegroup stmt should not be null", K(ret)); } ObTablegroupSchema &alter_tablegroup_schema = alter_tablegroup_stmt->get_alter_tablegroup_arg().alter_tablegroup_schema_; for (int64_t i = 0; OB_SUCC(ret) && i < name_list->num_child_; ++i) { ObPartition part; ObString partition_name(static_cast(name_list->children_[i]->str_len_), name_list->children_[i]->str_value_); if (OB_FAIL(part.set_part_name(partition_name))) { ret = OB_ALLOCATE_MEMORY_FAILED; SQL_RESV_LOG(ERROR, "set partition name failed", K(partition_name), K(ret)); } else if (OB_FAIL(alter_tablegroup_schema.check_part_name(part))){ SQL_RESV_LOG(WARN, "check part name failed!", K(part), K(ret)); } else if (OB_FAIL(alter_tablegroup_schema.add_partition(part))){ SQL_RESV_LOG(WARN, "add partition failed!", K(part), K(ret)); } } } } return ret; } int ObAlterTablegroupResolver::resolve_reorganize_partition(const ParseNode &node) { int ret = OB_SUCCESS; ObAlterTablegroupStmt *alter_tablegroup_stmt = get_alter_tablegroup_stmt(); if (T_ALTER_PARTITION_REORGANIZE != node.type_ || 2 != node.num_child_ || OB_ISNULL(node.children_[0]) || OB_ISNULL(node.children_[1]) || OB_ISNULL(alter_tablegroup_stmt)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid arguement", K(ret), "children num", node.num_child_, "children[0]", node.children_[0], "children[1]", node.children_[1]); } else { ObTablegroupSchema &alter_tablegroup_schema = alter_tablegroup_stmt->get_alter_tablegroup_arg().alter_tablegroup_schema_; ParseNode *name_list = node.children_[1]; if (OB_ISNULL(name_list)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret), K(name_list)); } else if (1 != name_list->num_child_) { ret = OB_NOT_SUPPORTED; LOG_WARN("alter tablegroup reorganize multi partition not supported now", K(ret)); LOG_USER_ERROR(OB_NOT_SUPPORTED, "alter tablegroup reorganize multiple partitions"); } else if (OB_NOT_NULL(name_list->children_[0])) { ObPartition part; ObString partition_name(static_cast(name_list->children_[0]->str_len_), name_list->children_[0]->str_value_); if (OB_FAIL(alter_tablegroup_schema.set_split_partition(partition_name))) { LOG_WARN("failed to set split partition name", K(ret)); } } else { ret = OB_ERR_UNEXPECTED; LOG_WARN("name list can not be null", K(ret), K(name_list)); } if (OB_FAIL(ret)) { //nothing } else if (OB_FAIL(resolve_add_partition(node))) { LOG_WARN("failed resolve add partition", K(ret)); } else if (1 == alter_tablegroup_schema.get_partition_num()) { ret = OB_ERR_SPLIT_INTO_ONE_PARTITION; LOG_USER_ERROR(OB_ERR_SPLIT_INTO_ONE_PARTITION); LOG_WARN("can not split partition into one partition", K(ret), K(alter_tablegroup_schema)); } } return ret; } int ObAlterTablegroupResolver::resolve_split_partition(const ParseNode &node) { int ret = OB_SUCCESS; ObAlterTablegroupStmt *alter_tablegroup_stmt = get_alter_tablegroup_stmt(); const ObTablegroupSchema *tablegroup_schema = NULL; if (OB_ISNULL(schema_checker_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid schema check", K(ret)); } else if (OB_FAIL(schema_checker_->get_tablegroup_schema(session_info_->get_effective_tenant_id(), alter_tablegroup_stmt->get_tablegroup_name(), tablegroup_schema))) { LOG_WARN("fail to get tablegroup schema", K(ret)); } else if (OB_ISNULL(tablegroup_schema)) { ret = OB_TABLEGROUP_NOT_EXIST; LOG_WARN("invalid tablegroup schema", K(ret)); } else if (T_ALTER_PARTITION_SPLIT != node.type_ || 2 != node.num_child_ || OB_ISNULL(node.children_[0]) || OB_ISNULL(node.children_[1]) || T_SPLIT_ACTION != node.children_[1]->type_) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret), "node_type", node.type_, "node_num", node.num_child_); } else if (OB_ISNULL(alter_tablegroup_stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("alter table stmt should not be null", K(ret)); } else { ParseNode *name_list = node.children_[0]; ObTablegroupSchema &alter_tablegroup_schema = alter_tablegroup_stmt->get_alter_tablegroup_arg().alter_tablegroup_schema_; if (OB_ISNULL(name_list)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret)); } else { ObString partition_name(static_cast(name_list->str_len_), name_list->str_value_); if (OB_FAIL(alter_tablegroup_schema.set_split_partition(partition_name))) { LOG_WARN("failed to set split partition name", K(ret)); } } int64_t partition_count = OB_INVALID_COUNT; int64_t expr_value_num = OB_INVALID_COUNT; const ParseNode *split_node = node.children_[1]; PartitionInfo part_info; if (OB_FAIL(ret)) { //nothing } else if (OB_ISNULL(split_node)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("split node is null", K(ret), K(split_node)); } else if (OB_FAIL(check_split_type_valid(split_node, tablegroup_schema->get_part_option().get_part_func_type()))) { LOG_WARN("failed to check split type valid", K(ret), K(tablegroup_schema)); } else if (OB_NOT_NULL(split_node->children_[AT_VALUES_NODE])) { // split at [into ()] partition_count = 1; if (OB_FAIL(resolve_split_at_partition(alter_tablegroup_stmt, split_node, tablegroup_schema->get_part_option().get_part_func_type(), part_info.part_func_exprs_, alter_tablegroup_schema, expr_value_num, true))) { LOG_WARN("failed to resolve split at partition", K(ret)); } } else if (OB_NOT_NULL(split_node->children_[PARTITION_DEFINE_NODE]) && OB_NOT_NULL(split_node->children_[PARTITION_DEFINE_NODE]->children_[0])) { // split into () ParseNode *range_element_node = split_node->children_[PARTITION_DEFINE_NODE]->children_[0]; if (OB_FAIL(resolve_split_into_partition(alter_tablegroup_stmt, range_element_node, tablegroup_schema->get_part_option().get_part_func_type(), part_info.part_func_exprs_, partition_count, expr_value_num, alter_tablegroup_schema, true))) { LOG_WARN("failed to resolve split at partition", K(ret)); } } else { //不能即没有at也没有partition说明 ret = OB_ERR_MISS_AT_VALUES; LOG_WARN("miss at and less than values", K(ret)); LOG_USER_ERROR(OB_ERR_MISS_AT_VALUES); } if (OB_FAIL(ret)) { } else { alter_tablegroup_stmt->set_part_func_expr_num(expr_value_num); alter_tablegroup_schema.get_part_option().set_part_func_type(tablegroup_schema->get_part_option().get_part_func_type()); alter_tablegroup_schema.get_part_option().set_part_num(partition_count);//最后一个partition可能没有最大值,需要在rs端处理 } } return ret; } } //namespace common } //namespace oceanbase