295 lines
12 KiB
C++
295 lines
12 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_TRANSFORM_AGGR_SUBQUERY_H_
|
|
#define _OB_TRANSFORM_AGGR_SUBQUERY_H_ 1
|
|
|
|
#include "sql/rewrite/ob_transform_rule.h"
|
|
#include "sql/resolver/dml/ob_select_stmt.h"
|
|
|
|
namespace oceanbase
|
|
{
|
|
namespace sql
|
|
{
|
|
class ObUpdateStmt;
|
|
/**
|
|
* ObTransformAggrSubquery实现JA类型的子查询的改写
|
|
* 改写的实现方式主要参考了如下一些论文:
|
|
* [Kim82] W.Kim, "On Optimizing an SQL-like Nested Query"
|
|
* [Ganski87] Richard A. Ganski and Harry K. T. Long, "Optimization of
|
|
* nested SQL queries Revisited"
|
|
* [Murlikrishna92] M.Murlikrishna, "Improved Unnesting Algorithms for Join
|
|
* Aggregate SQL queries"
|
|
* 改写的示例可以参看论文和mysqltest测试用例
|
|
*/
|
|
class ObTransformAggrSubquery : public ObTransformRule
|
|
{
|
|
public:
|
|
ObTransformAggrSubquery(ObTransformerCtx *ctx)
|
|
: ObTransformRule(ctx, TransMethod::POST_ORDER, T_UNNEST),
|
|
join_first_happened_(false)
|
|
{}
|
|
virtual ~ObTransformAggrSubquery() {}
|
|
virtual int transform_one_stmt(common::ObIArray<ObParentDMLStmt> &parent_stmts,
|
|
ObDMLStmt *&stmt,
|
|
bool &trans_happened) override;
|
|
protected:
|
|
virtual int check_hint_status(const ObDMLStmt &stmt, bool &need_trans) override;
|
|
virtual int construct_transform_hint(ObDMLStmt &stmt, void *trans_params) override;
|
|
private:
|
|
|
|
enum PullupFlag {
|
|
USE_OUTER_JOIN = 1,
|
|
ADD_CASE_WHEN_EXPR = 2,
|
|
JOIN_FIRST = 4,
|
|
AGGR_FIRST = 8
|
|
};
|
|
|
|
/**
|
|
* @brief The TransformParam struct
|
|
* a candidate ja query for transformation
|
|
*/
|
|
struct TransformParam {
|
|
TransformParam() : ja_query_ref_(NULL), nested_conditions_(), pullup_flag_(0),
|
|
not_null_expr_(NULL), parent_expr_of_query_ref(NULL)
|
|
{}
|
|
|
|
TransformParam(int64_t trans_strategy)
|
|
: ja_query_ref_(NULL), nested_conditions_(), pullup_flag_(trans_strategy),
|
|
not_null_expr_(NULL), parent_expr_of_query_ref(NULL), limit_for_exists_(false),
|
|
limit_value_(0)
|
|
{}
|
|
|
|
ObQueryRefRawExpr *ja_query_ref_; // the ja query ref expr
|
|
ObSEArray<ObRawExpr *, 4> query_refs_;
|
|
ObSEArray<ObRawExpr *, 4> nested_conditions_; // nested conditions in the ja query
|
|
ObSEArray<bool, 4> is_null_prop_; // need case when for a expr
|
|
ObArray<ObRawExpr *> not_null_const_;
|
|
int64_t pullup_flag_; // the methods uesd when pulling up the ja query
|
|
ObRawExpr *not_null_expr_; // not null expr of subquery if correlated join happened
|
|
ObRawExpr *parent_expr_of_query_ref; // parent expr need to be modified for vector subquery comparison
|
|
bool limit_for_exists_;
|
|
int64_t limit_value_;
|
|
ObSEArray<ObPCParamEqualInfo, 1, common::ModulePageAllocator, true> equal_param_info_;
|
|
TO_STRING_KV(K_(ja_query_ref),
|
|
K_(query_refs),
|
|
K_(nested_conditions),
|
|
K_(is_null_prop),
|
|
K_(pullup_flag),
|
|
K_(not_null_expr),
|
|
K_(limit_for_exists),
|
|
K_(limit_value),
|
|
K_(equal_param_info));
|
|
};
|
|
|
|
struct TransStmtInfo {
|
|
TransStmtInfo()
|
|
: qb_name_(), unnest_(nullptr), pullup_strategy_(AGGR_FIRST) {}
|
|
int assign(const TransStmtInfo& other)
|
|
{
|
|
qb_name_ = other.qb_name_;
|
|
unnest_ = other.unnest_;
|
|
pullup_strategy_ = other.pullup_strategy_;
|
|
return common::OB_SUCCESS;
|
|
}
|
|
TO_STRING_KV(K_(qb_name), KPC_(unnest), K_(pullup_strategy));
|
|
common::ObString qb_name_;
|
|
const ObHint *unnest_;
|
|
int64_t pullup_strategy_;
|
|
};
|
|
|
|
int do_transform(ObDMLStmt *&stmt, bool &trans_happened);
|
|
int transform_with_aggregation_first(ObDMLStmt *&stmt,
|
|
bool &trans_happened);
|
|
|
|
int do_aggr_first_transform(ObDMLStmt *&stmt,
|
|
ObRawExpr *expr,
|
|
bool &trans_happened);
|
|
|
|
int gather_transform_params(ObDMLStmt &stmt,
|
|
ObRawExpr *root_expr,
|
|
ObRawExpr *child_expr,
|
|
int64_t pullup_strategy,
|
|
const bool is_select_item_expr,
|
|
ObIArray<TransformParam> ¶ms);
|
|
|
|
int check_aggr_first_validity(ObQueryRefRawExpr &query_ref,
|
|
const bool is_vector_assign,
|
|
ObIArray<ObRawExpr*> &nested_conditions,
|
|
const bool is_select_item_expr,
|
|
bool &is_valid,
|
|
int64_t &limit_value,
|
|
ObIArray<ObPCParamEqualInfo> &equal_param_info);
|
|
|
|
int choose_pullup_method(ObIArray<ObRawExpr *> &conditions,
|
|
TransformParam ¶m);
|
|
|
|
int fill_query_refs(ObDMLStmt *stmt, ObRawExpr *expr, TransformParam ¶m);
|
|
|
|
int transform_child_stmt(ObDMLStmt *stmt,
|
|
ObSelectStmt &subquery,
|
|
TransformParam ¶m);
|
|
|
|
int deduce_query_values(ObDMLStmt &stmt,
|
|
TransformParam ¶m,
|
|
ObIArray<ObRawExpr *> &select_exprs,
|
|
ObIArray<ObRawExpr *> &view_columns,
|
|
ObIArray<ObRawExpr *> &real_values);
|
|
|
|
int transform_upper_stmt(ObDMLStmt &stmt, TransformParam ¶m);
|
|
|
|
int transform_from_list(ObDMLStmt &stmt,
|
|
TableItem *view_table_item,
|
|
const ObIArray<ObRawExpr *> &joined_conds,
|
|
const int64_t pullup_flag);
|
|
|
|
int extract_nullable_exprs(const ObRawExpr *expr,
|
|
ObIArray<const ObRawExpr*> &vars);
|
|
|
|
inline bool use_outer_join(int64_t flag)
|
|
{ return 0 != (flag & USE_OUTER_JOIN); }
|
|
|
|
inline bool add_case_when_expr(int64_t flag)
|
|
{ return 0 != (flag & ADD_CASE_WHEN_EXPR); }
|
|
|
|
inline bool join_first(int64_t flag)
|
|
{ return 0 != (flag & JOIN_FIRST); }
|
|
|
|
inline bool aggr_first(int64_t flag)
|
|
{ return 0 != (flag & AGGR_FIRST); }
|
|
|
|
int transform_with_join_first(ObDMLStmt *&stmt,
|
|
bool &trans_happened);
|
|
|
|
int check_stmt_valid(ObDMLStmt &stmt, bool &is_valid);
|
|
|
|
int check_join_first_validity(ObQueryRefRawExpr &query_ref,
|
|
const bool is_vector_assign,
|
|
const bool in_exists,
|
|
const bool is_vector_cmp,
|
|
ObIArray<ObRawExpr *> &constraints,
|
|
bool &add_limit_constraints,
|
|
int64_t &limit_value,
|
|
bool &is_valid,
|
|
ObIArray<ObPCParamEqualInfo> &equal_param_info);
|
|
|
|
int choose_pullup_method_for_exists(ObQueryRefRawExpr *query_ref,
|
|
int64_t &pullup_flag,
|
|
const bool with_not,
|
|
bool &is_valid);
|
|
|
|
int get_trans_param(ObDMLStmt &stmt,
|
|
TransformParam &trans_param,
|
|
ObRawExpr *&root,
|
|
bool &post_group_by);
|
|
|
|
int get_trans_view(ObDMLStmt &stmt,
|
|
ObSelectStmt *&view_stmt,
|
|
ObRawExpr *root_expr,
|
|
bool post_group_by);
|
|
|
|
int do_join_first_transform(ObSelectStmt &select_stmt,
|
|
TransformParam &trans_param,
|
|
ObRawExpr *root_expr,
|
|
const bool is_first_trans);
|
|
|
|
int get_unique_keys(ObDMLStmt &stmt, ObIArray<ObRawExpr *> &pkeys, const bool is_first_trans);
|
|
|
|
int transform_from_list(ObDMLStmt &stmt,
|
|
ObSelectStmt &subquery,
|
|
const int64_t pullup_flag);
|
|
|
|
int rebuild_conditon(ObSelectStmt &stmt, ObSelectStmt &subquery);
|
|
|
|
int check_single_set_subquery(const ObSelectStmt &subquery,
|
|
bool &is_valid,
|
|
bool &limit_to_aggr,
|
|
int64_t &limit_value,
|
|
bool check_limit = true);
|
|
|
|
int check_subquery_aggr_item(const ObSelectStmt &subquery,
|
|
bool &is_valid);
|
|
|
|
int check_count_const_validity(const ObSelectStmt &subquery,
|
|
ObIArray<ObRawExpr *> &constraints,
|
|
bool &is_valid);
|
|
|
|
int is_count_const_expr(const ObRawExpr *expr, bool &is_count_const);
|
|
|
|
int replace_count_const(ObAggFunRawExpr *agg_expr, ObRawExpr *not_null_expr);
|
|
|
|
int check_can_use_outer_join(TransformParam ¶m, bool &is_valid);
|
|
int check_subquery_select(const ObQueryRefRawExpr &query_ref, bool &is_valid);
|
|
int check_subquery_orderby(const ObQueryRefRawExpr &query_ref, bool &is_valid);
|
|
|
|
int check_subquery_select_for_limit_1(ObSelectStmt &subquery, bool &is_valid, ObIArray<ObPCParamEqualInfo>& equal_param_info);
|
|
|
|
int check_join_first_condition_for_limit_1(ObQueryRefRawExpr &query_ref,
|
|
ObSelectStmt &subquery,
|
|
bool &is_valid);
|
|
|
|
int check_subquery_having(const ObQueryRefRawExpr &query_ref,
|
|
const ObSelectStmt &subquery,
|
|
bool &is_valid);
|
|
|
|
int check_subquery_conditions(ObQueryRefRawExpr &query_ref,
|
|
ObSelectStmt &subquery,
|
|
ObIArray<ObRawExpr *> &nested_conds,
|
|
const bool check_idx,
|
|
bool &is_valid,
|
|
bool &has_equal_correlation);
|
|
|
|
int replace_columns_and_aggrs(ObRawExpr *&expr, ObTransformerCtx *ctx);
|
|
|
|
int modify_aggr_param_expr_for_outer_join(TransformParam& trans_param);
|
|
|
|
int modify_vector_comparison_expr_if_necessary(ObSelectStmt &select_stmt, ObRawExprFactory *expr_factory, ObSEArray<ObRawExpr*, 4> &select_exprs, ObRawExpr *parent_expr_of_query_ref);
|
|
|
|
inline bool is_exists_op(const ObItemType type)
|
|
{ return type == T_OP_EXISTS || type == T_OP_NOT_EXISTS; }
|
|
|
|
bool check_is_filter(const ObDMLStmt &stmt, const ObRawExpr *expr);
|
|
|
|
int get_filters(ObDMLStmt &stmt, ObRawExpr *expr, ObIArray<ObRawExpr *> &filters);
|
|
|
|
int is_valid_group_by(const ObSelectStmt &subquery, bool &is_valid);
|
|
int extract_no_rewrite_select_exprs(ObDMLStmt *&stmt);
|
|
int extract_no_rewrite_expr(ObRawExpr *expr);
|
|
int check_need_spj(ObDMLStmt *stmt, bool &is_valid);
|
|
int transform_with_aggr_first_for_having(ObDMLStmt *&stmt, bool &trans_happened);
|
|
int check_hint_allowed_unnest(ObDMLStmt &stmt,
|
|
ObSelectStmt &subquery,
|
|
const int64_t hint_loc,
|
|
const int64_t pullup_strategy,
|
|
bool &allowed);
|
|
int add_trans_stmt_info(ObSelectStmt &subquery, int64_t flag);
|
|
int check_limit_validity(ObSelectStmt &subquery,
|
|
bool &add_limit_constraints,
|
|
int64_t &limit_value,
|
|
bool &is_valid);
|
|
int add_constraints_for_limit(TransformParam ¶m);
|
|
|
|
int convert_limit_as_aggr(ObSelectStmt *subquery, TransformParam &trans_param);
|
|
ObHint* get_sub_unnest_hint(ObSelectStmt &subquery, int64_t pullup_strategy);
|
|
ObItemType get_unnest_strategy(int64_t pullup_strategy);
|
|
private:
|
|
common::ObSEArray<ObRawExpr *, 8, common::ModulePageAllocator, true> no_rewrite_exprs_;
|
|
common::ObSEArray<TransStmtInfo, 4, common::ModulePageAllocator, true> trans_stmt_infos_;
|
|
bool join_first_happened_;
|
|
};
|
|
|
|
}
|
|
}
|
|
|
|
#endif /* _OB_TRANSFORM_AGGREGATION_SUBQUERY_H_ */
|
|
|