Skip to content

Commit 113704a

Browse files
tianzhouclaude
andauthored
fix: correct LANGUAGE for overloaded functions with mixed languages (#368) (#370)
The JOIN between information_schema.routines and pg_proc matched only on function name and namespace, causing a cross-join for overloaded functions. This resulted in wrong LANGUAGE (and other attributes) being assigned when overloads had different languages (e.g., sql vs plpgsql). Fix by adding OID matching via specific_name to all 4 affected queries. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 2569d87 commit 113704a

7 files changed

Lines changed: 117 additions & 18 deletions

File tree

cmd/dump/dump_integration_test.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,13 @@ func TestDumpCommand_Issue345ArrayCast(t *testing.T) {
130130
runExactMatchTest(t, "issue_345_array_cast")
131131
}
132132

133+
func TestDumpCommand_Issue191FunctionProcedureOverload(t *testing.T) {
134+
if testing.Short() {
135+
t.Skip("Skipping integration test in short mode")
136+
}
137+
runExactMatchTest(t, "issue_191_function_procedure_overload")
138+
}
139+
133140
func TestDumpCommand_Issue318CrossSchemaComment(t *testing.T) {
134141
if testing.Short() {
135142
t.Skip("Skipping integration test in short mode")

ir/queries/queries.sql

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -542,11 +542,12 @@ SELECT
542542
p.proisstrict AS is_strict,
543543
p.prosecdef AS is_security_definer
544544
FROM information_schema.routines r
545-
LEFT JOIN pg_proc p ON p.proname = r.routine_name
545+
LEFT JOIN pg_proc p ON p.proname = r.routine_name
546546
AND p.pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = r.routine_schema)
547+
AND p.oid = (regexp_match(r.specific_name, '_(\d+)$'))[1]::oid
547548
LEFT JOIN pg_depend d ON d.objid = p.oid AND d.deptype = 'e'
548549
LEFT JOIN pg_description desc_func ON desc_func.objoid = p.oid AND desc_func.classoid = 'pg_proc'::regclass
549-
WHERE
550+
WHERE
550551
r.routine_schema NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
551552
AND r.routine_schema NOT LIKE 'pg_temp_%'
552553
AND r.routine_schema NOT LIKE 'pg_toast_temp_%'
@@ -566,11 +567,12 @@ SELECT
566567
oidvectortypes(p.proargtypes) AS procedure_arguments,
567568
pg_get_function_arguments(p.oid) AS procedure_signature
568569
FROM information_schema.routines r
569-
LEFT JOIN pg_proc p ON p.proname = r.routine_name
570+
LEFT JOIN pg_proc p ON p.proname = r.routine_name
570571
AND p.pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = r.routine_schema)
572+
AND p.oid = (regexp_match(r.specific_name, '_(\d+)$'))[1]::oid
571573
LEFT JOIN pg_depend d ON d.objid = p.oid AND d.deptype = 'e'
572574
LEFT JOIN pg_description desc_proc ON desc_proc.objoid = p.oid AND desc_proc.classoid = 'pg_proc'::regclass
573-
WHERE
575+
WHERE
574576
r.routine_schema NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
575577
AND r.routine_schema NOT LIKE 'pg_temp_%'
576578
AND r.routine_schema NOT LIKE 'pg_toast_temp_%'
@@ -994,6 +996,7 @@ SELECT
994996
FROM information_schema.routines r
995997
LEFT JOIN pg_proc p ON p.proname = r.routine_name
996998
AND p.pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = r.routine_schema)
999+
AND p.oid = (regexp_match(r.specific_name, '_(\d+)$'))[1]::oid
9971000
LEFT JOIN pg_depend d ON d.objid = p.oid AND d.deptype = 'e'
9981001
LEFT JOIN pg_description desc_func ON desc_func.objoid = p.oid AND desc_func.classoid = 'pg_proc'::regclass
9991002
WHERE r.routine_schema = $1
@@ -1020,6 +1023,7 @@ SELECT
10201023
FROM information_schema.routines r
10211024
LEFT JOIN pg_proc p ON p.proname = r.routine_name
10221025
AND p.pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = r.routine_schema)
1026+
AND p.oid = (regexp_match(r.specific_name, '_(\d+)$'))[1]::oid
10231027
LEFT JOIN pg_depend d ON d.objid = p.oid AND d.deptype = 'e'
10241028
LEFT JOIN pg_description desc_proc ON desc_proc.objoid = p.oid AND desc_proc.classoid = 'pg_proc'::regclass
10251029
WHERE r.routine_schema = $1

ir/queries/queries.sql.go

