@@ -1904,6 +1904,143 @@ RETURNING k, v;
19041904(0 rows)
19051905
19061906DROP TABLE withz;
1907+ -- WITH referenced by MERGE statement
1908+ CREATE TABLE m AS SELECT i AS k, (i || ' v')::text v FROM generate_series(1, 16, 3) i;
1909+ ALTER TABLE m ADD UNIQUE (k);
1910+ WITH RECURSIVE cte_basic AS (SELECT 1 a, 'cte_basic val' b)
1911+ MERGE INTO m USING (select 0 k, 'merge source SubPlan' v) o ON m.k=o.k
1912+ WHEN MATCHED THEN UPDATE SET v = (SELECT b || ' merge update' FROM cte_basic WHERE cte_basic.a = m.k LIMIT 1)
1913+ WHEN NOT MATCHED THEN INSERT VALUES(o.k, o.v);
1914+ ERROR: WITH RECURSIVE is not supported for MERGE statement
1915+ -- Basic:
1916+ WITH cte_basic AS (SELECT 1 a, 'cte_basic val' b)
1917+ MERGE INTO m USING (select 0 k, 'merge source SubPlan' v) o ON m.k=o.k
1918+ WHEN MATCHED THEN UPDATE SET v = (SELECT b || ' merge update' FROM cte_basic WHERE cte_basic.a = m.k LIMIT 1)
1919+ WHEN NOT MATCHED THEN INSERT VALUES(o.k, o.v);
1920+ -- Examine
1921+ SELECT * FROM m where k = 0;
1922+ k | v
1923+ ---+----------------------
1924+ 0 | merge source SubPlan
1925+ (1 row)
1926+
1927+ -- See EXPLAIN output for same query:
1928+ EXPLAIN (VERBOSE, COSTS OFF)
1929+ WITH cte_basic AS (SELECT 1 a, 'cte_basic val' b)
1930+ MERGE INTO m USING (select 0 k, 'merge source SubPlan' v) o ON m.k=o.k
1931+ WHEN MATCHED THEN UPDATE SET v = (SELECT b || ' merge update' FROM cte_basic WHERE cte_basic.a = m.k LIMIT 1)
1932+ WHEN NOT MATCHED THEN INSERT VALUES(o.k, o.v);
1933+ QUERY PLAN
1934+ -------------------------------------------------------------------
1935+ Merge on public.m
1936+ CTE cte_basic
1937+ -> Result
1938+ Output: 1, 'cte_basic val'::text
1939+ -> Hash Right Join
1940+ Output: o.k, o.v, o.*, m_1.ctid
1941+ Hash Cond: (m_1.k = o.k)
1942+ -> Seq Scan on public.m m_1
1943+ Output: m_1.ctid, m_1.k
1944+ -> Hash
1945+ Output: o.k, o.v, o.*
1946+ -> Subquery Scan on o
1947+ Output: o.k, o.v, o.*
1948+ -> Result
1949+ Output: 0, 'merge source SubPlan'::text
1950+ SubPlan 2
1951+ -> Limit
1952+ Output: ((cte_basic.b || ' merge update'::text))
1953+ -> CTE Scan on cte_basic
1954+ Output: (cte_basic.b || ' merge update'::text)
1955+ Filter: (cte_basic.a = m.k)
1956+ (21 rows)
1957+
1958+ -- InitPlan
1959+ WITH cte_init AS (SELECT 1 a, 'cte_init val' b)
1960+ MERGE INTO m USING (select 1 k, 'merge source InitPlan' v) o ON m.k=o.k
1961+ WHEN MATCHED THEN UPDATE SET v = (SELECT b || ' merge update' FROM cte_init WHERE a = 1 LIMIT 1)
1962+ WHEN NOT MATCHED THEN INSERT VALUES(o.k, o.v);
1963+ -- Examine
1964+ SELECT * FROM m where k = 1;
1965+ k | v
1966+ ---+---------------------------
1967+ 1 | cte_init val merge update
1968+ (1 row)
1969+
1970+ -- See EXPLAIN output for same query:
1971+ EXPLAIN (VERBOSE, COSTS OFF)
1972+ WITH cte_init AS (SELECT 1 a, 'cte_init val' b)
1973+ MERGE INTO m USING (select 1 k, 'merge source InitPlan' v) o ON m.k=o.k
1974+ WHEN MATCHED THEN UPDATE SET v = (SELECT b || ' merge update' FROM cte_init WHERE a = 1 LIMIT 1)
1975+ WHEN NOT MATCHED THEN INSERT VALUES(o.k, o.v);
1976+ QUERY PLAN
1977+ --------------------------------------------------------------------
1978+ Merge on public.m
1979+ CTE cte_init
1980+ -> Result
1981+ Output: 1, 'cte_init val'::text
1982+ InitPlan 2 (returns $1)
1983+ -> Limit
1984+ Output: ((cte_init.b || ' merge update'::text))
1985+ -> CTE Scan on cte_init
1986+ Output: (cte_init.b || ' merge update'::text)
1987+ Filter: (cte_init.a = 1)
1988+ -> Hash Right Join
1989+ Output: o.k, o.v, o.*, m_1.ctid
1990+ Hash Cond: (m_1.k = o.k)
1991+ -> Seq Scan on public.m m_1
1992+ Output: m_1.ctid, m_1.k
1993+ -> Hash
1994+ Output: o.k, o.v, o.*
1995+ -> Subquery Scan on o
1996+ Output: o.k, o.v, o.*
1997+ -> Result
1998+ Output: 1, 'merge source InitPlan'::text
1999+ (21 rows)
2000+
2001+ -- MERGE source comes from CTE:
2002+ WITH merge_source_cte AS (SELECT 15 a, 'merge_source_cte val' b)
2003+ MERGE INTO m USING (select * from merge_source_cte) o ON m.k=o.a
2004+ WHEN MATCHED THEN UPDATE SET v = (SELECT b || merge_source_cte.*::text || ' merge update' FROM merge_source_cte WHERE a = 15)
2005+ WHEN NOT MATCHED THEN INSERT VALUES(o.a, o.b || (SELECT merge_source_cte.*::text || ' merge insert' FROM merge_source_cte));
2006+ -- Examine
2007+ SELECT * FROM m where k = 15;
2008+ k | v
2009+ ----+--------------------------------------------------------------
2010+ 15 | merge_source_cte val(15,"merge_source_cte val") merge insert
2011+ (1 row)
2012+
2013+ -- See EXPLAIN output for same query:
2014+ EXPLAIN (VERBOSE, COSTS OFF)
2015+ WITH merge_source_cte AS (SELECT 15 a, 'merge_source_cte val' b)
2016+ MERGE INTO m USING (select * from merge_source_cte) o ON m.k=o.a
2017+ WHEN MATCHED THEN UPDATE SET v = (SELECT b || merge_source_cte.*::text || ' merge update' FROM merge_source_cte WHERE a = 15)
2018+ WHEN NOT MATCHED THEN INSERT VALUES(o.a, o.b || (SELECT merge_source_cte.*::text || ' merge insert' FROM merge_source_cte));
2019+ QUERY PLAN
2020+ ---------------------------------------------------------------------------------------------------------------
2021+ Merge on public.m
2022+ CTE merge_source_cte
2023+ -> Result
2024+ Output: 15, 'merge_source_cte val'::text
2025+ InitPlan 2 (returns $1)
2026+ -> CTE Scan on merge_source_cte merge_source_cte_1
2027+ Output: ((merge_source_cte_1.b || (merge_source_cte_1.*)::text) || ' merge update'::text)
2028+ Filter: (merge_source_cte_1.a = 15)
2029+ InitPlan 3 (returns $2)
2030+ -> CTE Scan on merge_source_cte merge_source_cte_2
2031+ Output: ((merge_source_cte_2.*)::text || ' merge insert'::text)
2032+ -> Hash Right Join
2033+ Output: merge_source_cte.a, merge_source_cte.b, ROW(merge_source_cte.a, merge_source_cte.b), m_1.ctid
2034+ Hash Cond: (m_1.k = merge_source_cte.a)
2035+ -> Seq Scan on public.m m_1
2036+ Output: m_1.ctid, m_1.k
2037+ -> Hash
2038+ Output: merge_source_cte.a, merge_source_cte.b
2039+ -> CTE Scan on merge_source_cte
2040+ Output: merge_source_cte.a, merge_source_cte.b
2041+ (20 rows)
2042+
2043+ DROP TABLE m;
19072044-- check that run to completion happens in proper ordering
19082045TRUNCATE TABLE y;
19092046INSERT INTO y SELECT generate_series(1, 3);
0 commit comments