/** * 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 &parent_stmts, ObDMLStmt *&stmt, bool &trans_happened) override; virtual int transform_one_stmt_with_outline(common::ObIArray &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 &unnest_stmts, bool &trans_happened); int transform_single_set_query(ObDMLStmt *stmt, ObIArray &unnest_stmts, bool &trans_happened); int transform_one_expr(ObDMLStmt *stmt, ObRawExpr *expr, ObIArray &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 &queries); int check_subquery_validity(ObDMLStmt &stmt, ObRawExpr *root_expr, ObQueryRefRawExpr *subquery_expr, bool in_where_cond, ObIArray &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 &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 &subq_exprs, ObSelectStmt* subquery, ObRawExpr *expr, ObIArray &semi_conds, ObIArray &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 &semi_conditions, SemiInfo *&semi_info); int fill_semi_left_table_ids(ObDMLStmt *stmt, SemiInfo *info); int is_where_having_subquery_correlated(const ObIArray &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_ */