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

Commit 77e3204

Browse files
committed
Fix usage of "tableoid" in GENERATED expressions.
We consider this supported (though I've got my doubts that it's a good idea, because tableoid is not immutable). However, several code paths failed to fill the field in soon enough, causing such a GENERATED expression to see zero or the wrong value. This occurred when ALTER TABLE adds a new GENERATED column to a table with existing rows, and during regular INSERT or UPDATE on a foreign table with GENERATED columns. Noted during investigation of a report from Vitaly Ustinov. Back-patch to v12 where GENERATED came in. Discussion: https://postgr.es/m/CAM_DEiWR2DPT6U4xb-Ehigozzd3n3G37ZB1+867zbsEVtYoJww@mail.gmail.com
1 parent d18ee6f commit 77e3204

File tree

4 files changed

+38
-17
lines changed

4 files changed

+38
-17
lines changed

src/backend/commands/tablecmds.c

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5373,6 +5373,14 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
53735373
foreach(lc, dropped_attrs)
53745374
newslot->tts_isnull[lfirst_int(lc)] = true;
53755375

5376+
/*
5377+
* Constraints and GENERATED expressions might reference the
5378+
* tableoid column, so fill tts_tableOid with the desired
5379+
* value. (We must do this each time, because it gets
5380+
* overwritten with newrel's OID during storing.)
5381+
*/
5382+
newslot->tts_tableOid = RelationGetRelid(oldrel);
5383+
53765384
/*
53775385
* Process supplied expressions to replace selected columns.
53785386
*
@@ -5416,11 +5424,6 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
54165424
&newslot->tts_isnull[ex->attnum - 1]);
54175425
}
54185426

5419-
/*
5420-
* Constraints might reference the tableoid column, so
5421-
* initialize t_tableOid before evaluating them.
5422-
*/
5423-
newslot->tts_tableOid = RelationGetRelid(oldrel);
54245427
insertslot = newslot;
54255428
}
54265429
else

