Files
oceanbase/src/sql/resolver/dml/ob_del_upd_resolver.cpp
2023-12-14 09:17:42 +00:00

4598 lines
209 KiB
C++

/**
* 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<ObAssignment> &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<ObAssignment> &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 &params)
: 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<ObTableAssignment> &table_assigns,
ObStmtScope scope)
{
int ret = OB_SUCCESS;
ObDMLStmt *stmt = get_stmt();
ObSEArray<ObColumnRefRawExpr *, 8> column_list;
ObSEArray<ObRawExpr*, 8> 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, &params_, 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, &params_, 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<ObColumnRefRawExpr *> &target_list,
ObIArray<ObRawExpr *> &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<ObUpdateStmt*>(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<ColumnItem> 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<ObColumnRefRawExpr *, 4> columns;
ObSEArray<ObRawExpr *, 4> 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<ObQueryRefRawExpr *>(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<ObConstRawExpr*>(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<ObObjParam &>(
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<ObQueryRefRawExpr *>(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<ObColumnRefRawExpr *> &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<ObColumnRefRawExpr *>(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<ObColumnRefRawExpr *>(col_expr)))) {
LOG_WARN("failed to push back column expr", K(ret));
}
}
}
return ret;
}
int ObDelUpdResolver::generate_wrapper_expr_for_assignemnts(ObIArray<ObAssignment> &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<ObTableAssignment> &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<ObColumnRefRawExpr *, 1> 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, &params_, 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<ObTableAssignment> &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<ObAssignment> &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<uint64_t> 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<ObColumnRefRawExpr *>(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<ObColumnRefRawExpr *>(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<ObColumnRefRawExpr *>(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<ObColumnRefRawExpr *>(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<char *>(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<ObSelectStmt &>(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<ObSelectStmt &>(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<int>(strlen(err_log_default_columns_[index])), err_log_default_columns_[index]);
} else {
// TODO oracle默认的5列类型不能为LONG 由于暂时不支持LONG类型,所以暂时不做检查
// 暂时不实现 ORA_ERR_TAG$ 列
}
index++;
} else {
ObSEArray<ObDmlTableInfo*, 2> 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<uint64_t> 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<ObDmlTableInfo*, 1> 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<ObColumnRefRawExpr *>(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<int32_t>(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<ObString> 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<ObRawExpr*, 4> rowkey_exprs;
ObSEArray<ObDmlTableInfo*, 1> 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<ObColumnRefRawExpr*> &all_cols,
ObIArray<ObRawExpr*> &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<uint64_t, 4> 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<ObColumnRefRawExpr*> &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<ObColumnRefRawExpr*> &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<ObColumnRefRawExpr*> &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<ObColumnRefRawExpr*> &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<ObColumnRefRawExpr *> &column_items)
{
int ret = OB_SUCCESS;
ColumnItem *col_item = NULL;
ObDelUpdStmt *del_upd_stmt = dynamic_cast<ObDelUpdStmt*>(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<ObColumnRefRawExpr*> &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<ObColumnRefRawExpr *> &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<ObColumnRefRawExpr*> &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<uint64_t, 2> 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<ObColumnRefRawExpr *, 8> pk_cols;
ObSEArray<ObRawExpr *, 8> 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<uint64_t> &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<ObDelUpdStmt *>(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<ObRawExpr *, 4> view_columns;
ObSEArray<ObRawExpr *, 4> 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<ObRawExpr *> &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<ObObjAccessRawExpr*>(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<const pl::ObRecordType*>(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<ObRawExpr*> &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<const ObConstRawExpr*>(expr->get_param_expr(2));
ObColumnRefRawExpr *col_expr = static_cast<ObColumnRefRawExpr *>(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<ObRawExpr*> &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<ObRawExpr *, 4> view_columns;
ObSEArray<ObRawExpr *, 4> base_columns;
ObSEArray<ObRawExpr *, 4> 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<ObRawExpr *> &view_columns,
ObIArray<ObRawExpr *> &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<ObColumnRefRawExpr *>(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, &params_, 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, &params_, 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<ObInsertStmt*>(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<ObColumnRefRawExpr*>(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<ColumnItem> 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<ObMergeResolver*>(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<ObRawExpr*> value_row;
ObArray<int64_t> 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<ObColumnRefRawExpr*> 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, &params_, 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<ObColumnRefRawExpr*> &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<ObRawExpr*> *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<ObRawExpr*> &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, &params_, static_cast<ObDMLResolver*>(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<uint64_t, 8> 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<uint64_t> &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<ObColumnRefRawExpr *, 1> 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<ObColumnRefRawExpr*> &all_cols = table_info.column_exprs_;
const ObIArray<ObRawExpr*> &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<ObColumnRefRawExpr*>& dep_cols,
const ObIArray<ObColumnRefRawExpr*>& values_desc)
{
int ret = OB_SUCCESS;
if (0 == dep_cols.count()) {
// do nothing
} else {
ObSEArray<ObColumnRefRawExpr*, 4> 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<uint64_t>& the_missing_label_se_columns,
ObSelectStmt &select_stmt)
{
int ret = OB_SUCCESS;
ObSEArray<SelectItem, 2> 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<SelectItem>& 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<SelectItem>(copier,
select_items,
select_stmt.get_select_items())) {
LOG_WARN("failed to deep copy stmt objects", K(ret));
}
} else {
ObIArray<ObSelectStmt*> &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<ObItemType>(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<SelectItem, 4> 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<ObRawExpr*> &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<uint64_t>& 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<uint64_t>& the_missing_label_se_columns,
ObIArray<ObRawExpr*> &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<ObTableAssignment, 2> 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<ObTableAssignment> &table_assigns)
{
int ret = OB_SUCCESS;
ObDelUpdStmt *del_upd_stmt = get_del_upd_stmt();
ObTableAssignment &table_assign = table_assigns.at(0);
ObSEArray<ObDmlTableInfo*, 2> 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<ObColumnRefRawExpr*>& table_columns = dml_table_infos.at(0)->column_exprs_;
ObIArray<share::AutoincParam> &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<ObRawExpr*> *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<uint64_t>& 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<uint64_t> &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<ObColumnRefRawExpr*> &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<ObColumnRefRawExpr*, 8> 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<ObColumnRefRawExpr*>& insert_columns = table_info.column_exprs_;
ObColumnRefRawExpr *b_expr = static_cast<ObColumnRefRawExpr*>(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<const ObSequenceRawExpr *>(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<ObColumnRefRawExpr*> &value_descs, bool &need_match)
{
int ret = OB_SUCCESS;
need_match = false;
ObSEArray<uint64_t, 4> 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 */