Files
oceanbase/src/sql/rewrite/ob_transformer_impl.cpp
2023-03-17 02:40:51 +00:00

735 lines
30 KiB
C++

/**
* 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_REWRITE
#include "sql/rewrite/ob_transformer_impl.h"
#include "common/ob_common_utility.h"
#include "sql/session/ob_sql_session_info.h"
#include "sql/resolver/expr/ob_raw_expr_util.h"
#include "sql/rewrite/ob_transform_view_merge.h"
#include "sql/rewrite/ob_transform_min_max.h"
#include "sql/rewrite/ob_transform_where_subquery_pullup.h"
#include "sql/rewrite/ob_transform_eliminate_outer_join.h"
#include "sql/rewrite/ob_transform_simplify_distinct.h"
#include "sql/rewrite/ob_transform_simplify_expr.h"
#include "sql/rewrite/ob_transform_simplify_groupby.h"
#include "sql/rewrite/ob_transform_simplify_subquery.h"
#include "sql/rewrite/ob_transform_simplify_winfunc.h"
#include "sql/rewrite/ob_transform_simplify_orderby.h"
#include "sql/rewrite/ob_transform_simplify_limit.h"
#include "sql/rewrite/ob_transform_query_push_down.h"
#include "sql/rewrite/ob_transform_aggr_subquery.h"
#include "sql/rewrite/ob_transform_simplify_set.h"
#include "sql/rewrite/ob_transform_project_pruning.h"
#include "sql/rewrite/ob_transform_or_expansion.h"
#include "sql/rewrite/ob_transform_join_elimination.h"
#include "sql/rewrite/ob_transform_win_magic.h"
#include "sql/rewrite/ob_transform_groupby_pullup.h"
#include "sql/rewrite/ob_transform_groupby_pushdown.h"
#include "sql/rewrite/ob_transform_subquery_coalesce.h"
#include "sql/rewrite/ob_transform_pre_process.h"
#include "sql/rewrite/ob_transform_predicate_move_around.h"
#include "sql/rewrite/ob_transform_semi_to_inner.h"
#include "sql/rewrite/ob_transform_join_limit_pushdown.h"
#include "sql/rewrite/ob_transform_temp_table.h"
#include "sql/rewrite/ob_transform_const_propagate.h"
#include "sql/rewrite/ob_transform_left_join_to_anti.h"
#include "sql/rewrite/ob_transform_count_to_exists.h"
#include "sql/rewrite/ob_transform_expr_pullup.h"
#include "sql/rewrite/ob_transform_dblink.h"
#include "common/ob_smart_call.h"
#include "sql/engine/ob_exec_context.h"
using namespace oceanbase::common;
using namespace oceanbase::share;
namespace oceanbase
{
namespace sql
{
int ObTransformerImpl::transform(ObDMLStmt *&stmt)
{
int ret = OB_SUCCESS;
bool trans_happended = false;
if (OB_ISNULL(stmt)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret));
} else if (OB_FAIL(do_transform_dblink_write(stmt, trans_happended))) {
LOG_WARN("failed to do transform dblink write", K(ret));
} else if (trans_happended) {
//dml write query will be executed in remote, do not need transform
} else if (OB_FAIL(SMART_CALL(get_stmt_trans_info(stmt)))) {
LOG_WARN("get_stmt_trans_info failed", K(ret));
} else if (OB_FAIL(do_transform_pre_precessing(stmt))) {
LOG_WARN("failed to do transform pre_precessing", K(ret));
} else if (OB_FAIL(stmt->formalize_stmt_expr_reference())) {
LOG_WARN("failed to formalize stmt reference", K(ret));
} else if (OB_FAIL(do_transform(stmt))) {
LOG_WARN("failed to do transform", K(ret));
} else if (OB_FAIL(do_transform_dblink_read(stmt))) {
LOG_WARN("failed to do transform dblink read", K(ret));
} else if (OB_FAIL(stmt->formalize_stmt_expr_reference())) {
LOG_WARN("failed to formalize stmt reference", K(ret));
} else if (OB_FAIL(do_after_transform(stmt))) {
LOG_WARN("failed deal after transform", K(ret));
} else {
print_trans_stat();
}
return ret;
}
int ObTransformerImpl::get_stmt_trans_info(ObDMLStmt *stmt)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(stmt) || OB_ISNULL(ctx_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("stmt is null", K(ret));
} else if (stmt->is_select_stmt()) {
int64_t size = 0;
if (OB_FAIL(static_cast<ObSelectStmt *>(stmt)->get_set_stmt_size(size))) {
LOG_WARN("get set stmt size failed", K(ret));
} else if (size > ObTransformerImpl::MAX_SET_STMT_SIZE_OF_COSTED_BASED_RELUES) {
ctx_->is_set_stmt_oversize_ = true;
}
}
if (OB_SUCC(ret) && !ctx_->is_set_stmt_oversize_) {
ObSEArray<ObSelectStmt*, 4> child_stmts;
if (OB_FAIL(stmt->get_child_stmts(child_stmts))) {
LOG_WARN("failed to get child stmts", K(ret));
}
for (int64_t i = 0; OB_SUCC(ret) && !ctx_->is_set_stmt_oversize_&& i < child_stmts.count(); i++) {
if (OB_FAIL(SMART_CALL(get_stmt_trans_info(child_stmts.at(i))))) {
LOG_WARN("get_stmt_trans_info failed", K(ret));
}
}
}
return ret;
}
int ObTransformerImpl::do_transform(ObDMLStmt *&stmt)
{
int ret = OB_SUCCESS;
uint64_t need_types = ObTransformRule::ALL_TRANSFORM_RULES;
bool transformation_enabled = true;
const ObQueryCtx *query_ctx = NULL;
if (OB_ISNULL(stmt) || OB_ISNULL(query_ctx = stmt->get_query_ctx())
|| OB_ISNULL(ctx_) || OB_ISNULL(ctx_->session_info_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(stmt), K(query_ctx), K(ctx_),
K(ctx_->session_info_), K(ret));
} else if (OB_FAIL(ctx_->session_info_->is_transformation_enabled(transformation_enabled))) {
LOG_WARN("fail to get transformation_enabled", K(ret));
} else if (!transformation_enabled || query_ctx->get_global_hint().disable_query_transform()) {
/*do nothing*/
} else if (OB_FAIL(choose_rewrite_rules(stmt, need_types))) {
LOG_WARN("failed choose rewrite rules for stmt", K(ret));
} else if (need_types == 0) {
// do nothing
} else if (OB_FAIL(transform_rule_set(stmt, need_types, max_iteration_count_))) {
LOG_WARN("failed to transform one rule set", K(ret));
} else { /*do nothing*/ }
return ret;
}
// do somthing after transform postprocess:
// 1. add pre calc constraints.
// 2. add trans happened hints
int ObTransformerImpl::do_after_transform(ObDMLStmt *stmt)
{
int ret = OB_SUCCESS;
ObQueryCtx *query_ctx = NULL;
ObExecContext *exec_ctx = NULL;
if (OB_ISNULL(stmt) || OB_ISNULL(query_ctx = stmt->get_query_ctx())
|| OB_ISNULL(ctx_) || OB_ISNULL(exec_ctx = ctx_->exec_ctx_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret), K(stmt), K(query_ctx), K(ctx_), K(exec_ctx));
} else if (OB_FAIL(finalize_exec_params(stmt))) {
LOG_WARN("failed to finalize exec param", K(ret));
} else if (OB_FAIL(add_trans_happended_hints(*query_ctx, *ctx_))) {
LOG_WARN("failed to add trans happended hints", K(ret));
} else if (OB_FAIL(add_param_and_expr_constraints(*exec_ctx, *ctx_, *stmt))) {
LOG_WARN("failed to add pre calc constraints", K(ret));
} else if (OB_FAIL(adjust_global_dependency_tables(stmt))) {
LOG_WARN("failed to adjust global depency", K(ret));
}
return ret;
}
int ObTransformerImpl::get_all_stmts(ObDMLStmt *stmt,
ObIArray<ObDMLStmt*> &all_stmts)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(stmt)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret));
} else if (OB_FAIL(all_stmts.push_back(stmt))) {
LOG_WARN("failed to push back stmt", K(ret));
} else {
ObIArray<TableItem*> &tables = stmt->get_table_items();
for (int64_t i = 0; OB_SUCC(ret) && i < tables.count(); i++) {
if (OB_ISNULL(tables.at(i))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret));
} else if (!tables.at(i)->is_temp_table()) {
/* do nothing */
} else if (has_exist_in_array(all_stmts, static_cast<ObDMLStmt*>(tables.at(i)->ref_query_))) {
//do nothing
} else if (OB_FAIL(SMART_CALL(get_all_stmts(tables.at(i)->ref_query_, all_stmts)))) {
LOG_WARN("failed to get all stmts", K(ret));
}
}
if (OB_SUCC(ret)) {
ObSEArray<ObSelectStmt*, 4> child_stmts;
if (OB_FAIL(stmt->get_child_stmts(child_stmts))) {
LOG_WARN("failed to get child stmts", K(ret));
}
for (int64_t i = 0; OB_SUCC(ret) && i < child_stmts.count(); i++) {
if (OB_FAIL(SMART_CALL(get_all_stmts(child_stmts.at(i), all_stmts)))) {
LOG_WARN("failed to get all stmts", K(ret));
}
}
}
}
return ret;
}
int ObTransformerImpl::do_transform_pre_precessing(ObDMLStmt *&stmt)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(stmt) || OB_ISNULL(ctx_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(stmt), K(ret));
} else {
ObTransformPreProcess trans(ctx_);
trans.set_transformer_type(PRE_PROCESS);
uint64_t dummy_value = 0;
OPT_TRACE_TITLE("start pre process transform");
if (OB_FAIL(trans.transform(stmt, dummy_value))) {
LOG_WARN("failed to do transform pre processing", K(ret));
} else {
LOG_TRACE("succeed to do transform pre processing");
}
}
return ret;
}
int ObTransformerImpl::do_transform_dblink_write(ObDMLStmt *&stmt, bool &trans_happened)
{
int ret = OB_SUCCESS;
trans_happened = false;
if (OB_ISNULL(stmt) || OB_ISNULL(ctx_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(stmt), K(ret));
} else {
ObTransformDBlink trans(ctx_);
trans.set_transformer_type(PROCESS_DBLINK);
trans.set_transform_for_write(true);
uint64_t dummy_value = 0;
if (stmt->is_dml_write_stmt()) {
ObSEArray<ObParentDMLStmt, 4> parent_stmts;
if (OB_FAIL(trans.transform_self(parent_stmts, 0, stmt))) {
LOG_WARN("failed to transform self", K(ret));
} else {
trans_happened = trans.get_trans_happened();
LOG_TRACE("succeed to do transform dml dblink write");
}
}
}
return ret;
}
int ObTransformerImpl::do_transform_dblink_read(ObDMLStmt *&stmt)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(stmt) || OB_ISNULL(ctx_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(stmt), K(ret));
} else {
ObTransformDBlink trans(ctx_);
trans.set_transformer_type(PROCESS_DBLINK);
trans.set_transform_for_write(false);
uint64_t dummy_value = 0;
if (OB_FAIL(trans.transform(stmt, dummy_value))) {
LOG_WARN("failed to do transform dblink read", K(ret));
} else {
LOG_TRACE("succeed to do transform dblink read");
}
}
return ret;
}
int ObTransformerImpl::transform_heuristic_rule(ObDMLStmt *&stmt)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(stmt)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("stmt is NULL", K(ret));
} else if (OB_FAIL(transform_rule_set(stmt,
ObTransformRule::ALL_HEURISTICS_RULES,
max_iteration_count_))) {
LOG_WARN("failed to transform one rule set", K(ret));
} else { /*do nothing*/ }
return ret;
}
int ObTransformerImpl::transform_rule_set(ObDMLStmt *&stmt,
uint64_t needed_types,
int64_t iteration_count)
{
int ret = OB_SUCCESS;
if (0 != (needed_types & needed_transform_types_)) {
bool need_next_iteration = true;
int64_t i = 0;
for (i = 0; OB_SUCC(ret) && need_next_iteration && i < iteration_count; ++i) {
bool trans_happened_in_iteration = false;
LOG_TRACE("start to transform one iteration", K(i));
OPT_TRACE("-- begin ", i, " iteration");
if (OB_FAIL(transform_rule_set_in_one_iteration(stmt,
needed_types,
trans_happened_in_iteration))) {
LOG_WARN("failed to do transformation one iteration", K(i), K(ret));
} else if (!trans_happened_in_iteration) {
need_next_iteration = false;
} else if (OB_FAIL(stmt->formalize_stmt_expr_reference())) {
LOG_WARN("failed to formalize stmt expr", K(ret));
} else if (OB_FAIL(stmt->formalize_stmt(ctx_->session_info_))) {
LOG_WARN("failed to formalize stmt", K(ret));
} else {
need_next_iteration = true;
}
LOG_TRACE("succeed to transform one iteration", K(i), K(need_next_iteration), K(ret));
OPT_TRACE("-- end ", i, " iteration");
}
if (OB_SUCC(ret) && i == max_iteration_count_) {
LOG_INFO("transformer ends without convergence", K(max_iteration_count_));
}
}
return ret;
}
int ObTransformerImpl::transform_rule_set_in_one_iteration(ObDMLStmt *&stmt,
uint64_t needed_types,
bool &trans_happened)
{
int ret = OB_SUCCESS;
trans_happened = false;
if (OB_ISNULL(stmt)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("stmt is NULL", K(ret));
} else {
/*
* The ordering to apply the following rules is important,
* think carefully when new rules are added
*/
APPLY_RULE_IF_NEEDED(SIMPLIFY_EXPR, ObTransformSimplifyExpr);
APPLY_RULE_IF_NEEDED(SIMPLIFY_DISTINCT, ObTransformSimplifyDistinct);
APPLY_RULE_IF_NEEDED(SIMPLIFY_GROUPBY, ObTransformSimplifyGroupby);
APPLY_RULE_IF_NEEDED(SIMPLIFY_WINFUNC, ObTransformSimplifyWinfunc);
APPLY_RULE_IF_NEEDED(SIMPLIFY_ORDERBY, ObTransformSimplifyOrderby);
APPLY_RULE_IF_NEEDED(SIMPLIFY_LIMIT, ObTransformSimplifyLimit);
APPLY_RULE_IF_NEEDED(TEMP_TABLE_OPTIMIZATION, ObTransformTempTable);
APPLY_RULE_IF_NEEDED(PROJECTION_PRUNING, ObTransformProjectPruning);
APPLY_RULE_IF_NEEDED(CONST_PROPAGATE, ObTransformConstPropagate);
APPLY_RULE_IF_NEEDED(SUBQUERY_COALESCE, ObTransformSubqueryCoalesce);
APPLY_RULE_IF_NEEDED(SIMPLIFY_SET, ObTransformSimplifySet);
APPLY_RULE_IF_NEEDED(VIEW_MERGE, ObTransformViewMerge);
APPLY_RULE_IF_NEEDED(COUNT_TO_EXISTS, ObTransformCountToExists);
APPLY_RULE_IF_NEEDED(WHERE_SQ_PULL_UP, ObWhereSubQueryPullup);
APPLY_RULE_IF_NEEDED(SIMPLIFY_SUBQUERY, ObTransformSimplifySubquery);
APPLY_RULE_IF_NEEDED(SEMI_TO_INNER, ObTransformSemiToInner);
APPLY_RULE_IF_NEEDED(QUERY_PUSH_DOWN, ObTransformQueryPushDown);
APPLY_RULE_IF_NEEDED(SELECT_EXPR_PULLUP, ObTransformExprPullup);
APPLY_RULE_IF_NEEDED(ELIMINATE_OJ, ObTransformEliminateOuterJoin);
APPLY_RULE_IF_NEEDED(JOIN_ELIMINATION, ObTransformJoinElimination);
APPLY_RULE_IF_NEEDED(JOIN_LIMIT_PUSHDOWN, ObTransformJoinLimitPushDown);
APPLY_RULE_IF_NEEDED(LEFT_JOIN_TO_ANTI, ObTransformLeftJoinToAnti);
APPLY_RULE_IF_NEEDED(AGGR_SUBQUERY, ObTransformAggrSubquery);
APPLY_RULE_IF_NEEDED(WIN_MAGIC, ObTransformWinMagic);
APPLY_RULE_IF_NEEDED(GROUPBY_PUSHDOWN, ObTransformGroupByPushdown);
APPLY_RULE_IF_NEEDED(GROUPBY_PULLUP, ObTransformGroupByPullup);
APPLY_RULE_IF_NEEDED(FASTMINMAX, ObTransformMinMax);
APPLY_RULE_IF_NEEDED(PREDICATE_MOVE_AROUND, ObTransformPredicateMoveAround);
APPLY_RULE_IF_NEEDED(OR_EXPANSION, ObTransformOrExpansion);
}
return ret;
}
int ObTransformerImpl::get_cost_based_trans_happened(TRANSFORM_TYPE type, bool &trans_happened) const
{
int ret = OB_SUCCESS;
trans_happened = false;
if (OB_ISNULL(ctx_)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid argument", K(ret), K(ctx_));
} else {
trans_happened = is_type_needed(ctx_->happened_cost_based_trans_, type);
}
return ret;
}
int ObTransformerImpl::collect_trans_stat(const ObTransformRule &rule)
{
int ret = OB_SUCCESS;
if (rule.get_trans_happened()) {
int64_t idx = rule.get_transformer_type();
if (idx >= 1 && idx < MAX_RULE_COUNT) {
++ trans_count_[idx];
}
}
return ret;
}
void ObTransformerImpl::print_trans_stat()
{
for (int64_t i = 1; i < TRANSFORM_TYPE_COUNT_PLUS_ONE; ++i) {
LOG_TRACE("Transform Stat ", "Rule", i, "Happened", trans_count_[i]);
}
}
int ObTransformerImpl::choose_rewrite_rules(ObDMLStmt *stmt, uint64_t &need_types)
{
int ret = OB_SUCCESS;
uint64_t disable_list = 0;
StmtFunc func;
ObSqlCtx *sql_ctx = NULL;
if (OB_ISNULL(stmt)
|| OB_ISNULL(ctx_->exec_ctx_)
|| OB_ISNULL(sql_ctx = ctx_->exec_ctx_->get_sql_ctx())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("stmt is null", K(ret), K(stmt));
} else if (sql_ctx->multi_stmt_item_.is_batched_multi_stmt()) {
need_types = 0; //如果是batch优化暂时不做改写
} else if (OB_FAIL(check_stmt_functions(stmt, func))) {
LOG_WARN("failed to check stmt functions", K(ret));
} else {
//TODO::unpivot open @xifeng
if (func.contain_unpivot_query_ || func.contain_enum_set_values_ || func.contain_geometry_values_) {
disable_list = ObTransformRule::ALL_TRANSFORM_RULES;
}
if (func.contain_sequence_) {
ObTransformRule::add_trans_type(disable_list, WIN_MAGIC);
}
if (func.contain_for_update_) {
ObTransformRule::add_trans_type(disable_list, JOIN_ELIMINATION);
ObTransformRule::add_trans_type(disable_list, WIN_MAGIC);
ObTransformRule::add_trans_type(disable_list, NL_FULL_OUTER_JOIN);
ObTransformRule::add_trans_type(disable_list, OR_EXPANSION);
}
if (func.update_global_index_) {
ObTransformRule::add_trans_type(disable_list, OR_EXPANSION);
ObTransformRule::add_trans_type(disable_list, WIN_MAGIC);
}
if (func.contain_link_table_) {
disable_list |= (~ObTransformRule::ALL_HEURISTICS_RULES);
// Below rules might generate filter which contains constant values which has implicit types,
// which can not be printed in the link sql.
// example:
// create table t (c1 varchar(10), c2 char(10))
// select * from t where c1 = 'a' and c2 = c1;
// => select * from t where c1 = 'a' and c2 = implicit cast('a' as varchar);
ObTransformRule::add_trans_type(disable_list, PREDICATE_MOVE_AROUND);
ObTransformRule::add_trans_type(disable_list, CONST_PROPAGATE);
ObTransformRule::add_trans_type(disable_list, SIMPLIFY_EXPR);
}
need_types = ObTransformRule::ALL_TRANSFORM_RULES & (~disable_list);
}
return ret;
}
int ObTransformerImpl::check_stmt_functions(ObDMLStmt *stmt, StmtFunc &func)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(stmt)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("stmt is null", K(ret), K(stmt));
} else {
func.contain_hie_query_ = func.contain_hie_query_ || stmt->is_hierarchical_query();
func.contain_sequence_ = func.contain_sequence_ || stmt->has_sequence();
func.contain_for_update_ = func.contain_for_update_ || stmt->has_for_update();
func.contain_unpivot_query_ = func.contain_unpivot_query_ || stmt->is_unpivot_select();
}
for (int64_t i = 0; OB_SUCC(ret)
&& (!func.contain_enum_set_values_ || !func.contain_geometry_values_)
&& i < stmt->get_column_items().count(); ++i) {
const ColumnItem &col = stmt->get_column_items().at(i);
if (OB_ISNULL(col.get_expr())) {
ret = OB_ERR_UNEXPECTED;
} else {
func.contain_enum_set_values_ |= ob_is_enumset_tc(col.get_expr()->get_data_type());
func.contain_geometry_values_ |= ob_is_geometry_tc(col.get_expr()->get_data_type());
}
}
for (int64_t i = 0; OB_SUCC(ret) && !func.contain_link_table_ &&
i < stmt->get_table_items().count(); ++i) {
TableItem *table = stmt->get_table_item(i);
if (OB_ISNULL(table)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null table item", K(ret));
} else if (table->is_link_table()) {
func.contain_link_table_ = true;
}
}
if (OB_SUCC(ret) && (stmt->is_delete_stmt() ||
stmt->is_update_stmt() ||
stmt->is_merge_stmt() ||
stmt->is_insert_stmt())) {
ObDelUpdStmt *del_upd_stmt = static_cast<ObDelUpdStmt *>(stmt);
func.update_global_index_ = func.update_global_index_ || del_upd_stmt->has_global_index();
}
if (OB_SUCC(ret) && !func.all_found()) {
ObSEArray<ObSelectStmt*, 8> child_stmts;
if (OB_FAIL(stmt->get_child_stmts(child_stmts))) {
LOG_WARN("get child stmt failed", K(ret));
}
for (int64_t i = 0; OB_SUCC(ret) && i < child_stmts.count(); ++i) {
ObSelectStmt *sub_stmt = child_stmts.at(i);
if (OB_ISNULL(sub_stmt)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("sub stmt is null", K(ret));
} else if (OB_FAIL(SMART_CALL(check_stmt_functions(sub_stmt, func)))) {
LOG_WARN("failed to check stmt functions", K(ret));
}
}
}
return ret;
}
int ObTransformerImpl::finalize_exec_params(ObDMLStmt *stmt)
{
int ret = OB_SUCCESS;
ObSEArray<ObSelectStmt *, 4> child_stmts;
if (OB_ISNULL(stmt)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("stmt is null", K(ret));
} else if (OB_FAIL(stmt->get_child_stmts(child_stmts))) {
LOG_WARN("failed to get child stmts", K(ret));
} else {
ObArray<ObDMLStmt::TempTableInfo> temp_table_infos;
if (OB_FAIL(stmt->collect_temp_table_infos(temp_table_infos))) {
LOG_WARN("failed to collect temp table infos", K(ret));
}
for (int64_t i = 0; OB_SUCC(ret) && i < temp_table_infos.count(); ++i) {
if (OB_FAIL(child_stmts.push_back(temp_table_infos.at(i).temp_table_query_))) {
LOG_WARN("failed to push back temp table query", K(ret));
}
}
}
for (int64_t i = 0; OB_SUCC(ret) && i < stmt->get_subquery_expr_size(); ++i) {
ObQueryRefRawExpr *query_ref = NULL;
if (OB_ISNULL(query_ref = stmt->get_subquery_exprs().at(i))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("query ref expr is null", K(ret));
}
for (int64_t j = 0; OB_SUCC(ret) && j < query_ref->get_param_count(); ++j) {
ObExecParamRawExpr *exec_param = NULL;
if (OB_ISNULL(exec_param = query_ref->get_exec_param(j))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("exec param is null", K(ret));
} else if (exec_param->get_param_index() >= 0) {
// do nothing
} else {
exec_param->set_param_index(stmt->get_question_marks_count());
stmt->increase_question_marks_count();
}
}
}
for (int64_t i = 0; OB_SUCC(ret) && i < child_stmts.count(); ++i) {
if (OB_FAIL(SMART_CALL(finalize_exec_params(child_stmts.at(i))))) {
LOG_WARN("failed to finalize exec params", K(ret));
}
}
return ret;
}
// TODO @yibo perhaps we can't remove dependency table.
// for example, t1 left join t2 on t1.c1 = t2.c1 eliminate t2 relay on t2.c1 is unique,
// if schema version of t2 change, t2.c1 may not uniuqe.
int ObTransformerImpl::adjust_global_dependency_tables(ObDMLStmt *stmt)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(stmt)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret));
} else {
ObIArray<share::schema::ObSchemaObjVersion> *global_tables = stmt->get_global_dependency_table();
if (OB_ISNULL(global_tables)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret));
} else { /*do nothing.*/ }
for (int64_t i = 0; OB_SUCC(ret) && i < global_tables->count(); ++i) {
bool is_existed = false;
if (global_tables->at(i).is_base_table()) {
if (OB_FAIL(stmt->check_if_table_exists(global_tables->at(i).object_id_,
is_existed))) {
LOG_WARN("failed to check if exists in stmt.", K(ret));
} else if (!is_existed) {
global_tables->at(i).is_existed_ = false;
} else { /* do nothing. */ }
} else { /* do nothing. */ }
}
}
return ret;
}
int ObTransformerImpl::add_param_and_expr_constraints(ObExecContext &exec_ctx,
ObTransformerCtx &trans_ctx,
ObDMLStmt &stmt)
{
int ret = OB_SUCCESS;
ObSEArray<ObHiddenColumnItem, 8> pre_calc_error_exprs;
ObQueryCtx *query_ctx = NULL;
if (OB_ISNULL(query_ctx = stmt.get_query_ctx())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null", K(ret), K(query_ctx));
} else if (OB_FAIL(append(query_ctx->all_plan_const_param_constraints_,
trans_ctx.plan_const_param_constraints_))) {
LOG_WARN("fail to append const param constraints. ", K(ret));
} else if (OB_FAIL(append(query_ctx->all_equal_param_constraints_,
trans_ctx.equal_param_constraints_))) {
LOG_WARN("fail to append equal param constraints. ", K(ret));
} else if (OB_FAIL(query_ctx->all_expr_constraints_.assign(trans_ctx.expr_constraints_))) {
LOG_WARN("fail to assign expr constraints", K(ret));
}
return ret;
}
int ObTransformerImpl::add_all_rowkey_columns_to_stmt(ObDMLStmt *stmt)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(stmt) || OB_ISNULL(ctx_) || OB_ISNULL(ctx_->schema_checker_)
|| OB_ISNULL(ctx_->expr_factory_) || OB_ISNULL(ctx_->session_info_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null", K(ret), K(stmt), K(ctx_));
} else {
ObIArray<TableItem*> &tables = stmt->get_table_items();
TableItem *table_item = NULL;
const ObTableSchema *table_schema = NULL;
ObSEArray<ColumnItem, 16> column_items;
for (int64_t i = 0; OB_SUCC(ret) && i < tables.count(); ++i) {
if (OB_ISNULL(table_item = tables.at(i))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null", K(ret), K(table_item));
} else if (!table_item->is_basic_table() && !table_item->is_link_table()) {
/* do nothing */
} else if (OB_FAIL(ctx_->schema_checker_->get_table_schema(ctx_->session_info_->get_effective_tenant_id(),
table_item->ref_id_,
table_schema,
table_item->is_link_table()))) {
LOG_WARN("table schema not found", K(table_schema));
} else if (OB_ISNULL(table_schema)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get invalid table schema", K(table_schema));
} else if (OB_FAIL(add_all_rowkey_columns_to_stmt(*table_schema, *table_item,
*ctx_->expr_factory_,
*stmt,
column_items))) {
LOG_WARN("add all rowkey exprs failed", K(ret));
}
}
if (OB_SUCC(ret) && !column_items.empty()) {
ObIArray<ColumnItem> &orign_column_items = stmt->get_column_items();
for (int i = 0; OB_SUCC(ret) && i < orign_column_items.count(); ++i) {
if (OB_ISNULL(orign_column_items.at(i).expr_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret), K(orign_column_items.at(i).expr_));
} else if (!orign_column_items.at(i).expr_->is_rowkey_column() &&
OB_FAIL(column_items.push_back(orign_column_items.at(i)))) {
LOG_WARN("failed to push back column item", K(ret));
}
}
if (OB_SUCC(ret) && OB_FAIL(stmt->get_column_items().assign(column_items))) {
LOG_WARN("failed to assign column items", K(ret));
}
}
}
return ret;
}
int ObTransformerImpl::add_all_rowkey_columns_to_stmt(const ObTableSchema &table_schema,
const TableItem &table_item,
ObRawExprFactory &expr_factory,
ObDMLStmt &stmt,
ObIArray<ColumnItem> &column_items)
{
int ret = OB_SUCCESS;
const ObRowkeyInfo &rowkey_info = table_schema.get_rowkey_info();
const ObColumnSchemaV2 *column_schema = NULL;
uint64_t column_id = OB_INVALID_ID;
ColumnItem *exists_col_item = NULL;
ObColumnRefRawExpr *rowkey = NULL;
for (int col_idx = 0; OB_SUCC(ret) && col_idx < rowkey_info.get_size(); ++col_idx) {
if (OB_FAIL(rowkey_info.get_column_id(col_idx, column_id))) {
LOG_WARN("Failed to get column id", K(ret));
} else if (NULL != (exists_col_item = stmt.get_column_item_by_id(table_item.table_id_,
column_id))) {
if (OB_FAIL(column_items.push_back(*exists_col_item))) {
LOG_WARN("failed to push back column item", K(ret));
}
} else if (OB_MOCK_LINK_TABLE_PK_COLUMN_ID == column_id && table_item.is_link_table()) {
continue;
} else if (OB_ISNULL(column_schema = (table_schema.get_column_schema(column_id)))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("failed to get column schema", K(column_id), K(ret));
} else if (OB_FAIL(ObRawExprUtils::build_column_expr(expr_factory, *column_schema, rowkey))) {
LOG_WARN("build column expr failed", K(ret));
} else if (OB_ISNULL(rowkey)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("failed to create raw expr for dummy output", K(ret));
} else {
ColumnItem column_item;
rowkey->set_ref_id(table_item.table_id_, column_schema->get_column_id());
rowkey->set_column_attr(table_item.get_table_name(), column_schema->get_column_name_str());
rowkey->set_database_name(table_item.database_name_);
if (!table_item.alias_name_.empty()) {
rowkey->set_table_alias_name();
}
column_item.table_id_ = rowkey->get_table_id();
column_item.column_id_ = rowkey->get_column_id();
column_item.base_tid_ = table_item.ref_id_;
column_item.base_cid_ = rowkey->get_column_id();
column_item.column_name_ = rowkey->get_column_name();
column_item.set_default_value(column_schema->get_cur_default_value());
column_item.expr_ = rowkey;
if (OB_FAIL(stmt.add_column_item(column_item))) {
LOG_WARN("add column item to stmt failed", K(ret));
} else if (OB_FAIL(column_items.push_back(column_item))) {
LOG_WARN("failed to push back column item", K(ret));
} else if (FALSE_IT(rowkey->clear_explicited_referece())) {
} else if (OB_FAIL(rowkey->formalize(NULL))) {
LOG_WARN("formalize rowkey failed", K(ret));
} else if (OB_FAIL(rowkey->pull_relation_id())) {
LOG_WARN("failed to pullup relation ids", K(ret));
}
}
}
return ret;
}
int ObTransformerImpl::add_trans_happended_hints(ObQueryCtx &query_ctx,
ObTransformerCtx &trans_ctx)
{
int ret = OB_SUCCESS;
ObQueryHint &query_hint = query_ctx.get_query_hint_for_update();
if (OB_FAIL(query_hint.outline_trans_hints_.assign(trans_ctx.outline_trans_hints_))) {
LOG_WARN("failed to assign trans hints", K(ret));
} else if (OB_FAIL(query_hint.used_trans_hints_.assign(trans_ctx.used_trans_hints_))) {
LOG_WARN("failed to assign trans hints", K(ret));
}
return ret;
}
}
}