Skip to content

Commit 4bd715c

Browse files
committed
Merge branch 'rel_1_2_beta' of https://github.com/postgrespro/pg_pathman into rel_1_2_beta
2 parents 9575107 + 2a31969 commit 4bd715c

10 files changed

+490
-165
lines changed

expected/pathman_calamity.out

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,44 @@ SELECT debug_capture();
1212
set client_min_messages = NOTICE;
1313
/* create table to be partitioned */
1414
CREATE TABLE calamity.part_test(val serial);
15+
/* check function build_hash_condition() */
16+
SELECT build_hash_condition('int4', 'val', 10, 1);
17+
build_hash_condition
18+
-------------------------------------------------
19+
public.get_hash_part_idx(hashint4(val), 10) = 1
20+
(1 row)
21+
22+
SELECT build_hash_condition('text', 'val', 10, 1);
23+
build_hash_condition
24+
-------------------------------------------------
25+
public.get_hash_part_idx(hashtext(val), 10) = 1
26+
(1 row)
27+
28+
SELECT build_hash_condition('int4', 'val', 1, 1);
29+
ERROR: 'partition_index' must be lower than 'partitions_count'
30+
SELECT build_hash_condition('int4', 'val', 10, 20);
31+
ERROR: 'partition_index' must be lower than 'partitions_count'
32+
SELECT build_hash_condition('text', 'val', 10, NULL) IS NULL;
33+
?column?
34+
----------
35+
t
36+
(1 row)
37+
38+
SELECT build_hash_condition('calamity.part_test', 'val', 10, 1);
39+
ERROR: no hash function for type calamity.part_test
40+
/* check function build_range_condition() */
41+
SELECT build_range_condition('val', 10, 20);
42+
build_range_condition
43+
----------------------------
44+
val >= '10' AND val < '20'
45+
(1 row)
46+
47+
SELECT build_range_condition('val', 10, NULL) IS NULL;
48+
?column?
49+
----------
50+
t
51+
(1 row)
52+
1553
/* check function validate_relname() */
1654
SELECT validate_relname('calamity.part_test');
1755
validate_relname

expected/pathman_permissions.out

Lines changed: 58 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,20 @@ CREATE ROLE user1 LOGIN;
55
CREATE ROLE user2 LOGIN;
66
GRANT USAGE, CREATE ON SCHEMA permissions TO user1;
77
GRANT USAGE, CREATE ON SCHEMA permissions TO user2;
8-
ALTER DEFAULT PRIVILEGES FOR ROLE user1
9-
IN SCHEMA permissions
10-
GRANT SELECT, INSERT ON TABLES
11-
TO user2;
128
/* Switch to #1 */
139
SET ROLE user1;
1410
CREATE TABLE permissions.user1_table(id serial, a int);
1511
INSERT INTO permissions.user1_table SELECT g, g FROM generate_series(1, 20) as g;
16-
/* Should fail */
12+
/* Should fail (can't SELECT) */
13+
SET ROLE user2;
14+
SELECT create_range_partitions('permissions.user1_table', 'id', 1, 10, 2);
15+
ERROR: permission denied for relation user1_table
16+
/* Grant SELECT to user2 */
17+
SET ROLE user1;
18+
GRANT SELECT ON permissions.user1_table TO user2;
19+
/* Should fail (don't own parent) */
1720
SET ROLE user2;
1821
SELECT create_range_partitions('permissions.user1_table', 'id', 1, 10, 2);
19-
NOTICE: sequence "user1_table_seq" does not exist, skipping
2022
WARNING: only the owner or superuser can change partitioning configuration of table "user1_table"
2123
ERROR: new row violates row-level security policy for table "pathman_config"
2224
/* Should be ok */
@@ -58,21 +60,61 @@ WARNING: only the owner or superuser can change partitioning configuration of t
5860
/* No rights to insert, should fail */
5961
SET ROLE user2;
6062
INSERT INTO permissions.user1_table (id, a) VALUES (35, 0);
61-
/* Have rights, should be ok (bgw connects as user1) */
63+
ERROR: permission denied for relation user1_table
64+
/* No rights to create partitions (need INSERT privilege) */
65+
SET ROLE user2;
66+
SELECT prepend_range_partition('permissions.user1_table');
67+
ERROR: permission denied for parent relation "user1_table"
68+
/* Allow user2 to create partitions */
6269
SET ROLE user1;
6370
GRANT INSERT ON permissions.user1_table TO user2;
71+
GRANT UPDATE(a) ON permissions.user1_table TO user2; /* per-column ACL */
72+
/* Should be able to prepend a partition */
73+
SET ROLE user2;
74+
SELECT prepend_range_partition('permissions.user1_table');
75+
prepend_range_partition
76+
---------------------------
77+
permissions.user1_table_4
78+
(1 row)
79+
80+
SELECT attname, attacl from pg_attribute
81+
WHERE attrelid = (SELECT partition FROM pathman_partition_list
82+
WHERE parent = 'permissions.user1_table'::REGCLASS
83+
ORDER BY range_min::int ASC /* prepend */
84+
LIMIT 1)
85+
ORDER BY attname; /* check ACL for each column */
86+
attname | attacl
87+
----------+-----------------
88+
a | {user2=w/user1}
89+
cmax |
90+
cmin |
91+
ctid |
92+
id |
93+
tableoid |
94+
xmax |
95+
xmin |
96+
(8 rows)
97+
98+
/* Have rights, should be ok (parent's ACL is shared by new children) */
6499
SET ROLE user2;
65100
INSERT INTO permissions.user1_table (id, a) VALUES (35, 0) RETURNING *;
66101
id | a
67102
----+---
68103
35 | 0
69104
(1 row)
70105

