Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit dfa6081

Browse files
committed
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
1 parent ceadcbe commit dfa6081

File tree

4 files changed

+94
-5
lines changed

4 files changed

+94
-5
lines changed

src/backend/catalog/heap.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,6 @@ heap_create(const char *relname,
353353
case RELKIND_COMPOSITE_TYPE:
354354
case RELKIND_FOREIGN_TABLE:
355355
case RELKIND_PARTITIONED_TABLE:
356-
case RELKIND_PARTITIONED_INDEX:
357356
create_storage = false;
358357

359358
/*
@@ -362,6 +361,15 @@ heap_create(const char *relname,
362361
*/
363362
reltablespace = InvalidOid;
364363
break;
364+
365+
case RELKIND_PARTITIONED_INDEX:
366+
/*
367+
* Preserve tablespace so that it's used as tablespace for indexes
368+
* on future partitions.
369+
*/
370+
create_storage = false;
371+
break;
372+
365373
case RELKIND_SEQUENCE:
366374
create_storage = true;
367375

src/backend/commands/tablecmds.c

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,7 @@ static bool ATPrepChangePersistence(Relation rel, bool toLogged);
449449
static void ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel,
450450
const char *tablespacename, LOCKMODE lockmode);
451451
static void ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode);
452+
static void ATExecPartedIdxSetTableSpace(Relation rel, Oid newTableSpace);
452453
static void ATExecSetRelOptions(Relation rel, List *defList,
453454
AlterTableType operation,
454455
LOCKMODE lockmode);
@@ -3875,7 +3876,8 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
38753876
pass = AT_PASS_DROP;
38763877
break;
38773878
case AT_SetTableSpace: /* SET TABLESPACE */
3878-
ATSimplePermissions(rel, ATT_TABLE | ATT_MATVIEW | ATT_INDEX);
3879+
ATSimplePermissions(rel, ATT_TABLE | ATT_MATVIEW | ATT_INDEX |
3880+
ATT_PARTITIONED_INDEX);
38793881
/* This command never recurses */
38803882
ATPrepSetTableSpace(tab, rel, cmd->name, lockmode);
38813883
pass = AT_PASS_MISC; /* doesn't actually matter */
@@ -4211,10 +4213,13 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
42114213
*/
42124214
break;
42134215
case AT_SetTableSpace: /* SET TABLESPACE */
4214-
42154216
/*
4216-
* Nothing to do here; Phase 3 does the work
4217+
* Only do this for partitioned indexes, for which this is just
4218+
* a catalog change. Other relation types are handled by Phase 3.
42174219
*/
4220+
if (rel->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
4221+
ATExecPartedIdxSetTableSpace(rel, tab->newTableSpace);
4222+
42184223
break;
42194224
case AT_SetRelOptions: /* SET (...) */
42204225
case AT_ResetRelOptions: /* RESET (...) */
@@ -11080,6 +11085,55 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
1108011085
list_free(reltoastidxids);
1108111086
}
1108211087

