52 #include "utils/fmgroids.h"
78 bool verbose,
bool *pSwapToastByContent,
122 foreach(lc,
stmt->params)
126 if (strcmp(opt->
defname,
"verbose") == 0)
130 (
errcode(ERRCODE_SYNTAX_ERROR),
131 errmsg(
"unrecognized CLUSTER option \"%s\"",
138 if (
stmt->relation != NULL)
161 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
162 errmsg(
"cannot cluster temporary tables of other sessions")));
164 if (
stmt->indexname == NULL)
179 (
errcode(ERRCODE_UNDEFINED_OBJECT),
180 errmsg(
"there is no previously clustered index for table \"%s\"",
181 stmt->relation->relname)));
190 rel->
rd_rel->relnamespace);
193 (
errcode(ERRCODE_UNDEFINED_OBJECT),
194 errmsg(
"index \"%s\" for table \"%s\" does not exist",
195 stmt->indexname,
stmt->relation->relname)));
198 if (rel->
rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
238 Assert(rel->
rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
318 int save_sec_context;
423 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
424 errmsg(
"cannot cluster a shared catalog")));
434 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
435 errmsg(
"cannot cluster temporary tables of other sessions")));
438 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
439 errmsg(
"cannot vacuum temporary tables of other sessions")));
459 if (OldHeap->
rd_rel->relkind == RELKIND_MATVIEW &&
467 OldHeap->
rd_rel->relkind == RELKIND_MATVIEW ||
468 OldHeap->
rd_rel->relkind == RELKIND_TOASTVALUE);
514 (
errcode(ERRCODE_WRONG_OBJECT_TYPE),
515 errmsg(
"\"%s\" is not an index for table \"%s\"",
522 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
523 errmsg(
"cannot cluster on index \"%s\" because access method does not support clustering",
534 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
535 errmsg(
"cannot cluster on partial index \"%s\"",
546 if (!OldIndex->
rd_index->indisvalid)
548 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
549 errmsg(
"cannot cluster on invalid index \"%s\"",
570 if (rel->
rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
572 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
573 errmsg(
"cannot mark index clustered in partitioned table")));
596 elog(
ERROR,
"cache lookup failed for index %u", thisIndexOid);
603 if (indexForm->indisclustered)
605 indexForm->indisclustered =
false;
608 else if (thisIndexOid == indexOid)
611 if (!indexForm->indisvalid)
612 elog(
ERROR,
"cannot cluster on invalid index %u", indexOid);
613 indexForm->indisclustered =
true;
638 Oid accessMethod = OldHeap->
rd_rel->relam;
639 Oid tableSpace = OldHeap->
rd_rel->reltablespace;
642 bool is_system_catalog;
643 bool swap_toast_by_content;
652 relpersistence = OldHeap->
rd_rel->relpersistence;
666 &swap_toast_by_content, &frozenXid, &cutoffMulti);
673 swap_toast_by_content,
false,
true,
674 frozenXid, cutoffMulti,
691 char relpersistence,
LOCKMODE lockmode)
718 elog(
ERROR,
"cache lookup failed for relation %u", OIDOldHeap);
722 reloptions = (
Datum) 0;
724 if (relpersistence == RELPERSISTENCE_TEMP)
741 snprintf(NewHeapName,
sizeof(NewHeapName),
"pg_temp_%u", OIDOldHeap);
749 OldHeap->
rd_rel->relowner,
785 toastid = OldHeap->
rd_rel->reltoastrelid;
791 elog(
ERROR,
"cache lookup failed for relation %u", toastid);
795 reloptions = (
Datum) 0;
831 double num_tuples = 0,
833 tups_recently_dead = 0;
860 Assert(newTupDesc->natts == oldTupDesc->natts);
875 if (OldHeap->
rd_rel->reltoastrelid)
885 if (OldHeap->
rd_rel->reltoastrelid && NewHeap->
rd_rel->reltoastrelid)
887 *pSwapToastByContent =
true;
910 *pSwapToastByContent =
false;
926 OldHeap->
rd_rel->relfrozenxid))
934 OldHeap->
rd_rel->relminmxid))
944 if (OldIndex != NULL && OldIndex->
rd_rel->relam == BTREE_AM_OID)
950 if (OldIndex != NULL && !use_sort)
952 (
errmsg(
"clustering \"%s.%s\" using index scan on \"%s\"",
958 (
errmsg(
"clustering \"%s.%s\" using sequential scan and sort",
963 (
errmsg(
"vacuuming \"%s.%s\"",
976 &num_tuples, &tups_vacuumed,
977 &tups_recently_dead);
990 (
errmsg(
"\"%s.%s\": found %.0f removable, %.0f nonremovable row versions in %u pages",
993 tups_vacuumed, num_tuples,
995 errdetail(
"%.0f dead row versions cannot be removed yet.\n"
1000 if (OldIndex != NULL)
1010 elog(
ERROR,
"cache lookup failed for relation %u", OIDNewHeap);
1013 relform->relpages = num_pages;
1014 relform->reltuples = num_tuples;
1017 if (OIDOldHeap != RelationRelationId)
1058 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;
1097 Assert(!target_is_pg_class);
1099 swaptemp = relform1->relfilenode;
1100 relform1->relfilenode = relform2->relfilenode;
1101 relform2->relfilenode = swaptemp;
1103 swaptemp = relform1->reltablespace;
1104 relform1->reltablespace = relform2->reltablespace;
1105 relform2->reltablespace = swaptemp;
1107 swaptemp = relform1->relam;
1108 relform1->relam = relform2->relam;
1109 relform2->relam = swaptemp;
1111 swptmpchr = relform1->relpersistence;
1112 relform1->relpersistence = relform2->relpersistence;
1113 relform2->relpersistence = swptmpchr;
1116 if (!swap_toast_by_content)
1118 swaptemp = relform1->reltoastrelid;
1119 relform1->reltoastrelid = relform2->reltoastrelid;
1120 relform2->reltoastrelid = swaptemp;
1131 elog(
ERROR,
"cannot swap mapped relation \"%s\" with non-mapped relation",
1141 if (relform1->reltablespace != relform2->reltablespace)
1142 elog(
ERROR,
"cannot change tablespace of mapped relation \"%s\"",
1144 if (relform1->relpersistence != relform2->relpersistence)
1145 elog(
ERROR,
"cannot change persistence of mapped relation \"%s\"",
1147 if (relform1->relam != relform2->relam)
1148 elog(
ERROR,
"cannot change access method of mapped relation \"%s\"",
1150 if (!swap_toast_by_content &&
1151 (relform1->reltoastrelid || relform2->reltoastrelid))
1152 elog(
ERROR,
"cannot swap toast by links for mapped relation \"%s\"",
1160 elog(
ERROR,
"could not find relation mapping for relation \"%s\", OID %u",
1161 NameStr(relform1->relname), r1);
1164 elog(
ERROR,
"could not find relation mapping for relation \"%s\", OID %u",
1165 NameStr(relform2->relname), r2);
1175 *mapped_tables++ = r2;
1206 if (relform1->relkind != RELKIND_INDEX)
1210 relform1->relfrozenxid = frozenXid;
1211 relform1->relminmxid = cutoffMulti;
1218 int32 swap_allvisible;
1220 swap_pages = relform1->relpages;
1221 relform1->relpages = relform2->relpages;
1222 relform2->relpages = swap_pages;
1224 swap_tuples = relform1->reltuples;
1225 relform1->reltuples = relform2->reltuples;
1226 relform2->reltuples = swap_tuples;
1228 swap_allvisible = relform1->relallvisible;
1229 relform1->relallvisible = relform2->relallvisible;
1230 relform2->relallvisible = swap_allvisible;
1242 if (!target_is_pg_class)
1273 if (relform1->reltoastrelid || relform2->reltoastrelid)
1275 if (swap_toast_by_content)
1277 if (relform1->reltoastrelid && relform2->reltoastrelid)
1281 relform2->reltoastrelid,
1283 swap_toast_by_content,
1292 elog(
ERROR,
"cannot swap toast files by content when there's only one");
1319 elog(
ERROR,
"cannot swap toast files by links for system catalogs");
1322 if (relform1->reltoastrelid)
1325 relform1->reltoastrelid,
1328 elog(
ERROR,
"expected one dependency record for TOAST table, found %ld",
1331 if (relform2->reltoastrelid)
1334 relform2->reltoastrelid,
1337 elog(
ERROR,
"expected one dependency record for TOAST table, found %ld",
1342 baseobject.
classId = RelationRelationId;
1344 toastobject.
classId = RelationRelationId;
1347 if (relform1->reltoastrelid)
1350 toastobject.
objectId = relform1->reltoastrelid;
1355 if (relform2->reltoastrelid)
1358 toastobject.
objectId = relform2->reltoastrelid;
1370 if (swap_toast_by_content &&
1371 relform1->relkind == RELKIND_TOASTVALUE &&
1372 relform2->relkind == RELKIND_TOASTVALUE)
1386 swap_toast_by_content,
1425 bool is_system_catalog,
1426 bool swap_toast_by_content,
1427 bool check_constraints,
1431 char newrelpersistence)
1434 Oid mapped_tables[4];
1444 memset(mapped_tables, 0,
sizeof(mapped_tables));
1451 (OIDOldHeap == RelationRelationId),
1452 swap_toast_by_content, is_internal,
1453 frozenXid, cutoffMulti, mapped_tables);
1459 if (is_system_catalog)
1478 if (check_constraints)
1485 if (newrelpersistence == RELPERSISTENCE_UNLOGGED)
1487 else if (newrelpersistence == RELPERSISTENCE_PERMANENT)
1512 if (OIDOldHeap == RelationRelationId)
1522 elog(
ERROR,
"cache lookup failed for relation %u", OIDOldHeap);
1525 relform->relfrozenxid = frozenXid;
1526 relform->relminmxid = cutoffMulti;
1534 object.classId = RelationRelationId;
1535 object.objectId = OIDNewHeap;
1536 object.objectSubId = 0;
1565 if (!swap_toast_by_content)
1583 NewToastName,
true,
false);
1590 NewToastName,
true,
true);
1604 if (!is_system_catalog)
1638 Anum_pg_index_indisclustered,
1686 foreach(lc, inhoids)
1728 (
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)
TransactionId MultiXactId
#define PG_USED_FOR_ASSERTS_ONLY
#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
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, 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)
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 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)
bool has_partition_ancestor_privs(Oid relid, Oid userid, AclMode acl)
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)