PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
cluster.h File Reference
#include "nodes/parsenodes.h"
#include "storage/lock.h"
#include "utils/relcache.h"
Include dependency graph for cluster.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

void cluster (ClusterStmt *stmt, bool isTopLevel)
 
void cluster_rel (Oid tableOid, Oid indexOid, bool recheck, bool verbose)
 
void check_index_is_clusterable (Relation OldHeap, Oid indexOid, bool recheck, LOCKMODE lockmode)
 
void mark_index_clustered (Relation rel, Oid indexOid, bool is_internal)
 
Oid make_new_heap (Oid OIDOldHeap, Oid NewTableSpace, char relpersistence, LOCKMODE lockmode)
 
void finish_heap_swap (Oid OIDOldHeap, Oid OIDNewHeap, bool is_system_catalog, bool swap_toast_by_content, bool check_constraints, bool is_internal, TransactionId frozenXid, MultiXactId minMulti, char newrelpersistence)
 

Function Documentation

void check_index_is_clusterable ( Relation  OldHeap,
Oid  indexOid,
bool  recheck,
LOCKMODE  lockmode 
)

Definition at line 418 of file cluster.c.

References IndexAmRoutine::amclusterable, Anum_pg_index_indpred, ereport, errcode(), errmsg(), ERROR, heap_attisnull(), index_close(), index_open(), IndexIsValid, NoLock, NULL, RelationData::rd_amroutine, RelationData::rd_index, RelationData::rd_indextuple, RelationGetRelationName, and RelationGetRelid.

Referenced by ATExecClusterOn(), and cluster_rel().

419 {
420  Relation OldIndex;
421 
422  OldIndex = index_open(indexOid, lockmode);
423 
424  /*
425  * Check that index is in fact an index on the given relation
426  */
427  if (OldIndex->rd_index == NULL ||
428  OldIndex->rd_index->indrelid != RelationGetRelid(OldHeap))
429  ereport(ERROR,
430  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
431  errmsg("\"%s\" is not an index for table \"%s\"",
432  RelationGetRelationName(OldIndex),
433  RelationGetRelationName(OldHeap))));
434 
435  /* Index AM must allow clustering */
436  if (!OldIndex->rd_amroutine->amclusterable)
437  ereport(ERROR,
438  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
439  errmsg("cannot cluster on index \"%s\" because access method does not support clustering",
440  RelationGetRelationName(OldIndex))));
441 
442  /*
443  * Disallow clustering on incomplete indexes (those that might not index
444  * every row of the relation). We could relax this by making a separate
445  * seqscan pass over the table to copy the missing rows, but that seems
446  * expensive and tedious.
447  */
449  ereport(ERROR,
450  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
451  errmsg("cannot cluster on partial index \"%s\"",
452  RelationGetRelationName(OldIndex))));
453 
454  /*
455  * Disallow if index is left over from a failed CREATE INDEX CONCURRENTLY;
456  * it might well not contain entries for every heap row, or might not even
457  * be internally consistent. (But note that we don't check indcheckxmin;
458  * the worst consequence of following broken HOT chains would be that we
459  * might put recently-dead tuples out-of-order in the new table, and there
460  * is little harm in that.)
461  */
462  if (!IndexIsValid(OldIndex->rd_index))
463  ereport(ERROR,
464  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
465  errmsg("cannot cluster on invalid index \"%s\"",
466  RelationGetRelationName(OldIndex))));
467 
468  /* Drop relcache refcnt on OldIndex, but keep lock */
469  index_close(OldIndex, NoLock);
470 }
#define IndexIsValid(indexForm)
Definition: pg_index.h:107
int errcode(int sqlerrcode)
Definition: elog.c:575
struct IndexAmRoutine * rd_amroutine
Definition: rel.h:177
struct HeapTupleData * rd_indextuple
Definition: rel.h:157
Form_pg_index rd_index
Definition: rel.h:155
#define ERROR
Definition: elog.h:43
#define NoLock
Definition: lockdefs.h:34
bool heap_attisnull(HeapTuple tup, int attnum)
Definition: heaptuple.c:297
#define RelationGetRelationName(relation)
Definition: rel.h:433
#define ereport(elevel, rest)
Definition: elog.h:122
bool amclusterable
Definition: amapi.h:189
#define Anum_pg_index_indpred
Definition: pg_index.h:92
#define NULL
Definition: c.h:226
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:176
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define RelationGetRelid(relation)
Definition: rel.h:413
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:151
void cluster ( ClusterStmt stmt,
bool  isTopLevel 
)

Definition at line 106 of file cluster.c.

