stop distributing views with no distributed dependency if GUC DistributeLocalViews is set false. (#6083)

pull/6128/head
aykut-bozkurt 2022-08-04 12:34:40 +03:00 committed by GitHub
parent 4ffe436bf9
commit 3ddc089651
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 212 additions and 1 deletions

View File

@ -35,11 +35,50 @@
#include "utils/lsyscache.h"
#include "utils/syscache.h"
/*
* GUC controls some restrictions for local objects. For example,
* if it is disabled, a local view with no distributed relation dependency
* will be created even if it has circular dependency and will not
* log error or warning. Citus will normally restrict that behaviour for the
* local views. e.g CREATE TABLE local_t (a int);
* CREATE VIEW vv1 as SELECT * FROM local_t;
* CREATE OR REPLACE VIEW vv2 as SELECT * FROM vv1;
*
* When the GUC is disabled, citus also wont distribute the local
* view which has no citus relation dependency to workers. Otherwise, it distributes
* them by default. e.g create view v as select 1;
*/
bool EnforceLocalObjectRestrictions = true;
static List * FilterNameListForDistributedViews(List *viewNamesList, bool missing_ok);
static void AppendQualifiedViewNameToCreateViewCommand(StringInfo buf, Oid viewOid);
static void AppendViewDefinitionToCreateViewCommand(StringInfo buf, Oid viewOid);
static void AppendAliasesToCreateViewCommand(StringInfo createViewCommand, Oid viewOid);
static void AppendOptionsToCreateViewCommand(StringInfo createViewCommand, Oid viewOid);
static bool ViewHasDistributedRelationDependency(ObjectAddress *viewObjectAddress);
/*
* ViewHasDistributedRelationDependency returns true if given view at address has
* any distributed relation dependency.
*/
static bool
ViewHasDistributedRelationDependency(ObjectAddress *viewObjectAddress)
{
List *dependencies = GetAllDependenciesForObject(viewObjectAddress);
ObjectAddress *dependency = NULL;
foreach_ptr(dependency, dependencies)
{
if (dependency->classId == RelationRelationId && IsAnyObjectDistributed(
list_make1(dependency)))
{
return true;
}
}
return false;
}
/*
* PreprocessViewStmt is called during the planning phase for CREATE OR REPLACE VIEW
@ -110,6 +149,36 @@ PostprocessViewStmt(Node *node, const char *queryString)
return NIL;
}
/*
* If it is disabled, a local view with no distributed relation dependency
* will be created even if it has circular dependency and will not
* log error or warning. Citus will normally restrict that behaviour for the
* local views. e.g CREATE TABLE local_t (a int);
* CREATE VIEW vv1 as SELECT * FROM local_t;
* CREATE OR REPLACE VIEW vv2 as SELECT * FROM vv1;
*
* When the GUC is disabled, citus also wont distribute the local
* view which has no citus relation dependency to workers. Otherwise, it distributes
* them by default. e.g create view v as select 1;
*
* We disable local object restrictions during pg vanilla tests to not diverge
* from Postgres in terms of error messages.
*/
if (!EnforceLocalObjectRestrictions)
{
/* we asserted that we have only one address. */
ObjectAddress *viewAddress = linitial(viewAddresses);
if (!ViewHasDistributedRelationDependency(viewAddress))
{
/*
* The local view has no distributed relation dependency, so we can allow
* it to be created even if it has circular dependency.
*/
return NIL;
}
}
EnsureAllObjectDependenciesExistOnAllNodes(viewAddresses);
/* We have already asserted that we have exactly 1 address in the addresses. */

View File

@ -843,7 +843,10 @@ ErrorOrWarnIfObjectHasUnsupportedDependency(const ObjectAddress *objectAddress)
}
else
{
RaiseDeferredError(errMsg, WARNING);
if (EnableUnsupportedFeatureMessages)
{
RaiseDeferredError(errMsg, WARNING);
}
}
return true;

View File

