From 14181072cf11fcb4f0dea693be57c0376ff48e51 Mon Sep 17 00:00:00 2001 From: naisila Date: Fri, 9 Jun 2023 16:32:27 +0300 Subject: [PATCH] Rework PlannedStmt and Query's Permission Info The main issue lies in the following entries of PlannedStmt: { rtable permInfos } Each rtable has an int perminfoindex, and its actual permission info is obtained through the following: permInfos[perminfoindex] We had a crash because perminfoindexes were not updated in the finalized planned statement after distributed planner hook. So, basically, everywhere we set a query's or planned statement's rtable entry, we need to set the rteperminfos/permInfos accordingly. Relevant PG commits: https://github.com/postgres/postgres/commit/a61b1f74823c9c4f79c95226a461f1e7a367764b a61b1f74823c9c4f79c95226a461f1e7a367764b https://github.com/postgres/postgres/commit/b803b7d132e3505ab77c29acf91f3d1caa298f95 b803b7d132e3505ab77c29acf91f3d1caa298f95 --- .../distributed/planner/distributed_planner.c | 34 ++++++++++++ .../planner/fast_path_router_planner.c | 3 ++ .../planner/insert_select_planner.c | 32 +++++++++++ .../planner/query_colocation_checker.c | 17 ++++++ .../planner/query_pushdown_planning.c | 3 ++ .../distributed/planner/recursive_planning.c | 54 +++++++++++++++++++ 6 files changed, 143 insertions(+) diff --git a/src/backend/distributed/planner/distributed_planner.c b/src/backend/distributed/planner/distributed_planner.c index 3b6a8f9f7..724580802 100644 --- a/src/backend/distributed/planner/distributed_planner.c +++ b/src/backend/distributed/planner/distributed_planner.c @@ -56,6 +56,9 @@ #include "nodes/makefuncs.h" #include "nodes/nodeFuncs.h" #include "nodes/pg_list.h" +#if PG_VERSION_NUM >= PG_VERSION_16 +#include "parser/parse_relation.h" +#endif #include "parser/parsetree.h" #include "parser/parse_type.h" #include "optimizer/optimizer.h" @@ -1467,6 +1470,27 @@ FinalizeNonRouterPlan(PlannedStmt *localPlan, DistributedPlan *distributedPlan, /* add original range table list for access permission checks */ finalPlan->rtable = list_concat(finalPlan->rtable, localPlan->rtable); +#if PG_VERSION_NUM >= PG_VERSION_16 + + /* + * Original range table list is concatented 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. + */ + int list_length_final_permInfos = list_length(finalPlan->permInfos); + finalPlan->permInfos = list_concat(finalPlan->permInfos, localPlan->permInfos); + + ListCell *lc; + foreach(lc, localPlan->rtable) + { + RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc); + if (rte->perminfoindex != 0) + { + rte->perminfoindex = rte->perminfoindex + list_length_final_permInfos; + } + } +#endif + return finalPlan; } @@ -1504,6 +1528,16 @@ FinalizeRouterPlan(PlannedStmt *localPlan, CustomScan *customScan) /* add original range table list for access permission checks */ routerPlan->rtable = list_concat(routerPlan->rtable, localPlan->rtable); +#if PG_VERSION_NUM >= PG_VERSION_16 + + /* + * We know that extra remoteScanRangeTableEntry has perminfoindex 0 + * therefore we can simply use the perminfos we had in localplan + */ + Assert(remoteScanRangeTableEntry->perminfoindex == 0); + routerPlan->permInfos = localPlan->permInfos; +#endif + routerPlan->canSetTag = true; routerPlan->relationOids = NIL; diff --git a/src/backend/distributed/planner/fast_path_router_planner.c b/src/backend/distributed/planner/fast_path_router_planner.c index 41802ee83..933ee7425 100644 --- a/src/backend/distributed/planner/fast_path_router_planner.c +++ b/src/backend/distributed/planner/fast_path_router_planner.c @@ -136,6 +136,9 @@ GeneratePlaceHolderPlannedStmt(Query *parse) result->stmt_len = parse->stmt_len; result->rtable = copyObject(parse->rtable); +#if PG_VERSION_NUM >= PG_VERSION_16 + result->permInfos = copyObject(parse->rteperminfos); +#endif result->planTree = (Plan *) plan; result->hasReturning = (parse->returningList != NIL); diff --git a/src/backend/distributed/planner/insert_select_planner.c b/src/backend/distributed/planner/insert_select_planner.c index 24d550004..b883a2d68 100644 --- a/src/backend/distributed/planner/insert_select_planner.c +++ b/src/backend/distributed/planner/insert_select_planner.c @@ -31,6 +31,7 @@ #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" @@ -602,6 +603,22 @@ CreateCombineQueryForRouterPlan(DistributedPlan *distPlan) combineQuery->querySource = QSRC_ORIGINAL; combineQuery->canSetTag = true; 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); + } +#endif + combineQuery->targetList = targetList; combineQuery->jointree = joinTree; return combineQuery; @@ -1539,6 +1556,21 @@ WrapSubquery(Query *subquery) selectAlias, false, true)); 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); + } +#endif + /* set the FROM expression to the subquery */ RangeTblRef *newRangeTableRef = makeNode(RangeTblRef); newRangeTableRef->rtindex = 1; diff --git a/src/backend/distributed/planner/query_colocation_checker.c b/src/backend/distributed/planner/query_colocation_checker.c index f5701fdb1..8b57abc56 100644 --- a/src/backend/distributed/planner/query_colocation_checker.c +++ b/src/backend/distributed/planner/query_colocation_checker.c @@ -28,6 +28,7 @@ #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 */ @@ -277,6 +278,22 @@ WrapRteRelationIntoSubquery(RangeTblEntry *rteRelation, List *requiredAttributes RangeTblEntry *newRangeTableEntry = copyObject(rteRelation); subquery->rtable = list_make1(newRangeTableEntry); +#if PG_VERSION_NUM >= PG_VERSION_16 + subquery->rteperminfos = NIL; + newRangeTableEntry->perminfoindex = 0; + if (rteRelation->perminfoindex != 0) + { + /* 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); + } +#endif + /* set the FROM expression to the subquery */ newRangeTableRef = makeNode(RangeTblRef); newRangeTableRef->rtindex = SINGLE_RTE_INDEX; diff --git a/src/backend/distributed/planner/query_pushdown_planning.c b/src/backend/distributed/planner/query_pushdown_planning.c index cbe6a3606..200509974 100644 --- a/src/backend/distributed/planner/query_pushdown_planning.c +++ b/src/backend/distributed/planner/query_pushdown_planning.c @@ -1915,6 +1915,9 @@ SubqueryPushdownMultiNodeTree(Query *originalQuery) pushedDownQuery->targetList = subqueryTargetEntryList; pushedDownQuery->jointree = copyObject(queryTree->jointree); pushedDownQuery->rtable = copyObject(queryTree->rtable); +#if PG_VERSION_NUM >= PG_VERSION_16 + pushedDownQuery->rteperminfos = copyObject(queryTree->rteperminfos); +#endif pushedDownQuery->setOperations = copyObject(queryTree->setOperations); pushedDownQuery->querySource = queryTree->querySource; pushedDownQuery->hasSubLinks = queryTree->hasSubLinks; diff --git a/src/backend/distributed/planner/recursive_planning.c b/src/backend/distributed/planner/recursive_planning.c index f582fd9df..c50eb78e0 100644 --- a/src/backend/distributed/planner/recursive_planning.c +++ b/src/backend/distributed/planner/recursive_planning.c @@ -72,6 +72,7 @@ #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" @@ -88,6 +89,7 @@ #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" @@ -1850,6 +1852,24 @@ CreateOuterSubquery(RangeTblEntry *rangeTableEntry, List *outerSubqueryTargetLis innerSubqueryRTE->eref->colnames = innerSubqueryColNames; outerSubquery->rtable = list_make1(innerSubqueryRTE); +#if PG_VERSION_NUM >= PG_VERSION_16 + 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 + + /* set the FROM expression to the subquery */ RangeTblRef *newRangeTableRef = makeNode(RangeTblRef); newRangeTableRef->rtindex = 1; @@ -2022,6 +2042,24 @@ TransformFunctionRTE(RangeTblEntry *rangeTblEntry) /* set the FROM expression to the subquery */ subquery->rtable = list_make1(newRangeTableEntry); + +#if PG_VERSION_NUM >= PG_VERSION_16 + 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; subquery->jointree = makeFromExpr(list_make1(newRangeTableRef), NULL); @@ -2392,6 +2430,22 @@ 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;