Skip to content
21 changes: 21 additions & 0 deletions src/backend/distributed/commands/create_distributed_table.c
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ static void DoCopyFromLocalTableIntoShards(Relation distributedRelation,
TupleTableSlot *slot,
EState *estate);
static void ErrorIfTemporaryTable(Oid relationId);
static void ErrorIfForeignTable(Oid relationOid);

/* exports for SQL callable functions */
PG_FUNCTION_INFO_V1(master_create_distributed_table);
Expand Down Expand Up @@ -333,6 +334,7 @@ EnsureCitusTableCanBeCreated(Oid relationOid)
EnsureRelationExists(relationOid);
EnsureTableOwner(relationOid);
ErrorIfTemporaryTable(relationOid);
ErrorIfForeignTable(relationOid);

/*
* We should do this check here since the codes in the following lines rely
Expand Down Expand Up @@ -1880,3 +1882,22 @@ DistributionColumnUsesGeneratedStoredColumn(TupleDesc relationDesc,

return false;
}


/*
* ErrorIfForeignTable errors out if the relation with given relationOid
* is a foreign table.
*/
static void
ErrorIfForeignTable(Oid relationOid)
{
if (IsForeignTable(relationOid))
{
char *relname = get_rel_name(relationOid);
char *qualifiedRelname = generate_qualified_relation_name(relationOid);
ereport(ERROR, (errmsg("foreign tables cannot be distributed"),
(errhint("Can add foreign table \"%s\" to metadata by running: "
"SELECT citus_add_local_table_to_metadata($$%s$$);",
relname, qualifiedRelname))));
}
}
2 changes: 1 addition & 1 deletion src/backend/distributed/commands/table.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@
/* controlled via GUC, should be accessed via GetEnableLocalReferenceForeignKeys() */
bool EnableLocalReferenceForeignKeys = true;


/* Local functions forward declarations for unsupported command checks */
static void PostprocessCreateTableStmtForeignKeys(CreateStmt *createStatement);
static void PostprocessCreateTableStmtPartitionOf(CreateStmt *createStatement,
Expand Down Expand Up @@ -1786,6 +1785,7 @@ PreprocessAlterTableSchemaStmt(Node *node, const char *queryString,
{
return NIL;
}

DDLJob *ddlJob = palloc0(sizeof(DDLJob));
QualifyTreeNode((Node *) stmt);
ddlJob->targetRelationId = relationId;
Expand Down
63 changes: 58 additions & 5 deletions src/backend/distributed/planner/distributed_planner.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "distributed/citus_nodefuncs.h"
#include "distributed/citus_nodes.h"
#include "distributed/citus_ruleutils.h"
#include "distributed/commands.h"
#include "distributed/cte_inline.h"
#include "distributed/function_call_delegation.h"
#include "distributed/insert_select_planner.h"
Expand Down Expand Up @@ -71,7 +72,8 @@ static uint64 NextPlanId = 1;
/* keep track of planner call stack levels */
int PlannerLevel = 0;

static bool ListContainsDistributedTableRTE(List *rangeTableList);
static bool ListContainsDistributedTableRTE(List *rangeTableList,
bool *maybeHasForeignDistributedTable);
static bool IsUpdateOrDelete(Query *query);
static PlannedStmt * CreateDistributedPlannedStmt(
DistributedPlanningContext *planContext);
Expand Down Expand Up @@ -123,6 +125,7 @@ static PlannedStmt * PlanDistributedStmt(DistributedPlanningContext *planContext
int rteIdCounter);
static RTEListProperties * GetRTEListProperties(List *rangeTableList);
static List * TranslatedVars(PlannerInfo *root, int relationIndex);
static void WarnIfListHasForeignDistributedTable(List *rangeTableList);


/* Distributed planner hook */
Expand All @@ -149,10 +152,18 @@ distributed_planner(Query *parse,
}
else if (CitusHasBeenLoaded())
{
needsDistributedPlanning = ListContainsDistributedTableRTE(rangeTableList);
bool maybeHasForeignDistributedTable = false;
needsDistributedPlanning =
ListContainsDistributedTableRTE(rangeTableList,
&maybeHasForeignDistributedTable);
if (needsDistributedPlanning)
{
fastPathRouterQuery = FastPathRouterQuery(parse, &distributionKeyValue);

if (maybeHasForeignDistributedTable)
{
WarnIfListHasForeignDistributedTable(rangeTableList);
}
}
}

Expand Down Expand Up @@ -311,17 +322,19 @@ NeedsDistributedPlanning(Query *query)

List *allRTEs = ExtractRangeTableEntryList(query);

return ListContainsDistributedTableRTE(allRTEs);
return ListContainsDistributedTableRTE(allRTEs, NULL);
}


/*
* ListContainsDistributedTableRTE gets a list of range table entries
* and returns true if there is at least one distributed relation range
* table entry in the list.
* table entry in the list. The boolean maybeHasForeignDistributedTable
* variable is set to true if the list contains a foreign table.
*/
static bool
ListContainsDistributedTableRTE(List *rangeTableList)
ListContainsDistributedTableRTE(List *rangeTableList,
bool *maybeHasForeignDistributedTable)
{
ListCell *rangeTableCell = NULL;

Expand All @@ -336,6 +349,12 @@ ListContainsDistributedTableRTE(List *rangeTableList)

if (IsCitusTable(rangeTableEntry->relid))
{
if (maybeHasForeignDistributedTable != NULL &&
IsForeignTable(rangeTableEntry->relid))
{
*maybeHasForeignDistributedTable = true;
Comment thread
onderkalaci marked this conversation as resolved.
}

return true;
}
}
Expand Down Expand Up @@ -2408,3 +2427,37 @@ GetRTEListProperties(List *rangeTableList)

return rteListProperties;
}


