Skip to content

Commit 7da19fd

Browse files
committed
disable ALTER COLUMN partitioned_column TYPE for tables partitioned by HASH
1 parent 3012641 commit 7da19fd

File tree

5 files changed

+236
-9
lines changed

5 files changed

+236
-9
lines changed

expected/pathman_column_type.out

Lines changed: 104 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
SET search_path = 'public';
33
CREATE EXTENSION pg_pathman;
44
CREATE SCHEMA test_column_type;
5+
/*
6+
* RANGE partitioning.
7+
*/
58
/* create new table (val int) */
69
CREATE TABLE test_column_type.test(val INT4 NOT NULL);
710
SELECT create_range_partitions('test_column_type.test', 'val', 1, 10, 10);
@@ -51,6 +54,106 @@ SELECT tableoid::regclass, * FROM test_column_type.test;
5154
test_column_type.test_1 | 1
5255
(1 row)
5356

57+
SELECT drop_partitions('test_column_type.test');
58+
NOTICE: function test_column_type.test_upd_trig_func() does not exist, skipping
59+
NOTICE: 1 rows copied from test_column_type.test_1
60+
NOTICE: 0 rows copied from test_column_type.test_2
61+
NOTICE: 0 rows copied from test_column_type.test_3
62+
NOTICE: 0 rows copied from test_column_type.test_4
63+
NOTICE: 0 rows copied from test_column_type.test_5
64+
NOTICE: 0 rows copied from test_column_type.test_6
65+
NOTICE: 0 rows copied from test_column_type.test_7
66+
NOTICE: 0 rows copied from test_column_type.test_8
67+
NOTICE: 0 rows copied from test_column_type.test_9
68+
NOTICE: 0 rows copied from test_column_type.test_10
69+
drop_partitions
70+
-----------------
71+
10
72+
(1 row)
73+
74+
DROP TABLE test_column_type.test CASCADE;
75+
/*
76+
* HASH partitioning.
77+
*/
78+
/* create new table (id int, val int) */
79+
CREATE TABLE test_column_type.test(id INT4 NOT NULL, val INT4);
80+
SELECT create_hash_partitions('test_column_type.test', 'id', 5);
81+
create_hash_partitions
82+
------------------------
83+
5
84+
(1 row)
85+
86+
/* make sure that bounds and dispatch info has been cached */
87+
SELECT * FROM test_column_type.test;
88+
id | val
89+
----+-----
90+
(0 rows)
91+
92+
SELECT context, entries FROM pathman_cache_stats ORDER BY context;
93+
context | entries
94+
--------------------------+---------
95+
maintenance | 0
96+
partition bounds cache | 5
97+
partition dispatch cache | 1
98+
partition parents cache | 5
99+
(4 rows)
100+
101+
/* change column's type (should NOT work) */
102+
ALTER TABLE test_column_type.test ALTER id TYPE NUMERIC;
103+
ERROR: cannot change type of column "id" of table "test" partitioned by HASH
104+
/* make sure that everything works properly */
105+
SELECT * FROM test_column_type.test;
106+
id | val
107+
----+-----
108+
(0 rows)
109+
110+
SELECT context, entries FROM pathman_cache_stats ORDER BY context;
111+
context | entries
112+
--------------------------+---------
113+
maintenance | 0
114+
partition bounds cache | 5
115+
partition dispatch cache | 1
116+
partition parents cache | 5
117+
(4 rows)
118+
119+
/* change column's type (should flush caches) */
120+
ALTER TABLE test_column_type.test ALTER val TYPE NUMERIC;
121+
/* make sure that everything works properly */
122+
SELECT * FROM test_column_type.test;
123+
id | val
124+
----+-----
125+
(0 rows)
126+
127+
SELECT context, entries FROM pathman_cache_stats ORDER BY context;
128+
context | entries
129+
--------------------------+---------
130+
maintenance | 0
131+
partition bounds cache | 5
132+
partition dispatch cache | 1
133+
partition parents cache | 5
134+
(4 rows)
135+
136+
/* check insert dispatching */
137+
INSERT INTO test_column_type.test VALUES (1);
138+
SELECT tableoid::regclass, * FROM test_column_type.test;
139+
tableoid | id | val
140+
-------------------------+----+-----
141+
test_column_type.test_0 | 1 |
142+
(1 row)
143+
144+
SELECT drop_partitions('test_column_type.test');
145+
NOTICE: function test_column_type.test_upd_trig_func() does not exist, skipping
146+
NOTICE: 1 rows copied from test_column_type.test_0
147+
NOTICE: 0 rows copied from test_column_type.test_1
148+
NOTICE: 0 rows copied from test_column_type.test_2
149+
NOTICE: 0 rows copied from test_column_type.test_3
150+
NOTICE: 0 rows copied from test_column_type.test_4
151+
drop_partitions
152+
-----------------
153+
5
154+
(1 row)
155+
156+
DROP TABLE test_column_type.test CASCADE;
54157
DROP SCHEMA test_column_type CASCADE;
55-
NOTICE: drop cascades to 12 other objects
158+
NOTICE: drop cascades to sequence test_column_type.test_seq
56159
DROP EXTENSION pg_pathman;

