Skip to content

Commit 0de4a65

Browse files
breken-aiCopilot
authored andcommitted
Qualify and quote the support function in ALTER FUNCTION .. SUPPORT (#8873)
DESCRIPTION: Fixes ALTER FUNCTION .. SUPPORT with a user-defined support function `ALTER FUNCTION f SUPPORT my_support` on a distributed function sends the support function name to the workers exactly as the user typed it. The workers run the command without the coordinator's `search_path`, so this only works when the support function is in `public` or `pg_catalog`. Here the support function exists on every node, in the same schema as `f`: ``` ALTER FUNCTION func_with_support_2(int, int) SUPPORT my_support; ERROR: function my_support(internal) does not exist CONTEXT: while executing command on localhost:57638 ``` A name that needs quoting also fails, because `AppendDefElemSupport` prints it with `defGetString`: ``` ALTER FUNCTION func_with_support(int, int) SUPPORT "Support Func"; ERROR: syntax error at or near "Func" ``` #5849 (for #5844) made the command valid by assuming the support function exists on the workers. This PR keeps that assumption and changes two things: - `QualifyAlterFunctionStmt` resolves the support function the same way postgres does (`LookupFuncName` with a single `internal` argument) and qualifies it with its schema. - The deparser prints the name with `NameListToQuotedString`. **Test.** I added cases to `function_propagation.sql` for an unqualified support function in the test schema and for a quoted support function name. They check `prosupport` on the workers. - On `main` @ c267b0b, both `ALTER`s fail as shown above and the workers keep `generate_series_int8_support`. - With the fix, the workers show `function_propagation_schema."Support Func", function_propagation_schema.my_support`. I ran this on PG 17.11 in Docker with `make check-custom-schedule` (minimal cluster setup + `function_propagation`). `uncrustify` with the citus-style config reports no changes. This PR was prepared with an AI coding agent (Claude) working for the breken-ai account. I reviewed the change and the test output. (cherry picked from commit bfb8600) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: d89d1f43-18ea-4405-bd1b-5c3129e391a9
1 parent 72a23f7 commit 0de4a65

4 files changed

Lines changed: 73 additions & 1 deletion

File tree

‎src/backend/distributed/deparser/deparse_function_stmts.c‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,8 @@ AppendDefElemSet(StringInfo buf, DefElem *def)
296296
static void
297297
AppendDefElemSupport(StringInfo buf, DefElem *def)
298298
{
299-
appendStringInfo(buf, " SUPPORT %s", defGetString(def));
299+
appendStringInfo(buf, " SUPPORT %s",
300+
NameListToQuotedString(castNode(List, def->arg)));
300301
}
301302

302303

‎src/backend/distributed/deparser/qualify_function_stmt.c‎

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,20 @@
2121
#include "access/htup_details.h"
2222
#include "catalog/namespace.h"
2323
#include "catalog/pg_proc.h"
24+
#include "catalog/pg_type.h"
25+
#include "nodes/value.h"
2426
#include "parser/parse_func.h"
2527
#include "utils/lsyscache.h"
2628
#include "utils/syscache.h"
2729

2830
#include "distributed/deparser.h"
31+
#include "distributed/listutils.h"
2932
#include "distributed/version_compat.h"
3033

3134
/* forward declaration for qualify functions */
3235
static void QualifyFunction(ObjectWithArgs *func, ObjectType type);
3336
static void QualifyFunctionSchemaName(ObjectWithArgs *func, ObjectType type);
37+
static void QualifySupportFunctionName(DefElem *supportDefElem);
3438

3539

3640
/* AssertObjectTypeIsFunctionType asserts we aren't receiving something we shouldn't */
@@ -59,6 +63,48 @@ QualifyAlterFunctionStmt(Node *node)
5963
AssertObjectTypeIsFunctional(stmt->objtype);
6064

6165
QualifyFunction(stmt->func, stmt->objtype);
66+
67+
DefElem *action = NULL;
68+
foreach_declared_ptr(action, stmt->actions)
69+
{
70+
if (strcmp(action->defname, "support") == 0)
71+
{
72+
QualifySupportFunctionName(action);
73+
}
74+
}
75+
}
76+
77+
78+
/*
79+
* QualifySupportFunctionName makes the support function name of an
80+
* ALTER FUNCTION .. SUPPORT .. statement fully qualified, so the workers
81+
* resolve the same function the coordinator does regardless of search_path.
82+
*/
83+
static void
84+
QualifySupportFunctionName(DefElem *supportDefElem)
85+
{
86+
List *supportName = castNode(List, supportDefElem->arg);
87+
char *schemaName = NULL;
88+
char *functionName = NULL;
89+
90+
DeconstructQualifiedName(supportName, &schemaName, &functionName);
91+
if (schemaName != NULL)
92+
{
93+
return;
94+
}
95+
96+
/* support functions take a single internal argument, see interpret_func_support */
97+
Oid argTypes[1] = { INTERNALOID };
98+
Oid supportOid = LookupFuncName(supportName, 1, argTypes, true);
99+
if (!OidIsValid(supportOid))
100+
{
101+
/* postgres reports the missing function when it executes the statement */
102+
return;
103+
}
104+
105+
schemaName = get_namespace_name(get_func_namespace(supportOid));
106+
supportDefElem->arg = (Node *) list_make2(makeString(schemaName),
107+
makeString(pstrdup(functionName)));
62108
}
63109

