1- /* TODO: function that subdivide specified period with specivied interval*/
2-
31/*
42 * Creates RANGE partitions for specified relation based on datetime attribute
53*/
@@ -8,13 +6,14 @@ CREATE OR REPLACE FUNCTION @extschema@.create_range_partitions(
86 , p_attributeTEXT
97 , p_start_value ANYELEMENT
108 , p_interval INTERVAL
11- , p_countINTEGER )
9+ , p_countINTEGER DEFAULT NULL )
1210RETURNSINTEGER AS
1311$$
1412DECLARE
15- v_valueTEXT ;
13+ v_rows_countINTEGER ;
14+ v_max p_start_value%TYPE;
15+ v_cur_value p_start_value%TYPE := p_start_value;
1616 iINTEGER ;
17- sqlTEXT ;
1817BEGIN
1918 p_relation := @extschema@.validate_relname(p_relation);
2019
@@ -26,25 +25,40 @@ BEGIN
2625 RAISE EXCEPTION' Relation "%" has already been partitioned' , p_relation;
2726 END IF;
2827
29- EXECUTE format(' DROP SEQUENCE IF EXISTS %s_seq' , p_relation);
30- EXECUTE format(' CREATE SEQUENCE %s_seq START 1' , p_relation);
28+ /* Try to determine partitions count if not set*/
29+ IF p_count ISNULL THEN
30+ EXECUTE format(' SELECT count(*), max(%s) FROM %s'
31+ , p_attribute, p_relation)
32+ INTO v_rows_count, v_max;
3133
32- /* check boundaries*/
33- sql := format(' SELECT @extschema@.check_boundaries(' ' %s' ' ,' ' %s' ' ,' ' %s' ' ,' ' %s' ' ::%s)'
34- , p_relation
35- , p_attribute
36- , p_start_value
37- , p_start_value+ p_interval* p_count
38- , pg_typeof(p_start_value));
39- RAISE NOTICE' sql: %' , sql;
34+ IF v_rows_count= 0 THEN
35+ RAISE EXCEPTION' Cannot determine partitions count for empty table' ;
36+ END IF;
37+
38+ IF v_max ISNULL THEN
39+ RAISE EXCEPTION' ' ' %' ' column has NULL values' , p_attribute;
40+ END IF;
4041
42+ p_count := 0 ;
43+ WHILE v_cur_value<= v_max
44+ LOOP
45+ v_cur_value := v_cur_value+ p_interval;
46+ p_count := p_count+ 1 ;
47+ END LOOP;
48+ END IF;
49+
50+ /* check boundaries*/
4151 EXECUTE format(' SELECT @extschema@.check_boundaries(' ' %s' ' ,' ' %s' ' ,' ' %s' ' ,' ' %s' ' ::%s)'
4252 , p_relation
4353 , p_attribute
4454 , p_start_value
4555 , p_start_value+ p_interval* p_count
4656 , pg_typeof(p_start_value));
4757
58+
59+ EXECUTE format(' DROP SEQUENCE IF EXISTS %s_seq' , p_relation);
60+ EXECUTE format(' CREATE SEQUENCE %s_seq START 1' , p_relation);
61+
4862INSERT INTO @extschema@.pathman_config (relname, attname, parttype)
4963VALUES (p_relation, p_attribute,2 );
5064
6781 PERFORM @extschema@.partition_data(p_relation);
6882
6983 RETURN p_count;
84+
85+ EXCEPTION WHEN others THEN
86+ PERFORM @extschema@.on_remove_partitions(p_relation::regclass::integer );
87+ RAISE EXCEPTION' % %' , SQLERRM, SQLSTATE;
7088END
7189$$ LANGUAGE plpgsql;
7290
@@ -78,11 +96,13 @@ CREATE OR REPLACE FUNCTION @extschema@.create_range_partitions(
7896 , p_attributeTEXT
7997 , p_start_value ANYELEMENT
8098 , p_interval ANYELEMENT
81- , p_countINTEGER )
99+ , p_countINTEGER DEFAULT NULL )
82100RETURNSINTEGER AS
83101$$
84102DECLARE
85- v_valueTEXT ;
103+ v_rows_countINTEGER ;
104+ v_max p_start_value%TYPE;
105+ v_cur_value p_start_value%TYPE := p_start_value;
86106 iINTEGER ;
87107BEGIN
88108 p_relation := @extschema@.validate_relname(p_relation);
@@ -95,15 +115,37 @@ BEGIN
95115 RAISE EXCEPTION' Relation "%" has already been partitioned' , p_relation;
96116 END IF;
97117
98- EXECUTE format(' DROP SEQUENCE IF EXISTS %s_seq' , p_relation);
99- EXECUTE format(' CREATE SEQUENCE %s_seq START 1' , p_relation);
118+ /* Try to determine partitions count if not set*/
119+ IF p_count ISNULL THEN
120+ EXECUTE format(' SELECT count(*), max(%s) FROM %s'
121+ , p_attribute, p_relation)
122+ INTO v_rows_count, v_max;
123+
124+ IF v_rows_count= 0 THEN
125+ RAISE EXCEPTION' Cannot determine partitions count for empty table' ;
126+ END IF;
127+
128+ IF v_max ISNULL THEN
129+ RAISE EXCEPTION' ' ' %' ' column has NULL values' , p_attribute;
130+ END IF;
131+
132+ p_count := 0 ;
133+ WHILE v_cur_value<= v_max
134+ LOOP
135+ v_cur_value := v_cur_value+ p_interval;
136+ p_count := p_count+ 1 ;
137+ END LOOP;
138+ END IF;
100139
101140/* check boundaries*/
102141 PERFORM @extschema@.check_boundaries(p_relation
103142 , p_attribute
104143 , p_start_value
105144 , p_start_value+ p_interval* p_count);
106145
146+ EXECUTE format(' DROP SEQUENCE IF EXISTS %s_seq' , p_relation);
147+ EXECUTE format(' CREATE SEQUENCE %s_seq START 1' , p_relation);
148+
107149INSERT INTO @extschema@.pathman_config (relname, attname, parttype)
108150VALUES (p_relation, p_attribute,2 );
109151
@@ -128,8 +170,7 @@ BEGIN
128170 RETURN p_count;
129171
130172EXCEPTION WHEN others THEN
131- EXECUTE format(' DROP TABLE %s CASCADE' , p_relation);
132- PERFORM on_remove_partitions(p_relation::regclass::integer );
173+ PERFORM @extschema@.on_remove_partitions(p_relation::regclass::integer );
133174 RAISE EXCEPTION' % %' , SQLERRM, SQLSTATE;
134175END
135176$$ LANGUAGE plpgsql;
@@ -146,7 +187,6 @@ CREATE OR REPLACE FUNCTION @extschema@.create_partitions_from_range(
146187RETURNSINTEGER AS
147188$$
148189DECLARE
149- v_valueTEXT ;
150190 v_intervalDOUBLE PRECISION ;
151191 v_dt_interval INTERVAL;
152192 v_type REGTYPE;
@@ -191,9 +231,13 @@ BEGIN
191231 PERFORM @extschema@.on_create_partitions(p_relation::regclass::oid );
192232
193233/* Copy data*/
194- -- PERFORM @extschema@.partition_data(p_relation);
234+ PERFORM @extschema@.partition_data(p_relation);
195235
196236 RETURN i;
237+
238+ EXCEPTION WHEN others THEN
239+ PERFORM @extschema@.on_remove_partitions(p_relation::regclass::integer );
240+ RAISE EXCEPTION' % %' , SQLERRM, SQLSTATE;
197241END
198242$$ LANGUAGE plpgsql;
199243
@@ -209,7 +253,6 @@ CREATE OR REPLACE FUNCTION @extschema@.create_partitions_from_range(
209253RETURNSINTEGER AS
210254$$
211255DECLARE
212- v_valueTEXT ;
213256 v_intervalDOUBLE PRECISION ;
214257 v_dt_interval INTERVAL;
215258 v_type REGTYPE;
@@ -249,9 +292,13 @@ BEGIN
249292 PERFORM @extschema@.on_create_partitions(p_relation::regclass::oid );
250293
251294/* Copy data*/
252- -- PERFORM @extschema@.partition_data(p_relation);
295+ PERFORM @extschema@.partition_data(p_relation);
253296
254297 RETURN i;
298+
299+ EXCEPTION WHEN others THEN
300+ PERFORM @extschema@.on_remove_partitions(p_relation::regclass::integer );
301+ RAISE EXCEPTION' % %' , SQLERRM, SQLSTATE;
255302END
256303$$ LANGUAGE plpgsql;
257304
@@ -270,28 +317,25 @@ DECLARE
270317 v_max p_start_value%TYPE;
271318 v_countINTEGER ;
272319BEGIN
273- RAISE NOTICE' check_boundaries(%)' , p_relname;
274320/* Get min and max values*/
275321 EXECUTE format(' SELECT count(*), min(%s), max(%s) FROM %s WHERE NOT %s IS NULL' ,
276322 p_attribute, p_attribute, p_relname, p_attribute)
277323 INTO v_count, v_min, v_max;
278324
279- RAISE NOTICE' >>> MIN, MAX <<< %, %, %' , v_count, v_min, v_max;
280-
281325/* check if column has NULL values*/
282326 IF v_count> 0 AND (v_min ISNULL OR v_max ISNULL ) THEN
283327 RAISE EXCEPTION' ' ' %' ' column has NULL values' , p_attribute;
284328 END IF;
285329
286330/* check lower boundary*/
287- IF p_start_value< v_min THEN
331+ IF p_start_value> v_min THEN
288332 RAISE EXCEPTION' Start value is less than minimum value of' ' %' ' '
289333 , p_attribute;
290334 END IF;
291335
292336/* check upper boundary*/
293- IF p_end_value> = v_max THEN
294- RAISE EXCEPTION' End value is greater than maximum value of' ' %' ' '
337+ IF p_end_value< = v_max THEN
338+ RAISE EXCEPTION' Not enough partitions to fit all the values of' ' %' ' '
295339 , p_attribute;
296340 END IF;
297341END