[FEAT MERGE]:Merge foreign key feature to master

Co-authored-by: YangEfei <yangyifei96@outlook.com>
This commit is contained in:
obdev
2023-08-30 13:10:42 +00:00
committed by ob-robot
parent b4427e1a69
commit 044fadf593
59 changed files with 2587 additions and 223 deletions

View File

@ -29,7 +29,7 @@
#include "sql/engine/expr/ob_expr_lob_utils.h"
#include "lib/geo/ob_geo_utils.h"
#include "sql/ob_sql_utils.h"
#include "sql/engine/dml/ob_fk_checker.h"
namespace oceanbase
{
using namespace common;
@ -1207,11 +1207,61 @@ int ObDMLService::init_trigger_for_insert(
return ret;
}
int ObDMLService::init_fk_checker_array(ObDMLRtCtx &dml_rtctx,
const ObDMLBaseCtDef &dml_ctdef,
FkCheckerArray &fk_checker_array)
{
int ret = OB_SUCCESS;
ObIAllocator &allocator = dml_rtctx.get_exec_ctx().get_allocator();
const ObForeignKeyArgArray &fk_args = dml_ctdef.fk_args_;
if (!fk_args.empty()) {
if (OB_FAIL(fk_checker_array.allocate_array(allocator, fk_args.count()))) {
LOG_WARN("failed to create foreign key checker array", K(ret));
} else {
for (int i = 0; OB_SUCC(ret) && i < fk_args.count(); ++i) {
fk_checker_array.at(i) = nullptr;
}
}
}
for (int i = 0; OB_SUCC(ret) && i < fk_args.count(); ++i) {
const ObForeignKeyArg &fk_arg = fk_args.at(i);
ObForeignKeyChecker *fk_checker = nullptr;
if (fk_arg.use_das_scan_) {
if (OB_ISNULL(fk_arg.fk_ctdef_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("need to perform foreign key check by das scan task, but scan ctdef is null", K(ret));
} else {
// create fk_checker here
void *checker_buf = allocator.alloc(sizeof(ObForeignKeyChecker));
if (OB_ISNULL(checker_buf)) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("cllocate foreign key checker buffer failed", K(ret));
} else {
fk_checker = new(checker_buf) ObForeignKeyChecker(dml_rtctx.get_eval_ctx(), *fk_arg.fk_ctdef_);
fk_checker_array.at(i) = fk_checker;
const ObExprFrameInfo *expr_frame_info = NULL;
expr_frame_info = nullptr != dml_rtctx.op_.get_spec().expr_frame_info_
? dml_rtctx.op_.get_spec().expr_frame_info_
: &(dml_rtctx.op_.get_spec().plan_->get_expr_frame_info());
int64_t estimate_row = dml_rtctx.op_.get_spec().rows_;
ObIAllocator *allocator = &dml_rtctx.op_.get_exec_ctx().get_allocator();
if (OB_FAIL(fk_checker->init_foreign_key_checker(estimate_row, expr_frame_info, *fk_arg.fk_ctdef_,
dml_ctdef.new_row_, allocator))) {
LOG_WARN("failed to init foreign key checker", K(ret));
}
}
}
}
}
return ret;
}
int ObDMLService::init_ins_rtdef(
ObDMLRtCtx &dml_rtctx,
ObInsRtDef &ins_rtdef,
const ObInsCtDef &ins_ctdef,
ObIArray<ObExpr*> &clear_exprs)
ObIArray<ObExpr*> &clear_exprs,
ObIArray<ObForeignKeyChecker*> &fk_checkers)
{
int ret = OB_SUCCESS;
dml_rtctx.get_exec_ctx().set_dml_event(ObDmlEventType::DE_INSERTING);
@ -1230,9 +1280,16 @@ int ObDMLService::init_ins_rtdef(
LOG_WARN("init related das ctdef failed", K(ret));
} else if (OB_FAIL(init_trigger_for_insert(dml_rtctx, ins_ctdef, ins_rtdef, clear_exprs))) {
LOG_WARN("failed to init trigger for insert", K(ret));
} else if (OB_FAIL(init_fk_checker_array(dml_rtctx, ins_ctdef, ins_rtdef.fk_checker_array_))) {
LOG_WARN("failed to init foreign key checker array", K(ret));
} else {
ins_rtdef.das_rtdef_.related_ctdefs_ = &ins_ctdef.related_ctdefs_;
ins_rtdef.das_rtdef_.related_rtdefs_ = &ins_rtdef.related_rtdefs_;
for (int64_t i = 0; OB_SUCC(ret) && i < ins_rtdef.fk_checker_array_.count(); ++i) {
if (OB_NOT_NULL(ins_rtdef.fk_checker_array_.at(i))) {
fk_checkers.push_back(ins_rtdef.fk_checker_array_.at(i));
}
}
}
return ret;
}
@ -1271,6 +1328,8 @@ int ObDMLService::init_del_rtdef(ObDMLRtCtx &dml_rtctx,
LOG_WARN("init related das ctdef failed", K(ret));
} else if (OB_FAIL(init_trigger_for_delete(dml_rtctx, del_ctdef, del_rtdef))) {
LOG_WARN("failed to init trigger for delete", K(ret));
} else if (OB_FAIL(init_fk_checker_array(dml_rtctx, del_ctdef, del_rtdef.fk_checker_array_))) {
LOG_WARN("failed to init foreign key checker array", K(ret));
} else {
del_rtdef.das_rtdef_.related_ctdefs_ = &del_ctdef.related_ctdefs_;
del_rtdef.das_rtdef_.related_rtdefs_ = &del_rtdef.related_rtdefs_;
@ -1397,7 +1456,8 @@ int ObDMLService::init_upd_rtdef(
ObDMLRtCtx &dml_rtctx,
ObUpdRtDef &upd_rtdef,
const ObUpdCtDef &upd_ctdef,
ObIArray<ObExpr*> &clear_exprs)
ObIArray<ObExpr*> &clear_exprs,
ObIArray<ObForeignKeyChecker*> &fk_checkers)
{
int ret = OB_SUCCESS;
const ObDASTableLocMeta *loc_meta = get_table_loc_meta(upd_ctdef.multi_ctdef_);
@ -1416,10 +1476,17 @@ int ObDMLService::init_upd_rtdef(
LOG_WARN("init related das ctdef failed", K(ret));
} else if (OB_FAIL(init_trigger_for_update(dml_rtctx, upd_ctdef, upd_rtdef, dml_rtctx.op_, clear_exprs))) {
LOG_WARN("failed to init trigger for update", K(ret));
} else if (OB_FAIL(init_fk_checker_array(dml_rtctx, upd_ctdef, upd_rtdef.fk_checker_array_))) {
LOG_WARN("failed to init foreign key checker array", K(ret));
} else {
upd_rtdef.dupd_rtdef_.related_ctdefs_ = &upd_ctdef.related_upd_ctdefs_;
upd_rtdef.dupd_rtdef_.related_rtdefs_ = &upd_rtdef.related_upd_rtdefs_;
dml_rtctx.get_exec_ctx().set_update_columns(&upd_ctdef.assign_columns_);
for (int64_t i = 0; OB_SUCC(ret) && i < upd_rtdef.fk_checker_array_.count(); ++i) {
if (OB_NOT_NULL(upd_rtdef.fk_checker_array_.at(i))) {
fk_checkers.push_back(upd_rtdef.fk_checker_array_.at(i));
}
}
}
if (OB_SUCC(ret) && T_DISTINCT_NONE != upd_ctdef.distinct_algo_) {
@ -2079,68 +2146,82 @@ int ObDMLService::get_nested_dup_table_ctx(const uint64_t table_id, DASDelCtxLi
return ret;
}
int ObDMLService::handle_after_row_processing_batch(ObDMLModifyRowsList *dml_modify_rows)
int ObDMLService::handle_after_processing_multi_row(ObDMLModifyRowsList *dml_modify_rows, ObTableModifyOp *dml_op)
{
int ret = OB_SUCCESS;
const ObDmlEventType t_insert = ObDmlEventType::DE_INSERTING;
const ObDmlEventType t_update = ObDmlEventType::DE_UPDATING;
const ObDmlEventType t_delete = ObDmlEventType::DE_DELETING;
ObDMLModifyRowsList::iterator row_iter = dml_modify_rows->begin();
for (; OB_SUCC(ret) && row_iter != dml_modify_rows->end(); row_iter++) {
ObDMLModifyRowNode &modify_row = *row_iter;
if (OB_ISNULL(modify_row.full_row_) && OB_ISNULL(modify_row.new_row_) && OB_ISNULL(modify_row.old_row_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("invalid parameter for batch post row processing", K(ret));
} else if (OB_ISNULL(modify_row.dml_op_) || OB_ISNULL(modify_row.dml_ctdef_) || OB_ISNULL(modify_row.dml_rtdef_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("invalid parameter for batch post row processing", K(ret));
} else {
ObTableModifyOp &op = *modify_row.dml_op_;
const ObDMLBaseCtDef &dml_ctdef = *modify_row.dml_ctdef_;
ObDMLBaseRtDef &dml_rtdef = *modify_row.dml_rtdef_;
const ObDmlEventType dml_event = modify_row.dml_event_;
// process foreign key
if (OB_NOT_NULL(modify_row.full_row_) && OB_FAIL(modify_row.full_row_->to_expr(modify_row.dml_ctdef_->full_row_, op.get_eval_ctx()))) {
LOG_WARN("failed to covert stored full row to expr", K(ret));
} else if (OB_NOT_NULL(modify_row.old_row_) && OB_FAIL(modify_row.old_row_->to_expr(dml_ctdef.old_row_, op.get_eval_ctx()))) {
LOG_WARN("failed to covert stored old row to expr", K(ret));
} else if (OB_NOT_NULL(modify_row.new_row_) && OB_FAIL(modify_row.new_row_->to_expr(dml_ctdef.new_row_, op.get_eval_ctx()))) {
LOG_WARN("failed to covert stored new row to expr", K(ret));
if (OB_ISNULL(dml_modify_rows) || OB_ISNULL(dml_op)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("dml operator or modify rows list is null", K(dml_modify_rows), K(dml_op));
} else {
ObDMLModifyRowsList::iterator row_iter = dml_modify_rows->begin();
for (; OB_SUCC(ret) && row_iter != dml_modify_rows->end(); row_iter++) {
ObDMLModifyRowNode &modify_row = *row_iter;
if (OB_ISNULL(modify_row.full_row_) && OB_ISNULL(modify_row.new_row_) && OB_ISNULL(modify_row.old_row_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("invalid parameter for batch post row processing", K(ret));
} else if (OB_ISNULL(modify_row.dml_op_) || OB_ISNULL(modify_row.dml_ctdef_) || OB_ISNULL(modify_row.dml_rtdef_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("invalid parameter for batch post row processing", K(ret));
} else {
if (t_update == dml_event) {
// for update op, Foreign key checks need to be performed only if the value has changed
if (reinterpret_cast<ObUpdRtDef &>(dml_rtdef).is_row_changed_ && OB_FAIL(ForeignKeyHandle::do_handle(op, dml_ctdef, dml_rtdef))) {
LOG_WARN("failed to handle foreign key constraints", K(ret));
ObTableModifyOp &op = *modify_row.dml_op_;
const ObDMLBaseCtDef &dml_ctdef = *modify_row.dml_ctdef_;
ObDMLBaseRtDef &dml_rtdef = *modify_row.dml_rtdef_;
const ObDmlEventType dml_event = modify_row.dml_event_;
// process foreign key
if (OB_NOT_NULL(modify_row.full_row_) && OB_FAIL(modify_row.full_row_->to_expr(modify_row.dml_ctdef_->full_row_, op.get_eval_ctx()))) {
LOG_WARN("failed to covert stored full row to expr", K(ret));
} else if (OB_NOT_NULL(modify_row.old_row_) && OB_FAIL(modify_row.old_row_->to_expr(dml_ctdef.old_row_, op.get_eval_ctx()))) {
LOG_WARN("failed to covert stored old row to expr", K(ret));
} else if (OB_NOT_NULL(modify_row.new_row_) && OB_FAIL(modify_row.new_row_->to_expr(dml_ctdef.new_row_, op.get_eval_ctx()))) {
LOG_WARN("failed to covert stored new row to expr", K(ret));
} else if (op.need_foreign_key_checks()) {
if (t_update == dml_event && !reinterpret_cast<ObUpdRtDef &>(dml_rtdef).is_row_changed_) {
LOG_DEBUG("update operation don't change any value, no need to perform foreign key check");
} else {
// if check foreign key in batch, build fk check tasks here
if (dml_op->get_spec().check_fk_batch_) {
if (OB_FAIL(build_batch_fk_check_tasks(dml_ctdef, dml_rtdef))) {
LOG_WARN("failed to build batch check foreign key checks", K(ret));
}
} else if (OB_FAIL(ForeignKeyHandle::do_handle(op, dml_ctdef, dml_rtdef))) {
LOG_WARN("failed to handle foreign key constraints", K(ret));
}
}
}
// process after row trigger
if (OB_SUCC(ret) && dml_ctdef.trig_ctdef_.all_tm_points_.has_after_row()) {
ObEvalCtx &eval_ctx = op.get_eval_ctx();
if (dml_event != t_insert && dml_event != t_update && dml_event != t_delete) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("invalid trigger event", K(ret));
} else if (t_insert == dml_event && OB_FAIL(TriggerHandle::init_param_new_row(
eval_ctx, dml_ctdef.trig_ctdef_, dml_rtdef.trig_rtdef_))) {
LOG_WARN("failed to init trigger parameter for new row", K(ret));
} else if (t_delete == dml_event && OB_FAIL(TriggerHandle::init_param_old_row(
eval_ctx, dml_ctdef.trig_ctdef_, dml_rtdef.trig_rtdef_))) {
LOG_WARN("failed to init trigger parameter for old row", K(ret));
} else if (t_update == dml_event && OB_FAIL(TriggerHandle::init_param_rows(
eval_ctx, dml_ctdef.trig_ctdef_, dml_rtdef.trig_rtdef_))) {
LOG_WARN("failed to init trigger parameter for old row and new row", K(ret));
} else if (OB_FAIL(TriggerHandle::do_handle_after_row(op, dml_ctdef.trig_ctdef_, dml_rtdef.trig_rtdef_, dml_event))) {
LOG_WARN("failed to handle after trigger", K(ret));
}
} else if (OB_FAIL(ForeignKeyHandle::do_handle(op, dml_ctdef, dml_rtdef))) {
LOG_WARN("failed to handle foreign key constraints", K(ret));
}
}
// process after row trigger
if (OB_SUCC(ret) && dml_ctdef.trig_ctdef_.all_tm_points_.has_after_row()) {
ObEvalCtx &eval_ctx = op.get_eval_ctx();
if (dml_event != t_insert && dml_event != t_update && dml_event != t_delete) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("invalid trigger event", K(ret));
} else if (t_insert == dml_event && OB_FAIL(TriggerHandle::init_param_new_row(
eval_ctx, dml_ctdef.trig_ctdef_, dml_rtdef.trig_rtdef_))) {
LOG_WARN("failed to init trigger parameter for new row", K(ret));
} else if (t_delete == dml_event && OB_FAIL(TriggerHandle::init_param_old_row(
eval_ctx, dml_ctdef.trig_ctdef_, dml_rtdef.trig_rtdef_))) {
LOG_WARN("failed to init trigger parameter for old row", K(ret));
} else if (t_update == dml_event && OB_FAIL(TriggerHandle::init_param_rows(
eval_ctx, dml_ctdef.trig_ctdef_, dml_rtdef.trig_rtdef_))) {
LOG_WARN("failed to init trigger parameter for old row and new row", K(ret));
} else if (OB_FAIL(TriggerHandle::do_handle_after_row(op, dml_ctdef.trig_ctdef_, dml_rtdef.trig_rtdef_, dml_event))) {
LOG_WARN("failed to handle after trigger", K(ret));
}
}
}
// check the result of batch foreign key check results
if (OB_SUCC(ret) && dml_op->get_spec().check_fk_batch_ && OB_FAIL(dml_op->perform_batch_fk_check())) {
LOG_WARN("failed to perform batch foreign key check", K(ret));
}
}
return ret;
}
int ObDMLService::handle_after_row_processing_single(ObDMLModifyRowsList *dml_modify_rows)
int ObDMLService::handle_after_processing_single_row(ObDMLModifyRowsList *dml_modify_rows)
{
int ret = OB_SUCCESS;
// for single-row processing, the expr defined in ctdef and trig parameters haven't been refreshed
@ -2185,18 +2266,49 @@ int ObDMLService::handle_after_row_processing_single(ObDMLModifyRowsList *dml_mo
return ret;
}
int ObDMLService::handle_after_row_processing(bool execute_single_row, ObDMLModifyRowsList *dml_modify_rows)
int ObDMLService::handle_after_row_processing(ObTableModifyOp *op,
ObDMLModifyRowsList *dml_modify_rows)
{
int ret = OB_SUCCESS;
if (1 > dml_modify_rows->size()) {
if (OB_ISNULL(op) || OB_ISNULL(dml_modify_rows)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("table modify operator or list of the modify rows is null", K(ret), K(op), K(dml_modify_rows));
} else if (1 > dml_modify_rows->size()) {
// after row processing list is empty, nothing to do
#ifndef NDEBUG
LOG_INFO("No row need to perform foreign key check or after row trigger");
#endif
} else if (execute_single_row) {
ret = handle_after_row_processing_single(dml_modify_rows);
} else if (op->execute_single_row_) {
ret = handle_after_processing_single_row(dml_modify_rows);
} else {
ret = handle_after_row_processing_batch(dml_modify_rows);
ret = handle_after_processing_multi_row(dml_modify_rows, op);
}
return ret;
}
int ObDMLService::build_batch_fk_check_tasks(const ObDMLBaseCtDef &dml_ctdef,
ObDMLBaseRtDef &dml_rtdef)
{
int ret = OB_SUCCESS;
if (dml_rtdef.fk_checker_array_.count() != dml_ctdef.fk_args_.count()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("foreign key aruments count is not equal with foreign key checker count",
K(ret),K(dml_rtdef.fk_checker_array_.count()), K(dml_ctdef.fk_args_.count()));
} else {
for (int i = 0; OB_SUCC(ret) && i < dml_rtdef.fk_checker_array_.count(); ++i) {
ObForeignKeyChecker *fk_checker = dml_rtdef.fk_checker_array_.at(i);
const ObForeignKeyArg &fk_arg = dml_ctdef.fk_args_.at(i);
bool need_check = true;
if (OB_ISNULL(fk_checker)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("foreign key checker is nullptr", K(ret), K(i));
} else if (!fk_arg.use_das_scan_) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("foreign key check can not use das scan", K(ret), K(i));
} else if (OB_FAIL(fk_checker->build_fk_check_das_task(fk_arg.columns_, dml_ctdef.new_row_, need_check))) {
LOG_WARN("failed to build batch foreign key check scan task", K(ret));
}
}
}
return ret;
}