From 67ac3da2b016bf36e08dd7b13e03ebb21984207e Mon Sep 17 00:00:00 2001 From: aykut-bozkurt <51649454+aykut-bozkurt@users.noreply.github.com> Date: Mon, 25 Jul 2022 16:43:34 +0300 Subject: [PATCH] added citus_depended_objects udf and HideCitusDependentObjects GUC to hide citus depended objects from pg meta queries (#6055) use RecurseObjectDependencies api to find if an object is citus depended make vanilla tests runnable to see if citus_depended function is working correctly --- src/backend/distributed/metadata/dependency.c | 150 +++++++++ .../distributed/metadata/metadata_cache.c | 26 ++ .../distributed/planner/distributed_planner.c | 20 ++ .../distributed/planner/multi_explain.c | 15 + src/backend/distributed/shared_library_init.c | 13 + .../distributed/test/citus_depended_object.c | 151 +++++++++ .../distributed/utils/citus_depended_object.c | 287 ++++++++++++++++++ .../distributed/citus_depended_object.h | 24 ++ src/include/distributed/metadata/dependency.h | 1 + src/include/distributed/metadata/distobject.h | 1 + src/include/distributed/metadata_cache.h | 1 + src/test/regress/.gitignore | 21 ++ src/test/regress/Makefile | 9 +- .../expected/citus_depended_object.out | 195 ++++++++++++ src/test/regress/multi_1_schedule | 2 +- src/test/regress/pg_regress_multi.pl | 96 +++++- .../regress/sql/citus_depended_object.sql | 151 +++++++++ 17 files changed, 1146 insertions(+), 17 deletions(-) create mode 100644 src/backend/distributed/test/citus_depended_object.c create mode 100644 src/backend/distributed/utils/citus_depended_object.c create mode 100644 src/include/distributed/citus_depended_object.h create mode 100644 src/test/regress/expected/citus_depended_object.out create mode 100644 src/test/regress/sql/citus_depended_object.sql diff --git a/src/backend/distributed/metadata/dependency.c b/src/backend/distributed/metadata/dependency.c index 67747dee6..e03edadda 100644 --- a/src/backend/distributed/metadata/dependency.c +++ b/src/backend/distributed/metadata/dependency.c @@ -34,7 +34,9 @@ #include "catalog/pg_rewrite_d.h" #include "catalog/pg_shdepend.h" #include "catalog/pg_type.h" +#include "commands/extension.h" #include "common/hashfn.h" +#include "distributed/citus_depended_object.h" #include "distributed/commands.h" #include "distributed/commands/utility_hook.h" #include "distributed/listutils.h" @@ -168,11 +170,18 @@ static bool FollowNewSupportedDependencies(ObjectAddressCollector *collector, DependencyDefinition *definition); static bool FollowAllDependencies(ObjectAddressCollector *collector, DependencyDefinition *definition); +static bool FollowExtAndInternalDependencies(ObjectAddressCollector *collector, + DependencyDefinition *definition); static void ApplyAddToDependencyList(ObjectAddressCollector *collector, DependencyDefinition *definition); +static void ApplyAddCitusDependedObjectsToDependencyList( + ObjectAddressCollector *collector, + DependencyDefinition *definition); static List * GetViewRuleReferenceDependencyList(Oid relationId); static List * ExpandCitusSupportedTypes(ObjectAddressCollector *collector, ObjectAddress target); +static List * ExpandForPgVanilla(ObjectAddressCollector *collector, + ObjectAddress target); static List * GetDependentRoleIdsFDW(Oid FDWOid); static List * ExpandRolesToGroups(Oid roleid); static ViewDependencyNode * BuildViewDependencyGraph(Oid relationId, HTAB *nodeMap); @@ -280,6 +289,26 @@ GetAllDependenciesForObject(const ObjectAddress *target) } +/* + * GetAllCitusDependedDependenciesForObject returns all the dependencies + * which are owned by citus extension for the target. + */ +List * +GetAllCitusDependedDependenciesForObject(const ObjectAddress *target) +{ + ObjectAddressCollector collector = { 0 }; + InitObjectAddressCollector(&collector); + + RecurseObjectDependencies(*target, + &ExpandForPgVanilla, + &FollowExtAndInternalDependencies, + &ApplyAddCitusDependedObjectsToDependencyList, + &collector); + + return collector.dependencyList; +} + + /* * OrderObjectAddressListInDependencyOrder given a list of ObjectAddresses return a new * list of the same ObjectAddresses ordered on dependency order where dependencies @@ -1121,6 +1150,37 @@ IsAnyObjectAddressOwnedByExtension(const List *targets, } +/* + * IsObjectAddressOwnedByCitus returns true if the given object address + * is owned by the citus or citus_columnar extensions. + */ +bool +IsObjectAddressOwnedByCitus(const ObjectAddress *objectAddress) +{ + Oid citusId = get_extension_oid("citus", true); + Oid citusColumnarId = get_extension_oid("citus_columnar", true); + + /* return false because we could not find any citus extension */ + if (!OidIsValid(citusId) && !OidIsValid(citusColumnarId)) + { + return false; + } + + ObjectAddress extObjectAddress = InvalidObjectAddress; + bool ownedByExt = IsObjectAddressOwnedByExtension(objectAddress, + &extObjectAddress); + if (!ownedByExt) + { + return false; + } + + bool ownedByCitus = extObjectAddress.objectId == citusId; + bool ownedByCitusColumnar = extObjectAddress.objectId == citusColumnarId; + + return ownedByCitus || ownedByCitusColumnar; +} + + /* * FollowNewSupportedDependencies applies filters on pg_depend entries to follow all * objects which should be distributed before the root object can safely be created. @@ -1302,6 +1362,39 @@ FollowAllDependencies(ObjectAddressCollector *collector, } +/* + * FollowExtAndInternalDependencies applies filters on pg_depend entries to follow + * the dependency tree of objects in depth first order. We will visit all objects + * irrespective of it is supported by Citus or not and it is internal or not. + */ +static bool +FollowExtAndInternalDependencies(ObjectAddressCollector *collector, + DependencyDefinition *definition) +{ + ObjectAddress address = DependencyDefinitionObjectAddress(definition); + + /* + * If the object is already in our dependency list we do not have to follow any + * further + */ + if (IsObjectAddressCollected(address, collector)) + { + return false; + } + + if (CitusExtensionObject(&address)) + { + /* + * We do not need to follow citus extension because the purpose + * of our walk is to find if an object is owned by citus. + */ + return false; + } + + return true; +} + + /* * ApplyAddToDependencyList is an apply function for RecurseObjectDependencies that will * collect all the ObjectAddresses for pg_depend entries to the context, except it is @@ -1332,6 +1425,30 @@ ApplyAddToDependencyList(ObjectAddressCollector *collector, } +/* + * ApplyAddCitusDependedObjectsToDependencyList is an apply function for + * RecurseObjectDependencies that will collect all the ObjectAddresses for + * pg_depend entries to the context if it is citus extension owned one. + * + * The context here is assumed to be a (ObjectAddressCollector *) to the location where + * all ObjectAddresses will be collected. + */ +static void +ApplyAddCitusDependedObjectsToDependencyList(ObjectAddressCollector *collector, + DependencyDefinition *definition) +{ + ObjectAddress address = DependencyDefinitionObjectAddress(definition); + + /* + * We only collect the object if it is owned by citus extension. + */ + if (IsObjectAddressOwnedByCitus(&address)) + { + CollectObjectAddress(collector, &address); + } +} + + /* * ExpandCitusSupportedTypes base on supported types by citus we might want to expand * the list of objects to visit in pg_depend. @@ -1515,6 +1632,39 @@ ExpandCitusSupportedTypes(ObjectAddressCollector *collector, ObjectAddress targe } +/* + * ExpandForPgVanilla only expands only comosite types because other types + * will find their dependencies in pg_depend. The method should only be called by + * is_citus_depended_object udf. + */ +static List * +ExpandForPgVanilla(ObjectAddressCollector *collector, + ObjectAddress target) +{ + /* should only be called if GUC is enabled */ + Assert(HideCitusDependentObjects == true); + + List *result = NIL; + + if (target.classId == TypeRelationId && get_typtype(target.objectId) == + TYPTYPE_COMPOSITE) + { + /* + * types depending on other types are not captured in pg_depend, instead + * they are described with their dependencies by the relation that + * describes the composite type. + */ + Oid typeRelationId = get_typ_typrelid(target.objectId); + DependencyDefinition *dependency = + CreateObjectAddressDependencyDef(RelationRelationId, + typeRelationId); + result = lappend(result, dependency); + } + + return result; +} + + /* * GetDependentRoleIdsFDW returns a list of role oids that has privileges on the * FDW with the given object id. diff --git a/src/backend/distributed/metadata/metadata_cache.c b/src/backend/distributed/metadata/metadata_cache.c index fb6efdae6..7373162aa 100644 --- a/src/backend/distributed/metadata/metadata_cache.c +++ b/src/backend/distributed/metadata/metadata_cache.c @@ -35,6 +35,7 @@ #include "commands/extension.h" #include "commands/trigger.h" #include "distributed/backend_data.h" +#include "distributed/citus_depended_object.h" #include "distributed/colocation_utils.h" #include "distributed/connection_management.h" #include "distributed/citus_ruleutils.h" @@ -182,6 +183,7 @@ typedef struct MetadataCacheData Oid relationIsAKnownShardFuncId; Oid jsonbExtractPathFuncId; Oid jsonbExtractPathTextFuncId; + Oid CitusDependentObjectFuncId; bool databaseNameValid; char databaseName[NAMEDATALEN]; } MetadataCacheData; @@ -2896,6 +2898,30 @@ JsonbExtractPathTextFuncId(void) } +/* + * CitusDependentObjectFuncId returns oid of the is_citus_depended_object function. + */ +Oid +CitusDependentObjectFuncId(void) +{ + if (!HideCitusDependentObjects) + { + ereport(ERROR, (errmsg( + "is_citus_depended_object can only be used while running the regression tests"))); + } + + if (MetadataCache.CitusDependentObjectFuncId == InvalidOid) + { + const int argCount = 2; + + MetadataCache.CitusDependentObjectFuncId = + FunctionOid("pg_catalog", "is_citus_depended_object", argCount); + } + + return MetadataCache.CitusDependentObjectFuncId; +} + + /* * CurrentDatabaseName gets the name of the current database and caches * the result. diff --git a/src/backend/distributed/planner/distributed_planner.c b/src/backend/distributed/planner/distributed_planner.c index 7cc87dc9a..5b677fb77 100644 --- a/src/backend/distributed/planner/distributed_planner.c +++ b/src/backend/distributed/planner/distributed_planner.c @@ -17,9 +17,11 @@ #include #include "access/htup_details.h" +#include "access/xact.h" #include "catalog/pg_class.h" #include "catalog/pg_proc.h" #include "catalog/pg_type.h" +#include "distributed/citus_depended_object.h" #include "distributed/citus_nodefuncs.h" #include "distributed/citus_nodes.h" #include "distributed/citus_ruleutils.h" @@ -204,6 +206,13 @@ distributed_planner(Query *parse, */ HideShardsFromSomeApplications(parse); + /* + * If GUC is set, we prevent queries, which contain pg meta relations, from + * showing any citus dependent object. The flag is expected to be set only before + * postgres vanilla tests. + */ + HideCitusDependentObjectsOnQueriesOfPgMetaTables((Node *) parse, NULL); + /* create a restriction context and put it at the end if context list */ planContext.plannerRestrictionContext = CreateAndPushPlannerRestrictionContext(); @@ -345,6 +354,17 @@ ListContainsDistributedTableRTE(List *rangeTableList, continue; } + if (HideCitusDependentObjects && IsolationIsSerializable() && IsPgLocksTable( + rangeTableEntry)) + { + /* + * Postgres tidscan.sql test fails if we do not filter pg_locks table because + * test results, which show taken locks in serializable isolation mode, + * fails by showing extra lock taken by IsCitusTable below. + */ + continue; + } + if (IsCitusTable(rangeTableEntry->relid)) { if (maybeHasForeignDistributedTable != NULL && diff --git a/src/backend/distributed/planner/multi_explain.c b/src/backend/distributed/planner/multi_explain.c index b627ecbfa..b9ee05aec 100644 --- a/src/backend/distributed/planner/multi_explain.c +++ b/src/backend/distributed/planner/multi_explain.c @@ -25,6 +25,7 @@ #include "commands/explain.h" #include "commands/tablecmds.h" #include "optimizer/cost.h" +#include "distributed/citus_depended_object.h" #include "distributed/citus_nodefuncs.h" #include "distributed/connection_management.h" #include "distributed/deparse_shard_query.h" @@ -1185,6 +1186,20 @@ CitusExplainOneQuery(Query *query, int cursorOptions, IntoClause *into, INSTR_TIME_SET_CURRENT(planstart); + /* + * We should not hide any objects while explaining some query to not break + * postgres vanilla tests. + * + * The filter 'is_citus_depended_object' is added to explain result + * and causes some tests to fail if HideCitusDependentObjects is true. + * Therefore, we disable HideCitusDependentObjects until the current transaction + * ends. + * + * We do not use security quals because a postgres vanilla test fails + * with a change of order for its result. + */ + SetLocalHideCitusDependentObjectsDisabledWhenAlreadyEnabled(); + /* plan the query */ PlannedStmt *plan = pg_plan_query_compat(query, NULL, cursorOptions, params); INSTR_TIME_SET_CURRENT(planduration); diff --git a/src/backend/distributed/shared_library_init.c b/src/backend/distributed/shared_library_init.c index 6c44d2127..6a5f229c9 100644 --- a/src/backend/distributed/shared_library_init.c +++ b/src/backend/distributed/shared_library_init.c @@ -32,6 +32,7 @@ #include "common/string.h" #include "executor/executor.h" #include "distributed/backend_data.h" +#include "distributed/citus_depended_object.h" #include "distributed/citus_nodefuncs.h" #include "distributed/citus_safe_lib.h" #include "distributed/commands.h" @@ -1272,6 +1273,18 @@ RegisterCitusConfigVariables(void) GUC_NO_SHOW_ALL, NULL, NULL, NULL); + DefineCustomBoolVariable( + "citus.hide_citus_dependent_objects", + gettext_noop( + "Hides some objects, which depends on citus extension, from pg meta class queries." + "It is intended to be used only before postgres vanilla tests to not break them."), + NULL, + &HideCitusDependentObjects, + false, + PGC_USERSET, + GUC_SUPERUSER_ONLY | GUC_NO_SHOW_ALL, + NULL, NULL, NULL); + /* * This was a GUC we added on Citus 11.0.1, and * replaced with another name on 11.0.2 via #5920. diff --git a/src/backend/distributed/test/citus_depended_object.c b/src/backend/distributed/test/citus_depended_object.c new file mode 100644 index 000000000..f7eb383b4 --- /dev/null +++ b/src/backend/distributed/test/citus_depended_object.c @@ -0,0 +1,151 @@ +/* + * citus_depended_object.c + * + * Implements udf function related to hiding citus depended objects while executing + * postgres vanilla tests. + * + * Copyright (c) Citus Data, Inc. + */ + +#include "postgres.h" + +#include "catalog/pg_aggregate.h" +#include "catalog/pg_am.h" +#include "catalog/pg_attribute.h" +#include "catalog/pg_attrdef.h" +#include "catalog/pg_constraint.h" +#include "catalog/pg_class.h" +#include "catalog/pg_depend.h" +#include "catalog/pg_enum.h" +#include "catalog/pg_event_trigger.h" +#include "catalog/pg_language.h" +#include "catalog/pg_namespace.h" +#include "catalog/pg_proc.h" +#include "catalog/pg_rewrite.h" +#include "catalog/pg_sequence.h" +#include "catalog/pg_statistic.h" +#include "catalog/pg_trigger.h" +#include "catalog/pg_ts_config.h" +#include "catalog/pg_ts_dict.h" +#include "catalog/pg_ts_template.h" +#include "catalog/pg_type.h" +#include "distributed/citus_depended_object.h" +#include "distributed/listutils.h" +#include "distributed/metadata_cache.h" +#include "distributed/metadata/dependency.h" +#include "distributed/metadata/distobject.h" + +static bool IsCitusDependentObject(ObjectAddress objectAddress); + +PG_FUNCTION_INFO_V1(is_citus_depended_object); + +/* + * is_citus_depended_object a wrapper around IsCitusDependentObject, so + * see the details there. + * + * The first parameter expects an oid for + * a pg meta class, and the second parameter expects an oid for + * the object which is found in the pg meta class. + */ +Datum +is_citus_depended_object(PG_FUNCTION_ARGS) +{ + CheckCitusVersion(ERROR); + + if (PG_ARGISNULL(0) || PG_ARGISNULL(1)) + { + /* Because we want to return false for null arguments, we donot use strict keyword while creating that function. */ + PG_RETURN_BOOL(false); + } + + Oid metaTableId = PG_GETARG_OID(0); + Oid objectId = PG_GETARG_OID(1); + + if (!OidIsValid(metaTableId) || !OidIsValid(objectId)) + { + /* we cannot continue without valid meta table or object oid */ + PG_RETURN_BOOL(false); + } + + bool dependsOnCitus = false; + + ObjectAddress objectAdress = { metaTableId, objectId, 0 }; + + switch (metaTableId) + { + case ProcedureRelationId: + case AccessMethodRelationId: + case EventTriggerRelationId: + case TriggerRelationId: + case TSConfigRelationId: + case TSTemplateRelationId: + case TSDictionaryRelationId: + case LanguageRelationId: + case RewriteRelationId: + case AttrDefaultRelationId: + case NamespaceRelationId: + case ConstraintRelationId: + case TypeRelationId: + case RelationRelationId: + { + /* meta classes that access their own oid */ + dependsOnCitus = IsCitusDependentObject(objectAdress); + break; + } + + case EnumRelationId: + { + /* + * we do not directly access the oid in pg_enum, + * because it does not exist in pg_depend, but its type does + */ + objectAdress.classId = TypeRelationId; + dependsOnCitus = IsCitusDependentObject(objectAdress); + break; + } + + case IndexRelationId: + case AttributeRelationId: + case SequenceRelationId: + case StatisticRelationId: + { + /* meta classes that access their relation's oid */ + objectAdress.classId = RelationRelationId; + dependsOnCitus = IsCitusDependentObject(objectAdress); + break; + } + + case AggregateRelationId: + { + /* We access procedure oid for aggregates. */ + objectAdress.classId = ProcedureRelationId; + dependsOnCitus = IsCitusDependentObject(objectAdress); + break; + } + + default: + { + break; + } + } + + PG_RETURN_BOOL(dependsOnCitus); +} + + +/* + * IsCitusDependentObject returns true if the given object depends on the citus extension. + */ +static bool +IsCitusDependentObject(ObjectAddress objectAddress) +{ + if (IsObjectAddressOwnedByCitus(&objectAddress)) + { + /* object itself is owned by citus */ + return true; + } + + /* check if object's any dependency is owned by citus. */ + List *citusDependencies = GetAllCitusDependedDependenciesForObject(&objectAddress); + return list_length(citusDependencies) > 0; +} diff --git a/src/backend/distributed/utils/citus_depended_object.c b/src/backend/distributed/utils/citus_depended_object.c new file mode 100644 index 000000000..b844c3515 --- /dev/null +++ b/src/backend/distributed/utils/citus_depended_object.c @@ -0,0 +1,287 @@ +/* + * citus_depended_object.c + * + * Implements exposed functions related to hiding citus depended objects. + * + * Copyright (c) Citus Data, Inc. + */ + +#include "postgres.h" +#include "miscadmin.h" + +#include "catalog/namespace.h" +#include "catalog/pg_aggregate.h" +#include "catalog/pg_am.h" +#include "catalog/pg_attribute.h" +#include "catalog/pg_attrdef.h" +#include "catalog/pg_constraint.h" +#include "catalog/pg_class.h" +#include "catalog/pg_depend.h" +#include "catalog/pg_enum.h" +#include "catalog/pg_event_trigger.h" +#include "catalog/pg_language.h" +#include "catalog/pg_namespace.h" +#include "catalog/pg_proc.h" +#include "catalog/pg_rewrite.h" +#include "catalog/pg_sequence.h" +#include "catalog/pg_statistic.h" +#include "catalog/pg_trigger.h" +#include "catalog/pg_ts_config.h" +#include "catalog/pg_ts_dict.h" +#include "catalog/pg_ts_template.h" +#include "catalog/pg_type.h" +#include "distributed/citus_depended_object.h" +#include "distributed/metadata_cache.h" +#include "distributed/listutils.h" +#include "nodes/makefuncs.h" +#include "nodes/nodeFuncs.h" +#include "nodes/parsenodes.h" +#include "utils/lsyscache.h" + +/* + * GUC hides any objects, which depends on citus extension, from pg meta class queries, + * it is intended to be used in vanilla tests to not break postgres test logs + */ +bool HideCitusDependentObjects = false; + +static Node * CreateCitusDependentObjectExpr(int pgMetaTableVarno, int pgMetaTableOid); +static List * GetCitusDependedObjectArgs(int pgMetaTableVarno, int pgMetaTableOid); + +/* + * IsPgLocksTable returns true if RTE is pg_locks table. + */ +bool +IsPgLocksTable(RangeTblEntry *rte) +{ + Oid pgLocksId = get_relname_relid("pg_locks", get_namespace_oid("pg_catalog", false)); + return rte->relid == pgLocksId; +} + + +/* + * SetLocalHideCitusDependentObjectsDisabledWhenAlreadyEnabled disables the GUC HideCitusDependentObjects + * if only it is enabled for local transaction. + */ +void +SetLocalHideCitusDependentObjectsDisabledWhenAlreadyEnabled(void) +{ + if (!HideCitusDependentObjects) + { + return; + } + + set_config_option("citus.hide_citus_dependent_objects", "false", + (superuser() ? PGC_SUSET : PGC_USERSET), PGC_S_SESSION, + GUC_ACTION_LOCAL, true, 0, false); +} + + +/* + * HideCitusDependentObjectsOnQueriesOfPgMetaTables adds a NOT is_citus_depended_object(oid, oid) expr + * to the quals of meta class RTEs that we are interested in. + */ +bool +HideCitusDependentObjectsOnQueriesOfPgMetaTables(Node *node, void *context) +{ + if (!CitusHasBeenLoaded() || !HideCitusDependentObjects || node == NULL) + { + return false; + } + + if (IsA(node, Query)) + { + Query *query = (Query *) node; + MemoryContext queryContext = GetMemoryChunkContext(query); + + /* + * We process the whole rtable rather than visiting individual RangeTblEntry's + * in the walker, since we need to know the varno to generate the right + * filter. + */ + int varno = 0; + RangeTblEntry *rangeTableEntry = NULL; + + foreach_ptr(rangeTableEntry, query->rtable) + { + varno++; + + if (rangeTableEntry->rtekind == RTE_RELATION) + { + /* make sure the expression is in the right memory context */ + MemoryContext originalContext = MemoryContextSwitchTo(queryContext); + + Oid metaTableOid = InvalidOid; + + /* + * add NOT is_citus_depended_object(oid, oid) to the quals + * of the RTE if it is a pg meta table that we are interested in. + */ + switch (rangeTableEntry->relid) + { + /* pg_class */ + case RelationRelationId: + + /* pg_proc */ + case ProcedureRelationId: + + /* pg_am */ + case AccessMethodRelationId: + + /* pg_type */ + case TypeRelationId: + + /* pg_enum */ + case EnumRelationId: + + /* pg_event_trigger */ + case EventTriggerRelationId: + + /* pg_trigger */ + case TriggerRelationId: + + /* pg_rewrite */ + case RewriteRelationId: + + /* pg_attrdef */ + case AttrDefaultRelationId: + + /* pg_constraint */ + case ConstraintRelationId: + + /* pg_ts_config */ + case TSConfigRelationId: + + /* pg_ts_template */ + case TSTemplateRelationId: + + /* pg_ts_dict */ + case TSDictionaryRelationId: + + /* pg_language */ + case LanguageRelationId: + + /* pg_namespace */ + case NamespaceRelationId: + + /* pg_sequence */ + case SequenceRelationId: + + /* pg_statistic */ + case StatisticRelationId: + + /* pg_attribute */ + case AttributeRelationId: + + /* pg_index */ + case IndexRelationId: + + /* pg_aggregate */ + case AggregateRelationId: + { + metaTableOid = rangeTableEntry->relid; + break; + } + + default: + { + metaTableOid = InvalidOid; + break; + } + } + + if (OidIsValid(metaTableOid)) + { + /* + * We found a valid pg meta class in query, + * so we assert below conditions. + */ + Assert(query->jointree != NULL); + Assert(query->jointree->fromlist != NULL); + + Node *citusDependentObjExpr = + CreateCitusDependentObjectExpr(varno, metaTableOid); + + /* + * We do not use security quals because a postgres vanilla test fails + * with a change of order for its result. + */ + query->jointree->quals = make_and_qual( + query->jointree->quals, citusDependentObjExpr); + } + + MemoryContextSwitchTo(originalContext); + } + } + + return query_tree_walker((Query *) node, + HideCitusDependentObjectsOnQueriesOfPgMetaTables, + context, 0); + } + + return expression_tree_walker(node, HideCitusDependentObjectsOnQueriesOfPgMetaTables, + context); +} + + +/* + * CreateCitusDependentObjectExpr constructs an expression of the form: + * NOT pg_catalog.is_citus_depended_object(oid, oid) + */ +static Node * +CreateCitusDependentObjectExpr(int pgMetaTableVarno, int pgMetaTableOid) +{ + /* build the call to read_intermediate_result */ + FuncExpr *funcExpr = makeNode(FuncExpr); + funcExpr->funcid = CitusDependentObjectFuncId(); + funcExpr->funcretset = false; + funcExpr->funcvariadic = false; + funcExpr->funcformat = 0; + funcExpr->funccollid = 0; + funcExpr->inputcollid = 0; + funcExpr->location = -1; + funcExpr->args = GetCitusDependedObjectArgs(pgMetaTableVarno, pgMetaTableOid); + + BoolExpr *notExpr = makeNode(BoolExpr); + notExpr->boolop = NOT_EXPR; + notExpr->args = list_make1(funcExpr); + notExpr->location = -1; + + return (Node *) notExpr; +} + + +/* + * GetCitusDependedObjectArgs returns func arguments for pg_catalog.is_citus_depended_object + */ +static List * +GetCitusDependedObjectArgs(int pgMetaTableVarno, int pgMetaTableOid) +{ + /* + * set attribute number for the oid, which we are insterest in, inside pg meta tables. + * We are accessing the 1. col(their own oid or their relation's oid) to get the related + * object's oid for all of the pg meta tables except pg_enum and pg_index. For pg_enum, + * class, we access its 2. col(its type's oid) to see if its type depends on citus, + * so it does. For pg_index, we access its 2. col (its relation's oid) to see if its relation + * depends on citus, so it does. + */ + AttrNumber oidAttNum = 1; + if (pgMetaTableOid == EnumRelationId || pgMetaTableOid == IndexRelationId) + { + oidAttNum = 2; + } + + /* create const for meta table oid */ + Const *metaTableOidConst = makeConst(OIDOID, -1, InvalidOid, sizeof(Oid), + ObjectIdGetDatum(pgMetaTableOid), + false, true); + + /* + * create a var for the oid that we are interested in, + * col type should be regproc for pg_aggregate table; else oid + */ + Oid varType = (pgMetaTableOid == AggregateRelationId) ? REGPROCOID : OIDOID; + Var *oidVar = makeVar(pgMetaTableVarno, oidAttNum, + varType, -1, InvalidOid, 0); + + return list_make2((Node *) metaTableOidConst, (Node *) oidVar); +} diff --git a/src/include/distributed/citus_depended_object.h b/src/include/distributed/citus_depended_object.h new file mode 100644 index 000000000..61abfa68a --- /dev/null +++ b/src/include/distributed/citus_depended_object.h @@ -0,0 +1,24 @@ +/*------------------------------------------------------------------------- + * + * citus_depended_object.h + * Exposes functions related to hiding citus depended objects while executing + * postgres vanilla tests. + * + * Copyright (c) CitusDependent Data, Inc. + * + *------------------------------------------------------------------------- + */ + +#ifndef CITUS_DEPENDED_OBJECT_H +#define CITUS_DEPENDED_OBJECT_H + +#include "nodes/nodes.h" +#include "nodes/parsenodes.h" + +extern bool HideCitusDependentObjects; + +extern void SetLocalHideCitusDependentObjectsDisabledWhenAlreadyEnabled(void); +extern bool HideCitusDependentObjectsOnQueriesOfPgMetaTables(Node *node, void *context); +extern bool IsPgLocksTable(RangeTblEntry *rte); + +#endif /* CITUS_DEPENDED_OBJECT_H */ diff --git a/src/include/distributed/metadata/dependency.h b/src/include/distributed/metadata/dependency.h index f04e3a869..c5a65319e 100644 --- a/src/include/distributed/metadata/dependency.h +++ b/src/include/distributed/metadata/dependency.h @@ -26,6 +26,7 @@ extern List * GetAllDependenciesForObject(const ObjectAddress *target); extern bool ErrorOrWarnIfAnyObjectHasUnsupportedDependency(List *objectAddresses); extern DeferredErrorMessage * DeferErrorIfAnyObjectHasUnsupportedDependency(const List * objectAddresses); +extern List * GetAllCitusDependedDependenciesForObject(const ObjectAddress *target); extern List * OrderObjectAddressListInDependencyOrder(List *objectAddressList); extern bool SupportedDependencyByCitus(const ObjectAddress *address); extern List * GetPgDependTuplesForDependingObjects(Oid targetObjectClassId, diff --git a/src/include/distributed/metadata/distobject.h b/src/include/distributed/metadata/distobject.h index cb905bbfe..900c15590 100644 --- a/src/include/distributed/metadata/distobject.h +++ b/src/include/distributed/metadata/distobject.h @@ -29,6 +29,7 @@ extern void UnmarkObjectDistributed(const ObjectAddress *address); extern bool IsTableOwnedByExtension(Oid relationId); extern bool IsAnyObjectAddressOwnedByExtension(const List *targets, ObjectAddress *extensionAddress); +extern bool IsObjectAddressOwnedByCitus(const ObjectAddress *objectAddress); extern ObjectAddress PgGetObjectAddress(char *ttype, ArrayType *namearr, ArrayType *argsarr); extern List * GetDistributedObjectAddressList(void); diff --git a/src/include/distributed/metadata_cache.h b/src/include/distributed/metadata_cache.h index 81cdeee4c..92f8a4514 100644 --- a/src/include/distributed/metadata_cache.h +++ b/src/include/distributed/metadata_cache.h @@ -263,6 +263,7 @@ extern Oid CitusTableVisibleFuncId(void); extern Oid RelationIsAKnownShardFuncId(void); extern Oid JsonbExtractPathFuncId(void); extern Oid JsonbExtractPathTextFuncId(void); +extern Oid CitusDependentObjectFuncId(void); /* enum oids */ extern Oid PrimaryNodeRoleId(void); diff --git a/src/test/regress/.gitignore b/src/test/regress/.gitignore index 8bbe973b4..bdc8b8df9 100644 --- a/src/test/regress/.gitignore +++ b/src/test/regress/.gitignore @@ -28,3 +28,24 @@ # core dumps core + +# postgres vanilla test's outputs +constraints.sql +copy.sql +create_function_0.sql +create_function_1.sql +create_function_2.sql +largeobject.sql +misc.sql +security_label.sql +tablespace.sql +constraints.out +copy.out +create_function_0.out +create_function_1.out +create_function_2.out +largeobject.out +largeobject_1.out +misc.out +security_label.out +tablespace.out diff --git a/src/test/regress/Makefile b/src/test/regress/Makefile index 6007d2508..0c3d05b4d 100644 --- a/src/test/regress/Makefile +++ b/src/test/regress/Makefile @@ -188,13 +188,8 @@ check-isolation-base: all $(isolation_test_files) $(pg_regress_multi_check) --load-extension=citus --isolationtester \ -- $(MULTI_REGRESS_OPTS) --inputdir=$(citus_abs_srcdir)/build --schedule=$(citus_abs_srcdir)/base_isolation_schedule $(EXTRA_TESTS) -check-vanilla: all - # it is possible that sometimes vanilla tests will fail, which is related to postgres. - # So we try it once more if it fails to prevent some failures in our CI. - ${MAKE} check-vanilla-internal || ${MAKE} check-vanilla-internal - -check-vanilla-internal: - $(pg_regress_multi_check) --load-extension=citus --vanillatest +check-vanilla: + $(pg_regress_multi_check) --vanillatest --vanilla-dev check-multi-mx: all $(pg_regress_multi_check) --load-extension=citus \ diff --git a/src/test/regress/expected/citus_depended_object.out b/src/test/regress/expected/citus_depended_object.out new file mode 100644 index 000000000..88eca1f5a --- /dev/null +++ b/src/test/regress/expected/citus_depended_object.out @@ -0,0 +1,195 @@ +-- create the udf is_citus_depended_object that is needed for the tests +CREATE OR REPLACE FUNCTION + pg_catalog.is_citus_depended_object(oid,oid) + RETURNS bool + LANGUAGE C + AS 'citus', $$is_citus_depended_object$$; +-- execute tests in a separate namespace +CREATE SCHEMA citus_dependend_object; +SET search_path TO citus_dependend_object; +-- PG_CLASS VISIBILITY +-- check if we correctly determine whether a relation is citus dependent or not. +CREATE TABLE no_hide_pg_class(relname text); +CREATE TABLE hide_pg_class(relname text); +-- create a relation that depends on noderole type which is a citus object +CREATE TABLE citus_depended_class(nrole noderole); +-- create a relation that depends on columnar access method which is a citus object +CREATE TABLE citus_depended_class2(id int); +SELECT alter_table_set_access_method('citus_depended_class2', 'columnar'); +NOTICE: creating a new table for citus_dependend_object.citus_depended_class2 +NOTICE: moving the data of citus_dependend_object.citus_depended_class2 +NOTICE: dropping the old citus_dependend_object.citus_depended_class2 +NOTICE: renaming the new table to citus_dependend_object.citus_depended_class2 + alter_table_set_access_method +--------------------------------------------------------------------- + +(1 row) + +-- create a relation that does not depend on citus +CREATE TABLE citus_independed_class(id int); +-- store all relations +SET citus.hide_citus_dependent_objects TO false; +INSERT INTO no_hide_pg_class SELECT relname FROM pg_class; +-- store all relations except citus relations +SET citus.hide_citus_dependent_objects TO true; +INSERT INTO hide_pg_class SELECT relname FROM pg_class; +-- prove that some relations are hidden or not +SELECT relname, + CASE + WHEN relname IN + ( + SELECT relname FROM no_hide_pg_class + EXCEPT + SELECT relname FROM hide_pg_class + ) THEN true + ELSE false + END AS is_hidden +FROM (VALUES ('pg_dist_shard'), ('pg_dist_placement'), ('pg_type'), ('pg_proc'), +('citus_depended_class'), ('citus_depended_class2'), ('citus_independed_class')) rels(relname); + relname | is_hidden +--------------------------------------------------------------------- + pg_dist_shard | t + pg_dist_placement | t + pg_type | f + pg_proc | f + citus_depended_class | t + citus_depended_class2 | t + citus_independed_class | f +(7 rows) + +-- PG_TYPE VISIBILITY +-- check if we correctly determine whether a type is citus dependent or not. +CREATE TABLE no_hide_pg_type(typname text); +CREATE TABLE hide_pg_type(typname text); +-- create a type that depends on noderole type which is a citus object +CREATE TYPE citus_depended_type AS (nrole noderole); +-- create a relation that does not depend on citus +CREATE TYPE citus_independed_type AS (id int); +-- store all types +SET citus.hide_citus_dependent_objects TO false; +INSERT INTO no_hide_pg_type SELECT typname FROM pg_type; +-- store all types except citus types +SET citus.hide_citus_dependent_objects TO true; +INSERT INTO hide_pg_type SELECT typname FROM pg_type; +-- prove that some types are hidden or not +SELECT typname, + CASE + WHEN typname IN + ( + SELECT typname FROM no_hide_pg_type + EXCEPT + SELECT typname FROM hide_pg_type + ) THEN true + ELSE false + END AS is_hidden +FROM (VALUES ('noderole'), ('_noderole'), ('int'), ('_int'), +('citus_depended_type'), ('citus_independed_type')) types(typname); + typname | is_hidden +--------------------------------------------------------------------- + noderole | t + _noderole | t + int | f + _int | f + citus_depended_type | t + citus_independed_type | f +(6 rows) + +-- PG_AM VISIBILITY +-- check if we correctly determine whether an access method is citus dependent or not. +CREATE TABLE no_hide_pg_am(amname text); +CREATE TABLE hide_pg_am(amname text); +-- store all access methods +SET citus.hide_citus_dependent_objects TO false; +INSERT INTO no_hide_pg_am SELECT amname FROM pg_am; +-- store all access methods except citus access methods +SET citus.hide_citus_dependent_objects TO true; +INSERT INTO hide_pg_am SELECT amname FROM pg_am; +-- show all hidden access methods +SELECT amname AS hidden_am FROM no_hide_pg_am +EXCEPT +SELECT amname AS hidden_am FROM hide_pg_am +ORDER BY 1; + hidden_am +--------------------------------------------------------------------- + columnar +(1 row) + +-- show all unhidden access methods +SELECT amname AS unhidden_am FROM no_hide_pg_am +EXCEPT +( + SELECT amname FROM no_hide_pg_am + EXCEPT + SELECT amname FROM hide_pg_am +) +ORDER BY 1; + unhidden_am +--------------------------------------------------------------------- + brin + btree + gin + gist + hash + heap + spgist +(7 rows) + +-- PG_PROC VISIBILITY +-- check if we correctly determine whether a procedure is citus dependent or not. +CREATE TABLE no_hide_pg_proc(proname text); +CREATE TABLE hide_pg_proc(proname text); +-- create a procedure that depends on noderole type which is a citus object +CREATE OR REPLACE PROCEDURE citus_depended_proc(nrole noderole) +LANGUAGE SQL +AS $$ +$$; +-- create a procedure that does not depend on citus +CREATE OR REPLACE PROCEDURE citus_independed_proc(id int) +LANGUAGE SQL +AS $$ +$$; +-- store all access procedures +SET citus.hide_citus_dependent_objects TO false; +INSERT INTO no_hide_pg_proc SELECT proname FROM pg_proc; +-- store all access procedures except citus procedures +SET citus.hide_citus_dependent_objects TO true; +INSERT INTO hide_pg_proc SELECT proname FROM pg_proc; +-- prove that some procedures are hidden or not +SELECT proname, + CASE + WHEN proname IN + ( + SELECT proname FROM no_hide_pg_proc + EXCEPT + SELECT proname FROM hide_pg_proc + ) THEN true + ELSE false + END AS is_hidden +FROM (VALUES ('master_add_node'), ('format'), +('citus_depended_proc'), ('citus_independed_proc')) procs(proname); + proname | is_hidden +--------------------------------------------------------------------- + master_add_node | t + format | f + citus_depended_proc | t + citus_independed_proc | f +(4 rows) + +-- drop the namespace with all its objects +DROP SCHEMA citus_dependend_object CASCADE; +NOTICE: drop cascades to 15 other objects +DETAIL: drop cascades to table no_hide_pg_class +drop cascades to table hide_pg_class +drop cascades to table citus_depended_class +drop cascades to table citus_depended_class2 +drop cascades to table citus_independed_class +drop cascades to table no_hide_pg_type +drop cascades to table hide_pg_type +drop cascades to type citus_depended_type +drop cascades to type citus_independed_type +drop cascades to table no_hide_pg_am +drop cascades to table hide_pg_am +drop cascades to table no_hide_pg_proc +drop cascades to table hide_pg_proc +drop cascades to function citus_depended_proc(noderole) +drop cascades to function citus_independed_proc(integer) diff --git a/src/test/regress/multi_1_schedule b/src/test/regress/multi_1_schedule index 74cc196d4..a2bd068ba 100644 --- a/src/test/regress/multi_1_schedule +++ b/src/test/regress/multi_1_schedule @@ -46,7 +46,7 @@ test: multi_read_from_secondaries # ---------- # multi_citus_tools tests utility functions written for citus tools # ---------- -test: multi_citus_tools +test: multi_citus_tools citus_depended_object # ---------- # multi_replicate_reference_table tests replicating reference tables to new nodes after we add new nodes diff --git a/src/test/regress/pg_regress_multi.pl b/src/test/regress/pg_regress_multi.pl index aec7e71d5..403879f1f 100755 --- a/src/test/regress/pg_regress_multi.pl +++ b/src/test/regress/pg_regress_multi.pl @@ -60,6 +60,7 @@ my $MASTER_FOLLOWERDIR = 'master-follower'; # Option parsing my $isolationtester = 0; my $vanillatest = 0; +my $vanillaDev = 0; my $followercluster = 0; my $bindir = ""; my $libdir = undef; @@ -96,6 +97,7 @@ if ($Config{osname} eq "MSWin32") GetOptions( 'isolationtester' => \$isolationtester, 'vanillatest' => \$vanillatest, + 'vanilla-dev' => \$vanillaDev, 'follower-cluster' => \$followercluster, 'bindir=s' => \$bindir, 'libdir=s' => \$libdir, @@ -486,6 +488,20 @@ push(@pgOptions, "citus.show_shards_for_app_name_prefixes='pg_regress'"); # we disable slow start by default to encourage parallelism within tests push(@pgOptions, "citus.executor_slow_start_interval=0ms"); +### +# we set some GUCs to not break postgres vanilla tests +# +# NOTE: we do not want to set the option right now because +# vanilla tests currently fail. We will remove the vanillaDev flag +# after fully supported pg vanilla tests with citus +# extension created. +### +if(!$vanillaDev && $vanillatest) +{ + # we enable hiding the citus dependent objects from pg meta class queries to not break postgres vanilla test behaviour + push(@pgOptions, "citus.hide_citus_dependent_objects=true"); +} + if ($useMitmproxy) { # make tests reproducible by never trying to negotiate ssl @@ -994,26 +1010,88 @@ my $startTime = time(); my $exitcode = 0; +sub PrepForVanillaTest +{ + ### + # We want to add is_citus_depended_object function to the default db. + # But without use-existing flag, pg_regress drops if exist and creates + # the default db. Thus, we set use-existing flag and manually create + # the default db, citus extension and the is_citus_depended_object + # function. + ### + + my $dbName = shift; + + # prepare tablespace folder + rmdir "./testtablespace"; + mkdir "./testtablespace"; + + # create default db + system(catfile($bindir, "psql"), + ('-X', '-h', $host, '-p', $masterPort, '-U', $user, "-d", "postgres", + '-c', "CREATE DATABASE $dbName;")) == 0 + or die "Could not create $dbName database on master"; + + # alter default db's lc_monetary to C + system(catfile($bindir, "psql"), + ('-X', '-h', $host, '-p', $masterPort, '-U', $user, "-d", $dbName, + '-c', "ALTER DATABASE $dbName SET lc_monetary TO 'C';")) == 0 + or die "Could not create $dbName database on master"; + + if ($vanillaDev) + { + return; + } + + # create extension citus + system(catfile($bindir, "psql"), + ('-X', '-h', $host, '-p', $masterPort, '-U', $user, "-d", $dbName, + '-c', "CREATE EXTENSION citus;")) == 0 + or die "Could not create citus extension on master"; + + # we do not want to expose that udf other than vanilla tests + my $citus_depended_object_def = "CREATE OR REPLACE FUNCTION + pg_catalog.is_citus_depended_object(oid,oid) + RETURNS bool + LANGUAGE C + AS 'citus', \$\$is_citus_depended_object\$\$;"; + system(catfile($bindir, "psql"), + ('-X', '-h', $host, '-p', $masterPort, '-U', $user, "-d", $dbName, + '-c', $citus_depended_object_def)) == 0 + or die "Could not create FUNCTION is_citus_depended_object on master"; +} + # Finally run the tests if ($vanillatest) { - $ENV{PGHOST} = $host; - $ENV{PGPORT} = $masterPort; - $ENV{PGUSER} = $user; $ENV{VANILLATEST} = "1"; + my $dbName = "regression"; + PrepForVanillaTest($dbName); + if (-f "$vanillaSchedule") { - rmdir "./testtablespace"; - mkdir "./testtablespace"; - my $pgregressdir=catfile(dirname("$pgxsdir"), "regress"); - $exitcode = system("$plainRegress", ("--inputdir", $pgregressdir), - ("--schedule", catfile("$pgregressdir", "parallel_schedule"))) + $exitcode = system("$plainRegress", + ("--inputdir", $pgregressdir), + ("--schedule", catfile("$pgregressdir", "parallel_schedule")), + ("--use-existing"), + ("--host","$host"), + ("--port","$masterPort"), + ("--user","$user"), + ("--dbname", "$dbName")) } else { - $exitcode = system("make", ("-C", catfile("$postgresBuilddir", "src", "test", "regress"), "installcheck-parallel")) + my $pgregressdir=catfile("$postgresSrcdir", "src", "test", "regress"); + $exitcode = system("$plainRegress", + ("--inputdir", $pgregressdir), + ("--schedule", catfile("$pgregressdir", "parallel_schedule")), + ("--use-existing"), + ("--host","$host"), + ("--port","$masterPort"), + ("--user","$user"), + ("--dbname", "$dbName")) } } elsif ($isolationtester) diff --git a/src/test/regress/sql/citus_depended_object.sql b/src/test/regress/sql/citus_depended_object.sql new file mode 100644 index 000000000..4f35acb1e --- /dev/null +++ b/src/test/regress/sql/citus_depended_object.sql @@ -0,0 +1,151 @@ +-- create the udf is_citus_depended_object that is needed for the tests +CREATE OR REPLACE FUNCTION + pg_catalog.is_citus_depended_object(oid,oid) + RETURNS bool + LANGUAGE C + AS 'citus', $$is_citus_depended_object$$; + +-- execute tests in a separate namespace +CREATE SCHEMA citus_dependend_object; +SET search_path TO citus_dependend_object; + +-- PG_CLASS VISIBILITY +-- check if we correctly determine whether a relation is citus dependent or not. +CREATE TABLE no_hide_pg_class(relname text); +CREATE TABLE hide_pg_class(relname text); + +-- create a relation that depends on noderole type which is a citus object +CREATE TABLE citus_depended_class(nrole noderole); + +-- create a relation that depends on columnar access method which is a citus object +CREATE TABLE citus_depended_class2(id int); +SELECT alter_table_set_access_method('citus_depended_class2', 'columnar'); + +-- create a relation that does not depend on citus +CREATE TABLE citus_independed_class(id int); + +-- store all relations +SET citus.hide_citus_dependent_objects TO false; +INSERT INTO no_hide_pg_class SELECT relname FROM pg_class; + +-- store all relations except citus relations +SET citus.hide_citus_dependent_objects TO true; +INSERT INTO hide_pg_class SELECT relname FROM pg_class; + +-- prove that some relations are hidden or not +SELECT relname, + CASE + WHEN relname IN + ( + SELECT relname FROM no_hide_pg_class + EXCEPT + SELECT relname FROM hide_pg_class + ) THEN true + ELSE false + END AS is_hidden +FROM (VALUES ('pg_dist_shard'), ('pg_dist_placement'), ('pg_type'), ('pg_proc'), +('citus_depended_class'), ('citus_depended_class2'), ('citus_independed_class')) rels(relname); + +-- PG_TYPE VISIBILITY +-- check if we correctly determine whether a type is citus dependent or not. +CREATE TABLE no_hide_pg_type(typname text); +CREATE TABLE hide_pg_type(typname text); + +-- create a type that depends on noderole type which is a citus object +CREATE TYPE citus_depended_type AS (nrole noderole); + +-- create a relation that does not depend on citus +CREATE TYPE citus_independed_type AS (id int); + +-- store all types +SET citus.hide_citus_dependent_objects TO false; +INSERT INTO no_hide_pg_type SELECT typname FROM pg_type; + +-- store all types except citus types +SET citus.hide_citus_dependent_objects TO true; +INSERT INTO hide_pg_type SELECT typname FROM pg_type; + +-- prove that some types are hidden or not +SELECT typname, + CASE + WHEN typname IN + ( + SELECT typname FROM no_hide_pg_type + EXCEPT + SELECT typname FROM hide_pg_type + ) THEN true + ELSE false + END AS is_hidden +FROM (VALUES ('noderole'), ('_noderole'), ('int'), ('_int'), +('citus_depended_type'), ('citus_independed_type')) types(typname); + +-- PG_AM VISIBILITY +-- check if we correctly determine whether an access method is citus dependent or not. +CREATE TABLE no_hide_pg_am(amname text); +CREATE TABLE hide_pg_am(amname text); + +-- store all access methods +SET citus.hide_citus_dependent_objects TO false; +INSERT INTO no_hide_pg_am SELECT amname FROM pg_am; + +-- store all access methods except citus access methods +SET citus.hide_citus_dependent_objects TO true; +INSERT INTO hide_pg_am SELECT amname FROM pg_am; + +-- show all hidden access methods +SELECT amname AS hidden_am FROM no_hide_pg_am +EXCEPT +SELECT amname AS hidden_am FROM hide_pg_am +ORDER BY 1; + +-- show all unhidden access methods +SELECT amname AS unhidden_am FROM no_hide_pg_am +EXCEPT +( + SELECT amname FROM no_hide_pg_am + EXCEPT + SELECT amname FROM hide_pg_am +) +ORDER BY 1; + +-- PG_PROC VISIBILITY +-- check if we correctly determine whether a procedure is citus dependent or not. +CREATE TABLE no_hide_pg_proc(proname text); +CREATE TABLE hide_pg_proc(proname text); + +-- create a procedure that depends on noderole type which is a citus object +CREATE OR REPLACE PROCEDURE citus_depended_proc(nrole noderole) +LANGUAGE SQL +AS $$ +$$; + +-- create a procedure that does not depend on citus +CREATE OR REPLACE PROCEDURE citus_independed_proc(id int) +LANGUAGE SQL +AS $$ +$$; + +-- store all access procedures +SET citus.hide_citus_dependent_objects TO false; +INSERT INTO no_hide_pg_proc SELECT proname FROM pg_proc; + +-- store all access procedures except citus procedures +SET citus.hide_citus_dependent_objects TO true; +INSERT INTO hide_pg_proc SELECT proname FROM pg_proc; + +-- prove that some procedures are hidden or not +SELECT proname, + CASE + WHEN proname IN + ( + SELECT proname FROM no_hide_pg_proc + EXCEPT + SELECT proname FROM hide_pg_proc + ) THEN true + ELSE false + END AS is_hidden +FROM (VALUES ('master_add_node'), ('format'), +('citus_depended_proc'), ('citus_independed_proc')) procs(proname); + +-- drop the namespace with all its objects +DROP SCHEMA citus_dependend_object CASCADE;