sql/pathman_column_type.sql

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ CREATE EXTENSION pg_pathman;
55
CREATE SCHEMA test_column_type;
66

77

8+
/*
9+
* RANGE partitioning.
10+
*/
11+
812
/* create new table (val int) */
913
CREATE TABLE test_column_type.test(val INT4 NOT NULL);
1014
SELECT create_range_partitions('test_column_type.test', 'val', 1, 10, 10);
@@ -24,6 +28,43 @@ SELECT context, entries FROM pathman_cache_stats ORDER BY context;
2428
INSERT INTO test_column_type.test VALUES (1);
2529
SELECT tableoid::regclass, * FROM test_column_type.test;
2630

31+
SELECT drop_partitions('test_column_type.test');
32+
DROP TABLE test_column_type.test CASCADE;
33+
34+
35+
/*
36+
* HASH partitioning.
37+
*/
38+
39+
/* create new table (id int, val int) */
40+
CREATE TABLE test_column_type.test(id INT4 NOT NULL, val INT4);
41+
SELECT create_hash_partitions('test_column_type.test', 'id', 5);
42+
43+
/* make sure that bounds and dispatch info has been cached */
44+
SELECT * FROM test_column_type.test;
45+
SELECT context, entries FROM pathman_cache_stats ORDER BY context;
46+
47+
/* change column's type (should NOT work) */
48+
ALTER TABLE test_column_type.test ALTER id TYPE NUMERIC;
49+
50+
/* make sure that everything works properly */
51+
SELECT * FROM test_column_type.test;
52+
SELECT context, entries FROM pathman_cache_stats ORDER BY context;
53+
54+
/* change column's type (should flush caches) */
55+
ALTER TABLE test_column_type.test ALTER val TYPE NUMERIC;
56+
57+
/* make sure that everything works properly */
58+
SELECT * FROM test_column_type.test;
59+
SELECT context, entries FROM pathman_cache_stats ORDER BY context;
60+
61+
/* check insert dispatching */
62+
INSERT INTO test_column_type.test VALUES (1);
63+
SELECT tableoid::regclass, * FROM test_column_type.test;
64+
65+
SELECT drop_partitions('test_column_type.test');
66+
DROP TABLE test_column_type.test CASCADE;
67+
2768

2869
DROP SCHEMA test_column_type CASCADE;
2970
DROP EXTENSION pg_pathman;