@ -1204,6 +1204,17 @@ RegisterCitusConfigVariables(void)
GUC_NO_SHOW_ALL,
NULL, NULL, NULL);
DefineCustomBoolVariable(
"citus.enforce_object_restrictions_for_local_objects",
gettext_noop(
"Controls some restrictions for local objects."),
NULL,
&EnforceLocalObjectRestrictions,
true,
PGC_USERSET,
GUC_NO_SHOW_ALL,
NULL, NULL, NULL);
DefineCustomIntVariable(
"citus.executor_slow_start_interval",
gettext_noop("Time to wait between opening connections to the same worker node"),

View File

@ -31,6 +31,8 @@ extern bool EnableUnsafeTriggers;
extern int MaxMatViewSizeToAutoRecreate;
extern bool EnforceLocalObjectRestrictions;
extern void SwitchToSequentialAndLocalExecutionIfRelationNameTooLong(Oid relationId,
char *
finalRelationName);

View File

@ -855,6 +855,85 @@ HINT: Use DROP MATERIALIZED VIEW to remove a materialized view.
DROP MATERIALIZED VIEW IF EXISTS axx.temp_view_to_drop;
DROP MATERIALIZED VIEW IF EXISTS axx.temp_view_to_drop;
NOTICE: materialized view "temp_view_to_drop" does not exist, skipping
-- Test the GUC citus.enforce_object_restrictions_for_local_objects
SET search_path to view_prop_schema;
CREATE TABLE local_t (a int);
-- tests when citus.enforce_object_restrictions_for_local_objects=true
SET citus.enforce_object_restrictions_for_local_objects TO true;
-- views will be created locally with warnings
CREATE VIEW vv1 as SELECT * FROM local_t;
WARNING: "view vv1" has dependency to "table local_t" that is not in Citus' metadata
DETAIL: "view vv1" will be created only locally
HINT: Distribute "table local_t" first to distribute "view vv1"
CREATE OR REPLACE VIEW vv2 as SELECT * FROM vv1;
WARNING: "view vv2" has dependency to "table local_t" that is not in Citus' metadata
DETAIL: "view vv2" will be created only locally
HINT: Distribute "table local_t" first to distribute "view vv2"
-- view will fail due to local circular dependency
CREATE OR REPLACE VIEW vv1 as SELECT * FROM vv2;
ERROR: Citus can not handle circular dependencies between distributed objects
DETAIL: "view vv1" circularly depends itself, resolve circular dependency first
-- local view with no citus relation dependency will be distributed
CREATE VIEW v_dist AS SELECT 1;
-- show that the view is in pg_dist_object
SELECT COUNT(*) FROM pg_dist_object WHERE objid = 'v_dist'::regclass;
count
---------------------------------------------------------------------
1
(1 row)
-- tests when citus.enforce_object_restrictions_for_local_objects=false
SET citus.enforce_object_restrictions_for_local_objects TO false;
SET citus.enable_unsupported_feature_messages TO false;
-- views will be created locally without errors OR warnings
CREATE VIEW vv3 as SELECT * FROM local_t;
CREATE OR REPLACE VIEW vv4 as SELECT * FROM vv3;
CREATE OR REPLACE VIEW vv3 as SELECT * FROM vv4;
-- show that views are NOT in pg_dist_object
SELECT COUNT(*) FROM pg_dist_object WHERE objid IN ('vv3'::regclass, 'vv4'::regclass);
count
---------------------------------------------------------------------
0
(1 row)
-- local view with no citus relation dependency will NOT be distributed
CREATE VIEW v_local_only AS SELECT 1;
-- show that the view is NOT in pg_dist_object
SELECT COUNT(*) FROM pg_dist_object WHERE objid = 'v_local_only'::regclass;
count
---------------------------------------------------------------------
0
(1 row)
-- distribute the local table and check the distribution of dependent views
SELECT create_distributed_table('local_t', 'a');
create_distributed_table
---------------------------------------------------------------------
(1 row)
-- show that views with no circular dependency are in pg_dist_object
SELECT COUNT(*) FROM pg_dist_object WHERE objid IN ('vv1'::regclass, 'vv2'::regclass);
count
---------------------------------------------------------------------
2
(1 row)
-- show that views with circular dependency are NOT in pg_dist_object
SELECT COUNT(*) FROM pg_dist_object WHERE objid IN ('vv3'::regclass, 'vv4'::regclass);
count
---------------------------------------------------------------------
0
(1 row)
-- show that we cannot re-create the circular views ever
CREATE OR REPLACE VIEW vv3 as SELECT * FROM local_t;
CREATE OR REPLACE VIEW vv4 as SELECT * FROM vv3;
CREATE OR REPLACE VIEW vv3 as SELECT * FROM vv4;
ERROR: Citus can not handle circular dependencies between distributed objects
DETAIL: "view vv3" circularly depends itself, resolve circular dependency first
RESET citus.enable_unsupported_feature_messages;
RESET citus.enforce_object_restrictions_for_local_objects;
SET client_min_messages TO ERROR;
DROP SCHEMA view_prop_schema_inner CASCADE;
DROP SCHEMA view_prop_schema, axx CASCADE;

View File

@ -503,6 +503,9 @@ if(!$vanillaDev && $vanillatest)
# we disable citus related unwanted messages to not break postgres vanilla test behaviour.
push(@pgOptions, "citus.enable_unsupported_feature_messages=false");
# we disable some restrictions for local objects like local views to not break postgres vanilla test behaviour.
push(@pgOptions, "citus.enforce_object_restrictions_for_local_objects=false");
}
if ($useMitmproxy)

