Skip to content

Commit e8521d3

Browse files
committed
Add support for CREATE TABLE .. PARTITION OF
1 parent 48df7a3 commit e8521d3

File tree

5 files changed

+164
-24
lines changed

5 files changed

+164
-24
lines changed

expected/pathman_declarative.out

+31-2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ CREATE TABLE test.range_rel (
77
id SERIAL PRIMARY KEY,
88
dt DATE NOT NULL
99
);
10+
CREATE TABLE test.r2 (LIKE test.range_rel);
11+
ALTER TABLE test.range_rel ATTACH PARTITION test.r2
12+
FOR VALUES FROM ('2015-05-01') TO ('2015-06-01');
13+
ERROR: "range_rel" is not partitioned
1014
INSERT INTO test.range_rel (dt)
1115
SELECT g FROM generate_series('2015-01-01', '2015-04-30', '1 day'::interval) AS g;
1216
SELECT pathman.create_range_partitions('test.range_rel', 'dt',
@@ -25,7 +29,12 @@ SELECT * FROM pathman.pathman_partition_list;
2529
test.range_rel | test.range_rel_4 | 2 | dt | 04-01-2015 | 05-01-2015
2630
(4 rows)
2731

28-
CREATE TABLE test.r2 (LIKE test.range_rel);
32+
ALTER TABLE test.range_rel ATTACH PARTITION test.r2
33+
FOR VALUES IN ('2015-05-01', '2015-06-01');
34+
ERROR: pg_pathman only supports queries for range partitions
35+
ALTER TABLE test.range_rel ATTACH PARTITION test.r2
36+
FOR VALUES FROM ('2014-05-01') TO ('2015-06-01');
37+
ERROR: specified range [05-01-2014, 06-01-2015) overlaps with existing partitions
2938
ALTER TABLE test.range_rel ATTACH PARTITION test.r2
3039
FOR VALUES FROM ('2015-05-01') TO ('2015-06-01');
3140
SELECT * FROM pathman.pathman_partition_list;
@@ -66,7 +75,27 @@ SELECT * FROM pathman.pathman_partition_list;
6675
id | integer | | not null | | plain | |
6776
dt | date | | not null | | plain | |
6877

78+
CREATE TABLE test.r4 PARTITION OF test.range_rel
79+
FOR VALUES IN ('2015-05-01', '2015-06-01');
80+
ERROR: pg_pathman only supports queries for range partitions
81+
CREATE TABLE test.r4 PARTITION OF test.range_rel
82+
FOR VALUES FROM ('2014-05-01') TO ('2015-06-01');
83+
ERROR: specified range [05-01-2014, 06-01-2015) overlaps with existing partitions
84+
CREATE TABLE test.r4 PARTITION OF test.range_rel
85+
FOR VALUES FROM ('2015-06-01') TO ('2016-01-01');
86+
\d+ test.r4;
87+
Table "test.r4"
88+
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
89+
--------+---------+-----------+----------+--------------------------------------------+---------+--------------+-------------
90+
id | integer | | not null | nextval('test.range_rel_id_seq'::regclass) | plain | |
91+
dt | date | | not null | | plain | |
92+
Indexes:
93+
"r4_pkey" PRIMARY KEY, btree (id)
94+
Check constraints:
95+
"pathman_r4_check" CHECK (dt >= '06-01-2015'::date AND dt < '01-01-2016'::date)
96+
Inherits: test.range_rel
97+
6998
DROP SCHEMA test CASCADE;
70-
NOTICE: drop cascades to 7 other objects
99+
NOTICE: drop cascades to 8 other objects
71100
DROP EXTENSION pg_pathman CASCADE;
72101
DROP SCHEMA pathman CASCADE;

sql/pathman_declarative.sql

+15-1
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,20 @@ CREATE TABLE test.range_rel (
99
id SERIAL PRIMARY KEY,
1010
dt DATE NOT NULL
1111
);
12+
CREATE TABLE test.r2 (LIKE test.range_rel);
13+
ALTER TABLE test.range_rel ATTACH PARTITION test.r2
14+
FOR VALUES FROM ('2015-05-01') TO ('2015-06-01');
1215

1316
INSERT INTO test.range_rel (dt)
1417
SELECT g FROM generate_series('2015-01-01', '2015-04-30', '1 day'::interval) AS g;
1518
SELECT pathman.create_range_partitions('test.range_rel', 'dt',
1619
'2015-01-01'::DATE, '1 month'::INTERVAL);
1720

1821
SELECT * FROM pathman.pathman_partition_list;
19-
CREATE TABLE test.r2 (LIKE test.range_rel);
22+
ALTER TABLE test.range_rel ATTACH PARTITION test.r2
23+
FOR VALUES IN ('2015-05-01', '2015-06-01');
24+
ALTER TABLE test.range_rel ATTACH PARTITION test.r2
25+
FOR VALUES FROM ('2014-05-01') TO ('2015-06-01');
2026
ALTER TABLE test.range_rel ATTACH PARTITION test.r2
2127
FOR VALUES FROM ('2015-05-01') TO ('2015-06-01');
2228
SELECT * FROM pathman.pathman_partition_list;
@@ -25,6 +31,14 @@ ALTER TABLE test.range_rel DETACH PARTITION test.r2;
2531
SELECT * FROM pathman.pathman_partition_list;
2632
\d+ test.r2;
2733

34+
CREATE TABLE test.r4 PARTITION OF test.range_rel
35+
FOR VALUES IN ('2015-05-01', '2015-06-01');
36+
CREATE TABLE test.r4 PARTITION OF test.range_rel
37+
FOR VALUES FROM ('2014-05-01') TO ('2015-06-01');
38+
CREATE TABLE test.r4 PARTITION OF test.range_rel
39+
FOR VALUES FROM ('2015-06-01') TO ('2016-01-01');
40+
\d+ test.r4;
41+
2842
DROP SCHEMA test CASCADE;
2943
DROP EXTENSION pg_pathman CASCADE;
3044
DROP SCHEMA pathman CASCADE;

src/declarative.c

+105-14
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "declarative.h"
22
#include "utils.h"
3+
#include "partition_creation.h"
34

45
#include "fmgr.h"
56
#include "access/htup_details.h"
@@ -57,31 +58,37 @@ modify_declative_partitioning_query(Query *query)
5758
}
5859

