PostgreSQL Source Code git master
Loading...
Searching...
No Matches
cluster.h File Reference
#include "nodes/parsenodes.h"
#include "parser/parse_node.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.

Data Structures

struct  ClusterParams
 

Macros

#define CLUOPT_VERBOSE   0x01 /* print progress info */
 
#define CLUOPT_RECHECK   0x02 /* recheck relation state */
 
#define CLUOPT_RECHECK_ISCLUSTERED
 
#define CLUOPT_ANALYZE   0x08 /* do an ANALYZE */
 

Typedefs

typedef struct ClusterParams ClusterParams
 

Functions

void ExecRepack (ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
 
void cluster_rel (RepackCommand command, Relation OldHeap, Oid indexOid, ClusterParams *params)
 
void check_index_is_clusterable (Relation OldHeap, Oid indexOid, LOCKMODE lockmode)
 
void mark_index_clustered (Relation rel, Oid indexOid, bool is_internal)
 
Oid make_new_heap (Oid OIDOldHeap, Oid NewTableSpace, Oid NewAccessMethod, 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 cutoffMulti, char newrelpersistence)
 

Macro Definition Documentation

◆ CLUOPT_ANALYZE

#define CLUOPT_ANALYZE   0x08 /* do an ANALYZE */

Definition at line 26 of file cluster.h.

◆ CLUOPT_RECHECK

#define CLUOPT_RECHECK   0x02 /* recheck relation state */

Definition at line 24 of file cluster.h.

◆ CLUOPT_RECHECK_ISCLUSTERED

#define CLUOPT_RECHECK_ISCLUSTERED
Value:
0x04 /* recheck relation state for
* indisclustered */

Definition at line 25 of file cluster.h.

31{
32 bits32 options; /* bitmask of CLUOPT_* */
34
35
36extern void ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel);
37
38extern void cluster_rel(RepackCommand command, Relation OldHeap, Oid indexOid,
39 ClusterParams *params);
41 LOCKMODE lockmode);
42extern void mark_index_clustered(Relation rel, Oid indexOid, bool is_internal);
43
45 char relpersistence, LOCKMODE lockmode);
50 bool is_internal,
53 char newrelpersistence);
54
55#endif /* CLUSTER_H */
TransactionId MultiXactId
Definition c.h:718
uint32 bits32
Definition c.h:597
uint32 TransactionId
Definition c.h:708
void check_index_is_clusterable(Relation OldHeap, Oid indexOid, LOCKMODE lockmode)
Definition cluster.c:508
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:1459
void ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel)
Definition cluster.c:113
void cluster_rel(RepackCommand command, Relation OldHeap, Oid indexOid, ClusterParams *params)
Definition cluster.c:300
Oid make_new_heap(Oid OIDOldHeap, Oid NewTableSpace, Oid NewAccessMethod, char relpersistence, LOCKMODE lockmode)
Definition cluster.c:719
void mark_index_clustered(Relation rel, Oid indexOid, bool is_internal)
Definition cluster.c:568
#define stmt
int LOCKMODE
Definition lockdefs.h:26
RepackCommand
unsigned int Oid
static int fb(int x)

◆ CLUOPT_VERBOSE

#define CLUOPT_VERBOSE   0x01 /* print progress info */

Definition at line 23 of file cluster.h.

Typedef Documentation

◆ ClusterParams

Function Documentation

◆ check_index_is_clusterable()

void check_index_is_clusterable ( Relation  OldHeap,
Oid  indexOid,
LOCKMODE  lockmode 
)
extern

Definition at line 508 of file cluster.c.

