From 90c2c33118756860b6d5d3b1cbb38b4dfd0f9015 Mon Sep 17 00:00:00 2001 From: 2149 <260391947@qq.com> Date: Wed, 14 Jun 2023 02:48:20 +0000 Subject: [PATCH] [CP] Fix bug for last_insert_id() --- .../engine/expr/ob_expr_last_insert_id.cpp | 7 +- src/sql/resolver/expr/ob_raw_expr.cpp | 2 +- .../expr/ob_raw_expr_info_extractor.cpp | 2 +- src/sql/rewrite/ob_predicate_deduce.cpp | 37 +--- src/sql/rewrite/ob_transform_pre_process.cpp | 204 ++++++++++++++++++ src/sql/rewrite/ob_transform_pre_process.h | 6 + src/sql/rewrite/ob_transform_utils.cpp | 53 +++++ src/sql/rewrite/ob_transform_utils.h | 1 + .../test_suite/pl/r/mysql/sp_mysql.result | 2 +- 9 files changed, 274 insertions(+), 40 deletions(-) diff --git a/src/sql/engine/expr/ob_expr_last_insert_id.cpp b/src/sql/engine/expr/ob_expr_last_insert_id.cpp index a349d16b0..85bfa5ed6 100644 --- a/src/sql/engine/expr/ob_expr_last_insert_id.cpp +++ b/src/sql/engine/expr/ob_expr_last_insert_id.cpp @@ -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); diff --git a/src/sql/resolver/expr/ob_raw_expr.cpp b/src/sql/resolver/expr/ob_raw_expr.cpp index d7ea9971f..6072e169c 100644 --- a/src/sql/resolver/expr/ob_raw_expr.cpp +++ b/src/sql/resolver/expr/ob_raw_expr.cpp @@ -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()) diff --git a/src/sql/resolver/expr/ob_raw_expr_info_extractor.cpp b/src/sql/resolver/expr/ob_raw_expr_info_extractor.cpp index ea673e13b..c197b8e61 100644 --- a/src/sql/resolver/expr/ob_raw_expr_info_extractor.cpp +++ b/src/sql/resolver/expr/ob_raw_expr_info_extractor.cpp @@ -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() diff --git a/src/sql/rewrite/ob_predicate_deduce.cpp b/src/sql/rewrite/ob_predicate_deduce.cpp index bd856bd0f..ac7873666 100644 --- a/src/sql/rewrite/ob_predicate_deduce.cpp +++ b/src/sql/rewrite/ob_predicate_deduce.cpp @@ -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(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; diff --git a/src/sql/rewrite/ob_transform_pre_process.cpp b/src/sql/rewrite/ob_transform_pre_process.cpp index 4ea85810c..076b9dc35 100644 --- a/src/sql/rewrite/ob_transform_pre_process.cpp +++ b/src/sql/rewrite/ob_transform_pre_process.cpp @@ -238,6 +238,14 @@ int ObTransformPreProcess::transform_one_stmt(common::ObIArray 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(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(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(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 &exprs, bool &is_happended) { + int ret = OB_SUCCESS; + ObSEArray 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 diff --git a/src/sql/rewrite/ob_transform_pre_process.h b/src/sql/rewrite/ob_transform_pre_process.h index c607cab5c..6df50d7db 100644 --- a/src/sql/rewrite/ob_transform_pre_process.h +++ b/src/sql/rewrite/ob_transform_pre_process.h @@ -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 &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); }; diff --git a/src/sql/rewrite/ob_transform_utils.cpp b/src/sql/rewrite/ob_transform_utils.cpp index a765f7259..0d63885f2 100644 --- a/src/sql/rewrite/ob_transform_utils.cpp +++ b/src/sql/rewrite/ob_transform_utils.cpp @@ -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(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 diff --git a/src/sql/rewrite/ob_transform_utils.h b/src/sql/rewrite/ob_transform_utils.h index 35cd1727d..600cb7dc4 100644 --- a/src/sql/rewrite/ob_transform_utils.h +++ b/src/sql/rewrite/ob_transform_utils.h @@ -1772,6 +1772,7 @@ public: static int extract_shared_exprs(ObDMLStmt *parent, ObIArray &relation_exprs, ObIArray &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, diff --git a/tools/deploy/mysql_test/test_suite/pl/r/mysql/sp_mysql.result b/tools/deploy/mysql_test/test_suite/pl/r/mysql/sp_mysql.result index 1e0ed0d7f..0348b8f1a 100644 --- a/tools/deploy/mysql_test/test_suite/pl/r/mysql/sp_mysql.result +++ b/tools/deploy/mysql_test/test_suite/pl/r/mysql/sp_mysql.result @@ -4569,7 +4569,7 @@ last_insert_id() 1 select bug15728()| bug15728() -0 +1 drop function bug15728| drop table t3| drop procedure if exists bug18787|