References AccessExclusiveLock, ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate(), cluster_rel(), CommitTransactionCommand(), elog, ereport, errcode(), errmsg(), ERROR, get_relname_relid(), get_tables_to_cluster(), GETSTRUCT, GetTransactionSnapshot(), heap_close, heap_open(), HeapTupleIsValid, ClusterStmt::indexname, RelToCluster::indexOid, INDEXRELID, InvalidOid, lfirst, lfirst_oid, MemoryContextDelete(), NoLock, NULL, ObjectIdGetDatum, OidIsValid, PopActiveSnapshot(), PortalContext, PreventTransactionChain(), PushActiveSnapshot(), RangeVarCallbackOwnsTable(), RangeVarGetRelidExtended(), RelationData::rd_rel, ClusterStmt::relation, RELATION_IS_OTHER_TEMP, RelationGetIndexList(), ReleaseSysCache(), RangeVar::relname, SearchSysCache1, StartTransactionCommand(), RelToCluster::tableOid, and ClusterStmt::verbose.

Referenced by standard_ProcessUtility(), start_postmaster(), and stop_postmaster().

107 {
108  if (stmt->relation != NULL)
109  {
110  /* This is the single-relation case. */
111  Oid tableOid,
112  indexOid = InvalidOid;
113  Relation rel;
114 
115  /* Find, lock, and check permissions on the table */
116  tableOid = RangeVarGetRelidExtended(stmt->relation,
118  false, false,
120  rel = heap_open(tableOid, NoLock);
121 
122  /*
123  * Reject clustering a remote temp table ... their local buffer
124  * manager is not going to cope.
125  */
126  if (RELATION_IS_OTHER_TEMP(rel))
127  ereport(ERROR,
128  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
129  errmsg("cannot cluster temporary tables of other sessions")));
130 
131  if (stmt->indexname == NULL)
132  {
133  ListCell *index;
134 
135  /* We need to find the index that has indisclustered set. */
136  foreach(index, RelationGetIndexList(rel))
137  {
138  HeapTuple idxtuple;
139  Form_pg_index indexForm;
140 
141  indexOid = lfirst_oid(index);
142  idxtuple = SearchSysCache1(INDEXRELID,
143  ObjectIdGetDatum(indexOid));
144  if (!HeapTupleIsValid(idxtuple))
145  elog(ERROR, "cache lookup failed for index %u", indexOid);
146  indexForm = (Form_pg_index) GETSTRUCT(idxtuple);
147  if (indexForm->indisclustered)
148  {
149  ReleaseSysCache(idxtuple);
150  break;
151  }
152  ReleaseSysCache(idxtuple);
153  indexOid = InvalidOid;
154  }
155 
156  if (!OidIsValid(indexOid))
157  ereport(ERROR,
158  (errcode(ERRCODE_UNDEFINED_OBJECT),
159  errmsg("there is no previously clustered index for table \"%s\"",
160  stmt->relation->relname)));
161  }
162  else
163  {
164  /*
165  * The index is expected to be in the same namespace as the
166  * relation.
167  */
168  indexOid = get_relname_relid(stmt->indexname,
169  rel->rd_rel->relnamespace);
170  if (!OidIsValid(indexOid))
171  ereport(ERROR,
172  (errcode(ERRCODE_UNDEFINED_OBJECT),
173  errmsg("index \"%s\" for table \"%s\" does not exist",
174  stmt->indexname, stmt->relation->relname)));
175  }
176 
177  /* close relation, keep lock till commit */
178  heap_close(rel, NoLock);
179 
180  /* Do the job. */
181  cluster_rel(tableOid, indexOid, false, stmt->verbose);
182  }
183  else
184  {
185  /*
186  * This is the "multi relation" case. We need to cluster all tables
187  * that have some index with indisclustered set.
188  */
189  MemoryContext cluster_context;
190  List *rvs;
191  ListCell *rv;
192 
193  /*
194  * We cannot run this form of CLUSTER inside a user transaction block;
195  * we'd be holding locks way too long.
196  */
197  PreventTransactionChain(isTopLevel, "CLUSTER");
198 
199  /*
200  * Create special memory context for cross-transaction storage.
201  *
202  * Since it is a child of PortalContext, it will go away even in case
203  * of error.
204  */
205  cluster_context = AllocSetContextCreate(PortalContext,
206  "Cluster",
208 
209  /*
210  * Build the list of relations to cluster. Note that this lives in
211  * cluster_context.
212  */
213  rvs = get_tables_to_cluster(cluster_context);
214 
215  /* Commit to get out of starting transaction */
218 
219  /* Ok, now that we've got them all, cluster them one by one */
220  foreach(rv, rvs)
221  {
222  RelToCluster *rvtc = (RelToCluster *) lfirst(rv);
223 
224  /* Start a new transaction for each relation. */
226  /* functions in indexes may want a snapshot set */
228  /* Do the job. */
229  cluster_rel(rvtc->tableOid, rvtc->indexOid, true, stmt->verbose);
232  }
233 
234  /* Start a new transaction for the cleanup work. */
236 
237  /* Clean up working storage */
238  MemoryContextDelete(cluster_context);
239  }
240 }
void RangeVarCallbackOwnsTable(const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
Definition: tablecmds.c:12585
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:200
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, bool missing_ok, bool nowait, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:217
void CommitTransactionCommand(void)
Definition: xact.c:2745
int errcode(int sqlerrcode)
Definition: elog.c:575
void PopActiveSnapshot(void)
Definition: snapmgr.c:807
#define heap_close(r, l)
Definition: heapam.h:97
Form_pg_class rd_rel
Definition: rel.h:113
unsigned int Oid
Definition: postgres_ext.h:31
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:300
#define OidIsValid(objectId)
Definition: c.h:534
#define SearchSysCache1(cacheId, key1)
Definition: syscache.h:149
Oid tableOid
Definition: cluster.c:65
MemoryContext PortalContext
Definition: mcxt.c:52
Definition: type.h:90
char * relname
Definition: primnodes.h:67
char * indexname
Definition: parsenodes.h:2957
#define ObjectIdGetDatum(X)
Definition: postgres.h:515
#define ERROR
Definition: elog.h:43
void cluster_rel(Oid tableOid, Oid indexOid, bool recheck, bool verbose)
Definition: cluster.c:260
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition: lsyscache.c:1651
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:145
#define NoLock
Definition: lockdefs.h:34
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:728
static List * get_tables_to_cluster(MemoryContext cluster_context)
Definition: cluster.c:1634
#define ereport(elevel, rest)
Definition: elog.h:122
FormData_pg_index * Form_pg_index
Definition: pg_index.h:67
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:440
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1083
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1287
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:226
#define lfirst(lc)
Definition: pg_list.h:106
#define RELATION_IS_OTHER_TEMP(relation)
Definition: rel.h:530
void StartTransactionCommand(void)
Definition: xact.c:2675
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4336
Oid indexOid
Definition: cluster.c:66
#define AccessExclusiveLock
Definition: lockdefs.h:46
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define elog
Definition: elog.h:219
RangeVar * relation
Definition: parsenodes.h:2956
Definition: pg_list.h:45
#define lfirst_oid(lc)
Definition: pg_list.h:108
void PreventTransactionChain(bool isTopLevel, const char *stmtType)
Definition: xact.c:3152
void cluster_rel ( Oid  tableOid,
Oid  indexOid,
bool  recheck,
bool  verbose 
)

Definition at line 260 of file cluster.c.

References AccessExclusiveLock, CHECK_FOR_INTERRUPTS, check_index_is_clusterable(), CheckTableNotInUse(), ereport, errcode(), errmsg(), ERROR, GETSTRUCT, GetUserId(), HeapTupleIsValid, INDEXRELID, ObjectIdGetDatum, OidIsValid, pg_class_ownercheck(), RelationData::rd_rel, rebuild_relation(), relation_close(), RELATION_IS_OTHER_TEMP, RelationIsPopulated, ReleaseSysCache(), RELKIND_MATVIEW, RELOID, SearchSysCache1, SearchSysCacheExists1, TransferPredicateLocksToHeapRelation(), and try_relation_open().

Referenced by cluster(), and vacuum_rel().

261 {
262  Relation OldHeap;
263 
264  /* Check for user-requested abort. */
266 
267  /*
268  * We grab exclusive access to the target rel and index for the duration
269  * of the transaction. (This is redundant for the single-transaction
270  * case, since cluster() already did it.) The index lock is taken inside
271  * check_index_is_clusterable.
272  */
273  OldHeap = try_relation_open(tableOid, AccessExclusiveLock);
274 
275  /* If the table has gone away, we can skip processing it */
276  if (!OldHeap)
277  return;
278 
279  /*
280  * Since we may open a new transaction for each relation, we have to check
281  * that the relation still is what we think it is.
282  *
283  * If this is a single-transaction CLUSTER, we can skip these tests. We
284  * *must* skip the one on indisclustered since it would reject an attempt
285  * to cluster a not-previously-clustered index.
286  */
287  if (recheck)
288  {
289  HeapTuple tuple;
290  Form_pg_index indexForm;
291 
292  /* Check that the user still owns the relation */
293  if (!pg_class_ownercheck(tableOid, GetUserId()))
294  {
296  return;
297  }
298 
299  /*
300  * Silently skip a temp table for a remote session. Only doing this
301  * check in the "recheck" case is appropriate (which currently means
302  * somebody is executing a database-wide CLUSTER), because there is
303  * another check in cluster() which will stop any attempt to cluster
304  * remote temp tables by name. There is another check in cluster_rel
305  * which is redundant, but we leave it for extra safety.
306  */
307  if (RELATION_IS_OTHER_TEMP(OldHeap))
308  {
310  return;
311  }
312 
313  if (OidIsValid(indexOid))
314  {
315  /*
316  * Check that the index still exists
317  */
319  {
321  return;
322  }
323 
324  /*
325  * Check that the index is still the one with indisclustered set.
326  */
327  tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexOid));
328  if (!HeapTupleIsValid(tuple)) /* probably can't happen */
329  {
331  return;
332  }
333  indexForm = (Form_pg_index) GETSTRUCT(tuple);
334  if (!indexForm->indisclustered)
335  {
336  ReleaseSysCache(tuple);
338  return;
339  }
340  ReleaseSysCache(tuple);
341  }
342  }
343 
344  /*
345  * We allow VACUUM FULL, but not CLUSTER, on shared catalogs. CLUSTER
346  * would work in most respects, but the index would only get marked as
347  * indisclustered in the current database, leading to unexpected behavior
348  * if CLUSTER were later invoked in another database.
349  */
350  if (OidIsValid(indexOid) && OldHeap->rd_rel->relisshared)
351  ereport(ERROR,
352  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
353  errmsg("cannot cluster a shared catalog")));
354 
355  /*
356  * Don't process temp tables of other backends ... their local buffer
357  * manager is not going to cope.
358  */
359  if (RELATION_IS_OTHER_TEMP(OldHeap))
360  {
361  if (OidIsValid(indexOid))
362  ereport(ERROR,
363  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
364  errmsg("cannot cluster temporary tables of other sessions")));
365  else
366  ereport(ERROR,
367  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
368  errmsg("cannot vacuum temporary tables of other sessions")));
369  }
370 
371  /*
372  * Also check for active uses of the relation in the current transaction,
373  * including open scans and pending AFTER trigger events.
374  */
375  CheckTableNotInUse(OldHeap, OidIsValid(indexOid) ? "CLUSTER" : "VACUUM");
376 
377  /* Check heap and index are valid to cluster on */
378  if (OidIsValid(indexOid))
379  check_index_is_clusterable(OldHeap, indexOid, recheck, AccessExclusiveLock);
380 
381  /*
382  * Quietly ignore the request if this is a materialized view which has not
383  * been populated from its query. No harm is done because there is no data
384  * to deal with, and we don't want to throw an error if this is part of a
385  * multi-relation request -- for example, CLUSTER was run on the entire
386  * database.
387  */
388  if (OldHeap->rd_rel->relkind == RELKIND_MATVIEW &&
389  !RelationIsPopulated(OldHeap))
390  {
392  return;
393  }
394 
395  /*
396  * All predicate locks on the tuples or pages are about to be made
397  * invalid, because we move tuples around. Promote them to relation
398  * locks. Predicate locks on indexes will be promoted when they are
399  * reindexed.
400  */
402 
403  /* rebuild_relation does all the dirty work */
404  rebuild_relation(OldHeap, indexOid, verbose);
405 
406  /* NB: rebuild_relation does heap_close() on OldHeap */
407 }
#define RelationIsPopulated(relation)
Definition: rel.h:549
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
Relation try_relation_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1150
Oid GetUserId(void)
Definition: miscinit.c:283
#define RELKIND_MATVIEW
Definition: pg_class.h:167
int errcode(int sqlerrcode)
Definition: elog.c:575
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: heapam.c:1263
Form_pg_class rd_rel
Definition: rel.h:113
#define OidIsValid(objectId)
Definition: c.h:534
#define SearchSysCache1(cacheId, key1)
Definition: syscache.h:149
#define SearchSysCacheExists1(cacheId, key1)
Definition: syscache.h:167
#define ObjectIdGetDatum(X)
Definition: postgres.h:515
#define ERROR
Definition: elog.h:43
static void rebuild_relation(Relation OldHeap, Oid indexOid, bool verbose)
Definition: cluster.c:555
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:2950
#define ereport(elevel, rest)
Definition: elog.h:122
void TransferPredicateLocksToHeapRelation(Relation relation)
Definition: predicate.c:3007
static int verbose
Definition: pg_basebackup.c:87
FormData_pg_index * Form_pg_index
Definition: pg_index.h:67
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1083
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define RELATION_IS_OTHER_TEMP(relation)
Definition: rel.h:530
bool pg_class_ownercheck(Oid class_oid, Oid roleid)
Definition: aclchk.c:4521
#define AccessExclusiveLock
Definition: lockdefs.h:46
int errmsg(const char *fmt,...)
Definition: elog.c:797
void check_index_is_clusterable(Relation OldHeap, Oid indexOid, bool recheck, LOCKMODE lockmode)
Definition: cluster.c:418
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:97
void finish_heap_swap ( Oid  OIDOldHeap,
Oid  OIDNewHeap,
bool  is_system_catalog,
bool  swap_toast_by_content,
bool  check_constraints,
bool  is_internal,
TransactionId  frozenXid,
MultiXactId  minMulti,
char  newrelpersistence 
)

