Skip to content

Commit 84682ff

Browse files
committed
Add support for ALTER TABLE .. ATTACH PARTITION
1 parent 50c078b commit 84682ff

File tree

7 files changed

+324
-3
lines changed

7 files changed

+324
-3
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ OBJS = src/init.o src/relation_info.o src/utils.o src/partition_filter.o \
88
src/hooks.o src/nodes_common.o src/xact_handling.o src/utility_stmt_hooking.o \
99
src/planner_tree_modification.o src/debug_print.o src/partition_creation.o \
1010
src/compat/pg_compat.o src/compat/rowmarks_fix.o src/partition_router.o \
11-
src/partition_overseer.o $(WIN32RES)
11+
src/partition_overseer.o src/declarative.o $(WIN32RES)
1212

1313
ifdef USE_PGXS
1414
override PG_CPPFLAGS += -I$(CURDIR)/src/include

src/declarative.c

Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
#include "declarative.h"
2+
#include "utils.h"
3+
4+
#include "fmgr.h"
5+
#include "access/htup_details.h"
6+
#include "catalog/namespace.h"
7+
#include "catalog/pg_type.h"
8+
#include "catalog/pg_proc.h"
9+
#include "nodes/nodeFuncs.h"
10+
#include "parser/parse_func.h"
11+
#include "parser/parse_coerce.h"
12+
#include "utils/int8.h"
13+
#include "utils/lsyscache.h"
14+
#include "utils/builtins.h"
15+
#include "utils/int8.h"
16+
#include "utils/lsyscache.h"
17+
#include "utils/syscache.h"
18+
#include "utils/varbit.h"
19+
20+
/*
21+
* Modifies query of declarative partitioning commands,
22+
* There is a little hack here, ATTACH PARTITION command
23+
* expects relation with REL_PARTITIONED_TABLE relkind.
24+
* To avoid this check we negate subtype, and then after the checks
25+
* we set it back (look `is_pathman_related_partitioning_cmd`)
26+
*/
27+
void
28+
modify_declative_partitioning_query(Query *query)
29+
{
30+
if (query->commandType != CMD_UTILITY)
31+
return;
32+
33+
if (IsA(query->utilityStmt, AlterTableStmt))
34+
{
35+
ListCell *lcmd;
36+
Oid relid;
37+
38+
AlterTableStmt *stmt = (AlterTableStmt *) query->utilityStmt;
39+
relid = RangeVarGetRelid(stmt->relation, NoLock, true);
40+
if (get_pathman_relation_info(relid) != NULL)
41+
{
42+
foreach(lcmd, stmt->cmds)
43+
{
44+
AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
45+
switch (cmd->subtype)
46+
{
47+
case AT_AttachPartition:
48+
case AT_DetachPartition:
49+
cmd->subtype = -cmd->subtype;
50+
break;
51+
default:
52+
break;
53+
}
54+
}
55+
}
56+
}
57+
}
58+
59+
/* is it one of declarative partitioning commands? */
60+
bool is_pathman_related_partitioning_cmd(Node *parsetree)
61+
{
62+
if (IsA(parsetree, AlterTableStmt))
63+
{
64+
ListCell *lc;
65+
AlterTableStmt *stmt = (AlterTableStmt *) parsetree;
66+
int cnt = 0;
67+
68+
foreach(lc, stmt->cmds)
69+
{
70+
AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lc);
71+
int subtype = cmd->subtype;
72+
73+
if (subtype < 0)
74+
subtype = -subtype;
75+
76+
switch (subtype)
77+
{
78+
case AT_AttachPartition:
79+
case AT_DetachPartition:
80+
/*
81+
* we need to fix all subtypes,
82+
* possibly we're not going to handle this
83+
*/
84+
cmd->subtype = -(cmd->subtype);
85+
continue;
86+
default:
87+
cnt++;
88+
}
89+
}
90+
91+
return (cnt == 0);
92+
}
93+
return false;
94+
}
95+
96+
static FuncExpr *
97+
make_fn_expr(Oid funcOid, List *args)
98+
{
99+
FuncExpr *fn_expr;
100+
HeapTuple procTup;
101+
Form_pg_proc procStruct;
102+
103+
procTup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcOid));
104+
if (!HeapTupleIsValid(procTup))
105+
elog(ERROR, "cache lookup failed for function %u", funcOid);
106+
procStruct = (Form_pg_proc) GETSTRUCT(procTup);
107+
108+
fn_expr = makeFuncExpr(funcOid, procStruct->prorettype, args,
109+
InvalidOid, InvalidOid, COERCE_EXPLICIT_CALL);
110+
ReleaseSysCache(procTup);
111+
return fn_expr;
112+
}
113+
114+
/*
115+
* Transform one constant in a partition bound spec
116+
*/
117+
static Const *
118+
transform_bound_value(ParseState *pstate, A_Const *con,
119+
Oid colType, int32 colTypmod)
120+
{
121+
Node *value;
122+
123+
/* Make it into a Const */
124+
value = (Node *) make_const(pstate, &con->val, con->location);
125+
126+
/* Coerce to correct type */
127+
value = coerce_to_target_type(pstate,
128+
value, exprType(value),
129+
colType,
130+
colTypmod,
131+
COERCION_ASSIGNMENT,
132+
COERCE_IMPLICIT_CAST,
133+
-1);
134+
135+
if (value == NULL)
136+
ereport(ERROR,
137+
(errcode(ERRCODE_DATATYPE_MISMATCH),
138+
errmsg("specified value cannot be cast to type %s",
139+
format_type_be(colType)),
140+
parser_errposition(pstate, con->location)));
141+
142+
/* Simplify the expression, in case we had a coercion */
143+
if (!IsA(value, Const))
144+
value = (Node *) expression_planner((Expr *) value);
145+
146+
/* Fail if we don't have a constant (i.e., non-immutable coercion) */
147+
if (!IsA(value, Const))
148+
ereport(ERROR,
149+
(errcode(ERRCODE_DATATYPE_MISMATCH),
150+
errmsg("specified value cannot be cast to type %s",
151+
format_type_be(colType)),
152+
errdetail("The cast requires a non-immutable conversion."),
153+
errhint("Try putting the literal value in single quotes."),
154+
parser_errposition(pstate, con->location)));
155+
156+
return (Const *) value;
157+
}
158+
159+
/* handle ALTER TABLE .. ATTACH PARTITION command */
160+
void handle_attach_partition(AlterTableStmt *stmt, AlterTableCmd *cmd)
161+
{
162+
Oid parent_relid,
163+
partition_relid,
164+
proc_args[] = { REGCLASSOID, REGCLASSOID,
165+
ANYELEMENTOID, ANYELEMENTOID };
166+
167+
List *proc_name;
168+
FmgrInfo proc_flinfo;
169+
FunctionCallInfoData proc_fcinfo;
170+
char *pathman_schema;
171+
PartitionRangeDatum *ldatum,
172+
*rdatum;
173+
Const *lval,
174+
*rval;
175+
A_Const *con;
176+
List *fn_args;
177+
ParseState *pstate = make_parsestate(NULL);
178+
const PartRelationInfo *prel;
179+
180+
PartitionCmd *pcmd = (PartitionCmd *) cmd->def;
181+
182+
Assert(cmd->subtype == AT_AttachPartition);
183+
184+
parent_relid = RangeVarGetRelid(stmt->relation, NoLock, false);
185+
if ((prel = get_pathman_relation_info(parent_relid)) == NULL)
186+
elog(ERROR, "relation is not partitioned");
187+
188+
partition_relid = RangeVarGetRelid(pcmd->name, NoLock, false);
189+
190+
/* Fetch pg_pathman's schema */
191+
pathman_schema = get_namespace_name(get_pathman_schema());
192+
193+
/* Build function's name */
194+
proc_name = list_make2(makeString(pathman_schema),
195+
makeString(CppAsString(attach_range_partition)));
196+
197+
ldatum = (PartitionRangeDatum *) linitial(pcmd->bound->lowerdatums);
198+
con = castNode(A_Const, ldatum->value);
199+
lval = transform_bound_value(pstate, con, prel->ev_type, prel->ev_typmod);
200+
201+
rdatum = (PartitionRangeDatum *) linitial(pcmd->bound->upperdatums);
202+
con = castNode(A_Const, rdatum->value);
203+
rval = transform_bound_value(pstate, con, prel->ev_type, prel->ev_typmod);
204+
205+
/* Lookup function's Oid and get FmgrInfo */
206+
fmgr_info(LookupFuncName(proc_name, 4, proc_args, false), &proc_flinfo);
207+
208+
InitFunctionCallInfoData(proc_fcinfo, &proc_flinfo,
209+
4, InvalidOid, NULL, NULL);
210+
proc_fcinfo.arg[0] = ObjectIdGetDatum(parent_relid);
211+
proc_fcinfo.argnull[0] = false;
212+
proc_fcinfo.arg[1] = ObjectIdGetDatum(partition_relid);
213+
proc_fcinfo.argnull[1] = false;
214+
215+
/* Make function expression, we will need it to determine argument types */
216+
fn_args = list_make4(NULL, NULL, lval, rval);
217+
proc_fcinfo.flinfo->fn_expr =
218+
(Node *) make_fn_expr(proc_fcinfo.flinfo->fn_oid, fn_args);
219+
220+
if ((!list_length(pcmd->bound->lowerdatums)) ||
221+
(!list_length(pcmd->bound->upperdatums)))
222+
elog(ERROR, "provide start and end value for range partition");
223+
224+
proc_fcinfo.arg[2] = lval->constvalue;
225+
proc_fcinfo.argnull[2] = ldatum->infinite || lval->constisnull;
226+
proc_fcinfo.arg[3] = rval->constvalue;
227+
proc_fcinfo.argnull[3] = rdatum->infinite || rval->constisnull;
228+
229+
/* Invoke the callback */
230+
FunctionCallInvoke(&proc_fcinfo);
231+
}
232+
233+
/* handle ALTER TABLE .. DETACH PARTITION command */
234+
void handle_detach_partition(AlterTableStmt *stmt, AlterTableCmd *cmd)
235+
{
236+
Assert(cmd->subtype == AT_DetachPartition);
237+
}

