Skip to content

Commit 6290f6b

Browse files
committed
added ALTER TABLE ... PARTITION BY clause which partitions existing table
1 parent 47f8fbe commit 6290f6b

File tree

10 files changed

+185
-115
lines changed

10 files changed

+185
-115
lines changed

src/backend/commands/partition.c

Lines changed: 91 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,11 @@
2929
#include "utils/lsyscache.h"
3030

3131

32-
static void create_hash_partitions(CreateStmt *stmt, Oid relid, const char* attname);
33-
static void create_range_partitions(CreateStmt *stmt, Oid relid, const char *attname);
32+
static void create_hash_partitions(PartitionInfo *pinfo,
33+
Oid relid,
34+
const char* attname,
35+
bool partition_data);
36+
static void create_range_partitions(PartitionInfo *pinfo, Oid relid, const char *attname, bool partition_data);
3437
static Node *cookPartitionKeyValue(Oid relid, const char *raw, Node *raw_value);
3538
static char *RangeVarGetString(const RangeVar *rangevar);
3639
static Oid RangeVarGetNamespaceId(const RangeVar *rangevar);
@@ -40,9 +43,8 @@ static Oid RangeVarGetNamespaceId(const RangeVar *rangevar);
4043

4144

4245
void
43-
create_partitions(CreateStmt *stmt, Oid relid)
46+
create_partitions(PartitionInfo *pinfo, Oid relid, bool partition_data)
4447
{
45-
PartitionInfo *pinfo = (PartitionInfo *) stmt->partition_info;
4648
Value *attname = (Value *) linitial(((ColumnRef *) pinfo->key)->fields);
4749

4850
if (SPI_connect() != SPI_OK_CONNECT)
@@ -52,12 +54,12 @@ create_partitions(CreateStmt *stmt, Oid relid)
5254
{
5355
case P_HASH:
5456
{
55-
create_hash_partitions(stmt, relid, strVal(attname));
57+
create_hash_partitions(pinfo, relid, strVal(attname), partition_data);
5658
break;
5759
}
5860
case P_RANGE:
5961
{
60-
create_range_partitions(stmt, relid, strVal(attname));
62+
create_range_partitions(pinfo, relid, strVal(attname), partition_data);
6163
break;
6264
}
6365
}
@@ -67,11 +69,13 @@ create_partitions(CreateStmt *stmt, Oid relid)
6769

6870

6971
static void
70-
create_hash_partitions(CreateStmt *stmt, Oid relid, const char* attname)
72+
create_hash_partitions(PartitionInfo *pinfo,
73+
Oid relid,
74+
const char* attname,
75+
bool partition_data)
7176
{
72-
PartitionInfo *pinfo = (PartitionInfo *) stmt->partition_info;
73-
char **relnames = NULL;
74-
char **tablespaces = NULL;
77+
char **relnames = NULL;
78+
char **tablespaces = NULL;
7579

7680
if (list_length(pinfo->partitions) > 0)
7781
{
@@ -96,6 +100,7 @@ create_hash_partitions(CreateStmt *stmt, Oid relid, const char* attname)
96100
pm_create_hash_partitions(relid,
97101
attname,
98102
pinfo->partitions_count,
103+
partition_data,
99104
relnames,
100105
tablespaces);
101106

@@ -112,34 +117,34 @@ create_hash_partitions(CreateStmt *stmt, Oid relid, const char* attname)
112117
* and all partitions via pg_pathman's wrapper functions
113118
*/
114119
static void
115-
create_range_partitions(CreateStmt *stmt, Oid relid, const char *attname)
120+
create_range_partitions(PartitionInfo *pinfo,
121+
Oid relid,
122+
const char *attname,
123+
bool partition_data)
116124
{
117125
ListCell *lc;
118126
Datum last_bound = (Datum) 0;
119127
bool last_bound_is_null = true;
120-
PartitionInfo *pinfo = (PartitionInfo *) stmt->partition_info;
121128

122129
/* partitioning key */
123-
AttrNumber attnum = get_attnum(relid, attname);
124-
Oid atttype;
125-
int32 atttypmod;
130+
AttrNumber attnum = get_attnum(relid, attname);
131+
Oid atttype;
132+
int32 atttypmod;
133+
Datum start_value;
126134

127135
/* parameters */
128-
Datum interval_datum = (Datum) 0;
129-
Oid interval_type;
130-
131-
/* for parsing interval */
132-
Const *interval_const;
133-
ParseState *pstate = make_parsestate(NULL);
136+
Datum interval_datum = (Datum) 0;
137+
Oid interval_type;
138+
Const *interval_const;
139+
ParseState *pstate = make_parsestate(NULL);
134140

135141
if (!attnum)
136-
elog(ERROR,
137-
"Unknown attribute '%s'",
138-
attname);
142+
elog(ERROR, "Unknown attribute '%s'", attname);
143+
139144
atttype = get_atttype(relid, attnum);
140145
atttypmod = get_atttypmod(relid, attnum);
141146

142-
/* Convert interval to Const node */
147+
/* If interval is set then convert it to a suitable Datum value */
143148
if (pinfo->interval != NULL)
144149
{
145150
if (IsA(pinfo->interval, A_Const))
@@ -152,44 +157,75 @@ create_range_partitions(CreateStmt *stmt, Oid relid, const char *attname)
152157
else
153158
elog(ERROR, "Constant interval value is expected");
154159

155-
/* If attribute is of type DATE or TIMESTAMP then convert interval to Interval type */
156-
if (atttype == DATEOID || atttype == TIMESTAMPOID || atttype == TIMESTAMPTZOID)
160+
/*
161+
* If attribute is of type DATE or TIMESTAMP then convert interval to
162+
* Interval type
163+
*/
164+
switch (atttype)
157165
{
158-
char *interval_literal;
159-
160-
/* We should get an UNKNOWN type here */
161-
if (interval_const->consttype != UNKNOWNOID)
162-
elog(ERROR, "Expected a literal as an interval value");
163-
164-
/* Get a text representation of the interval */
165-
interval_literal = DatumGetCString(interval_const->constvalue);
166-
interval_datum = DirectFunctionCall3(interval_in,
167-
CStringGetDatum(interval_literal),
168-
ObjectIdGetDatum(InvalidOid),
169-
Int32GetDatum(-1));
170-
interval_type = INTERVALOID;
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;
171188
}
172-
else
189+
}
190+
else /* If interval is not set */
191+
{
192+
switch (atttype)
173193
{
174-
interval_datum = interval_const->constvalue;
175-
interval_type = interval_const->consttype;
194+
case DATEOID:
195+
case TIMESTAMPOID:
196+
case TIMESTAMPTZOID:
197+
interval_type = INTERVALOID;
198+
default:
199+
interval_type = atttype;
176200
}
177201
}
178-
else /* If interval is not set */
202+
203+
/*
204+
* Start value. It is always non-NULL whenever partition_data = True.
205+
* Otherwise the actual start value doesn't matter
206+
*/
207+
Assert( (pinfo->start_value != NULL) == partition_data );
208+
if (pinfo->start_value)
179209
{
180-
if (atttype == DATEOID || atttype == TIMESTAMPOID || atttype == TIMESTAMPTZOID)
181-
interval_type = INTERVALOID;
182-
else
183-
interval_type = atttype;
210+
Node *n = cookPartitionKeyValue(relid,
211+
attname,
212+
(Node *) pinfo->start_value);
213+
if (!IsA(n, Const))
214+
elog(ERROR, "Start value must be a constatnt");
215+
start_value = ((Const *) n)->constvalue;
184216
}
217+
else
218+
start_value = (Datum) 0;
185219

186220
/* Invoke pg_pathman's wrapper */
187221
pm_create_range_partitions(relid,
188222
attname,
189223
atttype,
224+
start_value,
190225
interval_datum,
191226
interval_type,
192-
pinfo->interval == NULL);
227+
pinfo->interval == NULL,
228+
partition_data);
193229

194230
/* Add partitions */
195231
foreach(lc, pinfo->partitions)
@@ -522,3 +558,9 @@ RangeVarGetNamespaceId(const RangeVar *rangevar)
522558

523559
return namespace_id;
524560
}
561+
562+
void
563+
partition_existing_table(Oid relid, AlterTableCmd *cmd)
564+
{
565+
566+
}

src/backend/commands/pathman_wrapper.c

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ get_pathman_schema(void)
153153

154154

155155
const char *
156-
get_pathman_schema_name()
156+
get_pathman_schema_name(void)
157157
{
158158
Oid schema_oid = get_pathman_schema();
159159

@@ -266,6 +266,7 @@ void
266266
pm_create_hash_partitions(Oid relid,
267267
const char *attname,
268268
uint32_t partitions_count,
269+
bool partition_data,
269270
char **relnames,
270271
char **tablespaces)
271272
{
@@ -276,7 +277,7 @@ pm_create_hash_partitions(Oid relid,
276277
PG_SETARG_DATUM(&args, 0, OIDOID, ObjectIdGetDatum(relid));
277278
PG_SETARG_DATUM(&args, 1, TEXTOID, CStringGetTextDatum(attname));
278279
PG_SETARG_DATUM(&args, 2, INT4OID, ObjectIdGetDatum(UInt32GetDatum(partitions_count)));
279-
PG_SETARG_DATUM(&args, 3, BOOLOID, BoolGetDatum(false));
280+
PG_SETARG_DATUM(&args, 3, BOOLOID, BoolGetDatum(partition_data));
280281

281282
if (relnames != NULL)
282283
PG_SETARG_DATUM(&args, 4, TEXTARRAYOID,
@@ -327,28 +328,39 @@ void
327328
pm_create_range_partitions(Oid relid,
328329
const char *attname,
329330
Oid atttype,
331+
Datum start_from,
330332
Datum interval,
331333
Oid interval_type,
332-
bool interval_isnull)
334+
bool interval_isnull,
335+
bool partition_data)
333336
{
334337
FuncArgs args;
335338
int ret;
336339

337-
InitFuncArgs(&args, 5);
340+
InitFuncArgs(&args, 6);
338341
PG_SETARG_DATUM(&args, 0, OIDOID, relid);
339342
PG_SETARG_DATUM(&args, 1, TEXTOID, PointerGetDatum(cstring_to_text(attname)));
340-
/* TODO: get value from first partition */
341-
PG_SETARG_DATUM(&args, 2, atttype, Int32GetDatum(0));
343+
PG_SETARG_DATUM(&args, 2, atttype, start_from);
342344

343345
if (!interval_isnull)
344346
PG_SETARG_DATUM(&args, 3, interval_type, interval);
345347
else
346348
PG_SETARG_NULL(&args, 3, interval_type);
347349

348-
/* Zero partitions */
349-
PG_SETARG_DATUM(&args, 4, INT4OID, Int32GetDatum(0));
350+
/*
351+
* If we want to migrate data right away then we need to prepopulate
352+
* partitions. In this case we set partitions count as NULL so that
353+
* pg_pathman would calculate it based on table data. Otherwise set
354+
* partitions count to zero assuming that new partitions will be added
355+
* explicitly by invoking pm_add_range_partition()
356+
*/
357+
if (partition_data)
358+
PG_SETARG_NULL(&args, 4, INT4OID);
359+
else
360+
PG_SETARG_DATUM(&args, 4, INT4OID, Int32GetDatum(0));
361+
PG_SETARG_DATUM(&args, 5, BOOLOID, BoolGetDatum(partition_data));
350362

351-
ret = pathman_invoke("create_range_partitions($1, $2, $3, $4, $5)", &args);
363+
ret = pathman_invoke("create_range_partitions($1, $2, $3, $4, $5, $6)", &args);
352364
FreeFuncArgs(&args);
353365

354366
if (!ret)

src/backend/commands/tablecmds.c

Lines changed: 6 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -723,40 +723,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
723723
/* Handle partitioning */
724724
if (stmt->partition_info)
725725
{
726-
(void) create_partitions(stmt, rel->rd_id);
727-
728-
// PartitionInfo *pinfo = (PartitionInfo *) stmt->partition_info;
729-
// // PartitionTable();
730-
// if (SPI_connect() != SPI_OK_CONNECT)
731-
// elog(ERROR, "could not connect using SPI");
732-
733-
734-
// // switch (pinfo->partition_type)
735-
// // {
736-
// // case PT_HASH:
737-
// // {
738-
// // // char *attname = ((ColumnRef *) pinfo->key)->fields;
739-
// // Value *attname = (Value *) linitial(((ColumnRef *) pinfo->key)->fields);
740-
// // int nargs = 3;
741-
// // Oid types[3] = {OIDOID, TEXTOID, INT4OID};
742-
// // Datum values[3] = {
743-
// // ObjectIdGetDatum(rel->rd_id),
744-
// // CStringGetTextDatum(strVal(attname)),
745-
// // UInt32GetDatum(pinfo->partitions_count)};
746-
747-
// // SPI_execute_with_args(
748-
// // "SELECT create_hash_partitions($1, $2, $3)",
749-
// // nargs, types, values, NULL, false, 0);
750-
// // // elog(ERROR, "HASH doesn't implemented yet");
751-
// // break;
752-
// // }
753-
// // case PT_RANGE:
754-
// // // SPI_exec("SELECT create_range_partitions()")
755-
// // elog(ERROR, "RANGE doesn't implemented yet");
756-
// // break;
757-
// // }
758-
759-
// SPI_finish(); /* close SPI connection */
726+
(void) create_partitions(stmt->partition_info, rel->rd_id, false);
760727
}
761728

762729
return address;
@@ -3106,6 +3073,7 @@ AlterTableGetLockLevel(List *cmds)
31063073
case AT_RenamePartition:
31073074
case AT_DropPartition:
31083075
case AT_MovePartition:
3076+
case AT_PartitionBy:
31093077
break;
31103078

31113079
default: /* oops */
@@ -3440,6 +3408,7 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
34403408
case AT_RenamePartition:
34413409
case AT_DropPartition:
34423410
case AT_MovePartition:
3411+
case AT_PartitionBy:
34433412
pass = AT_PASS_MISC;
34443413
break;
34453414

@@ -3783,6 +3752,9 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
37833752
case AT_MovePartition:
37843753
move_partition(rel->rd_id, cmd);
37853754
break;
3755+
case AT_PartitionBy:
3756+
create_partitions((PartitionInfo *) cmd->def, rel->rd_id, true);
3757+
break;
37863758
default: /* oops */
37873759
elog(ERROR, "unrecognized alter table type: %d",
37883760
(int) cmd->subtype);

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