[CP] Fix bug for last_insert_id()

This commit is contained in:
2149 2023-06-14 02:48:20 +00:00 committed by ob-robot
parent 435d6eb508
commit 90c2c33118
9 changed files with 274 additions and 40 deletions

View File

@ -62,15 +62,16 @@ int ObExprLastInsertID::eval_last_insert_id(
{
int ret = OB_SUCCESS;
ObPhysicalPlanCtx *plan_ctx = ctx.exec_ctx_.get_physical_plan_ctx();
ObSQLSessionInfo *session = ctx.exec_ctx_.get_my_session();
ObDatum *arg = NULL;
if (NULL == plan_ctx) {
if (NULL == plan_ctx || NULL == session) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("phy plan context is NULL", K(ret));
LOG_WARN("phy plan context or session is NULL", K(ret), K(plan_ctx), K(session));
} else if (OB_FAIL(expr.eval_param_value(ctx, arg))) {
LOG_WARN("evaluate parameter failed", K(ret));
} else {
if (0 == expr.arg_cnt_) {
expr_datum.set_uint(plan_ctx->get_last_insert_id_session());
expr_datum.set_uint(session->get_local_last_insert_id());
} else if (1 == expr.arg_cnt_) {
plan_ctx->set_last_insert_id_with_expr(true);
plan_ctx->set_last_insert_id_changed(true);

View File

@ -745,7 +745,7 @@ int ObRawExpr::is_const_inherit_expr(bool &is_const_inherit,
|| T_FUN_NORMAL_UDF == type_
|| T_FUN_SYS_REMOVE_CONST == type_
|| T_FUN_SYS_WRAPPER_INNER == type_
|| T_FUN_SYS_LAST_INSERT_ID == type_
|| (T_FUN_SYS_LAST_INSERT_ID == type_ && get_param_count() > 0)
|| T_FUN_SYS_TO_BLOB == type_
|| (T_FUN_SYS_SYSDATE == type_ && lib::is_mysql_mode())
|| (param_need_replace ? is_not_calculable_expr() : cnt_not_calculable_expr())

View File

@ -470,7 +470,7 @@ int ObRawExprInfoExtractor::visit(ObSysFunRawExpr &expr)
if (T_FUN_SYS_AUTOINC_NEXTVAL == expr.get_expr_type()
|| T_FUN_SYS_TABLET_AUTOINC_NEXTVAL == expr.get_expr_type()
|| T_FUN_SYS_SLEEP == expr.get_expr_type()
|| T_FUN_SYS_LAST_INSERT_ID == expr.get_expr_type()
|| (T_FUN_SYS_LAST_INSERT_ID == expr.get_expr_type() && expr.get_param_count() > 0)
|| T_FUN_SYS_PART_ID == expr.get_expr_type()
|| T_OP_GET_PACKAGE_VAR == expr.get_expr_type()
|| T_OP_GET_SUBPROGRAM_VAR == expr.get_expr_type()

View File

@ -265,48 +265,17 @@ int ObPredicateDeduce::check_index_part_cond(ObTransformerCtx &ctx,
int ret = OB_SUCCESS;
is_valid = false;
ObRawExpr *check_expr = NULL;
ObSQLSessionInfo *session_info = ctx.session_info_;
if (OB_ISNULL(left_expr) || OB_ISNULL(right_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("invalid index", K(ret), K(left_expr), K(right_expr));
} else if (OB_ISNULL(session_info)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("session_info is null", K(ret));
}else if (left_expr->is_column_ref_expr() && right_expr->is_const_expr()) {
} else if (left_expr->is_column_ref_expr() && right_expr->is_const_expr()) {
check_expr = left_expr;
} else if (right_expr->is_column_ref_expr() && left_expr->is_const_expr()) {
check_expr = right_expr;
}
if (OB_SUCC(ret) && NULL != check_expr) {
ObColumnRefRawExpr *col = static_cast<ObColumnRefRawExpr *>(check_expr);
const share::schema::ObColumnSchemaV2 *column_schema = NULL;
TableItem *table = stmt_.get_table_item_by_id(col->get_table_id());
if (OB_ISNULL(table)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("table is null", K(ret), K(*col));
} else if (!table->is_basic_table()) {
} else if (OB_FAIL(ctx.schema_checker_->get_column_schema(session_info->get_effective_tenant_id(),
table->ref_id_,
col->get_column_id(),
column_schema,
true))) {
LOG_WARN("failed to get column schema", K(ret), K(table->ref_id_), K(col->get_column_id()), K(col->get_table_id()), K(table), K(col), K(lbt()));
} else if (OB_ISNULL(column_schema)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("column schema is null", K(ret));
} else if (column_schema->is_rowkey_column()) {
is_valid = true;
} else if (OB_FAIL(ctx.schema_checker_->check_column_has_index(column_schema->get_tenant_id(),
table->ref_id_,
col->get_column_id(),
is_valid))) {
LOG_WARN("failed to check column is a key", K(ret));
} else if (is_valid) {
// do nothing
} else if (ctx.schema_checker_->check_if_partition_key(session_info->get_effective_tenant_id(),
table->ref_id_, col->get_column_id(), is_valid)) {
LOG_WARN("failed to check if partition key", K(ret));
if (OB_FAIL(ObTransformUtils::check_is_index_part_key(ctx, stmt_, check_expr, is_valid))) {
LOG_WARN("fail to check if check_expr is index or part key", K(ret));
}
}
return ret;

View File

@ -238,6 +238,14 @@ int ObTransformPreProcess::transform_one_stmt(common::ObIArray<ObParentDMLStmt>
LOG_TRACE("succeed to transform rollup exprs", K(is_happened));
}
}
if (OB_SUCC(ret)) {
if (OB_FAIL(transform_for_last_insert_id(stmt, is_happened))) {
LOG_WARN("failed to transform for last_insert_id.", K(ret));
} else {
trans_happened |= is_happened;
LOG_TRACE("succeed to transform for last_insert_id.",K(is_happened), K(ret));
}
}
if (OB_SUCC(ret)) {
LOG_DEBUG("transform pre process succ", K(*stmt));
if (OB_FAIL(stmt->formalize_stmt(ctx_->session_info_))) {
@ -9206,5 +9214,201 @@ int ObTransformPreProcess::check_pre_aggregate(const ObSelectStmt &select_stmt,
return ret;
}
int ObTransformPreProcess::transform_for_last_insert_id(ObDMLStmt *stmt, bool &trans_happened) {
int ret = OB_SUCCESS;
trans_happened = false;
if (OB_ISNULL(stmt)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected null", K(ret), K(stmt));
} else if (stmt->is_select_stmt()) {
ObSelectStmt *sel_stmt = static_cast<ObSelectStmt*>(stmt);
bool is_happened = false;
if (OB_FAIL(expand_for_last_insert_id(*stmt, sel_stmt->get_having_exprs(), is_happened))) {
LOG_WARN("fail to expand having exprs",K(ret));
} else {
trans_happened |= is_happened;
}
if (OB_FAIL(ret)) {
} else if (OB_FAIL(expand_for_last_insert_id(*stmt, sel_stmt->get_condition_exprs(), is_happened))) {
LOG_WARN("fail to expand condition exprs",K(ret));
} else {
trans_happened |= is_happened;
}
for (int64_t i = 0; OB_SUCC(ret) && i < sel_stmt->get_joined_tables().count(); ++i) {
if (OB_FAIL(expand_last_insert_id_for_join(*stmt, sel_stmt->get_joined_tables().at(i), is_happened))) {
LOG_WARN("failed to expand join conditions", K(ret));
} else {
trans_happened |= is_happened;
}
}
} else if (stmt->is_delete_stmt() || stmt->is_update_stmt()) {
bool is_happened = false;
if (OB_FAIL(expand_for_last_insert_id(*stmt, stmt->get_condition_exprs(), is_happened))) {
LOG_WARN("fail to expand having exprs",K(ret));
} else {
trans_happened |= is_happened;
}
}
return ret;
}
int ObTransformPreProcess::expand_last_insert_id_for_join(ObDMLStmt &stmt, JoinedTable *join_table, bool &has_happened) {
int ret = OB_SUCCESS;
bool is_happened = false;
has_happened = false;
if (OB_ISNULL(join_table) || OB_ISNULL(join_table->left_table_) || OB_ISNULL(join_table->right_table_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected null", K(ret), K(join_table));
} else if (OB_FAIL(expand_for_last_insert_id(stmt, join_table->join_conditions_, has_happened))) {
LOG_WARN("failed to expand join conditions", K(ret));
} else if (join_table->left_table_->is_joined_table() &&
OB_FAIL(expand_last_insert_id_for_join(stmt, static_cast<JoinedTable*>(join_table->left_table_), is_happened))) {
LOG_WARN("fail to expand last_insert_id in left join table", K(ret));
} else if (FALSE_IT(has_happened |= is_happened)) {
} else if (join_table->right_table_->is_joined_table() &&
OB_FAIL(expand_last_insert_id_for_join(stmt, static_cast<JoinedTable*>(join_table->right_table_), is_happened))) {
LOG_WARN("fail to expand last_insert_id in right join table", K(ret));
} else {
has_happened |= is_happened;
}
return ret;
}
int ObTransformPreProcess::expand_for_last_insert_id(ObDMLStmt &stmt, ObIArray<ObRawExpr*> &exprs, bool &is_happended) {
int ret = OB_SUCCESS;
ObSEArray<ObRawExpr *, 4> new_exprs;
is_happended = false;
for (int64_t i = 0; OB_SUCC(ret) && i < exprs.count(); ++i) {
ObRawExpr *expr = exprs.at(i);
if (OB_ISNULL(expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected null", K(ret), K(expr), K(i));
} else if (expr->has_flag(CNT_LAST_INSERT_ID) &&
(IS_RANGE_CMP_OP(expr->get_expr_type()) || T_OP_EQ == expr->get_expr_type()) &&
!expr->has_flag(CNT_RAND_FUNC) &&
!expr->has_flag(CNT_SUB_QUERY) &&
!expr->has_flag(CNT_ROWNUM) &&
!expr->has_flag(CNT_SEQ_EXPR) &&
!expr->has_flag(CNT_USER_VARIABLE)) {
bool removable = false;
ObRawExpr *left = expr->get_param_expr(0);
ObRawExpr *right = expr->get_param_expr(1);
ObRawExpr *check_expr = NULL;
if (OB_ISNULL(left) || OB_ISNULL(right)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected null", K(ret), K(left), K(right));
} else if (left->has_flag(CNT_LAST_INSERT_ID) && !left->has_flag(CNT_COLUMN) && right->has_flag(CNT_COLUMN)) {
check_expr = right;
} else if (right->has_flag(CNT_LAST_INSERT_ID) && !right->has_flag(CNT_COLUMN) && left->has_flag(CNT_COLUMN)) {
check_expr = left;
}
if (OB_FAIL(ret) || NULL == check_expr) {
//do nothing
} else if (OB_FAIL(ObTransformUtils::check_is_index_part_key(*ctx_, stmt, check_expr, removable))) {
LOG_WARN("fail to check if it's a index/part condition", K(ret));
} else if (!removable) {
//do nothing if the param which does not contain last_insert_id is not a index key with lossless cast or a index key.
} else if (OB_FAIL(check_last_insert_id_removable(expr, removable))) {
LOG_WARN("fail to check whether last_insert_id can be removed", K(ret));
} else if (removable) {
ObRawExpr *param_expr = check_expr == left ? right : left;
ObRawExpr *new_expr = NULL;
if (OB_FAIL(ObRawExprCopier::copy_expr(
*ctx_->expr_factory_,
param_expr,
param_expr))) {
LOG_WARN("failed to copy expr", K(ret));
} else if (OB_ISNULL(param_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("new param is invalid", K(ret));
} else if (OB_FAIL(remove_last_insert_id(param_expr))) {
LOG_WARN("failed to remove last insert id exprs", K(ret));
} else if (OB_FAIL(param_expr->formalize(ctx_->session_info_))) {
LOG_WARN("failed to formalize expr", K(ret));
} else if (!param_expr->is_const_expr()) {
//do nothing
} else if (OB_FAIL(ObRawExprCopier::copy_expr_node(*ctx_->expr_factory_,
expr,
new_expr))) {
LOG_WARN("failed to copy expr", K(ret));
} else if (OB_ISNULL(new_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("failed to build new expr", K(ret));
} else if (new_expr->get_param_expr(0) == check_expr) {
new_expr->get_param_expr(1) = param_expr;
} else {
new_expr->get_param_expr(0) = param_expr;
}
if (OB_SUCC(ret) && NULL != new_expr) {
if (OB_FAIL(new_expr->formalize(ctx_->session_info_))) {
LOG_WARN("failed to formalize expr", K(ret));
} else if (OB_FAIL(exprs.push_back(new_expr))) {
LOG_WARN("failed to push back new pred", K(ret));
} else {
is_happended = true;
}
}
}
}
}
return ret;
}
int ObTransformPreProcess::check_last_insert_id_removable(const ObRawExpr *expr, bool &is_removable) {
int ret = OB_SUCCESS;
is_removable = true;
if (OB_ISNULL(expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected null", K(ret), K(expr));
} else if (expr->has_flag(IS_LAST_INSERT_ID)) {
if (1 != expr->get_param_count()) {
is_removable = false;
} else {
const ObRawExpr *param = expr->get_param_expr(0);
if (OB_ISNULL(param)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected null", K(ret), K(param));
} else if (!param->has_flag(IS_CONST) && !param->has_flag(IS_CONST_EXPR)) {
is_removable = false;
}
}
} else if (expr->has_flag(CNT_LAST_INSERT_ID)) {
bool flag = true;
for (int64_t i = 0; OB_SUCC(ret) && is_removable && i < expr->get_param_count(); ++i) {
if (OB_FAIL(check_last_insert_id_removable(expr->get_param_expr(i), flag))) {
LOG_WARN("fail to check whether last insert id expr is removable", K(ret));
} else {
is_removable = is_removable & flag;
}
}
}
return ret;
}
int ObTransformPreProcess::remove_last_insert_id(ObRawExpr *&expr) {
int ret = OB_SUCCESS;
if (OB_ISNULL(expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected null", K(ret));
} else if (expr->has_flag(IS_LAST_INSERT_ID)) {
if (1 == expr->get_param_count()) {
ObRawExpr *new_expr = expr->get_param_expr(0);
if (OB_ISNULL(new_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected null", K(ret), K(new_expr));
} else if (new_expr->has_flag(IS_CONST) || new_expr->has_flag(IS_CONST_EXPR)) {
expr = new_expr;
}
}
} else if (expr->has_flag(CNT_LAST_INSERT_ID)) {
for (int64_t i = 0; OB_SUCC(ret) && i < expr->get_param_count(); ++i) {
if (OB_FAIL(remove_last_insert_id(expr->get_param_expr(i)))) {
LOG_WARN("fail to check whether last insert id expr is removable", K(ret));
}
}
} else {}
return ret;
}
} // end namespace sql
} // end namespace oceanbase

View File

@ -594,6 +594,12 @@ struct DistinctObjMeta
int add_column_conv_to_multiset(ObQueryRefRawExpr *multiset_expr,
const pl::ObPLDataType &elem_type,
bool& trans_happened);
int transform_for_last_insert_id(ObDMLStmt *stmt, bool &trans_happened);
int expand_for_last_insert_id(ObDMLStmt &stmt, ObIArray<ObRawExpr*> &exprs, bool &is_happended);
int expand_last_insert_id_for_join(ObDMLStmt &stmt, JoinedTable *join_table, bool &is_happened);
int remove_last_insert_id(ObRawExpr *&expr);
int check_last_insert_id_removable(const ObRawExpr *expr, bool &is_removable);
private:
DISALLOW_COPY_AND_ASSIGN(ObTransformPreProcess);
};

View File

@ -13211,5 +13211,58 @@ int ObTransformUtils::create_udt_hidden_columns(ObTransformerCtx *ctx,
return ret;
}
int ObTransformUtils::check_is_index_part_key(ObTransformerCtx &ctx,
ObDMLStmt &stmt,
ObRawExpr *check_expr,
bool &is_valid)
{
int ret = OB_SUCCESS;
is_valid = false;
ObSQLSessionInfo *session_info = ctx.session_info_;
if (OB_ISNULL(check_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("invalid index", K(ret), K(check_expr));
} else if (OB_ISNULL(session_info)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("session_info is null", K(ret));
} else if (OB_FAIL(ObOptimizerUtil::get_expr_without_lossless_cast(check_expr, check_expr))) {
LOG_WARN("failed to get expr without lossless cast", K(ret));
} else if (!check_expr->is_column_ref_expr()) {
// do nothing
} else {
ObColumnRefRawExpr *col = static_cast<ObColumnRefRawExpr *>(check_expr);
const share::schema::ObColumnSchemaV2 *column_schema = NULL;
TableItem *table = stmt.get_table_item_by_id(col->get_table_id());
if (OB_ISNULL(table)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("table is null", K(ret), K(*col));
} else if (!table->is_basic_table()) {
} else if (OB_FAIL(ctx.schema_checker_->get_column_schema(session_info->get_effective_tenant_id(),
table->ref_id_,
col->get_column_id(),
column_schema,
true))) {
LOG_WARN("failed to get column schema", K(ret), K(table->ref_id_), K(col->get_column_id()), K(col->get_table_id()), K(table), K(col), K(lbt()));
} else if (OB_ISNULL(column_schema)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("column schema is null", K(ret));
} else if (column_schema->is_rowkey_column()) {
is_valid = true;
} else if (OB_FAIL(ctx.schema_checker_->check_column_has_index(column_schema->get_tenant_id(),
table->ref_id_,
col->get_column_id(),
is_valid))) {
LOG_WARN("failed to check column is a key", K(ret));
} else if (is_valid) {
// do nothing
} else if (ctx.schema_checker_->check_if_partition_key(session_info->get_effective_tenant_id(),
table->ref_id_, col->get_column_id(), is_valid)) {
LOG_WARN("failed to check if partition key", K(ret));
}
}
return ret;
}
} // namespace sql
} // namespace oceanbase

View File

@ -1772,6 +1772,7 @@ public:
static int extract_shared_exprs(ObDMLStmt *parent,
ObIArray<ObRawExpr *> &relation_exprs,
ObIArray<ObRawExpr *> &common_exprs);
static int check_is_index_part_key(ObTransformerCtx &ctx, ObDMLStmt &stmt, ObRawExpr *check_expr, bool &is_valid);
private:
static int inner_get_lazy_left_join(ObDMLStmt *stmt,
TableItem *table,

View File

@ -4569,7 +4569,7 @@ last_insert_id()
1
select bug15728()|
bug15728()
0
1
drop function bug15728|
drop table t3|
drop procedure if exists bug18787|