Fix handling of GENERATED columns in CREATE TABLE LIKE INCLUDING DEFAULTS.

LIKE INCLUDING DEFAULTS tried to copy the attrdef expression without
copying the state of the attgenerated column.  This is in fact wrong,
because GENERATED and DEFAULT expressions are not the same kind of animal;
one can contain Vars and the other not.  We *must* copy attgenerated
when we're copying the attrdef expression.  Rearrange the if-tests
so that the expression is copied only when the correct one of
INCLUDING DEFAULTS and INCLUDING GENERATED has been specified.

Per private report from Manuel Rigger.

Tom Lane and Peter Eisentraut
This commit is contained in:
Tom Lane 2019-09-25 17:30:42 -04:00
parent bffe1bd684
commit b81a9c2fc5
3 changed files with 100 additions and 6 deletions

View File

@ -1023,11 +1023,13 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
attmap[parent_attno - 1] = list_length(cxt->columns);
/*
* Copy default, if present and the default has been requested
* Copy default, if present and it should be copied. We have separate
* options for plain default expressions and GENERATED defaults.
*/
if (attribute->atthasdef &&
(table_like_clause->options & CREATE_TABLE_LIKE_DEFAULTS ||
table_like_clause->options & CREATE_TABLE_LIKE_GENERATED))
(attribute->attgenerated ?
(table_like_clause->options & CREATE_TABLE_LIKE_GENERATED) :
(table_like_clause->options & CREATE_TABLE_LIKE_DEFAULTS)))
{
Node *this_default = NULL;
AttrDefault *attrdef;
@ -1065,9 +1067,7 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
attributeName,
RelationGetRelationName(relation))));
if (attribute->attgenerated &&
(table_like_clause->options & CREATE_TABLE_LIKE_GENERATED))
def->generated = attribute->attgenerated;
def->generated = attribute->attgenerated;
}
/*

View File

@ -159,6 +159,80 @@ 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);
\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
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
Table "public.test_like_4a"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
a | integer | | |
b | integer | | |
c | integer | | |
INSERT INTO test_like_4a VALUES(11);
TABLE test_like_4a;
a | b | c
----+---+---
11 | |
(1 row)
\d test_like_4b
Table "public.test_like_4b"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
a | integer | | |
b | integer | | | 42
c | integer | | |
INSERT INTO test_like_4b VALUES(11);
TABLE test_like_4b;
a | b | c
----+----+---
11 | 42 |
(1 row)
\d test_like_4c
Table "public.test_like_4c"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+------------------------------------
a | integer | | |
b | integer | | |
c | integer | | | generated always as (a * 2) stored
INSERT INTO test_like_4c VALUES(11);
TABLE test_like_4c;
a | b | c
----+---+----
11 | | 22
(1 row)
\d test_like_4d
Table "public.test_like_4d"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+------------------------------------
a | integer | | |
b | integer | | | 42
c | integer | | | generated always as (a * 2) stored
INSERT INTO test_like_4d VALUES(11);
TABLE test_like_4d;
a | b | c
----+----+----
11 | 42 | 22
(1 row)
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 */
INSERT INTO inhg VALUES (5, 10);
INSERT INTO inhg VALUES (20, 10); -- should fail

View File

@ -65,6 +65,26 @@ 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);
\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;
\d test_like_4b
INSERT INTO test_like_4b VALUES(11);
TABLE test_like_4b;
\d test_like_4c
INSERT INTO test_like_4c VALUES(11);
TABLE test_like_4c;
\d test_like_4d
INSERT INTO test_like_4d VALUES(11);
TABLE 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 */
INSERT INTO inhg VALUES (5, 10);
INSERT INTO inhg VALUES (20, 10); -- should fail