Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature issue#49 #76

Merged
merged 9 commits into from
Feb 27, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
33 changes: 33 additions & 0 deletions distribution_metadata.c
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,39 @@ IsDistributedTable(Oid tableId)
}


/*
* DistributedTablesExist returns true if pg_shard has a record of any
* distributed tables; otherwise this function returns false.
*/
bool
DistributedTablesExist(void)
{
bool distributedTablesExist = false;
RangeVar *heapRangeVar = NULL;
Relation heapRelation = NULL;
HeapScanDesc scanDesc = NULL;
HeapTuple heapTuple = NULL;

heapRangeVar = makeRangeVar(METADATA_SCHEMA_NAME, PARTITION_TABLE_NAME, -1);
heapRelation = relation_openrv(heapRangeVar, AccessShareLock);

scanDesc = heap_beginscan(heapRelation, SnapshotSelf, 0, NULL);

heapTuple = heap_getnext(scanDesc, ForwardScanDirection);

/*
* Check whether the partition metadata table contains any tuples. If so,
* at least one distributed table exists.
*/
distributedTablesExist = HeapTupleIsValid(heapTuple);

heap_endscan(scanDesc);
relation_close(heapRelation, AccessShareLock);

return distributedTablesExist;
}


/*
* ColumnNameToColumn accepts a relation identifier and column name and returns
* a Var that represents that column in that relation. This function throws an
Expand Down
1 change: 1 addition & 0 deletions distribution_metadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ extern List * LoadShardPlacementList(int64 shardId);
extern Var * PartitionColumn(Oid distributedTableId);
extern char PartitionType(Oid distributedTableId);
extern bool IsDistributedTable(Oid tableId);
extern bool DistributedTablesExist(void);
extern Var * ColumnNameToColumn(Oid relationId, char *columnName);
extern void InsertPartitionRow(Oid distributedTableId, char partitionType,
text *partitionKeyText);
Expand Down
11 changes: 8 additions & 3 deletions expected/distribution_metadata.out
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,11 @@ SELECT COUNT(*) FROM pg_locks WHERE locktype = 'advisory' AND objid = 5;
0
(1 row)

-- clean up after ourselves
DROP TABLE events;
DROP TABLE customers;
-- ===================================================================
-- test distribution metadata dependency
-- ===================================================================
-- cannot drop extension
DROP EXTENSION pg_shard;
ERROR: cannot drop extension pg_shard because other objects depend on it
DETAIL: Existing distributed tables depend on extension pg_shard
HINT: Use DROP ... CASCADE to drop the dependent objects too.
78 changes: 78 additions & 0 deletions pg_shard.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include "catalog/namespace.h"
#include "catalog/pg_class.h"
#include "catalog/pg_type.h"
#include "catalog/objectaddress.h"
#include "commands/extension.h"
#include "executor/execdesc.h"
#include "executor/executor.h"
Expand Down Expand Up @@ -136,6 +137,7 @@ static void PgShardExecutorEnd(QueryDesc *queryDesc);
static void PgShardProcessUtility(Node *parsetree, const char *queryString,
ProcessUtilityContext context, ParamListInfo params,
DestReceiver *dest, char *completionTag);
static void ErrorOnDropIfDistributedTablesExist(DropStmt *dropStatement);


/* declarations for dynamic loading */
Expand Down Expand Up @@ -2016,6 +2018,11 @@ PgShardProcessUtility(Node *parsetree, const char *queryString,
}
}
}
else if (statementType == T_DropStmt)
{
DropStmt *dropStatement = (DropStmt *) parsetree;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The nesting gets pretty deep here. Can you move the drop logic into its own function?

ErrorOnDropIfDistributedTablesExist(dropStatement);
}

if (PreviousProcessUtilityHook != NULL)
{
Expand All @@ -2028,3 +2035,74 @@ PgShardProcessUtility(Node *parsetree, const char *queryString,
params, dest, completionTag);
}
}


/*
* ErrorOnDropIfDistributedTablesExist prevents attempts to drop the pg_shard
* extension if any distributed tables still exist. This prevention will be
* circumvented if the user includes the CASCADE option in their DROP command,
* in which case a notice is printed and the DROP is allowed to proceed.
*/
static void
ErrorOnDropIfDistributedTablesExist(DropStmt *dropStatement)
{
Oid extensionOid = InvalidOid;
bool missingOK = true;
ListCell *dropStatementObject = NULL;
bool distributedTablesExist = false;

/* we're only worried about dropping extensions */
if (dropStatement->removeType != OBJECT_EXTENSION)
{
return;
}

extensionOid = get_extension_oid(PG_SHARD_EXTENSION_NAME, missingOK);
if (extensionOid == InvalidOid)
{
/*
* Exit early if the extension has not been created (CREATE EXTENSION).
* This check is required because it's possible to load the hooks in an
* extension without formally "creating" it.
*/
return;
}

/* nothing to do if no distributed tables are present */
distributedTablesExist = DistributedTablesExist();
if (!distributedTablesExist)
{
return;
}

foreach(dropStatementObject, dropStatement->objects)
{
List *objectNameList = lfirst(dropStatementObject);
char *objectName = NameListToString(objectNameList);

/* we're only concerned with the pg_shard extension */
if (strncmp(PG_SHARD_EXTENSION_NAME, objectName, NAMEDATALEN) != 0)
{
continue;
}

if (dropStatement->behavior == DROP_CASCADE)
{
/* if CASCADE was used, emit NOTICE and proceed with DROP */
ereport(NOTICE, (errmsg("shards remain on worker nodes"),
errdetail("Shards created by the extension are not removed "
"by DROP EXTENSION.")));
}
else
{
/* without CASCADE, error if distributed tables present */
ereport(ERROR, (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
errmsg("cannot drop extension " PG_SHARD_EXTENSION_NAME
" because other objects depend on it"),
errdetail("Existing distributed tables depend on extension "
PG_SHARD_EXTENSION_NAME),
errhint("Use DROP ... CASCADE to drop the dependent "
"objects too.")));
}
}
}
9 changes: 6 additions & 3 deletions sql/distribution_metadata.sql
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,9 @@ COMMIT;
-- lock should be gone now
SELECT COUNT(*) FROM pg_locks WHERE locktype = 'advisory' AND objid = 5;

-- clean up after ourselves
DROP TABLE events;
DROP TABLE customers;
-- ===================================================================
-- test distribution metadata dependency
-- ===================================================================

-- cannot drop extension
DROP EXTENSION pg_shard;