Skip to content

Commit 89b69db

Browse files
committed
Allow examine_simple_variable() to work on INSERT RETURNING Vars.
Since commit 599b33b, this function assumed that every RTE_RELATION RangeTblEntry would have an associated RelOptInfo. But that's not so: we only build RelOptInfos for relations that are scanned by the query. In particular the target of an INSERT won't have one, so that Vars appearing in an INSERT ... RETURNING list will not have an associated RelOptInfo. This apparently wasn't a problem before commit f7816ae taught examine_simple_variable() to drill down into CTEs containing INSERT RETURNING, but it is now. To fix, add a fallback code path that gets the userid to use directly from the RTEPermissionInfo associated with the RTE. (Sadly, we must have two code paths, because not every RTE has a RTEPermissionInfo either.) Per report from Alexander Lakhin. No back-patch, since the case is apparently unreachable before f7816ae. Discussion: https://postgr.es/m/608a4886-6c60-0f9e-97d5-591256bd4150@gmail.com
1 parent bea18b1 commit 89b69db

File tree

5 files changed

+56
-5
lines changed

5 files changed

+56
-5
lines changed

src/backend/optimizer/util/relnode.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,19 @@ find_base_rel(PlannerInfo *root, int relid)
420420
return NULL; /* keep compiler quiet */
421421
}
422422

423+
/*
424+
* find_base_rel_noerr
425+
* Find a base or otherrel relation entry, returning NULL if there's none
426+
*/
427+
RelOptInfo *
428+
find_base_rel_noerr(PlannerInfo *root, int relid)
429+
{
430+
/* use an unsigned comparison to prevent negative array element access */
431+
if ((uint32) relid < (uint32) root->simple_rel_array_size)
432+
return root->simple_rel_array[relid];
433+
return NULL;
434+
}
435+
423436
/*
424437
* find_base_rel_ignore_join
425438
* Find a base or otherrel relation entry, which must already exist.

src/backend/utils/adt/selfuncs.c

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@
119119
#include "optimizer/paths.h"
120120
#include "optimizer/plancat.h"
121121
#include "parser/parse_clause.h"
122+
#include "parser/parse_relation.h"
122123
#include "parser/parsetree.h"
123124
#include "statistics/statistics.h"
124125
#include "storage/bufmgr.h"
@@ -5434,17 +5435,30 @@ examine_simple_variable(PlannerInfo *root, Var *var,
54345435

54355436
if (HeapTupleIsValid(vardata->statsTuple))
54365437
{
5437-
RelOptInfo *onerel = find_base_rel(root, var->varno);
5438+
RelOptInfo *onerel = find_base_rel_noerr(root, var->varno);
54385439
Oid userid;
54395440

54405441
/*
54415442
* Check if user has permission to read this column. We require
54425443
* all rows to be accessible, so there must be no securityQuals
5443-
* from security barrier views or RLS policies. Use
5444-
* onerel->userid if it's set, in case we're accessing the table
5445-
* via a view.
5444+
* from security barrier views or RLS policies.
5445+
*
5446+
* Normally the Var will have an associated RelOptInfo from which
5447+
* we can find out which userid to do the check as; but it might
5448+
* not if it's a RETURNING Var for an INSERT target relation. In
5449+
* that case use the RTEPermissionInfo associated with the RTE.
54465450
*/
5447-
userid = OidIsValid(onerel->userid) ? onerel->userid : GetUserId();
5451+
if (onerel)
5452+
userid = onerel->userid;
5453+
else
5454+
{
5455+
RTEPermissionInfo *perminfo;
5456+
5457+
perminfo = getRTEPermissionInfo(root->parse->rteperminfos, rte);
5458+
userid = perminfo->checkAsUser;
5459+
}
5460+
if (!OidIsValid(userid))
5461+
userid = GetUserId();
54485462

54495463
vardata->acl_ok =
54505464
rte->securityQuals == NIL &&

src/include/optimizer/pathnode.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,7 @@ extern void expand_planner_arrays(PlannerInfo *root, int add_size);
307307
extern RelOptInfo *build_simple_rel(PlannerInfo *root, int relid,
308308
RelOptInfo *parent);
309309
extern RelOptInfo *find_base_rel(PlannerInfo *root, int relid);
310+
extern RelOptInfo *find_base_rel_noerr(PlannerInfo *root, int relid);
310311
extern RelOptInfo *find_base_rel_ignore_join(PlannerInfo *root, int relid);
311312
extern RelOptInfo *find_join_rel(PlannerInfo *root, Relids relids);
312313
extern RelOptInfo *build_join_rel(PlannerInfo *root,

src/test/regress/expected/with.out

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -654,6 +654,24 @@ select count(*) from tenk1 a
654654
-> CTE Scan on x
655655
(8 rows)
656656

657+
explain (costs off)
658+
with x as materialized (insert into tenk1 default values returning unique1)
659+
select count(*) from tenk1 a
660+
where unique1 in (select * from x);
661+
QUERY PLAN
662+
------------------------------------------------------------
663+
Aggregate
664+
CTE x
665+
-> Insert on tenk1
666+
-> Result
667+
-> Nested Loop
668+
-> HashAggregate
669+
Group Key: x.unique1
670+
-> CTE Scan on x
671+
-> Index Only Scan using tenk1_unique1 on tenk1 a
672+
Index Cond: (unique1 = x.unique1)
673+
(10 rows)
674+
657675
-- SEARCH clause
658676
create temp table graph0( f int, t int, label text );
659677
insert into graph0 values

src/test/regress/sql/with.sql

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,11 @@ with x as materialized (select unique1 from tenk1 b)
354354
select count(*) from tenk1 a
355355
where unique1 in (select * from x);
356356

357+
explain (costs off)
358+
with x as materialized (insert into tenk1 default values returning unique1)
359+
select count(*) from tenk1 a
360+
where unique1 in (select * from x);
361+
357362
-- SEARCH clause
358363

359364
create temp table graph0( f int, t int, label text );

0 commit comments

Comments
 (0)