Skip to content

Commit 501e41d

Browse files
committed
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
1 parent f9463d2 commit 501e41d

File tree

7 files changed

+86
-4
lines changed

7 files changed

+86
-4
lines changed

contrib/test_decoding/expected/toast.out

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,10 @@ ALTER TABLE toasted_several REPLICA IDENTITY FULL;
305305
ALTER TABLE toasted_several ALTER COLUMN toasted_key SET STORAGE EXTERNAL;
306306
ALTER TABLE toasted_several ALTER COLUMN toasted_col1 SET STORAGE EXTERNAL;
307307
ALTER TABLE toasted_several ALTER COLUMN toasted_col2 SET STORAGE EXTERNAL;
308+
-- Change the storage of the index back to EXTENDED, separately from
309+
-- the table. This is currently not doable via DDL, but it is
310+
-- supported internally.
311+
UPDATE pg_attribute SET attstorage = 'x' WHERE attrelid = 'toasted_several_pkey'::regclass AND attname = 'toasted_key';
308312
INSERT INTO toasted_several(toasted_key) VALUES(repeat('9876543210', 10000));
309313
SELECT pg_column_size(toasted_key) > 2^16 FROM toasted_several;
310314
?column?

contrib/test_decoding/sql/toast.sql

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,11 @@ ALTER TABLE toasted_several ALTER COLUMN toasted_key SET STORAGE EXTERNAL;
279279
ALTER TABLE toasted_several ALTER COLUMN toasted_col1 SET STORAGE EXTERNAL;
280280
ALTER TABLE toasted_several ALTER COLUMN toasted_col2 SET STORAGE EXTERNAL;
281281

282+
-- Change the storage of the index back to EXTENDED, separately from
283+
-- the table. This is currently not doable via DDL, but it is
284+
-- supported internally.
285+
UPDATE pg_attribute SET attstorage = 'x' WHERE attrelid = 'toasted_several_pkey'::regclass AND attname = 'toasted_key';
286+
282287
INSERT INTO toasted_several(toasted_key) VALUES(repeat('9876543210', 10000));
283288
SELECT pg_column_size(toasted_key) > 2^16 FROM toasted_several;
284289

