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

Commit 2b0ee12

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 84f5c29 commit 2b0ee12

File tree

4 files changed

+38
-17
lines changed

4 files changed

+38
-17
lines changed

src/backend/commands/tablecmds.c

+8-5
Original file line numberDiff line numberDiff line change
@@ -5761,6 +5761,14 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
57615761
foreach(lc, dropped_attrs)
57625762
newslot->tts_isnull[lfirst_int(lc)] = true;
57635763

5764+
/*
5765+
* Constraints and GENERATED expressions might reference the
5766+
* tableoid column, so fill tts_tableOid with the desired
5767+
* value. (We must do this each time, because it gets
5768+
* overwritten with newrel's OID during storing.)
5769+
*/
5770+
newslot->tts_tableOid = RelationGetRelid(oldrel);
5771+
57645772
/*
57655773
* Process supplied expressions to replace selected columns.
57665774
*
@@ -5804,11 +5812,6 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
58045812
&newslot->tts_isnull[ex->attnum - 1]);
58055813
}
58065814

5807-
/*
5808-
* Constraints might reference the tableoid column, so
5809-
* initialize t_tableOid before evaluating them.
5810-
*/
5811-
newslot->tts_tableOid = RelationGetRelid(oldrel);
58125815
insertslot = newslot;
58135816
}
58145817
else

src/backend/executor/nodeModifyTable.c

+18-6
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,12 @@ ExecInsert(ModifyTableState *mtstate,
658658
}
659659
else if (resultRelInfo->ri_FdwRoutine)
660660
{
661+
/*
662+
* GENERATED expressions might reference the tableoid column, so
663+
* (re-)initialize tts_tableOid before evaluating them.
664+
*/
665+
slot->tts_tableOid = RelationGetRelid(resultRelInfo->ri_RelationDesc);
666+
661667
/*
662668
* Compute stored generated columns
663669
*/
@@ -729,7 +735,7 @@ ExecInsert(ModifyTableState *mtstate,
729735
/*
730736
* AFTER ROW Triggers or RETURNING expressions might reference the
731737
* tableoid column, so (re-)initialize tts_tableOid before evaluating
732-
* them.
738+
* them. (This covers the case where the FDW replaced the slot.)
733739
*/
734740
slot->tts_tableOid = RelationGetRelid(resultRelInfo->ri_RelationDesc);
735741
}
@@ -738,8 +744,8 @@ ExecInsert(ModifyTableState *mtstate,
738744
WCOKind wco_kind;
739745

740746
/*
741-
* Constraints might reference the tableoid column, so (re-)initialize
742-
* tts_tableOid before evaluating them.
747+
* Constraints and GENERATED expressions might reference the tableoid
748+
* column, so (re-)initialize tts_tableOid before evaluating them.
743749
*/
744750
slot->tts_tableOid = RelationGetRelid(resultRelationDesc);
745751

@@ -1629,6 +1635,12 @@ ExecUpdate(ModifyTableState *mtstate,
16291635
}
16301636
else if (resultRelInfo->ri_FdwRoutine)
16311637
{
1638+
/*
1639+
* GENERATED expressions might reference the tableoid column, so
1640+
* (re-)initialize tts_tableOid before evaluating them.
1641+
*/
1642+
slot->tts_tableOid = RelationGetRelid(resultRelInfo->ri_RelationDesc);
1643+
16321644
/*
16331645
* Compute stored generated columns
16341646
*/
@@ -1651,7 +1663,7 @@ ExecUpdate(ModifyTableState *mtstate,
16511663
/*
16521664
* AFTER ROW Triggers or RETURNING expressions might reference the
16531665
* tableoid column, so (re-)initialize tts_tableOid before evaluating
1654-
* them.
1666+
* them. (This covers the case where the FDW replaced the slot.)
16551667
*/
16561668
slot->tts_tableOid = RelationGetRelid(resultRelationDesc);
16571669
}
@@ -1662,8 +1674,8 @@ ExecUpdate(ModifyTableState *mtstate,
16621674
bool update_indexes;
16631675

16641676
/*
1665-
* Constraints might reference the tableoid column, so (re-)initialize
1666-
* tts_tableOid before evaluating them.
1677+
* Constraints and GENERATED expressions might reference the tableoid
1678+
* column, so (re-)initialize tts_tableOid before evaluating them.
16671679
*/
16681680
slot->tts_tableOid = RelationGetRelid(resultRelationDesc);
16691681

src/test/regress/expected/generated.out

+8-5
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...
@@ -455,14 +456,16 @@ DROP TYPE double_int;
455456
-- using tableoid is allowed
456457
CREATE TABLE gtest_tableoid (
457458
a int PRIMARY KEY,
458-
b bool GENERATED ALWAYS AS (tableoid <> 0) STORED
459+
b bool GENERATED ALWAYS AS (tableoid = 'gtest_tableoid'::regclass) STORED
459460
);
460461
INSERT INTO gtest_tableoid VALUES (1), (2);
462+
ALTER TABLE gtest_tableoid ADD COLUMN
463+
c regclass GENERATED ALWAYS AS (tableoid) STORED;
461464
SELECT * FROM gtest_tableoid;
462-
a | b
463-
---+---
464-
1 | t
465-
2 | t
465+
a | b | c
466+
---+---+----------------
467+
1 | t | gtest_tableoid
468+
2 | t | gtest_tableoid
466469
(2 rows)
467470

468471
-- drop column behavior

src/test/regress/sql/generated.sql

+4-1
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
@@ -218,9 +219,11 @@ DROP TYPE double_int;
218219
-- using tableoid is allowed
219220
CREATE TABLE gtest_tableoid (
220221
a int PRIMARY KEY,
221-
b bool GENERATED ALWAYS AS (tableoid <> 0) STORED
222+
b bool GENERATED ALWAYS AS (tableoid = 'gtest_tableoid'::regclass) STORED
222223
);
223224
INSERT INTO gtest_tableoid VALUES (1), (2);
225+
ALTER TABLE gtest_tableoid ADD COLUMN
226+
c regclass GENERATED ALWAYS AS (tableoid) STORED;
224227
SELECT * FROM gtest_tableoid;
225228

226229
-- drop column behavior

0 commit comments

Comments
 (0)