5960
/* is it one of declarative partitioning commands? */
60-
bool is_pathman_related_partitioning_cmd(Node *parsetree)
61+
bool
62+
is_pathman_related_partitioning_cmd(Node *parsetree, Oid *parent_relid)
6163
{
6264
if (IsA(parsetree, AlterTableStmt))
6365
{
6466
ListCell *lc;
6567
AlterTableStmt *stmt = (AlterTableStmt *) parsetree;
6668
int cnt = 0;
6769

70+
*parent_relid = RangeVarGetRelid(stmt->relation, NoLock, false);
71+
if (get_pathman_relation_info(*parent_relid) == NULL)
72+
return false;
73+
74+
/*
75+
* Since cmds can contain multiple commmands but we can handle only
76+
* two of them here, so we need to check that there are only commands
77+
* we can handle. In case if cmds contain other commands we skip all
78+
* commands in this statement.
79+
*/
6880
foreach(lc, stmt->cmds)
6981
{
7082
AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lc);
71-
int subtype = cmd->subtype;
72-
73-
if (subtype < 0)
74-
subtype = -subtype;
75-
76-
switch (subtype)
83+
switch (abs(cmd->subtype))
7784
{
7885
case AT_AttachPartition:
7986
case AT_DetachPartition:
8087
/*
81-
* we need to fix all subtypes,
88+
* We need to fix all subtypes,
8289
* possibly we're not going to handle this
8390
*/
84-
cmd->subtype = -(cmd->subtype);
91+
cmd->subtype = abs(cmd->subtype);
8592
continue;
8693
default:
8794
cnt++;
@@ -90,6 +97,26 @@ bool is_pathman_related_partitioning_cmd(Node *parsetree)
9097

9198
return (cnt == 0);
9299
}
100+
else if (IsA(parsetree, CreateStmt))
101+
{
102+
/* inhRelations != NULL, partbound != NULL, tableElts == NULL */
103+
CreateStmt *stmt = (CreateStmt *) parsetree;
104+
105+
if (stmt->inhRelations && stmt->partbound != NULL)
106+
{
107+
RangeVar *rv = castNode(RangeVar, linitial(stmt->inhRelations));
108+
*parent_relid = RangeVarGetRelid(rv, NoLock, false);
109+
if (get_pathman_relation_info(*parent_relid) == NULL)
110+
return false;
111+
112+
if (stmt->tableElts != NIL)
113+
elog(ERROR, "pg_pathman doesn't support column definitions "
114+
"in declarative syntax yet");
115+
116+
return true;
117+
118+
}
119+
}
93120
return false;
94121
}
95122

@@ -157,10 +184,10 @@ transform_bound_value(ParseState *pstate, A_Const *con,
157184
}
158185

159186
/* handle ALTER TABLE .. ATTACH PARTITION command */
160-
void handle_attach_partition(AlterTableStmt *stmt, AlterTableCmd *cmd)
187+
void
188+
handle_attach_partition(Oid parent_relid, AlterTableCmd *cmd)
161189
{
162-
Oid parent_relid,
163-
partition_relid,
190+
Oid partition_relid,
164191
proc_args[] = { REGCLASSOID, REGCLASSOID,
165192
ANYELEMENTOID, ANYELEMENTOID };
166193

@@ -181,7 +208,10 @@ void handle_attach_partition(AlterTableStmt *stmt, AlterTableCmd *cmd)
181208

182209
Assert(cmd->subtype == AT_AttachPartition);
183210

184-
parent_relid = RangeVarGetRelid(stmt->relation, NoLock, false);
211+
if (pcmd->bound->strategy != PARTITION_STRATEGY_RANGE)
212+
ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
213+
errmsg("pg_pathman only supports queries for range partitions")));
214+
185215
if ((prel = get_pathman_relation_info(parent_relid)) == NULL)
186216
elog(ERROR, "relation is not partitioned");
187217

