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

yjhjstz pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cloudberry.git


The following commit(s) were added to refs/heads/main by this push:
     new 95486365241 Fix ORCA choosing wrong column type for CTAS with UNION 
ALL (#1431) (#1645)
95486365241 is described below

commit 95486365241206725901fb2e1c5fa97149f155fa
Author: Jianghua.yjh <[email protected]>
AuthorDate: Wed Apr 1 05:43:21 2026 -0700

    Fix ORCA choosing wrong column type for CTAS with UNION ALL (#1431) (#1645)
    
    * Fix ORCA choosing wrong column type for CTAS with UNION ALL (#1431)
    
    When removing redundant Result nodes in the ORCA post-processing,
    push_down_expr_mutator replaces parent Var nodes with child expressions.
    It already propagates typmod for Const child expressions, but missed the
    case where the child expression is also a Var. This caused the correctly
    resolved common typmod (e.g. -1 for varchar without length) to be
    overwritten by the child's original typmod (e.g. varchar(1)), resulting
    in wrong column types in the created table.
    
    * Add regression test for CTAS with UNION ALL typmod fix (#1431)
    
    Verify that ORCA produces the correct column type (character varying
    without length limit) when creating a table from UNION ALL of branches
    with different varchar lengths.
    
    ---------
    
    Co-authored-by: reshke <[email protected]>
---
 src/backend/optimizer/plan/orca.c                |   4 +
 src/test/regress/expected/union_gp.out           |  30 +++++
 src/test/regress/expected/union_gp_optimizer.out | 134 +++++++++++++++--------
 src/test/regress/sql/union_gp.sql                |  25 ++++-
 4 files changed, 147 insertions(+), 46 deletions(-)

diff --git a/src/backend/optimizer/plan/orca.c 
b/src/backend/optimizer/plan/orca.c
index 97f63f7a334..514385cc2e9 100644
--- a/src/backend/optimizer/plan/orca.c
+++ b/src/backend/optimizer/plan/orca.c
@@ -545,6 +545,10 @@ push_down_expr_mutator(Node *node, List *child_tlist)
                        {
                                ((Const *) child_tle->expr)->consttypmod = 
((Var *) node)->vartypmod;
                        }
+                       else if (IsA(child_tle->expr, Var))
+                       {
+                               ((Var *) child_tle->expr)->vartypmod = ((Var *) 
node)->vartypmod;
+                       }
 
                        return (Node *) child_tle->expr;
                }
diff --git a/src/test/regress/expected/union_gp.out 
b/src/test/regress/expected/union_gp.out
index 5bdae3e887c..d134f223502 100644
--- a/src/test/regress/expected/union_gp.out
+++ b/src/test/regress/expected/union_gp.out
@@ -2342,6 +2342,36 @@ with result as (update r_1240 set a = a +1 where a < 5 
returning *) select * fro
 drop table r_1240;
 drop table p1_1240;
 --
+-- Test CTAS with UNION ALL when branches have different typmods (issue #1431).
+-- ORCA should resolve the output column type to character varying (no length),
+-- same as the Postgres planner, instead of picking the first branch's typmod.
+--
+create table union_ctas_t1(id int, name varchar(1));
+create table union_ctas_t2(id int, name varchar(2));
+insert into union_ctas_t1 values (1, 'a');
+insert into union_ctas_t2 values (1, 'ab');
+create table union_ctas_result as
+  (select id, name from union_ctas_t1)
+  union all
+  (select id, name from union_ctas_t2);
+-- name column should be "character varying" without length, not varchar(1)
+select atttypmod from pg_attribute
+where attrelid = 'union_ctas_result'::regclass and attname = 'name';
+ atttypmod 
+-----------
+        -1
+(1 row)
+
+-- data should not be truncated
+select * from union_ctas_result order by name;
+ id | name 
+----+------
+  1 | a
+  1 | ab
+(2 rows)
+
+drop table union_ctas_t1, union_ctas_t2, union_ctas_result;
+--
 -- Clean up
 --
 DROP TABLE IF EXISTS T_a1 CASCADE;
diff --git a/src/test/regress/expected/union_gp_optimizer.out 
b/src/test/regress/expected/union_gp_optimizer.out
index 8ff8655591d..8704f0fe7a7 100644
--- a/src/test/regress/expected/union_gp_optimizer.out
+++ b/src/test/regress/expected/union_gp_optimizer.out
@@ -1,7 +1,7 @@
 -- Additional GPDB-added tests for UNION
 SET optimizer_trace_fallback=on;
 create temp table t_union1 (a int, b int);
-NOTICE:  Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'a' 
as the Greenplum Database data distribution key for this table.
+NOTICE:  Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'a' 
as the Apache Cloudberry data distribution key for this table.
 HINT:  The 'DISTRIBUTED BY' clause determines the distribution of data. Make 
sure column(s) chosen are the optimal data distribution key to minimize skew.
 select distinct a, null::integer as c from t_union1 union select a, b from 
t_union1;
  a | c 
@@ -44,8 +44,8 @@ LINE 1: select 1 intersect (select 1, 2 union all select 3, 
4);
 select 1 a, row_number() over (partition by 'a') union all (select 1 a , 2 b);
  a | row_number 
 ---+------------
- 1 |          2
  1 |          1
+ 1 |          2
 (2 rows)
 
 -- This should preserve domain types
@@ -104,8 +104,7 @@ DETAIL:  Falling back to Postgres-based planner because 
GPORCA does not support
 (1 row)
 
 CREATE TABLE union_ctas (a, b) AS SELECT 1, 2 UNION SELECT 1, 1 UNION SELECT 
1, 1;
-NOTICE:  Table doesn't have 'DISTRIBUTED BY' clause -- Using column(s) named 
'a' as the Greenplum Database data distribution key for this table.
-HINT:  The 'DISTRIBUTED BY' clause determines the distribution of data. Make 
sure column(s) chosen are the optimal data distribution key to minimize skew.
+NOTICE:  Table doesn't have 'DISTRIBUTED BY' clause. Creating a NULL policy 
entry.
 SELECT * FROM union_ctas;
  a | b 
 ---+---
@@ -116,11 +115,9 @@ SELECT * FROM union_ctas;
 DROP TABLE union_ctas;
 -- MPP-21075: push quals below union
 CREATE TABLE union_quals1 (a, b) AS SELECT i, i%2 from generate_series(1,10) i;
-NOTICE:  Table doesn't have 'DISTRIBUTED BY' clause -- Using column(s) named 
'a' as the Greenplum Database data distribution key for this table.
-HINT:  The 'DISTRIBUTED BY' clause determines the distribution of data. Make 
sure column(s) chosen are the optimal data distribution key to minimize skew.
+NOTICE:  Table doesn't have 'DISTRIBUTED BY' clause. Creating a NULL policy 
entry.
 CREATE TABLE union_quals2 (a, b) AS SELECT i%2, i from generate_series(1,10) i;
-NOTICE:  Table doesn't have 'DISTRIBUTED BY' clause -- Using column(s) named 
'a' as the Greenplum Database data distribution key for this table.
-HINT:  The 'DISTRIBUTED BY' clause determines the distribution of data. Make 
sure column(s) chosen are the optimal data distribution key to minimize skew.
+NOTICE:  Table doesn't have 'DISTRIBUTED BY' clause. Creating a NULL policy 
entry.
 SELECT * FROM (SELECT a, b from union_quals1 UNION SELECT b, a from 
union_quals2) as foo(a,b) where a > b order by a;
  a  | b 
 ----+---
@@ -225,7 +222,7 @@ select distinct a from (select  distinct 'A' from (select 
'C' from (select disti
 -- on a single QE.
 --
 CREATE TABLE test1 (id int);
-NOTICE:  Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'id' 
as the Greenplum Database data distribution key for this table.
+NOTICE:  Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'id' 
as the Apache Cloudberry data distribution key for this table.
 HINT:  The 'DISTRIBUTED BY' clause determines the distribution of data. Make 
sure column(s) chosen are the optimal data distribution key to minimize skew.
 insert into test1 values (1);
 CREATE EXTERNAL WEB TABLE test2 (id int) EXECUTE 'echo 2' ON COORDINATOR 
FORMAT 'csv';
@@ -234,8 +231,8 @@ union
 (SELECT 'test2' as branch, id FROM test2);
  branch | id 
 --------+----
- test1  |  1
  test2  |  2
+ test1  |  1
 (2 rows)
 
 explain (SELECT 'test1' as branch, id FROM test1 LIMIT 1)
@@ -243,10 +240,10 @@ union
 (SELECT 'test2' as branch, id FROM test2);
                                                           QUERY PLAN           
                                               
 
------------------------------------------------------------------------------------------------------------------------------
- Gather Motion 3:1  (slice1; segments: 3)  (cost=0.00..984.78 rows=1125 
width=12)
-   ->  HashAggregate  (cost=0.00..984.73 rows=375 width=12)
+ Gather Motion 3:1  (slice1; segments: 3)  (cost=0.00..985.86 rows=1125 
width=12)
+   ->  HashAggregate  (cost=0.00..985.81 rows=375 width=12)
          Group Key: ('test1'::text), test1.id
-         ->  Append  (cost=0.00..984.65 rows=334 width=12)
+         ->  Append  (cost=0.00..985.73 rows=334 width=12)
                ->  Redistribute Motion 1:3  (slice2)  (cost=0.00..431.00 
rows=1 width=12)
                      Hash Key: ('test1'::text), test1.id
                      ->  GroupAggregate  (cost=0.00..431.00 rows=1 width=12)
@@ -257,16 +254,16 @@ union
                                        ->  Result  (cost=0.00..431.00 rows=1 
width=12)
                                              ->  Gather Motion 3:1  (slice3; 
segments: 3)  (cost=0.00..431.00 rows=1 width=4)
                                                    ->  Seq Scan on test1  
(cost=0.00..431.00 rows=1 width=4)
-               ->  HashAggregate  (cost=0.00..553.64 rows=334 width=12)
-                     Group Key: ('test2'::text), test2.id
-                     ->  Redistribute Motion 3:3  (slice4; segments: 3)  
(cost=0.00..553.56 rows=334 width=12)
-                           Hash Key: ('test2'::text), test2.id
-                           ->  Streaming HashAggregate  (cost=0.00..553.55 
rows=334 width=12)
-                                 Group Key: 'test2'::text, test2.id
-                                 ->  Result  (cost=0.00..471.53 rows=333334 
width=12)
-                                       ->  Redistribute Motion 1:3  (slice5)  
(cost=0.00..467.53 rows=333334 width=4)
-                                             ->  Foreign Scan on test2  
(cost=0.00..449.70 rows=1000000 width=4)
- Optimizer: Pivotal Optimizer (GPORCA)
+               ->  HashAggregate  (cost=0.00..554.73 rows=334 width=12)
+                     Group Key: ('test2'::text), id
+                     ->  Redistribute Motion 3:3  (slice4; segments: 3)  
(cost=0.00..554.64 rows=334 width=12)
+                           Hash Key: ('test2'::text), id
+                           ->  Streaming HashAggregate  (cost=0.00..554.63 
rows=334 width=12)
+                                 Group Key: 'test2'::text, id
+                                 ->  Result  (cost=0.00..473.73 rows=333334 
width=12)
+                                       ->  Redistribute Motion 1:3  (slice5)  
(cost=0.00..469.73 rows=333334 width=4)
+                                             ->  Foreign Scan on test2  
(cost=0.00..451.90 rows=1000000 width=4)
+ Optimizer: GPORCA
 (24 rows)
 
 --
@@ -320,8 +317,8 @@ INFO:  GPORCA failed to produce a plan, falling back to 
Postgres-based planner
 DETAIL:  Unknown error: Partially Distributed Data
                                       QUERY PLAN                               
        
 
---------------------------------------------------------------------------------------
- Gather Motion 1:1  (slice1; segments: 1)  (cost=1922.00..1922.00 rows=172200 
width=8)
-   ->  Append  (cost=0.00..1922.00 rows=172200 width=8)
+ Gather Motion 1:1  (slice1; segments: 1)  (cost=2783.00..2783.00 rows=172200 
width=8)
+   ->  Append  (cost=0.00..2783.00 rows=172200 width=8)
          ->  Seq Scan on rep2  (cost=0.00..961.00 rows=86100 width=8)
          ->  Seq Scan on rep3  (cost=0.00..961.00 rows=86100 width=8)
  Optimizer: Postgres query optimizer
@@ -353,7 +350,7 @@ INSERT INTO T_a1 SELECT i, i%5 from generate_series(1,10) i;
 CREATE TABLE T_b2 (b1 int, b2 int) DISTRIBUTED BY(b2);
 INSERT INTO T_b2 SELECT i, i%5 from generate_series(1,20) i;
 CREATE TABLE T_random (c1 int, c2 int);
-NOTICE:  Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'c1' 
as the Greenplum Database data distribution key for this table.
+NOTICE:  Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'c1' 
as the Apache Cloudberry data distribution key for this table.
 HINT:  The 'DISTRIBUTED BY' clause determines the distribution of data. Make 
sure column(s) chosen are the optimal data distribution key to minimize skew.
 INSERT INTO T_random SELECT i, i%5 from generate_series(1,30) i;
 --start_ignore
@@ -2079,14 +2076,18 @@ insert into t1_ncols values (1, 11, 'one', 
'2001-01-01');
 insert into t2_ncols values (2, 22, 'two', '2002-02-02');
 insert into t2_ncols values (4, 44, 'four','2004-04-04');
 select b from t1_ncols union all select a from t2_ncols;
+NOTICE:  One or more columns in the following table(s) do not have statistics: 
t2_ncols
+HINT:  For non-partitioned tables, run analyze <table_name>(<column_list>). 
For partitioned tables, run analyze rootpartition <table_name>(<column_list>). 
See log for columns missing statistics.
  b  
 ----
-  4
-  2
  11
+  2
+  4
 (3 rows)
 
 select a+100, b, d from t1_ncols union select b, a+200, d from t2_ncols order 
by 1;
+NOTICE:  One or more columns in the following table(s) do not have statistics: 
t2_ncols
+HINT:  For non-partitioned tables, run analyze <table_name>(<column_list>). 
For partitioned tables, run analyze rootpartition <table_name>(<column_list>). 
See log for columns missing statistics.
  ?column? |  b  |     d      
 ----------+-----+------------
        22 | 202 | 02-02-2002
@@ -2095,15 +2096,19 @@ select a+100, b, d from t1_ncols union select b, a+200, 
d from t2_ncols order by
 (3 rows)
 
 select c, a from v1_ncols;
+NOTICE:  One or more columns in the following table(s) do not have statistics: 
t2_ncols
+HINT:  For non-partitioned tables, run analyze <table_name>(<column_list>). 
For partitioned tables, run analyze rootpartition <table_name>(<column_list>). 
See log for columns missing statistics.
   c   | a 
 ------+---
  one  | 1
- four | 4
  two  | 2
+ four | 4
 (3 rows)
 
 with cte1(aa, b, c, d) as (select a*100, b, c, d from t1_ncols union select * 
from t2_ncols)
 select x.aa/100 aaa, x.c, y.c from cte1 x join cte1 y on x.aa=y.aa;
+NOTICE:  One or more columns in the following table(s) do not have statistics: 
t2_ncols
+HINT:  For non-partitioned tables, run analyze <table_name>(<column_list>). 
For partitioned tables, run analyze rootpartition <table_name>(<column_list>). 
See log for columns missing statistics.
  aaa |  c   |  c   
 -----+------+------
    0 | two  | two
@@ -2122,13 +2127,13 @@ NOTICE:  schema "union_schema" does not exist, skipping
 -- end_ignore
 create schema union_schema;
 create table union_schema.t1(a int, b int);
-NOTICE:  Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'a' 
as the Greenplum Database data distribution key for this table.
+NOTICE:  Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'a' 
as the Apache Cloudberry data distribution key for this table.
 HINT:  The 'DISTRIBUTED BY' clause determines the distribution of data. Make 
sure column(s) chosen are the optimal data distribution key to minimize skew.
 create table union_schema.t2(a int, b int);
-NOTICE:  Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'a' 
as the Greenplum Database data distribution key for this table.
+NOTICE:  Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'a' 
as the Apache Cloudberry data distribution key for this table.
 HINT:  The 'DISTRIBUTED BY' clause determines the distribution of data. Make 
sure column(s) chosen are the optimal data distribution key to minimize skew.
 create table union_schema.t3(a int, b int);
-NOTICE:  Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'a' 
as the Greenplum Database data distribution key for this table.
+NOTICE:  Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'a' 
as the Apache Cloudberry data distribution key for this table.
 HINT:  The 'DISTRIBUTED BY' clause determines the distribution of data. Make 
sure column(s) chosen are the optimal data distribution key to minimize skew.
 set allow_system_table_mods = on;
 update gp_distribution_policy set numsegments = 1
@@ -2188,8 +2193,8 @@ INFO:  GPORCA failed to produce a plan, falling back to 
Postgres-based planner
 DETAIL:  Unknown error: Partially Distributed Data
                                              QUERY PLAN                        
                      
 
-----------------------------------------------------------------------------------------------------
- Gather Motion 3:1  (slice1; segments: 3)  (cost=1.23..1472.30 rows=86130 
width=8)
-   ->  Append  (cost=1.23..323.90 rows=28710 width=8)
+ Gather Motion 3:1  (slice1; segments: 3)  (cost=1.23..1615.85 rows=86130 
width=8)
+   ->  Append  (cost=1.23..467.45 rows=28710 width=8)
          ->  Hash Join  (cost=1.23..2.80 rows=10 width=8)
                Hash Cond: (t2.b = t1.a)
                ->  Redistribute Motion 2:3  (slice2; segments: 2)  
(cost=0.00..1.40 rows=20 width=4)
@@ -2208,6 +2213,8 @@ INFO:  GPORCA failed to produce a plan, falling back to 
Postgres-based planner
 DETAIL:  Unknown error: Partially Distributed Data
  a  | b  | a  | b  
 ----+----+----+----
+  1 |  1 |  1 |  1
+  5 |  5 |  5 |  5
   2 |  2 |  2 |  2
   3 |  3 |  3 |  3
   4 |  4 |  4 |  4
@@ -2216,8 +2223,6 @@ DETAIL:  Unknown error: Partially Distributed Data
   8 |  8 |  8 |  8
   9 |  9 |  9 |  9
  10 | 10 | 10 | 10
-  1 |  1 |  1 |  1
-  5 |  5 |  5 |  5
 (10 rows)
 
 select union_schema.t1.a, union_schema.t2.b
@@ -2229,6 +2234,8 @@ INFO:  GPORCA failed to produce a plan, falling back to 
Postgres-based planner
 DETAIL:  Unknown error: Partially Distributed Data
  a  | b  
 ----+----
+  1 |  1
+  5 |  5
   2 |  2
   3 |  3
   4 |  4
@@ -2237,8 +2244,6 @@ DETAIL:  Unknown error: Partially Distributed Data
   8 |  8
   9 |  9
  10 | 10
-  1 |  1
-  5 |  5
 (10 rows)
 
 truncate union_schema.t1, union_schema.t2;
@@ -2276,8 +2281,8 @@ INFO:  GPORCA failed to produce a plan, falling back to 
Postgres-based planner
 DETAIL:  Unknown error: Partially Distributed Data
                                                 QUERY PLAN                     
                            
 
-----------------------------------------------------------------------------------------------------------
- Gather Motion 3:1  (slice1; segments: 3)  (cost=1.32..1472.20 rows=86130 
width=8)
-   ->  Append  (cost=1.32..323.80 rows=28710 width=8)
+ Gather Motion 3:1  (slice1; segments: 3)  (cost=1.32..1615.75 rows=86130 
width=8)
+   ->  Append  (cost=1.32..467.35 rows=28710 width=8)
          ->  Hash Join  (cost=1.32..2.70 rows=10 width=8)
                Hash Cond: (t1.a = t2.b)
                ->  Seq Scan on t1  (cost=0.00..1.20 rows=20 width=4)
@@ -2340,6 +2345,8 @@ reset allow_system_table_mods;
 create table rep (a int) distributed replicated;
 insert into rep select i from generate_series (1, 10) i; 
 create table dist (a int);
+NOTICE:  Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'a' 
as the Apache Cloudberry data distribution key for this table.
+HINT:  The 'DISTRIBUTED BY' clause determines the distribution of data. Make 
sure column(s) chosen are the optimal data distribution key to minimize skew.
 insert into dist select i from generate_series (1, 1000) i;
 analyze dist;
 analyze rep;
@@ -2352,7 +2359,7 @@ explain select a from rep union all select a from dist;
  Gather Motion 3:1  (slice1; segments: 3)  (cost=0.00..862.03 rows=1010 
width=4)
    ->  Append  (cost=0.00..862.01 rows=337 width=4)
          ->  Result  (cost=0.00..431.00 rows=4 width=4)
-               One-Time Filter: (gp_execution_segment() = 2)
+               One-Time Filter: (gp_execution_segment() = 0)
                ->  Seq Scan on rep  (cost=0.00..431.00 rows=10 width=4)
          ->  Seq Scan on dist  (cost=0.00..431.01 rows=334 width=4)
  Optimizer: GPORCA
@@ -2368,12 +2375,12 @@ analyze rand;
 explain select i from generate_series(1,1000) i union all select a from rand;
                                        QUERY PLAN                              
         
 
----------------------------------------------------------------------------------------
- Gather Motion 3:1  (slice1; segments: 3)  (cost=0.00..431.28 rows=11000 
width=4)
+ Gather Motion 3:1  (slice1; segments: 3)  (cost=0.00..431.29 rows=11000 
width=4)
    ->  Append  (cost=0.00..431.12 rows=3667 width=4)
          ->  Result  (cost=0.00..0.01 rows=334 width=4)
-               One-Time Filter: (gp_execution_segment() = 2)
+               One-Time Filter: (gp_execution_segment() = 0)
                ->  Function Scan on generate_series  (cost=0.00..0.00 rows=334 
width=4)
-         ->  Seq Scan on rand  (cost=0.00..431.06 rows=3334 width=4)
+         ->  Seq Scan on rand  (cost=0.00..431.07 rows=3334 width=4)
  Optimizer: GPORCA
 (7 rows)
 
@@ -2460,7 +2467,7 @@ DETAIL:  Falling back to Postgres-based planner because 
GPORCA does not support
          ->  Gather Motion 3:1  (slice2; segments: 3)
                ->  Subquery Scan on "*SELECT* 2"
                      ->  Seq Scan on p1_1240
- Optimizer: Postgres-based planner
+ Optimizer: Postgres query optimizer
 (11 rows)
 
 with result as (update r_1240 set a = a +1 where a < 5 returning *) select * 
from result except select * from p1_1240;
@@ -2475,6 +2482,43 @@ DETAIL:  Falling back to Postgres-based planner because 
GPORCA does not support
 drop table r_1240;
 drop table p1_1240;
 --
+-- Test CTAS with UNION ALL when branches have different typmods (issue #1431).
+-- ORCA should resolve the output column type to character varying (no length),
+-- same as the Postgres planner, instead of picking the first branch's typmod.
+--
+create table union_ctas_t1(id int, name varchar(1));
+NOTICE:  Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'id' 
as the Apache Cloudberry data distribution key for this table.
+HINT:  The 'DISTRIBUTED BY' clause determines the distribution of data. Make 
sure column(s) chosen are the optimal data distribution key to minimize skew.
+create table union_ctas_t2(id int, name varchar(2));
+NOTICE:  Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'id' 
as the Apache Cloudberry data distribution key for this table.
+HINT:  The 'DISTRIBUTED BY' clause determines the distribution of data. Make 
sure column(s) chosen are the optimal data distribution key to minimize skew.
+insert into union_ctas_t1 values (1, 'a');
+insert into union_ctas_t2 values (1, 'ab');
+create table union_ctas_result as
+  (select id, name from union_ctas_t1)
+  union all
+  (select id, name from union_ctas_t2);
+NOTICE:  Table doesn't have 'DISTRIBUTED BY' clause. Creating a NULL policy 
entry.
+-- name column should be "character varying" without length, not varchar(1)
+select atttypmod from pg_attribute
+where attrelid = 'union_ctas_result'::regclass and attname = 'name';
+INFO:  GPORCA failed to produce a plan, falling back to Postgres-based planner
+DETAIL:  Falling back to Postgres-based planner because GPORCA does not 
support the following feature: Queries on master-only tables
+ atttypmod 
+-----------
+        -1
+(1 row)
+
+-- data should not be truncated
+select * from union_ctas_result order by name;
+ id | name 
+----+------
+  1 | a
+  1 | ab
+(2 rows)
+
+drop table union_ctas_t1, union_ctas_t2, union_ctas_result;
+--
 -- Clean up
 --
 DROP TABLE IF EXISTS T_a1 CASCADE;
diff --git a/src/test/regress/sql/union_gp.sql 
b/src/test/regress/sql/union_gp.sql
index e7cac952704..9e9e5c3a815 100644
--- a/src/test/regress/sql/union_gp.sql
+++ b/src/test/regress/sql/union_gp.sql
@@ -721,9 +721,32 @@ drop table r_1240;
 drop table p1_1240;
 
 --
--- Clean up
+-- Test CTAS with UNION ALL when branches have different typmods (issue #1431).
+-- ORCA should resolve the output column type to character varying (no length),
+-- same as the Postgres planner, instead of picking the first branch's typmod.
 --
+create table union_ctas_t1(id int, name varchar(1));
+create table union_ctas_t2(id int, name varchar(2));
+insert into union_ctas_t1 values (1, 'a');
+insert into union_ctas_t2 values (1, 'ab');
+
+create table union_ctas_result as
+  (select id, name from union_ctas_t1)
+  union all
+  (select id, name from union_ctas_t2);
+
+-- name column should be "character varying" without length, not varchar(1)
+select atttypmod from pg_attribute
+where attrelid = 'union_ctas_result'::regclass and attname = 'name';
+
+-- data should not be truncated
+select * from union_ctas_result order by name;
 
+drop table union_ctas_t1, union_ctas_t2, union_ctas_result;
+
+--
+-- Clean up
+--
 DROP TABLE IF EXISTS T_a1 CASCADE;
 DROP TABLE IF EXISTS T_b2 CASCADE;
 DROP TABLE IF EXISTS T_random CASCADE;


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

Reply via email to