Skip to content

Commit 687e6ca

Browse files
committed
[WIP] introduce 'partition_creation' subsystem
1 parent f603e6c commit 687e6ca

File tree

3 files changed

+268
-1
lines changed

3 files changed

+268
-1
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ OBJS = src/init.o src/relation_info.o src/utils.o src/partition_filter.o \
55
src/runtimeappend.o src/runtime_merge_append.o src/pg_pathman.o src/rangeset.o \
66
src/pl_funcs.o src/pl_range_funcs.o src/pl_hash_funcs.o src/pathman_workers.o \
77
src/hooks.o src/nodes_common.o src/xact_handling.o src/copy_stmt_hooking.o \
8-
src/pg_compat.o $(WIN32RES)
8+
src/partition_creation.o src/pg_compat.o $(WIN32RES)
99

1010
EXTENSION = pg_pathman
1111
EXTVERSION = 1.1

src/partition_creation.c

Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
#include "pathman.h"
2+
#include "init.h"
3+
#include "partition_creation.h"
4+
#include "relation_info.h"
5+
6+
#include "access/reloptions.h"
7+
#include "access/xact.h"
8+
#include "catalog/heap.h"
9+
#include "catalog/toasting.h"
10+
#include "commands/defrem.h"
11+
#include "commands/event_trigger.h"
12+
#include "commands/tablecmds.h"
13+
#include "nodes/makefuncs.h"
14+
#include "parser/parse_expr.h"
15+
#include "parser/parse_node.h"
16+
#include "parser/parse_relation.h"
17+
#include "utils/lsyscache.h"
18+
#include "utils/syscache.h"
19+
20+
21+
/* TODO: comment */
22+
Oid
23+
create_single_range_partition(Oid parent_relid,
24+
Datum start_value,
25+
Datum end_value,
26+
Oid value_type,
27+
RangeVar *partition_rv,
28+
char *tablespace)
29+
{
30+
CreateStmt create_stmt;
31+
ObjectAddress partition_addr;
32+
Oid child_relid;
33+
Relation child_relation;
34+
Datum toast_options;
35+
TableLikeClause like_clause;
36+
Constraint *check_constr;
37+
RangeVar *parent_rv;
38+
Oid parent_nsp;
39+
char *parent_name,
40+
*parent_nsp_name,
41+
partitioned_column;
42+
Datum config_values[Natts_pathman_config];
43+
bool config_nulls[Natts_pathman_config];
44+
static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
45+
46+
/* Lock parent and check if it exists */
47+
LockRelationOid(parent_relid, ShareUpdateExclusiveLock);
48+
if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(parent_relid)))
49+
elog(ERROR, "relation %u does not exist", parent_relid);
50+
51+
/* Check that table is registered in PATHMAN_CONFIG */
52+
if (!pathman_config_contains_relation(parent_relid,
53+
config_values, config_nulls, NULL))
54+
elog(ERROR, "table \"%s\" is not partitioned",
55+
get_rel_name_or_relid(parent_relid));
56+
57+
/* Cache parent's namespace and name */
58+
parent_name = get_rel_name(parent_relid);
59+
parent_nsp = get_rel_namespace(parent_relid);
60+
parent_nsp_name = get_namespace_name(parent_nsp);
61+
62+
/* Make up parent's RangeVar */
63+
parent_rv = makeRangeVar(parent_nsp_name, parent_name, -1);
64+
65+
/* Generate a name if asked to */
66+
if (!partition_rv)
67+
{
68+
char *part_name;
69+
70+
/* Make up a name for the partition */
71+
part_name = ChooseRelationName(parent_name, NULL, "part", parent_nsp);
72+
73+
/* Make RangeVar for the partition */
74+
partition_rv = makeRangeVar(parent_nsp_name, part_name, -1);
75+
}
76+
77+
/* Initialize TableLikeClause structure */
78+
NodeSetTag(&like_clause, T_TableLikeClause);
79+
like_clause.relation = copyObject(parent_rv);
80+
like_clause.options = CREATE_TABLE_LIKE_ALL;
81+
82+
/* Initialize CreateStmt structure */
83+
NodeSetTag(&create_stmt, T_CreateStmt);
84+
create_stmt.relation = copyObject(partition_rv);
85+
create_stmt.tableElts = list_make1(&like_clause);
86+
create_stmt.inhRelations = list_make1(copyObject(parent_rv));
87+
create_stmt.ofTypename = NULL;
88+
create_stmt.constraints = list_make1(&check_constr);
89+
create_stmt.options = NIL;
90+
create_stmt.oncommit = ONCOMMIT_NOOP;
91+
create_stmt.tablespacename = tablespace;
92+
create_stmt.if_not_exists = false;
93+
94+
/* Create new partition owned by parent's posessor */
95+
partition_addr = DefineRelation(&create_stmt, RELKIND_RELATION,
96+
get_rel_owner(parent_relid), NULL);
97+
98+
/* Save data about a simple DDL command that was just executed */
99+
EventTriggerCollectSimpleCommand(partition_addr,
100+
InvalidObjectAddress,
101+
(Node *) &create_stmt);
102+
103+
/* Save partition's Oid */
104+
child_relid = partition_addr.objectId;
105+
106+
/*
107+
* Let NewRelationCreateToastTable decide if this
108+
* one needs a secondary relation too.
109+
*/
110+
CommandCounterIncrement();
111+
112+
/* Parse and validate reloptions for the toast table */
113+
toast_options = transformRelOptions((Datum) 0, create_stmt.options,
114+
"toast", validnsps, true, false);
115+
116+
/* Parse options for a new toast table */
117+
(void) heap_reloptions(RELKIND_TOASTVALUE, toast_options, true);
118+
119+
/* Now create the toast table if needed */
120+
NewRelationCreateToastTable(child_relid, toast_options);
121+
122+
/* Update config one more time */
123+
CommandCounterIncrement();
124+
125+
/* Fetch partitioned column's name */
126+
partitioned_column = config_values[Anum_pathman_config_attname - 1];
127+
128+
/* Build check constraint for RANGE partition */
129+
check_constr = build_range_check_constraint(partitioned_column,
130+
start_value,
131+
end_value,
132+
value_type);
133+
134+
/* Open the relation and add new check constraint */
135+
child_relation = heap_openrv(partition_rv, AccessExclusiveLock);
136+
AddRelationNewConstraints(child_relation, NIL,
137+
list_make1(check_constr),
138+
false, true, true);
139+
heap_close(child_relation, NoLock);
140+
141+
/* Invoke init_callback on partition */
142+
invoke_init_callback(parent_relid, child_relid, InvalidOid,
143+
start_value, end_value, value_type);
144+
145+
return child_relid;
146+
}
147+
148+
Node *
149+
raw_range_check_tree(char *attname,
150+
Datum start_value,
151+
Datum end_value,
152+
Oid value_type)
153+
{
154+
BoolExpr *and_oper = makeNode(BoolExpr);
155+
A_Expr *left_arg = makeNode(A_Expr),
156+
*right_arg = makeNode(A_Expr);
157+
A_Const *left_const = makeNode(A_Const),
158+
*right_const = makeNode(A_Const);
159+
ColumnRef *col_ref = makeNode(ColumnRef);
160+
161+
/* Partitioned column */
162+
col_ref->fields = list_make1(makeString(attname));
163+
col_ref->location = -1;
164+
165+
/* Left boundary */
166+
left_const->val = *makeString(datum_to_cstring(start_value, value_type));
167+
left_const->location = -1;
168+
169+
/* Right boundary */
170+
right_const->val = *makeString(datum_to_cstring(end_value, value_type));
171+
right_const->location = -1;
172+
173+
/* Left comparison (VAR >= start_value) */
174+
left_arg->name = list_make1(makeString(">="));
175+
left_arg->kind = AEXPR_OP;
176+
left_arg->lexpr = (Node *) col_ref;
177+
left_arg->rexpr = (Node *) left_const;
178+
left_arg->location = -1;
179+
180+
/* Right comparision (VAR < end_value) */
181+
right_arg->name = list_make1(makeString("<"));
182+
right_arg->kind = AEXPR_OP;
183+
right_arg->lexpr = (Node *) col_ref;
184+
right_arg->rexpr = (Node *) right_const;
185+
right_arg->location = -1;
186+
187+
and_oper->boolop = AND_EXPR;
188+
and_oper->args = list_make2(left_arg, right_arg);
189+
and_oper->location = -1;
190+
191+
return (Node *) and_oper;
192+
}
193+
194+
Node *
195+
good_range_check_tree(RangeVar *partition,
196+
char *attname,
197+
Datum start_value,
198+
Datum end_value,
199+
Oid value_type)
200+
{
201+
ParseState *pstate = make_parsestate(NULL);
202+
RangeTblEntry *partition_rte;
203+
Node *expression,
204+
*raw_expression;
205+
ParseNamespaceItem pni;
206+
207+
/* Required for transformExpr() */
208+
partition_rte = addRangeTableEntry(pstate, partition, NULL, false, false);
209+
210+
memset((void *) &pni, 0, sizeof(ParseNamespaceItem));
211+
pni.p_rte = partition_rte;
212+
pni.p_rel_visible = true;
213+
pni.p_cols_visible = true;
214+
215+
pstate->p_namespace = list_make1(&pni);
216+
pstate->p_rtable = list_make1(partition_rte);
217+
218+
/* Transform raw check constraint expression into Constraint */
219+
raw_expression = raw_range_check_tree(attname, start_value, end_value, value_type);
220+
expression = transformExpr(pstate, raw_expression, EXPR_KIND_CHECK_CONSTRAINT);
221+
222+
return (Node *) expression;
223+
}
224+
225+
Constraint *
226+
build_range_check_constraint(char *attname,
227+
Datum start_value,
228+
Datum end_value,
229+
Oid value_type)
230+
{
231+
Constraint *range_constr;
232+
233+
range_constr = makeNode(Constraint);
234+
range_constr->conname = NULL;
235+
range_constr->deferrable = false;
236+
range_constr->initdeferred = false;
237+
range_constr->location = -1;
238+
range_constr->contype = CONSTR_CHECK;
239+
range_constr->is_no_inherit = true;
240+
241+
range_constr->raw_expr = raw_range_check_tree(attname,
242+
start_value,
243+
end_value,
244+
value_type);
245+
246+
return range_constr;
247+
}
248+
249+
/* TODO: comment */
250+
void
251+
invoke_init_callback(Oid parent_relid,
252+
Oid child_relid,
253+
Oid init_callback,
254+
Datum start_value,
255+
Datum end_value,
256+
Oid value_type)
257+
{
258+
259+
}

src/partition_creation.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
2+
#include "postgres.h"
3+
#include "nodes/parsenodes.h"
4+
5+
Constraint *build_range_check_constraint(char *attname,
6+
Datum start_value,
7+
Datum end_value,
8+
Oid value_type);

0 commit comments

Comments
 (0)