src/hooks.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "compat/pg_compat.h"
1414
#include "compat/rowmarks_fix.h"
1515

16+
#include "declarative.h"
1617
#include "hooks.h"
1718
#include "init.h"
1819
#include "partition_filter.h"
@@ -766,6 +767,8 @@ pathman_post_parse_analyze_hook(ParseState *pstate, Query *query)
766767
{
767768
load_config(); /* perform main cache initialization */
768769
}
770+
if (!IsPathmanReady())
771+
return;
769772

770773
/* Process inlined SQL functions (we've already entered planning stage) */
771774
if (IsPathmanReady() && get_planner_calls_count() > 0)
@@ -812,7 +815,10 @@ pathman_post_parse_analyze_hook(ParseState *pstate, Query *query)
812815

813816
/* Modify query tree if needed */
814817
pathman_transform_query(query, NULL);
818+
return;
815819
}
820+
821+
pathman_post_analyze_query(query);
816822
}
817823

818824
/*
@@ -950,6 +956,31 @@ pathman_process_utility_hook(Node *first_arg,
950956
get_attname_compat(relation_oid, attr_number),
951957
get_rel_name(relation_oid))));
952958
}
959+
else if (is_pathman_related_partitioning_cmd(parsetree))
960+
{
961+
/* we can handle all the partitioning commands */
962+
if (IsA(parsetree, AlterTableStmt))
963+
{
964+
ListCell *lc;
965+
AlterTableStmt *stmt = (AlterTableStmt *) parsetree;
966+
967+
foreach(lc, stmt->cmds)
968+
{
969+
AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lc);
970+
switch (cmd->subtype)
971+
{
972+
case AT_AttachPartition:
973+
handle_attach_partition(stmt, cmd);
974+
return;
975+
case AT_DetachPartition:
976+
handle_detach_partition(stmt, cmd);
977+
return;
978+
default:
979+
elog(ERROR, "can't handle this command");
980+
}
981+
}
982+
}
983+
}
953984
}
954985

