BUG #15251: query plan affected by grant select on partition

From: PG Bug reporting form <noreply(at)postgresql(dot)org>
To: pgsql-bugs(at)lists(dot)postgresql(dot)org
Cc: pgsqlpl(at)gmail(dot)com
Subject: BUG #15251: query plan affected by grant select on partition
Date: 2018-06-22 13:00:58
Message-ID: 152967245839.1266.6939666809369185595@wrigleys.postgresql.org
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-bugs

The following bug has been logged on the website:

Bug reference: 15251
Logged by: Peter
Email address: pgsqlpl(at)gmail(dot)com
PostgreSQL version: 10.4
Operating system: Ubuntu 14.04
Description:

Description:
Plan of SELECT query on a parent table, which actually get data from an
inherited table (partition) depends on grants for a partition.
- When current_user is missing a grant to SELECT from a partition then
planner incorrectly decides to use BitmapAnd on two GIN Indexes (see "Bad
plan" below).
- When current_user has grant to SELECT from a partition then planner
correctly decides to use one of two GIN Indexes which is more reductive.

Reproducible on:
- Ubuntu 10.4-2.pgdg14.04+1
- Ubuntu 9.6.9-2.pgdg14.04+1
- Ubuntu 9.5.13-2.pgdg14.04+1

Code:

CREATE EXTENSION IF NOT EXISTS pg_trgm; -- for gin_trgm_ops

-- base table
DROP TABLE IF EXISTS c CASCADE;
CREATE TABLE c
(
id bigserial NOT NULL PRIMARY KEY
, ts timestamptz NOT NULL --
partitioning
, p text NOT NULL -- trigram based
search
, t int[] NOT NULL DEFAULT '{0}' -- row level
security
);
CREATE INDEX g3_c_p ON c USING GIN (p gin_trgm_ops);
CREATE INDEX gx_c_t ON c USING GIN(t);

-- create partition
CREATE TABLE cc201806
(
CHECK (ts >= '2018-06-01 00:00:00'
AND ts < '2018-07-01 00:00:00')
) INHERITS (c);

CREATE EXTENSION IF NOT EXISTS pgcrypto; -- gen_random_bytes
-- populate partition
INSERT INTO cc201806 (id, ts, p) SELECT i, clock_timestamp(),
encode(gen_random_bytes(11), 'hex') FROM generate_series(1, 1000000) AS
gs(i);
-- make indexes after instert to speedup above insert
CREATE INDEX g3_cc201806_p ON cc201806 USING GIN (p gin_trgm_ops);
CREATE INDEX gx_cc201806_t ON cc201806 USING GIN(t);

ANALYZE; -- have good statistics

-- use restricted role (in actual DB, it is an owner of SECURITY DEFINER
function, executing following query as a dynamic statement)
DROP ROLE IF EXISTS u;
CREATE ROLE u;
GRANT SELECT ON c TO u;
;
-- exec once to cache data
EXPLAIN (ANALYZE, BUFFERS)
SELECT *
FROM c
WHERE p ~ 'bbbb'
AND t && '{1, 2, 0}'::int[] -- this array is actually a function
call
;

-- missing GRANT SELECT ON partition
REVOKE SELECT ON cc201806 FROM u;
SET ROLE u;
EXPLAIN (ANALYZE, BUFFERS)
SELECT *
FROM c
WHERE p ~ 'bbbb'
AND t && '{1, 2, 0}'::int[] -- this array is actually a function
call
;

RESET ROLE;
GRANT SELECT ON cc201806 TO u;
SET ROLE u;
EXPLAIN (ANALYZE, BUFFERS)
SELECT *
FROM c
WHERE p ~ 'bbbb'
AND t && '{1, 2, 0}'::int[] -- this array is actually a function
call
;

SELECT version();
SHOW work_mem; -- 4MB
SHOW effective_cache_size; -- 4GB
SHOW shared_buffers; -- 256MB

Examples of resulting plans:

Bad plan:
-------------------------------------------------------------------------------------------------------------------------------------------------
Append (cost=0.00..2233.50 rows=120 width=64) (actual
time=157.626..167.316 rows=276 loops=1)
Buffers: shared hit=3866
-> Seq Scan on c (cost=0.00..0.00 rows=1 width=80) (actual
time=0.001..0.001 rows=0 loops=1)
Filter: ((p ~ 'bbbb'::text) AND (t && '{1,2,0}'::integer[]))
-> Bitmap Heap Scan on cc201806 (cost=1792.25..2233.50 rows=119
width=64) (actual time=157.624..167.284 rows=276 loops=1)
Recheck Cond: ((p ~ 'bbbb'::text) AND (t &&
'{1,2,0}'::integer[]))
Rows Removed by Index Recheck: 4212
Heap Blocks: exact=3723
Buffers: shared hit=3866
-> BitmapAnd (cost=1792.25..1792.25 rows=119 width=0) (actual
time=157.019..157.019 rows=0 loops=1)
Buffers: shared hit=143
-> Bitmap Index Scan on g3_cc201806_p (cost=0.00..84.00
rows=8000 width=0) (actual time=1.608..1.608 rows=4488 loops=1)
Index Cond: (p ~ 'bbbb'::text)
Buffers: shared hit=7
-> Bitmap Index Scan on gx_cc201806_t (cost=0.00..1707.94
rows=14925 width=0) (actual time=155.163..155.163 rows=1000000 loops=1)
Index Cond: (t && '{1,2,0}'::integer[])
Buffers: shared hit=136
Planning time: 0.316 ms
Execution time: 167.372 ms

Good plan:
-----------------------------------------------------------------------------------------------------------------------------------
Append (cost=0.00..390.13 rows=101 width=64) (actual time=2.192..11.944
rows=276 loops=1)
Buffers: shared hit=3730
-> Seq Scan on c (cost=0.00..0.00 rows=1 width=80) (actual
time=0.001..0.001 rows=0 loops=1)
Filter: ((p ~ 'bbbb'::text) AND (t && '{1,2,0}'::integer[]))
-> Bitmap Heap Scan on cc201806 (cost=16.77..390.13 rows=100 width=64)
(actual time=2.189..11.912 rows=276 loops=1)
Recheck Cond: (p ~ 'bbbb'::text)
Rows Removed by Index Recheck: 4212
Filter: (t && '{1,2,0}'::integer[])
Heap Blocks: exact=3723
Buffers: shared hit=3730
-> Bitmap Index Scan on g3_cc201806_p (cost=0.00..16.75 rows=100
width=0) (actual time=1.565..1.565 rows=4488 loops=1)
Index Cond: (p ~ 'bbbb'::text)
Buffers: shared hit=7
Planning time: 0.413 ms
Execution time: 11.996 ms

Responses

Browse pgsql-bugs by date

  From Date Subject
Next Message PG Bug reporting form 2018-06-25 09:50:15 BUG #15252: "do not dump comments" in pg_restore help
Previous Message Mario De Frutos Dieguez 2018-06-22 09:15:03 Re: Fwd: Problem with a "complex" upsert