Lines changed: 8 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
{
22
"name": "issue_191_function_procedure_overload",
3-
"description": "Test case for overloaded functions and procedures not being fully dumped (GitHub issue #191)",
3+
"description": "Test case for overloaded functions and procedures (GitHub issues #191, #368)",
44
"source": "https://github.com/pgplex/pgschema/issues/191",
55
"notes": [
6-
"Tests that all overloaded functions are preserved when dumping (not just the last one)",
7-
"Tests that all overloaded procedures are preserved when dumping",
8-
"Covers overloads with different parameter counts: test_func(integer) vs test_func(integer, integer)",
9-
"Covers overloads with different parameter types: test_func(integer) vs test_func(text)"
6+
"#191: Tests that all overloaded functions are preserved when dumping (not just the last one)",
7+
"#191: Tests that all overloaded procedures are preserved when dumping",
8+
"#191: Covers overloads with different parameter counts: test_func(integer) vs test_func(integer, integer)",
9+
"#191: Covers overloads with different parameter types: test_func(integer) vs test_func(text)",
10+
"#368: Tests that overloaded functions with different languages (sql vs plpgsql) each get the correct LANGUAGE"
1011
]
1112
}

testdata/dump/issue_191_function_procedure_overload/pgdump.sql

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,32 @@ END;
9595
$$;
9696

9797

98+
--
99+
-- Name: provide_tx(text[]); Type: FUNCTION; Schema: public; Owner: -
100+
--
101+
102+
CREATE FUNCTION public.provide_tx(VARIADIC p_txs text[])
103+
RETURNS void
104+
LANGUAGE sql
105+
AS $$
106+
SELECT 1;
107+
$$;
108+
109+
110+
--
111+
-- Name: provide_tx(uuid); Type: FUNCTION; Schema: public; Owner: -
112+
--
113+
114+
CREATE FUNCTION public.provide_tx(p_id uuid)
115+
RETURNS void
116+
LANGUAGE plpgsql
117+
AS $$
118+
BEGIN
119+
RAISE NOTICE '%', p_id;
120+
END;
121+
$$;
122+
123+
98124
--
99125
-- PostgreSQL database dump complete
100126
--

testdata/dump/issue_191_function_procedure_overload/pgschema.sql

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,40 @@
22
-- pgschema database dump
33
--
44

5-
-- Dumped from database version PostgreSQL 17.5
6-
-- Dumped by pgschema version 1.5.0
5+
-- Dumped from database version PostgreSQL 18.0
6+
-- Dumped by pgschema version 1.7.4
77

88

9+
--
10+
-- Name: provide_tx(text[]); Type: FUNCTION; Schema: -; Owner: -
11+
--
12+
13+
CREATE OR REPLACE FUNCTION provide_tx(
14+
VARIADIC p_txs text[]
15+
)
16+
RETURNS void
17+
LANGUAGE sql
18+
VOLATILE
19+
AS $$
20+
SELECT 1;
21+
$$;
22+
23+
--
24+
-- Name: provide_tx(uuid); Type: FUNCTION; Schema: -; Owner: -
25+
--
26+
27+
CREATE OR REPLACE FUNCTION provide_tx(
28+
p_id uuid
29+
)
30+
RETURNS void
31+
LANGUAGE plpgsql
32+
VOLATILE
33+
AS $$
34+
BEGIN
35+
RAISE NOTICE '%', p_id;
36+
END;
37+
$$;
38+
939
--
1040
-- Name: test_func(integer); Type: FUNCTION; Schema: -; Owner: -
1141
--
@@ -97,3 +127,4 @@ BEGIN
97127
RAISE NOTICE 'Text: %', a;
98128
END;
99129
$$;
130+

testdata/dump/issue_191_function_procedure_overload/raw.sql

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
--
22
-- Test case for GitHub issue #191: Overloaded functions and procedures not fully dumped
3+
-- Also covers #368: dump emits wrong LANGUAGE for overloaded functions with mixed languages
34
--
4-
-- This test case reproduces a bug where only the last overloaded function/procedure
5-
-- is included in the dump output. Functions and procedures are stored by name only,
6-
-- causing overloads with different signatures to overwrite each other.
5+
-- #191: Only the last overloaded function/procedure was included in the dump output.
6+
-- Functions and procedures were stored by name only, causing overloads with
7+
-- different signatures to overwrite each other.
8+
-- #368: When overloaded functions have different languages (e.g., sql vs plpgsql),
9+
-- the dump may assign the wrong language due to a cross-join in the query
10+
-- between information_schema.routines and pg_proc.
711
--
812

913
--
@@ -70,3 +74,25 @@ BEGIN
7074
RAISE NOTICE 'Text: %', a;
7175
END;
7276
$$;
77+
78+
--
79+
-- Mixed-language function overloads (#368): same name, different languages
80+
--
81+
82+
-- Overload 1: SQL language
83+
CREATE OR REPLACE FUNCTION provide_tx(VARIADIC p_txs text[])
84+
RETURNS void
85+
LANGUAGE sql
86+
AS $$
87+
SELECT 1;
88+
$$;
89+
90+
-- Overload 2: plpgsql language
91+
CREATE OR REPLACE FUNCTION provide_tx(p_id uuid)
92+
RETURNS void
93+
LANGUAGE plpgsql
94+
AS $$
95+
BEGIN
96+
RAISE NOTICE '%', p_id;
97+
END;
98+
$$;

0 commit comments

Comments
 (0)