Files
oceanbase/src/sql/rewrite/ob_transform_where_subquery_pullup.h
2023-08-07 10:42:40 +00:00

254 lines
10 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.
*/
#ifndef _OB_WHERE_SUBQUERY_PULLUP_H_
#define _OB_WHERE_SUBQUERY_PULLUP_H_
#include "sql/rewrite/ob_transform_rule.h"
#include "sql/resolver/dml/ob_select_stmt.h"
namespace oceanbase
{
namespace sql
{
/**
* 这个类主要进行和子查询相关的SQL改写,它主要分为两类:
* 1. eliminate_subquery 简化子查询的某一部分,或者移除整个冗余的子查询
* (1)移除整个冗余的子查询
* 1. 对于在执行前即可计算出恒TURE或者恒FALSE的EXIST / NOT EXIST
* 语句,可以在这一阶段消除,替换成相应的TURE或者FALSE,判断规则见
* subquery_can_be_eliminated_in_exists()
* (2)简化子查询的一部分
* 1. 对于不能消除的EXIST / NOT EXIST,它的SELECT LIST和ORDER BY均可
* 消除;在一定条件下,GROUP BY也可以消除,判断规则见
* groupby_can_be_eliminated_in_exists()
* 2. 对于不能消除的EXIST / NOT EXIST,如果本身没有LIMIT语句,会为它加
* 上LIMIT 1。
* 3. 对于ANY / ALL子查询,在一定条件下,GROUP BY也可以消除,判断规则见
* groupby_can_be_eliminated_in_any_all()
*
* 2. pullup_subquery 将子查询提升为一个view或者合并到主查询中
* (1)将子查询合并到主查询中,改写成SEMI JOIN或者ANTI JOIN
* 通常认为改写(2)要优于改写(3),如果能直接合并入主查询中,不会再进行改写(3)
* e.g.
* (示例1:子查询和主查询相关联)
* SELECT * FROM T1 WHERE T1.c1 in (SELECT T2.c1 FROM T2 WHERE T1.c2 < T2.c2)
* ->
* SELECT *
* FROM T1 SEMI JOIN T2
* WHERE T1.c1 = T2.c1 AND T1.c2 < T2.c2
* (2)将和主查询无关的子查询提升为一个view,改写成SEMI JOIN或者ANTI JOIN
* e.g.
* SELECT * FROM T1 WHERE T1.c1 in (SELECT T2.c1 FROM T2 LIMIT 3)
* ->
* SELECT *
* FROM T1 SEMI JOIN (SELECT T2.c1 FROM T2 LIMIT 3) AS SUBQ
* WHERE T1.c1 = SUBQ.c1
*
*/
class ObWhereSubQueryPullup : public ObTransformRule
{
public:
ObWhereSubQueryPullup(ObTransformerCtx *ctx)
: ObTransformRule(ctx, TransMethod::POST_ORDER, T_UNNEST)
{}
virtual ~ObWhereSubQueryPullup() {}
virtual int transform_one_stmt(common::ObIArray<ObParentDMLStmt> &parent_stmts,
ObDMLStmt *&stmt,
bool &trans_happened) override;
virtual int transform_one_stmt_with_outline(common::ObIArray<ObParentDMLStmt> &parent_stmts,
ObDMLStmt *&stmt,
bool &trans_happened) override;
private:
struct SingleSetParam {
SingleSetParam():
query_ref_expr_(NULL),
not_null_column_(NULL),
null_reject_select_idx_(),
use_outer_join_(false)
{}
virtual ~SingleSetParam(){}
TO_STRING_KV(
K_(query_ref_expr),
K_(not_null_column),
K_(null_reject_select_idx),
K_(use_outer_join)
);
ObQueryRefRawExpr *query_ref_expr_;
ObRawExpr *not_null_column_;
ObSqlBitSet<> null_reject_select_idx_;
bool use_outer_join_;
};
struct TransformParam {
TransformParam() : op_(NULL),
subquery_expr_(NULL),
subquery_(NULL),
left_hand_(NULL),
can_be_transform_(true),
is_correlated_(false),
need_create_spj_(false),
need_add_limit_constraint_(false)
{}
ObOpRawExpr *op_; // the all/any/exists contain subquery expr;
ObQueryRefRawExpr *subquery_expr_;//the query expr
ObSelectStmt *subquery_; //subquery select stmt
ObRawExpr *left_hand_; //the all/any op left expr
bool can_be_transform_; //能否被改写
bool is_correlated_;//是否直接相关的
bool need_create_spj_;
//Just in case different parameters hit same plan, firstly we need add const param constraint
bool need_add_limit_constraint_;
TO_STRING_KV(K_(op),
K_(subquery_expr),
K_(subquery),
K_(left_hand),
K_(can_be_transform),
K_(is_correlated),
K_(need_create_spj),
K_(need_add_limit_constraint));
};
int transform_anyall_query(ObDMLStmt *stmt,
ObIArray<ObSelectStmt*> &unnest_stmts,
bool &trans_happened);
int transform_single_set_query(ObDMLStmt *stmt,
ObIArray<ObSelectStmt*> &unnest_stmts,
bool &trans_happened);
int transform_one_expr(ObDMLStmt *stmt,
ObRawExpr *expr,
ObIArray<ObSelectStmt*> &unnest_stmts,
bool &trans_happened);
int gather_transform_params(ObDMLStmt *stmt,
ObRawExpr *expr,
TransformParam &trans_param);
int can_be_unnested(const ObItemType op_type,
const ObSelectStmt *subquery,
bool &can_be,
bool &need_add_limit_constraint);
int check_limit(const ObItemType op_type,
const ObSelectStmt *subquery,
bool &has_limit,
bool &need_add_limit_constraint) const;
int do_transform_pullup_subquery(ObDMLStmt* stmt, ObRawExpr* expr, TransformParam &trans_param, bool &trans_happened);
int get_single_set_subquery(ObDMLStmt &stmt,
ObRawExpr *root_expr,
ObRawExpr *expr,
bool in_where_cond,
ObIArray<SingleSetParam> &queries);
int check_subquery_validity(ObDMLStmt &stmt,
ObRawExpr *root_expr,
ObQueryRefRawExpr *subquery_expr,
bool in_where_cond,
ObIArray<SingleSetParam> &queries);
bool is_vector_query(ObQueryRefRawExpr *query);
int unnest_single_set_subquery(ObDMLStmt *stmt,
SingleSetParam& param,
const bool is_vector_assign);
int wrap_case_when_for_select_expr(SingleSetParam& param,
ObIArray<ObRawExpr *> &select_exprs);
int wrap_case_when(ObSelectStmt &child_stmt,
ObRawExpr *not_null_column,
ObRawExpr *&expr);
int pull_up_semi_info(ObDMLStmt* stmt,
ObSelectStmt* subquery);
int trans_from_list(ObDMLStmt *stmt,
ObSelectStmt *subquery,
const bool use_outer_join);
int pullup_non_correlated_subquery_as_view(ObDMLStmt *stmt,
ObSelectStmt *subquery,
ObRawExpr *expr,
ObQueryRefRawExpr *subquery_expr);
int pullup_correlated_subquery_as_view(ObDMLStmt *stmt,
ObSelectStmt *subquery,
ObRawExpr *expr,
ObQueryRefRawExpr *subquery_expr);
int check_transform_validity(ObDMLStmt *stmt, const ObRawExpr* expr, TransformParam &trans_param);
int check_basic_validity(ObDMLStmt *stmt, const ObRawExpr* expr, TransformParam &trans_param);
int check_subquery_validity(ObQueryRefRawExpr *query_ref,
ObSelectStmt *subquery,
bool is_correlated,
bool &is_valid);
int pull_up_tables_and_columns(ObDMLStmt* stmt, ObSelectStmt* subquery);
int generate_conditions(ObDMLStmt *stmt,
ObIArray<ObRawExpr *> &subq_exprs,
ObSelectStmt* subquery,
ObRawExpr *expr,
ObIArray<ObRawExpr*> &semi_conds,
ObIArray<ObRawExpr*> &right_conds);
int get_semi_oper_type(ObRawExpr *op, ObItemType &oper_type);
int generate_anti_condition(ObDMLStmt *stmt,
const ObSelectStmt *subquery,
ObRawExpr* expr,
ObRawExpr* left_arg,
ObRawExpr* right_arg,
ObRawExpr* generated_column_,
ObRawExpr* &anti_expr);
int make_null_test(ObDMLStmt *stmt, ObRawExpr *in_expr, ObRawExpr *&out_expr);
int generate_semi_info(ObDMLStmt* stmt,
ObRawExpr* expr,
TableItem *right_table,
ObIArray<ObRawExpr*> &semi_conditions,
SemiInfo *&semi_info);
int fill_semi_left_table_ids(ObDMLStmt *stmt,
SemiInfo *info);
int is_where_having_subquery_correlated(const ObIArray<ObExecParamRawExpr *> &exec_params,
const ObSelectStmt &subquery,
bool &is_correlated);
int check_const_select(const ObSelectStmt &stmt, bool &is_const_select) const;
virtual int check_hint_status(const ObDMLStmt &stmt, bool &need_trans) override;
virtual int construct_transform_hint(ObDMLStmt &stmt, void *trans_params) override;
int check_hint_allowed_unnest(const ObDMLStmt &stmt,
const ObSelectStmt &subquery,
bool &allowed);
private:
DISALLOW_COPY_AND_ASSIGN(ObWhereSubQueryPullup);
};
}
}
#endif /* _OB_WHERE_SUBQUERY_PULLUP_H_ */