diff options
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/executor/nodeMergejoin.c | 59 | ||||
-rw-r--r-- | src/backend/optimizer/path/joinpath.c | 12 |
2 files changed, 59 insertions, 12 deletions
diff --git a/src/backend/executor/nodeMergejoin.c b/src/backend/executor/nodeMergejoin.c index 362181c26f4..0c611015134 100644 --- a/src/backend/executor/nodeMergejoin.c +++ b/src/backend/executor/nodeMergejoin.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeMergejoin.c,v 1.99 2010/01/02 16:57:44 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeMergejoin.c,v 1.100 2010/01/05 23:25:36 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -398,8 +398,13 @@ MJCompare(MergeJoinState *mergestate) * want to report that the tuples are equal. Instead, if result is still * 0, change it to +1. This will result in advancing the inner side of * the join. + * + * Likewise, if there was a constant-false joinqual, do not report + * equality. We have to check this as part of the mergequals, else the + * rescan logic will do the wrong thing. */ - if (nulleqnull && result == 0) + if (result == 0 && + (nulleqnull || mergestate->mj_ConstFalseJoin)) result = 1; MemoryContextSwitchTo(oldContext); @@ -487,6 +492,32 @@ MJFillInner(MergeJoinState *node) } +/* + * Check that a qual condition is constant true or constant false. + * If it is constant false (or null), set *is_const_false to TRUE. + * + * Constant true would normally be represented by a NIL list, but we allow an + * actual bool Const as well. We do expect that the planner will have thrown + * away any non-constant terms that have been ANDed with a constant false. + */ +static bool +check_constant_qual(List *qual, bool *is_const_false) +{ + ListCell *lc; + + foreach(lc, qual) + { + Const *con = (Const *) lfirst(lc); + + if (!con || !IsA(con, Const)) + return false; + if (con->constisnull || !DatumGetBool(con->constvalue)) + *is_const_false = true; + } + return true; +} + + /* ---------------------------------------------------------------- * ExecMergeTupleDump * @@ -1025,9 +1056,13 @@ ExecMergeJoin(MergeJoinState *node) * state for the rescanned inner tuples. We know all of * them will match this new outer tuple and therefore * won't be emitted as fill tuples. This works *only* - * because we require the extra joinquals to be nil when - * doing a right or full join --- otherwise some of the - * rescanned tuples might fail the extra joinquals. + * because we require the extra joinquals to be constant + * when doing a right or full join --- otherwise some of + * the rescanned tuples might fail the extra joinquals. + * This obviously won't happen for a constant-true extra + * joinqual, while the constant-false case is handled by + * forcing the merge clause to never match, so we never + * get here. */ ExecRestrPos(innerPlan); @@ -1439,6 +1474,7 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags) mergestate->js.joinqual = (List *) ExecInitExpr((Expr *) node->join.joinqual, (PlanState *) mergestate); + mergestate->mj_ConstFalseJoin = false; /* mergeclauses are handled below */ /* @@ -1498,10 +1534,11 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags) ExecGetResultType(outerPlanState(mergestate))); /* - * Can't handle right or full join with non-nil extra joinclauses. - * This should have been caught by planner. + * Can't handle right or full join with non-constant extra + * joinclauses. This should have been caught by planner. */ - if (node->join.joinqual != NIL) + if (!check_constant_qual(node->join.joinqual, + &mergestate->mj_ConstFalseJoin)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("RIGHT JOIN is only supported with merge-joinable join conditions"))); @@ -1517,9 +1554,11 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags) ExecGetResultType(innerPlanState(mergestate))); /* - * Can't handle right or full join with non-nil extra joinclauses. + * Can't handle right or full join with non-constant extra + * joinclauses. This should have been caught by planner. */ - if (node->join.joinqual != NIL) + if (!check_constant_qual(node->join.joinqual, + &mergestate->mj_ConstFalseJoin)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("FULL JOIN is only supported with merge-joinable join conditions"))); diff --git a/src/backend/optimizer/path/joinpath.c b/src/backend/optimizer/path/joinpath.c index f69ffbed7a8..2e208cb6210 100644 --- a/src/backend/optimizer/path/joinpath.c +++ b/src/backend/optimizer/path/joinpath.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/path/joinpath.c,v 1.128 2010/01/02 16:57:46 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/path/joinpath.c,v 1.129 2010/01/05 23:25:36 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1184,10 +1184,18 @@ select_mergejoin_clauses(PlannerInfo *root, if (isouterjoin && restrictinfo->is_pushed_down) continue; + /* Check that clause is a mergeable operator clause */ if (!restrictinfo->can_join || restrictinfo->mergeopfamilies == NIL) { - have_nonmergeable_joinclause = true; + /* + * The executor can handle extra joinquals that are constants, + * but not anything else, when doing right/full merge join. (The + * reason to support constants is so we can do FULL JOIN ON + * FALSE.) + */ + if (!restrictinfo->clause || !IsA(restrictinfo->clause, Const)) + have_nonmergeable_joinclause = true; continue; /* not mergejoinable */ } |