Merge pull request #4292 from citusdata/fix_local_join

Do not rely on set_rel_pathlist_hook for finding local relations
pull/4300/head^2
Önder Kalacı 2020-11-06 11:26:03 +01:00 committed by GitHub
commit 1f723cabd2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 297 additions and 21 deletions

View File

@ -1804,7 +1804,6 @@ multi_relation_restriction_hook(PlannerInfo *root, RelOptInfo *relOptInfo,
MemoryContext oldMemoryContext = MemoryContextSwitchTo(restrictionsMemoryContext);
bool distributedTable = IsCitusTable(rte->relid);
bool localTable = !distributedTable;
RelationRestriction *relationRestriction = palloc0(sizeof(RelationRestriction));
relationRestriction->index = restrictionIndex;
@ -1820,8 +1819,6 @@ multi_relation_restriction_hook(PlannerInfo *root, RelOptInfo *relOptInfo,
RelationRestrictionContext *relationRestrictionContext =
plannerRestrictionContext->relationRestrictionContext;
relationRestrictionContext->hasDistributedRelation |= distributedTable;
relationRestrictionContext->hasLocalRelation |= localTable;
/*
* We're also keeping track of whether all participant
@ -2308,12 +2305,26 @@ GetRTEListProperties(List *rangeTableList)
*/
continue;
}
else if (rangeTableEntry->relkind == RELKIND_MATVIEW)
if (rangeTableEntry->relkind == RELKIND_MATVIEW)
{
/*
* Skip over materialized views, here we should not consider
* materialized views as local tables.
* Record materialized views as they are similar to postgres local tables
* but it is nice to record them separately.
*
* Regular tables, partitioned tables or foreign tables can be a local or
* distributed tables and we can qualify them accurately.
*
* For regular views, we don't care because their definitions are already
* in the same query tree and we can detect what is inside the view definition.
*
* For materialized views, they are just local tables in the queries. But, when
* REFRESH MATERIALIZED VIEW is used, they behave similar to regular views, adds
* the view definition to the query. Hence, it is useful to record it seperately
* and let the callers decide on what to do.
*/
rteListProperties->hasMaterializedView = true;
continue;
}

View File

@ -2153,8 +2153,6 @@ PlanRouterQuery(Query *originalQuery,
bool replacePrunedQueryWithDummy, bool *multiShardModifyQuery,
Const **partitionValueConst)
{
RelationRestrictionContext *relationRestrictionContext =
plannerRestrictionContext->relationRestrictionContext;
bool isMultiShardQuery = false;
DeferredErrorMessage *planningError = NULL;
bool shardsPresent = false;
@ -2267,13 +2265,15 @@ PlanRouterQuery(Query *originalQuery,
/* we need anchor shard id for select queries with router planner */
uint64 shardId = GetAnchorShardId(*prunedShardIntervalListList);
bool hasLocalRelation = relationRestrictionContext->hasLocalRelation;
/* both Postgres tables and materialized tables are locally avaliable */
RTEListProperties *rteProperties = GetRTEListPropertiesForQuery(originalQuery);
bool hasPostgresLocalRelation =
rteProperties->hasPostgresLocalTable || rteProperties->hasMaterializedView;
List *taskPlacementList =
CreateTaskPlacementListForShardIntervals(*prunedShardIntervalListList,
shardsPresent,
replacePrunedQueryWithDummy,
hasLocalRelation);
hasPostgresLocalRelation);
if (taskPlacementList == NIL)
{
planningError = DeferredError(ERRCODE_FEATURE_NOT_SUPPORTED,
@ -3554,8 +3554,6 @@ CopyRelationRestrictionContext(RelationRestrictionContext *oldContext)
(RelationRestrictionContext *) palloc(sizeof(RelationRestrictionContext));
ListCell *relationRestrictionCell = NULL;
newContext->hasDistributedRelation = oldContext->hasDistributedRelation;
newContext->hasLocalRelation = oldContext->hasLocalRelation;
newContext->allReferenceTables = oldContext->allReferenceTables;
newContext->relationRestrictionList = NIL;

View File

@ -1820,10 +1820,6 @@ FilterPlannerRestrictionForQuery(PlannerRestrictionContext *plannerRestrictionCo
filteredRelationRestrictionContext->allReferenceTables =
(totalRelationCount == referenceRelationCount);
/* we currently don't support local relations and we cannot come up to this point */
filteredRelationRestrictionContext->hasLocalRelation = false;
filteredRelationRestrictionContext->hasDistributedRelation = true;
/* finally set the relation and join restriction contexts */
filteredPlannerRestrictionContext->relationRestrictionContext =
filteredRelationRestrictionContext;

View File

@ -40,8 +40,6 @@ extern int PlannerLevel;
typedef struct RelationRestrictionContext
{
bool hasDistributedRelation;
bool hasLocalRelation;
bool allReferenceTables;
List *relationRestrictionList;
} RelationRestrictionContext;
@ -148,8 +146,10 @@ typedef struct RTEListProperties
/* includes hash, append and range partitioned tables */
bool hasDistributedTable;
/* union of above three */
/* union of hasReferenceTable, hasCitusLocalTable and hasDistributedTable */
bool hasCitusTable;
bool hasMaterializedView;
} RTEListProperties;

View File

@ -29,6 +29,15 @@ SELECT count(*) FROM temp_lineitem;
1706
(1 row)
-- can create router materialized views
CREATE MATERIALIZED VIEW mode_counts_router
AS SELECT l_shipmode, count(*) FROM temp_lineitem WHERE l_orderkey = 1 GROUP BY l_shipmode;
SELECT * FROM mode_counts_router;
l_shipmode | count
---------------------------------------------------------------------
AIR | 1
(1 row)
-- can create and query materialized views
CREATE MATERIALIZED VIEW mode_counts
AS SELECT l_shipmode, count(*) FROM temp_lineitem GROUP BY l_shipmode;
@ -59,6 +68,7 @@ SELECT * FROM mode_counts WHERE l_shipmode = 'AIR' ORDER BY 2 DESC, 1 LIMIT 10;
DROP MATERIALIZED VIEW mode_counts;
DROP TABLE temp_lineitem CASCADE;
NOTICE: drop cascades to materialized view mode_counts_router
-- Refresh single-shard materialized view
CREATE MATERIALIZED VIEW materialized_view AS
SELECT orders_hash_part.o_orderdate, total_price.price_sum

View File

@ -0,0 +1,201 @@
CREATE SCHEMA postgres_local_table;
SET search_path TO postgres_local_table;
CREATE TABLE local_table(a INT);
INSERT INTO local_table VALUES (1),(2),(3);
CREATE RECURSIVE VIEW recursive_view(val_1, val_2) AS
(
VALUES(0,1)
UNION ALL
SELECT GREATEST(val_1,val_2),val_1 + val_2 AS local_table
FROM
recursive_view
WHERE val_2 < 50
);
CREATE RECURSIVE VIEW recursive_defined_non_recursive_view(c) AS (SELECT 1 FROM local_table);
CREATE TABLE ref_table(a int, b INT);
SELECT create_reference_table('ref_table');
create_reference_table
---------------------------------------------------------------------
(1 row)
INSERT INTO ref_table VALUES (1,1);
SELECT ref_table.* FROM ref_table LEFT OUTER JOIN (SELECT * FROM recursive_view WHERE FALSE) AS sub ON FALSE;
a | b
---------------------------------------------------------------------
1 | 1
(1 row)
SELECT ref_table.* FROM ref_table LEFT OUTER JOIN (SELECT * FROM (SELECT 1, random() FROM local_table) as s WHERE FALSE) AS sub ON FALSE ORDER BY 1,2;
a | b
---------------------------------------------------------------------
1 | 1
(1 row)
SELECT ref_table.* FROM ref_table LEFT OUTER JOIN (SELECT * FROM recursive_view WHERE FALSE) AS sub ON TRUE ORDER BY 1,2;
a | b
---------------------------------------------------------------------
1 | 1
(1 row)
SELECT ref_table.* FROM ref_table LEFT OUTER JOIN (SELECT * FROM (SELECT 1, random() FROM local_table) as s WHERE FALSE) AS sub ON TRUE ORDER BY 1,2;
a | b
---------------------------------------------------------------------
1 | 1
(1 row)
SELECT ref_table.* FROM ref_table LEFT OUTER JOIN (SELECT * FROM recursive_view WHERE TRUE) AS sub ON TRUE ORDER BY 1,2;
a | b
---------------------------------------------------------------------
1 | 1
1 | 1
1 | 1
1 | 1
1 | 1
1 | 1
1 | 1
1 | 1
1 | 1
1 | 1
(10 rows)
SELECT ref_table.* FROM ref_table LEFT OUTER JOIN (SELECT * FROM (SELECT 1, random() FROM local_table) as s WHERE TRUE) AS sub ON TRUE ORDER BY 1,2;
a | b
---------------------------------------------------------------------
1 | 1
1 | 1
1 | 1
(3 rows)
SELECT ref_table.* FROM ref_table JOIN (SELECT * FROM recursive_view WHERE FALSE) AS sub ON FALSE ORDER BY 1,2;
a | b
---------------------------------------------------------------------
(0 rows)
SELECT ref_table.* FROM ref_table JOIN (SELECT * FROM (SELECT 1, random() FROM local_table) as s WHERE FALSE) AS sub ON FALSE ORDER BY 1,2;
a | b
---------------------------------------------------------------------
(0 rows)
SELECT ref_table.* FROM ref_table JOIN (SELECT * FROM recursive_view WHERE FALSE) AS sub ON TRUE ORDER BY 1,2;
a | b
---------------------------------------------------------------------
(0 rows)
SELECT ref_table.* FROM ref_table JOIN (SELECT * FROM (SELECT 1, random() FROM local_table) as s WHERE FALSE) AS sub ON TRUE ORDER BY 1,2;
a | b
---------------------------------------------------------------------
(0 rows)
SELECT ref_table.* FROM ref_table JOIN (SELECT * FROM recursive_view WHERE TRUE) AS sub ON TRUE ORDER BY 1,2;
a | b
---------------------------------------------------------------------
1 | 1
1 | 1
1 | 1
1 | 1
1 | 1
1 | 1
1 | 1
1 | 1
1 | 1
1 | 1
(10 rows)
SELECT ref_table.* FROM ref_table JOIN (SELECT * FROM (SELECT 1, random() FROM local_table) as s WHERE TRUE) AS sub ON TRUE ORDER BY 1,2;
a | b
---------------------------------------------------------------------
1 | 1
1 | 1
1 | 1
(3 rows)
SELECT ref_table.* FROM ref_table LEFT OUTER JOIN (SELECT * FROM recursive_defined_non_recursive_view WHERE FALSE) AS sub ON FALSE ORDER BY 1,2;
a | b
---------------------------------------------------------------------
1 | 1
(1 row)
SELECT ref_table.* FROM ref_table LEFT OUTER JOIN (SELECT * FROM recursive_defined_non_recursive_view WHERE FALSE) AS sub ON TRUE ORDER BY 1,2;
a | b
---------------------------------------------------------------------
1 | 1
(1 row)
SELECT ref_table.* FROM ref_table LEFT OUTER JOIN (SELECT * FROM recursive_defined_non_recursive_view WHERE TRUE) AS sub ON TRUE ORDER BY 1,2;
a | b
---------------------------------------------------------------------
1 | 1
1 | 1
1 | 1
(3 rows)
SELECT ref_table.* FROM ref_table JOIN (SELECT * FROM recursive_defined_non_recursive_view WHERE FALSE) AS sub ON FALSE ORDER BY 1,2;
a | b
---------------------------------------------------------------------
(0 rows)
SELECT ref_table.* FROM ref_table JOIN (SELECT * FROM recursive_defined_non_recursive_view WHERE FALSE) AS sub ON TRUE ORDER BY 1,2;
a | b
---------------------------------------------------------------------
(0 rows)
SELECT ref_table.* FROM ref_table JOIN (SELECT * FROM recursive_defined_non_recursive_view WHERE TRUE) AS sub ON TRUE ORDER BY 1,2;
a | b
---------------------------------------------------------------------
1 | 1
1 | 1
1 | 1
(3 rows)
SELECT ref_table.* FROM ref_table WHERE EXISTS (SELECT * FROM local_table l WHERE l.a = ref_table.a);
ERROR: direct joins between distributed and local tables are not supported
HINT: Use CTE's or subqueries to select from local tables and use them in joins
SELECT ref_table.* FROM ref_table WHERE EXISTS (SELECT * FROM local_table l WHERE l.a = ref_table.a) AND false;
a | b
---------------------------------------------------------------------
(0 rows)
SELECT ref_table.* FROM ref_table WHERE EXISTS (SELECT * FROM local_table l WHERE l.a = ref_table.a AND false);
a | b
---------------------------------------------------------------------
(0 rows)
SELECT ref_table.* FROM ref_table WHERE EXISTS (SELECT * FROM recursive_view l WHERE l.val_1 = ref_table.a);
a | b
---------------------------------------------------------------------
1 | 1
(1 row)
SELECT ref_table.* FROM ref_table WHERE EXISTS (SELECT * FROM recursive_view l WHERE l.val_1 = ref_table.a) AND false;
a | b
---------------------------------------------------------------------
(0 rows)
SELECT ref_table.* FROM ref_table WHERE EXISTS (SELECT * FROM recursive_view l WHERE l.val_1 = ref_table.a AND false);
a | b
---------------------------------------------------------------------
(0 rows)
SELECT ref_table.* FROM ref_table WHERE EXISTS (SELECT * FROM recursive_defined_non_recursive_view l WHERE l.c = ref_table.a);
a | b
---------------------------------------------------------------------
1 | 1
(1 row)
SELECT ref_table.* FROM ref_table WHERE EXISTS (SELECT * FROM recursive_defined_non_recursive_view l WHERE l.c = ref_table.a) AND false;
a | b
---------------------------------------------------------------------
(0 rows)
SELECT ref_table.* FROM ref_table WHERE EXISTS (SELECT * FROM recursive_defined_non_recursive_view l WHERE l.c = ref_table.a AND false);
a | b
---------------------------------------------------------------------
(0 rows)
DROP SCHEMA postgres_local_table CASCADE;
NOTICE: drop cascades to 4 other objects
DETAIL: drop cascades to table local_table
drop cascades to view recursive_view
drop cascades to view recursive_defined_non_recursive_view
drop cascades to table ref_table

View File

@ -85,7 +85,7 @@ test: set_operation_and_local_tables
test: subqueries_deep subquery_view subquery_partitioning subquery_complex_target_list subqueries_not_supported subquery_in_where
test: non_colocated_leaf_subquery_joins non_colocated_subquery_joins non_colocated_join_order
test: subquery_prepared_statements pg12 cte_inline pg13
test: subquery_prepared_statements pg12 cte_inline pg13 recursive_view_local_table
test: tableam
# ----------

View File

@ -19,6 +19,11 @@ SELECT count(*) FROM temp_lineitem;
INSERT INTO temp_lineitem SELECT * FROM air_shipped_lineitems WHERE l_shipmode = 'MAIL';
SELECT count(*) FROM temp_lineitem;
-- can create router materialized views
CREATE MATERIALIZED VIEW mode_counts_router
AS SELECT l_shipmode, count(*) FROM temp_lineitem WHERE l_orderkey = 1 GROUP BY l_shipmode;
SELECT * FROM mode_counts_router;
-- can create and query materialized views
CREATE MATERIALIZED VIEW mode_counts
AS SELECT l_shipmode, count(*) FROM temp_lineitem GROUP BY l_shipmode;

View File

@ -0,0 +1,55 @@
CREATE SCHEMA postgres_local_table;
SET search_path TO postgres_local_table;
CREATE TABLE local_table(a INT);
INSERT INTO local_table VALUES (1),(2),(3);
CREATE RECURSIVE VIEW recursive_view(val_1, val_2) AS
(
VALUES(0,1)
UNION ALL
SELECT GREATEST(val_1,val_2),val_1 + val_2 AS local_table
FROM
recursive_view
WHERE val_2 < 50
);
CREATE RECURSIVE VIEW recursive_defined_non_recursive_view(c) AS (SELECT 1 FROM local_table);
CREATE TABLE ref_table(a int, b INT);
SELECT create_reference_table('ref_table');
INSERT INTO ref_table VALUES (1,1);
SELECT ref_table.* FROM ref_table LEFT OUTER JOIN (SELECT * FROM recursive_view WHERE FALSE) AS sub ON FALSE;
SELECT ref_table.* FROM ref_table LEFT OUTER JOIN (SELECT * FROM (SELECT 1, random() FROM local_table) as s WHERE FALSE) AS sub ON FALSE ORDER BY 1,2;
SELECT ref_table.* FROM ref_table LEFT OUTER JOIN (SELECT * FROM recursive_view WHERE FALSE) AS sub ON TRUE ORDER BY 1,2;
SELECT ref_table.* FROM ref_table LEFT OUTER JOIN (SELECT * FROM (SELECT 1, random() FROM local_table) as s WHERE FALSE) AS sub ON TRUE ORDER BY 1,2;
SELECT ref_table.* FROM ref_table LEFT OUTER JOIN (SELECT * FROM recursive_view WHERE TRUE) AS sub ON TRUE ORDER BY 1,2;
SELECT ref_table.* FROM ref_table LEFT OUTER JOIN (SELECT * FROM (SELECT 1, random() FROM local_table) as s WHERE TRUE) AS sub ON TRUE ORDER BY 1,2;
SELECT ref_table.* FROM ref_table JOIN (SELECT * FROM recursive_view WHERE FALSE) AS sub ON FALSE ORDER BY 1,2;
SELECT ref_table.* FROM ref_table JOIN (SELECT * FROM (SELECT 1, random() FROM local_table) as s WHERE FALSE) AS sub ON FALSE ORDER BY 1,2;
SELECT ref_table.* FROM ref_table JOIN (SELECT * FROM recursive_view WHERE FALSE) AS sub ON TRUE ORDER BY 1,2;
SELECT ref_table.* FROM ref_table JOIN (SELECT * FROM (SELECT 1, random() FROM local_table) as s WHERE FALSE) AS sub ON TRUE ORDER BY 1,2;
SELECT ref_table.* FROM ref_table JOIN (SELECT * FROM recursive_view WHERE TRUE) AS sub ON TRUE ORDER BY 1,2;
SELECT ref_table.* FROM ref_table JOIN (SELECT * FROM (SELECT 1, random() FROM local_table) as s WHERE TRUE) AS sub ON TRUE ORDER BY 1,2;
SELECT ref_table.* FROM ref_table LEFT OUTER JOIN (SELECT * FROM recursive_defined_non_recursive_view WHERE FALSE) AS sub ON FALSE ORDER BY 1,2;
SELECT ref_table.* FROM ref_table LEFT OUTER JOIN (SELECT * FROM recursive_defined_non_recursive_view WHERE FALSE) AS sub ON TRUE ORDER BY 1,2;
SELECT ref_table.* FROM ref_table LEFT OUTER JOIN (SELECT * FROM recursive_defined_non_recursive_view WHERE TRUE) AS sub ON TRUE ORDER BY 1,2;
SELECT ref_table.* FROM ref_table JOIN (SELECT * FROM recursive_defined_non_recursive_view WHERE FALSE) AS sub ON FALSE ORDER BY 1,2;
SELECT ref_table.* FROM ref_table JOIN (SELECT * FROM recursive_defined_non_recursive_view WHERE FALSE) AS sub ON TRUE ORDER BY 1,2;
SELECT ref_table.* FROM ref_table JOIN (SELECT * FROM recursive_defined_non_recursive_view WHERE TRUE) AS sub ON TRUE ORDER BY 1,2;
SELECT ref_table.* FROM ref_table WHERE EXISTS (SELECT * FROM local_table l WHERE l.a = ref_table.a);
SELECT ref_table.* FROM ref_table WHERE EXISTS (SELECT * FROM local_table l WHERE l.a = ref_table.a) AND false;
SELECT ref_table.* FROM ref_table WHERE EXISTS (SELECT * FROM local_table l WHERE l.a = ref_table.a AND false);
SELECT ref_table.* FROM ref_table WHERE EXISTS (SELECT * FROM recursive_view l WHERE l.val_1 = ref_table.a);
SELECT ref_table.* FROM ref_table WHERE EXISTS (SELECT * FROM recursive_view l WHERE l.val_1 = ref_table.a) AND false;
SELECT ref_table.* FROM ref_table WHERE EXISTS (SELECT * FROM recursive_view l WHERE l.val_1 = ref_table.a AND false);
SELECT ref_table.* FROM ref_table WHERE EXISTS (SELECT * FROM recursive_defined_non_recursive_view l WHERE l.c = ref_table.a);
SELECT ref_table.* FROM ref_table WHERE EXISTS (SELECT * FROM recursive_defined_non_recursive_view l WHERE l.c = ref_table.a) AND false;
SELECT ref_table.* FROM ref_table WHERE EXISTS (SELECT * FROM recursive_defined_non_recursive_view l WHERE l.c = ref_table.a AND false);
DROP SCHEMA postgres_local_table CASCADE;