Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 1597948

Browse files
committed
Fix application of identity values in some cases
Investigation of 2d2d06b revealed that identity values were not applied in some further cases, including logical replication subscribers, VALUES RTEs, and ALTER TABLE ... ADD COLUMN. To fix all that, apply the identity column expression in build_column_default() instead of repeating the same logic at each call site. For ALTER TABLE ... ADD COLUMN ... IDENTITY, the previous coding completely ignored that existing rows for the new column should have values filled in from the identity sequence. The coding using build_column_default() fails for this because the sequence ownership isn't registered until after ALTER TABLE, and we can't do it before because we don't have the column in the catalog yet. So we specially remember in ColumnDef the sequence name that we decided on and build a custom NextValueExpr using that. Reviewed-by: Michael Paquier <michael.paquier@gmail.com>
1 parent b94988f commit 1597948

File tree

11 files changed

+102
-30
lines changed

11 files changed

+102
-30
lines changed

src/backend/commands/copy.c

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
#include "access/sysattr.h"
2626
#include "access/xact.h"
2727
#include "access/xlog.h"
28-
#include "catalog/dependency.h"
2928
#include "catalog/pg_type.h"
3029
#include "commands/copy.h"
3130
#include "commands/defrem.h"
@@ -3064,19 +3063,8 @@ BeginCopyFrom(ParseState *pstate,
30643063
{
30653064
/* attribute is NOT to be copied from input */
30663065
/* use default value if one exists */
3067-
Expr *defexpr;
3068-
3069-
if (attr[attnum - 1]->attidentity)
3070-
{
3071-
NextValueExpr *nve = makeNode(NextValueExpr);
3072-
3073-
nve->seqid = getOwnedSequence(RelationGetRelid(cstate->rel),
3074-
attnum);
3075-
nve->typeId = attr[attnum - 1]->atttypid;
3076-
defexpr = (Expr *) nve;
3077-
}
3078-
else
3079-
defexpr = (Expr *) build_column_default(cstate->rel, attnum);
3066+
Expr *defexpr = (Expr *) build_column_default(cstate->rel,
3067+
attnum);
30803068

30813069
if (defexpr != NULL)
30823070
{

src/backend/commands/tablecmds.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5342,7 +5342,21 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
53425342
if (relkind != RELKIND_VIEW && relkind != RELKIND_COMPOSITE_TYPE
53435343
&& relkind != RELKIND_FOREIGN_TABLE && attribute.attnum > 0)
53445344
{
5345-
defval = (Expr *) build_column_default(rel, attribute.attnum);
5345+
/*
5346+
* For an identity column, we can't use build_column_default(),
5347+
* because the sequence ownership isn't set yet. So do it manually.
5348+
*/
5349+
if (colDef->identity)
5350+
{
5351+
NextValueExpr *nve = makeNode(NextValueExpr);
5352+
5353+
nve->seqid = RangeVarGetRelid(colDef->identitySequence, NoLock, false);
5354+
nve->typeId = typeOid;
5355+
5356+
defval = (Expr *) nve;
5357+
}
5358+
else
5359+
defval = (Expr *) build_column_default(rel, attribute.attnum);
53465360

53475361
if (!defval && DomainHasConstraints(typeOid))
53485362
{

src/backend/nodes/copyfuncs.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2812,6 +2812,7 @@ _copyColumnDef(const ColumnDef *from)
28122812
COPY_NODE_FIELD(raw_default);
28132813
COPY_NODE_FIELD(cooked_default);
28142814
COPY_SCALAR_FIELD(identity);
2815+
COPY_NODE_FIELD(identitySequence);
28152816
COPY_NODE_FIELD(collClause);
28162817
COPY_SCALAR_FIELD(collOid);
28172818
COPY_NODE_FIELD(constraints);

src/backend/nodes/equalfuncs.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2544,6 +2544,7 @@ _equalColumnDef(const ColumnDef *a, const ColumnDef *b)
25442544
COMPARE_NODE_FIELD(raw_default);
25452545
COMPARE_NODE_FIELD(cooked_default);
25462546
COMPARE_SCALAR_FIELD(identity);
2547+
COMPARE_NODE_FIELD(identitySequence);
25472548
COMPARE_NODE_FIELD(collClause);
25482549
COMPARE_SCALAR_FIELD(collOid);
25492550
COMPARE_NODE_FIELD(constraints);

src/backend/nodes/outfuncs.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2801,6 +2801,7 @@ _outColumnDef(StringInfo str, const ColumnDef *node)
28012801
WRITE_NODE_FIELD(raw_default);
28022802
WRITE_NODE_FIELD(cooked_default);
28032803
WRITE_CHAR_FIELD(identity);
2804+
WRITE_NODE_FIELD(identitySequence);
28042805
WRITE_NODE_FIELD(collClause);
28052806
WRITE_OID_FIELD(collOid);
28062807
WRITE_NODE_FIELD(constraints);

src/backend/parser/parse_utilcmd.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,14 @@ generateSerialExtraStmts(CreateStmtContext *cxt, ColumnDef *column,
475475

476476
cxt->blist = lappend(cxt->blist, seqstmt);
477477

478+
/*
479+
* Store the identity sequence name that we decided on. ALTER TABLE
480+
* ... ADD COLUMN ... IDENTITY needs this so that it can fill the new
481+
* column with values from the sequence, while the association of the
482+
* sequence with the table is not set until after the ALTER TABLE.
483+
*/
484+
column->identitySequence = seqstmt->sequence;
485+
478486
/*
479487
* Build an ALTER SEQUENCE ... OWNED BY command to mark the sequence as
480488
* owned by this column, and add it to the list of things to be done after

src/backend/rewrite/rewriteHandler.c

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -844,17 +844,7 @@ rewriteTargetListIU(List *targetList,
844844
{
845845
Node *new_expr;
846846

847-
if (att_tup->attidentity)
848-
{
849-
NextValueExpr *nve = makeNode(NextValueExpr);
850-
851-
nve->seqid = getOwnedSequence(RelationGetRelid(target_relation), attrno);
852-
nve->typeId = att_tup->atttypid;
853-
854-
new_expr = (Node *) nve;
855-
}
856-
else
857-
new_expr = build_column_default(target_relation, attrno);
847+
new_expr = build_column_default(target_relation, attrno);
858848

859849
/*
860850
* If there is no default (ie, default is effectively NULL), we
@@ -1123,6 +1113,16 @@ build_column_default(Relation rel, int attrno)
11231113
Node *expr = NULL;
11241114
Oid exprtype;
11251115

1116+
if (att_tup->attidentity)
1117+
{
1118+
NextValueExpr *nve = makeNode(NextValueExpr);
1119+
1120+
nve->seqid = getOwnedSequence(RelationGetRelid(rel), attrno);
1121+
nve->typeId = att_tup->atttypid;
1122+
1123+
return (Node *) nve;
1124+
}
1125+
11261126
/*
11271127
* Scan to see if relation has a default for this column.
11281128
*/

src/include/nodes/parsenodes.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,8 @@ typedef struct ColumnDef
647647
Node *raw_default; /* default value (untransformed parse tree) */
648648
Node *cooked_default; /* default value (transformed expr tree) */
649649
char identity; /* attidentity setting */
650+
RangeVar *identitySequence; /* to store identity sequence name for ALTER
651+
* TABLE ... ADD COLUMN */
650652
CollateClause *collClause; /* untransformed COLLATE spec, if any */
651653
Oid collOid; /* collation OID (InvalidOid if not set) */
652654
List *constraints; /* other constraints on column */

src/test/regress/expected/identity.out

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,19 @@ SELECT * FROM itest4;
104104
2 |
105105
(2 rows)
106106

107+
-- VALUES RTEs
108+
INSERT INTO itest3 VALUES (DEFAULT, 'a');
109+
INSERT INTO itest3 VALUES (DEFAULT, 'b'), (DEFAULT, 'c');
110+
SELECT * FROM itest3;
111+
a | b
112+
----+---
113+
7 |
114+
12 |
115+
17 | a
116+
22 | b
117+
27 | c
118+
(5 rows)
119+
107120
-- OVERRIDING tests
108121
INSERT INTO itest1 VALUES (10, 'xyz');
109122
INSERT INTO itest1 OVERRIDING USER VALUE VALUES (10, 'xyz');
@@ -237,6 +250,21 @@ SELECT * FROM itestv11;
237250
11 | xyz
238251
(3 rows)
239252

253+
-- ADD COLUMN
254+
CREATE TABLE itest13 (a int);
255+
-- add column to empty table
256+
ALTER TABLE itest13 ADD COLUMN b int GENERATED BY DEFAULT AS IDENTITY;
257+
INSERT INTO itest13 VALUES (1), (2), (3);
258+
-- add column to populated table
259+
ALTER TABLE itest13 ADD COLUMN c int GENERATED BY DEFAULT AS IDENTITY;
260+
SELECT * FROM itest13;
261+
a | b | c
262+
---+---+---
263+
1 | 1 | 1
264+
2 | 2 | 2
265+
3 | 3 | 3
266+
(3 rows)
267+
240268
-- various ALTER COLUMN tests
241269
-- fail, not allowed for identity columns
242270
ALTER TABLE itest1 ALTER COLUMN a SET DEFAULT 1;

src/test/regress/sql/identity.sql

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,14 @@ SELECT * FROM itest3;
5454
SELECT * FROM itest4;
5555

5656

57+
-- VALUES RTEs
58+
59+
INSERT INTO itest3 VALUES (DEFAULT, 'a');
60+
INSERT INTO itest3 VALUES (DEFAULT, 'b'), (DEFAULT, 'c');
61+
62+
SELECT * FROM itest3;
63+
64+
5765
-- OVERRIDING tests
5866

5967
INSERT INTO itest1 VALUES (10, 'xyz');
@@ -138,6 +146,17 @@ INSERT INTO itestv11 OVERRIDING SYSTEM VALUE VALUES (11, 'xyz');
138146
SELECT * FROM itestv11;
139147

140148

149+
-- ADD COLUMN
150+
151+
CREATE TABLE itest13 (a int);
152+
-- add column to empty table
153+
ALTER TABLE itest13 ADD COLUMN b int GENERATED BY DEFAULT AS IDENTITY;
154+
INSERT INTO itest13 VALUES (1), (2), (3);
155+
-- add column to populated table
156+
ALTER TABLE itest13 ADD COLUMN c int GENERATED BY DEFAULT AS IDENTITY;
157+
SELECT * FROM itest13;
158+
159+
141160
-- various ALTER COLUMN tests
142161

143162
-- fail, not allowed for identity columns

src/test/subscription/t/008_diff_schema.pl

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use warnings;
44
use PostgresNode;
55
use TestLib;
6-
use Test::More tests => 3;
6+
use Test::More tests => 4;
77

88
sub wait_for_caught_up
99
{
@@ -31,7 +31,7 @@ sub wait_for_caught_up
3131
"INSERT INTO test_tab VALUES (1, 'foo'), (2, 'bar')");
3232

3333
# Setup structure on subscriber
34-
$node_subscriber->safe_psql('postgres', "CREATE TABLE test_tab (a int primary key, b text, c timestamptz DEFAULT now(), d bigint DEFAULT 999)");
34+
$node_subscriber->safe_psql('postgres', "CREATE TABLE test_tab (a int primary key, b text, c timestamptz DEFAULT now(), d bigint DEFAULT 999, e int GENERATED BY DEFAULT AS IDENTITY)");
3535

3636
# Setup logical replication
3737
my $publisher_connstr = $node_publisher->connstr . ' dbname=postgres';
@@ -61,8 +61,8 @@ sub wait_for_caught_up
6161
wait_for_caught_up($node_publisher, $appname);
6262

6363
$result =
64-
$node_subscriber->safe_psql('postgres', "SELECT count(*), count(c), count(d = 999) FROM test_tab");
65-
is($result, qq(2|2|2), 'check extra columns contain local defaults');
64+
$node_subscriber->safe_psql('postgres', "SELECT count(*), count(c), count(d = 999), count(e) FROM test_tab");
65+
is($result, qq(2|2|2|2), 'check extra columns contain local defaults after copy');
6666

6767
# Change the local values of the extra columns on the subscriber,
6868
# update publisher, and check that subscriber retains the expected
@@ -76,5 +76,15 @@ sub wait_for_caught_up
7676
$node_subscriber->safe_psql('postgres', "SELECT count(*), count(extract(epoch from c) = 987654321), count(d = 999) FROM test_tab");
7777
is($result, qq(2|2|2), 'check extra columns contain locally changed data');
7878

79+
# Another insert
80+
$node_publisher->safe_psql('postgres',
81+
"INSERT INTO test_tab VALUES (3, 'baz')");
82+
83+
wait_for_caught_up($node_publisher, $appname);
84+
85+
$result =
86+
$node_subscriber->safe_psql('postgres', "SELECT count(*), count(c), count(d = 999), count(e) FROM test_tab");
87+
is($result, qq(3|3|3|3), 'check extra columns contain local defaults after apply');
88+
7989
$node_subscriber->stop;
8090
$node_publisher->stop;

0 commit comments

Comments
 (0)