This is an automated email from the ASF dual-hosted git repository.

chenjinbao1989 pushed a commit to branch cbdb-postgres-merge
in repository https://gitbox.apache.org/repos/asf/cloudberry.git


The following commit(s) were added to refs/heads/cbdb-postgres-merge by this 
push:
     new 4ac5445c650 fix_with
4ac5445c650 is described below

commit 4ac5445c650c93f0f9bae220e0d6cf6cda9a7b74
Author: liushengsong <[email protected]>
AuthorDate: Wed Jan 14 17:55:45 2026 +0800

    fix_with
---
 src/backend/parser/parse_cte.c     |  63 +++++++++
 src/test/regress/expected/with.out | 274 +++++++++++++++++--------------------
 src/test/regress/sql/with.sql      | 115 ++++++++--------
 3 files changed, 244 insertions(+), 208 deletions(-)

diff --git a/src/backend/parser/parse_cte.c b/src/backend/parser/parse_cte.c
index 8559088df23..a052f260bca 100644
--- a/src/backend/parser/parse_cte.c
+++ b/src/backend/parser/parse_cte.c
@@ -281,6 +281,69 @@ analyzeCTE(ParseState *pstate, CommonTableExpr *cte)
        /* Analysis not done already */
        Assert(!IsA(cte->ctequery, Query));
 
+       /*
+        * Before analyzing the CTE's query, we'd better identify the data type 
of
+        * the cycle mark column if any, since the query could refer to that.
+        * Other validity checks on the cycle clause will be done afterwards.
+        */
+       if (cycle_clause)
+       {
+               TypeCacheEntry *typentry;
+               Oid                     op;
+
+               cycle_clause->cycle_mark_value =
+                       transformExpr(pstate, cycle_clause->cycle_mark_value,
+                                                 EXPR_KIND_CYCLE_MARK);
+               cycle_clause->cycle_mark_default =
+                       transformExpr(pstate, cycle_clause->cycle_mark_default,
+                                                 EXPR_KIND_CYCLE_MARK);
+
+               cycle_clause->cycle_mark_type =
+                       select_common_type(pstate,
+                                                          
list_make2(cycle_clause->cycle_mark_value,
+                                                                               
  cycle_clause->cycle_mark_default),
+                                                          "CYCLE", NULL);
+               cycle_clause->cycle_mark_value =
+                       coerce_to_common_type(pstate,
+                                                                 
cycle_clause->cycle_mark_value,
+                                                                 
cycle_clause->cycle_mark_type,
+                                                                 
"CYCLE/SET/TO");
+               cycle_clause->cycle_mark_default =
+                       coerce_to_common_type(pstate,
+                                                                 
cycle_clause->cycle_mark_default,
+                                                                 
cycle_clause->cycle_mark_type,
+                                                                 
"CYCLE/SET/DEFAULT");
+
+               cycle_clause->cycle_mark_typmod =
+                       select_common_typmod(pstate,
+                                                                
list_make2(cycle_clause->cycle_mark_value,
+                                                                               
        cycle_clause->cycle_mark_default),
+                                                                
cycle_clause->cycle_mark_type);
+
+               cycle_clause->cycle_mark_collation =
+                       select_common_collation(pstate,
+                                                                       
list_make2(cycle_clause->cycle_mark_value,
+                                                                               
           cycle_clause->cycle_mark_default),
+                                                                       true);
+
+               /* Might as well look up the relevant <> operator while we are 
at it */
+               typentry = lookup_type_cache(cycle_clause->cycle_mark_type,
+                                                                        
TYPECACHE_EQ_OPR);
+               if (!OidIsValid(typentry->eq_opr))
+                       ereport(ERROR,
+                                       errcode(ERRCODE_UNDEFINED_FUNCTION),
+                                       errmsg("could not identify an equality 
operator for type %s",
+                                                  
format_type_be(cycle_clause->cycle_mark_type)));
+               op = get_negator(typentry->eq_opr);
+               if (!OidIsValid(op))
+                       ereport(ERROR,
+                                       errcode(ERRCODE_UNDEFINED_FUNCTION),
+                                       errmsg("could not identify an 
inequality operator for type %s",
+                                                  
format_type_be(cycle_clause->cycle_mark_type)));
+
+               cycle_clause->cycle_mark_neop = op;
+       }
+
        query = parse_sub_analyze(cte->ctequery, pstate, cte, NULL, true);
        cte->ctequery = (Node *) query;
 
