PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
cluster.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * cluster.c
4  * CLUSTER a table on an index. This is now also used for VACUUM FULL.
5  *
6  * There is hardly anything left of Paul Brown's original implementation...
7  *
8  *
9  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
10  * Portions Copyright (c) 1994-5, Regents of the University of California
11  *
12  *
13  * IDENTIFICATION
14  * src/backend/commands/cluster.c
15  *
16  *-------------------------------------------------------------------------
17  */
18 #include "postgres.h"
19 
20 #include "access/amapi.h"
21 #include "access/multixact.h"
22 #include "access/relscan.h"
23 #include "access/rewriteheap.h"
24 #include "access/transam.h"
25 #include "access/tuptoaster.h"
26 #include "access/xact.h"
27 #include "access/xlog.h"
28 #include "catalog/pg_am.h"
29 #include "catalog/catalog.h"
30 #include "catalog/dependency.h"
31 #include "catalog/heap.h"
32 #include "catalog/index.h"
33 #include "catalog/namespace.h"
34 #include "catalog/objectaccess.h"
35 #include "catalog/toasting.h"
36 #include "commands/cluster.h"
37 #include "commands/tablecmds.h"
38 #include "commands/vacuum.h"
39 #include "miscadmin.h"
40 #include "optimizer/planner.h"
41 #include "storage/bufmgr.h"
42 #include "storage/lmgr.h"
43 #include "storage/predicate.h"
44 #include "storage/smgr.h"
45 #include "utils/acl.h"
46 #include "utils/fmgroids.h"
47 #include "utils/inval.h"
48 #include "utils/lsyscache.h"
49 #include "utils/memutils.h"
50 #include "utils/pg_rusage.h"
51 #include "utils/relmapper.h"
52 #include "utils/snapmgr.h"
53 #include "utils/syscache.h"
54 #include "utils/tqual.h"
55 #include "utils/tuplesort.h"
56 
57 
58 /*
59  * This struct is used to pass around the information on tables to be
60  * clustered. We need this so we can make a list of them when invoked without
61  * a specific table/index pair.
62  */
63 typedef struct
64 {
67 } RelToCluster;
68 
69 
70 static void rebuild_relation(Relation OldHeap, Oid indexOid, bool verbose);
71 static void copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex,
72  bool verbose, bool *pSwapToastByContent,
73  TransactionId *pFreezeXid, MultiXactId *pCutoffMulti);
74 static List *get_tables_to_cluster(MemoryContext cluster_context);
75 static void reform_and_rewrite_tuple(HeapTuple tuple,
76  TupleDesc oldTupDesc, TupleDesc newTupDesc,
77  Datum *values, bool *isnull,
78  bool newRelHasOids, RewriteState rwstate);
79 
80 
81 /*---------------------------------------------------------------------------
82  * This cluster code allows for clustering multiple tables at once. Because
83  * of this, we cannot just run everything on a single transaction, or we
84  * would be forced to acquire exclusive locks on all the tables being
85  * clustered, simultaneously --- very likely leading to deadlock.
86  *
87  * To solve this we follow a similar strategy to VACUUM code,
88  * clustering each relation in a separate transaction. For this to work,
89  * we need to:
90  * - provide a separate memory context so that we can pass information in
91  * a way that survives across transactions
92  * - start a new transaction every time a new relation is clustered
93  * - check for validity of the information on to-be-clustered relations,
94  * as someone might have deleted a relation behind our back, or
95  * clustered one on a different index
96  * - end the transaction
97  *
98  * The single-relation case does not have any such overhead.
99  *
100  * We also allow a relation to be specified without index. In that case,
101  * the indisclustered bit will be looked up, and an ERROR will be thrown
102  * if there is no index with the bit set.
103  *---------------------------------------------------------------------------
104  */
105 void
106 cluster(ClusterStmt *stmt, bool isTopLevel)
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 }
241 
242 /*
243  * cluster_rel
244  *
245  * This clusters the table by creating a new, clustered table and
246  * swapping the relfilenodes of the new table and the old table, so
247  * the OID of the original table is preserved. Thus we do not lose
248  * GRANT, inheritance nor references to this table (this was a bug
249  * in releases through 7.3).
250  *
251  * Indexes are rebuilt too, via REINDEX. Since we are effectively bulk-loading
252  * the new table, it's better to create the indexes afterwards than to fill
253  * them incrementally while we load the table.
254  *
255  * If indexOid is InvalidOid, the table will be rewritten in physical order
256  * instead of index order. This is the new implementation of VACUUM FULL,
257  * and error messages should refer to the operation as VACUUM not CLUSTER.
258  */
259 void
260 cluster_rel(Oid tableOid, Oid indexOid, bool recheck, bool verbose)
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 }
408 
409 /*
410  * Verify that the specified heap and index are valid to cluster on
411  *
412  * Side effect: obtains lock on the index. The caller may
413  * in some cases already have AccessExclusiveLock on the table, but
414  * not in all cases so we can't rely on the table-level lock for
415  * protection here.
416  */
417 void
418 check_index_is_clusterable(Relation OldHeap, Oid indexOid, bool recheck, LOCKMODE lockmode)
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 }
471 
472 /*
473  * mark_index_clustered: mark the specified index as the one clustered on
474  *
475  * With indexOid == InvalidOid, will mark all indexes of rel not-clustered.
476  */
477 void
478 mark_index_clustered(Relation rel, Oid indexOid, bool is_internal)
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 }
545 
546 /*
547  * rebuild_relation: rebuild an existing relation in index or physical order
548  *
549  * OldHeap: table to rebuild --- must be opened and exclusive-locked!
550  * indexOid: index to cluster by, or InvalidOid to rewrite in physical order.
551  *
552  * NB: this routine closes OldHeap at the right time; caller should not.
553  */
554 static void
555 rebuild_relation(Relation OldHeap, Oid indexOid, bool verbose)
556 {
557  Oid tableOid = RelationGetRelid(OldHeap);
558  Oid tableSpace = OldHeap->rd_rel->reltablespace;
559  Oid OIDNewHeap;
560  char relpersistence;
561  bool is_system_catalog;
562  bool swap_toast_by_content;
563  TransactionId frozenXid;
564  MultiXactId cutoffMulti;
565 
566  /* Mark the correct index as clustered */
567  if (OidIsValid(indexOid))
568  mark_index_clustered(OldHeap, indexOid, true);
569 
570  /* Remember info about rel before closing OldHeap */
571  relpersistence = OldHeap->rd_rel->relpersistence;
572  is_system_catalog = IsSystemRelation(OldHeap);
573 
574  /* Close relcache entry, but keep lock until transaction commit */
575  heap_close(OldHeap, NoLock);
576 
577  /* Create the transient table that will receive the re-ordered data */
578  OIDNewHeap = make_new_heap(tableOid, tableSpace,
579  relpersistence,
581 
582  /* Copy the heap data into the new table in the desired order */
583  copy_heap_data(OIDNewHeap, tableOid, indexOid, verbose,
584  &swap_toast_by_content, &frozenXid, &cutoffMulti);
585 
586  /*
587  * Swap the physical files of the target and transient tables, then
588  * rebuild the target's indexes and throw away the transient table.
589  */
590  finish_heap_swap(tableOid, OIDNewHeap, is_system_catalog,
591  swap_toast_by_content, false, true,
592  frozenXid, cutoffMulti,
593  relpersistence);
594 }
595 
596 
597 /*
598  * Create the transient table that will be filled with new data during
599  * CLUSTER, ALTER TABLE, and similar operations. The transient table
600  * duplicates the logical structure of the OldHeap, but is placed in
601  * NewTableSpace which might be different from OldHeap's. Also, it's built
602  * with the specified persistence, which might differ from the original's.
603  *
604  * After this, the caller should load the new heap with transferred/modified
605  * data, then call finish_heap_swap to complete the operation.
606  */
607 Oid
608 make_new_heap(Oid OIDOldHeap, Oid NewTableSpace, char relpersistence,
609  LOCKMODE lockmode)
610 {
611  TupleDesc OldHeapDesc;
612  char NewHeapName[NAMEDATALEN];
613  Oid OIDNewHeap;
614  Oid toastid;
615  Relation OldHeap;
616  HeapTuple tuple;
617  Datum reloptions;
618  bool isNull;
619  Oid namespaceid;
620 
621  OldHeap = heap_open(OIDOldHeap, lockmode);
622  OldHeapDesc = RelationGetDescr(OldHeap);
623 
624  /*
625  * Note that the NewHeap will not receive any of the defaults or
626  * constraints associated with the OldHeap; we don't need 'em, and there's
627  * no reason to spend cycles inserting them into the catalogs only to
628  * delete them.
629  */
630 
631  /*
632  * But we do want to use reloptions of the old heap for new heap.
633  */
634  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(OIDOldHeap));
635  if (!HeapTupleIsValid(tuple))
636  elog(ERROR, "cache lookup failed for relation %u", OIDOldHeap);
637  reloptions = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_reloptions,
638  &isNull);
639  if (isNull)
640  reloptions = (Datum) 0;
641 
642  if (relpersistence == RELPERSISTENCE_TEMP)
643  namespaceid = LookupCreationNamespace("pg_temp");
644  else
645  namespaceid = RelationGetNamespace(OldHeap);
646 
647  /*
648  * Create the new heap, using a temporary name in the same namespace as
649  * the existing table. NOTE: there is some risk of collision with user
650  * relnames. Working around this seems more trouble than it's worth; in
651  * particular, we can't create the new heap in a different namespace from
652  * the old, or we will have problems with the TEMP status of temp tables.
653  *
654  * Note: the new heap is not a shared relation, even if we are rebuilding
655  * a shared rel. However, we do make the new heap mapped if the source is
656  * mapped. This simplifies swap_relation_files, and is absolutely
657  * necessary for rebuilding pg_class, for reasons explained there.
658  */
659  snprintf(NewHeapName, sizeof(NewHeapName), "pg_temp_%u", OIDOldHeap);
660 
661  OIDNewHeap = heap_create_with_catalog(NewHeapName,
662  namespaceid,
663  NewTableSpace,
664  InvalidOid,
665  InvalidOid,
666  InvalidOid,
667  OldHeap->rd_rel->relowner,
668  OldHeapDesc,
669  NIL,
671  relpersistence,
672  false,
673  RelationIsMapped(OldHeap),
674  true,
675  0,
677  reloptions,
678  false,
679  true,
680  true,
681  NULL);
682  Assert(OIDNewHeap != InvalidOid);
683 
684  ReleaseSysCache(tuple);
685 
686  /*
687  * Advance command counter so that the newly-created relation's catalog
688  * tuples will be visible to heap_open.
689  */
691 
692  /*
693  * If necessary, create a TOAST table for the new relation.
694  *
695  * If the relation doesn't have a TOAST table already, we can't need one
696  * for the new relation. The other way around is possible though: if some
697  * wide columns have been dropped, NewHeapCreateToastTable can decide that
698  * no TOAST table is needed for the new table.
699  *
700  * Note that NewHeapCreateToastTable ends with CommandCounterIncrement, so
701  * that the TOAST table will be visible for insertion.
702  */
703  toastid = OldHeap->rd_rel->reltoastrelid;
704  if (OidIsValid(toastid))
705  {
706  /* keep the existing toast table's reloptions, if any */
707  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(toastid));
708  if (!HeapTupleIsValid(tuple))
709  elog(ERROR, "cache lookup failed for relation %u", toastid);
710  reloptions = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_reloptions,
711  &isNull);
712  if (isNull)
713  reloptions = (Datum) 0;
714 
715  NewHeapCreateToastTable(OIDNewHeap, reloptions, lockmode);
716 
717  ReleaseSysCache(tuple);
718  }
719 
720  heap_close(OldHeap, NoLock);
721 
722  return OIDNewHeap;
723 }
724 
725 /*
726  * Do the physical copying of heap data.
727  *
728  * There are three output parameters:
729  * *pSwapToastByContent is set true if toast tables must be swapped by content.
730  * *pFreezeXid receives the TransactionId used as freeze cutoff point.
731  * *pCutoffMulti receives the MultiXactId used as a cutoff point.
732  */
733 static void
734 copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex, bool verbose,
735  bool *pSwapToastByContent, TransactionId *pFreezeXid,
736  MultiXactId *pCutoffMulti)
737 {
738  Relation NewHeap,
739  OldHeap,
740  OldIndex;
741  TupleDesc oldTupDesc;
742  TupleDesc newTupDesc;
743  int natts;
744  Datum *values;
745  bool *isnull;
746  IndexScanDesc indexScan;
747  HeapScanDesc heapScan;
748  bool use_wal;
749  bool is_system_catalog;
751  TransactionId FreezeXid;
753  RewriteState rwstate;
754  bool use_sort;
755  Tuplesortstate *tuplesort;
756  double num_tuples = 0,
757  tups_vacuumed = 0,
758  tups_recently_dead = 0;
759  int elevel = verbose ? INFO : DEBUG2;
760  PGRUsage ru0;
761 
762  pg_rusage_init(&ru0);
763 
764  /*
765  * Open the relations we need.
766  */
767  NewHeap = heap_open(OIDNewHeap, AccessExclusiveLock);
768  OldHeap = heap_open(OIDOldHeap, AccessExclusiveLock);
769  if (OidIsValid(OIDOldIndex))
770  OldIndex = index_open(OIDOldIndex, AccessExclusiveLock);
771  else
772  OldIndex = NULL;
773 
774  /*
775  * Their tuple descriptors should be exactly alike, but here we only need
776  * assume that they have the same number of columns.
777  */
778  oldTupDesc = RelationGetDescr(OldHeap);
779  newTupDesc = RelationGetDescr(NewHeap);
780  Assert(newTupDesc->natts == oldTupDesc->natts);
781 
782  /* Preallocate values/isnull arrays */
783  natts = newTupDesc->natts;
784  values = (Datum *) palloc(natts * sizeof(Datum));
785  isnull = (bool *) palloc(natts * sizeof(bool));
786 
787  /*
788  * If the OldHeap has a toast table, get lock on the toast table to keep
789  * it from being vacuumed. This is needed because autovacuum processes
790  * toast tables independently of their main tables, with no lock on the
791  * latter. If an autovacuum were to start on the toast table after we
792  * compute our OldestXmin below, it would use a later OldestXmin, and then
793  * possibly remove as DEAD toast tuples belonging to main tuples we think
794  * are only RECENTLY_DEAD. Then we'd fail while trying to copy those
795  * tuples.
796  *
797  * We don't need to open the toast relation here, just lock it. The lock
798  * will be held till end of transaction.
799  */
800  if (OldHeap->rd_rel->reltoastrelid)
801  LockRelationOid(OldHeap->rd_rel->reltoastrelid, AccessExclusiveLock);
802 
803  /*
804  * We need to log the copied data in WAL iff WAL archiving/streaming is
805  * enabled AND it's a WAL-logged rel.
806  */
807  use_wal = XLogIsNeeded() && RelationNeedsWAL(NewHeap);
808 
809  /* use_wal off requires smgr_targblock be initially invalid */
811 
812  /*
813  * If both tables have TOAST tables, perform toast swap by content. It is
814  * possible that the old table has a toast table but the new one doesn't,
815  * if toastable columns have been dropped. In that case we have to do
816  * swap by links. This is okay because swap by content is only essential
817  * for system catalogs, and we don't support schema changes for them.
818  */
819  if (OldHeap->rd_rel->reltoastrelid && NewHeap->rd_rel->reltoastrelid)
820  {
821  *pSwapToastByContent = true;
822 
823  /*
824  * When doing swap by content, any toast pointers written into NewHeap
825  * must use the old toast table's OID, because that's where the toast
826  * data will eventually be found. Set this up by setting rd_toastoid.
827  * This also tells toast_save_datum() to preserve the toast value
828  * OIDs, which we want so as not to invalidate toast pointers in
829  * system catalog caches, and to avoid making multiple copies of a
830  * single toast value.
831  *
832  * Note that we must hold NewHeap open until we are done writing data,
833  * since the relcache will not guarantee to remember this setting once
834  * the relation is closed. Also, this technique depends on the fact
835  * that no one will try to read from the NewHeap until after we've
836  * finished writing it and swapping the rels --- otherwise they could
837  * follow the toast pointers to the wrong place. (It would actually
838  * work for values copied over from the old toast table, but not for
839  * any values that we toast which were previously not toasted.)
840  */
841  NewHeap->rd_toastoid = OldHeap->rd_rel->reltoastrelid;
842  }
843  else
844  *pSwapToastByContent = false;
845 
846  /*
847  * Compute xids used to freeze and weed out dead tuples and multixacts.
848  * Since we're going to rewrite the whole table anyway, there's no reason
849  * not to be aggressive about this.
850  */
851  vacuum_set_xid_limits(OldHeap, 0, 0, 0, 0,
852  &OldestXmin, &FreezeXid, NULL, &MultiXactCutoff,
853  NULL);
854 
855  /*
856  * FreezeXid will become the table's new relfrozenxid, and that mustn't go
857  * backwards, so take the max.
858  */
859  if (TransactionIdPrecedes(FreezeXid, OldHeap->rd_rel->relfrozenxid))
860  FreezeXid = OldHeap->rd_rel->relfrozenxid;
861 
862  /*
863  * MultiXactCutoff, similarly, shouldn't go backwards either.
864  */
865  if (MultiXactIdPrecedes(MultiXactCutoff, OldHeap->rd_rel->relminmxid))
866  MultiXactCutoff = OldHeap->rd_rel->relminmxid;
867 
868  /* return selected values to caller */
869  *pFreezeXid = FreezeXid;
870  *pCutoffMulti = MultiXactCutoff;
871 
872  /* Remember if it's a system catalog */
873  is_system_catalog = IsSystemRelation(OldHeap);
874 
875  /* Initialize the rewrite operation */
876  rwstate = begin_heap_rewrite(OldHeap, NewHeap, OldestXmin, FreezeXid,
877  MultiXactCutoff, use_wal);
878 
879  /*
880  * Decide whether to use an indexscan or seqscan-and-optional-sort to scan
881  * the OldHeap. We know how to use a sort to duplicate the ordering of a
882  * btree index, and will use seqscan-and-sort for that case if the planner
883  * tells us it's cheaper. Otherwise, always indexscan if an index is
884  * provided, else plain seqscan.
885  */
886  if (OldIndex != NULL && OldIndex->rd_rel->relam == BTREE_AM_OID)
887  use_sort = plan_cluster_use_sort(OIDOldHeap, OIDOldIndex);
888  else
889  use_sort = false;
890 
891  /* Set up sorting if wanted */
892  if (use_sort)
893  tuplesort = tuplesort_begin_cluster(oldTupDesc, OldIndex,
894  maintenance_work_mem, false);
895  else
896  tuplesort = NULL;
897 
898  /*
899  * Prepare to scan the OldHeap. To ensure we see recently-dead tuples
900  * that still need to be copied, we scan with SnapshotAny and use
901  * HeapTupleSatisfiesVacuum for the visibility test.
902  */
903  if (OldIndex != NULL && !use_sort)
904  {
905  heapScan = NULL;
906  indexScan = index_beginscan(OldHeap, OldIndex, SnapshotAny, 0, 0);
907  index_rescan(indexScan, NULL, 0, NULL, 0);
908  }
909  else
910  {
911  heapScan = heap_beginscan(OldHeap, SnapshotAny, 0, (ScanKey) NULL);
912  indexScan = NULL;
913  }
914 
915  /* Log what we're doing */
916  if (indexScan != NULL)
917  ereport(elevel,
918  (errmsg("clustering \"%s.%s\" using index scan on \"%s\"",
920  RelationGetRelationName(OldHeap),
921  RelationGetRelationName(OldIndex))));
922  else if (tuplesort != NULL)
923  ereport(elevel,
924  (errmsg("clustering \"%s.%s\" using sequential scan and sort",
926  RelationGetRelationName(OldHeap))));
927  else
928  ereport(elevel,
929  (errmsg("vacuuming \"%s.%s\"",
931  RelationGetRelationName(OldHeap))));
932 
933  /*
934  * Scan through the OldHeap, either in OldIndex order or sequentially;
935  * copy each tuple into the NewHeap, or transiently to the tuplesort
936  * module. Note that we don't bother sorting dead tuples (they won't get
937  * to the new table anyway).
938  */
939  for (;;)
940  {
941  HeapTuple tuple;
942  Buffer buf;
943  bool isdead;
944 
946 
947  if (indexScan != NULL)
948  {
949  tuple = index_getnext(indexScan, ForwardScanDirection);
950  if (tuple == NULL)
951  break;
952 
953  /* Since we used no scan keys, should never need to recheck */
954  if (indexScan->xs_recheck)
955  elog(ERROR, "CLUSTER does not support lossy index conditions");
956 
957  buf = indexScan->xs_cbuf;
958  }
959  else
960  {
961  tuple = heap_getnext(heapScan, ForwardScanDirection);
962  if (tuple == NULL)
963  break;
964 
965  buf = heapScan->rs_cbuf;
966  }
967 
969 
970  switch (HeapTupleSatisfiesVacuum(tuple, OldestXmin, buf))
971  {
972  case HEAPTUPLE_DEAD:
973  /* Definitely dead */
974  isdead = true;
975  break;
977  tups_recently_dead += 1;
978  /* fall through */
979  case HEAPTUPLE_LIVE:
980  /* Live or recently dead, must copy it */
981  isdead = false;
982  break;
984 
985  /*
986  * Since we hold exclusive lock on the relation, normally the
987  * only way to see this is if it was inserted earlier in our
988  * own transaction. However, it can happen in system
989  * catalogs, since we tend to release write lock before commit
990  * there. Give a warning if neither case applies; but in any
991  * case we had better copy it.
992  */
993  if (!is_system_catalog &&
995  elog(WARNING, "concurrent insert in progress within table \"%s\"",
996  RelationGetRelationName(OldHeap));
997  /* treat as live */
998  isdead = false;
999  break;
1001 
1002  /*
1003  * Similar situation to INSERT_IN_PROGRESS case.
1004  */
1005  if (!is_system_catalog &&
1007  elog(WARNING, "concurrent delete in progress within table \"%s\"",
1008  RelationGetRelationName(OldHeap));
1009  /* treat as recently dead */
1010  tups_recently_dead += 1;
1011  isdead = false;
1012  break;
1013  default:
1014  elog(ERROR, "unexpected HeapTupleSatisfiesVacuum result");
1015  isdead = false; /* keep compiler quiet */
1016  break;
1017  }
1018 
1020 
1021  if (isdead)
1022  {
1023  tups_vacuumed += 1;
1024  /* heap rewrite module still needs to see it... */
1025  if (rewrite_heap_dead_tuple(rwstate, tuple))
1026  {
1027  /* A previous recently-dead tuple is now known dead */
1028  tups_vacuumed += 1;
1029  tups_recently_dead -= 1;
1030  }
1031  continue;
1032  }
1033 
1034  num_tuples += 1;
1035  if (tuplesort != NULL)
1036  tuplesort_putheaptuple(tuplesort, tuple);
1037  else
1039  oldTupDesc, newTupDesc,
1040  values, isnull,
1041  NewHeap->rd_rel->relhasoids, rwstate);
1042  }
1043 
1044  if (indexScan != NULL)
1045  index_endscan(indexScan);
1046  if (heapScan != NULL)
1047  heap_endscan(heapScan);
1048 
1049  /*
1050  * In scan-and-sort mode, complete the sort, then read out all live tuples
1051  * from the tuplestore and write them to the new relation.
1052  */
1053  if (tuplesort != NULL)
1054  {
1055  tuplesort_performsort(tuplesort);
1056 
1057  for (;;)
1058  {
1059  HeapTuple tuple;
1060 
1062 
1063  tuple = tuplesort_getheaptuple(tuplesort, true);
1064  if (tuple == NULL)
1065  break;
1066 
1068  oldTupDesc, newTupDesc,
1069  values, isnull,
1070  NewHeap->rd_rel->relhasoids, rwstate);
1071  }
1072 
1073  tuplesort_end(tuplesort);
1074  }
1075 
1076  /* Write out any remaining tuples, and fsync if needed */
1077  end_heap_rewrite(rwstate);
1078 
1079  /* Reset rd_toastoid just to be tidy --- it shouldn't be looked at again */
1080  NewHeap->rd_toastoid = InvalidOid;
1081 
1082  /* Log what we did */
1083  ereport(elevel,
1084  (errmsg("\"%s\": found %.0f removable, %.0f nonremovable row versions in %u pages",
1085  RelationGetRelationName(OldHeap),
1086  tups_vacuumed, num_tuples,
1087  RelationGetNumberOfBlocks(OldHeap)),
1088  errdetail("%.0f dead row versions cannot be removed yet.\n"
1089  "%s.",
1090  tups_recently_dead,
1091  pg_rusage_show(&ru0))));
1092 
1093  /* Clean up */
1094  pfree(values);
1095  pfree(isnull);
1096 
1097  if (OldIndex != NULL)
1098  index_close(OldIndex, NoLock);
1099  heap_close(OldHeap, NoLock);
1100  heap_close(NewHeap, NoLock);
1101 }
1102 
1103 /*
1104  * Swap the physical files of two given relations.
1105  *
1106  * We swap the physical identity (reltablespace, relfilenode) while keeping the
1107  * same logical identities of the two relations. relpersistence is also
1108  * swapped, which is critical since it determines where buffers live for each
1109  * relation.
1110  *
1111  * We can swap associated TOAST data in either of two ways: recursively swap
1112  * the physical content of the toast tables (and their indexes), or swap the
1113  * TOAST links in the given relations' pg_class entries. The former is needed
1114  * to manage rewrites of shared catalogs (where we cannot change the pg_class
1115  * links) while the latter is the only way to handle cases in which a toast
1116  * table is added or removed altogether.
1117  *
1118  * Additionally, the first relation is marked with relfrozenxid set to
1119  * frozenXid. It seems a bit ugly to have this here, but the caller would
1120  * have to do it anyway, so having it here saves a heap_update. Note: in
1121  * the swap-toast-links case, we assume we don't need to change the toast
1122  * table's relfrozenxid: the new version of the toast table should already
1123  * have relfrozenxid set to RecentXmin, which is good enough.
1124  *
1125  * Lastly, if r2 and its toast table and toast index (if any) are mapped,
1126  * their OIDs are emitted into mapped_tables[]. This is hacky but beats
1127  * having to look the information up again later in finish_heap_swap.
1128  */
1129 static void
1130 swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class,
1131  bool swap_toast_by_content,
1132  bool is_internal,
1133  TransactionId frozenXid,
1134  MultiXactId cutoffMulti,
1135  Oid *mapped_tables)
1136 {
1137  Relation relRelation;
1138  HeapTuple reltup1,
1139  reltup2;
1140  Form_pg_class relform1,
1141  relform2;
1142  Oid relfilenode1,
1143  relfilenode2;
1144  Oid swaptemp;
1145  char swptmpchr;
1146 
1147  /* We need writable copies of both pg_class tuples. */
1149 
1151  if (!HeapTupleIsValid(reltup1))
1152  elog(ERROR, "cache lookup failed for relation %u", r1);
1153  relform1 = (Form_pg_class) GETSTRUCT(reltup1);
1154 
1156  if (!HeapTupleIsValid(reltup2))
1157  elog(ERROR, "cache lookup failed for relation %u", r2);
1158  relform2 = (Form_pg_class) GETSTRUCT(reltup2);
1159 
1160  relfilenode1 = relform1->relfilenode;
1161  relfilenode2 = relform2->relfilenode;
1162 
1163  if (OidIsValid(relfilenode1) && OidIsValid(relfilenode2))
1164  {
1165  /*
1166  * Normal non-mapped relations: swap relfilenodes, reltablespaces,
1167  * relpersistence
1168  */
1169  Assert(!target_is_pg_class);
1170 
1171  swaptemp = relform1->relfilenode;
1172  relform1->relfilenode = relform2->relfilenode;
1173  relform2->relfilenode = swaptemp;
1174 
1175  swaptemp = relform1->reltablespace;
1176  relform1->reltablespace = relform2->reltablespace;
1177  relform2->reltablespace = swaptemp;
1178 
1179  swptmpchr = relform1->relpersistence;
1180  relform1->relpersistence = relform2->relpersistence;
1181  relform2->relpersistence = swptmpchr;
1182 
1183  /* Also swap toast links, if we're swapping by links */
1184  if (!swap_toast_by_content)
1185  {
1186  swaptemp = relform1->reltoastrelid;
1187  relform1->reltoastrelid = relform2->reltoastrelid;
1188  relform2->reltoastrelid = swaptemp;
1189  }
1190  }
1191  else
1192  {
1193  /*
1194  * Mapped-relation case. Here we have to swap the relation mappings
1195  * instead of modifying the pg_class columns. Both must be mapped.
1196  */
1197  if (OidIsValid(relfilenode1) || OidIsValid(relfilenode2))
1198  elog(ERROR, "cannot swap mapped relation \"%s\" with non-mapped relation",
1199  NameStr(relform1->relname));
1200 
1201  /*
1202  * We can't change the tablespace nor persistence of a mapped rel, and
1203  * we can't handle toast link swapping for one either, because we must
1204  * not apply any critical changes to its pg_class row. These cases
1205  * should be prevented by upstream permissions tests, so these checks
1206  * are non-user-facing emergency backstop.
1207  */
1208  if (relform1->reltablespace != relform2->reltablespace)
1209  elog(ERROR, "cannot change tablespace of mapped relation \"%s\"",
1210  NameStr(relform1->relname));
1211  if (relform1->relpersistence != relform2->relpersistence)
1212  elog(ERROR, "cannot change persistence of mapped relation \"%s\"",
1213  NameStr(relform1->relname));
1214  if (!swap_toast_by_content &&
1215  (relform1->reltoastrelid || relform2->reltoastrelid))
1216  elog(ERROR, "cannot swap toast by links for mapped relation \"%s\"",
1217  NameStr(relform1->relname));
1218 
1219  /*
1220  * Fetch the mappings --- shouldn't fail, but be paranoid
1221  */
1222  relfilenode1 = RelationMapOidToFilenode(r1, relform1->relisshared);
1223  if (!OidIsValid(relfilenode1))
1224  elog(ERROR, "could not find relation mapping for relation \"%s\", OID %u",
1225  NameStr(relform1->relname), r1);
1226  relfilenode2 = RelationMapOidToFilenode(r2, relform2->relisshared);
1227  if (!OidIsValid(relfilenode2))
1228  elog(ERROR, "could not find relation mapping for relation \"%s\", OID %u",
1229  NameStr(relform2->relname), r2);
1230 
1231  /*
1232  * Send replacement mappings to relmapper. Note these won't actually
1233  * take effect until CommandCounterIncrement.
1234  */
1235  RelationMapUpdateMap(r1, relfilenode2, relform1->relisshared, false);
1236  RelationMapUpdateMap(r2, relfilenode1, relform2->relisshared, false);
1237 
1238  /* Pass OIDs of mapped r2 tables back to caller */
1239  *mapped_tables++ = r2;
1240  }
1241 
1242  /*
1243  * In the case of a shared catalog, these next few steps will only affect
1244  * our own database's pg_class row; but that's okay, because they are all
1245  * noncritical updates. That's also an important fact for the case of a
1246  * mapped catalog, because it's possible that we'll commit the map change
1247  * and then fail to commit the pg_class update.
1248  */
1249 
1250  /* set rel1's frozen Xid and minimum MultiXid */
1251  if (relform1->relkind != RELKIND_INDEX)
1252  {
1253  Assert(TransactionIdIsNormal(frozenXid));
1254  relform1->relfrozenxid = frozenXid;
1255  Assert(MultiXactIdIsValid(cutoffMulti));
1256  relform1->relminmxid = cutoffMulti;
1257  }
1258 
1259  /* swap size statistics too, since new rel has freshly-updated stats */
1260  {
1261  int32 swap_pages;
1262  float4 swap_tuples;
1263  int32 swap_allvisible;
1264 
1265  swap_pages = relform1->relpages;
1266  relform1->relpages = relform2->relpages;
1267  relform2->relpages = swap_pages;
1268 
1269  swap_tuples = relform1->reltuples;
1270  relform1->reltuples = relform2->reltuples;
1271  relform2->reltuples = swap_tuples;
1272 
1273  swap_allvisible = relform1->relallvisible;
1274  relform1->relallvisible = relform2->relallvisible;
1275  relform2->relallvisible = swap_allvisible;
1276  }
1277 
1278  /*
1279  * Update the tuples in pg_class --- unless the target relation of the
1280  * swap is pg_class itself. In that case, there is zero point in making
1281  * changes because we'd be updating the old data that we're about to throw
1282  * away. Because the real work being done here for a mapped relation is
1283  * just to change the relation map settings, it's all right to not update
1284  * the pg_class rows in this case. The most important changes will instead
1285  * performed later, in finish_heap_swap() itself.
1286  */
1287  if (!target_is_pg_class)
1288  {
1289  CatalogIndexState indstate;
1290 
1291  indstate = CatalogOpenIndexes(relRelation);
1292  CatalogTupleUpdateWithInfo(relRelation, &reltup1->t_self, reltup1,
1293  indstate);
1294  CatalogTupleUpdateWithInfo(relRelation, &reltup2->t_self, reltup2,
1295  indstate);
1296  CatalogCloseIndexes(indstate);
1297  }
1298  else
1299  {
1300  /* no update ... but we do still need relcache inval */
1303  }
1304 
1305  /*
1306  * Post alter hook for modified relations. The change to r2 is always
1307  * internal, but r1 depends on the invocation context.
1308  */
1310  InvalidOid, is_internal);
1312  InvalidOid, true);
1313 
1314  /*
1315  * If we have toast tables associated with the relations being swapped,
1316  * deal with them too.
1317  */
1318  if (relform1->reltoastrelid || relform2->reltoastrelid)
1319  {
1320  if (swap_toast_by_content)
1321  {
1322  if (relform1->reltoastrelid && relform2->reltoastrelid)
1323  {
1324  /* Recursively swap the contents of the toast tables */
1325  swap_relation_files(relform1->reltoastrelid,
1326  relform2->reltoastrelid,
1327  target_is_pg_class,
1328  swap_toast_by_content,
1329  is_internal,
1330  frozenXid,
1331  cutoffMulti,
1332  mapped_tables);
1333  }
1334  else
1335  {
1336  /* caller messed up */
1337  elog(ERROR, "cannot swap toast files by content when there's only one");
1338  }
1339  }
1340  else
1341  {
1342  /*
1343  * We swapped the ownership links, so we need to change dependency
1344  * data to match.
1345  *
1346  * NOTE: it is possible that only one table has a toast table.
1347  *
1348  * NOTE: at present, a TOAST table's only dependency is the one on
1349  * its owning table. If more are ever created, we'd need to use
1350  * something more selective than deleteDependencyRecordsFor() to
1351  * get rid of just the link we want.
1352  */
1353  ObjectAddress baseobject,
1354  toastobject;
1355  long count;
1356 
1357  /*
1358  * We disallow this case for system catalogs, to avoid the
1359  * possibility that the catalog we're rebuilding is one of the
1360  * ones the dependency changes would change. It's too late to be
1361  * making any data changes to the target catalog.
1362  */
1363  if (IsSystemClass(r1, relform1))
1364  elog(ERROR, "cannot swap toast files by links for system catalogs");
1365 
1366  /* Delete old dependencies */
1367  if (relform1->reltoastrelid)
1368  {
1370  relform1->reltoastrelid,
1371  false);
1372  if (count != 1)
1373  elog(ERROR, "expected one dependency record for TOAST table, found %ld",
1374  count);
1375  }
1376  if (relform2->reltoastrelid)
1377  {
1379  relform2->reltoastrelid,
1380  false);
1381  if (count != 1)
1382  elog(ERROR, "expected one dependency record for TOAST table, found %ld",
1383  count);
1384  }
1385 
1386  /* Register new dependencies */
1387  baseobject.classId = RelationRelationId;
1388  baseobject.objectSubId = 0;
1389  toastobject.classId = RelationRelationId;
1390  toastobject.objectSubId = 0;
1391 
1392  if (relform1->reltoastrelid)
1393  {
1394  baseobject.objectId = r1;
1395  toastobject.objectId = relform1->reltoastrelid;
1396  recordDependencyOn(&toastobject, &baseobject,
1398  }
1399 
1400  if (relform2->reltoastrelid)
1401  {
1402  baseobject.objectId = r2;
1403  toastobject.objectId = relform2->reltoastrelid;
1404  recordDependencyOn(&toastobject, &baseobject,
1406  }
1407  }
1408  }
1409 
1410  /*
1411  * If we're swapping two toast tables by content, do the same for their
1412  * valid index. The swap can actually be safely done only if the relations
1413  * have indexes.
1414  */
1415  if (swap_toast_by_content &&
1416  relform1->relkind == RELKIND_TOASTVALUE &&
1417  relform2->relkind == RELKIND_TOASTVALUE)
1418  {
1419  Oid toastIndex1,
1420  toastIndex2;
1421 
1422  /* Get valid index for each relation */
1423  toastIndex1 = toast_get_valid_index(r1,
1425  toastIndex2 = toast_get_valid_index(r2,
1427 
1428  swap_relation_files(toastIndex1,
1429  toastIndex2,
1430  target_is_pg_class,
1431  swap_toast_by_content,
1432  is_internal,
1435  mapped_tables);
1436  }
1437 
1438  /* Clean up. */
1439  heap_freetuple(reltup1);
1440  heap_freetuple(reltup2);
1441 
1442  heap_close(relRelation, RowExclusiveLock);
1443 
1444  /*
1445  * Close both relcache entries' smgr links. We need this kluge because
1446  * both links will be invalidated during upcoming CommandCounterIncrement.
1447  * Whichever of the rels is the second to be cleared will have a dangling
1448  * reference to the other's smgr entry. Rather than trying to avoid this
1449  * by ordering operations just so, it's easiest to close the links first.
1450  * (Fortunately, since one of the entries is local in our transaction,
1451  * it's sufficient to clear out our own relcache this way; the problem
1452  * cannot arise for other backends when they see our update on the
1453  * non-transient relation.)
1454  *
1455  * Caution: the placement of this step interacts with the decision to
1456  * handle toast rels by recursion. When we are trying to rebuild pg_class
1457  * itself, the smgr close on pg_class must happen after all accesses in
1458  * this function.
1459  */
1462 }
1463 
1464 /*
1465  * Remove the transient table that was built by make_new_heap, and finish
1466  * cleaning up (including rebuilding all indexes on the old heap).
1467  */
1468 void
1469 finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap,
1470  bool is_system_catalog,
1471  bool swap_toast_by_content,
1472  bool check_constraints,
1473  bool is_internal,
1474  TransactionId frozenXid,
1475  MultiXactId cutoffMulti,
1476  char newrelpersistence)
1477 {
1478  ObjectAddress object;
1479  Oid mapped_tables[4];
1480  int reindex_flags;
1481  int i;
1482 
1483  /* Zero out possible results from swapped_relation_files */
1484  memset(mapped_tables, 0, sizeof(mapped_tables));
1485 
1486  /*
1487  * Swap the contents of the heap relations (including any toast tables).
1488  * Also set old heap's relfrozenxid to frozenXid.
1489  */
1490  swap_relation_files(OIDOldHeap, OIDNewHeap,
1491  (OIDOldHeap == RelationRelationId),
1492  swap_toast_by_content, is_internal,
1493  frozenXid, cutoffMulti, mapped_tables);
1494 
1495  /*
1496  * If it's a system catalog, queue an sinval message to flush all
1497  * catcaches on the catalog when we reach CommandCounterIncrement.
1498  */
1499  if (is_system_catalog)
1500  CacheInvalidateCatalog(OIDOldHeap);
1501 
1502  /*
1503  * Rebuild each index on the relation (but not the toast table, which is
1504  * all-new at this point). It is important to do this before the DROP
1505  * step because if we are processing a system catalog that will be used
1506  * during DROP, we want to have its indexes available. There is no
1507  * advantage to the other order anyway because this is all transactional,
1508  * so no chance to reclaim disk space before commit. We do not need a
1509  * final CommandCounterIncrement() because reindex_relation does it.
1510  *
1511  * Note: because index_build is called via reindex_relation, it will never
1512  * set indcheckxmin true for the indexes. This is OK even though in some
1513  * sense we are building new indexes rather than rebuilding existing ones,
1514  * because the new heap won't contain any HOT chains at all, let alone
1515  * broken ones, so it can't be necessary to set indcheckxmin.
1516  */
1517  reindex_flags = REINDEX_REL_SUPPRESS_INDEX_USE;
1518  if (check_constraints)
1519  reindex_flags |= REINDEX_REL_CHECK_CONSTRAINTS;
1520 
1521  /*
1522  * Ensure that the indexes have the same persistence as the parent
1523  * relation.
1524  */
1525  if (newrelpersistence == RELPERSISTENCE_UNLOGGED)
1526  reindex_flags |= REINDEX_REL_FORCE_INDEXES_UNLOGGED;
1527  else if (newrelpersistence == RELPERSISTENCE_PERMANENT)
1528  reindex_flags |= REINDEX_REL_FORCE_INDEXES_PERMANENT;
1529 
1530  reindex_relation(OIDOldHeap, reindex_flags, 0);
1531 
1532  /*
1533  * If the relation being rebuild is pg_class, swap_relation_files()
1534  * couldn't update pg_class's own pg_class entry (check comments in
1535  * swap_relation_files()), thus relfrozenxid was not updated. That's
1536  * annoying because a potential reason for doing a VACUUM FULL is a
1537  * imminent or actual anti-wraparound shutdown. So, now that we can
1538  * access the new relation using it's indices, update relfrozenxid.
1539  * pg_class doesn't have a toast relation, so we don't need to update the
1540  * corresponding toast relation. Not that there's little point moving all
1541  * relfrozenxid updates here since swap_relation_files() needs to write to
1542  * pg_class for non-mapped relations anyway.
1543  */
1544  if (OIDOldHeap == RelationRelationId)
1545  {
1546  Relation relRelation;
1547  HeapTuple reltup;
1548  Form_pg_class relform;
1549 
1551 
1552  reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(OIDOldHeap));
1553  if (!HeapTupleIsValid(reltup))
1554  elog(ERROR, "cache lookup failed for relation %u", OIDOldHeap);
1555  relform = (Form_pg_class) GETSTRUCT(reltup);
1556 
1557  relform->relfrozenxid = frozenXid;
1558  relform->relminmxid = cutoffMulti;
1559 
1560  CatalogTupleUpdate(relRelation, &reltup->t_self, reltup);
1561 
1562  heap_close(relRelation, RowExclusiveLock);
1563  }
1564 
1565  /* Destroy new heap with old filenode */
1566  object.classId = RelationRelationId;
1567  object.objectId = OIDNewHeap;
1568  object.objectSubId = 0;
1569 
1570  /*
1571  * The new relation is local to our transaction and we know nothing
1572  * depends on it, so DROP_RESTRICT should be OK.
1573  */
1575 
1576  /* performDeletion does CommandCounterIncrement at end */
1577 
1578  /*
1579  * Now we must remove any relation mapping entries that we set up for the
1580  * transient table, as well as its toast table and toast index if any. If
1581  * we fail to do this before commit, the relmapper will complain about new
1582  * permanent map entries being added post-bootstrap.
1583  */
1584  for (i = 0; OidIsValid(mapped_tables[i]); i++)
1585  RelationMapRemoveMapping(mapped_tables[i]);
1586 
1587  /*
1588  * At this point, everything is kosher except that, if we did toast swap
1589  * by links, the toast table's name corresponds to the transient table.
1590  * The name is irrelevant to the backend because it's referenced by OID,
1591  * but users looking at the catalogs could be confused. Rename it to
1592  * prevent this problem.
1593  *
1594  * Note no lock required on the relation, because we already hold an
1595  * exclusive lock on it.
1596  */
1597  if (!swap_toast_by_content)
1598  {
1599  Relation newrel;
1600 
1601  newrel = heap_open(OIDOldHeap, NoLock);
1602  if (OidIsValid(newrel->rd_rel->reltoastrelid))
1603  {
1604  Oid toastidx;
1605  char NewToastName[NAMEDATALEN];
1606 
1607  /* Get the associated valid index to be renamed */
1608  toastidx = toast_get_valid_index(newrel->rd_rel->reltoastrelid,
1609  AccessShareLock);
1610 
1611  /* rename the toast table ... */
1612  snprintf(NewToastName, NAMEDATALEN, "pg_toast_%u",
1613  OIDOldHeap);
1614  RenameRelationInternal(newrel->rd_rel->reltoastrelid,
1615  NewToastName, true);
1616 
1617  /* ... and its valid index too. */
1618  snprintf(NewToastName, NAMEDATALEN, "pg_toast_%u_index",
1619  OIDOldHeap);
1620 
1621  RenameRelationInternal(toastidx,
1622  NewToastName, true);
1623  }
1624  relation_close(newrel, NoLock);
1625  }
1626 }
1627 
1628 
1629 /*
1630  * Get a list of tables that the current user owns and
1631  * have indisclustered set. Return the list in a List * of rvsToCluster
1632  * with the tableOid and the indexOid on which the table is already
1633  * clustered.
1634  */
1635 static List *
1637 {
1638  Relation indRelation;
1639  HeapScanDesc scan;
1640  ScanKeyData entry;
1641  HeapTuple indexTuple;
1643  MemoryContext old_context;
1644  RelToCluster *rvtc;
1645  List *rvs = NIL;
1646 
1647  /*
1648  * Get all indexes that have indisclustered set and are owned by
1649  * appropriate user. System relations or nailed-in relations cannot ever
1650  * have indisclustered set, because CLUSTER will refuse to set it when
1651  * called with one of them as argument.
1652  */
1653  indRelation = heap_open(IndexRelationId, AccessShareLock);
1654  ScanKeyInit(&entry,
1656  BTEqualStrategyNumber, F_BOOLEQ,
1657  BoolGetDatum(true));
1658  scan = heap_beginscan_catalog(indRelation, 1, &entry);
1659  while ((indexTuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
1660  {
1661  index = (Form_pg_index) GETSTRUCT(indexTuple);
1662 
1663  if (!pg_class_ownercheck(index->indrelid, GetUserId()))
1664  continue;
1665 
1666  /*
1667  * We have to build the list in a different memory context so it will
1668  * survive the cross-transaction processing
1669  */
1670  old_context = MemoryContextSwitchTo(cluster_context);
1671 
1672  rvtc = (RelToCluster *) palloc(sizeof(RelToCluster));
1673  rvtc->tableOid = index->indrelid;
1674  rvtc->indexOid = index->indexrelid;
1675  rvs = lcons(rvtc, rvs);
1676 
1677  MemoryContextSwitchTo(old_context);
1678  }
1679  heap_endscan(scan);
1680 
1681  relation_close(indRelation, AccessShareLock);
1682 
1683  return rvs;
1684 }
1685 
1686 
1687 /*
1688  * Reconstruct and rewrite the given tuple
1689  *
1690  * We cannot simply copy the tuple as-is, for several reasons:
1691  *
1692  * 1. We'd like to squeeze out the values of any dropped columns, both
1693  * to save space and to ensure we have no corner-case failures. (It's
1694  * possible for example that the new table hasn't got a TOAST table
1695  * and so is unable to store any large values of dropped cols.)
1696  *
1697  * 2. The tuple might not even be legal for the new table; this is
1698  * currently only known to happen as an after-effect of ALTER TABLE
1699  * SET WITHOUT OIDS.
1700  *
1701  * So, we must reconstruct the tuple from component Datums.
1702  */
1703 static void
1705  TupleDesc oldTupDesc, TupleDesc newTupDesc,
1706  Datum *values, bool *isnull,
1707  bool newRelHasOids, RewriteState rwstate)
1708 {
1709  HeapTuple copiedTuple;
1710  int i;
1711 
1712  heap_deform_tuple(tuple, oldTupDesc, values, isnull);
1713 
1714  /* Be sure to null out any dropped columns */
1715  for (i = 0; i < newTupDesc->natts; i++)
1716  {
1717  if (newTupDesc->attrs[i]->attisdropped)
1718  isnull[i] = true;
1719  }
1720 
1721  copiedTuple = heap_form_tuple(newTupDesc, values, isnull);
1722 
1723  /* Preserve OID, if any */
1724  if (newRelHasOids)
1725  HeapTupleSetOid(copiedTuple, HeapTupleGetOid(tuple));
1726 
1727  /* The heap rewrite module does the rest */
1728  rewrite_heap_tuple(rwstate, tuple, copiedTuple);
1729 
1730  heap_freetuple(copiedTuple);
1731 }
#define HeapTupleHeaderGetUpdateXid(tup)
Definition: htup_details.h:359
#define RelationIsPopulated(relation)
Definition: rel.h:552
#define NIL
Definition: pg_list.h:69
#define BUFFER_LOCK_UNLOCK
Definition: bufmgr.h:87
void RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal)
Definition: tablecmds.c:2914
void RangeVarCallbackOwnsTable(const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
Definition: tablecmds.c:12938
void tuplesort_performsort(Tuplesortstate *state)
Definition: tuplesort.c:1773
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:200
void end_heap_rewrite(RewriteState state)
Definition: rewriteheap.c:314
HeapTuple tuplesort_getheaptuple(Tuplesortstate *state, bool forward)
Definition: tuplesort.c:2150
bool plan_cluster_use_sort(Oid tableOid, Oid indexOid)
Definition: planner.c:5960
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
void heap_endscan(HeapScanDesc scan)
Definition: heapam.c:1578
bool IsSystemRelation(Relation relation)
Definition: catalog.c:63
#define RELPERSISTENCE_UNLOGGED
Definition: pg_class.h:171
#define IndexIsValid(indexForm)
Definition: pg_index.h:107
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 cutoffMulti, char newrelpersistence)
Definition: cluster.c:1469
uint32 TransactionId
Definition: c.h:397
RewriteState begin_heap_rewrite(Relation old_heap, Relation new_heap, TransactionId oldest_xmin, TransactionId freeze_xid, MultiXactId cutoff_multi, bool use_wal)
Definition: rewriteheap.c:248
#define RelationGetDescr(relation)
Definition: rel.h:428
int LOCKMODE
Definition: lockdefs.h:26
Relation try_relation_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1147
bool TransactionIdIsCurrentTransactionId(TransactionId xid)
Definition: xact.c:773
Oid GetUserId(void)
Definition: miscinit.c:283
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, bool missing_ok, bool nowait, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:218
Oid LookupCreationNamespace(const char *nspname)
Definition: namespace.c:2896
#define Anum_pg_class_reloptions
Definition: pg_class.h:134
#define IndexRelationId
Definition: pg_index.h:29
void CommitTransactionCommand(void)
Definition: xact.c:2748
#define RelationRelationId
Definition: pg_class.h:29
#define XLogIsNeeded()
Definition: xlog.h:145
#define BTREE_AM_OID
Definition: pg_am.h:70
Form_pg_attribute * attrs
Definition: tupdesc.h:74
long deleteDependencyRecordsFor(Oid classId, Oid objectId, bool skipExtensionDeps)
Definition: pg_depend.c:191
#define RELKIND_MATVIEW
Definition: pg_class.h:165
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
Oid toast_get_valid_index(Oid toastoid, LOCKMODE lock)
Definition: tuptoaster.c:1431
#define AccessShareLock
Definition: lockdefs.h:36
HTSV_Result HeapTupleSatisfiesVacuum(HeapTuple htup, TransactionId OldestXmin, Buffer buffer)
Definition: tqual.c:1164
void index_rescan(IndexScanDesc scan, ScanKey keys, int nkeys, ScanKey orderbys, int norderbys)
Definition: indexam.c:310
static void reform_and_rewrite_tuple(HeapTuple tuple, TupleDesc oldTupDesc, TupleDesc newTupDesc, Datum *values, bool *isnull, bool newRelHasOids, RewriteState rwstate)
Definition: cluster.c:1704
int errcode(int sqlerrcode)
Definition: elog.c:575
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: heapam.c:1260
#define INFO
Definition: elog.h:33
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
void vacuum_set_xid_limits(Relation rel, int freeze_min_age, int freeze_table_age, int multixact_freeze_min_age, int multixact_freeze_table_age, TransactionId *oldestXmin, TransactionId *freezeLimit, TransactionId *xidFullScanLimit, MultiXactId *multiXactCutoff, MultiXactId *mxactFullScanLimit)
Definition: vacuum.c:501
void PopActiveSnapshot(void)
Definition: snapmgr.c:812
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:44
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:692
#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:114
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1372
unsigned int Oid
Definition: postgres_ext.h:31
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:304
#define OidIsValid(objectId)
Definition: c.h:538
#define RelationGetTargetBlock(relation)
Definition: rel.h:488
struct IndexAmRoutine * rd_amroutine
Definition: rel.h:181
int natts
Definition: tupdesc.h:73
#define SearchSysCache1(cacheId, key1)
Definition: syscache.h:156
Oid tableOid
Definition: cluster.c:65
signed int int32
Definition: c.h:256
bool IsSystemClass(Oid relid, Form_pg_class reltuple)
Definition: catalog.c:75
struct HeapTupleData * rd_indextuple
Definition: rel.h:161
MemoryContext PortalContext
Definition: mcxt.c:52
HeapTupleHeader t_data
Definition: htup.h:67
void pg_rusage_init(PGRUsage *ru0)
Definition: pg_rusage.c:27
Definition: type.h:89
#define RELPERSISTENCE_PERMANENT
Definition: pg_class.h:170
#define HeapTupleSetOid(tuple, oid)
Definition: htup_details.h:698
#define NAMEDATALEN
char * relname
Definition: primnodes.h:68
Form_pg_index rd_index
Definition: rel.h:159
#define SearchSysCacheExists1(cacheId, key1)
Definition: syscache.h:174
char * indexname
Definition: parsenodes.h:3061
void pfree(void *pointer)
Definition: mcxt.c:950
Buffer xs_cbuf
Definition: relscan.h:120
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
static void rebuild_relation(Relation OldHeap, Oid indexOid, bool verbose)
Definition: cluster.c:555
void cluster_rel(Oid tableOid, Oid indexOid, bool recheck, bool verbose)
Definition: cluster.c:260
ItemPointerData t_self
Definition: htup.h:65
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition: lsyscache.c:1683
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:165
#define DEBUG2
Definition: elog.h:24
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3033
#define NoLock
Definition: lockdefs.h:34
static char * buf
Definition: pg_test_fsync.c:66
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:733
#define InvokeObjectPostAlterHookArg(classId, objectId, subId,auxiliaryId, is_internal)
Definition: objectaccess.h:166
bool heap_attisnull(HeapTuple tup, int attnum)
Definition: heaptuple.c:297
Oid rd_toastoid
Definition: rel.h:215
#define RowExclusiveLock
Definition: lockdefs.h:38
int errdetail(const char *fmt,...)
Definition: elog.c:873
static MultiXactId MultiXactCutoff
Definition: vacuumlazy.c:140
const char * pg_rusage_show(const PGRUsage *ru0)
Definition: pg_rusage.c:40
void performDeletion(const ObjectAddress *object, DropBehavior behavior, int flags)
Definition: dependency.c:303
#define InvalidTransactionId
Definition: transam.h:31
#define RelationGetRelationName(relation)
Definition: rel.h:436
static TransactionId OldestXmin
Definition: vacuumlazy.c:138
void cluster(ClusterStmt *stmt, bool isTopLevel)
Definition: cluster.c:106
#define MultiXactIdIsValid(multi)
Definition: multixact.h:27
HeapScanDesc heap_beginscan_catalog(Relation relation, int nkeys, ScanKey key)
Definition: heapam.c:1399
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:3010
static List * get_tables_to_cluster(MemoryContext cluster_context)
Definition: cluster.c:1636
void index_endscan(IndexScanDesc scan)
Definition: indexam.c:340
#define ereport(elevel, rest)
Definition: elog.h:122
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
void TransferPredicateLocksToHeapRelation(Relation relation)
Definition: predicate.c:3075
static int verbose
Definition: pg_basebackup.c:84
#define WARNING
Definition: elog.h:40
void CatalogTupleUpdateWithInfo(Relation heapRel, ItemPointer otid, HeapTuple tup, CatalogIndexState indstate)
Definition: indexing.c:231
#define RelationIsMapped(relation)
Definition: rel.h:453
FormData_pg_index * Form_pg_index
Definition: pg_index.h:67
void mark_index_clustered(Relation rel, Oid indexOid, bool is_internal)
Definition: cluster.c:478
float float4
Definition: c.h:380
static int elevel
Definition: vacuumlazy.c:136
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:322
static void copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex, bool verbose, bool *pSwapToastByContent, TransactionId *pFreezeXid, MultiXactId *pCutoffMulti)
Definition: cluster.c:734
#define RELKIND_TOASTVALUE
Definition: pg_class.h:163
Oid RelationMapOidToFilenode(Oid relationId, bool shared)
Definition: relmapper.c:146
uintptr_t Datum
Definition: postgres.h:372
void CommandCounterIncrement(void)
Definition: xact.c:922
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1117
#define SnapshotAny
Definition: tqual.h:28
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1279
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
HeapTuple heap_getnext(HeapScanDesc scan, ScanDirection direction)
Definition: heapam.c:1794
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1284
#define InvalidMultiXactId
Definition: multixact.h:23
bool amclusterable
Definition: amapi.h:189
#define RelationGetNumberOfBlocks(reln)
Definition: bufmgr.h:199
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:1130
#define BoolGetDatum(X)
Definition: postgres.h:408
#define InvalidOid
Definition: postgres_ext.h:36
int maintenance_work_mem
Definition: globals.c:114
Buffer rs_cbuf
Definition: relscan.h:70
#define Anum_pg_index_indpred
Definition: pg_index.h:92
void RelationCloseSmgrByOid(Oid relationId)
Definition: relcache.c:2859
List * lcons(void *datum, List *list)
Definition: list.c:259
TransactionId MultiXactId
Definition: c.h:407
void CacheInvalidateCatalog(Oid catalogId)
Definition: inval.c:1209
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define REINDEX_REL_FORCE_INDEXES_UNLOGGED
Definition: index.h:125
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
#define lfirst(lc)
Definition: pg_list.h:106
void RelationMapRemoveMapping(Oid relationId)
Definition: relmapper.c:357
#define RELATION_IS_OTHER_TEMP(relation)
Definition: rel.h:533
bool pg_class_ownercheck(Oid class_oid, Oid roleid)
Definition: aclchk.c:4546
void StartTransactionCommand(void)
Definition: xact.c:2678
CatalogIndexState CatalogOpenIndexes(Relation heapRel)
Definition: indexing.c:40
#define HeapTupleHeaderGetXmin(tup)
Definition: htup_details.h:307
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:210
#define InvalidBlockNumber
Definition: block.h:33
#define REINDEX_REL_CHECK_CONSTRAINTS
Definition: index.h:124
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3140
#define RelationNeedsWAL(relation)
Definition: rel.h:505
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4345
Oid indexOid
Definition: cluster.c:66
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:176
void heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *values, bool *isnull)
Definition: heaptuple.c:933
Tuplesortstate * tuplesort_begin_cluster(TupleDesc tupDesc, Relation indexRel, int workMem, bool randomAccess)
Definition: tuplesort.c:828
static Datum values[MAXATTR]
Definition: bootstrap.c:163
FormData_pg_class * Form_pg_class
Definition: pg_class.h:95
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:165
bool rewrite_heap_dead_tuple(RewriteState state, HeapTuple old_tuple)
Definition: rewriteheap.c:578
#define AccessExclusiveLock
Definition: lockdefs.h:45
void * palloc(Size size)
Definition: mcxt.c:849
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 Anum_pg_index_indisclustered
Definition: pg_index.h:81
int i
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:1019
void tuplesort_putheaptuple(Tuplesortstate *state, HeapTuple tup)
Definition: tuplesort.c:1386
#define NameStr(name)
Definition: c.h:499
#define RELKIND_INDEX
Definition: pg_class.h:161
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define BUFFER_LOCK_SHARE
Definition: bufmgr.h:88
#define REINDEX_REL_FORCE_INDEXES_PERMANENT
Definition: index.h:126
void CatalogCloseIndexes(CatalogIndexState indstate)
Definition: indexing.c:58
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:100
void CacheInvalidateRelcacheByTuple(HeapTuple classTuple)
Definition: inval.c:1269
#define elog
Definition: elog.h:219
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:695
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:105
#define RELPERSISTENCE_TEMP
Definition: pg_class.h:172
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:1167
#define TransactionIdIsNormal(xid)
Definition: transam.h:42
#define RELKIND_RELATION
Definition: pg_class.h:160
RangeVar * relation
Definition: parsenodes.h:3060
bool reindex_relation(Oid relid, int flags, int options)
Definition: index.c:3509
Definition: pg_list.h:45
HeapScanDesc heap_beginscan(Relation relation, Snapshot snapshot, int nkeys, ScanKey key)
Definition: heapam.c:1391
int Buffer
Definition: buf.h:23
void rewrite_heap_tuple(RewriteState state, HeapTuple old_tuple, HeapTuple new_tuple)
Definition: rewriteheap.c:380
#define RelationGetRelid(relation)
Definition: rel.h:416
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:151
#define BTEqualStrategyNumber
Definition: stratnum.h:31
Oid make_new_heap(Oid OIDOldHeap, Oid NewTableSpace, char relpersistence, LOCKMODE lockmode)
Definition: cluster.c:608
HeapTuple index_getnext(IndexScanDesc scan, ScanDirection direction)
Definition: indexam.c:659
#define lfirst_oid(lc)
Definition: pg_list.h:108
void RelationMapUpdateMap(Oid relationId, Oid fileNode, bool shared, bool immediate)
Definition: relmapper.c:248
IndexScanDesc index_beginscan(Relation heapRelation, Relation indexRelation, Snapshot snapshot, int nkeys, int norderbys)
Definition: indexam.c:221
#define PERFORM_DELETION_INTERNAL
Definition: dependency.h:174
void PreventTransactionChain(bool isTopLevel, const char *stmtType)
Definition: xact.c:3155
#define RelationGetNamespace(relation)
Definition: rel.h:443
void NewHeapCreateToastTable(Oid relOid, Datum reloptions, LOCKMODE lockmode)
Definition: toasting.c:65