mirror of
https://github.com/postgres/postgres.git
synced 2025-11-24 00:23:06 +03:00
REINDEX CONCURRENTLY
This adds the CONCURRENTLY option to the REINDEX command. A REINDEX CONCURRENTLY on a specific index creates a new index (like CREATE INDEX CONCURRENTLY), then renames the old index away and the new index in place and adjusts the dependencies, and then drops the old index (like DROP INDEX CONCURRENTLY). The REINDEX command also has the capability to run its other variants (TABLE, DATABASE) with the CONCURRENTLY option (but not SYSTEM). The reindexdb command gets the --concurrently option. Author: Michael Paquier, Andreas Karlsson, Peter Eisentraut Reviewed-by: Andres Freund, Fujii Masao, Jim Nasby, Sergei Kornilov Discussion: https://www.postgresql.org/message-id/flat/60052986-956b-4478-45ed-8bd119e9b9cf%402ndquadrant.com#74948a1044c56c5e817a5050f554ddee
This commit is contained in:
@@ -395,6 +395,94 @@ changeDependencyFor(Oid classId, Oid objectId,
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
* Adjust all dependency records to point to a different object of the same type
|
||||
*
|
||||
* refClassId/oldRefObjectId specify the old referenced object.
|
||||
* newRefObjectId is the new referenced object (must be of class refClassId).
|
||||
*
|
||||
* Returns the number of records updated.
|
||||
*/
|
||||
long
|
||||
changeDependenciesOn(Oid refClassId, Oid oldRefObjectId,
|
||||
Oid newRefObjectId)
|
||||
{
|
||||
long count = 0;
|
||||
Relation depRel;
|
||||
ScanKeyData key[2];
|
||||
SysScanDesc scan;
|
||||
HeapTuple tup;
|
||||
ObjectAddress objAddr;
|
||||
bool newIsPinned;
|
||||
|
||||
depRel = table_open(DependRelationId, RowExclusiveLock);
|
||||
|
||||
/*
|
||||
* If oldRefObjectId is pinned, there won't be any dependency entries on
|
||||
* it --- we can't cope in that case. (This isn't really worth expending
|
||||
* code to fix, in current usage; it just means you can't rename stuff out
|
||||
* of pg_catalog, which would likely be a bad move anyway.)
|
||||
*/
|
||||
objAddr.classId = refClassId;
|
||||
objAddr.objectId = oldRefObjectId;
|
||||
objAddr.objectSubId = 0;
|
||||
|
||||
if (isObjectPinned(&objAddr, depRel))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("cannot remove dependency on %s because it is a system object",
|
||||
getObjectDescription(&objAddr))));
|
||||
|
||||
/*
|
||||
* We can handle adding a dependency on something pinned, though, since
|
||||
* that just means deleting the dependency entry.
|
||||
*/
|
||||
objAddr.objectId = newRefObjectId;
|
||||
|
||||
newIsPinned = isObjectPinned(&objAddr, depRel);
|
||||
|
||||
/* Now search for dependency records */
|
||||
ScanKeyInit(&key[0],
|
||||
Anum_pg_depend_refclassid,
|
||||
BTEqualStrategyNumber, F_OIDEQ,
|
||||
ObjectIdGetDatum(refClassId));
|
||||
ScanKeyInit(&key[1],
|
||||
Anum_pg_depend_refobjid,
|
||||
BTEqualStrategyNumber, F_OIDEQ,
|
||||
ObjectIdGetDatum(oldRefObjectId));
|
||||
|
||||
scan = systable_beginscan(depRel, DependReferenceIndexId, true,
|
||||
NULL, 2, key);
|
||||
|
||||
while (HeapTupleIsValid((tup = systable_getnext(scan))))
|
||||
{
|
||||
Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
|
||||
|
||||
if (newIsPinned)
|
||||
CatalogTupleDelete(depRel, &tup->t_self);
|
||||
else
|
||||
{
|
||||
/* make a modifiable copy */
|
||||
tup = heap_copytuple(tup);
|
||||
depform = (Form_pg_depend) GETSTRUCT(tup);
|
||||
|
||||
depform->refobjid = newRefObjectId;
|
||||
|
||||
CatalogTupleUpdate(depRel, &tup->t_self, tup);
|
||||
|
||||
heap_freetuple(tup);
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
systable_endscan(scan);
|
||||
|
||||
table_close(depRel, RowExclusiveLock);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
* isObjectPinned()
|
||||
*
|
||||
@@ -754,3 +842,58 @@ get_index_constraint(Oid indexId)
|
||||
|
||||
return constraintId;
|
||||
}
|
||||
|
||||
/*
|
||||
* get_index_ref_constraints
|
||||
* Given the OID of an index, return the OID of all foreign key
|
||||
* constraints which reference the index.
|
||||
*/
|
||||
List *
|
||||
get_index_ref_constraints(Oid indexId)
|
||||
{
|
||||
List *result = NIL;
|
||||
Relation depRel;
|
||||
ScanKeyData key[3];
|
||||
SysScanDesc scan;
|
||||
HeapTuple tup;
|
||||
|
||||
/* Search the dependency table for the index */
|
||||
depRel = table_open(DependRelationId, AccessShareLock);
|
||||
|
||||
ScanKeyInit(&key[0],
|
||||
Anum_pg_depend_refclassid,
|
||||
BTEqualStrategyNumber, F_OIDEQ,
|
||||
ObjectIdGetDatum(RelationRelationId));
|
||||
ScanKeyInit(&key[1],
|
||||
Anum_pg_depend_refobjid,
|
||||
BTEqualStrategyNumber, F_OIDEQ,
|
||||
ObjectIdGetDatum(indexId));
|
||||
ScanKeyInit(&key[2],
|
||||
Anum_pg_depend_refobjsubid,
|
||||
BTEqualStrategyNumber, F_INT4EQ,
|
||||
Int32GetDatum(0));
|
||||
|
||||
scan = systable_beginscan(depRel, DependReferenceIndexId, true,
|
||||
NULL, 3, key);
|
||||
|
||||
while (HeapTupleIsValid(tup = systable_getnext(scan)))
|
||||
{
|
||||
Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
|
||||
|
||||
/*
|
||||
* We assume any normal dependency from a constraint must be what we
|
||||
* are looking for.
|
||||
*/
|
||||
if (deprec->classid == ConstraintRelationId &&
|
||||
deprec->objsubid == 0 &&
|
||||
deprec->deptype == DEPENDENCY_NORMAL)
|
||||
{
|
||||
result = lappend_oid(result, deprec->objid);
|
||||
}
|
||||
}
|
||||
|
||||
systable_endscan(scan);
|
||||
table_close(depRel, AccessShareLock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user