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

Commit dfe51ff

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 41c6a5b commit dfe51ff

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
@@ -5102,6 +5102,14 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
51025102
foreach(lc, dropped_attrs)
51035103
newslot->tts_isnull[lfirst_int(lc)] = true;
51045104

5105+
/*
5106+
* Constraints and GENERATED expressions might reference the
5107+
* tableoid column, so fill tts_tableOid with the desired
5108+
* value. (We must do this each time, because it gets
5109+
* overwritten with newrel's OID during storing.)
5110+
*/
5111+
newslot->tts_tableOid = RelationGetRelid(oldrel);
5112+
51055113
/*
51065114
* Process supplied expressions to replace selected columns.
51075115
*
@@ -5145,11 +5153,6 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
51455153
&newslot->tts_isnull[ex->attnum - 1]);
51465154
}
51475155

5148-
/*
5149-
* Constraints might reference the tableoid column, so
5150-
* initialize t_tableOid before evaluating them.
5151-
*/
5152-
newslot->tts_tableOid = RelationGetRelid(oldrel);
51535156
insertslot = newslot;
51545157
}
51555158
else

src/backend/executor/nodeModifyTable.c

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,12 @@ ExecInsert(ModifyTableState *mtstate,
412412
}
413413
else if (resultRelInfo->ri_FdwRoutine)
414414
{
415+
/*
416+
* GENERATED expressions might reference the tableoid column, so
417+
* (re-)initialize tts_tableOid before evaluating them.
418+
*/
419+
slot->tts_tableOid = RelationGetRelid(resultRelInfo->ri_RelationDesc);
420+
415421
/*
416422
* Compute stored generated columns
417423
*/
@@ -433,7 +439,7 @@ ExecInsert(ModifyTableState *mtstate,
433439
/*
434440
* AFTER ROW Triggers or RETURNING expressions might reference the
435441
* tableoid column, so (re-)initialize tts_tableOid before evaluating
436-
* them.
442+
* them. (This covers the case where the FDW replaced the slot.)
437443
*/
438444
slot->tts_tableOid = RelationGetRelid(resultRelInfo->ri_RelationDesc);
439445
}
@@ -442,8 +448,8 @@ ExecInsert(ModifyTableState *mtstate,
442448
WCOKind wco_kind;
443449

444450
/*
445-
* Constraints might reference the tableoid column, so (re-)initialize
446-
* tts_tableOid before evaluating them.
451+
* Constraints and GENERATED expressions might reference the tableoid
452+
* column, so (re-)initialize tts_tableOid before evaluating them.
447453
*/
448454
slot->tts_tableOid = RelationGetRelid(resultRelationDesc);
449455

@@ -1148,6 +1154,12 @@ ExecUpdate(ModifyTableState *mtstate,
11481154
}
11491155
else if (resultRelInfo->ri_FdwRoutine)
11501156
{
1157+
/*
1158+
* GENERATED expressions might reference the tableoid column, so
1159+
* (re-)initialize tts_tableOid before evaluating them.
1160+
*/
1161+
slot->tts_tableOid = RelationGetRelid(resultRelInfo->ri_RelationDesc);
1162+
11511163
/*
11521164
* Compute stored generated columns
11531165
*/
@@ -1169,7 +1181,7 @@ ExecUpdate(ModifyTableState *mtstate,
11691181
/*
11701182
* AFTER ROW Triggers or RETURNING expressions might reference the
11711183
* tableoid column, so (re-)initialize tts_tableOid before evaluating
1172-
* them.
1184+
* them. (This covers the case where the FDW replaced the slot.)
11731185
*/
11741186
slot->tts_tableOid = RelationGetRelid(resultRelationDesc);
11751187
}
@@ -1180,8 +1192,8 @@ ExecUpdate(ModifyTableState *mtstate,
11801192
bool update_indexes;
11811193

11821194
/*
1183-
* Constraints might reference the tableoid column, so (re-)initialize
1184-
* tts_tableOid before evaluating them.
1195+
* Constraints and GENERATED expressions might reference the tableoid
1196+
* column, so (re-)initialize tts_tableOid before evaluating them.
11851197
*/
11861198
slot->tts_tableOid = RelationGetRelid(resultRelationDesc);
11871199

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)