64110

‎src/test/regress/expected/function_propagation.out‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1321,6 +1321,21 @@ CREATE FUNCTION func_with_support_2(int, int) RETURNS bool
13211321
LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE
13221322
AS $$int4eq$$;
13231323
ALTER FUNCTION func_with_support_2(int, int) SUPPORT generate_series_int8_support;
1324+
-- user-defined support functions must resolve on the workers too, even when the
1325+
-- name is not schema qualified or needs quoting
1326+
CREATE FUNCTION my_support(internal) RETURNS internal
1327+
LANGUAGE internal STRICT AS $$generate_series_int8_support$$;
1328+
ALTER FUNCTION func_with_support_2(int, int) SUPPORT my_support;
1329+
CREATE FUNCTION "Support Func"(internal) RETURNS internal
1330+
LANGUAGE internal STRICT AS $$generate_series_int8_support$$;
1331+
ALTER FUNCTION func_with_support(int, int) SUPPORT "Support Func";
1332+
SELECT result FROM run_command_on_workers($$SELECT string_agg(prosupport::regproc::text, ', ' ORDER BY proname) FROM pg_proc WHERE proname IN ('func_with_support', 'func_with_support_2')$$);
1333+
result
1334+
---------------------------------------------------------------------
1335+
function_propagation_schema."Support Func", function_propagation_schema.my_support
1336+
function_propagation_schema."Support Func", function_propagation_schema.my_support
1337+
(2 rows)
1338+
13241339
RESET search_path;
13251340
SET client_min_messages TO WARNING;
13261341
DROP SCHEMA function_propagation_schema CASCADE;

‎src/test/regress/sql/function_propagation.sql‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -861,6 +861,16 @@ CREATE FUNCTION func_with_support_2(int, int) RETURNS bool
861861

862862
ALTER FUNCTION func_with_support_2(int, int) SUPPORT generate_series_int8_support;
863863

864+
-- user-defined support functions must resolve on the workers too, even when the
865+
-- name is not schema qualified or needs quoting
866+
CREATE FUNCTION my_support(internal) RETURNS internal
867+
LANGUAGE internal STRICT AS $$generate_series_int8_support$$;
868+
ALTER FUNCTION func_with_support_2(int, int) SUPPORT my_support;
869+
CREATE FUNCTION "Support Func"(internal) RETURNS internal
870+
LANGUAGE internal STRICT AS $$generate_series_int8_support$$;
871+
ALTER FUNCTION func_with_support(int, int) SUPPORT "Support Func";
872+
SELECT result FROM run_command_on_workers($$SELECT string_agg(prosupport::regproc::text, ', ' ORDER BY proname) FROM pg_proc WHERE proname IN ('func_with_support', 'func_with_support_2')$$);
873+
864874
RESET search_path;
865875
SET client_min_messages TO WARNING;
866876
DROP SCHEMA function_propagation_schema CASCADE;

0 commit comments

Comments
 (0)