citus/src/backend/distributed/worker/worker_drop_protocol.c

129 lines
4.0 KiB
C

/*-------------------------------------------------------------------------
*
* worker_drop_protocol.c
*
* Routines for dropping distributed tables and their metadata on worker nodes.
*
* Copyright (c) 2016, Citus Data, Inc.
*
* $Id$
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/genam.h"
#include "access/heapam.h"
#include "access/xact.h"
#include "catalog/dependency.h"
#include "catalog/pg_foreign_server.h"
#include "distributed/citus_ruleutils.h"
#include "distributed/distribution_column.h"
#include "distributed/master_metadata_utility.h"
#include "distributed/metadata_cache.h"
#include "foreign/foreign.h"
#include "utils/fmgroids.h"
PG_FUNCTION_INFO_V1(worker_drop_distributed_table);
/*
* worker_drop_distributed_table drops the distributed table with the given oid,
* then, removes the associated rows from pg_dist_partition, pg_dist_shard and
* pg_dist_placement. The function also drops the server for foreign tables.
*
* Note that drop fails if any dependent objects are present for any of the
* distributed tables. Also, shard placements of the distributed tables are
* not dropped as in the case of "DROP TABLE distributed_table;" command.
*
* The function errors out if the input relation Oid is not a regular or foreign table.
* The function is meant to be called only by the coordinator, therefore requires
* superuser privileges.
*/
Datum
worker_drop_distributed_table(PG_FUNCTION_ARGS)
{
Datum relationIdDatum = PG_GETARG_OID(0);
Oid relationId = DatumGetObjectId(relationIdDatum);
ObjectAddress distributedTableObject = { InvalidOid, InvalidOid, 0 };
Relation distributedRelation = NULL;
List *shardList = NULL;
ListCell *shardCell = NULL;
char relationKind = '\0';
CheckCitusVersion(ERROR);
EnsureSuperUser();
shardList = LoadShardList(relationId);
/* first check the relation type */
distributedRelation = relation_open(relationId, AccessShareLock);
relationKind = distributedRelation->rd_rel->relkind;
EnsureRelationKindSupported(relationId);
/* close the relation since we do not need anymore */
relation_close(distributedRelation, AccessShareLock);
/* prepare distributedTableObject for dropping the table */
distributedTableObject.classId = RelationRelationId;
distributedTableObject.objectId = relationId;
distributedTableObject.objectSubId = 0;
/* drop the server for the foreign relations */
if (relationKind == RELKIND_FOREIGN_TABLE)
{
ObjectAddresses *objects = new_object_addresses();
ObjectAddress foreignServerObject = { InvalidOid, InvalidOid, 0 };
ForeignTable *foreignTable = GetForeignTable(relationId);
Oid serverId = foreignTable->serverid;
/* prepare foreignServerObject for dropping the server */
foreignServerObject.classId = ForeignServerRelationId;
foreignServerObject.objectId = serverId;
foreignServerObject.objectSubId = 0;
/* add the addresses that are going to be dropped */
add_exact_object_address(&distributedTableObject, objects);
add_exact_object_address(&foreignServerObject, objects);
/* drop both the table and the server */
performMultipleDeletions(objects, DROP_RESTRICT,
PERFORM_DELETION_INTERNAL);
}
else
{
/* drop the table with cascade since other tables may be referring to it */
performDeletion(&distributedTableObject, DROP_CASCADE,
PERFORM_DELETION_INTERNAL);
}
/* iterate over shardList to delete the corresponding rows */
foreach(shardCell, shardList)
{
List *shardPlacementList = NIL;
ListCell *shardPlacementCell = NULL;
uint64 *shardIdPointer = (uint64 *) lfirst(shardCell);
uint64 shardId = (*shardIdPointer);
shardPlacementList = ShardPlacementList(shardId);
foreach(shardPlacementCell, shardPlacementList)
{
ShardPlacement *placement = (ShardPlacement *) lfirst(shardPlacementCell);
/* delete the row from pg_dist_placement */
DeleteShardPlacementRow(placement->placementId);
}
/* delete the row from pg_dist_shard */
DeleteShardRow(shardId);
}
/* delete the row from pg_dist_partition */
DeletePartitionRow(relationId);
PG_RETURN_VOID();
}