*** pgsql/src/backend/optimizer/plan/createplan.c 2009/06/11 14:48:59 1.260 --- pgsql/src/backend/optimizer/plan/createplan.c 2009/07/17 23:19:59 1.260.2.1 *************** *** 10,16 **** * * * IDENTIFICATION ! * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.259 2009/05/09 22:51:41 tgl Exp $ * *------------------------------------------------------------------------- */ --- 10,16 ---- * * * IDENTIFICATION ! * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.260 2009/06/11 14:48:59 momjian Exp $ * *------------------------------------------------------------------------- */ *************** create_mergejoin_plan(PlannerInfo *root, *** 1620,1629 **** bool *mergenullsfirst; MergeJoin *join_plan; int i; - EquivalenceClass *lastoeclass; - EquivalenceClass *lastieclass; - PathKey *opathkey; - PathKey *ipathkey; ListCell *lc; ListCell *lop; ListCell *lip; --- 1620,1625 ---- *************** create_mergejoin_plan(PlannerInfo *root, *** 1729,1738 **** mergestrategies = (int *) palloc(nClauses * sizeof(int)); mergenullsfirst = (bool *) palloc(nClauses * sizeof(bool)); - lastoeclass = NULL; - lastieclass = NULL; - opathkey = NULL; - ipathkey = NULL; lop = list_head(outerpathkeys); lip = list_head(innerpathkeys); i = 0; --- 1725,1730 ---- *************** create_mergejoin_plan(PlannerInfo *root, *** 1741,1746 **** --- 1733,1743 ---- RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc); EquivalenceClass *oeclass; EquivalenceClass *ieclass; + PathKey *opathkey; + PathKey *ipathkey; + EquivalenceClass *opeclass; + EquivalenceClass *ipeclass; + ListCell *l2; /* fetch outer/inner eclass from mergeclause */ Assert(IsA(rinfo, RestrictInfo)); *************** create_mergejoin_plan(PlannerInfo *root, *** 1757,1784 **** Assert(oeclass != NULL); Assert(ieclass != NULL); ! /* should match current or next pathkeys */ ! /* we check this carefully for debugging reasons */ ! if (oeclass != lastoeclass) { - if (!lop) - elog(ERROR, "too few pathkeys for mergeclauses"); opathkey = (PathKey *) lfirst(lop); ! lop = lnext(lop); ! lastoeclass = opathkey->pk_eclass; ! if (oeclass != lastoeclass) ! elog(ERROR, "outer pathkeys do not match mergeclause"); } ! if (ieclass != lastieclass) { - if (!lip) - elog(ERROR, "too few pathkeys for mergeclauses"); ipathkey = (PathKey *) lfirst(lip); ! lip = lnext(lip); ! lastieclass = ipathkey->pk_eclass; ! if (ieclass != lastieclass) ! elog(ERROR, "inner pathkeys do not match mergeclause"); } /* pathkeys should match each other too (more debugging) */ if (opathkey->pk_opfamily != ipathkey->pk_opfamily || opathkey->pk_strategy != ipathkey->pk_strategy || --- 1754,1853 ---- Assert(oeclass != NULL); Assert(ieclass != NULL); ! /* ! * For debugging purposes, we check that the eclasses match the ! * paths' pathkeys. In typical cases the merge clauses are one-to-one ! * with the pathkeys, but when dealing with partially redundant query ! * conditions, we might have clauses that re-reference earlier path ! * keys. The case that we need to reject is where a pathkey is ! * entirely skipped over. ! * ! * lop and lip reference the first as-yet-unused pathkey elements; ! * it's okay to match them, or any element before them. If they're ! * NULL then we have found all pathkey elements to be used. ! */ ! if (lop) { opathkey = (PathKey *) lfirst(lop); ! opeclass = opathkey->pk_eclass; ! if (oeclass == opeclass) ! { ! /* fast path for typical case */ ! lop = lnext(lop); ! } ! else ! { ! /* redundant clauses ... must match something before lop */ ! foreach(l2, outerpathkeys) ! { ! if (l2 == lop) ! break; ! opathkey = (PathKey *) lfirst(l2); ! opeclass = opathkey->pk_eclass; ! if (oeclass == opeclass) ! break; ! } ! if (oeclass != opeclass) ! elog(ERROR, "outer pathkeys do not match mergeclauses"); ! } } ! else ! { ! /* redundant clauses ... must match some already-used pathkey */ ! opathkey = NULL; ! opeclass = NULL; ! foreach(l2, outerpathkeys) ! { ! opathkey = (PathKey *) lfirst(l2); ! opeclass = opathkey->pk_eclass; ! if (oeclass == opeclass) ! break; ! } ! if (l2 == NULL) ! elog(ERROR, "outer pathkeys do not match mergeclauses"); ! } ! ! if (lip) { ipathkey = (PathKey *) lfirst(lip); ! ipeclass = ipathkey->pk_eclass; ! if (ieclass == ipeclass) ! { ! /* fast path for typical case */ ! lip = lnext(lip); ! } ! else ! { ! /* redundant clauses ... must match something before lip */ ! foreach(l2, innerpathkeys) ! { ! if (l2 == lip) ! break; ! ipathkey = (PathKey *) lfirst(l2); ! ipeclass = ipathkey->pk_eclass; ! if (ieclass == ipeclass) ! break; ! } ! if (ieclass != ipeclass) ! elog(ERROR, "inner pathkeys do not match mergeclauses"); ! } ! } ! else ! { ! /* redundant clauses ... must match some already-used pathkey */ ! ipathkey = NULL; ! ipeclass = NULL; ! foreach(l2, innerpathkeys) ! { ! ipathkey = (PathKey *) lfirst(l2); ! ipeclass = ipathkey->pk_eclass; ! if (ieclass == ipeclass) ! break; ! } ! if (l2 == NULL) ! elog(ERROR, "inner pathkeys do not match mergeclauses"); } + /* pathkeys should match each other too (more debugging) */ if (opathkey->pk_opfamily != ipathkey->pk_opfamily || opathkey->pk_strategy != ipathkey->pk_strategy || *************** create_mergejoin_plan(PlannerInfo *root, *** 1792,1797 **** --- 1861,1871 ---- i++; } + /* + * Note: it is not an error if we have additional pathkey elements + * (i.e., lop or lip isn't NULL here). The input paths might be + * better-sorted than we need for the current mergejoin. + */ /* * Now we can build the mergejoin node.