Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit a61b1f7

Browse files
committedDec 6, 2022
Rework query relation permission checking
Currently, information about the permissions to be checked on relations mentioned in a query is stored in their range table entries. So the executor must scan the entire range table looking for relations that need to have permissions checked. This can make the permission checking part of the executor initialization needlessly expensive when many inheritance children are present in the range range. While the permissions need not be checked on the individual child relations, the executor still must visit every range table entry to filter them out. This commit moves the permission checking information out of the range table entries into a new plan node called RTEPermissionInfo. Every top-level (inheritance "root") RTE_RELATION entry in the range table gets one and a list of those is maintained alongside the range table. This new list is initialized by the parser when initializing the range table. The rewriter can add more entries to it as rules/views are expanded. Finally, the planner combines the lists of the individual subqueries into one flat list that is passed to the executor for checking. To make it quick to find the RTEPermissionInfo entry belonging to a given relation, RangeTblEntry gets a new Index field 'perminfoindex' that stores the corresponding RTEPermissionInfo's index in the query's list of the latter. ExecutorCheckPerms_hook has gained another List * argument; the signature is now: typedef bool (*ExecutorCheckPerms_hook_type) (List *rangeTable, List *rtePermInfos, bool ereport_on_violation); The first argument is no longer used by any in-core uses of the hook, but we leave it in place because there may be other implementations that do. Implementations should likely scan the rtePermInfos list to determine which operations to allow or deny. Author: Amit Langote <amitlangote09@gmail.com> Discussion: https://postgr.es/m/CA+HiwqGjJDmUhDSfv-U2qhKJjt9ST7Xh9JXC_irsAQ1TAUsJYg@mail.gmail.com
1 parent b5bbaf0 commit a61b1f7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+953
-533
lines changed
 

