50 #include "utils/fmgroids.h"
75 bool verbose,
bool *pSwapToastByContent,
119 foreach(lc,
stmt->params)
123 if (strcmp(opt->
defname,
"verbose") == 0)
127 (
errcode(ERRCODE_SYNTAX_ERROR),
128 errmsg(
"unrecognized CLUSTER option \"%s\"",
135 if (
stmt->relation != NULL)
158 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
159 errmsg(
"cannot cluster temporary tables of other sessions")));
161 if (
stmt->indexname == NULL)
176 (
errcode(ERRCODE_UNDEFINED_OBJECT),
177 errmsg(
"there is no previously clustered index for table \"%s\"",
178 stmt->relation->relname)));
187 rel->
rd_rel->relnamespace);
190 (
errcode(ERRCODE_UNDEFINED_OBJECT),
191 errmsg(
"index \"%s\" for table \"%s\" does not exist",
192 stmt->indexname,
stmt->relation->relname)));
195 if (rel->
rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
235 Assert(rel->
rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
315 int save_sec_context;
421 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
422 errmsg(
"cannot cluster a shared catalog")));
432 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
433 errmsg(
"cannot cluster temporary tables of other sessions")));
436 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
437 errmsg(
"cannot vacuum temporary tables of other sessions")));
457 if (OldHeap->
rd_rel->relkind == RELKIND_MATVIEW &&
465 OldHeap->
rd_rel->relkind == RELKIND_MATVIEW ||
466 OldHeap->
rd_rel->relkind == RELKIND_TOASTVALUE);
512 (
errcode(ERRCODE_WRONG_OBJECT_TYPE),
513 errmsg(
"\"%s\" is not an index for table \"%s\"",
520 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
521 errmsg(
"cannot cluster on index \"%s\" because access method does not support clustering",
532 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
533 errmsg(
"cannot cluster on partial index \"%s\"",
544 if (!OldIndex->
rd_index->indisvalid)
546 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
547 errmsg(
"cannot cluster on invalid index \"%s\"",
568 if (rel->
rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
570 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
571 errmsg(
"cannot mark index clustered in partitioned table")));
594 elog(
ERROR,
"cache lookup failed for index %u", thisIndexOid);
601 if (indexForm->indisclustered)
603 indexForm->indisclustered =
false;
606 else if (thisIndexOid == indexOid)
609 if (!indexForm->indisvalid)
610 elog(
ERROR,
"cannot cluster on invalid index %u", indexOid);
611 indexForm->indisclustered =
true;
636 Oid accessMethod = OldHeap->
rd_rel->relam;
637 Oid tableSpace = OldHeap->
rd_rel->reltablespace;
640 bool is_system_catalog;
641 bool swap_toast_by_content;
650 relpersistence = OldHeap->
rd_rel->relpersistence;
664 &swap_toast_by_content, &frozenXid, &cutoffMulti);
671 swap_toast_by_content,
false,
true,
672 frozenXid, cutoffMulti,
689 char relpersistence,
LOCKMODE lockmode)
716 elog(
ERROR,
"cache lookup failed for relation %u", OIDOldHeap);
720 reloptions = (
Datum) 0;
722 if (relpersistence == RELPERSISTENCE_TEMP)
739 snprintf(NewHeapName,
sizeof(NewHeapName),
"pg_temp_%u", OIDOldHeap);
747 OldHeap->
rd_rel->relowner,
783 toastid = OldHeap->
rd_rel->reltoastrelid;
789 elog(
ERROR,
"cache lookup failed for relation %u", toastid);
793 reloptions = (
Datum) 0;
829 double num_tuples = 0,
831 tups_recently_dead = 0;
858 Assert(newTupDesc->natts == oldTupDesc->natts);
873 if (OldHeap->
rd_rel->reltoastrelid)
883 if (OldHeap->
rd_rel->reltoastrelid && NewHeap->
rd_rel->reltoastrelid)
885 *pSwapToastByContent =
true;
908 *pSwapToastByContent =
false;
948 if (OldIndex != NULL && OldIndex->
rd_rel->relam == BTREE_AM_OID)
954 if (OldIndex != NULL && !use_sort)
956 (
errmsg(
"clustering \"%s.%s\" using index scan on \"%s\"",
962 (
errmsg(
"clustering \"%s.%s\" using sequential scan and sort",
967 (
errmsg(
"vacuuming \"%s.%s\"",
980 &num_tuples, &tups_vacuumed,
981 &tups_recently_dead);
994 (
errmsg(
"\"%s.%s\": found %.0f removable, %.0f nonremovable row versions in %u pages",
997 tups_vacuumed, num_tuples,
999 errdetail(
"%.0f dead row versions cannot be removed yet.\n"
1004 if (OldIndex != NULL)
1014 elog(
ERROR,
"cache lookup failed for relation %u", OIDNewHeap);
1017 relform->relpages = num_pages;
1018 relform->reltuples = num_tuples;
1021 if (OIDOldHeap != RelationRelationId)
1062 bool swap_toast_by_content,
1085 elog(
ERROR,
"cache lookup failed for relation %u", r1);
1090 elog(
ERROR,
"cache lookup failed for relation %u", r2);
1093 relfilenumber1 = relform1->relfilenode;
1094 relfilenumber2 = relform2->relfilenode;
1095 relam1 = relform1->relam;
1096 relam2 = relform2->relam;
1105 Assert(!target_is_pg_class);
1107 swaptemp = relform1->relfilenode;
1108 relform1->relfilenode = relform2->relfilenode;
1109 relform2->relfilenode = swaptemp;
1111 swaptemp = relform1->reltablespace;
1112 relform1->reltablespace = relform2->reltablespace;
1113 relform2->reltablespace = swaptemp;
1115 swaptemp = relform1->relam;
1116 relform1->relam = relform2->relam;
1117 relform2->relam = swaptemp;
1119 swptmpchr = relform1->relpersistence;
1120 relform1->relpersistence = relform2->relpersistence;
1121 relform2->relpersistence = swptmpchr;
1124 if (!swap_toast_by_content)
1126 swaptemp = relform1->reltoastrelid;
1127 relform1->reltoastrelid = relform2->reltoastrelid;
1128 relform2->reltoastrelid = swaptemp;
1139 elog(
ERROR,
"cannot swap mapped relation \"%s\" with non-mapped relation",
1149 if (relform1->reltablespace != relform2->reltablespace)
1150 elog(
ERROR,
"cannot change tablespace of mapped relation \"%s\"",
1152 if (relform1->relpersistence != relform2->relpersistence)
1153 elog(
ERROR,
"cannot change persistence of mapped relation \"%s\"",
1155 if (relform1->relam != relform2->relam)
1156 elog(
ERROR,
"cannot change access method of mapped relation \"%s\"",
1158 if (!swap_toast_by_content &&
1159 (relform1->reltoastrelid || relform2->reltoastrelid))
1160 elog(
ERROR,
"cannot swap toast by links for mapped relation \"%s\"",
1168 elog(
ERROR,
"could not find relation mapping for relation \"%s\", OID %u",
1169 NameStr(relform1->relname), r1);
1172 elog(
ERROR,
"could not find relation mapping for relation \"%s\", OID %u",
1173 NameStr(relform2->relname), r2);
1183 *mapped_tables++ = r2;
1214 if (relform1->relkind != RELKIND_INDEX)
1218 relform1->relfrozenxid = frozenXid;
1219 relform1->relminmxid = cutoffMulti;
1226 int32 swap_allvisible;
1228 swap_pages = relform1->relpages;
1229 relform1->relpages = relform2->relpages;
1230 relform2->relpages = swap_pages;
1232 swap_tuples = relform1->reltuples;
1233 relform1->reltuples = relform2->reltuples;
1234 relform2->reltuples = swap_tuples;
1236 swap_allvisible = relform1->relallvisible;
1237 relform1->relallvisible = relform2->relallvisible;
1238 relform2->relallvisible = swap_allvisible;
1250 if (!target_is_pg_class)
1273 if (relam1 != relam2)
1277 AccessMethodRelationId,
1280 elog(
ERROR,
"could not change access method dependency for relation \"%s.%s\"",
1285 AccessMethodRelationId,
1288 elog(
ERROR,
"could not change access method dependency for relation \"%s.%s\"",
1306 if (relform1->reltoastrelid || relform2->reltoastrelid)
1308 if (swap_toast_by_content)
1310 if (relform1->reltoastrelid && relform2->reltoastrelid)
1314 relform2->reltoastrelid,
1316 swap_toast_by_content,
1325 elog(
ERROR,
"cannot swap toast files by content when there's only one");
1352 elog(
ERROR,
"cannot swap toast files by links for system catalogs");
1355 if (relform1->reltoastrelid)
1358 relform1->reltoastrelid,
1361 elog(
ERROR,
"expected one dependency record for TOAST table, found %ld",
1364 if (relform2->reltoastrelid)
1367 relform2->reltoastrelid,
1370 elog(
ERROR,
"expected one dependency record for TOAST table, found %ld",
1375 baseobject.
classId = RelationRelationId;
1377 toastobject.
classId = RelationRelationId;
1380 if (relform1->reltoastrelid)
1383 toastobject.
objectId = relform1->reltoastrelid;
1388 if (relform2->reltoastrelid)
1391 toastobject.
objectId = relform2->reltoastrelid;
1403 if (swap_toast_by_content &&
1404 relform1->relkind == RELKIND_TOASTVALUE &&
1405 relform2->relkind == RELKIND_TOASTVALUE)
1419 swap_toast_by_content,
1439 bool is_system_catalog,
1440 bool swap_toast_by_content,
1441 bool check_constraints,
1445 char newrelpersistence)
1448 Oid mapped_tables[4];
1458 memset(mapped_tables, 0,
sizeof(mapped_tables));
1465 (OIDOldHeap == RelationRelationId),
1466 swap_toast_by_content, is_internal,
1467 frozenXid, cutoffMulti, mapped_tables);
1473 if (is_system_catalog)
1492 if (check_constraints)
1499 if (newrelpersistence == RELPERSISTENCE_UNLOGGED)
1501 else if (newrelpersistence == RELPERSISTENCE_PERMANENT)
1526 if (OIDOldHeap == RelationRelationId)
1536 elog(
ERROR,
"cache lookup failed for relation %u", OIDOldHeap);
1539 relform->relfrozenxid = frozenXid;
1540 relform->relminmxid = cutoffMulti;
1548 object.classId = RelationRelationId;
1549 object.objectId = OIDNewHeap;
1550 object.objectSubId = 0;
1579 if (!swap_toast_by_content)
1597 NewToastName,
true,
false);
1604 NewToastName,
true,
true);
1618 if (!is_system_catalog)
1652 Anum_pg_index_indisclustered,
1700 foreach(lc, inhoids)
1744 (
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)