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