/** * 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 "common/ob_smart_call.h" #include "share/ob_define.h" #include "sql/resolver/dml/ob_del_upd_resolver.h" #include "sql/resolver/dml/ob_default_value_utils.h" #include "sql/resolver/dml/ob_update_stmt.h" #include "sql/resolver/dml/ob_insert_stmt.h" #include "sql/resolver/dml/ob_delete_stmt.h" #include "sql/resolver/dml/ob_merge_stmt.h" #include "sql/resolver/dml/ob_insert_all_stmt.h" #include "sql/rewrite/ob_transform_utils.h" #include "sql/resolver/ob_stmt_type.h" #include "pl/ob_pl_resolver.h" #include "sql/parser/parse_malloc.h" #include "sql/resolver/dml/ob_merge_resolver.h" namespace oceanbase { using namespace common; using namespace share; using namespace share::schema; using namespace pl; namespace sql { int ObTableAssignment::expand_expr(ObRawExprFactory &expr_factory, const ObIArray &assigns, ObRawExpr *&expr) { int ret = OB_SUCCESS; ObRawExprCopier copier(expr_factory); for (int64_t i = 0; OB_SUCC(ret) && i < assigns.count(); ++i) { if (OB_FAIL(copier.add_replaced_expr(assigns.at(i).column_expr_, assigns.at(i).expr_))) { LOG_WARN("failed to add replace expr", K(ret)); } } if (OB_SUCC(ret)) { ObRawExpr *new_expr = NULL; if (OB_FAIL(copier.copy_on_replace(expr, new_expr))) { LOG_WARN("failed to do copy on replace", K(ret)); } else { expr = new_expr; } } return ret; } int ObTableAssignment::replace_assigment_expr(const common::ObIArray &assigns, ObRawExpr *&expr) { int ret = OB_SUCCESS; if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (OB_UNLIKELY(!expr->has_flag(IS_COLUMN))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid expr", K(expr)); } else { //在已经加入到assigns中的表达式中查找,如果遇到已经赋值的column,则进行表达式替换; //eg:update test set c1 = c1+c2, c2=c1+3 //经过展开后,会将c1替换成c1+c2, 最后c2的赋值语句变成c2=c1+c2+3 for (int64_t i = 0; i < assigns.count(); i++) { if (assigns.at(i).column_expr_ == expr) { expr = assigns.at(i).expr_; break; } } } return ret; } ObDelUpdResolver::ObDelUpdResolver(ObResolverParams ¶ms) : ObDMLResolver(params), insert_column_ids_(), is_column_specify_(false), is_oracle_tmp_table_(false), oracle_tmp_table_type_(0) { // TODO Auto-generated constructor stub } ObDelUpdResolver::~ObDelUpdResolver() { // TODO Auto-generated destructor stub } int ObDelUpdResolver::resolve_assignments(const ParseNode &parse_node, ObIArray &table_assigns, ObStmtScope scope) { int ret = OB_SUCCESS; ObDMLStmt *stmt = get_stmt(); ObSEArray column_list; ObSEArray value_list; if (OB_ISNULL(stmt) || OB_ISNULL(params_.expr_factory_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("resolver invalid status", K(stmt), KP_(params_.expr_factory)); } else if (OB_FAIL(resolve_column_and_values(parse_node, column_list, value_list))) { LOG_WARN("failed to resovle column and values", K(ret)); } else { // 处理配对后的value ObAssignment assignment; ColumnItem *column = NULL; TableItem *table = NULL; for (int64_t i = 0; OB_SUCC(ret) && i < column_list.count(); i++) { // 处理column ObColumnRefRawExpr *ref_expr = column_list.at(i); if (OB_ISNULL(column = stmt->get_column_item_by_id( ref_expr->get_table_id(), ref_expr->get_column_id()))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get column item failed", K(*ref_expr), K(ret)); } else if (OB_ISNULL(table = stmt->get_table_item_by_id( ref_expr->get_table_id()))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get table item failed", K(*ref_expr), K(ret)); } else { // Statement `update (select * from t1) t set t.c1 = 1` is legal in oralce, illegal in mysql. const bool is_updatable_generated_table = (table->is_generated_table() || table->is_temp_table()) && (!is_mysql_mode() || table->is_view_table_); if (!table->is_basic_table() && !table->is_link_table() && !is_updatable_generated_table) { ret = OB_ERR_NON_UPDATABLE_TABLE; const ObString &table_name = table->alias_name_; ObString scope_name = "UPDATE"; LOG_USER_ERROR(OB_ERR_NON_UPDATABLE_TABLE, table_name.length(), table_name.ptr(), scope_name.length(), scope_name.ptr()); } if (OB_SUCC(ret) && (table->is_generated_table() || table->is_temp_table()) && !get_stmt()->has_instead_of_trigger()) { if (NULL == table->view_base_item_) { if (OB_FAIL(set_base_table_for_updatable_view(*table, *ref_expr))) { LOG_WARN("find base table for update view failed", K(ret)); } else if (OB_ISNULL(table->view_base_item_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("view base item is NULL", K(ret)); } } else { if (OB_FAIL(check_same_base_table(*table, *ref_expr))) { LOG_WARN("check modified columns is same base table failed", K(ret), K(*table), K(*ref_expr)); } } } } if (OB_SUCC(ret) && T_INSERT_SCOPE == scope) { if (OB_FAIL(mock_values_column_ref(ref_expr))) { LOG_WARN("fail to add value desc", K(ret)); } } // 处理表达式 if (OB_SUCC(ret)) { assignment.column_expr_ = column->expr_; ObRawExpr *expr = value_list.at(i); bool is_generated_column = true; SQL_RESV_LOG(DEBUG, "is standard assignment", K(is_mysql_mode())); // 这里Oracle和Mysql的逻辑不一样 // Mysql仅允许将生成列update为默认值 // Oracle不允许update生成列,因此分开进行处理 if (OB_FAIL(check_basic_column_generated(ref_expr, stmt, is_generated_column))) { LOG_WARN("check basic column generated failed", K(ret)); } else { if (is_mysql_mode()) { if (T_DEFAULT == expr->get_expr_type()) { ObDefaultValueUtils utils(stmt, ¶ms_, this); if (OB_FAIL(utils.resolve_default_expr(*column, expr, scope))) { LOG_WARN("failed to resolve default expr", K(*column), K(ret)); } } else if (is_generated_column) { ret = OB_NON_DEFAULT_VALUE_FOR_GENERATED_COLUMN; const ObString &column_name = ref_expr->get_column_name(); const ObString &table_name = ref_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 { // oracle mode if (is_generated_column) { ret = OB_ERR_UPDATE_OPERATION_ON_VIRTUAL_COLUMNS; LOG_WARN("virtual column cannot be updated in Oracle mode", K(ret)); } else if (ref_expr->is_always_identity_column()) { ret = OB_ERR_UPDATE_GENERATED_ALWAYS_IDENTITY_COLUMN; LOG_USER_ERROR(OB_ERR_UPDATE_GENERATED_ALWAYS_IDENTITY_COLUMN); } else if (T_DEFAULT == expr->get_expr_type()) { ObDefaultValueUtils utils(stmt, ¶ms_, this); if (OB_FAIL(utils.resolve_default_expr(*column, expr, scope))) { LOG_WARN("failed to resolve default expr", K(*column), K(ret)); } } } } if (OB_SUCC(ret)) { if (OB_FAIL(add_additional_function_according_to_type(column, expr, scope, true))) { LOG_WARN("fail to add additional function", K(ret), K(column)); } else if (OB_FAIL(recursive_values_expr(expr))) { LOG_WARN("fail to resolve values expr", K(ret)); } else { // 1. set geo sub type to cast mode to column covert expr when update // 2. check geo type while doing column covert. if (column->is_geo_ && T_FUN_COLUMN_CONV == expr->get_expr_type()) { ObColumnRefRawExpr *raw_expr = column->get_expr(); if (OB_ISNULL(raw_expr)) { ret = OB_ERR_NULL_VALUE; LOG_WARN("raw expr in column item is null", K(ret)); } else { ObGeoType geo_type = raw_expr->get_geo_type(); uint64_t cast_mode = expr->get_extra(); if (OB_FAIL(ObGeoCastUtils::set_geo_type_to_cast_mode(geo_type, cast_mode))) { LOG_WARN("fail to set geometry type to cast mode", K(ret), K(geo_type)); } else { expr->set_extra(cast_mode); } } } if (OB_SUCC(ret)) { assignment.expr_ = expr; if (OB_FAIL(add_assignment(table_assigns, table, column, assignment))) { LOG_WARN("failed to add assignment", K(ret)); } } } } } } } return ret; } int ObDelUpdResolver::resolve_column_and_values(const ParseNode &assign_list, ObIArray &target_list, ObIArray &value_list) { int ret = OB_SUCCESS; if (OB_ISNULL(allocator_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid argument", K(ret)); } else if (OB_UNLIKELY(T_ASSIGN_LIST != assign_list.type_ || assign_list.num_child_ < 1)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("resolver invalid status", K(ret), K(assign_list.type_)); } else { if (1 == assign_list.num_child_ && T_OBJ_ACCESS_REF == assign_list.children_[0]->type_) { //update set ROW=record的扩展用法 CK (OB_NOT_NULL(get_stmt())); if (OB_SUCC(ret)) { if (!get_stmt()->is_update_stmt()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("SET ROW must be in update statement", K(ret)); } else { ObUpdateStmt *stmt = static_cast(get_stmt()); if (1 != stmt->get_table_size()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("SET ROW must be used for single table", K(stmt->get_table_size()), K(ret)); } else if (params_.secondary_namespace_ == NULL) { TableItem *table_item = stmt->get_table_item(0); CK (OB_NOT_NULL(table_item)); if (OB_SUCC(ret)) { ObString row = ObString::make_string("row"); ObString table_name = table_item->get_table_name().length() > 0 ? table_item->get_table_name() : ObString::make_string(" "); ret = OB_ERR_BAD_FIELD_ERROR; //oracle will report an ORA-00936 error, ob does not have the error code. LOG_USER_ERROR(OB_ERR_BAD_FIELD_ERROR, row.length(), row.ptr(), table_name.length(), table_name.ptr()); LOG_WARN("column does not existed", K(ret)); } } else { TableItem *table_item = stmt->get_table_item(0); const share::schema::ObTableSchema *table_schema = NULL; ObArray column_items; CK (OB_NOT_NULL(table_item)); OZ (resolve_all_basic_table_columns(*table_item, false, &column_items)); for (int64_t i = 0; OB_SUCC(ret) && i < column_items.count(); ++i) { OZ (target_list.push_back(column_items.at(i).get_expr())); } OZ (expand_record_to_columns(*assign_list.children_[0], value_list)); if (OB_SUCC(ret) && target_list.count() != value_list.count()) { ret = OB_ERR_TOO_MANY_VALUES; LOG_WARN("too many values", K(ret), K(target_list.count()), K(value_list.count())); } } } } } else { for (int64_t i = 0; OB_SUCC(ret) && i < assign_list.num_child_; ++i) { ParseNode *left_node = NULL; ParseNode *right_node = NULL; ObRawExpr *value_expr = NULL; ObSEArray columns; ObSEArray values; if (OB_ISNULL(assign_list.children_[i]) || OB_ISNULL(left_node = assign_list.children_[i]->children_[0]) || OB_ISNULL(right_node = assign_list.children_[i]->children_[1])) { ret = OB_ERR_UNEXPECTED; LOG_WARN("assign node is empty", K(ret), K(assign_list.children_[i]), K(left_node), K(right_node)); } else if (OB_FAIL(resolve_assign_columns(*left_node, columns))) { LOG_WARN("failed to resolve assign target", K(ret)); } else if (OB_FAIL(resolve_sql_expr(*right_node, value_expr))) { LOG_WARN("failed to resolve value expr", K(ret)); } else if (columns.count() == 1) { if (value_expr->is_query_ref_expr()) { // update t1 set (c1) = (select c1 from t2), c2 = 5; // resolve as update t1 set c1 = (select c1 from t2), c2 = 5; ObQueryRefRawExpr *query_ref = static_cast(value_expr); ObSelectStmt *sel_stmt = NULL; if (OB_ISNULL(sel_stmt = query_ref->get_ref_stmt())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("select stmt is null", K(ret)); } else if (1 < sel_stmt->get_select_item_size()) { ret = OB_ERR_TOO_MANY_VALUES; LOG_WARN("too many values", K(ret)); } } else if (T_QUESTIONMARK == value_expr->get_expr_type() && !params_.is_prepare_stage_) { const ObColumnRefRawExpr *col_expr = columns.at(0); ObConstRawExpr *c_expr = static_cast(value_expr); CK (OB_NOT_NULL(col_expr)); CK (OB_NOT_NULL(c_expr)); if (OB_FAIL(ret)) { } else if (col_expr->get_result_type().get_obj_meta().is_enum_or_set() || col_expr->get_result_type().get_obj_meta().is_urowid() || params_.is_batch_stmt_) { // enum, set, rowid do not support cast int64_t param_idx = 0; OZ (c_expr->get_value().get_unknown(param_idx)); CK (OB_NOT_NULL(params_.param_list_)); CK (param_idx < params_.param_list_->count()); OX (const_cast( params_.param_list_->at(param_idx)).set_need_to_check_type(true)); } else { OZ (c_expr->add_flag(IS_TABLE_ASSIGN)); OX (c_expr->set_result_type(col_expr->get_result_type())); } } } else if (OB_UNLIKELY(!value_expr->is_query_ref_expr())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid stmt or value expr", K(ret)); } else { ObQueryRefRawExpr *query_ref = static_cast(value_expr); ObSelectStmt *sel_stmt = NULL; if (OB_ISNULL(sel_stmt = query_ref->get_ref_stmt())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("select stmt is null", K(ret)); } else if (columns.count() > sel_stmt->get_select_item_size()) { ret = OB_ERR_NOT_ENOUGH_VALUES; LOG_WARN("not enough values", K(ret)); } else if (columns.count() < sel_stmt->get_select_item_size()) { ret = OB_ERR_TOO_MANY_VALUES; LOG_WARN("too many values", K(ret)); } else if (OB_UNLIKELY(sel_stmt->get_CTE_table_size() > 0)) { ret = OB_ERR_NOT_SUBQUERY; LOG_WARN("subquery is cte", K(ret)); } else if (columns.count() > 1) { if (OB_FAIL(try_add_remove_const_epxr(*sel_stmt))) { LOG_WARN("failed to add remove const expr", K(ret)); } for (int64_t j = 0; OB_SUCC(ret) && j < columns.count(); ++j) { ObAliasRefRawExpr *alias_expr = NULL; if (OB_FAIL(ObRawExprUtils::build_query_output_ref( *params_.expr_factory_, query_ref, j, alias_expr))) { LOG_WARN("failed to build query output ref", K(ret)); } else if (OB_FAIL(values.push_back(alias_expr))) { LOG_WARN("failed to push back alias expr", K(ret)); } } } } if (OB_SUCC(ret)) { if (OB_FAIL(append(target_list, columns))) { LOG_WARN("failed to append target list", K(ret)); } else if (columns.count() == 1 && OB_FAIL(value_list.push_back(value_expr))) { LOG_WARN("failed to append value expr", K(ret)); } else if (columns.count() > 1 && OB_FAIL(append(value_list, values))) { LOG_WARN("failed to append values", K(ret)); } } } } } return ret; } int ObDelUpdResolver::try_add_remove_const_epxr(ObSelectStmt &stmt) { int ret = OB_SUCCESS; CK(NULL != session_info_); CK(NULL != params_.expr_factory_); if (OB_SUCC(ret)) { for (int64_t i = 0; OB_SUCC(ret) && i < stmt.get_select_item_size(); ++i) { ObRawExpr *&expr = stmt.get_select_item(i).expr_; CK(NULL != expr); if (OB_SUCC(ret)) { ObRawExpr *new_expr = NULL; OZ(ObRawExprUtils::build_remove_const_expr( *params_.expr_factory_, *session_info_, expr, new_expr)); CK(NULL != new_expr); OX(expr = new_expr); } } } return ret; } int ObDelUpdResolver::recursive_values_expr(ObRawExpr *&expr) { int ret = OB_SUCCESS; ObDMLStmt *stmt = get_stmt(); if (OB_ISNULL(stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("stmt is null"); } else if (expr && expr->has_flag(CNT_VALUES)) { if (expr->has_flag(IS_VALUES)) { if (OB_FAIL(process_values_function(expr))) { LOG_WARN("fail to resovle values expr", K(ret), K(*expr)); } } else { for (int64_t i = 0; OB_SUCC(ret) && i < expr->get_param_count(); i++) { if (OB_FAIL(SMART_CALL(recursive_values_expr(expr->get_param_expr(i))))) { LOG_WARN("resolve raw expr param failed", K(ret), K(i)); } } } } return ret; } int ObDelUpdResolver::process_values_function(ObRawExpr *&expr) { UNUSED(expr); return OB_SUCCESS; } int ObDelUpdResolver::resolve_assign_columns(const ParseNode &assign_target, ObIArray &column_list) { int ret = OB_SUCCESS; bool is_column_list = false; int64_t column_count = 1; bool is_merge_resolver = false; if (OB_ISNULL(get_stmt())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("stmt is null", K(ret)); } else if (assign_target.type_ != T_COLUMN_LIST && assign_target.type_ != T_COLUMN_REF) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid parse node", K(ret)); } else if (assign_target.type_ == T_COLUMN_LIST) { column_count = assign_target.num_child_; is_column_list = true; } else { is_merge_resolver = get_stmt()->is_merge_stmt(); } for (int64_t i = 0; OB_SUCC(ret) && i < column_count; ++i) { const ParseNode *col_node = (is_column_list ? assign_target.children_[i] : &assign_target); ObQualifiedName q_name; ObRawExpr *col_expr = NULL; ObNameCaseMode case_mode = OB_NAME_CASE_INVALID; if (OB_FAIL(session_info_->get_name_case_mode(case_mode))) { LOG_WARN("resolve column reference name failed", K(ret)); } else if (OB_FAIL(ObResolverUtils::resolve_column_ref( col_node, case_mode, q_name))) { LOG_WARN("resolve column reference name failed", K(ret)); } else if (q_name.is_star_) { ret = OB_ERR_UNEXPECTED; LOG_WARN("'*' should not be here, parser has already blocked this error", K(ret)); } else if (lib::is_oracle_mode() && ObCharset::case_insensitive_equal(OB_HIDDEN_LOGICAL_ROWID_COLUMN_NAME, q_name.col_name_)) { ret = OB_ERR_VIRTUAL_COL_NOT_ALLOWED; LOG_WARN("cannot update rowid pseudo column", K(ret), K(q_name)); } else if (is_merge_resolver) { // merge resolver does not check column unique column_namespace_checker_.disable_check_unique(); if (OB_FAIL(resolve_table_column_expr(q_name, col_expr))) { report_user_error_msg(ret, col_expr, q_name); LOG_WARN("resolve column ref expr failed", K(ret), K(q_name)); } column_namespace_checker_.enable_check_unique(); } else { // other kinds of resolver if (OB_FAIL(resolve_table_column_expr(q_name, col_expr))) { report_user_error_msg(ret, col_expr, q_name); LOG_WARN("resolve column ref expr failed", K(ret), K(q_name)); } } if (OB_FAIL(ret)) { } else if (OB_ISNULL(col_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("reference expr is null", K(ret)); } else if (!col_expr->is_column_ref_expr()) { ret = OB_ERR_NON_UPDATABLE_TABLE; LOG_WARN("update column should from updatable table", K(col_expr), K(ret)); } else { ObColumnRefRawExpr *base_col_expr = static_cast(col_expr); if (!get_stmt()->has_instead_of_trigger()) { if (OB_FAIL(ObTransformUtils::get_base_column(get_stmt(), base_col_expr))) { // this is not allow, but to compatible with oracle, the error will report at last ret = OB_SUCCESS; LOG_WARN("get base column failed", K(ret), KPC(base_col_expr)); } else if (OB_ISNULL(base_col_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("base_col_expr is null", K(ret)); } } if (OB_SUCC(ret) && OB_FAIL(column_list.push_back(static_cast(col_expr)))) { LOG_WARN("failed to push back column expr", K(ret)); } } } return ret; } int ObDelUpdResolver::generate_wrapper_expr_for_assignemnts(ObIArray &assigns, bool has_before_trigger) { int ret = OB_SUCCESS; if (has_before_trigger) { for (int64_t i = 0; OB_SUCC(ret) && i < assigns.count(); ++i) { ObAssignment &as = assigns.at(i); ObRawExpr *value_expr = as.expr_; if (OB_FAIL(ObRawExprUtils::build_wrapper_inner_expr( *params_.expr_factory_, *session_info_, as.expr_, as.expr_))) { LOG_WARN("failed to build wrapper inner expr", K(ret)); } else { LOG_DEBUG("add wrapper inner expr", K(*as.expr_), K(as.expr_)); } } } return ret; } int ObDelUpdResolver::resolve_additional_assignments(ObIArray &assigns, const ObStmtScope scope) { int ret = OB_SUCCESS; ObSchemaGetterGuard *schema_guard = NULL; const ObTableSchema* table_schema = NULL; const TableItem *table_item = NULL; ObDMLStmt *stmt = get_stmt(); bool trigger_exist = false; if (OB_ISNULL(params_.expr_factory_) || OB_ISNULL(stmt)) { ret = OB_NOT_INIT; LOG_WARN("params is invalid", K_(params_.expr_factory), K(stmt)); } else if (T_UPDATE_SCOPE != scope && T_INSERT_SCOPE != scope) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid input scope", K(scope)); } for (int64_t i = 0; OB_SUCC(ret) && i < assigns.count(); ++i) { if (OB_ISNULL(schema_checker_) || OB_ISNULL(schema_guard = schema_checker_->get_schema_guard()) || OB_ISNULL(table_item = stmt->get_table_item_by_id(assigns.at(i).table_id_))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid schema checker", K(schema_checker_)); } else if (OB_ISNULL(session_info_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("session_info_ is null", K(ret)); } else if (OB_FAIL(schema_checker_->get_table_schema(session_info_->get_effective_tenant_id(), table_item->get_base_table_item().ref_id_, table_schema, table_item->is_link_table()))) { LOG_WARN("fail to get table schema", K(ret), KPC(table_item)); } else if (OB_ISNULL(table_schema)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("fail to get table schema", KPC(table_item), K(table_schema)); } else if (OB_FAIL(table_schema->has_before_update_row_trigger(*schema_guard, trigger_exist))) { LOG_WARN("fail to call has_before_update_row_trigger", K(*table_schema)); } else if (OB_FAIL(generate_wrapper_expr_for_assignemnts(assigns.at(i).assignments_, trigger_exist))) { LOG_WARN("failed to resolve addtional assignments for const", K(ret), K(i)); } else { for (ObTableSchema::const_column_iterator iter = table_schema->column_begin(); (OB_SUCCESS == ret && iter != table_schema->column_end()); ++iter) { ColumnItem *col_item = NULL; ObColumnSchemaV2 *column_schema = *iter; bool need_assigned = false; uint64_t column_id = OB_INVALID_ID; if (NULL == column_schema) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get column schema fail", K(column_schema)); } else if (FALSE_IT(column_id = column_schema->get_column_id())) { //do nothing } else if (OB_FAIL(check_need_assignment(assigns.at(i).assignments_, table_item->table_id_, trigger_exist, *column_schema, need_assigned))) { LOG_WARN("fail to check assignment exist", KPC(table_item), K(column_id)); } else if (need_assigned) { // for insert scope, on duplicate key update column list already // exists in insert list, therefore, only need to add assignment. // add assign ObAssignment assignment; ObSEArray col_exprs; if (OB_FAIL(add_column_to_stmt(*table_item, *column_schema, col_exprs))) { LOG_WARN("add column to stmt failed", K(ret), K(*table_item), K(*column_schema)); } else if (col_exprs.empty()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("no column expr returned", K(ret)); } else if (OB_ISNULL(col_item = stmt->get_column_item_by_id( table_item->table_id_, col_exprs.at(0)->get_column_id()))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get column item failed", K(ret)); } else { assignment.column_expr_ = col_item->expr_; assignment.is_implicit_ = true; if (column_schema->is_on_update_current_timestamp()) { assignment.column_expr_->set_result_flag(ON_UPDATE_NOW_FLAG); ObDefaultValueUtils utils(stmt, ¶ms_, this); if (OB_FAIL(utils.build_now_expr(col_item, assignment.expr_))) { LOG_WARN("fail to build default expr", K(ret)); } } else if (column_schema->is_generated_column()) { if (OB_FAIL(copy_schema_expr(*params_.expr_factory_, col_item->expr_->get_dependant_expr(), assignment.expr_))) { LOG_WARN("failed to copy dependant expr", K(ret)); } } else if (trigger_exist) { assignment.expr_ = col_item->expr_; } if (OB_FAIL(ret)) { //do nothing } else if (OB_FAIL(ObRawExprUtils::build_column_conv_expr(*params_.expr_factory_, *params_.allocator_, *col_item->get_expr(), assignment.expr_, session_info_))) { LOG_WARN("fail to build format expr", K(ret)); } else if (trigger_exist && OB_FAIL(ObRawExprUtils::build_wrapper_inner_expr(*params_.expr_factory_, *session_info_, assignment.expr_, assignment.expr_))) { LOG_WARN("failed to build wrapper inner expr", K(ret)); } else { // 1. set geo sub type to cast mode to column covert expr when update // 2. check geo type while doing column covert. if (col_item->is_geo_ && T_FUN_COLUMN_CONV == assignment.expr_->get_expr_type()) { ObColumnRefRawExpr *raw_expr = col_item->get_expr(); if (OB_ISNULL(raw_expr)) { ret = OB_ERR_NULL_VALUE; LOG_WARN("raw expr in column item is null", K(ret)); } else { ObGeoType geo_type = raw_expr->get_geo_type(); uint64_t cast_mode = assignment.expr_->get_extra(); if (OB_FAIL(ObGeoCastUtils::set_geo_type_to_cast_mode(geo_type, cast_mode))) { LOG_WARN("fail to set geometry type to cast mode", K(ret), K(geo_type)); } else { assignment.expr_->set_extra(cast_mode); } } } if (OB_SUCC(ret)) { if (OB_FAIL(add_assignment(assigns, table_item, col_item, assignment))) { LOG_WARN("failed to ass assignment", K(ret)); } } } } } } // end for } if (OB_SUCC(ret)) { if (OB_FAIL(check_heap_table_update(assigns.at(i)))) { LOG_WARN("fail to add assignment to heap table", K(ret), K(i), "assigns", assigns.at(i)); } } } return ret; } // duplicated assignments are permitted, such SET c2=c1*2, c2=1+c2. int ObDelUpdResolver::add_assignment(common::ObIArray &assigns, const TableItem *table_item, const ColumnItem *col, ObAssignment &assign) { int ret = OB_SUCCESS; ObTableAssignment *table_assign = NULL; int64_t N = assigns.count(); if (OB_ISNULL(schema_checker_) || OB_ISNULL(table_item) || OB_ISNULL(assign.column_expr_) || OB_ISNULL(get_stmt()) || OB_ISNULL(get_stmt()->get_query_ctx())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret), K_(schema_checker), K(table_item), K_(assign.column_expr)); } else if (assign.column_expr_->get_result_type().is_lob() && params_.is_batch_stmt_) { ret = OB_BATCHED_MULTI_STMT_ROLLBACK; //batch stmt execution does not support update lob locator columns //because we can not do defensive check with lob locator columns LOG_TRACE("batch stmt can not supported with lob locator", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && i < N; ++i) { ObTableAssignment &ta = assigns.at(i); if (ta.table_id_ == assign.column_expr_->get_table_id()) { table_assign = &ta; break; } } if (OB_SUCC(ret) && NULL == table_assign) { ObTableAssignment new_ta; new_ta.table_id_ = table_item->table_id_; if (OB_FAIL(assigns.push_back(new_ta))) { LOG_WARN("failed to add ta", K(ret)); } else { table_assign = &assigns.at(assigns.count() - 1); } } if (OB_SUCC(ret) && (is_mysql_mode() || assign.column_expr_->is_generated_column())) { //in MySQL: //The second assignment in the following statement sets col2 to the current (updated) col1 value, //not the original col1 value. //The result is that col1 and col2 have the same value. //This behavior differs from standard SQL. //UPDATE t1 SET col1 = col1 + 1, col2 = col1; //But in Oracle, its behavior is same with standard SQL //set original col1 to col1 and col2 //For generated column, when cascaded column is updated, the generated column will be updated with new column ObRawExprCopier copier(*params_.expr_factory_); for (int64_t i = 0; OB_SUCC(ret) && i < table_assign->assignments_.count(); ++i) { if (!table_assign->assignments_.at(i).column_expr_->is_xml_column()) { if (OB_FAIL(copier.add_replaced_expr(table_assign->assignments_.at(i).column_expr_, table_assign->assignments_.at(i).expr_))) { LOG_WARN("failed to add replaced expr", K(ret)); } } else { // is generated column and ref column is xmltype, generated column ref hiddlen column actually // udt column replace is done in pre transfrom but here generate column need replace const ObRawExpr *from_expr = ObRawExprUtils::get_sql_udt_type_expr_recursively(assign.expr_); const ObRawExpr *to_expr = table_assign->assignments_.at(i).expr_; if (OB_ISNULL(from_expr)) { // do nonthing } else { if (OB_FAIL(copier.add_replaced_expr(from_expr, to_expr))) { LOG_WARN("failed to add replaced expr", K(ret)); } } } } for (int64_t i = 0; OB_SUCC(ret) && i < get_stmt()->get_subquery_expr_size(); ++i) { if (OB_FAIL(copier.add_skipped_expr(get_stmt()->get_subquery_exprs().at(i), false))) { LOG_WARN("failed to add skipped expr", K(ret)); } } if (OB_SUCC(ret) && OB_FAIL(copier.copy_on_replace(assign.expr_, assign.expr_))) { LOG_WARN("failed to copy on replace expr", K(ret)); } } bool found = false; if (OB_SUCC(ret)) { if (get_stmt()->get_query_ctx()->is_prepare_stmt()) { // do nothing } else { for (int64_t i = 0; OB_SUCC(ret) && !found && i < table_assign->assignments_.count(); ++i) { if (assign.column_expr_ == table_assign->assignments_.at(i).column_expr_) { table_assign->assignments_.at(i) = assign; table_assign->assignments_.at(i).is_duplicated_ = true; //this column was updated repeatedly found = true; } } } } if (OB_SUCC(ret) && !found) { if (OB_FAIL(table_assign->assignments_.push_back(assign))) { LOG_WARN("store assignment failed", K(ret)); } } return ret; } int ObDelUpdResolver::check_need_assignment(const common::ObIArray &assigns, uint64_t table_id, bool before_update_row_trigger_exist, const ObColumnSchemaV2 &column, bool &need_assign) { need_assign = false; int ret = OB_SUCCESS; bool exist = false; ObDMLStmt *stmt = get_stmt(); if (OB_ISNULL(stmt)) { ret = OB_NOT_INIT; LOG_WARN("stmt is NULL", K(ret)); } else if (stmt->has_instead_of_trigger()) { // 兼容oracle,这里的列不级联更新 // do nothing } else if (column.is_udt_hidden_column()) { // do nothing, will handle in udt transform } else if (column.is_generated_column()) { if (OB_FAIL(ObResolverUtils::check_whether_assigned(stmt, assigns, table_id, column.get_column_id(), exist))) { LOG_WARN("check column whether assigned failed", K(ret)); } else if (!exist) { ObArray cascaded_columns; if (OB_FAIL(column.get_cascaded_column_ids(cascaded_columns))) { LOG_WARN("get cascaded column ids failed", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && !exist && i < cascaded_columns.count(); ++i) { if (OB_FAIL(ObResolverUtils::check_whether_assigned(stmt, assigns, table_id, cascaded_columns.at(i), exist))) { LOG_WARN("check whether assigned cascaded columns failed", K(ret), K(table_id), K(cascaded_columns.at(i))); } } if (OB_SUCC(ret) && exist) { //the generated column isn't assigned, but the cascaded columns have been assigned //so assign the generated column need_assign = true; } } } else if (column.is_on_update_current_timestamp() || before_update_row_trigger_exist) { if (column.get_column_id() == OB_HIDDEN_PK_INCREMENT_COLUMN_ID) { // for heap_table the hidden_pk should not be updated } else if (OB_FAIL(ObResolverUtils::check_whether_assigned(stmt, assigns, table_id, column.get_column_id(), exist))) { LOG_WARN("check whether assigned cascaded columns failed", K(ret), K(table_id), K(column.get_column_id())); } else if (!exist) { need_assign = true; } } return ret; } int ObDelUpdResolver::set_base_table_for_updatable_view(TableItem &table_item, const ObColumnRefRawExpr &col_ref, const bool log_error/* = true */) { int ret = OB_SUCCESS; ObSelectStmt *stmt = table_item.ref_query_; ObDMLStmt *dml = get_stmt(); const int64_t idx = col_ref.get_column_id() - OB_APP_MIN_COLUMN_ID; OZ(check_stack_overflow()); if (OB_FAIL(ret)) { } else if (!table_item.is_generated_table() && !table_item.is_temp_table()) { ret = OB_INVALID_ARGUMENT; LOG_WARN("table is not view or stmt is NULL or invalid column id", K(ret), K(table_item), K(idx), KP(stmt), K(col_ref)); } else if (OB_ISNULL(dml) || OB_ISNULL(stmt) || idx < 0 || idx >= stmt->get_select_item_size()) { ret = OB_INVALID_ARGUMENT; LOG_WARN("table is not view or stmt is NULL or invalid column id", K(ret), K(table_item), K(idx), KP(stmt), K(col_ref)); } else if (OB_ISNULL(session_info_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("session_info_ is null", K(ret)); } else { if (table_item.is_view_table_) { const ObTableSchema *table_schema = NULL; if (OB_FAIL(schema_checker_->get_table_schema(session_info_->get_effective_tenant_id(), stmt->get_view_ref_id(), table_schema, table_item.is_link_table()))) { LOG_WARN("get table schema failed", K(ret)); } else if (OB_ISNULL(table_schema)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("NULL table schema", K(ret)); } else { if (!table_schema->get_view_schema().get_view_is_updatable()) { ret = OB_ERR_MODIFY_READ_ONLY_VIEW; } } } } if (OB_SUCC(ret)) { if (!dml->has_instead_of_trigger() && OB_FAIL(ObResolverUtils::uv_check_basic(*stmt, dml->is_insert_stmt()))) { LOG_WARN("not updatable", K(ret)); } else { ObRawExpr *expr = stmt->get_select_item(idx).expr_; if (!expr->is_column_ref_expr() || (lib::is_oracle_mode() && ObCharset::case_insensitive_equal(OB_HIDDEN_LOGICAL_ROWID_COLUMN_NAME, static_cast(expr)->get_column_name()))) { ret = is_mysql_mode() ? OB_ERR_NONUPDATEABLE_COLUMN : OB_ERR_VIRTUAL_COL_NOT_ALLOWED; LOG_WARN("column is not updatable", K(ret), K(col_ref)); } else { ObColumnRefRawExpr *new_col_ref = static_cast(expr); TableItem *new_table_item = stmt->get_table_item_by_id(new_col_ref->get_table_id()); if (NULL == new_table_item) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get NULL table item", K(ret)); } else { table_item.view_base_item_ = new_table_item; if (new_table_item->is_basic_table()) { const ObTableSchema *base_table_schema = NULL; if (OB_FAIL(schema_checker_->get_table_schema(session_info_->get_effective_tenant_id(), new_table_item->ref_id_, base_table_schema))) { LOG_WARN("get table schema failed", K(ret)); } else if (OB_ISNULL(base_table_schema)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("NULL table schema", K(ret)); } else if (OB_UNLIKELY(base_table_schema->is_vir_table())) { ret = OB_NOT_SUPPORTED; LOG_USER_ERROR(OB_NOT_SUPPORTED, "DML operation on Virtual Table/Temporary Table"); } } else if (new_table_item->is_generated_table() || new_table_item->is_temp_table()) { const bool inner_log_error = false; if (OB_FAIL(check_need_fired_trigger(new_table_item))) { LOG_WARN("check has need fired trigger failed", K(ret)); } else if (OB_FAIL(SMART_CALL(set_base_table_for_updatable_view(*new_table_item, *new_col_ref, inner_log_error)))) { LOG_WARN("find base table for updatable view failed", K(ret)); } } else if (new_table_item->is_fake_cte_table()) { ret = OB_ERR_ILLEGAL_VIEW_UPDATE; LOG_WARN("illegal view update", K(ret)); } else if (new_table_item->is_values_table()) { ret = dml->is_insert_stmt() ? OB_ERR_NON_INSERTABLE_TABLE : OB_ERR_NON_UPDATABLE_TABLE; LOG_WARN("view is not updatable", K(ret)); } else if (new_table_item->is_json_table()) { ret = OB_ERR_NON_INSERTABLE_TABLE; LOG_WARN("json table can not be insert", K(ret)); } else { ret = OB_ERR_UNEXPECTED; LOG_WARN("column is not updatable", K(ret), K(col_ref)); } } } } if (log_error && OB_SUCCESS != ret) { ObString update_str = "UPDATE"; if (OB_ERR_NONUPDATEABLE_COLUMN == ret) { LOG_USER_ERROR(OB_ERR_NONUPDATEABLE_COLUMN, col_ref.get_column_name().length(), col_ref.get_column_name().ptr()); } else if (OB_ERR_NON_INSERTABLE_TABLE == ret) { LOG_USER_ERROR(OB_ERR_NON_INSERTABLE_TABLE, table_item.table_name_.length(), table_item.table_name_.ptr()); } else if (OB_ERR_NON_UPDATABLE_TABLE == ret) { LOG_USER_ERROR(OB_ERR_NON_UPDATABLE_TABLE, table_item.table_name_.length(), table_item.table_name_.ptr(), update_str.length(), update_str.ptr()); } } } return ret; } int ObDelUpdResolver::set_base_table_for_view(TableItem &table_item, const bool log_error/* = true */) { int ret = OB_SUCCESS; ObSelectStmt *stmt = table_item.ref_query_; CK(OB_NOT_NULL(get_stmt()) && !get_stmt()->has_instead_of_trigger()); OZ(check_stack_overflow()); if (OB_FAIL(ret)) { } else if (!table_item.is_generated_table() || OB_ISNULL(stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("not generated table or referred query is NULL", K(ret)); } else if (OB_ISNULL(session_info_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("session_info_ is null", K(ret)); } else { if (table_item.is_view_table_) { const ObTableSchema *table_schema = NULL; if (OB_FAIL(schema_checker_->get_table_schema(session_info_->get_effective_tenant_id(), stmt->get_view_ref_id(), table_schema, table_item.is_link_table()))) { LOG_WARN("get table schema failed", K(ret)); } else if (OB_ISNULL(table_schema)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("NULL table schema", K(ret)); } else { if (!table_schema->get_view_schema().get_view_is_updatable()) { ret = OB_ERR_MODIFY_READ_ONLY_VIEW; } } } } if (OB_SUCC(ret)) { const bool is_insert = false; if (OB_FAIL(ObResolverUtils::uv_check_basic(*stmt, is_insert))) { LOG_WARN("not updatable", K(ret)); } else if (stmt->get_table_items().empty()) { // create view v as select 1 a; ret = is_mysql_mode() ? OB_ERR_NON_UPDATABLE_TABLE : OB_ERR_ILLEGAL_VIEW_UPDATE; LOG_WARN("no table item in select stmt", K(ret)); } else { // get the first table item for oracle mode TableItem *base = stmt->get_table_items().at(0); if (stmt->get_table_items().count() > 1) { // mysql delete join view not supported. if (is_mysql_mode()) { ret = OB_ERR_VIEW_DELETE_MERGE_VIEW; LOG_WARN("delete join view", K(ret)); } } if (OB_FAIL(ret)) { } else if (NULL == base) { ret = OB_ERR_UNEXPECTED; LOG_WARN("table item is null", K(ret)); } else if (base->is_link_table()) { table_item.view_base_item_ = base; } else if (base->is_basic_table()) { table_item.view_base_item_ = base; const ObTableSchema *base_table_schema = NULL; if (OB_FAIL(schema_checker_->get_table_schema(session_info_->get_effective_tenant_id(), base->ref_id_, base_table_schema))) { LOG_WARN("get table schema failed", K(ret)); } else if (OB_ISNULL(base_table_schema)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("NULL table schema", K(ret)); } else if (OB_UNLIKELY(base_table_schema->is_vir_table())) { ret = OB_NOT_SUPPORTED; LOG_USER_ERROR(OB_NOT_SUPPORTED, "DML operation on Virtual Table/Temporary Table"); } } else if (base->is_generated_table()) { table_item.view_base_item_ = base; const bool inner_log_error = false; if (OB_FAIL(SMART_CALL(set_base_table_for_view(*base, inner_log_error)))) { LOG_WARN("set base table for view failed", K(ret)); } } else if (base->cte_type_ != TableItem::NOT_CTE) { ret = OB_ERR_NON_UPDATABLE_TABLE; LOG_WARN("table is not updatable", K(ret)); } else if (base->is_values_table()) { ret = OB_ERR_NON_UPDATABLE_TABLE; LOG_WARN("non update table", K(ret)); } else if (base->is_json_table()) { ret = is_mysql_mode() ? OB_ERR_NON_UPDATABLE_TABLE : OB_ERR_O_DELETE_VIEW_NON_KEY_PRESERVED; LOG_WARN("non update json table", K(ret)); } else { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected table type in view", K(ret), K(*base)); } } if (log_error && OB_SUCCESS != ret) { ObString del_str = "DELETE";//仅仅只有mysql模式下的delete会用到这个报错信息 if (OB_ERR_NON_UPDATABLE_TABLE == ret) { LOG_USER_ERROR(OB_ERR_NON_UPDATABLE_TABLE, table_item.table_name_.length(), table_item.table_name_.ptr(), del_str.length(), del_str.ptr()); } else if (OB_ERR_VIEW_DELETE_MERGE_VIEW == ret) { LOG_USER_ERROR(OB_ERR_VIEW_DELETE_MERGE_VIEW, table_item.database_name_.length(), table_item.database_name_.ptr(), table_item.table_name_.length(), table_item.table_name_.ptr()); } } } return ret; } int ObDelUpdResolver::check_same_base_table(const TableItem &table_item, const ObColumnRefRawExpr &col_ref, const bool log_error/* = true */) { int ret = OB_SUCCESS; ObSelectStmt *stmt = table_item.ref_query_; const int64_t idx = col_ref.get_column_id() - OB_APP_MIN_COLUMN_ID; if ((!table_item.is_generated_table() && !table_item.is_temp_table()) || OB_ISNULL(table_item.view_base_item_) || OB_ISNULL(stmt) || idx < 0 || idx >= stmt->get_select_item_size()) { ret = OB_INVALID_ARGUMENT; LOG_WARN("table is not view or stmt is NULL or invalid column id", K(ret), K(table_item), K(idx), KP(stmt), K(col_ref)); } else { ObRawExpr *expr = stmt->get_select_item(idx).expr_; if (!expr->is_column_ref_expr() || (lib::is_oracle_mode() && ObCharset::case_insensitive_equal(OB_HIDDEN_LOGICAL_ROWID_COLUMN_NAME, static_cast(expr)->get_column_name()))) { ret = is_mysql_mode() ? OB_ERR_NONUPDATEABLE_COLUMN : OB_ERR_VIRTUAL_COL_NOT_ALLOWED; LOG_WARN("column is not updatable", K(ret), K(col_ref)); } else { ObColumnRefRawExpr *new_col_ref = static_cast(expr); const TableItem *new_table_item = table_item.view_base_item_; if (new_col_ref->get_table_id() != new_table_item->table_id_) { ret = is_mysql_mode() ? OB_ERR_VIEW_MULTIUPDATE : OB_ERR_O_VIEW_MULTIUPDATE; LOG_WARN("Can not modify more than one base table through a join view", K(ret), K(col_ref)); } else { if (new_table_item->is_basic_table() || new_table_item->is_link_table()) { // is base table, do nothing } else if (new_table_item->is_generated_table() || new_table_item->is_temp_table()) { const bool inner_log_error = false; if (OB_FAIL(check_same_base_table(*new_table_item, *new_col_ref, inner_log_error))) { LOG_WARN("check update columns is same base table failed", K(ret)); } } else if (new_table_item->is_fake_cte_table()) { ret = OB_ERR_ILLEGAL_VIEW_UPDATE; LOG_WARN("illegal view update", K(ret)); } else { ret = OB_ERR_UNEXPECTED; LOG_WARN("column is not updatable", K(ret), K(col_ref)); } } } if (log_error) { if (OB_ERR_NONUPDATEABLE_COLUMN == ret) { LOG_USER_ERROR(OB_ERR_NONUPDATEABLE_COLUMN, col_ref.get_column_name().length(), col_ref.get_column_name().ptr()); } else if (OB_ERR_VIEW_MULTIUPDATE == ret) { LOG_USER_ERROR(OB_ERR_VIEW_MULTIUPDATE, table_item.database_name_.length(), table_item.database_name_.ptr(), table_item.table_name_.length(), table_item.table_name_.ptr()); } } } return ret; } int ObDelUpdResolver::add_all_column_to_updatable_view(ObDMLStmt &stmt, const TableItem &table_item, const bool &has_need_fired_tg_on_view) { int ret = OB_SUCCESS; OZ(check_stack_overflow()); if (OB_FAIL(ret)) { } else if (OB_ISNULL(params_.session_info_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("params_.session_info_ is null", K(ret)); } else if (!table_item.is_basic_table() && !table_item.is_link_table() && !table_item.is_generated_table() && !table_item.is_temp_table()) { ret = OB_INVALID_ARGUMENT; LOG_WARN("unexpected table item", K(ret), K(table_item)); } else { if ((table_item.is_generated_table() || table_item.is_temp_table()) && !has_need_fired_tg_on_view) { if (OB_ISNULL(table_item.ref_query_) || OB_ISNULL(table_item.view_base_item_)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("generate table bug reference query is NULL or base table item is NULL", K(ret), K(table_item)); } else if (OB_FAIL(SMART_CALL(add_all_column_to_updatable_view( *table_item.ref_query_, *table_item.view_base_item_, has_need_fired_tg_on_view)))) { LOG_WARN("add all column for updatable view failed", K(ret), K(table_item)); } } } if (OB_SUCC(ret)) { auto add_select_item_func = [&](ObSelectStmt &select_stmt, ColumnItem &col) { int ret = OB_SUCCESS; bool found_in_select = false; FOREACH_CNT_X(si, select_stmt.get_select_items(), !found_in_select) { if (si->expr_ == col.expr_) { found_in_select = true; } } if (!found_in_select) { SelectItem select_item; select_item.implicit_filled_ = true; select_item.expr_ = col.expr_; // concat column's table name and column name as select item's alias name const int32_t size = col.expr_->get_table_name().length() + 1 // "." + col.expr_->get_column_name().length(); char *buf = static_cast(allocator_->alloc(size)); if (OB_ISNULL(buf)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("allocate memory failed", K(ret), K(size)); } else { char *p = buf; MEMCPY(p, col.expr_->get_table_name().ptr(), col.expr_->get_table_name().length()); p += col.expr_->get_table_name().length(); *p = '.'; p++; MEMCPY(p, col.expr_->get_column_name().ptr(), col.expr_->get_column_name().length()); select_item.alias_name_.assign_ptr(buf, size); } if (OB_SUCC(ret)) { if (OB_FAIL(select_stmt.add_select_item(select_item))) { LOG_WARN("add select item failed", K(ret)); } } } return ret; }; ColumnItem *col_item = NULL; if (table_item.is_basic_table() || table_item.is_link_table()) { const ObTableSchema *table_schema = NULL; if (OB_FAIL(schema_checker_->get_table_schema(params_.session_info_->get_effective_tenant_id(), table_item.ref_id_, table_schema, table_item.is_link_table()))) { LOG_WARN("get table schema failed", K(ret)); } else if (OB_ISNULL(table_schema)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("NULL table schema", K(ret)); } else { for (auto iter = table_schema->column_begin(); OB_SUCC(ret) && iter != table_schema->column_end(); iter++) { col_item = stmt.get_column_item_by_id(table_item.table_id_, (*iter)->get_column_id()); if (NULL == col_item) { // column not found if (OB_FAIL(resolve_basic_column_item(table_item, (*iter)->get_column_name(), true, col_item, &stmt))) { LOG_WARN("resolve basic column item failed", K(ret), K(table_item), K(*iter)); } } if (OB_SUCC(ret)) { if (stmt::T_SELECT == stmt.get_stmt_type() && !has_need_fired_tg_on_view) { // 包含instead-of-trigger的语句这里不需要加入到select_items_里面,因为此前的 // select_items_已恰好足够使用 if (OB_FAIL(add_select_item_func(static_cast(stmt), *col_item))) { LOG_WARN("add column item to select item failed", K(ret)); } } } } } } else if (table_item.is_generated_table() || table_item.is_temp_table()) { ObSelectStmt *ref_stmt = table_item.ref_query_; for (int64_t i = 0; OB_SUCC(ret) && i < ref_stmt->get_select_item_size(); i++) { const uint64_t column_id = OB_APP_MIN_COLUMN_ID + i; ObString col_name; // not used col_item = NULL; if (OB_FAIL(resolve_generated_table_column_item( table_item, col_name, col_item, &stmt, column_id))) { LOG_WARN("resolve generate table item failed", K(ret)); } else { if (stmt::T_SELECT == stmt.get_stmt_type()) { if (OB_FAIL(add_select_item_func(static_cast(stmt), *col_item))) { LOG_WARN("add column item to select item failed", K(ret)); } } } } } } return ret; } int ObDelUpdResolver::resolve_error_logging(const ParseNode *node) { int ret = OB_SUCCESS; const ParseNode *table_name_node = NULL; const ParseNode *reject_node = NULL; const ObTableSchema *table_schema = NULL; ObDelUpdStmt *del_upd_stmt = get_del_upd_stmt(); CK (OB_NOT_NULL(del_upd_stmt)); CK (OB_NOT_NULL(schema_checker_)); CK (OB_NOT_NULL(session_info_)); ObString database_name = session_info_->get_database_name(); uint64_t tenant_id = session_info_->get_effective_tenant_id(); if (ObItemType::T_ERR_LOG_CALUSE != node->type_) { ret = OB_ERR_UNEXPECTED; LOG_WARN("node type is not ObItemType::T_ERR_LOG_CALUSE"); } else { del_upd_stmt->set_is_error_logging(true); if (OB_ISNULL(table_name_node = node->children_[0])) { // 不指定table name ObString default_table_name; ObString dst_table_name; char buf[OB_MAX_USER_TABLE_NAME_LENGTH_ORACLE]; // 128 Bytes default_table_name.assign_buffer(buf, OB_MAX_USER_TABLE_NAME_LENGTH_ORACLE); const char *default_table_name_prefix = "ERR$_"; int write_length = default_table_name.write(default_table_name_prefix, strlen(default_table_name_prefix)); write_length += default_table_name.write(del_upd_stmt->get_table_item(0)->get_table_name().ptr(), del_upd_stmt->get_table_item(0)->get_table_name().length()); if (write_length != del_upd_stmt->get_table_item(0)->get_table_name().length() + strlen(default_table_name_prefix)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("write default table_name fail", K(write_length), K(del_upd_stmt->get_table_item(0)->get_table_name().length() + strlen(default_table_name_prefix))); } else if (OB_FAIL(schema_checker_->get_table_schema(tenant_id, database_name, default_table_name, false, table_schema))) { LOG_WARN("fail to get_table_schema ", K(ret)); } else if (OB_FAIL(OB_ISNULL(table_schema))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("table schema is null"); } else if (OB_FAIL(ob_write_string(*allocator_, default_table_name, dst_table_name))) { LOG_WARN("fail to write table to string", K(ret), K(default_table_name)); } else if (OB_FAIL(check_err_log_table(dst_table_name, database_name))) { LOG_WARN("check_err_log_table fails", K(ret), K(default_table_name), K(database_name)); } LOG_WARN("after append default table name", K(default_table_name)); } else if (ObItemType::T_INTO_ERR_LOG_TABLE != table_name_node->type_) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected error"); } else { // resolver error logging table 指定table if (OB_FAIL(resolve_err_log_table(table_name_node))) { LOG_WARN("fail execute resolve_err_log_table", K(ret)); } } // resolver error logging tag (simple_expr) // TODO @kaizhan.dkz暂时先不开发 // resolver reject limit if (OB_FAIL(ret)) { } else if (OB_ISNULL(reject_node = node->children_[2])) { // 不指定reject limit del_upd_stmt->set_err_log_reject_limit(0); } else if (ObItemType::T_ERR_LOG_LIMIT != reject_node->type_) { // error type ret = OB_ERR_UNEXPECTED; LOG_WARN("error type of reject_limit node", K(reject_node->type_)); } else if (OB_FAIL(resolve_err_log_reject(reject_node))) { LOG_WARN("resolve_err_log_reject failed", K(ret)); } } return ret; } int ObDelUpdResolver::check_err_log_table(ObString &table_name, ObString &database_name) { int ret = OB_SUCCESS; const ObTableSchema *table_schema = NULL; uint64_t tenant_id = session_info_->get_effective_tenant_id(); ObDelUpdStmt *del_upd_stmt = get_del_upd_stmt(); if (OB_ISNULL(del_upd_stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (OB_FAIL(schema_checker_->get_table_schema(tenant_id, database_name, table_name, false, table_schema))) { LOG_WARN("fail to get table schema", K(ret)); } else if (OB_ISNULL(table_schema)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("table_schema is null", K(ret)); } else { del_upd_stmt->set_err_log_table_id(table_schema->get_table_id()); del_upd_stmt->set_err_log_table_name(table_name); del_upd_stmt->set_err_log_database_name(database_name); ObColumnIterByPrevNextID iter(*table_schema); const ObColumnSchemaV2 *column_schema = NULL; int index = 0; while (OB_SUCC(ret) && OB_SUCC(iter.next(column_schema))) { if (OB_ISNULL(column_schema)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("The column is null", K(ret)); } else if (column_schema->is_shadow_column()) { // don't care shadow columns for error logging table continue; } else if (column_schema->is_invisible_column()) { // don't show invisible columns for error logging table continue; } else if (column_schema->is_hidden()) { // jump hidden column, for error logging table continue; } else if (index < 5) { // check table Meet the requirements of the error logging table // here check first 5 columns should be ORA_ERR_NUMBER$, ORA_ERR_MESG$ etc... if (0 != column_schema->get_column_name_str().case_compare(err_log_default_columns_[index]) ) { ret = OB_ERR_MISS_ERR_LOG_MANDATORY_COLUMN; LOG_USER_ERROR(OB_ERR_MISS_ERR_LOG_MANDATORY_COLUMN, static_cast(strlen(err_log_default_columns_[index])), err_log_default_columns_[index]); } else { // TODO oracle默认的5列类型不能为LONG 由于暂时不支持LONG类型,所以暂时不做检查 // 暂时不实现 ORA_ERR_TAG$ 列 } index++; } else { ObSEArray table_info; if (OB_FAIL(del_upd_stmt->get_dml_table_infos(table_info))) { LOG_WARN("failed to get dml table info", K(ret)); } else if (OB_UNLIKELY(1 != table_info.count())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected error", K(table_info.count()), K(ret)); } else if (OB_ISNULL(table_info.at(0))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else { for (int64_t i = 0; OB_SUCC(ret) && i < table_info.at(0)->column_exprs_.count(); i++) { ObColumnRefRawExpr *column_expr = NULL; ColumnItem column_item; if (OB_ISNULL(column_expr = table_info.at(0)->column_exprs_.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (0 != column_expr->get_column_name().case_compare(column_schema->get_column_name_str())) { continue; } else if (OB_FAIL(check_err_log_support_type(column_expr->get_data_type()))) { LOG_USER_ERROR(OB_NOT_SUPPORTED, "type for error logging"); LOG_WARN("column type is not supported for error_logging", K(column_expr->get_data_type())); } else if (OB_FAIL(del_upd_stmt->get_error_log_info().error_log_exprs_.push_back(column_expr))) { LOG_WARN("failed to push back column expr", K(ret)); } else { /*do nothing*/ } } } } } if (OB_ITER_END == ret) { ret = OB_SUCCESS; } } return ret; } int ObDelUpdResolver::check_err_log_support_type(ObObjType column_type) { int ret = OB_SUCCESS; ObObjOType column_o_type = ob_obj_type_to_oracle_type(column_type); switch (column_o_type) { case ObONotSupport: case ObONullType: case ObOLobType: case ObOExtendType: case ObOUnknownType: case ObOURowIDType: case ObOLobLocatorType: case ObOUDTSqlType: case ObOMaxType: ret = OB_NOT_SUPPORTED; break; default: break; } return ret; } // user specified error_logging table name int ObDelUpdResolver::resolve_err_log_table(const ParseNode *node) { int ret = OB_SUCCESS; ObString table_name; ObString database_name; uint64_t database_id = OB_INVALID_ID; uint64_t dblink_id = OB_INVALID_ID; ObString synonym_name; ObString dblink_name; ObString synonym_db_name; bool is_db_explicit; const ParseNode *relation_factor_node = NULL; bool use_sys_tenant = false; uint64_t table_id = OB_INVALID_ID; ObDelUpdStmt *del_upd_stmt = get_del_upd_stmt(); bool is_reverse_link = false; // no use ObArray ref_obj_ids; CK (OB_NOT_NULL(del_upd_stmt)); if (OB_ISNULL(relation_factor_node = node->children_[0])) { ret = OB_ERR_UNEXPECTED; LOG_WARN("node should not be null", K(ret)); } else if (T_RELATION_FACTOR != relation_factor_node->type_) { ret = OB_ERR_UNEXPECTED; LOG_WARN("relation_factor_node type should be T_RELATION_FACTOR", K(relation_factor_node->type_)); } else if (OB_FAIL(resolve_table_relation_factor_wrapper(relation_factor_node, dblink_id, database_id, table_name, synonym_name, synonym_db_name, database_name, dblink_name, is_db_explicit, use_sys_tenant, is_reverse_link, ref_obj_ids))) { if (OB_TABLE_NOT_EXIST == ret || OB_ERR_BAD_DATABASE == ret) { if (is_information_schema_database_id(database_id)) { ret = OB_ERR_UNKNOWN_TABLE; LOG_USER_ERROR(OB_ERR_UNKNOWN_TABLE, table_name.length(), table_name.ptr(), database_name.length(), database_name.ptr()); } else { ret = OB_TABLE_NOT_EXIST; LOG_USER_ERROR(OB_TABLE_NOT_EXIST, to_cstring(database_name), to_cstring(table_name)); } } else { LOG_WARN("fail to resolve table name", K(ret)); } } else if (OB_FAIL(check_err_log_table(table_name, database_name))) { LOG_WARN("check error logging table is not meetting requirement", K(ret), K(table_name), K(database_name)); } LOG_DEBUG("after resolver table_name", K(table_name), K(database_id), K(database_name), K(is_db_explicit), K(use_sys_tenant)); return ret; } int ObDelUpdResolver::resolve_err_log_reject(const ParseNode *node) { int ret = OB_SUCCESS; ObDelUpdStmt *del_upd_stmt = get_del_upd_stmt(); const ParseNode *limit_or_unlimited_node = NULL; CK (OB_NOT_NULL(del_upd_stmt)); if (OB_ISNULL(limit_or_unlimited_node = node->children_[0])) { ret = OB_ERR_UNEXPECTED; LOG_WARN("node is null", K(ret)); } else if (T_SIZE_UNLIMITED == limit_or_unlimited_node->type_) { // -1 is special for reject limit, -1 sysmbol unlimited del_upd_stmt->set_err_log_reject_limit(-1); } else { if (limit_or_unlimited_node->value_ < 0) { ret = OB_ERR_UNEXPECTED; LOG_WARN("reject limit should >= 0", K(ret)); } else { del_upd_stmt->set_err_log_reject_limit(limit_or_unlimited_node->value_); } } return ret; } int ObDelUpdResolver::resolve_returning(const ParseNode *parse_tree) { int ret = OB_SUCCESS; if (OB_NOT_NULL(parse_tree)) { ObDelUpdStmt *del_up_stmt = get_del_upd_stmt(); ObItemType item_type; int64_t aggr_cnt = 0; ObSEArray dml_table_infos; CK (OB_NOT_NULL(del_up_stmt)); CK (OB_LIKELY(T_RETURNING == parse_tree->type_)); CK (OB_LIKELY(2 == parse_tree->num_child_)); CK (OB_NOT_NULL(parse_tree->children_[0])); CK (OB_LIKELY(T_PROJECT_LIST == parse_tree->children_[0]->type_)); CK (OB_ISNULL(parse_tree->children_[1]) || OB_LIKELY(T_INTO_VARIABLES == parse_tree->children_[1]->type_)); if (OB_SUCC(ret)) { current_scope_ = T_FIELD_LIST_SCOPE; expr_resv_ctx_.set_new_scope(); const ParseNode *returning_exprs = parse_tree->children_[0]; const ParseNode *returning_intos = parse_tree->children_[1]; uint64_t base_table_id = OB_INVALID_ID; if (OB_FAIL(del_up_stmt->get_dml_table_infos(dml_table_infos))) { LOG_WARN("failed to get dml table infos", K(ret)); } else if (OB_UNLIKELY(dml_table_infos.count() != 1) || OB_ISNULL(dml_table_infos.at(0))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected dml table infos", K(ret), K(dml_table_infos)); } else if (OB_UNLIKELY(common::OB_INVALID_ID == (base_table_id = dml_table_infos.at(0)->ref_table_id_))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("base_table_id is invalid", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && i < returning_exprs->num_child_; i++) { ObRawExpr *expr = NULL; CK (OB_NOT_NULL(returning_exprs->children_[i])); CK (OB_NOT_NULL(returning_exprs->children_[i]->children_[0])); OZ (resolve_sql_expr(*(returning_exprs->children_[i]->children_[0]), expr)); CK (OB_NOT_NULL(expr)); OZ (expr->formalize(session_info_)); // only in static_typing_engine // create table t1(c1 int primary key, c2 clob, c3 blob); // insert into t1 values(1, 'ddd', empty_blob()) returning c1, concat(c2, '1'), c2, c3; // for this insert sql, concat(c2, '1') is a fake lob_locator, c2, c3 is a useful lob_locator if (OB_SUCC(ret) && expr->has_flag(IS_COLUMN) && expr->is_column_ref_expr() && (StmtType::T_INSERT == del_up_stmt->get_stmt_type() || StmtType::T_UPDATE == del_up_stmt->get_stmt_type())) { ObColumnRefRawExpr *ref_expr = static_cast(expr); if (ObObjType::ObLobType == ref_expr->get_data_type() && ref_expr->get_table_id() == base_table_id) { ObSysFunRawExpr *lob_expr = NULL; if (OB_FAIL(build_returning_lob_expr(ref_expr, lob_expr))) { LOG_WARN("fail to build returning lob expr", K(ret)); } else if (OB_ISNULL(lob_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("lob_expr is null", K(ret)); } else { expr = lob_expr; LOG_DEBUG("build returning lob expr", KPC(expr), KPC(ref_expr), KPC(lob_expr)); } } } if (OB_SUCC(ret) && (ob_is_user_defined_sql_type(expr->get_data_type()) || ob_is_xml_pl_type(expr->get_data_type(), expr->get_udt_id()))) { // ORA-22816 returning clause is currently not object type columns // but this is success in ORA: execute immediate 'insert into t1 values(4,5) returning udt1(c1, c2) into :a' using out a; // xmltype is not allowed: execute immediate 'insert into t2 values(:b) returning xmltype(c1) into :a' using b, out a; ret = OB_ERR_RETURNING_CLAUSE; LOG_WARN("RETURNING clause is currently not supported for object type", K(ret), K(expr->get_data_type())); } if (OB_SUCC(ret)) { ObString expr_name; expr_name.assign_ptr(returning_exprs->children_[i]->str_value_, static_cast(returning_exprs->children_[i]->str_len_)); del_up_stmt->add_value_to_returning_exprs(expr); del_up_stmt->add_value_to_returning_strs(expr_name); item_type = expr->get_expr_type(); if (IS_AGGR_FUN(item_type)) { aggr_cnt++; } } } ObArray user_vars; if (OB_SUCC(ret) && OB_NOT_NULL(returning_intos)) { OZ (resolve_into_variables(returning_intos, user_vars, del_up_stmt->get_returning_into_exprs(), NULL /* select_stmt */)); } if (OB_SUCC(ret)) { if (OB_FAIL(check_returning_validity())) { LOG_WARN("check returning validity failed", K(ret)); } } expr_resv_ctx_.revert_scope(); } } return ret; } int ObDelUpdResolver::check_returning_validity() { int ret = OB_SUCCESS; ObDelUpdStmt *del_upd_stmt = NULL; bool has_single_set_expr = false; bool has_simple_expr = false; bool has_sequence = false; if (OB_ISNULL(del_upd_stmt = get_del_upd_stmt()) || OB_UNLIKELY(!get_stmt()->is_insert_stmt() && !get_stmt()->is_update_stmt() && !get_stmt()->is_delete_stmt())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid stmt", K(ret)); } else { for (int64_t i = 0; OB_SUCC(ret) && i < del_upd_stmt->get_returning_exprs().count(); ++i) { bool cnt_simple_expr = false; bool cnt_single_set_expr = false; if (OB_FAIL(check_returinng_expr(del_upd_stmt->get_returning_exprs().at(i), cnt_single_set_expr, cnt_simple_expr, has_sequence))) { LOG_WARN("failed to check returning expr", K(ret)); } else if (has_sequence) { ret = OB_ERR_SEQ_NOT_ALLOWED_HERE; LOG_WARN("sequence number not allowed here in the returning clause", K(ret)); } else { has_single_set_expr = (cnt_single_set_expr || has_single_set_expr); has_simple_expr = (cnt_simple_expr || has_simple_expr); if (has_simple_expr && has_single_set_expr) { ret = OB_ERR_GROUP_FUNC_NOT_ALLOWED; LOG_WARN("cannot combine simple expressions and single-set aggregate expressions", K(ret)); } } } for (int64_t i = 0; OB_SUCC(ret) && i < del_upd_stmt->get_returning_aggr_item_size(); ++i) { ObAggFunRawExpr *aggr = NULL; if (OB_ISNULL(aggr = del_upd_stmt->get_returning_aggr_items().at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("returing aggregate expr is null", K(ret)); } else if (aggr->is_param_distinct()) { ret = OB_ERR_GROUP_FUNC_NOT_ALLOWED; LOG_WARN("Single-set aggregate functions cannot include the DISTINCT keyword", K(ret)); } } } return ret; } int ObDelUpdResolver::check_returinng_expr(ObRawExpr *expr, bool &has_single_set_expr, bool &has_simple_expr, bool &has_sequenece) { int ret = OB_SUCCESS; if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("expr is null", K(ret)); } else if (expr->is_aggr_expr()) { has_single_set_expr = true; } else if (expr->is_column_ref_expr()) { has_simple_expr = true; } else if (expr->get_expr_type() == T_FUN_SYS_SEQ_NEXTVAL) { has_sequenece = true; } for (int64_t i = 0; OB_SUCC(ret) && i < expr->get_param_count(); ++i) { bool cnt_simple_expr = false; if (OB_FAIL(check_returinng_expr(expr->get_param_expr(i), has_single_set_expr, cnt_simple_expr, has_sequenece))) { LOG_WARN("failed to check returning expr", K(ret)); } else if (!expr->is_aggr_expr() && cnt_simple_expr) { has_simple_expr = true; } } return ret; } int ObDelUpdResolver::gen_rowid_expr_for_returning(ObSysFunRawExpr *&rowid_expr) { int ret = OB_SUCCESS; const ObTableSchema *table_schema = NULL; ObDelUpdStmt *del_upd_stmt = get_del_upd_stmt(); ObSEArray rowkey_exprs; ObSEArray tables_info; if (OB_ISNULL(allocator_) || OB_ISNULL(session_info_) || OB_ISNULL(schema_checker_) || OB_ISNULL(del_upd_stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(allocator_), K(session_info_), K(del_upd_stmt), K(ret)); } else if (OB_FAIL(del_upd_stmt->get_dml_table_infos(tables_info))) { LOG_WARN("failed to get dml table info", K(ret)); } else if (OB_UNLIKELY(1 != tables_info.count())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected error", K(tables_info.count()), K(ret)); } else if (OB_ISNULL(tables_info.at(0))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (OB_FAIL(schema_checker_->get_table_schema(session_info_->get_effective_tenant_id(), tables_info.at(0)->ref_table_id_, table_schema))) { LOG_WARN("get table schema failed", K(ret)); } else if (OB_ISNULL(table_schema)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (OB_FAIL(get_exprs_serialize_to_rowid(del_upd_stmt, table_schema, tables_info.at(0)->column_exprs_, rowkey_exprs))) { LOG_WARN("generated rowkey exprs failed", K(ret)); } else if (OB_FAIL(ObRawExprUtils::build_rowid_expr(del_upd_stmt, *params_.expr_factory_, *allocator_, *(session_info_), *table_schema, tables_info.at(0)->table_id_, rowkey_exprs, rowid_expr))) { LOG_WARN("build rowid_expr failed", K(ret)); } else { /*do nothing*/ } return ret; } int ObDelUpdResolver::get_exprs_serialize_to_rowid(ObDMLStmt *stmt, const ObTableSchema *&tbl_schema, const ObIArray &all_cols, ObIArray &rowkey_cols) { int ret = OB_SUCCESS; rowkey_cols.reuse(); if (OB_ISNULL(stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid argument", K(ret)); } else { ObSEArray col_ids; int64_t rowkey_cnt; OZ(tbl_schema->get_column_ids_serialize_to_rowid(col_ids, rowkey_cnt)); CK(col_ids.count() > 0); for (int64_t i = 0; i < all_cols.count(); ++i) { int64_t idx; ObColumnRefRawExpr* base_col_expr = all_cols.at(i); if (OB_FAIL(ObTransformUtils::get_base_column(stmt, base_col_expr))) { LOG_WARN("get base column failed", K(ret)); } else if (OB_ISNULL(base_col_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("base_col_expr is null", K(ret)); } else if (has_exist_in_array(col_ids, base_col_expr->get_column_id(), &idx)) { if (OB_FAIL(rowkey_cols.push_back((ObRawExpr*)all_cols.at(i)))) { LOG_WARN("rowkey cols push back failed", K(ret), K(i), K(all_cols)); } } } } return ret; } int ObDelUpdResolver::build_returning_lob_expr(ObColumnRefRawExpr *ref_expr, ObSysFunRawExpr *&expr) { int ret = OB_SUCCESS; ObConstRawExpr *table_id_expr = NULL; ObConstRawExpr *column_id_expr = NULL; ObSysFunRawExpr *rowid_expr = NULL; CK(OB_NOT_NULL(session_info_)); if (OB_FAIL(ret)) { } else if (OB_FAIL(ObRawExprUtils::build_returning_lob_expr(*params_.expr_factory_, *session_info_, ref_expr, expr))) { LOG_WARN("fail to build_returning_lob_expr", K(ret), KPC(ref_expr)); } else if (OB_FAIL(gen_rowid_expr_for_returning(rowid_expr))) { LOG_WARN("fail to gen rowid expr for returning", K(ret)); } else if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("lob expr is null", K(ret)); } else if (OB_FAIL(ObRawExprUtils::build_const_int_expr(*params_.expr_factory_, ObUInt64Type, ref_expr->get_table_id(), table_id_expr))) { LOG_WARN("fail to build const int expr", K(ret)); } else if (OB_FAIL(ObRawExprUtils::build_const_int_expr(*params_.expr_factory_, ObUInt64Type, ref_expr->get_column_id(), column_id_expr))) { LOG_WARN("fail to build const int expr", K(ret)); } else if (OB_FAIL(expr->add_param_expr(table_id_expr))) { LOG_WARN("fail to add param expr", K(ret)); } else if (OB_FAIL(expr->add_param_expr(column_id_expr))) { LOG_WARN("fail to add param expr", K(ret)); } else if (OB_FAIL(expr->add_param_expr(rowid_expr))) { LOG_WARN("fail to add param expr", K(ret)); } else if (OB_FAIL(expr->formalize(session_info_))) { LOG_WARN("formalize fail", K(expr->get_param_count())); } return ret; } bool ObDelUpdResolver::need_all_columns(const ObTableSchema &table_schema, const int64_t binlog_row_image) { // Returns True although binlog_row_image is MINIMAL temporarily, // because optimizer may need full columns currently. // This can be optimized later. return (table_schema.is_heap_table() || table_schema.get_foreign_key_infos().count() > 0 || table_schema.get_trigger_list().count() > 0 || table_schema.has_check_constraint() || table_schema.has_generated_and_partkey_column() || binlog_row_image == ObBinlogRowImage::FULL || binlog_row_image == ObBinlogRowImage::MINIMAL); } int ObDelUpdResolver::add_all_columns_to_stmt(const TableItem &table_item, ObIArray &column_exprs) { int ret = OB_SUCCESS; const ObTableSchema *table_schema = NULL; const TableItem& base_table_item = table_item.get_base_table_item(); if (OB_ISNULL(params_.session_info_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("params_.session_info_ is null", K(ret)); } else if (OB_FAIL(schema_checker_->get_table_schema(params_.session_info_->get_effective_tenant_id(), base_table_item.ref_id_, table_schema, base_table_item.is_link_table()))) { LOG_WARN("not find table schema", K(ret), K(base_table_item)); } else if (OB_ISNULL(table_schema)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(table_schema), K(ret)); } else { ObTableSchema::const_column_iterator iter = table_schema->column_begin(); ObTableSchema::const_column_iterator end = table_schema->column_end(); for (; OB_SUCC(ret) && iter != end; ++iter) { const ObColumnSchemaV2 *column = *iter; if (OB_ISNULL(column)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid column schema", K(column)); } else if (OB_FAIL(add_column_to_stmt(table_item, *column, column_exprs))) { LOG_WARN("add column item to stmt failed", K(ret)); } } //end for } return ret; } int ObDelUpdResolver::add_all_lob_columns_to_stmt(const TableItem &table_item, ObIArray &column_exprs) { int ret = OB_SUCCESS; const ObTableSchema *table_schema = NULL; const TableItem& base_table_item = table_item.get_base_table_item(); if (OB_ISNULL(params_.session_info_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("params_.session_info_ is null", K(ret)); } else if (OB_FAIL(schema_checker_->get_table_schema(params_.session_info_->get_effective_tenant_id(), base_table_item.ref_id_, table_schema, base_table_item.is_link_table()))) { LOG_WARN("not find table schema", K(ret), K(base_table_item)); } else if (OB_ISNULL(table_schema)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(table_schema), K(ret)); } else { ObTableSchema::const_column_iterator iter = table_schema->column_begin(); ObTableSchema::const_column_iterator end = table_schema->column_end(); for (; OB_SUCC(ret) && iter != end; ++iter) { const ObColumnSchemaV2 *column = *iter; if (OB_ISNULL(column)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid column schema", K(column)); } else if (!column->get_meta_type().is_lob_storage()) { // do nothing } else if (OB_FAIL(add_column_to_stmt(table_item, *column, column_exprs))) { LOG_WARN("add column item to stmt failed", K(ret)); } } //end for } return ret; } int ObDelUpdResolver::add_all_columns_to_stmt_for_trigger(const TableItem &table_item, ObIArray &column_exprs) { int ret = OB_SUCCESS; ObSelectStmt *ref_stmt = table_item.ref_query_; if (OB_ISNULL(ref_stmt) || OB_ISNULL(get_stmt())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else { for (int64_t i = 0; OB_SUCC(ret) && i < ref_stmt->get_select_item_size(); i++) { ObColumnRefRawExpr *col_expr = get_stmt()->get_column_expr_by_id(table_item.table_id_, i + OB_APP_MIN_COLUMN_ID); if (OB_ISNULL(col_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (OB_FAIL(add_var_to_array_no_dup(column_exprs, col_expr))) { LOG_WARN("failed to append array", K(ret)); } else { /*do nothing*/ } } } return ret; } int ObDelUpdResolver::add_all_rowkey_columns_to_stmt(const TableItem &table_item, ObIArray &column_exprs) { int ret = OB_SUCCESS; const ObTableSchema *table_schema = NULL; const ObColumnSchemaV2 *column_schema = NULL; uint64_t rowkey_column_id = 0; const TableItem &base_table_item = table_item.get_base_table_item(); ObDelUpdStmt *stmt = get_del_upd_stmt(); if (OB_ISNULL(stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(stmt)); } else if (stmt->has_instead_of_trigger()) { // do nothing, instead of trigger doesn't have rowkey } else if (OB_ISNULL(params_.session_info_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("params_.session_info_ is null", K(ret)); } else if (OB_FAIL(schema_checker_->get_table_schema(params_.session_info_->get_effective_tenant_id(), base_table_item.ref_id_, table_schema, base_table_item.is_link_table()))) { LOG_WARN("table schema not found", K(base_table_item)); } else if (NULL == table_schema) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get invalid table schema", K(table_item)); } else { const ObRowkeyInfo &rowkey_info = table_schema->get_rowkey_info(); for (int64_t i = 0; OB_SUCC(ret) && i < rowkey_info.get_size(); ++i) { if (OB_FAIL(rowkey_info.get_column_id(i, rowkey_column_id))) { LOG_WARN("get rowkey info failed", K(ret), K(i), K(rowkey_info)); } else if (OB_FAIL(get_column_schema(base_table_item.ref_id_, rowkey_column_id, column_schema, true, base_table_item.is_link_table()))) { LOG_WARN("get column schema failed", K(rowkey_column_id)); } else if (OB_FAIL(add_column_to_stmt(table_item, *column_schema, column_exprs))) { LOG_WARN("add column to stmt failed", K(ret), K(table_item)); } } } return ret; } //for ObDelUpdStmt // add column's related columns in index to stmt // if column_id is OB_INVALID_ID, all indexes' columns would be added to stmt // @param[in] table_id table id // @param[in] column_id column id int ObDelUpdResolver::add_index_related_columns_to_stmt(const TableItem &table_item, const uint64_t column_id, ObIArray &column_items) { int ret = OB_SUCCESS; ColumnItem *col_item = NULL; ObDelUpdStmt *del_upd_stmt = dynamic_cast(get_stmt()); if (OB_ISNULL(del_upd_stmt) || OB_ISNULL(schema_checker_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("This function only for class inherited ObDelUpdStmt", K(del_upd_stmt), K_(schema_checker)); } else if (OB_ISNULL(col_item = del_upd_stmt->get_column_item_by_id(table_item.table_id_, column_id))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("column item not found", K(ret), K(table_item), K(column_id)); } else if (OB_ISNULL(params_.session_info_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("params_.session_info_ is null", K(ret)); } else { uint64_t base_table_id = table_item.get_base_table_item().ref_id_; uint64_t base_column_id = (table_item.is_generated_table() || table_item.is_temp_table()) ? col_item->base_cid_ : col_item->column_id_; const ObTableSchema *table_schema = NULL; const ObTableSchema *index_schema = NULL; const ObColumnSchemaV2 *column_schema = NULL; uint64_t tenant_id = params_.session_info_->get_effective_tenant_id(); if (OB_FAIL(schema_checker_->get_table_schema(tenant_id, base_table_id, table_schema, table_item.get_base_table_item().is_link_table()))) { LOG_WARN("invalid table id", K(base_table_id)); } else if (NULL == (column_schema = table_schema->get_column_schema(base_column_id))) { LOG_WARN("get column schema failed", K(ret), K(base_table_id), K(base_column_id)); } else if (column_schema->is_rowkey_column()) { //if the column id is rowkey, wo need to add all columns in table schema to columns if (OB_FAIL(add_all_columns_to_stmt(table_item, column_items))) { LOG_WARN("add all columns to stmt failed", K(ret)); } else { LOG_DEBUG("add all column to stmt due to the update column is primary key"); } } else { uint64_t index_tids[OB_MAX_INDEX_PER_TABLE]; int64_t index_count = OB_MAX_INDEX_PER_TABLE; // get all the indexes if (OB_FAIL(schema_checker_->get_can_write_index_array(tenant_id, base_table_id, index_tids, index_count))) { LOG_WARN("fail to get index", K(ret)); } else { for (int64_t i = 0; OB_SUCC(ret) && i < index_count; ++i) { uint64_t index_id = index_tids[i]; // get index schema if (OB_FAIL(schema_checker_->get_table_schema(tenant_id, index_id, index_schema))) { LOG_WARN("get index schema failed", K(index_id)); } else { //only add the column items in the index schema which contain the column_id if (NULL != (column_schema = index_schema->get_column_schema(base_column_id))) { if (OB_FAIL(add_all_index_rowkey_to_stmt(table_item, index_schema, column_items))) { LOG_WARN("add all index rowkey to stmt failed", K(ret)); } } } } } } } return ret; } int ObDelUpdResolver::add_all_index_rowkey_to_stmt(const TableItem &table_item, common::ObIArray &column_exprs) { int ret = OB_SUCCESS; const ObTableSchema *index_schema = NULL; uint64_t idx_tids[OB_MAX_INDEX_PER_TABLE]; int64_t idx_count = OB_MAX_INDEX_PER_TABLE; if (OB_ISNULL(schema_checker_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (OB_ISNULL(params_.session_info_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("params_.session_info_ is null", K(ret)); } else if (OB_FAIL(schema_checker_->get_can_write_index_array( params_.session_info_->get_effective_tenant_id(), table_item.get_base_table_item().ref_id_, idx_tids, idx_count))) { LOG_WARN("failed to get all index", K(ret)); } else { // Secondly, for each index, all all its rowkey for (int64_t i = 0; OB_SUCC(ret) && i < idx_count; ++i) { if (OB_FAIL(schema_checker_->get_table_schema(params_.session_info_->get_effective_tenant_id(), idx_tids[i], index_schema))) { LOG_WARN("get index schema failed", "index_id", idx_tids[i], K(ret)); } else if (OB_FAIL(add_all_index_rowkey_to_stmt(table_item, index_schema, column_exprs))) { LOG_WARN("add all index rowkey column to stmt failed", K(ret)); } } } return ret; } int ObDelUpdResolver::add_all_index_rowkey_to_stmt(const TableItem &table_item, const ObTableSchema *index_schema, ObIArray &column_items) { int ret = OB_SUCCESS; ObDMLStmt *stmt = get_stmt(); uint64_t rowkey_column_id = OB_INVALID_ID; const ObColumnSchemaV2 *column_schema = NULL; if (NULL == index_schema || NULL == stmt || !index_schema->is_index_table()) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(index_schema), K(stmt)); } else { uint64_t base_table_id = table_item.get_base_table_item().ref_id_; ObTableSchema::const_column_iterator b = index_schema->column_begin(); ObTableSchema::const_column_iterator e = index_schema->column_end(); for (; OB_SUCC(ret) && b != e; ++b) { if (NULL == (*b)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("fail to to get column schema", K(*b)); } else { rowkey_column_id = (*b)->get_column_id(); if ((*b)->is_shadow_column()) { continue; } if (OB_FAIL(get_column_schema(base_table_id, rowkey_column_id, column_schema, true, table_item.get_base_table_item().is_link_table()))) { LOG_WARN("get column schema failed", K(ret), K(base_table_id), K(rowkey_column_id)); } else if (OB_ISNULL(column_schema)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("fail to get column schema", K(ret), K(base_table_id), K(rowkey_column_id)); } else if (OB_FAIL(add_column_to_stmt(table_item, *column_schema, column_items))) { LOG_WARN("add column to stmt failed", K(ret), K(table_item), K(*column_schema)); } } } } return ret; } int ObDelUpdResolver::add_all_partition_key_columns_to_stmt(const TableItem &table_item, ObIArray &column_exprs, ObDMLStmt *stmt /*= NULL*/) { int ret = OB_SUCCESS; const ObTableSchema *table_schema = NULL; const ObColumnSchemaV2 *column_schema = NULL; uint64_t rowkey_column_id = 0; uint64_t base_table_id = table_item.get_base_table_item().ref_id_; stmt = (NULL == stmt) ? get_stmt() : stmt; if (OB_ISNULL(stmt) || OB_ISNULL(schema_checker_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get stmt fail", K(ret), K(stmt), K(schema_checker_)); } else if (OB_ISNULL(params_.session_info_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("params_.session_info_ is null", K(ret)); } else if (OB_FAIL(schema_checker_->get_table_schema(params_.session_info_->get_effective_tenant_id(), base_table_id, table_schema, table_item.is_link_table()))) { LOG_WARN("table schema not found", K(base_table_id), K(table_item)); } else if (NULL == table_schema) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get invalid table schema", K(table_item)); } else if (table_schema->is_heap_table()) { const ObPartitionKeyInfo &partition_keys = table_schema->get_partition_key_info(); const ObPartitionKeyInfo &subpartition_keys = table_schema->get_subpartition_key_info(); ObSEArray column_ids; if (partition_keys.is_valid() && OB_FAIL(partition_keys.get_column_ids(column_ids))) { LOG_WARN("fail to get column ids from partition keys", K(ret)); } else if (subpartition_keys.is_valid() && OB_FAIL(subpartition_keys.get_column_ids(column_ids))) { LOG_WARN("fail to get column ids from subpartition keys", K(ret)); } else { for (int64_t i = 0; OB_SUCC(ret) && i < column_ids.count(); ++i) { uint64_t rowkey_column_id = column_ids.at(i); if (OB_FAIL(get_column_schema(base_table_id, rowkey_column_id, column_schema, true, table_item.is_link_table()))) { LOG_WARN("get column schema failed", K(base_table_id), K(rowkey_column_id)); } else if (OB_FAIL(add_column_to_stmt(table_item, *column_schema, column_exprs, stmt))) { LOG_WARN("add column to stmt failed", K(ret), K(table_item), KPC(column_schema)); } } } } return ret; } int ObDelUpdResolver::uv_check_key_preserved(const TableItem &table_item, bool &key_preserved) { int ret = OB_SUCCESS; if (table_item.is_generated_table() && table_item.get_base_table_item().is_link_table()) { // skip check link table key preserved, do not check it, remote database will report error if the actual key_preserved is false. key_preserved = true; } else if (table_item.is_generated_table() || table_item.is_temp_table()) { key_preserved = false; if (NULL == table_item.ref_query_) { ret = OB_ERR_UNEXPECTED; LOG_WARN("ref query or view base table item is NULL", K(ret)); } else { ObSEArray pk_cols; ObSEArray pk_cols_raw; bool unique = false; // rowkey already add to stmt, it is safe to add again. if (OB_FAIL(add_all_rowkey_columns_to_stmt(table_item, pk_cols))) { LOG_WARN("get all rowkey exprs failed", K(ret)); // if table is heap table, we need to add partition keys because they're no longer in rowkey } else if (OB_FAIL(add_all_partition_key_columns_to_stmt(table_item, pk_cols))) { LOG_WARN("fail to add partition keys", K(ret)); } else { FOREACH_CNT_X(e, pk_cols, OB_SUCC(ret)) { int64_t idx = (*e)->get_column_id() - OB_APP_MIN_COLUMN_ID; if (idx < 0 || idx >= table_item.ref_query_->get_select_item_size()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid select item index", K(ret), K(*e)); } else if (OB_FAIL(pk_cols_raw.push_back( table_item.ref_query_->get_select_item(idx).expr_))) { LOG_WARN("array push back failed", K(ret)); } } } if (OB_FAIL(ret)) { } else if (OB_FAIL(ObTransformUtils::check_stmt_unique(table_item.ref_query_, session_info_, schema_checker_, pk_cols_raw, true /* strict */, unique))) { LOG_WARN("check stmt unique failed", K(ret)); } else { key_preserved = unique; } } } return ret; } int ObDelUpdResolver::check_need_fired_trigger(const TableItem* table_item) { int ret = OB_SUCCESS; bool has = false; const ObTableSchema *table_schema = NULL; ObSchemaGetterGuard *schema_guard = NULL; uint64_t table_id = OB_INVALID_ID; CK (OB_NOT_NULL(table_item)); if (OB_SUCC(ret) && !session_info_->get_ddl_info().is_ddl() && !table_item->is_index_table_ && (table_item->is_basic_table() || table_item->is_view_table_)) { CK (OB_NOT_NULL(schema_checker_)); CK (OB_NOT_NULL(schema_guard = schema_checker_->get_schema_guard())); OX (table_id = table_item->ref_id_); if (OB_SUCC(ret)) { if (stmt::T_INSERT == stmt_->get_stmt_type() || stmt::T_INSERT_ALL == stmt_->get_stmt_type()) { table_id = (!OB_ISNULL(table_item->ref_query_) && table_item->ref_query_->is_view_stmt()) ? table_item->ref_query_->get_view_ref_id() : table_item->get_base_table_item().ref_id_; } else if (!table_item->alias_name_.empty() && table_item->is_view_table_) { uint64_t tenant_id = session_info_->get_effective_tenant_id(); CK (OB_NOT_NULL(schema_checker_)); CK (OB_NOT_NULL(schema_guard = schema_checker_->get_schema_guard())) OZ (schema_guard->get_table_id(tenant_id, table_item->database_name_, table_item->table_name_, false /*is_index*/, ObSchemaGetterGuard::ALL_NON_HIDDEN_TYPES, table_id)); } } OZ (schema_checker_->get_table_schema(session_info_->get_effective_tenant_id(), table_id, table_schema), table_id); CK (OB_NOT_NULL(table_schema)); if (OB_SUCC(ret)) { const uint64_t tenant_id = table_schema->get_tenant_id(); const ObIArray &tg_list = table_schema->get_trigger_list(); const ObTriggerInfo *tg_info = NULL; uint64_t tg_id = OB_INVALID_ID; uint64_t dml_event = 0; switch (stmt_->get_stmt_type()) { case stmt::T_INSERT: case stmt::T_INSERT_ALL: dml_event = ObTriggerEvents::get_insert_event(); break; case stmt::T_UPDATE: dml_event = ObTriggerEvents::get_update_event(); break; case stmt::T_DELETE: dml_event = ObTriggerEvents::get_delete_event(); break; case stmt::T_MERGE: dml_event = ObTriggerEvents::get_all_event(); break; case stmt::T_REPLACE: dml_event = ObTriggerEvents::get_insert_event() + ObTriggerEvents::get_update_event(); break; default: ret = OB_ERR_UNEXPECTED; LOG_WARN("stmt type is error", K(stmt_->get_stmt_type()), K(ret)); break; } for (int64_t i = 0; OB_SUCC(ret) && !has && i < tg_list.count(); i++) { OX (tg_id = tg_list.at(i)); OZ (schema_guard->get_trigger_info(tenant_id, tg_id, tg_info)); OV (OB_NOT_NULL(tg_info)); OX (has = (tg_info->is_enable() && tg_info->has_event(dml_event))); } OX (stmt_->get_query_ctx()->disable_udf_parallel_ |= has); if (OB_SUCC(ret) && has && table_schema->is_user_view()) { if (!stmt_->is_support_instead_of_trigger_stmt()) { ret = OB_NOT_SUPPORTED; LOG_WARN("only insert/update/delete stmt support instead of trigger", K(ret), K(stmt_->get_stmt_type())); LOG_USER_ERROR(OB_NOT_SUPPORTED, "except for insert/update/delete statement, instead of trigger is"); } else { ObDelUpdStmt *del_upd_stmt = static_cast(stmt_); if (del_upd_stmt->is_returning()) { ret = OB_ERR_RETURNING_CLAUSE; LOG_WARN("RETURNING clause is currently not supported for INSTEAD OF Triggers", K(ret)); } else { del_upd_stmt->set_has_instead_of_trigger(true); } } } } } return ret; } // generated column、identity column int ObDelUpdResolver::view_pullup_special_column_exprs() { int ret = OB_SUCCESS; ObDMLStmt *dml_stmt = get_stmt(); if (OB_ISNULL(params_.expr_factory_) || OB_ISNULL(dml_stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("param factory or dml stmt is null", K(ret), K(params_.expr_factory_), K(dml_stmt)); } for (int64_t i = 0; OB_SUCC(ret) && i < dml_stmt->get_table_size(); i++) { ObSelectStmt *sel_stmt = NULL; const TableItem *t = NULL; if (OB_ISNULL(t = dml_stmt->get_table_item(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("table item is null", K(ret), K(i)); } else if ((t->is_generated_table() || t->is_temp_table()) && (OB_NOT_NULL(t->view_base_item_) || dml_stmt->has_instead_of_trigger())) { if (dml_stmt->has_instead_of_trigger()) { sel_stmt = t->ref_query_; } else { while (NULL != t && (t->is_generated_table() || t->is_temp_table())) { sel_stmt = t->ref_query_; t = t->view_base_item_; } } if (OB_ISNULL(sel_stmt) || OB_ISNULL(t)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("ref_query_ is null", K(ret)); } for(int j = 0; OB_SUCC(ret) && j < dml_stmt->get_column_size(); j++) { ColumnItem *view_column_item = dml_stmt->get_column_item(j); if (OB_ISNULL(view_column_item) || OB_ISNULL(view_column_item->expr_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("view column item not exists in stmt or expr_ is null", K(ret), K(view_column_item)); } else { ColumnItem *basic_column_item = NULL; if (dml_stmt->has_instead_of_trigger()) { basic_column_item = sel_stmt->get_column_item_by_id(view_column_item->base_tid_, view_column_item->base_cid_); } else if (view_column_item->table_id_ == dml_stmt->get_table_item(i)->table_id_) { basic_column_item = sel_stmt->get_column_item_by_id(t->table_id_, view_column_item->base_cid_); } if (OB_NOT_NULL(basic_column_item)) { if (OB_ISNULL(basic_column_item->expr_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("basic column item expr_ is null", K(ret)); } else if (basic_column_item->expr_->is_generated_column()) { ObRawExpr *ref_expr = NULL; uint64_t tid = dml_stmt->has_instead_of_trigger() ? view_column_item->base_tid_ : t->ref_id_; if (OB_FAIL(copy_schema_expr(*params_.expr_factory_, basic_column_item->expr_->get_dependant_expr(), ref_expr))) { LOG_WARN("failed to copy dependant expr", K(ret)); } else if (OB_FAIL(view_pullup_column_ref_exprs_recursively(ref_expr, tid, dml_stmt))){ LOG_WARN("view pull up generated column exprs recursively failed", K(ret)); } else { view_column_item->expr_->set_dependant_expr(ref_expr); view_column_item->expr_->set_column_flags( basic_column_item->expr_->get_column_flags()); } } else if (basic_column_item->expr_->is_identity_column()) { view_column_item->expr_->set_column_flags( basic_column_item->expr_->get_column_flags()); } } } } } } return ret; } int ObDelUpdResolver::view_pullup_part_exprs() { int ret = OB_SUCCESS; ObDMLStmt *stmt = NULL; TableItem *table = NULL; if (OB_ISNULL(stmt = get_stmt()) || OB_ISNULL(params_.expr_factory_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("params have NULL", K(ret)); } for (int64_t idx = 0; idx < stmt->get_table_size(); idx++) { if (OB_ISNULL(table = stmt->get_table_item(idx))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("table item is NULL", K(ret)); } else if (&table->get_base_table_item() == table) { // skip } else if (table->is_generated_table() || table->is_temp_table()) { ObSelectStmt *sel_stmt = NULL; const TableItem *t = table; ObSEArray view_columns; ObSEArray base_columns; ObRawExprCopier copier(*params_.expr_factory_); while (NULL != t && (t->is_generated_table() || t->is_temp_table())) { sel_stmt = t->ref_query_; t = t->view_base_item_; } if (OB_ISNULL(sel_stmt) || OB_ISNULL(t)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get select stmt for base table item failed", K(ret)); } else if (OB_FAIL(get_pullup_column_map(*stmt, *sel_stmt, table->table_id_, view_columns, base_columns))) { // link.zt seems to have problem, base_tid is better to be refined as table_id LOG_WARN("failed to get pullup column map", K(ret)); } else if (OB_FAIL(copier.add_replaced_expr(base_columns, view_columns))) { LOG_WARN("failed to add replace pair", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && i < sel_stmt->get_part_exprs().count(); ++i) { ObDMLStmt::PartExprItem pei = sel_stmt->get_part_exprs().at(i); if (pei.table_id_ != table->get_base_table_item().table_id_) { continue; } else if (OB_FAIL(copier.copy(pei.part_expr_, pei.part_expr_))) { LOG_WARN("failed to copy part expr", K(ret)); } else if (OB_FAIL(copier.copy(pei.subpart_expr_, pei.subpart_expr_))) { LOG_WARN("failed to copy subpart expr", K(ret)); } else if (OB_FAIL(stmt->get_part_exprs().push_back(pei))) { LOG_WARN("failed to push back pullup partition expr", K(ret)); } } } } return ret; } int ObDelUpdResolver::expand_record_to_columns(const ParseNode &record_node, ObIArray &value_list) { int ret = OB_SUCCESS; ObRawExpr *row_expr = NULL; CK(T_OBJ_ACCESS_REF == record_node.type_, OB_NOT_NULL(params_.secondary_namespace_), OB_NOT_NULL(params_.allocator_), OB_NOT_NULL(params_.expr_factory_)); OZ (pl::ObPLResolver::resolve_raw_expr(record_node, *params_.allocator_, *params_.expr_factory_, *params_.secondary_namespace_, params_.is_prepare_protocol_, row_expr)); if (OB_SUCC(ret) && NULL != row_expr) { if (row_expr->is_obj_access_expr()) { ObObjAccessRawExpr &access_expr = *static_cast(row_expr); pl::ObPLDataType composite_type; OZ (access_expr.get_final_type(composite_type)); if (!composite_type.is_record_type()) { ret = OB_NOT_SUPPORTED; LOG_WARN("not support to expand", K(composite_type), K(ret)); LOG_USER_ERROR(OB_NOT_SUPPORTED, "SET ROW isn't record type"); } else { const pl::ObRecordType *record_type = NULL; const pl::ObUserDefinedType *user_type = NULL; ParseNode *column_node = NULL; const ParseNode *member_node = &record_node; int64_t multi_level_count = 0; while (NULL != member_node && member_node->num_child_ > 1 && NULL != member_node->children_[1]) { if (NULL != member_node->children_[0] && T_IDENT == member_node->children_[0]->type_ && T_OBJ_ACCESS_REF == member_node->children_[1]->type_) { // do nothing } else { multi_level_count++; } member_node = member_node->children_[1]; } if (multi_level_count > 0) { ret = OB_NOT_SUPPORTED; LOG_WARN("not support to expand", K(composite_type), K(ret)); LOG_USER_ERROR(OB_NOT_SUPPORTED, "mutil level record reference"); } else if (OB_ISNULL(column_node = new_terminal_node(allocator_, T_IDENT))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("make db name T_IDENT node failed", K(ret)); } else if (OB_ISNULL(member_node->children_[1] = new_non_terminal_node(allocator_, T_OBJ_ACCESS_REF, 2, column_node, nullptr))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("make db name T_IDENT node failed", K(ret)); } else { /*do nothing*/ } OZ (params_.secondary_namespace_->get_user_type(composite_type.get_user_type_id(), user_type, NULL/*no use*/)); CK (OB_NOT_NULL(user_type)); OX (record_type = static_cast(user_type)); for (int64_t i = 0; OB_SUCC(ret) && i < record_type->get_member_count(); ++i) { ObRawExpr* column_expr = NULL; column_node->str_value_ = parse_strndup(record_type->get_record_member_name(i)->ptr(), record_type->get_record_member_name(i)->length(), allocator_); column_node->str_len_ = record_type->get_record_member_name(i)->length(); OZ (resolve_sql_expr(record_node, column_expr)); OZ (column_expr->formalize(session_info_)); OZ (value_list.push_back(column_expr)); } } } else { ret = OB_NOT_SUPPORTED; LOG_WARN("not support to expand", K(*row_expr), K(ret)); LOG_USER_ERROR(OB_NOT_SUPPORTED, "SET ROW isn't record type"); } } return ret; } // input: target table item of dml. // This function get check constraints from table_item and add into dml_stmt. int ObDelUpdResolver::resolve_check_constraints(const TableItem* table_item, ObIArray &check_exprs) { int ret = OB_SUCCESS; ObDMLStmt *dml_stmt = NULL; const ObTableSchema *table_schema = NULL; if (OB_ISNULL(table_item) || OB_ISNULL(schema_checker_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("table item is null", K(ret)); } else if (OB_ISNULL(dml_stmt = get_stmt())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get stmt null", K(ret)); } else if (OB_ISNULL(session_info_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("session_info_ is null", K(ret)); } else if (OB_FAIL(schema_checker_->get_table_schema(session_info_->get_effective_tenant_id(), table_item->get_base_table_item().ref_id_, table_schema))) { LOG_WARN("fail to get table schema", K(ret), K(table_item->get_base_table_item().ref_id_)); } 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_FAIL(generate_check_constraint_exprs(table_item, table_schema, check_exprs))) { LOG_WARN("fail to add check constraint to stmt", K(ret)); } else { for (int64_t i = 0; OB_SUCC(ret) && i < check_exprs.count(); ++i) { ObRawExpr *&expr = check_exprs.at(i); if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("check constraint expr is null", K(ret)); } else if (OB_FAIL(view_pullup_column_ref_exprs_recursively(expr, table_item->get_base_table_item().ref_id_, dml_stmt))) { LOG_WARN("view pullup column_ref_exprs recursively failed", K(ret)); } else if (expr->get_expr_type() == T_FUN_SYS_IS_JSON && expr->get_param_count() == 5 && OB_NOT_NULL(expr->get_param_expr(0)) && OB_NOT_NULL(expr->get_param_expr(2)) && expr->get_param_expr(0)->get_expr_type() == T_REF_COLUMN && expr->get_param_expr(2)->get_expr_type() == T_INT) { const ObConstRawExpr *const_expr = static_cast(expr->get_param_expr(2)); ObColumnRefRawExpr *col_expr = static_cast(expr->get_param_expr(0)); int is_json_opt = const_expr->get_value().get_int(); if (is_json_opt == 1) { col_expr->set_strict_json_column(IS_JSON_CONSTRAINT_STRICT); } else { col_expr->set_strict_json_column(IS_JSON_CONSTRAINT_RELAX); } } } } return ret; } int ObDelUpdResolver::resolve_view_check_exprs(uint64_t table_id, const TableItem* table_item, const bool cascaded, common::ObIArray &check_exprs) { int ret = OB_SUCCESS; ObDelUpdStmt *del_upd_stmt = NULL; ObSelectStmt *select_stmt = NULL; ObRawExprFactory *expr_factory = params_.expr_factory_; ViewCheckOption check_option = VIEW_CHECK_OPTION_NONE; if (OB_ISNULL(table_item) || OB_ISNULL(schema_checker_) || OB_ISNULL(expr_factory)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(table_item), K(schema_checker_), K(expr_factory)); } else if (!table_item->is_generated_table()) { // do nothing } else if (OB_ISNULL(del_upd_stmt = get_del_upd_stmt()) || OB_ISNULL(select_stmt = table_item->ref_query_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(del_upd_stmt), K(select_stmt)); } else if (!cascaded && VIEW_CHECK_OPTION_NONE == (check_option = select_stmt->get_check_option())) { if (OB_FAIL(resolve_view_check_exprs(table_id, table_item->view_base_item_, cascaded, check_exprs))) { LOG_WARN("resolve view check exprs failed", K(ret)); } } else { if (select_stmt->get_condition_size() > 0) { ObRawExprCopier copier(*expr_factory); ObSEArray view_columns; ObSEArray base_columns; ObSEArray pullup_conditions; // todo link.zt, why the ref_id is used here? // may have problem when a table is used twice by the view. if (OB_FAIL(get_pullup_column_map(*del_upd_stmt, *select_stmt, table_id, view_columns, base_columns))) { LOG_WARN("failed to get pullup column map", K(ret)); } else if (OB_FAIL(copier.add_replaced_expr(base_columns, view_columns))) { LOG_WARN("failed to add replace pair", K(ret)); } else if (OB_FAIL(copier.copy_on_replace(select_stmt->get_condition_exprs(), pullup_conditions))) { LOG_WARN("failed to copy condition expr as view check exprs", K(ret)); } else if (OB_FAIL(append(check_exprs, pullup_conditions))) { LOG_WARN("failed to append pullup conditions", K(ret)); } } if (OB_SUCC(ret)) { const bool new_cascaded = cascaded || VIEW_CHECK_OPTION_CASCADED == check_option; if (OB_FAIL(resolve_view_check_exprs(table_id, table_item->view_base_item_, new_cascaded, check_exprs))) { LOG_WARN("resolve view check exprs failed", K(ret)); } } } return ret; } int ObDelUpdResolver::get_pullup_column_map(ObDMLStmt &stmt, ObSelectStmt &sel_stmt, uint64_t table_id, ObIArray &view_columns, ObIArray &base_columns) { int ret = OB_SUCCESS; for (int64_t i = 0; OB_SUCC(ret) && i < stmt.get_column_size(); ++i) { ColumnItem &parent_column = stmt.get_column_items().at(i); if (parent_column.table_id_ == table_id) { for (int64_t j = 0; OB_SUCC(ret) && j < sel_stmt.get_column_size(); ++j) { ColumnItem &child_column = sel_stmt.get_column_items().at(j); if (child_column.base_tid_ == parent_column.base_tid_ && child_column.base_cid_ == parent_column.base_cid_) { if (OB_FAIL(view_columns.push_back(parent_column.expr_)) || OB_FAIL(base_columns.push_back(child_column.expr_))) { LOG_WARN("failed to push back column expr", K(ret)); } } } } } return ret; } int ObDelUpdResolver::view_pullup_column_ref_exprs_recursively(ObRawExpr *&expr, uint64_t base_table_id, const ObDMLStmt *stmt) { int ret = OB_SUCCESS; bool is_stack_overflow = false; if (OB_FAIL(check_stack_overflow(is_stack_overflow))) { LOG_WARN("check stack overflow failed", K(ret)); } else if (is_stack_overflow) { ret = OB_SIZE_OVERFLOW; LOG_WARN("too deep recursive", K(ret)); } else if (OB_ISNULL(stmt) || OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("stmt or expr is null", K(ret), K(stmt), K(expr)); } else if(expr->is_column_ref_expr()) { ObColumnRefRawExpr *ref_expr = static_cast(expr); bool found = false; for (int64_t i = 0; OB_SUCC(ret) && !found && i < stmt->get_column_size(); i++) { const ColumnItem *column_item = stmt->get_column_item(i); if (OB_ISNULL(column_item) || OB_ISNULL(column_item->expr_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("column expr null"); } else if (base_table_id == column_item->base_tid_ && ref_expr->get_column_id() == column_item->base_cid_) { expr = column_item->expr_; found = true; } } } else { for (int i = 0; OB_SUCC(ret) && i < expr->get_param_count(); i++) { ObRawExpr *&t_expr = expr->get_param_expr(i); if (OB_FAIL(SMART_CALL(view_pullup_column_ref_exprs_recursively(t_expr, base_table_id, stmt)))) { LOG_WARN("generated column expr pull up failed", K(ret)); } } } return ret; } int ObDelUpdResolver::generate_column_conv_function(ObInsertTableInfo &table_info) { int ret = OB_SUCCESS; ObDelUpdStmt* del_upd_stmt = get_del_upd_stmt(); if (OB_ISNULL(del_upd_stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get null stmt", K(ret)); } else if (OB_FAIL(table_info.column_conv_exprs_.prepare_allocate(table_info.column_exprs_.count()))) { LOG_WARN("failed to prepare allocate", K(ret)); } else { uint64_t table_id = table_info.table_id_; for (int64_t i = 0; OB_SUCC(ret) && i < table_info.column_exprs_.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 = table_info.column_exprs_.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid table column", K(ret), K(i), K(table_info.column_exprs_)); } else if (FALSE_IT(column_id = tbl_col->get_column_id())) { } else if (OB_ISNULL(column_item = del_upd_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(table_info, column_id, column_ref))) { LOG_WARN("fail to check column is exists", K(ret), K(column_id)); } else if ((!session_info_->get_ddl_info().is_ddl() || OB_ISNULL(column_ref)) && ( tbl_col->is_xml_column() || (tbl_col->is_udt_hidden_column()))) { if (!tbl_col->is_xml_column()) { // do nothing, hidden column with build with xml column together } else if (OB_FAIL(build_column_conv_function_for_udt_column(table_info, i, column_ref))) { LOG_WARN("failed to build column conv for udt_columns", K(ret)); } } else if (OB_ISNULL(column_ref)) { if (OB_FAIL(build_column_conv_function_with_default_expr(table_info, i))) { LOG_WARN("build column convert function with default expr failed", K(ret)); } } else if (OB_FAIL(build_column_conv_function_with_value_desc(table_info, i, column_ref))) { LOG_WARN("failed to build column conv with value desc", K(ret)); } } //end for } return ret; } int ObDelUpdResolver::find_value_desc(ObInsertTableInfo &table_info, uint64_t column_id, ObRawExpr *&column_ref) { int ret = OB_SUCCESS; ObDelUpdStmt *del_upd_stmt = get_del_upd_stmt(); column_ref = NULL; bool find = false; ObColumnRefRawExpr *expr = nullptr; bool value_from_select = false; uint64_t table_id = OB_INVALID_ID; if (OB_ISNULL(del_upd_stmt)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid insert stmt", K(del_upd_stmt)); } else { value_from_select = del_upd_stmt->get_from_item_size() > 0; } if (!value_from_select) { // do nothing } else if (OB_UNLIKELY(del_upd_stmt->get_from_item_size() != 1)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid from items", K(ret), K(del_upd_stmt->get_from_items())); } else { table_id = del_upd_stmt->get_from_item(0).table_id_; } for (int64_t i = 0; OB_SUCC(ret) && !find && i < table_info.values_desc_.count(); i++) { if (OB_ISNULL(expr = table_info.values_desc_.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("fail to get values expr", K(i), K(table_info.values_desc_), K(ret)); } else if (column_id == expr->get_column_id()) { find = true; if (value_from_select) { column_ref = del_upd_stmt->get_column_expr_by_id(table_id, i + OB_APP_MIN_COLUMN_ID); } else { column_ref = table_info.values_desc_.at(i); } } } return ret; } int ObDelUpdResolver::build_column_conv_function_with_value_desc(ObInsertTableInfo& table_info, const int64_t idx, ObRawExpr *column_ref) { int ret = OB_SUCCESS; ObDelUpdStmt *del_upd_stmt = get_del_upd_stmt(); const ObColumnRefRawExpr *tbl_col = table_info.column_exprs_.at(idx); uint64_t table_id = table_info.table_id_; if (OB_ISNULL(del_upd_stmt) || OB_ISNULL(column_ref) || OB_ISNULL(tbl_col)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid arguments", K(ret)); } else if (OB_ISNULL(session_info_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("session_info_ is null", K(ret)); } else { uint64_t column_id = tbl_col->get_column_id(); ColumnItem *column_item = NULL; bool skip_convert = false; bool trigger_exist = false; const schema::ObTableSchema *table_schema = nullptr; if (OB_ISNULL(column_item = del_upd_stmt->get_column_item_by_id(table_id, column_id))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null column item", K(ret)); } else if (session_info_->get_ddl_info().is_ddl()) { // TODO: yibo do not check each time TableItem* table_item = del_upd_stmt->get_table_item_by_id(table_info.table_id_); if (OB_ISNULL(table_item)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get null table item", K(ret)); } else if (OB_FAIL(schema_checker_->get_table_schema(session_info_->get_effective_tenant_id(), table_item->ddl_table_id_, table_schema))) { LOG_WARN("get table schema failed", K(ret), K(table_item->ddl_table_id_)); } else if (OB_ISNULL(table_schema)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("table schema is null", K(ret), K(table_item->ddl_table_id_)); } else { skip_convert = table_schema->is_index_table() || column_item->column_id_ == OB_HIDDEN_PK_INCREMENT_COLUMN_ID; LOG_TRACE("skip convert expr in ddl", K(table_item->ddl_table_id_), K(skip_convert)); } } else { const TableItem *table_item = NULL; ObSchemaGetterGuard *schema_guard = NULL; if (OB_ISNULL(schema_checker_) || OB_ISNULL(schema_guard = schema_checker_->get_schema_guard())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid schema checker", K(schema_checker_)); } else if (OB_FAIL(schema_checker_->get_table_schema(session_info_->get_effective_tenant_id(), table_info.ref_table_id_, table_schema, table_info.is_link_table_))) { LOG_WARN("fail to get table schema", K(ret), KPC(table_item)); } else if (OB_ISNULL(table_schema)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("fail to get table schema", KPC(table_item), K(table_schema)); } else if (OB_FAIL(table_schema->has_before_insert_row_trigger(*schema_guard, trigger_exist))) { LOG_WARN("fail to call has_before_update_row_trigger", K(*table_schema)); } } if (OB_FAIL(ret)) { } else if (!skip_convert && OB_FAIL(add_additional_function_according_to_type(column_item, column_ref, T_INSERT_SCOPE, ObObjMeta::is_binary(tbl_col->get_data_type(), tbl_col->get_collation_type())))) { LOG_WARN("failed to build column conv expr", K(ret)); } else if (column_item->is_geo_) { // 1. set geo sub type to cast mode to column covert expr when update // 2. check geo type while doing column covert. ObColumnRefRawExpr *raw_expr = column_item->get_expr(); if (OB_ISNULL(raw_expr)) { ret = OB_ERR_NULL_VALUE; LOG_WARN("raw expr in column item is null", K(ret)); } else { ObGeoType geo_type = raw_expr->get_geo_type(); uint64_t cast_mode = column_ref->get_extra(); if (OB_FAIL(ObGeoCastUtils::set_geo_type_to_cast_mode(geo_type, cast_mode))) { LOG_WARN("fail to set geometry type to cast mode", K(ret), K(geo_type)); } else { column_ref->set_extra(cast_mode); } } } if (OB_SUCC(ret)) { if (trigger_exist && OB_FAIL(ObRawExprUtils::build_wrapper_inner_expr(*params_.expr_factory_, *session_info_, column_ref, column_ref))) { LOG_WARN("failed to build wrapper inner expr", K(ret)); } else { table_info.column_conv_exprs_.at(idx) = column_ref; LOG_TRACE("add column conv expr", K(*column_ref), K(trigger_exist)); } } } return ret; } int ObDelUpdResolver::build_column_conv_function_with_default_expr(ObInsertTableInfo& table_info, const int64_t idx) { int ret = OB_SUCCESS; ObDelUpdStmt *del_upd_stmt = get_del_upd_stmt(); const ObColumnRefRawExpr *tbl_col = table_info.column_exprs_.at(idx); uint64_t table_id = table_info.table_id_; if (OB_ISNULL(del_upd_stmt) || OB_ISNULL(tbl_col) || OB_ISNULL(session_info_) || OB_ISNULL(params_.expr_factory_)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid arguments", K(ret)); } else { ObSchemaGetterGuard *schema_guard = NULL; const ObTableSchema* table_schema = NULL; bool trigger_exist = false; ColumnItem *column_item = del_upd_stmt->get_column_item_by_id(table_id, tbl_col->get_column_id()); ObRawExpr *function_expr = NULL; ObRawExpr *expr = NULL; ObDefaultValueUtils utils(del_upd_stmt, ¶ms_, this); if (OB_ISNULL(schema_checker_) || OB_ISNULL(schema_guard = schema_checker_->get_schema_guard())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid schema checker", K(schema_checker_)); } else if (OB_FAIL(schema_checker_->get_table_schema(session_info_->get_effective_tenant_id(), table_info.ref_table_id_, table_schema, table_info.is_link_table_))) { LOG_WARN("fail to get table schema", K(ret)); } else if (OB_ISNULL(table_schema)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("fail to get table schema", K(table_info), K(table_schema)); } else if (OB_FAIL(table_schema->has_before_insert_row_trigger(*schema_guard, trigger_exist))) { LOG_WARN("fail to call has_before_update_row_trigger", K(*table_schema)); } else if (OB_ISNULL(column_item)) { 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, del_upd_stmt->has_instead_of_trigger()))) { 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)); } 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(tbl_col->get_data_type(), tbl_col->get_collation_type())) { if (OB_FAIL(build_padding_expr(session_info_, column_item, expr))) { LOG_WARN("Build padding expr error", K(ret)); } } // maybe 没有必要再加一层column // conv函数,如果能够保证schema表中的默认值已经是合法值 if (OB_FAIL(ret)) { } else if (expr->get_expr_type() == T_TABLET_AUTOINC_NEXTVAL) { // 如果是堆表的隐藏自增列,不需要构建conv表达式 function_expr = expr; } 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 if (trigger_exist && OB_FAIL(ObRawExprUtils::build_wrapper_inner_expr(*params_.expr_factory_, *session_info_, expr, expr))) { LOG_WARN("failed to build wrapper inner expr", K(ret)); } else { function_expr = expr; } } if (OB_SUCC(ret)) { table_info.column_conv_exprs_.at(idx) = function_expr; LOG_DEBUG("add column conv expr", K(*function_expr)); } } return ret; } int ObDelUpdResolver::build_column_conv_function_for_udt_column(ObInsertTableInfo& table_info, const int64_t idx, ObRawExpr *column_ref) { int ret = OB_SUCCESS; ObDelUpdStmt *del_upd_stmt = get_del_upd_stmt(); const ObColumnRefRawExpr *tbl_col = table_info.column_exprs_.at(idx); uint64_t table_id = table_info.table_id_; if (OB_ISNULL(del_upd_stmt) || OB_ISNULL(tbl_col) || OB_ISNULL(session_info_) || OB_ISNULL(params_.expr_factory_)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid arguments", K(ret)); } else { ObSchemaGetterGuard *schema_guard = NULL; const ObTableSchema* table_schema = NULL; bool trigger_exist = false; ColumnItem *column_item = del_upd_stmt->get_column_item_by_id(table_id, tbl_col->get_column_id()); uint64_t udt_set_id = tbl_col->get_udt_set_id(); ColumnItem *hidden_column_item = NULL; int64_t hidd_idx = 0; for (int64_t i = 0; OB_ISNULL(hidden_column_item) && i < table_info.column_exprs_.count(); i++) { if (table_info.column_exprs_.at(i)->get_column_id() != tbl_col->get_column_id() && table_info.column_exprs_.at(i)->get_udt_set_id() == tbl_col->get_udt_set_id()) { hidden_column_item = del_upd_stmt->get_column_item_by_id(table_id, table_info.column_exprs_.at(i)->get_column_id()); hidd_idx = i; } } if (OB_ISNULL(hidden_column_item)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("find hidden column failed", K(schema_checker_)); } else { ObRawExpr *function_expr = NULL; ObRawExpr *expr = NULL; ObDefaultValueUtils utils(del_upd_stmt, ¶ms_, this); if (OB_ISNULL(schema_checker_) || OB_ISNULL(schema_guard = schema_checker_->get_schema_guard())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid schema checker", K(schema_checker_)); } else if (OB_FAIL(schema_checker_->get_table_schema(session_info_->get_effective_tenant_id(), table_info.ref_table_id_, table_schema, table_info.is_link_table_))) { LOG_WARN("fail to get table schema", K(ret)); } else if (OB_ISNULL(table_schema)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("fail to get table schema", K(table_info), K(table_schema)); } else if (OB_FAIL(table_schema->has_before_insert_row_trigger(*schema_guard, trigger_exist))) { LOG_WARN("fail to call has_before_update_row_trigger", K(*table_schema)); } else if (OB_ISNULL(column_item)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null column item", K(ret), K(column_item)); } else if (OB_NOT_NULL(column_ref)) { if (OB_FAIL(add_additional_function_according_to_type(hidden_column_item, column_ref, T_INSERT_SCOPE, ObObjMeta::is_binary(tbl_col->get_data_type(), tbl_col->get_collation_type())))) { LOG_WARN("failed to build column conv expr", K(ret)); } else { function_expr = column_ref; } } else { // use default value from default_value_expr_ if (OB_NOT_NULL(column_item->default_value_expr_)) { if (T_FUN_COLUMN_CONV == column_item->default_value_expr_->get_expr_type()) { if (column_item->default_value_expr_->get_param_expr(4)->is_const_raw_expr()) { expr = column_item->default_value_expr_->get_param_expr(4); } else if (column_item->default_value_expr_->get_param_expr(4)->get_expr_type() == T_FUN_SYS_CAST) { expr = column_item->default_value_expr_->get_param_expr(4)->get_param_expr(0); } else if (column_item->default_value_expr_->get_param_expr(4)->is_sys_func_expr()) { expr = column_item->default_value_expr_->get_param_expr(4); } } } else if (!column_item->default_value_.is_null()) { ObObj tmp = hidden_column_item->default_value_; hidden_column_item->set_default_value(column_item->default_value_); hidden_column_item->default_value_.set_collation_type(CS_TYPE_UTF8MB4_BIN); hidden_column_item->default_value_.set_collation_level(tmp.get_collation_level()); hidden_column_item->default_value_.set_type(ObVarcharType); } if (OB_SUCC(ret) && OB_ISNULL(expr)) { if (OB_FAIL(utils.generate_insert_value(hidden_column_item, expr, del_upd_stmt->has_instead_of_trigger()))) { LOG_WARN("failed to generate insert value", K(ret)); } } if (OB_FAIL(ret)) { } else if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("expr should not be null", K(ret)); } else if (OB_FAIL(ObRawExprUtils::transform_udt_column_value_expr(*params_.expr_factory_, expr, expr))) { LOG_WARN("transform udt value expr failed", K(ret)); } else if (OB_FAIL(ObRawExprUtils::build_column_conv_expr(*params_.expr_factory_, *params_.allocator_, *hidden_column_item->get_expr(), // build col conv for hidden column expr, session_info_))) { LOG_WARN("fail to build column conv expr", K(ret)); } else if (trigger_exist && OB_FAIL(ObRawExprUtils::build_wrapper_inner_expr(*params_.expr_factory_, *session_info_, expr, expr))) { LOG_WARN("failed to build wrapper inner expr", K(ret)); } else { function_expr = expr; } } if (OB_SUCC(ret)) { ObConstRawExpr *c_expr = NULL; if (OB_FAIL(params_.expr_factory_->create_raw_expr(T_NULL, c_expr))) { LOG_WARN("create raw expr failed", K(ret)); } else { // udt column convert expr is useless, make T_NULL for it; table_info.column_conv_exprs_.at(idx) = c_expr; table_info.column_conv_exprs_.at(hidd_idx) = function_expr; LOG_DEBUG("add column conv expr", K(*function_expr)); } } } } return ret; } int ObDelUpdResolver::generate_autoinc_params(ObInsertTableInfo &table_info) { int ret = OB_SUCCESS; ObDelUpdStmt *del_upd_stmt = get_del_upd_stmt(); const ObTableSchema *table_schema = NULL; int64_t auto_increment_cache_size = -1; if (OB_ISNULL(del_upd_stmt) || OB_ISNULL(params_.session_info_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(del_upd_stmt), K(params_.session_info_)); } else if (OB_FAIL(schema_checker_->get_table_schema(params_.session_info_->get_effective_tenant_id(), table_info.ref_table_id_, table_schema))) { LOG_WARN("fail to get table schema", K(ret), K(table_info.ref_table_id_)); } else if (OB_ISNULL(table_schema)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(table_schema)); } else if (OB_FAIL(params_.session_info_->get_auto_increment_cache_size(auto_increment_cache_size))) { LOG_WARN("fail to get increment factor", K(ret)); } 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()) { del_upd_stmt->set_affected_last_insert_id(true); AutoincParam param; param.tenant_id_ = params_.session_info_->get_effective_tenant_id(); param.autoinc_table_id_ = table_info.ref_table_id_; 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.auto_increment_cache_size_ = auto_increment_cache_size; 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; param.autoinc_mode_is_order_ = table_schema->is_order_auto_increment_mode(); param.autoinc_version_ = table_schema->get_truncate_version(); param.autoinc_auto_increment_ = table_schema->get_auto_increment(); // 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; param.part_value_no_order_ = true; } else if (column_schema->is_tbl_part_key_column()) { // don't keep intra-partition value asc order when partkey column is auto inc param.part_value_no_order_ = true; } 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(del_upd_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", del_upd_stmt->get_autoinc_params()); return ret; } int ObDelUpdResolver::get_value_row_size(uint64_t& value_row_size) { int ret = OB_SUCCESS; ObDelUpdStmt *del_upd_stmt = get_del_upd_stmt(); value_row_size = 1; if (OB_ISNULL(del_upd_stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (del_upd_stmt->is_insert_stmt()) { ObInsertStmt *insert_stmt = static_cast(del_upd_stmt); if (!insert_stmt->value_from_select()) { if (params_.is_batch_stmt_) { value_row_size = params_.batch_stmt_num_; } else { value_row_size = insert_stmt->get_insert_row_count(); } } } return ret; } int ObDelUpdResolver::resolve_insert_columns(const ParseNode *node, ObInsertTableInfo& table_info) { int ret = OB_SUCCESS; TableItem *table_item = NULL; ObDelUpdStmt *del_upd_stmt = get_del_upd_stmt(); if (OB_ISNULL(del_upd_stmt) || OB_ISNULL(session_info_) || OB_ISNULL(schema_checker_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid insert stmt", K(del_upd_stmt), K_(session_info), K_(schema_checker)); } else if (OB_ISNULL(table_item = del_upd_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 (lib::is_oracle_mode() && ObCharset::case_insensitive_equal(OB_HIDDEN_LOGICAL_ROWID_COLUMN_NAME, column_ref.col_name_)) { ret = OB_ERR_VIRTUAL_COL_NOT_ALLOWED; LOG_WARN("cannot insert rowid pseudo column", K(ret), K(column_ref)); } 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 (!session_info_->get_ddl_info().is_ddl() && 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 (!session_info_->get_ddl_info().is_ddl() && 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_FAIL(mock_values_column_ref(column_expr))) { LOG_WARN("mock values column reference failed", K(ret)); } }//end for } else { if (del_upd_stmt->get_table_size() != 1 && del_upd_stmt->get_stmt_type() != stmt::T_MERGE) { ret = OB_ERR_PARSER_SYNTAX; LOG_WARN("Insert statement only support one table", K(del_upd_stmt->get_stmt_type()), K(ret)); } ObArray column_items; if (OB_SUCC(ret)) { if (table_item->is_basic_table() || table_item->is_link_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 (del_upd_stmt->get_stmt_type() == stmt::T_MERGE && table_item->is_generated_table()) { if (OB_FAIL(static_cast(this)->resolve_merge_generated_table_columns( del_upd_stmt, table_item, column_items))) { LOG_WARN("resolve generated table columns failed", K(ret)); } } else if (table_item->is_generated_table() || table_item->is_temp_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() || table_item->is_temp_table()) && !del_upd_stmt->has_instead_of_trigger()) { FOREACH_CNT_X(desc, table_info.values_desc_, OB_SUCC(ret)) { const ColumnItem *column_item = del_upd_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 ObDelUpdResolver::resolve_insert_values(const ParseNode *node, ObInsertTableInfo& table_info) { int ret = OB_SUCCESS; ObDelUpdStmt *del_upd_stmt = get_del_upd_stmt(); ObArray value_row; ObArray value_idxs; //store the old order of columns in values_desc uint64_t value_count = OB_INVALID_ID; bool is_all_default = false; bool is_update_view = false; if (OB_ISNULL(del_upd_stmt) || OB_ISNULL(node) || OB_ISNULL(session_info_) || T_VALUE_LIST != node->type_ || OB_ISNULL(node->children_) || OB_ISNULL(del_upd_stmt->get_query_ctx())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid arguemnt", K(del_upd_stmt), K(node), K(session_info_), 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. */ } if (FAILEDx(table_info.values_vector_.reserve(node->num_child_ * table_info.values_desc_.count()))) { // works for most cases. except label security/timestamp generation needs extend memory LOG_WARN("reserve memory fail", K(ret)); } if (OB_SUCC(ret)) { TableItem* table_item = NULL; if (OB_FAIL(check_need_match_all_params(table_info.values_desc_, del_upd_stmt->get_query_ctx()->need_match_all_params_))) { LOG_WARN("check need match all params failed", K(ret)); } else if (OB_ISNULL(table_item = del_upd_stmt->get_table_item_by_id(table_info.table_id_))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (table_item->is_generated_table()) { is_update_view = true; } } if (OB_SUCC(ret)) { //move generated columns behind basic columns before resolve values ObArray tmp_values_desc; if (OB_FAIL(value_idxs.reserve(table_info.values_desc_.count()))) { LOG_WARN("fail to reserve memory", K(ret)); } else if (OB_FAIL(tmp_values_desc.reserve(table_info.values_desc_.count()))) { LOG_WARN("fail to reserve memory", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && i < 2; ++i) { for (int64_t j = 0; OB_SUCC(ret) && j < table_info.values_desc_.count(); ++j) { if (OB_ISNULL(table_info.values_desc_.at(j))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("inalid value desc", K(j), K(table_info.values_desc_)); } else if ((i == 0 && !table_info.values_desc_.at(j)->is_generated_column()) || (i == 1 && table_info.values_desc_.at(j)->is_generated_column())) { if (OB_FAIL(tmp_values_desc.push_back(table_info.values_desc_.at(j)))) { LOG_WARN("fail to push back values_desc_", K(ret)); } else if (OB_FAIL(value_idxs.push_back(j))) { LOG_WARN("fail to push back value index", K(ret)); } } } } if (OB_SUCC(ret)) { table_info.values_desc_.reuse(); if (OB_FAIL(append(table_info.values_desc_, tmp_values_desc))) { LOG_WARN("fail to append new values_desc"); } } } if (OB_SUCC(ret)) { //move generated columns behind basic columns before resolve values OZ (adjust_values_desc_position(table_info, value_idxs)); } 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_ != table_info.values_desc_.count() && !(1 == vector_node->num_child_ && T_EMPTY == vector_node->children_[0]->type_) && !(1 == node->num_child_ && T_OBJ_ACCESS_REF == vector_node->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", table_info.values_desc_.count()); } if (OB_SUCC(ret)) { if (T_OBJ_ACCESS_REF == vector_node->type_) { if (NULL != params_.secondary_namespace_) { OZ (expand_record_to_columns(*vector_node, value_row)); } else { ret = OB_UNIMPLEMENTED_FEATURE; LOG_WARN("insert values doesn't support record type without '()'", K(ret)); } } else { if (OB_FAIL(value_row.reserve(vector_node->num_child_))) { LOG_WARN("fail reserve rows", K(ret), "size", vector_node->num_child_); } 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; //for case: values(), read the first child const ParseNode *value_node = (1 == vector_node->num_child_) ? vector_node->children_[0] : vector_node->children_[value_idxs.at(j)]; if (OB_ISNULL(value_node) || OB_ISNULL(column_expr = table_info.values_desc_.at(j))) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("inalid children node", K(j), K(vector_node)); } else if (T_EMPTY == value_node->type_) { //nothing todo } else { uint64_t column_id = column_expr->get_column_id(); ObDefaultValueUtils utils(del_upd_stmt, ¶ms_, this); bool is_generated_column = false; if (OB_FAIL(resolve_sql_expr(*value_node, 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 (is_update_view && is_oracle_mode()) { ret = OB_ERR_DEFAULT_FOR_MODIFYING_VIEWS; LOG_USER_ERROR(OB_ERR_DEFAULT_FOR_MODIFYING_VIEWS); } else if (OB_ISNULL(column_item = del_upd_stmt->get_column_item_by_id(table_info.table_id_, column_id))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get column item by id failed", K(table_info.table_id_), K(column_id)); } else if (column_expr->is_generated_column()) { //values中对应的生成列出现了default关键字,我们统一将default替换成生成列对应的表达式 //下面的统一处理逻辑会为values中的column进行替换 if (OB_FAIL(copy_schema_expr(*params_.expr_factory_, column_item->expr_->get_dependant_expr(), expr))) { LOG_WARN("copy expr failed", K(ret)); } } else if (OB_FAIL(utils.resolve_default_expr(*column_item, expr, T_INSERT_SCOPE))) { LOG_WARN("fail to resolve default value", "table_id", table_info.table_id_, K(column_id), K(ret)); } } else if (OB_FAIL(check_basic_column_generated(column_expr, del_upd_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; if (!is_oracle_mode()) { ColumnItem *orig_col_item = NULL; if (NULL != (orig_col_item = del_upd_stmt->get_column_item_by_id(table_info.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_always_identity_column()) { ret = OB_ERR_INSERT_INTO_GENERATED_ALWAYS_IDENTITY_COLUMN; LOG_USER_ERROR(OB_ERR_INSERT_INTO_GENERATED_ALWAYS_IDENTITY_COLUMN); } else { if ((column_expr->is_table_part_key_column() || column_expr->is_table_part_key_org_column()) && expr->has_flag(CNT_SEQ_EXPR)) { del_upd_stmt->set_has_part_key_sequence(true); } } const ObIArray &dep_cols = table_info.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 = del_upd_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, column_expr->is_generated_column()))) { 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, table_info, i+1, value_count, is_all_default))) { LOG_WARN("fail to check column value count", K(ret)); } else if (is_all_default) { //处理insert into test values(),()的情况 if (OB_FAIL(build_row_for_empty_brackets(value_row, table_info))) { 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(append(table_info.values_vector_, value_row))) { LOG_WARN("failed to append value row", K(ret)); } } } value_row.reset(); } return ret; } int ObDelUpdResolver::check_column_value_pair(ObArray *value_row, ObInsertTableInfo& table_info, const int64_t row_index, const uint64_t value_count, bool& is_all_default) { int ret = OB_SUCCESS; //如果现实指定了列,那么values()不容许为空 is_all_default = false; 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 (value_row->count() != 0 && table_info.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; } //如果values后面跟的是空括号的话,需要根据stmt语句中column列表的顺序加入default value; //特例,如果stmt中没有指定column列表的话,则会在resolve_insert_column时加入全部的列 int ObDelUpdResolver::build_row_for_empty_brackets(ObArray &value_row, ObInsertTableInfo& table_info) { int ret = OB_SUCCESS; ObDelUpdStmt *del_upd_stmt = get_del_upd_stmt(); if (OB_ISNULL(del_upd_stmt)){ ret = OB_ERR_UNEXPECTED; LOG_WARN("get null stmt", K(del_upd_stmt), K(ret)); } else { ColumnItem *item = NULL; ObDefaultValueUtils utils(del_upd_stmt, ¶ms_, static_cast(this)); for (int64_t i = 0; i < table_info.values_desc_.count() && OB_SUCCESS == ret; ++i) { ObRawExpr *expr = NULL; int64_t column_id = table_info.values_desc_.at(i)->get_column_id(); if (OB_ISNULL(item = del_upd_stmt->get_column_item_by_id(table_info.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(copy_schema_expr(*params_.expr_factory_, item->expr_->get_dependant_expr(), expr))) { 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 (); 场景下不可以自动生成 nextval 表达式,而应该生成 null // 否则会出现问题: 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 ObDelUpdResolver::check_update_part_key(const ObTableAssignment &ta, uint64_t ref_table_id, bool &is_updated, bool is_link /* = false */) { int ret = OB_SUCCESS; is_updated = false; ObSEArray part_key_ids; if (OB_ISNULL(get_stmt())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get null stmt", K(ret)); } else if (OB_FAIL(!is_link && get_part_key_ids(ref_table_id, part_key_ids))) { LOG_WARN("fail to get part key ids", K(ret), K(ref_table_id)); } for (int64_t i = 0; !is_updated && OB_SUCC(ret) && i < ta.assignments_.count(); ++i) { ObColumnRefRawExpr *column_expr = ta.assignments_.at(i).column_expr_; ColumnItem *column_item = nullptr; if (OB_ISNULL(column_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get null column expr", K(ret)); } else if (OB_ISNULL(column_item = get_stmt()->get_column_item_by_id(column_expr->get_table_id(), column_expr->get_column_id()))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get null column item", K(ret), KPC(column_expr)); } else if (has_exist_in_array(part_key_ids, column_item->base_cid_)) { is_updated = true; } } return ret; } int ObDelUpdResolver::get_part_key_ids(const int64_t table_id, common::ObIArray &array) { int ret = OB_SUCCESS; const ObTableSchema *table_schema = NULL; array.reuse(); if (OB_ISNULL(session_info_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("session_info_ is null", K(ret)); } else if (OB_FAIL(schema_checker_->get_table_schema(session_info_->get_effective_tenant_id(), table_id, table_schema))) { LOG_WARN("table schema not found", "table_id", table_id); } else if (NULL == table_schema) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get table schema error", K(table_id), K(table_schema)); } else if (table_schema->is_partitioned_table()) { uint64_t part_key_column_id = OB_INVALID_ID; if (OB_SUCC(ret)) { const ObPartitionKeyInfo &part_key_info = table_schema->get_partition_key_info(); for (int64_t i = 0; OB_SUCC(ret) && i < part_key_info.get_size(); ++i) { if (OB_FAIL(part_key_info.get_column_id(i, part_key_column_id))) { LOG_WARN("get rowkey info failed", K(ret), K(i), K(part_key_info)); break; } else if (OB_FAIL(array.push_back(part_key_column_id))) { LOG_WARN("fail to add primary key to array", K(ret), K(part_key_column_id)); } } } if (OB_SUCC(ret)) { const ObPartitionKeyInfo &subpart_key_info = table_schema->get_subpartition_key_info(); for (int64_t i = 0; OB_SUCC(ret) && i < subpart_key_info.get_size(); ++i) { if (OB_FAIL(subpart_key_info.get_column_id(i, part_key_column_id))) { LOG_WARN("get rowkey info failed", K(ret), K(i), K(subpart_key_info)); break; } else if (OB_FAIL(array.push_back(part_key_column_id))) { LOG_WARN("fail to add primary key to array", K(ret), K(part_key_column_id)); } } } } return ret; } int ObDelUpdResolver::build_hidden_pk_assignment(ObTableAssignment &ta, const TableItem *table_item, const ObTableSchema *table_schema) { int ret = OB_SUCCESS; bool is_end_loop = false; ObDMLStmt *stmt = get_stmt(); ObTableSchema::const_column_iterator iter = table_schema->column_begin(); for (; OB_SUCC(ret) && !is_end_loop && iter != table_schema->column_end(); ++iter) { ColumnItem *col_item = NULL; ObColumnSchemaV2 *column_schema = *iter; if (NULL == column_schema) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get column schema fail", K(column_schema)); } else if (column_schema->get_column_id() != OB_HIDDEN_PK_INCREMENT_COLUMN_ID) { //do nothing } else { is_end_loop = true; ObAssignment assignment; ObSEArray col_exprs; ObColumnRefRawExpr *col_expr = NULL; ObRawExpr *expr = NULL; if (OB_FAIL(add_column_to_stmt(*table_item, *column_schema, col_exprs))) { LOG_WARN("add column to stmt failed", K(ret), K(*table_item), K(*column_schema)); } else if (col_exprs.empty()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("no column expr returned", K(ret)); } else if (OB_ISNULL(col_expr = col_exprs.at(0))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("no column expr returned", K(ret)); } else if (OB_ISNULL(col_item = stmt->get_column_item_by_id(table_item->table_id_, col_exprs.at(0)->get_column_id()))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get column item failed", K(ret), "table_id", table_item->table_id_, "column_id", col_exprs.at(0)->get_column_id()); } else if (OB_FAIL(build_heap_table_hidden_pk_expr(expr, col_expr))) { LOG_WARN("fail to build heap_hidden_pk_expr", K(ret), K(col_expr)); } else { assignment.column_expr_ = col_item->expr_; assignment.expr_ = expr; assignment.is_implicit_ = true; } if (OB_FAIL(ta.assignments_.push_back(assignment))) { LOG_WARN("fail to push assignements", K(ret), K(assignment)); } } } return ret; } int ObDelUpdResolver::check_heap_table_update(ObTableAssignment &tas) { int ret = OB_SUCCESS; const TableItem *table = NULL; const ObTableSchema *table_schema = NULL; bool is_update_part_key = false; ObDMLStmt *stmt = get_stmt(); if (OB_ISNULL(stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("stmt is null", K(ret)); } else if (OB_ISNULL(params_.session_info_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("params_.session_info_ is null", K(ret)); } else if (OB_ISNULL(table = stmt->get_table_item_by_id(tas.table_id_))) { LOG_WARN("fail to get table_item", K(ret), K(tas)); } else if (OB_FAIL(schema_checker_->get_table_schema(params_.session_info_->get_effective_tenant_id(), table->get_base_table_item().ref_id_, table_schema, table->is_link_table()))) { LOG_WARN("fail to get table schema", K(ret), "base_table_id", table->get_base_table_item().ref_id_); } else if (!table_schema->is_heap_table()) { // 不是堆表,什么都不需要做 } else if (OB_FAIL(check_update_part_key(tas, table->get_base_table_item().ref_id_, is_update_part_key, table->get_base_table_item().is_link_table()))) { LOG_WARN("fail to check whether update part key", K(ret), K(tas), "base_table_id", table->get_base_table_item().ref_id_); } else if (!is_update_part_key) { // 不更新分区建,do nothing } else if (OB_FAIL(build_hidden_pk_assignment(tas, table, table_schema))) { LOG_WARN("fail to build hidden_pk assignment", K(ret), K(tas), KPC(table)); } return ret; } // TODO @yibo, add_column is used to handle some recursive dependency in insert resolver, should remove int ObDelUpdResolver::generate_insert_table_info(const TableItem &table_item, ObInsertTableInfo &table_info, bool add_column /*= true */) { int ret = OB_SUCCESS; ObDelUpdStmt *del_upd_stmt = get_del_upd_stmt(); const TableItem &base_table_item = table_item.get_base_table_item(); const ObTableSchema *table_schema = NULL; uint64_t index_tid[OB_MAX_INDEX_PER_TABLE]; int64_t gindex_cnt = OB_MAX_INDEX_PER_TABLE; if (OB_ISNULL(del_upd_stmt) || OB_ISNULL(schema_checker_) || OB_ISNULL(session_info_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(del_upd_stmt), K(schema_checker_), K(session_info_)); } else if (OB_FAIL(schema_checker_->get_can_write_index_array(session_info_->get_effective_tenant_id(), base_table_item.ref_id_, index_tid, gindex_cnt, true))) { LOG_WARN("failed to get global index", K(ret)); } else if (OB_FAIL(schema_checker_->get_table_schema(session_info_->get_effective_tenant_id(), base_table_item.ref_id_, table_schema, base_table_item.is_link_table()))) { LOG_WARN("failed to get table schema", K(ret)); } else if (OB_ISNULL(table_schema)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (OB_FAIL(table_info.part_ids_.assign(base_table_item.part_ids_))) { LOG_WARN("failed to assign part ids", K(ret)); } else if (!del_upd_stmt->has_instead_of_trigger()) { if (add_column && OB_FAIL(add_all_rowkey_columns_to_stmt(table_item, table_info.column_exprs_))) { LOG_WARN("failed to add rowkey columns", K(ret)); } else if (add_column && OB_FAIL(add_all_columns_to_stmt(table_item, table_info.column_exprs_))) { LOG_WARN("failed to add columns", K(ret)); // } else if (OB_FAIL(prune_columns_for_ddl(table_item, table_info.column_exprs_))) { // LOG_WARN("failed to prune columns for ddl", K(ret)); } else { table_info.table_id_ = table_item.table_id_; table_info.loc_table_id_ = base_table_item.table_id_; table_info.ref_table_id_ = base_table_item.ref_id_; table_info.table_name_ = table_schema->get_table_name_str(); table_info.is_link_table_ = base_table_item.is_link_table(); } } else { uint64_t view_id = OB_INVALID_ID; if (add_column && OB_FAIL(add_all_columns_to_stmt_for_trigger(table_item, table_info.column_exprs_))) { LOG_WARN("failed to add columns to stmt for trigger", K(ret)); } else if (OB_FAIL(get_view_id_for_trigger(table_item, view_id))) { LOG_WARN("get view id failed", K(table_item), K(ret)); } else { table_info.table_id_ = table_item.table_id_; table_info.loc_table_id_ = table_item.table_id_; table_info.ref_table_id_ = view_id; table_info.table_name_ = table_item.table_name_; } } if (OB_SUCC(ret) && gindex_cnt > 0) { del_upd_stmt->set_has_global_index(true); } return ret; } int ObDelUpdResolver::replace_gen_col_dependent_col(ObInsertTableInfo& table_info) { int ret = OB_SUCCESS; ObColumnRefRawExpr* col_expr = NULL; for (int64_t i = 0; OB_SUCC(ret) && i < table_info.column_exprs_.count(); i++) { if (OB_ISNULL(col_expr = table_info.column_exprs_.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (!col_expr->is_generated_column()) { // do nothing } else if (i >= table_info.column_conv_exprs_.count() || OB_ISNULL(table_info.column_conv_exprs_.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid null column conv function", K(ret), K(i), K(table_info.column_conv_exprs_.count())); } else if (OB_FAIL(replace_col_with_new_value(table_info, table_info.column_conv_exprs_.at(i)))) { LOG_WARN("failed to replace col with new value", K(ret)); } } return ret; } int ObDelUpdResolver::replace_col_with_new_value(ObInsertTableInfo& table_info, ObRawExpr *&expr) { int ret = OB_SUCCESS; const ObIArray &all_cols = table_info.column_exprs_; const ObIArray &conv_funcs = table_info.column_conv_exprs_; 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, c3 int as(c1+c2)); // insert into t1(c1) values(1); // values_desc: c1 // dep_cols: c1, c2 // after remove dup: c2 int ObDelUpdResolver::remove_dup_dep_cols_for_heap_table(ObIArray& dep_cols, const ObIArray& values_desc) { int ret = OB_SUCCESS; if (0 == dep_cols.count()) { // do nothing } else { 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; } int ObDelUpdResolver::check_insert_column_duplicate(uint64_t column_id, bool &is_duplicate) { int ret = OB_SUCCESS; is_duplicate = false; 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 ObDelUpdResolver::add_new_sel_item_for_oracle_label_security_table(ObDmlTableInfo& table_info, ObIArray& the_missing_label_se_columns, ObSelectStmt &select_stmt) { int ret = OB_SUCCESS; ObSEArray select_items; for (int64_t i = 0; OB_SUCC(ret) && i < the_missing_label_se_columns.count(); ++i) { SelectItem select_item; ObRawExpr *session_row_label_func = NULL; uint64_t column_id = the_missing_label_se_columns.at(i); if (OB_FAIL(create_session_row_label_expr(table_info, column_id, session_row_label_func))) { LOG_WARN("fail to create session row label expr", K(ret), K(column_id)); } else { select_item.expr_ = session_row_label_func; if (OB_FAIL(select_items.push_back(select_item))) { LOG_WARN("push subquery select items failed", K(ret)); } LOG_DEBUG("add sub select item", K(ret)); } } if (OB_SUCC(ret) && !select_items.empty()) { if (OB_FAIL(add_select_items(select_stmt, select_items))) { LOG_WARN("failed to add select items", K(ret)); } } return ret; } int ObDelUpdResolver::create_session_row_label_expr(ObDmlTableInfo& table_info, uint64_t column_id, ObRawExpr *&expr) { int ret = OB_SUCCESS; const ObDelUpdStmt *dep_upd_stmt = get_del_upd_stmt(); if (OB_ISNULL(params_.expr_factory_) || OB_ISNULL(schema_checker_) || OB_ISNULL(session_info_) || OB_ISNULL(dep_upd_stmt) || OB_INVALID_ID == column_id) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid arguemnt", K(ret), K(column_id), KPC(dep_upd_stmt)); } ObString policy_name; if (OB_SUCC(ret)) { uint64_t table_id = table_info.ref_table_id_; const ObColumnSchemaV2 *column_schema = NULL; if (OB_FAIL(get_column_schema(table_id, column_id, column_schema, true, ObSqlSchemaGuard::is_link_table(dep_upd_stmt, table_info.table_id_)))) { LOG_WARN("fail to get column item", K(ret), K(table_id), K(column_id)); } else if (OB_FAIL(schema_checker_->get_label_se_policy_name_by_column_name(session_info_->get_effective_tenant_id(), column_schema->get_column_name_str(), policy_name))) { LOG_WARN("fail to get label security policy name", K(ret)); } } ObConstRawExpr *policy_name_expr = NULL; if (OB_SUCC(ret)) { if (OB_FAIL(ObRawExprUtils::build_const_string_expr(*params_.expr_factory_, ObVarcharType, policy_name, ObCharset::get_default_collation(ObCharset::get_default_charset()), policy_name_expr))) { LOG_WARN("fail to build policy name expr", K(ret)); } else if (OB_ISNULL(policy_name_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("expr is NULL", K(ret)); } } ObSysFunRawExpr *session_row_label_func = NULL; if (OB_SUCC(ret)) { if (OB_FAIL(params_.expr_factory_->create_raw_expr(T_FUN_LABEL_SE_SESSION_ROW_LABEL, session_row_label_func))) { LOG_WARN("create raw expr failed", K(ret)); } else if (OB_ISNULL(session_row_label_func)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("dummy expr is null", K(session_row_label_func)); } else { ObString func_name(N_OLS_SESSION_ROW_LABEL); session_row_label_func->set_func_name(func_name); if (OB_FAIL(session_row_label_func->add_param_expr(policy_name_expr))) { LOG_WARN("fail to add param expr", K(ret)); } else if (OB_FAIL(session_row_label_func->formalize(session_info_))) { LOG_WARN("failed to do formalize", K(ret)); } } } if (OB_SUCC(ret)) { expr = session_row_label_func; } return ret; } int ObDelUpdResolver::add_select_items(ObSelectStmt &select_stmt, const ObIArray& select_items) { int ret = OB_SUCCESS; if (OB_ISNULL(params_.expr_factory_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("expr factory is null", K(ret)); } else if (!select_stmt.is_set_stmt()) { ObRawExprCopier copier(*params_.expr_factory_); if (deep_copy_stmt_objects(copier, select_items, select_stmt.get_select_items())) { LOG_WARN("failed to deep copy stmt objects", 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; } /** * set stmt的左右子查询添加select item后需要为set stmt创建select item */ int ObDelUpdResolver::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.is_real_alias_ = select_item.is_real_alias_ || ObRawExprUtils::is_column_ref_skip_implicit_cast(select_item.expr_); 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_)); } } } return ret; } //查询插入的查询项添加session_id值, //insert into t1 select c1,c2 ... --> //insert into t1 select c1,c2, session_id值 ... int ObDelUpdResolver::add_new_sel_item_for_oracle_temp_table(ObSelectStmt &select_stmt) { int ret = OB_SUCCESS; if (is_oracle_tmp_table_) { ObSysFunRawExpr *session_id_expr = NULL; ObConstRawExpr *temp_table_type = NULL; ObConstRawExpr *sess_create_time_expr = NULL; ObSEArray select_items; SelectItem select_item; select_item.is_implicit_added_ = true; if (OB_FAIL(params_.expr_factory_->create_raw_expr(T_FUN_GET_TEMP_TABLE_SESSID, 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_FAIL(params_.expr_factory_->create_raw_expr(T_INT, temp_table_type))) { LOG_WARN("create raw expr failed", K(ret)); } else if (OB_ISNULL(session_id_expr) || OB_ISNULL(sess_create_time_expr) || OB_ISNULL(temp_table_type)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("dummy expr is null", K(ret)); } if (OB_SUCC(ret)) { ObObj val; val.set_int(oracle_tmp_table_type_); temp_table_type->set_value(val); } if (OB_SUCC(ret)) { session_id_expr->set_func_name(N_TEMP_TABLE_SSID); select_item.expr_ = session_id_expr; if (OB_FAIL(session_id_expr->add_param_expr(temp_table_type))) { LOG_WARN("fail to add param expr", K(ret)); } else if (OB_FAIL(session_id_expr->formalize(session_info_))) { LOG_WARN("fail to formalize expr", K(ret)); } else if (OB_FAIL(select_items.push_back(select_item))) { LOG_WARN("push subquery select items failed", K(ret)); } } if (OB_SUCC(ret)) { ObObj val; val.set_int(0); sess_create_time_expr->set_value(val); select_item.expr_ = sess_create_time_expr; if (OB_FAIL(sess_create_time_expr->formalize(session_info_))) { LOG_WARN("fail to formalize expr", K(ret)); } else if (OB_FAIL(select_items.push_back(select_item))) { LOG_WARN("push subquery select items failed", K(ret)); } } if (OB_SUCC(ret)) { 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; } // 值插入、查询插入对oracle临时表都要添加__session_id和__sess_create_time字段到目标列 int ObDelUpdResolver::add_new_column_for_oracle_temp_table(uint64_t ref_table_id, uint64_t table_id /* = OB_INVALID_ID */, ObDMLStmt *stmt /* = NULL */) { int ret = OB_SUCCESS; if (is_oracle_tmp_table_) { const share::schema::ObColumnSchemaV2 *column_schema = NULL; const share::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(get_table_schema(table_id, ref_table_id, stmt, 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)) { if (OB_FAIL(mock_values_column_ref(session_id_expr))) { LOG_WARN("mock values column reference failed", K(ret)); } else if (OB_FAIL(mock_values_column_ref(sess_create_time_expr))) { LOG_WARN("mock values column reference failed", K(ret)); } } } return ret; } // 值插入、查询插入对oracle临时表的都要添加__session_id字段到values int ObDelUpdResolver::add_new_value_for_oracle_temp_table(ObIArray &value_row) { int ret = OB_SUCCESS; if (is_oracle_tmp_table_) { ObSysFunRawExpr *session_id_expr = NULL; ObConstRawExpr *sess_create_time_expr = NULL; ObConstRawExpr *temp_table_type = NULL; if (OB_ISNULL(session_info_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid session_info_ ", K(session_info_)); } else if (OB_FAIL(params_.expr_factory_->create_raw_expr(T_FUN_GET_TEMP_TABLE_SESSID, 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_FAIL(params_.expr_factory_->create_raw_expr(T_INT, temp_table_type))) { LOG_WARN("create raw expr failed", K(ret)); } else if (OB_ISNULL(session_id_expr) || OB_ISNULL(sess_create_time_expr) || OB_ISNULL(temp_table_type)) { 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(0); sess_create_time_expr->set_value(val); session_id_expr->set_func_name(N_TEMP_TABLE_SSID); val.set_int(oracle_tmp_table_type_); temp_table_type->set_value(val); if (OB_FAIL(session_id_expr->add_param_expr(temp_table_type))) { LOG_WARN("fail to add param expr", K(ret)); } else if (OB_FAIL(session_id_expr->formalize(session_info_))) { LOG_WARN("fail to formalize expr", K(ret)); } else if (OB_FAIL(sess_create_time_expr->formalize(session_info_))) { LOG_WARN("fail to formalize expr", K(ret)); } else if (OB_FAIL(value_row.push_back(session_id_expr))) { LOG_WARN("push back to output expr failed", K(ret)); } else 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)); } } return ret; } //如果指定column没有label security列,在这里加上这一列,创建表达式指定插入的值为session write label int ObDelUpdResolver::add_new_column_for_oracle_label_security_table(ObIArray& the_missing_label_se_columns, uint64_t ref_table_id, uint64_t table_id /* = OB_INVALID_ID */, ObDMLStmt *stmt /* = NULL */) { int ret = OB_SUCCESS; const ObTableSchema *table_schema = 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(get_table_schema(table_id, ref_table_id, stmt, 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 { for (int64_t i = 0; OB_SUCC(ret) && i < the_missing_label_se_columns.count(); ++i) { uint64_t column_id = the_missing_label_se_columns.at(i); const share::schema::ObColumnSchemaV2 *column_schema = NULL; ObColumnRefRawExpr *label_se_column_expr = NULL; if (OB_ISNULL(column_schema = table_schema->get_column_schema(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, label_se_column_expr))) { LOG_WARN("build column expr failed", K(ret)); } else if (OB_ISNULL(label_se_column_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("build expr is NULL", K(ret)); } else if (OB_FAIL(label_se_column_expr->formalize(session_info_))) { LOG_WARN("fail to formalize rowkey", KPC(label_se_column_expr), K(ret)); } else { label_se_column_expr->set_ref_id(table_schema->get_table_id(), column_schema->get_column_id()); label_se_column_expr->set_column_attr(table_schema->get_table_name(), column_schema->get_column_name_str()); if (OB_FAIL(mock_values_column_ref(label_se_column_expr))) { LOG_WARN("mock values column reference failed", K(ret)); } } } } return ret; } int ObDelUpdResolver::add_new_value_for_oracle_label_security_table(ObDmlTableInfo& table_info, ObIArray& the_missing_label_se_columns, ObIArray &value_row) { int ret = OB_SUCCESS; for (int64_t i = 0; OB_SUCC(ret) && i < the_missing_label_se_columns.count(); ++i) { ObRawExpr *session_row_label_func = NULL; uint64_t column_id = the_missing_label_se_columns.at(i); if (OB_FAIL(create_session_row_label_expr(table_info, column_id, session_row_label_func))) { LOG_WARN("fail to create session row label expr", K(ret), K(column_id)); } else if (OB_FAIL(value_row.push_back(session_row_label_func))) { LOG_WARN("push back to output expr failed", K(ret)); } LOG_DEBUG("add session row label expr", K(session_row_label_func), K(value_row), K(lbt())); } return ret; } int ObDelUpdResolver::resolve_insert_update_assignment(const ParseNode *node, ObInsertTableInfo& table_info) { int ret = OB_SUCCESS; ObSEArray tables_assign; if (OB_ISNULL(node) || T_ASSIGN_LIST != node->type_) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(node)); } else if (OB_FAIL(resolve_assignments(*node, tables_assign, T_UPDATE_SCOPE))) { LOG_WARN("resolve assignment error", K(ret)); } else if (OB_FAIL(resolve_additional_assignments(tables_assign, T_INSERT_SCOPE))) { LOG_WARN("resolve additional assignment error", K(ret)); } else if (tables_assign.count() != 1) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Table assignments in insert_stmt should only one table", K(ret), K(tables_assign)); } else if (OB_FAIL(table_info.assignments_.assign(tables_assign.at(0).assignments_))) { LOG_WARN("failed to assign assignmnts", K(ret)); } else if (OB_FAIL(add_relation_columns(tables_assign))) { LOG_WARN("Add needed columns error", K(ret)); } return ret; } int ObDelUpdResolver::add_relation_columns(ObIArray &table_assigns) { int ret = OB_SUCCESS; ObDelUpdStmt *del_upd_stmt = get_del_upd_stmt(); ObTableAssignment &table_assign = table_assigns.at(0); ObSEArray dml_table_infos; if (OB_ISNULL(del_upd_stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("fail to get insert stmt", K(del_upd_stmt)); } else if (OB_FAIL(del_upd_stmt->get_dml_table_infos(dml_table_infos))) { LOG_WARN("failed to get dml table infos", K(ret)); } else if (dml_table_infos.count() != 1 || OB_ISNULL(dml_table_infos.at(0))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected dml table infos", K(dml_table_infos), K(ret)); } else if (dml_table_infos.at(0)->table_id_ != table_assign.table_id_) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Table assignment should be the table of del_upd_stmt", K(table_assign.table_id_), K(dml_table_infos.at(0)->table_id_), K(ret)); } else { //add auto_incrememnt column const ObIArray& table_columns = dml_table_infos.at(0)->column_exprs_; ObIArray &auto_params = del_upd_stmt->get_autoinc_params(); 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 = del_upd_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 ObDelUpdResolver::replace_column_ref(ObArray *value_row, ObRawExpr *&expr, bool in_generated_column) { //对于merge stmt,该function并不对expr进行替换 UNUSED(expr); UNUSED(value_row); UNUSED(in_generated_column); return OB_SUCCESS; } int ObDelUpdResolver::get_label_se_columns(ObInsertTableInfo& table_info, ObIArray& label_se_columns) { int ret = OB_SUCCESS; //handle label security columns //统计哪些安全列没有插入,后面做特殊处理 ObDelUpdStmt *del_upd_stmt = get_del_upd_stmt(); if (OB_ISNULL(del_upd_stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("fail to get insert stmt", K(del_upd_stmt)); } else if (!del_upd_stmt->has_instead_of_trigger()) { const ObTableSchema *table_schema = NULL; if (OB_FAIL(get_table_schema(table_info.table_id_, table_info.ref_table_id_, del_upd_stmt, 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 (table_schema->has_label_se_column()) { const ObIArray &label_se_column_ids = table_schema->get_label_se_column_ids(); for (int64_t i = 0; OB_SUCC(ret) && i < label_se_column_ids.count(); ++i) { bool label_se_column_already_handled = false; uint64_t column_id = label_se_column_ids.at(i); if (OB_FAIL(check_insert_column_duplicate(column_id, label_se_column_already_handled))) { LOG_WARN("fail to check insert column duplicate", K(ret)); } else { if (!label_se_column_already_handled) { if (OB_FAIL(label_se_columns.push_back(column_id))) { //record for label se columns LOG_WARN("push back to array failed", K(ret)); } } else { //do nothing } } } } } return ret; } int ObDelUpdResolver::prune_columns_for_ddl(const TableItem &table_item, ObIArray &column_exprs) { int ret = OB_SUCCESS; if (OB_ISNULL(session_info_) || OB_ISNULL(schema_checker_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(session_info_), K(schema_checker_)); } else if (session_info_->get_ddl_info().is_ddl()) { const ObTableSchema *ddl_table_schema = nullptr; uint64_t ddl_table_id = table_item.ddl_table_id_; ObSEArray tmp_column_exprs; if (OB_FAIL(tmp_column_exprs.assign(column_exprs))) { LOG_WARN("failed to assign column exprs", K(ret)); } else if (OB_FAIL(schema_checker_->get_table_schema(session_info_->get_effective_tenant_id(), ddl_table_id, ddl_table_schema))) { LOG_WARN("not find table schema", K(ret), K(table_item), K(ddl_table_id)); } else if (nullptr == ddl_table_schema) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get illegal table schema", K(ddl_table_schema)); } else { column_exprs.reuse(); for (int64_t i = 0; OB_SUCC(ret) && i < tmp_column_exprs.count(); ++i) { ObColumnRefRawExpr* column = tmp_column_exprs.at(i); bool has_column = false; if (OB_ISNULL(column)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(column)); } else if (OB_FAIL(ddl_table_schema->has_column(column->get_column_id(), has_column))) { LOG_WARN("faild to check schema has column", K(ret)); } else if (!has_column) { // do nothing } else if (OB_FAIL(column_exprs.push_back(column))) { LOG_WARN("failed to push back column expr", K(ret)); } } } } return ret; } int ObDelUpdResolver::replace_column_ref_for_check_constraint(ObInsertTableInfo& table_info, ObRawExpr *&expr) { int ret = OB_SUCCESS; if (OB_ISNULL(expr) || OB_ISNULL(params_.expr_factory_)) { LOG_WARN("invalid argument", K(expr)); ret = OB_INVALID_ARGUMENT; } else if (ObRawExprUtils::find_expr(table_info.column_conv_exprs_, expr)) { // do nothing } else if (expr->get_param_count() > 0) { for (int64_t i = 0; OB_SUCC(ret) && i < expr->get_param_count(); i++) { if (OB_FAIL(SMART_CALL(replace_column_ref_for_check_constraint(table_info, expr->get_param_expr(i))))) { LOG_WARN("replace column ref for check constraint", K(ret), KPC(expr->get_param_expr(i))); } } } else if (expr->is_column_ref_expr()) { const ObIArray& insert_columns = table_info.column_exprs_; ObColumnRefRawExpr *b_expr = static_cast(expr); if (OB_ISNULL(b_expr)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid expr or insert_columns", K(b_expr)); } 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 = table_info.column_conv_exprs_.at(index); } } } } return ret; } int ObDelUpdResolver::add_default_sequence_id_to_stmt(const uint64_t table_id) { int ret = OB_SUCCESS; ObDelUpdStmt *del_upd_stmt = nullptr; if (OB_ISNULL(del_upd_stmt = get_del_upd_stmt())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("stmt is NULL", K(ret)); } else { for (int64_t i = 0; i < del_upd_stmt->get_column_items().count() && OB_SUCC(ret); i++) { const ObRawExpr *default_expr = NULL; if (del_upd_stmt->get_column_items().at(i).table_id_ == table_id && NULL != (default_expr = del_upd_stmt->get_column_items().at(i).default_value_expr_) && default_expr->has_flag(CNT_SEQ_EXPR)) { if (OB_FAIL(recursive_search_sequence_expr(default_expr))) { LOG_WARN("recursive search sequence expr failed", K(ret)); } } } } return ret; } int ObDelUpdResolver::recursive_search_sequence_expr(const ObRawExpr *default_expr) { int ret = OB_SUCCESS; if (OB_ISNULL(default_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("expr is null", K(ret)); } else if (default_expr->has_flag(IS_SEQ_EXPR)) { const ObSequenceRawExpr *seq_raw_expr = static_cast(default_expr); int64_t sequence_id = seq_raw_expr->get_sequence_id(); const ObString &action = seq_raw_expr->get_action(); if (OB_FAIL(add_sequence_id_to_stmt(sequence_id, 0 == action.case_compare("CURRVAL")))) { LOG_WARN("add sequence id to stmt failed", K(ret)); } } else { for (int64_t i = 0; i < default_expr->get_param_count() && OB_SUCC(ret); i++) { const ObRawExpr *child_expr = default_expr->get_param_expr(i); if (child_expr->has_flag(CNT_SEQ_EXPR) && OB_FAIL(SMART_CALL(recursive_search_sequence_expr(child_expr)))) { LOG_WARN("resursive search sequence expr failed", K(ret)); } } } return ret; } int ObDelUpdResolver::check_need_match_all_params(const common::ObIArray &value_descs, bool &need_match) { int ret = OB_SUCCESS; need_match = false; ObSEArray col_ids; ObBitSet<> column_bs; for (int64_t i = 0; OB_SUCC(ret) && i < value_descs.count() && !need_match; ++i) { ObColumnRefRawExpr *value_desc = value_descs.at(i); if (OB_ISNULL(value_desc)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("value desc is null", K(ret), K(value_descs)); } else if (OB_FAIL(column_bs.add_member(value_desc->get_column_id()))) { LOG_WARN("add column id failed", K(ret)); } } //if a depend column exists in value_desc, need match the datatypes of all params for (int64_t i = 0; OB_SUCC(ret) && i < value_descs.count() && !need_match; ++i) { if (value_descs.at(i)->is_generated_column()) { col_ids.reset(); if (OB_FAIL(ObRawExprUtils::extract_column_ids(value_descs.at(i)->get_dependant_expr(), col_ids))) { LOG_WARN("extract column exprs failed", K(ret)); } else { for (int64_t j = 0; j < col_ids.count() && !need_match; ++j) { if (column_bs.has_member(col_ids.at(j))) { need_match = true; } } } } } return ret; } } /* namespace sql */ } /* namespace oceanbase */