/*
* WarnIfListHasForeignDistributedTable iterates the given list and logs a WARNING
* if the given relation is a distributed foreign table.
* We do that because now we only support Citus Local Tables for foreign tables.
*/
static void
WarnIfListHasForeignDistributedTable(List *rangeTableList)
{
static bool DistributedForeignTableWarningPrompted = false;

RangeTblEntry *rangeTableEntry = NULL;
foreach_ptr(rangeTableEntry, rangeTableList)
{
if (DistributedForeignTableWarningPrompted)
{
return;
}

Oid relationId = rangeTableEntry->relid;
if (IsForeignTable(relationId) && IsCitusTable(relationId) &&
!IsCitusTableType(relationId, CITUS_LOCAL_TABLE))
{
DistributedForeignTableWarningPrompted = true;
ereport(WARNING, (errmsg(
"support for distributed foreign tables are deprecated, "
"please use Citus managed local tables"),
(errdetail(
"Foreign tables can be added to metadata using UDF: "
"citus_add_local_table_to_metadata()"))));
}
}
}
31 changes: 3 additions & 28 deletions src/test/regress/expected/foreign_tables_mx.out
Original file line number Diff line number Diff line change
Expand Up @@ -199,36 +199,11 @@ NOTICE: renaming the new table to foreign_tables_schema_mx.foreign_table

(1 row)

-- both should error out
SELECT create_distributed_table('foreign_table','data');
create_distributed_table
---------------------------------------------------------------------

(1 row)

SELECT undistribute_table('foreign_table');
NOTICE: creating a new table for foreign_tables_schema_mx.foreign_table
NOTICE: dropping the old foreign_tables_schema_mx.foreign_table
NOTICE: renaming the new table to foreign_tables_schema_mx.foreign_table
undistribute_table
---------------------------------------------------------------------

(1 row)

ERROR: foreign tables cannot be distributed
SELECT create_reference_table('foreign_table');
create_reference_table
---------------------------------------------------------------------

(1 row)

SELECT undistribute_table('foreign_table');
NOTICE: creating a new table for foreign_tables_schema_mx.foreign_table
NOTICE: dropping the old foreign_tables_schema_mx.foreign_table
NOTICE: renaming the new table to foreign_tables_schema_mx.foreign_table
undistribute_table
---------------------------------------------------------------------

(1 row)

ERROR: foreign tables cannot be distributed
INSERT INTO foreign_table_test VALUES (1, 'testt');
SELECT * FROM foreign_table ORDER BY a;
data | a
Expand Down
68 changes: 0 additions & 68 deletions src/test/regress/expected/mixed_relkind_tests.out
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,6 @@ SELECT create_distributed_table('partitioned_distributed_table', 'a');

CREATE VIEW view_on_part_dist AS SELECT * FROM partitioned_distributed_table;
CREATE MATERIALIZED VIEW mat_view_on_part_dist AS SELECT * FROM partitioned_distributed_table;
CREATE FOREIGN TABLE foreign_distributed_table (a int, b int) SERVER fake_fdw_server;
SELECT create_distributed_table('foreign_distributed_table', 'a');
create_distributed_table
---------------------------------------------------------------------

(1 row)

