Initial commit

Disregard it.
pull/1288/head
velioglu 2017-03-17 16:03:36 +03:00
parent e2ee7de0af
commit 8f7e69fd0d
3 changed files with 71 additions and 183 deletions

View File

@ -35,6 +35,7 @@
#include "commands/extension.h"
#include "commands/trigger.h"
#include "distributed/colocation_utils.h"
#include "distributed/create_distributed_table.h"
#include "distributed/distribution_column.h"
#include "distributed/master_metadata_utility.h"
#include "distributed/master_protocol.h"
@ -81,8 +82,6 @@ static char LookupDistributionMethod(Oid distributionMethodOid);
static Oid SupportFunctionForColumn(Var *partitionColumn, Oid accessMethodId,
int16 supportFunctionNumber);
static bool LocalTableEmpty(Oid tableId);
static void ErrorIfNotSupportedConstraint(Relation relation, char distributionMethod,
Var *distributionColumn, uint32 colocationId);
static void ErrorIfNotSupportedForeignConstraint(Relation relation,
char distributionMethod,
Var *distributionColumn,
@ -438,7 +437,7 @@ ConvertToDistributedTable(Oid relationId, char *distributionColumnName,
* ii. Second, INSERT INTO .. ON CONFLICT (i.e., UPSERT) queries can be executed
* with no further check for constraints.
*/
static void
void
ErrorIfNotSupportedConstraint(Relation relation, char distributionMethod,
Var *distributionColumn, uint32 colocationId)
{

View File

@ -32,6 +32,7 @@
#include "commands/prepare.h"
#include "distributed/citus_ruleutils.h"
#include "distributed/colocation_utils.h"
#include "distributed/create_distributed_table.h"
#include "distributed/master_metadata_utility.h"
#include "distributed/master_protocol.h"
#include "distributed/metadata_cache.h"
@ -370,6 +371,15 @@ multi_ProcessUtility(Node *parsetree,
standard_ProcessUtility(parsetree, queryString, context,
params, dest, completionTag);
/* we control alter table statement here to use same checks with creating table */
if (IsA(parsetree, AlterTableStmt))
{
AlterTableStmt *alterTableStatement = (AlterTableStmt *) parsetree;
ErrorIfUnsupportedAlterTableStmt(alterTableStatement);
}
if (commandMustRunAsOwner)
{
SetUserIdAndSecContext(savedUserId, savedSecurityContext);
@ -816,11 +826,9 @@ PlanAlterTableStmt(AlterTableStmt *alterTableStatement, const char *alterTableCo
return NULL;
}
ErrorIfUnsupportedAlterTableStmt(alterTableStatement);
/*
* We check if there is a ADD FOREIGN CONSTRAINT command in sub commands list.
* If there is we assign referenced releation id to rightRelationId and we also
* If there is we assign referenced relation id to rightRelationId and we also
* set skip_validation to true to prevent PostgreSQL to verify validity of the
* foreign constraint in master. Validity will be checked in workers anyway.
*/
@ -1454,26 +1462,29 @@ ErrorIfUnsupportedAlterTableStmt(AlterTableStmt *alterTableStatement)
case AT_AddConstraint:
{
Relation relation = NULL;
char distributionMethod;
Var *distributionColumn = NULL;
uint32 colocationId = 0;
LOCKMODE lockmode = 0;
Oid leftRelationId = InvalidOid;
lockmode = AlterTableGetLockLevel(alterTableStatement->cmds);
leftRelationId = AlterTableLookupRelation(alterTableStatement, lockmode);
relation = relation_open(leftRelationId, ExclusiveLock);
distributionMethod = PartitionMethod(leftRelationId);
distributionColumn = PartitionKey(leftRelationId);
colocationId = TableColocationId(leftRelationId);
Constraint *constraint = (Constraint *) command->def;
LOCKMODE lockmode = AlterTableGetLockLevel(alterTableStatement->cmds);
Oid referencingTableId = InvalidOid;
Oid referencedTableId = InvalidOid;
Var *referencingTablePartitionColumn = NULL;
Var *referencedTablePartitionColumn = NULL;
ListCell *referencingTableAttr = NULL;
ListCell *referencedTableAttr = NULL;
bool foreignConstraintOnPartitionColumn = false;
/* we only allow adding foreign constraints with ALTER TABLE */
if (constraint->contype != CONSTR_FOREIGN)
/* extra checks for alter table */
if (constraint->contype == CONSTR_FOREIGN)
{
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot create constraint"),
errdetail("Citus cannot execute ADD CONSTRAINT "
"command other than ADD CONSTRAINT FOREIGN "
"KEY.")));
}
/* we only allow foreign constraints if they are only subcommand */
if (commandList->length > 1)
{
@ -1484,54 +1495,6 @@ ErrorIfUnsupportedAlterTableStmt(AlterTableStmt *alterTableStatement)
"subcommands."),
errhint("You can issue each subcommand separately")));
}
referencingTableId = RangeVarGetRelid(alterTableStatement->relation,
lockmode,
alterTableStatement->missing_ok);
referencedTableId = RangeVarGetRelid(constraint->pktable, lockmode,
alterTableStatement->missing_ok);
/* we do not support foreign keys for reference tables */
if (PartitionMethod(referencingTableId) == DISTRIBUTE_BY_NONE ||
PartitionMethod(referencedTableId) == DISTRIBUTE_BY_NONE)
{
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot create foreign key constraint"),
errdetail(
"Foreign key constraints are not allowed from or "
"to reference tables.")));
}
/*
* ON DELETE SET NULL and ON DELETE SET DEFAULT is not supported. Because
* we do not want to set partition column to NULL or default value.
*/
if (constraint->fk_del_action == FKCONSTR_ACTION_SETNULL ||
constraint->fk_del_action == FKCONSTR_ACTION_SETDEFAULT)
{
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot create foreign key constraint"),
errdetail("SET NULL or SET DEFAULT is not supported"
" in ON DELETE operation.")));
}
/*
* ON UPDATE SET NULL, ON UPDATE SET DEFAULT and UPDATE CASCADE is not
* supported. Because we do not want to set partition column to NULL or
* default value. Also cascading update operation would require
* re-partitioning. Updating partition column value is not allowed anyway
* even outside of foreign key concept.
*/
if (constraint->fk_upd_action == FKCONSTR_ACTION_SETNULL ||
constraint->fk_upd_action == FKCONSTR_ACTION_SETDEFAULT ||
constraint->fk_upd_action == FKCONSTR_ACTION_CASCADE)
{
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot create foreign key constraint"),
errdetail("SET NULL, SET DEFAULT or CASCADE is not"
" supported in ON UPDATE operation.")));
}
/*
* We will use constraint name in each placement by extending it at
* workers. Therefore we require it to be exist.
@ -1544,100 +1507,10 @@ ErrorIfUnsupportedAlterTableStmt(AlterTableStmt *alterTableStatement)
"name on a distributed table is currently "
"not supported.")));
}
/* to enforce foreign constraints, tables must be co-located */
if (!TablesColocated(referencingTableId, referencedTableId))
{
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot create foreign key constraint"),
errdetail("Foreign key constraint can only be created"
" on co-located tables.")));
}
/*
* The following logic requires the referenced columns to exists in
* the statement. Otherwise, we cannot apply some of the checks.
*/
if (constraint->pk_attrs == NULL)
{
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot create foreign key constraint "
"because referenced column list is empty"),
errhint("Add column names to \"REFERENCES\" part of "
"the statement.")));
}
/*
* Referencing column's list length should be equal to referenced columns
* list length.
*/
if (constraint->fk_attrs->length != constraint->pk_attrs->length)
{
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot create foreign key constraint"),
errdetail("Referencing column list and referenced "
"column list must be in same size.")));
}
/*
* Partition column must exist in both referencing and referenced side
* of the foreign key constraint. They also must be in same ordinal.
*/
referencingTablePartitionColumn = PartitionKey(referencingTableId);
referencedTablePartitionColumn = PartitionKey(referencedTableId);
/*
* We iterate over fk_attrs and pk_attrs together because partition
* column must be at the same place in both referencing and referenced
* side of the foreign key constraint
*/
forboth(referencingTableAttr, constraint->fk_attrs,
referencedTableAttr, constraint->pk_attrs)
{
char *referencingAttrName = strVal(lfirst(referencingTableAttr));
char *referencedAttrName = strVal(lfirst(referencedTableAttr));
AttrNumber referencingAttrNo = get_attnum(referencingTableId,
referencingAttrName);
AttrNumber referencedAttrNo = get_attnum(referencedTableId,
referencedAttrName);
if (referencingTablePartitionColumn->varattno == referencingAttrNo &&
referencedTablePartitionColumn->varattno == referencedAttrNo)
{
foreignConstraintOnPartitionColumn = true;
}
}
if (!foreignConstraintOnPartitionColumn)
{
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot create foreign key constraint"),
errdetail("Partition column must exist both "
"referencing and referenced side of the "
"foreign constraint statement and it must "
"be in the same ordinal in both sides.")));
}
/*
* We do not allow to create foreign constraints if shard replication
* factor is greater than 1. Because in our current design, multiple
* replicas may cause locking problems and inconsistent shard contents.
*/
if (!SingleReplicatedTable(referencingTableId) ||
!SingleReplicatedTable(referencedTableId))
{
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot create foreign key constraint"),
errdetail("Citus Community Edition currently "
"supports foreign key constraints only for "
"\"citus.shard_replication_factor = 1\"."),
errhint("Please change "
"\"citus.shard_replication_factor to 1\". To "
"learn more about using foreign keys with "
"other replication factors, please contact"
" us at "
"https://citusdata.com/about/contact_us.")));
}
ErrorIfNotSupportedConstraint(relation, distributionMethod,
distributionColumn, colocationId);
break;
}

View File

@ -0,0 +1,16 @@
/*
* create_distributed_table.h
*
* Created on: Mar 17, 2017
* Author: velioglub
*/
#ifndef SRC_INCLUDE_DISTRIBUTED_CREATE_DISTRIBUTED_TABLE_H_
#define SRC_INCLUDE_DISTRIBUTED_CREATE_DISTRIBUTED_TABLE_H_
extern void ErrorIfNotSupportedConstraint(Relation relation,
char distributionMethod,
Var *distributionColumn,
uint32 colocationId);
#endif /* SRC_INCLUDE_DISTRIBUTED_CREATE_DISTRIBUTED_TABLE_H_ */