@@ -139,6 +139,13 @@ static CitusTableParams DecideCitusTableParams(CitusTableType tableType,
139
139
distributedTableParams );
140
140
static void CreateCitusTable (Oid relationId , CitusTableType tableType ,
141
141
DistributedTableParams * distributedTableParams );
142
+ static void ConvertCitusLocalTableToTableType (Oid relationId ,
143
+ CitusTableType tableType ,
144
+ DistributedTableParams *
145
+ distributedTableParams );
146
+ static uint32 SingleShardTableColocationNodeId (uint32 colocationId );
147
+ static uint32 SingleShardTableGetNodeId (Oid relationId );
148
+ static int64 NoneDistTableGetShardId (Oid relationId );
142
149
static void CreateHashDistributedTableShards (Oid relationId , int shardCount ,
143
150
Oid colocatedTableId , bool localTableEmpty );
144
151
static void CreateSingleShardTableShard (Oid relationId , Oid colocatedTableId ,
@@ -1095,23 +1102,36 @@ CreateCitusTable(Oid relationId, CitusTableType tableType,
1095
1102
}
1096
1103
1097
1104
/*
1098
- * EnsureTableNotDistributed errors out when relation is a citus table but
1099
- * we don't want to ask user to first undistribute their citus local tables
1100
- * when creating reference or distributed tables from them.
1101
- * For this reason, here we undistribute citus local tables beforehand.
1102
- * But since UndistributeTable does not support undistributing relations
1103
- * involved in foreign key relationships, we first drop foreign keys that
1104
- * given relation is involved, then we undistribute the relation and finally
1105
- * we re-create dropped foreign keys at the end of this function.
1105
+ * EnsureTableNotDistributed errors out when relation is a Citus table.
1106
+ *
1107
+ * For this reason, we either undistribute the Citus Local table first
1108
+ * and then follow the usual code-path to create distributed table; or
1109
+ * we simply move / replicate its shard to create a single-shard table /
1110
+ * reference table, and then we update the metadata accordingly.
1111
+ *
1112
+ * If we're about it to undistribute it (because we will create a distributed
1113
+ * table soon), then we first drop foreign keys that given relation is
1114
+ * involved because UndistributeTable does not support undistributing
1115
+ * relations involved in foreign key relationships. At the end of this
1116
+ * function, we then re-create the dropped foreign keys.
1106
1117
*/
1107
1118
List * originalForeignKeyRecreationCommands = NIL ;
1108
1119
if (IsCitusTableType (relationId , CITUS_LOCAL_TABLE ))
1109
1120
{
1110
- /* store foreign key creation commands that relation is involved */
1111
- originalForeignKeyRecreationCommands =
1112
- GetFKeyCreationCommandsRelationInvolvedWithTableType (relationId ,
1113
- INCLUDE_ALL_TABLE_TYPES );
1114
- relationId = DropFKeysAndUndistributeTable (relationId );
1121
+ if (tableType == REFERENCE_TABLE || tableType == SINGLE_SHARD_DISTRIBUTED )
1122
+ {
1123
+ ConvertCitusLocalTableToTableType (relationId , tableType ,
1124
+ distributedTableParams );
1125
+ return ;
1126
+ }
1127
+ else
1128
+ {
1129
+ /* store foreign key creation commands that relation is involved */
1130
+ originalForeignKeyRecreationCommands =
1131
+ GetFKeyCreationCommandsRelationInvolvedWithTableType (relationId ,
1132
+ INCLUDE_ALL_TABLE_TYPES );
1133
+ relationId = DropFKeysAndUndistributeTable (relationId );
1134
+ }
1115
1135
}
1116
1136
/*
1117
1137
* To support foreign keys between reference tables and local tables,
@@ -1319,6 +1339,215 @@ CreateCitusTable(Oid relationId, CitusTableType tableType,
1319
1339
}
1320
1340
1321
1341
1342
+ /*
1343
+ * ConvertCitusLocalTableToTableType converts given Citus local table to
1344
+ * given table type.
1345
+ *
1346
+ * This only supports converting Citus local tables to reference tables
1347
+ * (by replicating the shard to workers) and single-shard distributed
1348
+ * tables (by moving the shard to appropriate worker).
1349
+ */
1350
+ static void
1351
+ ConvertCitusLocalTableToTableType (Oid relationId , CitusTableType tableType ,
1352
+ DistributedTableParams * distributedTableParams )
1353
+ {
1354
+ if (!IsCitusTableType (relationId , CITUS_LOCAL_TABLE ))
1355
+ {
1356
+ ereport (ERROR , (errmsg ("table is not a local table added to metadata" )));
1357
+ }
1358
+
1359
+ if (tableType != REFERENCE_TABLE && tableType != SINGLE_SHARD_DISTRIBUTED )
1360
+ {
1361
+ ereport (ERROR , (errmsg ("table type is not supported for conversion" )));
1362
+ }
1363
+
1364
+ LockRelationOid (relationId , ExclusiveLock );
1365
+
1366
+ Var * distributionColumn = NULL ;
1367
+ CitusTableParams citusTableParams = DecideCitusTableParams (tableType ,
1368
+ distributedTableParams );
1369
+
1370
+ uint32 colocationId = INVALID_COLOCATION_ID ;
1371
+ if (distributedTableParams &&
1372
+ distributedTableParams -> colocationParam .colocationParamType ==
1373
+ COLOCATE_WITH_COLOCATION_ID )
1374
+ {
1375
+ colocationId = distributedTableParams -> colocationParam .colocationId ;
1376
+ }
1377
+ else
1378
+ {
1379
+ colocationId = ColocationIdForNewTable (relationId , tableType ,
1380
+ distributedTableParams ,
1381
+ distributionColumn );
1382
+ }
1383
+
1384
+ /* check constraints etc. on table based on new distribution params */
1385
+ EnsureRelationCanBeDistributed (relationId , distributionColumn ,
1386
+ citusTableParams .distributionMethod ,
1387
+ colocationId , citusTableParams .replicationModel );
1388
+
1389
+ /*
1390
+ * Regarding the foreign key relationships that given relation is involved,
1391
+ * EnsureRelationCanBeDistributed() only checks the ones where the relation is
1392
+ * the referencing table.
1393
+ *
1394
+ * And given that the table at hand is a Citus local table, right now it may
1395
+ * only be referenced by a reference table or a Citus local table.
1396
+ *
1397
+ * However, given that neither of those two cases are not applicable for a
1398
+ * distributed table, here we throw an error assuming that the referencing
1399
+ * relation is a reference table or a Citus local table.
1400
+ *
1401
+ * While doing so, we use the same error message used in
1402
+ * ErrorIfUnsupportedForeignConstraintExists(), which is eventually called
1403
+ * by EnsureRelationCanBeDistributed().
1404
+ *
1405
+ * Note that we don't need to check the same if we're creating a reference
1406
+ * table from a Citus local table because all the foreign keys referencing
1407
+ * Citus local tables are supported by reference tables.
1408
+ */
1409
+ if (tableType == SINGLE_SHARD_DISTRIBUTED )
1410
+ {
1411
+ int fkeyFlags = (INCLUDE_REFERENCED_CONSTRAINTS | EXCLUDE_SELF_REFERENCES |
1412
+ INCLUDE_ALL_TABLE_TYPES );
1413
+ List * externalReferencedFkeyIds = GetForeignKeyOids (relationId , fkeyFlags );
1414
+ if (list_length (externalReferencedFkeyIds ) != 0 )
1415
+ {
1416
+ ereport (ERROR , (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
1417
+ errmsg ("cannot create foreign key constraint "
1418
+ "since foreign keys from reference tables "
1419
+ "and local tables to distributed tables "
1420
+ "are not supported" ),
1421
+ errdetail ("Reference tables and local tables "
1422
+ "can only have foreign keys to reference "
1423
+ "tables and local tables" )));
1424
+ }
1425
+ }
1426
+
1427
+ EnsureReferenceTablesExistOnAllNodes ();
1428
+
1429
+ LockColocationId (colocationId , ShareLock );
1430
+
1431
+ int64 shardId = NoneDistTableGetShardId (relationId );
1432
+ WorkerNode * sourceNode = CoordinatorNodeIfAddedAsWorkerOrError ();
1433
+
1434
+ if (tableType == SINGLE_SHARD_DISTRIBUTED )
1435
+ {
1436
+ uint32 targetNodeId = SingleShardTableColocationNodeId (colocationId );
1437
+ if (targetNodeId != sourceNode -> nodeId )
1438
+ {
1439
+ bool missingOk = false;
1440
+ WorkerNode * targetNode = FindNodeWithNodeId (targetNodeId , missingOk );
1441
+
1442
+ TransferCitusLocalTableShardInXact (shardId , sourceNode -> workerName ,
1443
+ sourceNode -> workerPort ,
1444
+ targetNode -> workerName ,
1445
+ targetNode -> workerPort ,
1446
+ SHARD_TRANSFER_MOVE );
1447
+ }
1448
+ }
1449
+ else if (tableType == REFERENCE_TABLE )
1450
+ {
1451
+ List * nodeList = ActivePrimaryNonCoordinatorNodeList (ShareLock );
1452
+ nodeList = SortList (nodeList , CompareWorkerNodes );
1453
+
1454
+ WorkerNode * targetNode = NULL ;
1455
+ foreach_ptr (targetNode , nodeList )
1456
+ {
1457
+ TransferCitusLocalTableShardInXact (shardId , sourceNode -> workerName ,
1458
+ sourceNode -> workerPort ,
1459
+ targetNode -> workerName ,
1460
+ targetNode -> workerPort ,
1461
+ SHARD_TRANSFER_COPY );
1462
+ }
1463
+ }
1464
+
1465
+ bool autoConverted = false;
1466
+ UpdateNoneDistTableMetadataGlobally (
1467
+ relationId , citusTableParams .replicationModel ,
1468
+ colocationId , autoConverted );
1469
+
1470
+ /*
1471
+ * TransferCitusLocalTableShardInXact() moves / copies partition shards
1472
+ * to the target node too, but we still need to update the metadata
1473
+ * for them.
1474
+ */
1475
+ if (PartitionedTable (relationId ))
1476
+ {
1477
+ Oid partitionRelationId = InvalidOid ;
1478
+ List * partitionList = PartitionList (relationId );
1479
+ foreach_oid (partitionRelationId , partitionList )
1480
+ {
1481
+ UpdateNoneDistTableMetadataGlobally (
1482
+ partitionRelationId , citusTableParams .replicationModel ,
1483
+ colocationId , autoConverted );
1484
+ }
1485
+ }
1486
+ }
1487
+
1488
+
1489
+ /*
1490
+ * SingleShardTableColocationNodeId takes a colocation id that is known to be
1491
+ * used / going be used to colocate a set of single-shard tables and returns
1492
+ * id of the node that should store the shards of those tables.
1493
+ */
1494
+ static uint32
1495
+ SingleShardTableColocationNodeId (uint32 colocationId )
1496
+ {
1497
+ List * tablesInColocationGroup = ColocationGroupTableList (colocationId , 1 );
1498
+ if (list_length (tablesInColocationGroup ) == 0 )
1499
+ {
1500
+ int workerNodeIndex =
1501
+ EmptySingleShardTableColocationDecideNodeId (colocationId );
1502
+ List * workerNodeList = DistributedTablePlacementNodeList (RowShareLock );
1503
+ WorkerNode * workerNode = (WorkerNode * ) list_nth (workerNodeList , workerNodeIndex );
1504
+
1505
+ return workerNode -> nodeId ;
1506
+ }
1507
+ else
1508
+ {
1509
+ Oid colocatedTableId = linitial_oid (tablesInColocationGroup );
1510
+ return SingleShardTableGetNodeId (colocatedTableId );
1511
+ }
1512
+ }
1513
+
1514
+
1515
+ /*
1516
+ * SingleShardTableGetNodeId returns id of the node that stores shard of
1517
+ * given single-shard table.
1518
+ */
1519
+ static uint32
1520
+ SingleShardTableGetNodeId (Oid relationId )
1521
+ {
1522
+ int64 shardId = NoneDistTableGetShardId (relationId );
1523
+
1524
+ List * shardPlacementList = ShardPlacementList (shardId );
1525
+ if (list_length (shardPlacementList ) != 1 )
1526
+ {
1527
+ ereport (ERROR , (errmsg ("table shard does not have a single shard placement" )));
1528
+ }
1529
+
1530
+ return ((ShardPlacement * ) linitial (shardPlacementList ))-> nodeId ;
1531
+ }
1532
+
1533
+
1534
+ /*
1535
+ * NoneDistTableGetShardId returns shard id of given table that is known
1536
+ * to be a none-distriubted table.
1537
+ */
1538
+ static int64
1539
+ NoneDistTableGetShardId (Oid relationId )
1540
+ {
1541
+ if (HasDistributionKey (relationId ))
1542
+ {
1543
+ ereport (ERROR , (errmsg ("table is not a none-distributed table" )));
1544
+ }
1545
+
1546
+ List * shardIntervalList = LoadShardIntervalList (relationId );
1547
+ return ((ShardInterval * ) linitial (shardIntervalList ))-> shardId ;
1548
+ }
1549
+
1550
+
1322
1551
/*
1323
1552
* DecideCitusTableParams decides CitusTableParams based on given CitusTableType
1324
1553
* and DistributedTableParams if it's a distributed table.
0 commit comments