src/hooks.c

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -712,8 +712,9 @@ pathman_process_utility_hook(Node *parsetree,
712712
{
713713
if (IsPathmanReady())
714714
{
715-
Oid partition_relid;
716-
AttrNumber partitioned_col;
715+
Oid relation_oid;
716+
PartType part_type;
717+
AttrNumber attr_number;
717718

718719
/* Override standard COPY statement if needed */
719720
if (is_pathman_related_copy(parsetree))
@@ -730,12 +731,25 @@ pathman_process_utility_hook(Node *parsetree,
730731
}
731732

732733
/* Override standard RENAME statement if needed */
733-
if (is_pathman_related_table_rename(parsetree,
734-
&partition_relid,
735-
&partitioned_col))
736-
PathmanRenameConstraint(partition_relid,
737-
partitioned_col,
734+
else if (is_pathman_related_table_rename(parsetree,
735+
&relation_oid,
736+
&attr_number))
737+
PathmanRenameConstraint(relation_oid,
738+
attr_number,
738739
(const RenameStmt *) parsetree);
740+
741+
/* Override standard ALTER COLUMN TYPE statement if needed */
742+
else if (is_pathman_related_alter_column_type(parsetree,
743+
&relation_oid,
744+
&attr_number,
745+
&part_type) &&
746+
part_type == PT_HASH)
747+
ereport(ERROR,
748+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
749+
errmsg("cannot change type of column \"%s\""
750+
" of table \"%s\" partitioned by HASH",
751+
get_attname(relation_oid, attr_number),
752+
get_rel_name(relation_oid))));
739753
}
740754

741755
/* Call hooks set by other extensions if needed */

src/include/utility_stmt_hooking.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
#define COPY_STMT_HOOKING_H
1414

1515

16+
#include "relation_info.h"
17+
1618
#include "postgres.h"
1719
#include "commands/copy.h"
1820
#include "nodes/nodes.h"
@@ -23,6 +25,10 @@ bool is_pathman_related_copy(Node *parsetree);
2325
bool is_pathman_related_table_rename(Node *parsetree,
2426
Oid *partition_relid_out,
2527
AttrNumber *partitioned_col_out);
28+
bool is_pathman_related_alter_column_type(Node *parsetree,
29+
Oid *parent_relid_out,
30+
AttrNumber *attr_number_out,
31+
PartType *part_type_out);
2632

2733
/* Statement handlers */
2834
void PathmanDoCopy(const CopyStmt *stmt, const char *queryString, uint64 *processed);

src/utility_stmt_hooking.c

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
#include "init.h"
1616
#include "utility_stmt_hooking.h"
1717
#include "partition_filter.h"
18-
#include "relation_info.h"
1918

2019
#include "access/htup_details.h"
2120
#include "access/sysattr.h"
@@ -179,6 +178,70 @@ is_pathman_related_table_rename(Node *parsetree,
179178
return false;
180179
}
181180

181+
/*
182+
* Is pg_pathman supposed to handle this ALTER COLUMN TYPE stmt?
183+
*/
184+
bool
185+
is_pathman_related_alter_column_type(Node *parsetree,
186+
Oid *parent_relid_out,
187+
AttrNumber *attr_number_out,
188+
PartType *part_type_out)
189+
{
190+
AlterTableStmt *alter_table_stmt = (AlterTableStmt *) parsetree;
191+
ListCell *lc;
192+
Oid parent_relid;
193+
const PartRelationInfo *prel;
194+
195+
Assert(IsPathmanReady());
196+
197+
if (!IsA(alter_table_stmt, AlterTableStmt))
198+
return false;
199+
200+
/* Are we going to modify some table? */
201+
if (alter_table_stmt->relkind != OBJECT_TABLE)
202+
return false;
203+
204+
/* Assume it's a parent, fetch its Oid */
205+
parent_relid = RangeVarGetRelid(alter_table_stmt->relation,
206+
AccessShareLock,
207+
false);
208+
209+
/* Is parent partitioned? */
210+
if ((prel = get_pathman_relation_info(parent_relid)) != NULL)
211+
{
212+
/* Return 'parent_relid' and 'prel->parttype' */
213+
if (parent_relid_out) *parent_relid_out = parent_relid;
214+
if (part_type_out) *part_type_out = prel->parttype;
215+
}
216+
else return false;
217+
218+
/* Examine command list */
219+
foreach (lc, alter_table_stmt->cmds)
220+
{
221+
AlterTableCmd *alter_table_cmd = (AlterTableCmd *) lfirst(lc);
222+
223+
if (!IsA(alter_table_cmd, AlterTableCmd))
224+
continue;
225+
226+
/* Is it an ALTER COLUMN TYPE statement? */
227+
if (alter_table_cmd->subtype != AT_AlterColumnType)
228+
continue;
229+
230+
/* Is it a partitioned column? */
231+
if (get_attnum(parent_relid, alter_table_cmd->name) != prel->attnum)
232+
continue;
233+
234+
/* Return 'prel->attnum' */
235+
if (attr_number_out) *attr_number_out = prel->attnum;
236+
237+
/* Success! */
238+
return true;
239+
}
240+
241+
/* Default failure */
242+
return false;
243+
}
244+
182245

183246
/*
184247
* CopyGetAttnums - build an integer list of attnums to be copied

0 commit comments

Comments
 (0)