diff options
author | Alvaro Herrera <alvherre@alvh.no-ip.org> | 2018-11-03 13:23:37 -0300 |
---|---|---|
committer | Alvaro Herrera <alvherre@alvh.no-ip.org> | 2018-11-03 13:25:29 -0300 |
commit | 33e6c34c32677a168bee4bc6c335aa8d73211a56 (patch) | |
tree | d9c10c05800aaac9f109269478588681c2c11259 /src/backend/commands/tablecmds.c | |
parent | 0e88ba1fe1e02086e718982a86c94c3c366c9d62 (diff) | |
download | postgresql-33e6c34c32677a168bee4bc6c335aa8d73211a56.tar.gz postgresql-33e6c34c32677a168bee4bc6c335aa8d73211a56.zip |
Fix tablespace handling for partitioned indexes
When creating partitioned indexes, the tablespace was not being saved
for the parent index. This meant that subsequently created partitions
would not use the right tablespace for their indexes.
ALTER INDEX SET TABLESPACE and ALTER INDEX ALL IN TABLESPACE raised
errors when tried; fix them too. This requires bespoke code for
ATExecCmd() that applies to the special case when the tablespace move is
just a catalog change.
Discussion: https://postgr.es/m/20181102003138.uxpaca6qfxzskepi@alvherre.pgsql
Diffstat (limited to 'src/backend/commands/tablecmds.c')
-rw-r--r-- | src/backend/commands/tablecmds.c | 60 |
1 files changed, 57 insertions, 3 deletions
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 357c73073de..fdd22f4923b 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -446,6 +446,7 @@ static bool ATPrepChangePersistence(Relation rel, bool toLogged); static void ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel, const char *tablespacename, LOCKMODE lockmode); static void ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode); +static void ATExecPartedIdxSetTableSpace(Relation rel, Oid newTableSpace); static void ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation, LOCKMODE lockmode); @@ -3845,7 +3846,8 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, pass = AT_PASS_DROP; break; case AT_SetTableSpace: /* SET TABLESPACE */ - ATSimplePermissions(rel, ATT_TABLE | ATT_MATVIEW | ATT_INDEX); + ATSimplePermissions(rel, ATT_TABLE | ATT_MATVIEW | ATT_INDEX | + ATT_PARTITIONED_INDEX); /* This command never recurses */ ATPrepSetTableSpace(tab, rel, cmd->name, lockmode); pass = AT_PASS_MISC; /* doesn't actually matter */ @@ -4181,10 +4183,13 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel, */ break; case AT_SetTableSpace: /* SET TABLESPACE */ - /* - * Nothing to do here; Phase 3 does the work + * Only do this for partitioned indexes, for which this is just + * a catalog change. Other relation types are handled by Phase 3. */ + if (rel->rd_rel->relkind == RELKIND_PARTITIONED_INDEX) + ATExecPartedIdxSetTableSpace(rel, tab->newTableSpace); + break; case AT_SetRelOptions: /* SET (...) */ case AT_ResetRelOptions: /* RESET (...) */ @@ -11050,6 +11055,55 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode) } /* + * Special handling of ALTER TABLE SET TABLESPACE for partitioned indexes, + * which have no storage (so not handled in Phase 3 like other relation types) + */ +static void +ATExecPartedIdxSetTableSpace(Relation rel, Oid newTableSpace) +{ + HeapTuple tuple; + Oid oldTableSpace; + Relation pg_class; + Form_pg_class rd_rel; + Oid indexOid = RelationGetRelid(rel); + + Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_INDEX); + + /* + * No work if no change in tablespace. + */ + oldTableSpace = rel->rd_rel->reltablespace; + if (newTableSpace == oldTableSpace || + (newTableSpace == MyDatabaseTableSpace && oldTableSpace == 0)) + { + InvokeObjectPostAlterHook(RelationRelationId, + indexOid, 0); + return; + } + + /* Get a modifiable copy of the relation's pg_class row */ + pg_class = heap_open(RelationRelationId, RowExclusiveLock); + + tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(indexOid)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for relation %u", indexOid); + rd_rel = (Form_pg_class) GETSTRUCT(tuple); + + /* update the pg_class row */ + rd_rel->reltablespace = (newTableSpace == MyDatabaseTableSpace) ? InvalidOid : newTableSpace; + CatalogTupleUpdate(pg_class, &tuple->t_self, tuple); + + InvokeObjectPostAlterHook(RelationRelationId, indexOid, 0); + + heap_freetuple(tuple); + + heap_close(pg_class, RowExclusiveLock); + + /* Make sure the reltablespace change is visible */ + CommandCounterIncrement(); +} + +/* * Alter Table ALL ... SET TABLESPACE * * Allows a user to move all objects of some type in a given tablespace in the |