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.c61
1 files changed, 43 insertions, 18 deletions
diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c
index 9f38f072498..bc67d34fd79 100644
--- a/src/backend/optimizer/plan/subselect.c
+++ b/src/backend/optimizer/plan/subselect.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.129 2008/01/17 20:35:27 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.129.2.1 2008/04/21 20:54:24 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -725,10 +725,13 @@ convert_IN_to_join(PlannerInfo *root, SubLink *sublink)
Query *parse = root->parse;
Query *subselect = (Query *) sublink->subselect;
List *in_operators;
+ List *left_exprs;
+ List *right_exprs;
Relids left_varnos;
int rtindex;
RangeTblEntry *rte;
RangeTblRef *rtr;
+ List *subquery_vars;
InClauseInfo *ininfo;
Node *result;
@@ -744,28 +747,37 @@ convert_IN_to_join(PlannerInfo *root, SubLink *sublink)
return NULL;
if (sublink->testexpr && IsA(sublink->testexpr, OpExpr))
{
- Oid opno = ((OpExpr *) sublink->testexpr)->opno;
+ OpExpr *op = (OpExpr *) sublink->testexpr;
+ Oid opno = op->opno;
List *opfamilies;
List *opstrats;
+ if (list_length(op->args) != 2)
+ return NULL; /* not binary operator? */
get_op_btree_interpretation(opno, &opfamilies, &opstrats);
if (!list_member_int(opstrats, ROWCOMPARE_EQ))
return NULL;
in_operators = list_make1_oid(opno);
+ left_exprs = list_make1(linitial(op->args));
+ right_exprs = list_make1(lsecond(op->args));
}
else if (and_clause(sublink->testexpr))
{
ListCell *lc;
- /* OK, but we need to extract the per-column operator OIDs */
- in_operators = NIL;
+ /* OK, but we need to extract the per-column info */
+ in_operators = left_exprs = right_exprs = NIL;
foreach(lc, ((BoolExpr *) sublink->testexpr)->args)
{
OpExpr *op = (OpExpr *) lfirst(lc);
if (!IsA(op, OpExpr)) /* probably shouldn't happen */
return NULL;
+ if (list_length(op->args) != 2)
+ return NULL; /* not binary operator? */
in_operators = lappend_oid(in_operators, op->opno);
+ left_exprs = lappend(left_exprs, linitial(op->args));
+ right_exprs = lappend(right_exprs, lsecond(op->args));
}
}
else
@@ -782,10 +794,13 @@ convert_IN_to_join(PlannerInfo *root, SubLink *sublink)
* The left-hand expressions must contain some Vars of the current query,
* else it's not gonna be a join.
*/
- left_varnos = pull_varnos(sublink->testexpr);
+ left_varnos = pull_varnos((Node *) left_exprs);
if (bms_is_empty(left_varnos))
return NULL;
+ /* ... and the right-hand expressions better not contain Vars at all */
+ Assert(!contain_var_clause((Node *) right_exprs));
+
/*
* The combining operators and left-hand expressions mustn't be volatile.
*/
@@ -811,6 +826,20 @@ convert_IN_to_join(PlannerInfo *root, SubLink *sublink)
parse->jointree->fromlist = lappend(parse->jointree->fromlist, rtr);
/*
+ * Build a list of Vars representing the subselect outputs.
+ */
+ subquery_vars = generate_subquery_vars(root,
+ subselect->targetList,
+ rtindex);
+
+ /*
+ * Build the result qual expression, replacing Params with these Vars.
+ */
+ result = convert_testexpr(root,
+ sublink->testexpr,
+ subquery_vars);
+
+ /*
* Now build the InClauseInfo node.
*/
ininfo = makeNode(InClauseInfo);
@@ -819,24 +848,20 @@ convert_IN_to_join(PlannerInfo *root, SubLink *sublink)
ininfo->in_operators = in_operators;
/*
- * ininfo->sub_targetlist is filled with a list of Vars representing the
- * subselect outputs.
+ * ininfo->sub_targetlist must be filled with a list of expressions that
+ * would need to be unique-ified if we try to implement the IN using a
+ * regular join to unique-ified subquery output. This is most easily done
+ * by applying convert_testexpr to just the RHS inputs of the testexpr
+ * operators. That handles cases like type coercions of the subquery
+ * outputs, clauses dropped due to const-simplification, etc.
*/
- ininfo->sub_targetlist = generate_subquery_vars(root,
- subselect->targetList,
- rtindex);
- Assert(list_length(in_operators) == list_length(ininfo->sub_targetlist));
+ ininfo->sub_targetlist = (List *) convert_testexpr(root,
+ (Node *) right_exprs,
+ subquery_vars);
/* Add the completed node to the query's list */
root->in_info_list = lappend(root->in_info_list, ininfo);
- /*
- * Build the result qual expression.
- */
- result = convert_testexpr(root,
- sublink->testexpr,
- ininfo->sub_targetlist);
-
return result;
}