|
| 1 | +\set VERBOSITY terse |
| 2 | +SET search_path = 'public'; |
| 3 | +CREATE EXTENSION pg_pathman; |
| 4 | +CREATE SCHEMA permissions; |
| 5 | +CREATE ROLE user1 LOGIN; |
| 6 | +CREATE ROLE user2 LOGIN; |
| 7 | +GRANT USAGE, CREATE ON SCHEMA permissions TO user1; |
| 8 | +GRANT USAGE, CREATE ON SCHEMA permissions TO user2; |
| 9 | +/* Switch to #1 */ |
| 10 | +SET ROLE user1; |
| 11 | +CREATE TABLE permissions.user1_table(id serial, a int); |
| 12 | +INSERT INTO permissions.user1_table SELECT g, g FROM generate_series(1, 20) as g; |
| 13 | +/* Should fail (can't SELECT) */ |
| 14 | +SET ROLE user2; |
| 15 | +DO $$ |
| 16 | +BEGIN |
| 17 | + SELECT create_range_partitions('permissions.user1_table', 'id', 1, 10, 2); |
| 18 | +EXCEPTION |
| 19 | + WHEN insufficient_privilege THEN |
| 20 | + RAISE NOTICE 'Insufficient priviliges'; |
| 21 | +END$$; |
| 22 | +NOTICE: Insufficient priviliges |
| 23 | +/* Grant SELECT to user2 */ |
| 24 | +SET ROLE user1; |
| 25 | +GRANT SELECT ON permissions.user1_table TO user2; |
| 26 | +/* Should fail (don't own parent) */ |
| 27 | +SET ROLE user2; |
| 28 | +DO $$ |
| 29 | +BEGIN |
| 30 | + SELECT create_range_partitions('permissions.user1_table', 'id', 1, 10, 2); |
| 31 | +EXCEPTION |
| 32 | + WHEN insufficient_privilege THEN |
| 33 | + RAISE NOTICE 'Insufficient priviliges'; |
| 34 | +END$$; |
| 35 | +NOTICE: Insufficient priviliges |
| 36 | +/* Should be ok */ |
| 37 | +SET ROLE user1; |
| 38 | +SELECT create_range_partitions('permissions.user1_table', 'id', 1, 10, 2); |
| 39 | + create_range_partitions |
| 40 | +------------------------- |
| 41 | + 2 |
| 42 | +(1 row) |
| 43 | + |
| 44 | +/* Should be able to see */ |
| 45 | +SET ROLE user2; |
| 46 | +SELECT * FROM pathman_config; |
| 47 | + partrel | expr | parttype | range_interval |
| 48 | +-------------------------+------+----------+---------------- |
| 49 | + permissions.user1_table | id | 2 | 10 |
| 50 | +(1 row) |
| 51 | + |
| 52 | +SELECT * FROM pathman_config_params; |
| 53 | + partrel | enable_parent | auto | init_callback | spawn_using_bgw |
| 54 | +-------------------------+---------------+------+---------------+----------------- |
| 55 | + permissions.user1_table | f | t | | f |
| 56 | +(1 row) |
| 57 | + |
| 58 | +/* Should fail */ |
| 59 | +SET ROLE user2; |
| 60 | +SELECT set_enable_parent('permissions.user1_table', true); |
| 61 | +WARNING: only the owner or superuser can change partitioning configuration of table "user1_table" |
| 62 | +ERROR: new row violates row-level security policy for table "pathman_config_params" |
| 63 | +SELECT set_auto('permissions.user1_table', false); |
| 64 | +WARNING: only the owner or superuser can change partitioning configuration of table "user1_table" |
| 65 | +ERROR: new row violates row-level security policy for table "pathman_config_params" |
| 66 | +/* Should fail */ |
| 67 | +SET ROLE user2; |
| 68 | +DELETE FROM pathman_config |
| 69 | +WHERE partrel = 'permissions.user1_table'::regclass; |
| 70 | +WARNING: only the owner or superuser can change partitioning configuration of table "user1_table" |
| 71 | +/* No rights to insert, should fail */ |
| 72 | +SET ROLE user2; |
| 73 | +DO $$ |
| 74 | +BEGIN |
| 75 | + INSERT INTO permissions.user1_table (id, a) VALUES (35, 0); |
| 76 | +EXCEPTION |
| 77 | + WHEN insufficient_privilege THEN |
| 78 | + RAISE NOTICE 'Insufficient priviliges'; |
| 79 | +END$$; |
| 80 | +NOTICE: Insufficient priviliges |
| 81 | +/* No rights to create partitions (need INSERT privilege) */ |
| 82 | +SET ROLE user2; |
| 83 | +SELECT prepend_range_partition('permissions.user1_table'); |
| 84 | +ERROR: permission denied for parent relation "user1_table" |
| 85 | +/* Allow user2 to create partitions */ |
| 86 | +SET ROLE user1; |
| 87 | +GRANT INSERT ON permissions.user1_table TO user2; |
| 88 | +GRANT UPDATE(a) ON permissions.user1_table TO user2; /* per-column ACL */ |
| 89 | +/* Should be able to prepend a partition */ |
| 90 | +SET ROLE user2; |
| 91 | +SELECT prepend_range_partition('permissions.user1_table'); |
| 92 | + prepend_range_partition |
| 93 | +--------------------------- |
| 94 | + permissions.user1_table_4 |
| 95 | +(1 row) |
| 96 | + |
| 97 | +SELECT attname, attacl FROM pg_attribute |
| 98 | +WHERE attrelid = (SELECT "partition" FROM pathman_partition_list |
| 99 | + WHERE parent = 'permissions.user1_table'::REGCLASS |
| 100 | + ORDER BY range_min::int ASC /* prepend */ |
| 101 | + LIMIT 1) |
| 102 | +ORDER BY attname; /* check ACL for each column */ |
| 103 | + attname | attacl |
| 104 | +----------+----------------- |
| 105 | + a | {user2=w/user1} |
| 106 | + cmax | |
| 107 | + cmin | |
| 108 | + ctid | |
| 109 | + id | |
| 110 | + tableoid | |
| 111 | + xmax | |
| 112 | + xmin | |
| 113 | +(8 rows) |
| 114 | + |
| 115 | +/* Have rights, should be ok (parent's ACL is shared by new children) */ |
| 116 | +SET ROLE user2; |
| 117 | +INSERT INTO permissions.user1_table (id, a) VALUES (35, 0) RETURNING *; |
| 118 | + id | a |
| 119 | +----+--- |
| 120 | + 35 | 0 |
| 121 | +(1 row) |
| 122 | + |
| 123 | +SELECT relname, relacl FROM pg_class |
| 124 | +WHERE oid = ANY (SELECT "partition" FROM pathman_partition_list |
| 125 | + WHERE parent = 'permissions.user1_table'::REGCLASS |
| 126 | + ORDER BY range_max::int DESC /* append */ |
| 127 | + LIMIT 3) |
| 128 | +ORDER BY relname; /* we also check ACL for "user1_table_2" */ |
| 129 | + relname | relacl |
| 130 | +---------------+--------------------------------------- |
| 131 | + user1_table_2 | {user1=arwdDxtm/user1,user2=r/user1} |
| 132 | + user1_table_5 | {user1=arwdDxtm/user1,user2=ar/user1} |
| 133 | + user1_table_6 | {user1=arwdDxtm/user1,user2=ar/user1} |
| 134 | +(3 rows) |
| 135 | + |
| 136 | +/* Try to drop partition, should fail */ |
| 137 | +DO $$ |
| 138 | +BEGIN |
| 139 | + SELECT drop_range_partition('permissions.user1_table_4'); |
| 140 | +EXCEPTION |
| 141 | + WHEN insufficient_privilege THEN |
| 142 | + RAISE NOTICE 'Insufficient priviliges'; |
| 143 | +END$$; |
| 144 | +NOTICE: Insufficient priviliges |
| 145 | +/* Disable automatic partition creation */ |
| 146 | +SET ROLE user1; |
| 147 | +SELECT set_auto('permissions.user1_table', false); |
| 148 | + set_auto |
| 149 | +---------- |
| 150 | + |
| 151 | +(1 row) |
| 152 | + |
| 153 | +/* Partition creation, should fail */ |
| 154 | +SET ROLE user2; |
| 155 | +INSERT INTO permissions.user1_table (id, a) VALUES (55, 0) RETURNING *; |
| 156 | +ERROR: no suitable partition for key '55' |
| 157 | +/* Finally drop partitions */ |
| 158 | +SET ROLE user1; |
| 159 | +SELECT drop_partitions('permissions.user1_table'); |
| 160 | +NOTICE: 10 rows copied from permissions.user1_table_1 |
| 161 | +NOTICE: 10 rows copied from permissions.user1_table_2 |
| 162 | +NOTICE: 0 rows copied from permissions.user1_table_4 |
| 163 | +NOTICE: 0 rows copied from permissions.user1_table_5 |
| 164 | +NOTICE: 1 rows copied from permissions.user1_table_6 |
| 165 | + drop_partitions |
| 166 | +----------------- |
| 167 | + 5 |
| 168 | +(1 row) |
| 169 | + |
| 170 | +/* Switch to #2 */ |
| 171 | +SET ROLE user2; |
| 172 | +/* Test ddl event trigger */ |
| 173 | +CREATE TABLE permissions.user2_table(id serial); |
| 174 | +SELECT create_hash_partitions('permissions.user2_table', 'id', 3); |
| 175 | + create_hash_partitions |
| 176 | +------------------------ |
| 177 | + 3 |
| 178 | +(1 row) |
| 179 | + |
| 180 | +INSERT INTO permissions.user2_table SELECT generate_series(1, 30); |
| 181 | +SELECT drop_partitions('permissions.user2_table'); |
| 182 | +NOTICE: 9 rows copied from permissions.user2_table_0 |
| 183 | +NOTICE: 11 rows copied from permissions.user2_table_1 |
| 184 | +NOTICE: 10 rows copied from permissions.user2_table_2 |
| 185 | + drop_partitions |
| 186 | +----------------- |
| 187 | + 3 |
| 188 | +(1 row) |
| 189 | + |
| 190 | +/* Switch to #1 */ |
| 191 | +SET ROLE user1; |
| 192 | +CREATE TABLE permissions.dropped_column(a int, val int not null, b int, c int); |
| 193 | +INSERT INTO permissions.dropped_column SELECT i,i,i,i FROM generate_series(1, 30) i; |
| 194 | +GRANT SELECT(val), INSERT(val) ON permissions.dropped_column TO user2; |
| 195 | +SELECT create_range_partitions('permissions.dropped_column', 'val', 1, 10); |
| 196 | + create_range_partitions |
| 197 | +------------------------- |
| 198 | + 3 |
| 199 | +(1 row) |
| 200 | + |
| 201 | +SELECT attrelid::regclass, attname, attacl FROM pg_attribute |
| 202 | +WHERE attrelid = ANY (SELECT "partition" FROM pathman_partition_list |
| 203 | + WHERE parent = 'permissions.dropped_column'::REGCLASS) |
| 204 | + AND attacl IS NOT NULL |
| 205 | +ORDER BY attrelid::regclass::text; /* check ACL for each column */ |
| 206 | + attrelid | attname | attacl |
| 207 | +------------------------------+---------+------------------ |
| 208 | + permissions.dropped_column_1 | val | {user2=ar/user1} |
| 209 | + permissions.dropped_column_2 | val | {user2=ar/user1} |
| 210 | + permissions.dropped_column_3 | val | {user2=ar/user1} |
| 211 | +(3 rows) |
| 212 | + |
| 213 | +ALTER TABLE permissions.dropped_column DROP COLUMN a; /* DROP "a" */ |
| 214 | +SELECT append_range_partition('permissions.dropped_column'); |
| 215 | + append_range_partition |
| 216 | +------------------------------ |
| 217 | + permissions.dropped_column_4 |
| 218 | +(1 row) |
| 219 | + |
| 220 | +SELECT attrelid::regclass, attname, attacl FROM pg_attribute |
| 221 | +WHERE attrelid = ANY (SELECT "partition" FROM pathman_partition_list |
| 222 | + WHERE parent = 'permissions.dropped_column'::REGCLASS) |
| 223 | + AND attacl IS NOT NULL |
| 224 | +ORDER BY attrelid::regclass::text; /* check ACL for each column (+1 partition) */ |
| 225 | + attrelid | attname | attacl |
| 226 | +------------------------------+---------+------------------ |
| 227 | + permissions.dropped_column_1 | val | {user2=ar/user1} |
| 228 | + permissions.dropped_column_2 | val | {user2=ar/user1} |
| 229 | + permissions.dropped_column_3 | val | {user2=ar/user1} |
| 230 | + permissions.dropped_column_4 | val | {user2=ar/user1} |
| 231 | +(4 rows) |
| 232 | + |
| 233 | +ALTER TABLE permissions.dropped_column DROP COLUMN b; /* DROP "b" */ |
| 234 | +SELECT append_range_partition('permissions.dropped_column'); |
| 235 | + append_range_partition |
| 236 | +------------------------------ |
| 237 | + permissions.dropped_column_5 |
| 238 | +(1 row) |
| 239 | + |
| 240 | +SELECT attrelid::regclass, attname, attacl FROM pg_attribute |
| 241 | +WHERE attrelid = ANY (SELECT "partition" FROM pathman_partition_list |
| 242 | + WHERE parent = 'permissions.dropped_column'::REGCLASS) |
| 243 | + AND attacl IS NOT NULL |
| 244 | +ORDER BY attrelid::regclass::text; /* check ACL for each column (+1 partition) */ |
| 245 | + attrelid | attname | attacl |
| 246 | +------------------------------+---------+------------------ |
| 247 | + permissions.dropped_column_1 | val | {user2=ar/user1} |
| 248 | + permissions.dropped_column_2 | val | {user2=ar/user1} |
| 249 | + permissions.dropped_column_3 | val | {user2=ar/user1} |
| 250 | + permissions.dropped_column_4 | val | {user2=ar/user1} |
| 251 | + permissions.dropped_column_5 | val | {user2=ar/user1} |
| 252 | +(5 rows) |
| 253 | + |
| 254 | +DROP TABLE permissions.dropped_column CASCADE; |
| 255 | +NOTICE: drop cascades to 6 other objects |
| 256 | +/* Finally reset user */ |
| 257 | +RESET ROLE; |
| 258 | +DROP OWNED BY user1; |
| 259 | +DROP OWNED BY user2; |
| 260 | +DROP USER user1; |
| 261 | +DROP USER user2; |
| 262 | +DROP SCHEMA permissions; |
| 263 | +DROP EXTENSION pg_pathman; |
0 commit comments