aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer')
-rw-r--r--src/backend/optimizer/plan/subselect.c80
-rw-r--r--src/backend/optimizer/prep/prepjointree.c12
-rw-r--r--src/backend/optimizer/util/clauses.c14
3 files changed, 101 insertions, 5 deletions
diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c
index 8230cbea3c3..e7cb3fede66 100644
--- a/src/backend/optimizer/plan/subselect.c
+++ b/src/backend/optimizer/plan/subselect.c
@@ -1214,6 +1214,86 @@ inline_cte_walker(Node *node, inline_cte_walker_context *context)
return expression_tree_walker(node, inline_cte_walker, context);
}
+/*
+ * Attempt to transform 'testexpr' over the VALUES subquery into
+ * a ScalarArrayOpExpr. We currently support the transformation only when
+ * it ends up with a constant array. Otherwise, the evaluation of non-hashed
+ * SAOP might be slower than the corresponding Hash Join with VALUES.
+ *
+ * Return transformed ScalarArrayOpExpr or NULL if transformation isn't
+ * allowed.
+ */
+ScalarArrayOpExpr *
+convert_VALUES_to_ANY(PlannerInfo *root, Node *testexpr, Query *values)
+{
+ RangeTblEntry *rte;
+ Node *leftop;
+ Node *rightop;
+ Oid opno;
+ ListCell *lc;
+ Oid inputcollid;
+ List *exprs = NIL;
+
+ /*
+ * Check we have a binary operator over a single-column subquery with no
+ * joins and no LIMIT/OFFSET/ORDER BY clauses.
+ */
+ if (!IsA(testexpr, OpExpr) ||
+ list_length(((OpExpr *) testexpr)->args) != 2 ||
+ list_length(values->targetList) > 1 ||
+ values->limitCount != NULL ||
+ values->limitOffset != NULL ||
+ values->sortClause != NIL ||
+ list_length(values->rtable) != 1)
+ return NULL;
+
+ rte = linitial_node(RangeTblEntry, values->rtable);
+ leftop = linitial(((OpExpr *) testexpr)->args);
+ rightop = lsecond(((OpExpr *) testexpr)->args);
+ opno = ((OpExpr *) testexpr)->opno;
+ inputcollid = ((OpExpr *) testexpr)->inputcollid;
+
+ /*
+ * Also, check that only RTE corresponds to VALUES; the list of values has
+ * at least two items and no volatile functions.
+ */
+ if (rte->rtekind != RTE_VALUES ||
+ list_length(rte->values_lists) < 2 ||
+ contain_volatile_functions((Node *) rte->values_lists))
+ return NULL;
+
+ foreach(lc, rte->values_lists)
+ {
+ List *elem = lfirst(lc);
+ Node *value = linitial(elem);
+
+ /*
+ * Prepare an evaluation of the right side of the operator with
+ * substitution of the given value.
+ */
+ value = convert_testexpr(root, rightop, list_make1(value));
+
+ /*
+ * Try to evaluate constant expressions. We could get Const as a
+ * result.
+ */
+ value = eval_const_expressions(root, value);
+
+ /*
+ * As we only support constant output arrays, all the items must also
+ * be constant.
+ */
+ if (!IsA(value, Const))
+ return NULL;
+
+ exprs = lappend(exprs, value);
+ }
+
+ /* Finally, build ScalarArrayOpExpr at the top of the 'exprs' list. */
+ return make_SAOP_expr(opno, leftop, exprType(rightop),
+ linitial_oid(rte->colcollations), inputcollid,
+ exprs, false);
+}
/*
* convert_ANY_sublink_to_join: try to convert an ANY SubLink to a join
diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c
index d131a5bbc59..87dc6f56b57 100644
--- a/src/backend/optimizer/prep/prepjointree.c
+++ b/src/backend/optimizer/prep/prepjointree.c
@@ -664,6 +664,18 @@ pull_up_sublinks_qual_recurse(PlannerInfo *root, Node *node,
/* Is it a convertible ANY or EXISTS clause? */
if (sublink->subLinkType == ANY_SUBLINK)
{
+ ScalarArrayOpExpr *saop;
+
+ if ((saop = convert_VALUES_to_ANY(root,
+ sublink->testexpr,
+ (Query *) sublink->subselect)) != NULL)
+
+ /*
+ * The VALUES sequence was simplified. Nothing more to do
+ * here.
+ */
+ return (Node *) saop;
+
if ((j = convert_ANY_sublink_to_join(root, sublink,
available_rels1)) != NULL)
{
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 9965df1b965..26a3e050086 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -5484,26 +5484,30 @@ make_SAOP_expr(Oid oper, Node *leftexpr, Oid coltype, Oid arraycollid,
bool typbyval;
char typalign;
Datum *elems;
+ bool *nulls;
int i = 0;
ArrayType *arrayConst;
+ int dims[1] = {list_length(exprs)};
+ int lbs[1] = {1};
get_typlenbyvalalign(coltype, &typlen, &typbyval, &typalign);
elems = (Datum *) palloc(sizeof(Datum) * list_length(exprs));
+ nulls = (bool *) palloc(sizeof(bool) * list_length(exprs));
foreach_node(Const, value, exprs)
{
- Assert(!value->constisnull);
-
- elems[i++] = value->constvalue;
+ elems[i] = value->constvalue;
+ nulls[i++] = value->constisnull;
}
- arrayConst = construct_array(elems, i, coltype,
- typlen, typbyval, typalign);
+ arrayConst = construct_md_array(elems, nulls, 1, dims, lbs,
+ coltype, typlen, typbyval, typalign);
arrayNode = (Node *) makeConst(arraytype, -1, arraycollid,
-1, PointerGetDatum(arrayConst),
false, false);
pfree(elems);
+ pfree(nulls);
list_free(exprs);
}