Skip to content

Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace #3

New issue

Have a question about this project? Sign up for a free account to open an issue and contact its maintainers and the community.

By clicking “Sign up for ”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on ? Sign in to your account

Open
wants to merge 3 commits into
base: master_ci
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
PrevPrevious commit
Allow CLUSTER and VACUUM FULL to change tablespace
  • Loading branch information
@ololobus
ololobus committedMar 26, 2020
commit 692bcadfacfa0c47fec7b6969525d33d0cac1f83
11 changes: 10 additions & 1 deletion doc/src/sgml/ref/cluster.sgml
Original file line numberDiff line numberDiff line change
Expand Up@@ -21,7 +21,7 @@ PostgreSQL documentation

<refsynopsisdiv>
<synopsis>
CLUSTER [VERBOSE] <replaceable class="parameter">table_name</replaceable> [ USING <replaceable class="parameter">index_name</replaceable> ]
CLUSTER [VERBOSE] <replaceable class="parameter">table_name</replaceable> [ USING <replaceable class="parameter">index_name</replaceable> ] [ TABLESPACE <replaceable class="parameter">new_tablespace</replaceable> ]
CLUSTER [VERBOSE]
</synopsis>
</refsynopsisdiv>
Expand DownExpand Up@@ -99,6 +99,15 @@ CLUSTER [VERBOSE]
</listitem>
</varlistentry>

<varlistentry>
<term><replaceable class="parameter">new_tablespace</replaceable></term>
<listitem>
<para>
The name of a specific tablespace to store clustered relations.
</para>
</listitem>
</varlistentry>

<varlistentry>
<term><literal>VERBOSE</literal></term>
<listitem>
Expand Down
11 changes: 11 additions & 0 deletions doc/src/sgml/ref/vacuum.sgml
Original file line numberDiff line numberDiff line change
Expand Up@@ -23,6 +23,7 @@ PostgreSQL documentation
<synopsis>
VACUUM [ ( <replaceable class="parameter">option</replaceable> [, ...] ) ] [ <replaceable class="parameter">table_and_columns</replaceable> [, ...] ]
VACUUM [ FULL ] [ FREEZE ] [ VERBOSE ] [ ANALYZE ] [ <replaceable class="parameter">table_and_columns</replaceable> [, ...] ]
VACUUM ( FULL [, ...] ) [ TABLESPACE <replaceable class="parameter">new_tablespace</replaceable> ] [ <replaceable class="parameter">table_and_columns</replaceable> [, ...] ]

<phrase>where <replaceable class="parameter">option</replaceable> can be one of:</phrase>

Expand DownExpand Up@@ -299,6 +300,16 @@ VACUUM [ FULL ] [ FREEZE ] [ VERBOSE ] [ ANALYZE ] [ <replaceable class="paramet
</para>
</listitem>
</varlistentry>

<varlistentry>
<term><replaceable class="parameter">new_tablespace</replaceable></term>
<listitem>
<para>
The name of a specific tablespace to write a new copy of the table.
</para>
</listitem>
</varlistentry>

</variablelist>
</refsect1>

Expand Down
58 changes: 52 additions & 6 deletions src/backend/commands/cluster.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -33,10 +33,12 @@
#include "catalog/namespace.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_am.h"
#include "catalog/pg_tablespace.h"
#include "catalog/toasting.h"
#include "commands/cluster.h"
#include "commands/progress.h"
#include "commands/tablecmds.h"
#include "commands/tablespace.h"
#include "commands/vacuum.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
Expand DownExpand Up@@ -67,7 +69,7 @@ typedef struct
} RelToCluster;


static void rebuild_relation(Relation OldHeap, Oid indexOid, bool verbose);
static void rebuild_relation(Relation OldHeap, Oid indexOid, Oid NewTableSpaceOid, bool verbose);
static void copy_table_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex,
bool verbose, bool *pSwapToastByContent,
TransactionId *pFreezeXid, MultiXactId *pCutoffMulti);
Expand DownExpand Up@@ -101,6 +103,22 @@ static List *get_tables_to_cluster(MemoryContext cluster_context);
void
cluster(ClusterStmt *stmt, bool isTopLevel)
{
/* Oid of tablespace to use for clustered relation. */
Oid tablespaceOid = InvalidOid;

/* Select tablespace Oid to use. */
if (stmt->tablespacename)
{
tablespaceOid = get_tablespace_oid(stmt->tablespacename, false);

/* Can't move a non-shared relation into pg_global */
if (tablespaceOid == GLOBALTABLESPACE_OID)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot move non-shared relation to tablespace \"%s\"",
stmt->tablespacename)));
}

