Commit 39a68e5c authored by Robert Haas's avatar Robert Haas

Fix toast table creation.

Instead of using slightly-too-clever heuristics to decide when we must
create a TOAST table, just check whether one is needed every time the
table is altered.  Checking whether a toast table is needed is cheap
enough that we needn't worry about doing it on every ALTER TABLE command,
and the previous coding is apparently prone to accidental breakage:
commit 04e17bae broken ALTER TABLE ..
SET STORAGE, which moved some actions from AT_PASS_COL_ATTRS to
AT_PASS_MISC, and commit 6c572399 broke
ALTER TABLE .. ADD COLUMN by changing the way that adding columns
recurses into child tables.

Noah Misch, with one comment change by me
parent eca75a12
...@@ -59,11 +59,11 @@ AlterTableCreateToastTable(Oid relOid, Datum reloptions) ...@@ -59,11 +59,11 @@ AlterTableCreateToastTable(Oid relOid, Datum reloptions)
Relation rel; Relation rel;
/* /*
* Grab an exclusive lock on the target table, which we will NOT release * Grab a DDL-exclusive lock on the target table, since we'll update the
* until end of transaction. (This is probably redundant in all present * pg_class tuple. This is redundant for all present users. Tuple toasting
* uses...) * behaves safely in the face of a concurrent TOAST table add.
*/ */
rel = heap_open(relOid, AccessExclusiveLock); rel = heap_open(relOid, ShareUpdateExclusiveLock);
/* create_toast_table does all the work */ /* create_toast_table does all the work */
(void) create_toast_table(rel, InvalidOid, InvalidOid, reloptions); (void) create_toast_table(rel, InvalidOid, InvalidOid, reloptions);
...@@ -103,7 +103,7 @@ BootstrapToastTable(char *relName, Oid toastOid, Oid toastIndexOid) ...@@ -103,7 +103,7 @@ BootstrapToastTable(char *relName, Oid toastOid, Oid toastIndexOid)
/* /*
* create_toast_table --- internal workhorse * create_toast_table --- internal workhorse
* *
* rel is already opened and exclusive-locked * rel is already opened and locked
* toastOid and toastIndexOid are normally InvalidOid, but during * toastOid and toastIndexOid are normally InvalidOid, but during
* bootstrap they can be nonzero to specify hand-assigned OIDs * bootstrap they can be nonzero to specify hand-assigned OIDs
*/ */
......
...@@ -3022,18 +3022,12 @@ ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode) ...@@ -3022,18 +3022,12 @@ ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode)
} }
} }
/* /* Check to see if a toast table must be added. */
* Check to see if a toast table must be added, if we executed any
* subcommands that might have added a column or changed column storage.
*/
foreach(ltab, *wqueue) foreach(ltab, *wqueue)
{ {
AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab); AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
if (tab->relkind == RELKIND_RELATION && if (tab->relkind == RELKIND_RELATION)
(tab->subcmds[AT_PASS_ADD_COL] ||
tab->subcmds[AT_PASS_ALTER_TYPE] ||
tab->subcmds[AT_PASS_COL_ATTRS]))
AlterTableCreateToastTable(tab->relid, (Datum) 0); AlterTableCreateToastTable(tab->relid, (Datum) 0);
} }
} }
......
...@@ -1522,6 +1522,19 @@ ERROR: composite type recur1 cannot be made a member of itself ...@@ -1522,6 +1522,19 @@ ERROR: composite type recur1 cannot be made a member of itself
alter table recur1 add column f2 int; alter table recur1 add column f2 int;
alter table recur1 alter column f2 type recur2; -- fails alter table recur1 alter column f2 type recur2; -- fails
ERROR: composite type recur1 cannot be made a member of itself ERROR: composite type recur1 cannot be made a member of itself
-- SET STORAGE may need to add a TOAST table
create table test_storage (a text);
alter table test_storage alter a set storage plain;
alter table test_storage add b int default 0; -- rewrite table to remove its TOAST table
alter table test_storage alter a set storage extended; -- re-add TOAST table
select reltoastrelid <> 0 as has_toast_table
from pg_class
where oid = 'test_storage'::regclass;
has_toast_table
-----------------
t
(1 row)
-- --
-- lock levels -- lock levels
-- --
......
...@@ -153,6 +153,12 @@ SELECT * FROM e_star*; ...@@ -153,6 +153,12 @@ SELECT * FROM e_star*;
ALTER TABLE a_star* ADD COLUMN a text; ALTER TABLE a_star* ADD COLUMN a text;
-- That ALTER TABLE should have added TOAST tables.
SELECT relname, reltoastrelid <> 0 AS has_toast_table
FROM pg_class
WHERE oid::regclass IN ('a_star', 'c_star')
ORDER BY 1;
--UPDATE b_star* --UPDATE b_star*
-- SET a = text 'gazpacho' -- SET a = text 'gazpacho'
-- WHERE aa > 4; -- WHERE aa > 4;
......
...@@ -376,6 +376,17 @@ SELECT * FROM e_star*; ...@@ -376,6 +376,17 @@ SELECT * FROM e_star*;
ALTER TABLE a_star* ADD COLUMN a text; ALTER TABLE a_star* ADD COLUMN a text;
NOTICE: merging definition of column "a" for child "d_star" NOTICE: merging definition of column "a" for child "d_star"
-- That ALTER TABLE should have added TOAST tables.
SELECT relname, reltoastrelid <> 0 AS has_toast_table
FROM pg_class
WHERE oid::regclass IN ('a_star', 'c_star')
ORDER BY 1;
relname | has_toast_table
---------+-----------------
a_star | t
c_star | t
(2 rows)
--UPDATE b_star* --UPDATE b_star*
-- SET a = text 'gazpacho' -- SET a = text 'gazpacho'
-- WHERE aa > 4; -- WHERE aa > 4;
......
...@@ -1133,6 +1133,16 @@ alter table recur1 add column f2 recur2; -- fails ...@@ -1133,6 +1133,16 @@ alter table recur1 add column f2 recur2; -- fails
alter table recur1 add column f2 int; alter table recur1 add column f2 int;
alter table recur1 alter column f2 type recur2; -- fails alter table recur1 alter column f2 type recur2; -- fails
-- SET STORAGE may need to add a TOAST table
create table test_storage (a text);
alter table test_storage alter a set storage plain;
alter table test_storage add b int default 0; -- rewrite table to remove its TOAST table
alter table test_storage alter a set storage extended; -- re-add TOAST table
select reltoastrelid <> 0 as has_toast_table
from pg_class
where oid = 'test_storage'::regclass;
-- --
-- lock levels -- lock levels
-- --
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment