735 lines
30 KiB
C++
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;
|
|
}
|
|
|
|
}
|
|
}
|