if (stmt->relation != NULL)
{
/* This is the single-relation case. */
Expand DownExpand Up@@ -182,7 +200,7 @@ cluster(ClusterStmt *stmt, bool isTopLevel)
table_close(rel, NoLock);

/* Do the job. */
cluster_rel(tableOid, indexOid, stmt->options);
cluster_rel(tableOid, indexOid, tablespaceOid, stmt->options);
}
else
{
Expand DownExpand Up@@ -230,7 +248,7 @@ cluster(ClusterStmt *stmt, bool isTopLevel)
/* functions in indexes may want a snapshot set */
PushActiveSnapshot(GetTransactionSnapshot());
/* Do the job. */
cluster_rel(rvtc->tableOid, rvtc->indexOid,
cluster_rel(rvtc->tableOid, rvtc->indexOid, tablespaceOid,
stmt->options | CLUOPT_RECHECK);
PopActiveSnapshot();
CommitTransactionCommand();
Expand DownExpand Up@@ -262,7 +280,7 @@ cluster(ClusterStmt *stmt, bool isTopLevel)
* and error messages should refer to the operation as VACUUM not CLUSTER.
*/
void
cluster_rel(Oid tableOid, Oid indexOid, int options)
cluster_rel(Oid tableOid, Oid indexOid, Oid tablespaceOid, int options)
{
Relation OldHeap;
bool verbose = ((options & CLUOPT_VERBOSE) != 0);
Expand DownExpand Up@@ -375,6 +393,23 @@ cluster_rel(Oid tableOid, Oid indexOid, int options)
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot cluster a shared catalog")));

if (OidIsValid(tablespaceOid) &&
!allowSystemTableMods && IsSystemRelation(OldHeap))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied: \"%s\" is a system catalog",
RelationGetRelationName(OldHeap))));

/*
* We cannot support moving mapped relations into different tablespaces.
* (In particular this eliminates all shared catalogs.)
*/
if (OidIsValid(tablespaceOid) && RelationIsMapped(OldHeap))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot change tablespace of mapped relation \"%s\"",
RelationGetRelationName(OldHeap))));

/*
* Don't process temp tables of other backends ... their local buffer
* manager is not going to cope.
Expand DownExpand Up@@ -425,7 +460,7 @@ cluster_rel(Oid tableOid, Oid indexOid, int options)
TransferPredicateLocksToHeapRelation(OldHeap);

/* rebuild_relation does all the dirty work */
rebuild_relation(OldHeap, indexOid, verbose);
rebuild_relation(OldHeap, indexOid, tablespaceOid, verbose);

/* NB: rebuild_relation does table_close() on OldHeap */

Expand DownExpand Up@@ -584,7 +619,7 @@ mark_index_clustered(Relation rel, Oid indexOid, bool is_internal)
* NB: this routine closes OldHeap at the right time; caller should not.
*/
static void
rebuild_relation(Relation OldHeap, Oid indexOid, bool verbose)
rebuild_relation(Relation OldHeap, Oid indexOid, Oid NewTablespaceOid, bool verbose)
{
Oid tableOid = RelationGetRelid(OldHeap);
Oid tableSpace = OldHeap->rd_rel->reltablespace;
Expand All@@ -595,6 +630,10 @@ rebuild_relation(Relation OldHeap, Oid indexOid, bool verbose)
TransactionId frozenXid;
MultiXactId cutoffMulti;

/* Use new tablespace if passed. */
if (OidIsValid(NewTablespaceOid))
tableSpace = NewTablespaceOid;

/* Mark the correct index as clustered */
if (OidIsValid(indexOid))
mark_index_clustered(OldHeap, indexOid, true);
Expand DownExpand Up@@ -1039,6 +1078,13 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class,
*/
Assert(!target_is_pg_class);

if (!allowSystemTableMods && IsSystemClass(r1, relform1) &&
relform1->reltablespace != relform2->reltablespace)
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied: \"%s\" is a system catalog",
get_rel_name(r1))));

