1010 *
1111 *
1212 * IDENTIFICATION
13- * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.260 2009/06/11 14:48:59 momjian Exp $
13+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.261 2009/07/17 23:19:34 tgl Exp $
1414 *
1515 *-------------------------------------------------------------------------
1616 */
@@ -1620,10 +1620,6 @@ create_mergejoin_plan(PlannerInfo *root,
16201620 bool * mergenullsfirst ;
16211621 MergeJoin * join_plan ;
16221622 int i ;
1623- EquivalenceClass * lastoeclass ;
1624- EquivalenceClass * lastieclass ;
1625- PathKey * opathkey ;
1626- PathKey * ipathkey ;
16271623 ListCell * lc ;
16281624 ListCell * lop ;
16291625 ListCell * lip ;
@@ -1729,10 +1725,6 @@ create_mergejoin_plan(PlannerInfo *root,
17291725 mergestrategies = (int * ) palloc (nClauses * sizeof (int ));
17301726 mergenullsfirst = (bool * ) palloc (nClauses * sizeof (bool ));
17311727
1732- lastoeclass = NULL ;
1733- lastieclass = NULL ;
1734- opathkey = NULL ;
1735- ipathkey = NULL ;
17361728 lop = list_head (outerpathkeys );
17371729 lip = list_head (innerpathkeys );
17381730 i = 0 ;
@@ -1741,6 +1733,11 @@ create_mergejoin_plan(PlannerInfo *root,
17411733 RestrictInfo * rinfo = (RestrictInfo * ) lfirst (lc );
17421734 EquivalenceClass * oeclass ;
17431735 EquivalenceClass * ieclass ;
1736+ PathKey * opathkey ;
1737+ PathKey * ipathkey ;
1738+ EquivalenceClass * opeclass ;
1739+ EquivalenceClass * ipeclass ;
1740+ ListCell * l2 ;
17441741
17451742 /* fetch outer/inner eclass from mergeclause */
17461743 Assert (IsA (rinfo , RestrictInfo ));
@@ -1757,28 +1754,100 @@ create_mergejoin_plan(PlannerInfo *root,
17571754 Assert (oeclass != NULL );
17581755 Assert (ieclass != NULL );
17591756
1760- /* should match current or next pathkeys */
1761- /* we check this carefully for debugging reasons */
1762- if (oeclass != lastoeclass )
1757+ /*
1758+ * For debugging purposes, we check that the eclasses match the
1759+ * paths' pathkeys. In typical cases the merge clauses are one-to-one
1760+ * with the pathkeys, but when dealing with partially redundant query
1761+ * conditions, we might have clauses that re-reference earlier path
1762+ * keys. The case that we need to reject is where a pathkey is
1763+ * entirely skipped over.
1764+ *
1765+ * lop and lip reference the first as-yet-unused pathkey elements;
1766+ * it's okay to match them, or any element before them. If they're
1767+ * NULL then we have found all pathkey elements to be used.
1768+ */
1769+ if (lop )
17631770 {
1764- if (!lop )
1765- elog (ERROR , "too few pathkeys for mergeclauses" );
17661771 opathkey = (PathKey * ) lfirst (lop );
1767- lop = lnext (lop );
1768- lastoeclass = opathkey -> pk_eclass ;
1769- if (oeclass != lastoeclass )
1770- elog (ERROR , "outer pathkeys do not match mergeclause" );
1772+ opeclass = opathkey -> pk_eclass ;
1773+ if (oeclass == opeclass )
1774+ {
1775+ /* fast path for typical case */
1776+ lop = lnext (lop );
1777+ }
1778+ else
1779+ {
1780+ /* redundant clauses ... must match something before lop */
1781+ foreach (l2 , outerpathkeys )
1782+ {
1783+ if (l2 == lop )
1784+ break ;
1785+ opathkey = (PathKey * ) lfirst (l2 );
1786+ opeclass = opathkey -> pk_eclass ;
1787+ if (oeclass == opeclass )
1788+ break ;
1789+ }
1790+ if (oeclass != opeclass )
1791+ elog (ERROR , "outer pathkeys do not match mergeclauses" );
1792+ }
17711793 }
1772- if (ieclass != lastieclass )
1794+ else
1795+ {
1796+ /* redundant clauses ... must match some already-used pathkey */
1797+ opathkey = NULL ;
1798+ opeclass = NULL ;
1799+ foreach (l2 , outerpathkeys )
1800+ {
1801+ opathkey = (PathKey * ) lfirst (l2 );
1802+ opeclass = opathkey -> pk_eclass ;
1803+ if (oeclass == opeclass )
1804+ break ;
1805+ }
1806+ if (l2 == NULL )
1807+ elog (ERROR , "outer pathkeys do not match mergeclauses" );
1808+ }
1809+
1810+ if (lip )
17731811 {
1774- if (!lip )
1775- elog (ERROR , "too few pathkeys for mergeclauses" );
17761812 ipathkey = (PathKey * ) lfirst (lip );
1777- lip = lnext (lip );
1778- lastieclass = ipathkey -> pk_eclass ;
1779- if (ieclass != lastieclass )
1780- elog (ERROR , "inner pathkeys do not match mergeclause" );
1813+ ipeclass = ipathkey -> pk_eclass ;
1814+ if (ieclass == ipeclass )
1815+ {
1816+ /* fast path for typical case */
1817+ lip = lnext (lip );
1818+ }
1819+ else
1820+ {
1821+ /* redundant clauses ... must match something before lip */
1822+ foreach (l2 , innerpathkeys )
1823+ {
1824+ if (l2 == lip )
1825+ break ;
1826+ ipathkey = (PathKey * ) lfirst (l2 );
1827+ ipeclass = ipathkey -> pk_eclass ;
1828+ if (ieclass == ipeclass )
1829+ break ;
1830+ }
1831+ if (ieclass != ipeclass )
1832+ elog (ERROR , "inner pathkeys do not match mergeclauses" );
1833+ }
1834+ }
1835+ else
1836+ {
1837+ /* redundant clauses ... must match some already-used pathkey */
1838+ ipathkey = NULL ;
1839+ ipeclass = NULL ;
1840+ foreach (l2 , innerpathkeys )
1841+ {
1842+ ipathkey = (PathKey * ) lfirst (l2 );
1843+ ipeclass = ipathkey -> pk_eclass ;
1844+ if (ieclass == ipeclass )
1845+ break ;
1846+ }
1847+ if (l2 == NULL )
1848+ elog (ERROR , "inner pathkeys do not match mergeclauses" );
17811849 }
1850+
17821851 /* pathkeys should match each other too (more debugging) */
17831852 if (opathkey -> pk_opfamily != ipathkey -> pk_opfamily ||
17841853 opathkey -> pk_strategy != ipathkey -> pk_strategy ||
@@ -1792,6 +1861,11 @@ create_mergejoin_plan(PlannerInfo *root,
17921861 i ++ ;
17931862 }
17941863
1864+ /*
1865+ * Note: it is not an error if we have additional pathkey elements
1866+ * (i.e., lop or lip isn't NULL here). The input paths might be
1867+ * better-sorted than we need for the current mergejoin.
1868+ */
17951869
17961870 /*
17971871 * Now we can build the mergejoin node.
0 commit comments