-- and insert some data
INSERT INTO postgres_local_table SELECT * FROM generate_series(0, 5);
INSERT INTO partitioned_postgres_local_table SELECT * FROM generate_series(0, 5);
Expand Down Expand Up @@ -145,12 +138,6 @@ SELECT * FROM unlogged_distributed_table UNION SELECT 1,1 ORDER BY 1,2;
5 | 6
(7 rows)

SELECT * from foreign_distributed_table UNION SELECT 1,1 ORDER BY 1,2;
a | b
---------------------------------------------------------------------
1 | 1
(1 row)

SELECT 1 UNION SELECT * FROM citus_local_table ORDER BY 1;
?column?
---------------------------------------------------------------------
Expand Down Expand Up @@ -378,17 +365,6 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c
455
(1 row)

SELECT COUNT(*) FROM
(SELECT *, random() FROM unlogged_distributed_table) AS foo,
(SELECT *, random() FROM foreign_distributed_table) AS bar
WHERE foo.a = bar.b;
DEBUG: generating subplan XXX_1 for subquery SELECT a, b, random() AS random FROM mixed_relkind_tests.foreign_distributed_table
DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT unlogged_distributed_table.a, unlogged_distributed_table.b, random() AS random FROM mixed_relkind_tests.unlogged_distributed_table) foo, (SELECT intermediate_result.a, intermediate_result.b, intermediate_result.random FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer, b integer, random double precision)) bar WHERE (foo.a OPERATOR(pg_catalog.=) bar.b)
count
---------------------------------------------------------------------
0
(1 row)

UPDATE partitioned_distributed_table SET b = foo.a FROM citus_local_table AS foo;
DEBUG: Wrapping relation "citus_local_table" "foo" to a subquery
DEBUG: generating subplan XXX_1 for subquery SELECT a FROM mixed_relkind_tests.citus_local_table foo WHERE true
Expand Down Expand Up @@ -486,15 +462,6 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c
1014
(1 row)

WITH cte_1 AS MATERIALIZED (SELECT * FROM foreign_distributed_table)
SELECT COUNT(*) FROM cte_1 JOIN foreign_distributed_table USING (a);
DEBUG: generating subplan XXX_1 for CTE cte_1: SELECT a, b FROM mixed_relkind_tests.foreign_distributed_table
DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer, b integer)) cte_1 JOIN mixed_relkind_tests.foreign_distributed_table USING (a))
count
---------------------------------------------------------------------
0
(1 row)

WITH cte_1 AS MATERIALIZED (SELECT * FROM partitioned_distributed_table)
SELECT COUNT(*) FROM cte_1 JOIN partitioned_distributed_table USING (b);
DEBUG: generating subplan XXX_1 for CTE cte_1: SELECT a, b FROM mixed_relkind_tests.partitioned_distributed_table
Expand Down Expand Up @@ -658,18 +625,6 @@ $Q$);
Task Count: 4
(4 rows)

SELECT public.coordinator_plan($Q$
EXPLAIN (COSTS OFF)
SELECT a, COUNT(*) OVER (PARTITION BY a) FROM foreign_distributed_table ORDER BY 1,2;
$Q$);
coordinator_plan
---------------------------------------------------------------------
Sort
Sort Key: remote_scan.a, remote_scan.count
-> Custom Scan (Citus Adaptive)
Task Count: 4
(4 rows)

-- pull to coordinator WINDOW
SELECT public.coordinator_plan($Q$
EXPLAIN (COSTS OFF)
Expand All @@ -686,21 +641,6 @@ $Q$);
Task Count: 4
(7 rows)

SELECT public.coordinator_plan($Q$
EXPLAIN (COSTS OFF)
SELECT a, COUNT(*) OVER (PARTITION BY a+1) FROM foreign_distributed_table ORDER BY 1,2;
$Q$);
coordinator_plan
---------------------------------------------------------------------
Sort
Sort Key: remote_scan.a, (count(*) OVER (?))
-> WindowAgg
-> Sort
Sort Key: remote_scan.worker_column_2
-> Custom Scan (Citus Adaptive)
Task Count: 4
(7 rows)

-- FOR UPDATE
SELECT * FROM partitioned_distributed_table WHERE a = 1 ORDER BY 1,2 FOR UPDATE;
a | b
Expand Down Expand Up @@ -737,14 +677,6 @@ BEGIN;
---------------------------------------------------------------------
(0 rows)

COMMIT;
BEGIN;
ALTER TABLE foreign_distributed_table DROP COLUMN b CASCADE;
SELECT * FROM foreign_distributed_table;
a
---------------------------------------------------------------------
(0 rows)

COMMIT;
-- cleanup at exit
DROP SCHEMA mixed_relkind_tests CASCADE;
Loading