*** pgsql/src/backend/executor/nodeMergejoin.c 2009/06/11 14:48:57 1.97 --- pgsql/src/backend/executor/nodeMergejoin.c 2010/01/05 23:25:44 1.97.2.1 *************** *** 8,14 **** * * * IDENTIFICATION ! * $PostgreSQL: pgsql/src/backend/executor/nodeMergejoin.c,v 1.96 2009/04/02 20:59:10 momjian Exp $ * *------------------------------------------------------------------------- */ --- 8,14 ---- * * * IDENTIFICATION ! * $PostgreSQL: pgsql/src/backend/executor/nodeMergejoin.c,v 1.97 2009/06/11 14:48:57 momjian Exp $ * *------------------------------------------------------------------------- */ *************** MJCompare(MergeJoinState *mergestate) *** 398,405 **** * 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. */ ! if (nulleqnull && result == 0) result = 1; MemoryContextSwitchTo(oldContext); --- 398,410 ---- * 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 (result == 0 && ! (nulleqnull || mergestate->mj_ConstFalseJoin)) result = 1; MemoryContextSwitchTo(oldContext); *************** MJFillInner(MergeJoinState *node) *** 487,492 **** --- 492,523 ---- } + /* + * 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 * *************** ExecMergeJoin(MergeJoinState *node) *** 1025,1033 **** * 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. */ ExecRestrPos(innerPlan); --- 1056,1068 ---- * 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 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); *************** ExecInitMergeJoin(MergeJoin *node, EStat *** 1439,1444 **** --- 1474,1480 ---- mergestate->js.joinqual = (List *) ExecInitExpr((Expr *) node->join.joinqual, (PlanState *) mergestate); + mergestate->mj_ConstFalseJoin = false; /* mergeclauses are handled below */ /* *************** ExecInitMergeJoin(MergeJoin *node, EStat *** 1500,1509 **** ExecGetResultType(outerPlanState(mergestate))); /* ! * Can't handle right or full join with non-nil extra joinclauses. ! * This should have been caught by planner. */ ! if (node->join.joinqual != NIL) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("RIGHT JOIN is only supported with merge-joinable join conditions"))); --- 1536,1546 ---- ExecGetResultType(outerPlanState(mergestate))); /* ! * Can't handle right or full join with non-constant extra ! * joinclauses. This should have been caught by planner. */ ! 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"))); *************** ExecInitMergeJoin(MergeJoin *node, EStat *** 1519,1527 **** ExecGetResultType(innerPlanState(mergestate))); /* ! * Can't handle right or full join with non-nil extra joinclauses. */ ! if (node->join.joinqual != NIL) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("FULL JOIN is only supported with merge-joinable join conditions"))); --- 1556,1566 ---- ExecGetResultType(innerPlanState(mergestate))); /* ! * Can't handle right or full join with non-constant extra ! * joinclauses. This should have been caught by planner. */ ! 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")));