src/backend/commands/tablecmds.c

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7383,6 +7383,7 @@ ATExecSetStorage(Relation rel, const char *colName, Node *newValue, LOCKMODE loc
73837383
Form_pg_attribute attrtuple;
73847384
AttrNumber attnum;
73857385
ObjectAddress address;
7386+
ListCell *lc;
73867387

73877388
Assert(IsA(newValue, String));
73887389
storagemode = strVal(newValue);
@@ -7442,6 +7443,52 @@ ATExecSetStorage(Relation rel, const char *colName, Node *newValue, LOCKMODE loc
74427443

74437444
heap_freetuple(tuple);
74447445

7446+
/*
7447+
* Apply the change to indexes as well (only for simple index columns,
7448+
* matching behavior of index.c ConstructTupleDescriptor()).
7449+
*/
7450+
foreach(lc, RelationGetIndexList(rel))
7451+
{
7452+
Oid indexoid = lfirst_oid(lc);
7453+
Relation indrel;
7454+
AttrNumber indattnum = 0;
7455+
7456+
indrel = index_open(indexoid, lockmode);
7457+
7458+
for (int i = 0; i < indrel->rd_index->indnatts; i++)
7459+
{
7460+
if (indrel->rd_index->indkey.values[i] == attnum)
7461+
{
7462+
indattnum = i + 1;
7463+
break;
7464+
}
7465+
}
7466+
7467+
if (indattnum == 0)
7468+
{
7469+
index_close(indrel, lockmode);
7470+
continue;
7471+
}
7472+
7473+
tuple = SearchSysCacheCopyAttNum(RelationGetRelid(indrel), indattnum);
7474+
7475+
if (HeapTupleIsValid(tuple))
7476+
{
7477+
attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
7478+
attrtuple->attstorage = newstorage;
7479+
7480+
CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
7481+
7482+
InvokeObjectPostAlterHook(RelationRelationId,
7483+
RelationGetRelid(rel),
7484+
attrtuple->attnum);
7485+
7486+
heap_freetuple(tuple);
7487+
}
7488+
7489+
index_close(indrel, lockmode);
7490+
}
7491+
74457492
table_close(attrelation, RowExclusiveLock);
74467493

74477494
ObjectAddressSubSet(address, RelationRelationId,

src/test/regress/expected/alter_table.out

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2172,6 +2172,26 @@ where oid = 'test_storage'::regclass;
21722172
t
21732173
(1 row)
21742174

2175+
-- test that SET STORAGE propagates to index correctly
2176+
create index test_storage_idx on test_storage (b, a);
2177+
alter table test_storage alter column a set storage external;
2178+
\d+ test_storage
2179+
Table "public.test_storage"
2180+
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
2181+
--------+---------+-----------+----------+---------+----------+--------------+-------------
2182+
a | text | | | | external | |
2183+
b | integer | | | 0 | plain | |
2184+
Indexes:
2185+
"test_storage_idx" btree (b, a)
2186+
2187+
\d+ test_storage_idx
2188+
Index "public.test_storage_idx"
2189+
Column | Type | Key? | Definition | Storage | Stats target
2190+
--------+---------+------+------------+----------+--------------
2191+
b | integer | yes | b | plain |
2192+
a | text | yes | a | external |
2193+
btree, for table "public.test_storage"
2194+
21752195
-- ALTER COLUMN TYPE with a check constraint and a child table (bug #13779)
21762196
CREATE TABLE test_inh_check (a float check (a > 10.2), b float);
21772197
CREATE TABLE test_inh_check_child() INHERITS(test_inh_check);

src/test/regress/expected/vacuum.out

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ CREATE TABLE no_index_cleanup (i INT PRIMARY KEY, t TEXT);
134134
CREATE INDEX no_index_cleanup_idx ON no_index_cleanup(t);
135135
ALTER TABLE no_index_cleanup ALTER COLUMN t SET STORAGE EXTERNAL;
136136
INSERT INTO no_index_cleanup(i, t) VALUES (generate_series(1,30),
137-
repeat('1234567890',300));
137+
repeat('1234567890',269));
138138
-- index cleanup option is ignored if VACUUM FULL
139139
VACUUM (INDEX_CLEANUP TRUE, FULL TRUE) no_index_cleanup;
140140
VACUUM (FULL TRUE) no_index_cleanup;
@@ -148,7 +148,7 @@ ALTER TABLE no_index_cleanup SET (vacuum_index_cleanup = true);
148148
VACUUM no_index_cleanup;
149149
-- Parameter is set for both the parent table and its toast relation.
150150
INSERT INTO no_index_cleanup(i, t) VALUES (generate_series(31,60),
151-
repeat('1234567890',300));
151+
repeat('1234567890',269));
152152
DELETE FROM no_index_cleanup WHERE i < 45;
153153
-- Only toast index is cleaned up.
154154
ALTER TABLE no_index_cleanup SET (vacuum_index_cleanup = false,

src/test/regress/sql/alter_table.sql

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1472,6 +1472,12 @@ select reltoastrelid <> 0 as has_toast_table
14721472
from pg_class
14731473
where oid = 'test_storage'::regclass;
14741474

1475+
-- test that SET STORAGE propagates to index correctly
1476+
create index test_storage_idx on test_storage (b, a);
1477+
alter table test_storage alter column a set storage external;
1478+
\d+ test_storage
1479+
\d+ test_storage_idx
1480+
14751481
-- ALTER COLUMN TYPE with a check constraint and a child table (bug #13779)
14761482
CREATE TABLE test_inh_check (a float check (a > 10.2), b float);
14771483
CREATE TABLE test_inh_check_child() INHERITS(test_inh_check);

src/test/regress/sql/vacuum.sql

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ CREATE TABLE no_index_cleanup (i INT PRIMARY KEY, t TEXT);
115115
CREATE INDEX no_index_cleanup_idx ON no_index_cleanup(t);
116116
ALTER TABLE no_index_cleanup ALTER COLUMN t SET STORAGE EXTERNAL;
117117
INSERT INTO no_index_cleanup(i, t) VALUES (generate_series(1,30),
118-
repeat('1234567890',300));
118+
repeat('1234567890',269));
119119
-- index cleanup option is ignored if VACUUM FULL
120120
VACUUM (INDEX_CLEANUP TRUE, FULL TRUE) no_index_cleanup;
121121
VACUUM (FULL TRUE) no_index_cleanup;
@@ -129,7 +129,7 @@ ALTER TABLE no_index_cleanup SET (vacuum_index_cleanup = true);
129129
VACUUM no_index_cleanup;
130130
-- Parameter is set for both the parent table and its toast relation.
131131
INSERT INTO no_index_cleanup(i, t) VALUES (generate_series(31,60),
132-
repeat('1234567890',300));
132+
repeat('1234567890',269));
133133
DELETE FROM no_index_cleanup WHERE i < 45;
134134
-- Only toast index is cleaned up.
135135
ALTER TABLE no_index_cleanup SET (vacuum_index_cleanup = false,

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy