Skip to content

Commit 7190951

Browse files
author
Dražen Odobašić
committed
Match literal underscore in LIKE pattern "pg\_%"
`_` matches single character in LIKE pattern matching, so a pattern `LIKE 'pg_%'` would match anything that starts with `pg` and is at least 3 characters long, like 'pg1'. To correct matching pattern and only match `pg_%` we need to escape literal underscore `pg\_%`
1 parent f4b7c18 commit 7190951

File tree

4 files changed

+146
-9
lines changed

4 files changed

+146
-9
lines changed

expected/sample.out

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,18 +37,21 @@ DETAIL: Failing row contains (8, user2, {CREATE}, SCHEMA, appschema, sometable,
3737
CREATE SCHEMA appschema;
3838
GRANT USAGE ON SCHEMA appschema TO PUBLIC; -- missing CREATE for user1
3939
GRANT CREATE ON SCHEMA appschema TO user2; -- too much
40+
CREATE SCHEMA pgabc123;
41+
GRANT USAGE ON SCHEMA pgabc123 TO user1;
4042
/* table */
4143
-- desired permissions
4244
INSERT INTO permission_target
4345
(role_name, permissions, object_type, schema_name, object_name, column_name)
4446
VALUES ('user1', ARRAY['SELECT','INSERT','UPDATE','DELETE']::perm_type[], 'TABLE', 'appschema', NULL, NULL),
45-
('user2', ARRAY['SELECT']::perm_type[], 'TABLE', 'appschema', NULL, NULL);
47+
('user2', ARRAY['SELECT']::perm_type[], 'TABLE', 'appschema', NULL, NULL),
48+
('user1', ARRAY['SELECT']::perm_type[], 'TABLE', 'pgabc213', 'sometable', NULL);
4649
-- this should fail
4750
INSERT INTO permission_target
4851
(role_name, permissions, object_type, schema_name, object_name, column_name)
4952
VALUES ('user2', ARRAY['INSERT']::perm_type[], 'TABLE', 'appschema', 'apptable', 'acolumn');
5053
ERROR: new row for relation "permission_target" violates check constraint "permission_target_valid"
51-
DETAIL: Failing row contains (11, user2, {INSERT}, TABLE, appschema, apptable, acolumn).
54+
DETAIL: Failing row contains (12, user2, {INSERT}, TABLE, appschema, apptable, acolumn).
5255
-- actual permissions
5356
CREATE TABLE appschema.apptable (
5457
id integer PRIMARY KEY,
@@ -60,8 +63,14 @@ CREATE TABLE appschema.apptable2 (
6063
val text NOT NULL,
6164
created timestamp with time zone NOT NULL DEFAULT current_timestamp
6265
); -- missing all permissions on this one
66+
CREATE TABLE pgabc123.sometable (
67+
id integer PRIMARY KEY,
68+
val text NOT NULL,
69+
created timestamp with time zone NOT NULL DEFAULT current_timestamp
70+
);
6371
GRANT SELECT, INSERT, UPDATE ON appschema.apptable TO user1; -- missing DELETE
6472
GRANT SELECT, INSERT ON appschema.apptable TO user2; -- extra privilege INSERT
73+
GRANT SELECT ON pgabc123.sometable TO user1;
6574
/* column */
6675
-- desired permissions
6776
INSERT INTO permission_target
@@ -72,7 +81,7 @@ INSERT INTO permission_target
7281
(role_name, permissions, object_type, schema_name, object_name, column_name)
7382
VALUES ('user2', ARRAY['DELETE']::perm_type[], 'COLUMN', 'appschema', 'apptable2', 'val');
7483
ERROR: new row for relation "permission_target" violates check constraint "permission_target_valid"
75-
DETAIL: Failing row contains (13, user2, {DELETE}, COLUMN, appschema, apptable2, val).
84+
DETAIL: Failing row contains (14, user2, {DELETE}, COLUMN, appschema, apptable2, val).
7685
-- actual permissions
7786
-- missing REFERENCES for user1 on apptable2.val
7887
GRANT UPDATE (val) ON appschema.apptable2 TO user2; -- extra privilege UPDATE
@@ -109,7 +118,7 @@ INSERT INTO permission_target
109118
(role_name, permissions, object_type, schema_name, object_name, column_name)
110119
VALUES ('users', ARRAY['UPDATE']::perm_type[], 'FUNCTION', 'appschema', 'appfun(integer)', NULL);
111120
ERROR: new row for relation "permission_target" violates check constraint "permission_target_valid"
112-
DETAIL: Failing row contains (21, users, {UPDATE}, FUNCTION, appschema, appfun(integer), null).
121+
DETAIL: Failing row contains (22, users, {UPDATE}, FUNCTION, appschema, appfun(integer), null).
113122
-- actual permissions
114123
CREATE FUNCTION appschema.appfun(i integer) RETURNS integer
115124
LANGUAGE sql IMMUTABLE AS
@@ -119,13 +128,14 @@ SELECT object_type, role_name, schema_name, object_name, column_name, permission
119128
FROM all_permissions
120129
WHERE granted
121130
AND role_name IN ('users', 'user1', 'user2')
122-
AND coalesce(schema_name, 'appschema') = 'appschema'
131+
AND coalesce(schema_name, 'appschema') IN ('appschema', 'pgabc123')
123132
ORDER BY object_type, role_name, schema_name, object_name, column_name, permission;
124133
object_type | role_name | schema_name | object_name | column_name | permission
125134
-------------+-----------+-------------+-----------------+-------------+------------
126135
TABLE | user1 | appschema | apptable | | SELECT
127136
TABLE | user1 | appschema | apptable | | INSERT
128137
TABLE | user1 | appschema | apptable | | UPDATE
138+
TABLE | user1 | pgabc123 | sometable | | SELECT
129139
TABLE | user2 | appschema | apptable | | SELECT
130140
TABLE | user2 | appschema | apptable | | INSERT
131141
VIEW | user1 | appschema | appview | | SELECT
@@ -142,6 +152,7 @@ ORDER BY object_type, role_name, schema_name, object_name, column_name, permissi
142152
FUNCTION | user2 | appschema | appfun(integer) | | EXECUTE
143153
FUNCTION | users | appschema | appfun(integer) | | EXECUTE
144154
SCHEMA | user1 | appschema | | | USAGE
155+
SCHEMA | user1 | pgabc123 | | | USAGE
145156
SCHEMA | user2 | appschema | | | USAGE
146157
SCHEMA | user2 | appschema | | | CREATE
147158
SCHEMA | users | appschema | | | USAGE
@@ -152,7 +163,7 @@ ORDER BY object_type, role_name, schema_name, object_name, column_name, permissi
152163
DATABASE | user2 | | | | TEMPORARY
153164
DATABASE | users | | | | CONNECT
154165
DATABASE | users | | | | TEMPORARY
155-
(29 rows)
166+
(31 rows)
156167

157168
/* report differences */
158169
SELECT * FROM permission_diffs()
@@ -229,7 +240,9 @@ DROP VIEW appschema.appview;
229240
DROP SEQUENCE appschema.appseq;
230241
DROP TABLE appschema.apptable;
231242
DROP TABLE appschema.apptable2;
243+
DROP TABLE pgabc123.sometable;
232244
DROP SCHEMA appschema;
245+
DROP SCHEMA pgabc123;
233246
REVOKE ALL ON DATABASE contrib_regression FROM user1, user2, users;
234247
DROP ROLE user1;
235248
DROP ROLE user2;

pg_permissions--1.3--1.4.sql

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
2+
\echo Use "ALTER EXTENSION pg_permissions UPDATE" to load this file. \quit
3+
4+
CREATE OR REPLACE VIEW table_permissions AS
5+
SELECT obj_type 'TABLE' AS object_type,
6+
r.rolname AS role_name,
7+
t.relnamespace::regnamespace::name AS schema_name,
8+
t.relname::text AS object_name,
9+
NULL::name AS column_name,
10+
p.perm::perm_type AS permission,
11+
has_table_privilege(r.oid, t.oid, p.perm) AS granted
12+
FROM pg_catalog.pg_class AS t
13+
CROSS JOIN pg_catalog.pg_roles AS r
14+
CROSS JOIN unnest(
15+
CASE WHEN current_setting('server_version_num')::integer < 170000
16+
THEN ARRAY['SELECT','INSERT','UPDATE','DELETE','TRUNCATE','REFERENCES','TRIGGER']
17+
ELSE ARRAY['SELECT','INSERT','UPDATE','DELETE','TRUNCATE','REFERENCES','TRIGGER','MAINTAIN']
18+
END
19+
) AS p(perm)
20+
WHERE t.relnamespace::regnamespace::name <> 'information_schema'
21+
AND t.relnamespace::regnamespace::name NOT LIKE 'pg\_%'
22+
AND t.relkind = 'r'
23+
AND NOT r.rolsuper;
24+
25+
26+
CREATE OR REPLACE VIEW view_permissions AS
27+
SELECT obj_type 'VIEW' AS object_type,
28+
r.rolname AS role_name,
29+
t.relnamespace::regnamespace::name AS schema_name,
30+
t.relname::text AS object_name,
31+
NULL::name AS column_name,
32+
p.perm::perm_type AS permission,
33+
has_table_privilege(r.oid, t.oid, p.perm) AS granted
34+
FROM pg_catalog.pg_class AS t
35+
CROSS JOIN pg_catalog.pg_roles AS r
36+
CROSS JOIN unnest(
37+
CASE WHEN current_setting('server_version_num')::integer < 170000
38+
THEN ARRAY['SELECT','INSERT','UPDATE','DELETE','TRUNCATE','REFERENCES','TRIGGER']
39+
ELSE ARRAY['SELECT','INSERT','UPDATE','DELETE','TRUNCATE','REFERENCES','TRIGGER','MAINTAIN']
40+
END
41+
) AS p(perm)
42+
WHERE t.relnamespace::regnamespace::name <> 'information_schema'
43+
AND t.relnamespace::regnamespace::name NOT LIKE 'pg\_%'
44+
AND t.relkind = 'v'
45+
AND NOT r.rolsuper;
46+
47+
48+
CREATE OR REPLACE VIEW column_permissions AS
49+
SELECT obj_type 'COLUMN' AS object_type,
50+
r.rolname AS role_name,
51+
t.relnamespace::regnamespace::name AS schema_name,
52+
t.relname::text AS object_name,
53+
c.attname AS column_name,
54+
p.perm::perm_type AS permission,
55+
has_column_privilege(r.oid, t.oid, c.attnum, p.perm)
56+
AND NOT has_table_privilege(r.oid, t.oid, p.perm) AS granted
57+
FROM pg_catalog.pg_class AS t
58+
JOIN pg_catalog.pg_attribute AS c ON t.oid = c.attrelid
59+
CROSS JOIN pg_catalog.pg_roles AS r
60+
CROSS JOIN (VALUES ('SELECT'), ('INSERT'), ('UPDATE'), ('REFERENCES')) AS p(perm)
61+
WHERE t.relnamespace::regnamespace::name <> 'information_schema'
62+
AND t.relnamespace::regnamespace::name NOT LIKE 'pg\_%'
63+
AND c.attnum > 0 AND NOT c.attisdropped
64+
AND t.relkind IN ('r', 'v')
65+
AND NOT r.rolsuper;
66+
67+
68+
CREATE OR REPLACE VIEW sequence_permissions AS
69+
SELECT obj_type 'SEQUENCE' AS object_type,
70+
r.rolname AS role_name,
71+
t.relnamespace::regnamespace::name AS schema_name,
72+
t.relname::text AS object_name,
73+
NULL::name AS column_name,
74+
p.perm::perm_type AS permission,
75+
has_sequence_privilege(r.oid, t.oid, p.perm) AS granted
76+
FROM pg_catalog.pg_class AS t
77+
CROSS JOIN pg_catalog.pg_roles AS r
78+
CROSS JOIN (VALUES ('SELECT'), ('USAGE'), ('UPDATE')) AS p(perm)
79+
WHERE t.relnamespace::regnamespace::name <> 'information_schema'
80+
AND t.relnamespace::regnamespace::name NOT LIKE 'pg\_%'
81+
AND t.relkind = 'S'
82+
AND NOT r.rolsuper;
83+
84+
85+
CREATE OR REPLACE VIEW function_permissions AS
86+
SELECT obj_type 'FUNCTION' AS object_type,
87+
r.rolname AS role_name,
88+
f.pronamespace::regnamespace::name AS schema_name,
89+
regexp_replace(f.oid::regprocedure::text, '^((("[^"]*")|([^"][^.]*))\.)?', '') AS object_name,
90+
NULL::name AS column_name,
91+
perm_type 'EXECUTE' AS permission,
92+
has_function_privilege(r.oid, f.oid, 'EXECUTE') AS granted
93+
FROM pg_catalog.pg_proc f
94+
CROSS JOIN pg_catalog.pg_roles AS r
95+
WHERE f.pronamespace::regnamespace::name <> 'information_schema'
96+
AND f.pronamespace::regnamespace::name NOT LIKE 'pg\_%'
97+
AND NOT r.rolsuper;
98+
99+
100+
CREATE OR REPLACE VIEW schema_permissions AS
101+
SELECT obj_type 'SCHEMA' AS object_type,
102+
r.rolname AS role_name,
103+
n.nspname AS schema_name,
104+
NULL::text AS object_name,
105+
NULL::name AS column_name,
106+
p.perm::perm_type AS permission,
107+
has_schema_privilege(r.oid, n.oid, p.perm) AS granted
108+
FROM pg_catalog.pg_namespace AS n
109+
CROSS JOIN pg_catalog.pg_roles AS r
110+
CROSS JOIN (VALUES ('USAGE'), ('CREATE')) AS p(perm)
111+
WHERE n.nspname <> 'information_schema'
112+
AND n.nspname NOT LIKE 'pg\_%'
113+
AND NOT r.rolsuper;

pg_permissions.control

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
comment = 'view object permissions and compare them with the desired state'
2-
default_version = '1.3'
2+
default_version = '1.4'
33
relocatable = false
44
superuser = false

sql/sample.sql

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,17 @@ VALUES ('user2', ARRAY['CREATE']::perm_type[], 'SCHEMA', 'appschema', 'sometable
4040
CREATE SCHEMA appschema;
4141
GRANT USAGE ON SCHEMA appschema TO PUBLIC; -- missing CREATE for user1
4242
GRANT CREATE ON SCHEMA appschema TO user2; -- too much
43+
CREATE SCHEMA pgabc123;
44+
GRANT USAGE ON SCHEMA pgabc123 TO user1;
4345

4446
/* table */
4547

4648
-- desired permissions
4749
INSERT INTO permission_target
4850
(role_name, permissions, object_type, schema_name, object_name, column_name)
4951
VALUES ('user1', ARRAY['SELECT','INSERT','UPDATE','DELETE']::perm_type[], 'TABLE', 'appschema', NULL, NULL),
50-
('user2', ARRAY['SELECT']::perm_type[], 'TABLE', 'appschema', NULL, NULL);
52+
('user2', ARRAY['SELECT']::perm_type[], 'TABLE', 'appschema', NULL, NULL),
53+
('user1', ARRAY['SELECT']::perm_type[], 'TABLE', 'pgabc213', 'sometable', NULL);
5154
-- this should fail
5255
INSERT INTO permission_target
5356
(role_name, permissions, object_type, schema_name, object_name, column_name)
@@ -63,8 +66,14 @@ CREATE TABLE appschema.apptable2 (
6366
val text NOT NULL,
6467
created timestamp with time zone NOT NULL DEFAULT current_timestamp
6568
); -- missing all permissions on this one
69+
CREATE TABLE pgabc123.sometable (
70+
id integer PRIMARY KEY,
71+
val text NOT NULL,
72+
created timestamp with time zone NOT NULL DEFAULT current_timestamp
73+
);
6674
GRANT SELECT, INSERT, UPDATE ON appschema.apptable TO user1; -- missing DELETE
6775
GRANT SELECT, INSERT ON appschema.apptable TO user2; -- extra privilege INSERT
76+
GRANT SELECT ON pgabc123.sometable TO user1;
6877

6978
/* column */
7079

@@ -128,7 +137,7 @@ SELECT object_type, role_name, schema_name, object_name, column_name, permission
128137
FROM all_permissions
129138
WHERE granted
130139
AND role_name IN ('users', 'user1', 'user2')
131-
AND coalesce(schema_name, 'appschema') = 'appschema'
140+
AND coalesce(schema_name, 'appschema') IN ('appschema', 'pgabc123')
132141
ORDER BY object_type, role_name, schema_name, object_name, column_name, permission;
133142

134143
/* report differences */
@@ -168,7 +177,9 @@ DROP VIEW appschema.appview;
168177
DROP SEQUENCE appschema.appseq;
169178
DROP TABLE appschema.apptable;
170179
DROP TABLE appschema.apptable2;
180+
DROP TABLE pgabc123.sometable;
171181
DROP SCHEMA appschema;
182+
DROP SCHEMA pgabc123;
172183
REVOKE ALL ON DATABASE contrib_regression FROM user1, user2, users;
173184

174185
DROP ROLE user1;

0 commit comments

Comments
 (0)