71-
SELECT relacl FROM pg_class WHERE oid = 'permissions.user1_table_4'::regclass;
72-
relacl
73-
--------------------------------------
74-
{user1=arwdDxt/user1,user2=ar/user1}
75-
(1 row)
106+
SELECT relname, relacl FROM pg_class
107+
WHERE oid = ANY (SELECT partition FROM pathman_partition_list
108+
WHERE parent = 'permissions.user1_table'::REGCLASS
109+
ORDER BY range_max::int DESC /* append */
110+
LIMIT 3)
111+
ORDER BY relname; /* we also check ACL for "user1_table_2" */
112+
relname | relacl
113+
---------------+--------------------------------------
114+
user1_table_2 | {user1=arwdDxt/user1,user2=r/user1}
115+
user1_table_5 | {user1=arwdDxt/user1,user2=ar/user1}
116+
user1_table_6 | {user1=arwdDxt/user1,user2=ar/user1}
117+
(3 rows)
76118

77119
/* Try to drop partition, should fail */
78120
SELECT drop_range_partition('permissions.user1_table_4');
@@ -95,11 +137,12 @@ SELECT drop_partitions('permissions.user1_table');
95137
NOTICE: function permissions.user1_table_upd_trig_func() does not exist, skipping
96138
NOTICE: 10 rows copied from permissions.user1_table_1
97139
NOTICE: 10 rows copied from permissions.user1_table_2
98-
NOTICE: 0 rows copied from permissions.user1_table_3
99-
NOTICE: 2 rows copied from permissions.user1_table_4
140+
NOTICE: 0 rows copied from permissions.user1_table_4
141+
NOTICE: 0 rows copied from permissions.user1_table_5
142+
NOTICE: 1 rows copied from permissions.user1_table_6
100143
drop_partitions
101144
-----------------
102-
4
145+
5
103146
(1 row)
104147

105148
/* Switch to #2 */

hash.sql

Lines changed: 63 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,6 @@ CREATE OR REPLACE FUNCTION @extschema@.create_hash_partitions(
1818
partition_data BOOLEAN DEFAULT TRUE)
1919
RETURNS INTEGER AS
2020
$$
21-
DECLARE
22-
v_child_relname TEXT;
23-
v_plain_schema TEXT;
24-
v_plain_relname TEXT;
25-
-- v_atttype REGTYPE;
26-
-- v_hashfunc REGPROC;
27-
v_init_callback REGPROCEDURE;
28-
2921
BEGIN
3022
PERFORM @extschema@.validate_relname(parent_relid);
3123

@@ -40,13 +32,6 @@ BEGIN
4032
attribute := lower(attribute);
4133
PERFORM @extschema@.common_relation_checks(parent_relid, attribute);
4234

43-
/* Fetch atttype and its hash function */
44-
-- v_atttype := @extschema@.get_attribute_type(parent_relid, attribute);
45-
-- v_hashfunc := @extschema@.get_type_hash_func(v_atttype);
46-
47-
SELECT * INTO v_plain_schema, v_plain_relname
48-
FROM @extschema@.get_plain_schema_and_relname(parent_relid);
49-
5035
/* Insert new entry to pathman config */
5136
INSERT INTO @extschema@.pathman_config (partrel, attname, parttype)
5237
VALUES (parent_relid, attribute, 1);
@@ -74,29 +59,42 @@ SET client_min_messages = WARNING;
7459

