2222#include "utils/array.h"
2323
2424
25+ static char * * deconstruct_text_array (Datum arr ,int * num_elems );
26+
27+
2528/* Function declarations */
2629
2730PG_FUNCTION_INFO_V1 (create_hash_partitions_internal );
@@ -32,112 +35,85 @@ PG_FUNCTION_INFO_V1( get_hash_part_idx );
3235PG_FUNCTION_INFO_V1 (build_hash_condition );
3336
3437
35- static char * * deconstruct_text_array (Datum arr ,int * num_elems );
36-
37-
3838/*
3939 * Create HASH partitions implementation (written in C).
4040 */
4141Datum
4242create_hash_partitions_internal (PG_FUNCTION_ARGS )
4343{
44- Oid parent_relid = PG_GETARG_OID (0 );
45- Datum partitioned_col_name = PG_GETARG_DATUM (1 );
46- Oid partitioned_col_type ;
47- uint32 part_count = PG_GETARG_INT32 (2 ),
48- i ;
49-
50- /* Partitions names and tablespaces */
51- char * * names = NULL ,
52- * * tablespaces = NULL ;
53- int names_size = 0 ,
54- tablespaces_size = 0 ;
55- RangeVar * * rangevars = NULL ;
44+ /* Free allocated arrays */
45+ #define DeepFreeArray (arr ,arr_len ) \
46+ do { \
47+ int arr_elem; \
48+ if (!arr) break; \
49+ for (arr_elem = 0; arr_elem < arr_len; arr_elem++) \
50+ pfree(arr[arr_elem]); \
51+ pfree(arr); \
52+ } while (0)
53+
54+ Oid parent_relid = PG_GETARG_OID (0 );
55+ const char * partitioned_col_name = TextDatumGetCString (PG_GETARG_DATUM (1 ));
56+ Oid partitioned_col_type ;
57+ uint32 part_count = PG_GETARG_INT32 (2 ),
58+ i ;
59+
60+ /* Partition names and tablespaces */
61+ char * * relnames = NULL ,
62+ * * tablespaces = NULL ;
63+ int relnames_size = 0 ,
64+ tablespaces_size = 0 ;
65+ RangeVar * * rangevars = NULL ;
5666
5767/* Check that there's no partitions yet */
5868if (get_pathman_relation_info (parent_relid ))
5969elog (ERROR ,"cannot add new HASH partitions" );
6070
6171partitioned_col_type = get_attribute_type (parent_relid ,
62- TextDatumGetCString ( partitioned_col_name ) ,
72+ partitioned_col_name ,
6373 false);
6474
65- /*Get partition names and tablespaces */
75+ /*Extract partition names */
6676if (!PG_ARGISNULL (3 ))
67- names = deconstruct_text_array (PG_GETARG_DATUM (3 ),& names_size );
77+ relnames = deconstruct_text_array (PG_GETARG_DATUM (3 ),& relnames_size );
6878
79+ /* Extract partition tablespaces */
6980if (!PG_ARGISNULL (4 ))
7081tablespaces = deconstruct_text_array (PG_GETARG_DATUM (4 ),& tablespaces_size );
7182
83+ /* If both arrays are present, check that their lengths are equal */
84+ if (relnames && tablespaces && relnames_size != tablespaces_size )
85+ elog (ERROR ,"sizes of arrays 'relnames' and 'tablespaces' are different" );
86+
7287/* Convert partition names into RangeVars */
73- if (names_size > 0 )
88+ if (relnames )
7489{
75- rangevars = palloc (sizeof (RangeVar )* names_size );
76- for (i = 0 ;i < names_size ;i ++ )
90+ rangevars = palloc (sizeof (RangeVar )* relnames_size );
91+ for (i = 0 ;i < relnames_size ;i ++ )
7792{
78- List * nl = stringToQualifiedNameList (names [i ]);
93+ List * nl = stringToQualifiedNameList (relnames [i ]);
7994
8095rangevars [i ]= makeRangeVarFromNameList (nl );
8196}
8297}
8398
99+ /* Finally create HASH partitions */
84100for (i = 0 ;i < part_count ;i ++ )
85101{
86- RangeVar * rel = rangevars != NULL ?rangevars [i ] :NULL ;
87- char * tablespace = tablespaces != NULL ?tablespaces [i ] :NULL ;
102+ RangeVar * partition_rv = rangevars ?rangevars [i ] :NULL ;
103+ char * tablespace = tablespaces ?tablespaces [i ] :NULL ;
88104
89105/* Create a partition (copy FKs, invoke callbacks etc) */
90106create_single_hash_partition_internal (parent_relid ,i ,part_count ,
91107partitioned_col_type ,
92- rel ,tablespace );
108+ partition_rv ,tablespace );
93109}
94110
95- PG_RETURN_VOID ();
96- }
97-
98- /*
99- * Convert Datum into cstring array
100- */
101- static char * *
102- deconstruct_text_array (Datum arr ,int * num_elems )
103- {
104- ArrayType * arrayval ;
105- int16 elemlen ;
106- bool elembyval ;
107- char elemalign ;
108- Datum * elem_values ;
109- bool * elem_nulls ;
110- int16 i ;
111-
112- arrayval = DatumGetArrayTypeP (arr );
113-
114- Assert (ARR_ELEMTYPE (arrayval )== TEXTOID );
115-
116- get_typlenbyvalalign (ARR_ELEMTYPE (arrayval ),
117- & elemlen ,& elembyval ,& elemalign );
118- deconstruct_array (arrayval ,
119- ARR_ELEMTYPE (arrayval ),
120- elemlen ,elembyval ,elemalign ,
121- & elem_values ,& elem_nulls ,num_elems );
122-
123- /* If there are actual values then convert them into cstrings */
124- if (num_elems > 0 )
125- {
126- char * * strings = palloc (sizeof (char * )* * num_elems );
127-
128- for (i = 0 ;i < * num_elems ;i ++ )
129- {
130- if (elem_nulls [i ])
131- elog (ERROR ,
132- "Partition name and tablespace arrays cannot contain nulls" );
133-
134- strings [i ]= TextDatumGetCString (elem_values [i ]);
135- }
136-
137- return strings ;
138- }
111+ /* Free arrays */
112+ DeepFreeArray (relnames ,relnames_size );
113+ DeepFreeArray (tablespaces ,tablespaces_size );
114+ DeepFreeArray (rangevars ,relnames_size );
139115
140- return NULL ;
116+ PG_RETURN_VOID () ;
141117}
142118
143119/*
@@ -201,3 +177,53 @@ build_hash_condition(PG_FUNCTION_ARGS)
201177
202178PG_RETURN_TEXT_P (cstring_to_text (result ));
203179}
180+
181+
182+ /*
183+ * ------------------
184+ * Helper functions
185+ * ------------------
186+ */
187+
188+ /* Convert Datum into CSTRING array */
189+ static char * *
190+ deconstruct_text_array (Datum arr ,int * num_elems )
191+ {
192+ ArrayType * arrayval ;
193+ int16 elemlen ;
194+ bool elembyval ;
195+ char elemalign ;
196+ Datum * elem_values ;
197+ bool * elem_nulls ;
198+ int16 i ;
199+
200+ arrayval = DatumGetArrayTypeP (arr );
201+
202+ Assert (ARR_ELEMTYPE (arrayval )== TEXTOID );
203+
204+ get_typlenbyvalalign (ARR_ELEMTYPE (arrayval ),
205+ & elemlen ,& elembyval ,& elemalign );
206+ deconstruct_array (arrayval ,
207+ ARR_ELEMTYPE (arrayval ),
208+ elemlen ,elembyval ,elemalign ,
209+ & elem_values ,& elem_nulls ,num_elems );
210+
211+ /* If there are actual values then convert them into CSTRINGs */
212+ if (num_elems > 0 )
213+ {
214+ char * * strings = palloc (sizeof (char * )* * num_elems );
215+
216+ for (i = 0 ;i < * num_elems ;i ++ )
217+ {
218+ if (elem_nulls [i ])
219+ elog (ERROR ,"partition name and tablespace arrays "
220+ "may not contain nulls" );
221+
222+ strings [i ]= TextDatumGetCString (elem_values [i ]);
223+ }
224+
225+ return strings ;
226+ }
227+
228+ return NULL ;
229+ }