Error out for views with circular dependencies (#6051)

Adds error check for views with circular dependencies
pull/6090/head
Ahmet Gedemenli 2022-07-27 17:57:45 +03:00 committed by GitHub
parent b08e5ec29d
commit 2b2a529653
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 72 additions and 10 deletions

View File

@ -202,12 +202,12 @@ ErrorIfCircularDependencyExists(const ObjectAddress *objectAddress)
/*
* DeferErrorIfCircularDependencyExists checks whether given object has
* circular dependency with itself via existing objects of pg_dist_object.
* circular dependency with itself. If so, returns a deferred error.
*/
DeferredErrorMessage *
DeferErrorIfCircularDependencyExists(const ObjectAddress *objectAddress)
{
List *dependencies = GetAllSupportedDependenciesForObject(objectAddress);
List *dependencies = GetAllDependenciesForObject(objectAddress);
ObjectAddress *dependency = NULL;
foreach_ptr(dependency, dependencies)

View File

@ -1615,7 +1615,7 @@ ExpandCitusSupportedTypes(ObjectAddressCollector *collector, ObjectAddress targe
* rule and that rule has dependencies to other objects.
*/
char relKind = get_rel_relkind(relationId);
if (relKind == RELKIND_VIEW)
if (relKind == RELKIND_VIEW || relKind == RELKIND_MATVIEW)
{
List *ruleRefDepList = GetViewRuleReferenceDependencyList(relationId);
result = list_concat(result, ruleRefDepList);
@ -2109,6 +2109,23 @@ GetDependingViews(Oid relationId)
ViewDependencyNode *dependingNode = NULL;
foreach_ptr(dependingNode, node->dependingNodes)
{
ObjectAddress relationAddress = { 0 };
ObjectAddressSet(relationAddress, RelationRelationId, dependingNode->id);
/*
* This function does not catch views with circular dependencies,
* because of the remaining dependency count check below.
* Here we check if the view has a circular dependency or not.
* If yes, we error out with a message that tells the user that
* Citus does not handle circular dependencies.
*/
DeferredErrorMessage *depError =
DeferErrorIfCircularDependencyExists(&relationAddress);
if (depError != NULL)
{
RaiseDeferredError(depError, ERROR);
}
dependingNode->remainingDependencyCount--;
if (dependingNode->remainingDependencyCount == 0)
{

View File

@ -882,8 +882,13 @@ CREATE MATERIALIZED VIEW matview_101 AS SELECT * from loc_tb;
CREATE VIEW v103 AS SELECT * from loc_tb;
CREATE MATERIALIZED VIEW matview_102 AS SELECT * from loc_tb JOIN v103 USING (a);
CREATE OR REPLACE VIEW v103 AS SELECT * from loc_tb JOIN matview_102 USING (a);
-- fails to add local table to metadata, because of the circular dependency
ALTER TABLE loc_tb ADD CONSTRAINT fkey FOREIGN KEY (a) references ref_tb(a);
ERROR: Citus can not handle circular dependencies between distributed objects
-- drop the view&matview with circular dependency
DROP VIEW v103 CASCADE;
SET client_min_messages TO DEBUG1;
-- auto undistribute
-- now it should successfully add to metadata and create the views on workers
ALTER TABLE loc_tb ADD CONSTRAINT fkey FOREIGN KEY (a) references ref_tb(a);
DEBUG: executing "CREATE OR REPLACE VIEW citus_local_tables_mx.v100 (a) AS SELECT loc_tb.a
FROM citus_local_tables_mx.loc_tb; ALTER VIEW citus_local_tables_mx.v100 OWNER TO postgres"
@ -907,6 +912,7 @@ select run_command_on_workers($$SELECT count(*) from citus_local_tables_mx.v100,
(localhost,57638,t,0)
(2 rows)
-- auto undistribute
ALTER TABLE loc_tb DROP CONSTRAINT fkey;
-- fails because fkey is dropped and table is converted to local table
select run_command_on_workers($$SELECT count(*) from citus_local_tables_mx.v100$$);
@ -1075,6 +1081,29 @@ SELECT count(*) FROM citus_local_tables_mx.mv4;
0
(1 row)
-- test circular dependency detection among views
create table root_tbl (a int);
create materialized view chain_v1 as select * from root_tbl;
create view chain_v2 as select * from chain_v1;
WARNING: "view chain_v2" has dependency to "table root_tbl" that is not in Citus' metadata
create materialized view chain_v3 as select * from chain_v2;
create or replace view chain_v2 as select * from chain_v1 join chain_v3 using (a);
WARNING: "view chain_v2" has dependency on unsupported object "materialized view chain_v3"
-- catch circular dependency and error out
select citus_add_local_table_to_metadata('root_tbl');
ERROR: Citus can not handle circular dependencies between distributed objects
-- same for create_distributed_table
select create_distributed_table('root_tbl','a');
ERROR: Citus can not handle circular dependencies between distributed objects
-- fix the circular dependency and add to metadata
create or replace view chain_v2 as select * from chain_v1;
WARNING: "view chain_v2" has dependency to "table root_tbl" that is not in Citus' metadata
select citus_add_local_table_to_metadata('root_tbl');
citus_add_local_table_to_metadata
---------------------------------------------------------------------
(1 row)
-- todo: add more matview tests once 5968 and 6028 are fixed
-- cleanup at exit
set client_min_messages to error;

View File

@ -811,11 +811,8 @@ WARNING: "view v_test_2" has dependency to "table employees" that is not in Cit
DETAIL: "view v_test_2" will be created only locally
HINT: Distribute "table employees" first to distribute "view v_test_2"
SELECT create_distributed_table('employees','employee_id');
create_distributed_table
---------------------------------------------------------------------
(1 row)
ERROR: Citus can not handle circular dependencies between distributed objects
DETAIL: "view v_test_1" circularly depends itself, resolve circular dependency first
-- verify not distributed
SELECT run_command_on_workers($$SELECT count(*) FROM v_test_1$$);
run_command_on_workers

View File

@ -460,14 +460,20 @@ CREATE VIEW v103 AS SELECT * from loc_tb;
CREATE MATERIALIZED VIEW matview_102 AS SELECT * from loc_tb JOIN v103 USING (a);
CREATE OR REPLACE VIEW v103 AS SELECT * from loc_tb JOIN matview_102 USING (a);
-- fails to add local table to metadata, because of the circular dependency
ALTER TABLE loc_tb ADD CONSTRAINT fkey FOREIGN KEY (a) references ref_tb(a);
-- drop the view&matview with circular dependency
DROP VIEW v103 CASCADE;
SET client_min_messages TO DEBUG1;
-- auto undistribute
-- now it should successfully add to metadata and create the views on workers
ALTER TABLE loc_tb ADD CONSTRAINT fkey FOREIGN KEY (a) references ref_tb(a);
SET client_min_messages TO WARNING;
-- works fine
select run_command_on_workers($$SELECT count(*) from citus_local_tables_mx.v100, citus_local_tables_mx.v101, citus_local_tables_mx.v102$$);
-- auto undistribute
ALTER TABLE loc_tb DROP CONSTRAINT fkey;
-- fails because fkey is dropped and table is converted to local table
select run_command_on_workers($$SELECT count(*) from citus_local_tables_mx.v100$$);
@ -537,6 +543,19 @@ SELECT count(*) FROM citus_local_tables_mx.mv2;
SELECT count(*) FROM citus_local_tables_mx.mv3;
SELECT count(*) FROM citus_local_tables_mx.mv4;
-- test circular dependency detection among views
create table root_tbl (a int);
create materialized view chain_v1 as select * from root_tbl;
create view chain_v2 as select * from chain_v1;
create materialized view chain_v3 as select * from chain_v2;
create or replace view chain_v2 as select * from chain_v1 join chain_v3 using (a);
-- catch circular dependency and error out
select citus_add_local_table_to_metadata('root_tbl');
-- same for create_distributed_table
select create_distributed_table('root_tbl','a');
-- fix the circular dependency and add to metadata
create or replace view chain_v2 as select * from chain_v1;
select citus_add_local_table_to_metadata('root_tbl');
-- todo: add more matview tests once 5968 and 6028 are fixed
-- cleanup at exit