34
34
$$
35
35
LANGUAGE plpgsql;
36
36
37
+ /*
38
+ * Check RANGE partition boundaries.
39
+ */
40
+ CREATE
OR REPLACE FUNCTION @
[email protected] _boundaries(
41
+ parent_relid REGCLASS,
42
+ p_attribute TEXT ,
43
+ p_start_value ANYELEMENT,
44
+ p_end_value ANYELEMENT)
45
+ RETURNS VOID AS
46
+ $$
47
+ DECLARE
48
+ v_min p_start_value%TYPE;
49
+ v_max p_start_value%TYPE;
50
+ v_count BIGINT ;
51
+
52
+ BEGIN
53
+ /* Get min and max values */
54
+ EXECUTE format(' SELECT count(*), min(%1$s), max(%1$s)
55
+ FROM %2$s WHERE NOT %1$s IS NULL' ,
56
+ p_attribute, parent_relid::TEXT )
57
+ INTO v_count, v_min, v_max;
58
+
59
+ /* Check if column has NULL values */
60
+ IF v_count > 0 AND (v_min IS NULL OR v_max IS NULL ) THEN
61
+ RAISE EXCEPTION ' ' ' %' ' column contains NULL values' , p_attribute;
62
+ END IF;
63
+
64
+ /* Check lower boundary */
65
+ IF p_start_value > v_min THEN
66
+ RAISE EXCEPTION ' Start value is less than minimum value of ' ' %' ' ' ,
67
+ p_attribute;
68
+ END IF;
69
+
70
+ /* Check upper boundary */
71
+ IF p_end_value <= v_max THEN
72
+ RAISE EXCEPTION ' Not enough partitions to fit all values of ' ' %' ' ' ,
73
+ p_attribute;
74
+ END IF;
75
+ END
76
+ $$ LANGUAGE plpgsql;
77
+
37
78
/*
38
79
* Creates RANGE partitions for specified relation based on datetime attribute
39
80
*/
@@ -53,6 +94,9 @@ DECLARE
53
94
i INTEGER ;
54
95
55
96
BEGIN
97
+ /* Acquire exclusive lock on parent */
98
+ PERFORM @
[email protected] _partitioned_relation(parent_relid);
99
+
56
100
PERFORM @
[email protected] _relname(parent_relid);
57
101
p_attribute := lower (p_attribute);
58
102
PERFORM @
[email protected] _relation_checks(parent_relid, p_attribute);
@@ -147,6 +191,9 @@ DECLARE
147
191
i INTEGER ;
148
192
149
193
BEGIN
194
+ /* Acquire exclusive lock on parent */
195
+ PERFORM @
[email protected] _partitioned_relation(parent_relid);
196
+
150
197
PERFORM @
[email protected] _relname(parent_relid);
151
198
p_attribute := lower (p_attribute);
152
199
PERFORM @
[email protected] _relation_checks(parent_relid, p_attribute);
@@ -239,6 +286,9 @@ DECLARE
239
286
part_count INTEGER := 0 ;
240
287
241
288
BEGIN
289
+ /* Acquire exclusive lock on parent */
290
+ PERFORM @
[email protected] _partitioned_relation(parent_relid);
291
+
242
292
PERFORM @
[email protected] _relname(parent_relid);
243
293
p_attribute := lower (p_attribute);
244
294
PERFORM @
[email protected] _relation_checks(parent_relid, p_attribute);
@@ -304,6 +354,9 @@ DECLARE
304
354
part_count INTEGER := 0 ;
305
355
306
356
BEGIN
357
+ /* Acquire exclusive lock on parent */
358
+ PERFORM @
[email protected] _partitioned_relation(parent_relid);
359
+
307
360
PERFORM @
[email protected] _relname(parent_relid);
308
361
p_attribute := lower (p_attribute);
309
362
PERFORM @
[email protected] _relation_checks(parent_relid, p_attribute);
351
404
$$ LANGUAGE plpgsql;
352
405
353
406
/*
354
- * Check RANGE partition boundaries.
355
- */
356
- CREATE
OR REPLACE FUNCTION @
[email protected] _boundaries(
357
- parent_relid REGCLASS,
358
- p_attribute TEXT ,
359
- p_start_value ANYELEMENT,
360
- p_end_value ANYELEMENT)
361
- RETURNS VOID AS
362
- $$
363
- DECLARE
364
- v_min p_start_value%TYPE;
365
- v_max p_start_value%TYPE;
366
- v_count BIGINT ;
367
-
368
- BEGIN
369
- /* Get min and max values */
370
- EXECUTE format(' SELECT count(*), min(%1$s), max(%1$s)
371
- FROM %2$s WHERE NOT %1$s IS NULL' ,
372
- p_attribute, parent_relid::TEXT )
373
- INTO v_count, v_min, v_max;
374
-
375
- /* Check if column has NULL values */
376
- IF v_count > 0 AND (v_min IS NULL OR v_max IS NULL ) THEN
377
- RAISE EXCEPTION ' ' ' %' ' column contains NULL values' , p_attribute;
378
- END IF;
379
-
380
- /* Check lower boundary */
381
- IF p_start_value > v_min THEN
382
- RAISE EXCEPTION ' Start value is less than minimum value of ' ' %' ' ' ,
383
- p_attribute;
384
- END IF;
385
-
386
- /* Check upper boundary */
387
- IF p_end_value <= v_max THEN
388
- RAISE EXCEPTION ' Not enough partitions to fit all values of ' ' %' ' ' ,
389
- p_attribute;
390
- END IF;
391
- END
392
- $$ LANGUAGE plpgsql;
393
-
394
- /*
395
- * Creates new RANGE partition. Returns partition name
407
+ * Creates new RANGE partition. Returns partition name.
408
+ * NOTE: This function SHOULD NOT take xact_handling lock (BGWs in 9.5).
396
409
*/
397
410
CREATE
OR REPLACE FUNCTION @
[email protected] _single_range_partition(
398
411
parent_relid REGCLASS,
@@ -485,6 +498,9 @@ BEGIN
485
498
v_part_relname :
= @
[email protected] _relname(p_partition);
486
499
v_parent_relid
= @
[email protected] _parent_of_partition(p_partition);
487
500
501
+ /* Acquire exclusive lock on parent */
502
+ PERFORM @
[email protected] _partitioned_relation(v_parent_relid);
503
+
488
504
SELECT attname, parttype
489
505
490
506
WHERE partrel = v_parent_relid
@@ -573,6 +589,9 @@ BEGIN
573
589
RAISE EXCEPTION ' Cannot merge partitions with different parents' ;
574
590
END IF;
575
591
592
+ /* Acquire exclusive lock on parent */
593
+ PERFORM @
[email protected] _partitioned_relation(v_parent_relid1);
594
+
576
595
SELECT attname, parttype
577
596
578
597
WHERE partrel = v_parent_relid1
@@ -604,8 +623,8 @@ LANGUAGE plpgsql;
604
623
* Merge two partitions. All data will be copied to the first one. Second
605
624
* partition will be destroyed.
606
625
*
607
- * Notes : dummy field is used to pass the element type to the function
608
- * (it is necessary because of pseudo-types used in function)
626
+ * NOTE : dummy field is used to pass the element type to the function
627
+ * (it is necessary because of pseudo-types used in function).
609
628
*/
610
629
CREATE
OR REPLACE FUNCTION @
[email protected] _range_partitions_internal(
611
630
parent_relid REGCLASS,
@@ -668,7 +687,7 @@ $$ LANGUAGE plpgsql;
668
687
669
688
670
689
/*
671
- * Append new partition
690
+ * Append new partition.
672
691
*/
673
692
CREATE
OR REPLACE FUNCTION @
[email protected] _range_partition(
674
693
parent_relid REGCLASS,
@@ -682,6 +701,9 @@ DECLARE
682
701
v_interval TEXT ;
683
702
684
703
BEGIN
704
+ /* Acquire exclusive lock on parent */
705
+ PERFORM @
[email protected] _partitioned_relation(parent_relid);
706
+
685
707
SELECT attname, range_interval
686
708
687
709
WHERE partrel = parent_relid
715
737
$$
716
738
LANGUAGE plpgsql;
717
739
718
-
740
+ /*
741
+ * Spawn logic for append_partition(). We have to
742
+ * separate this in order to pass the 'p_range'.
743
+ *
744
+ * NOTE: we don't take a xact_handling lock here.
745
+ */
719
746
CREATE
OR REPLACE FUNCTION @
[email protected] _partition_internal(
720
747
parent_relid REGCLASS,
721
748
p_atttype TEXT ,
@@ -761,7 +788,7 @@ LANGUAGE plpgsql;
761
788
762
789
763
790
/*
764
- * Prepend new partition
791
+ * Prepend new partition.
765
792
*/
766
793
CREATE
OR REPLACE FUNCTION @
[email protected] _range_partition(
767
794
parent_relid REGCLASS,
808
835
$$
809
836
LANGUAGE plpgsql;
810
837
811
-
838
+ /*
839
+ * Spawn logic for prepend_partition(). We have to
840
+ * separate this in order to pass the 'p_range'.
841
+ *
842
+ * NOTE: we don't take a xact_handling lock here.
843
+ */
812
844
CREATE
OR REPLACE FUNCTION @
[email protected] _partition_internal(
813
845
parent_relid REGCLASS,
814
846
p_atttype TEXT ,
@@ -867,6 +899,9 @@ DECLARE
867
899
v_part_name TEXT ;
868
900
869
901
BEGIN
902
+ /* Acquire exclusive lock on parent */
903
+ PERFORM @
[email protected] _partitioned_relation(parent_relid);
904
+
870
905
IF p_start_value >= p_end_value THEN
871
906
RAISE EXCEPTION ' Failed to create partition: p_start_value is greater than p_end_value' ;
872
907
END IF;
@@ -908,6 +943,9 @@ BEGIN
908
943
parent_relid :
= @
[email protected] _parent_of_partition(p_partition);
909
944
part_name := p_partition::TEXT ; /* save the name to be returned */
910
945
946
+ /* Acquire exclusive lock on parent */
947
+ PERFORM @
[email protected] _partitioned_relation(parent_relid);
948
+
911
949
/* Drop table */
912
950
EXECUTE format(' DROP TABLE %s' , part_name);
913
951
@@ -938,6 +976,9 @@ DECLARE
938
976
rel_persistence CHAR ;
939
977
940
978
BEGIN
979
+ /* Acquire exclusive lock on parent */
980
+ PERFORM @
[email protected] _partitioned_relation(parent_relid);
981
+
941
982
/* Ignore temporary tables */
942
983
SELECT relpersistence FROM pg_catalog .pg_class
943
984
WHERE oid = p_partition INTO rel_persistence;
@@ -998,6 +1039,9 @@ DECLARE
998
1039
BEGIN
999
1040
parent_relid
= @
[email protected] _parent_of_partition(p_partition);
1000
1041
1042
+ /* Acquire exclusive lock on parent */
1043
+ PERFORM @
[email protected] _partitioned_relation(parent_relid);
1044
+
1001
1045
v_attname := attname
1002
1046
1003
1047
WHERE partrel = parent_relid;
0 commit comments