mirror of https://github.com/citusdata/citus.git
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 correctlypull/6075/head
parent
e2a9495334
commit
67ac3da2b0
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -17,9 +17,11 @@
|
|||
#include <limits.h>
|
||||
|
||||
#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 &&
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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 */
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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)
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
Loading…
Reference in New Issue