Skip to content

Commit 13762aa

Browse files
committed
Add fallback relation for COPY
1 parent 64b78a5 commit 13762aa

10 files changed

+194
-35
lines changed

expected/pathman_utility_stmt.out

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,8 +279,30 @@ SELECT COUNT(*) FROM copy_stmt_hooking.test2;
279279
1
280280
(1 row)
281281

282+
/* check fallback relation for NULLs */
283+
COPY copy_stmt_hooking.test2(t) FROM stdin;
284+
ERROR: partitioning expression's value should not be NULL
285+
SET pg_pathman.enable_fallback_relation=ON;
286+
COPY copy_stmt_hooking.test2(t) FROM stdin;
287+
ERROR: null value in column "t" violates not-null constraint
288+
ALTER TABLE copy_stmt_hooking.test2 ALTER COLUMN t DROP NOT NULL;
289+
COPY copy_stmt_hooking.test2(t) FROM stdin;
290+
SELECT * FROM copy_stmt_hooking.pathman_test2_fallback;
291+
b | t
292+
---+---
293+
|
294+
(1 row)
295+
296+
SET pg_pathman.fallback_relation_name='fallbacks';
297+
COPY copy_stmt_hooking.test2(t) FROM stdin;
298+
SELECT * FROM copy_stmt_hooking.fallbacks;
299+
b | t
300+
---+---
301+
|
302+
(1 row)
303+
282304
DROP SCHEMA copy_stmt_hooking CASCADE;
283-
NOTICE: drop cascades to 797 other objects
305+
NOTICE: drop cascades to 823 other objects
284306
/*
285307
* Test auto check constraint renaming
286308
*/

sql/pathman_utility_stmt.sql

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,33 @@ COPY copy_stmt_hooking.test2(t) FROM stdin;
158158
\.
159159
SELECT COUNT(*) FROM copy_stmt_hooking.test2;
160160

161+
/* check fallback relation for NULLs */
162+
COPY copy_stmt_hooking.test2(t) FROM stdin;
163+
2017-02-02 20:00:00
164+
\N
165+
2017-02-02 20:00:00
166+
\.
167+
SET pg_pathman.enable_fallback_relation=ON;
168+
COPY copy_stmt_hooking.test2(t) FROM stdin;
169+
2017-02-02 20:00:00
170+
\N
171+
2017-02-02 20:00:00
172+
\.
173+
ALTER TABLE copy_stmt_hooking.test2 ALTER COLUMN t DROP NOT NULL;
174+
COPY copy_stmt_hooking.test2(t) FROM stdin;
175+
2017-02-02 20:00:00
176+
\N
177+
2017-02-02 20:00:00
178+
\.
179+
SELECT * FROM copy_stmt_hooking.pathman_test2_fallback;
180+
SET pg_pathman.fallback_relation_name='fallbacks';
181+
COPY copy_stmt_hooking.test2(t) FROM stdin;
182+
2017-02-03 20:00:00
183+
\N
184+
2017-02-03 20:00:00
185+
\.
186+
SELECT * FROM copy_stmt_hooking.fallbacks;
187+
161188
DROP SCHEMA copy_stmt_hooking CASCADE;
162189

163190

src/include/partition_creation.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,14 @@ Oid create_single_hash_partition_internal(Oid parent_relid,
4343
RangeVar *partition_rv,
4444
char *tablespace);
4545

46+
/*
47+
* Create one partition. Also used to created parent like tables
48+
* without any inheritance.
49+
*/
50+
Oid create_single_partition_internal(Oid parent_relid,
51+
RangeVar *partition_rv,
52+
char *tablespace,
53+
bool inherit_parent);
4654

