Skip to content

Commit ccc01a8

Browse files
committed
Merge branch 'master_pg_upgrade_bug' into rel_future_beta
2 parents 99eb0c1 + 338a2cd commit ccc01a8

File tree

9 files changed

+146
-16
lines changed

9 files changed

+146
-16
lines changed

expected/pathman_callbacks.out

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,39 @@ WARNING: callback arg: {"parent": "abc", "parttype": "2", "partition": "abc_2",
129129

130130
DROP TABLE abc CASCADE;
131131
NOTICE: drop cascades to 2 other objects
132+
/* test the temprary deletion of callback function */
133+
CREATE TABLE abc(a serial, b int);
134+
SELECT set_init_callback('abc',
135+
'callbacks.abc_on_part_created_callback');
136+
set_init_callback
137+
-------------------
138+
139+
(1 row)
140+
141+
SELECT create_range_partitions('abc', 'a', 1, 100, 2);
142+
WARNING: callback arg: {"parent": "abc", "parttype": "2", "partition": "abc_1", "range_max": "101", "range_min": "1", "parent_schema": "public", "partition_schema": "public"}
143+
WARNING: callback arg: {"parent": "abc", "parttype": "2", "partition": "abc_2", "range_max": "201", "range_min": "101", "parent_schema": "public", "partition_schema": "public"}
144+
create_range_partitions
145+
-------------------------
146+
2
147+
(1 row)
148+
149+
INSERT INTO abc VALUES (201, 0);
150+
WARNING: callback arg: {"parent": "abc", "parttype": "2", "partition": "abc_3", "range_max": "301", "range_min": "201", "parent_schema": "public", "partition_schema": "public"}
151+
DROP FUNCTION callbacks.abc_on_part_created_callback(jsonb);
152+
INSERT INTO abc VALUES (301, 0);
153+
ERROR: callback function "callbacks.abc_on_part_created_callback(jsonb)" does not exist
154+
CREATE OR REPLACE FUNCTION callbacks.abc_on_part_created_callback(
155+
args JSONB)
156+
RETURNS VOID AS $$
157+
BEGIN
158+
RAISE WARNING 'callback arg: %', args::TEXT;
159+
END
160+
$$ language plpgsql;
161+
INSERT INTO abc VALUES (301, 0);
162+
WARNING: callback arg: {"parent": "abc", "parttype": "2", "partition": "abc_5", "range_max": "401", "range_min": "301", "parent_schema": "public", "partition_schema": "public"}
163+
DROP TABLE abc CASCADE;
164+
NOTICE: drop cascades to 4 other objects
132165
DROP SCHEMA callbacks CASCADE;
133166
NOTICE: drop cascades to 2 other objects
134167
DROP EXTENSION pg_pathman CASCADE;

expected/pathman_permissions.out

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ SELECT * FROM pathman_config;
4141
SELECT * FROM pathman_config_params;
4242
partrel | enable_parent | auto | init_callback | spawn_using_bgw
4343
-------------------------+---------------+------+---------------+-----------------
44-
permissions.user1_table | f | t | - | f
44+
permissions.user1_table | f | t | | f
4545
(1 row)
4646

4747
/* Should fail */

hash.sql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ BEGIN
145145

146146
/* Fetch init_callback from 'params' table */
147147
WITH stub_callback(stub) as (values (0))
148-
SELECT coalesce(init_callback, 0::REGPROCEDURE)
148+
SELECT init_callback
149149
FROM stub_callback
150150
LEFT JOIN @extschema@.pathman_config_params AS params
151151
ON params.partrel = parent_relid

init.sql

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,24 +56,25 @@ CREATE TABLE IF NOT EXISTS @extschema@.pathman_config (
5656
* NOTE: this function is used in CHECK CONSTRAINT.
5757
*/
5858
CREATE OR REPLACE FUNCTION @extschema@.validate_part_callback(
59-
callback REGPROC,
59+
callback TEXT,
6060
raise_error BOOL DEFAULT TRUE)
6161
RETURNS BOOL AS 'pg_pathman', 'validate_part_callback_pl'
62-
LANGUAGE C STRICT;
62+
LANGUAGE C;
6363

6464

6565
/*
6666
* Optional parameters for partitioned tables.
6767
* partrel - regclass (relation type, stored as Oid)
6868
* enable_parent - add parent table to plan
6969
* auto - enable automatic partition creation
70-
* init_callback - cb to be executed on partition creation
70+
* init_callback - text signature of cb to be executed on partition
71+
* creation
7172
*/
7273
CREATE TABLE IF NOT EXISTS @extschema@.pathman_config_params (
7374
partrel REGCLASS NOT NULL PRIMARY KEY,
7475
enable_parent BOOLEAN NOT NULL DEFAULT FALSE,
7576
auto BOOLEAN NOT NULL DEFAULT TRUE,
76-
init_callback REGPROCEDURE NOT NULL DEFAULT 0,
77+
init_callback TEXT DEFAULT NULL,
7778
spawn_using_bgw BOOLEAN NOT NULL DEFAULT FALSE
7879

7980
CHECK (@extschema@.validate_part_callback(init_callback)) /* check signature */
@@ -140,7 +141,7 @@ BEGIN
140141
USING relation, value;
141142
END
142143
$$
143-
LANGUAGE plpgsql STRICT;
144+
LANGUAGE plpgsql;
144145

145146
/*
146147
* Include\exclude parent relation in query plan.
@@ -178,8 +179,25 @@ CREATE OR REPLACE FUNCTION @extschema@.set_init_callback(
178179
callback REGPROC DEFAULT 0)
179180
RETURNS VOID AS
180181
$$
182+
DECLARE
183+
regproc_text TEXT := NULL;
184+
181185
BEGIN
182-
PERFORM @extschema@.pathman_set_param(relation, 'init_callback', callback);
186+
187+
/* Fetch schema-qualified name of callback */
188+
IF callback != 0 THEN
189+
SELECT quote_ident(nspname) || '.' ||
190+
quote_ident(proname) || '(' ||
191+
(SELECT string_agg(x.argtype::REGTYPE::TEXT, ',')
192+
FROM unnest(proargtypes) AS x(argtype)) ||
193+
')'
194+
FROM pg_catalog.pg_proc p JOIN pg_catalog.pg_namespace n
195+
ON n.oid = p.pronamespace
196+
WHERE p.oid = callback
197+
INTO regproc_text; /* <= result */
198+
END IF;
199+
200+
PERFORM @extschema@.pathman_set_param(relation, 'init_callback', regproc_text);
183201
END
184202
$$
185203
LANGUAGE plpgsql STRICT;

range.sql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -946,7 +946,7 @@ BEGIN
946946

947947
/* Fetch init_callback from 'params' table */
948948
WITH stub_callback(stub) as (values (0))
949-
SELECT coalesce(init_callback, 0::REGPROCEDURE)
949+
SELECT init_callback
950950
FROM stub_callback
951951
LEFT JOIN @extschema@.pathman_config_params AS params
952952
ON params.partrel = parent_relid

sql/pathman_callbacks.sql

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,5 +53,26 @@ SELECT create_range_partitions('abc', 'a', 1, 100, 2);
5353

5454
DROP TABLE abc CASCADE;
5555

56+
/* test the temprary deletion of callback function */
57+
CREATE TABLE abc(a serial, b int);
58+
SELECT set_init_callback('abc',
59+
'callbacks.abc_on_part_created_callback');
60+
SELECT create_range_partitions('abc', 'a', 1, 100, 2);
61+
62+
INSERT INTO abc VALUES (201, 0);
63+
DROP FUNCTION callbacks.abc_on_part_created_callback(jsonb);
64+
INSERT INTO abc VALUES (301, 0);
65+
CREATE OR REPLACE FUNCTION callbacks.abc_on_part_created_callback(
66+
args JSONB)
67+
RETURNS VOID AS $$
68+
BEGIN
69+
RAISE WARNING 'callback arg: %', args::TEXT;
70+
END
71+
$$ language plpgsql;
72+
INSERT INTO abc VALUES (301, 0);
73+
74+
DROP TABLE abc CASCADE;
75+
76+
5677
DROP SCHEMA callbacks CASCADE;
5778
DROP EXTENSION pg_pathman CASCADE;

src/init.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -782,7 +782,6 @@ read_pathman_params(Oid relid, Datum *values, bool *isnull)
782782
Assert(!isnull[Anum_pathman_config_params_partrel - 1]);
783783
Assert(!isnull[Anum_pathman_config_params_enable_parent - 1]);
784784
Assert(!isnull[Anum_pathman_config_params_auto - 1]);
785-
Assert(!isnull[Anum_pathman_config_params_init_callback - 1]);
786785
Assert(!isnull[Anum_pathman_config_params_spawn_using_bgw - 1]);
787786
}
788787

src/partition_creation.c

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ static ObjectAddress create_table_using_stmt(CreateStmt *create_stmt,
7474
static void copy_foreign_keys(Oid parent_relid, Oid partition_oid);
7575
static void postprocess_child_table_and_atts(Oid parent_relid, Oid partition_relid);
7676

77+
static Oid text_to_regprocedure(text *proname_args);
78+
7779
static Constraint *make_constraint_common(char *name, Node *raw_expr);
7880

7981
static Value make_string_value_struct(char *str);
@@ -406,13 +408,20 @@ create_partitions_for_value_internal(Oid relid, Datum value, Oid value_type)
406408
{
407409
ErrorData *edata;
408410

411+
/* Simply rethrow ERROR if we're in backend */
412+
if (!IsBackgroundWorker)
413+
PG_RE_THROW();
414+
409415
/* Switch to the original context & copy edata */
410416
MemoryContextSwitchTo(old_mcxt);
411417
edata = CopyErrorData();
412418
FlushErrorState();
413419

414-
elog(LOG, "create_partitions_internal(): %s [%u]",
415-
edata->message, MyProcPid);
420+
/* Produce log message if we're in BGW */
421+
ereport(LOG,
422+
(errmsg(CppAsString(create_partitions_for_value_internal) ": %s [%u]",
423+
edata->message, MyProcPid),
424+
(edata->detail) ? errdetail("%s", edata->detail) : 0));
416425

417426
FreeErrorData(edata);
418427

@@ -1466,14 +1475,26 @@ invoke_init_callback_internal(init_callback_params *cb_params)
14661475
/* Search for init_callback entry in PATHMAN_CONFIG_PARAMS */
14671476
if (read_pathman_params(parent_oid, param_values, param_isnull))
14681477
{
1469-
Datum init_cb_datum; /* Oid of init_callback */
1478+
Datum init_cb_datum; /* signature of init_callback */
14701479
AttrNumber init_cb_attno = Anum_pathman_config_params_init_callback;
14711480

1472-
/* Extract Datum storing callback's Oid */
1481+
/* Extract Datum storing callback's signature */
14731482
init_cb_datum = param_values[init_cb_attno - 1];
14741483

14751484
/* Cache init_callback's Oid */
1476-
cb_params->callback = DatumGetObjectId(init_cb_datum);
1485+
if (init_cb_datum)
1486+
{
1487+
/* Try fetching callback's Oid */
1488+
cb_params->callback = text_to_regprocedure(DatumGetTextP(init_cb_datum));
1489+
1490+
if (!RegProcedureIsValid(cb_params->callback))
1491+
ereport(ERROR,
1492+
(errcode(ERRCODE_INTEGRITY_CONSTRAINT_VIOLATION),
1493+
errmsg("callback function \"%s\" does not exist",
1494+
TextDatumGetCString(init_cb_datum))));
1495+
}
1496+
else
1497+
cb_params->callback = InvalidOid;
14771498
cb_params->callback_is_cached = true;
14781499
}
14791500
}
@@ -1619,3 +1640,31 @@ validate_part_callback(Oid procid, bool emit_error)
16191640

16201641
return is_ok;
16211642
}
1643+
1644+
/*
1645+
* Utility function that converts signature of procedure into regprocedure.
1646+
*
1647+
* Precondition: proc_signature != NULL.
1648+
*
1649+
* Returns InvalidOid if proname_args is not found.
1650+
* Raise error if it's incorrect.
1651+
*/
1652+
static Oid
1653+
text_to_regprocedure(text *proc_signature)
1654+
{
1655+
FunctionCallInfoData fcinfo;
1656+
Datum result;
1657+
1658+
InitFunctionCallInfoData(fcinfo, NULL, 1, InvalidOid, NULL, NULL);
1659+
1660+
#if PG_VERSION_NUM >= 90600
1661+
fcinfo.arg[0] = PointerGetDatum(proc_signature);
1662+
#else
1663+
fcinfo.arg[0] = CStringGetDatum(text_to_cstring(proc_signature));
1664+
#endif
1665+
fcinfo.argnull[0] = false;
1666+
1667+
result = to_regprocedure(&fcinfo);
1668+
1669+
return DatumGetObjectId(result);
1670+
}

src/pl_funcs.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -792,7 +792,17 @@ prevent_relation_modification(PG_FUNCTION_ARGS)
792792
Datum
793793
validate_part_callback_pl(PG_FUNCTION_ARGS)
794794
{
795-
PG_RETURN_BOOL(validate_part_callback(PG_GETARG_OID(0), PG_GETARG_BOOL(1)));
795+
const char *cb_cstring;
796+
Oid cb_oid;
797+
798+
if (PG_ARGISNULL(0))
799+
PG_RETURN_BOOL(true);
800+
801+
cb_cstring = text_to_cstring(PG_GETARG_TEXT_P(0));
802+
cb_oid = DatumGetObjectId(DirectFunctionCall1(regprocedurein,
803+
CStringGetDatum(cb_cstring)));
804+
805+
PG_RETURN_BOOL(validate_part_callback(cb_oid, PG_GETARG_BOOL(1)));
796806
}
797807

798808
/*

0 commit comments

Comments
 (0)