diff --git a/src/test/regress/expected/with.out 
b/src/test/regress/expected/with.out
index 82e567168b1..64820370511 100644
--- a/src/test/regress/expected/with.out
+++ b/src/test/regress/expected/with.out
@@ -694,7 +694,6 @@ select * from search_graph order by seq;
                                  Output: g_1.f, g_1.t, g_1.label
                                  ->  Seq Scan on public.graph0 g_1
                                        Output: g_1.f, g_1.t, g_1.label
- Optimizer: Postgres query optimizer
 (22 rows)
 
 with recursive search_graph(f, t, label) as (
@@ -1128,29 +1127,26 @@ with recursive search_graph(f, t, label) as (
        where g.f = sg.t
 ) cycle f, t set is_cycle using path
 select * from search_graph;
-                                                                              
QUERY PLAN                                                                      
         
------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- CTE Scan on search_graph
-   Output: search_graph.f, search_graph.t, search_graph.label, 
search_graph.is_cycle, search_graph.path
-   CTE search_graph
-     ->  Recursive Union
-           ->  Seq Scan on pg_temp.graph g
-                 Output: g.f, g.t, g.label, false, ARRAY[ROW(g.f, g.t)]
-           ->  Merge Join
-                 Output: g_1.f, g_1.t, g_1.label, CASE WHEN (ROW(g_1.f, g_1.t) 
= ANY (sg.path)) THEN true ELSE false END, array_cat(sg.path, ARRAY[ROW(g_1.f, 
g_1.t)])
-                 Merge Cond: (g_1.f = sg.t)
-                 ->  Sort
-                       Output: g_1.f, g_1.t, g_1.label
-                       Sort Key: g_1.f
-                       ->  Seq Scan on pg_temp.graph g_1
-                             Output: g_1.f, g_1.t, g_1.label
-                 ->  Sort
-                       Output: sg.path, sg.t
-                       Sort Key: sg.t
-                       ->  WorkTable Scan on search_graph sg
-                             Output: sg.path, sg.t
-                             Filter: (NOT sg.is_cycle)
-(20 rows)
+                                                                             
QUERY PLAN                                                                      
        
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)
+   Output: g.f, g.t, g.label, (false), (ARRAY[ROW(g.f, g.t)])
+   ->  Recursive Union
+         ->  Seq Scan on pg_temp.graph g
+               Output: g.f, g.t, g.label, false, ARRAY[ROW(g.f, g.t)]
+         ->  Hash Join
+               Output: g_1.f, g_1.t, g_1.label, CASE WHEN (ROW(g_1.f, g_1.t) = 
ANY (sg.path)) THEN true ELSE false END, array_cat(sg.path, ARRAY[ROW(g_1.f, 
g_1.t)])
+               Hash Cond: (sg.t = g_1.f)
+               ->  WorkTable Scan on search_graph sg
+                     Output: sg.f, sg.t, sg.label, sg.is_cycle, sg.path
+                     Filter: (NOT sg.is_cycle)
+               ->  Hash
+                     Output: g_1.f, g_1.t, g_1.label
+                     ->  Broadcast Motion 3:3  (slice2; segments: 3)
+                           Output: g_1.f, g_1.t, g_1.label
+                           ->  Seq Scan on pg_temp.graph g_1
+                                 Output: g_1.f, g_1.t, g_1.label
+(19 rows)
 
 with recursive search_graph(f, t, label) as (
        select * from graph g
@@ -1234,18 +1230,15 @@ with recursive test as (
   from test
 ) cycle x set is_cycle using path
 select * from test;
-                                                                               
           QUERY PLAN                                                           
                                
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- CTE Scan on test
-   Output: test.x, test.is_cycle, test.path
-   CTE test
-     ->  Recursive Union
-           ->  Result
-                 Output: 0, false, '{(0)}'::record[]
-           ->  WorkTable Scan on test test_1
-                 Output: ((test_1.x + 1) % 10), CASE WHEN (ROW(((test_1.x + 1) 
% 10)) = ANY (test_1.path)) THEN true ELSE false END, array_cat(test_1.path, 
ARRAY[ROW(((test_1.x + 1) % 10))])
-                 Filter: (NOT test_1.is_cycle)
-(9 rows)
+                                                                               
  QUERY PLAN                                                                    
              
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ Recursive Union
+   ->  Result
+         Output: 0, false, ARRAY[ROW(0)]
+   ->  WorkTable Scan on test
+         Output: ((test.x + 1) % 10), CASE WHEN (ROW(((test.x + 1) % 10)) = 
ANY (test.path)) THEN true ELSE false END, array_cat(test.path, 
ARRAY[ROW(((test.x + 1) % 10))])
+         Filter: (NOT test.is_cycle)
+(8 rows)
 
 with recursive test as (
   select 0 as x
@@ -2016,7 +2009,6 @@ WITH RECURSIVE x(n) AS (SELECT n FROM x UNION ALL SELECT 
1)
 ERROR:  recursive reference to query "x" must not appear within its 
non-recursive term
 LINE 1: WITH RECURSIVE x(n) AS (SELECT n FROM x UNION ALL SELECT 1)
                                               ^
-<<<<<<< HEAD
 -- recursive term with a self-reference within a subquery is not allowed
 WITH RECURSIVE cte(level, id) as (
        SELECT 1, 2
@@ -2050,8 +2042,6 @@ WITH RECURSIVE x(n) AS (
 ERROR:  window functions in the target list of a recursive query is not 
supported
 LINE 4:  SELECT level+1, row_number() over() FROM x, bar)
                          ^
-CREATE TEMPORARY TABLE y (a INTEGER) DISTRIBUTED RANDOMLY;
-=======
 -- allow this, because we historically have
 WITH RECURSIVE x(n) AS (
   WITH x1 AS (SELECT 1 AS n)
@@ -2100,8 +2090,7 @@ WITH RECURSIVE x(n) AS (
 ERROR:  recursive query "x" must not contain data-modifying statements
 LINE 1: WITH RECURSIVE x(n) AS (
                        ^
-CREATE TEMPORARY TABLE y (a INTEGER);
->>>>>>> REL_16_9
+CREATE TEMPORARY TABLE y (a INTEGER) DISTRIBUTED RANDOMLY;
 INSERT INTO y SELECT generate_series(1, 10);
 -- LEFT JOIN
 WITH RECURSIVE x(n) AS (SELECT a FROM y WHERE a = 1
@@ -2810,14 +2799,6 @@ INSERT INTO bug6051 SELECT * FROM t1;
 ERROR:  writable CTE queries cannot be themselves writable
 DETAIL:  Apache Cloudberry currently only support CTEs with one writable 
clause, called in a non-writable context.
 HINT:  Rewrite the query to only include one writable clause.
-SELECT * FROM bug6051;
- i 
----
- 1
- 2
- 3
-(3 rows)
-
 CREATE TEMP TABLE bug6051_2 (i int);
 CREATE RULE bug6051_ins AS ON INSERT TO bug6051 DO INSTEAD
  INSERT INTO bug6051_2
@@ -2835,36 +2816,22 @@ SELECT * FROM bug6051;
  3
 (3 rows)
 
-<<<<<<< HEAD
-SELECT * FROM bug6051_2;
- i 
----
-(0 rows)
-
--- check INSERT...SELECT rule actions are disallowed on commands
-=======
 -- check INSERT ... SELECT rule actions are disallowed on commands
->>>>>>> REL_16_9
 -- that have modifyingCTEs
 CREATE OR REPLACE RULE bug6051_ins AS ON INSERT TO bug6051 DO INSTEAD
  INSERT INTO bug6051_2
  SELECT NEW.i;
 WITH t1 AS ( DELETE FROM bug6051 RETURNING * )
 INSERT INTO bug6051 SELECT * FROM t1;
-<<<<<<< HEAD
 ERROR:  writable CTE queries cannot be themselves writable
 DETAIL:  Apache Cloudberry currently only support CTEs with one writable 
clause, called in a non-writable context.
 HINT:  Rewrite the query to only include one writable clause.
-=======
-ERROR:  INSERT ... SELECT rule actions are not supported for queries having 
data-modifying statements in WITH
->>>>>>> REL_16_9
 -- silly example to verify that hasModifyingCTE flag is propagated
 CREATE TEMP TABLE bug6051_3 AS
   SELECT a FROM generate_series(11,13) AS a;
 CREATE RULE bug6051_3_ins AS ON INSERT TO bug6051_3 DO INSTEAD
   SELECT i FROM bug6051_2;
-<<<<<<< HEAD
-BEGIN; SET LOCAL force_parallel_mode = on;
+BEGIN; SET LOCAL debug_parallel_query = on;
 WITH t1 AS ( DELETE FROM bug6051_3 RETURNING * )
   INSERT INTO bug6051_3 SELECT * FROM t1;
 ERROR:  writable CTE queries cannot be themselves writable
@@ -2878,29 +2845,6 @@ SELECT * FROM bug6051_3;
  13
  12
 (3 rows)
-=======
-BEGIN; SET LOCAL debug_parallel_query = on;
-WITH t1 AS ( DELETE FROM bug6051_3 RETURNING * )
-  INSERT INTO bug6051_3 SELECT * FROM t1;
- i 
----
- 1
- 2
- 3
- 1
- 2
- 3
- 1
- 2
- 3
-(9 rows)
-
-COMMIT;
-SELECT * FROM bug6051_3;
- a 
----
-(0 rows)
->>>>>>> REL_16_9
 
 -- check case where CTE reference is removed due to optimization
 EXPLAIN (VERBOSE, COSTS OFF)
@@ -3187,30 +3131,38 @@ WITH cte_basic AS MATERIALIZED (SELECT 1 a, 'cte_basic 
val' b)
 MERGE INTO m USING (select 0 k, 'merge source SubPlan' v offset 0) o ON m.k=o.k
 WHEN MATCHED THEN UPDATE SET v = (SELECT b || ' merge update' FROM cte_basic 
WHERE cte_basic.a = m.k LIMIT 1)
 WHEN NOT MATCHED THEN INSERT VALUES(o.k, o.v);
-                            QUERY PLAN                             
--------------------------------------------------------------------
+                                     QUERY PLAN                                
      
+-------------------------------------------------------------------------------------
  Merge on public.m
-   CTE cte_basic
-     ->  Result
-           Output: 1, 'cte_basic val'::text
-   ->  Hash Right Join
-         Output: m.ctid, o.k, o.v, o.*
-         Hash Cond: (m.k = o.k)
-         ->  Seq Scan on public.m
-               Output: m.ctid, m.k
-         ->  Hash
-               Output: o.k, o.v, o.*
-               ->  Subquery Scan on o
-                     Output: o.k, o.v, o.*
-                     ->  Result
-                           Output: 0, 'merge source SubPlan'::text
-   SubPlan 2
+   ->  Explicit Redistribute Motion 3:3  (slice1; segments: 3)
+         Output: m.ctid, m.gp_segment_id, o.k, o.v, o.*
+         ->  Split Merge
+               Output: m.ctid, m.gp_segment_id, o.k, o.v, o.*
+               ->  Hash Right Join
+                     Output: m.ctid, m.gp_segment_id, o.k, o.v, o.*
+                     Hash Cond: (m.k = o.k)
+                     ->  Seq Scan on public.m
+                           Output: m.ctid, m.gp_segment_id, m.k
+                     ->  Hash
+                           Output: o.k, o.v, o.*
+                           ->  Redistribute Motion 1:3  (slice2; segments: 1)
+                                 Output: o.k, o.v, o.*
+                                 Hash Key: o.k
+                                 ->  Subquery Scan on o
+                                       Output: o.k, o.v, o.*
+                                       ->  Result
+                                             Output: 0, 'merge source 
SubPlan'::text
+   SubPlan 1
      ->  Limit
-           Output: ((cte_basic.b || ' merge update'::text))
-           ->  CTE Scan on cte_basic
-                 Output: (cte_basic.b || ' merge update'::text)
-                 Filter: (cte_basic.a = m.k)
-(21 rows)
+           Output: ((share0_ref1.b || ' merge update'::text))
+           ->  Result
+                 Output: (share0_ref1.b || ' merge update'::text)
+                 Filter: (share0_ref1.a = m.k)
+                 ->  Shared Scan (share slice:id 0:0)
+                       Output: share0_ref1.a, share0_ref1.b
+                       ->  Result
+                             Output: 1, 'cte_basic val'::text
+(31 rows)
 
 -- InitPlan
 WITH cte_init AS MATERIALIZED (SELECT 1 a, 'cte_init val' b)
@@ -3230,30 +3182,38 @@ WITH cte_init AS MATERIALIZED (SELECT 1 a, 'cte_init 
val' b)
 MERGE INTO m USING (select 1 k, 'merge source InitPlan' v offset 0) o ON 
m.k=o.k
 WHEN MATCHED THEN UPDATE SET v = (SELECT b || ' merge update' FROM cte_init 
WHERE a = 1 LIMIT 1)
 WHEN NOT MATCHED THEN INSERT VALUES(o.k, o.v);
-                             QUERY PLAN                             
---------------------------------------------------------------------
+                                      QUERY PLAN                               
       
+--------------------------------------------------------------------------------------
  Merge on public.m
-   CTE cte_init
-     ->  Result
-           Output: 1, 'cte_init val'::text
-   InitPlan 2 (returns $1)
+   InitPlan 1 (returns $0)  (slice3)
      ->  Limit
            Output: ((cte_init.b || ' merge update'::text))
-           ->  CTE Scan on cte_init
+           ->  Subquery Scan on cte_init
                  Output: (cte_init.b || ' merge update'::text)
                  Filter: (cte_init.a = 1)
-   ->  Hash Right Join
-         Output: m.ctid, o.k, o.v, o.*
-         Hash Cond: (m.k = o.k)
-         ->  Seq Scan on public.m
-               Output: m.ctid, m.k
-         ->  Hash
-               Output: o.k, o.v, o.*
-               ->  Subquery Scan on o
-                     Output: o.k, o.v, o.*
-                     ->  Result
-                           Output: 1, 'merge source InitPlan'::text
-(21 rows)
+                 ->  Shared Scan (share slice:id 3:0)
+                       Output: share0_ref1.a, share0_ref1.b
+                       ->  Result
+                             Output: 1, 'cte_init val'::text
+   ->  Explicit Redistribute Motion 3:3  (slice1; segments: 3)
+         Output: m.ctid, m.gp_segment_id, o.k, o.v, o.*
+         ->  Split Merge
+               Output: m.ctid, m.gp_segment_id, o.k, o.v, o.*
+               ->  Hash Right Join
+                     Output: m.ctid, m.gp_segment_id, o.k, o.v, o.*
+                     Hash Cond: (m.k = o.k)
+                     ->  Seq Scan on public.m
+                           Output: m.ctid, m.gp_segment_id, m.k
+                     ->  Hash
+                           Output: o.k, o.v, o.*
+                           ->  Redistribute Motion 1:3  (slice2; segments: 1)
+                                 Output: o.k, o.v, o.*
+                                 Hash Key: o.k
+                                 ->  Subquery Scan on o
+                                       Output: o.k, o.v, o.*
+                                       ->  Result
+                                             Output: 1, 'merge source 
InitPlan'::text
+(31 rows)
 
 -- MERGE source comes from CTE:
 WITH merge_source_cte AS MATERIALIZED (SELECT 15 a, 'merge_source_cte val' b)
@@ -3273,29 +3233,41 @@ WITH merge_source_cte AS MATERIALIZED (SELECT 15 a, 
'merge_source_cte val' b)
 MERGE INTO m USING (select * from merge_source_cte) o ON m.k=o.a
 WHEN MATCHED THEN UPDATE SET v = (SELECT b || merge_source_cte.*::text || ' 
merge update' FROM merge_source_cte WHERE a = 15)
 WHEN NOT MATCHED THEN INSERT VALUES(o.a, o.b || (SELECT 
merge_source_cte.*::text || ' merge insert' FROM merge_source_cte));
-                                             QUERY PLAN                        
                      
------------------------------------------------------------------------------------------------------
+                                           QUERY PLAN                          
                  
+-------------------------------------------------------------------------------------------------
  Merge on public.m
-   CTE merge_source_cte
-     ->  Result
-           Output: 15, 'merge_source_cte val'::text
-   InitPlan 2 (returns $1)
-     ->  CTE Scan on merge_source_cte merge_source_cte_1
-           Output: ((merge_source_cte_1.b || (merge_source_cte_1.*)::text) || 
' merge update'::text)
-           Filter: (merge_source_cte_1.a = 15)
-   InitPlan 3 (returns $2)
-     ->  CTE Scan on merge_source_cte merge_source_cte_2
-           Output: ((merge_source_cte_2.*)::text || ' merge insert'::text)
-   ->  Hash Right Join
-         Output: m.ctid, merge_source_cte.a, merge_source_cte.b, 
merge_source_cte.*
-         Hash Cond: (m.k = merge_source_cte.a)
-         ->  Seq Scan on public.m
-               Output: m.ctid, m.k
-         ->  Hash
-               Output: merge_source_cte.a, merge_source_cte.b, 
merge_source_cte.*
-               ->  CTE Scan on merge_source_cte
-                     Output: merge_source_cte.a, merge_source_cte.b, 
merge_source_cte.*
-(20 rows)
+   InitPlan 1 (returns $0)  (slice3)
+     ->  Subquery Scan on merge_source_cte
+           Output: ((merge_source_cte.b || (merge_source_cte.*)::text) || ' 
merge update'::text)
+           Filter: (merge_source_cte.a = 15)
+           ->  Shared Scan (share slice:id 3:0)
+                 Output: share0_ref1.a, share0_ref1.b
+                 ->  Result
+                       Output: 15, 'merge_source_cte val'::text
+   InitPlan 2 (returns $1)  (slice4)
+     ->  Subquery Scan on merge_source_cte_1
+           Output: ((merge_source_cte_1.*)::text || ' merge insert'::text)
+           ->  Shared Scan (share slice:id 4:0)
+                 Output: share0_ref2.a, share0_ref2.b
+   ->  Explicit Redistribute Motion 3:3  (slice1; segments: 3)
+         Output: m.ctid, m.gp_segment_id, o.a, o.b, o.*
+         ->  Split Merge
+               Output: m.ctid, m.gp_segment_id, o.a, o.b, o.*
+               ->  Hash Right Join
+                     Output: m.ctid, m.gp_segment_id, o.a, o.b, o.*
+                     Hash Cond: (m.k = o.a)
+                     ->  Seq Scan on public.m
+                           Output: m.ctid, m.gp_segment_id, m.k
+                     ->  Hash
+                           Output: o.a, o.b, o.*
+                           ->  Redistribute Motion 1:3  (slice2)
+                                 Output: o.a, o.b, o.*
+                                 Hash Key: o.a
+                                 ->  Subquery Scan on o
+                                       Output: o.a, o.b, o.*
+                                       ->  Shared Scan (share slice:id 2:0)
+                                             Output: share0_ref3.a, 
share0_ref3.b
+(34 rows)
 
 DROP TABLE m;
 -- check that run to completion happens in proper ordering
@@ -3554,7 +3526,7 @@ SELECT * FROM parent;
 -- check EXPLAIN VERBOSE for a wCTE with RETURNING
 EXPLAIN (VERBOSE, COSTS OFF)
 WITH wcte AS ( INSERT INTO int8_tbl VALUES ( 42, 47 ) RETURNING q2 )
-DELETE FROM a USING wcte WHERE aa = q2;
+DELETE FROM a_star USING wcte WHERE aa = q2;
 ERROR:  writable CTE queries cannot be themselves writable
 DETAIL:  Apache Cloudberry currently only support CTEs with one writable 
clause, called in a non-writable context.
 HINT:  Rewrite the query to only include one writable clause.
diff --git a/src/test/regress/sql/with.sql b/src/test/regress/sql/with.sql
index d3f939867a0..e58ade9f747 100644
--- a/src/test/regress/sql/with.sql
+++ b/src/test/regress/sql/with.sql
@@ -954,8 +954,6 @@ WITH RECURSIVE x(n) AS (
        SELECT level+1, row_number() over() FROM x, bar)
   SELECT * FROM x LIMIT 10;
 
-CREATE TEMPORARY TABLE y (a INTEGER) DISTRIBUTED RANDOMLY;
-
 -- allow this, because we historically have
 WITH RECURSIVE x(n) AS (
   WITH x1 AS (SELECT 1 AS n)
@@ -991,6 +989,8 @@ WITH RECURSIVE x(n) AS (
   DELETE FROM graph RETURNING f)
        SELECT * FROM x;
 
+CREATE TEMPORARY TABLE y (a INTEGER) DISTRIBUTED RANDOMLY;
+
 INSERT INTO y SELECT generate_series(1, 10);
 
 -- LEFT JOIN
@@ -1332,8 +1332,6 @@ SELECT * FROM bug6051;
 WITH t1 AS ( DELETE FROM bug6051 RETURNING * )
 INSERT INTO bug6051 SELECT * FROM t1;
 
-SELECT * FROM bug6051;
-
 CREATE TEMP TABLE bug6051_2 (i int);
 
 CREATE RULE bug6051_ins AS ON INSERT TO bug6051 DO INSTEAD
@@ -1344,7 +1342,6 @@ WITH t1 AS ( DELETE FROM bug6051 RETURNING * )
 INSERT INTO bug6051 SELECT * FROM t1;
 
 SELECT * FROM bug6051;
-SELECT * FROM bug6051_2;
 
 -- check INSERT ... SELECT rule actions are disallowed on commands
 -- that have modifyingCTEs
@@ -1492,58 +1489,62 @@ UPDATE SET (k, v) = (SELECT k, v FROM upsert_cte WHERE 
upsert_cte.k = withz.k)
 RETURNING k, v;
 
 DROP TABLE withz;
--- MERGE16_FIXME: MERGE with CTE has some errors, Disable it first
--- 
--- -- WITH referenced by MERGE statement
--- CREATE TABLE m AS SELECT i AS k, (i || ' v')::text v FROM 
generate_series(1, 16, 3) i;
--- ALTER TABLE m ADD UNIQUE (k);
--- 
--- WITH RECURSIVE cte_basic AS (SELECT 1 a, 'cte_basic val' b)
--- MERGE INTO m USING (select 0 k, 'merge source SubPlan' v) o ON m.k=o.k
--- WHEN MATCHED THEN UPDATE SET v = (SELECT b || ' merge update' FROM 
cte_basic WHERE cte_basic.a = m.k LIMIT 1)
--- WHEN NOT MATCHED THEN INSERT VALUES(o.k, o.v);
--- 
--- -- Basic:
--- WITH cte_basic AS MATERIALIZED (SELECT 1 a, 'cte_basic val' b)
--- MERGE INTO m USING (select 0 k, 'merge source SubPlan' v offset 0) o ON 
m.k=o.k
--- WHEN MATCHED THEN UPDATE SET v = (SELECT b || ' merge update' FROM 
cte_basic WHERE cte_basic.a = m.k LIMIT 1)
--- WHEN NOT MATCHED THEN INSERT VALUES(o.k, o.v);
--- -- Examine
--- SELECT * FROM m where k = 0;
--- 
--- -- See EXPLAIN output for same query:
--- EXPLAIN (VERBOSE, COSTS OFF)
--- WITH cte_basic AS MATERIALIZED (SELECT 1 a, 'cte_basic val' b)
--- MERGE INTO m USING (select 0 k, 'merge source SubPlan' v offset 0) o ON 
m.k=o.k
--- WHEN MATCHED THEN UPDATE SET v = (SELECT b || ' merge update' FROM 
cte_basic WHERE cte_basic.a = m.k LIMIT 1)
--- WHEN NOT MATCHED THEN INSERT VALUES(o.k, o.v);
--- 
--- -- Examine
--- SELECT * FROM m where k = 1;
--- 
--- -- See EXPLAIN output for same query:
--- EXPLAIN (VERBOSE, COSTS OFF)
--- WITH cte_init AS MATERIALIZED (SELECT 1 a, 'cte_init val' b)
--- MERGE INTO m USING (select 1 k, 'merge source InitPlan' v offset 0) o ON 
m.k=o.k
--- WHEN MATCHED THEN UPDATE SET v = (SELECT b || ' merge update' FROM cte_init 
WHERE a = 1 LIMIT 1)
--- WHEN NOT MATCHED THEN INSERT VALUES(o.k, o.v);
--- 
--- -- MERGE source comes from CTE:
--- WITH merge_source_cte AS MATERIALIZED (SELECT 15 a, 'merge_source_cte val' 
b)
--- MERGE INTO m USING (select * from merge_source_cte) o ON m.k=o.a
--- WHEN MATCHED THEN UPDATE SET v = (SELECT b || merge_source_cte.*::text || ' 
merge update' FROM merge_source_cte WHERE a = 15)
--- WHEN NOT MATCHED THEN INSERT VALUES(o.a, o.b || (SELECT 
merge_source_cte.*::text || ' merge insert' FROM merge_source_cte));
--- -- Examine
--- SELECT * FROM m where k = 15;
--- 
--- -- See EXPLAIN output for same query:
--- EXPLAIN (VERBOSE, COSTS OFF)
--- WITH merge_source_cte AS MATERIALIZED (SELECT 15 a, 'merge_source_cte val' 
b)
--- MERGE INTO m USING (select * from merge_source_cte) o ON m.k=o.a
--- WHEN MATCHED THEN UPDATE SET v = (SELECT b || merge_source_cte.*::text || ' 
merge update' FROM merge_source_cte WHERE a = 15)
--- WHEN NOT MATCHED THEN INSERT VALUES(o.a, o.b || (SELECT 
merge_source_cte.*::text || ' merge insert' FROM merge_source_cte));
--- 
--- DROP TABLE m;
+
+-- WITH referenced by MERGE statement
+CREATE TABLE m AS SELECT i AS k, (i || ' v')::text v FROM generate_series(1, 
16, 3) i;
+ALTER TABLE m ADD UNIQUE (k);
+
+WITH RECURSIVE cte_basic AS (SELECT 1 a, 'cte_basic val' b)
+MERGE INTO m USING (select 0 k, 'merge source SubPlan' v) o ON m.k=o.k
+WHEN MATCHED THEN UPDATE SET v = (SELECT b || ' merge update' FROM cte_basic 
WHERE cte_basic.a = m.k LIMIT 1)
+WHEN NOT MATCHED THEN INSERT VALUES(o.k, o.v);
+
+-- Basic:
+WITH cte_basic AS MATERIALIZED (SELECT 1 a, 'cte_basic val' b)
+MERGE INTO m USING (select 0 k, 'merge source SubPlan' v offset 0) o ON m.k=o.k
+WHEN MATCHED THEN UPDATE SET v = (SELECT b || ' merge update' FROM cte_basic 
WHERE cte_basic.a = m.k LIMIT 1)
+WHEN NOT MATCHED THEN INSERT VALUES(o.k, o.v);
+-- Examine
+SELECT * FROM m where k = 0;
+
+-- See EXPLAIN output for same query:
+EXPLAIN (VERBOSE, COSTS OFF)
+WITH cte_basic AS MATERIALIZED (SELECT 1 a, 'cte_basic val' b)
+MERGE INTO m USING (select 0 k, 'merge source SubPlan' v offset 0) o ON m.k=o.k
+WHEN MATCHED THEN UPDATE SET v = (SELECT b || ' merge update' FROM cte_basic 
WHERE cte_basic.a = m.k LIMIT 1)
+WHEN NOT MATCHED THEN INSERT VALUES(o.k, o.v);
+
+-- InitPlan
+WITH cte_init AS MATERIALIZED (SELECT 1 a, 'cte_init val' b)
+MERGE INTO m USING (select 1 k, 'merge source InitPlan' v offset 0) o ON 
m.k=o.k
+WHEN MATCHED THEN UPDATE SET v = (SELECT b || ' merge update' FROM cte_init 
WHERE a = 1 LIMIT 1)
+WHEN NOT MATCHED THEN INSERT VALUES(o.k, o.v);
+-- Examine
+SELECT * FROM m where k = 1;
+
+-- See EXPLAIN output for same query:
+EXPLAIN (VERBOSE, COSTS OFF)
+WITH cte_init AS MATERIALIZED (SELECT 1 a, 'cte_init val' b)
+MERGE INTO m USING (select 1 k, 'merge source InitPlan' v offset 0) o ON 
m.k=o.k
+WHEN MATCHED THEN UPDATE SET v = (SELECT b || ' merge update' FROM cte_init 
WHERE a = 1 LIMIT 1)
+WHEN NOT MATCHED THEN INSERT VALUES(o.k, o.v);
+
+-- MERGE source comes from CTE:
+WITH merge_source_cte AS MATERIALIZED (SELECT 15 a, 'merge_source_cte val' b)
+MERGE INTO m USING (select * from merge_source_cte) o ON m.k=o.a
+WHEN MATCHED THEN UPDATE SET v = (SELECT b || merge_source_cte.*::text || ' 
merge update' FROM merge_source_cte WHERE a = 15)
+WHEN NOT MATCHED THEN INSERT VALUES(o.a, o.b || (SELECT 
merge_source_cte.*::text || ' merge insert' FROM merge_source_cte));
+-- Examine
+SELECT * FROM m where k = 15;
+
+-- See EXPLAIN output for same query:
+EXPLAIN (VERBOSE, COSTS OFF)
+WITH merge_source_cte AS MATERIALIZED (SELECT 15 a, 'merge_source_cte val' b)
+MERGE INTO m USING (select * from merge_source_cte) o ON m.k=o.a
+WHEN MATCHED THEN UPDATE SET v = (SELECT b || merge_source_cte.*::text || ' 
merge update' FROM merge_source_cte WHERE a = 15)
+WHEN NOT MATCHED THEN INSERT VALUES(o.a, o.b || (SELECT 
merge_source_cte.*::text || ' merge insert' FROM merge_source_cte));
+
+DROP TABLE m;
 
 -- check that run to completion happens in proper ordering
 


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to