init push

This commit is contained in:
oceanbase-admin
2021-05-31 22:56:52 +08:00
commit cea7de1475
7020 changed files with 5689869 additions and 0 deletions

View File

@ -0,0 +1,505 @@
/**
* 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_ENG
#include "sql/engine/dml/ob_table_merge_op.h"
#include "lib/utility/ob_unify_serialize.h"
#include "share/ob_autoincrement_service.h"
#include "sql/engine/ob_physical_plan_ctx.h"
#include "sql/session/ob_sql_session_info.h"
#include "storage/ob_partition_service.h"
#include "sql/engine/ob_physical_plan.h"
#include "common/sql_mode/ob_sql_mode_utils.h"
#include "common/rowkey/ob_rowkey.h"
#include "sql/engine/ob_physical_plan.h"
#include "sql/engine/ob_exec_context.h"
#include "sql/ob_sql_utils.h"
namespace oceanbase {
using namespace common;
using namespace share;
using namespace sql;
using storage::INSERT_RETURN_ONE_DUP;
using storage::ObPartitionService;
namespace sql {
OB_SERIALIZE_MEMBER((ObTableMergeOpInput, ObTableModifyOpInput));
OB_SERIALIZE_MEMBER((ObTableMergeSpec, ObTableModifySpec), has_insert_clause_, has_update_clause_, delete_conds_,
update_conds_, insert_conds_, rowkey_exprs_, delete_column_ids_, updated_column_ids_, updated_column_infos_,
old_row_, new_row_);
ObTableMergeSpec::ObTableMergeSpec(common::ObIAllocator& alloc, const ObPhyOperatorType type)
: ObTableModifySpec(alloc, type),
has_insert_clause_(false),
has_update_clause_(false),
delete_conds_(alloc),
update_conds_(alloc),
insert_conds_(alloc),
rowkey_exprs_(alloc),
delete_column_ids_(alloc),
updated_column_ids_(alloc),
updated_column_infos_(alloc),
old_row_(alloc),
new_row_(alloc)
{}
int ObTableMergeSpec::set_updated_column_info(
int64_t array_index, uint64_t column_id, uint64_t project_index, bool auto_filled_timestamp)
{
int ret = OB_SUCCESS;
ColumnContent column;
column.projector_index_ = project_index;
column.auto_filled_timestamp_ = auto_filled_timestamp;
CK(array_index >= 0 && array_index < updated_column_ids_.count());
CK(array_index >= 0 && array_index < updated_column_infos_.count());
if (OB_SUCC(ret)) {
updated_column_ids_.at(array_index) = column_id;
updated_column_infos_.at(array_index) = column;
}
return ret;
}
int ObTableMergeSpec::init_updated_column_count(common::ObIAllocator& allocator, int64_t count)
{
UNUSED(allocator);
int ret = common::OB_SUCCESS;
OZ(updated_column_infos_.prepare_allocate(count));
OZ(updated_column_ids_.prepare_allocate(count));
return ret;
}
ObTableMergeOp::ObTableMergeOp(ObExecContext& ctx, const ObOpSpec& spec, ObOpInput* input)
: ObTableModifyOp(ctx, spec, input),
insert_row_(),
insert_row_store_(ctx_.get_allocator(), ObModIds::OB_SQL_ROW_STORE, OB_SERVER_TENANT_ID, false),
old_row_(),
new_row_(),
affected_rows_(0)
{}
int ObTableMergeOp::inner_open()
{
int ret = OB_SUCCESS;
ObPhysicalPlanCtx* plan_ctx = NULL;
ObSQLSessionInfo* my_session = NULL;
int64_t schema_version = 0;
int64_t binlog_row_image = ObBinlogRowImage::FULL;
if (OB_FAIL(ObTableModifyOp::inner_open())) {
LOG_WARN("open child operator failed", K(ret));
} else if (OB_ISNULL((plan_ctx = ctx_.get_physical_plan_ctx()))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get physical plan context failed", K(ret));
} else if (OB_ISNULL((my_session = GET_MY_SESSION(ctx_)))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("fail to get my session", K(ret));
} else if (OB_FAIL(get_spec().plan_->get_base_table_version(MY_SPEC.index_tid_, schema_version))) {
LOG_WARN("failed to get base table version", K(ret));
} else if (OB_ISNULL(child_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("invalid child op", K(ret), K(child_));
} else if (OB_FAIL(my_session->get_binlog_row_image(binlog_row_image))) {
LOG_WARN("fail to get binlog row image", K(ret));
} else {
dml_param_.timeout_ = plan_ctx->get_ps_timeout_timestamp();
dml_param_.schema_version_ = schema_version;
dml_param_.is_total_quantity_log_ = (ObBinlogRowImage::FULL == binlog_row_image);
dml_param_.sql_mode_ = my_session->get_sql_mode();
dml_param_.tz_info_ = TZ_INFO(my_session);
dml_param_.table_param_ = &MY_SPEC.table_param_;
dml_param_.tenant_schema_version_ = plan_ctx->get_tenant_schema_version();
if (MY_SPEC.gi_above_) {
OZ(get_gi_task());
}
if (OB_SUCC(ret)) {
OZ(do_table_merge());
}
}
return ret;
}
int ObTableMergeOp::do_table_merge()
{
int ret = OB_SUCCESS;
ObPhysicalPlanCtx* plan_ctx = NULL;
ObSQLSessionInfo* my_session = NULL;
ObPartitionKey* pkey;
ObPartitionService* partition_service = NULL;
ObTaskExecutorCtx* executor_ctx = NULL;
if (iter_end_) {
LOG_DEBUG("can't get gi task, iter end", K(iter_end_), K(MY_SPEC.id_));
} else if (OB_FAIL(get_part_location(part_infos_))) {
LOG_WARN("get part location failed", K(ret));
} else if (part_infos_.count() != 1) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("the part info count is not right", K(ret), K(part_infos_.count()));
} else if (OB_ISNULL(pkey = &part_infos_.at(0).partition_key_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("the partition key is null", K(ret), K(pkey));
} else if (OB_FAIL(set_autoinc_param_pkey(*pkey))) {
LOG_WARN("set autoinc param pkey failed", K(pkey), K(ret));
} else if (OB_ISNULL(plan_ctx = ctx_.get_physical_plan_ctx())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get physical plan context failed");
} else if (OB_ISNULL(my_session = GET_MY_SESSION(ctx_))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("fail to get my session", K(ret));
} else if (OB_ISNULL(executor_ctx = GET_TASK_EXECUTOR_CTX(ctx_))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("fail to get task executor ctx", K(ret));
} else if (OB_ISNULL(partition_service = executor_ctx->get_partition_service())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("fail to get partition service", K(ret));
} else {
if (OB_FAIL(set_autoinc_param_pkey(*pkey))) {
LOG_WARN("set autoinc param pkey failed", K(pkey), K(ret));
}
// since inner open performes get_next_row, assgin opened_ as true
opened_ = true;
while (OB_SUCC(ret)) {
bool is_match = false;
clear_evaluated_flag();
if (OB_FAIL(try_check_status())) {
} else if (OB_FAIL(child_->get_next_row())) {
if (OB_ITER_END != ret) {
LOG_WARN("fail to get next row", K(ret));
}
} else if (OB_FAIL(check_is_match(is_match))) {
LOG_WARN("failed to check is match", K(ret));
} else if (is_match) { // execute update
if (MY_SPEC.has_update_clause_ && OB_FAIL(process_update(partition_service, *pkey, dml_param_))) {
LOG_WARN("fail to process update", K(ret));
}
} else { // execute insert
if (MY_SPEC.has_insert_clause_ &&
OB_FAIL(process_insert(partition_service, my_session->get_trans_desc(), dml_param_, *pkey))) {
LOG_WARN("fail to insert row", K(ret));
}
}
} // end while
if (OB_ITER_END == ret &&
OB_FAIL(insert_all_rows(partition_service, my_session->get_trans_desc(), dml_param_, *pkey))) {
if (OB_ITER_END != ret) {
LOG_WARN("insert all rows failed", K(ret));
}
}
// deal with different ret
if (OB_ITER_END != ret) {
if (OB_TRY_LOCK_ROW_CONFLICT != ret && OB_TRANSACTION_SET_VIOLATION != ret) {
LOG_WARN("failed to deal with merge into", K(ret));
}
if (OB_SUCC(ret)) {
ret = OB_ERR_UNEXPECTED;
}
} else {
ret = OB_SUCCESS;
}
}
if (OB_SUCC(ret)) {
plan_ctx->add_affected_rows(affected_rows_);
}
return ret;
}
int ObTableMergeOp::rescan()
{
int ret = OB_SUCCESS;
if (!MY_SPEC.gi_above_) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("table merge into rescan not supported", K(ret));
} else if (OB_FAIL(ObTableModifyOp::rescan())) {
LOG_WARN("rescan child operator failed", K(ret));
} else {
reset();
if (OB_SUCC(ret)) {
if (OB_FAIL(get_gi_task())) {
LOG_WARN("get granule task failed", K(ret));
} else if (OB_FAIL(do_table_merge())) {
LOG_WARN("do table merge into failed", K(ret));
}
}
}
return ret;
}
int ObTableMergeOp::check_is_match(bool& is_match)
{
int ret = OB_SUCCESS;
const ObTableMergeSpec& spec = MY_SPEC;
is_match = false;
for (int64_t i = 0; OB_SUCC(ret) && !is_match && i < spec.rowkey_exprs_.count(); ++i) {
ObDatum* datum = NULL;
const ObExpr* e = spec.rowkey_exprs_.at(i);
if (OB_ISNULL(e)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("expr is null", K(ret));
} else if (e->eval(eval_ctx_, datum)) {
LOG_WARN("failed to evaluate expression", K(ret));
} else {
is_match = !datum->is_null();
}
}
return ret;
}
int ObTableMergeOp::calc_delete_condition(const ObIArray<ObExpr*>& exprs, bool& is_true_cond)
{
int ret = OB_SUCCESS;
if (0 == exprs.count()) {
is_true_cond = false;
} else if (OB_FAIL(calc_condition(exprs, is_true_cond))) {
LOG_WARN("fail to calc delete join condition", K(ret), K(exprs));
}
return ret;
}
int ObTableMergeOp::calc_condition(const ObIArray<ObExpr*>& exprs, bool& is_true_cond)
{
int ret = OB_SUCCESS;
ObDatum* cmp_res = NULL;
is_true_cond = true;
ARRAY_FOREACH(exprs, i)
{
if (OB_FAIL(exprs.at(i)->eval(eval_ctx_, cmp_res))) {
LOG_WARN("fail to calc other join condition", K(ret), K(*exprs.at(i)));
} else if (cmp_res->is_null() || 0 == cmp_res->get_int()) {
is_true_cond = false;
break;
}
}
return ret;
}
int ObTableMergeOp::process_insert(ObPartitionService* partition_service, const transaction::ObTransDesc& trans_desc,
const storage::ObDMLBaseParam& dml_param, const common::ObPartitionKey& pkey)
{
int ret = OB_SUCCESS;
bool is_true_cond = false;
int64_t cur_affected = 0;
ObNewRowIterator* duplicated_rows = NULL;
if (!MY_SPEC.has_insert_clause_) { // do nothing
LOG_DEBUG("trace insert clause", K(ret));
} else if (OB_FAIL(calc_condition(MY_SPEC.insert_conds_, is_true_cond))) {
LOG_WARN("fail to calc condition", K(MY_SPEC.insert_conds_), K(ret));
} else if (is_true_cond) {
bool is_filtered = false;
// in resolve phase, insert's check expression will be put in
// check_constraint_exprs_'s second half
int64_t cst_beg_idx = MY_SPEC.check_constraint_exprs_.count() / 2;
int64_t cst_end_idx = MY_SPEC.check_constraint_exprs_.count();
if (OB_FAIL(check_row_null(MY_SPEC.storage_row_output_, MY_SPEC.column_infos_))) {
LOG_WARN("failed to check null", K(ret));
} else if (OB_FAIL(
filter_row_for_check_cst(MY_SPEC.check_constraint_exprs_, is_filtered, cst_beg_idx, cst_end_idx))) {
LOG_WARN("failed to filter row for constraint", K(ret));
} else if (is_filtered) {
ret = OB_ERR_CHECK_CONSTRAINT_VIOLATED;
LOG_WARN("row is filtered by check", K(ret));
} else if (OB_FAIL(project_row(MY_SPEC.storage_row_output_, insert_row_))) {
LOG_WARN("failed to project row", K(ret));
} else if (OB_FAIL(partition_service->insert_row(trans_desc,
dml_param,
pkey,
MY_SPEC.column_ids_,
MY_SPEC.primary_key_ids_,
insert_row_,
INSERT_RETURN_ONE_DUP,
cur_affected,
duplicated_rows))) {
if (OB_TRY_LOCK_ROW_CONFLICT != ret && OB_TRANSACTION_SET_VIOLATION != ret) {
LOG_WARN("fail to insert row", K(pkey), K(MY_SPEC.column_ids_), K(ret));
}
LOG_DEBUG("trace insert clause", K(ret), K(affected_rows_));
}
if (OB_SUCC(ret)) {
affected_rows_ += cur_affected;
}
if (OB_ERR_PRIMARY_KEY_DUPLICATE == ret) {
if (OB_FAIL(insert_row_store_.add_row(insert_row_, false))) {
LOG_WARN("add row to row store failed", K(ret), K(insert_row_));
}
}
if (nullptr != duplicated_rows) {
(void)partition_service->revert_insert_iter(pkey, duplicated_rows);
duplicated_rows = nullptr;
}
}
return ret;
}
int ObTableMergeOp::insert_all_rows(ObPartitionService* partition_service, const transaction::ObTransDesc& trans_desc,
const storage::ObDMLBaseParam& dml_param, const common::ObPartitionKey& pkey)
{
int ret = OB_SUCCESS;
ObRowStore::Iterator insert_row_iter;
ObNewRow* insert_row = nullptr;
int64_t cur_affected = 0;
ObNewRowIterator* duplicated_rows = NULL;
CK(OB_NOT_NULL(partition_service));
insert_row_iter = insert_row_store_.begin();
while (OB_SUCC(ret) && (OB_SUCC(insert_row_iter.get_next_row(insert_row, nullptr)))) {
if (OB_FAIL(partition_service->insert_row(trans_desc,
dml_param,
pkey,
MY_SPEC.column_ids_,
MY_SPEC.primary_key_ids_,
*insert_row,
INSERT_RETURN_ONE_DUP,
cur_affected,
duplicated_rows))) {
if (OB_TRY_LOCK_ROW_CONFLICT != ret && OB_TRANSACTION_SET_VIOLATION != ret) {
LOG_WARN("fail to insert row", K(pkey), K(MY_SPEC.column_ids_), K(ret));
}
} else {
affected_rows_ += cur_affected;
}
if (nullptr != duplicated_rows) {
(void)partition_service->revert_insert_iter(pkey, duplicated_rows);
}
}
return ret;
}
int ObTableMergeOp::inner_close()
{
int ret = OB_SUCCESS;
if (OB_FAIL(ObTableModifyOp::inner_close())) {
LOG_WARN("fail to do inner close", K(ret));
}
return ret;
}
int ObTableMergeOp::inner_get_next_row()
{
return OB_ITER_END;
}
int ObTableMergeOp::process_update(
ObPartitionService* partition_service, const ObPartitionKey& pkey, storage::ObDMLBaseParam& dml_param)
{
int ret = OB_SUCCESS;
bool need_update = false;
bool need_delete = false;
bool is_conflict = false;
ObSQLSessionInfo* my_session = GET_MY_SESSION(ctx_);
OZ(calc_condition(MY_SPEC.update_conds_, need_update));
if (need_update) {
OZ(generate_origin_row(is_conflict));
OZ(calc_delete_condition(MY_SPEC.delete_conds_, need_delete));
if (is_conflict) {
ret = need_delete ? OB_ERR_SPECIFIED_ROW_NO_LONGER_EXISTS : OB_ERR_UPDATE_TWICE;
} else {
if (need_delete) {
OZ(project_row(MY_SPEC.old_row_, old_row_));
OZ(partition_service->delete_row(my_session->get_trans_desc(), dml_param, pkey, MY_SPEC.column_ids_, old_row_));
OX(affected_rows_ += 1);
} else {
OZ(update_row(partition_service, pkey, dml_param));
}
}
}
return ret;
}
int ObTableMergeOp::generate_origin_row(bool& conflict)
{
int ret = OB_SUCCESS;
bool is_distinct = true;
conflict = false;
if (OB_FAIL(check_rowkey_whether_distinct(
MY_SPEC.old_row_, MY_SPEC.primary_key_ids_.count(), T_HASH_DISTINCT, rowkey_dist_ctx_, is_distinct))) {
LOG_WARN("faield to check whether row distinct", K(ret));
} else if (!is_distinct) {
conflict = true;
}
return ret;
}
int ObTableMergeOp::update_row(
ObPartitionService* partition_service, const ObPartitionKey& pkey, storage::ObDMLBaseParam& dml_param)
{
int ret = OB_SUCCESS;
ObSQLSessionInfo* my_session = GET_MY_SESSION(ctx_);
ObNewRowIterator* duplicated_rows = NULL;
int64_t cur_affected = 0;
OV(OB_NOT_NULL(partition_service));
OZ(check_row_null(MY_SPEC.new_row_, MY_SPEC.column_infos_));
bool is_filtered = false;
// In resolve phase, check constraint expression corresponding to
// update subquery will be put in first half.
int64_t cst_beg_idx = 0;
int64_t cst_end_idx = MY_SPEC.check_constraint_exprs_.count() / 2;
OZ(filter_row_for_check_cst(MY_SPEC.check_constraint_exprs_, is_filtered, cst_beg_idx, cst_end_idx));
OV(!is_filtered, OB_ERR_CHECK_CONSTRAINT_VIOLATED);
// do update.
bool is_row_changed = false;
OZ(check_updated_value(*this, MY_SPEC.updated_column_infos_, MY_SPEC.old_row_, MY_SPEC.new_row_, is_row_changed));
OZ(project_row(MY_SPEC.old_row_, old_row_));
OZ(project_row(MY_SPEC.new_row_, new_row_));
if (!is_row_changed) {
OZ(lock_row(partition_service, pkey, dml_param));
} else {
OZ(partition_service->delete_row(my_session->get_trans_desc(), dml_param, pkey, MY_SPEC.column_ids_, old_row_));
OZ(partition_service->insert_row(my_session->get_trans_desc(),
dml_param,
pkey,
MY_SPEC.column_ids_,
MY_SPEC.primary_key_ids_,
new_row_,
INSERT_RETURN_ONE_DUP,
cur_affected,
duplicated_rows));
if (OB_ERR_PRIMARY_KEY_DUPLICATE == ret) {
ret = OB_SUCCESS;
OZ(insert_row_store_.add_row(new_row_, false));
}
if (nullptr != duplicated_rows) {
(void)partition_service->revert_insert_iter(pkey, duplicated_rows);
duplicated_rows = nullptr;
}
OX(affected_rows_ += 1);
}
return ret;
}
int ObTableMergeOp::lock_row(
ObPartitionService* partition_service, const ObPartitionKey& pkey, storage::ObDMLBaseParam& dml_param)
{
int ret = OB_SUCCESS;
if (OB_ISNULL((partition_service))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("fail to get partition service", K(ret));
} else {
if (OB_SUCC(ret)) {
if (OB_FAIL(ObTableModifyOp::lock_row(MY_SPEC.rowkey_exprs_, dml_param, pkey))) {
if (OB_TRY_LOCK_ROW_CONFLICT != ret && OB_TRANSACTION_SET_VIOLATION != ret) {
LOG_WARN("fail to lock row", K(ret));
}
} else {
affected_rows_ += 1;
}
}
}
return ret;
}
} // namespace sql
} // namespace oceanbase