swaptemp = relform1->relfilenode;
relform1->relfilenode = relform2->relfilenode;
relform2->relfilenode = swaptemp;
Expand Down
51 changes: 48 additions & 3 deletions src/backend/commands/vacuum.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -31,13 +31,16 @@
#include "access/tableam.h"
#include "access/transam.h"
#include "access/xact.h"
#include "catalog/catalog.h"
#include "catalog/namespace.h"
#include "catalog/pg_database.h"
#include "catalog/pg_inherits.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_tablespace.h"
#include "commands/cluster.h"
#include "commands/defrem.h"
#include "commands/vacuum.h"
#include "commands/tablespace.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "pgstat.h"
Expand DownExpand Up@@ -106,6 +109,8 @@ ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel)
bool disable_page_skipping = false;
bool parallel_option = false;
ListCell *lc;
Oid tablespaceOid = InvalidOid; /* Oid of tablespace to use for relations
* after VACUUM FULL. */

/* Set default value */
params.index_cleanup = VACOPT_TERNARY_DEFAULT;
Expand DownExpand Up@@ -241,6 +246,28 @@ ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel)
params.multixact_freeze_table_age = -1;
}

/* Get tablespace Oid to use. */
if (vacstmt->tablespacename)
{
if (params.options & VACOPT_FULL)
{
tablespaceOid = get_tablespace_oid(vacstmt->tablespacename, false);

/* Can't move a non-shared relation into pg_global */
if (tablespaceOid == GLOBALTABLESPACE_OID)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot move non-shared relation to tablespace \"%s\"",
vacstmt->tablespacename)));
}
else
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("incompatible TABLESPACE option"),
errdetail("You can only use TABLESPACE with VACUUM FULL.")));
}
params.tablespace_oid = tablespaceOid;

/* user-invoked vacuum is never "for wraparound" */
params.is_wraparound = false;

Expand DownExpand Up@@ -1672,8 +1699,9 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params)
LOCKMODE lmode;
Relation onerel;
LockRelId onerelid;
Oid toast_relid;
Oid save_userid;
Oid toast_relid,
save_userid,
tablespaceOid = InvalidOid;
int save_sec_context;
int save_nestlevel;

Expand DownExpand Up@@ -1807,6 +1835,23 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params)
return true;
}

/*
* We cannot support moving system relations into different tablespaces,
* unless allow_system_table_mods=1.
*/
if (params->options & VACOPT_FULL &&
OidIsValid(params->tablespace_oid) &&
IsSystemRelation(onerel) && !allowSystemTableMods)
{
ereport(WARNING,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("skipping tablespace change of \"%s\"",
RelationGetRelationName(onerel)),
errdetail("Cannot move system relation, only VACUUM is performed.")));
}
else
tablespaceOid = params->tablespace_oid;

/*
* Get a session-level lock too. This will protect our access to the
* relation across multiple transactions, so that we can vacuum the
Expand DownExpand Up@@ -1876,7 +1921,7 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params)
cluster_options |= CLUOPT_VERBOSE;

/* VACUUM FULL is now a variant of CLUSTER; see cluster.c */
cluster_rel(relid, InvalidOid, cluster_options);
cluster_rel(relid, InvalidOid, tablespaceOid, cluster_options);
}
else
table_relation_vacuum(onerel, params, vac_strategy);
Expand Down
2 changes: 2 additions & 0 deletions src/backend/nodes/copyfuncs.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -3316,6 +3316,7 @@ _copyClusterStmt(const ClusterStmt *from)
COPY_NODE_FIELD(relation);
COPY_STRING_FIELD(indexname);
COPY_SCALAR_FIELD(options);
COPY_STRING_FIELD(tablespacename);

return newnode;
}
Expand DownExpand Up@@ -3901,6 +3902,7 @@ _copyVacuumStmt(const VacuumStmt *from)
COPY_NODE_FIELD(options);
COPY_NODE_FIELD(rels);
COPY_SCALAR_FIELD(is_vacuumcmd);
COPY_STRING_FIELD(tablespacename);

return newnode;
}
Expand Down
2 changes: 2 additions & 0 deletions src/backend/nodes/equalfuncs.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -1215,6 +1215,7 @@ _equalClusterStmt(const ClusterStmt *a, const ClusterStmt *b)
COMPARE_NODE_FIELD(relation);
COMPARE_STRING_FIELD(indexname);
COMPARE_SCALAR_FIELD(options);
COMPARE_SCALAR_FIELD(tablespacename);

return true;
}
Expand DownExpand Up@@ -1702,6 +1703,7 @@ _equalVacuumStmt(const VacuumStmt *a, const VacuumStmt *b)
COMPARE_NODE_FIELD(options);
COMPARE_NODE_FIELD(rels);
COMPARE_SCALAR_FIELD(is_vacuumcmd);
COMPARE_SCALAR_FIELD(tablespacename);

return true;
}
Expand Down
Loading