any_to_or.diff.txt
text/plain
Filename: any_to_or.diff.txt
Type: text/plain
Part: 2
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 67921a08262..3cddc0a4082 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -50,6 +50,8 @@
#include "port/pg_bitutils.h"
#include "rewrite/rewriteManip.h"
#include "utils/lsyscache.h"
+#include "parser/parse_expr.h"
+#include "utils/array.h"
/* Bitmask flags for pushdown_safety_info.unsafeFlags */
@@ -759,6 +761,179 @@ set_rel_consider_parallel(PlannerInfo *root, RelOptInfo *rel,
rel->consider_parallel = true;
}
+static List*
+research_or_list(Expr *qual, List *or_list, RestrictInfo *sub_rinfo)
+{
+ List *elem_exprs = NIL;
+
+ /* Check: it is an expr of the form 'F(x) oper ConstExpr' */
+ if (!IsA(qual, ScalarArrayOpExpr))
+ {
+ /* Again, it's not the expr we can transform */
+ or_list = lappend(or_list, qual);
+ }
+ else
+ {
+ ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) qual;
+ Expr *rightop = (Expr *) lsecond(saop->args);
+ ListCell *lc1;
+
+ if (sub_rinfo && !op_mergejoinable(((OpExpr *) sub_rinfo->clause)->opno, exprType(get_leftop(sub_rinfo->clause))))
+ {
+ /* And again, filter out non-equality operators */
+ or_list = lappend(or_list, (void *) qual);
+ }
+ else if (rightop && IsA(rightop, Const))
+ {
+ ArrayType *arrval;
+ int16 elemlen;
+ bool elembyval;
+ char elemalign;
+ Datum *elem_values;
+ bool *elem_nulls;
+ int num_elems,
+ i;
+ Const *arr = (Const *) rightop;
+
+ arrval = DatumGetArrayTypeP(arr->constvalue);
+ get_typlenbyvalalign(ARR_ELEMTYPE(arrval),
+ &elemlen, &elembyval, &elemalign);
+ deconstruct_array(arrval,
+ ARR_ELEMTYPE(arrval),
+ elemlen, elembyval, elemalign,
+ &elem_values, &elem_nulls,
+ &num_elems);
+
+ for (i = 0; i < num_elems; i++)
+ {
+ Const *elem_expr;
+
+ /*
+ * A null array element must lead to a null comparison result,
+ * since saop_op is known strict. We can ignore it in the
+ * useOr case, but otherwise it implies self-contradiction.
+ */
+ if (elem_nulls[i])
+ {
+ or_list = lappend(or_list, (void *) qual);
+ elem_exprs = NIL;
+ break;
+ }
+
+ elem_expr = makeConst(ARR_ELEMTYPE(arrval), -1,
+ arr->constcollid, elemlen,
+ elem_values[i], false, elembyval);
+ elem_exprs = lappend(elem_exprs, elem_expr);
+ }
+ }
+ else if (rightop && IsA(rightop, ArrayExpr) && !((ArrayExpr *) rightop)->multidims)
+ {
+ ArrayExpr *arrexpr = (ArrayExpr *)get_rightop(rightop);
+ elem_exprs = arrexpr->elements;
+ }
+ else
+ or_list = lappend(or_list, qual);
+
+ if (elem_exprs)
+ foreach(lc1, elem_exprs)
+ {
+ Expr *elem_clause;
+
+ elem_clause = make_opclause(((ScalarArrayOpExpr*) qual)->opno, BOOLOID, false,
+ (Expr *) linitial(((ScalarArrayOpExpr*)qual)->args), lfirst(lc1),
+ InvalidOid, ((ScalarArrayOpExpr*)qual)->inputcollid);
+ or_list = lappend(or_list, (void*) elem_clause);
+ }
+ }
+ return or_list;
+}
+
+static List *
+get_baserestrictinfo(PlannerInfo *root, List *baserestrictinfo)
+{
+ ListCell *lc;
+ List *modified_rinfo = NIL;
+ bool or_transformation = false;
+
+ if (!enable_or_transformation)
+ return NULL;
+
+ foreach(lc, baserestrictinfo)
+ {
+ RestrictInfo *rinfo_base = lfirst_node(RestrictInfo, lc);
+ RestrictInfo *rinfo;
+ List *or_list = NIL;
+
+ ListCell *lc_eargs,
+ *lc_rargs;
+
+ if (!IsA(rinfo_base->clause, BoolExpr) && !IsA(rinfo_base->clause, ScalarArrayOpExpr))
+ {
+ /* Add a clause without changes */
+ modified_rinfo = lappend(modified_rinfo, rinfo_base);
+ continue;
+ }
+
+ if (IsA(rinfo_base->clause, BoolExpr) && is_orclause(rinfo_base->clause))
+ forboth(lc_eargs, ((BoolExpr *) rinfo_base->clause)->args,
+ lc_rargs, ((BoolExpr *) rinfo_base->orclause)->args)
+ {
+ Expr *orqual = (Expr *) lfirst(lc_eargs);
+ RestrictInfo *sub_rinfo = lfirst_node(RestrictInfo, lc_rargs);
+
+ if (!IsA(orqual, OpExpr) ||
+ !(bms_is_empty(sub_rinfo->left_relids) ^
+ bms_is_empty(sub_rinfo->right_relids)) ||
+ contain_volatile_functions((Node *) orqual))
+ {
+ /* Again, it's not the expr we can transform */
+ or_list = lappend(or_list, (void *) orqual);
+ continue;
+ }
+
+ or_list = research_or_list(orqual, or_list, sub_rinfo);
+ }
+ else if (IsA(rinfo_base->clause, ScalarArrayOpExpr))
+ {
+ Expr *orqual = rinfo_base->clause;
+
+ or_list = research_or_list(orqual, or_list, NULL);
+ }
+ else
+ {
+ or_list = lappend(or_list, (void*)rinfo_base->clause);
+ }
+
+
+ rinfo = make_restrictinfo(root,
+ list_length(or_list) > 1 ? makeBoolExpr(OR_EXPR, or_list, -1):
+ (Expr *) linitial(or_list),
+ rinfo_base->is_pushed_down,
+ rinfo_base->has_clone,
+ rinfo_base->is_clone,
+ rinfo_base->pseudoconstant,
+ rinfo_base->security_level,
+ rinfo_base->required_relids,
+ rinfo_base->incompatible_relids,
+ rinfo_base->outer_relids);
+ rinfo->eval_cost=rinfo_base->eval_cost;
+ rinfo->norm_selec=rinfo_base->norm_selec;
+ rinfo->outer_selec=rinfo_base->outer_selec;
+ rinfo->left_bucketsize=rinfo_base->left_bucketsize;
+ rinfo->right_bucketsize=rinfo_base->right_bucketsize;
+ rinfo->left_mcvfreq=rinfo_base->left_mcvfreq;
+ rinfo->right_mcvfreq=rinfo_base->right_mcvfreq;
+ modified_rinfo = lappend(modified_rinfo, rinfo);
+ or_transformation = true;
+ }
+
+ if(or_transformation)
+ return modified_rinfo;
+
+ return baserestrictinfo;
+}
+
+
/*
* set_plain_rel_pathlist
* Build access paths for a plain relation (no subquery, no inheritance)
@@ -767,6 +942,7 @@ static void
set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
{
Relids required_outer;
+ List *baserestrict_base = copyObject(rel->baserestrictinfo);
/*
* We don't support pushing join clauses into the quals of a seqscan, but
@@ -778,6 +954,8 @@ set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
/* Consider sequential scan */
add_path(rel, create_seqscan_path(root, rel, required_outer, 0));
+ rel->baserestrictinfo = get_baserestrictinfo(root, rel->baserestrictinfo);
+
/* If appropriate, consider parallel sequential scan */
if (rel->consider_parallel && required_outer == NULL)
create_plain_partial_paths(root, rel);