From f87f52db53b7caf56d0bb04138cb0357d2db2223 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=80=E6=8C=83?= Date: Tue, 1 Feb 2022 20:58:07 +0800 Subject: [PATCH v1 5/6] Support ScalarArrayOpExpr and perudoconstant on ef_filter. --- src/backend/optimizer/path/equivclass.c | 110 +++++++++++++++++------- src/backend/optimizer/plan/initsplan.c | 59 ++++++++----- src/include/nodes/pathnodes.h | 3 +- 3 files changed, 120 insertions(+), 52 deletions(-) diff --git a/src/backend/optimizer/path/equivclass.c b/src/backend/optimizer/path/equivclass.c index 9ce0249b10d..4271bacb070 100644 --- a/src/backend/optimizer/path/equivclass.c +++ b/src/backend/optimizer/path/equivclass.c @@ -1386,23 +1386,55 @@ generate_base_implied_equalities_no_const(PlannerInfo *root, rightexpr = (Expr *) ef->ef_const; } - opno = get_opfamily_member(family, - exprType((Node *) leftexpr), - exprType((Node *) rightexpr), - strategy); + if (ef->ef_expr_type == T_OpExpr) + { + opno = get_opfamily_member(family, + exprType((Node *) leftexpr), + exprType((Node *) rightexpr), + strategy); - if (opno == InvalidOid) - continue; + if (opno == InvalidOid) + continue; - rinfo = process_implied_equality(root, opno, - ec->ec_collation, - leftexpr, - rightexpr, - bms_copy(ec->ec_relids), - bms_copy(cur_em->em_nullable_relids), - ec->ec_min_security, - ec->ec_below_outer_join, - false); + rinfo = process_implied_equality(root, opno, + ec->ec_collation, + leftexpr, + rightexpr, + bms_copy(ec->ec_relids), + bms_copy(cur_em->em_nullable_relids), + ec->ec_min_security, + ec->ec_below_outer_join, + false); + } + else + { + ScalarArrayOpExpr *arr_opexpr; + Relids relids; + + Assert(ef->ef_expr_type == T_ScalarArrayOpExpr); + arr_opexpr = makeNode(ScalarArrayOpExpr); + arr_opexpr->opno = ef->ef_opno; + arr_opexpr->opfuncid = get_opcode(ef->ef_opno); + arr_opexpr->useOr = true; /* See is_simple_filter_qual */ + arr_opexpr->args = list_make2(leftexpr, ef->ef_const); + arr_opexpr->inputcollid = ec->ec_collation; + + relids = pull_varnos(root, (Node *)arr_opexpr); + + rinfo = make_restrictinfo(root, + (Expr *) arr_opexpr, + true, + false, + false, /* perudoconstant */ + ec->ec_min_security, + relids, + NULL, + bms_copy(cur_em->em_nullable_relids)); + + // check_mergejoinable(rinfo); + + distribute_restrictinfo_to_rels(root, rinfo); + } rinfo->derived = ec; } @@ -2009,29 +2041,48 @@ distribute_filter_quals_to_eclass(PlannerInfo *root, List *quallist) */ foreach(l, quallist) { - OpExpr *opexpr = (OpExpr *) lfirst(l); - Expr *leftexpr = (Expr *) linitial(opexpr->args); - Expr *rightexpr = (Expr *) lsecond(opexpr->args); - Const *constexpr; - Expr *varexpr; + Expr *expr = lfirst(l); + + List *args; + Node *leftexpr; + Node *rightexpr; + Node *constexpr; + Node *varexpr; + Oid opno; + Relids exprrels; int relid; bool const_isleft; ListCell *l2; - /* - * Determine if the the OpExpr is in the form "expr op const" or - * "const op expr". - */ - if (IsA(leftexpr, Const)) + if (nodeTag(expr) == T_OpExpr) + { + OpExpr *opexpr = (OpExpr *) lfirst(l); + args = opexpr->args; + opno = opexpr->opno; + } + else if (nodeTag(expr) == T_ScalarArrayOpExpr) + { + ScalarArrayOpExpr *arr_expr = (ScalarArrayOpExpr *) lfirst(l); + args = arr_expr->args; + opno = arr_expr->opno; + } + else + { + Assert(false); + } + + leftexpr = linitial(args); + rightexpr = lsecond(args); + if (is_pseudo_constant_clause(leftexpr)) { - constexpr = (Const *) leftexpr; + constexpr = leftexpr; varexpr = rightexpr; const_isleft = true; } else { - constexpr = (Const *) rightexpr; + constexpr = rightexpr; varexpr = leftexpr; const_isleft = false; } @@ -2073,10 +2124,11 @@ distribute_filter_quals_to_eclass(PlannerInfo *root, List *quallist) { EquivalenceFilter *efilter; efilter = makeNode(EquivalenceFilter); - efilter->ef_const = (Const *) copyObject(constexpr); + efilter->ef_const = (Node *)copyObject(constexpr); efilter->ef_const_is_left = const_isleft; - efilter->ef_opno = opexpr->opno; + efilter->ef_opno = opno; efilter->ef_source_rel = relid; + efilter->ef_expr_type = nodeTag(expr); ec->ec_filters = lappend(ec->ec_filters, efilter); break; /* Onto the next eclass */ diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c index b219bee8567..a0f12198b8c 100644 --- a/src/backend/optimizer/plan/initsplan.c +++ b/src/backend/optimizer/plan/initsplan.c @@ -656,33 +656,42 @@ create_lateral_join_info(PlannerInfo *root) * Analyzes an OpExpr to determine if it may be useful as an * EquivalenceFilter. Returns true if the OpExpr may be of some use, or * false if it should not be used. + * */ static bool -is_simple_filter_qual(PlannerInfo *root, OpExpr *expr) +is_simple_filter_qual(PlannerInfo *root, Expr *expr) { - Expr *leftexpr; - Expr *rightexpr; - - if (!IsA(expr, OpExpr)) - return false; - - if (list_length(expr->args) != 2) - return false; - - leftexpr = (Expr *) linitial(expr->args); - rightexpr = (Expr *) lsecond(expr->args); - - /* XXX should we restrict these to simple Var op Const expressions? */ - if (IsA(leftexpr, Const)) + Node *leftexpr; + Node *rightexpr; + List *args = NIL; + + if (IsA(expr, OpExpr)) + args = castNode(OpExpr, expr)->args; + else if (IsA(expr, ScalarArrayOpExpr)) + { + ScalarArrayOpExpr *arr_opexpr = castNode(ScalarArrayOpExpr, expr); + if (!arr_opexpr->useOr) + /* Just support IN for now */ + return false; + args = arr_opexpr->args; + } + + if (list_length(args) != 2) + return false; + + leftexpr = linitial(args); + rightexpr = lsecond(args); + + if (is_pseudo_constant_clause(leftexpr)) { - if (bms_membership(pull_varnos(root, (Node *) rightexpr)) == BMS_SINGLETON && - !contain_volatile_functions((Node *) rightexpr)) + if (bms_membership(pull_varnos(root, rightexpr)) == BMS_SINGLETON && + !contain_volatile_functions(rightexpr)) return true; } - else if (IsA(rightexpr, Const)) + else if (is_pseudo_constant_clause(rightexpr)) { - if (bms_membership(pull_varnos(root, (Node *) leftexpr)) == BMS_SINGLETON && - !contain_volatile_functions((Node *) leftexpr)) + if (bms_membership(pull_varnos(root, leftexpr)) == BMS_SINGLETON && + !contain_volatile_functions(leftexpr)) return true; } @@ -739,7 +748,13 @@ deconstruct_jointree(PlannerInfo *root) result = deconstruct_recurse(root, (Node *) root->parse->jointree, false, &qualscope, &inner_join_rels, - &postponed_qual_list, &filter_qual_list); + &postponed_qual_list, + /* + * geqo option here is just used for testing + * during review stage, set enable_geqo to + * false to disable this feature. + */ + enable_geqo ? &filter_qual_list : NULL); /* Shouldn't be any leftover quals */ Assert(postponed_qual_list == NIL); @@ -2024,7 +2039,7 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause, distribute_restrictinfo_to_rels(root, restrictinfo); /* Check if the qual looks useful to harvest as an EquivalenceFilter */ - if (filter_qual_list != NULL && is_simple_filter_qual(root, (OpExpr *) clause)) + if (filter_qual_list != NULL && is_simple_filter_qual(root, (Expr *) clause)) *filter_qual_list = lappend(*filter_qual_list, clause); } diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h index dbe1775f96d..c1ef0066188 100644 --- a/src/include/nodes/pathnodes.h +++ b/src/include/nodes/pathnodes.h @@ -1035,10 +1035,11 @@ typedef struct EquivalenceFilter { NodeTag type; - Const *ef_const; /* the constant expression to filter on */ + Node *ef_const; /* pseudo const */ Oid ef_opno; /* Operator Oid of filter operator */ bool ef_const_is_left; /* Is the Const on the left of the OpExrp? */ Index ef_source_rel; /* relid of originating relation. */ + NodeTag ef_expr_type; } EquivalenceFilter; /* -- 2.21.0