Skip to content

Commit 80a656b

Browse files
committed
allow constant expressions in LESS THAN (...) and INTERVAL (...) sections
1 parent e7ea385 commit 80a656b

File tree

3 files changed

+95
-75
lines changed

3 files changed

+95
-75
lines changed

contrib/test_partitioning/expected/partition.out

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -74,19 +74,21 @@ SELECT * FROM pathman_partition_list;
7474

7575
DROP TABLE abc CASCADE;
7676
NOTICE: drop cascades to 4 other objects
77-
/* Create hash partitioned table */
7877
CREATE TABLE abc(id serial)
79-
PARTITION BY HASH (id) PARTITIONS (3);
78+
PARTITION BY HASH (id)
79+
(
80+
PARTITION abc_first,
81+
PARTITION abc_second
82+
);
8083
SELECT * FROM pathman_partition_list;
81-
parent | partition | parttype | partattr | range_min | range_max
82-
--------+-----------+----------+----------+-----------+-----------
83-
abc | abc_0 | 1 | id | |
84-
abc | abc_1 | 1 | id | |
85-
abc | abc_2 | 1 | id | |
86-
(3 rows)
84+
parent | partition | parttype | partattr | range_min | range_max
85+
--------+------------+----------+----------+-----------+-----------
86+
abc | abc_first | 1 | id | |
87+
abc | abc_second | 1 | id | |
88+
(2 rows)
8789

8890
DROP TABLE abc CASCADE;
89-
NOTICE: drop cascades to 3 other objects
91+
NOTICE: drop cascades to 2 other objects
9092
CREATE TABLE abc(id serial);
9193
INSERT INTO abc SELECT generate_series(1, 1000);
9294
ALTER TABLE abc PARTITION BY RANGE (id) START FROM (1) INTERVAL (100);

src/backend/commands/partition.c

Lines changed: 82 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@
2424
#include "commands/tablespace.h"
2525
#include "executor/spi.h"
2626
#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"
2731
#include "parser/parse_node.h"
2832
#include "utils/builtins.h"
2933
#include "utils/timestamp.h"
@@ -41,9 +45,11 @@ static void create_range_partitions(PartitionInfo *pinfo,
4145
PartitionDataType partition_data);
4246
static void read_interval_value(Node *raw_interval,
4347
Oid atttype,
48+
int32 atttypmod,
4449
Oid *interval_type,
4550
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);
4753
static char *RangeVarGetString(const RangeVar *rangevar);
4854
static Oid RangeVarGetNamespaceId(const RangeVar *rangevar);
4955
static char *generate_unique_child_relname(Oid relid, const char *prefix);
@@ -166,7 +172,6 @@ create_range_partitions(PartitionInfo *pinfo,
166172
/* parameters */
167173
Datum interval_datum;
168174
Oid interval_type;
169-
ParseState *pstate = make_parsestate(NULL);
170175

171176
if (!attnum)
172177
elog(ERROR, "Unknown attribute '%s'", attname);
@@ -175,7 +180,7 @@ create_range_partitions(PartitionInfo *pinfo,
175180
atttypmod = get_atttypmod(relid, attnum);
176181

177182
/* Interval */
178-
read_interval_value(pinfo->interval, atttype, &interval_type, &interval_datum);
183+
read_interval_value(pinfo->interval, atttype, atttypmod, &interval_type, &interval_datum);
179184

180185
/*
181186
* Start value. It is always non-NULL whenever partition_data = True.
@@ -185,10 +190,10 @@ create_range_partitions(PartitionInfo *pinfo,
185190
if (pinfo->start_value)
186191
{
187192
Node *n = cookPartitionKeyValue(relid,
188-
attname,
189-
(Node *) pinfo->start_value);
193+
attname,
194+
(Node *) pinfo->start_value);
190195
if (!IsA(n, Const))
191-
elog(ERROR, "Start value must be a constatnt");
196+
elog(ERROR, "Start value should be a constant expression");
192197
start_value = ((Const *) n)->constvalue;
193198
}
194199
else
@@ -213,7 +218,8 @@ create_range_partitions(PartitionInfo *pinfo,
213218
Node *bound_expr;
214219

215220
/* 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);
217223

218224
if (!IsA(bound_expr, Const))
219225
elog(ERROR, "Constant expected");
@@ -259,70 +265,35 @@ create_range_partitions(PartitionInfo *pinfo,
259265
static void
260266
read_interval_value(Node *raw_interval,
261267
Oid atttype,
268+
int32 atttypmod,
262269
Oid *interval_type,
263270
Datum *interval_datum)
264271
{
265-
ParseState *pstate = make_parsestate(NULL);
272+
int32 interval_typmod;
266273

267274
/* Default value */
268275
*interval_datum = (Datum) 0;
269276

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)
272279
{
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;
314289
}
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)
316293
{
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;
326297
}
327298
}
328299

