Propagate ALTER TABLE ... SET STORAGE to indexes
When creating a new index, the attstorage setting of the table column is copied to regular (non-expression) index columns. But a later ALTER TABLE ... SET STORAGE is not propagated to indexes, thus creating an inconsistent and undumpable state. Discussion: https://www.postgresql.org/message-id/flat/9765d72b-37c0-06f5-e349-2a580aafd989%402ndquadrant.com
This commit is contained in:
parent
f9463d2a90
commit
501e41dd3c
@ -305,6 +305,10 @@ ALTER TABLE toasted_several REPLICA IDENTITY FULL;
|
|||||||
ALTER TABLE toasted_several ALTER COLUMN toasted_key SET STORAGE EXTERNAL;
|
ALTER TABLE toasted_several ALTER COLUMN toasted_key SET STORAGE EXTERNAL;
|
||||||
ALTER TABLE toasted_several ALTER COLUMN toasted_col1 SET STORAGE EXTERNAL;
|
ALTER TABLE toasted_several ALTER COLUMN toasted_col1 SET STORAGE EXTERNAL;
|
||||||
ALTER TABLE toasted_several ALTER COLUMN toasted_col2 SET STORAGE EXTERNAL;
|
ALTER TABLE toasted_several ALTER COLUMN toasted_col2 SET STORAGE EXTERNAL;
|
||||||
|
-- Change the storage of the index back to EXTENDED, separately from
|
||||||
|
-- the table. This is currently not doable via DDL, but it is
|
||||||
|
-- supported internally.
|
||||||
|
UPDATE pg_attribute SET attstorage = 'x' WHERE attrelid = 'toasted_several_pkey'::regclass AND attname = 'toasted_key';
|
||||||
INSERT INTO toasted_several(toasted_key) VALUES(repeat('9876543210', 10000));
|
INSERT INTO toasted_several(toasted_key) VALUES(repeat('9876543210', 10000));
|
||||||
SELECT pg_column_size(toasted_key) > 2^16 FROM toasted_several;
|
SELECT pg_column_size(toasted_key) > 2^16 FROM toasted_several;
|
||||||
?column?
|
?column?
|
||||||
|
@ -279,6 +279,11 @@ ALTER TABLE toasted_several ALTER COLUMN toasted_key SET STORAGE EXTERNAL;
|
|||||||
ALTER TABLE toasted_several ALTER COLUMN toasted_col1 SET STORAGE EXTERNAL;
|
ALTER TABLE toasted_several ALTER COLUMN toasted_col1 SET STORAGE EXTERNAL;
|
||||||
ALTER TABLE toasted_several ALTER COLUMN toasted_col2 SET STORAGE EXTERNAL;
|
ALTER TABLE toasted_several ALTER COLUMN toasted_col2 SET STORAGE EXTERNAL;
|
||||||
|
|
||||||
|
-- Change the storage of the index back to EXTENDED, separately from
|
||||||
|
-- the table. This is currently not doable via DDL, but it is
|
||||||
|
-- supported internally.
|
||||||
|
UPDATE pg_attribute SET attstorage = 'x' WHERE attrelid = 'toasted_several_pkey'::regclass AND attname = 'toasted_key';
|
||||||
|
|
||||||
INSERT INTO toasted_several(toasted_key) VALUES(repeat('9876543210', 10000));
|
INSERT INTO toasted_several(toasted_key) VALUES(repeat('9876543210', 10000));
|
||||||
SELECT pg_column_size(toasted_key) > 2^16 FROM toasted_several;
|
SELECT pg_column_size(toasted_key) > 2^16 FROM toasted_several;
|
||||||
|
|
||||||
|
@ -7383,6 +7383,7 @@ ATExecSetStorage(Relation rel, const char *colName, Node *newValue, LOCKMODE loc
|
|||||||
Form_pg_attribute attrtuple;
|
Form_pg_attribute attrtuple;
|
||||||
AttrNumber attnum;
|
AttrNumber attnum;
|
||||||
ObjectAddress address;
|
ObjectAddress address;
|
||||||
|
ListCell *lc;
|
||||||
|
|
||||||
Assert(IsA(newValue, String));
|
Assert(IsA(newValue, String));
|
||||||
storagemode = strVal(newValue);
|
storagemode = strVal(newValue);
|
||||||
@ -7442,6 +7443,52 @@ ATExecSetStorage(Relation rel, const char *colName, Node *newValue, LOCKMODE loc
|
|||||||
|
|
||||||
heap_freetuple(tuple);
|
heap_freetuple(tuple);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Apply the change to indexes as well (only for simple index columns,
|
||||||
|
* matching behavior of index.c ConstructTupleDescriptor()).
|
||||||
|
*/
|
||||||
|
foreach(lc, RelationGetIndexList(rel))
|
||||||
|
{
|
||||||
|
Oid indexoid = lfirst_oid(lc);
|
||||||
|
Relation indrel;
|
||||||
|
AttrNumber indattnum = 0;
|
||||||
|
|
||||||
|
indrel = index_open(indexoid, lockmode);
|
||||||
|
|
||||||
|
for (int i = 0; i < indrel->rd_index->indnatts; i++)
|
||||||
|
{
|
||||||
|
if (indrel->rd_index->indkey.values[i] == attnum)
|
||||||
|
{
|
||||||
|
indattnum = i + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (indattnum == 0)
|
||||||
|
{
|
||||||
|
index_close(indrel, lockmode);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
tuple = SearchSysCacheCopyAttNum(RelationGetRelid(indrel), indattnum);
|
||||||
|
|
||||||
|
if (HeapTupleIsValid(tuple))
|
||||||
|
{
|
||||||
|
attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
|
||||||
|
attrtuple->attstorage = newstorage;
|
||||||
|
|
||||||
|
CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
|
||||||
|
|
||||||
|
InvokeObjectPostAlterHook(RelationRelationId,
|
||||||
|
RelationGetRelid(rel),
|
||||||
|
attrtuple->attnum);
|
||||||
|
|
||||||
|
heap_freetuple(tuple);
|
||||||
|
}
|
||||||
|
|
||||||
|
index_close(indrel, lockmode);
|
||||||
|
}
|
||||||
|
|
||||||
table_close(attrelation, RowExclusiveLock);
|
table_close(attrelation, RowExclusiveLock);
|
||||||
|
|
||||||
ObjectAddressSubSet(address, RelationRelationId,
|
ObjectAddressSubSet(address, RelationRelationId,
|
||||||
|
@ -2172,6 +2172,26 @@ where oid = 'test_storage'::regclass;
|
|||||||
t
|
t
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
|
-- test that SET STORAGE propagates to index correctly
|
||||||
|
create index test_storage_idx on test_storage (b, a);
|
||||||
|
alter table test_storage alter column a set storage external;
|
||||||
|
\d+ test_storage
|
||||||
|
Table "public.test_storage"
|
||||||
|
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
|
||||||
|
--------+---------+-----------+----------+---------+----------+--------------+-------------
|
||||||
|
a | text | | | | external | |
|
||||||
|
b | integer | | | 0 | plain | |
|
||||||
|
Indexes:
|
||||||
|
"test_storage_idx" btree (b, a)
|
||||||
|
|
||||||
|
\d+ test_storage_idx
|
||||||
|
Index "public.test_storage_idx"
|
||||||
|
Column | Type | Key? | Definition | Storage | Stats target
|
||||||
|
--------+---------+------+------------+----------+--------------
|
||||||
|
b | integer | yes | b | plain |
|
||||||
|
a | text | yes | a | external |
|
||||||
|
btree, for table "public.test_storage"
|
||||||
|
|
||||||
-- ALTER COLUMN TYPE with a check constraint and a child table (bug #13779)
|
-- ALTER COLUMN TYPE with a check constraint and a child table (bug #13779)
|
||||||
CREATE TABLE test_inh_check (a float check (a > 10.2), b float);
|
CREATE TABLE test_inh_check (a float check (a > 10.2), b float);
|
||||||
CREATE TABLE test_inh_check_child() INHERITS(test_inh_check);
|
CREATE TABLE test_inh_check_child() INHERITS(test_inh_check);
|
||||||
|
@ -134,7 +134,7 @@ CREATE TABLE no_index_cleanup (i INT PRIMARY KEY, t TEXT);
|
|||||||
CREATE INDEX no_index_cleanup_idx ON no_index_cleanup(t);
|
CREATE INDEX no_index_cleanup_idx ON no_index_cleanup(t);
|
||||||
ALTER TABLE no_index_cleanup ALTER COLUMN t SET STORAGE EXTERNAL;
|
ALTER TABLE no_index_cleanup ALTER COLUMN t SET STORAGE EXTERNAL;
|
||||||
INSERT INTO no_index_cleanup(i, t) VALUES (generate_series(1,30),
|
INSERT INTO no_index_cleanup(i, t) VALUES (generate_series(1,30),
|
||||||
repeat('1234567890',300));
|
repeat('1234567890',269));
|
||||||
-- index cleanup option is ignored if VACUUM FULL
|
-- index cleanup option is ignored if VACUUM FULL
|
||||||
VACUUM (INDEX_CLEANUP TRUE, FULL TRUE) no_index_cleanup;
|
VACUUM (INDEX_CLEANUP TRUE, FULL TRUE) no_index_cleanup;
|
||||||
VACUUM (FULL TRUE) no_index_cleanup;
|
VACUUM (FULL TRUE) no_index_cleanup;
|
||||||
@ -148,7 +148,7 @@ ALTER TABLE no_index_cleanup SET (vacuum_index_cleanup = true);
|
|||||||
VACUUM no_index_cleanup;
|
VACUUM no_index_cleanup;
|
||||||
-- Parameter is set for both the parent table and its toast relation.
|
-- Parameter is set for both the parent table and its toast relation.
|
||||||
INSERT INTO no_index_cleanup(i, t) VALUES (generate_series(31,60),
|
INSERT INTO no_index_cleanup(i, t) VALUES (generate_series(31,60),
|
||||||
repeat('1234567890',300));
|
repeat('1234567890',269));
|
||||||
DELETE FROM no_index_cleanup WHERE i < 45;
|
DELETE FROM no_index_cleanup WHERE i < 45;
|
||||||
-- Only toast index is cleaned up.
|
-- Only toast index is cleaned up.
|
||||||
ALTER TABLE no_index_cleanup SET (vacuum_index_cleanup = false,
|
ALTER TABLE no_index_cleanup SET (vacuum_index_cleanup = false,
|
||||||
|
@ -1472,6 +1472,12 @@ select reltoastrelid <> 0 as has_toast_table
|
|||||||
from pg_class
|
from pg_class
|
||||||
where oid = 'test_storage'::regclass;
|
where oid = 'test_storage'::regclass;
|
||||||
|
|
||||||
|
-- test that SET STORAGE propagates to index correctly
|
||||||
|
create index test_storage_idx on test_storage (b, a);
|
||||||
|
alter table test_storage alter column a set storage external;
|
||||||
|
\d+ test_storage
|
||||||
|
\d+ test_storage_idx
|
||||||
|
|
||||||
-- ALTER COLUMN TYPE with a check constraint and a child table (bug #13779)
|
-- ALTER COLUMN TYPE with a check constraint and a child table (bug #13779)
|
||||||
CREATE TABLE test_inh_check (a float check (a > 10.2), b float);
|
CREATE TABLE test_inh_check (a float check (a > 10.2), b float);
|
||||||
CREATE TABLE test_inh_check_child() INHERITS(test_inh_check);
|
CREATE TABLE test_inh_check_child() INHERITS(test_inh_check);
|
||||||
|
@ -115,7 +115,7 @@ CREATE TABLE no_index_cleanup (i INT PRIMARY KEY, t TEXT);
|
|||||||
CREATE INDEX no_index_cleanup_idx ON no_index_cleanup(t);
|
CREATE INDEX no_index_cleanup_idx ON no_index_cleanup(t);
|
||||||
ALTER TABLE no_index_cleanup ALTER COLUMN t SET STORAGE EXTERNAL;
|
ALTER TABLE no_index_cleanup ALTER COLUMN t SET STORAGE EXTERNAL;
|
||||||
INSERT INTO no_index_cleanup(i, t) VALUES (generate_series(1,30),
|
INSERT INTO no_index_cleanup(i, t) VALUES (generate_series(1,30),
|
||||||
repeat('1234567890',300));
|
repeat('1234567890',269));
|
||||||
-- index cleanup option is ignored if VACUUM FULL
|
-- index cleanup option is ignored if VACUUM FULL
|
||||||
VACUUM (INDEX_CLEANUP TRUE, FULL TRUE) no_index_cleanup;
|
VACUUM (INDEX_CLEANUP TRUE, FULL TRUE) no_index_cleanup;
|
||||||
VACUUM (FULL TRUE) no_index_cleanup;
|
VACUUM (FULL TRUE) no_index_cleanup;
|
||||||
@ -129,7 +129,7 @@ ALTER TABLE no_index_cleanup SET (vacuum_index_cleanup = true);
|
|||||||
VACUUM no_index_cleanup;
|
VACUUM no_index_cleanup;
|
||||||
-- Parameter is set for both the parent table and its toast relation.
|
-- Parameter is set for both the parent table and its toast relation.
|
||||||
INSERT INTO no_index_cleanup(i, t) VALUES (generate_series(31,60),
|
INSERT INTO no_index_cleanup(i, t) VALUES (generate_series(31,60),
|
||||||
repeat('1234567890',300));
|
repeat('1234567890',269));
|
||||||
DELETE FROM no_index_cleanup WHERE i < 45;
|
DELETE FROM no_index_cleanup WHERE i < 45;
|
||||||
-- Only toast index is cleaned up.
|
-- Only toast index is cleaned up.
|
||||||
ALTER TABLE no_index_cleanup SET (vacuum_index_cleanup = false,
|
ALTER TABLE no_index_cleanup SET (vacuum_index_cleanup = false,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user