1+ /* **********************************************************************
2+ * Modify config params table
3+ **********************************************************************/
4+ ALTER TABLE @
[email protected] _config_params ADD COLUMN init_callback REGPROCEDURE
NOT NULL DEFAULT
0 ;
5+ ALTER TABLE @
[email protected] _config_params ALTER COLUMN enable_parent
SET DEFAULT FALSE;
6+
7+ /* Enable permissions */
8+ GRANT SELECT , INSERT, UPDATE , DELETE
9+ 10+ TO public;
11+
12+ CREATE
OR REPLACE FUNCTION @
[email protected] _security_policy(relation regclass)
13+ RETURNS BOOL AS ' pg_pathman' , ' check_security_policy' LANGUAGE C STRICT;
14+
15+ CREATE POLICY deny_modification
ON @
[email protected] _config
16+ FOR ALL USING (check_security_policy(partrel));
17+
18+ CREATE POLICY deny_modification
ON @
[email protected] _config_params
19+ FOR ALL USING (check_security_policy(partrel));
20+
21+ CREATE POLICY allow_select
ON @
[email protected] _config FOR
SELECT USING (true);
22+
23+ CREATE POLICY allow_select
ON @
[email protected] _config_params FOR
SELECT USING (true);
24+
25+ ALTER TABLE @
[email protected] _config ENABLE ROW LEVEL SECURITY;
26+ ALTER TABLE @
[email protected] _config_params ENABLE ROW LEVEL SECURITY;
27+
28+ GRANT SELECT ON @
[email protected] _concurrent_part_tasks TO PUBLIC;
29+
30+ /* Drop irrelevant functions */
31+ DROP FUNCTION @
[email protected] _relcache(
OID );
32+ DROP FUNCTION @
[email protected] _set_param(REGCLASS,
TEXT ,
BOOLEAN );
33+ DROP FUNCTION @
[email protected] _parent(REGCLASS);
34+ DROP FUNCTION @
[email protected] _parent(relation REGCLASS);
35+ DROP FUNCTION @
[email protected] _auto(relation REGCLASS);
36+ DROP FUNCTION @
[email protected] _auto(relation REGCLASS);
37+ DROP FUNCTION @
[email protected] _table_concurrently(relation regclass);
38+ DROP FUNCTION @extschema@._partition_data_concurrent(REGCLASS, ANYELEMENT, ANYELEMENT, INT , OUT BIGINT );
39+ DROP FUNCTION @
[email protected] _relation_checks(REGCLASS,
TEXT );
40+
41+ /* Alter functions' modifiers */
42+ ALTER FUNCTION @
[email protected] _count(REGCLASS) STRICT;
43+ ALTER FUNCTION @
[email protected] _data(REGCLASS, OUT
BIGINT ) STRICT;
44+ ALTER FUNCTION @
[email protected] _pathman_for(REGCLASS) STRICT;
45+ ALTER FUNCTION @
[email protected] _plain_schema_and_relname(REGCLASS, OUT
TEXT , OUT
TEXT ) STRICT;
46+
47+ /* Create functions */
48+ CREATE
OR REPLACE FUNCTION @
[email protected] _set_param(
49+ relation REGCLASS,
50+ param TEXT ,
51+ value ANYELEMENT)
52+ RETURNS VOID AS
53+ $$
54+ BEGIN
55+ EXECUTE format(
' INSERT INTO @[email protected] _config_params56+ (partrel, %1$s) VALUES ($1, $2)
57+ ON CONFLICT (partrel) DO UPDATE SET %1$s = $2' , param)
58+ USING relation, value;
59+ END
60+ $$
61+ LANGUAGE plpgsql;
62+
63+ CREATE
OR REPLACE FUNCTION @
[email protected] _enable_parent(
64+ relation REGCLASS,
65+ value BOOLEAN )
66+ RETURNS VOID AS
67+ $$
68+ BEGIN
69+ PERFORM @
[email protected] _set_param(relation,
' enable_parent' , value);
70+ END
71+ $$
72+ LANGUAGE plpgsql STRICT;
73+
74+ /*
75+ * Partition table using ConcurrentPartWorker.
76+ */
77+ CREATE
OR REPLACE FUNCTION @
[email protected] _table_concurrently(
78+ relation REGCLASS,
79+ batch_size INTEGER DEFAULT 1000 ,
80+ sleep_time FLOAT8 DEFAULT 1 .0 )
81+ RETURNS VOID AS ' pg_pathman' , ' partition_table_concurrently'
82+ LANGUAGE C STRICT;
83+
84+ /*
85+ * Copy rows to partitions concurrently.
86+ */
87+ CREATE OR REPLACE FUNCTION @extschema@._partition_data_concurrent(
88+ relation REGCLASS,
89+ p_min ANYELEMENT DEFAULT NULL ::text ,
90+ p_max ANYELEMENT DEFAULT NULL ::text ,
91+ p_limit INT DEFAULT NULL ,
92+ OUT p_total BIGINT )
93+ AS
94+ $$
95+ DECLARE
96+ v_attr TEXT ;
97+ v_limit_clause TEXT := ' ' ;
98+ v_where_clause TEXT := ' ' ;
99+ ctids TID[];
100+
101+ BEGIN
102+ SELECT attname INTO v_attr
103+ FROM @
[email protected] _config
WHERE partrel
= relation;
104+
105+ p_total := 0 ;
106+
107+ /* Format LIMIT clause if needed */
108+ IF NOT p_limit IS NULL THEN
109+ v_limit_clause := format(' LIMIT %s' , p_limit);
110+ END IF;
111+
112+ /* Format WHERE clause if needed */
113+ IF NOT p_min IS NULL THEN
114+ v_where_clause := format(' %1$s >= $1' , v_attr);
115+ END IF;
116+
117+ IF NOT p_max IS NULL THEN
118+ IF NOT p_min IS NULL THEN
119+ v_where_clause := v_where_clause || ' AND ' ;
120+ END IF;
121+ v_where_clause := v_where_clause || format(' %1$s < $2' , v_attr);
122+ END IF;
123+
124+ IF v_where_clause != ' ' THEN
125+ v_where_clause := ' WHERE ' || v_where_clause;
126+ END IF;
127+
128+ /* Lock rows and copy data */
129+ RAISE NOTICE ' Copying data to partitions...' ;
130+ EXECUTE format(' SELECT array(SELECT ctid FROM ONLY %1$s %2$s %3$s FOR UPDATE NOWAIT)' ,
131+ relation, v_where_clause, v_limit_clause)
132+ USING p_min, p_max
133+ INTO ctids;
134+
135+ EXECUTE format('
136+ WITH data AS (
137+ DELETE FROM ONLY %1$s WHERE ctid = ANY($1) RETURNING *)
138+ INSERT INTO %1$s SELECT * FROM data' ,
139+ relation)
140+ USING ctids;
141+
142+ /* Get number of inserted rows */
143+ GET DIAGNOSTICS p_total = ROW_COUNT;
144+ RETURN;
145+ END
146+ $$
147+ LANGUAGE plpgsql
148+ SET pg_pathman .enable_partitionfilter = on ; /* ensures that PartitionFilter is ON */
149+
150+ /*
151+ * Aggregates several common relation checks before partitioning.
152+ * Suitable for every partitioning type.
153+ */
154+ CREATE
OR REPLACE FUNCTION @
[email protected] _relation_checks(
155+ relation REGCLASS,
156+ p_attribute TEXT )
157+ RETURNS BOOLEAN AS
158+ $$
159+ DECLARE
160+ v_rec RECORD;
161+ is_referenced BOOLEAN ;
162+ rel_persistence CHAR ;
163+
164+ BEGIN
165+ /* Ignore temporary tables */
166+ SELECT relpersistence FROM pg_catalog .pg_class
167+ WHERE oid = relation INTO rel_persistence;
168+
169+ IF rel_persistence = ' t' ::CHAR THEN
170+ RAISE EXCEPTION ' temporary table "%" cannot be partitioned' ,
171+ relation::TEXT ;
172+ END IF;
173+
174+ IF EXISTS (
SELECT * FROM @
[email protected] _config
175+ WHERE partrel = relation) THEN
176+ RAISE EXCEPTION ' relation "%" has already been partitioned' , relation;
177+ END IF;
178+
179+ IF @
[email protected] _attribute_nullable(relation, p_attribute) THEN
180+ RAISE EXCEPTION ' partitioning key ' ' %' ' must be NOT NULL' , p_attribute;
181+ END IF;
182+
183+ /* Check if there are foreign keys that reference the relation */
184+ FOR v_rec IN (SELECT * FROM pg_catalog .pg_constraint
185+ WHERE confrelid = relation::REGCLASS::OID )
186+ LOOP
187+ is_referenced := TRUE;
188+ RAISE WARNING ' foreign key "%" references relation "%"' ,
189+ v_rec .conname , relation;
190+ END LOOP;
191+
192+ IF is_referenced THEN
193+ RAISE EXCEPTION ' relation "%" is referenced from other relations' , relation;
194+ END IF;
195+
196+ RETURN TRUE;
197+ END
198+ $$
199+ LANGUAGE plpgsql;
0 commit comments