11088+
/*
11089+
* Special handling of ALTER TABLE SET TABLESPACE for partitioned indexes,
11090+
* which have no storage (so not handled in Phase 3 like other relation types)
11091+
*/
11092+
static void
11093+
ATExecPartedIdxSetTableSpace(Relation rel, Oid newTableSpace)
11094+
{
11095+
HeapTuple tuple;
11096+
Oid oldTableSpace;
11097+
Relation pg_class;
11098+
Form_pg_class rd_rel;
11099+
Oid indexOid = RelationGetRelid(rel);
11100+
11101+
Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_INDEX);
11102+
11103+
/*
11104+
* No work if no change in tablespace.
11105+
*/
11106+
oldTableSpace = rel->rd_rel->reltablespace;
11107+
if (newTableSpace == oldTableSpace ||
11108+
(newTableSpace == MyDatabaseTableSpace && oldTableSpace == 0))
11109+
{
11110+
InvokeObjectPostAlterHook(RelationRelationId,
11111+
indexOid, 0);
11112+
return;
11113+
}
11114+
11115+
/* Get a modifiable copy of the relation's pg_class row */
11116+
pg_class = heap_open(RelationRelationId, RowExclusiveLock);
11117+
11118+
tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(indexOid));
11119+
if (!HeapTupleIsValid(tuple))
11120+
elog(ERROR, "cache lookup failed for relation %u", indexOid);
11121+
rd_rel = (Form_pg_class) GETSTRUCT(tuple);
11122+
11123+
/* update the pg_class row */
11124+
rd_rel->reltablespace = (newTableSpace == MyDatabaseTableSpace) ? InvalidOid : newTableSpace;
11125+
CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
11126+
11127+
InvokeObjectPostAlterHook(RelationRelationId, indexOid, 0);
11128+
11129+
heap_freetuple(tuple);
11130+
11131+
heap_close(pg_class, RowExclusiveLock);
11132+
11133+
/* Make sure the reltablespace change is visible */
11134+
CommandCounterIncrement();
11135+
}
11136+
1108311137
/*
1108411138
* Alter Table ALL ... SET TABLESPACE
1108511139
*

src/test/regress/input/tablespace.source

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,14 @@ CREATE INDEX foo_idx on testschema.foo(i) TABLESPACE regress_tblspace;
4444
SELECT relname, spcname FROM pg_catalog.pg_tablespace t, pg_catalog.pg_class c
4545
where c.reltablespace = t.oid AND c.relname = 'foo_idx';
4646

47+
-- partitioned index
48+
CREATE TABLE testschema.part (a int) PARTITION BY LIST (a);
49+
CREATE TABLE testschema.part1 PARTITION OF testschema.part FOR VALUES IN (1);
50+
CREATE INDEX part_a_idx ON testschema.part (a) TABLESPACE regress_tblspace;
51+
CREATE TABLE testschema.part2 PARTITION OF testschema.part FOR VALUES IN (2);
52+
SELECT relname, spcname FROM pg_catalog.pg_tablespace t, pg_catalog.pg_class c
53+
where c.reltablespace = t.oid AND c.relname LIKE 'part%_idx';
54+
4755
-- check that default_tablespace doesn't affect ALTER TABLE index rebuilds
4856
CREATE TABLE testschema.test_default_tab(id bigint) TABLESPACE regress_tblspace;
4957
INSERT INTO testschema.test_default_tab VALUES (1);
@@ -93,6 +101,8 @@ CREATE UNIQUE INDEX anindex ON testschema.atable(column1);
93101

94102
ALTER TABLE testschema.atable SET TABLESPACE regress_tblspace;
95103
ALTER INDEX testschema.anindex SET TABLESPACE regress_tblspace;
104+
ALTER INDEX testschema.part_a_idx SET TABLESPACE pg_default;
105+
ALTER INDEX testschema.part_a_idx SET TABLESPACE regress_tblspace;
96106

97107
INSERT INTO testschema.atable VALUES(3); -- ok
98108
INSERT INTO testschema.atable VALUES(1); -- fail (checks index)

src/test/regress/output/tablespace.source

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,20 @@ SELECT relname, spcname FROM pg_catalog.pg_tablespace t, pg_catalog.pg_class c
6161
foo_idx | regress_tblspace
6262
(1 row)
6363

64+
-- partitioned index
65+
CREATE TABLE testschema.part (a int) PARTITION BY LIST (a);
66+
CREATE TABLE testschema.part1 PARTITION OF testschema.part FOR VALUES IN (1);
67+
CREATE INDEX part_a_idx ON testschema.part (a) TABLESPACE regress_tblspace;
68+
CREATE TABLE testschema.part2 PARTITION OF testschema.part FOR VALUES IN (2);
69+
SELECT relname, spcname FROM pg_catalog.pg_tablespace t, pg_catalog.pg_class c
70+
where c.reltablespace = t.oid AND c.relname LIKE 'part%_idx';
71+
relname | spcname
72+
-------------+------------------
73+
part1_a_idx | regress_tblspace
74+
part2_a_idx | regress_tblspace
75+
part_a_idx | regress_tblspace
76+
(3 rows)
77+
6478
-- check that default_tablespace doesn't affect ALTER TABLE index rebuilds
6579
CREATE TABLE testschema.test_default_tab(id bigint) TABLESPACE regress_tblspace;
6680
INSERT INTO testschema.test_default_tab VALUES (1);
@@ -200,6 +214,8 @@ CREATE TABLE testschema.atable AS VALUES (1), (2);
200214
CREATE UNIQUE INDEX anindex ON testschema.atable(column1);
201215
ALTER TABLE testschema.atable SET TABLESPACE regress_tblspace;
202216
ALTER INDEX testschema.anindex SET TABLESPACE regress_tblspace;
217+
ALTER INDEX testschema.part_a_idx SET TABLESPACE pg_default;
218+
ALTER INDEX testschema.part_a_idx SET TABLESPACE regress_tblspace;
203219
INSERT INTO testschema.atable VALUES(3); -- ok
204220
INSERT INTO testschema.atable VALUES(1); -- fail (checks index)
205221
ERROR: duplicate key value violates unique constraint "anindex"
@@ -241,10 +257,11 @@ NOTICE: no matching relations in tablespace "regress_tblspace_renamed" found
241257
-- Should succeed
242258
DROP TABLESPACE regress_tblspace_renamed;
243259
DROP SCHEMA testschema CASCADE;
244-
NOTICE: drop cascades to 5 other objects
260+
NOTICE: drop cascades to 6 other objects
245261
DETAIL: drop cascades to table testschema.foo
246262
drop cascades to table testschema.asselect
247263
drop cascades to table testschema.asexecute
264+
drop cascades to table testschema.part
248265
drop cascades to table testschema.atable
249266
drop cascades to table testschema.tablespace_acl
250267
DROP ROLE regress_tablespace_user1;

0 commit comments

Comments
 (0)