From bf7233ee4a546219b078b5a0afc654ec02958bee Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Thu, 9 Apr 2020 14:10:01 +0200 Subject: 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 --- src/backend/commands/tablecmds.c | 47 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) (limited to 'src/backend/commands/tablecmds.c') diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 1a6ccff8f1c..b36683e7497 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -6973,6 +6973,7 @@ ATExecSetStorage(Relation rel, const char *colName, Node *newValue, LOCKMODE loc Form_pg_attribute attrtuple; AttrNumber attnum; ObjectAddress address; + ListCell *lc; Assert(IsA(newValue, String)); storagemode = strVal(newValue); @@ -7032,6 +7033,52 @@ ATExecSetStorage(Relation rel, const char *colName, Node *newValue, LOCKMODE loc 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); ObjectAddressSubSet(address, RelationRelationId, -- cgit v1.2.3