src/backend/executor/nodeModifyTable.c

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,12 @@ ExecInsert(ModifyTableState *mtstate,
437437
}
438438
else if (resultRelInfo->ri_FdwRoutine)
439439
{
440+
/*
441+
* GENERATED expressions might reference the tableoid column, so
442+
* (re-)initialize tts_tableOid before evaluating them.
443+
*/
444+
slot->tts_tableOid = RelationGetRelid(resultRelInfo->ri_RelationDesc);
445+
440446
/*
441447
* Compute stored generated columns
442448
*/
@@ -458,7 +464,7 @@ ExecInsert(ModifyTableState *mtstate,
458464
/*
459465
* AFTER ROW Triggers or RETURNING expressions might reference the
460466
* tableoid column, so (re-)initialize tts_tableOid before evaluating
461-
* them.
467+
* them. (This covers the case where the FDW replaced the slot.)
462468
*/
463469
slot->tts_tableOid = RelationGetRelid(resultRelInfo->ri_RelationDesc);
464470
}
@@ -467,8 +473,8 @@ ExecInsert(ModifyTableState *mtstate,
467473
WCOKind wco_kind;
468474

469475
/*
470-
* Constraints might reference the tableoid column, so (re-)initialize
471-
* tts_tableOid before evaluating them.
476+
* Constraints and GENERATED expressions might reference the tableoid
477+
* column, so (re-)initialize tts_tableOid before evaluating them.
472478
*/
473479
slot->tts_tableOid = RelationGetRelid(resultRelationDesc);
474480

@@ -1172,6 +1178,12 @@ ExecUpdate(ModifyTableState *mtstate,
11721178
}
11731179
else if (resultRelInfo->ri_FdwRoutine)
11741180
{
1181+
/*
1182+
* GENERATED expressions might reference the tableoid column, so
1183+
* (re-)initialize tts_tableOid before evaluating them.
1184+
*/
1185+
slot->tts_tableOid = RelationGetRelid(resultRelInfo->ri_RelationDesc);
1186+
11751187
/*
11761188
* Compute stored generated columns
11771189
*/
@@ -1193,7 +1205,7 @@ ExecUpdate(ModifyTableState *mtstate,
11931205
/*
11941206
* AFTER ROW Triggers or RETURNING expressions might reference the
11951207
* tableoid column, so (re-)initialize tts_tableOid before evaluating
1196-
* them.
1208+
* them. (This covers the case where the FDW replaced the slot.)
11971209
*/
11981210
slot->tts_tableOid = RelationGetRelid(resultRelationDesc);
11991211
}
@@ -1204,8 +1216,8 @@ ExecUpdate(ModifyTableState *mtstate,
12041216
bool update_indexes;
12051217

12061218
/*
1207-
* Constraints might reference the tableoid column, so (re-)initialize
1208-
* tts_tableOid before evaluating them.
1219+
* Constraints and GENERATED expressions might reference the tableoid
1220+
* column, so (re-)initialize tts_tableOid before evaluating them.
12091221
*/
12101222
slot->tts_tableOid = RelationGetRelid(resultRelationDesc);
12111223

src/test/regress/expected/generated.out

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ ERROR: both identity and generation expression specified for column "b" of tabl
6464
LINE 1: ...t PRIMARY KEY, b int GENERATED ALWAYS AS identity GENERATED ...
6565
^
6666
-- reference to system column not allowed in generated column
67+
-- (except tableoid, which we test below)
6768
CREATE TABLE gtest_err_6a (a int PRIMARY KEY, b bool GENERATED ALWAYS AS (xmin <> 37) STORED);
6869
ERROR: cannot use system column "xmin" in column generation expression
6970
LINE 1: ...a (a int PRIMARY KEY, b bool GENERATED ALWAYS AS (xmin <> 37...
@@ -414,14 +415,16 @@ DROP TYPE double_int;
414415
-- using tableoid is allowed
415416
CREATE TABLE gtest_tableoid (
416417
a int PRIMARY KEY,
417-
b bool GENERATED ALWAYS AS (tableoid <> 0) STORED
418+
b bool GENERATED ALWAYS AS (tableoid = 'gtest_tableoid'::regclass) STORED
418419
);
419420
INSERT INTO gtest_tableoid VALUES (1), (2);
421+
ALTER TABLE gtest_tableoid ADD COLUMN
422+
c regclass GENERATED ALWAYS AS (tableoid) STORED;
420423
SELECT * FROM gtest_tableoid;
421-
a | b
422-
---+---
423-
1 | t
424-
2 | t
424+
a | b | c
425+
---+---+----------------
426+
1 | t | gtest_tableoid
427+
2 | t | gtest_tableoid
425428
(2 rows)
426429

427430
-- drop column behavior

src/test/regress/sql/generated.sql

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ CREATE TABLE gtest_err_5a (a int PRIMARY KEY, b int DEFAULT 5 GENERATED ALWAYS A
2929
CREATE TABLE gtest_err_5b (a int PRIMARY KEY, b int GENERATED ALWAYS AS identity GENERATED ALWAYS AS (a * 2) STORED);
3030

3131
-- reference to system column not allowed in generated column
32+
-- (except tableoid, which we test below)
3233
CREATE TABLE gtest_err_6a (a int PRIMARY KEY, b bool GENERATED ALWAYS AS (xmin <> 37) STORED);
3334

3435
-- various prohibited constructs
@@ -201,9 +202,11 @@ DROP TYPE double_int;
201202
-- using tableoid is allowed
202203
CREATE TABLE gtest_tableoid (
203204
a int PRIMARY KEY,
204-
b bool GENERATED ALWAYS AS (tableoid <> 0) STORED
205+
b bool GENERATED ALWAYS AS (tableoid = 'gtest_tableoid'::regclass) STORED
205206
);
206207
INSERT INTO gtest_tableoid VALUES (1), (2);
208+
ALTER TABLE gtest_tableoid ADD COLUMN
209+
c regclass GENERATED ALWAYS AS (tableoid) STORED;
207210
SELECT * FROM gtest_tableoid;
208211

209212
-- drop column behavior

0 commit comments

Comments
 (0)