@@ -375,10 +346,52 @@ cookPartitionKeyValue(Oid relid, const char *attname, Node *raw_value)
375346
atttypmod,
376347
(char *) attname);
377348

349+
/* Simplify expression */
350+
cookie = eval_const_expressions(NULL, cookie);
351+
378352
return cookie;
379353
}
380354

381355

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+
382395
void
383396
add_range_partition(Oid parent, PartitionNode *rpinfo)
384397
{
@@ -400,7 +413,7 @@ add_range_partition(Oid parent, PartitionNode *rpinfo)
400413
bound = cookPartitionKeyValue(parent, attname, (Node *) rpinfo->upper_bound);
401414

402415
if (!IsA(bound, Const))
403-
elog(ERROR, "Constant expected");
416+
elog(ERROR, "Upper bound should be a constant expression");
404417

405418
pm_get_part_range(parent, -1, atttype, &lower, &upper);
406419
pm_add_range_partition(parent,
@@ -486,12 +499,14 @@ split_range_partition(Oid parent,
486499
elog(ERROR, "could not connect using SPI");
487500

488501
attname = pm_get_partition_key(parent);
502+
orig = (PartitionNode *) linitial(cmd->partitions);
503+
partition_relid = RangeVarGetRelid(orig->relation, NoLock, false);
489504

490505
/* Split value is stored in def attribute */
491-
orig = (PartitionNode *) linitial(cmd->partitions);
492506
split_value = cookPartitionKeyValue(parent, attname, (Node *) cmd->def);
493507

494-
partition_relid = RangeVarGetRelid(orig->relation, NoLock, false);
508+
if (!IsA(split_value, Const))
509+
elog(ERROR, "Upper bound should be a constant expression");
495510

496511
/*
497512
* When splitting partition pg_pathman leaves first partition name and
@@ -669,6 +684,7 @@ partitioned_table_set_interval(Oid relid, AlterTableCmd *cmd)
669684
const char *attname;
670685
AttrNumber attnum;
671686
Oid atttype;
687+
int32 atttypmod;
672688
Datum interval_datum;
673689
Oid interval_type;
674690
bool interval_isnull = (cmd->def == NULL);
@@ -680,10 +696,12 @@ partitioned_table_set_interval(Oid relid, AlterTableCmd *cmd)
680696
attname = pm_get_partition_key(relid);
681697
attnum = get_attnum(relid, attname);
682698
atttype = get_atttype(relid, attnum);
699+
atttypmod = get_atttypmod(relid, attnum);
683700

684701
/* Convert A_Const to Datum */
685702
read_interval_value(cmd->def,
686703
atttype,
704+
atttypmod,
687705
&interval_type,
688706
&interval_datum);
689707

src/backend/parser/gram.y

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2616,7 +2616,7 @@ alterPartitionType:
26162616
n->partitions_count = $7;
26172617
$$ = (PartitionInfo *)n;
26182618
}
2619-
| RANGE '(' columnref ')' START FROM '(' b_expr ')' INTERVAL '(' AexprConst ')'
2619+
| RANGE '(' columnref ')' START FROM '(' b_expr ')' INTERVAL '(' b_expr ')'
26202620
{
26212621
PartitionInfo *n = makeNode(PartitionInfo);
26222622
n->partition_type = P_RANGE;
@@ -3141,7 +3141,7 @@ OptHashPartitionsListElement:
31413141
;
31423142

31433143
OptRangePartitionsInterval:
3144-
INTERVAL '(' AexprConst ')' { $$ = $3; }
3144+
INTERVAL '(' b_expr ')' { $$ = $3; }
31453145
| /* EMPTY */ { $$ = NULL; }
31463146
;
31473147

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy