Skip to content

Commit 0a3b7e5

Browse files
committed
on partition created callback
1 parent 2f8eb90 commit 0a3b7e5

File tree

10 files changed

+301
-14
lines changed

10 files changed

+301
-14
lines changed

expected/pg_pathman.out

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1768,3 +1768,59 @@ NOTICE: 100 rows copied from test_fkey_0
17681768
10
17691769
(1 row)
17701770

1771+
/* Check callbacks */
1772+
CREATE TABLE log(id serial, message text);
1773+
CREATE FUNCTION abc_on_partition_created_callback(args jsonb)
1774+
RETURNS VOID AS $$
1775+
DECLARE
1776+
start_value TEXT := args->>'start';
1777+
end_value TEXT := args::jsonb->'end';
1778+
BEGIN
1779+
-- raise notice 'callback: %', args->start;
1780+
INSERT INTO log(message)
1781+
VALUES (start_value || '-' || end_value);
1782+
END
1783+
$$ language plpgsql;
1784+
CREATE TABLE abc(a serial, b int);
1785+
SELECT create_range_partitions('abc', 'a', 1, 100, 2);
1786+
NOTICE: sequence "abc_seq" does not exist, skipping
1787+
create_range_partitions
1788+
-------------------------
1789+
2
1790+
(1 row)
1791+
1792+
SELECT set_callback('abc', 'abc_on_partition_created_callback');
1793+
set_callback
1794+
--------------
1795+
1796+
(1 row)
1797+
1798+
INSERT INTO abc VALUES (123, 1);
1799+
INSERT INTO abc VALUES (223, 1);
1800+
SELECT append_range_partition('abc');
1801+
append_range_partition
1802+
------------------------
1803+
public.abc_4
1804+
(1 row)
1805+
1806+
SELECT prepend_range_partition('abc');
1807+
prepend_range_partition
1808+
-------------------------
1809+
public.abc_5
1810+
(1 row)
1811+
1812+
SELECT add_range_partition('abc', 401, 501);
1813+
add_range_partition
1814+
---------------------
1815+
public.abc_6
1816+
(1 row)
1817+
1818+
SELECT message FROM log;
1819+
message
1820+
---------
1821+
201-301
1822+
301-401
1823+
-99-1
1824+
401-501
1825+
(4 rows)
1826+

init.sql

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,23 +31,17 @@ CREATE TABLE IF NOT EXISTS @extschema@.pathman_config (
3131
* partrel - regclass (relation type, stored as Oid)
3232
* enable_parent - add parent table to plan
3333
* auto - enable automatic partition creation
34+
* callback -
3435
*/
3536
CREATE TABLE IF NOT EXISTS @extschema@.pathman_config_params (
3637
partrel REGCLASS NOT NULL PRIMARY KEY,
3738
enable_parent BOOLEAN NOT NULL DEFAULT TRUE,
38-
auto BOOLEAN NOT NULL DEFAULT TRUE
39+
auto BOOLEAN NOT NULL DEFAULT TRUE,
40+
callback REGPROCEDURE
3941
);
4042
CREATE UNIQUE INDEX i_pathman_config_params
4143
ON @extschema@.pathman_config_params(partrel);
4244

43-
CREATE TYPE partition AS (
44-
parent REGCLASS,
45-
parttype INTEGER,
46-
child REGCLASS,
47-
start_value TEXT,
48-
end_value TEXT
49-
);
50-
5145
/*
5246
* Invalidate relcache every time someone changes parameters config.
5347
*/
@@ -101,7 +95,7 @@ LANGUAGE plpgsql;
10195
CREATE OR REPLACE FUNCTION @extschema@.pathman_set_param(
10296
relation REGCLASS,
10397
param TEXT,
104-
value BOOLEAN)
98+
value ANYELEMENT)
10599
RETURNS VOID AS
106100
$$
107101
BEGIN
@@ -161,6 +155,19 @@ END
161155
$$
162156
LANGUAGE plpgsql;
163157

158+
/*
159+
* Set partition creation callback
160+
*/
161+
CREATE OR REPLACE FUNCTION @extschema@.set_callback(relation REGCLASS, callback REGPROC)
162+
RETURNS VOID AS
163+
$$
164+
BEGIN
165+
PERFORM @extschema@.validate_on_partition_created_callback(callback);
166+
PERFORM @extschema@.pathman_set_param(relation, 'callback', callback);
167+
END
168+
$$
169+
LANGUAGE plpgsql;
170+
164171
/*
165172
* Show all existing concurrent partitioning tasks.
166173
*/
@@ -710,3 +717,23 @@ LANGUAGE C STRICT;
710717
CREATE OR REPLACE FUNCTION @extschema@.get_rel_tablespace_name(relation REGCLASS)
711718
RETURNS TEXT AS 'pg_pathman', 'get_rel_tablespace_name'
712719
LANGUAGE C STRICT;
720+
721+
/*
722+
* Checks that callback function meets specific requirements. Particularly it
723+
* must have the only JSONB argument and VOID return type
724+
*/
725+
CREATE OR REPLACE FUNCTION @extschema@.validate_on_partition_created_callback(callback REGPROC)
726+
RETURNS VOID AS 'pg_pathman', 'validate_on_partition_created_callback'
727+
LANGUAGE C STRICT;
728+
729+
/*
730+
* Builds JSONB object containing new partition parameters and invoke the
731+
* callback
732+
*/
733+
CREATE OR REPLACE FUNCTION @extschema@.invoke_on_partition_created_callback(
734+
parent REGCLASS,
735+
partition REGCLASS,
736+
start_value ANYELEMENT,
737+
end_value ANYELEMENT)
738+
RETURNS VOID AS 'pg_pathman', 'invoke_on_partition_created_callback'
739+
LANGUAGE C STRICT;