Definition at line 1467 of file cluster.c.

References AccessShareLock, CacheInvalidateCatalog(), CatalogTupleUpdate(), DROP_RESTRICT, elog, ERROR, GETSTRUCT, heap_close, heap_open(), HeapTupleIsValid, i, NAMEDATALEN, NoLock, ObjectIdGetDatum, OidIsValid, PERFORM_DELETION_INTERNAL, performDeletion(), RelationData::rd_rel, REINDEX_REL_CHECK_CONSTRAINTS, REINDEX_REL_FORCE_INDEXES_PERMANENT, REINDEX_REL_FORCE_INDEXES_UNLOGGED, REINDEX_REL_SUPPRESS_INDEX_USE, reindex_relation(), relation_close(), RelationMapRemoveMapping(), RelationRelationId, RELOID, RELPERSISTENCE_PERMANENT, RELPERSISTENCE_UNLOGGED, RenameRelationInternal(), RowExclusiveLock, SearchSysCacheCopy1, snprintf(), swap_relation_files(), HeapTupleData::t_self, and toast_get_valid_index().

Referenced by ATRewriteTables(), rebuild_relation(), and refresh_by_heap_swap().

1475 {
1476  ObjectAddress object;
1477  Oid mapped_tables[4];
1478  int reindex_flags;
1479  int i;
1480 
1481  /* Zero out possible results from swapped_relation_files */
1482  memset(mapped_tables, 0, sizeof(mapped_tables));
1483 
1484  /*
1485  * Swap the contents of the heap relations (including any toast tables).
1486  * Also set old heap's relfrozenxid to frozenXid.
1487  */
1488  swap_relation_files(OIDOldHeap, OIDNewHeap,
1489  (OIDOldHeap == RelationRelationId),
1490  swap_toast_by_content, is_internal,
1491  frozenXid, cutoffMulti, mapped_tables);
1492 
1493  /*
1494  * If it's a system catalog, queue an sinval message to flush all
1495  * catcaches on the catalog when we reach CommandCounterIncrement.
1496  */
1497  if (is_system_catalog)
1498  CacheInvalidateCatalog(OIDOldHeap);
1499 
1500  /*
1501  * Rebuild each index on the relation (but not the toast table, which is
1502  * all-new at this point). It is important to do this before the DROP
1503  * step because if we are processing a system catalog that will be used
1504  * during DROP, we want to have its indexes available. There is no
1505  * advantage to the other order anyway because this is all transactional,
1506  * so no chance to reclaim disk space before commit. We do not need a
1507  * final CommandCounterIncrement() because reindex_relation does it.
1508  *
1509  * Note: because index_build is called via reindex_relation, it will never
1510  * set indcheckxmin true for the indexes. This is OK even though in some
1511  * sense we are building new indexes rather than rebuilding existing ones,
1512  * because the new heap won't contain any HOT chains at all, let alone
1513  * broken ones, so it can't be necessary to set indcheckxmin.
1514  */
1515  reindex_flags = REINDEX_REL_SUPPRESS_INDEX_USE;
1516  if (check_constraints)
1517  reindex_flags |= REINDEX_REL_CHECK_CONSTRAINTS;
1518 
1519  /*
1520  * Ensure that the indexes have the same persistence as the parent
1521  * relation.
1522  */
1523  if (newrelpersistence == RELPERSISTENCE_UNLOGGED)
1524  reindex_flags |= REINDEX_REL_FORCE_INDEXES_UNLOGGED;
1525  else if (newrelpersistence == RELPERSISTENCE_PERMANENT)
1526  reindex_flags |= REINDEX_REL_FORCE_INDEXES_PERMANENT;
1527 
1528  reindex_relation(OIDOldHeap, reindex_flags, 0);
1529 
1530  /*
1531  * If the relation being rebuild is pg_class, swap_relation_files()
1532  * couldn't update pg_class's own pg_class entry (check comments in
1533  * swap_relation_files()), thus relfrozenxid was not updated. That's
1534  * annoying because a potential reason for doing a VACUUM FULL is a
1535  * imminent or actual anti-wraparound shutdown. So, now that we can
1536  * access the new relation using it's indices, update relfrozenxid.
1537  * pg_class doesn't have a toast relation, so we don't need to update the
1538  * corresponding toast relation. Not that there's little point moving all
1539  * relfrozenxid updates here since swap_relation_files() needs to write to
1540  * pg_class for non-mapped relations anyway.
1541  */
1542  if (OIDOldHeap == RelationRelationId)
1543  {
1544  Relation relRelation;
1545  HeapTuple reltup;
1546  Form_pg_class relform;
1547 
1549 
1550  reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(OIDOldHeap));
1551  if (!HeapTupleIsValid(reltup))
1552  elog(ERROR, "cache lookup failed for relation %u", OIDOldHeap);
1553  relform = (Form_pg_class) GETSTRUCT(reltup);
1554 
1555  relform->relfrozenxid = frozenXid;
1556  relform->relminmxid = cutoffMulti;
1557 
1558  CatalogTupleUpdate(relRelation, &reltup->t_self, reltup);
1559 
1560  heap_close(relRelation, RowExclusiveLock);
1561  }
1562 
1563  /* Destroy new heap with old filenode */
1564  object.classId = RelationRelationId;
1565  object.objectId = OIDNewHeap;
1566  object.objectSubId = 0;
1567 
1568  /*
1569  * The new relation is local to our transaction and we know nothing
1570  * depends on it, so DROP_RESTRICT should be OK.
1571  */
1573 
1574  /* performDeletion does CommandCounterIncrement at end */
1575 
1576  /*
1577  * Now we must remove any relation mapping entries that we set up for the
1578  * transient table, as well as its toast table and toast index if any. If
1579  * we fail to do this before commit, the relmapper will complain about new
1580  * permanent map entries being added post-bootstrap.
1581  */
1582  for (i = 0; OidIsValid(mapped_tables[i]); i++)
1583  RelationMapRemoveMapping(mapped_tables[i]);
1584 
1585  /*
1586  * At this point, everything is kosher except that, if we did toast swap
1587  * by links, the toast table's name corresponds to the transient table.
1588  * The name is irrelevant to the backend because it's referenced by OID,
1589  * but users looking at the catalogs could be confused. Rename it to
1590  * prevent this problem.
1591  *
1592  * Note no lock required on the relation, because we already hold an
1593  * exclusive lock on it.
1594  */
1595  if (!swap_toast_by_content)
1596  {
1597  Relation newrel;
1598 
1599  newrel = heap_open(OIDOldHeap, NoLock);
1600  if (OidIsValid(newrel->rd_rel->reltoastrelid))
1601  {
1602  Oid toastidx;
1603  char NewToastName[NAMEDATALEN];
1604 
1605  /* Get the associated valid index to be renamed */
1606  toastidx = toast_get_valid_index(newrel->rd_rel->reltoastrelid,
1607  AccessShareLock);
1608 
1609  /* rename the toast table ... */
1610  snprintf(NewToastName, NAMEDATALEN, "pg_toast_%u",
1611  OIDOldHeap);
1612  RenameRelationInternal(newrel->rd_rel->reltoastrelid,
1613  NewToastName, true);
1614 
1615  /* ... and its valid index too. */
1616  snprintf(NewToastName, NAMEDATALEN, "pg_toast_%u_index",
1617  OIDOldHeap);
1618 
1619  RenameRelationInternal(toastidx,
1620  NewToastName, true);
1621  }
1622  relation_close(newrel, NoLock);
1623  }
1624 }
void RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal)
Definition: tablecmds.c:2854
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
#define RELPERSISTENCE_UNLOGGED
Definition: pg_class.h:171
#define RelationRelationId
Definition: pg_class.h:29
Oid toast_get_valid_index(Oid toastoid, LOCKMODE lock)
Definition: tuptoaster.c:1363
#define AccessShareLock
Definition: lockdefs.h:36
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: heapam.c:1263
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
#define heap_close(r, l)
Definition: heapam.h:97
#define REINDEX_REL_SUPPRESS_INDEX_USE
Definition: index.h:123
Form_pg_class rd_rel
Definition: rel.h:113
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:534
#define RELPERSISTENCE_PERMANENT
Definition: pg_class.h:170
#define NAMEDATALEN
#define ObjectIdGetDatum(X)
Definition: postgres.h:515
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
#define NoLock
Definition: lockdefs.h:34
#define RowExclusiveLock
Definition: lockdefs.h:38
void performDeletion(const ObjectAddress *object, DropBehavior behavior, int flags)
Definition: dependency.c:301
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1287
static void swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class, bool swap_toast_by_content, bool is_internal, TransactionId frozenXid, MultiXactId cutoffMulti, Oid *mapped_tables)
Definition: cluster.c:1128
void CacheInvalidateCatalog(Oid catalogId)
Definition: inval.c:1201
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define REINDEX_REL_FORCE_INDEXES_UNLOGGED
Definition: index.h:125
void RelationMapRemoveMapping(Oid relationId)
Definition: relmapper.c:356
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:210
#define REINDEX_REL_CHECK_CONSTRAINTS
Definition: index.h:124
FormData_pg_class * Form_pg_class
Definition: pg_class.h:95
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:158
int i
#define REINDEX_REL_FORCE_INDEXES_PERMANENT
Definition: index.h:126
#define elog
Definition: elog.h:219
bool reindex_relation(Oid relid, int flags, int options)
Definition: index.c:3515
#define PERFORM_DELETION_INTERNAL
Definition: dependency.h:173
Oid make_new_heap ( Oid  OIDOldHeap,
Oid  NewTableSpace,
char  relpersistence,
LOCKMODE  lockmode 
)