955986
/* Finally call process_utility_hook_next or standard_ProcessUtility */

src/include/declarative.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#ifndef DECLARATIVE_H
2+
#define DECLARATIVE_H
3+
4+
#include "postgres.h"
5+
#include "nodes/nodes.h"
6+
#include "nodes/parsenodes.h"
7+
8+
typedef enum DeclarativeCommandType {
9+
DP_ATTACH, /* ALTER TABLE .. ATTACH PARTITION */
10+
DP_DETACH /* ALTER TABLE .. DETACH PARTITION */
11+
} DeclarativeCommandType;
12+
13+
void modify_declative_partitioning_query(Query *query);
14+
bool is_pathman_related_partitioning_cmd(Node *parsetree);
15+
16+
/* actual actions */
17+
void handle_attach_partition(AlterTableStmt *stmt, AlterTableCmd *cmd);
18+
void handle_detach_partition(AlterTableStmt *stmt, AlterTableCmd *cmd);
19+
20+
#endif /* DECLARATIVE_H */

src/include/planner_tree_modification.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,9 @@ void state_tree_visitor(PlanState *state,
3434
void (*visitor) (PlanState *state, void *context),
3535
void *context);
3636

37-
/* Query tree rewriting utility */
37+
/* Query tree rewriting utilities */
3838
void pathman_transform_query(Query *parse, ParamListInfo params);
39+
void pathman_post_analyze_query(Query *parse);
3940

