patch 4.0
This commit is contained in:
@ -14,6 +14,7 @@
|
||||
#include "sql/resolver/dml/ob_delete_resolver.h"
|
||||
#include "sql/session/ob_sql_session_info.h"
|
||||
#include "sql/resolver/ob_resolver_utils.h"
|
||||
#include "sql/optimizer/ob_optimizer_util.h"
|
||||
|
||||
/**
|
||||
* DELETE syntax from MySQL 5.7
|
||||
@ -36,102 +37,104 @@
|
||||
* USING table_references
|
||||
* [WHERE where_condition]
|
||||
*/
|
||||
namespace oceanbase {
|
||||
namespace oceanbase
|
||||
{
|
||||
using namespace common;
|
||||
using namespace share;
|
||||
using namespace share::schema;
|
||||
namespace sql {
|
||||
ObDeleteResolver::ObDeleteResolver(ObResolverParams& params) : ObDMLResolver(params)
|
||||
namespace sql
|
||||
{
|
||||
ObDeleteResolver::ObDeleteResolver(ObResolverParams ¶ms)
|
||||
: ObDelUpdResolver(params)
|
||||
{
|
||||
params.contain_dml_ = true;
|
||||
}
|
||||
|
||||
ObDeleteResolver::~ObDeleteResolver()
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
int ObDeleteResolver::resolve(const ParseNode& parse_tree)
|
||||
int ObDeleteResolver::resolve(const ParseNode &parse_tree)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
ParseNode* table_node = parse_tree.children_[TABLE];
|
||||
|
||||
// create the delete stmt
|
||||
ObDeleteStmt* delete_stmt = NULL;
|
||||
ObDeleteStmt *delete_stmt = NULL;
|
||||
bool is_multi_table_delete = false;
|
||||
if (NULL == (delete_stmt = create_stmt<ObDeleteStmt>())) {
|
||||
ret = OB_ALLOCATE_MEMORY_FAILED;
|
||||
LOG_ERROR("create delete stmt failed");
|
||||
LOG_ERROR("create delete stmt failed", K(ret));
|
||||
} else if (OB_UNLIKELY(parse_tree.type_ != T_DELETE) || OB_UNLIKELY(parse_tree.num_child_ < 2)) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("parse tree type is invalid", K_(parse_tree.type), K_(parse_tree.num_child));
|
||||
} else if (OB_ISNULL(table_node)) {
|
||||
} else if (OB_ISNULL(parse_tree.children_[TABLE])) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("table_node is null");
|
||||
LOG_WARN("table_node is null", K(ret));
|
||||
} else {
|
||||
stmt_ = delete_stmt;
|
||||
if (OB_FAIL(resolve_table_list(*table_node, is_multi_table_delete))) {
|
||||
if (OB_FAIL(resolve_outline_data_hints())) {
|
||||
LOG_WARN("resolve outline data hints failed", K(ret));
|
||||
} else if (OB_FAIL(resolve_table_list(*parse_tree.children_[TABLE], is_multi_table_delete))) {
|
||||
LOG_WARN("resolve table failed", K(ret));
|
||||
}
|
||||
}
|
||||
for (int64_t i = 0; OB_SUCC(ret) && i < delete_tables_.count(); ++i) {
|
||||
const TableItem* table_item = delete_tables_.at(i);
|
||||
CK(OB_NOT_NULL(table_item));
|
||||
OZ(add_related_columns_to_stmt(*table_item));
|
||||
OZ(resolve_global_delete_index_info(*table_item));
|
||||
}
|
||||
|
||||
if (OB_SUCC(ret)) {
|
||||
if (OB_FAIL(resolve_where_clause(parse_tree.children_[WHERE]))) {
|
||||
LOG_WARN("resolve delete where clause failed", K(ret));
|
||||
} else if (OB_FAIL(resolve_order_clause(parse_tree.children_[ORDER_BY]))) {
|
||||
LOG_WARN("resolve delete order clause failed", K(ret));
|
||||
} else if (OB_FAIL(resolve_limit_clause(parse_tree.children_[LIMIT]))) {
|
||||
LOG_WARN("resolve delete limit clause failed", K(ret));
|
||||
} else if (OB_FAIL(resolve_hints(parse_tree.children_[HINT]))) {
|
||||
LOG_WARN("resolve hints failed", K(ret));
|
||||
} else if (OB_FAIL(resolve_returning(parse_tree.children_[RETURNING]))) {
|
||||
LOG_WARN("resolve returning failed", K(ret));
|
||||
} else if (OB_FAIL(delete_stmt->formalize_stmt(session_info_))) {
|
||||
LOG_WARN("pull stmt all expr relation ids failed", K(ret));
|
||||
} else if (is_oracle_mode() && OB_FAIL(resolve_check_constraints(delete_stmt->get_table_item(0)))) {
|
||||
LOG_WARN("resolve check constraint failed", K(ret));
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; OB_SUCC(ret) && i < delete_tables_.count(); i++) {
|
||||
const TableItem* table_item = delete_tables_.at(i);
|
||||
if (OB_FAIL(try_add_rowid_column_to_stmt(*table_item))) {
|
||||
LOG_WARN("failed to try adding rowid column", K(ret));
|
||||
}
|
||||
} // for end
|
||||
|
||||
if (OB_SUCC(ret)) {
|
||||
TableItem* delete_table = NULL;
|
||||
if (OB_FAIL(view_pullup_part_exprs())) {
|
||||
LOG_WARN("view pull up part exprs failed", K(ret));
|
||||
} else if (OB_FAIL(check_view_deletable())) {
|
||||
LOG_TRACE("view not deletable", K(ret));
|
||||
} else if (delete_stmt->get_from_item_size() == 1 &&
|
||||
NULL != (delete_table = delete_stmt->get_table_item(delete_stmt->get_from_item(0))) &&
|
||||
delete_table->is_basic_table()) {
|
||||
// do nothing
|
||||
} else {
|
||||
delete_stmt->set_dml_source_from_join(true);
|
||||
for (int64_t i = 0; OB_SUCC(ret) && i < delete_tables_.count(); ++i) {
|
||||
const TableItem *table_item = delete_tables_.at(i);
|
||||
if (OB_ISNULL(table_item)) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("get unexpected null", K(ret));
|
||||
} else if (OB_FAIL(generate_delete_table_info(*table_item))) {
|
||||
LOG_WARN("failed to generate delete table info", K(ret));
|
||||
} else if (is_oracle_mode() && !delete_stmt->has_instead_of_trigger()) {
|
||||
// resolve check constraint for disable and validate check
|
||||
ObSEArray<ObRawExpr*, 4> ck_exprs;
|
||||
if (OB_FAIL(resolve_check_constraints(table_item, ck_exprs))) {
|
||||
LOG_WARN("resolve check constraint failed", K(ret));
|
||||
}
|
||||
} else { /*do nothing*/ }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (OB_SUCC(ret)) {
|
||||
if (OB_FAIL(delete_stmt->check_dml_need_filter_null())) {
|
||||
LOG_WARN("failed to check dml need filter null", K(ret));
|
||||
} else if (OB_FAIL(check_safe_update_mode(delete_stmt, is_multi_table_delete))) {
|
||||
LOG_WARN("failed to check safe update mode", K(ret));
|
||||
} else {
|
||||
/*do nothing */
|
||||
if (OB_SUCC(ret)) {
|
||||
if (OB_FAIL(check_multi_delete_table_conflict())) {
|
||||
LOG_WARN("failed to check multi-delete table conflict", K(ret));
|
||||
}
|
||||
}
|
||||
|
||||
if (OB_SUCC(ret)) {
|
||||
if (OB_FAIL(resolve_where_clause(parse_tree.children_[WHERE]))) {
|
||||
LOG_WARN("resolve delete where clause failed", K(ret));
|
||||
} else if (OB_FAIL(resolve_order_clause(parse_tree.children_[ORDER_BY]))) {
|
||||
LOG_WARN("resolve delete order clause failed", K(ret));
|
||||
} else if (OB_FAIL(resolve_limit_clause(parse_tree.children_[LIMIT]))) {
|
||||
LOG_WARN("resolve delete limit clause failed", K(ret));
|
||||
} else if (OB_FAIL(resolve_hints(parse_tree.children_[HINT]))) {
|
||||
LOG_WARN("resolve hints failed", K(ret));
|
||||
} else if (OB_FAIL(resolve_returning(parse_tree.children_[RETURNING]))) {
|
||||
LOG_WARN("resolve returning failed", K(ret));
|
||||
} else if (is_oracle_mode() && NULL != parse_tree.children_[ERRORLOGGING] &&
|
||||
OB_FAIL(resolve_error_logging(parse_tree.children_[ERRORLOGGING]))) {
|
||||
LOG_WARN("failed to resolve error logging", K(ret));
|
||||
} else if (OB_FAIL(delete_stmt->formalize_stmt(session_info_))) {
|
||||
LOG_WARN("pull stmt all expr relation ids failed", K(ret));
|
||||
} else { /*do nothing*/ }
|
||||
}
|
||||
|
||||
if (OB_SUCC(ret)) {
|
||||
if (!delete_stmt->has_instead_of_trigger() && OB_FAIL(view_pullup_part_exprs())) {
|
||||
// instead of trigger的delete语句不需要 pull up
|
||||
LOG_WARN("view pull up part exprs failed", K(ret));
|
||||
} else if (OB_FAIL(check_view_deletable())) {
|
||||
LOG_WARN("failed to check view deletable", K(ret));
|
||||
} else if (OB_FAIL(delete_stmt->check_dml_need_filter_null())) {
|
||||
LOG_WARN("failed to check dml need filter null", K(ret));
|
||||
} else if (OB_FAIL(check_safe_update_mode(delete_stmt, is_multi_table_delete))) {
|
||||
LOG_WARN("failed to check safe update mode", K(ret));
|
||||
} else { /*do nothing */ }
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ObDeleteResolver::check_safe_update_mode(ObDeleteStmt* delete_stmt, bool is_multi_table_delete)
|
||||
int ObDeleteResolver::check_safe_update_mode(ObDeleteStmt *delete_stmt, bool is_multi_table_delete)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
bool is_sql_safe_updates = false;
|
||||
@ -141,25 +144,27 @@ int ObDeleteResolver::check_safe_update_mode(ObDeleteStmt* delete_stmt, bool is_
|
||||
} else if (OB_FAIL(params_.session_info_->get_sql_safe_updates(is_sql_safe_updates))) {
|
||||
LOG_WARN("failed to get is safe update mode", K(ret));
|
||||
} else if (is_sql_safe_updates) {
|
||||
/* Update table values in mysql safe mode, you need to meet:
|
||||
* Prerequisite: Single table deletion, not multi-table deletion, must contain where conditions;
|
||||
* At least one of the following conditions must be met:
|
||||
* 1. Contains limit, there are related columns in the where condition;
|
||||
* 2. The query range can be extracted in the where condition ==> Since the query range can only be extracted in the
|
||||
* optimizer stage, the condition is Check at the optimizer stage
|
||||
*/
|
||||
if (is_multi_table_delete || delete_stmt->get_condition_exprs().empty()) {
|
||||
/*mysql安全模式下更新表值,需要满足:
|
||||
* 前提条件:单表删除,不能是多表删除,必须含有where条件;
|
||||
* 下面条件二者至少满足其中一个:
|
||||
* 1.含有limit,where条件中有相关列存在;
|
||||
* 2.有where条件中能够抽取query range ==> 由于抽取query range只能在optimizer阶段才能够抽取,因此该条件在
|
||||
* optimizer阶段去检查
|
||||
*/
|
||||
if (is_multi_table_delete || delete_stmt->get_condition_exprs().empty()) {//前提条件
|
||||
ret = OB_ERR_SAFE_UPDATE_MODE_NEED_WHERE_OR_LIMIT;
|
||||
LOG_WARN("using safe update mode need WHERE or LIMIT", K(ret));
|
||||
} else if (delete_stmt->has_limit()) {
|
||||
} else if (delete_stmt->has_limit()) {//条件1
|
||||
bool is_const_expr = true;
|
||||
for (int64_t i = 0; OB_SUCC(ret) && is_const_expr && i < delete_stmt->get_condition_exprs().count(); ++i) {
|
||||
const ObRawExpr* expr = delete_stmt->get_condition_expr(i);
|
||||
for (int64_t i = 0;
|
||||
OB_SUCC(ret) && is_const_expr && i < delete_stmt->get_condition_exprs().count();
|
||||
++i) {
|
||||
const ObRawExpr *expr = delete_stmt->get_condition_expr(i);
|
||||
if (OB_ISNULL(expr)) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("get unexpected null", K(expr));
|
||||
} else {
|
||||
is_const_expr = expr->has_const_or_const_expr_flag();
|
||||
is_const_expr = expr->is_const_expr();
|
||||
}
|
||||
}
|
||||
if (OB_SUCC(ret) && is_const_expr) {
|
||||
@ -167,19 +172,49 @@ int ObDeleteResolver::check_safe_update_mode(ObDeleteStmt* delete_stmt, bool is_
|
||||
LOG_WARN("using safe update mode need WHERE or LIMIT", K(ret));
|
||||
}
|
||||
}
|
||||
} else { /*do nothing*/
|
||||
} else {/*do nothing*/}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ObDeleteResolver::check_multi_delete_table_conflict()
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
const ObDeleteStmt *delete_stmt = get_delete_stmt();
|
||||
if (OB_ISNULL(delete_stmt)) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("get unexpected null", K(ret));
|
||||
} else if (delete_stmt->get_delete_table_info().count() <= 1) {
|
||||
/*do nothing*/
|
||||
} else {
|
||||
const ObIArray<ObDeleteTableInfo*> &tables_info = delete_stmt->get_delete_table_info();
|
||||
for (int64_t i = 0; OB_SUCC(ret) && i < tables_info.count() - 1; ++i) {
|
||||
if (OB_ISNULL(tables_info.at(i))) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("get unexpected null", K(ret));
|
||||
} else {
|
||||
for (int64_t j = i + 1; OB_SUCC(ret) && j < tables_info.count(); ++j) {
|
||||
if (OB_ISNULL(tables_info.at(j))) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("get unexpected null", K(ret));
|
||||
} else if (tables_info.at(i)->ref_table_id_ == tables_info.at(j)->ref_table_id_) {
|
||||
ret = OB_NOT_SUPPORTED;
|
||||
LOG_USER_ERROR(OB_NOT_SUPPORTED, "multiple aliases to same table");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ObDeleteResolver::resolve_table_list(const ParseNode& table_list, bool& is_multi_table_delete)
|
||||
int ObDeleteResolver::resolve_table_list(const ParseNode &table_list, bool &is_multi_table_delete)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
TableItem* table_item = NULL;
|
||||
TableItem *table_item = NULL;
|
||||
is_multi_table_delete = false;
|
||||
const ParseNode* delete_list = NULL;
|
||||
const ParseNode* from_list = NULL;
|
||||
ObDeleteStmt* delete_stmt = get_delete_stmt();
|
||||
const ParseNode *delete_list = NULL;
|
||||
const ParseNode *from_list = NULL;
|
||||
ObDeleteStmt *delete_stmt = get_delete_stmt();
|
||||
|
||||
CK(T_DELETE_TABLE_NODE == table_list.type_);
|
||||
CK(2 == table_list.num_child_);
|
||||
@ -195,17 +230,18 @@ int ObDeleteResolver::resolve_table_list(const ParseNode& table_list, bool& is_m
|
||||
CK(OB_NOT_NULL(from_list->children_));
|
||||
|
||||
for (int64_t i = 0; OB_SUCC(ret) && i < from_list->num_child_; ++i) {
|
||||
const ParseNode* table_node = from_list->children_[i];
|
||||
const ParseNode *table_node = from_list->children_[i];
|
||||
CK(OB_NOT_NULL(table_node));
|
||||
if (OB_SUCC(ret)) {
|
||||
if (OB_FAIL(ObDMLResolver::resolve_table(*table_node, table_item))) {
|
||||
LOG_WARN("failed to resolve table", K(ret));
|
||||
} else if (table_item->is_function_table()) {
|
||||
} else if (table_item->is_function_table()) {//兼容oracle行为
|
||||
ret = OB_WRONG_TABLE_NAME;
|
||||
LOG_WARN("invalid table name", K(ret));
|
||||
} else if (OB_FAIL(column_namespace_checker_.add_reference_table(table_item))) {
|
||||
LOG_WARN("add reference table to namespace checker failed", K(ret));
|
||||
} else if (OB_FAIL(delete_stmt->add_from_item(table_item->table_id_, table_item->is_joined_table()))) {
|
||||
} else if (OB_FAIL(delete_stmt->add_from_item(table_item->table_id_,
|
||||
table_item->is_joined_table()))) {
|
||||
LOG_WARN("failed to add from item", K(ret));
|
||||
} else {
|
||||
/*
|
||||
@ -219,11 +255,16 @@ int ObDeleteResolver::resolve_table_list(const ParseNode& table_list, bool& is_m
|
||||
|
||||
if (OB_SUCC(ret)) {
|
||||
if (NULL == delete_list) {
|
||||
// single table delete, delete list is same with from list
|
||||
bool has_tg = false;
|
||||
//single table delete, delete list is same with from list
|
||||
CK(delete_stmt->get_table_size() == 1);
|
||||
OZ(delete_tables_.push_back(delete_stmt->get_table_item(0)));
|
||||
if (OB_SUCC(ret) && delete_stmt->get_table_item(0)->is_view_table_ && is_oracle_mode()) {
|
||||
OZ(has_need_fired_trigger_on_view(delete_stmt->get_table_item(0), has_tg));
|
||||
}
|
||||
OX(delete_stmt->set_has_instead_of_trigger(has_tg));
|
||||
} else {
|
||||
// multi table delete
|
||||
//multi table delete
|
||||
is_multi_table_delete = true;
|
||||
ObString table_name;
|
||||
ObString db_name;
|
||||
@ -232,21 +273,33 @@ int ObDeleteResolver::resolve_table_list(const ParseNode& table_list, bool& is_m
|
||||
table_name.reset();
|
||||
db_name.reset();
|
||||
table_item = NULL;
|
||||
const ParseNode* table_node = delete_list->children_[i];
|
||||
OZ(resolve_table_relation_node(table_node, table_name, db_name, true));
|
||||
OZ(find_delete_table_with_mysql_rule(db_name, table_name, table_item));
|
||||
OZ(delete_tables_.push_back(table_item));
|
||||
const ParseNode *table_node = delete_list->children_[i];
|
||||
if (OB_FAIL(resolve_table_relation_node(table_node, table_name, db_name, true))) {
|
||||
LOG_WARN("failed to resolve table relation node", K(ret));
|
||||
} else if (OB_FAIL(find_delete_table_with_mysql_rule(db_name, table_name, table_item))) {
|
||||
LOG_WARN("failed to find delete table with mysql rule", K(ret));
|
||||
} else if (OB_ISNULL(table_item)) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("get null table item", K(ret));
|
||||
} else if (OB_UNLIKELY(ObOptimizerUtil::find_item(delete_tables_, table_item))) {
|
||||
ret = OB_ERR_NONUNIQ_TABLE;
|
||||
LOG_USER_ERROR(OB_ERR_NONUNIQ_TABLE, table_item->table_name_.length(),
|
||||
table_item->table_name_.ptr());
|
||||
} else if (OB_FAIL(delete_tables_.push_back(table_item))) {
|
||||
LOG_WARN("failed to push back table item", K(ret));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (OB_SUCC(ret)) {
|
||||
FOREACH_CNT_X(table_item, delete_tables_, OB_SUCC(ret))
|
||||
{
|
||||
if (NULL != *table_item && (*table_item)->is_generated_table()) {
|
||||
if (OB_FAIL(set_base_table_for_view(*const_cast<TableItem*>(*table_item)))) {
|
||||
FOREACH_CNT_X(table_item, delete_tables_, OB_SUCC(ret)) {
|
||||
if (NULL != *table_item && ((*table_item)->is_generated_table() || (*table_item)->is_temp_table())) {
|
||||
if (!delete_stmt->has_instead_of_trigger()
|
||||
&& OB_FAIL(set_base_table_for_view(**table_item))) {
|
||||
LOG_WARN("set base table for delete view failed", K(ret));
|
||||
} else if (OB_FAIL(add_all_column_to_updatable_view(*delete_stmt, **table_item))) {
|
||||
} else if (OB_FAIL(add_all_column_to_updatable_view(*delete_stmt, **table_item,
|
||||
delete_stmt->has_instead_of_trigger()))) {
|
||||
LOG_WARN("add all column to updatable view failed", K(ret));
|
||||
}
|
||||
}
|
||||
@ -256,11 +309,12 @@ int ObDeleteResolver::resolve_table_list(const ParseNode& table_list, bool& is_m
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ObDeleteResolver::find_delete_table_with_mysql_rule(
|
||||
const ObString& db_name, const ObString& table_name, TableItem*& table_item)
|
||||
int ObDeleteResolver::find_delete_table_with_mysql_rule(const ObString &db_name,
|
||||
const ObString &table_name,
|
||||
TableItem *&table_item)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
ObDMLStmt* stmt = get_stmt();
|
||||
ObDMLStmt *stmt = get_stmt();
|
||||
CK(OB_NOT_NULL(stmt));
|
||||
CK(OB_NOT_NULL(session_info_));
|
||||
ObString final_db_name;
|
||||
@ -271,17 +325,17 @@ int ObDeleteResolver::find_delete_table_with_mysql_rule(
|
||||
if (table_items.count() == 1) {
|
||||
table_item = const_cast<TableItem*>(table_items.at(0));
|
||||
} else if (db_name.empty()) {
|
||||
// If there are multiple table_items in table_items, it means that the delete clause does not specify the
|
||||
// database_name of the table And all tables in the from clause are base tables, such as delete t1.* from db1.t1,
|
||||
// db2.t1; In this case, we think that the database_name in the delete clause is consistent with the session
|
||||
//如果table_items中有多个table_item,说明delete子句没有指定table的database_name
|
||||
//而from子句中所有表都是基表,例如delete t1.* from db1.t1, db2.t1;
|
||||
//这种情况下,我们认为delete子句中的database_name和session上的保持一致
|
||||
ObString final_db_name = session_info_->get_database_name();
|
||||
if (final_db_name.empty()) {
|
||||
ret = OB_ERR_NO_DB_SELECTED;
|
||||
LOG_WARN("no database selected");
|
||||
}
|
||||
for (int64_t i = 0; OB_SUCC(ret) && OB_ISNULL(table_item) && i < table_items.count(); ++i) {
|
||||
if (ObCharset::case_insensitive_equal(final_db_name, table_items.at(i)->database_name_) &&
|
||||
ObCharset::case_insensitive_equal(table_name, table_items.at(i)->table_name_)) {
|
||||
if (ObCharset::case_insensitive_equal(final_db_name, table_items.at(i)->database_name_)
|
||||
&& ObCharset::case_insensitive_equal(table_name, table_items.at(i)->table_name_)) {
|
||||
table_item = const_cast<TableItem*>(table_items.at(i));
|
||||
}
|
||||
}
|
||||
@ -292,151 +346,93 @@ int ObDeleteResolver::find_delete_table_with_mysql_rule(
|
||||
ret = OB_ERR_UNKNOWN_TABLE;
|
||||
ObString print_table_name = concat_table_name(db_name, table_name);
|
||||
ObString scope_name = ObString::make_string("MULTI DELETE");
|
||||
LOG_USER_ERROR(OB_ERR_UNKNOWN_TABLE,
|
||||
print_table_name.length(),
|
||||
print_table_name.ptr(),
|
||||
scope_name.length(),
|
||||
scope_name.ptr());
|
||||
} else if (!table_item->is_basic_table() && !table_item->is_generated_table()) {
|
||||
LOG_USER_ERROR(OB_ERR_UNKNOWN_TABLE, print_table_name.length(), print_table_name.ptr(),
|
||||
scope_name.length(), scope_name.ptr());
|
||||
} else if (!table_item->is_basic_table() && !table_item->is_generated_table() && !table_item->is_temp_table()) {
|
||||
ret = OB_ERR_NON_UPDATABLE_TABLE;
|
||||
ObString print_table_name = concat_table_name(db_name, table_name);
|
||||
ObString scope_name = ObString::make_string("DELETE");
|
||||
LOG_USER_ERROR(OB_ERR_NON_UPDATABLE_TABLE,
|
||||
print_table_name.length(),
|
||||
print_table_name.ptr(),
|
||||
scope_name.length(),
|
||||
scope_name.ptr());
|
||||
LOG_USER_ERROR(OB_ERR_NON_UPDATABLE_TABLE, print_table_name.length(), print_table_name.ptr(),
|
||||
scope_name.length(), scope_name.ptr());
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ObDeleteResolver::add_related_columns_to_stmt(const TableItem& table_item)
|
||||
int ObDeleteResolver::generate_delete_table_info(const TableItem &table_item)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
ObDeleteStmt* delete_stmt = get_delete_stmt();
|
||||
if (NULL == schema_checker_ || NULL == delete_stmt) {
|
||||
const TableItem &base_table_item = table_item.get_base_table_item();
|
||||
void *ptr = NULL;
|
||||
const ObTableSchema *table_schema = NULL;
|
||||
ObDeleteStmt *delete_stmt = get_delete_stmt();
|
||||
ObDeleteTableInfo *table_info = NULL;
|
||||
uint64_t index_tid[OB_MAX_INDEX_PER_TABLE];
|
||||
int64_t gindex_cnt = OB_MAX_INDEX_PER_TABLE;
|
||||
int64_t binlog_row_image = ObBinlogRowImage::FULL;
|
||||
if (OB_ISNULL(schema_checker_) || OB_ISNULL(params_.session_info_) ||
|
||||
OB_ISNULL(allocator_) || OB_ISNULL(delete_stmt)) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
SQL_RESV_LOG(WARN, "schema_checker_ or delete_stmt is null");
|
||||
}
|
||||
const ObTableSchema* table_schema = NULL;
|
||||
// Firstly, add primary index(data table) rowkey columns
|
||||
IndexDMLInfo* primary_dml_info = NULL;
|
||||
if (OB_SUCC(ret)) {
|
||||
if (NULL == (primary_dml_info = delete_stmt->get_or_add_table_columns(table_item.table_id_))) {
|
||||
ret = OB_ALLOCATE_MEMORY_FAILED;
|
||||
LOG_WARN("failed to get table columns", K(table_item));
|
||||
} else if (OB_FAIL(add_all_rowkey_columns_to_stmt(table_item, primary_dml_info->column_exprs_))) {
|
||||
LOG_WARN("add all rowkey columns to stmt failed", K(ret));
|
||||
}
|
||||
}
|
||||
if (OB_SUCC(ret)) {
|
||||
int64_t binlog_row_image = ObBinlogRowImage::FULL;
|
||||
if (OB_FAIL(params_.session_info_->get_binlog_row_image(binlog_row_image))) {
|
||||
LOG_WARN("fail to get binlog row image", K(ret));
|
||||
} else if (OB_FAIL(schema_checker_->get_table_schema(table_item.get_base_table_item().ref_id_, table_schema))) {
|
||||
SQL_RESV_LOG(WARN, "fail to get table schema", K(ret), K(table_item));
|
||||
} else if (OB_ISNULL(table_schema)) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("table_schema is null", K(ret), K(table_item.get_base_table_item().ref_id_));
|
||||
} else if (need_all_columns(*table_schema, binlog_row_image)) {
|
||||
if (OB_FAIL(add_all_columns_to_stmt(table_item, primary_dml_info->column_exprs_))) {
|
||||
LOG_WARN("fail to add all column to stmt", K(ret), K(table_item));
|
||||
LOG_WARN("get unexpected null", K(schema_checker_), K(params_.session_info_),
|
||||
K(allocator_), K(delete_stmt), 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("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(schema_checker_->get_can_write_index_array(params_.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(params_.session_info_->get_binlog_row_image(binlog_row_image))) {
|
||||
LOG_WARN("fail to get binlog row image", K(ret));
|
||||
} else if (NULL == (ptr = allocator_->alloc(sizeof(ObDeleteTableInfo)))) {
|
||||
ret = OB_ALLOCATE_MEMORY_FAILED;
|
||||
LOG_WARN("failed to allocate table info", K(ret));
|
||||
} else {
|
||||
table_info = new(ptr) ObDeleteTableInfo();
|
||||
if (OB_FAIL(table_info->part_ids_.assign(base_table_item.part_ids_))) {
|
||||
LOG_WARN("failed to assign part ids", K(ret));
|
||||
} else if (!delete_stmt->has_instead_of_trigger()) {
|
||||
// todo @zimiao error logging also need all columns ?
|
||||
if (OB_FAIL(add_all_rowkey_columns_to_stmt(table_item, table_info->column_exprs_))) {
|
||||
LOG_WARN("add all rowkey columns to stmt failed", K(ret));
|
||||
} else if (need_all_columns(*table_schema, binlog_row_image)) {
|
||||
if (OB_FAIL(add_all_columns_to_stmt(table_item, table_info->column_exprs_))) {
|
||||
LOG_WARN("fail to add all column to stmt", K(ret), K(table_item));
|
||||
}
|
||||
} else if (OB_FAIL(add_all_index_rowkey_to_stmt(table_item,
|
||||
table_info->column_exprs_))) {
|
||||
LOG_WARN("fail to add relate column to stmt", K(ret), K(table_item));
|
||||
}
|
||||
if (OB_SUCC(ret)) {
|
||||
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();
|
||||
}
|
||||
} else {
|
||||
uint64_t view_id = OB_INVALID_ID;
|
||||
if (OB_FAIL(add_all_columns_to_stmt_for_trigger(table_item, table_info->column_exprs_))) {
|
||||
LOG_WARN("failed to add all columns to stmt", 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_;
|
||||
}
|
||||
} else if (OB_FAIL(add_index_related_column_to_stmt(table_item, primary_dml_info->column_exprs_))) {
|
||||
LOG_WARN("fail to add relate column to stmt", K(ret), K(table_item));
|
||||
}
|
||||
if (OB_SUCC(ret)) {
|
||||
primary_dml_info->table_id_ = table_item.table_id_;
|
||||
primary_dml_info->loc_table_id_ = table_item.get_base_table_item().table_id_;
|
||||
primary_dml_info->index_tid_ = table_item.get_base_table_item().ref_id_;
|
||||
primary_dml_info->rowkey_cnt_ = table_schema->get_rowkey_column_num();
|
||||
primary_dml_info->part_cnt_ = table_schema->get_partition_cnt();
|
||||
primary_dml_info->index_name_ = table_schema->get_table_name_str();
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ObDeleteResolver::add_index_related_column_to_stmt(
|
||||
const TableItem& table_item, 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;
|
||||
ObDeleteStmt* delete_stmt = get_delete_stmt();
|
||||
CK(OB_NOT_NULL(schema_checker_));
|
||||
CK(OB_NOT_NULL(delete_stmt));
|
||||
if (OB_SUCC(ret)) {
|
||||
if (OB_FAIL(schema_checker_->get_can_write_index_array(
|
||||
table_item.get_base_table_item().ref_id_, idx_tids, idx_count))) {
|
||||
SQL_RESV_LOG(WARN, "get can write index array failed", K(ret));
|
||||
}
|
||||
}
|
||||
// Secondly, for each index, all all its rowkey
|
||||
ObArray<ObColumnRefRawExpr*> column_items;
|
||||
for (int64_t i = 0; OB_SUCC(ret) && i < idx_count; ++i) {
|
||||
column_items.reset();
|
||||
if (OB_FAIL(schema_checker_->get_table_schema(idx_tids[i], index_schema))) {
|
||||
SQL_RESV_LOG(WARN, "get index schema failed", "index_id", idx_tids[i]);
|
||||
} 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 ObDeleteResolver::resolve_global_delete_index_info(const TableItem& table_item)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
int64_t binlog_row_image = 0;
|
||||
IndexDMLInfo index_dml_info;
|
||||
ObAssignments empty_assignments;
|
||||
ObDeleteStmt* delete_stmt = get_delete_stmt();
|
||||
uint64_t index_tid[OB_MAX_INDEX_PER_TABLE];
|
||||
int64_t index_cnt = OB_MAX_INDEX_PER_TABLE;
|
||||
CK(OB_NOT_NULL(delete_stmt));
|
||||
CK(OB_NOT_NULL(params_.session_info_));
|
||||
OC((params_.session_info_->get_binlog_row_image)(binlog_row_image));
|
||||
OC((schema_checker_->get_can_write_index_array)(
|
||||
table_item.get_base_table_item().ref_id_, index_tid, index_cnt, true));
|
||||
|
||||
if (OB_SUCC(ret)) {
|
||||
delete_stmt->set_has_global_index(index_cnt > 0);
|
||||
}
|
||||
for (int64_t i = 0; OB_SUCC(ret) && i < index_cnt; ++i) {
|
||||
index_dml_info.reset();
|
||||
const ObTableSchema* index_schema = NULL;
|
||||
if (OB_FAIL(schema_checker_->get_table_schema(index_tid[i], index_schema))) {
|
||||
LOG_WARN("get index table schema failed", K(ret), K(index_tid[i]));
|
||||
} else if (OB_ISNULL(index_schema)) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("index schema is null");
|
||||
} else if (OB_FAIL(resolve_index_related_column_exprs(
|
||||
table_item.table_id_, *index_schema, empty_assignments, index_dml_info.column_exprs_))) {
|
||||
LOG_WARN("resolve index related column exprs failed", K(ret));
|
||||
} else {
|
||||
index_dml_info.table_id_ = table_item.table_id_;
|
||||
index_dml_info.loc_table_id_ = table_item.get_base_table_item().table_id_;
|
||||
index_dml_info.index_tid_ = index_tid[i];
|
||||
index_dml_info.rowkey_cnt_ = index_schema->get_rowkey_column_num();
|
||||
index_dml_info.part_cnt_ = index_schema->get_partition_cnt();
|
||||
index_dml_info.index_type_ = index_schema->get_index_type();
|
||||
if (OB_FAIL(index_schema->get_index_name(index_dml_info.index_name_))) {
|
||||
LOG_WARN("get index name from index schema failed", K(ret));
|
||||
} else if (OB_FAIL(delete_stmt->add_multi_table_dml_info(index_dml_info))) {
|
||||
LOG_WARN("add index dml info to update stmt failed", K(ret));
|
||||
}
|
||||
}
|
||||
if (OB_SUCC(ret) && !with_clause_without_record_) {
|
||||
ObSchemaObjVersion table_version;
|
||||
table_version.object_id_ = index_schema->get_table_id();
|
||||
table_version.object_type_ = DEPENDENCY_TABLE;
|
||||
table_version.version_ = index_schema->get_schema_version();
|
||||
if (OB_FAIL(delete_stmt->add_global_dependency_table(table_version))) {
|
||||
LOG_WARN("add global dependency table failed", K(ret));
|
||||
}
|
||||
if (OB_FAIL(delete_stmt->get_delete_table_info().push_back(table_info))) {
|
||||
LOG_WARN("failed to push back table info", K(ret));
|
||||
} else if (gindex_cnt > 0) {
|
||||
delete_stmt->set_has_global_index(true);
|
||||
} else { /*do nothing*/ }
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
@ -446,13 +442,12 @@ int ObDeleteResolver::check_view_deletable()
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
// uv_check_basic && mysql join already checked in set_base_table_for_view()
|
||||
FOREACH_CNT_X(it, delete_tables_, OB_SUCC(ret))
|
||||
{
|
||||
const TableItem* table = *it;
|
||||
FOREACH_CNT_X(it, delete_tables_, OB_SUCC(ret)) {
|
||||
const TableItem *table = *it;
|
||||
if (OB_ISNULL(*it)) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("NULL table table ", K(ret));
|
||||
} else if (!table->is_generated_table()) {
|
||||
} else if (!table->is_generated_table() && !table->is_temp_table()) {
|
||||
continue;
|
||||
} else if (OB_ISNULL(table->ref_query_)) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
@ -465,10 +460,11 @@ int ObDeleteResolver::check_view_deletable()
|
||||
bool has_dependent_subquery = false;
|
||||
bool ref_update_table = false;
|
||||
if (OB_FAIL(ObResolverUtils::uv_check_select_item_subquery(
|
||||
*table, has_subquery, has_dependent_subquery, ref_update_table))) {
|
||||
*table, has_subquery, has_dependent_subquery, ref_update_table))) {
|
||||
LOG_WARN("updatable view check select table failed", K(ret));
|
||||
} else {
|
||||
LOG_DEBUG("update view check", K(has_subquery), K(has_dependent_subquery), K(ref_update_table));
|
||||
LOG_DEBUG("update view check",
|
||||
K(has_subquery), K(has_dependent_subquery), K(ref_update_table));
|
||||
ret = (has_dependent_subquery || ref_update_table) ? OB_ERR_NON_UPDATABLE_TABLE : OB_SUCCESS;
|
||||
}
|
||||
}
|
||||
@ -476,33 +472,30 @@ int ObDeleteResolver::check_view_deletable()
|
||||
if (OB_ERR_NON_UPDATABLE_TABLE == ret) {
|
||||
ObString str = "DELETE";
|
||||
LOG_USER_ERROR(OB_ERR_NON_UPDATABLE_TABLE,
|
||||
table->get_table_name().length(),
|
||||
table->get_table_name().ptr(),
|
||||
str.length(),
|
||||
str.ptr());
|
||||
table->get_table_name().length(), table->get_table_name().ptr(),
|
||||
str.length(), str.ptr());
|
||||
}
|
||||
}
|
||||
|
||||
if (OB_SUCC(ret) && lib::is_oracle_mode()) {
|
||||
if (OB_SUCC(ret) && lib::is_oracle_mode() && !get_delete_stmt()->has_instead_of_trigger()) {
|
||||
if (OB_SUCC(ret)) {
|
||||
bool has_distinct = false;
|
||||
if (OB_FAIL(
|
||||
ObResolverUtils::uv_check_oracle_distinct(*table, *session_info_, *schema_checker_, has_distinct))) {
|
||||
if (OB_FAIL(ObResolverUtils::uv_check_oracle_distinct(
|
||||
*table, *session_info_, *schema_checker_, has_distinct))) {
|
||||
LOG_WARN("check updatable view distinct failed", K(ret));
|
||||
} else {
|
||||
LOG_DEBUG("check has distinct", K(ret), K(has_distinct));
|
||||
ret = has_distinct ? OB_ERR_ILLEGAL_VIEW_UPDATE : ret;
|
||||
}
|
||||
}
|
||||
|
||||
// check key preserved table
|
||||
if (OB_SUCC(ret)) {
|
||||
// check key preserved table
|
||||
bool key_preserved = 0;
|
||||
if (OB_FAIL(uv_check_key_preserved(*table, key_preserved))) {
|
||||
LOG_WARN("check key preserved failed", K(ret));
|
||||
} else {
|
||||
LOG_DEBUG("check key preserved", K(key_preserved));
|
||||
ret = !key_preserved ? OB_ERR_O_DELETE_VIEW_NON_KEY_PRESERVED : ret;
|
||||
ret = !key_preserved ? OB_ERR_O_DELETE_VIEW_NON_KEY_PRESERVED: ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -511,40 +504,5 @@ int ObDeleteResolver::check_view_deletable()
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ObDeleteResolver::try_add_rowid_column_to_stmt(const TableItem& table_item)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
ObDeleteStmt* delete_stmt = get_delete_stmt();
|
||||
IndexDMLInfo* primary_dml_info = NULL;
|
||||
ObArray<ObColumnRefRawExpr*> column_exprs;
|
||||
if (OB_ISNULL(delete_stmt)) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
SQL_RESV_LOG(WARN, "delete stmt is null", K(ret));
|
||||
} else if (OB_ISNULL(primary_dml_info = delete_stmt->get_or_add_table_columns(table_item.table_id_))) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
SQL_RESV_LOG(WARN, "unexpecteed null primary dml info", K(ret));
|
||||
} else if (OB_FAIL(delete_stmt->get_column_exprs(column_exprs))) {
|
||||
LOG_WARN("failed to get column exprs", K(ret));
|
||||
} else {
|
||||
int rowid_col_idx = -1;
|
||||
for (int i = 0; - 1 == rowid_col_idx && OB_SUCC(ret) && i < column_exprs.count(); i++) {
|
||||
if (OB_ISNULL(column_exprs.at(i))) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
SQL_RESV_LOG(WARN, "unexpected null column expr", K(ret));
|
||||
} else if (OB_HIDDEN_LOGICAL_ROWID_COLUMN_ID == column_exprs.at(i)->get_column_id() &&
|
||||
table_item.table_id_ == column_exprs.at(i)->get_table_id()) {
|
||||
rowid_col_idx = i;
|
||||
}
|
||||
} // for end
|
||||
|
||||
if (OB_FAIL(ret) || -1 == rowid_col_idx) {
|
||||
// do nothing
|
||||
} else if (OB_FAIL(add_var_to_array_no_dup(primary_dml_info->column_exprs_, column_exprs.at(rowid_col_idx)))) {
|
||||
SQL_RESV_LOG(WARN, "failed to add element to array", K(ret));
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace sql
|
||||
} // namespace oceanbase
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user