diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c index a8c2af4c5d..c5c67ec5b4 100644 --- a/src/backend/parser/parse_utilcmd.c +++ b/src/backend/parser/parse_utilcmd.c @@ -914,6 +914,7 @@ static void transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_clause) { AttrNumber parent_attno; + AttrNumber new_attno; Relation relation; TupleDesc tupleDesc; TupleConstr *constr; @@ -976,6 +977,26 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla */ attmap = (AttrNumber *) palloc0(sizeof(AttrNumber) * tupleDesc->natts); + /* + * We must fill the attmap now so that it can be used to process generated + * column default expressions in the per-column loop below. + */ + new_attno = 1; + for (parent_attno = 1; parent_attno <= tupleDesc->natts; + parent_attno++) + { + Form_pg_attribute attribute = TupleDescAttr(tupleDesc, + parent_attno - 1); + + /* + * Ignore dropped columns in the parent. attmap entry is left zero. + */ + if (attribute->attisdropped) + continue; + + attmap[parent_attno - 1] = list_length(cxt->columns) + (new_attno++); + } + /* * Insert the copied attributes into the cxt for the new table definition. */ @@ -988,7 +1009,7 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla ColumnDef *def; /* - * Ignore dropped columns in the parent. attmap entry is left zero. + * Ignore dropped columns in the parent. */ if (attribute->attisdropped) continue; @@ -1020,8 +1041,6 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla */ cxt->columns = lappend(cxt->columns, def); - attmap[parent_attno - 1] = list_length(cxt->columns); - /* * Copy default, if present and it should be copied. We have separate * options for plain default expressions and GENERATED defaults. diff --git a/src/test/regress/expected/create_table_like.out b/src/test/regress/expected/create_table_like.out index 2a063a8369..da0e8ac298 100644 --- a/src/test/regress/expected/create_table_like.out +++ b/src/test/regress/expected/create_table_like.out @@ -159,14 +159,15 @@ SELECT * FROM test_like_gen_3; (1 row) DROP TABLE test_like_gen_1, test_like_gen_2, test_like_gen_3; -CREATE TABLE test_like_4 (a int, b int DEFAULT 42, c int GENERATED ALWAYS AS (a * 2) STORED); +-- also test generated column with a "forward" reference (bug #16342) +CREATE TABLE test_like_4 (b int DEFAULT 42, c int GENERATED ALWAYS AS (a * 2) STORED, a int); \d test_like_4 Table "public.test_like_4" Column | Type | Collation | Nullable | Default --------+---------+-----------+----------+------------------------------------ - a | integer | | | b | integer | | | 42 c | integer | | | generated always as (a * 2) stored + a | integer | | | CREATE TABLE test_like_4a (LIKE test_like_4); CREATE TABLE test_like_4b (LIKE test_like_4 INCLUDING DEFAULTS); @@ -176,12 +177,12 @@ CREATE TABLE test_like_4d (LIKE test_like_4 INCLUDING DEFAULTS INCLUDING GENERAT Table "public.test_like_4a" Column | Type | Collation | Nullable | Default --------+---------+-----------+----------+--------- - a | integer | | | b | integer | | | c | integer | | | + a | integer | | | -INSERT INTO test_like_4a VALUES(11); -TABLE test_like_4a; +INSERT INTO test_like_4a (a) VALUES(11); +SELECT a, b, c FROM test_like_4a; a | b | c ----+---+--- 11 | | @@ -191,12 +192,12 @@ TABLE test_like_4a; Table "public.test_like_4b" Column | Type | Collation | Nullable | Default --------+---------+-----------+----------+--------- - a | integer | | | b | integer | | | 42 c | integer | | | + a | integer | | | -INSERT INTO test_like_4b VALUES(11); -TABLE test_like_4b; +INSERT INTO test_like_4b (a) VALUES(11); +SELECT a, b, c FROM test_like_4b; a | b | c ----+----+--- 11 | 42 | @@ -206,12 +207,12 @@ TABLE test_like_4b; Table "public.test_like_4c" Column | Type | Collation | Nullable | Default --------+---------+-----------+----------+------------------------------------ - a | integer | | | b | integer | | | c | integer | | | generated always as (a * 2) stored + a | integer | | | -INSERT INTO test_like_4c VALUES(11); -TABLE test_like_4c; +INSERT INTO test_like_4c (a) VALUES(11); +SELECT a, b, c FROM test_like_4c; a | b | c ----+---+---- 11 | | 22 @@ -221,12 +222,12 @@ TABLE test_like_4c; Table "public.test_like_4d" Column | Type | Collation | Nullable | Default --------+---------+-----------+----------+------------------------------------ - a | integer | | | b | integer | | | 42 c | integer | | | generated always as (a * 2) stored + a | integer | | | -INSERT INTO test_like_4d VALUES(11); -TABLE test_like_4d; +INSERT INTO test_like_4d (a) VALUES(11); +SELECT a, b, c FROM test_like_4d; a | b | c ----+----+---- 11 | 42 | 22 diff --git a/src/test/regress/sql/create_table_like.sql b/src/test/regress/sql/create_table_like.sql index 589ee12ebc..5d30f63e00 100644 --- a/src/test/regress/sql/create_table_like.sql +++ b/src/test/regress/sql/create_table_like.sql @@ -65,24 +65,25 @@ INSERT INTO test_like_gen_3 (a) VALUES (1); SELECT * FROM test_like_gen_3; DROP TABLE test_like_gen_1, test_like_gen_2, test_like_gen_3; -CREATE TABLE test_like_4 (a int, b int DEFAULT 42, c int GENERATED ALWAYS AS (a * 2) STORED); +-- also test generated column with a "forward" reference (bug #16342) +CREATE TABLE test_like_4 (b int DEFAULT 42, c int GENERATED ALWAYS AS (a * 2) STORED, a int); \d test_like_4 CREATE TABLE test_like_4a (LIKE test_like_4); CREATE TABLE test_like_4b (LIKE test_like_4 INCLUDING DEFAULTS); CREATE TABLE test_like_4c (LIKE test_like_4 INCLUDING GENERATED); CREATE TABLE test_like_4d (LIKE test_like_4 INCLUDING DEFAULTS INCLUDING GENERATED); \d test_like_4a -INSERT INTO test_like_4a VALUES(11); -TABLE test_like_4a; +INSERT INTO test_like_4a (a) VALUES(11); +SELECT a, b, c FROM test_like_4a; \d test_like_4b -INSERT INTO test_like_4b VALUES(11); -TABLE test_like_4b; +INSERT INTO test_like_4b (a) VALUES(11); +SELECT a, b, c FROM test_like_4b; \d test_like_4c -INSERT INTO test_like_4c VALUES(11); -TABLE test_like_4c; +INSERT INTO test_like_4c (a) VALUES(11); +SELECT a, b, c FROM test_like_4c; \d test_like_4d -INSERT INTO test_like_4d VALUES(11); -TABLE test_like_4d; +INSERT INTO test_like_4d (a) VALUES(11); +SELECT a, b, c FROM test_like_4d; DROP TABLE test_like_4, test_like_4a, test_like_4b, test_like_4c, test_like_4d; CREATE TABLE inhg (x text, LIKE inhx INCLUDING INDEXES, y text); /* copies indexes */