@@ -231,7 +261,8 @@ void handle_attach_partition(AlterTableStmt *stmt, AlterTableCmd *cmd)
231261
}
232262

233263
/* handle ALTER TABLE .. DETACH PARTITION command */
234-
void handle_detach_partition(AlterTableStmt *stmt, AlterTableCmd *cmd)
264+
void
265+
handle_detach_partition(AlterTableCmd *cmd)
235266
{
236267
List *proc_name;
237268
FmgrInfo proc_flinfo;
@@ -262,3 +293,63 @@ void handle_detach_partition(AlterTableStmt *stmt, AlterTableCmd *cmd)
262293
/* Invoke the callback */
263294
FunctionCallInvoke(&proc_fcinfo);
264295
}
296+
297+
/* handle CREATE TABLE .. PARTITION OF <parent> FOR VALUES FROM .. TO .. */
298+
void
299+
handle_create_partition_of(Oid parent_relid, CreateStmt *stmt)
300+
{
301+
Bound start,
302+
end;
303+
const PartRelationInfo *prel;
304+
ParseState *pstate = make_parsestate(NULL);
305+
PartitionRangeDatum *ldatum,
306+
*rdatum;
307+
Const *lval,
308+
*rval;
309+
A_Const *con;
310+
311+
/* we show errors earlier for these asserts */
312+
Assert(stmt->inhRelations != NULL);
313+
Assert(stmt->tableElts == NIL);
314+
315+
if (stmt->partbound->strategy != PARTITION_STRATEGY_RANGE)
316+
ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
317+
errmsg("pg_pathman only supports queries for range partitions")));
318+
319+
if ((prel = get_pathman_relation_info(parent_relid)) == NULL)
320+
ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
321+
errmsg("table \"%s\" is not partitioned",
322+
get_rel_name_or_relid(parent_relid))));
323+
324+
if (prel->parttype != PT_RANGE)
325+
ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
326+
errmsg("table \"%s\" is not partitioned by RANGE",
327+
get_rel_name_or_relid(parent_relid))));
328+
329+
ldatum = (PartitionRangeDatum *) linitial(stmt->partbound->lowerdatums);
330+
con = castNode(A_Const, ldatum->value);
331+
lval = transform_bound_value(pstate, con, prel->ev_type, prel->ev_typmod);
332+
333+
rdatum = (PartitionRangeDatum *) linitial(stmt->partbound->upperdatums);
334+
con = castNode(A_Const, rdatum->value);
335+
rval = transform_bound_value(pstate, con, prel->ev_type, prel->ev_typmod);
336+
337+
start = lval->constisnull?
338+
MakeBoundInf(MINUS_INFINITY) :
339+
MakeBound(lval->constvalue);
340+
341+
end = rval->constisnull?
342+
MakeBoundInf(PLUS_INFINITY) :
343+
MakeBound(rval->constvalue);
344+
345+
/* more checks */
346+
check_range_available(parent_relid, &start, &end, lval->consttype, true);
347+
348+
/* Create a new RANGE partition and return its Oid */
349+
create_single_range_partition_internal(parent_relid,
350+
&start,
351+
&end,
352+
lval->consttype,
353+
stmt->relation,
354+
stmt->tablespacename);
355+
}

