10
10
*
11
11
*
12
12
* 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 $
14
14
*
15
15
*-------------------------------------------------------------------------
16
16
*/
@@ -1620,10 +1620,6 @@ create_mergejoin_plan(PlannerInfo *root,
1620
1620
bool * mergenullsfirst ;
1621
1621
MergeJoin * join_plan ;
1622
1622
int i ;
1623
- EquivalenceClass * lastoeclass ;
1624
- EquivalenceClass * lastieclass ;
1625
- PathKey * opathkey ;
1626
- PathKey * ipathkey ;
1627
1623
ListCell * lc ;
1628
1624
ListCell * lop ;
1629
1625
ListCell * lip ;
@@ -1729,10 +1725,6 @@ create_mergejoin_plan(PlannerInfo *root,
1729
1725
mergestrategies = (int * ) palloc (nClauses * sizeof (int ));
1730
1726
mergenullsfirst = (bool * ) palloc (nClauses * sizeof (bool ));
1731
1727
1732
- lastoeclass = NULL ;
1733
- lastieclass = NULL ;
1734
- opathkey = NULL ;
1735
- ipathkey = NULL ;
1736
1728
lop = list_head (outerpathkeys );
1737
1729
lip = list_head (innerpathkeys );
1738
1730
i = 0 ;
@@ -1741,6 +1733,11 @@ create_mergejoin_plan(PlannerInfo *root,
1741
1733
RestrictInfo * rinfo = (RestrictInfo * ) lfirst (lc );
1742
1734
EquivalenceClass * oeclass ;
1743
1735
EquivalenceClass * ieclass ;
1736
+ PathKey * opathkey ;
1737
+ PathKey * ipathkey ;
1738
+ EquivalenceClass * opeclass ;
1739
+ EquivalenceClass * ipeclass ;
1740
+ ListCell * l2 ;
1744
1741
1745
1742
/* fetch outer/inner eclass from mergeclause */
1746
1743
Assert (IsA (rinfo , RestrictInfo ));
@@ -1757,28 +1754,100 @@ create_mergejoin_plan(PlannerInfo *root,
1757
1754
Assert (oeclass != NULL );
1758
1755
Assert (ieclass != NULL );
1759
1756
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 )
1763
1770
{
1764
- if (!lop )
1765
- elog (ERROR , "too few pathkeys for mergeclauses" );
1766
1771
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
+ }
1771
1793
}
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 )
1773
1811
{
1774
- if (!lip )
1775
- elog (ERROR , "too few pathkeys for mergeclauses" );
1776
1812
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" );
1781
1849
}
1850
+
1782
1851
/* pathkeys should match each other too (more debugging) */
1783
1852
if (opathkey -> pk_opfamily != ipathkey -> pk_opfamily ||
1784
1853
opathkey -> pk_strategy != ipathkey -> pk_strategy ||
@@ -1792,6 +1861,11 @@ create_mergejoin_plan(PlannerInfo *root,
1792
1861
i ++ ;
1793
1862
}
1794
1863
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
+ */
1795
1869
1796
1870
/*
1797
1871
* Now we can build the mergejoin node.
0 commit comments