You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Repair bogus EPQ plans generated for postgres_fdw foreign joins.
postgres_fdw's postgresGetForeignPlan() assumes without checking that the
outer_plan it's given for a join relation must have a NestLoop, MergeJoin,
or HashJoin node at the top. That's been wrong at least since commit
4bbf6ed (which could cause insertion of a Sort node on top) and it seems
like a pretty unsafe thing to Just Assume even without that.
Through blind good fortune, this doesn't seem to have any worse
consequences today than strange EXPLAIN output, but it's clearly trouble
waiting to happen.
To fix, test the node type explicitly before touching Join-specific
fields, and avoid jamming the new tlist into a node type that can't
do projection. Export a new support function from createplan.c
to avoid building low-level knowledge about the latter into FDWs.
Back-patch to 9.6 where the faulty coding was added. Note that the
associated regression test cases don't show any changes before v11,
apparently because the tests back-patched with 4bbf6ed don't actually
exercise the problem case before then (there's no top-level Sort
in those plans).
Discussion: https://postgr.es/m/8946.1544644803@sss.pgh.pa.us
Remote SQL: SELECT r1."C 1", r2."C 1", r1.c3, CASE WHEN (r1.*)::text IS NOT NULL THEN ROW(r1."C 1", r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8) END, CASE WHEN (r2.*)::text IS NOT NULL THEN ROW(r2."C 1", r2.c2, r2.c3, r2.c4, r2.c5, r2.c6, r2.c7, r2.c8) END FROM ("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r1."C 1" = r2."C 1")))) ORDER BY r1.c3 ASC NULLS LAST, r1."C 1" ASC NULLS LAST FOR UPDATE OF r1
1712
-
-> Sort
1713
-
Output: t1.c1, t1.c3, t1.*, t2.c1, t2.*
1714
-
Sort Key: t1.c3 USING <, t1.c1
1715
-
-> Merge Join
1712
+
-> Result
1713
+
Output: t1.c1, t2.c1, t1.c3, t1.*, t2.*
1714
+
-> Sort
1716
1715
Output: t1.c1, t1.c3, t1.*, t2.c1, t2.*
1717
-
Merge Cond: (t1.c1 = t2.c1)
1718
-
-> Sort
1719
-
Output: t1.c1, t1.c3, t1.*
1720
-
Sort Key: t1.c1
1721
-
-> Foreign Scan on public.ft1 t1
1716
+
Sort Key: t1.c3, t1.c1
1717
+
-> Merge Join
1718
+
Output: t1.c1, t1.c3, t1.*, t2.c1, t2.*
1719
+
Merge Cond: (t1.c1 = t2.c1)
1720
+
-> Sort
1722
1721
Output: t1.c1, t1.c3, t1.*
1723
-
Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" FOR UPDATE
1724
-
-> Sort
1725
-
Output: t2.c1, t2.*
1726
-
Sort Key: t2.c1
1727
-
-> Foreign Scan on public.ft2 t2
1722
+
Sort Key: t1.c1
1723
+
-> Foreign Scan on public.ft1 t1
1724
+
Output: t1.c1, t1.c3, t1.*
1725
+
Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" FOR UPDATE
Remote SQL: SELECT r1."C 1", r2."C 1", r1.c3, CASE WHEN (r1.*)::text IS NOT NULL THEN ROW(r1."C 1", r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8) END, CASE WHEN (r2.*)::text IS NOT NULL THEN ROW(r2."C 1", r2.c2, r2.c3, r2.c4, r2.c5, r2.c6, r2.c7, r2.c8) END FROM ("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r1."C 1" = r2."C 1")))) ORDER BY r1.c3 ASC NULLS LAST, r1."C 1" ASC NULLS LAST FOR UPDATE OF r1 FOR UPDATE OF r2
1759
-
-> Sort
1760
-
Output: t1.c1, t1.c3, t1.*, t2.c1, t2.*
1761
-
Sort Key: t1.c3 USING <, t1.c1
1762
-
-> Merge Join
1761
+
-> Result
1762
+
Output: t1.c1, t2.c1, t1.c3, t1.*, t2.*
1763
+
-> Sort
1763
1764
Output: t1.c1, t1.c3, t1.*, t2.c1, t2.*
1764
-
Merge Cond: (t1.c1 = t2.c1)
1765
-
-> Sort
1766
-
Output: t1.c1, t1.c3, t1.*
1767
-
Sort Key: t1.c1
1768
-
-> Foreign Scan on public.ft1 t1
1765
+
Sort Key: t1.c3, t1.c1
1766
+
-> Merge Join
1767
+
Output: t1.c1, t1.c3, t1.*, t2.c1, t2.*
1768
+
Merge Cond: (t1.c1 = t2.c1)
1769
+
-> Sort
1769
1770
Output: t1.c1, t1.c3, t1.*
1770
-
Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" FOR UPDATE
1771
-
-> Sort
1772
-
Output: t2.c1, t2.*
1773
-
Sort Key: t2.c1
1774
-
-> Foreign Scan on public.ft2 t2
1771
+
Sort Key: t1.c1
1772
+
-> Foreign Scan on public.ft1 t1
1773
+
Output: t1.c1, t1.c3, t1.*
1774
+
Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" FOR UPDATE
1775
+
-> Sort
1775
1776
Output: t2.c1, t2.*
1776
-
Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" FOR UPDATE
1777
-
(26 rows)
1777
+
Sort Key: t2.c1
1778
+
-> Foreign Scan on public.ft2 t2
1779
+
Output: t2.c1, t2.*
1780
+
Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" FOR UPDATE
1781
+
(28 rows)
1778
1782
1779
1783
SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c3, t1.c1 OFFSET 100 LIMIT 10 FOR UPDATE;
1780
1784
c1 | c1
@@ -1804,25 +1808,27 @@ SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c3, t
Remote SQL: SELECT r1."C 1", r2."C 1", r1.c3, CASE WHEN (r1.*)::text IS NOT NULL THEN ROW(r1."C 1", r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8) END, CASE WHEN (r2.*)::text IS NOT NULL THEN ROW(r2."C 1", r2.c2, r2.c3, r2.c4, r2.c5, r2.c6, r2.c7, r2.c8) END FROM ("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r1."C 1" = r2."C 1")))) ORDER BY r1.c3 ASC NULLS LAST, r1."C 1" ASC NULLS LAST FOR SHARE OF r1
1807
-
-> Sort
1808
-
Output: t1.c1, t1.c3, t1.*, t2.c1, t2.*
1809
-
Sort Key: t1.c3 USING <, t1.c1
1810
-
-> Merge Join
1811
+
-> Result
1812
+
Output: t1.c1, t2.c1, t1.c3, t1.*, t2.*
1813
+
-> Sort
1811
1814
Output: t1.c1, t1.c3, t1.*, t2.c1, t2.*
1812
-
Merge Cond: (t1.c1 = t2.c1)
1813
-
-> Sort
1814
-
Output: t1.c1, t1.c3, t1.*
1815
-
Sort Key: t1.c1
1816
-
-> Foreign Scan on public.ft1 t1
1815
+
Sort Key: t1.c3, t1.c1
1816
+
-> Merge Join
1817
+
Output: t1.c1, t1.c3, t1.*, t2.c1, t2.*
1818
+
Merge Cond: (t1.c1 = t2.c1)
1819
+
-> Sort
1817
1820
Output: t1.c1, t1.c3, t1.*
1818
-
Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" FOR SHARE
1819
-
-> Sort
1820
-
Output: t2.c1, t2.*
1821
-
Sort Key: t2.c1
1822
-
-> Foreign Scan on public.ft2 t2
1821
+
Sort Key: t1.c1
1822
+
-> Foreign Scan on public.ft1 t1
1823
+
Output: t1.c1, t1.c3, t1.*
1824
+
Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" FOR SHARE
Remote SQL: SELECT r1."C 1", r2."C 1", r1.c3, CASE WHEN (r1.*)::text IS NOT NULL THEN ROW(r1."C 1", r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8) END, CASE WHEN (r2.*)::text IS NOT NULL THEN ROW(r2."C 1", r2.c2, r2.c3, r2.c4, r2.c5, r2.c6, r2.c7, r2.c8) END FROM ("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r1."C 1" = r2."C 1")))) ORDER BY r1.c3 ASC NULLS LAST, r1."C 1" ASC NULLS LAST FOR SHARE OF r1 FOR SHARE OF r2
1854
-
-> Sort
1855
-
Output: t1.c1, t1.c3, t1.*, t2.c1, t2.*
1856
-
Sort Key: t1.c3 USING <, t1.c1
1857
-
-> Merge Join
1860
+
-> Result
1861
+
Output: t1.c1, t2.c1, t1.c3, t1.*, t2.*
1862
+
-> Sort
1858
1863
Output: t1.c1, t1.c3, t1.*, t2.c1, t2.*
1859
-
Merge Cond: (t1.c1 = t2.c1)
1860
-
-> Sort
1861
-
Output: t1.c1, t1.c3, t1.*
1862
-
Sort Key: t1.c1
1863
-
-> Foreign Scan on public.ft1 t1
1864
+
Sort Key: t1.c3, t1.c1
1865
+
-> Merge Join
1866
+
Output: t1.c1, t1.c3, t1.*, t2.c1, t2.*
1867
+
Merge Cond: (t1.c1 = t2.c1)
1868
+
-> Sort
1864
1869
Output: t1.c1, t1.c3, t1.*
1865
-
Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" FOR SHARE
1866
-
-> Sort
1867
-
Output: t2.c1, t2.*
1868
-
Sort Key: t2.c1
1869
-
-> Foreign Scan on public.ft2 t2
1870
+
Sort Key: t1.c1
1871
+
-> Foreign Scan on public.ft1 t1
1872
+
Output: t1.c1, t1.c3, t1.*
1873
+
Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" FOR SHARE
1874
+
-> Sort
1870
1875
Output: t2.c1, t2.*
1871
-
Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" FOR SHARE
1872
-
(26 rows)
1876
+
Sort Key: t2.c1
1877
+
-> Foreign Scan on public.ft2 t2
1878
+
Output: t2.c1, t2.*
1879
+
Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" FOR SHARE
1880
+
(28 rows)
1873
1881
1874
1882
SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c3, t1.c1 OFFSET 100 LIMIT 10 FOR SHARE;
0 commit comments