Skip to content

Commit a6642b3

Browse files
committed
Add support for partitioned tables and indexes in REINDEX
Until now, REINDEX was not able to work with partitioned tables and indexes, forcing users to reindex partitions one by one. This extends REINDEX INDEX and REINDEX TABLE so as they can accept a partitioned index and table in input, respectively, to reindex all the partitions assigned to them with physical storage (foreign tables, partitioned tables and indexes are then discarded). This shares some logic with schema and database REINDEX as each partition gets processed in its own transaction after building a list of relations to work on. This choice has the advantage to minimize the number of invalid indexes to one partition with REINDEX CONCURRENTLY in the event a cancellation or failure in-flight, as the only indexes handled at once in a single REINDEX CONCURRENTLY loop are the ones from the partition being working on. Isolation tests are added to emulate some cases I bumped into while developing this feature, particularly with the concurrent drop of a leaf partition reindexed. However, this is rather limited as LOCK would cause REINDEX to block in the first transaction building the list of partitions. Per its multi-transaction nature, this new flavor cannot run in a transaction block, similarly to REINDEX SCHEMA, SYSTEM and DATABASE. Author: Justin Pryzby, Michael Paquier Reviewed-by: Anastasia Lubennikova Discussion: https://postgr.es/m/[email protected]
1 parent a547e68 commit a6642b3

File tree

13 files changed

+656
-92
lines changed

13 files changed

+656
-92
lines changed

contrib/postgres_fdw/expected/postgres_fdw.out

+21
Original file line numberDiff line numberDiff line change
@@ -4044,6 +4044,27 @@ SELECT f_test(100);
40444044

40454045
DROP FUNCTION f_test(int);
40464046
-- ===================================================================
4047+
-- REINDEX
4048+
-- ===================================================================
4049+
-- remote table is not created here
4050+
CREATE FOREIGN TABLE reindex_foreign (c1 int, c2 int)
4051+
SERVER loopback2 OPTIONS (table_name 'reindex_local');
4052+
REINDEX TABLE reindex_foreign; -- error
4053+
ERROR: "reindex_foreign" is not a table or materialized view
4054+
REINDEX TABLE CONCURRENTLY reindex_foreign; -- error
4055+
ERROR: "reindex_foreign" is not a table or materialized view
4056+
DROP FOREIGN TABLE reindex_foreign;
4057+
-- partitions and foreign tables
4058+
CREATE TABLE reind_fdw_parent (c1 int) PARTITION BY RANGE (c1);
4059+
CREATE TABLE reind_fdw_0_10 PARTITION OF reind_fdw_parent
4060+
FOR VALUES FROM (0) TO (10);
4061+
CREATE FOREIGN TABLE reind_fdw_10_20 PARTITION OF reind_fdw_parent
4062+
FOR VALUES FROM (10) TO (20)
4063+
SERVER loopback OPTIONS (table_name 'reind_local_10_20');
4064+
REINDEX TABLE reind_fdw_parent; -- ok
4065+
REINDEX TABLE CONCURRENTLY reind_fdw_parent; -- ok
4066+
DROP TABLE reind_fdw_parent;
4067+
-- ===================================================================
40474068
-- conversion error
40484069
-- ===================================================================
40494070
ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 TYPE int;

contrib/postgres_fdw/sql/postgres_fdw.sql

+20
Original file line numberDiff line numberDiff line change
@@ -1081,6 +1081,26 @@ $$ LANGUAGE plpgsql;
10811081
SELECT f_test(100);
10821082
DROP FUNCTION f_test(int);
10831083

1084+
-- ===================================================================
1085+
-- REINDEX
1086+
-- ===================================================================
1087+
-- remote table is not created here
1088+
CREATE FOREIGN TABLE reindex_foreign (c1 int, c2 int)
1089+
SERVER loopback2 OPTIONS (table_name 'reindex_local');
1090+
REINDEX TABLE reindex_foreign; -- error
1091+
REINDEX TABLE CONCURRENTLY reindex_foreign; -- error
1092+
DROP FOREIGN TABLE reindex_foreign;
1093+
-- partitions and foreign tables
1094+
CREATE TABLE reind_fdw_parent (c1 int) PARTITION BY RANGE (c1);
1095+
CREATE TABLE reind_fdw_0_10 PARTITION OF reind_fdw_parent
1096+
FOR VALUES FROM (0) TO (10);
1097+
CREATE FOREIGN TABLE reind_fdw_10_20 PARTITION OF reind_fdw_parent
1098+
FOR VALUES FROM (10) TO (20)
1099+
SERVER loopback OPTIONS (table_name 'reind_local_10_20');
1100+
REINDEX TABLE reind_fdw_parent; -- ok
1101+
REINDEX TABLE CONCURRENTLY reind_fdw_parent; -- ok
1102+
DROP TABLE reind_fdw_parent;
1103+
10841104
-- ===================================================================
10851105
-- conversion error
10861106
-- ===================================================================