Definition at line 606 of file cluster.c.

References Anum_pg_class_reloptions, Assert, CommandCounterIncrement(), elog, ERROR, heap_close, heap_create_with_catalog(), heap_open(), HeapTupleIsValid, InvalidOid, LookupCreationNamespace(), NAMEDATALEN, NewHeapCreateToastTable(), NIL, NoLock, NULL, ObjectIdGetDatum, OidIsValid, ONCOMMIT_NOOP, RelationData::rd_rel, RelationGetDescr, RelationGetNamespace, RelationIsMapped, ReleaseSysCache(), RELKIND_RELATION, RELOID, RELPERSISTENCE_TEMP, SearchSysCache1, snprintf(), and SysCacheGetAttr().

Referenced by ATRewriteTables(), ExecRefreshMatView(), and rebuild_relation().

608 {
609  TupleDesc OldHeapDesc;
610  char NewHeapName[NAMEDATALEN];
611  Oid OIDNewHeap;
612  Oid toastid;
613  Relation OldHeap;
614  HeapTuple tuple;
615  Datum reloptions;
616  bool isNull;
617  Oid namespaceid;
618 
619  OldHeap = heap_open(OIDOldHeap, lockmode);
620  OldHeapDesc = RelationGetDescr(OldHeap);
621 
622  /*
623  * Note that the NewHeap will not receive any of the defaults or
624  * constraints associated with the OldHeap; we don't need 'em, and there's
625  * no reason to spend cycles inserting them into the catalogs only to
626  * delete them.
627  */
628 
629  /*
630  * But we do want to use reloptions of the old heap for new heap.
631  */
632  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(OIDOldHeap));
633  if (!HeapTupleIsValid(tuple))
634  elog(ERROR, "cache lookup failed for relation %u", OIDOldHeap);
635  reloptions = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_reloptions,
636  &isNull);
637  if (isNull)
638  reloptions = (Datum) 0;
639 
640  if (relpersistence == RELPERSISTENCE_TEMP)
641  namespaceid = LookupCreationNamespace("pg_temp");
642  else
643  namespaceid = RelationGetNamespace(OldHeap);
644 
645  /*
646  * Create the new heap, using a temporary name in the same namespace as
647  * the existing table. NOTE: there is some risk of collision with user
648  * relnames. Working around this seems more trouble than it's worth; in
649  * particular, we can't create the new heap in a different namespace from
650  * the old, or we will have problems with the TEMP status of temp tables.
651  *
652  * Note: the new heap is not a shared relation, even if we are rebuilding
653  * a shared rel. However, we do make the new heap mapped if the source is
654  * mapped. This simplifies swap_relation_files, and is absolutely
655  * necessary for rebuilding pg_class, for reasons explained there.
656  */
657  snprintf(NewHeapName, sizeof(NewHeapName), "pg_temp_%u", OIDOldHeap);
658 
659  OIDNewHeap = heap_create_with_catalog(NewHeapName,
660  namespaceid,
661  NewTableSpace,
662  InvalidOid,
663  InvalidOid,
664  InvalidOid,
665  OldHeap->rd_rel->relowner,
666  OldHeapDesc,
667  NIL,
669  relpersistence,
670  false,
671  RelationIsMapped(OldHeap),
672  true,
673  0,
675  reloptions,
676  false,
677  true,
678  true,
679  NULL);
680  Assert(OIDNewHeap != InvalidOid);
681 
682  ReleaseSysCache(tuple);
683 
684  /*
685  * Advance command counter so that the newly-created relation's catalog
686  * tuples will be visible to heap_open.
687  */
689 
690  /*
691  * If necessary, create a TOAST table for the new relation.
692  *
693  * If the relation doesn't have a TOAST table already, we can't need one
694  * for the new relation. The other way around is possible though: if some
695  * wide columns have been dropped, NewHeapCreateToastTable can decide that
696  * no TOAST table is needed for the new table.
697  *
698  * Note that NewHeapCreateToastTable ends with CommandCounterIncrement, so
699  * that the TOAST table will be visible for insertion.
700  */
701  toastid = OldHeap->rd_rel->reltoastrelid;
702  if (OidIsValid(toastid))
703  {
704  /* keep the existing toast table's reloptions, if any */
705  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(toastid));
706  if (!HeapTupleIsValid(tuple))
707  elog(ERROR, "cache lookup failed for relation %u", toastid);
708  reloptions = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_reloptions,
709  &isNull);
710  if (isNull)
711  reloptions = (Datum) 0;
712 
713  NewHeapCreateToastTable(OIDNewHeap, reloptions, lockmode);
714 
715  ReleaseSysCache(tuple);
716  }
717 
718  heap_close(OldHeap, NoLock);
719 
720  return OIDNewHeap;
721 }
#define NIL
Definition: pg_list.h:69
#define RelationGetDescr(relation)
Definition: rel.h:425
Oid LookupCreationNamespace(const char *nspname)
Definition: namespace.c:2730
#define Anum_pg_class_reloptions
Definition: pg_class.h:134
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
#define heap_close(r, l)
Definition: heapam.h:97
Form_pg_class rd_rel
Definition: rel.h:113
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:534
#define SearchSysCache1(cacheId, key1)
Definition: syscache.h:149
#define NAMEDATALEN
#define ObjectIdGetDatum(X)
Definition: postgres.h:515
#define ERROR
Definition: elog.h:43
#define NoLock
Definition: lockdefs.h:34
#define RelationIsMapped(relation)
Definition: rel.h:450
uintptr_t Datum
Definition: postgres.h:374
void CommandCounterIncrement(void)
Definition: xact.c:921
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1083
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1245
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1287
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:671
Oid heap_create_with_catalog(const char *relname, Oid relnamespace, Oid reltablespace, Oid relid, Oid reltypeid, Oid reloftypeid, Oid ownerid, TupleDesc tupdesc, List *cooked_constraints, char relkind, char relpersistence, bool shared_relation, bool mapped_relation, bool oidislocal, int oidinhcount, OnCommitAction oncommit, Datum reloptions, bool use_user_acl, bool allow_system_table_mods, bool is_internal, ObjectAddress *typaddress)
Definition: heap.c:1015
#define elog
Definition: elog.h:219
#define RELPERSISTENCE_TEMP
Definition: pg_class.h:172
#define RELKIND_RELATION
Definition: pg_class.h:160
#define RelationGetNamespace(relation)
Definition: rel.h:440
void NewHeapCreateToastTable(Oid relOid, Datum reloptions, LOCKMODE lockmode)
Definition: toasting.c:65
void mark_index_clustered ( Relation  rel,
Oid  indexOid,
bool  is_internal 
)

