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
This commit is contained in:
parent
d18ee6f92d
commit
77e3204ecb
@ -5373,6 +5373,14 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
|
|||||||
foreach(lc, dropped_attrs)
|
foreach(lc, dropped_attrs)
|
||||||
newslot->tts_isnull[lfirst_int(lc)] = true;
|
newslot->tts_isnull[lfirst_int(lc)] = true;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Constraints and GENERATED expressions might reference the
|
||||||
|
* tableoid column, so fill tts_tableOid with the desired
|
||||||
|
* value. (We must do this each time, because it gets
|
||||||
|
* overwritten with newrel's OID during storing.)
|
||||||
|
*/
|
||||||
|
newslot->tts_tableOid = RelationGetRelid(oldrel);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Process supplied expressions to replace selected columns.
|
* Process supplied expressions to replace selected columns.
|
||||||
*
|
*
|
||||||
@ -5416,11 +5424,6 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
|
|||||||
&newslot->tts_isnull[ex->attnum - 1]);
|
&newslot->tts_isnull[ex->attnum - 1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Constraints might reference the tableoid column, so
|
|
||||||
* initialize t_tableOid before evaluating them.
|
|
||||||
*/
|
|
||||||
newslot->tts_tableOid = RelationGetRelid(oldrel);
|
|
||||||
insertslot = newslot;
|
insertslot = newslot;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -437,6 +437,12 @@ ExecInsert(ModifyTableState *mtstate,
|
|||||||
}
|
}
|
||||||
else if (resultRelInfo->ri_FdwRoutine)
|
else if (resultRelInfo->ri_FdwRoutine)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* GENERATED expressions might reference the tableoid column, so
|
||||||
|
* (re-)initialize tts_tableOid before evaluating them.
|
||||||
|
*/
|
||||||
|
slot->tts_tableOid = RelationGetRelid(resultRelInfo->ri_RelationDesc);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Compute stored generated columns
|
* Compute stored generated columns
|
||||||
*/
|
*/
|
||||||
@ -458,7 +464,7 @@ ExecInsert(ModifyTableState *mtstate,
|
|||||||
/*
|
/*
|
||||||
* AFTER ROW Triggers or RETURNING expressions might reference the
|
* AFTER ROW Triggers or RETURNING expressions might reference the
|
||||||
* tableoid column, so (re-)initialize tts_tableOid before evaluating
|
* tableoid column, so (re-)initialize tts_tableOid before evaluating
|
||||||
* them.
|
* them. (This covers the case where the FDW replaced the slot.)
|
||||||
*/
|
*/
|
||||||
slot->tts_tableOid = RelationGetRelid(resultRelInfo->ri_RelationDesc);
|
slot->tts_tableOid = RelationGetRelid(resultRelInfo->ri_RelationDesc);
|
||||||
}
|
}
|
||||||
@ -467,8 +473,8 @@ ExecInsert(ModifyTableState *mtstate,
|
|||||||
WCOKind wco_kind;
|
WCOKind wco_kind;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Constraints might reference the tableoid column, so (re-)initialize
|
* Constraints and GENERATED expressions might reference the tableoid
|
||||||
* tts_tableOid before evaluating them.
|
* column, so (re-)initialize tts_tableOid before evaluating them.
|
||||||
*/
|
*/
|
||||||
slot->tts_tableOid = RelationGetRelid(resultRelationDesc);
|
slot->tts_tableOid = RelationGetRelid(resultRelationDesc);
|
||||||
|
|
||||||
@ -1172,6 +1178,12 @@ ExecUpdate(ModifyTableState *mtstate,
|
|||||||
}
|
}
|
||||||
else if (resultRelInfo->ri_FdwRoutine)
|
else if (resultRelInfo->ri_FdwRoutine)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* GENERATED expressions might reference the tableoid column, so
|
||||||
|
* (re-)initialize tts_tableOid before evaluating them.
|
||||||
|
*/
|
||||||
|
slot->tts_tableOid = RelationGetRelid(resultRelInfo->ri_RelationDesc);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Compute stored generated columns
|
* Compute stored generated columns
|
||||||
*/
|
*/
|
||||||
@ -1193,7 +1205,7 @@ ExecUpdate(ModifyTableState *mtstate,
|
|||||||
/*
|
/*
|
||||||
* AFTER ROW Triggers or RETURNING expressions might reference the
|
* AFTER ROW Triggers or RETURNING expressions might reference the
|
||||||
* tableoid column, so (re-)initialize tts_tableOid before evaluating
|
* tableoid column, so (re-)initialize tts_tableOid before evaluating
|
||||||
* them.
|
* them. (This covers the case where the FDW replaced the slot.)
|
||||||
*/
|
*/
|
||||||
slot->tts_tableOid = RelationGetRelid(resultRelationDesc);
|
slot->tts_tableOid = RelationGetRelid(resultRelationDesc);
|
||||||
}
|
}
|
||||||
@ -1204,8 +1216,8 @@ ExecUpdate(ModifyTableState *mtstate,
|
|||||||
bool update_indexes;
|
bool update_indexes;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Constraints might reference the tableoid column, so (re-)initialize
|
* Constraints and GENERATED expressions might reference the tableoid
|
||||||
* tts_tableOid before evaluating them.
|
* column, so (re-)initialize tts_tableOid before evaluating them.
|
||||||
*/
|
*/
|
||||||
slot->tts_tableOid = RelationGetRelid(resultRelationDesc);
|
slot->tts_tableOid = RelationGetRelid(resultRelationDesc);
|
||||||
|
|
||||||
|
@ -64,6 +64,7 @@ ERROR: both identity and generation expression specified for column "b" of tabl
|
|||||||
LINE 1: ...t PRIMARY KEY, b int GENERATED ALWAYS AS identity GENERATED ...
|
LINE 1: ...t PRIMARY KEY, b int GENERATED ALWAYS AS identity GENERATED ...
|
||||||
^
|
^
|
||||||
-- reference to system column not allowed in generated column
|
-- reference to system column not allowed in generated column
|
||||||
|
-- (except tableoid, which we test below)
|
||||||
CREATE TABLE gtest_err_6a (a int PRIMARY KEY, b bool GENERATED ALWAYS AS (xmin <> 37) STORED);
|
CREATE TABLE gtest_err_6a (a int PRIMARY KEY, b bool GENERATED ALWAYS AS (xmin <> 37) STORED);
|
||||||
ERROR: cannot use system column "xmin" in column generation expression
|
ERROR: cannot use system column "xmin" in column generation expression
|
||||||
LINE 1: ...a (a int PRIMARY KEY, b bool GENERATED ALWAYS AS (xmin <> 37...
|
LINE 1: ...a (a int PRIMARY KEY, b bool GENERATED ALWAYS AS (xmin <> 37...
|
||||||
@ -414,14 +415,16 @@ DROP TYPE double_int;
|
|||||||
-- using tableoid is allowed
|
-- using tableoid is allowed
|
||||||
CREATE TABLE gtest_tableoid (
|
CREATE TABLE gtest_tableoid (
|
||||||
a int PRIMARY KEY,
|
a int PRIMARY KEY,
|
||||||
b bool GENERATED ALWAYS AS (tableoid <> 0) STORED
|
b bool GENERATED ALWAYS AS (tableoid = 'gtest_tableoid'::regclass) STORED
|
||||||
);
|
);
|
||||||
INSERT INTO gtest_tableoid VALUES (1), (2);
|
INSERT INTO gtest_tableoid VALUES (1), (2);
|
||||||
|
ALTER TABLE gtest_tableoid ADD COLUMN
|
||||||
|
c regclass GENERATED ALWAYS AS (tableoid) STORED;
|
||||||
SELECT * FROM gtest_tableoid;
|
SELECT * FROM gtest_tableoid;
|
||||||
a | b
|
a | b | c
|
||||||
---+---
|
---+---+----------------
|
||||||
1 | t
|
1 | t | gtest_tableoid
|
||||||
2 | t
|
2 | t | gtest_tableoid
|
||||||
(2 rows)
|
(2 rows)
|
||||||
|
|
||||||
-- drop column behavior
|
-- drop column behavior
|
||||||
|
@ -29,6 +29,7 @@ CREATE TABLE gtest_err_5a (a int PRIMARY KEY, b int DEFAULT 5 GENERATED ALWAYS A
|
|||||||
CREATE TABLE gtest_err_5b (a int PRIMARY KEY, b int GENERATED ALWAYS AS identity GENERATED ALWAYS AS (a * 2) STORED);
|
CREATE TABLE gtest_err_5b (a int PRIMARY KEY, b int GENERATED ALWAYS AS identity GENERATED ALWAYS AS (a * 2) STORED);
|
||||||
|
|
||||||
-- reference to system column not allowed in generated column
|
-- reference to system column not allowed in generated column
|
||||||
|
-- (except tableoid, which we test below)
|
||||||
CREATE TABLE gtest_err_6a (a int PRIMARY KEY, b bool GENERATED ALWAYS AS (xmin <> 37) STORED);
|
CREATE TABLE gtest_err_6a (a int PRIMARY KEY, b bool GENERATED ALWAYS AS (xmin <> 37) STORED);
|
||||||
|
|
||||||
-- various prohibited constructs
|
-- various prohibited constructs
|
||||||
@ -201,9 +202,11 @@ DROP TYPE double_int;
|
|||||||
-- using tableoid is allowed
|
-- using tableoid is allowed
|
||||||
CREATE TABLE gtest_tableoid (
|
CREATE TABLE gtest_tableoid (
|
||||||
a int PRIMARY KEY,
|
a int PRIMARY KEY,
|
||||||
b bool GENERATED ALWAYS AS (tableoid <> 0) STORED
|
b bool GENERATED ALWAYS AS (tableoid = 'gtest_tableoid'::regclass) STORED
|
||||||
);
|
);
|
||||||
INSERT INTO gtest_tableoid VALUES (1), (2);
|
INSERT INTO gtest_tableoid VALUES (1), (2);
|
||||||
|
ALTER TABLE gtest_tableoid ADD COLUMN
|
||||||
|
c regclass GENERATED ALWAYS AS (tableoid) STORED;
|
||||||
SELECT * FROM gtest_tableoid;
|
SELECT * FROM gtest_tableoid;
|
||||||
|
|
||||||
-- drop column behavior
|
-- drop column behavior
|
||||||
|
Loading…
x
Reference in New Issue
Block a user