11
11
#include "postgres.h"
12
12
#include "miscadmin.h"
13
13
14
+ #include "access/xact.h"
14
15
#include "access/htup_details.h"
15
16
#include "catalog/heap.h"
16
17
#include "catalog/namespace.h"
27
28
#include "utils/builtins.h"
28
29
#include "utils/timestamp.h"
29
30
#include "utils/lsyscache.h"
31
+ #include "utils/snapmgr.h"
30
32
31
33
32
34
static void create_hash_partitions (PartitionInfo * pinfo ,
33
35
Oid relid ,
34
36
const char * attname ,
35
- bool partition_data );
36
- static void create_range_partitions (PartitionInfo * pinfo , Oid relid , const char * attname , bool partition_data );
37
+ PartitionDataType partition_data );
38
+ static void create_range_partitions (PartitionInfo * pinfo ,
39
+ Oid relid ,
40
+ const char * attname ,
41
+ PartitionDataType partition_data );
42
+ static void read_interval_value (PartitionInfo * pinfo ,
43
+ Oid atttype ,
44
+ Oid * interval_type ,
45
+ Datum * interval_datum );
37
46
static Node * cookPartitionKeyValue (Oid relid , const char * raw , Node * raw_value );
38
47
static char * RangeVarGetString (const RangeVar * rangevar );
39
48
static Oid RangeVarGetNamespaceId (const RangeVar * rangevar );
@@ -43,7 +52,7 @@ static Oid RangeVarGetNamespaceId(const RangeVar *rangevar);
43
52
44
53
45
54
void
46
- create_partitions (PartitionInfo * pinfo , Oid relid , bool partition_data )
55
+ create_partitions (PartitionInfo * pinfo , Oid relid , PartitionDataType partition_data )
47
56
{
48
57
Value * attname = (Value * ) linitial (((ColumnRef * ) pinfo -> key )-> fields );
49
58
@@ -64,18 +73,38 @@ create_partitions(PartitionInfo *pinfo, Oid relid, bool partition_data)
64
73
}
65
74
}
66
75
67
- SPI_finish (); /* close SPI connection */
76
+ SPI_finish ();
77
+
78
+ /* Start concurrent partitioning if needed */
79
+ if (partition_data == PDT_CONCURRENT )
80
+ {
81
+ /*
82
+ * We must commit current transaction to make partitions visible to the
83
+ * worker
84
+ */
85
+ PopActiveSnapshot ();
86
+ CommitTransactionCommand ();
87
+ StartTransactionCommand ();
88
+
89
+ if (SPI_connect () != SPI_OK_CONNECT )
90
+ elog (ERROR , "could not connect using SPI" );
91
+
92
+ /* Start worker */
93
+ pm_partition_table_concurrently (relid );
94
+
95
+ SPI_finish ();
96
+ }
68
97
}
69
98
70
99
71
100
static void
72
101
create_hash_partitions (PartitionInfo * pinfo ,
73
102
Oid relid ,
74
103
const char * attname ,
75
- bool partition_data )
104
+ PartitionDataType partition_data )
76
105
{
77
- char * * relnames = NULL ;
78
- char * * tablespaces = NULL ;
106
+ char * * relnames = NULL ;
107
+ char * * tablespaces = NULL ;
79
108
80
109
if (list_length (pinfo -> partitions ) > 0 )
81
110
{
@@ -100,7 +129,7 @@ create_hash_partitions(PartitionInfo *pinfo,
100
129
pm_create_hash_partitions (relid ,
101
130
attname ,
102
131
pinfo -> partitions_count ,
103
- partition_data ,
132
+ partition_data == PDT_REGULAR ,
104
133
relnames ,
105
134
tablespaces );
106
135
@@ -120,7 +149,7 @@ static void
120
149
create_range_partitions (PartitionInfo * pinfo ,
121
150
Oid relid ,
122
151
const char * attname ,
123
- bool partition_data )
152
+ PartitionDataType partition_data )
124
153
{
125
154
ListCell * lc ;
126
155
Datum last_bound = (Datum ) 0 ;
@@ -133,9 +162,8 @@ create_range_partitions(PartitionInfo *pinfo,
133
162
Datum start_value ;
134
163
135
164
/* parameters */
136
- Datum interval_datum = ( Datum ) 0 ;
165
+ Datum interval_datum ;
137
166
Oid interval_type ;
138
- Const * interval_const ;
139
167
ParseState * pstate = make_parsestate (NULL );
140
168
141
169
if (!attnum )
@@ -144,67 +172,14 @@ create_range_partitions(PartitionInfo *pinfo,
144
172
atttype = get_atttype (relid , attnum );
145
173
atttypmod = get_atttypmod (relid , attnum );
146
174
147
- /* If interval is set then convert it to a suitable Datum value */
148
- if (pinfo -> interval != NULL )
149
- {
150
- if (IsA (pinfo -> interval , A_Const ))
151
- {
152
- A_Const * con = (A_Const * ) pinfo -> interval ;
153
- Value * val = & con -> val ;
154
-
155
- interval_const = make_const (pstate , val , con -> location );
156
- }
157
- else
158
- elog (ERROR , "Constant interval value is expected" );
159
-
160
- /*
161
- * If attribute is of type DATE or TIMESTAMP then convert interval to
162
- * Interval type
163
- */
164
- switch (atttype )
165
- {
166
- case DATEOID :
167
- case TIMESTAMPOID :
168
- case TIMESTAMPTZOID :
169
- {
170
- char * interval_literal ;
171
-
172
- /* We should get an UNKNOWN type here */
173
- if (interval_const -> consttype != UNKNOWNOID )
174
- elog (ERROR , "Expected a literal as an interval value" );
175
-
176
- /* Get a text representation of the interval */
177
- interval_literal = DatumGetCString (interval_const -> constvalue );
178
- interval_datum = DirectFunctionCall3 (interval_in ,
179
- CStringGetDatum (interval_literal ),
180
- ObjectIdGetDatum (InvalidOid ),
181
- Int32GetDatum (-1 ));
182
- interval_type = INTERVALOID ;
183
- }
184
- break ;
185
- default :
186
- interval_datum = interval_const -> constvalue ;
187
- interval_type = interval_const -> consttype ;
188
- }
189
- }
190
- else /* If interval is not set */
191
- {
192
- switch (atttype )
193
- {
194
- case DATEOID :
195
- case TIMESTAMPOID :
196
- case TIMESTAMPTZOID :
197
- interval_type = INTERVALOID ;
198
- default :
199
- interval_type = atttype ;
200
- }
201
- }
175
+ /* Interval */
176
+ read_interval_value (pinfo , atttype , & interval_type , & interval_datum );
202
177
203
178
/*
204
179
* Start value. It is always non-NULL whenever partition_data = True.
205
180
* Otherwise the actual start value doesn't matter
206
181
*/
207
- Assert ( ( pinfo -> start_value != NULL ) == partition_data );
182
+ Assert (pinfo -> start_value != NULL && partition_data != PDT_NONE );
208
183
if (pinfo -> start_value )
209
184
{
210
185
Node * n = cookPartitionKeyValue (relid ,
@@ -225,7 +200,8 @@ create_range_partitions(PartitionInfo *pinfo,
225
200
interval_datum ,
226
201
interval_type ,
227
202
pinfo -> interval == NULL ,
228
- partition_data );
203
+ partition_data == PDT_REGULAR ,
204
+ partition_data == PDT_CONCURRENT );
229
205
230
206
/* Add partitions */
231
207
foreach (lc , pinfo -> partitions )
@@ -251,6 +227,97 @@ create_range_partitions(PartitionInfo *pinfo,
251
227
last_bound = ((Const * ) bound_expr )-> constvalue ;
252
228
last_bound_is_null = false;
253
229
}
230
+
231
+ /*
232
+ * Add semi-infinite partition to the left (only for ALTER TABLE ...
233
+ * PARTITION BY), i.e. when start value is set
234
+ */
235
+ if (pinfo -> start_value )
236
+ {
237
+
238
+ pm_add_range_partition (relid ,
239
+ atttype ,
240
+ NULL ,
241
+ (Datum ) 0 , /* it doesn't matter */
242
+ start_value ,
243
+ true,
244
+ false,
245
+ NULL );
246
+ }
247
+ }
248
+
249
+
250
+ /*
251
+ * Converts
252
+ */
253
+ static void
254
+ read_interval_value (PartitionInfo * pinfo ,
255
+ Oid atttype ,
256
+ Oid * interval_type ,
257
+ Datum * interval_datum )
258
+ {
259
+ ParseState * pstate = make_parsestate (NULL );
260
+
261
+ /* Default value */
262
+ * interval_datum = (Datum ) 0 ;
263
+
264
+ /* If interval is set then convert it to a suitable Datum value */
265
+ if (pinfo -> interval != NULL )
266
+ {
267
+ Const * interval_const ;
268
+
269
+ if (IsA (pinfo -> interval , A_Const ))
270
+ {
271
+ A_Const * con = (A_Const * ) pinfo -> interval ;
272
+ Value * val = & con -> val ;
273
+
274
+ interval_const = make_const (pstate , val , con -> location );
275
+ }
276
+ else
277
+ elog (ERROR , "Constant interval value is expected" );
278
+
279
+ /*
280
+ * If attribute is of type DATE or TIMESTAMP then convert interval to
281
+ * Interval type
282
+ */
283
+ switch (atttype )
284
+ {
285
+ case DATEOID :
286
+ case TIMESTAMPOID :
287
+ case TIMESTAMPTZOID :
288
+ {
289
+ char * interval_literal ;
290
+
291
+ /* We should get an UNKNOWN type here */
292
+ if (interval_const -> consttype != UNKNOWNOID )
293
+ elog (ERROR , "Expected a literal as an interval value" );
294
+
295
+ /* Get a text representation of the interval */
296
+ interval_literal = DatumGetCString (interval_const -> constvalue );
297
+ * interval_datum = DirectFunctionCall3 (interval_in ,
298
+ CStringGetDatum (interval_literal ),
299
+ ObjectIdGetDatum (InvalidOid ),
300
+ Int32GetDatum (-1 ));
301
+ * interval_type = INTERVALOID ;
302
+ }
303
+ break ;
304
+ default :
305
+ * interval_datum = interval_const -> constvalue ;
306
+ * interval_type = interval_const -> consttype ;
307
+ }
308
+ }
309
+ else /* If interval is not set */
310
+ {
311
+ switch (atttype )
312
+ {
313
+ case DATEOID :
314
+ case TIMESTAMPOID :
315
+ case TIMESTAMPTZOID :
316
+ * interval_type = INTERVALOID ;
317
+ default :
318
+ * interval_type = atttype ;
319
+ }
320
+ }
254
321
}
255
322
256
323
0 commit comments