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)
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