Correctly set userid of subquery relations' child rels

The RelOptInfo->userid field (the user ID to check permissions as) of an
"otherrel" relation was being copied from its parent relation, which is
correct in most cases but wrong when the parent is a subquery.  In that
case, using the value from the RTEPermissionInfo of the child itself is
the appropriate thing to do.

Coming up with a test case where user-visible behavior changes proves
hard enough, so we don't add one here.

Bug introduced by a61b1f7482, discovered by Amit while reviewing
nearby code.

Author: Amit Langote <amitlangote09@gmail.com>
Discussion: https://postgr.es/m/CA+HiwqE0WY_AhLnGtTsY7eYebG212XWbM-D8gr2A_ToOHyCywQ@mail.gmail.com
This commit is contained in:
Alvaro Herrera 2023-02-20 16:00:42 +01:00
parent 94cad7a3e6
commit a316a3bc6d
No known key found for this signature in database
GPG Key ID: 1C20ACB9D5C564AE
1 changed files with 14 additions and 4 deletions

View File

@ -233,12 +233,22 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent)
rel->serverid = InvalidOid;
if (rte->rtekind == RTE_RELATION)
{
Assert(parent == NULL ||
parent->rtekind == RTE_RELATION ||
parent->rtekind == RTE_SUBQUERY);
/*
* Get the userid from the relation's RTEPermissionInfo, though only
* the tables mentioned in query are assigned RTEPermissionInfos.
* Child relations (otherrels) simply use the parent's value.
* For any RELATION rte, we need a userid with which to check
* permission access. Baserels simply use their own
* RTEPermissionInfo's checkAsUser.
*
* For otherrels normally there's no RTEPermissionInfo, so we use the
* parent's, which normally has one. The exceptional case is that the
* parent is a subquery, in which case the otherrel will have its own.
*/
if (parent == NULL)
if (rel->reloptkind == RELOPT_BASEREL ||
(rel->reloptkind == RELOPT_OTHER_MEMBER_REL &&
parent->rtekind == RTE_SUBQUERY))
{
RTEPermissionInfo *perminfo;