/** * 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/dml/ob_insert_resolver.h" #include "share/ob_define.h" #include "share/schema/ob_schema_struct.h" #include "share/schema/ob_column_schema.h" #include "share/ob_autoincrement_param.h" #include "common/sql_mode/ob_sql_mode_utils.h" #include "sql/resolver/dml/ob_select_stmt.h" #include "sql/resolver/dml/ob_select_resolver.h" #include "sql/resolver/expr/ob_raw_expr_info_extractor.h" #include "sql/session/ob_sql_session_info.h" #include "sql/resolver/ob_resolver_utils.h" #include "sql/rewrite/ob_transform_utils.h" #include "sql/resolver/expr/ob_raw_expr_util.h" #include "sql/resolver/dml/ob_insert_stmt.h" #include "sql/parser/parse_malloc.h" #include "ob_default_value_utils.h" #include "observer/ob_server.h" #include "common/ob_smart_call.h" namespace oceanbase { using namespace common; using namespace share; using namespace share::schema; namespace sql { ObInsertResolver::ObInsertResolver(ObResolverParams& params) : ObDMLResolver(params), insert_column_ids_(), row_count_(0), sub_select_resolver_(NULL), autoinc_col_added_(false), is_column_specify_(false), is_all_default_(false), is_oracle_tmp_table_(false), is_oracle_tmp_table_array_() { params.contain_dml_ = true; } ObInsertResolver::~ObInsertResolver() { if (NULL != sub_select_resolver_) { sub_select_resolver_->~ObSelectResolver(); } } int ObInsertResolver::resolve(const ParseNode& parse_tree) { int ret = OB_SUCCESS; ObInsertStmt* insert_stmt = NULL; if (OB_UNLIKELY(T_INSERT != parse_tree.type_) || OB_UNLIKELY(4 > parse_tree.num_child_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid parse tree", K(parse_tree.type_), K(parse_tree.num_child_)); } else if (OB_ISNULL(insert_stmt = create_stmt())) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_ERROR("create insert stmt failed", K(insert_stmt)); } else if (OB_ISNULL(parse_tree.children_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid parse tree", K(parse_tree.children_)); } else if (OB_ISNULL(session_info_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid session info", K(session_info_)); } else if (FALSE_IT(session_info_->set_ignore_stmt(NULL != parse_tree.children_[3] ? true : false))) { // do nothing } else if (OB_LIKELY(T_SINGLE_TABLE_INSERT == parse_tree.children_[0]->type_)) { if (OB_FAIL(resolve_single_table_insert(*parse_tree.children_[0]))) { LOG_WARN("resolve single table insert failed", K(ret)); } } else { //@TODO: resolve multi table insert(oracle) } if (OB_SUCC(ret)) { // REPLACE flag if (OB_ISNULL(parse_tree.children_[1])) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("invalid node for is_replacement", K(parse_tree.children_[1])); } else if (parse_tree.children_[1]->type_ == T_REPLACE) { insert_stmt->set_replace(true); if (OB_FAIL(add_rowkey_ids(insert_stmt->get_insert_base_tid(), insert_stmt->get_primary_key_ids()))) { LOG_WARN("fail to add rowkey column for replace", K(ret)); } } else { insert_stmt->set_replace(false); } } // resolve hints and inner cast if (OB_SUCC(ret)) { if (OB_FAIL(resolve_hints(parse_tree.children_[2]))) { LOG_WARN("failed to resolve hints", K(ret)); } } if (OB_SUCC(ret)) { insert_stmt->set_ignore(session_info_->is_ignore_stmt()); if (insert_stmt->is_replace() && insert_stmt->is_ignore()) { ret = OB_NOT_SUPPORTED; LOG_USER_ERROR(OB_NOT_SUPPORTED, "replace statement with ignore"); } } if (OB_SUCC(ret)) { if (OB_FAIL(insert_stmt->formalize_stmt(session_info_))) { LOG_WARN("pull stmt all expr relation ids failed", K(ret)); } } if (OB_SUCC(ret)) { if (OB_FAIL(resolve_multi_table_dml_info())) { LOG_WARN("resolve index dml info failed", K(ret)); } else if (OB_FAIL(resolve_duplicate_key_checker())) { LOG_WARN("resolve duplicate key checker failed", K(ret)); } } // Replace column in shadow key as conv expr // The column in the shadow key is replaced with conv expr because of each index in the multi part insert // The access_exprs_ corresponding to the sub-plan will directly depend on // the output of multi_part_insert (conv_exprs) // In order to calculate the shadow key, the value of conv_exprs can be used directly, // so it needs to be replaced here; // For replace/insert_up, access_exprs_ depends on table_columns, so there is no need to replace if (OB_SUCC(ret) && session_info_->use_static_typing_engine() && !insert_stmt->is_replace() && !insert_stmt->get_insert_up()) { CK(insert_stmt->get_all_table_columns().count() == 1); ObIArray& index_infos = insert_stmt->get_all_table_columns().at(0).index_dml_infos_; common::ObIArray& conv_columns = insert_stmt->get_column_conv_functions(); const common::ObIArray* table_columns = insert_stmt->get_table_columns(); CK(OB_NOT_NULL(table_columns)); CK(conv_columns.count() == table_columns->count()); for (int64_t i = 0; i < index_infos.count() && OB_SUCC(ret); i++) { IndexDMLInfo& index_info = index_infos.at(i); for (int64_t col_idx = 0; OB_SUCC(ret) && col_idx < index_info.column_exprs_.count(); col_idx++) { ObColumnRefRawExpr* col_expr = index_info.column_exprs_.at(col_idx); CK(OB_NOT_NULL(col_expr)); if (is_shadow_column(col_expr->get_column_id())) { ObRawExpr* spk_expr = col_expr->get_dependant_expr(); for (int64_t k = 0; OB_SUCC(ret) && k < table_columns->count(); k++) { OZ(ObRawExprUtils::replace_ref_column(spk_expr, table_columns->at(k), conv_columns.at(k))); } // for assignment end } } } } // expand returning expr with conv expr in new engine if (OB_SUCC(ret) && session_info_->use_static_typing_engine()) { common::ObIArray& conv_columns = insert_stmt->get_column_conv_functions(); const common::ObIArray* table_columns = insert_stmt->get_table_columns(); CK(NULL != table_columns); CK(conv_columns.count() == table_columns->count()); for (int64_t i = 0; OB_SUCC(ret) && i < insert_stmt->get_returning_exprs().count(); i++) { for (int64_t j = 0; OB_SUCC(ret) && j < table_columns->count(); j++) { OZ(ObRawExprUtils::replace_ref_column( insert_stmt->get_returning_exprs().at(i), table_columns->at(j), conv_columns.at(j))); } } } if (OB_SUCC(ret)) { if (OB_FAIL(view_pullup_part_exprs())) { LOG_WARN("pullup part exprs for view failed", K(ret)); } } if (OB_SUCC(ret)) { if (OB_FAIL(check_view_insertable())) { LOG_TRACE("view not insertable", K(ret)); } } if (OB_SUCC(ret) && insert_stmt->value_from_select() && session_info_->use_static_typing_engine() && !insert_stmt->get_insert_up()) { if (OB_FAIL(fill_index_dml_info_column_conv_exprs())) { LOG_WARN("fail to fill index dml info column conv exprs", K(ret)); } } if (OB_SUCC(ret)) { if (insert_stmt->is_ignore() && insert_stmt->has_global_index()) { ret = OB_NOT_SUPPORTED; LOG_USER_ERROR(OB_NOT_SUPPORTED, "ignore with global index"); } } return ret; } int ObInsertResolver::resolve_single_table_insert(const ParseNode& node) { int ret = OB_SUCCESS; // resolve insert table reference // the target table must be resolved first, // insert_stmt appoint that the first table in table_items_ is the target table const ParseNode* insert_into = NULL; const ParseNode* values_node = NULL; ObInsertStmt* insert_stmt = get_insert_stmt(); CK(OB_NOT_NULL(session_info_)); CK(OB_NOT_NULL(insert_stmt)); CK(OB_NOT_NULL(insert_into = node.children_[0])); CK(OB_NOT_NULL(values_node = node.children_[1])); CK(OB_NOT_NULL(params_.session_info_)); OZ(resolve_insert_field(*insert_into)); OZ(resolve_values(*values_node)); if (OB_SUCC(ret) && !insert_stmt->get_table_items().empty() && NULL != insert_stmt->get_table_item(0) && insert_stmt->get_table_item(0)->is_generated_table()) { OZ(add_all_column_to_updatable_view(*insert_stmt, *insert_stmt->get_table_item(0))); OZ(view_pullup_generated_column_exprs()); } OZ(add_new_column_for_oracle_temp_table(insert_stmt->get_insert_base_tid())); OZ(set_table_columns()); OZ(check_has_unique_index()); OZ(save_autoinc_params()); OZ(add_column_conv_function()); // In static engine we need to replace the dependent column of generate column with the // new insert value. e.g.: // c3 as c1 + c2 // after add_column_conv_function() the c3's new value is: column_conv(c1 + c2) // should be replaced to: column_conv(column_conv(__values.c1) + column_conv(__values.c2). // // The old engine no need to do this because it calculate generate column with the // new inserted row. OZ(replace_gen_col_dependent_col()); OZ(add_rowkey_ids(insert_stmt->get_insert_base_tid(), insert_stmt->get_primary_key_ids())); if (OB_SUCC(ret)) { if (lib::is_oracle_mode()) { // resolve returning node ParseNode* returning_node = node.children_[2]; OZ(resolve_returning(returning_node)); } else { // resolve assignments ParseNode* assign_list = node.children_[2]; if (NULL != assign_list) { insert_stmt->set_insert_up(true); OZ(resolve_insert_update_assignment(assign_list)); } } } if (OB_SUCC(ret) && lib::is_oracle_mode()) { if (0 == insert_stmt->get_table_items().count() || OB_ISNULL(insert_stmt->get_table_item(0))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("table items count is zero in insert stmt", K(ret)); } else if (OB_FAIL(resolve_check_constraints(insert_stmt->get_table_item(0)))) { LOG_WARN("resolve check constraint failed", K(ret)); } else if (session_info_->use_static_typing_engine()) { for (uint64_t i = 0; OB_SUCC(ret) && i < insert_stmt->get_check_constraint_exprs_size(); ++i) { if (OB_FAIL(replace_column_ref_for_check_constraint(insert_stmt->get_check_constraint_exprs().at(i)))) { LOG_WARN("fail to replace column ref for check constraint", K(ret)); } } } } return ret; } int ObInsertResolver::fill_index_dml_info_column_conv_exprs() { int ret = OB_SUCCESS; ObInsertStmt* insert_stmt = static_cast(get_stmt()); CK(OB_NOT_NULL(insert_stmt)); if (OB_SUCC(ret)) { ObIArray& dml_infos = insert_stmt->get_all_table_columns().at(0).index_dml_infos_; IndexDMLInfo& primary_dml_info = dml_infos.at(0); if (OB_FAIL(primary_dml_info.column_convert_exprs_.assign(insert_stmt->get_column_conv_functions()))) { LOG_WARN("fail to assign array", K(ret)); } for (int64_t i = 1; OB_SUCC(ret) && i < dml_infos.count(); ++i) { IndexDMLInfo& index_dml_info = dml_infos.at(i); if (OB_FAIL(fill_index_column_convert_exprs(session_info_->use_static_typing_engine(), primary_dml_info, index_dml_info.column_exprs_, index_dml_info.column_convert_exprs_))) { LOG_WARN("fail to fill index column convert expr", K(ret)); } } } return ret; } // Generate information related to multi table dml first for the optimizer to choose // You need to use this information when you need to generate a multi table dml-related plan // In the multi table insert scenario, you need to specify the table_offset of the inserted table in stmt int ObInsertResolver::resolve_multi_table_dml_info(uint64_t table_offset /*default 0*/) { int ret = OB_SUCCESS; ObInsertStmt* insert_stmt = get_insert_stmt(); if (OB_ISNULL(insert_stmt) || OB_ISNULL(schema_checker_) || OB_UNLIKELY(table_offset < 0 || table_offset >= insert_stmt->get_table_items().count())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("insert stmt is null", K(insert_stmt), K_(schema_checker), K(table_offset), K(insert_stmt->get_table_items().count()), K(ret)); } else { uint64_t index_tid[OB_MAX_INDEX_PER_TABLE]; int64_t index_cnt = OB_MAX_INDEX_PER_TABLE; IndexDMLInfo index_dml_info; OZ(schema_checker_->get_can_write_index_array( insert_stmt->get_insert_base_tid(table_offset), index_tid, index_cnt, true)); if (OB_SUCC(ret)) { insert_stmt->set_has_global_index(index_cnt > 0); } for (int64_t i = 0; OB_SUCC(ret) && i < index_cnt; ++i) { const ObTableSchema* index_schema = NULL; index_dml_info.reset(); if (OB_FAIL(schema_checker_->get_table_schema(index_tid[i], index_schema))) { LOG_WARN("get index table schema failed", K(ret), K(index_tid)); } else if (OB_ISNULL(index_schema)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("index schema is null", K(index_tid)); } else if (OB_FAIL(resolve_index_all_column_exprs( insert_stmt->get_insert_table_id(table_offset), *index_schema, index_dml_info.column_exprs_))) { LOG_WARN("resolve index column exprs failed", K(ret)); } else if (OB_ISNULL(insert_stmt->get_table_item(table_offset))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get table item failed", K(ret)); } else { index_dml_info.table_id_ = insert_stmt->get_insert_table_id(table_offset); index_dml_info.loc_table_id_ = (insert_stmt->get_table_items().count() > 0 && insert_stmt->get_table_items().at(table_offset) != NULL) ? insert_stmt->get_table_items().at(table_offset)->get_base_table_item().table_id_ : OB_INVALID_ID; index_dml_info.index_tid_ = index_schema->get_table_id(); index_dml_info.rowkey_cnt_ = index_schema->get_rowkey_column_num(); index_dml_info.part_cnt_ = index_schema->get_partition_cnt(); if (OB_FAIL(index_schema->get_index_name(index_dml_info.index_name_))) { LOG_WARN("get index name from index schema failed", K(ret)); } else if (OB_FAIL(insert_stmt->add_multi_table_dml_info(index_dml_info))) { LOG_WARN("add index dml info to stmt failed", K(ret), K(index_dml_info)); } } if (OB_SUCC(ret) && !with_clause_without_record_) { ObSchemaObjVersion table_version; table_version.object_id_ = index_schema->get_table_id(); table_version.object_type_ = DEPENDENCY_TABLE; table_version.version_ = index_schema->get_schema_version(); if (OB_FAIL(insert_stmt->add_global_dependency_table(table_version))) { LOG_WARN("add global dependency table failed", K(ret)); } } } } return ret; } int ObInsertResolver::find_value_desc(uint64_t column_id, ObRawExpr*& column_ref, uint64_t index /*default 0*/) { int ret = OB_SUCCESS; ObInsertStmt* insert_stmt = get_insert_stmt(); column_ref = NULL; if (OB_ISNULL(insert_stmt)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid insert stmt", K(insert_stmt)); } else if (!insert_stmt->value_from_select()) { ObIArray& value_desc = insert_stmt->get_values_desc(); ret = OB_ENTRY_NOT_EXIST; for (int64_t i = 0; i < value_desc.count() && OB_ENTRY_NOT_EXIST == ret; i++) { ObColumnRefRawExpr* expr = value_desc.at(i); if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("fail to get values expr", K(i), K(value_desc)); } else if (column_id == expr->get_column_id()) { column_ref = value_desc.at(i); ret = OB_SUCCESS; } } } else { // select item ret = OB_ENTRY_NOT_EXIST; uint64_t source_table_id = OB_INVALID_ID; if (OB_UNLIKELY(insert_stmt->get_from_item_size() != 1)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid from items", K(ret), K(insert_stmt->get_from_items())); } else { source_table_id = insert_stmt->get_from_item(0).table_id_; } for (int64_t i = 0; i < insert_stmt->get_values_desc().count() && OB_ENTRY_NOT_EXIST == ret; i++) { if (OB_ISNULL(insert_stmt->get_values_desc().at(i))) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("invalid value desc", K(i), K(insert_stmt->get_values_desc())); } else if (column_id != insert_stmt->get_values_desc().at(i)->get_column_id()) { // do nothing } else if (OB_ISNULL( column_ref = insert_stmt->get_column_expr_by_id(source_table_id, i + OB_APP_MIN_COLUMN_ID))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("column expr is not found in the generated table", K(ret)); } else { ret = OB_SUCCESS; } } } if (OB_ENTRY_NOT_EXIST == ret) { ret = OB_SUCCESS; } UNUSED(index); return ret; } int ObInsertResolver::add_column_conv_function(uint64_t index /*default 0*/) { int ret = OB_SUCCESS; ObInsertStmt* insert_stmt = get_insert_stmt(); if (OB_ISNULL(insert_stmt) || OB_ISNULL(params_.expr_factory_)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(insert_stmt), K_(params_.expr_factory)); } else { CK(OB_NOT_NULL(insert_stmt->get_table_columns(index))); uint64_t table_id = insert_stmt->get_insert_table_id(index); if (OB_FAIL(insert_stmt->get_column_conv_functions().prepare_allocate( insert_stmt->get_table_columns(index)->count()))) { LOG_WARN("failed to prepare allocate", K(ret)); } else { for (int i = 0; i < insert_stmt->get_column_conv_functions().count(); i++) { insert_stmt->get_column_conv_functions().at(i) = NULL; } } for (int64_t i = 0; OB_SUCC(ret) && i < insert_stmt->get_table_columns(index)->count(); i++) { uint64_t column_id = OB_INVALID_ID; ColumnItem* column_item = NULL; ObRawExpr* column_ref = NULL; const ObColumnRefRawExpr* tbl_col = NULL; if (OB_ISNULL(tbl_col = insert_stmt->get_table_columns(index)->at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid table column", K(ret), K(i), K(insert_stmt->get_table_columns(index))); } else if (FALSE_IT(column_id = tbl_col->get_column_id())) { // nothing to do } else if (OB_ISNULL(column_item = insert_stmt->get_column_item_by_id(table_id, column_id))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("fail to find column item", K(ret), K(column_id), K(column_item), K(*tbl_col)); } else if (OB_FAIL(find_value_desc(column_id, column_ref, index))) { LOG_WARN("fail to check column is exists", K(ret), K(column_id)); } else if (OB_ISNULL(column_ref)) { if (OB_FAIL(build_column_conv_function_with_default_expr(i, index))) { LOG_WARN("build column convert function with default expr failed", K(ret)); } } else if (OB_FAIL(build_column_conv_function_with_value_desc(i, column_ref, index))) { LOG_WARN("failed to build column conv with value desc", K(ret)); } } // end for } return ret; } int ObInsertResolver::replace_gen_col_dependent_col() { int ret = OB_SUCCESS; ObInsertStmt* insert_stmt = get_insert_stmt(); CK(NULL != insert_stmt); CK(NULL != session_info_); const auto& all_cols = *insert_stmt->get_table_columns(); auto& conv_funcs = insert_stmt->get_column_conv_functions(); for (int64_t i = 0; OB_SUCC(ret) && session_info_->use_static_typing_engine() && i < all_cols.count(); i++) { CK(NULL != all_cols.at(i)); if (OB_SUCC(ret) && all_cols.at(i)->is_generated_column()) { if (i >= conv_funcs.count() || OB_ISNULL(conv_funcs.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid null column conv function", K(ret), K(i), K(all_cols.count())); } else { OZ(replace_col_with_new_value(conv_funcs.at(i))); } } } return ret; } int ObInsertResolver::process_values_function(ObRawExpr*& expr) { int ret = OB_SUCCESS; ObInsertStmt* insert_stmt = get_insert_stmt(); if (OB_ISNULL(expr)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(expr)); } else if (OB_UNLIKELY(!expr->has_flag(IS_VALUES)) || OB_UNLIKELY(expr->get_param_count() != 1)) { LOG_WARN("invalid expr", K(expr), K(expr->get_param_count())); ret = OB_INVALID_ARGUMENT; } else if (OB_UNLIKELY(expr->get_param_expr(0)->get_expr_type() != T_REF_COLUMN)) { LOG_WARN("invalid param expr", "type", expr->get_param_expr(0)->get_expr_type()); ret = OB_INVALID_ARGUMENT; } else if (OB_ISNULL(insert_stmt)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("invalid insert stmt", K(ret), K(insert_stmt)); } else { const ObIArray* insert_columns = insert_stmt->get_table_columns(); ObColumnRefRawExpr* b_expr = static_cast(expr->get_param_expr(0)); if (OB_ISNULL(b_expr) || OB_ISNULL(insert_columns)) { LOG_WARN("invalid expr or insert_columns", K(b_expr), K(insert_columns)); ret = OB_INVALID_ARGUMENT; } else { int64_t table_id = insert_stmt->get_insert_table_id(); uint64_t column_id = b_expr->get_column_id(); ColumnItem* column_item = NULL; if (OB_ISNULL(column_item = insert_stmt->get_column_item_by_id(table_id, column_id))) { LOG_WARN("fail to get column item", K(ret), K(table_id), K(column_id)); } else { const int64_t N = insert_columns->count(); int64_t index = OB_INVALID_INDEX; ret = OB_ENTRY_NOT_EXIST; for (int64_t i = 0; i < N && OB_ENTRY_NOT_EXIST == ret; i++) { if (OB_ISNULL(insert_columns->at(i))) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("invalid insert columns", K(i), K(insert_columns->at(i))); } else if (insert_columns->at(i)->get_column_id() == column_id) { index = i; ret = OB_SUCCESS; } } if (OB_FAIL(ret)) { // do nothing } else if (OB_UNLIKELY(index == OB_INVALID_INDEX)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("fail to find column position", K(column_id)); } else { ObRawExpr* value_expr = get_insert_stmt()->get_column_conv_functions().at(index); if (OB_FAIL(add_additional_function_according_to_type(column_item, value_expr, T_INSERT_SCOPE, true))) { LOG_WARN("fail to add additional function", K(ret)); } else if (OB_FAIL(ObRawExprUtils::replace_ref_column(expr, b_expr, value_expr))) { LOG_WARN("fail to replace ref column", K(ret), K(b_expr), K(value_expr)); } else { SQL_RESV_LOG(DEBUG, "replace ref column", K(expr), K(b_expr), K(value_expr), K(column_id)); } } } } } return ret; } int ObInsertResolver::replace_column_ref_for_check_constraint(ObRawExpr*& expr) { int ret = OB_SUCCESS; ObInsertStmt* insert_stmt = get_insert_stmt(); if (OB_ISNULL(expr) || OB_ISNULL(insert_stmt) || OB_ISNULL(params_.expr_factory_)) { LOG_WARN("invalid argument", K(expr), K(insert_stmt)); ret = OB_INVALID_ARGUMENT; } else if (expr->get_param_count() > 0) { for (int i = 0; OB_SUCC(ret) && i < expr->get_param_count(); i++) { if (OB_FAIL(SMART_CALL(replace_column_ref_for_check_constraint(expr->get_param_expr(i))))) { LOG_WARN("replace column ref for check constraint", K(ret), KPC(expr->get_param_expr(i))); } } } if (OB_SUCC(ret) && expr->is_column_ref_expr()) { const ObIArray* insert_columns = insert_stmt->get_table_columns(); ObColumnRefRawExpr* b_expr = static_cast(expr); if (OB_ISNULL(b_expr) || OB_ISNULL(insert_columns)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid expr or insert_columns", K(b_expr), K(insert_columns)); } else { const int64_t N = insert_columns->count(); int64_t index = OB_INVALID_INDEX; ret = OB_ENTRY_NOT_EXIST; for (int64_t i = 0; i < N && OB_ENTRY_NOT_EXIST == ret; ++i) { if (OB_ISNULL(insert_columns->at(i))) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("invalid insert columns", K(i), K(insert_columns->at(i))); } else if (b_expr == insert_columns->at(i)) { index = i; ret = OB_SUCCESS; } } if (OB_SUCC(ret)) { if (OB_UNLIKELY(index == OB_INVALID_INDEX)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("fail to find column position", K(ret)); } else { expr = insert_stmt->get_column_conv_functions().at(index); } } } } return ret; } int ObInsertResolver::replace_column_ref(ObArray* value_row, ObRawExpr*& expr) { int ret = OB_SUCCESS; ObInsertStmt* insert_stmt = get_insert_stmt(); if (OB_ISNULL(expr) || OB_ISNULL(value_row) || OB_ISNULL(insert_stmt) || OB_ISNULL(params_.expr_factory_)) { LOG_WARN("invalid argument", K(expr), K(value_row), K(insert_stmt)); ret = OB_INVALID_ARGUMENT; } else if (OB_ISNULL(allocator_)) { ret = OB_ERR_UNEXPECTED; OB_LOG(ERROR, "fail to get allocator", K(ret), K_(allocator)); } else if (expr->get_param_count() > 0) { for (int i = 0; OB_SUCC(ret) && i < expr->get_param_count(); i++) { if (OB_FAIL(SMART_CALL(replace_column_ref(value_row, expr->get_param_expr(i))))) { LOG_WARN("fail to postorder_spread", K(ret), K(expr->get_param_expr(i))); } } } if (OB_SUCC(ret) && expr->is_column_ref_expr()) { int64_t value_index = -1; ObIArray& value_desc = insert_stmt->get_values_desc(); if (share::is_oracle_mode()) { ret = OB_NOT_SUPPORTED; LOG_WARN("column not allowed here", KPC(expr)); } else if (value_desc.count() < value_row->count()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid array size", K(value_row->count()), K(value_desc.count())); } else { ObColumnRefRawExpr* b_expr = static_cast(expr); uint64_t column_id = b_expr->get_column_id(); ret = OB_ENTRY_NOT_EXIST; for (int64_t i = 0; OB_ENTRY_NOT_EXIST == ret && i < value_row->count(); i++) { if (value_desc.at(i)->get_column_id() == column_id) { value_index = i; ret = OB_SUCCESS; } } ColumnItem* column_item = NULL; if (OB_ENTRY_NOT_EXIST == ret) { if (OB_FAIL(replace_column_to_default(expr))) { LOG_WARN("fail to replace column to default", K(ret), K(*expr)); } else { SQL_RESV_LOG(DEBUG, "replace column ref to default", K(*expr)); } } else if (OB_ISNULL(column_item = insert_stmt->get_column_item_by_id( get_insert_stmt()->get_insert_table_id(), column_id))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("fail to find column item", K(ret), K(column_id)); } else { ObRawExpr*& value_expr = value_row->at(value_index); if (OB_ISNULL(value_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("fail to get value expr", K(value_index), K(value_expr), K(value_row)); } else if (OB_FAIL(add_additional_function_according_to_type(column_item, value_expr, T_INSERT_SCOPE, true))) { LOG_WARN("fail to build column conv expr", K(ret)); } if (OB_SUCC(ret)) { expr = insert_stmt->get_values_desc().at(value_index); insert_stmt->set_is_all_const_values(false); SQL_RESV_LOG(DEBUG, "replace column ref to value", K(*expr), K(value_index)); } } } } return ret; } int ObInsertResolver::add_select_list_for_set_stmt(ObSelectStmt& select_stmt) { int ret = OB_SUCCESS; SelectItem new_select_item; ObExprResType res_type; ObSelectStmt* child_stmt = NULL; if (!select_stmt.is_set_stmt()) { // do nothing } else if (OB_ISNULL(child_stmt = select_stmt.get_set_query(0)) || OB_ISNULL(params_.expr_factory_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("null stmt", K(ret), K(child_stmt)); } else { int64_t num = child_stmt->get_select_item_size(); for (int64_t i = select_stmt.get_select_item_size(); OB_SUCC(ret) && i < num; i++) { SelectItem& select_item = child_stmt->get_select_item(i); // unused // ObString set_column_name = left_select_item.alias_name_; ObItemType set_op_type = static_cast(T_OP_SET + select_stmt.get_set_op()); res_type.reset(); new_select_item.alias_name_ = select_item.alias_name_; new_select_item.expr_name_ = select_item.expr_name_; new_select_item.default_value_ = select_item.default_value_; new_select_item.default_value_expr_ = select_item.default_value_expr_; new_select_item.is_real_alias_ = true; res_type = select_item.expr_->get_result_type(); if (OB_FAIL(ObRawExprUtils::make_set_op_expr( *params_.expr_factory_, i, set_op_type, res_type, session_info_, new_select_item.expr_))) { LOG_WARN("create set op expr failed", K(ret)); } else if (OB_FAIL(select_stmt.add_select_item(new_select_item))) { LOG_WARN("push back set select item failed", K(ret)); } else if (OB_ISNULL(new_select_item.expr_) || OB_UNLIKELY(!new_select_item.expr_->is_set_op_expr())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("expr is null or is not set op expr", "set op", PC(new_select_item.expr_)); } else { new_select_item.expr_->set_expr_level(child_stmt->get_current_level()); } } } return ret; } int ObInsertResolver::add_select_items(ObSelectStmt& select_stmt, const ObIArray& select_items) { int ret = OB_SUCCESS; if (!select_stmt.is_set_stmt()) { if (OB_ISNULL(params_.expr_factory_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null expr factory", K(ret)); } else if (OB_FAIL(ObTransformUtils::deep_copy_select_items( *params_.expr_factory_, select_items, select_stmt.get_select_items(), COPY_REF_DEFAULT))) { LOG_WARN("deep copy select items failed", K(ret)); } } else { ObIArray& child_query = select_stmt.get_set_query(); const int64_t child_num = child_query.count(); for (int64_t i = 0; OB_SUCC(ret) && i < child_num; ++i) { if (OB_ISNULL(child_query.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null stmt", K(ret)); } else if (OB_FAIL(SMART_CALL(add_select_items(*child_query.at(i), select_items)))) { LOG_WARN("failed to add select items", K(ret)); } } if (OB_SUCC(ret) && OB_FAIL(add_select_list_for_set_stmt(select_stmt))) { LOG_WARN("failed to create select list", K(ret)); } } return ret; } int ObInsertResolver::add_new_sel_item_for_oracle_temp_table(ObSelectStmt& select_stmt) { int ret = OB_SUCCESS; if (is_oracle_tmp_table_) { ObConstRawExpr* session_id_expr = NULL; ObConstRawExpr* sess_create_time_expr = NULL; ObSEArray select_items; SelectItem select_item; if (OB_FAIL(params_.expr_factory_->create_raw_expr(T_INT, session_id_expr))) { LOG_WARN("create raw expr failed", K(ret)); } else if (OB_FAIL(params_.expr_factory_->create_raw_expr(T_INT, sess_create_time_expr))) { LOG_WARN("create raw expr failed", K(ret)); } else if (OB_ISNULL(session_id_expr) || OB_ISNULL(sess_create_time_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("dummy expr is null", K(session_id_expr), K(sess_create_time_expr)); } else { ObObj val; val.set_int(session_info_->get_sessid_for_table()); session_id_expr->set_value(val); select_item.is_implicit_added_ = true; select_item.expr_ = session_id_expr; if (OB_FAIL(select_items.push_back(select_item))) { LOG_WARN("push subquery select items failed", K(ret)); } else if (session_info_->is_obproxy_mode() && 0 == session_info_->get_sess_create_time()) { ret = OB_NOT_SUPPORTED; SQL_RESV_LOG(WARN, "can't insert into oracle temporary table via obproxy, upgrade obproxy first", K(ret)); LOG_USER_ERROR(OB_NOT_SUPPORTED, "obproxy version is too old, insert into temporary table"); } else { val.set_int(session_info_->get_sess_create_time()); sess_create_time_expr->set_value(val); select_item.expr_ = sess_create_time_expr; if (OB_FAIL(select_items.push_back(select_item))) { LOG_WARN("push subquery select items failed", K(ret)); } else if (OB_FAIL(add_select_items(select_stmt, select_items))) { LOG_WARN("failed to add select items", K(ret)); } LOG_DEBUG("add __session_id & __sess_create_time to select item succeed"); } } } return ret; } int ObInsertResolver::add_new_value_for_oracle_temp_table(ObIArray& value_row) { int ret = OB_SUCCESS; if (is_oracle_tmp_table_) { ObConstRawExpr* session_id_expr = NULL; ObConstRawExpr* sess_create_time_expr = NULL; ObInsertStmt* insert_stmt = get_insert_stmt(); if (OB_ISNULL(session_info_) || OB_ISNULL(insert_stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid session_info_ or insert_stmt", K(session_info_), K(insert_stmt)); } else if (OB_FAIL(params_.expr_factory_->create_raw_expr(T_INT, session_id_expr))) { LOG_WARN("create raw expr failed", K(ret)); } else if (OB_FAIL(params_.expr_factory_->create_raw_expr(T_INT, sess_create_time_expr))) { LOG_WARN("create raw expr failed", K(ret)); } else if (OB_ISNULL(session_id_expr) || OB_ISNULL(sess_create_time_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("dummy expr is null", K(session_id_expr), K(sess_create_time_expr)); } else { ObObj val; val.set_int(session_info_->get_sessid_for_table()); session_id_expr->set_value(val); if (OB_FAIL(value_row.push_back(session_id_expr))) { LOG_WARN("push back to output expr failed", K(ret)); } else if (session_info_->is_obproxy_mode() && 0 == session_info_->get_sess_create_time()) { ret = OB_NOT_SUPPORTED; SQL_RESV_LOG(WARN, "can't insert into oracle temporary table via obproxy, upgrade obproxy first", K(ret)); LOG_USER_ERROR(OB_NOT_SUPPORTED, "obproxy version is too old, insert into temporary table"); } else { val.set_int(session_info_->get_sess_create_time()); sess_create_time_expr->set_value(val); if (OB_FAIL(value_row.push_back(sess_create_time_expr))) { LOG_WARN("push back to output expr failed", K(ret)); } LOG_DEBUG("add session id & sess create time value succeed", K(session_id_expr), K(sess_create_time_expr), K(value_row), K(lbt())); } } } return ret; } int ObInsertResolver::add_new_column_for_oracle_temp_table(uint64_t table_id) { int ret = OB_SUCCESS; if (is_oracle_tmp_table_) { const schema::ObColumnSchemaV2* column_schema = NULL; const schema::ObColumnSchemaV2* column_schema2 = NULL; const ObTableSchema* table_schema = NULL; ObColumnRefRawExpr* session_id_expr = NULL; ObColumnRefRawExpr* sess_create_time_expr = NULL; if (OB_ISNULL(session_info_) || OB_ISNULL(schema_checker_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid session_info_", K(session_info_)); } else if (OB_FAIL(schema_checker_->get_table_schema(table_id, table_schema))) { LOG_WARN("not find table schema", K(ret)); } else if (OB_ISNULL(table_schema)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("fail to get tale schema", K(ret), K(table_schema)); } else if (OB_ISNULL(column_schema = (table_schema->get_column_schema(OB_HIDDEN_SESSION_ID_COLUMN_ID)))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("failed to get column schema", K(ret)); } else if (OB_FAIL(ObRawExprUtils::build_column_expr(*params_.expr_factory_, *column_schema, session_id_expr))) { LOG_WARN("build column expr failed", K(ret)); } else if (OB_ISNULL(session_id_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("session id expr is null"); } else if (OB_FAIL(session_id_expr->formalize(session_info_))) { LOG_WARN("fail to formalize rowkey", KPC(session_id_expr), K(ret)); } else if (OB_ISNULL(column_schema2 = (table_schema->get_column_schema(OB_HIDDEN_SESS_CREATE_TIME_COLUMN_ID)))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("failed to get column schema", K(ret)); } else if (OB_FAIL( ObRawExprUtils::build_column_expr(*params_.expr_factory_, *column_schema2, sess_create_time_expr))) { LOG_WARN("build column expr failed", K(ret)); } else if (OB_ISNULL(sess_create_time_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("session create time expr is null"); } else if (OB_FAIL(sess_create_time_expr->formalize(session_info_))) { LOG_WARN("fail to formalize rowkey", KPC(sess_create_time_expr), K(ret)); } else { session_id_expr->set_ref_id(table_schema->get_table_id(), column_schema->get_column_id()); session_id_expr->set_column_attr(table_schema->get_table_name(), column_schema->get_column_name_str()); sess_create_time_expr->set_ref_id(table_schema->get_table_id(), column_schema2->get_column_id()); sess_create_time_expr->set_column_attr(table_schema->get_table_name(), column_schema2->get_column_name_str()); LOG_DEBUG( "add __session_id & __sess_create_time to target succeed", K(*session_id_expr), K(*sess_create_time_expr)); } if (OB_SUCC(ret) && OB_FAIL(mock_values_column_ref(session_id_expr))) { LOG_WARN("mock values column reference failed", K(ret)); } else if (OB_SUCC(ret) && OB_FAIL(mock_values_column_ref(sess_create_time_expr))) { LOG_WARN("mock values column reference failed", K(ret)); } } return ret; } int ObInsertResolver::resolve_insert_field(const ParseNode& insert_into) { int ret = OB_SUCCESS; ObInsertStmt* insert_stmt = get_insert_stmt(); const ParseNode* table_node = NULL; TableItem* table_item = NULL; ObSelectStmt* ref_stmt = NULL; CK(OB_NOT_NULL(insert_stmt)); CK(OB_NOT_NULL(table_node = insert_into.children_[0])); // resolve insert table // oracle mode allow to use insert subquery... => eg:insert into (select * from t1)v values(1,2,3); // When the node child is 2, it means that the above situation exists, and special treatment is required if (is_oracle_mode() && table_node->num_child_ == 2) { if (OB_FAIL(ObDMLResolver::resolve_table(*table_node, table_item))) { LOG_WARN("failed to resolve table", K(ret)); } else if (OB_ISNULL(table_item) || !table_item->is_generated_table() || OB_ISNULL(ref_stmt = table_item->ref_query_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected error", K(table_item), K(ref_stmt), K(ret)); } else if (OB_UNLIKELY(ref_stmt->get_from_items().count() != 1)) { // This is to be compatible with oracle's error reporting behavior. // When inserting data directly into the subquery, if the from item in the subquery is not 1 item, // it is illegal to report an error. // Other situations are similar to the update view judgment, and the judgment will not be repeated here ret = OB_ERR_ILLEGAL_VIEW_UPDATE; LOG_WARN("not updatable", K(ret)); } else if (OB_FAIL(set_base_table_for_view(*table_item))) { LOG_WARN("set base table for insert view failed", K(ret)); } else { /*do nothing*/ } } else { OZ(resolve_basic_table(*table_node, table_item)); } OZ(column_namespace_checker_.add_reference_table(table_item)); if (OB_SUCC(ret)) { current_scope_ = T_INSERT_SCOPE; const ObTableSchema* table_schema = NULL; if (TableItem::ALIAS_TABLE == table_item->type_) { OZ(schema_checker_->get_table_schema(table_item->get_base_table_item().ref_id_, table_schema)); } else { OZ(schema_checker_->get_table_schema(table_item->get_base_table_item().table_id_, table_schema)); } if (OB_SUCC(ret)) { if (table_schema->is_oracle_tmp_table()) { // The sessions of the oracle temporary table will not create their own private objects // and can only set the flag when the data increases session_info_->set_has_temp_table_flag(); is_oracle_tmp_table_ = true; } } } // resolve insert columns if (OB_SUCC(ret) && 2 == insert_into.num_child_) { OZ(resolve_insert_columns(insert_into.children_[1])); } OZ(remove_dup_dep_cols_for_heap_table(*insert_stmt)); return ret; } int ObInsertResolver::resolve_insert_assign(const ParseNode& assign_list) { int ret = OB_SUCCESS; // insert into t1 set c1=1, c2=1; ObTablesAssignments assigns; ObInsertStmt* insert_stmt = get_insert_stmt(); if (OB_ISNULL(insert_stmt)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("invalid insert stmt", K(ret), K(insert_stmt)); } else if (OB_FAIL(resolve_assignments(assign_list, assigns, current_scope_))) { LOG_WARN("resolve insert set assignment list failed", K(ret)); } else { ObArray value_row; int64_t table_count = assigns.count(); for (int64_t i = 0; OB_SUCC(ret) && i < table_count; i++) { ObTableAssignment& ts = assigns.at(i); int64_t assign_count = ts.assignments_.count(); for (int64_t j = 0; OB_SUCC(ret) && j < assign_count; j++) { ObAssignment& assign = ts.assignments_.at(j); // add column_item if (OB_ISNULL(assign.column_expr_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid assginment variable", K(i), K(j), K(assign)); } else if (assign.is_duplicated_) { ret = OB_ERR_FIELD_SPECIFIED_TWICE; LOG_USER_ERROR(OB_ERR_FIELD_SPECIFIED_TWICE, to_cstring(assign.column_expr_->get_column_name())); } else if (OB_FAIL(replace_column_to_default(assign.expr_))) { LOG_WARN("replace values column to default failed", K(ret)); } else if (OB_FAIL(assign.expr_->formalize(session_info_))) { LOG_WARN("formalize expr failed", K(ret)); } else if (OB_FAIL(value_row.push_back(assign.expr_))) { LOG_WARN("Can not add expr_id to ObArray", K(ret)); } } if (OB_SUCCESS == ret && OB_FAIL(add_new_value_for_oracle_temp_table(value_row))) { LOG_WARN("add cur session value failed", K(ret)); } } if (OB_SUCC(ret)) { if (OB_FAIL(add_value_row(value_row))) { LOG_WARN("Add value-row to ObInsertStmt error", K(ret)); } } } return ret; } int ObInsertResolver::resolve_values(const ParseNode& value_node) { int ret = OB_SUCCESS; ObInsertStmt* insert_stmt = get_insert_stmt(); void* select_buffer = NULL; if (OB_ISNULL(insert_stmt) || OB_ISNULL(allocator_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid stat", K(insert_stmt), K_(allocator)); } else if (T_VALUE_LIST == value_node.type_) { // value list if (OB_FAIL(resolve_insert_values(&value_node))) { LOG_WARN("resolve insert values failed", K(ret)); } } else if (T_ASSIGN_LIST == value_node.type_) { if (OB_FAIL(resolve_insert_assign(value_node))) { LOG_WARN("resolve insert assign list failed", K(ret)); } } else if (OB_ISNULL(select_buffer = allocator_->alloc(sizeof(ObSelectResolver)))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("allocate select buffer failed", K(ret), "size", sizeof(ObSelectResolver)); } else { // value from sub-query(insert into table select ..) ObSelectStmt* select_stmt = NULL; sub_select_resolver_ = new (select_buffer) ObSelectResolver(params_); // insert clause and select clause in insert into select belong to the same namespace level // so select resolver current level equal to insert resolver sub_select_resolver_->set_current_level(current_level_); // The select layer should not see the attributes of the upper insert stmt, // so the upper scope stmt should be empty sub_select_resolver_->set_parent_namespace_resolver(NULL); TableItem* sub_select_table = NULL; ObString view_name; ObSEArray column_items; if (OB_UNLIKELY(T_SELECT != value_node.type_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid value node", K(value_node.type_)); } else if (OB_FAIL(sub_select_resolver_->resolve(value_node))) { LOG_WARN("failed to resolve select stmt in INSERT stmt", K(ret)); } else if (OB_ISNULL(select_stmt = sub_select_resolver_->get_select_stmt())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid select stmt", K(select_stmt)); } else if (OB_FAIL(check_insert_select_field(*insert_stmt, *select_stmt))) { LOG_WARN("check insert select field failed", K(ret), KPC(insert_stmt), KPC(select_stmt)); } else if (OB_FAIL(add_new_sel_item_for_oracle_temp_table(*select_stmt))) { LOG_WARN("add session id value to select item failed", K(ret)); } else if (OB_FAIL(insert_stmt->generate_view_name(*allocator_, view_name))) { LOG_WARN("failed to generate view name", K(ret)); } else if (OB_FAIL(resolve_generate_table_item(select_stmt, view_name, sub_select_table))) { LOG_WARN("failed to resolve generate table item", K(ret)); } else if (OB_FAIL(resolve_all_generated_table_columns(*sub_select_table, column_items))) { LOG_WARN("failed to resolve all generated table columns", K(ret)); } else { insert_stmt->add_from_item(sub_select_table->table_id_); } } return ret; } int ObInsertResolver::check_insert_select_field(ObInsertStmt& insert_stmt, ObSelectStmt& select_stmt) { int ret = OB_SUCCESS; const ObIArray& values_desc = insert_stmt.get_values_desc(); if (values_desc.count() != select_stmt.get_select_item_size()) { ret = OB_ERR_COULUMN_VALUE_NOT_MATCH; LOG_USER_ERROR(OB_ERR_COULUMN_VALUE_NOT_MATCH, 1l); } for (int64_t i = 0; OB_SUCC(ret) && i < values_desc.count(); ++i) { const ObColumnRefRawExpr* value_desc = values_desc.at(i); if (OB_ISNULL(value_desc)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("value desc is null", K(ret)); } else if (value_desc->is_generated_column()) { ret = OB_NON_DEFAULT_VALUE_FOR_GENERATED_COLUMN; ColumnItem* orig_col_item = NULL; if (NULL != (orig_col_item = insert_stmt.get_column_item_by_id( insert_stmt.get_insert_table_id(), value_desc->get_column_id())) && orig_col_item->expr_ != NULL) { const ObString& column_name = orig_col_item->expr_->get_column_name(); const ObString& table_name = orig_col_item->expr_->get_table_name(); LOG_USER_ERROR(OB_NON_DEFAULT_VALUE_FOR_GENERATED_COLUMN, column_name.length(), column_name.ptr(), table_name.length(), table_name.ptr()); } } } return ret; } int ObInsertResolver::add_rowkey_columns_for_insert_up() { int ret = OB_SUCCESS; ObInsertStmt* insert_stmt = get_insert_stmt(); if (OB_ISNULL(insert_stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("fail to get insert stmt", K(insert_stmt)); } else if (OB_FAIL(add_rowkey_ids(insert_stmt->get_insert_base_tid(), insert_stmt->get_primary_key_ids()))) { LOG_WARN("fail to add rowkey ids", K(ret)); } return ret; } int ObInsertResolver::add_relation_columns() { int ret = OB_SUCCESS; ObInsertStmt* insert_stmt = get_insert_stmt(); if (OB_ISNULL(insert_stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("fail to get insert stmt", K(insert_stmt)); } else if (insert_stmt->get_table_assignments().count() != 1) { ret = OB_NOT_SUPPORTED; LOG_WARN("Table assignments should in insert_stmt only one table", K(ret)); } else { ObTableAssignment& table_assign = insert_stmt->get_table_assignments().at(0); if (insert_stmt->get_insert_table_id() != table_assign.table_id_) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Table assignment should be the table of insert_stmt", K(table_assign.table_id_), K(insert_stmt->get_insert_table_id()), K(ret)); } if (OB_SUCC(ret)) { // add auto_incrememnt column const ObIArray* table_columns = insert_stmt->get_table_columns(); ObIArray& auto_params = insert_stmt->get_autoinc_params(); CK(OB_NOT_NULL(table_columns)); for (int64_t i = 0; i < auto_params.count() && OB_SUCCESS == ret; i++) { if (auto_params.at(i).autoinc_col_id_ != OB_HIDDEN_PK_INCREMENT_COLUMN_ID) { bool is_exist = false; int64_t index = -1; for (int64_t j = 0; j < table_columns->count() && OB_SUCC(ret); ++j) { const ColumnItem* col_item = insert_stmt->get_column_item_by_id(table_assign.table_id_, table_columns->at(j)->get_column_id()); if (OB_ISNULL(col_item)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("column item not found", K(ret)); } else if (auto_params.at(i).autoinc_col_id_ == col_item->base_cid_) { is_exist = true; index = j; break; } } if (is_exist == false) { ret = OB_ERR_UNEXPECTED; LOG_WARN("auto increment column id not found in table columns", K(ret), K(auto_params.at(i))); } else { auto_params.at(i).autoinc_old_value_index_ = index; } } } } } return ret; } int ObInsertResolver::check_insert_column_duplicate(uint64_t column_id, bool& is_duplicate) { int ret = OB_SUCCESS; is_duplicate = false; if (OB_HIDDEN_LOGICAL_ROWID_COLUMN_ID == column_id) { // do nothing } else if (OB_HASH_EXIST == (ret = insert_column_ids_.exist_refactored(column_id))) { ret = OB_SUCCESS; is_duplicate = true; } else if (OB_HASH_NOT_EXIST != ret) { LOG_WARN("check column id whether exist failed", K(ret), K(column_id)); } else if (OB_FAIL(insert_column_ids_.set_refactored(column_id))) { LOG_WARN("set column id to insert column ids failed", K(ret), K(column_id)); } else { ret = OB_SUCCESS; } return ret; } int ObInsertResolver::resolve_insert_columns(const ParseNode* node) { int ret = OB_SUCCESS; TableItem* table_item = NULL; ObInsertStmt* insert_stmt = get_insert_stmt(); if (OB_ISNULL(insert_stmt) || OB_ISNULL(session_info_) || OB_ISNULL(schema_checker_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid insert stmt", K(insert_stmt), K_(session_info), K_(schema_checker)); } else if (OB_ISNULL(table_item = insert_stmt->get_table_item(0))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("table item is null", K(ret)); } else if (NULL != node && T_COLUMN_LIST == node->type_) { ParseNode* column_node = NULL; is_column_specify_ = true; if (OB_ISNULL(node->children_)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("invalid node children", K(node->children_)); } for (int32_t i = 0; OB_SUCC(ret) && i < node->num_child_; i++) { column_node = node->children_[i]; ObQualifiedName column_ref; ObRawExpr* ref_expr = NULL; ObColumnRefRawExpr* column_expr = NULL; ObNameCaseMode case_mode = OB_NAME_CASE_INVALID; bool is_duplicate = false; if (OB_ISNULL(column_node)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid node children", K(column_node)); } else if (OB_FAIL(session_info_->get_name_case_mode(case_mode))) { LOG_WARN("fail to get name case mode", K(ret)); } else if (OB_FAIL(ObResolverUtils::resolve_column_ref(column_node, case_mode, column_ref))) { LOG_WARN("failed to resolve column def", K(ret)); } else if (OB_FAIL(resolve_basic_column_ref(column_ref, ref_expr))) { LOG_WARN("resolve basic column reference failed", K(ret)); report_user_error_msg(ret, ref_expr, column_ref); } else if (OB_ISNULL(ref_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("column_expr is null"); } else if (!ref_expr->is_column_ref_expr()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("ref expr is invalid", K(ret), KPC(ref_expr)); } else if (FALSE_IT(column_expr = static_cast(ref_expr))) { // do nothing } else if (OB_FAIL(check_insert_column_duplicate(column_expr->get_column_id(), is_duplicate))) { LOG_WARN("check insert column duplicate failed", K(ret)); } else if (is_duplicate) { ret = OB_ERR_FIELD_SPECIFIED_TWICE; LOG_USER_ERROR(OB_ERR_FIELD_SPECIFIED_TWICE, to_cstring(column_expr->get_column_name())); } else if (OB_HIDDEN_SESSION_ID_COLUMN_ID == column_expr->get_column_id()) { ret = OB_NOT_SUPPORTED; LOG_USER_ERROR(OB_NOT_SUPPORTED, "specify __session_id value"); } else if (OB_HIDDEN_SESS_CREATE_TIME_COLUMN_ID == column_expr->get_column_id()) { ret = OB_NOT_SUPPORTED; LOG_USER_ERROR(OB_NOT_SUPPORTED, "specify __sess_create_time value"); } else if (OB_HIDDEN_LOGICAL_ROWID_COLUMN_ID == column_expr->get_column_id()) { ObString scope_name = ObString::make_string(get_scope_name(current_scope_)); ret = OB_ERR_BAD_FIELD_ERROR; LOG_USER_ERROR(OB_ERR_BAD_FIELD_ERROR, column_expr->get_column_name().length(), column_expr->get_column_name().ptr(), scope_name.length(), scope_name.ptr()); } else if (OB_FAIL(mock_values_column_ref(column_expr))) { LOG_WARN("mock values column reference failed", K(ret)); } } // end for } else { if (insert_stmt->get_table_size() != 1 && insert_stmt->get_stmt_type() != stmt::T_MERGE) { ret = OB_ERR_PARSER_SYNTAX; LOG_WARN("Insert statement only support one table", K(insert_stmt->get_stmt_type()), K(ret)); } ObArray column_items; if (OB_SUCC(ret)) { if (table_item->is_basic_table()) { if (OB_FAIL(resolve_all_basic_table_columns(*table_item, false, &column_items))) { LOG_WARN("resolve all basic table columns failed", K(ret)); } } else if (table_item->is_generated_table()) { if (OB_FAIL(resolve_all_generated_table_columns(*table_item, column_items))) { LOG_WARN("resolve all generated table columns failed", K(ret)); } } else { ret = OB_ERR_PARSER_SYNTAX; LOG_WARN("Only base table or view can be inserted", K(table_item->type_), K(ret)); } } if (OB_SUCC(ret)) { int64_t N = column_items.count(); for (int64_t i = 0; OB_SUCC(ret) && i < N; i++) { uint64_t column_id = column_items.at(i).column_id_; bool is_duplicate = false; if (OB_FAIL(check_insert_column_duplicate(column_id, is_duplicate))) { LOG_WARN("check insert column duplicate failed", K(ret)); } else if (is_duplicate) { ret = OB_ERR_FIELD_SPECIFIED_TWICE; LOG_USER_ERROR(OB_ERR_FIELD_SPECIFIED_TWICE, to_cstring(column_items.at(i).column_name_)); } else if (OB_FAIL(mock_values_column_ref(column_items.at(i).expr_))) { LOG_WARN("mock values column reference failed", K(ret)); } } } } if (OB_SUCC(ret) && table_item->is_generated_table()) { FOREACH_CNT_X(desc, insert_stmt->get_values_desc(), OB_SUCC(ret)) { const ColumnItem* column_item = insert_stmt->get_column_item_by_id(table_item->table_id_, (*desc)->get_column_id()); if (OB_ISNULL(column_item)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("column item not found", K(ret)); } else { if (NULL == table_item->view_base_item_) { if (OB_FAIL(set_base_table_for_updatable_view(*table_item, *column_item->expr_))) { LOG_WARN("find base table failed", K(ret)); } else if (OB_ISNULL(table_item->view_base_item_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("view base table is NULL", K(ret)); } } else { if (OB_FAIL(check_same_base_table(*table_item, *column_item->expr_))) { LOG_WARN("check insert columns is same base table failed", K(ret), K(*table_item), K(*column_item->expr_)); } } } } } return ret; } int ObInsertResolver::mock_values_column_ref(const ObColumnRefRawExpr* column_ref) { int ret = OB_SUCCESS; ObInsertStmt* stmt = get_insert_stmt(); ObColumnRefRawExpr* value_desc = NULL; if (OB_ISNULL(column_ref) || OB_ISNULL(stmt) || OB_ISNULL(params_.expr_factory_)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(column_ref), K(stmt), KP_(params_.expr_factory)); } else { bool found_column = false; for (int64_t i = 0; OB_SUCC(ret) && i < stmt->get_values_desc().count(); ++i) { if (OB_ISNULL(value_desc = stmt->get_values_desc().at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("value desc is null"); } else if (column_ref->get_column_id() == value_desc->get_column_id()) { found_column = true; break; } } if (found_column) { // ignore generating new column } else if (stmt->get_stmt_type() == stmt::T_MERGE) { if (OB_FAIL(stmt->get_values_desc().push_back(const_cast(column_ref)))) { LOG_WARN("failed to push back values desc", K(ret), K(*value_desc)); } } else if (OB_FAIL(params_.expr_factory_->create_raw_expr(T_REF_COLUMN, value_desc))) { LOG_WARN("create column ref raw expr failed", K(ret)); } else if (OB_ISNULL(value_desc)) { ret = OB_ERR_UNEXPECTED; LOG_WARN(("value desc is null")); } else { value_desc->set_result_type(column_ref->get_result_type()); value_desc->set_result_flag(column_ref->get_result_flag()); value_desc->set_column_flags(column_ref->get_column_flags()); value_desc->set_dependant_expr(const_cast(column_ref->get_dependant_expr())); value_desc->set_ref_id(stmt->get_insert_table_id(), column_ref->get_column_id()); value_desc->set_expr_level(current_level_); value_desc->set_column_attr(ObString::make_string(OB_VALUES), column_ref->get_column_name()); if (ob_is_enumset_tc(column_ref->get_result_type().get_type()) && OB_FAIL(value_desc->set_enum_set_values(column_ref->get_enum_set_values()))) { LOG_WARN("failed to set_enum_set_values", K(*column_ref), K(ret)); } if (OB_SUCC(ret)) { if (OB_FAIL(value_desc->add_flag(IS_COLUMN))) { LOG_WARN("failed to add flag IS_COLUMN", K(ret)); } else if (OB_FAIL(stmt->get_values_desc().push_back(value_desc))) { LOG_WARN("failed to push back values desc", K(ret), K(*value_desc)); } else { /*do nothing*/ } } } } return ret; } int ObInsertResolver::replace_column_to_default(ObRawExpr*& origin) { int ret = OB_SUCCESS; ObInsertStmt* insert_stmt = get_insert_stmt(); if (OB_ISNULL(origin)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("null pointer passed in", K(ret)); } else { if (T_REF_COLUMN == origin->get_expr_type()) { ObColumnRefRawExpr* b_expr = static_cast(origin); ColumnItem* column_item = NULL; ObDefaultValueUtils utils(insert_stmt, ¶ms_, static_cast(this)); if (OB_ISNULL(column_item = insert_stmt->get_column_item_by_id( insert_stmt->get_insert_table_id(), b_expr->get_column_id()))) { LOG_WARN("fail to get column item", K(ret)); } else if (OB_FAIL(utils.resolve_column_ref_in_insert(column_item, origin))) { LOG_WARN("fail to resolve column ref in insert", K(ret)); } } else { int64_t N = origin->get_param_count(); for (int64_t i = 0; OB_SUCC(ret) && i < N; ++i) { ObRawExpr*& cur_child = origin->get_param_expr(i); if (OB_FAIL(replace_column_to_default(cur_child))) { LOG_WARN("failed to replace child column_ref expr to default value", K(ret)); } } } } return ret; } int ObInsertResolver::check_returning_validity() { int ret = OB_SUCCESS; ObInsertStmt* insert_stmt = get_insert_stmt(); if (OB_ISNULL(insert_stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid stmt", K(ret), K(insert_stmt)); } else if (insert_stmt->value_from_select()) { ret = OB_ERR_CMD_NOT_PROPERLY_ENDED; LOG_WARN("insert into select does not have returning into clause", K(ret)); } else if (insert_stmt->get_returning_aggr_item_size() > 0) { ret = OB_ERR_GROUP_FUNC_NOT_ALLOWED; LOG_WARN("insert into returning into does not allow group function", K(ret)); } else if (OB_FAIL(ObDMLResolver::check_returning_validity())) { LOG_WARN("check returning validity failed", K(ret)); } return ret; } int ObInsertResolver::resolve_insert_values(const ParseNode* node) { int ret = OB_SUCCESS; ObInsertStmt* insert_stmt = get_insert_stmt(); ObArray value_row; uint64_t value_count = OB_INVALID_ID; if (OB_ISNULL(insert_stmt) || OB_ISNULL(node) || T_VALUE_LIST != node->type_ || OB_ISNULL(node->children_)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid arguemnt", K(insert_stmt), K(node)); } if (OB_ISNULL(session_info_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("session is null", K(ret)); } else if (is_oracle_mode() && 1 < node->num_child_) { // values only hold one row in oracle mode // ret = OB_ERR_CMD_NOT_PROPERLY_ENDED; // LOG_DEBUG("not supported in oracle mode", K(ret)); /* * If the VALUES clause of an INSERT statement contains a record variable, no other * variable or value is allowed in the clause. */ } for (int64_t i = 0; OB_SUCC(ret) && i < node->num_child_; i++) { ParseNode* vector_node = node->children_[i]; if (OB_ISNULL(vector_node) || OB_ISNULL(vector_node->children_)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("invalid node children", K(i), K(node)); } else if (vector_node->num_child_ != insert_stmt->get_values_desc().count() && !(1 == vector_node->num_child_ && T_EMPTY == vector_node->children_[0]->type_)) { ret = OB_ERR_COULUMN_VALUE_NOT_MATCH; LOG_USER_ERROR(OB_ERR_COULUMN_VALUE_NOT_MATCH, i + 1); LOG_WARN("Column count doesn't match value count", "num_child", vector_node->num_child_, "vector_count", insert_stmt->get_values_desc().count()); } if (OB_SUCC(ret)) { for (int32_t j = 0; OB_SUCC(ret) && j < vector_node->num_child_; j++) { ObRawExpr* expr = NULL; ObRawExpr* tmp_expr = NULL; const ObColumnRefRawExpr* column_expr = NULL; if (OB_ISNULL(vector_node->children_[j]) || OB_ISNULL(column_expr = insert_stmt->get_values_desc().at(j))) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("inalid children node", K(j), K(vector_node)); } else if (T_EMPTY == vector_node->children_[j]->type_) { // nothing todo } else { uint64_t column_id = column_expr->get_column_id(); ObDefaultValueUtils utils(insert_stmt, ¶ms_, this); bool is_generated_column = false; if (OB_FAIL(resolve_sql_expr(*(vector_node->children_[j]), expr))) { LOG_WARN("resolve sql expr failed", K(ret)); } else if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("fail to resolve sql expr", K(ret), K(expr)); } else if (T_DEFAULT == expr->get_expr_type()) { ColumnItem* column_item = NULL; if (column_expr->is_generated_column()) { if (OB_FAIL(ObRawExprUtils::copy_expr( *params_.expr_factory_, column_expr->get_dependant_expr(), expr, COPY_REF_DEFAULT))) { LOG_WARN("copy expr failed", K(ret)); } } else if (OB_ISNULL(column_item = insert_stmt->get_column_item_by_id( insert_stmt->get_insert_table_id(), column_id))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get column item by id failed", K(insert_stmt->get_insert_table_id()), K(column_id)); } else if (OB_FAIL(utils.resolve_default_expr(*column_item, expr, T_INSERT_SCOPE))) { LOG_WARN("fail to resolve default value", "table_id", insert_stmt->get_insert_table_id(), K(column_id), K(ret)); } } else if (OB_FAIL(check_basic_column_generated(column_expr, insert_stmt, is_generated_column))) { LOG_WARN("check column generated failed", K(ret)); } else if (is_generated_column) { ret = OB_NON_DEFAULT_VALUE_FOR_GENERATED_COLUMN; ColumnItem* orig_col_item = NULL; if (NULL != (orig_col_item = insert_stmt->get_column_item_by_id(insert_stmt->get_insert_table_id(), column_id)) && orig_col_item->expr_ != NULL) { const ObString& column_name = orig_col_item->expr_->get_column_name(); const ObString& table_name = orig_col_item->expr_->get_table_name(); LOG_USER_ERROR(OB_NON_DEFAULT_VALUE_FOR_GENERATED_COLUMN, column_name.length(), column_name.ptr(), table_name.length(), table_name.ptr()); } } else if (column_expr->is_table_part_key_column() && expr->has_flag(CNT_SEQ_EXPR)) { insert_stmt->set_has_part_key_sequence(true); } const ObIArray& dep_cols = insert_stmt->get_part_generated_col_dep_cols(); if (OB_SUCC(ret) && 0 != dep_cols.count()) { ColumnItem* col_item = NULL; for (int64_t i = 0; OB_SUCC(ret) && i < dep_cols.count(); ++i) { const ObColumnRefRawExpr* col_ref = dep_cols.at(i); CK(OB_NOT_NULL(col_ref)); CK(OB_NOT_NULL( col_item = insert_stmt->get_column_item_by_id(col_ref->get_table_id(), col_ref->get_column_id()))); if (OB_SUCC(ret)) { if (NULL == col_item->default_value_expr_) { OZ(utils.resolve_default_expr(*col_item, col_item->default_value_expr_, T_INSERT_SCOPE)); } } } } tmp_expr = expr; // mysql support insert into xx values(expr, ...), expr contains column_ref // which has default values in column schema, replace column ref to const value here // eg: CREATE TABLE t1(f1 VARCHAR(100) DEFAULT 'test',id int primary key); // INSERT INTO t1 VALUES(SUBSTR(f1, 1, 3),1); // select * from t1; // f1 id // tes 1 if (OB_SUCC(ret)) { if (tmp_expr->has_flag(CNT_COLUMN)) { if (OB_FAIL(replace_column_ref(&value_row, tmp_expr))) { LOG_WARN("fail to replace column ref", K(ret)); } else { SQL_RESV_LOG(DEBUG, "replace column to default", K(ret), K(*tmp_expr)); } } } if (OB_SUCC(ret)) { if (OB_FAIL(tmp_expr->formalize(session_info_))) { LOG_WARN("formalize value expr failed", K(ret)); } else if (OB_FAIL(value_row.push_back(tmp_expr))) { LOG_WARN("Can not add expr_id to ObArray", K(ret)); } } } // end else } // end for } if (OB_SUCC(ret)) { if (OB_INVALID_ID == value_count) { value_count = value_row.count(); } if (OB_FAIL(check_column_value_pair(&value_row, i + 1, value_count))) { LOG_WARN("fail to check column value count", K(ret)); } else if (is_all_default_) { // Handle the situation of insert into test values(),() if (OB_FAIL(build_row_for_empty_brackets(value_row))) { LOG_WARN("fail to build row for empty brackets", K(ret)); } } else { } if (OB_SUCC(ret)) { if (OB_FAIL(add_new_value_for_oracle_temp_table(value_row))) { LOG_WARN("failed to add __session_id value"); } else if (OB_FAIL(add_value_row(value_row))) { LOG_WARN("Add value-row to ObInsertStmt error", K(ret)); } } } value_row.reset(); } return ret; } int ObInsertResolver::check_column_value_pair( ObArray* value_row, const int64_t row_index, const uint64_t value_count) { int ret = OB_SUCCESS; // If the column is actually specified, then values() is not allowed to be empty ObInsertStmt* insert_stmt = get_insert_stmt(); if (OB_ISNULL(value_row)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(value_row)); } else if (value_row->count() == 0) { is_all_default_ = true; if (is_column_specify_) { ret = OB_ERR_COULUMN_VALUE_NOT_MATCH; LOG_USER_ERROR(OB_ERR_COULUMN_VALUE_NOT_MATCH, row_index); } else { } } else { } if (OB_SUCC(ret)) { uint64_t row_value_count = value_row->count(); if (value_count != row_value_count) { ret = OB_ERR_COULUMN_VALUE_NOT_MATCH; LOG_USER_ERROR(OB_ERR_COULUMN_VALUE_NOT_MATCH, row_index); } else { } } if (OB_SUCC(ret)) { if (OB_ISNULL(insert_stmt)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("invalid insert stmt", K(insert_stmt)); } else if (value_row->count() != 0 && insert_stmt->get_values_desc().count() != value_row->count()) { ret = OB_ERR_COULUMN_VALUE_NOT_MATCH; LOG_USER_ERROR(OB_ERR_COULUMN_VALUE_NOT_MATCH, row_index); } else { } } return ret; } int ObInsertResolver::get_value_row_size(uint64_t& value_row_size) const { int ret = OB_SUCCESS; value_row_size = 0; ObInsertStmt* insert_stmt = const_cast(this)->get_insert_stmt(); if (OB_ISNULL(insert_stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("fail to get insert stmt", K(insert_stmt)); } else { if (insert_stmt->value_from_select()) { value_row_size = 1; } else { value_row_size = insert_stmt->get_row_count(); } } return ret; } int ObInsertResolver::resolve_column_ref_expr(const ObQualifiedName& q_name, ObRawExpr*& real_ref_expr) { int ret = OB_SUCCESS; if (OB_FAIL(resolve_basic_column_ref(q_name, real_ref_expr))) { if ((OB_ERR_BAD_FIELD_ERROR == ret || OB_ERR_COLUMN_NOT_FOUND == ret) && sub_select_resolver_ != NULL) { // In insert into select stmt, insert clause and select clause belong to the same namespace // the on duplicate key update clause will see the column in select clause, // so need to add table reference to insert resolve column namespace checker int64_t idx = -1; ObString dummy_name; TableItem* view = NULL; ColumnItem* col_item = NULL; ObSelectStmt* sel_stmt = sub_select_resolver_->get_select_stmt(); ObInsertStmt* insert_stmt = get_insert_stmt(); if (OB_ISNULL(sel_stmt) || OB_ISNULL(insert_stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("stmt is null", K(ret), K(sel_stmt), K(insert_stmt)); } else if (OB_UNLIKELY(insert_stmt->get_from_item_size() != 1) || OB_ISNULL(view = insert_stmt->get_table_item_by_id(insert_stmt->get_from_item(0).table_id_))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("does not find generated table item", K(ret), K(insert_stmt->get_from_items())); } else if (OB_FAIL(sub_select_resolver_->resolve_column_ref_expr(q_name, real_ref_expr))) { LOG_WARN("resolve column ref expr in sub select resolver failed", K(ret), K(q_name)); } else if (!real_ref_expr->is_column_ref_expr()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("expr is expected to be column", K(ret)); } else { for (idx = 0; OB_SUCC(ret) && idx < sel_stmt->get_select_item_size(); ++idx) { if (OB_ISNULL(sel_stmt->get_select_item(idx).expr_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("select expr is null", K(ret)); } else if (sel_stmt->get_select_item(idx).expr_ == real_ref_expr) { break; } } if (idx == sel_stmt->get_select_item_size()) { SelectItem sel_item; sel_item.expr_ = real_ref_expr; sel_item.expr_name_ = static_cast(real_ref_expr)->get_column_name(); sel_item.alias_name_ = sel_item.expr_name_; if (OB_FAIL(sel_stmt->add_select_item(sel_item))) { LOG_WARN("failed to add select item", K(ret)); } } if (OB_SUCC(ret)) { if (OB_FAIL(resolve_generated_table_column_item( *view, dummy_name, col_item, insert_stmt, idx + OB_APP_MIN_COLUMN_ID))) { LOG_WARN("failed to resolve generated table column item", K(ret)); } else if (OB_ISNULL(col_item)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("column item is null", K(ret), K(col_item)); } else { real_ref_expr = col_item->expr_; } } } } else { LOG_WARN("resolve basic column ref failed", K(ret), K(q_name)); } } return ret; } int ObInsertResolver::resolve_order_item(const ParseNode& sort_node, OrderItem& order_item) { UNUSED(sort_node); UNUSED(order_item); return OB_NOT_SUPPORTED; } int ObInsertResolver::build_row_for_empty_brackets(ObArray& value_row) { int ret = OB_SUCCESS; ObInsertStmt* insert_stmt = get_insert_stmt(); if (!is_all_default_) { // nothing to do } else if (OB_ISNULL(insert_stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("error unexpected", K(insert_stmt)); } else { ColumnItem* item = NULL; ObDefaultValueUtils utils(insert_stmt, ¶ms_, static_cast(this)); for (int64_t i = 0; i < insert_stmt->get_values_desc().count() && OB_SUCCESS == ret; ++i) { ObRawExpr* expr = NULL; int64_t column_id = insert_stmt->get_values_desc().at(i)->get_column_id(); if (OB_ISNULL(item = insert_stmt->get_column_item_by_id(insert_stmt->get_insert_table_id(), column_id))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("fail to get column item", K(column_id)); } else if (OB_UNLIKELY(item->expr_->is_generated_column())) { if (OB_FAIL(ObRawExprUtils::copy_expr( *params_.expr_factory_, item->expr_->get_dependant_expr(), expr, COPY_REF_DEFAULT))) { LOG_WARN("copy generated column dependant expr failed", K(ret)); } else if (expr->has_flag(CNT_COLUMN)) { if (OB_FAIL(replace_column_ref(&value_row, expr))) { LOG_WARN("replace column reference failed", K(ret)); } } if (OB_SUCC(ret) && OB_FAIL(value_row.push_back(expr))) { LOG_WARN("fail to push back value expr", K(ret)); } } else if (item->is_auto_increment()) { // insert into t (..) values (); the nextval expression cannot be automatically generated, // but null should be generated if (OB_FAIL(ObRawExprUtils::build_null_expr(*params_.expr_factory_, expr))) { LOG_WARN("failed to build next_val expr as null", K(ret)); } else if (OB_FAIL(value_row.push_back(expr))) { LOG_WARN("fail to push back value expr", K(ret)); } } else { if (OB_FAIL(utils.generate_insert_value(item, expr))) { LOG_WARN("fail to generate insert values", K(ret), K(column_id)); } else if (OB_FAIL(value_row.push_back(expr))) { LOG_WARN("fail to push back value expr", K(ret)); } } } } return ret; } int ObInsertResolver::check_has_unique_index() { int ret = OB_SUCCESS; const ObTableSchema* index_schema[common::OB_MAX_INDEX_PER_TABLE]; ObInsertStmt* insert_stmt = get_insert_stmt(); const ObTableSchema* table_schema = NULL; int64_t unique_index_cnt = 0; if (OB_ISNULL(insert_stmt)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("invalid insert stmt", K(insert_stmt)); } else if (OB_FAIL(schema_checker_->get_table_schema(insert_stmt->get_insert_base_tid(), table_schema))) { LOG_WARN("not find table schema", K(ret)); } else if (OB_ISNULL(table_schema)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("fail to get tale schema", K(ret), K(table_schema)); } else { ObSEArray simple_index_infos; if (!table_schema->is_no_pk_table()) { ++unique_index_cnt; } if (OB_FAIL(table_schema->get_simple_index_infos_without_delay_deleted_tid(simple_index_infos))) { LOG_WARN("get simple_index_infos without delay_deleted_tid failed", K(ret)); } else if (simple_index_infos.count() > 0) { for (int64_t i = 0; OB_SUCC(ret) && i < simple_index_infos.count(); i++) { if (OB_FAIL(schema_checker_->get_table_schema(simple_index_infos.at(i).table_id_, index_schema[i]))) { LOG_WARN("fail to get table schema", K(ret), "table_id", simple_index_infos.at(i).table_id_); } else if (OB_ISNULL(index_schema[i])) { ret = OB_ERR_UNEXPECTED; LOG_WARN("fail to get table schema", K(ret), K(index_schema[i])); } else if (index_schema[i]->is_unique_index() && !index_schema[i]->is_final_invalid_index()) { ++unique_index_cnt; } } // end for } else { } } if (OB_SUCC(ret)) { insert_stmt->set_only_one_unique_key(1 == unique_index_cnt); } return ret; } // Specify the order of input // In the multi table insert scenario, you need to specify the table_offset of the inserted table in stmt int ObInsertResolver::set_table_columns(uint64_t table_offset /*default 0*/) { int ret = OB_SUCCESS; ObInsertStmt* insert_stmt = get_insert_stmt(); const ObTableSchema* table_schema = NULL; ObArray column_items; TableItem* table_item = NULL; IndexDMLInfo* primary_dml_info = NULL; CK(OB_NOT_NULL(insert_stmt)); CK(insert_stmt->get_table_items().count() >= 1); CK(OB_NOT_NULL(schema_checker_)); if (OB_SUCC(ret)) { table_item = insert_stmt->get_table_item(table_offset); CK(OB_NOT_NULL(table_item)); OZ(schema_checker_->get_table_schema(table_item->get_base_table_item().ref_id_, table_schema), KPC(table_item)); } if (OB_SUCC(ret)) { primary_dml_info = insert_stmt->get_or_add_table_columns(table_item->table_id_); if (OB_ISNULL(primary_dml_info)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("get or add table columns failed", K(ret)); } else { primary_dml_info->table_id_ = table_item->table_id_; primary_dml_info->loc_table_id_ = table_item->get_base_table_item().table_id_; primary_dml_info->index_tid_ = table_item->get_base_table_item().ref_id_; primary_dml_info->rowkey_cnt_ = table_schema->get_rowkey_column_num(); primary_dml_info->part_cnt_ = table_schema->get_partition_cnt(); primary_dml_info->index_name_ = table_schema->get_table_name_str(); } // first add rowkey columns OZ(add_all_rowkey_columns_to_stmt(*table_item, primary_dml_info->column_exprs_), KPC(table_item)); // second add other table columns OZ(add_all_columns_to_stmt(*table_item, primary_dml_info->column_exprs_), KPC(table_item)); } return ret; } int ObInsertResolver::add_value_row(ObIArray& value_row) { int ret = OB_SUCCESS; int64_t i = 0; ObInsertStmt* insert_stmt = get_insert_stmt(); if (OB_ISNULL(insert_stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid insert stmt", K(insert_stmt)); } for (; OB_SUCC(ret) && i < value_row.count(); ++i) { if (OB_FAIL(insert_stmt->get_value_vectors().push_back(value_row.at(i)))) { LOG_WARN("push back expr failed", K(ret)); } } return ret; } // In the multi table insert scenario, you need to specify the table_offset of the inserted table in stmt int ObInsertResolver::save_autoinc_params(uint64_t table_offset /*default 0*/) { int ret = OB_SUCCESS; ObInsertStmt* insert_stmt = get_insert_stmt(); const ObTableSchema* table_schema = NULL; if (OB_ISNULL(insert_stmt) || OB_ISNULL(params_.session_info_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid insert stmt", K(insert_stmt), K(params_.session_info_)); } else if (OB_FAIL(schema_checker_->get_table_schema(insert_stmt->get_insert_base_tid(table_offset), table_schema))) { LOG_WARN("fail to get table schema", K(ret), "table_id", insert_stmt->get_insert_base_tid(table_offset)); } else if (OB_ISNULL(table_schema)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("fail to get table schema", K(ret), K(table_schema)); } else { for (ObTableSchema::const_column_iterator iter = table_schema->column_begin(); OB_SUCCESS == ret && iter != table_schema->column_end(); ++iter) { ObColumnSchemaV2* column_schema = *iter; if (OB_ISNULL(column_schema)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("invalid column schema", K(column_schema)); } else { uint64_t column_id = column_schema->get_column_id(); if (column_schema->is_autoincrement()) { insert_stmt->set_affected_last_insert_id(true); AutoincParam param; param.tenant_id_ = params_.session_info_->get_effective_tenant_id(); param.autoinc_table_id_ = insert_stmt->get_insert_base_tid(table_offset); param.autoinc_first_part_num_ = table_schema->get_first_part_num(); param.autoinc_table_part_num_ = table_schema->get_all_part_num(); param.autoinc_col_id_ = column_id; param.part_level_ = table_schema->get_part_level(); ObObjType column_type = table_schema->get_column_schema(column_id)->get_data_type(); param.autoinc_col_type_ = column_type; param.autoinc_desired_count_ = 0; // hidden pk auto-increment variables' default value is 1 // auto-increment variables for other columns are set in ob_sql.cpp // because physical plan may come from plan cache; it need be reset every time if (OB_HIDDEN_PK_INCREMENT_COLUMN_ID == column_id) { param.autoinc_increment_ = 1; param.autoinc_offset_ = 1; } uint64_t tid = insert_stmt->get_insert_table_id(table_offset); const ObIArray* table_columns = NULL; // get auto-increment column index in insert columns if (OB_ISNULL(table_columns = insert_stmt->get_table_columns(table_offset))) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("fail to get table schema", K(ret), K(table_columns)); } else { for (int64_t i = 0; OB_SUCC(ret) && i < table_columns->count() && OB_SUCC(ret); ++i) { const ColumnItem* col_item = insert_stmt->get_column_item_by_id(tid, table_columns->at(i)->get_column_id()); if (OB_ISNULL(col_item)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("column item not found", KK(ret)); } else if (column_id == col_item->base_cid_) { param.autoinc_col_index_ = i; break; } } if (OB_FAIL(get_value_row_size(param.total_value_count_))) { LOG_WARN("fail to get value row size", K(ret)); } else if (OB_FAIL(insert_stmt->get_autoinc_params().push_back(param))) { LOG_WARN("failed to push autoinc_param", K(param), K(ret)); } } } } } // end for } LOG_DEBUG("generate autoinc_params", "autoin_params", insert_stmt->get_autoinc_params()); return ret; } int ObInsertResolver::resolve_insert_update_assignment(const ParseNode* node) { int ret = OB_SUCCESS; ObInsertStmt* insert_stmt = get_insert_stmt(); if (OB_ISNULL(insert_stmt) || OB_ISNULL(node) || T_ASSIGN_LIST != node->type_) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(insert_stmt), K(node)); } if (OB_SUCC(ret)) { if (insert_stmt->is_replace()) { ret = OB_NOT_SUPPORTED; LOG_WARN("REPLACE statement does not support ON DUPLICATE KEY UPDATE clause"); } else if (OB_FAIL(add_rowkey_columns_for_insert_up())) { LOG_WARN("Add needed columns error", K(ret)); } else if (OB_FAIL(resolve_assignments(*node, insert_stmt->get_table_assignments(), T_UPDATE_SCOPE))) { LOG_WARN("resolve assignment error", K(ret)); } else if (OB_FAIL(resolve_additional_assignments(insert_stmt->get_table_assignments(), T_INSERT_SCOPE))) { LOG_WARN("resolve additional assignment error", K(ret)); } else if (insert_stmt->get_table_assignments().count() != 1) { ret = OB_NOT_SUPPORTED; LOG_WARN("Table assignments in insert_stmt should only one table", K(ret)); } else if (OB_FAIL(add_relation_columns())) { LOG_WARN("Add needed columns error", K(ret)); } } return ret; } // In the multi table insert scenario, you need to specify the table_offset of the inserted table in stmt int ObInsertResolver::resolve_duplicate_key_checker(uint64_t table_offset /*default 0*/) { int ret = OB_SUCCESS; ObInsertStmt* insert_stmt = get_insert_stmt(); if (OB_ISNULL(insert_stmt)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("insert stmt is null"); } else { uint64_t table_id = insert_stmt->get_insert_base_tid(table_offset); const ObTableSchema* tbl_schema = NULL; const ObTableSchema* index_schema = NULL; ObSEArray simple_index_infos; bool has_global_unique_index = false; ObUniqueConstraintInfo constraint_info; ObUniqueConstraintCheckStmt& constraint_check_stmt = insert_stmt->get_constraint_check_stmt(); // Duplicate check information of the main table OZ(schema_checker_->get_table_schema(table_id, tbl_schema), table_id); CK(OB_NOT_NULL(tbl_schema)); OZ(resolve_dupkey_scan_info(*tbl_schema, false, constraint_check_stmt.table_scan_info_, table_offset)); OZ(resolve_unique_index_constraint_info(*tbl_schema, constraint_info, table_offset)); OZ(constraint_check_stmt.constraint_infos_.push_back(constraint_info)); OZ(tbl_schema->get_simple_index_infos_without_delay_deleted_tid(simple_index_infos), table_id); for (int64_t i = 0; OB_SUCC(ret) && i < simple_index_infos.count(); ++i) { constraint_info.reset(); ObDupKeyScanInfo dupkey_scan_info; OZ(schema_checker_->get_table_schema(simple_index_infos.at(i).table_id_, index_schema), simple_index_infos.at(i).table_id_); if (OB_FAIL(ret)) { } else if (OB_ISNULL(index_schema)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("fail to get index schema", K(ret), K(simple_index_infos.at(i).table_id_)); } else if (!index_schema->is_final_invalid_index() && index_schema->is_unique_index()) { OZ(resolve_unique_index_constraint_info(*index_schema, constraint_info, table_offset)); OZ(constraint_check_stmt.constraint_infos_.push_back(constraint_info)); if (OB_SUCC(ret) && index_schema->is_global_index_table()) { // resolve duplicate checker info of global unique index has_global_unique_index = true; OZ(resolve_dupkey_scan_info(*index_schema, false, dupkey_scan_info, table_offset)); OZ(constraint_check_stmt.gui_scan_infos_.push_back(dupkey_scan_info)); } } } if (OB_SUCC(ret) && has_global_unique_index) { // build global unique index lookup operation OZ(resolve_dupkey_scan_info(*tbl_schema, true, constraint_check_stmt.gui_lookup_info_, table_offset)); } } return ret; } // In the multi table insert scenario, you need to specify the table_offset of the inserted table in stmt int ObInsertResolver::resolve_unique_index_constraint_info( const ObTableSchema& index_schema, ObUniqueConstraintInfo& constraint_info, uint64_t table_offset /*default 0*/) { int ret = OB_SUCCESS; const ObInsertStmt* insert_stmt = get_insert_stmt(); CK(OB_NOT_NULL(insert_stmt)); if (OB_SUCC(ret)) { constraint_info.table_id_ = insert_stmt->get_insert_table_id(table_offset); constraint_info.index_tid_ = index_schema.get_table_id(); if (!index_schema.is_index_table()) { constraint_info.constraint_name_ = "PRIMARY"; } else { OZ(index_schema.get_index_name(constraint_info.constraint_name_)); } } /* * create table t1(pk int, a int, b int, primary key (a), unique key uk_a_b (a, b)) partition by hash(a) partitions 3; * OceanBase(root@oceanbase)>explain replace into t1 values(80, 81, 82), (100, 101,102)\G; * *************************** 1. row *************************** * Query Plan: ============================================ * |ID|OPERATOR |NAME|EST. ROWS|COST| * -------------------------------------------- * |0 |MULTI TABLE REPLACE| |2 |1 | * |1 | EXPRESSION | |2 |1 | * ============================================ * * Outputs & filters: * ------------------------------------- * 0 - output([column_conv(INT,PS:(11,0),NOT NULL,__values.a)], [column_conv(INT,PS:(11,0),NULL,__values.pk)], * [column_conv(INT,PS:(11,0),NULL,__values.b)]), filter(nil), columns([{t1: ({t1: (t1.a, t1.pk, t1.b)}, {uk_a_b: * (t1.a, t1.b, uk_a_b.shadow_pk_0)})}]), partitions(p0, p2) 1 - output([__values.pk], [__values.a], [__values.b]), * filter(nil) values({80, 81, 82}, {100, 101, 102}) * * For the above plan, a, b, shadow_pk_0 will be used as constraint_columns expr, * The column dependent on shadow_pk_0 will be replaced with the expression of column_conv(..., __values.*), * And constraint_columns is used for duplicate_checker, in order to achieve more clarity, all duplicate_checker * The expression calculation involved in the final depends on the table column value, * so the shadow_pk_0 used for duplicate_checker depends on * column does not want to be replaced with column_conv(..., __value.*) expression, * so when parsing index_rowkey_exprs here, * Will not use the shadow_pk_0 in the previously generated index_column_exprs, * but regenerate a shadow_pk_0 expression, * The expression ultimately depends on the table column value; * */ OZ(resolve_index_rowkey_exprs( constraint_info.table_id_, index_schema, constraint_info.constraint_columns_, false /*use_shared_spk*/)); return ret; } // In the multi table insert scenario, you need to specify the table_offset of the inserted table in stmt int ObInsertResolver::resolve_dupkey_scan_info(const ObTableSchema& index_schema, bool is_gui_lookup, ObDupKeyScanInfo& dupkey_scan_info, uint64_t table_offset /*default 0*/) { int ret = OB_SUCCESS; ObInsertStmt* insert_stmt = get_insert_stmt(); const ObIArray* table_columns = NULL; int64_t primary_rowkey_cnt = 0; if (OB_ISNULL(insert_stmt)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("insert stmt is null", K(insert_stmt)); } else { dupkey_scan_info.table_id_ = insert_stmt->get_insert_table_id(table_offset); dupkey_scan_info.loc_table_id_ = (insert_stmt->get_table_items().count() > 0 && insert_stmt->get_table_items().at(table_offset) != NULL) ? insert_stmt->get_table_items().at(table_offset)->get_base_table_item().table_id_ : OB_INVALID_ID; dupkey_scan_info.index_tid_ = index_schema.get_table_id(); dupkey_scan_info.only_data_table_ = is_gui_lookup; ObSEArray index_rowkey_exprs; if (!insert_stmt->is_multi_insert_stmt()) { primary_rowkey_cnt = insert_stmt->get_primary_key_ids().count(); } else { primary_rowkey_cnt = insert_stmt->get_multi_insert_primary_key_ids().at(table_offset).count(); } if (OB_ISNULL(table_columns = insert_stmt->get_table_columns(table_offset))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(table_columns), K(table_offset)); } else if (OB_FAIL(resolve_index_rowkey_exprs( insert_stmt->get_insert_table_id(table_offset), index_schema, index_rowkey_exprs))) { LOG_WARN("resolve index rowkey exprs failed", K(ret), KPC(insert_stmt), K(index_schema)); } else if (index_schema.is_global_index_table()) { // For global unique index, // conflict_exprs is index rowkey exprs // output_exprs is data table rowkey exprs // access_exprs is index rowkey_exprs+data_table rowke exprs // First construct conflict_exprs if (OB_FAIL(dupkey_scan_info.conflict_exprs_.assign(index_rowkey_exprs))) { LOG_WARN("assign dupkey scan info access exprs failed", K(ret), K(index_rowkey_exprs)); } // Reconstruct access_exprs if (OB_SUCC(ret)) { if (OB_FAIL(dupkey_scan_info.access_exprs_.assign(dupkey_scan_info.conflict_exprs_))) { LOG_WARN("construct access exprs failed", K(ret), K(dupkey_scan_info.conflict_exprs_)); } } for (int64_t i = 0; OB_SUCC(ret) && i < primary_rowkey_cnt; ++i) { if (OB_FAIL(add_var_to_array_no_dup(dupkey_scan_info.access_exprs_, table_columns->at(i)))) { LOG_WARN("add var to array no duplicate key failed", K(ret), K(dupkey_scan_info)); } } // Spell output_exprs again for (int64_t i = 0; OB_SUCC(ret) && i < primary_rowkey_cnt; ++i) { if (OB_FAIL(dupkey_scan_info.output_exprs_.push_back(table_columns->at(i)))) { LOG_WARN("store table columns to dupkey scan output exprs failed", K(ret), K(table_columns)); } } } else { // For primary index and local unique index, // conflict_exprs is data table rowkey exprs + other local unique index column // output_exprs is data table rowkey exprs + other data table column exprs // For gui look up, conflict_exprs is data table rowkey exprs // output exprs is data table rowkey exprs + other data table column exprs // access exprs is data table rowkey exprs + other data table column exprs // First construct output exprs if (OB_FAIL(append(dupkey_scan_info.output_exprs_, *table_columns))) { LOG_WARN("append table columns to output exprs failed", K(table_columns)); } else if (OB_FAIL(dupkey_scan_info.access_exprs_.assign(*table_columns))) { LOG_WARN("construct access exprs failed", K(ret), K(table_columns)); } int64_t conflict_expr_cnt = is_gui_lookup ? primary_rowkey_cnt : table_columns->count(); for (int64_t i = 0; OB_SUCC(ret) && i < conflict_expr_cnt; ++i) { if (OB_FAIL(dupkey_scan_info.conflict_exprs_.push_back(table_columns->at(i)))) { LOG_WARN("store table column to dupkey scan access exprs failed", K(ret), K(table_columns)); } } } } if (OB_SUCC(ret)) { if (!index_schema.is_index_table()) { dupkey_scan_info.table_name_ = index_schema.get_table_name_str(); } else if (OB_FAIL(index_schema.get_index_name(dupkey_scan_info.table_name_))) { LOG_WARN("get index name from index schema failed", K(ret), K(index_schema)); } LOG_DEBUG("resolve duplicate key checker info", K(ret), K(is_gui_lookup), K(dupkey_scan_info)); } return ret; } int ObInsertResolver::check_view_insertable() { int ret = OB_SUCCESS; TableItem* table = NULL; ObInsertStmt* stmt = NULL; if (OB_ISNULL(stmt = get_insert_stmt()) || stmt->get_table_items().empty() || OB_ISNULL(table = stmt->get_table_item(0))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("stmt is NULL or table item is NULL", K(ret)); } // uv_check_basic already checked if (OB_SUCC(ret) && is_mysql_mode() && table->is_generated_table()) { // check duplicate base column and non column reference column. if (OB_SUCC(ret)) { bool has_dup_col = false; bool has_non_col_ref = false; if (OB_FAIL(ObResolverUtils::uv_check_dup_base_col(*table, has_dup_col, has_non_col_ref))) { LOG_WARN("check update view hash duplicate column failed", K(ret)); } else { LOG_DEBUG("update view check duplicate column", K(has_dup_col), K(has_non_col_ref)); if (has_dup_col || has_non_col_ref) { ret = OB_ERR_NON_INSERTABLE_TABLE; } } } // check all column belong to the insert base table, some columns already checked in // resolving assignment, but some columns are missing. e.g.: // create table t1 (c1 int primary key, c2 int); // create table t2 (c3 int primary key, c4 int); // create view v as select * from t1, t2 where c1 = c3; // insert into v (c2) values (1) on duplicate update c2 = c3 + c4; if (OB_SUCC(ret)) { bool log_error = true; ObSEArray col_exprs; FOREACH_CNT_X(tas, stmt->get_table_assignments(), OB_SUCC(ret)) { FOREACH_CNT_X(as, tas->assignments_, OB_SUCC(ret)) { col_exprs.reuse(); if (OB_FAIL(ObRawExprUtils::extract_column_exprs(as->expr_, col_exprs))) { LOG_WARN("extract column failed", K(ret)); } else { FOREACH_CNT_X(col, col_exprs, OB_SUCC(ret)) { if (OB_FAIL(check_same_base_table(*table, *static_cast(*col), log_error))) { LOG_TRACE("check same base table fail", K(ret)); } } } } } } // subquery in select list is checked in uv_check_dup_base_col // check subquery in where if (OB_SUCC(ret)) { bool ref_update_table = false; if (OB_FAIL(ObResolverUtils::uv_check_where_subquery(*table, ref_update_table))) { LOG_WARN("update view check where condition failed", K(ret)); } else { LOG_DEBUG("update view check", K(ref_update_table)); ret = ref_update_table ? OB_ERR_NON_INSERTABLE_TABLE : OB_SUCCESS; } } // check join if (OB_SUCC(ret)) { bool insertable = true; if (OB_FAIL( ObResolverUtils::uv_mysql_insertable_join(*table, table->get_base_table_item().ref_id_, insertable))) { LOG_WARN("check insertable join failed", K(ret)); } else { LOG_DEBUG("update view check join", K(insertable)); ret = insertable ? ret : OB_ERR_NON_INSERTABLE_TABLE; } } if (ret == OB_ERR_NON_INSERTABLE_TABLE) { LOG_USER_ERROR(OB_ERR_NON_INSERTABLE_TABLE, table->get_table_name().length(), table->get_table_name().ptr()); } } if (OB_SUCC(ret) && is_oracle_mode() && table->is_generated_table()) { if (OB_SUCC(ret)) { bool has_distinct = false; if (OB_FAIL(ObResolverUtils::uv_check_oracle_distinct(*table, *session_info_, *schema_checker_, has_distinct))) { LOG_WARN("check updatable view distinct failed", K(ret)); } else { LOG_DEBUG("check has distinct", K(ret), K(has_distinct)); ret = has_distinct ? OB_ERR_ILLEGAL_VIEW_UPDATE : ret; } } // check key preserved table if (OB_SUCC(ret)) { bool key_preserved = 0; if (OB_FAIL(uv_check_key_preserved(*table, key_preserved))) { LOG_WARN("check key preserved failed", K(ret)); } else { LOG_DEBUG("check key preserved", K(key_preserved)); ret = !key_preserved ? OB_ERR_O_UPDATE_VIEW_NON_KEY_PRESERVED : ret; } } // check dup base column if (OB_SUCC(ret)) { bool has_dup_col = false; bool has_non_col_ref = false; if (OB_FAIL(ObResolverUtils::uv_check_dup_base_col(*table, has_dup_col, has_non_col_ref))) { LOG_WARN("check update view hash duplicate column failed", K(ret)); } else { LOG_DEBUG("update view check duplicate column", K(has_dup_col), K(has_non_col_ref)); if (has_dup_col) { ret = OB_ERR_NON_INSERTABLE_TABLE; } } } } return ret; } /** * * Why do you cast here? * The processing in this place is very similar to the processing of set operations (eg. union). * The main reason is that the type of select item in insert into select is aligned with the type of columns of insert, * mainly to be able to * Able to form a pdml PK plan. PKEY cannot be done with different types. * * What is the impact on the old plan? In the old plan scenario, some performance degradation may occur. * */ int ObInsertResolver::inner_cast(common::ObIArray& target_columns, ObSelectStmt& select_stmt) { int ret = OB_SUCCESS; ObExprResType res_type; if (target_columns.count() != select_stmt.get_select_items().count()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected insert target column and select items", K(ret), K(target_columns), K(select_stmt.get_select_items())); } for (int64_t i = 0; i < target_columns.count() && OB_SUCC(ret); ++i) { SelectItem& select_item = select_stmt.get_select_item(i); res_type = target_columns.at(i)->get_result_type(); ObSysFunRawExpr* new_expr = NULL; if (res_type == select_item.expr_->get_result_type()) { // no need to generate cast expr. } else if (OB_FAIL(ObRawExprUtils::create_cast_expr( *params_.expr_factory_, select_item.expr_, res_type, new_expr, session_info_))) { LOG_WARN("create cast expr for stmt failed", K(ret)); } else { OZ(new_expr->add_flag(IS_INNER_ADDED_EXPR)); OX(select_item.expr_ = new_expr); } LOG_DEBUG("pdml build a cast expr", KPC(target_columns.at(i)), KPC(new_expr)); } return ret; } int ObInsertResolver::build_column_conv_function_with_value_desc( const int64_t idx, ObRawExpr* column_ref, uint64_t m_index) { int ret = OB_SUCCESS; ObInsertStmt* insert_stmt = get_insert_stmt(); if (OB_ISNULL(insert_stmt) || OB_UNLIKELY(insert_stmt->get_column_conv_functions().count() <= idx) || OB_ISNULL(insert_stmt->get_table_columns(m_index)) || OB_ISNULL(insert_stmt->get_table_columns(m_index)->at(idx)) || OB_ISNULL(column_ref)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid arguments", K(ret)); } else { uint64_t column_id = OB_INVALID_ID; uint64_t table_id = insert_stmt->get_insert_table_id(m_index); ColumnItem* column_item = NULL; ObRawExpr* function_expr = NULL; const ObColumnRefRawExpr* tbl_col = insert_stmt->get_table_columns(m_index)->at(idx); column_id = tbl_col->get_column_id(); if (OB_ISNULL(column_item = insert_stmt->get_column_item_by_id(table_id, column_id))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null column item", K(ret)); } else if (OB_FAIL(add_additional_function_according_to_type(column_item, column_ref, T_INSERT_SCOPE, ObObjMeta::is_binary(column_ref->get_data_type(), column_ref->get_collation_type())))) { LOG_WARN("failed to build column conv expr", K(ret)); } else { SQL_RESV_LOG(TRACE, "ad column conv expr", K(*column_ref)); function_expr = column_ref; insert_stmt->get_column_conv_functions().at(idx) = function_expr; } } return ret; } int ObInsertResolver::build_column_conv_function_with_default_expr(const int64_t idx, uint64_t m_index) { int ret = OB_SUCCESS; ObInsertStmt* insert_stmt = get_insert_stmt(); if (OB_ISNULL(insert_stmt) || OB_UNLIKELY(insert_stmt->get_column_conv_functions().count() <= idx) || OB_ISNULL(insert_stmt->get_table_columns(m_index)) || OB_ISNULL(insert_stmt->get_table_columns(m_index)->at(idx)) || OB_ISNULL(session_info_) || OB_ISNULL(params_.expr_factory_)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid arguments", K(ret)); } else { uint64_t table_id = insert_stmt->get_insert_table_id(m_index); const ObColumnRefRawExpr* tbl_col = insert_stmt->get_table_columns(m_index)->at(idx); uint64_t column_id = tbl_col->get_column_id(); ColumnItem* column_item = insert_stmt->get_column_item_by_id(table_id, column_id); ObRawExpr* function_expr = NULL; ObRawExpr* expr = NULL; ObDefaultValueUtils utils(insert_stmt, ¶ms_, this); if (OB_ISNULL(column_item) || OB_ISNULL(column_item->expr_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null column item", K(ret), K(column_item)); } else if (OB_FAIL(utils.generate_insert_value(column_item, expr))) { LOG_WARN("failed to generate insert value", K(ret)); } else if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("expr should not be null", K(ret)); } if (OB_FAIL(ret)) { // do nothing } else if (ob_is_enum_or_set_type(expr->get_data_type())) { function_expr = expr; } else { // For char type, compare and hash ignore space // For binary type, compare and hash not ignore '\0', so need to padding // '\0' for optimizer calculating partition location. As storage do right // trim of '\0', so don't worry extra space usage. if (ObObjMeta::is_binary(expr->get_data_type(), expr->get_collation_type())) { if (OB_FAIL(build_padding_expr(session_info_, column_item, expr))) { LOG_WARN("Build padding expr error", K(ret)); } } if (OB_FAIL(ret)) { } else if (OB_FAIL(ObRawExprUtils::build_column_conv_expr( *params_.expr_factory_, *params_.allocator_, *column_item->get_expr(), expr, session_info_))) { LOG_WARN("fail to build column conv expr", K(ret)); } else { function_expr = expr; SQL_RESV_LOG(DEBUG, "add column conv expr", K(*function_expr)); } } if (OB_SUCC(ret)) { insert_stmt->get_column_conv_functions().at(idx) = function_expr; } } return ret; } int ObInsertResolver::replace_col_with_new_value(ObRawExpr*& expr) { int ret = OB_SUCCESS; ObInsertStmt* insert_stmt = get_insert_stmt(); CK(NULL != insert_stmt) { const ObIArray& all_cols = *insert_stmt->get_table_columns(); const auto& conv_funcs = insert_stmt->get_column_conv_functions(); for (int i = 0; OB_SUCC(ret) && i < all_cols.count(); i++) { if (i >= conv_funcs.count() || OB_ISNULL(conv_funcs.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid null column conv function", K(ret), K(i), K(all_cols.count())); } else if (OB_FAIL(ObRawExprUtils::replace_ref_column(expr, all_cols.at(i), conv_funcs.at(i)))) { LOG_WARN("failed to replace ref column", K(ret)); } } // for end if (OB_SUCC(ret)) { if (OB_FAIL(expr->formalize(session_info_))) { LOG_WARN("failed to formalize expr", K(ret)); } } } return ret; } // part_generated_col_dep_cols_.count() != 0 means: // in heap table, generated column is partition key // we need to get all dependant columns of generated column. // here we remove all columns which dup with values_desc // eg: create table t1(c1 int, c2 int, c2 int as(c1+c2)); // insert into t1(c1) values(1); // values_desc: c1 // dep_cols: c1, c2 // after remove dup: c2 int ObInsertResolver::remove_dup_dep_cols_for_heap_table(ObInsertStmt& stmt) { int ret = OB_SUCCESS; ObIArray& dep_cols = stmt.get_part_generated_col_dep_cols(); if (0 == dep_cols.count()) { // do nothing } else { const ObIArray& values_desc = stmt.get_values_desc(); ObSEArray cols_no_dup; int64_t j = 0; for (int64_t i = 0; OB_SUCC(ret) && i < dep_cols.count(); ++i) { CK(OB_NOT_NULL(dep_cols.at(i))); for (j = 0; OB_SUCC(ret) && j < values_desc.count(); ++j) { CK(OB_NOT_NULL(values_desc.at(j))); if (OB_SUCC(ret) && values_desc.at(j)->get_column_id() == dep_cols.at(i)->get_column_id()) { break; } } // end for if (OB_SUCC(ret) && j >= values_desc.count()) { // not found OZ(cols_no_dup.push_back(dep_cols.at(i))); } } // end for OX(dep_cols.reset()); OZ(dep_cols.assign(cols_no_dup)); } LOG_DEBUG("remove dup dep cols done", K(dep_cols)); return ret; } } // namespace sql } // namespace oceanbase