509{
511
512 OldIndex = index_open(indexOid, lockmode);
513
514 /*
515 * Check that index is in fact an index on the given relation
516 */
517 if (OldIndex->rd_index == NULL ||
518 OldIndex->rd_index->indrelid != RelationGetRelid(OldHeap))
521 errmsg("\"%s\" is not an index for table \"%s\"",
524
525 /* Index AM must allow clustering */
526 if (!OldIndex->rd_indam->amclusterable)
529 errmsg("cannot cluster on index \"%s\" because access method does not support clustering",
531
532 /*
533 * Disallow clustering on incomplete indexes (those that might not index
534 * every row of the relation). We could relax this by making a separate
535 * seqscan pass over the table to copy the missing rows, but that seems
536 * expensive and tedious.
537 */
538 if (!heap_attisnull(OldIndex->rd_indextuple, Anum_pg_index_indpred, NULL))
541 errmsg("cannot cluster on partial index \"%s\"",
543
544 /*
545 * Disallow if index is left over from a failed CREATE INDEX CONCURRENTLY;
546 * it might well not contain entries for every heap row, or might not even
547 * be internally consistent. (But note that we don't check indcheckxmin;
548 * the worst consequence of following broken HOT chains would be that we
549 * might put recently-dead tuples out-of-order in the new table, and there
550 * is little harm in that.)
551 */
552 if (!OldIndex->rd_index->indisvalid)
555 errmsg("cannot cluster on invalid index \"%s\"",
557
558 /* Drop relcache refcnt on OldIndex, but keep lock */
560}
int errcode(int sqlerrcode)
Definition elog.c:874
#define ERROR
Definition elog.h:39
#define ereport(elevel,...)
Definition elog.h:150
bool heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
Definition heaptuple.c:456
void index_close(Relation relation, LOCKMODE lockmode)
Definition indexam.c:177
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition indexam.c:133
#define NoLock
Definition lockdefs.h:34
static char * errmsg
#define RelationGetRelid(relation)
Definition rel.h:514
#define RelationGetRelationName(relation)
Definition rel.h:548

References ereport, errcode(), errmsg, ERROR, fb(), heap_attisnull(), index_close(), index_open(), NoLock, RelationGetRelationName, and RelationGetRelid.

Referenced by ATExecClusterOn(), cluster_rel(), ExecRepack(), and process_single_relation().

◆ cluster_rel()

void cluster_rel ( RepackCommand  command,
Relation  OldHeap,
Oid  indexOid,
ClusterParams params 
)
extern

Definition at line 300 of file cluster.c.

302{
303 Oid tableOid = RelationGetRelid(OldHeap);
304 Oid save_userid;
305 int save_sec_context;
306 int save_nestlevel;
307 bool verbose = ((params->options & CLUOPT_VERBOSE) != 0);
308 bool recheck = ((params->options & CLUOPT_RECHECK) != 0);
310
312
313 /* Check for user-requested abort. */
315
318
319 /*
320 * Switch to the table owner's userid, so that any index functions are run
321 * as that user. Also lock down security-restricted operations and
322 * arrange to make GUC variable changes local to this command.
323 */
324 GetUserIdAndSecContext(&save_userid, &save_sec_context);
325 SetUserIdAndSecContext(OldHeap->rd_rel->relowner,
326 save_sec_context | SECURITY_RESTRICTED_OPERATION);
327 save_nestlevel = NewGUCNestLevel();
329
330 /*
331 * Since we may open a new transaction for each relation, we have to check
332 * that the relation still is what we think it is.
333 *
334 * If this is a single-transaction CLUSTER, we can skip these tests. We
335 * *must* skip the one on indisclustered since it would reject an attempt
336 * to cluster a not-previously-clustered index.
337 */
338 if (recheck &&
339 !cluster_rel_recheck(cmd, OldHeap, indexOid, save_userid,
340 params->options))
341 goto out;
342
343 /*
344 * We allow repacking shared catalogs only when not using an index. It
345 * would work to use an index in most respects, but the index would only
346 * get marked as indisclustered in the current database, leading to
347 * unexpected behavior if CLUSTER were later invoked in another database.
348 */
349 if (OidIsValid(indexOid) && OldHeap->rd_rel->relisshared)
352 /*- translator: first %s is name of a SQL command, eg. REPACK */
353 errmsg("cannot execute %s on a shared catalog",
355
356 /*
357 * Don't process temp tables of other backends ... their local buffer
358 * manager is not going to cope.
359 */
363 /*- translator: first %s is name of a SQL command, eg. REPACK */
364 errmsg("cannot execute %s on temporary tables of other sessions",
366
367 /*
368 * Also check for active uses of the relation in the current transaction,
369 * including open scans and pending AFTER trigger events.
370 */
372
373 /* Check heap and index are valid to cluster on */
374 if (OidIsValid(indexOid))
375 {
376 /* verify the index is good and lock it */
378 /* also open it */
379 index = index_open(indexOid, NoLock);
380 }
381 else
382 index = NULL;
383
384 /*
385 * When allow_system_table_mods is turned off, we disallow repacking a
386 * catalog on a particular index unless that's already the clustered index
387 * for that catalog.
388 *
389 * XXX We don't check for this in CLUSTER, because it's historically been
390 * allowed.
391 */
392 if (cmd != REPACK_COMMAND_CLUSTER &&
393 !allowSystemTableMods && OidIsValid(indexOid) &&
394 IsCatalogRelation(OldHeap) && !index->rd_index->indisclustered)
397 errmsg("permission denied: \"%s\" is a system catalog",
399 errdetail("System catalogs can only be clustered by the index they're already clustered on, if any, unless \"%s\" is enabled.",
400 "allow_system_table_mods"));
401
402 /*
403 * Quietly ignore the request if this is a materialized view which has not
404 * been populated from its query. No harm is done because there is no data
405 * to deal with, and we don't want to throw an error if this is part of a
406 * multi-relation request -- for example, CLUSTER was run on the entire
407 * database.
408 */
409 if (OldHeap->rd_rel->relkind == RELKIND_MATVIEW &&
411 {
413 goto out;
414 }
415
416 Assert(OldHeap->rd_rel->relkind == RELKIND_RELATION ||
417 OldHeap->rd_rel->relkind == RELKIND_MATVIEW ||
418 OldHeap->rd_rel->relkind == RELKIND_TOASTVALUE);
419
420 /*
421 * All predicate locks on the tuples or pages are about to be made
422 * invalid, because we move tuples around. Promote them to relation
423 * locks. Predicate locks on indexes will be promoted when they are
424 * reindexed.
425 */
427
428 /* rebuild_relation does all the dirty work */
430 /* rebuild_relation closes OldHeap, and index if valid */
431
432out:
433 /* Roll back any GUC changes executed by index functions */
434 AtEOXact_GUC(false, save_nestlevel);
435
436 /* Restore userid and security context */
437 SetUserIdAndSecContext(save_userid, save_sec_context);
438
440}
void pgstat_progress_start_command(ProgressCommandType cmdtype, Oid relid)
void pgstat_progress_update_param(int index, int64 val)
void pgstat_progress_end_command(void)
@ PROGRESS_COMMAND_REPACK
#define Assert(condition)
Definition c.h:915
#define OidIsValid(objectId)
Definition c.h:830
bool IsCatalogRelation(Relation relation)
Definition catalog.c:104
void check_index_is_clusterable(Relation OldHeap, Oid indexOid, LOCKMODE lockmode)
Definition cluster.c:508
static const char * RepackCommandAsString(RepackCommand cmd)
Definition cluster.c:2019
static bool cluster_rel_recheck(RepackCommand cmd, Relation OldHeap, Oid indexOid, Oid userid, int options)
Definition cluster.c:447
static void rebuild_relation(Relation OldHeap, Relation index, bool verbose)
Definition cluster.c:643
#define CLUOPT_VERBOSE
Definition cluster.h:23
#define CLUOPT_RECHECK
Definition cluster.h:24
int errdetail(const char *fmt,...) pg_attribute_printf(1
bool allowSystemTableMods
Definition globals.c:130
int NewGUCNestLevel(void)
Definition guc.c:2110
void RestrictSearchPath(void)
Definition guc.c:2121
void AtEOXact_GUC(bool isCommit, int nestLevel)
Definition guc.c:2137
bool CheckRelationLockedByMe(Relation relation, LOCKMODE lockmode, bool orstronger)
Definition lmgr.c:334
#define AccessExclusiveLock
Definition lockdefs.h:43
#define SECURITY_RESTRICTED_OPERATION
Definition miscadmin.h:319
#define CHECK_FOR_INTERRUPTS()
Definition miscadmin.h:123
void GetUserIdAndSecContext(Oid *userid, int *sec_context)
Definition miscinit.c:613
void SetUserIdAndSecContext(Oid userid, int sec_context)
Definition miscinit.c:620
@ REPACK_COMMAND_CLUSTER
static int verbose
void TransferPredicateLocksToHeapRelation(Relation relation)
Definition predicate.c:3122
#define PROGRESS_REPACK_COMMAND
Definition progress.h:85
#define RelationIsPopulated(relation)
Definition rel.h:686
#define RELATION_IS_OTHER_TEMP(relation)
Definition rel.h:667
void relation_close(Relation relation, LOCKMODE lockmode)
Definition relation.c:205
bits32 options
Definition cluster.h:31
Definition type.h:96
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition tablecmds.c:4432

References AccessExclusiveLock, allowSystemTableMods, Assert, AtEOXact_GUC(), CHECK_FOR_INTERRUPTS, check_index_is_clusterable(), CheckRelationLockedByMe(), CheckTableNotInUse(), CLUOPT_RECHECK, CLUOPT_VERBOSE, cluster_rel_recheck(), ereport, errcode(), errdetail(), errmsg, ERROR, fb(), GetUserIdAndSecContext(), index_open(), IsCatalogRelation(), NewGUCNestLevel(), NoLock, OidIsValid, ClusterParams::options, pgstat_progress_end_command(), pgstat_progress_start_command(), pgstat_progress_update_param(), PROGRESS_COMMAND_REPACK, PROGRESS_REPACK_COMMAND, rebuild_relation(), relation_close(), RELATION_IS_OTHER_TEMP, RelationGetRelationName, RelationGetRelid, RelationIsPopulated, REPACK_COMMAND_CLUSTER, RepackCommandAsString(), RestrictSearchPath(), SECURITY_RESTRICTED_OPERATION, SetUserIdAndSecContext(), TransferPredicateLocksToHeapRelation(), and verbose.

Referenced by ExecRepack(), process_single_relation(), and vacuum_rel().

◆ ExecRepack()

void ExecRepack ( ParseState pstate,
RepackStmt stmt,
bool  isTopLevel 
)
extern

Definition at line 113 of file cluster.c.

114{
115 ClusterParams params = {0};
116 Relation rel = NULL;
118 List *rtcs;
119
120 /* Parse option list */
121 foreach_node(DefElem, opt, stmt->params)
122 {
123 if (strcmp(opt->defname, "verbose") == 0)
124 params.options |= defGetBoolean(opt) ? CLUOPT_VERBOSE : 0;
125 else if (strcmp(opt->defname, "analyze") == 0 ||
126 strcmp(opt->defname, "analyse") == 0)
127 params.options |= defGetBoolean(opt) ? CLUOPT_ANALYZE : 0;
128 else
131 errmsg("unrecognized %s option \"%s\"",
132 RepackCommandAsString(stmt->command),
133 opt->defname),
134 parser_errposition(pstate, opt->location));
135 }
136
137 /*
138 * If a single relation is specified, process it and we're done ... unless
139 * the relation is a partitioned table, in which case we fall through.
140 */
141 if (stmt->relation != NULL)
142 {
143 rel = process_single_relation(stmt, &params);
144 if (rel == NULL)
145 return; /* all done */
146 }
147
148 /*
149 * Don't allow ANALYZE in the multiple-relation case for now. Maybe we
150 * can add support for this later.
151 */
152 if (params.options & CLUOPT_ANALYZE)
155 errmsg("cannot execute %s on multiple tables",
156 "REPACK (ANALYZE)"));
157
158 /*
159 * By here, we know we are in a multi-table situation. In order to avoid
160 * holding locks for too long, we want to process each table in its own
161 * transaction. This forces us to disallow running inside a user
162 * transaction block.
163 */
165
166 /* Also, we need a memory context to hold our list of relations */
168 "Repack",
170
171 params.options |= CLUOPT_RECHECK;
172
173 /*
174 * If we don't have a relation yet, determine a relation list. If we do,
175 * then it must be a partitioned table, and we want to process its
176 * partitions.
177 */
178 if (rel == NULL)
179 {
180 Assert(stmt->indexname == NULL);
181 rtcs = get_tables_to_repack(stmt->command, stmt->usingindex,
184 }
185 else
186 {
187 Oid relid;
188 bool rel_is_index;
189
190 Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
191
192 /*
193 * If USING INDEX was specified, resolve the index name now and pass
194 * it down.
195 */
196 if (stmt->usingindex)
197 {
198 /*
199 * If no index name was specified when repacking a partitioned
200 * table, punt for now. Maybe we can improve this later.
201 */
202 if (!stmt->indexname)
203 {
204 if (stmt->command == REPACK_COMMAND_CLUSTER)
207 errmsg("there is no previously clustered index for table \"%s\"",
209 else
212 /*- translator: first %s is name of a SQL command, eg. REPACK */
213 errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name",
214 RepackCommandAsString(stmt->command),
216 }
217
218 relid = determine_clustered_index(rel, stmt->usingindex,
219 stmt->indexname);
220 if (!OidIsValid(relid))
221 elog(ERROR, "unable to determine index to cluster on");
223
224 rel_is_index = true;
225 }
226 else
227 {
228 relid = RelationGetRelid(rel);
229 rel_is_index = false;
230 }
231
233 relid, rel_is_index,
235
236 /* close parent relation, releasing lock on it */
238 rel = NULL;
239 }
240
241 /* Commit to get out of starting transaction */
244
245 /* Cluster the tables, each in a separate transaction */
246 Assert(rel == NULL);
248 {
249 /* Start a new transaction for each relation. */
251
252 /*
253 * Open the target table, coping with the case where it has been
254 * dropped.
255 */
256 rel = try_table_open(rtc->tableOid, AccessExclusiveLock);
257 if (rel == NULL)
258 {
260 continue;
261 }
262
263 /* functions in indexes may want a snapshot set */
265
266 /* Process this table */
267 cluster_rel(stmt->command, rel, rtc->indexOid, &params);
268 /* cluster_rel closes the relation, but keeps lock */
269
272 }
273
274 /* Start a new transaction for the cleanup work. */
276
277 /* Clean up working storage */
279}
static Relation process_single_relation(RepackStmt *stmt, ClusterParams *params)
Definition cluster.c:1883
static List * get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid, bool rel_is_index, MemoryContext permcxt)
Definition cluster.c:1792
static List * get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
Definition cluster.c:1662
void cluster_rel(RepackCommand cmd, Relation OldHeap, Oid indexOid, ClusterParams *params)
Definition cluster.c:300
static Oid determine_clustered_index(Relation rel, bool usingindex, const char *indexname)
Definition cluster.c:1976
#define CLUOPT_ANALYZE
Definition cluster.h:26
#define CLUOPT_RECHECK_ISCLUSTERED
Definition cluster.h:25
bool defGetBoolean(DefElem *def)
Definition define.c:93
#define elog(elevel,...)
Definition elog.h:226
void MemoryContextDelete(MemoryContext context)
Definition mcxt.c:472
MemoryContext PortalContext
Definition mcxt.c:175
#define AllocSetContextCreate
Definition memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition memutils.h:160
int parser_errposition(ParseState *pstate, int location)
Definition parse_node.c:106
#define foreach_ptr(type, var, lst)
Definition pg_list.h:469
#define foreach_node(type, var, lst)
Definition pg_list.h:496
Snapshot GetTransactionSnapshot(void)
Definition snapmgr.c:272
void PushActiveSnapshot(Snapshot snapshot)
Definition snapmgr.c:682
void PopActiveSnapshot(void)
Definition snapmgr.c:775
Definition pg_list.h:54
Form_pg_class rd_rel
Definition rel.h:111
Relation try_table_open(Oid relationId, LOCKMODE lockmode)
Definition table.c:60
void table_close(Relation relation, LOCKMODE lockmode)
Definition table.c:126
void PreventInTransactionBlock(bool isTopLevel, const char *stmtType)
Definition xact.c:3670
void StartTransactionCommand(void)
Definition xact.c:3081
void CommitTransactionCommand(void)
Definition xact.c:3179

References AccessExclusiveLock, ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert, check_index_is_clusterable(), CLUOPT_ANALYZE, CLUOPT_RECHECK, CLUOPT_RECHECK_ISCLUSTERED, CLUOPT_VERBOSE, cluster_rel(), CommitTransactionCommand(), defGetBoolean(), determine_clustered_index(), elog, ereport, errcode(), errmsg, ERROR, fb(), foreach_node, foreach_ptr, get_tables_to_repack(), get_tables_to_repack_partitioned(), GetTransactionSnapshot(), MemoryContextDelete(), OidIsValid, ClusterParams::options, parser_errposition(), PopActiveSnapshot(), PortalContext, PreventInTransactionBlock(), process_single_relation(), PushActiveSnapshot(), RelationData::rd_rel, RelationGetRelationName, RelationGetRelid, REPACK_COMMAND_CLUSTER, RepackCommandAsString(), StartTransactionCommand(), stmt, table_close(), and try_table_open().

Referenced by standard_ProcessUtility().

◆ finish_heap_swap()

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 
)
extern

Definition at line 1459 of file cluster.c.

1467{
1468 ObjectAddress object;
1469 Oid mapped_tables[4];
1470 int reindex_flags;
1472 int i;
1473
1474 /* Report that we are now swapping relation files */
1477
1478 /* Zero out possible results from swapped_relation_files */
1479 memset(mapped_tables, 0, sizeof(mapped_tables));
1480
1481 /*
1482 * Swap the contents of the heap relations (including any toast tables).
1483 * Also set old heap's relfrozenxid to frozenXid.
1484 */
1487 swap_toast_by_content, is_internal,
1489
1490 /*
1491 * If it's a system catalog, queue a sinval message to flush all catcaches
1492 * on the catalog when we reach CommandCounterIncrement.
1493 */
1496
1497 /*
1498 * Rebuild each index on the relation (but not the toast table, which is
1499 * all-new at this point). It is important to do this before the DROP
1500 * step because if we are processing a system catalog that will be used
1501 * during DROP, we want to have its indexes available. There is no
1502 * advantage to the other order anyway because this is all transactional,
1503 * so no chance to reclaim disk space before commit. We do not need a
1504 * final CommandCounterIncrement() because reindex_relation does it.
1505 *
1506 * Note: because index_build is called via reindex_relation, it will never
1507 * set indcheckxmin true for the indexes. This is OK even though in some
1508 * sense we are building new indexes rather than rebuilding existing ones,
1509 * because the new heap won't contain any HOT chains at all, let alone
1510 * broken ones, so it can't be necessary to set indcheckxmin.
1511 */
1515
1516 /*
1517 * Ensure that the indexes have the same persistence as the parent
1518 * relation.
1519 */
1520 if (newrelpersistence == RELPERSISTENCE_UNLOGGED)
1522 else if (newrelpersistence == RELPERSISTENCE_PERMANENT)
1524
1525 /* Report that we are now reindexing relations */
1528
1530
1531 /* Report that we are now doing clean up */
1534
1535 /*
1536 * If the relation being rebuilt is pg_class, swap_relation_files()
1537 * couldn't update pg_class's own pg_class entry (check comments in
1538 * swap_relation_files()), thus relfrozenxid was not updated. That's
1539 * annoying because a potential reason for doing a VACUUM FULL is a
1540 * imminent or actual anti-wraparound shutdown. So, now that we can
1541 * access the new relation using its indices, update relfrozenxid.
1542 * pg_class doesn't have a toast relation, so we don't need to update the
1543 * corresponding toast relation. Not that there's little point moving all
1544 * relfrozenxid updates here since swap_relation_files() needs to write to
1545 * pg_class for non-mapped relations anyway.
1546 */
1548 {
1552
1554
1557 elog(ERROR, "cache lookup failed for relation %u", OIDOldHeap);
1559
1560 relform->relfrozenxid = frozenXid;
1561 relform->relminmxid = cutoffMulti;
1562
1564
1566 }
1567
1568 /* Destroy new heap with old filenumber */
1569 object.classId = RelationRelationId;
1570 object.objectId = OIDNewHeap;
1571 object.objectSubId = 0;
1572
1573 /*
1574 * The new relation is local to our transaction and we know nothing
1575 * depends on it, so DROP_RESTRICT should be OK.
1576 */
1578
1579 /* performDeletion does CommandCounterIncrement at end */
1580
1581 /*
1582 * Now we must remove any relation mapping entries that we set up for the
1583 * transient table, as well as its toast table and toast index if any. If
1584 * we fail to do this before commit, the relmapper will complain about new
1585 * permanent map entries being added post-bootstrap.
1586 */
1587 for (i = 0; OidIsValid(mapped_tables[i]); i++)
1589
1590 /*
1591 * At this point, everything is kosher except that, if we did toast swap
1592 * by links, the toast table's name corresponds to the transient table.
1593 * The name is irrelevant to the backend because it's referenced by OID,
1594 * but users looking at the catalogs could be confused. Rename it to
1595 * prevent this problem.
1596 *
1597 * Note no lock required on the relation, because we already hold an
1598 * exclusive lock on it.
1599 */
1601 {
1603
1605 if (OidIsValid(newrel->rd_rel->reltoastrelid))
1606 {
1607 Oid toastidx;
1609
1610 /* Get the associated valid index to be renamed */
1611 toastidx = toast_get_valid_index(newrel->rd_rel->reltoastrelid,
1612 NoLock);
1613
1614 /* rename the toast table ... */
1615 snprintf(NewToastName, NAMEDATALEN, "pg_toast_%u",
1616 OIDOldHeap);
1617 RenameRelationInternal(newrel->rd_rel->reltoastrelid,
1618 NewToastName, true, false);
1619
1620 /* ... and its valid index too. */
1621 snprintf(NewToastName, NAMEDATALEN, "pg_toast_%u_index",
1622 OIDOldHeap);
1623
1625 NewToastName, true, true);
1626
1627 /*
1628 * Reset the relrewrite for the toast. The command-counter
1629 * increment is required here as we are about to update the tuple
1630 * that is updated as part of RenameRelationInternal.
1631 */
1633 ResetRelRewrite(newrel->rd_rel->reltoastrelid);
1634 }
1636 }
1637
1638 /* if it's not a catalog table, clear any missing attribute settings */
1639 if (!is_system_catalog)
1640 {
1642
1646 }
1647}
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:1077
void performDeletion(const ObjectAddress *object, DropBehavior behavior, int flags)
Definition dependency.c:274
#define PERFORM_DELETION_INTERNAL
Definition dependency.h:92
void RelationClearMissing(Relation rel)
Definition heap.c:1964
#define HeapTupleIsValid(tuple)
Definition htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
bool reindex_relation(const ReindexStmt *stmt, Oid relid, int flags, const ReindexParams *params)
Definition index.c:3946
#define REINDEX_REL_FORCE_INDEXES_UNLOGGED
Definition index.h:162
#define REINDEX_REL_SUPPRESS_INDEX_USE
Definition index.h:160
#define REINDEX_REL_FORCE_INDEXES_PERMANENT
Definition index.h:163
#define REINDEX_REL_CHECK_CONSTRAINTS
Definition index.h:161
void CatalogTupleUpdate(Relation heapRel, const ItemPointerData *otid, HeapTuple tup)
Definition indexing.c:313
void CacheInvalidateCatalog(Oid catalogId)
Definition inval.c:1612
int i
Definition isn.c:77
#define RowExclusiveLock
Definition lockdefs.h:38
@ DROP_RESTRICT
FormData_pg_class * Form_pg_class
Definition pg_class.h:160
#define NAMEDATALEN
#define snprintf
Definition port.h:260
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:252
#define PROGRESS_REPACK_PHASE
Definition progress.h:86
#define PROGRESS_REPACK_PHASE_SWAP_REL_FILES
Definition progress.h:101
#define PROGRESS_REPACK_PHASE_FINAL_CLEANUP
Definition progress.h:103
#define PROGRESS_REPACK_PHASE_REBUILD_INDEX
Definition progress.h:102
void RelationMapRemoveMapping(Oid relationId)
Definition relmapper.c:439
#define SearchSysCacheCopy1(cacheId, key1)
Definition syscache.h:91
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition table.c:40
void ResetRelRewrite(Oid myrelid)
Definition tablecmds.c:4379
void RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, bool is_index)
Definition tablecmds.c:4286
Oid toast_get_valid_index(Oid toastoid, LOCKMODE lock)
void CommandCounterIncrement(void)
Definition xact.c:1102

References CacheInvalidateCatalog(), CatalogTupleUpdate(), CommandCounterIncrement(), DROP_RESTRICT, elog, ERROR, fb(), GETSTRUCT(), HeapTupleIsValid, i, NAMEDATALEN, NoLock, ObjectIdGetDatum(), OidIsValid, PERFORM_DELETION_INTERNAL, performDeletion(), pgstat_progress_update_param(), PROGRESS_REPACK_PHASE, PROGRESS_REPACK_PHASE_FINAL_CLEANUP, PROGRESS_REPACK_PHASE_REBUILD_INDEX, PROGRESS_REPACK_PHASE_SWAP_REL_FILES, REINDEX_REL_CHECK_CONSTRAINTS, REINDEX_REL_FORCE_INDEXES_PERMANENT, REINDEX_REL_FORCE_INDEXES_UNLOGGED, REINDEX_REL_SUPPRESS_INDEX_USE, reindex_relation(), relation_close(), RelationClearMissing(), RelationMapRemoveMapping(), RenameRelationInternal(), ResetRelRewrite(), RowExclusiveLock, SearchSysCacheCopy1, snprintf, swap_relation_files(), table_close(), table_open(), and toast_get_valid_index().

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

◆ make_new_heap()

Oid make_new_heap ( Oid  OIDOldHeap,
Oid  NewTableSpace,
Oid  NewAccessMethod,
char  relpersistence,
LOCKMODE  lockmode 
)
extern

Definition at line 719 of file cluster.c.

721{
725 Oid toastid;
727 HeapTuple tuple;
728 Datum reloptions;
729 bool isNull;
731
732 OldHeap = table_open(OIDOldHeap, lockmode);
734
735 /*
736 * Note that the NewHeap will not receive any of the defaults or
737 * constraints associated with the OldHeap; we don't need 'em, and there's
738 * no reason to spend cycles inserting them into the catalogs only to
739 * delete them.
740 */
741
742 /*
743 * But we do want to use reloptions of the old heap for new heap.
744 */
746 if (!HeapTupleIsValid(tuple))
747 elog(ERROR, "cache lookup failed for relation %u", OIDOldHeap);
749 &isNull);
750 if (isNull)
751 reloptions = (Datum) 0;
752
753 if (relpersistence == RELPERSISTENCE_TEMP)
755 else
757
758 /*
759 * Create the new heap, using a temporary name in the same namespace as
760 * the existing table. NOTE: there is some risk of collision with user
761 * relnames. Working around this seems more trouble than it's worth; in
762 * particular, we can't create the new heap in a different namespace from
763 * the old, or we will have problems with the TEMP status of temp tables.
764 *
765 * Note: the new heap is not a shared relation, even if we are rebuilding
766 * a shared rel. However, we do make the new heap mapped if the source is
767 * mapped. This simplifies swap_relation_files, and is absolutely
768 * necessary for rebuilding pg_class, for reasons explained there.
769 */
770 snprintf(NewHeapName, sizeof(NewHeapName), "pg_temp_%u", OIDOldHeap);
771
778 OldHeap->rd_rel->relowner,
781 NIL,
783 relpersistence,
784 false,
787 reloptions,
788 false,
789 true,
790 true,
792 NULL);
794
795 ReleaseSysCache(tuple);
796
797 /*
798 * Advance command counter so that the newly-created relation's catalog
799 * tuples will be visible to table_open.
800 */
802
803 /*
804 * If necessary, create a TOAST table for the new relation.
805 *
806 * If the relation doesn't have a TOAST table already, we can't need one
807 * for the new relation. The other way around is possible though: if some
808 * wide columns have been dropped, NewHeapCreateToastTable can decide that
809 * no TOAST table is needed for the new table.
810 *
811 * Note that NewHeapCreateToastTable ends with CommandCounterIncrement, so
812 * that the TOAST table will be visible for insertion.
813 */
814 toastid = OldHeap->rd_rel->reltoastrelid;
815 if (OidIsValid(toastid))
816 {
817 /* keep the existing toast table's reloptions, if any */
819 if (!HeapTupleIsValid(tuple))
820 elog(ERROR, "cache lookup failed for relation %u", toastid);
822 &isNull);
823 if (isNull)
824 reloptions = (Datum) 0;
825
826 NewHeapCreateToastTable(OIDNewHeap, reloptions, lockmode, toastid);
827
828 ReleaseSysCache(tuple);
829 }
830
832
833 return OIDNewHeap;
834}
Oid heap_create_with_catalog(const char *relname, Oid relnamespace, Oid reltablespace, Oid relid, Oid reltypeid, Oid reloftypeid, Oid ownerid, Oid accessmtd, TupleDesc tupdesc, List *cooked_constraints, char relkind, char relpersistence, bool shared_relation, bool mapped_relation, OnCommitAction oncommit, Datum reloptions, bool use_user_acl, bool allow_system_table_mods, bool is_internal, Oid relrewrite, ObjectAddress *typaddress)
Definition heap.c:1122
Oid LookupCreationNamespace(const char *nspname)
Definition namespace.c:3500
#define NIL
Definition pg_list.h:68
uint64_t Datum
Definition postgres.h:70
#define InvalidOid
@ ONCOMMIT_NOOP
Definition primnodes.h:59
#define RelationGetDescr(relation)
Definition rel.h:540
#define RelationIsMapped(relation)
Definition rel.h:563
#define RelationGetNamespace(relation)
Definition rel.h:555
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:264
HeapTuple SearchSysCache1(SysCacheIdentifier cacheId, Datum key1)
Definition syscache.c:220
Datum SysCacheGetAttr(SysCacheIdentifier cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition syscache.c:595
void NewHeapCreateToastTable(Oid relOid, Datum reloptions, LOCKMODE lockmode, Oid OIDOldToast)
Definition toasting.c:64

References Assert, CommandCounterIncrement(), elog, ERROR, fb(), heap_create_with_catalog(), HeapTupleIsValid, InvalidOid, LookupCreationNamespace(), NAMEDATALEN, NewHeapCreateToastTable(), NIL, NoLock, ObjectIdGetDatum(), OidIsValid, ONCOMMIT_NOOP, RelationGetDescr, RelationGetNamespace, RelationIsMapped, ReleaseSysCache(), SearchSysCache1(), snprintf, SysCacheGetAttr(), table_close(), and table_open().

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

◆ mark_index_clustered()

void mark_index_clustered ( Relation  rel,
Oid  indexOid,
bool  is_internal 
)
extern

Definition at line 568 of file cluster.c.

569{
574
575 /* Disallow applying to a partitioned table */
576 if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
579 errmsg("cannot mark index clustered in partitioned table")));
580
581 /*
582 * If the index is already marked clustered, no need to do anything.
583 */
584 if (OidIsValid(indexOid))
585 {
586 if (get_index_isclustered(indexOid))
587 return;
588 }
589
590 /*
591 * Check each index of the relation and set/clear the bit as needed.
592 */
594
595 foreach(index, RelationGetIndexList(rel))
596 {
598
602 elog(ERROR, "cache lookup failed for index %u", thisIndexOid);
604
605 /*
606 * Unset the bit if set. We know it's wrong because we checked this
607 * earlier.
608 */
609 if (indexForm->indisclustered)
610 {
611 indexForm->indisclustered = false;
613 }
614 else if (thisIndexOid == indexOid)
615 {
616 /* this was checked earlier, but let's be real sure */
617 if (!indexForm->indisvalid)
618 elog(ERROR, "cannot cluster on invalid index %u", indexOid);
619 indexForm->indisclustered = true;
621 }
622
624 InvalidOid, is_internal);
625
627 }
628
630}
void heap_freetuple(HeapTuple htup)
Definition heaptuple.c:1435
bool get_index_isclustered(Oid index_oid)
Definition lsyscache.c:3821
#define InvokeObjectPostAlterHookArg(classId, objectId, subId, auxiliaryId, is_internal)
END_CATALOG_STRUCT typedef FormData_pg_index * Form_pg_index
Definition pg_index.h:74
#define lfirst_oid(lc)
Definition pg_list.h:174
List * RelationGetIndexList(Relation relation)
Definition relcache.c:4831

References CatalogTupleUpdate(), elog, ereport, errcode(), errmsg, ERROR, fb(), Form_pg_index, get_index_isclustered(), GETSTRUCT(), heap_freetuple(), HeapTupleIsValid, InvalidOid, InvokeObjectPostAlterHookArg, lfirst_oid, ObjectIdGetDatum(), OidIsValid, RelationData::rd_rel, RelationGetIndexList(), RowExclusiveLock, SearchSysCacheCopy1, table_close(), and table_open().

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