View File

@ -497,6 +497,50 @@ DROP VIEW IF EXISTS axx.temp_view_to_drop;
DROP MATERIALIZED VIEW IF EXISTS axx.temp_view_to_drop;
DROP MATERIALIZED VIEW IF EXISTS axx.temp_view_to_drop;
-- Test the GUC citus.enforce_object_restrictions_for_local_objects
SET search_path to view_prop_schema;
CREATE TABLE local_t (a int);
-- tests when citus.enforce_object_restrictions_for_local_objects=true
SET citus.enforce_object_restrictions_for_local_objects TO true;
-- views will be created locally with warnings
CREATE VIEW vv1 as SELECT * FROM local_t;
CREATE OR REPLACE VIEW vv2 as SELECT * FROM vv1;
-- view will fail due to local circular dependency
CREATE OR REPLACE VIEW vv1 as SELECT * FROM vv2;
-- local view with no citus relation dependency will be distributed
CREATE VIEW v_dist AS SELECT 1;
-- show that the view is in pg_dist_object
SELECT COUNT(*) FROM pg_dist_object WHERE objid = 'v_dist'::regclass;
-- tests when citus.enforce_object_restrictions_for_local_objects=false
SET citus.enforce_object_restrictions_for_local_objects TO false;
SET citus.enable_unsupported_feature_messages TO false;
-- views will be created locally without errors OR warnings
CREATE VIEW vv3 as SELECT * FROM local_t;
CREATE OR REPLACE VIEW vv4 as SELECT * FROM vv3;
CREATE OR REPLACE VIEW vv3 as SELECT * FROM vv4;
-- show that views are NOT in pg_dist_object
SELECT COUNT(*) FROM pg_dist_object WHERE objid IN ('vv3'::regclass, 'vv4'::regclass);
-- local view with no citus relation dependency will NOT be distributed
CREATE VIEW v_local_only AS SELECT 1;
-- show that the view is NOT in pg_dist_object
SELECT COUNT(*) FROM pg_dist_object WHERE objid = 'v_local_only'::regclass;
-- distribute the local table and check the distribution of dependent views
SELECT create_distributed_table('local_t', 'a');
-- show that views with no circular dependency are in pg_dist_object
SELECT COUNT(*) FROM pg_dist_object WHERE objid IN ('vv1'::regclass, 'vv2'::regclass);
-- show that views with circular dependency are NOT in pg_dist_object
SELECT COUNT(*) FROM pg_dist_object WHERE objid IN ('vv3'::regclass, 'vv4'::regclass);
-- show that we cannot re-create the circular views ever
CREATE OR REPLACE VIEW vv3 as SELECT * FROM local_t;
CREATE OR REPLACE VIEW vv4 as SELECT * FROM vv3;
CREATE OR REPLACE VIEW vv3 as SELECT * FROM vv4;
RESET citus.enable_unsupported_feature_messages;
RESET citus.enforce_object_restrictions_for_local_objects;
SET client_min_messages TO ERROR;
DROP SCHEMA view_prop_schema_inner CASCADE;
DROP SCHEMA view_prop_schema, axx CASCADE;