7560
/*
7661
* Replace hash partition with another one. It could be useful in case when
77-
* someone wants to attach foreign table as a partition
62+
* someone wants to attach foreign table as a partition.
63+
*
64+
* lock_parent - should we take an exclusive lock?
7865
*/
7966
CREATE OR REPLACE FUNCTION @extschema@.replace_hash_partition(
8067
old_partition REGCLASS,
81-
new_partition REGCLASS)
68+
new_partition REGCLASS,
69+
lock_parent BOOL DEFAULT TRUE)
8270
RETURNS REGCLASS AS
8371
$$
8472
DECLARE
85-
v_attname TEXT;
73+
parent_relid REGCLASS;
74+
part_attname TEXT; /* partitioned column */
75+
old_constr_name TEXT; /* name of old_partition's constraint */
76+
old_constr_def TEXT; /* definition of old_partition's constraint */
8677
rel_persistence CHAR;
87-
v_init_callback REGPROCEDURE;
88-
v_parent_relid REGCLASS;
89-
v_part_count INT;
90-
v_part_num INT;
78+
p_init_callback REGPROCEDURE;
79+
9180
BEGIN
9281
PERFORM @extschema@.validate_relname(old_partition);
9382
PERFORM @extschema@.validate_relname(new_partition);
9483

9584
/* Parent relation */
96-
v_parent_relid := @extschema@.get_parent_of_partition(old_partition);
85+
parent_relid := @extschema@.get_parent_of_partition(old_partition);
86+
87+
IF lock_parent THEN
88+
/* Acquire data modification lock (prevent further modifications) */
89+
PERFORM @extschema@.prevent_relation_modification(parent_relid);
90+
ELSE
91+
/* Acquire lock on parent */
92+
PERFORM @extschema@.lock_partitioned_relation(parent_relid);
93+
END IF;
9794

98-
/* Acquire lock on parent */
99-
PERFORM @extschema@.lock_partitioned_relation(v_parent_relid);
95+
/* Acquire data modification lock (prevent further modifications) */
96+
PERFORM @extschema@.prevent_relation_modification(old_partition);
97+
PERFORM @extschema@.prevent_relation_modification(new_partition);
10098

10199
/* Ignore temporary tables */
102100
SELECT relpersistence FROM pg_catalog.pg_class
@@ -108,52 +106,54 @@ BEGIN
108106
END IF;
109107

110108
/* Check that new partition has an equal structure as parent does */
111-
IF NOT @extschema@.validate_relations_equality(v_parent_relid, new_partition) THEN
109+
IF NOT @extschema@.validate_relations_equality(parent_relid, new_partition) THEN
112110
RAISE EXCEPTION 'partition must have the exact same structure as parent';
113111
END IF;
114112

115113
/* Get partitioning key */
116-
v_attname := attname FROM @extschema@.pathman_config WHERE partrel = v_parent_relid;
117-
IF v_attname IS NULL THEN
118-
RAISE EXCEPTION 'table "%" is not partitioned', v_parent_relid::TEXT;
114+
part_attname := attname FROM @extschema@.pathman_config WHERE partrel = parent_relid;
115+
IF part_attname IS NULL THEN
116+
RAISE EXCEPTION 'table "%" is not partitioned', parent_relid::TEXT;
119117
END IF;
120118

121-
/* Calculate partitions count and old partition's number */
122-
v_part_count := count(*) FROM @extschema@.pathman_partition_list WHERE parent = v_parent_relid;
123-
v_part_num := @extschema@.get_partition_hash(v_parent_relid, old_partition);
119+
/* Fetch name of old_partition's HASH constraint */
120+
old_constr_name = @extschema@.build_check_constraint_name(old_partition::REGCLASS,
121+
part_attname);
122+
123+
/* Fetch definition of old_partition's HASH constraint */
124+
SELECT pg_catalog.pg_get_constraintdef(oid) FROM pg_catalog.pg_constraint
125+
WHERE conrelid = old_partition AND conname = old_constr_name
126+
INTO old_constr_def;
124127