4041
/* These functions scribble on Plan tree */
4142
Plan *add_partition_filters(List *rtable, Plan *plan);

src/planner_tree_modification.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#include "compat/rowmarks_fix.h"
1414

15+
#include "declarative.h"
1516
#include "partition_filter.h"
1617
#include "partition_router.h"
1718
#include "partition_overseer.h"
@@ -107,6 +108,7 @@ typedef struct
107108
} adjust_appendrel_varnos_cxt;
108109

109110
static bool pathman_transform_query_walker(Node *node, void *context);
111+
static bool pathman_post_analyze_query_walker(Node *node, void *context);
110112

111113
static void disable_standard_inheritance(Query *parse, transform_query_cxt *context);
112114
static void handle_modification_query(Query *parse, transform_query_cxt *context);
@@ -337,6 +339,12 @@ pathman_transform_query(Query *parse, ParamListInfo params)
337339
pathman_transform_query_walker((Node *) parse, (void *) &context);
338340
}
339341

342+
void
343+
pathman_post_analyze_query(Query *parse)
344+
{
345+
pathman_post_analyze_query_walker((Node *) parse, NULL);
346+
}
347+
340348
/* Walker for pathman_transform_query() */
341349
static bool
342350
pathman_transform_query_walker(Node *node, void *context)
@@ -410,6 +418,31 @@ pathman_transform_query_walker(Node *node, void *context)
410418
context);
411419
}
412420

421+
static bool
422+
pathman_post_analyze_query_walker(Node *node, void *context)
423+
{
424+
if (node == NULL)
425+
return false;
426+
427+
else if (IsA(node, Query))
428+
{
429+
Query *query = (Query *) node;
430+
431+
/* Make changes for declarative syntax */
432+
modify_declative_partitioning_query(query);
433+
434+
/* Handle Query node */
435+
return query_tree_walker(query,
436+
pathman_post_analyze_query_walker,
437+
context,
438+
0);
439+
}
440+
441+
/* Handle expression subtree */
442+
return expression_tree_walker(node,
443+
pathman_post_analyze_query_walker,
444+
context);
445+
}
413446

414447
/*
415448
* ----------------------

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