PostgreSQL Source Code git master
Loading...
Searching...
No Matches
cluster.h File Reference
#include "nodes/parsenodes.h"
#include "parser/parse_node.h"
#include "storage/lockdefs.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:748
uint32 bits32
Definition c.h:627
uint32 TransactionId
Definition c.h:738
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:1455
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:715
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:178
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition indexam.c:134
#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:945
#define OidIsValid(objectId)
Definition c.h:860
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:2015
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:639
#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:2142
void RestrictSearchPath(void)
Definition guc.c:2153
void AtEOXact_GUC(bool isCommit, int nestLevel)
Definition guc.c:2169
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:3132
#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:206
bits32 options
Definition cluster.h:31
Definition type.h:96
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition tablecmds.c:4447

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:1879
static List * get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid, bool rel_is_index, MemoryContext permcxt)
Definition cluster.c:1788
static List * get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
Definition cluster.c:1658
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:1972
#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 1455 of file cluster.c.

1463{
1464 ObjectAddress object;
1465 Oid mapped_tables[4];
1466 int reindex_flags;
1468 int i;
1469
1470 /* Report that we are now swapping relation files */
1473
1474 /* Zero out possible results from swapped_relation_files */
1475 memset(mapped_tables, 0, sizeof(mapped_tables));
1476
1477 /*
1478 * Swap the contents of the heap relations (including any toast tables).
1479 * Also set old heap's relfrozenxid to frozenXid.
1480 */
1483 swap_toast_by_content, is_internal,
1485
1486 /*
1487 * If it's a system catalog, queue a sinval message to flush all catcaches
1488 * on the catalog when we reach CommandCounterIncrement.
1489 */
1492
1493 /*
1494 * Rebuild each index on the relation (but not the toast table, which is
1495 * all-new at this point). It is important to do this before the DROP
1496 * step because if we are processing a system catalog that will be used
1497 * during DROP, we want to have its indexes available. There is no
1498 * advantage to the other order anyway because this is all transactional,
1499 * so no chance to reclaim disk space before commit. We do not need a
1500 * final CommandCounterIncrement() because reindex_relation does it.
1501 *
1502 * Note: because index_build is called via reindex_relation, it will never
1503 * set indcheckxmin true for the indexes. This is OK even though in some
1504 * sense we are building new indexes rather than rebuilding existing ones,
1505 * because the new heap won't contain any HOT chains at all, let alone
1506 * broken ones, so it can't be necessary to set indcheckxmin.
1507 */
1511
1512 /*
1513 * Ensure that the indexes have the same persistence as the parent
1514 * relation.
1515 */
1516 if (newrelpersistence == RELPERSISTENCE_UNLOGGED)
1518 else if (newrelpersistence == RELPERSISTENCE_PERMANENT)
1520
1521 /* Report that we are now reindexing relations */
1524
1526
1527 /* Report that we are now doing clean up */
1530
1531 /*
1532 * If the relation being rebuilt is pg_class, swap_relation_files()
1533 * couldn't update pg_class's own pg_class entry (check comments in
1534 * swap_relation_files()), thus relfrozenxid was not updated. That's
1535 * annoying because a potential reason for doing a VACUUM FULL is a
1536 * imminent or actual anti-wraparound shutdown. So, now that we can
1537 * access the new relation using its indices, update relfrozenxid.
1538 * pg_class doesn't have a toast relation, so we don't need to update the
1539 * corresponding toast relation. Not that there's little point moving all
1540 * relfrozenxid updates here since swap_relation_files() needs to write to
1541 * pg_class for non-mapped relations anyway.
1542 */
1544 {
1548
1550
1553 elog(ERROR, "cache lookup failed for relation %u", OIDOldHeap);
1555
1556 relform->relfrozenxid = frozenXid;
1557 relform->relminmxid = cutoffMulti;
1558
1560
1562 }
1563
1564 /* Destroy new heap with old filenumber */
1565 object.classId = RelationRelationId;
1566 object.objectId = OIDNewHeap;
1567 object.objectSubId = 0;
1568
1569 /*
1570 * The new relation is local to our transaction and we know nothing
1571 * depends on it, so DROP_RESTRICT should be OK.
1572 */
1574
1575 /* performDeletion does CommandCounterIncrement at end */
1576
1577 /*
1578 * Now we must remove any relation mapping entries that we set up for the
1579 * transient table, as well as its toast table and toast index if any. If
1580 * we fail to do this before commit, the relmapper will complain about new
1581 * permanent map entries being added post-bootstrap.
1582 */
1583 for (i = 0; OidIsValid(mapped_tables[i]); i++)
1585
1586 /*
1587 * At this point, everything is kosher except that, if we did toast swap
1588 * by links, the toast table's name corresponds to the transient table.
1589 * The name is irrelevant to the backend because it's referenced by OID,
1590 * but users looking at the catalogs could be confused. Rename it to
1591 * prevent this problem.
1592 *
1593 * Note no lock required on the relation, because we already hold an
1594 * exclusive lock on it.
1595 */
1597 {
1599
1601 if (OidIsValid(newrel->rd_rel->reltoastrelid))
1602 {
1603 Oid toastidx;
1605
1606 /* Get the associated valid index to be renamed */
1607 toastidx = toast_get_valid_index(newrel->rd_rel->reltoastrelid,
1608 NoLock);
1609
1610 /* rename the toast table ... */
1611 snprintf(NewToastName, NAMEDATALEN, "pg_toast_%u",
1612 OIDOldHeap);
1613 RenameRelationInternal(newrel->rd_rel->reltoastrelid,
1614 NewToastName, true, false);
1615
1616 /* ... and its valid index too. */
1617 snprintf(NewToastName, NAMEDATALEN, "pg_toast_%u_index",
1618 OIDOldHeap);
1619
1621 NewToastName, true, true);
1622
1623 /*
1624 * Reset the relrewrite for the toast. The command-counter
1625 * increment is required here as we are about to update the tuple
1626 * that is updated as part of RenameRelationInternal.
1627 */
1629 ResetRelRewrite(newrel->rd_rel->reltoastrelid);
1630 }
1632 }
1633
1634 /* if it's not a catalog table, clear any missing attribute settings */
1635 if (!is_system_catalog)
1636 {
1638
1642 }
1643}
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:1073
void performDeletion(const ObjectAddress *object, DropBehavior behavior, int flags)
Definition dependency.c:279
#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:3949
#define REINDEX_REL_FORCE_INDEXES_UNLOGGED
Definition index.h:168
#define REINDEX_REL_SUPPRESS_INDEX_USE
Definition index.h:166
#define REINDEX_REL_FORCE_INDEXES_PERMANENT
Definition index.h:169
#define REINDEX_REL_CHECK_CONSTRAINTS
Definition index.h:167
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:4394
void RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, bool is_index)
Definition tablecmds.c:4301
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 715 of file cluster.c.

