mirror of https://github.com/citusdata/citus.git
create_distributed_table in transaction is fixed
parent
45f8017f42
commit
2c5d59f3a8
|
@ -100,6 +100,7 @@ static bool LocalTableEmpty(Oid tableId);
|
||||||
static void CopyLocalDataIntoShards(Oid relationId);
|
static void CopyLocalDataIntoShards(Oid relationId);
|
||||||
static List * TupleDescColumnNameList(TupleDesc tupleDescriptor);
|
static List * TupleDescColumnNameList(TupleDesc tupleDescriptor);
|
||||||
static bool RelationUsesIdentityColumns(TupleDesc relationDesc);
|
static bool RelationUsesIdentityColumns(TupleDesc relationDesc);
|
||||||
|
static bool CanUseExclusiveConnections(Oid relationId, bool localTableEmpty);
|
||||||
|
|
||||||
/* exports for SQL callable functions */
|
/* exports for SQL callable functions */
|
||||||
PG_FUNCTION_INFO_V1(master_create_distributed_table);
|
PG_FUNCTION_INFO_V1(master_create_distributed_table);
|
||||||
|
@ -484,26 +485,8 @@ CreateHashDistributedTableShards(Oid relationId, Oid colocatedTableId,
|
||||||
*/
|
*/
|
||||||
if (RegularTable(relationId))
|
if (RegularTable(relationId))
|
||||||
{
|
{
|
||||||
if (!localTableEmpty && MultiShardConnectionType == SEQUENTIAL_CONNECTION)
|
useExclusiveConnection = CanUseExclusiveConnections(relationId,
|
||||||
{
|
localTableEmpty);
|
||||||
char *relationName = get_rel_name(relationId);
|
|
||||||
|
|
||||||
ereport(ERROR, (errmsg("cannot distribute \"%s\" in sequential mode "
|
|
||||||
"because it is not empty", relationName),
|
|
||||||
errhint("If you have manually set "
|
|
||||||
"citus.multi_shard_modify_mode to 'sequential', "
|
|
||||||
"try with 'parallel' option. If that is not the "
|
|
||||||
"case, try distributing local tables when they "
|
|
||||||
"are empty.")));
|
|
||||||
}
|
|
||||||
else if (MultiShardConnectionType == SEQUENTIAL_CONNECTION)
|
|
||||||
{
|
|
||||||
useExclusiveConnection = false;
|
|
||||||
}
|
|
||||||
else if (!localTableEmpty || IsTransactionBlock())
|
|
||||||
{
|
|
||||||
useExclusiveConnection = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (colocatedTableId != InvalidOid)
|
if (colocatedTableId != InvalidOid)
|
||||||
|
@ -1107,6 +1090,44 @@ LocalTableEmpty(Oid tableId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CanUseExclusiveConnections checks if we can open parallel connections
|
||||||
|
* while creating shards. We simply error out if we need to execute
|
||||||
|
* sequentially but there is data in the table, since we cannot copy the
|
||||||
|
* data to shards sequentially.
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
CanUseExclusiveConnections(Oid relationId, bool localTableEmpty)
|
||||||
|
{
|
||||||
|
bool hasForeignKeyToReferenceTable = HasForeignKeyToReferenceTable(relationId);
|
||||||
|
bool shouldRunSequential = MultiShardConnectionType == SEQUENTIAL_CONNECTION ||
|
||||||
|
hasForeignKeyToReferenceTable;
|
||||||
|
|
||||||
|
if (!localTableEmpty && shouldRunSequential)
|
||||||
|
{
|
||||||
|
char *relationName = get_rel_name(relationId);
|
||||||
|
|
||||||
|
ereport(ERROR, (errmsg("cannot distribute \"%s\" in sequential mode "
|
||||||
|
"because it is not empty", relationName),
|
||||||
|
errhint("If you have manually set "
|
||||||
|
"citus.multi_shard_modify_mode to 'sequential', "
|
||||||
|
"try with 'parallel' option. If that is not the "
|
||||||
|
"case, try distributing local tables when they "
|
||||||
|
"are empty.")));
|
||||||
|
}
|
||||||
|
else if (shouldRunSequential)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (!localTableEmpty || IsTransactionBlock())
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CreateTruncateTrigger creates a truncate trigger on table identified by relationId
|
* CreateTruncateTrigger creates a truncate trigger on table identified by relationId
|
||||||
* and assigns citus_truncate_trigger() as handler.
|
* and assigns citus_truncate_trigger() as handler.
|
||||||
|
|
|
@ -370,6 +370,62 @@ GetTableForeignConstraintCommands(Oid relationId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* HasForeignKeyToReferenceTable function scans the pgConstraint table to
|
||||||
|
* fetch all of the constraints on the given relationId and see if at least one
|
||||||
|
* of them is a foreign key referencing to a reference table.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
HasForeignKeyToReferenceTable(Oid relationId)
|
||||||
|
{
|
||||||
|
Relation pgConstraint = NULL;
|
||||||
|
SysScanDesc scanDescriptor = NULL;
|
||||||
|
ScanKeyData scanKey[1];
|
||||||
|
int scanKeyCount = 1;
|
||||||
|
HeapTuple heapTuple = NULL;
|
||||||
|
bool hasForeignKeyToReferenceTable = false;
|
||||||
|
|
||||||
|
pgConstraint = heap_open(ConstraintRelationId, AccessShareLock);
|
||||||
|
ScanKeyInit(&scanKey[0], Anum_pg_constraint_conrelid, BTEqualStrategyNumber, F_OIDEQ,
|
||||||
|
relationId);
|
||||||
|
scanDescriptor = systable_beginscan(pgConstraint, ConstraintRelidIndexId, true, NULL,
|
||||||
|
scanKeyCount, scanKey);
|
||||||
|
|
||||||
|
heapTuple = systable_getnext(scanDescriptor);
|
||||||
|
while (HeapTupleIsValid(heapTuple))
|
||||||
|
{
|
||||||
|
Oid referencedTableId = InvalidOid;
|
||||||
|
Form_pg_constraint constraintForm = (Form_pg_constraint) GETSTRUCT(heapTuple);
|
||||||
|
|
||||||
|
if (constraintForm->contype != CONSTRAINT_FOREIGN)
|
||||||
|
{
|
||||||
|
heapTuple = systable_getnext(scanDescriptor);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
referencedTableId = constraintForm->confrelid;
|
||||||
|
|
||||||
|
if (!IsDistributedTable(referencedTableId))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PartitionMethod(referencedTableId) == DISTRIBUTE_BY_NONE)
|
||||||
|
{
|
||||||
|
hasForeignKeyToReferenceTable = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
heapTuple = systable_getnext(scanDescriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* clean up scan and close system catalog */
|
||||||
|
systable_endscan(scanDescriptor);
|
||||||
|
heap_close(pgConstraint, NoLock);
|
||||||
|
return hasForeignKeyToReferenceTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TableReferenced function checks whether given table is referenced by another table
|
* TableReferenced function checks whether given table is referenced by another table
|
||||||
* via foreign constraints. If it is referenced, this function returns true. To check
|
* via foreign constraints. If it is referenced, this function returns true. To check
|
||||||
|
|
|
@ -662,7 +662,10 @@ WorkerCreateShard(Oid relationId, int shardIndex, uint64 shardId, List *ddlComma
|
||||||
* In case of self referencing shards, relation itself might not be distributed
|
* In case of self referencing shards, relation itself might not be distributed
|
||||||
* already. Therefore we cannot use ColocatedShardIdInRelation which assumes
|
* already. Therefore we cannot use ColocatedShardIdInRelation which assumes
|
||||||
* given relation is distributed. Besides, since we know foreign key references
|
* given relation is distributed. Besides, since we know foreign key references
|
||||||
* itself, referencedShardId is actual shardId anyway.
|
* itself, referencedShardId is actual shardId anyway. Also, if the referenced
|
||||||
|
* relation is a reference table, we cannot use ColocatedShardIdInRelation since
|
||||||
|
* reference tables only have one shard. Instead, we fetch the one and only shard
|
||||||
|
* from shardlist and use it.
|
||||||
*/
|
*/
|
||||||
if (relationId == referencedRelationId)
|
if (relationId == referencedRelationId)
|
||||||
{
|
{
|
||||||
|
|
|
@ -19,6 +19,7 @@ extern void ErrorIfUnsupportedForeignConstraint(Relation relation, char
|
||||||
Var *distributionColumn, uint32
|
Var *distributionColumn, uint32
|
||||||
colocationId);
|
colocationId);
|
||||||
extern List * GetTableForeignConstraintCommands(Oid relationId);
|
extern List * GetTableForeignConstraintCommands(Oid relationId);
|
||||||
|
extern bool HasForeignKeyToReferenceTable(Oid relationId);
|
||||||
extern bool TableReferenced(Oid relationId);
|
extern bool TableReferenced(Oid relationId);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue