aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/plan/subselect.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/plan/subselect.c')
-rw-r--r--src/backend/optimizer/plan/subselect.c80
1 files changed, 80 insertions, 0 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