diff options
Diffstat (limited to 'src/backend/optimizer/plan/subselect.c')
-rw-r--r-- | src/backend/optimizer/plan/subselect.c | 61 |
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; } |