range.sql

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -504,7 +504,6 @@ BEGIN
504504
if NOT tablespace IS NULL THEN
505505
v_create_table_query := v_create_table_query || ' TABLESPACE ' ||tablespace;
506506
END IF;
507-
RAISE NOTICE 'query: %', v_create_table_query;
508507

509508
EXECUTE format(v_create_table_query,
510509
v_child_relname,
@@ -519,6 +518,10 @@ BEGIN
519518
p_end_value));
520519

521520
PERFORM @extschema@.copy_foreign_keys(parent_relid, v_child_relname::REGCLASS);
521+
PERFORM @extschema@.invoke_on_partition_created_callback(parent_relid,
522+
v_child_relname,
523+
p_start_value,
524+
p_end_value);
522525

523526
RETURN v_child_relname;
524527
END
@@ -1234,7 +1237,6 @@ BEGIN
12341237
END
12351238
$$ LANGUAGE plpgsql;
12361239

1237-
12381240
/*
12391241
* Construct CHECK constraint condition for a range partition.
12401242
*/

sql/pg_pathman.sql

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -665,3 +665,27 @@ SELECT create_hash_partitions('test_fkey', 'id', 10);
665665
INSERT INTO test_fkey VALUES(1, 'wrong');
666666
INSERT INTO test_fkey VALUES(1, 'test');
667667
SELECT drop_partitions('test_fkey');
668+
669+
/* Check callbacks */
670+
CREATE TABLE log(id serial, message text);
671+
672+
CREATE OR REPLACE FUNCTION abc_on_partition_created_callback(args jsonb)
673+
RETURNS VOID AS $$
674+
DECLARE
675+
start_value TEXT := args->>'start';
676+
end_value TEXT := args::jsonb->'end';
677+
BEGIN
678+
INSERT INTO log(message)
679+
VALUES (start_value || '-' || end_value);
680+
END
681+
$$ language plpgsql;
682+
683+
CREATE TABLE abc(a serial, b int);
684+
SELECT create_range_partitions('abc', 'a', 1, 100, 2);
685+
SELECT set_callback('abc', 'abc_on_partition_created_callback');
686+
INSERT INTO abc VALUES (123, 1);
687+
INSERT INTO abc VALUES (223, 1);
688+
SELECT append_range_partition('abc');
689+
SELECT prepend_range_partition('abc');
690+
SELECT add_range_partition('abc', 401, 501);
691+
SELECT message FROM log;

src/pathman.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,11 @@
5555
* Definitions for the "pathman_config_params" table
5656
*/
5757
#define PATHMAN_CONFIG_PARAMS "pathman_config_params"
58-
#define Natts_pathman_config_params 3
58+
#define Natts_pathman_config_params 4
5959
#define Anum_pathman_config_params_partrel 1 /* primary key */
6060
#define Anum_pathman_config_params_enable_parent 2 /* include parent into plan */
6161
#define Anum_pathman_config_params_auto 3 /* auto partitions creation */
62+
#define Anum_pathman_config_params_callback 4 /* auto partitions creation */
6263

6364
/*
6465
* Cache current PATHMAN_CONFIG relid (set during load_config()).

src/pl_funcs.c

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,14 @@
1313
#include "relation_info.h"
1414
#include "utils.h"
1515
#include "xact_handling.h"
16+
#include "fmgr.h"
1617

1718
#include "access/htup_details.h"
1819
#include "access/nbtree.h"
1920
#include "access/xact.h"
2021
#include "catalog/indexing.h"
22+
#include "catalog/pg_type.h"
23+
#include "catalog/pg_proc.h"
2124
#include "commands/sequence.h"
2225
#include "commands/tablespace.h"
2326
#include "miscadmin.h"
@@ -28,6 +31,8 @@
2831
#include "utils/lsyscache.h"
2932
#include "utils/syscache.h"
3033
#include "utils/typcache.h"
34+
#include "utils/jsonb.h"
35+
#include "utils/fmgroids.h"
3136

3237

3338
/* declarations */
@@ -57,7 +62,8 @@ PG_FUNCTION_INFO_V1( lock_partitioned_relation );
5762
PG_FUNCTION_INFO_V1( prevent_relation_modification );
5863
PG_FUNCTION_INFO_V1( debug_capture );
5964
PG_FUNCTION_INFO_V1( get_rel_tablespace_name );
60-
65+
PG_FUNCTION_INFO_V1( validate_on_partition_created_callback );
66+
PG_FUNCTION_INFO_V1( invoke_on_partition_created_callback );
6167

