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