‎contrib/postgres_fdw/postgres_fdw.c

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "optimizer/appendinfo.h"
3232
#include "optimizer/clauses.h"
3333
#include "optimizer/cost.h"
34+
#include "optimizer/inherit.h"
3435
#include "optimizer/optimizer.h"
3536
#include "optimizer/pathnode.h"
3637
#include "optimizer/paths.h"
@@ -657,8 +658,8 @@ postgresGetForeignRelSize(PlannerInfo *root,
657658
/*
658659
* If the table or the server is configured to use remote estimates,
659660
* identify which user to do remote access as during planning. This
660-
* should match what ExecCheckRTEPerms() does. If we fail due to lack of
661-
* permissions, the query would have failed at runtime anyway.
661+
* should match what ExecCheckPermissions() does. If we fail due to lack
662+
* of permissions, the query would have failed at runtime anyway.
662663
*/
663664
if (fpinfo->use_remote_estimate)
664665
{
@@ -1809,7 +1810,8 @@ postgresPlanForeignModify(PlannerInfo *root,
18091810
else if (operation == CMD_UPDATE)
18101811
{
18111812
int col;
1812-
Bitmapset *allUpdatedCols = bms_union(rte->updatedCols, rte->extraUpdatedCols);
1813+
RelOptInfo *rel = find_base_rel(root, resultRelation);
1814+
Bitmapset *allUpdatedCols = get_rel_all_updated_cols(root, rel);
18131815

18141816
col = -1;
18151817
while ((col = bms_next_member(allUpdatedCols, col)) >= 0)
@@ -2650,7 +2652,7 @@ postgresBeginDirectModify(ForeignScanState *node, int eflags)
26502652

26512653
/*
26522654
* Identify which user to do the remote access as. This should match what
2653-
* ExecCheckRTEPerms() does.
2655+
* ExecCheckPermissions() does.
26542656
*/
26552657
userid = OidIsValid(fsplan->checkAsUser) ? fsplan->checkAsUser : GetUserId();
26562658

@@ -3975,11 +3977,8 @@ create_foreign_modify(EState *estate,
39753977
fmstate = (PgFdwModifyState *) palloc0(sizeof(PgFdwModifyState));
39763978
fmstate->rel = rel;
39773979

3978-
/*
3979-
* Identify which user to do the remote access as. This should match what
3980-
* ExecCheckRTEPerms() does.
3981-
*/
3982-
userid = OidIsValid(rte->checkAsUser) ? rte->checkAsUser : GetUserId();
3980+
/* Identify which user to do the remote access as. */
3981+
userid = ExecGetResultRelCheckAsUser(resultRelInfo, estate);
39833982

39843983
/* Get info about foreign table. */
39853984
table = GetForeignTable(RelationGetRelid(rel));

‎contrib/sepgsql/dml.c

Lines changed: 19 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "commands/tablecmds.h"
2424
#include "executor/executor.h"
2525
#include "nodes/bitmapset.h"
26+
#include "parser/parsetree.h"
2627
#include "sepgsql.h"
2728
#include "utils/lsyscache.h"
2829
#include "utils/syscache.h"
@@ -277,38 +278,33 @@ check_relation_privileges(Oid relOid,
277278
* Entrypoint of the DML permission checks
278279
*/
279280
bool
280-
sepgsql_dml_privileges(List *rangeTabls, bool abort_on_violation)
281+
sepgsql_dml_privileges(List *rangeTbls, List *rteperminfos,
282+
bool abort_on_violation)
281283
{
282284
ListCell *lr;
283285

284-
foreach(lr, rangeTabls)
286+
foreach(lr, rteperminfos)
285287
{
286-
RangeTblEntry *rte = lfirst(lr);
288+
RTEPermissionInfo *perminfo = lfirst_node(RTEPermissionInfo, lr);
287289
uint32 required = 0;
288290
List *tableIds;
289291
ListCell *li;
290292

291-
/*
292-
* Only regular relations shall be checked
293-
*/
294-
if (rte->rtekind != RTE_RELATION)
295-
continue;
296-
297293
/*
298294
* Find out required permissions
299295
*/
300-
if (rte->requiredPerms & ACL_SELECT)
296+
if (perminfo->requiredPerms & ACL_SELECT)
301297
required |= SEPG_DB_TABLE__SELECT;
302-
if (rte->requiredPerms & ACL_INSERT)
298+
if (perminfo->requiredPerms & ACL_INSERT)
303299
required |= SEPG_DB_TABLE__INSERT;
304-
if (rte->requiredPerms & ACL_UPDATE)
300+
if (perminfo->requiredPerms & ACL_UPDATE)
305301
{
306-
if (!bms_is_empty(rte->updatedCols))
302+
if (!bms_is_empty(perminfo->updatedCols))
307303
required |= SEPG_DB_TABLE__UPDATE;
308304
else
309305
required |= SEPG_DB_TABLE__LOCK;
310306
}
311-
if (rte->requiredPerms & ACL_DELETE)
307+
if (perminfo->requiredPerms & ACL_DELETE)
312308
required |= SEPG_DB_TABLE__DELETE;
313309

314310
/*
@@ -323,10 +319,10 @@ sepgsql_dml_privileges(List *rangeTabls, bool abort_on_violation)
323319
* expand rte->relid into list of OIDs of inheritance hierarchy, then
324320
* checker routine will be invoked for each relations.
325321
*/
326-
if (!rte->inh)
327-
tableIds = list_make1_oid(rte->relid);
322+
if (!perminfo->inh)
323+
tableIds = list_make1_oid(perminfo->relid);
328324
else
329-
tableIds = find_all_inheritors(rte->relid, NoLock, NULL);
325+
tableIds = find_all_inheritors(perminfo->relid, NoLock, NULL);
330326

331327
foreach(li, tableIds)
332328
{
@@ -339,12 +335,12 @@ sepgsql_dml_privileges(List *rangeTabls, bool abort_on_violation)
339335
* child table has different attribute numbers, so we need to fix
340336
* up them.
341337
*/
342-
selectedCols = fixup_inherited_columns(rte->relid, tableOid,
343-
rte->selectedCols);
344-
insertedCols = fixup_inherited_columns(rte->relid, tableOid,
345-
rte->insertedCols);
346-
updatedCols = fixup_inherited_columns(rte->relid, tableOid,
347-
rte->updatedCols);
338+
selectedCols = fixup_inherited_columns(perminfo->relid, tableOid,
339+
perminfo->selectedCols);
340+
insertedCols = fixup_inherited_columns(perminfo->relid, tableOid,
341+
perminfo->insertedCols);
342+
updatedCols = fixup_inherited_columns(perminfo->relid, tableOid,
343+
perminfo->updatedCols);
348344

349345
/*
350346
* check permissions on individual tables

0 commit comments

Comments
 (0)
Please sign in to comment.