6268
static void on_partitions_created_internal(Oid partitioned_table, bool add_callbacks);
6369
static void on_partitions_updated_internal(Oid partitioned_table, bool add_callbacks);
@@ -776,3 +782,87 @@ get_rel_tablespace_name(PG_FUNCTION_ARGS)
776782
result = get_tablespace_name(tablespace_id);
777783
PG_RETURN_TEXT_P(cstring_to_text(result));
778784
}
785+
786+
/*
787+
* Checks that callback function meets specific requirements. Particularly it
788+
* must have the only JSONB argument and VOID return type
789+
*/
790+
Datum
791+
validate_on_partition_created_callback(PG_FUNCTION_ARGS)
792+
{
793+
HeapTuple tp;
794+
Oid callback = PG_GETARG_OID(0);
795+
Form_pg_proc functup;
796+
797+
tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(callback));
798+
if (!HeapTupleIsValid(tp))
799+
elog(ERROR, "cache lookup failed for function %u", callback);
800+
functup = (Form_pg_proc) GETSTRUCT(tp);
801+
802+
if (functup->pronargs != 1 || functup->proargtypes.values[0] != JSONBOID ||
803+
functup->prorettype != VOIDOID)
804+
elog(ERROR,
805+
"Callback function must have only one JSNOB argument "
806+
"and return VOID");
807+
808+
ReleaseSysCache(tp);
809+
PG_RETURN_VOID();
810+
}
811+
812+
/*
813+
* Builds JSONB object containing new partition parameters and invoke the
814+
* callback
815+
*/
816+
Datum
817+
invoke_on_partition_created_callback(PG_FUNCTION_ARGS)
818+
{
819+
char *json;
820+
Datum jsonb;
821+
Oid parent_oid = PG_GETARG_OID(0);
822+
Oid partition_oid = PG_GETARG_OID(1);
823+
Oid type = get_fn_expr_argtype(fcinfo->flinfo, 2);
824+
Datum start_value = PG_GETARG_DATUM(2);
825+
Datum end_value = PG_GETARG_DATUM(3);
826+
const PartRelationInfo *prel;
827+
828+
if ((prel = get_pathman_relation_info(parent_oid)) == NULL)
829+
elog(ERROR,
830+
"Relation %s isn't partitioned by pg_pathman",
831+
get_rel_name(parent_oid));
832+
833+
/* If there is no callback function specified then we're done */
834+
if (!prel->callback)
835+
PG_RETURN_VOID();
836+
837+
/* Convert ANYELEMENT arguments to jsonb */
838+
start_value = convert_to_jsonb(start_value, type);
839+
end_value = convert_to_jsonb(end_value, type);
840+
841+
/*
842+
* Build jsonb object to pass into callback
843+
*
844+
* XXX it would be nice to have this rewrited with pushJsonbValue() to get
845+
* rid of string formatting and parsing. See jsonb_build_object() for
846+
* example
847+
*/
848+
json = psprintf("{"
849+
"\"parent\": %u,"
850+
"\"partition\": %u,"
851+
"\"part_type\": %u,"
852+
"\"start\": %s,"
853+
"\"end\": %s,"
854+
"\"value_type\": %u}",
855+
parent_oid,
856+
partition_oid,
857+
prel->parttype,
858+
datum_to_cstring(start_value, JSONBOID),
859+
datum_to_cstring(end_value, JSONBOID),
860+
type
861+
);
862+
jsonb = OidFunctionCall1(F_JSONB_IN, CStringGetDatum(json));
863+
864+
/* Invoke callback */
865+
OidFunctionCall1(prel->callback, JsonbGetDatum(jsonb));
866+
867+
PG_RETURN_JSONB(jsonb);
868+
}

src/relation_info.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,12 +165,14 @@ refresh_pathman_relation_info(Oid relid,
165165
{
166166
prel->enable_parent = param_values[Anum_pathman_config_params_enable_parent - 1];
167167
prel->auto_partition = param_values[Anum_pathman_config_params_auto - 1];
168+
prel->callback = param_values[Anum_pathman_config_params_callback - 1];
168169
}
169170
/* Else set default values if they cannot be found */
170171
else
171172
{
172173
prel->enable_parent = false;
173174
prel->auto_partition = true;
175+
prel->callback = InvalidOid;
174176
}
175177

176178
/* We've successfully built a cache entry */

src/relation_info.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ typedef struct
4949
bool valid; /* is this entry valid? */
5050
bool enable_parent; /* include parent to the plan */
5151
bool auto_partition; /* auto partition creation */
52+
Oid callback; /* callback for partition creation */
5253

5354
uint32 children_count;
5455
Oid *children; /* Oids of child partitions */

0 commit comments

Comments
 (0)