2294 lines
96 KiB
C++
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> ¶m_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> ¶m_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
|