4755
/* RANGE constraints */
4856
Constraint * build_range_check_constraint(Oid child_relid,

src/include/partition_filter.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ typedef struct
103103

104104
extern bool pg_pathman_enable_partition_filter;
105105
extern int pg_pathman_insert_into_fdw;
106+
extern bool pg_pathman_enable_fallback_relation;
106107

107108
extern CustomScanMethods partition_filter_plan_methods;
108109
extern CustomExecMethods partition_filter_exec_methods;
@@ -138,6 +139,9 @@ ResultRelInfoHolder * select_partition_for_insert(Datum value, Oid value_type,
138139
ResultPartsStorage *parts_storage,
139140
EState *estate);
140141

142+
ResultRelInfoHolder * get_relation_for_fallback(const PartRelationInfo *prel,
143+
ResultPartsStorage *parts_storage,
144+
EState *estate);
141145

142146
Plan * make_partition_filter(Plan *subplan,
143147
Oid parent_relid,

src/include/pathman.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,9 +115,10 @@ Index append_child_relation(PlannerInfo *root,
115115

116116

117117
/*
118-
* Copied from PostgreSQL (prepunion.c)
118+
* Copied from PostgreSQL (prepunion.c, make_inh_translation_list)
119+
* 'attinhcount' checks were removed
119120
*/
120-
void make_inh_translation_list(Relation oldrelation, Relation newrelation,
121+
void make_translation_list(Relation oldrelation, Relation newrelation,
121122
Index newvarno, List **translated_vars);
122123

123124
Bitmapset *translate_col_privs(const Bitmapset *parent_privs,

src/include/utility_stmt_hooking.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
#include "commands/copy.h"
2020
#include "nodes/nodes.h"
2121

22-
2322
/* Various traits */
2423
bool is_pathman_related_copy(Node *parsetree);
2524
bool is_pathman_related_table_rename(Node *parsetree,

src/partition_creation.c

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,6 @@ static void create_single_partition_common(Oid parent_relid,
6363
init_callback_params *callback_params,
6464
List *trigger_columns);
6565

66-
static Oid create_single_partition_internal(Oid parent_relid,
67-
RangeVar *partition_rv,
68-
char *tablespace);
69-
7066
static char *choose_range_partition_name(Oid parent_relid, Oid parent_nsp);
7167
static char *choose_hash_partition_name(Oid parent_relid, uint32 part_idx);
7268

@@ -123,10 +119,11 @@ create_single_range_partition_internal(Oid parent_relid,
123119
/* Check pathman config anld fill variables */
124120
expr = build_partitioning_expression(parent_relid, NULL, &trigger_columns);
125121

126-
/* Create a partition & get 'partitioning expression' */
122+
/* Create a partition */
127123
partition_relid = create_single_partition_internal(parent_relid,
128124
partition_rv,
129-
tablespace);
125+
tablespace,
126+
true);
130127

131128
/* Build check constraint for RANGE partition */
132129
check_constr = build_range_check_constraint(partition_relid,
@@ -179,12 +176,13 @@ create_single_hash_partition_internal(Oid parent_relid,
179176
partition_rv = makeRangeVar(parent_nsp_name, partition_name, -1);
180177
}
181178

182-
/* Create a partition & get 'partitionining expression' */
179+
/* Create a partition */
183180
partition_relid = create_single_partition_internal(parent_relid,
184181
partition_rv,
185-
tablespace);
182+
tablespace,
183+
true);
186184

187-
/* check pathman config and fill variables */
185+
/* Build an expression and get column used in expression for triggers */
188186
expr = build_partitioning_expression(parent_relid, &expr_type, &trigger_columns);
189187

190188
/* Build check constraint for HASH partition */
@@ -667,10 +665,11 @@ choose_hash_partition_name(Oid parent_relid, uint32 part_idx)
667665
}
668666

669667
/* Create a partition-like table (no constraints yet) */
670-
static Oid
668+
Oid
671669
create_single_partition_internal(Oid parent_relid,
672670
RangeVar *partition_rv,
673-
char *tablespace)
671+
char *tablespace,
672+
bool inherit_parent)
674673
{
675674
/* Value to be returned */
676675
Oid partition_relid = InvalidOid; /* safety */
@@ -739,14 +738,15 @@ create_single_partition_internal(Oid parent_relid,
739738
NodeSetTag(&like_clause, T_TableLikeClause);
740739
like_clause.relation = copyObject(parent_rv);
741740
like_clause.options = CREATE_TABLE_LIKE_DEFAULTS |
742-
CREATE_TABLE_LIKE_INDEXES |
743741
CREATE_TABLE_LIKE_STORAGE;
742+
if (inherit_parent)
743+
like_clause.options |= CREATE_TABLE_LIKE_INDEXES;
744744

745745
/* Initialize CreateStmt structure */
746746
NodeSetTag(&create_stmt, T_CreateStmt);
747747
create_stmt.relation = copyObject(partition_rv);
748748
create_stmt.tableElts = list_make1(copyObject(&like_clause));
749-
create_stmt.inhRelations = list_make1(copyObject(parent_rv));
749+
create_stmt.inhRelations = inherit_parent? list_make1(copyObject(parent_rv)) : NIL;
750750
create_stmt.ofTypename = NULL;
751751
create_stmt.constraints = NIL;
752752
create_stmt.options = NIL;
@@ -898,7 +898,7 @@ postprocess_child_table_and_atts(Oid parent_relid, Oid partition_relid)
898898
parent_rel = heap_open(parent_relid, NoLock);
899899
partition_rel = heap_open(partition_relid, NoLock);
900900

901-
make_inh_translation_list(parent_rel, partition_rel, 0, &translated_vars);
901+
make_translation_list(parent_rel, partition_rel, 0, &translated_vars);
902902

903903
heap_close(parent_rel, NoLock);
904904
heap_close(partition_rel, NoLock);

src/partition_filter.c

Lines changed: 96 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828

2929
#define ALLOC_EXP 2
30+
#define PARENT_NAME_FMT "{parent_table}"
3031

3132

3233
/*
@@ -64,6 +65,9 @@ static const struct config_enum_entry pg_pathman_insert_into_fdw_options[] = {
6465
bool pg_pathman_enable_partition_filter = true;
6566
int pg_pathman_insert_into_fdw = PF_FDW_INSERT_POSTGRES;
6667

68+
bool pg_pathman_enable_fallback_relation = true;
69+
char *pg_pathman_fallback_relation_name;
70+
6771
CustomScanMethods partition_filter_plan_methods;
6872
CustomExecMethods partition_filter_exec_methods;
6973

@@ -128,6 +132,25 @@ init_partition_filter_static_data(void)
128132
NULL,
129133
NULL,
130134
NULL);
135+
136+
DefineCustomBoolVariable("pg_pathman.enable_fallback_relation",
137+
"Enables fallback relation for COPY when partitioning key returns NULL",
138+
NULL,
139+
&pg_pathman_enable_fallback_relation,
140+
false,
141+
PGC_USERSET,
142+
0,
143+
NULL,
144+
NULL,
145+
NULL);
146+
147+
DefineCustomStringVariable("pg_pathman.fallback_relation_name",
148+
"Partition name for NULL tuples in COPY command",
149+
NULL,
150+
&pg_pathman_fallback_relation_name,
151+
"pathman_" PARENT_NAME_FMT "_fallback",
152+
PGC_SUSET, 0,
153+
NULL, NULL, NULL);
131154
}
132155

133156

@@ -270,9 +293,6 @@ scan_result_parts_storage(Oid partid, ResultPartsStorage *parts_storage)
270293
child_rel = heap_open(partid, NoLock);
271294
CheckValidResultRel(child_rel, parts_storage->command_type);
272295

273-
/* Build Var translation list for 'inserted_cols' */
274-
make_inh_translation_list(parent_rel, child_rel, 0, &translated_vars);
275-
276296
/* Create RangeTblEntry for partition */
277297
child_rte = makeNode(RangeTblEntry);
278298
child_rte->rtekind = RTE_RELATION;
@@ -281,6 +301,9 @@ scan_result_parts_storage(Oid partid, ResultPartsStorage *parts_storage)
281301
child_rte->eref = parent_rte->eref;
282302
child_rte->requiredPerms = parent_rte->requiredPerms;
283303
child_rte->checkAsUser = parent_rte->checkAsUser;
304+
305+
/* Build Var translation list for 'inserted_cols' */
306+
make_translation_list(parent_rel, child_rel, 0, &translated_vars);
284307
child_rte->insertedCols = translate_col_privs(parent_rte->insertedCols,
285308
translated_vars);
286309
child_rte->updatedCols = translate_col_privs(parent_rte->updatedCols,
@@ -473,6 +496,76 @@ select_partition_for_insert(Datum value, Oid value_type,
473496
return rri_holder;
474497
}
475498

499+
static char *
500+
get_fallback_relation_name(Oid parent_relid)
501+
{
502+
char *parent_name = get_rel_name(parent_relid),
503+
*s = pstrdup(pg_pathman_fallback_relation_name);
504+
StringInfoData str;
505+
char *pos;
506+
507+
initStringInfo(&str);
508+
509+
if (strstr(s, PARENT_NAME_FMT) != NULL)
510+
{
511+
while ((pos = strstr(s, PARENT_NAME_FMT)) != NULL)
512+
{
513+
int tmpl_len = strlen(PARENT_NAME_FMT);
514+
515+
appendBinaryStringInfo(&str, s, pos - s);
516+
appendBinaryStringInfo(&str, parent_name, strlen(parent_name));
517+
appendBinaryStringInfo(&str, pos + tmpl_len, strlen(s) - (pos - s) - tmpl_len);
518+
memset(s, 0, tmpl_len);
519+
}
520+
}
521+
else appendStringInfoString(&str, s);
522+
pfree(s);
523+
524+
return str.data;
525+
}
526+
527+
static Oid
528+
get_fallback_relation(Oid parent_relid)
529+
{
530+
char *name = get_fallback_relation_name(parent_relid);
531+
Oid result,
532+
nsp;
533+
534+
nsp = get_rel_namespace(parent_relid);
535+
result = get_relname_relid(name, nsp);
536+
if (result == InvalidOid)
537+
{
538+
RangeVar *rv;
539+
char *nspname = get_namespace_name(nsp);
540+
541+
rv = makeRangeVar(nspname, name, -1);
542+
result = create_single_partition_internal(parent_relid, rv, NULL, false);
543+
}
544+
545+
return result;
546+
}
547+
548+
/*
549+
* Return holder for fallback partition
550+
*/
551+
ResultRelInfoHolder *
552+
get_relation_for_fallback(const PartRelationInfo *prel,
553+
ResultPartsStorage *parts_storage,
554+
EState *estate)
555+
{
556+
MemoryContext old_mcxt;
557+
ResultRelInfoHolder *rri_holder;
558+
Oid parent_relid = PrelParentRelid(prel),
559+
fallback_relid;
560+
561+
/* Replace parent table with a suitable partition */
562+
old_mcxt = MemoryContextSwitchTo(estate->es_query_cxt);
563+
fallback_relid = get_fallback_relation(parent_relid);
564+
rri_holder = scan_result_parts_storage(fallback_relid, parts_storage);
565+
MemoryContextSwitchTo(old_mcxt);
566+
567+
return rri_holder;
568+
}
476569

477570
/*
478571
* --------------------------------

src/pg_pathman.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -470,7 +470,7 @@ append_child_relation(PlannerInfo *root,
470470
appinfo->parent_reltype = RelationGetDescr(parent_relation)->tdtypeid;
471471
appinfo->child_reltype = RelationGetDescr(child_relation)->tdtypeid;
472472

473-
make_inh_translation_list(parent_relation, child_relation, childRTindex,
473+
make_translation_list(parent_relation, child_relation, childRTindex,
474474
&appinfo->translated_vars);
475475

476476
/* Now append 'appinfo' to 'root->append_rel_list' */
@@ -1747,14 +1747,14 @@ translate_col_privs(const Bitmapset *parent_privs,
17471747

17481748

17491749
/*
1750-
* make_inh_translation_list
1750+
* make_translation_list
17511751
* Build the list of translations from parent Vars to child Vars for
17521752
* an inheritance child.
17531753
*
17541754
* For paranoia's sake, we match type/collation as well as attribute name.
17551755
*/
17561756
void
1757-
make_inh_translation_list(Relation oldrelation, Relation newrelation,
1757+
make_translation_list(Relation oldrelation, Relation newrelation,
17581758
Index newvarno, List **translated_vars)
17591759
{
17601760
List *vars = NIL;
@@ -1812,7 +1812,7 @@ make_inh_translation_list(Relation oldrelation, Relation newrelation,
18121812
*/
18131813
if (old_attno < newnatts &&
18141814
(att = new_tupdesc->attrs[old_attno]) != NULL &&
1815-
!att->attisdropped && att->attinhcount != 0 &&
1815+
!att->attisdropped &&
18161816
strcmp(attname, NameStr(att->attname)) == 0)
18171817
new_attno = old_attno;
18181818
else
@@ -1831,7 +1831,7 @@ make_inh_translation_list(Relation oldrelation, Relation newrelation,
18311831
elog(ERROR, "error in function "
18321832
CppAsString(make_inh_translation_list));
18331833

1834-
if (!att->attisdropped && att->attinhcount != 0 &&
1834+
if (!att->attisdropped &&
18351835
strcmp(attname, NameStr(att->attname)) == 0)
18361836
break;
18371837
}

0 commit comments

Comments
 (0)