24
24
#include "commands/tablespace.h"
25
25
#include "executor/spi.h"
26
26
#include "nodes/value.h"
27
+ #include "nodes/nodeFuncs.h"
28
+ #include "optimizer/clauses.h"
29
+ #include "parser/parse_coerce.h"
30
+ #include "parser/parse_expr.h"
27
31
#include "parser/parse_node.h"
28
32
#include "utils/builtins.h"
29
33
#include "utils/timestamp.h"
@@ -41,9 +45,11 @@ static void create_range_partitions(PartitionInfo *pinfo,
41
45
PartitionDataType partition_data );
42
46
static void read_interval_value (Node * raw_interval ,
43
47
Oid atttype ,
48
+ int32 atttypmod ,
44
49
Oid * interval_type ,
45
50
Datum * interval_datum );
46
- static Node * cookPartitionKeyValue (Oid relid , const char * raw , Node * raw_value );
51
+ static Node * cookPartitionKeyValue (Oid relid , const char * attname , Node * raw_value );
52
+ static Const * cookInterval (Node * raw_interval , Oid interval_type , int32 interval_typmod );
47
53
static char * RangeVarGetString (const RangeVar * rangevar );
48
54
static Oid RangeVarGetNamespaceId (const RangeVar * rangevar );
49
55
static char * generate_unique_child_relname (Oid relid , const char * prefix );
@@ -166,7 +172,6 @@ create_range_partitions(PartitionInfo *pinfo,
166
172
/* parameters */
167
173
Datum interval_datum ;
168
174
Oid interval_type ;
169
- ParseState * pstate = make_parsestate (NULL );
170
175
171
176
if (!attnum )
172
177
elog (ERROR , "Unknown attribute '%s'" , attname );
@@ -175,7 +180,7 @@ create_range_partitions(PartitionInfo *pinfo,
175
180
atttypmod = get_atttypmod (relid , attnum );
176
181
177
182
/* Interval */
178
- read_interval_value (pinfo -> interval , atttype , & interval_type , & interval_datum );
183
+ read_interval_value (pinfo -> interval , atttype , atttypmod , & interval_type , & interval_datum );
179
184
180
185
/*
181
186
* Start value. It is always non-NULL whenever partition_data = True.
@@ -185,10 +190,10 @@ create_range_partitions(PartitionInfo *pinfo,
185
190
if (pinfo -> start_value )
186
191
{
187
192
Node * n = cookPartitionKeyValue (relid ,
188
- attname ,
189
- (Node * ) pinfo -> start_value );
193
+ attname ,
194
+ (Node * ) pinfo -> start_value );
190
195
if (!IsA (n , Const ))
191
- elog (ERROR , "Start value must be a constatnt " );
196
+ elog (ERROR , "Start value should be a constant expression " );
192
197
start_value = ((Const * ) n )-> constvalue ;
193
198
}
194
199
else
@@ -213,7 +218,8 @@ create_range_partitions(PartitionInfo *pinfo,
213
218
Node * bound_expr ;
214
219
215
220
/* Transform raw expression */
216
- bound_expr = cookDefault (pstate , orig , atttype , atttypmod , (char * ) attname );
221
+ // bound_expr = cookDefault(pstate, orig, atttype, atttypmod, (char *) attname);
222
+ bound_expr = cookPartitionKeyValue (relid , attname , orig );
217
223
218
224
if (!IsA (bound_expr , Const ))
219
225
elog (ERROR , "Constant expected" );
@@ -259,70 +265,35 @@ create_range_partitions(PartitionInfo *pinfo,
259
265
static void
260
266
read_interval_value (Node * raw_interval ,
261
267
Oid atttype ,
268
+ int32 atttypmod ,
262
269
Oid * interval_type ,
263
270
Datum * interval_datum )
264
271
{
265
- ParseState * pstate = make_parsestate ( NULL ) ;
272
+ int32 interval_typmod ;
266
273
267
274
/* Default value */
268
275
* interval_datum = (Datum ) 0 ;
269
276
270
- /* If interval is set then convert it to a suitable Datum value */
271
- if ( raw_interval != NULL )
277
+ /* Determine an interval type */
278
+ switch ( atttype )
272
279
{
273
- Const * interval_const ;
274
-
275
- if (IsA (raw_interval , A_Const ))
276
- {
277
- A_Const * con = (A_Const * ) raw_interval ;
278
- Value * val = & con -> val ;
279
-
280
- interval_const = make_const (pstate , val , con -> location );
281
- }
282
- else
283
- elog (ERROR , "Constant interval value is expected" );
284
-
285
- /*
286
- * If attribute is of type DATE or TIMESTAMP then convert interval to
287
- * Interval type
288
- */
289
- switch (atttype )
290
- {
291
- case DATEOID :
292
- case TIMESTAMPOID :
293
- case TIMESTAMPTZOID :
294
- {
295
- char * interval_literal ;
296
-
297
- /* We should get an UNKNOWN type here */
298
- if (interval_const -> consttype != UNKNOWNOID )
299
- elog (ERROR , "Expected a literal as an interval value" );
300
-
301
- /* Get a text representation of the interval */
302
- interval_literal = DatumGetCString (interval_const -> constvalue );
303
- * interval_datum = DirectFunctionCall3 (interval_in ,
304
- CStringGetDatum (interval_literal ),
305
- ObjectIdGetDatum (InvalidOid ),
306
- Int32GetDatum (-1 ));
307
- * interval_type = INTERVALOID ;
308
- }
309
- break ;
310
- default :
311
- * interval_datum = interval_const -> constvalue ;
312
- * interval_type = interval_const -> consttype ;
313
- }
280
+ case DATEOID :
281
+ case TIMESTAMPOID :
282
+ case TIMESTAMPTZOID :
283
+ * interval_type = INTERVALOID ;
284
+ interval_typmod = -1 ;
285
+ break ;
286
+ default :
287
+ * interval_type = atttype ;
288
+ interval_typmod = atttypmod ;
314
289
}
315
- else /* If interval is not set */
290
+
291
+ /* If interval is set then convert it to a suitable Datum value */
292
+ if (raw_interval )
316
293
{
317
- switch (atttype )
318
- {
319
- case DATEOID :
320
- case TIMESTAMPOID :
321
- case TIMESTAMPTZOID :
322
- * interval_type = INTERVALOID ;
323
- default :
324
- * interval_type = atttype ;
325
- }
294
+ Const * interval = cookInterval (raw_interval , * interval_type , interval_typmod );
295
+
296
+ * interval_datum = interval -> constvalue ;
326
297
}
327
298
}
328
299
@@ -375,10 +346,52 @@ cookPartitionKeyValue(Oid relid, const char *attname, Node *raw_value)
375
346
atttypmod ,
376
347
(char * ) attname );
377
348
349
+ /* Simplify expression */
350
+ cookie = eval_const_expressions (NULL , cookie );
351
+
378
352
return cookie ;
379
353
}
380
354
381
355
356
+ static Const *
357
+ cookInterval (Node * raw_interval , Oid interval_type , int32 interval_typmod )
358
+ {
359
+ ParseState * pstate = make_parsestate (NULL );
360
+ Node * cookie ;
361
+
362
+ cookie = transformExpr (pstate , raw_interval , EXPR_KIND_OTHER );
363
+
364
+ /*
365
+ * Coerce the expression to the correct type
366
+ */
367
+ if (OidIsValid (interval_type ))
368
+ {
369
+ Oid type_id = exprType (cookie );
370
+
371
+ cookie = coerce_to_target_type (pstate , cookie , type_id ,
372
+ interval_type , interval_typmod ,
373
+ COERCION_ASSIGNMENT ,
374
+ COERCE_IMPLICIT_CAST ,
375
+ -1 );
376
+ if (cookie == NULL )
377
+ ereport (ERROR ,
378
+ (errcode (ERRCODE_DATATYPE_MISMATCH ),
379
+ errmsg ("Interval is of type '%s'"
380
+ " but is should be of type '%s'" ,
381
+ format_type_be (type_id ),
382
+ format_type_be (interval_type ))));
383
+ }
384
+
385
+ /* Simplify expression */
386
+ cookie = eval_const_expressions (NULL , cookie );
387
+
388
+ if (!IsA (cookie , Const ))
389
+ elog (ERROR , "Interval must be a constant expression" );
390
+
391
+ return (Const * ) cookie ;
392
+ }
393
+
394
+
382
395
void
383
396
add_range_partition (Oid parent , PartitionNode * rpinfo )
384
397
{
@@ -400,7 +413,7 @@ add_range_partition(Oid parent, PartitionNode *rpinfo)
400
413
bound = cookPartitionKeyValue (parent , attname , (Node * ) rpinfo -> upper_bound );
401
414
402
415
if (!IsA (bound , Const ))
403
- elog (ERROR , "Constant expected " );
416
+ elog (ERROR , "Upper bound should be a constant expression " );
404
417
405
418
pm_get_part_range (parent , -1 , atttype , & lower , & upper );
406
419
pm_add_range_partition (parent ,
@@ -486,12 +499,14 @@ split_range_partition(Oid parent,
486
499
elog (ERROR , "could not connect using SPI" );
487
500
488
501
attname = pm_get_partition_key (parent );
502
+ orig = (PartitionNode * ) linitial (cmd -> partitions );
503
+ partition_relid = RangeVarGetRelid (orig -> relation , NoLock , false);
489
504
490
505
/* Split value is stored in def attribute */
491
- orig = (PartitionNode * ) linitial (cmd -> partitions );
492
506
split_value = cookPartitionKeyValue (parent , attname , (Node * ) cmd -> def );
493
507
494
- partition_relid = RangeVarGetRelid (orig -> relation , NoLock , false);
508
+ if (!IsA (split_value , Const ))
509
+ elog (ERROR , "Upper bound should be a constant expression" );
495
510
496
511
/*
497
512
* When splitting partition pg_pathman leaves first partition name and
@@ -669,6 +684,7 @@ partitioned_table_set_interval(Oid relid, AlterTableCmd *cmd)
669
684
const char * attname ;
670
685
AttrNumber attnum ;
671
686
Oid atttype ;
687
+ int32 atttypmod ;
672
688
Datum interval_datum ;
673
689
Oid interval_type ;
674
690
bool interval_isnull = (cmd -> def == NULL );
@@ -680,10 +696,12 @@ partitioned_table_set_interval(Oid relid, AlterTableCmd *cmd)
680
696
attname = pm_get_partition_key (relid );
681
697
attnum = get_attnum (relid , attname );
682
698
atttype = get_atttype (relid , attnum );
699
+ atttypmod = get_atttypmod (relid , attnum );
683
700
684
701
/* Convert A_Const to Datum */
685
702
read_interval_value (cmd -> def ,
686
703
atttype ,
704
+ atttypmod ,
687
705
& interval_type ,
688
706
& interval_datum );
689
707
0 commit comments