src/hooks.c

+9-4
Original file line numberDiff line numberDiff line change
@@ -963,9 +963,9 @@ pathman_process_utility_hook(Node *first_arg,
963963
get_rel_name(relation_oid))));
964964
}
965965
#if PG_VERSION_NUM >= 100000
966-
else if (is_pathman_related_partitioning_cmd(parsetree))
966+
else if (is_pathman_related_partitioning_cmd(parsetree, &relation_oid))
967967
{
968-
/* we can handle all the partitioning commands */
968+
/* we can handle all the partitioning commands in ALTER .. TABLE */
969969
if (IsA(parsetree, AlterTableStmt))
970970
{
971971
ListCell *lc;
@@ -977,16 +977,21 @@ pathman_process_utility_hook(Node *first_arg,
977977
switch (cmd->subtype)
978978
{
979979
case AT_AttachPartition:
980-
handle_attach_partition(stmt, cmd);
980+
handle_attach_partition(relation_oid, cmd);
981981
return;
982982
case AT_DetachPartition:
983-
handle_detach_partition(stmt, cmd);
983+
handle_detach_partition(cmd);
984984
return;
985985
default:
986986
elog(ERROR, "can't handle this command");
987987
}
988988
}
989989
}
990+
else if (IsA(parsetree, CreateStmt))
991+
{
992+
handle_create_partition_of(relation_oid, (CreateStmt *) parsetree);
993+
return;
994+
}
990995
}
991996
#endif
992997
}

src/include/declarative.h

+4-3
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@
66
#include "nodes/parsenodes.h"
77

88
void modify_declative_partitioning_query(Query *query);
9-
bool is_pathman_related_partitioning_cmd(Node *parsetree);
9+
bool is_pathman_related_partitioning_cmd(Node *parsetree, Oid *parent_relid);
1010

1111
/* actual actions */
12-
void handle_attach_partition(AlterTableStmt *stmt, AlterTableCmd *cmd);
13-
void handle_detach_partition(AlterTableStmt *stmt, AlterTableCmd *cmd);
12+
void handle_attach_partition(Oid parent_relid, AlterTableCmd *cmd);
13+
void handle_detach_partition(AlterTableCmd *cmd);
14+
void handle_create_partition_of(Oid parent_relid, CreateStmt *stmt);
1415

1516
#endif /* DECLARATIVE_H */

0 commit comments

Comments
 (0)