125128
/* Detach old partition */
126-
EXECUTE format('ALTER TABLE %s NO INHERIT %s', old_partition, v_parent_relid);
127-
EXECUTE format('ALTER TABLE %s DROP CONSTRAINT IF EXISTS %s',
128-
old_partition,
129-
@extschema@.build_check_constraint_name(old_partition::REGCLASS,
130-
v_attname));
131-
132-
/* Attach new one */
133-
EXECUTE format('ALTER TABLE %s INHERIT %s', new_partition, v_parent_relid);
134-
EXECUTE format('ALTER TABLE %s ADD CONSTRAINT %s CHECK (%s)',
129+
EXECUTE format('ALTER TABLE %s NO INHERIT %s', old_partition, parent_relid);
130+
EXECUTE format('ALTER TABLE %s DROP CONSTRAINT %s',
131+
old_partition,
132+
old_constr_name);
133+
134+
/* Attach the new one */
135+
EXECUTE format('ALTER TABLE %s INHERIT %s', new_partition, parent_relid);
136+
EXECUTE format('ALTER TABLE %s ADD CONSTRAINT %s %s',
135137
new_partition,
136-
@extschema@.build_check_constraint_name(new_partition::regclass,
137-
v_attname),
138-
@extschema@.build_hash_condition(new_partition::regclass,
139-
v_attname,
140-
v_part_count,
141-
v_part_num));
138+
@extschema@.build_check_constraint_name(new_partition::REGCLASS,
139+
part_attname),
140+
old_constr_def);
142141

143142
/* Fetch init_callback from 'params' table */
144143
WITH stub_callback(stub) as (values (0))
145144
SELECT coalesce(init_callback, 0::REGPROCEDURE)
146145
FROM stub_callback
147146
LEFT JOIN @extschema@.pathman_config_params AS params
148-
ON params.partrel = v_parent_relid
149-
INTO v_init_callback;
147+
ON params.partrel = parent_relid
148+
INTO p_init_callback;
150149

151-
PERFORM @extschema@.invoke_on_partition_created_callback(v_parent_relid,
150+
/* Finally invoke init_callback */
151+
PERFORM @extschema@.invoke_on_partition_created_callback(parent_relid,
152152
new_partition,
153-
v_init_callback);
153+
p_init_callback);
154154

155155
/* Invalidate cache */
156-
PERFORM @extschema@.on_update_partitions(v_parent_relid);
156+
PERFORM @extschema@.on_update_partitions(parent_relid);
157157

158158
RETURN new_partition;
159159
END
@@ -292,3 +292,14 @@ LANGUAGE C STRICT;
292292
CREATE OR REPLACE FUNCTION @extschema@.get_hash_part_idx(INTEGER, INTEGER)
293293
RETURNS INTEGER AS 'pg_pathman', 'get_hash_part_idx'
294294
LANGUAGE C STRICT;
295+
296+
/*
297+
* Build hash condition for a CHECK CONSTRAINT
298+
*/
299+
CREATE OR REPLACE FUNCTION @extschema@.build_hash_condition(
300+
attribute_type REGTYPE,
301+
attribute TEXT,
302+
partitions_count INT4,
303+
partitions_index INT4)
304+
RETURNS TEXT AS 'pg_pathman', 'build_hash_condition'
305+
LANGUAGE C STRICT;

init.sql

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -783,23 +783,3 @@ CREATE OR REPLACE FUNCTION @extschema@.invoke_on_partition_created_callback(
783783
init_callback REGPROCEDURE)
784784
RETURNS VOID AS 'pg_pathman', 'invoke_on_partition_created_callback'
785785
LANGUAGE C;
786-
787-
/*
788-
* Build hash condition for a CHECK CONSTRAINT
789-
*/
790-
CREATE OR REPLACE FUNCTION @extschema@.build_hash_condition(
791-
parent_relid REGCLASS,
792-
attname TEXT,
793-
partitions_count INT,
794-
partition_number INT)
795-
RETURNS TEXT AS 'pg_pathman', 'build_hash_condition'
796-
LANGUAGE C;
797-
798-
/*
799-
* Returns hash value for specified partition (0..N)
800-
*/
801-
CREATE OR REPLACE FUNCTION @extschema@.get_partition_hash(
802-
parent_relid REGCLASS,
803-
partition REGCLASS)
804-
RETURNS INT AS 'pg_pathman', 'get_partition_hash'
805-
LANGUAGE C;

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy