Files
oceanbase/src/sql/rewrite/ob_transform_temp_table.cpp
2023-04-06 07:56:07 +00:00

2294 lines
96 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 "ob_transform_temp_table.h"
#include "lib/allocator/ob_allocator.h"
#include "lib/hash/ob_hashmap.h"
#include "lib/oblog/ob_log_module.h"
#include "common/ob_common_utility.h"
#include "sql/resolver/expr/ob_raw_expr.h"
#include "sql/resolver/expr/ob_raw_expr_util.h"
#include "sql/resolver/dml/ob_dml_stmt.h"
#include "sql/resolver/dml/ob_select_stmt.h"
#include "sql/optimizer/ob_optimizer_util.h"
#include "sql/rewrite/ob_predicate_deduce.h"
#include "common/ob_smart_call.h"
using namespace oceanbase::common;
namespace oceanbase
{
namespace sql
{
ObTransformTempTable::~ObTransformTempTable()
{
if (OB_NOT_NULL(trans_param_)) {
trans_param_->~TempTableTransParam();
trans_param_ = NULL;
}
}
int ObTransformTempTable::transform_one_stmt(common::ObIArray<ObParentDMLStmt> &parent_stmts,
ObDMLStmt *&stmt,
bool &trans_happened)
{
int ret = OB_SUCCESS;
bool is_happened = false;
ObSEArray<ObSelectStmt*, 8> child_stmts;
ObSEArray<ObSelectStmt*, 8> non_correlated_stmts;
ObArray<TempTableInfo> temp_table_infos;
hash::ObHashMap<uint64_t, ObDMLStmt *> parent_map;
hash::ObHashMap<uint64_t, uint64_t> param_level;
uint64_t min_param_level = 0;
trans_happened = false;
//当前stmt是root stmt时才改写
if (parent_stmts.empty()) {
void *buf = NULL;
if (OB_ISNULL(buf = allocator_.alloc(sizeof(TempTableTransParam)))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("failed to allocate memory", K(ret));
} else {
trans_param_ = new(buf)TempTableTransParam;
}
if (OB_FAIL(ret)) {
} else if (OB_FAIL(parent_map.create(128, "TempTable"))) {
LOG_WARN("failed to init stmt map", K(ret));
} else if (OB_FAIL(param_level.create(128, "TempTable"))) {
LOG_WARN("failed to init expr map", K(ret));
} else if (OB_FAIL(ObTransformUtils::get_all_child_stmts(stmt, child_stmts, &parent_map))) {
LOG_WARN("failed to get all child stmts", K(ret));
} else if (OB_FAIL(get_non_correlated_subquery(stmt, 0, param_level, non_correlated_stmts, min_param_level))) {
LOG_WARN("failed to get non correlated subquery", K(ret));
} else if (OB_FAIL(ObOptimizerUtil::intersect(child_stmts, non_correlated_stmts, child_stmts))) {
LOG_WARN("failed to intersect child stmts", K(ret));
} else if (OB_FAIL(extract_common_subquery_as_cte(stmt, child_stmts, parent_map, is_happened))) {
LOG_WARN("failed to extract common subquery as cte", K(ret));
} else if (OB_FAIL(parent_map.destroy())) {
LOG_WARN("failed to destroy map", K(ret));
} else if (OB_FAIL(param_level.destroy())) {
LOG_WARN("failed to destroy map", K(ret));
} else {
trans_happened |= is_happened;
OPT_TRACE("extract common subquery as cte:", is_happened);
LOG_TRACE("succeed to extract common subquery as cte", K(is_happened));
}
if (OB_SUCC(ret)) {
if (OB_FAIL(collect_temp_table_infos(stmt, temp_table_infos))) {
LOG_WARN("failed to collect temp table infos", K(ret));
}
}
if (OB_SUCC(ret)) {
if (OB_FAIL(push_down_filter(temp_table_infos, is_happened))) {
LOG_WARN("failed to push down filter into temp table", K(ret));
} else {
trans_happened |= is_happened;
OPT_TRACE("push down filter into temp table:", is_happened);
LOG_TRACE("succeed to push down filter into temp table", K(is_happened));
}
}
if (OB_SUCC(ret)) {
temp_table_infos.reuse();
if (OB_FAIL(collect_temp_table_infos(stmt, temp_table_infos))) {
LOG_WARN("failed to collect temp table infos", K(ret));
}
}
if (OB_SUCC(ret)) {
if (OB_FAIL(project_pruning(temp_table_infos, is_happened))) {
LOG_WARN("failed to do project pruning for temp table", K(ret));
} else {
trans_happened |= is_happened;
OPT_TRACE("project pruning for temp table:", is_happened);
LOG_TRACE("succeed to do project pruning for temp table", K(temp_table_infos), K(is_happened));
}
}
if (OB_SUCC(ret)) {
if (OB_FAIL(expand_temp_table(temp_table_infos, is_happened))) {
LOG_WARN("failed to expand temp table", K(ret));
} else {
trans_happened |= is_happened;
OPT_TRACE("expand temp table:", is_happened);
LOG_TRACE("succeed to expand temp table", K(is_happened));
}
}
}
return ret;
}
/**
* @brief expand_temp_table
* 如果temp table只被引用一次或者temp table是一个简单的查询
* 例如单表查询,那么需要展开temp table,还原成generate table
*/
int ObTransformTempTable::expand_temp_table(ObIArray<TempTableInfo> &temp_table_info,
bool &trans_happened)
{
int ret = OB_SUCCESS;
trans_happened = false;
for (int64_t i = 0; OB_SUCC(ret) && i < temp_table_info.count(); ++i) {
TempTableInfo &helper = temp_table_info.at(i);
bool can_materia = false;
bool force_materia = false;
bool force_inline = false;
OPT_TRACE("try to expand temp table:", helper.temp_table_query_);
if (OB_ISNULL(helper.temp_table_query_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null ref query", K(helper), K(ret));
} else if (OB_FAIL(check_hint_allowed_trans(*helper.temp_table_query_,
force_inline,
force_materia))) {
LOG_WARN("failed to check force materialize", K(ret));
} else if (force_materia) {
OPT_TRACE("hint force materialize");
} else if (!force_inline &&
OB_FAIL(check_stmt_can_materialize(helper.temp_table_query_, can_materia))) {
LOG_WARN("failed to check extract cte valid", K(ret));
} else if (!can_materia ||
force_inline ||
1 == helper.table_infos_.count()) {
if (force_inline) {
OPT_TRACE("hint force extend temp table");
}
if (1 == helper.table_infos_.count()) {
OPT_TRACE("temp table if used once, will extend");
}
//深拷贝每一份查询,还原成generate table
ObDMLStmt *orig_stmt = helper.temp_table_query_;
if (OB_FAIL(inner_expand_temp_table(helper))) {
LOG_WARN("failed to extend temp table", K(ret));
} else if (OB_FAIL(add_normal_temp_table_trans_hint(*orig_stmt, T_INLINE))) {
LOG_WARN("failed to add transform hint", K(ret));
} else {
trans_happened = true;
}
}
}
return ret;
}
int ObTransformTempTable::inner_expand_temp_table(TempTableInfo &helper)
{
int ret = OB_SUCCESS;
ObSelectStmt *temp_table_query = NULL;
if (OB_ISNULL(ctx_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null ctx", K(ret));
}
for (int64_t j = 0; OB_SUCC(ret) && j < helper.table_infos_.count(); ++j) {
TableItem *table = helper.table_infos_.at(j).table_item_;
ObDMLStmt *upper_stmt = helper.table_infos_.at(j).upper_stmt_;
if (OB_ISNULL(table) || OB_ISNULL(upper_stmt)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null table item", K(ret));
} else if (!table->is_temp_table()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("expect temp table item", KPC(table), K(ret));
} else {
ObSelectStmt *child_stmt = NULL;
if (0 == j) {
temp_table_query = table->ref_query_;
if (OB_ISNULL(temp_table_query)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null stmt", K(ret));
} else if (OB_FAIL(temp_table_query->formalize_stmt(ctx_->session_info_))) {
LOG_WARN("failed to formalize stmt", K(ret));
} else if (OB_FAIL(temp_table_query->formalize_stmt_expr_reference())) {
LOG_WARN("failed to formalize stmt reference", K(ret));
} else if (OB_FAIL(upper_stmt->formalize_stmt_expr_reference())) {
LOG_WARN("failed to formalize stmt reference", K(ret));
}
} else if (OB_FAIL(ctx_->stmt_factory_->create_stmt<ObSelectStmt>(child_stmt))) {
LOG_WARN("failed to create stmt", K(ret));
} else if (OB_ISNULL(child_stmt) || OB_ISNULL(temp_table_query)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null stmt", K(ret));
} else if (OB_FAIL(child_stmt->deep_copy(*ctx_->stmt_factory_,
*ctx_->expr_factory_,
*temp_table_query))) {
LOG_WARN("failed to deep copy stmt", K(ret));
} else if (OB_FAIL(child_stmt->formalize_stmt(ctx_->session_info_))) {
LOG_WARN("failed to formalize stmt", K(ret));
} else if (OB_FAIL(child_stmt->formalize_stmt_expr_reference())) {
LOG_WARN("failed to formalize stmt reference", K(ret));
} else if (OB_FAIL(child_stmt->recursive_adjust_statement_id(ctx_->allocator_,
ctx_->src_hash_val_,
j))) {
LOG_WARN("failed to recursive adjust statement id", K(ret));
} else if (OB_FAIL(child_stmt->update_stmt_table_id(*temp_table_query))) {
LOG_WARN("failed to update table id", K(ret));
} else if (OB_FAIL(upper_stmt->formalize_stmt_expr_reference())) {
LOG_WARN("failed to formalize stmt reference", K(ret));
} else {
table->ref_query_ = child_stmt;
}
table->type_ = TableItem::GENERATED_TABLE;
}
}
return ret;
}
int ObTransformTempTable::check_stmt_can_materialize(ObSelectStmt *stmt, bool &is_valid)
{
int ret = OB_SUCCESS;
is_valid = true;
bool has_cross_product = false;
if (OB_ISNULL(stmt)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null stmt", K(ret));
} else if (0 == stmt->get_table_items().count() &&
!stmt->is_set_stmt()) {
//expression stmt不允许物化
is_valid = false;
OPT_TRACE("expression stmt can not materialize")
} else if (1 == stmt->get_table_items().count()) {
TableItem *table = stmt->get_table_item(0);
if (stmt->has_group_by() ||
stmt->has_limit() ||
stmt->has_window_function() ||
table->is_generated_table()) {
is_valid = true;
} else {
is_valid = false;
OPT_TRACE("single table query will not be materialized");
}
} else if (OB_FAIL(check_stmt_has_cross_product(stmt, has_cross_product))) {
LOG_WARN("failed to check has cross product", K(ret));
} else if (has_cross_product) {
is_valid = false;
OPT_TRACE("stmt has cross produce, will not be materialized");
}
return ret;
}
int ObTransformTempTable::check_stmt_has_cross_product(ObSelectStmt *stmt, bool &has_cross_product)
{
int ret = OB_SUCCESS;
has_cross_product = false;
ObSEArray<ObRawExpr*, 4> on_conditions;
ObSqlBitSet<> table_ids;
if (OB_ISNULL(stmt)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null stmt", K(ret));
} else if (stmt->is_set_stmt()) {
ObIArray<ObSelectStmt*> &set_query = stmt->get_set_query();
//继续检查set op的每个分支
for (int64_t i = 0; OB_SUCC(ret) && !has_cross_product && i < set_query.count(); ++i) {
if (OB_FAIL(SMART_CALL(check_stmt_has_cross_product(set_query.at(i),
has_cross_product)))) {
LOG_WARN("failed to check stmt condition", K(ret));
}
}
} else if (stmt->is_hierarchical_query()) {
//层次查询在post process之前都是笛卡尔积,可忽略
} else if (0 == stmt->get_table_items().count()) {
has_cross_product = true;
} else if (1 == stmt->get_table_items().count()) {
//do nothing
} else if (OB_FAIL(ObTransformUtils::get_on_conditions(*stmt, on_conditions))) {
LOG_WARN("failed to get on conditions", K(ret));
} else {
ObIArray<ObRawExpr*> &where_conditions = stmt->get_condition_exprs();
//收集连接条件引用的所有表
for (int64_t i = 0; OB_SUCC(ret) && i < where_conditions.count(); ++i) {
ObRawExpr *expr = where_conditions.at(i);
if (OB_ISNULL(expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null expr", K(ret));
} else if (!expr->has_flag(IS_JOIN_COND)) {
//do nothing
} else if (OB_FAIL(table_ids.add_members(expr->get_relation_ids()))) {
LOG_WARN("failed to add relation ids", K(ret));
}
}
for (int64_t i = 0; OB_SUCC(ret) && i < on_conditions.count(); ++i) {
ObRawExpr *expr = on_conditions.at(i);
if (OB_ISNULL(expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null expr", K(ret));
} else if (expr->get_relation_ids().num_members() < 2) {
//do nothing
} else if (OB_FAIL(table_ids.add_members(expr->get_relation_ids()))) {
LOG_WARN("failed to add relation ids", K(ret));
}
}
const ObIArray<SemiInfo*> &semi_infos = stmt->get_semi_infos();
for (int64_t i = 0; OB_SUCC(ret) && i < semi_infos.count(); ++i) {
const SemiInfo *info = semi_infos.at(i);
if (OB_ISNULL(info)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null semi info", K(ret));
}
for (int64_t j = 0; OB_SUCC(ret) && j < info->semi_conditions_.count(); ++j) {
const ObRawExpr *expr = info->semi_conditions_.at(j);
if (OB_ISNULL(expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null expr", K(ret));
} else if (expr->get_relation_ids().num_members() < 2) {
//do nothing
} else if (OB_FAIL(table_ids.add_members(expr->get_relation_ids()))) {
LOG_WARN("failed to add relation ids", K(ret));
}
}
}
//如果有表没有被连接条件引用,说明有笛卡尔积出现
for (int64_t i = 0; OB_SUCC(ret) && !has_cross_product && 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_ids.has_member(stmt->get_table_bit_index(table->table_id_))) {
//has cross product
has_cross_product = true;
} else if (!table->is_generated_table()) {
//do nothing
} else if (OB_FAIL(SMART_CALL(check_stmt_has_cross_product(table->ref_query_,
has_cross_product)))) {
LOG_WARN("failed to check stmt condition", K(ret));
}
}
}
return ret;
}
/**
* @brief extract_common_subquery_as_cte
* 比较当前stmt的所有child stmt,
* 把所有相似的stmt分为一组,抽离最大的公共部分作为temp table
*/
int ObTransformTempTable::extract_common_subquery_as_cte(ObDMLStmt *stmt,
ObIArray<ObSelectStmt*> &stmts,
hash::ObHashMap<uint64_t, ObDMLStmt *> &parent_map,
bool &trans_happened)
{
int ret = OB_SUCCESS;
trans_happened = false;
ObSEArray<StmtClassifyHelper, 8> stmt_groups;
const ObQueryHint *query_hint = NULL;
if (OB_ISNULL(stmt) || OB_ISNULL(ctx_) || OB_ISNULL(trans_param_)
|| OB_ISNULL(query_hint = stmt->get_stmt_hint().query_hint_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null stmt", K(ret));
} else if (OB_FAIL(remove_simple_stmts(stmts))) {
LOG_WARN("failed to remove simple stmts", K(ret));
} else if (OB_FAIL(classify_stmts(stmts, stmt_groups))) {
LOG_WARN("failed to sort stmts", K(ret));
}
//对每一组stmt抽离公共部分
for (int64_t i = 0; OB_SUCC(ret) && i < stmt_groups.count(); ++i) {
if (OB_FAIL(inner_extract_common_subquery_as_cte(*stmt,
stmt_groups.at(i).stmts_,
parent_map,
trans_happened))) {
LOG_WARN("failed to convert temp table", K(ret));
}
}
if (OB_SUCC(ret) && trans_happened) {
trans_param_->trans_type_ = T_MATERIALIZE;
if (OB_FAIL(add_transform_hint(*stmt, trans_param_))) {
LOG_WARN("failed to add hint", K(ret));
} else if (query_hint->has_outline_data()) {
++ctx_->trans_list_loc_;
}
}
return ret;
}
/**
* @brief inner_extract_common_subquery_as_cte
* stmt之间两两比较,分成多个相似组,
* 对每组相似stmt创建temp table
*/
int ObTransformTempTable::inner_extract_common_subquery_as_cte(ObDMLStmt &root_stmt,
ObIArray<ObSelectStmt*> &stmts,
hash::ObHashMap<uint64_t, ObDMLStmt *> &parent_map,
bool &trans_happened)
{
int ret = OB_SUCCESS;
ObStmtMapInfo map_info;
QueryRelation relation;
typedef ObSEArray<StmtCompareHelper, 8> StmtCompareHelperArray;
SMART_VAR(StmtCompareHelperArray, compare_info) {
//计算相似stmt分组
if (OB_ISNULL(ctx_) || OB_ISNULL(ctx_->allocator_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null param", K(ret));
}
for (int64_t i = 0; OB_SUCC(ret) && i < stmts.count(); ++i) {
bool find_similar = false;
ObSelectStmt *stmt = stmts.at(i);
if (OB_ISNULL(stmt)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null stmt ", K(ret));
}
for (int64_t j = 0; OB_SUCC(ret) && !find_similar && j < compare_info.count(); ++j) {
map_info.reset();
bool has_stmt = false;
StmtCompareHelper &helper = compare_info.at(j);
if (!helper.hint_force_stmt_set_.empty() &&
!helper.hint_force_stmt_set_.has_qb_name(stmt)) {
//hint forbid,do nothing
} else if (OB_FAIL(check_has_stmt(helper.stmt_,
stmt,
parent_map,
has_stmt))) {
LOG_WARN("failed to check has stmt", K(ret));
} else if (has_stmt) {
//do nothing
} else if (OB_FAIL(check_has_stmt(stmt,
helper.stmt_,
parent_map,
has_stmt))) {
LOG_WARN("failed to check has stmt", K(ret));
} else if (has_stmt) {
// do nothing
} else if (OB_FAIL(ObStmtComparer::check_stmt_containment(helper.stmt_,
stmt,
map_info,
relation))) {
LOG_WARN("failed to check stmt containment", K(ret));
} else if (!is_similar_stmt(*stmt, map_info, relation)) {
//do nothing
} else if (helper.stmt_->is_scala_group_by() ^ stmt->is_scala_group_by()) {
//do nothing
} else if (OB_FAIL(helper.similar_stmts_.push_back(stmt))) {
LOG_WARN("failed to push back stmt", K(ret));
} else if (OB_FAIL(helper.stmt_map_infos_.push_back(map_info))) {
LOG_WARN("failed to push back map info", K(ret));
} else {
find_similar = true;
}
}
if (OB_SUCC(ret) && !find_similar) {
SMART_VAR(StmtCompareHelper, helper) {
map_info.reset();
bool force_no_trans = false;
QbNameList qb_names;
if (OB_FAIL(get_hint_force_set(root_stmt,
*stmt,
qb_names,
force_no_trans))) {
LOG_WARN("failed to get hint set", K(ret));
} else if (force_no_trans) {
//do nothing
OPT_TRACE("hint reject materialize:", stmt);
} else if (OB_FAIL(ObStmtComparer::check_stmt_containment(stmt,
stmt,
map_info,
relation))) {
LOG_WARN("failed to check stmt containment", K(ret));
} else if (OB_FAIL(helper.similar_stmts_.push_back(stmt))) {
LOG_WARN("failed to push back stmt", K(ret));
} else if (OB_FAIL(helper.stmt_map_infos_.push_back(map_info))) {
LOG_WARN("failed to push back map info", K(ret));
} else if (OB_FAIL(helper.hint_force_stmt_set_.assign(qb_names))) {
LOG_WARN("failed to assign qb names", K(ret));
} else if (OB_FALSE_IT(helper.stmt_ = stmt)) {
} else if (OB_FAIL(compare_info.push_back(helper))) {
LOG_WARN("failed to push back compare info", K(ret));
}
}
}
}
//对每组相似stmt创建temp table
for (int64_t i = 0; OB_SUCC(ret) && i < compare_info.count(); ++i) {
StmtCompareHelper &helper = compare_info.at(i);
OPT_TRACE("try to materialize:", helper.stmt_);
if (!helper.hint_force_stmt_set_.empty() &&
!helper.hint_force_stmt_set_.is_equal(helper.similar_stmts_)) {
//hint forbid, do nothing
OPT_TRACE("hint reject transform");
} else if (helper.hint_force_stmt_set_.empty() &&
(helper.similar_stmts_.count() < 2)) {
//do nothing
} else if (OB_FAIL(create_temp_table(helper))) {
LOG_WARN("failed to create temp table", K(ret));
} else if (OB_FAIL(add_materialize_stmts(helper.similar_stmts_))) {
LOG_WARN("failed to add stmts", K(ret));
} else {
trans_happened = true;
}
}
}
return ret;
}
int ObTransformTempTable::add_materialize_stmts(const ObIArray<ObSelectStmt*> &stms)
{
int ret = OB_SUCCESS;
MaterializeStmts *new_stmts = NULL;
if (OB_ISNULL(trans_param_) ||
OB_ISNULL(new_stmts = (MaterializeStmts *) allocator_.alloc(sizeof(MaterializeStmts)))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("failed to allocate stmts array", K(ret));
} else {
new_stmts = new (new_stmts) MaterializeStmts();
if (OB_FAIL(new_stmts->assign(stms))) {
LOG_WARN("failed to assign array", K(ret));
} else if (OB_FAIL(trans_param_->materialize_stmts_.push_back(new_stmts))) {
LOG_WARN("failed to push back stmts", K(ret));
}
}
return ret;
}
int ObTransformTempTable::check_has_stmt(ObSelectStmt *left_stmt,
ObSelectStmt *right_stmt,
hash::ObHashMap<uint64_t, ObDMLStmt *> &parent_map,
bool &has_stmt)
{
int ret = OB_SUCCESS;
has_stmt = false;
ObDMLStmt *current = left_stmt;
ObDMLStmt *parent = NULL;
while (OB_SUCC(ret) && current != right_stmt && NULL != current) {
uint64_t key = reinterpret_cast<uint64_t>(current);
if (OB_FAIL(parent_map.get_refactored(key, parent))) {
if (ret == OB_HASH_NOT_EXIST) {
current = NULL;
ret = OB_SUCCESS;
} else {
LOG_WARN("failed to get value", K(ret));
}
} else {
current = parent;
}
}
if (OB_SUCC(ret) && current == right_stmt) {
has_stmt = true;
}
return ret;
}
bool ObTransformTempTable::is_similar_stmt(ObSelectStmt& stmt,
const ObStmtMapInfo &map_info,
QueryRelation relation)
{
bool bret = false;
if (stmt.is_set_stmt()) {
bret = QueryRelation::QUERY_EQUAL == relation;
} else if (stmt.get_table_size() < 2) {
if (stmt.get_group_expr_size() > 0 ||
stmt.get_rollup_expr_size() > 0 ||
stmt.get_grouping_sets_items_size() > 0 ||
stmt.get_multi_rollup_items_size() > 0) {
bret = map_info.is_group_equal_;
} else if (stmt.get_aggr_item_size() > 0) {
bret = map_info.is_table_equal_ && map_info.is_from_equal_ && map_info.is_semi_info_equal_ && map_info.is_cond_equal_;
}
} else {
bret = map_info.is_table_equal_ && map_info.is_from_equal_ && map_info.is_semi_info_equal_;
}
return bret;
}
/**
* @brief ObTransformTempTable::get_non_correlated_subquery
* @param stmt
* @param non_correlated_stmts
* @return
*/
int ObTransformTempTable::get_non_correlated_subquery(ObDMLStmt *stmt,
const uint64_t recursive_level,
hash::ObHashMap<uint64_t, uint64_t> &param_level,
ObIArray<ObSelectStmt *> &non_correlated_stmts,
uint64_t &min_param_level)
{
int ret = OB_SUCCESS;
ObArray<ObSelectStmt *> child_stmts;
ObArray<ObRawExpr *> relation_exprs;
min_param_level = recursive_level;
if (OB_ISNULL(stmt)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("stmt is null", K(ret), K(stmt));
} else if (OB_FAIL(stmt->get_relation_exprs(relation_exprs))) {
LOG_WARN("failed to get relation exprs", K(ret));
} else 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 < relation_exprs.count(); ++i) {
ObRawExpr *expr = relation_exprs.at(i);
if (OB_FAIL(check_exec_param_level(expr, param_level, min_param_level))) {
LOG_WARN("failed to check exec param level", K(ret));
}
}
for (int64_t i = 0; OB_SUCC(ret) && i < stmt->get_subquery_expr_size(); ++i) {
ObQueryRefRawExpr *query_ref = stmt->get_subquery_exprs().at(i);
if (OB_ISNULL(query_ref)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("query ref is null", K(ret), K(query_ref));
}
for (int64_t j = 0; OB_SUCC(ret) && j < query_ref->get_exec_params().count(); ++j) {
ObRawExpr *exec_param = query_ref->get_exec_params().at(j);
uint64_t key = reinterpret_cast<uint64_t>(exec_param);
if (OB_ISNULL(exec_param)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("exec param is null", K(ret));
} else if (OB_FAIL(param_level.set_refactored(key, recursive_level))) {
if (ret == OB_HASH_EXIST) {
ret = OB_SUCCESS;
} else {
LOG_WARN("failed to add exec param into map", K(ret));
}
}
}
}
for (int64_t i = 0; OB_SUCC(ret) && i < child_stmts.count(); ++i) {
uint64_t child_min_param_level = recursive_level + 1;
if (OB_FAIL(SMART_CALL(get_non_correlated_subquery(child_stmts.at(i),
recursive_level + 1,
param_level,
non_correlated_stmts,
child_min_param_level)))) {
LOG_WARN("failed to get non correlated subquery", K(ret));
} else if (child_min_param_level < min_param_level) {
min_param_level = child_min_param_level;
}
}
if (OB_SUCC(ret) && min_param_level == recursive_level && stmt->is_select_stmt()) {
if (OB_FAIL(non_correlated_stmts.push_back(static_cast<ObSelectStmt *>(stmt)))) {
LOG_WARN("failed to push back non correlated stmt", K(ret));
}
}
return ret;
}
int ObTransformTempTable::check_exec_param_level(const ObRawExpr *expr,
const hash::ObHashMap<uint64_t, uint64_t> &param_level,
uint64_t &min_param_level)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("expr is null", K(ret), K(expr));
} else if (expr->is_exec_param_expr()) {
uint64_t key = reinterpret_cast<uint64_t>(expr);
uint64_t level = UINT64_MAX;
if (OB_FAIL(param_level.get_refactored(key, level))) {
LOG_WARN("failed to get level", K(ret), K(*expr));
} else if (level < min_param_level) {
min_param_level = level;
}
} else if (expr->has_flag(CNT_DYNAMIC_PARAM)) {
for (int64_t i = 0; OB_SUCC(ret) && i < expr->get_param_count(); ++i) {
if (OB_FAIL(SMART_CALL(check_exec_param_level(expr->get_param_expr(i),
param_level,
min_param_level)))) {
LOG_WARN("failed to check exec param level", K(ret));
}
}
}
return ret;
}
int ObTransformTempTable::remove_simple_stmts(ObIArray<ObSelectStmt*> &stmts)
{
int ret = OB_SUCCESS;
ObSEArray<ObSelectStmt*, 8> new_stmts;
bool has_rownum = false;
bool is_valid = false;
for (int64_t i = 0; OB_SUCC(ret) && i < stmts.count(); ++i) {
ObSelectStmt *subquery = stmts.at(i);
if (OB_ISNULL(subquery)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null stmt", K(ret));
} else if (OB_FAIL(subquery->has_rownum(has_rownum))) {
LOG_WARN("failed to check has rownum", K(ret));
} else if (has_rownum) {
//do nothing
} else if (ObOptimizerUtil::find_item(ctx_->temp_table_ignore_stmts_, subquery)) {
//do nothing
} else if (OB_FAIL(check_stmt_can_materialize(subquery, is_valid))) {
LOG_WARN("failed to check stmt is valid", K(ret));
} else if (!is_valid) {
//do nothing
} else if (OB_FAIL(new_stmts.push_back(subquery))) {
LOG_WARN("failed to push back stmt", K(ret));
}
}
if (OB_SUCC(ret)) {
if (OB_FAIL(stmts.assign(new_stmts))) {
LOG_WARN("failed to assign stmts", K(ret));
}
}
return ret;
}
/**
* @classify_stmts
* 为了降低stmt比较的代价,
* 把stmt按照table size、generate table size分组,
* 每组stmt的basic table item size和generate table size相同
* 因为不同table item的stmt之间一定不相似
*/
int ObTransformTempTable::classify_stmts(ObIArray<ObSelectStmt*> &stmts,
ObIArray<StmtClassifyHelper> &stmt_groups)
{
int ret = OB_SUCCESS;
for (int64_t i = 0; OB_SUCC(ret) && i < stmts.count(); ++i) {
ObSelectStmt *stmt = stmts.at(i);
int64_t table_size = 0;
int64_t generate_table_size = 0;
if (OB_ISNULL(stmt)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null stmt", K(ret));
} else {
table_size = stmt->get_table_size();
}
for (int64_t j = 0; OB_SUCC(ret) && j < table_size; ++j) {
const TableItem *table_item = stmt->get_table_item(j);
if (OB_ISNULL(table_item)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("table_item is null", K(j));
} else if (table_item->is_generated_table()) {
++generate_table_size;
}
}
bool find = false;
for (int64_t j = 0; OB_SUCC(ret) && !find && j < stmt_groups.count(); ++j) {
if (stmt_groups.at(j).table_size_ == table_size &&
stmt_groups.at(j).generate_table_size_ == generate_table_size) {
if (OB_FAIL(stmt_groups.at(j).stmts_.push_back(stmt))) {
LOG_WARN("failed to push back stmt", K(ret));
} else {
find = true;
}
}
}
if (OB_SUCC(ret) && !find) {
StmtClassifyHelper helper;
helper.table_size_ = table_size;
helper.generate_table_size_ = generate_table_size;
if (OB_FAIL(helper.stmts_.push_back(stmt))) {
LOG_WARN("failed to push back stmt", K(ret));
} else if (OB_FAIL(stmt_groups.push_back(helper))) {
LOG_WARN("failed to push back stmt", K(ret));
}
}
}
return ret;
}
/**
* @create_temp_table
* 把相似stmt的公共部分抽离成temp table
*/
int ObTransformTempTable::create_temp_table(StmtCompareHelper& compare_info)
{
int ret = OB_SUCCESS;
ObStmtMapInfo common_map_info;
TableItem *table = NULL;
TableItem *temp_table = NULL;
ObSelectStmt *temp_table_query = NULL;
if (OB_ISNULL(compare_info.stmt_) || OB_ISNULL(ctx_) || OB_ISNULL(ctx_->allocator_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null param", K(ret));
} else if (OB_FAIL(compute_common_map_info(compare_info.stmt_map_infos_, common_map_info))) {
LOG_WARN("failed to compute common map info", K(ret));
} else if (compare_info.stmt_map_infos_.count() != compare_info.similar_stmts_.count()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect compare info", K(compare_info), K(ret));
}
//把stmt的公共部分封装成generate table
for (int64_t i = 0; OB_SUCC(ret) && i < compare_info.similar_stmts_.count(); ++i) {
if (OB_FAIL(inner_create_temp_table(compare_info.similar_stmts_.at(i),
compare_info.stmt_map_infos_.at(i),
common_map_info))) {
LOG_WARN("failed to replace temp table", K(ret));
} else if (OB_FAIL(append(ctx_->equal_param_constraints_,
compare_info.stmt_map_infos_.at(i).equal_param_map_))) {
LOG_WARN("failed to append equal param constraints", K(ret));
}
}
//把generate table转成temp table
for (int64_t i = 0; OB_SUCC(ret) && i < compare_info.similar_stmts_.count(); ++i) {
ObSelectStmt *stmt = compare_info.similar_stmts_.at(i);
if (OB_ISNULL(stmt)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null stmt", K(ret));
} else if (1 != stmt->get_table_size()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("expect one table item in stmt", KPC(stmt), K(ret));
} else if (OB_ISNULL(table = stmt->get_table_item(0))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null table item", K(ret));
} else if (!table->is_generated_table()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("expect generate table item", KPC(table), K(ret));
} else if (OB_ISNULL(table->ref_query_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null ref query", K(ret));
} else {
if (0 == i) {
temp_table_query = table->ref_query_;
temp_table = table;
if (OB_FAIL(stmt->generate_view_name(*ctx_->allocator_,
temp_table->table_name_,
true))) {
LOG_WARN("failed to generate view name", K(ret));
}
} else if (OB_FAIL(apply_temp_table(stmt,
table,
temp_table_query,
compare_info.stmt_map_infos_.at(i)))) {
LOG_WARN("failed to apply temp table", K(ret));
} else {
table->ref_query_ = temp_table_query;
table->table_name_ = temp_table->table_name_;
}
table->type_ = TableItem::TEMP_TABLE;
}
}
for (int64_t i = 0; OB_SUCC(ret) && i < compare_info.similar_stmts_.count(); ++i) {
ObSelectStmt *stmt = compare_info.similar_stmts_.at(i);
if (OB_ISNULL(stmt)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null stmt", K(ret));
} else if (OB_FAIL(stmt->formalize_stmt_expr_reference())) {
LOG_WARN("failed to formalize stmt reference", K(ret));
}
}
if (OB_SUCC(ret) && OB_NOT_NULL(temp_table_query)) {
if (OB_FAIL(ObTransformUtils::adjust_pseudo_column_like_exprs(*temp_table_query))) {
LOG_WARN("failed to adjust pseudo column like exprs", K(ret));
} else if (OB_FAIL(temp_table_query->formalize_stmt(ctx_->session_info_))) {
LOG_WARN("failed to formalize stmt", K(ret));
} else if (OB_FAIL(temp_table_query->formalize_stmt_expr_reference())) {
LOG_WARN("failed to formalize stmt reference", K(ret));
} else if (OB_FAIL(append(ctx_->equal_param_constraints_, common_map_info.equal_param_map_))) {
LOG_WARN("failed to append equal param constraints", K(ret));
}
}
LOG_TRACE("succeed to create temp table", KPC(temp_table_query));
return ret;
}
/**
* @brief compute_common_map_info
* 计算相似stmt的最大公共部分
*/
int ObTransformTempTable::compute_common_map_info(ObIArray<ObStmtMapInfo>& map_infos,
ObStmtMapInfo &common_map_info)
{
int ret = OB_SUCCESS;
for (int64_t i = 0; OB_SUCC(ret) && i < map_infos.count(); ++i) {
ObStmtMapInfo &map_info = map_infos.at(i);
if (0 == i) {
if (OB_FAIL(common_map_info.assign(map_info))) {
LOG_WARN("failed to assign map info", K(ret));
}
} else if (OB_FAIL(append(common_map_info.equal_param_map_, map_info.equal_param_map_))) {
LOG_WARN("failed to append equal param", K(ret));
} else {
//compute common condi map
if (OB_FAIL(compute_common_map(map_info.cond_map_, common_map_info.cond_map_))) {
LOG_WARN("failed to compute common map info", K(ret));
} else {
common_map_info.is_cond_equal_ &= map_info.is_cond_equal_;
}
//compute common group by map
if (OB_SUCC(ret)) {
//只有当where condition完全相同时才能考虑下压group by到temp table
//TODO:当前不相同的condition可以推迟到having执行时也可以下压group by
if (common_map_info.is_cond_equal_) {
if (OB_FAIL(compute_common_map(map_info.group_map_, common_map_info.group_map_))) {
LOG_WARN("failed to compute common map info", K(ret));
} else {
common_map_info.is_group_equal_ &= map_info.is_group_equal_;
}
} else {
common_map_info.group_map_.reset();
common_map_info.having_map_.reset();
common_map_info.select_item_map_.reset();
common_map_info.is_distinct_equal_ = false;
}
}
//compute common having map
if (OB_SUCC(ret)) {
if (common_map_info.is_group_equal_) {
if (OB_FAIL(compute_common_map(map_info.having_map_, common_map_info.having_map_))) {
LOG_WARN("failed to compute common map info", K(ret));
} else {
common_map_info.is_having_equal_ &= map_info.is_having_equal_;
}
} else {
common_map_info.having_map_.reset();
common_map_info.select_item_map_.reset();
common_map_info.is_distinct_equal_ = false;
}
}
//compute common select item map
if (OB_SUCC(ret)) {
if (common_map_info.is_having_equal_) {
if (OB_FAIL(compute_common_map(map_info.select_item_map_, common_map_info.select_item_map_))) {
LOG_WARN("failed to compute common map info", K(ret));
} else {
common_map_info.is_select_item_equal_ &= map_info.is_select_item_equal_;
}
} else {
common_map_info.select_item_map_.reset();
common_map_info.is_distinct_equal_ = false;
}
}
//compute common distinct map
if (OB_SUCC(ret)) {
if (common_map_info.is_select_item_equal_) {
common_map_info.is_distinct_equal_ = map_info.is_distinct_equal_;
}
}
}
}
return ret;
}
int ObTransformTempTable::compute_common_map(ObIArray<int64_t> &source_map,
ObIArray<int64_t> &common_map)
{
int ret = OB_SUCCESS;
if (source_map.count() != common_map.count()) {
common_map.reset();
} else {
for (int64_t i = 0; OB_SUCC(ret) && i < source_map.count(); ++i) {
if (OB_INVALID_ID == source_map.at(i)) {
common_map.at(i) = OB_INVALID_ID;
}
}
}
return ret;
}
/**
* @brief inner_create_temp_table
* 把stmt的公共部分封装在generate table内
*/
int ObTransformTempTable::inner_create_temp_table(ObSelectStmt *parent_stmt,
ObStmtMapInfo& map_info,
ObStmtMapInfo& common_map_info)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(parent_stmt) || OB_ISNULL(ctx_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null stmt", K(ret));
} else if (parent_stmt->is_set_stmt()) {
if (OB_FAIL(ObTransformUtils::pack_stmt(ctx_, parent_stmt))) {
LOG_WARN("failed to create temp table for set stmt", K(ret));
} else {
LOG_TRACE("succeed to create temp table", KPC(parent_stmt));
}
} else {
TableItem *view_table = NULL;
ObSEArray<TableItem *, 8> from_tables;
ObSEArray<SemiInfo *, 4> semi_infos;
ObSEArray<ObRawExpr *, 8> pushdown_select;
ObSEArray<ObRawExpr *, 8> pushdown_where;
ObSEArray<ObRawExpr *, 8> pushdown_groupby;
ObSEArray<ObRawExpr *, 8> pushdown_rollup;
ObSEArray<ObRawExpr *, 8> pushdown_having;
if (parent_stmt->get_condition_size() > 0 &&
OB_FAIL(pushdown_conditions(parent_stmt,
map_info.cond_map_,
common_map_info.cond_map_,
pushdown_where))) {
LOG_WARN("failed to pushdown conditions", K(ret));
} else if (!common_map_info.is_cond_equal_ ||
!common_map_info.is_group_equal_) {
//do nothing
//下压group by
} else if (parent_stmt->has_group_by() &&
OB_FAIL(ObTransformUtils::pushdown_group_by(parent_stmt,
pushdown_groupby,
pushdown_rollup,
pushdown_select))) {
LOG_WARN("failed to pushdown group by", K(ret));
//下压having
} else if (parent_stmt->get_having_expr_size() > 0 &&
OB_FAIL(pushdown_having_conditions(parent_stmt,
map_info.having_map_,
common_map_info.having_map_,
pushdown_having))) {
LOG_WARN("failed to pushdown having conditions", K(ret));
}
ObSEArray<TableItem *, 8> origin_tables;
if (OB_FAIL(ret)) {
} else if (OB_FAIL(ObTransformUtils::pushdown_pseudo_column_like_exprs(*parent_stmt, pushdown_select))) {
LOG_WARN("failed to pushdown pseudo column like exprs", K(ret));
} else if (OB_FAIL(origin_tables.assign(parent_stmt->get_table_items()))) {
LOG_WARN("failed to get table items", K(ret));
} else if (OB_FAIL(parent_stmt->get_from_tables(from_tables))) {
LOG_WARN("failed to get from tables", K(ret));
} else if (OB_FAIL(semi_infos.assign(parent_stmt->get_semi_infos()))) {
LOG_WARN("failed to assign semi info", K(ret));
} else if (OB_FAIL(ObTransformUtils::replace_with_empty_view(ctx_,
parent_stmt,
view_table,
from_tables,
&semi_infos))) {
LOG_WARN("failed to create empty view", K(ret));
} else if (OB_FAIL(ObTransformUtils::create_inline_view(ctx_,
parent_stmt,
view_table,
from_tables,
&pushdown_where,
&semi_infos,
&pushdown_select,
&pushdown_groupby,
&pushdown_rollup,
&pushdown_having))) {
LOG_WARN("failed to create inline view", K(ret));
} else if (OB_ISNULL(view_table->ref_query_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("null view query", K(ret));
// recover the order of table items,
// the table_map in ObStmtMapInfo will be used in apply_temp_table
} else if (OB_FAIL(view_table->ref_query_->get_table_items().assign(origin_tables))) {
LOG_WARN("failed to adjust table map", K(ret));
} else if (OB_FAIL(view_table->ref_query_->rebuild_tables_hash())) {
LOG_WARN("failed to rebuild table hash", K(ret));
} else if (OB_FAIL(view_table->ref_query_->update_column_item_rel_id())) {
LOG_WARN("failed to update column item by id", K(ret));
} else if (OB_FAIL(view_table->ref_query_->formalize_stmt(ctx_->session_info_))) {
LOG_WARN("failed to formalize stmt", K(ret));
}
}
return ret;
}
/**
* @brief pushdown_conditions
* 把公共的where condition重命名后下压到视图内
* 不同的where condition保留在原stmt中,等待谓词推导下压
*/
int ObTransformTempTable::pushdown_conditions(ObSelectStmt *parent_stmt,
const ObIArray<int64_t> &cond_map,
const ObIArray<int64_t> &common_cond_map,
ObIArray<ObRawExpr*> &pushdown_conds)
{
int ret = OB_SUCCESS;
ObSEArray<ObRawExpr*, 8> keep_conds;
if (OB_ISNULL(parent_stmt)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null param", K(ret));
} else if (cond_map.count() != common_cond_map.count()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect map info", K(cond_map), K(common_cond_map), K(ret));
} else {
ObIArray<ObRawExpr*> &conditions = parent_stmt->get_condition_exprs();
//找到相同的condition
for (int64_t i = 0; OB_SUCC(ret) && i < cond_map.count(); ++i) {
int64_t idx = cond_map.at(i);
if (OB_INVALID_ID == common_cond_map.at(i)) {
//do nothing
} else if (idx < 0 || idx > conditions.count()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect cond index", K(idx), K(ret));
} else if (OB_FAIL(pushdown_conds.push_back(conditions.at(idx)))) {
LOG_WARN("failed to push back expr", K(ret));
}
}
//找到不同的condition
for (int64_t i = 0; OB_SUCC(ret) && i < conditions.count(); ++i) {
if (ObOptimizerUtil::find_item(pushdown_conds, conditions.at(i))) {
//do nothing
} else if (OB_FAIL(keep_conds.push_back(conditions.at(i)))) {
LOG_WARN("failed to push back expr", K(ret));
}
}
if (OB_SUCC(ret) && !pushdown_conds.empty()) {
if (OB_FAIL(parent_stmt->get_condition_exprs().assign(keep_conds))) {
LOG_WARN("failed to assign exprs", K(ret));
}
}
}
return ret;
}
/**
* @brief pushdown_having_conditions
* 下推相同的having condition到视图中
*/
int ObTransformTempTable::pushdown_having_conditions(ObSelectStmt *parent_stmt,
const ObIArray<int64_t> &having_map,
const ObIArray<int64_t> &common_having_map,
ObIArray<ObRawExpr*> &pushdown_conds)
{
int ret = OB_SUCCESS;
ObSEArray<ObRawExpr*, 8> keep_conds;
if (OB_ISNULL(parent_stmt)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null param", K(ret));
} else if (having_map.count() != common_having_map.count()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect map info", K(having_map), K(common_having_map), K(ret));
} else {
ObIArray<ObRawExpr*> &conditions = parent_stmt->get_having_exprs();
//找到相同的having condition
for (int64_t i = 0; OB_SUCC(ret) && i < having_map.count(); ++i) {
int64_t idx = having_map.at(i);
if (OB_INVALID_ID == common_having_map.at(i)) {
//do nothing
} else if (idx < 0 || idx > conditions.count()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect cond index", K(idx), K(ret));
} else if (OB_FAIL(pushdown_conds.push_back(conditions.at(idx)))) {
LOG_WARN("failed to push back expr", K(ret));
}
}
//找到不同的having condition
for (int64_t i = 0; OB_SUCC(ret) && i < conditions.count(); ++i) {
if (ObOptimizerUtil::find_item(pushdown_conds, conditions.at(i))) {
//do nothing
} else if (OB_FAIL(keep_conds.push_back(conditions.at(i)))) {
LOG_WARN("failed to push back expr", K(ret));
}
}
if (OB_SUCC(ret) && !conditions.empty()) {
parent_stmt->get_having_exprs().reset();
if (OB_FAIL(append(parent_stmt->get_condition_exprs(), keep_conds))) {
LOG_WARN("failed to assign exprs", K(ret));
}
}
}
return ret;
}
/**
* @brief apply_temp_table
* 把视图view替换成temp table query,
* 已知条件:view与temp table query仅仅只是select item不同
* view与temp table query的基表映射关系存在于map info中
* 只需要把view中与temp table query不同的select item转换成temp table的select item
* 并且更新parent stmt的column item,引用temp table 的select item
* 如果有聚合函数,需要添加到temp table query中
*/
int ObTransformTempTable::apply_temp_table(ObSelectStmt *parent_stmt,
TableItem *view_table,
ObSelectStmt *temp_table_query,
ObStmtMapInfo& map_info)
{
int ret = OB_SUCCESS;
ObStmtCompareContext context;
//视图的select items
ObSEArray<ObRawExpr*, 16> view_select_list;
//视图的select items转换为temp table对应的select items
ObSEArray<ObRawExpr*, 16> new_select_list;
//temp table的select items
ObSEArray<ObRawExpr*, 16> temp_table_select_list;
//视图的column items
ObSEArray<ObRawExpr*, 16> view_column_list;
//temp table的column items
ObSEArray<ObRawExpr*, 16> temp_table_column_list;
//视图的column item转换为temp table对应的column items
ObSEArray<ObRawExpr*, 16> new_column_list;
//不存在于temp table中的column item
ObSEArray<ColumnItem, 16> new_column_items;
ObSEArray<ObRawExpr*, 16> old_column_exprs;
ObSelectStmt *view = NULL;
if (OB_ISNULL(parent_stmt) || OB_ISNULL(temp_table_query) ||
OB_ISNULL(view_table)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null param", K(ret));
} else if (!view_table->is_generated_table()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("expect generate table", KPC(view_table), K(ret));
} else if (OB_ISNULL(view = view_table->ref_query_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null ref query", KPC(view_table), K(ret));
} else if (OB_FAIL(view->get_select_exprs(view_select_list))) {
LOG_WARN("failed to get select exprs", K(ret));
} else if (OB_FAIL(view->get_column_exprs(view_column_list))) {
LOG_WARN("failed to get column exprs", K(ret));
} else if (OB_FAIL(temp_table_query->get_select_exprs(temp_table_select_list))) {
LOG_WARN("failed to get select exprs", K(ret));
} else if (OB_FAIL(temp_table_query->get_column_exprs(temp_table_column_list))) {
LOG_WARN("failed to get column exprs", K(ret));
} else {
context.init(temp_table_query, view, map_info,
&parent_stmt->get_query_ctx()->calculable_items_);
}
//找到对应的column item,不存在于temp table的column需要添加到temp table
for (int64_t i = 0; OB_SUCC(ret) && i < view_column_list.count(); ++i) {
ObRawExpr *view_column = view_column_list.at(i);
bool find = false;
if (OB_ISNULL(view_column)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null column expr", K(ret));
}
//column item是否存在于temp table中
for (int64_t j = 0; OB_SUCC(ret) && !find && j < temp_table_column_list.count(); ++j) {
ObRawExpr *temp_table_column = temp_table_column_list.at(j);
if (OB_ISNULL(temp_table_column)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null column expr", K(ret));
} else if (!temp_table_column->same_as(*view_column, &context)) {
//do nothing
} else if (OB_FAIL(new_column_list.push_back(temp_table_column))) {
LOG_WARN("failed to push back expr", K(ret));
} else {
find = true;
}
}
//不存在于temp table中的column需要添加到temp table中
if (OB_SUCC(ret) && !find) {
TableItem *table = NULL;
ColumnItem *column_item = NULL;
ObColumnRefRawExpr *col_ref = static_cast<ObColumnRefRawExpr*>(view_column);
uint64_t table_id = OB_INVALID_ID;
if (!view_column->is_column_ref_expr()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("expect column ref expr", KPC(view_column), K(ret));
} else if (OB_ISNULL(column_item = view->get_column_item_by_id(col_ref->get_table_id(),
col_ref->get_column_id()))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null column item", K(ret));
} else if (OB_FAIL(get_map_table_id(view,
temp_table_query,
map_info,
col_ref->get_table_id(),
table_id))) {
LOG_WARN("failed to get map table id", K(ret));
} else if (OB_FALSE_IT(column_item->table_id_ = table_id)) {
} else if (OB_FALSE_IT(col_ref->set_table_id(table_id))) {
} else if (OB_FAIL(new_column_items.push_back(*column_item))) {
LOG_WARN("failed to push back column item", K(ret));
} else if (OB_FAIL(new_column_list.push_back(view_column))) {
LOG_WARN("failed to push back expr", K(ret));
} else if (OB_ISNULL(table = temp_table_query->get_table_item_by_id(table_id))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null table item", K(ret));
} else {
col_ref->set_table_name(table->get_table_name());
}
}
}
//添加新的column item
if (OB_SUCC(ret) && !new_column_items.empty()) {
if (OB_FAIL(temp_table_query->add_column_item(new_column_items))) {
LOG_WARN("failed to add table item", K(ret));
}
}
//找到不同的select item
for (int64_t i = 0; OB_SUCC(ret) && i < view_select_list.count(); ++i) {
ObRawExpr *view_select = view_select_list.at(i);
ObColumnRefRawExpr *col_expr = NULL;
bool find = false;
if (OB_ISNULL(view_select)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null select expr", K(ret));
} else if (NULL == (col_expr = parent_stmt->get_column_expr_by_id(view_table->table_id_,
i + OB_APP_MIN_COLUMN_ID))) {
// unused select item, skip following procedure
find = true;
} else if (OB_FAIL(old_column_exprs.push_back(col_expr))) {
LOG_WARN("failed to push back expr", K(ret));
}
//select item是否存在于temp table中
for (int64_t j = 0; OB_SUCC(ret) && !find && j < temp_table_select_list.count(); ++j) {
ObRawExpr *temp_table_select = temp_table_select_list.at(j);
if (OB_ISNULL(temp_table_select)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null select expr", K(ret));
} else if (!temp_table_select->same_as(*view_select, &context)) {
//do nothing
} else if (OB_FAIL(new_select_list.push_back(temp_table_select))) {
LOG_WARN("failed to push back expr", K(ret));
} else {
find = true;
}
}
//不存在于temp table中的select expr需要转换成temp table的select item
if (OB_SUCC(ret) && !find) {
ObSEArray<ObAggFunRawExpr*, 8> aggr_items;
ObSEArray<ObWinFunRawExpr*, 8> win_func_exprs;
if (ObTransformUtils::replace_expr(view_column_list, new_column_list, view_select)) {
LOG_WARN("failed to replace expr", K(ret));
} else if (OB_FAIL(new_select_list.push_back(view_select))) {
LOG_WARN("failed to push back expr", K(ret));
} else if (OB_FAIL(ObTransformUtils::extract_aggr_expr(view_select, aggr_items))) {
LOG_WARN("failed to extract aggr expr", K(ret));
} else if (OB_FAIL(append(temp_table_query->get_aggr_items(), aggr_items))) {
LOG_WARN("failed to append aggr items", K(ret));
} else if (OB_FAIL(ObTransformUtils::extract_winfun_expr(view_select, win_func_exprs))) {
LOG_WARN("failed to extract win func exprs", K(ret));
} else if (OB_FAIL(append(temp_table_query->get_window_func_exprs(), win_func_exprs))) {
LOG_WARN("failed to append win func exprs", K(ret));
}
}
}
//为temp table创建新的select item,并替换parent stmt的引用
if (OB_SUCC(ret)) {
ObSEArray<ObRawExpr*, 16> new_column_exprs;
view_table->ref_query_ = temp_table_query;
if (OB_FALSE_IT(parent_stmt->clear_column_items())) {
} else if (OB_FAIL(ObTransformUtils::create_columns_for_view(ctx_,
*view_table,
parent_stmt,
new_select_list,
new_column_exprs))) {
LOG_WARN("failed to create column for view", K(ret));
} else if (OB_FAIL(parent_stmt->replace_relation_exprs(old_column_exprs, new_column_exprs))) {
LOG_WARN("failed to replace inner stmt expr", K(ret));
} else if (OB_FAIL(temp_table_query->adjust_subquery_list())) {
LOG_WARN("failed to adjust subquery list", K(ret));
}
}
return ret;
}
/**
* @brief get_map_table_id
* 找到视图中的table id对应temp table中的table id
*/
int ObTransformTempTable::get_map_table_id(ObSelectStmt *view,
ObSelectStmt *temp_table_query,
ObStmtMapInfo& map_info,
const uint64_t &view_table_id,
uint64_t &table_id)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(view) || OB_ISNULL(temp_table_query)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null stmt", K(ret));
}
bool find = false;
int64_t idx = OB_INVALID_ID;
for (int64_t i = 0; OB_SUCC(ret) && !find && i < view->get_table_size(); ++i) {
TableItem *table = view->get_table_item(i);
if (OB_ISNULL(table)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null table item", K(ret));
} else if (view_table_id == table->table_id_) {
find = true;
idx = i;
}
}
if (OB_SUCC(ret) && (!find || OB_INVALID_ID == idx)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("table shoud be found in view" ,K(view_table_id), K(ret));
}
find = false;
for (int64_t i = 0; OB_SUCC(ret) && !find && i < map_info.table_map_.count(); ++i) {
if (idx == map_info.table_map_.at(i)) {
idx = i;
find = true;
}
}
if (OB_SUCC(ret) && (!find || OB_INVALID_ID == idx ||
idx < 0 || idx > temp_table_query->get_table_size())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("incorrect table idx" ,K(idx), K(ret));
}
if (OB_SUCC(ret)) {
TableItem *table = temp_table_query->get_table_item(idx);
if (OB_ISNULL(table)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null table item", K(ret));
} else {
table_id = table->table_id_;
}
}
return ret;
}
int ObTransformTempTable::collect_temp_table_infos(ObDMLStmt *stmt,
ObIArray<TempTableInfo> &temp_table_infos)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(stmt)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null stmt", K(ret));
}
for (int64_t i = 0; OB_SUCC(ret) && i < stmt->get_table_size(); ++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_temp_table()) {
//do nothing
} else {
bool find = false;
//找到对应的temp table集合
for (int64_t j = 0; OB_SUCC(ret) && !find && j < temp_table_infos.count(); ++j) {
TempTableInfo &info = temp_table_infos.at(j);
if (table->ref_query_ == info.temp_table_query_) {
TableInfo table_info;
table_info.upper_stmt_ = stmt;
table_info.table_item_ = table;
if (OB_FAIL(inner_collect_temp_table_info(table_info))) {
LOG_WARN("failed to collect temp table info", K(ret));
} else if (OB_FAIL(info.table_infos_.push_back(table_info))) {
LOG_WARN("failed to push back table info", K(ret));
} else {
find = true;
}
}
}
if (OB_SUCC(ret) && !find) {
TempTableInfo info;
info.temp_table_query_ = table->ref_query_;
TableInfo table_info;
table_info.upper_stmt_ = stmt;
table_info.table_item_ = table;
if (OB_FAIL(SMART_CALL(collect_temp_table_infos(table->ref_query_, temp_table_infos)))) {
LOG_WARN("failed to collect temp table infos", K(ret));
} else if (OB_FAIL(inner_collect_temp_table_info(table_info))) {
LOG_WARN("failed to collect temp table info", K(ret));
} else if (OB_FAIL(info.table_infos_.push_back(table_info))) {
LOG_WARN("failed to push back table item", K(ret));
} else if (OB_FAIL(temp_table_infos.push_back(info))) {
LOG_WARN("failed to push back temp table info", K(ret));
}
}
}
}
if (OB_SUCC(ret)) {
ObSEArray<ObSelectStmt*, 8> temp_stmts;
if (OB_FAIL(stmt->get_child_stmts(temp_stmts))) {
LOG_WARN("failed to get child stmts", K(ret));
} else if (temp_stmts.empty()) {
//do nothing
} else if (OB_FAIL(SMART_CALL(collect_temp_table_infos(temp_stmts,
temp_table_infos)))) {
LOG_WARN("failed tp collect temp table infos", K(ret));
}
}
return ret;
}
int ObTransformTempTable::collect_temp_table_infos(ObIArray<ObSelectStmt*> &stmts,
ObIArray<TempTableInfo> &temp_table_infos)
{
int ret = OB_SUCCESS;
for (int64_t i = 0; OB_SUCC(ret) && i < stmts.count(); ++i) {
if (OB_FAIL(collect_temp_table_infos(stmts.at(i),
temp_table_infos))) {
LOG_WARN("failed to collect temp table infos", K(ret));
}
}
return ret;
}
int ObTransformTempTable::inner_collect_temp_table_info(TableInfo &table_info)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(table_info.upper_stmt_) || OB_ISNULL(table_info.table_item_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null param", K(ret));
} else if (OB_FAIL(table_info.upper_stmt_->get_column_ids(table_info.table_item_->table_id_,
table_info.column_ids_))) {
LOG_WARN("failed to get column ids", K(ret));
} else if (OB_FAIL(get_table_filters(table_info.upper_stmt_,
table_info.table_item_,
table_info.table_filters_))) {
LOG_WARN("failed to get table filters", K(ret));
}
return ret;
}
int ObTransformTempTable::get_table_filters(ObDMLStmt *stmt,
TableItem *table,
ObIArray<ObRawExpr*> &table_filters)
{
int ret = OB_SUCCESS;
ObSqlBitSet<> table_ids;
int32_t table_idx = OB_INVALID_INDEX;
uint64_t table_id = OB_INVALID_ID;
if (OB_ISNULL(stmt) || OB_ISNULL(table)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null param", K(ret));
} else if (OB_FALSE_IT(table_idx = stmt->get_table_bit_index(table->table_id_))) {
} else if (OB_FAIL(table_ids.add_member(table_idx))) {
LOG_WARN("failed to add member", K(table_idx), K(ret));
} else if (OB_FAIL(get_candi_exprs(table_ids,
stmt->get_condition_exprs(),
table_filters))) {
LOG_WARN("failed to get candi exprs", K(ret));
} else {
table_id = table->table_id_;
}
//如果是joined table内部表,如果在左侧,则可以使用where condition、
//如果在右侧,则不能使用where condition,选择可以使用的on condition
bool find = false;
for (int64_t i = 0; OB_SUCC(ret) && !find && i < stmt->get_from_item_size(); ++i) {
FromItem &from = stmt->get_from_item(i);
if (from.table_id_ == table_id) {
find = true;
} else if (from.is_joined_) {
JoinedTable *joined_table = stmt->get_joined_table(from.table_id_);
if (OB_ISNULL(joined_table)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null table item", K(ret));
} else if (!ObOptimizerUtil::find_item(joined_table->single_table_ids_, table_id)) {
//do nothing
} else if (OB_FAIL(get_table_filters_in_joined_table(joined_table,
table_id,
table_ids,
table_filters))) {
LOG_WARN("failed to get table filters", K(ret));
} else {
find = true;
}
}
}
return ret;
}
int ObTransformTempTable::get_table_filters_in_joined_table(JoinedTable *table,
uint64_t table_id,
const ObSqlBitSet<> &table_ids,
ObIArray<ObRawExpr*> &table_filters)
{
int ret = OB_SUCCESS;
ObSEArray<ObRawExpr*, 8> candi_filters;
bool in_left = false;
bool in_right = false;
if (OB_ISNULL(table) || OB_ISNULL(table->left_table_) ||
OB_ISNULL(table->right_table_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null table item", K(ret));
} else if (table->left_table_->is_joined_table()) {
JoinedTable *joined_table = static_cast<JoinedTable*>(table->left_table_);
if (ObOptimizerUtil::find_item(joined_table->single_table_ids_, table_id)) {
in_left = true;
}
} else if (!table->left_table_->is_joined_table()) {
if (table_id == table->left_table_->table_id_) {
in_left = true;
}
}
if (OB_SUCC(ret) && !in_left) {
if (table->right_table_->is_joined_table()) {
JoinedTable *joined_table = static_cast<JoinedTable*>(table->right_table_);
if (ObOptimizerUtil::find_item(joined_table->single_table_ids_, table_id)) {
in_right = true;
}
} else if (!table->right_table_->is_joined_table()) {
if (table_id == table->right_table_->table_id_) {
in_right = true;
}
}
}
if (OB_SUCC(ret) && in_left) {
if (INNER_JOIN == table->joined_type_) {
if (OB_FAIL(get_candi_exprs(table_ids,
table->join_conditions_,
table_filters))) {
LOG_WARN("failed to get candi exprs", K(ret));
}
} else if (LEFT_OUTER_JOIN == table->joined_type_) {
//do nothing
} else if (RIGHT_OUTER_JOIN == table->joined_type_) {
table_filters.reuse();
if (OB_FAIL(get_candi_exprs(table_ids,
table->join_conditions_,
table_filters))) {
LOG_WARN("failed to get candi exprs", K(ret));
}
} else {
table_filters.reuse();
}
if (OB_SUCC(ret) && table->left_table_->is_joined_table()) {
JoinedTable *joined_table = static_cast<JoinedTable*>(table->left_table_);
if (OB_FAIL(SMART_CALL(get_table_filters_in_joined_table(joined_table,
table_id,
table_ids,
table_filters)))) {
LOG_WARN("failed to get table filters", K(ret));
}
}
}
if (OB_SUCC(ret) && in_right) {
if (INNER_JOIN == table->joined_type_) {
if (OB_FAIL(get_candi_exprs(table_ids,
table->join_conditions_,
table_filters))) {
LOG_WARN("failed to get candi exprs", K(ret));
}
} else if (LEFT_OUTER_JOIN == table->joined_type_) {
table_filters.reuse();
if (OB_FAIL(get_candi_exprs(table_ids,
table->join_conditions_,
table_filters))) {
LOG_WARN("failed to get candi exprs", K(ret));
}
} else if (RIGHT_OUTER_JOIN == table->joined_type_) {
//do nothing
} else {
table_filters.reuse();
}
if (OB_SUCC(ret) && table->right_table_->is_joined_table()) {
JoinedTable *joined_table = static_cast<JoinedTable*>(table->right_table_);
if (OB_FAIL(SMART_CALL(get_table_filters_in_joined_table(joined_table,
table_id,
table_ids,
table_filters)))) {
LOG_WARN("failed to get table filters", K(ret));
}
}
}
return ret;
}
int ObTransformTempTable::get_candi_exprs(const ObSqlBitSet<> &table_ids,
const ObIArray<ObRawExpr*> &exprs,
ObIArray<ObRawExpr*> &candi_exprs)
{
int ret = OB_SUCCESS;
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("unexpect null expr", K(ret));
} else if (ObPredicateDeduce::contain_special_expr(*expr)) {
// do nothing
} else if (expr->has_flag(CNT_DYNAMIC_PARAM)) {
//do nothing
} else if (!expr->get_relation_ids().is_subset(table_ids)) {
//do nothing
} else if (OB_FAIL(candi_exprs.push_back(expr))) {
LOG_WARN("failed to push back expr", K(ret));
}
}
return ret;
}
int ObTransformTempTable::project_pruning(ObIArray<TempTableInfo> &temp_table_infos,
bool &trans_happened)
{
int ret = OB_SUCCESS;
trans_happened = false;
ObSqlBitSet<> removed_idx;
bool is_valid = false;
for (int64_t i = 0; OB_SUCC(ret) && i < temp_table_infos.count(); i++) {
removed_idx.reuse();
TempTableInfo &info = temp_table_infos.at(i);
trans_param_->trans_stmt_ = info.temp_table_query_;
trans_param_->trans_type_ = T_PROJECT_PRUNE;
OPT_TRACE("try to prune project for:",info.temp_table_query_);
if (OB_ISNULL(info.temp_table_query_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null stmt", K(ret));
} else if (OB_FAIL(check_hint_allowed_trans(*info.temp_table_query_,
T_PROJECT_PRUNE,
is_valid))) {
LOG_WARN("failed to check hint allowed prune", K(ret));
} else if (!is_valid) {
//do nothing
OPT_TRACE("hint reject transform");
} else if (OB_FAIL(ObTransformUtils::check_project_pruning_validity(*info.temp_table_query_,
is_valid))) {
LOG_WARN("failed to check project pruning valid", K(ret));
} else if (!is_valid) {
//do nothing
OPT_TRACE("can not prune project");
} else if (OB_FAIL(get_remove_select_item(info,
removed_idx))) {
LOG_WARN("failed to get remove select item", K(ret));
} else if (removed_idx.is_empty()) {
//do nothing
} else if (OB_FAIL(remove_select_items(info, removed_idx))) {
LOG_WARN("failed to rempve select item", K(ret));
} else if (OB_FAIL(add_normal_temp_table_trans_hint(*info.temp_table_query_, T_PROJECT_PRUNE))) {
LOG_WARN("failed to add transform hint", K(ret));
} else {
trans_happened = true;
}
}
return ret;
}
int ObTransformTempTable::get_remove_select_item(TempTableInfo &info,
ObSqlBitSet<> &removed_idx)
{
int ret = OB_SUCCESS;
ObSqlBitSet<> column_ids;
if (OB_ISNULL(info.temp_table_query_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null stmt", K(ret));
}
for (int64_t i = 0; OB_SUCC(ret) && i < info.table_infos_.count(); ++i) {
if (OB_FAIL(column_ids.add_members(info.table_infos_.at(i).column_ids_))) {
LOG_WARN("failed to add members", K(ret));
}
}
for (int64_t i = 0; OB_SUCC(ret) && i < info.temp_table_query_->get_select_item_size(); i++) {
bool need_remove = false;
if (column_ids.has_member(i + OB_APP_MIN_COLUMN_ID)) {
//do nothing
} else if (OB_FAIL(ObTransformUtils::check_select_item_need_remove(info.temp_table_query_,
i,
need_remove))) {
LOG_WARN("fail to check column in set ordrt by", K(ret));
} else if (need_remove) {
ret = removed_idx.add_member(i);
} else { /*do nothing*/ }
}
return ret;
}
int ObTransformTempTable::remove_select_items(TempTableInfo &info,
ObSqlBitSet<> &removed_idxs)
{
int ret = OB_SUCCESS;
int64_t count = 0;
ObSEArray<uint64_t, 16> new_column_ids;
ObArray<SelectItem> new_select_items;
ObSEArray<ColumnItem, 16> new_column_items;
ObSelectStmt *child_stmt = info.temp_table_query_;
if (OB_ISNULL(ctx_) || OB_ISNULL(child_stmt)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("argument invalid", K(ctx_), K(ret));
} else if (OB_FAIL(new_column_ids.prepare_allocate(child_stmt->get_select_item_size()))) {
LOG_WARN("failed to preallocate", K(ret));
}
//计算老的column id对应的新column id关系
for (int64_t i = 0; OB_SUCC(ret) && i < child_stmt->get_select_item_size(); i++) {
new_column_ids.at(i) = OB_INVALID_ID;
if (!removed_idxs.has_member(i) ) {
if (OB_FAIL(new_select_items.push_back(child_stmt->get_select_item(i)))) {
LOG_WARN("failed to push back select item", K(ret));
} else {
new_column_ids.at(i) = count + OB_APP_MIN_COLUMN_ID;
count++;
}
}
}
//更新upper stmt的column item
for (int64_t i = 0; OB_SUCC(ret) && i < info.table_infos_.count(); ++i) {
new_column_items.reuse();
ObDMLStmt *upper_stmt = info.table_infos_.at(i).upper_stmt_;
TableItem *table = info.table_infos_.at(i).table_item_;
if (OB_ISNULL(upper_stmt) || OB_ISNULL(table)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null param", K(ret));
} else if (OB_FAIL(upper_stmt->get_column_items(table->table_id_, new_column_items))) {
LOG_WARN("failed to get column items", K(ret));
}
for (int64_t j = 0; OB_SUCC(ret) && j < new_column_items.count(); ++j) {
ColumnItem &column = new_column_items.at(j);
uint64_t column_id = column.column_id_;
if (column_id - OB_APP_MIN_COLUMN_ID >= new_column_ids.count()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect column id", K(column), K(ret));
} else {
column.set_ref_id(table->table_id_, new_column_ids.at(column_id - OB_APP_MIN_COLUMN_ID));
}
}
if (OB_FAIL(ret)) {
} else if (OB_FAIL(upper_stmt->remove_column_item(table->table_id_))) {
LOG_WARN("failed to remove column item", K(ret));
} else if (OB_FAIL(upper_stmt->add_column_item(new_column_items))) {
LOG_WARN("failed to add column item", K(ret));
}
}
//消除child stmt的select item
if (OB_SUCC(ret)) {
if (child_stmt->is_set_stmt()) {
if (OB_FAIL(ObTransformUtils::remove_select_items(ctx_,
*child_stmt,
removed_idxs))) {
LOG_WARN("failed to remove select item", K(ret));
}
} else if (OB_FAIL(child_stmt->get_select_items().assign(new_select_items))) {
LOG_WARN("failed to assign select item", K(ret));
} else if (child_stmt->get_select_items().empty() &&
OB_FAIL(ObTransformUtils::create_dummy_select_item(*child_stmt, ctx_))) {
LOG_WARN("failed to create dummy select item", K(ret));
} else {/*do nothing*/}
}
return ret;
}
int ObTransformTempTable::push_down_filter(ObIArray<TempTableInfo> &temp_table_info,
bool &trans_happened)
{
int ret = OB_SUCCESS;
trans_happened = false;
for (int64_t i = 0; OB_SUCC(ret) && i < temp_table_info.count(); ++i) {
TempTableInfo &info = temp_table_info.at(i);
uint64_t filter_count = 0;
bool have_new_filter = false;
bool is_valid = false;
OPT_TRACE("try to pushdown filter into temp table:", info.temp_table_query_);
if (OB_ISNULL(info.temp_table_query_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null ref query", K(ret));
} else if (OB_FAIL(check_hint_allowed_trans(*info.temp_table_query_,
T_PUSH_PRED_CTE,
is_valid))) {
LOG_WARN("failed to check hint allowed pushdown filter", K(ret));
} else if (!is_valid) {
OPT_TRACE("hint reject transform");
continue;
}
for (int64_t j = 0; j < info.table_infos_.count(); ++j) {
if (!info.table_infos_.at(j).table_filters_.empty()) {
++filter_count;
}
if (!ObOptimizerUtil::subset_exprs(info.table_infos_.at(j).table_filters_,
ctx_->used_table_filters_)) {
have_new_filter = true;
}
}
if (OB_SUCC(ret) && filter_count == info.table_infos_.count() && have_new_filter) {
//当所有的引用表都有可以下推的谓词时才下推谓词
ObDMLStmt *orig_stmt = info.temp_table_query_;
if (OB_FAIL(inner_push_down_filter(info))) {
LOG_WARN("failed to pushdown preds into temp table", K(ret));
} else if (OB_FAIL(add_normal_temp_table_trans_hint(*orig_stmt, T_PUSH_PRED_CTE))) {
LOG_WARN("failed to add transform hint", K(ret));
} else {
trans_happened = true;
}
}
}
return ret;
}
int ObTransformTempTable::inner_push_down_filter(TempTableInfo& info)
{
int ret = OB_SUCCESS;
ObRawExprFactory *expr_factory = NULL;
ObSQLSessionInfo *session_info = NULL;
ObSEArray<ObRawExpr *, 8> and_exprs;
ObSEArray<ObRawExpr *, 8> rename_exprs;
ObRawExpr *or_expr = NULL;
if (OB_ISNULL(info.temp_table_query_) ||
OB_ISNULL(ctx_) ||
OB_ISNULL(expr_factory = ctx_->expr_factory_) ||
OB_ISNULL(session_info = ctx_->session_info_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null param", K(info), K(expr_factory), K(ret));
} else if (info.temp_table_query_->is_spj()) {
//do nothing
} else if (OB_FAIL(ObTransformUtils::pack_stmt(ctx_, info.temp_table_query_))) {
LOG_WARN("failed to create spj", K(ret));
}
for (int64_t i = 0; OB_SUCC(ret) && i < info.table_infos_.count(); ++i) {
ObDMLStmt *upper_stmt = info.table_infos_.at(i).upper_stmt_;
TableItem *table = info.table_infos_.at(i).table_item_;
ObIArray<ObRawExpr*> &table_filters = info.table_infos_.at(i).table_filters_;
ObRawExpr *and_expr = NULL;
rename_exprs.reuse();
if (table_filters.empty() || OB_ISNULL(upper_stmt) ||
OB_ISNULL(table)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null table info", K(ret));
} else if (OB_FAIL(ObOptimizerUtil::rename_pushdown_filter(*upper_stmt,
*info.temp_table_query_,
table->table_id_,
session_info,
*expr_factory,
table_filters,
rename_exprs))) {
LOG_WARN("failed to rename push down preds", K(ret));
} else if (OB_FAIL(ObRawExprUtils::build_and_expr(*expr_factory,
rename_exprs,
and_expr))) {
LOG_WARN("failed to build and expr", K(ret));
} else if (OB_FAIL(and_exprs.push_back(and_expr))) {
LOG_WARN("failed to push back expr", K(ret));
} else if (OB_FAIL(append(ctx_->used_table_filters_, table_filters))) {
LOG_WARN("failed to append table filters", K(ret));
}
}
if (OB_SUCC(ret)) {
if (OB_FAIL(ObRawExprUtils::build_or_exprs(*expr_factory,
and_exprs,
or_expr))) {
LOG_WARN("failed to build or expr", K(ret));
} else if (OB_FAIL(or_expr->formalize(session_info))) {
LOG_WARN("failed to formalize expr", K(ret));
} else if (OB_FAIL(or_expr->pull_relation_id())) {
LOG_WARN("failed to pull relation id and levels", K(ret));
} else if (OB_FAIL(info.temp_table_query_->get_condition_exprs().push_back(or_expr))) {
LOG_WARN("failed to push back expr", K(ret));
}
}
return ret;
}
// add hint about temp table transform: expand temp table, project pruning, filter pushdown
int ObTransformTempTable::add_normal_temp_table_trans_hint(ObDMLStmt &stmt, ObItemType type)
{
int ret = OB_SUCCESS;
ObString qb_name;
const ObQueryHint *query_hint = NULL;
ObMaterializeHint *hint = NULL;
ObItemType real_type = T_INLINE == type ? T_MATERIALIZE : type;
const ObHint *used_hint = stmt.get_stmt_hint().get_normal_hint(real_type);
if (OB_ISNULL(ctx_) || OB_ISNULL(ctx_->allocator_) ||
OB_ISNULL(query_hint = stmt.get_stmt_hint().query_hint_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected null", K(ret), K(ctx_), K(query_hint));
} else if (OB_FAIL(stmt.get_qb_name(qb_name))) {
LOG_WARN("failed to get qb name", K(ret), K(stmt.get_stmt_id()));
} else if (OB_FAIL(ObQueryHint::create_hint(ctx_->allocator_, type, hint))) {
LOG_WARN("failed to create hint", K(ret));
} else if (OB_FAIL(ctx_->outline_trans_hints_.push_back(hint))) {
LOG_WARN("failed to push back hint", K(ret));
} else if (NULL != used_hint && OB_FAIL(ctx_->add_used_trans_hint(used_hint))) {
LOG_WARN("failed to add used trans hint", K(ret));
} else if (OB_FAIL(ctx_->add_src_hash_val(qb_name))) {
LOG_WARN("failed to add src hash val", K(ret));
} else if (OB_FAIL(stmt.adjust_qb_name(ctx_->allocator_,
ctx_->src_qb_name_,
ctx_->src_hash_val_))) {
LOG_WARN("failed to add used trans hint", K(ret));
} else {
ctx_->src_hash_val_.pop_back();
hint->set_qb_name(qb_name);
if (query_hint->has_outline_data()) {
++ctx_->trans_list_loc_;
}
}
return ret;
}
// create and add T_MATERIALIZE hint
int ObTransformTempTable::construct_transform_hint(ObDMLStmt &stmt, void *trans_params)
{
int ret = OB_SUCCESS;
ObMaterializeHint *hint = NULL;
TempTableTransParam *params = static_cast<TempTableTransParam *>(trans_params);
if (OB_ISNULL(params) || OB_ISNULL(ctx_) || OB_ISNULL(ctx_->allocator_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected null", K(ret), K(params), K(ctx_));
} else if (OB_UNLIKELY(T_MATERIALIZE != params->trans_type_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect transform type", K(ret), "type", get_type_name(params->trans_type_));
} else if (OB_FAIL(ObQueryHint::create_hint(ctx_->allocator_, T_MATERIALIZE, hint))) {
LOG_WARN("failed to create hint", K(ret));
} else if (OB_FAIL(sort_materialize_stmts(params->materialize_stmts_))) {
LOG_WARN("failed to sort stmts", K(ret));
} else {
Ob2DArray<MaterializeStmts *> &child_stmts = params->materialize_stmts_;
ObSelectStmt* subquery = NULL;
bool use_hint = false;
const ObMaterializeHint *myhint = static_cast<const ObMaterializeHint*>(get_hint(stmt.get_stmt_hint()));
for (int64_t i = 0; OB_SUCC(ret) && i < child_stmts.count(); ++i) {
MaterializeStmts *subqueries = child_stmts.at(i);
QbNameList qb_names;
if (OB_ISNULL(subqueries)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null stmts", K(ret));
}
for (int j = 0; OB_SUCC(ret) && j < subqueries->count(); ++j) {
ObString subquery_qb_name;
ObSelectStmt *subquery = NULL;
if (OB_ISNULL(subquery = subqueries->at(j))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected null", K(ret), K(subquery));
} else if (OB_FAIL(subquery->get_qb_name(subquery_qb_name))) {
LOG_WARN("failed to get qb name", K(ret), K(stmt.get_stmt_id()));
} else if (OB_FAIL(qb_names.qb_names_.push_back(subquery_qb_name))) {
LOG_WARN("failed to push back qb name", K(ret));
} else if (OB_FAIL(ctx_->add_src_hash_val(subquery_qb_name))) {
LOG_WARN("failed to add src hash val", K(ret));
}
}
if (OB_FAIL(ret)) {
} else if (OB_FAIL(hint->add_qb_name_list(qb_names))) {
LOG_WARN("failed to add qb names", K(ret));
} else if (NULL != myhint && myhint->enable_materialize_subquery(qb_names.qb_names_)) {
use_hint = true;
}
}
if (OB_FAIL(ret)) {
} else if (OB_FAIL(ctx_->outline_trans_hints_.push_back(hint))) {
LOG_WARN("failed to push back hint", K(ret));
} else if (use_hint && OB_FAIL(ctx_->add_used_trans_hint(myhint))) {
LOG_WARN("failed to add used trans hint", K(ret));
} else {
hint->set_qb_name(ctx_->src_qb_name_);
}
}
return ret;
}
int ObTransformTempTable::need_transform(const common::ObIArray<ObParentDMLStmt> &parent_stmts,
const int64_t current_level,
const ObDMLStmt &stmt,
bool &need_trans)
{
int ret = OB_SUCCESS;
need_trans = false;
const ObQueryHint *query_hint = NULL;
const ObHint *trans_hint = NULL;
if (OB_ISNULL(ctx_) || OB_ISNULL(query_hint = stmt.get_stmt_hint().query_hint_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected null", K(ret), K(ctx_), K(query_hint));
} else if (!parent_stmts.empty() || current_level != 0 ||
is_normal_disabled_transform(stmt)) {
need_trans = false;
} else if (!query_hint->has_outline_data()) {
need_trans = true;
} else if (NULL == (trans_hint = query_hint->get_outline_trans_hint(ctx_->trans_list_loc_))) {
/*do nothing*/
OPT_TRACE("outline reject transform");
} else {
const ObItemType hint_type = trans_hint->get_hint_type();
need_trans = T_MATERIALIZE == hint_type
|| T_PUSH_PRED_CTE == hint_type
|| T_PROJECT_PRUNE == hint_type;
}
return ret;
}
// check hint T_MATERIALIZE for expand temp table
int ObTransformTempTable::check_hint_allowed_trans(const ObSelectStmt &subquery,
bool &force_inline,
bool &force_materialize) const
{
int ret = OB_SUCCESS;
force_inline = false;
force_materialize = false;
const ObQueryHint *query_hint = NULL;
const ObMaterializeHint *myhint = static_cast<const ObMaterializeHint*>(get_hint(subquery.get_stmt_hint()));
if (OB_ISNULL(ctx_) ||
OB_ISNULL(query_hint = subquery.get_stmt_hint().query_hint_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected null", K(ret), K(ctx_), K(query_hint));
} else if (!query_hint->has_outline_data()) {
if (NULL == myhint) {
/* do nothing */
} else if (OB_FAIL(ctx_->add_used_trans_hint(myhint))) {
LOG_WARN("failed to add used trans hint", K(ret));
} else {
force_inline = myhint->enable_inline();
force_materialize = myhint->enable_materialize();
}
} else {
force_inline = NULL != myhint && myhint->enable_inline()
&& query_hint->is_valid_outline_transform(ctx_->trans_list_loc_, myhint);
force_materialize = !force_inline;
}
return ret;
}
int ObTransformTempTable::get_hint_force_set(const ObDMLStmt &stmt,
const ObSelectStmt &subquery,
QbNameList &qb_names,
bool &hint_force_no_trans)
{
int ret = OB_SUCCESS;
hint_force_no_trans = false;
const ObQueryHint *query_hint = NULL;
ObString qb_name;
if (OB_ISNULL(ctx_) ||
OB_ISNULL(query_hint = stmt.get_stmt_hint().query_hint_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected null", K(ret), K(ctx_), K(query_hint));
} else if (OB_FAIL(subquery.get_qb_name(qb_name))) {
LOG_WARN("failed to get qb name", K(ret));
} else {
const ObHint *myhint = get_hint(stmt.get_stmt_hint());
const ObMaterializeHint *hint = static_cast<const ObMaterializeHint*>(myhint);
if (!query_hint->has_outline_data()) {
if (NULL == myhint ||
!hint->has_qb_name_list()) {
const ObHint *no_rewrite_hint = stmt.get_stmt_hint().get_no_rewrite_hint();
if (NULL != no_rewrite_hint) {
if (OB_FAIL(ctx_->add_used_trans_hint(no_rewrite_hint))) {
LOG_WARN("failed to add used transform hint", K(ret));
} else {
hint_force_no_trans = true;
}
}
} else if (OB_FAIL(hint->get_qb_name_list(qb_name, qb_names))) {
LOG_WARN("failed to get qb name list", K(ret));
}
} else {
bool is_valid = query_hint->is_valid_outline_transform(ctx_->trans_list_loc_,
myhint);
if (!is_valid) {
hint_force_no_trans = true;
} else if (OB_ISNULL(myhint)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null hint", K(ret));
} else if (OB_FAIL(hint->get_qb_name_list(qb_name, qb_names))) {
LOG_WARN("failed to get qb name list", K(ret));
} else if (qb_names.empty()) {
hint_force_no_trans = true;
}
}
}
return ret;
}
int ObTransformTempTable::sort_materialize_stmts(Ob2DArray<MaterializeStmts *> &materialize_stmts)
{
int ret = OB_SUCCESS;
ObSEArray<std::pair<int, int>, 4> index_map;
Ob2DArray<MaterializeStmts *> new_stmts;
auto cmp_func1 = [](ObSelectStmt* l_stmt, ObSelectStmt* r_stmt){
if (OB_ISNULL(l_stmt) || OB_ISNULL(r_stmt)) {
return false;
} else {
return l_stmt->get_stmt_id() < r_stmt->get_stmt_id();
}
};
auto cmp_func2 = [](std::pair<int,int> &lhs, std::pair<int,int> &rhs){
return lhs.second < rhs.second;
};
for (int64_t i = 0; OB_SUCC(ret) && i < materialize_stmts.count(); ++i) {
MaterializeStmts *subqueries = materialize_stmts.at(i);
if (OB_ISNULL(subqueries)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null stmts", K(ret));
} else {
std::sort(subqueries->begin(), subqueries->end(), cmp_func1);
}
}
for (int64_t i = 0; OB_SUCC(ret) && i < materialize_stmts.count(); ++i) {
MaterializeStmts *subqueries = materialize_stmts.at(i);
if (OB_ISNULL(subqueries)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null stmts", K(ret));
} else if (subqueries->empty() || OB_ISNULL(subqueries->at(0))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null stmts", K(ret));
} else if (OB_FAIL(index_map.push_back(std::pair<int,int>(i, subqueries->at(0)->get_stmt_id())))) {
LOG_WARN("failed to push back index", K(ret));
}
}
std::sort(index_map.begin(), index_map.end(), cmp_func2);
for (int64_t i = 0; OB_SUCC(ret) && i < index_map.count(); ++i) {
int index = index_map.at(i).first;
if (index < 0 || index >= materialize_stmts.count()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("index out of range", K(ret));
} else if (OB_FAIL(new_stmts.push_back(materialize_stmts.at(index)))) {
LOG_WARN("failed to push back stmts", K(ret));
}
}
if (OB_SUCC(ret)) {
if (OB_FAIL(materialize_stmts.assign(new_stmts))) {
LOG_WARN("failed to assign array", K(ret));
}
}
return ret;
}
// check hint for T_PUSH_PRED_CTE and T_PROJECT_PRUNE
int ObTransformTempTable::check_hint_allowed_trans(const ObSelectStmt &ref_query,
const ObItemType check_hint_type,
bool &allowed) const
{
int ret = OB_SUCCESS;
const ObQueryHint *query_hint = NULL;
const ObHint *myhint = ref_query.get_stmt_hint().get_normal_hint(check_hint_type);
bool is_enable = (NULL != myhint && myhint->is_enable_hint());
bool is_disable = (NULL != myhint && myhint->is_disable_hint());
allowed = false;
if (OB_ISNULL(ctx_) ||
OB_ISNULL(query_hint = ref_query.get_stmt_hint().query_hint_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected null", K(ret), K(ctx_), K(query_hint));
} else if (OB_UNLIKELY(T_PUSH_PRED_CTE != check_hint_type
&& T_PROJECT_PRUNE != check_hint_type)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect hint type", K(ret), "type", get_type_name(check_hint_type));
} else if (!query_hint->has_outline_data()) {
const ObHint *no_rewrite_hint = ref_query.get_stmt_hint().get_no_rewrite_hint();
if (is_enable) {
allowed = true;
} else if (NULL != no_rewrite_hint || is_disable) {
if (OB_FAIL(ctx_->add_used_trans_hint(no_rewrite_hint))) {
LOG_WARN("failed to add used transform hint", K(ret));
} else if (is_disable && OB_FAIL(ctx_->add_used_trans_hint(myhint))) {
LOG_WARN("failed to add used transform hint", K(ret));
}
} else {
allowed = true;
}
} else if (query_hint->is_valid_outline_transform(ctx_->trans_list_loc_, myhint)) {
allowed = true;
}
return ret;
}
int ObTransformTempTable::pushdown_shared_subqueries(ObSelectStmt *parent_stmt, ObIArray<ObRawExpr*> &candi_exprs) {
int ret = OB_SUCCESS;
TableItem *table = NULL;
ObSEArray<ObRawExpr*, 8> shared_exprs;
ObSEArray<ObRawExpr*, 8> column_exprs;
ObSEArray<ObRawExpr*, 8> pushdown_conds;
ObSEArray<ObRawExpr*, 8> rename_conds;
if (OB_ISNULL(parent_stmt) || OB_ISNULL(ctx_) || OB_ISNULL(ctx_->session_info_) || OB_ISNULL(ctx_->expr_factory_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null param", K(ret));
} else if (1 != parent_stmt->get_table_size()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("expect one table item in stmt", KPC(parent_stmt), K(ret));
} else if (OB_ISNULL(table = parent_stmt->get_table_item(0))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null table item", K(ret));
} else if (!table->is_generated_table()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("expect generate table item", KPC(table), K(ret));
} else if (OB_ISNULL(table->ref_query_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null ref query", K(ret));
} else if (OB_FAIL(ObTransformUtils::extract_shared_exprs(parent_stmt, candi_exprs, shared_exprs))) {
LOG_WARN("fail to get shared exprs", K(ret));
} else {
//push down shared exprs which contains shared subqueries
ObSEArray<ObQueryRefRawExpr*, 4> set_queries;
ObSEArray<ObRawExpr*, 8> relation_exprs;
for (int64_t i = 0; OB_SUCC(ret) && i < shared_exprs.count(); ++i) {
if (OB_ISNULL(shared_exprs.at(i))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("input expr is null", K(ret));
} else if (!shared_exprs.at(i)->has_flag(CNT_SUB_QUERY)) {
// do nothing
} else if (shared_exprs.at(i)->is_query_ref_expr()) {
ObQueryRefRawExpr *query_ref = static_cast<ObQueryRefRawExpr *>(shared_exprs.at(i));
if (query_ref->is_set() || query_ref->get_output_column() > 1) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("set queries and queries which have multi output columns can't be pushed down into select list", K(ret));
} else if (OB_FAIL(pushdown_conds.push_back(shared_exprs.at(i)))) {
LOG_WARN("failed to push back input expr", K(ret));
}
} else if (OB_FAIL(pushdown_conds.push_back(shared_exprs.at(i)))) {
LOG_WARN("failed to push back input expr", K(ret));
}
}
}
if (OB_SUCC(ret)) {
if (OB_FAIL(ObOptimizerUtil::rename_pushdown_filter(*parent_stmt, *table->ref_query_, table->table_id_, ctx_->session_info_,
*ctx_->expr_factory_, pushdown_conds, rename_conds))) {
LOG_WARN("failed to rename pushdown filter", K(ret));
} else if (OB_FAIL(ObTransformUtils::create_columns_for_view(ctx_, *table, parent_stmt, rename_conds, column_exprs))) {
LOG_WARN("failed to create columns for view", K(ret));
} else {
parent_stmt->get_table_items().pop_back();
if (OB_FAIL(parent_stmt->replace_relation_exprs(pushdown_conds, column_exprs))) {
LOG_WARN("failed to replace inner stmt expr", K(ret));
} else if (OB_FAIL(parent_stmt->get_table_items().push_back(table))) {
LOG_WARN("failed to push back view table item", K(ret));
}
}
}
return ret;
}
}//namespace sql
}//namespace oceanbase