doc/src/sgml/ref/reindex.sgml

+10-3
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,9 @@ REINDEX [ ( <replaceable class="parameter">option</replaceable> [, ...] ) ] { IN
8888
<term><literal>INDEX</literal></term>
8989
<listitem>
9090
<para>
91-
Recreate the specified index.
91+
Recreate the specified index. This form of <command>REINDEX</command>
92+
cannot be executed inside a transaction block when used with a
93+
partitioned index.
9294
</para>
9395
</listitem>
9496
</varlistentry>
@@ -99,6 +101,8 @@ REINDEX [ ( <replaceable class="parameter">option</replaceable> [, ...] ) ] { IN
99101
<para>
100102
Recreate all indexes of the specified table. If the table has a
101103
secondary <quote>TOAST</quote> table, that is reindexed as well.
104+
This form of <command>REINDEX</command> cannot be executed inside a
105+
transaction block when used with a partitioned table.
102106
</para>
103107
</listitem>
104108
</varlistentry>
@@ -259,8 +263,11 @@ REINDEX [ ( <replaceable class="parameter">option</replaceable> [, ...] ) ] { IN
259263
</para>
260264

261265
<para>
262-
Reindexing partitioned tables or partitioned indexes is not supported.
263-
Each individual partition can be reindexed separately instead.
266+
Reindexing partitioned indexes or partitioned tables is supported
267+
with <command>REINDEX INDEX</command> or <command>REINDEX TABLE</command>,
268+
respectively. Each partition of the specified partitioned relation is
269+
reindexed in a separate transaction. Those commands cannot be used inside
270+
a transaction block when working on a partitioned table or index.
264271
</para>
265272

266273
<refsect2 id="sql-reindex-concurrently" xreflabel="Rebuilding Indexes Concurrently">

src/backend/catalog/index.c

+10-15
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@
7777
#include "utils/lsyscache.h"
7878
#include "utils/memutils.h"
7979
#include "utils/pg_rusage.h"
80+
#include "utils/rel.h"
8081
#include "utils/snapmgr.h"
8182
#include "utils/syscache.h"
8283
#include "utils/tuplesort.h"
@@ -3486,11 +3487,12 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
34863487
iRel->rd_rel->relam);
34873488

34883489
/*
3489-
* The case of reindexing partitioned tables and indexes is handled
3490-
* differently by upper layers, so this case shouldn't arise.
3490+
* Partitioned indexes should never get processed here, as they have no
3491+
* physical storage.
34913492
*/
34923493
if (iRel->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
3493-
elog(ERROR, "unsupported relation kind for index \"%s\"",
3494+
elog(ERROR, "cannot reindex partitioned index \"%s.%s\"",
3495+
get_namespace_name(RelationGetNamespace(iRel)),
34943496
RelationGetRelationName(iRel));
34953497

34963498
/*
@@ -3707,20 +3709,13 @@ reindex_relation(Oid relid, int flags, int options)
37073709
return false;
37083710

37093711
/*
3710-
* This may be useful when implemented someday; but that day is not today.
3711-
* For now, avoid erroring out when called in a multi-table context
3712-
* (REINDEX SCHEMA) and happen to come across a partitioned table. The
3713-
* partitions may be reindexed on their own anyway.
3712+
* Partitioned tables should never get processed here, as they have no
3713+
* physical storage.
37143714
*/
37153715
if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
3716-
{
3717-
ereport(WARNING,
3718-
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3719-
errmsg("REINDEX of partitioned tables is not yet implemented, skipping \"%s\"",
3720-
RelationGetRelationName(rel))));
3721-
table_close(rel, ShareLock);
3722-
return false;
3723-
}
3716+
elog(ERROR, "cannot reindex partitioned table \"%s.%s\"",
3717+
get_namespace_name(RelationGetNamespace(rel)),
3718+
RelationGetRelationName(rel));
37243719

37253720
toast_relid = rel->rd_rel->reltoastrelid;
37263721

0 commit comments

Comments
 (0)