Definition at line 478 of file cluster.c.

References CatalogTupleUpdate(), elog, ERROR, GETSTRUCT, heap_close, heap_freetuple(), heap_open(), HeapTupleIsValid, IndexIsValid, IndexRelationId, INDEXRELID, InvalidOid, InvokeObjectPostAlterHookArg, lfirst_oid, ObjectIdGetDatum, OidIsValid, RelationGetIndexList(), ReleaseSysCache(), RowExclusiveLock, SearchSysCache1, SearchSysCacheCopy1, and HeapTupleData::t_self.

Referenced by ATExecClusterOn(), ATExecDropCluster(), and rebuild_relation().

479 {
480  HeapTuple indexTuple;
481  Form_pg_index indexForm;
482  Relation pg_index;
483  ListCell *index;
484 
485  /*
486  * If the index is already marked clustered, no need to do anything.
487  */
488  if (OidIsValid(indexOid))
489  {
490  indexTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexOid));
491  if (!HeapTupleIsValid(indexTuple))
492  elog(ERROR, "cache lookup failed for index %u", indexOid);
493  indexForm = (Form_pg_index) GETSTRUCT(indexTuple);
494 
495  if (indexForm->indisclustered)
496  {
497  ReleaseSysCache(indexTuple);
498  return;
499  }
500 
501  ReleaseSysCache(indexTuple);
502  }
503 
504  /*
505  * Check each index of the relation and set/clear the bit as needed.
506  */
508 
509  foreach(index, RelationGetIndexList(rel))
510  {
511  Oid thisIndexOid = lfirst_oid(index);
512 
513  indexTuple = SearchSysCacheCopy1(INDEXRELID,
514  ObjectIdGetDatum(thisIndexOid));
515  if (!HeapTupleIsValid(indexTuple))
516  elog(ERROR, "cache lookup failed for index %u", thisIndexOid);
517  indexForm = (Form_pg_index) GETSTRUCT(indexTuple);
518 
519  /*
520  * Unset the bit if set. We know it's wrong because we checked this
521  * earlier.
522  */
523  if (indexForm->indisclustered)
524  {
525  indexForm->indisclustered = false;
526  CatalogTupleUpdate(pg_index, &indexTuple->t_self, indexTuple);
527  }
528  else if (thisIndexOid == indexOid)
529  {
530  /* this was checked earlier, but let's be real sure */
531  if (!IndexIsValid(indexForm))
532  elog(ERROR, "cannot cluster on invalid index %u", indexOid);
533  indexForm->indisclustered = true;
534  CatalogTupleUpdate(pg_index, &indexTuple->t_self, indexTuple);
535  }
536 
538  InvalidOid, is_internal);
539 
540  heap_freetuple(indexTuple);
541  }
542 
543  heap_close(pg_index, RowExclusiveLock);
544 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
#define IndexIsValid(indexForm)
Definition: pg_index.h:107
#define IndexRelationId
Definition: pg_index.h:29
#define heap_close(r, l)
Definition: heapam.h:97
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1374
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:534
#define SearchSysCache1(cacheId, key1)
Definition: syscache.h:149
Definition: type.h:90
#define ObjectIdGetDatum(X)
Definition: postgres.h:515
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
#define InvokeObjectPostAlterHookArg(classId, objectId, subId,auxiliaryId, is_internal)
Definition: objectaccess.h:166
#define RowExclusiveLock
Definition: lockdefs.h:38
FormData_pg_index * Form_pg_index
Definition: pg_index.h:67
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1083
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1287
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:210
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4336
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:158
#define elog
Definition: elog.h:219
#define lfirst_oid(lc)
Definition: pg_list.h:108