52 #include "utils/fmgroids.h"
78 bool verbose,
bool *pSwapToastByContent,
121 foreach(lc,
stmt->params)
125 if (strcmp(opt->
defname,
"verbose") == 0)
129 (
errcode(ERRCODE_SYNTAX_ERROR),
130 errmsg(
"unrecognized CLUSTER option \"%s\"",
137 if (
stmt->relation != NULL)
159 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
160 errmsg(
"cannot cluster temporary tables of other sessions")));
162 if (
stmt->indexname == NULL)
177 (
errcode(ERRCODE_UNDEFINED_OBJECT),
178 errmsg(
"there is no previously clustered index for table \"%s\"",
179 stmt->relation->relname)));
188 rel->
rd_rel->relnamespace);
191 (
errcode(ERRCODE_UNDEFINED_OBJECT),
192 errmsg(
"index \"%s\" for table \"%s\" does not exist",
193 stmt->indexname,
stmt->relation->relname)));
196 if (rel->
rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
236 Assert(rel->
rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
316 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;
924 OldHeap->
rd_rel->relfrozenxid))
932 OldHeap->
rd_rel->relminmxid))
942 if (OldIndex != NULL && OldIndex->
rd_rel->relam == BTREE_AM_OID)
948 if (OldIndex != NULL && !use_sort)
950 (
errmsg(
"clustering \"%s.%s\" using index scan on \"%s\"",
956 (
errmsg(
"clustering \"%s.%s\" using sequential scan and sort",
961 (
errmsg(
"vacuuming \"%s.%s\"",
974 &num_tuples, &tups_vacuumed,
975 &tups_recently_dead);
988 (
errmsg(
"\"%s.%s\": found %.0f removable, %.0f nonremovable row versions in %u pages",
991 tups_vacuumed, num_tuples,
993 errdetail(
"%.0f dead row versions cannot be removed yet.\n"
998 if (OldIndex != NULL)
1008 elog(
ERROR,
"cache lookup failed for relation %u", OIDNewHeap);
1011 relform->relpages = num_pages;
1012 relform->reltuples = num_tuples;
1015 if (OIDOldHeap != RelationRelationId)
1056 bool swap_toast_by_content,
1079 elog(
ERROR,
"cache lookup failed for relation %u", r1);
1084 elog(
ERROR,
"cache lookup failed for relation %u", r2);
1087 relfilenumber1 = relform1->relfilenode;
1088 relfilenumber2 = relform2->relfilenode;
1089 relam1 = relform1->relam;
1090 relam2 = relform2->relam;
1099 Assert(!target_is_pg_class);
1101 swaptemp = relform1->relfilenode;
1102 relform1->relfilenode = relform2->relfilenode;
1103 relform2->relfilenode = swaptemp;
1105 swaptemp = relform1->reltablespace;
1106 relform1->reltablespace = relform2->reltablespace;
1107 relform2->reltablespace = swaptemp;
1109 swaptemp = relform1->relam;
1110 relform1->relam = relform2->relam;
1111 relform2->relam = swaptemp;
1113 swptmpchr = relform1->relpersistence;
1114 relform1->relpersistence = relform2->relpersistence;
1115 relform2->relpersistence = swptmpchr;
1118 if (!swap_toast_by_content)
1120 swaptemp = relform1->reltoastrelid;
1121 relform1->reltoastrelid = relform2->reltoastrelid;
1122 relform2->reltoastrelid = swaptemp;
1133 elog(
ERROR,
"cannot swap mapped relation \"%s\" with non-mapped relation",
1143 if (relform1->reltablespace != relform2->reltablespace)
1144 elog(
ERROR,
"cannot change tablespace of mapped relation \"%s\"",
1146 if (relform1->relpersistence != relform2->relpersistence)
1147 elog(
ERROR,
"cannot change persistence of mapped relation \"%s\"",
1149 if (relform1->relam != relform2->relam)
1150 elog(
ERROR,
"cannot change access method of mapped relation \"%s\"",
1152 if (!swap_toast_by_content &&
1153 (relform1->reltoastrelid || relform2->reltoastrelid))
1154 elog(
ERROR,
"cannot swap toast by links for mapped relation \"%s\"",
1162 elog(
ERROR,
"could not find relation mapping for relation \"%s\", OID %u",
1163 NameStr(relform1->relname), r1);
1166 elog(
ERROR,
"could not find relation mapping for relation \"%s\", OID %u",
1167 NameStr(relform2->relname), r2);
1177 *mapped_tables++ = r2;
1208 if (relform1->relkind != RELKIND_INDEX)
1212 relform1->relfrozenxid = frozenXid;
1213 relform1->relminmxid = cutoffMulti;
1220 int32 swap_allvisible;
1222 swap_pages = relform1->relpages;
1223 relform1->relpages = relform2->relpages;
1224 relform2->relpages = swap_pages;
1226 swap_tuples = relform1->reltuples;
1227 relform1->reltuples = relform2->reltuples;
1228 relform2->reltuples = swap_tuples;
1230 swap_allvisible = relform1->relallvisible;
1231 relform1->relallvisible = relform2->relallvisible;
1232 relform2->relallvisible = swap_allvisible;
1244 if (!target_is_pg_class)
1267 if (relam1 != relam2)
1271 AccessMethodRelationId,
1274 elog(
ERROR,
"could not change access method dependency for relation \"%s.%s\"",
1279 AccessMethodRelationId,
1282 elog(
ERROR,
"could not change access method dependency for relation \"%s.%s\"",
1300 if (relform1->reltoastrelid || relform2->reltoastrelid)
1302 if (swap_toast_by_content)
1304 if (relform1->reltoastrelid && relform2->reltoastrelid)
1308 relform2->reltoastrelid,
1310 swap_toast_by_content,
1319 elog(
ERROR,
"cannot swap toast files by content when there's only one");
1346 elog(
ERROR,
"cannot swap toast files by links for system catalogs");
1349 if (relform1->reltoastrelid)
1352 relform1->reltoastrelid,
1355 elog(
ERROR,
"expected one dependency record for TOAST table, found %ld",
1358 if (relform2->reltoastrelid)
1361 relform2->reltoastrelid,
1364 elog(
ERROR,
"expected one dependency record for TOAST table, found %ld",
1369 baseobject.
classId = RelationRelationId;
1371 toastobject.
classId = RelationRelationId;
1374 if (relform1->reltoastrelid)
1377 toastobject.
objectId = relform1->reltoastrelid;
1382 if (relform2->reltoastrelid)
1385 toastobject.
objectId = relform2->reltoastrelid;
1397 if (swap_toast_by_content &&
1398 relform1->relkind == RELKIND_TOASTVALUE &&
1399 relform2->relkind == RELKIND_TOASTVALUE)
1413 swap_toast_by_content,
1452 bool is_system_catalog,
1453 bool swap_toast_by_content,
1454 bool check_constraints,
1458 char newrelpersistence)
1461 Oid mapped_tables[4];
1471 memset(mapped_tables, 0,
sizeof(mapped_tables));
1478 (OIDOldHeap == RelationRelationId),
1479 swap_toast_by_content, is_internal,
1480 frozenXid, cutoffMulti, mapped_tables);
1486 if (is_system_catalog)
1505 if (check_constraints)
1512 if (newrelpersistence == RELPERSISTENCE_UNLOGGED)
1514 else if (newrelpersistence == RELPERSISTENCE_PERMANENT)
1539 if (OIDOldHeap == RelationRelationId)
1549 elog(
ERROR,
"cache lookup failed for relation %u", OIDOldHeap);
1552 relform->relfrozenxid = frozenXid;
1553 relform->relminmxid = cutoffMulti;
1561 object.classId = RelationRelationId;
1562 object.objectId = OIDNewHeap;
1563 object.objectSubId = 0;
1592 if (!swap_toast_by_content)
1610 NewToastName,
true,
false);
1617 NewToastName,
true,
true);
1631 if (!is_system_catalog)
1665 Anum_pg_index_indisclustered,
1713 foreach(lc, inhoids)
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
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
TransactionId MultiXactId
#define OidIsValid(objectId)
bool IsSystemRelation(Relation relation)
bool IsSharedRelation(Oid relationId)
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 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
elog(ERROR, "%s: %s", p2, msg)
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 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(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)
Assert(fmt[strlen(fmt) - 1] !='\n')
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)
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
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
#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 RelationCloseSmgrByOid(Oid relationId)
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
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 RangeVarCallbackOwnsTable(const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
void CheckTableNotInUse(Relation rel, const char *stmt)
void RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, bool is_index)
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)