From abfdf48aa08461a5d26dc4aeb76adb45aef9e120 Mon Sep 17 00:00:00 2001 From: naisila Date: Thu, 27 Jul 2023 13:37:50 +0300 Subject: [PATCH] Fix permission info --- .../distributed/planner/distributed_planner.c | 2 +- .../planner/insert_select_planner.c | 44 +++++----- .../planner/local_distributed_join_planner.c | 43 +++++++++- .../distributed/planner/merge_planner.c | 19 +++-- .../planner/query_colocation_checker.c | 28 ++++--- .../distributed/planner/recursive_planning.c | 84 +++++++++---------- .../distributed/utils/citus_nodefuncs.c | 3 - .../distributed/utils/relation_utils.c | 6 -- .../distributed/query_colocation_checker.h | 5 ++ src/include/distributed/recursive_planning.h | 5 ++ 10 files changed, 144 insertions(+), 95 deletions(-) diff --git a/src/backend/distributed/planner/distributed_planner.c b/src/backend/distributed/planner/distributed_planner.c index cd6be4f4f..22c2a8ac2 100644 --- a/src/backend/distributed/planner/distributed_planner.c +++ b/src/backend/distributed/planner/distributed_planner.c @@ -1474,7 +1474,7 @@ FinalizeNonRouterPlan(PlannedStmt *localPlan, DistributedPlan *distributedPlan, #if PG_VERSION_NUM >= PG_VERSION_16 /* - * Original range table list is concatented to final plan's range table list + * Original range table list is concatenated to final plan's range table list * therefore all the perminfoindexes should be updated to their value * PLUS the length of final plan's perminfos. */ diff --git a/src/backend/distributed/planner/insert_select_planner.c b/src/backend/distributed/planner/insert_select_planner.c index b883a2d68..418824ac3 100644 --- a/src/backend/distributed/planner/insert_select_planner.c +++ b/src/backend/distributed/planner/insert_select_planner.c @@ -31,7 +31,6 @@ #include "distributed/pg_dist_partition.h" #include "distributed/query_pushdown_planning.h" #include "distributed/recursive_planning.h" -#include "distributed/relation_utils.h" #include "distributed/repartition_executor.h" #include "distributed/resource_lock.h" #include "distributed/version_compat.h" @@ -605,18 +604,18 @@ CreateCombineQueryForRouterPlan(DistributedPlan *distPlan) combineQuery->rtable = list_make1(rangeTableEntry); #if PG_VERSION_NUM >= PG_VERSION_16 - combineQuery->rteperminfos = NIL; - if (rangeTableEntry->perminfoindex != 0) - { - /* create permission info for newRangeTableEntry */ - RTEPermissionInfo *perminfo = GetFilledPermissionInfo(rangeTableEntry->relid, - rangeTableEntry->inh, - CMD_SELECT); - /* update the subquery's rteperminfos accordingly */ - rangeTableEntry->perminfoindex = 1; - combineQuery->rteperminfos = list_make1(perminfo); - } + /* + * This part of the code is more of a sanity check for readability, + * it doesn't really do anything. + * We know that Only relation RTEs and subquery RTEs that were once relation + * RTEs (views) have their perminfoindex set. (see ExecCheckPermissions function) + * DerivedRangeTableEntry sets the rtekind to RTE_FUNCTION + * Hence we should have no perminfos here. + */ + Assert(rangeTableEntry->rtekind == RTE_FUNCTION && + rangeTableEntry->perminfoindex == 0); + combineQuery->rteperminfos = NIL; #endif combineQuery->targetList = targetList; @@ -1557,18 +1556,17 @@ WrapSubquery(Query *subquery) outerQuery->rtable = list_make1(newRangeTableEntry); #if PG_VERSION_NUM >= PG_VERSION_16 - outerQuery->rteperminfos = NIL; - if (newRangeTableEntry->perminfoindex != 0) - { - /* create permission info for newRangeTableEntry */ - RTEPermissionInfo *perminfo = GetFilledPermissionInfo(newRangeTableEntry->relid, - newRangeTableEntry->inh, - CMD_SELECT); - /* update the subquery's rteperminfos accordingly */ - newRangeTableEntry->perminfoindex = 1; - outerQuery->rteperminfos = list_make1(perminfo); - } + /* + * This part of the code is more of a sanity check for readability, + * it doesn't really do anything. + * addRangeTableEntryForSubquery doesn't add permission info + * because the range table is set to be RTE_SUBQUERY. + * Hence we should also have no perminfos here. + */ + Assert(newRangeTableEntry->rtekind == RTE_SUBQUERY && + newRangeTableEntry->perminfoindex == 0); + outerQuery->rteperminfos = NIL; #endif /* set the FROM expression to the subquery */ diff --git a/src/backend/distributed/planner/local_distributed_join_planner.c b/src/backend/distributed/planner/local_distributed_join_planner.c index 2c6a63de1..ecbd182f0 100644 --- a/src/backend/distributed/planner/local_distributed_join_planner.c +++ b/src/backend/distributed/planner/local_distributed_join_planner.c @@ -107,6 +107,7 @@ #include "optimizer/optimizer.h" #include "optimizer/planner.h" #include "optimizer/prep.h" +#include "parser/parse_relation.h" #include "parser/parsetree.h" #include "nodes/makefuncs.h" #include "nodes/nodeFuncs.h" @@ -136,6 +137,9 @@ typedef struct RangeTableEntryDetails RangeTblEntry *rangeTableEntry; List *requiredAttributeNumbers; bool hasConstantFilterOnUniqueColumn; +#if PG_VERSION_NUM >= PG_VERSION_16 + RTEPermissionInfo *perminfo; +#endif } RangeTableEntryDetails; /* @@ -176,7 +180,12 @@ static bool HasConstantFilterOnUniqueColumn(RangeTblEntry *rangeTableEntry, static ConversionCandidates * CreateConversionCandidates(PlannerRestrictionContext * plannerRestrictionContext, List *rangeTableList, +#if PG_VERSION_NUM >= PG_VERSION_16 + int resultRTEIdentity, + List *rteperminfos); +#else int resultRTEIdentity); +#endif static void AppendUniqueIndexColumnsToList(Form_pg_index indexForm, List **uniqueIndexes, int flags); static ConversionChoice GetConversionChoice(ConversionCandidates * @@ -205,10 +214,17 @@ RecursivelyPlanLocalTableJoins(Query *query, GetPlannerRestrictionContext(context); List *rangeTableList = query->rtable; +#if PG_VERSION_NUM >= PG_VERSION_16 + List *rteperminfos = query->rteperminfos; +#endif int resultRTEIdentity = ResultRTEIdentity(query); ConversionCandidates *conversionCandidates = CreateConversionCandidates(plannerRestrictionContext, +#if PG_VERSION_NUM >= PG_VERSION_16 + rangeTableList, resultRTEIdentity, rteperminfos); +#else rangeTableList, resultRTEIdentity); +#endif ConversionChoice conversionChoise = GetConversionChoice(conversionCandidates, plannerRestrictionContext); @@ -216,6 +232,12 @@ RecursivelyPlanLocalTableJoins(Query *query, List *rteListToConvert = RTEListToConvert(conversionCandidates, conversionChoise); ConvertRTEsToSubquery(rteListToConvert, context); + + /* + * Note: we don't need to remove converted rtes from query->rteperminfos to avoid + * crash of Assert(bms_num_members(indexset) == list_length(rteperminfos)); + * because query->rteperminfos has already gone through ExecCheckPermissions + */ } @@ -323,7 +345,12 @@ ConvertRTEsToSubquery(List *rangeTableEntryDetailsList, RecursivePlanningContext RangeTblEntry *rangeTableEntry = rangeTableEntryDetails->rangeTableEntry; List *requiredAttributeNumbers = rangeTableEntryDetails->requiredAttributeNumbers; ReplaceRTERelationWithRteSubquery(rangeTableEntry, +#if PG_VERSION_NUM >= PG_VERSION_16 + requiredAttributeNumbers, context, + rangeTableEntryDetails->perminfo); +#else requiredAttributeNumbers, context); +#endif } } @@ -530,7 +557,13 @@ RequiredAttrNumbersForRelationInternal(Query *queryToProcess, int rteIndex) */ static ConversionCandidates * CreateConversionCandidates(PlannerRestrictionContext *plannerRestrictionContext, - List *rangeTableList, int resultRTEIdentity) + List *rangeTableList, +#if PG_VERSION_NUM >= PG_VERSION_16 + int resultRTEIdentity, + List *rteperminfos) +#else + int resultRTEIdentity) +#endif { ConversionCandidates *conversionCandidates = palloc0(sizeof(ConversionCandidates)); @@ -564,6 +597,14 @@ CreateConversionCandidates(PlannerRestrictionContext *plannerRestrictionContext, RequiredAttrNumbersForRelation(rangeTableEntry, plannerRestrictionContext); rangeTableEntryDetails->hasConstantFilterOnUniqueColumn = HasConstantFilterOnUniqueColumn(rangeTableEntry, relationRestriction); +#if PG_VERSION_NUM >= PG_VERSION_16 + rangeTableEntryDetails->perminfo = NULL; + if (rangeTableEntry->perminfoindex) + { + rangeTableEntryDetails->perminfo = getRTEPermissionInfo(rteperminfos, + rangeTableEntry); + } +#endif bool referenceOrDistributedTable = IsCitusTableType(rangeTableEntry->relid, REFERENCE_TABLE) || diff --git a/src/backend/distributed/planner/merge_planner.c b/src/backend/distributed/planner/merge_planner.c index 71d840ad4..0a9fb590f 100644 --- a/src/backend/distributed/planner/merge_planner.c +++ b/src/backend/distributed/planner/merge_planner.c @@ -15,6 +15,7 @@ #include "nodes/makefuncs.h" #include "nodes/nodeFuncs.h" #include "optimizer/optimizer.h" +#include "parser/parse_relation.h" #include "parser/parsetree.h" #include "tcop/tcopprot.h" #include "utils/lsyscache.h" @@ -31,7 +32,6 @@ #include "distributed/pg_version_constants.h" #include "distributed/query_pushdown_planning.h" #include "distributed/query_colocation_checker.h" -#include "distributed/relation_utils.h" #include "distributed/repartition_executor.h" #include "distributed/shared_library_init.h" #include "distributed/shard_pruning.h" @@ -776,7 +776,9 @@ ConvertCteRTEIntoSubquery(Query *mergeQuery, RangeTblEntry *sourceRte) sourceRte->rtekind = RTE_SUBQUERY; #if PG_VERSION_NUM >= PG_VERSION_16 - sourceRte->perminfoindex = 0; + + /* sanity check - sourceRte was RTE_CTE previously so it should have no perminfo */ + Assert(sourceRte->perminfoindex == 0); #endif /* @@ -830,12 +832,11 @@ ConvertRelationRTEIntoSubquery(Query *mergeQuery, RangeTblEntry *sourceRte, #if PG_VERSION_NUM >= PG_VERSION_16 sourceResultsQuery->rteperminfos = NIL; - if (newRangeTableEntry->perminfoindex != 0) + if (newRangeTableEntry->perminfoindex) { /* create permission info for newRangeTableEntry */ - RTEPermissionInfo *perminfo = GetFilledPermissionInfo(newRangeTableEntry->relid, - newRangeTableEntry->inh, - CMD_SELECT); + RTEPermissionInfo *perminfo = getRTEPermissionInfo(mergeQuery->rteperminfos, + newRangeTableEntry); /* update the subquery's rteperminfos accordingly */ newRangeTableEntry->perminfoindex = 1; @@ -870,6 +871,12 @@ ConvertRelationRTEIntoSubquery(Query *mergeQuery, RangeTblEntry *sourceRte, sourceRte->rtekind = RTE_SUBQUERY; #if PG_VERSION_NUM >= PG_VERSION_16 sourceRte->perminfoindex = 0; + + /* + * Note: we don't need to remove replaced sourceRte from mergeQuery->rteperminfos to avoid + * crash of Assert(bms_num_members(indexset) == list_length(rteperminfos)); + * because mergeQuery->rteperminfos has already gone through ExecCheckPermissions + */ #endif sourceRte->subquery = sourceResultsQuery; sourceRte->inh = false; diff --git a/src/backend/distributed/planner/query_colocation_checker.c b/src/backend/distributed/planner/query_colocation_checker.c index 8b57abc56..a39e50a56 100644 --- a/src/backend/distributed/planner/query_colocation_checker.c +++ b/src/backend/distributed/planner/query_colocation_checker.c @@ -28,7 +28,6 @@ #include "distributed/query_colocation_checker.h" #include "distributed/pg_dist_partition.h" #include "distributed/relation_restriction_equivalence.h" -#include "distributed/relation_utils.h" #include "distributed/metadata_cache.h" #include "distributed/multi_logical_planner.h" /* only to access utility functions */ @@ -84,7 +83,16 @@ CreateColocatedJoinChecker(Query *subquery, PlannerRestrictionContext *restricti * functions (i.e., FilterPlannerRestrictionForQuery()) rely on queries * not relations. */ +#if PG_VERSION_NUM >= PG_VERSION_16 + RTEPermissionInfo *perminfo = NULL; + if (anchorRangeTblEntry->perminfoindex) + { + perminfo = getRTEPermissionInfo(subquery->rteperminfos, anchorRangeTblEntry); + } + anchorSubquery = WrapRteRelationIntoSubquery(anchorRangeTblEntry, NIL, perminfo); +#else anchorSubquery = WrapRteRelationIntoSubquery(anchorRangeTblEntry, NIL); +#endif } else if (anchorRangeTblEntry->rtekind == RTE_SUBQUERY) { @@ -267,7 +275,13 @@ SubqueryColocated(Query *subquery, ColocatedJoinChecker *checker) * designed for generating a stub query. */ Query * -WrapRteRelationIntoSubquery(RangeTblEntry *rteRelation, List *requiredAttributes) +WrapRteRelationIntoSubquery(RangeTblEntry *rteRelation, +#if PG_VERSION_NUM >= PG_VERSION_16 + List *requiredAttributes, + RTEPermissionInfo *perminfo) +#else + List * requiredAttributes) +#endif { Query *subquery = makeNode(Query); RangeTblRef *newRangeTableRef = makeNode(RangeTblRef); @@ -279,16 +293,8 @@ WrapRteRelationIntoSubquery(RangeTblEntry *rteRelation, List *requiredAttributes subquery->rtable = list_make1(newRangeTableEntry); #if PG_VERSION_NUM >= PG_VERSION_16 - subquery->rteperminfos = NIL; - newRangeTableEntry->perminfoindex = 0; - if (rteRelation->perminfoindex != 0) + if (perminfo) { - /* create permission info for newRangeTableEntry */ - RTEPermissionInfo *perminfo = GetFilledPermissionInfo(newRangeTableEntry->relid, - newRangeTableEntry->inh, - ACL_SELECT); - - /* update the subquery's rteperminfos accordingly */ newRangeTableEntry->perminfoindex = 1; subquery->rteperminfos = list_make1(perminfo); } diff --git a/src/backend/distributed/planner/recursive_planning.c b/src/backend/distributed/planner/recursive_planning.c index 3d5bdb746..ec1ab8419 100644 --- a/src/backend/distributed/planner/recursive_planning.c +++ b/src/backend/distributed/planner/recursive_planning.c @@ -72,7 +72,6 @@ #include "distributed/query_pushdown_planning.h" #include "distributed/recursive_planning.h" #include "distributed/relation_restriction_equivalence.h" -#include "distributed/relation_utils.h" #include "distributed/log_utils.h" #include "distributed/shard_pruning.h" #include "distributed/version_compat.h" @@ -81,6 +80,7 @@ #include "optimizer/optimizer.h" #include "optimizer/planner.h" #include "optimizer/prep.h" +#include "parser/parse_relation.h" #include "parser/parsetree.h" #include "nodes/makefuncs.h" #include "nodes/nodeFuncs.h" @@ -89,7 +89,6 @@ #include "nodes/pg_list.h" #include "nodes/primnodes.h" #include "nodes/pathnodes.h" -#include "parser/parse_relation.h" #include "utils/builtins.h" #include "utils/guc.h" #include "utils/lsyscache.h" @@ -888,8 +887,25 @@ RecursivelyPlanDistributedJoinNode(Node *node, Query *query, List *requiredAttributes = RequiredAttrNumbersForRelation(distributedRte, restrictionContext); +#if PG_VERSION_NUM >= PG_VERSION_16 + RTEPermissionInfo *perminfo = NULL; + if (distributedRte->perminfoindex) + { + perminfo = getRTEPermissionInfo(query->rteperminfos, distributedRte); + } + + ReplaceRTERelationWithRteSubquery(distributedRte, requiredAttributes, + recursivePlanningContext, perminfo); +#else ReplaceRTERelationWithRteSubquery(distributedRte, requiredAttributes, recursivePlanningContext); +#endif + + /* + * Note: we don't need to remove replaced rtes from query->rteperminfos to avoid + * crash of Assert(bms_num_members(indexset) == list_length(rteperminfos)); + * because query->rteperminfos has already gone through ExecCheckPermissions + */ } else if (distributedRte->rtekind == RTE_SUBQUERY) { @@ -1753,9 +1769,17 @@ NodeContainsSubqueryReferencingOuterQuery(Node *node) void ReplaceRTERelationWithRteSubquery(RangeTblEntry *rangeTableEntry, List *requiredAttrNumbers, +#if PG_VERSION_NUM >= PG_VERSION_16 + RecursivePlanningContext *context, + RTEPermissionInfo *perminfo) +{ + Query *subquery = WrapRteRelationIntoSubquery(rangeTableEntry, requiredAttrNumbers, + perminfo); +#else RecursivePlanningContext *context) { Query *subquery = WrapRteRelationIntoSubquery(rangeTableEntry, requiredAttrNumbers); +#endif List *outerQueryTargetList = CreateAllTargetListForRelation(rangeTableEntry->relid, requiredAttrNumbers); @@ -1781,6 +1805,12 @@ ReplaceRTERelationWithRteSubquery(RangeTblEntry *rangeTableEntry, /* replace the function with the constructed subquery */ rangeTableEntry->rtekind = RTE_SUBQUERY; #if PG_VERSION_NUM >= PG_VERSION_16 + + /* + * subquery already contains a copy of this rangeTableEntry's permission info + * Not we have replaced with the constructed subquery so we should + * set perminfoindex to 0. + */ rangeTableEntry->perminfoindex = 0; #endif rangeTableEntry->subquery = subquery; @@ -1856,20 +1886,11 @@ CreateOuterSubquery(RangeTblEntry *rangeTableEntry, List *outerSubqueryTargetLis outerSubquery->rtable = list_make1(innerSubqueryRTE); #if PG_VERSION_NUM >= PG_VERSION_16 + + /* sanity check */ + Assert(innerSubqueryRTE->rtekind == RTE_SUBQUERY && + innerSubqueryRTE->perminfoindex == 0); outerSubquery->rteperminfos = NIL; - innerSubqueryRTE->perminfoindex = 0; - - if (rangeTableEntry->perminfoindex != 0) - { - /* create permission info for innerSubqueryRTE */ - RTEPermissionInfo *perminfo = GetFilledPermissionInfo(innerSubqueryRTE->relid, - innerSubqueryRTE->inh, - ACL_SELECT); - - /* update the outerSubquery's rteperminfos accordingly */ - innerSubqueryRTE->perminfoindex = 1; - outerSubquery->rteperminfos = list_make1(perminfo); - } #endif @@ -2047,20 +2068,11 @@ TransformFunctionRTE(RangeTblEntry *rangeTblEntry) subquery->rtable = list_make1(newRangeTableEntry); #if PG_VERSION_NUM >= PG_VERSION_16 + + /* sanity check */ + Assert(newRangeTableEntry->rtekind == RTE_FUNCTION && + newRangeTableEntry->perminfoindex == 0); subquery->rteperminfos = NIL; - newRangeTableEntry->perminfoindex = 0; - - if (rangeTblEntry->perminfoindex != 0) - { - /* create permission info for newRangeTableEntry */ - RTEPermissionInfo *perminfo = GetFilledPermissionInfo(newRangeTableEntry->relid, - newRangeTableEntry->inh, - CMD_SELECT); - - /* update the subquery's rteperminfos accordingly */ - newRangeTableEntry->perminfoindex = 1; - subquery->rteperminfos = list_make1(perminfo); - } #endif newRangeTableRef->rtindex = 1; @@ -2196,9 +2208,6 @@ TransformFunctionRTE(RangeTblEntry *rangeTblEntry) /* replace the function with the constructed subquery */ rangeTblEntry->rtekind = RTE_SUBQUERY; -#if PG_VERSION_NUM >= PG_VERSION_16 - rangeTblEntry->perminfoindex = 0; -#endif rangeTblEntry->subquery = subquery; } @@ -2436,22 +2445,9 @@ BuildReadIntermediateResultsQuery(List *targetEntryList, List *columnAliasList, Query *resultQuery = makeNode(Query); resultQuery->commandType = CMD_SELECT; resultQuery->rtable = list_make1(rangeTableEntry); - #if PG_VERSION_NUM >= PG_VERSION_16 resultQuery->rteperminfos = NIL; - if (rangeTableEntry->perminfoindex != 0) - { - /* create permission info for newRangeTableEntry */ - RTEPermissionInfo *perminfo = GetFilledPermissionInfo(rangeTableEntry->relid, - rangeTableEntry->inh, - CMD_SELECT); - - /* update the subquery's rteperminfos accordingly */ - rangeTableEntry->perminfoindex = 1; - resultQuery->rteperminfos = list_make1(perminfo); - } #endif - resultQuery->jointree = joinTree; resultQuery->targetList = targetList; diff --git a/src/backend/distributed/utils/citus_nodefuncs.c b/src/backend/distributed/utils/citus_nodefuncs.c index a6e491342..aee1ff48a 100644 --- a/src/backend/distributed/utils/citus_nodefuncs.c +++ b/src/backend/distributed/utils/citus_nodefuncs.c @@ -148,9 +148,6 @@ SetRangeTblExtraData(RangeTblEntry *rte, CitusRTEKind rteKind, char *fragmentSch fauxFunction->funccolcollations = funcCollations; rte->rtekind = RTE_FUNCTION; -#if PG_VERSION_NUM >= PG_VERSION_16 - rte->perminfoindex = 0; -#endif rte->functions = list_make1(fauxFunction); } diff --git a/src/backend/distributed/utils/relation_utils.c b/src/backend/distributed/utils/relation_utils.c index ef02736ea..d39c1f071 100644 --- a/src/backend/distributed/utils/relation_utils.c +++ b/src/backend/distributed/utils/relation_utils.c @@ -45,9 +45,6 @@ RelationGetNamespaceName(Relation relation) * we are dealing with GetUserId(). * Currently the following entries are filled like this: * perminfo->checkAsUser = GetUserId(); - * perminfo->selectedCols = NULL; - * perminfo->insertedCols = NULL; - * perminfo->updatedCols = NULL; */ RTEPermissionInfo * GetFilledPermissionInfo(Oid relid, bool inh, AclMode requiredPerms) @@ -57,9 +54,6 @@ GetFilledPermissionInfo(Oid relid, bool inh, AclMode requiredPerms) perminfo->inh = inh; perminfo->requiredPerms = requiredPerms; perminfo->checkAsUser = GetUserId(); - perminfo->selectedCols = NULL; - perminfo->insertedCols = NULL; - perminfo->updatedCols = NULL; return perminfo; } diff --git a/src/include/distributed/query_colocation_checker.h b/src/include/distributed/query_colocation_checker.h index 969ecbcf9..3aef01e4a 100644 --- a/src/include/distributed/query_colocation_checker.h +++ b/src/include/distributed/query_colocation_checker.h @@ -35,7 +35,12 @@ extern ColocatedJoinChecker CreateColocatedJoinChecker(Query *subquery, restrictionContext); extern bool SubqueryColocated(Query *subquery, ColocatedJoinChecker *context); extern Query * WrapRteRelationIntoSubquery(RangeTblEntry *rteRelation, +#if PG_VERSION_NUM >= PG_VERSION_16 + List *requiredAttributes, + RTEPermissionInfo *perminfo); +#else List *requiredAttributes); +#endif extern List * CreateAllTargetListForRelation(Oid relationId, List *requiredAttributes); #endif /* QUERY_COLOCATION_CHECKER_H */ diff --git a/src/include/distributed/recursive_planning.h b/src/include/distributed/recursive_planning.h index 8943443aa..d25937ce0 100644 --- a/src/include/distributed/recursive_planning.h +++ b/src/include/distributed/recursive_planning.h @@ -42,7 +42,12 @@ extern bool GeneratingSubplans(void); extern bool ContainsLocalTableDistributedTableJoin(List *rangeTableList); extern void ReplaceRTERelationWithRteSubquery(RangeTblEntry *rangeTableEntry, List *requiredAttrNumbers, +#if PG_VERSION_NUM >= PG_VERSION_16 + RecursivePlanningContext *context, + RTEPermissionInfo *perminfo); +#else RecursivePlanningContext *context); +#endif extern bool IsRecursivelyPlannableRelation(RangeTblEntry *rangeTableEntry); extern bool IsRelationLocalTableOrMatView(Oid relationId); extern bool ContainsReferencesToOuterQuery(Query *query);