717{
721 Oid toastid;
723 HeapTuple tuple;
724 Datum reloptions;
725 bool isNull;
727
728 OldHeap = table_open(OIDOldHeap, lockmode);
730
731 /*
732 * Note that the NewHeap will not receive any of the defaults or
733 * constraints associated with the OldHeap; we don't need 'em, and there's
734 * no reason to spend cycles inserting them into the catalogs only to
735 * delete them.
736 */
737
738 /*
739 * But we do want to use reloptions of the old heap for new heap.
740 */
742 if (!HeapTupleIsValid(tuple))
743 elog(ERROR, "cache lookup failed for relation %u", OIDOldHeap);
745 &isNull);
746 if (isNull)
747 reloptions = (Datum) 0;
748
749 if (relpersistence == RELPERSISTENCE_TEMP)
751 else
753
754 /*
755 * Create the new heap, using a temporary name in the same namespace as
756 * the existing table. NOTE: there is some risk of collision with user
757 * relnames. Working around this seems more trouble than it's worth; in
758 * particular, we can't create the new heap in a different namespace from
759 * the old, or we will have problems with the TEMP status of temp tables.
760 *
761 * Note: the new heap is not a shared relation, even if we are rebuilding
762 * a shared rel. However, we do make the new heap mapped if the source is
763 * mapped. This simplifies swap_relation_files, and is absolutely
764 * necessary for rebuilding pg_class, for reasons explained there.
765 */
766 snprintf(NewHeapName, sizeof(NewHeapName), "pg_temp_%u", OIDOldHeap);
767
774 OldHeap->rd_rel->relowner,
777 NIL,
779 relpersistence,
780 false,
783 reloptions,
784 false,
785 true,
786 true,
788 NULL);
790
791 ReleaseSysCache(tuple);
792
793 /*
794 * Advance command counter so that the newly-created relation's catalog
795 * tuples will be visible to table_open.
796 */
798
799 /*
800 * If necessary, create a TOAST table for the new relation.
801 *
802 * If the relation doesn't have a TOAST table already, we can't need one
803 * for the new relation. The other way around is possible though: if some
804 * wide columns have been dropped, NewHeapCreateToastTable can decide that
805 * no TOAST table is needed for the new table.
806 *
807 * Note that NewHeapCreateToastTable ends with CommandCounterIncrement, so
808 * that the TOAST table will be visible for insertion.
809 */
810 toastid = OldHeap->rd_rel->reltoastrelid;
811 if (OidIsValid(toastid))
812 {
813 /* keep the existing toast table's reloptions, if any */
815 if (!HeapTupleIsValid(tuple))
816 elog(ERROR, "cache lookup failed for relation %u", toastid);
818 &isNull);
819 if (isNull)
820 reloptions = (Datum) 0;
821
822 NewHeapCreateToastTable(OIDNewHeap, reloptions, lockmode, toastid);
823
824 ReleaseSysCache(tuple);
825 }
826
828
829 return OIDNewHeap;
830}
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:265
HeapTuple SearchSysCache1(SysCacheIdentifier cacheId, Datum key1)
Definition syscache.c:221
Datum SysCacheGetAttr(SysCacheIdentifier cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition syscache.c:596
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 Assert(rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE);
576
577 /*
578 * If the index is already marked clustered, no need to do anything.
579 */
580 if (OidIsValid(indexOid))
581 {
582 if (get_index_isclustered(indexOid))
583 return;
584 }
585
586 /*
587 * Check each index of the relation and set/clear the bit as needed.
588 */
590
591 foreach(index, RelationGetIndexList(rel))
592 {
594
598 elog(ERROR, "cache lookup failed for index %u", thisIndexOid);
600
601 /*
602 * Unset the bit if set. We know it's wrong because we checked this
603 * earlier.
604 */
605 if (indexForm->indisclustered)
606 {
607 indexForm->indisclustered = false;
609 }
610 else if (thisIndexOid == indexOid)
611 {
612 /* this was checked earlier, but let's be real sure */
613 if (!indexForm->indisvalid)
614 elog(ERROR, "cannot cluster on invalid index %u", indexOid);
615 indexForm->indisclustered = true;
617 }
618
620 InvalidOid, is_internal);
621
623 }
624
626}
void heap_freetuple(HeapTuple htup)
Definition heaptuple.c:1384
bool get_index_isclustered(Oid index_oid)
Definition lsyscache.c:3823
#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:4827

References Assert, CatalogTupleUpdate(), elog, 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().