Skip to content

Commit ee9ccbc

Browse files
committed
improve type handling in function spawn_partitions_val() (issue #65)
1 parent 4827d9f commit ee9ccbc

File tree

4 files changed

+126
-19
lines changed

4 files changed

+126
-19
lines changed

expected/pathman_basic.out

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,51 @@ SELECT count(*) FROM test.insert_into_select_copy;
320320

321321
DROP TABLE test.insert_into_select_copy, test.insert_into_select CASCADE;
322322
NOTICE: drop cascades to 5 other objects
323+
/* Test INSERT hooking with DATE type */
324+
CREATE TABLE test.insert_date_test(val DATE NOT NULL);
325+
SELECT pathman.create_partitions_from_range('test.insert_date_test', 'val',
326+
date '20161001', date '20170101', interval '1 month');
327+
NOTICE: sequence "insert_date_test_seq" does not exist, skipping
328+
create_partitions_from_range
329+
------------------------------
330+
4
331+
(1 row)
332+
333+
INSERT INTO test.insert_date_test VALUES ('20161201'); /* just insert the date */
334+
SELECT count(*) FROM pathman.pathman_partition_list WHERE parent = 'test.insert_date_test'::REGCLASS;
335+
count
336+
-------
337+
4
338+
(1 row)
339+
340+
INSERT INTO test.insert_date_test VALUES ('20170311'); /* append new partitions */
341+
SELECT count(*) FROM pathman.pathman_partition_list WHERE parent = 'test.insert_date_test'::REGCLASS;
342+
count
343+
-------
344+
6
345+
(1 row)
346+
347+
INSERT INTO test.insert_date_test VALUES ('20160812'); /* prepend new partitions */
348+
SELECT count(*) FROM pathman.pathman_partition_list WHERE parent = 'test.insert_date_test'::REGCLASS;
349+
count
350+
-------
351+
8
352+
(1 row)
353+
354+
SELECT min(val) FROM test.insert_date_test; /* check first date */
355+
min
356+
------------
357+
08-12-2016
358+
(1 row)
359+
360+
SELECT max(val) FROM test.insert_date_test; /* check last date */
361+
max
362+
------------
363+
03-11-2017
364+
(1 row)
365+
366+
DROP TABLE test.insert_date_test CASCADE;
367+
NOTICE: drop cascades to 8 other objects
323368
/* Test special case: ONLY statement with not-ONLY for partitioned table */
324369
CREATE TABLE test.from_only_test(val INT NOT NULL);
325370
INSERT INTO test.from_only_test SELECT generate_series(1, 20);
@@ -1982,6 +2027,6 @@ EXPLAIN (COSTS OFF) SELECT * FROM test.index_on_childs WHERE c1 > 100 AND c1 < 2
19822027
(12 rows)
19832028

19842029
DROP SCHEMA test CASCADE;
1985-
NOTICE: drop cascades to 48 other objects
2030+
NOTICE: drop cascades to 49 other objects
19862031
DROP EXTENSION pg_pathman CASCADE;
19872032
DROP SCHEMA pathman CASCADE;

sql/pathman_basic.sql

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,26 @@ SELECT count(*) FROM test.insert_into_select_copy;
101101
DROP TABLE test.insert_into_select_copy, test.insert_into_select CASCADE;
102102

103103

104+
/* Test INSERT hooking with DATE type */
105+
CREATE TABLE test.insert_date_test(val DATE NOT NULL);
106+
SELECT pathman.create_partitions_from_range('test.insert_date_test', 'val',
107+
date '20161001', date '20170101', interval '1 month');
108+
109+
INSERT INTO test.insert_date_test VALUES ('20161201'); /* just insert the date */
110+
SELECT count(*) FROM pathman.pathman_partition_list WHERE parent = 'test.insert_date_test'::REGCLASS;
111+
112+
INSERT INTO test.insert_date_test VALUES ('20170311'); /* append new partitions */
113+
SELECT count(*) FROM pathman.pathman_partition_list WHERE parent = 'test.insert_date_test'::REGCLASS;
114+
115+
INSERT INTO test.insert_date_test VALUES ('20160812'); /* prepend new partitions */
116+
SELECT count(*) FROM pathman.pathman_partition_list WHERE parent = 'test.insert_date_test'::REGCLASS;
117+
118+
SELECT min(val) FROM test.insert_date_test; /* check first date */
119+
SELECT max(val) FROM test.insert_date_test; /* check last date */
120+
121+
DROP TABLE test.insert_date_test CASCADE;
122+
123+
104124
/* Test special case: ONLY statement with not-ONLY for partitioned table */
105125
CREATE TABLE test.from_only_test(val INT NOT NULL);
106126
INSERT INTO test.from_only_test SELECT generate_series(1, 20);

src/partition_creation.c

Lines changed: 54 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ static Datum extract_binary_interval_from_text(Datum interval_text,
4141
Oid part_atttype,
4242
Oid *interval_type);
4343

44+
static void extract_op_func_and_ret_type(char *opname, Oid type1, Oid type2,
45+
Oid *move_bound_op_func,
46+
Oid *move_bound_op_ret_type);
47+
4448
static Oid spawn_partitions_val(Oid parent_relid,
4549
Datum range_bound_min,
4650
Datum range_bound_max,
@@ -353,6 +357,29 @@ extract_binary_interval_from_text(Datum interval_text, /* interval as TEXT */
353357
return interval_binary;
354358
}
355359

360+
/*
361+
* Fetch binary operator by name and return it's function and ret type.
362+
*/
363+
static void
364+
extract_op_func_and_ret_type(char *opname, Oid type1, Oid type2,
365+
Oid *move_bound_op_func, /* returned value #1 */
366+
Oid *move_bound_op_ret_type) /* returned value #2 */
367+
{
368+
Operator op;
369+
370+
/* Get "move bound operator" descriptor */
371+
op = get_binary_operator(opname, type1, type2);
372+
if (!op)
373+
elog(ERROR, "missing %s operator for types %s and %s",
374+
opname, format_type_be(type1), format_type_be(type2));
375+
376+
*move_bound_op_func = oprfuncid(op);
377+
*move_bound_op_ret_type = get_operator_ret_type(op);
378+
379+
/* Don't forget to release system cache */
380+
ReleaseSysCache(op);
381+
}
382+
356383
/*
357384
* Append\prepend partitions if there's no partition to store 'value'.
358385
*
@@ -373,8 +400,8 @@ spawn_partitions_val(Oid parent_relid, /* parent's Oid */
373400
{
374401
bool should_append; /* append or prepend? */
375402

376-
Operator move_bound_op; /* descriptor */
377-
Oid move_bound_optype; /* operator's ret type */
403+
Oid move_bound_op_func, /* operator's function */
404+
move_bound_op_ret_type; /* operator's ret type */
378405

379406
FmgrInfo cmp_value_bound_finfo, /* exec 'value (>=|<) bound' */
380407
move_bound_finfo; /* exec 'bound + interval' */
@@ -404,36 +431,45 @@ spawn_partitions_val(Oid parent_relid, /* parent's Oid */
404431
/* There's a gap, halt and emit ERROR */
405432
else elog(ERROR, "cannot spawn a partition inside a gap");
406433

407-
/* Get "move bound operator" descriptor */
408-
move_bound_op = get_binary_operator(should_append ? "+" : "-",
409-
range_bound_type,
410-
interval_type);
411-
/* Get operator's ret type */
412-
move_bound_optype = get_operator_ret_type(move_bound_op);
413-
414-
/* Get operator's underlying function */
415-
fmgr_info(oprfuncid(move_bound_op), &move_bound_finfo);
416-
417-
/* Don't forget to release system cache */
418-
ReleaseSysCache(move_bound_op);
434+
/* Fetch operator's underlying function and ret type */
435+
extract_op_func_and_ret_type(should_append ? "+" : "-",
436+
range_bound_type,
437+
interval_type,
438+
&move_bound_op_func,
439+
&move_bound_op_ret_type);
419440

420-
/* Perform some casts if types don't match */
421-
if (move_bound_optype != range_bound_type)
441+
/* Perform casts if types don't match (e.g. date + interval = timestamp) */
442+
if (move_bound_op_ret_type != range_bound_type)
422443
{
444+
/* Cast 'cur_leading_bound' to 'move_bound_op_ret_type' */
423445
cur_leading_bound = perform_type_cast(cur_leading_bound,
424446
range_bound_type,
425-
move_bound_optype,
447+
move_bound_op_ret_type,
426448
NULL); /* might emit ERROR */
427449

428450
/* Update 'range_bound_type' */
429-
range_bound_type = move_bound_optype;
451+
range_bound_type = move_bound_op_ret_type;
430452

431453
/* Fetch new comparison function */
432454
fill_type_cmp_fmgr_info(&cmp_value_bound_finfo,
433455
value_type,
434456
range_bound_type);
457+
458+
/* Since type has changed, fetch another operator */
459+
extract_op_func_and_ret_type(should_append ? "+" : "-",
460+
range_bound_type,
461+
interval_type,
462+
&move_bound_op_func,
463+
&move_bound_op_ret_type);
464+
465+
/* What, again? Don't want to deal with this nightmare */
466+
if (move_bound_op_ret_type != range_bound_type)
467+
elog(ERROR, "error in spawn_partitions_val()");
435468
}
436469

470+
/* Get operator's underlying function */
471+
fmgr_info(move_bound_op_func, &move_bound_finfo);
472+
437473
/* Execute comparison function cmp(value, cur_leading_bound) */
438474
while (should_append ?
439475
check_ge(&cmp_value_bound_finfo, value, cur_leading_bound) :

src/utils.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,12 @@ fill_type_cmp_fmgr_info(FmgrInfo *finfo, Oid type1, Oid type2)
6666
Oid cmp_proc_oid;
6767
TypeCacheEntry *tce;
6868

69+
if (IsBinaryCoercible(type1, type2))
70+
type1 = type2;
71+
72+
else if (IsBinaryCoercible(type2, type1))
73+
type2 = type1;
74+
6975
tce = lookup_type_cache(type1, TYPECACHE_BTREE_OPFAMILY);
7076

7177
cmp_proc_oid = get_opfamily_proc(tce->btree_opf,

0 commit comments

Comments
 (0)