49 #include "utils/fmgroids.h"
74 bool verbose,
bool *pSwapToastByContent,
118 foreach(lc,
stmt->params)
122 if (strcmp(opt->
defname,
"verbose") == 0)
126 (
errcode(ERRCODE_SYNTAX_ERROR),
127 errmsg(
"unrecognized CLUSTER option \"%s\"",
134 if (
stmt->relation != NULL)
157 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
158 errmsg(
"cannot cluster temporary tables of other sessions")));
160 if (
stmt->indexname == NULL)
175 (
errcode(ERRCODE_UNDEFINED_OBJECT),
176 errmsg(
"there is no previously clustered index for table \"%s\"",
177 stmt->relation->relname)));
186 rel->
rd_rel->relnamespace);
189 (
errcode(ERRCODE_UNDEFINED_OBJECT),
190 errmsg(
"index \"%s\" for table \"%s\" does not exist",
191 stmt->indexname,
stmt->relation->relname)));
194 if (rel->
rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
234 Assert(rel->
rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
314 int save_sec_context;
420 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
421 errmsg(
"cannot cluster a shared catalog")));
431 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
432 errmsg(
"cannot cluster temporary tables of other sessions")));
435 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
436 errmsg(
"cannot vacuum temporary tables of other sessions")));
456 if (OldHeap->
rd_rel->relkind == RELKIND_MATVIEW &&
464 OldHeap->
rd_rel->relkind == RELKIND_MATVIEW ||
465 OldHeap->
rd_rel->relkind == RELKIND_TOASTVALUE);
511 (
errcode(ERRCODE_WRONG_OBJECT_TYPE),
512 errmsg(
"\"%s\" is not an index for table \"%s\"",
519 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
520 errmsg(
"cannot cluster on index \"%s\" because access method does not support clustering",
531 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
532 errmsg(
"cannot cluster on partial index \"%s\"",
543 if (!OldIndex->
rd_index->indisvalid)
545 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
546 errmsg(
"cannot cluster on invalid index \"%s\"",
567 if (rel->
rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
569 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
570 errmsg(
"cannot mark index clustered in partitioned table")));
593 elog(
ERROR,
"cache lookup failed for index %u", thisIndexOid);
600 if (indexForm->indisclustered)
602 indexForm->indisclustered =
false;
605 else if (thisIndexOid == indexOid)
608 if (!indexForm->indisvalid)
609 elog(
ERROR,
"cannot cluster on invalid index %u", indexOid);
610 indexForm->indisclustered =
true;
635 Oid accessMethod = OldHeap->
rd_rel->relam;
636 Oid tableSpace = OldHeap->
rd_rel->reltablespace;
639 bool is_system_catalog;
640 bool swap_toast_by_content;
649 relpersistence = OldHeap->
rd_rel->relpersistence;
663 &swap_toast_by_content, &frozenXid, &cutoffMulti);
670 swap_toast_by_content,
false,
true,
671 frozenXid, cutoffMulti,
688 char relpersistence,
LOCKMODE lockmode)
715 elog(
ERROR,
"cache lookup failed for relation %u", OIDOldHeap);
719 reloptions = (
Datum) 0;
721 if (relpersistence == RELPERSISTENCE_TEMP)
738 snprintf(NewHeapName,
sizeof(NewHeapName),
"pg_temp_%u", OIDOldHeap);
746 OldHeap->
rd_rel->relowner,
782 toastid = OldHeap->
rd_rel->reltoastrelid;
788 elog(
ERROR,
"cache lookup failed for relation %u", toastid);
792 reloptions = (
Datum) 0;
828 double num_tuples = 0,
830 tups_recently_dead = 0;
857 Assert(newTupDesc->natts == oldTupDesc->natts);
872 if (OldHeap->
rd_rel->reltoastrelid)
882 if (OldHeap->
rd_rel->reltoastrelid && NewHeap->
rd_rel->reltoastrelid)
884 *pSwapToastByContent =
true;
907 *pSwapToastByContent =
false;
947 if (OldIndex != NULL && OldIndex->
rd_rel->relam == BTREE_AM_OID)
953 if (OldIndex != NULL && !use_sort)
955 (
errmsg(
"clustering \"%s.%s\" using index scan on \"%s\"",
961 (
errmsg(
"clustering \"%s.%s\" using sequential scan and sort",
966 (
errmsg(
"vacuuming \"%s.%s\"",
979 &num_tuples, &tups_vacuumed,
980 &tups_recently_dead);
993 (
errmsg(
"\"%s.%s\": found %.0f removable, %.0f nonremovable row versions in %u pages",
996 tups_vacuumed, num_tuples,
998 errdetail(
"%.0f dead row versions cannot be removed yet.\n"
1003 if (OldIndex != NULL)
1013 elog(
ERROR,
"cache lookup failed for relation %u", OIDNewHeap);
1016 relform->relpages = num_pages;
1017 relform->reltuples = num_tuples;
1020 if (OIDOldHeap != RelationRelationId)
1061 bool swap_toast_by_content,
1084 elog(
ERROR,
"cache lookup failed for relation %u", r1);
1089 elog(
ERROR,
"cache lookup failed for relation %u", r2);
1092 relfilenumber1 = relform1->relfilenode;
1093 relfilenumber2 = relform2->relfilenode;
1094 relam1 = relform1->relam;
1095 relam2 = relform2->relam;
1104 Assert(!target_is_pg_class);
1106 swaptemp = relform1->relfilenode;
1107 relform1->relfilenode = relform2->relfilenode;
1108 relform2->relfilenode = swaptemp;
1110 swaptemp = relform1->reltablespace;
1111 relform1->reltablespace = relform2->reltablespace;
1112 relform2->reltablespace = swaptemp;
1114 swaptemp = relform1->relam;
1115 relform1->relam = relform2->relam;
1116 relform2->relam = swaptemp;
1118 swptmpchr = relform1->relpersistence;
1119 relform1->relpersistence = relform2->relpersistence;
1120 relform2->relpersistence = swptmpchr;
1123 if (!swap_toast_by_content)
1125 swaptemp = relform1->reltoastrelid;
1126 relform1->reltoastrelid = relform2->reltoastrelid;
1127 relform2->reltoastrelid = swaptemp;
1138 elog(
ERROR,
"cannot swap mapped relation \"%s\" with non-mapped relation",
1148 if (relform1->reltablespace != relform2->reltablespace)
1149 elog(
ERROR,
"cannot change tablespace of mapped relation \"%s\"",
1151 if (relform1->relpersistence != relform2->relpersistence)
1152 elog(
ERROR,
"cannot change persistence of mapped relation \"%s\"",
1154 if (relform1->relam != relform2->relam)
1155 elog(
ERROR,
"cannot change access method of mapped relation \"%s\"",
1157 if (!swap_toast_by_content &&
1158 (relform1->reltoastrelid || relform2->reltoastrelid))
1159 elog(
ERROR,
"cannot swap toast by links for mapped relation \"%s\"",
1167 elog(
ERROR,
"could not find relation mapping for relation \"%s\", OID %u",
1168 NameStr(relform1->relname), r1);
1171 elog(
ERROR,
"could not find relation mapping for relation \"%s\", OID %u",
1172 NameStr(relform2->relname), r2);
1182 *mapped_tables++ = r2;
1213 if (relform1->relkind != RELKIND_INDEX)
1217 relform1->relfrozenxid = frozenXid;
1218 relform1->relminmxid = cutoffMulti;
1225 int32 swap_allvisible;
1227 swap_pages = relform1->relpages;
1228 relform1->relpages = relform2->relpages;
1229 relform2->relpages = swap_pages;
1231 swap_tuples = relform1->reltuples;
1232 relform1->reltuples = relform2->reltuples;
1233 relform2->reltuples = swap_tuples;
1235 swap_allvisible = relform1->relallvisible;
1236 relform1->relallvisible = relform2->relallvisible;
1237 relform2->relallvisible = swap_allvisible;
1249 if (!target_is_pg_class)
1272 if (relam1 != relam2)
1276 AccessMethodRelationId,
1279 elog(
ERROR,
"could not change access method dependency for relation \"%s.%s\"",
1284 AccessMethodRelationId,
1287 elog(
ERROR,
"could not change access method dependency for relation \"%s.%s\"",
1305 if (relform1->reltoastrelid || relform2->reltoastrelid)
1307 if (swap_toast_by_content)
1309 if (relform1->reltoastrelid && relform2->reltoastrelid)
1313 relform2->reltoastrelid,
1315 swap_toast_by_content,
1324 elog(
ERROR,
"cannot swap toast files by content when there's only one");
1351 elog(
ERROR,
"cannot swap toast files by links for system catalogs");
1354 if (relform1->reltoastrelid)
1357 relform1->reltoastrelid,
1360 elog(
ERROR,
"expected one dependency record for TOAST table, found %ld",
1363 if (relform2->reltoastrelid)
1366 relform2->reltoastrelid,
1369 elog(
ERROR,
"expected one dependency record for TOAST table, found %ld",
1374 baseobject.
classId = RelationRelationId;
1376 toastobject.
classId = RelationRelationId;
1379 if (relform1->reltoastrelid)
1382 toastobject.
objectId = relform1->reltoastrelid;
1387 if (relform2->reltoastrelid)
1390 toastobject.
objectId = relform2->reltoastrelid;
1402 if (swap_toast_by_content &&
1403 relform1->relkind == RELKIND_TOASTVALUE &&
1404 relform2->relkind == RELKIND_TOASTVALUE)
1418 swap_toast_by_content,
1438 bool is_system_catalog,
1439 bool swap_toast_by_content,
1440 bool check_constraints,
1444 char newrelpersistence)
1447 Oid mapped_tables[4];
1457 memset(mapped_tables, 0,
sizeof(mapped_tables));
1464 (OIDOldHeap == RelationRelationId),
1465 swap_toast_by_content, is_internal,
1466 frozenXid, cutoffMulti, mapped_tables);
1472 if (is_system_catalog)
1491 if (check_constraints)
1498 if (newrelpersistence == RELPERSISTENCE_UNLOGGED)
1500 else if (newrelpersistence == RELPERSISTENCE_PERMANENT)
1525 if (OIDOldHeap == RelationRelationId)
1535 elog(
ERROR,
"cache lookup failed for relation %u", OIDOldHeap);
1538 relform->relfrozenxid = frozenXid;
1539 relform->relminmxid = cutoffMulti;
1547 object.classId = RelationRelationId;
1548 object.objectId = OIDNewHeap;
1549 object.objectSubId = 0;
1578 if (!swap_toast_by_content)
1596 NewToastName,
true,
false);
1603 NewToastName,
true,
true);
1617 if (!is_system_catalog)
1651 Anum_pg_index_indisclustered,
1699 foreach(lc, inhoids)
1743 (
errmsg(
"permission denied to cluster \"%s\", skipping it",
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
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_CLUSTER
#define RelationGetNumberOfBlocks(reln)
#define PG_USED_FOR_ASSERTS_ONLY
#define Assert(condition)
TransactionId MultiXactId
#define OidIsValid(objectId)
bool IsSystemRelation(Relation relation)
bool IsSystemClass(Oid relid, Form_pg_class reltuple)
void cluster_rel(Oid tableOid, Oid indexOid, ClusterParams *params)
void check_index_is_clusterable(Relation OldHeap, Oid indexOid, 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)
static List * get_tables_to_cluster(MemoryContext cluster_context)
static List * get_tables_to_cluster_partitioned(MemoryContext cluster_context, Oid indexOid)
static void rebuild_relation(Relation OldHeap, Oid indexOid, bool verbose)
static bool cluster_is_permitted_for_relation(Oid relid, Oid userid)
static void copy_table_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex, bool verbose, bool *pSwapToastByContent, TransactionId *pFreezeXid, MultiXactId *pCutoffMulti)
static void cluster_multiple_rels(List *rtcs, ClusterParams *params)
Oid make_new_heap(Oid OIDOldHeap, Oid NewTableSpace, Oid NewAccessMethod, char relpersistence, LOCKMODE lockmode)
void cluster(ParseState *pstate, ClusterStmt *stmt, bool isTopLevel)
void mark_index_clustered(Relation rel, Oid indexOid, bool is_internal)
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)
#define CLUOPT_RECHECK_ISCLUSTERED
bool defGetBoolean(DefElem *def)
void performDeletion(const ObjectAddress *object, DropBehavior behavior, int flags)
#define PERFORM_DELETION_INTERNAL
int errdetail(const char *fmt,...)
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
int NewGUCNestLevel(void)
void RestrictSearchPath(void)
void AtEOXact_GUC(bool isCommit, int nestLevel)
void RelationClearMissing(Relation rel)
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)
HeapTuple heap_getnext(TableScanDesc sscan, ScanDirection direction)
bool heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
void heap_freetuple(HeapTuple htup)
#define HeapTupleIsValid(tuple)
Oid IndexGetRelation(Oid indexId, bool missing_ok)
bool reindex_relation(const ReindexStmt *stmt, Oid relid, int flags, const ReindexParams *params)
#define REINDEX_REL_FORCE_INDEXES_UNLOGGED
#define REINDEX_REL_SUPPRESS_INDEX_USE
#define REINDEX_REL_FORCE_INDEXES_PERMANENT
#define REINDEX_REL_CHECK_CONSTRAINTS
void index_close(Relation relation, LOCKMODE lockmode)
Relation index_open(Oid relationId, LOCKMODE lockmode)
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
void CatalogCloseIndexes(CatalogIndexState indstate)
CatalogIndexState CatalogOpenIndexes(Relation heapRel)
void CatalogTupleUpdateWithInfo(Relation heapRel, ItemPointer otid, HeapTuple tup, CatalogIndexState indstate)
void CacheInvalidateCatalog(Oid catalogId)
void CacheInvalidateRelcacheByTuple(HeapTuple classTuple)
List * lappend(List *list, void *datum)
void LockRelationOid(Oid relid, LOCKMODE lockmode)
#define AccessExclusiveLock
char * get_namespace_name(Oid nspid)
char get_rel_relkind(Oid relid)
Oid get_rel_namespace(Oid relid)
char * get_rel_name(Oid relid)
bool get_index_isclustered(Oid index_oid)
Oid get_relname_relid(const char *relname, Oid relnamespace)
void MemoryContextDelete(MemoryContext context)
MemoryContext PortalContext
#define AllocSetContextCreate
#define ALLOCSET_DEFAULT_SIZES
#define SECURITY_RESTRICTED_OPERATION
#define CHECK_FOR_INTERRUPTS()
void GetUserIdAndSecContext(Oid *userid, int *sec_context)
void SetUserIdAndSecContext(Oid userid, int sec_context)
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
#define MultiXactIdIsValid(multi)
#define InvalidMultiXactId
Oid LookupCreationNamespace(const char *nspname)
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
#define InvokeObjectPostAlterHookArg(classId, objectId, subId, auxiliaryId, is_internal)
int parser_errposition(ParseState *pstate, int location)
FormData_pg_class * Form_pg_class
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
long deleteDependencyRecordsFor(Oid classId, Oid objectId, bool skipExtensionDeps)
FormData_pg_index * Form_pg_index
List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
const char * pg_rusage_show(const PGRUsage *ru0)
void pg_rusage_init(PGRUsage *ru0)
bool plan_cluster_use_sort(Oid tableOid, Oid indexOid)
static Datum BoolGetDatum(bool X)
static Datum ObjectIdGetDatum(Oid X)
void TransferPredicateLocksToHeapRelation(Relation relation)
#define PROGRESS_CLUSTER_PHASE
#define PROGRESS_CLUSTER_COMMAND_VACUUM_FULL
#define PROGRESS_CLUSTER_PHASE_REBUILD_INDEX
#define PROGRESS_CLUSTER_COMMAND_CLUSTER
#define PROGRESS_CLUSTER_PHASE_FINAL_CLEANUP
#define PROGRESS_CLUSTER_COMMAND
#define PROGRESS_CLUSTER_PHASE_SWAP_REL_FILES
MemoryContextSwitchTo(old_ctx)
#define RelationGetRelid(relation)
#define RelationGetDescr(relation)
#define RelationIsMapped(relation)
#define RelationGetRelationName(relation)
#define RelationIsPopulated(relation)
#define RELATION_IS_OTHER_TEMP(relation)
#define RelationGetNamespace(relation)
List * RelationGetIndexList(Relation relation)
void RelationAssumeNewRelfilelocator(Relation relation)
void RelationMapRemoveMapping(Oid relationId)
RelFileNumber RelationMapOidToFilenumber(Oid relationId, bool shared)
void RelationMapUpdateMap(Oid relationId, RelFileNumber fileNumber, bool shared, bool immediate)
#define RelFileNumberIsValid(relnumber)
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Snapshot GetTransactionSnapshot(void)
void PushActiveSnapshot(Snapshot snapshot)
void PopActiveSnapshot(void)
void relation_close(Relation relation, LOCKMODE lockmode)
Relation try_relation_open(Oid relationId, LOCKMODE lockmode)
Relation relation_open(Oid relationId, LOCKMODE lockmode)
#define BTEqualStrategyNumber
struct IndexAmRoutine * rd_indam
SubTransactionId rd_firstRelfilelocatorSubid
struct HeapTupleData * rd_indextuple
SubTransactionId rd_newRelfilelocatorSubid
SubTransactionId rd_createSubid
TransactionId FreezeLimit
TransactionId relfrozenxid
MultiXactId MultiXactCutoff
void ReleaseSysCache(HeapTuple tuple)
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
#define SearchSysCacheCopy1(cacheId, key1)
#define SearchSysCacheExists1(cacheId, key1)
void table_close(Relation relation, LOCKMODE lockmode)
Relation table_open(Oid relationId, LOCKMODE lockmode)
TableScanDesc table_beginscan_catalog(Relation relation, int nkeys, struct ScanKeyData *key)
static void table_endscan(TableScanDesc scan)
static void table_relation_copy_for_cluster(Relation OldTable, Relation NewTable, Relation OldIndex, bool use_sort, TransactionId OldestXmin, TransactionId *xid_cutoff, MultiXactId *multi_cutoff, double *num_tuples, double *tups_vacuumed, double *tups_recently_dead)
void ResetRelRewrite(Oid myrelid)
void CheckTableNotInUse(Relation rel, const char *stmt)
void RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, bool is_index)
void RangeVarCallbackMaintainsTable(const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
Oid toast_get_valid_index(Oid toastoid, LOCKMODE lock)
void NewHeapCreateToastTable(Oid relOid, Datum reloptions, LOCKMODE lockmode, Oid OIDOldToast)
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
#define InvalidTransactionId
#define TransactionIdIsValid(xid)
#define TransactionIdIsNormal(xid)
bool vacuum_get_cutoffs(Relation rel, const VacuumParams *params, struct VacuumCutoffs *cutoffs)
void CommandCounterIncrement(void)
void PreventInTransactionBlock(bool isTopLevel, const char *stmtType)
void StartTransactionCommand(void)
void CommitTransactionCommand(void)