PostgreSQL『ERROR: cannot change name of input parameter in FUNCTION』の原因と対処
- 作成日 2025.09.22
- 更新日 2025.10.06
- その他
CREATE OR REPLACE FUNCTIONで既存関数の「入力(IN)パラメータ名」を変更しようとすると、このエラーが出る。呼び出し側の名前付き引数(named notation)互換性を壊すのを防ぐため、PostgreSQLはIN引数名の置き換えを禁止している。最短復旧、恒久対策、互換維持のワークアラウンド、依存関係の洗い出しまでまとめた。
目次
エラーの意味と代表メッセージ
ERROR: cannot change name of input parameter in function・既存の関数に対して、IN引数の「名前」だけを変えてCREATE OR REPLACEしたときに発生
・引数の「型や順序」は同一でも、IN引数の“名前”変更は不可
発生条件(まずここを疑う)
□ 既存: CREATE FUNCTION f(a int, b text) RETURNS int ...
置換: CREATE OR REPLACE FUNCTION f(x int, y text) RETURNS int ... -- ←NG
□ ALTER FUNCTIONで引数名を直接変えようとした -- PostgreSQLは未対応
□ OUT/INOUTではなく、IN引数名を変えようとした
□ 呼び出し側で named notation(f(b => 'txt', a => 1))を使う可能性がある関数なぜ禁止されているのか(背景)
・PostgreSQLは「名前付き引数呼び出し」をサポート
例: SELECT f(b => 'text', a => 1);
・IN引数名を置き換えると、既存アプリが実行時に誤解釈/失敗する
・そのため、CREATE OR REPLACEでIN引数名だけ変えることを禁止最短復旧:元のIN引数名をそのまま使う
-- 既存の引数名を戻して置き換える(本体の修正だけ行う)
CREATE OR REPLACE FUNCTION f(a int, b text)
RETURNS int
LANGUAGE plpgsql AS $$
BEGIN
-- 本体を必要に応じて更新
RETURN a + length(b);
END
$$;・パラメータ名の変更を取りやめれば即復旧できる
ワークアラウンド1:関数内部で“別名”に割り当てる(PL/pgSQL)
-- 見通しの良い内部変数名にしたいだけなら、ALIASで内部別名を付ける
CREATE OR REPLACE FUNCTION f(a int, b text)
RETURNS int
LANGUAGE plpgsql AS $$
DECLARE
user_id ALIAS FOR $1; -- a の別名
comment ALIAS FOR $2; -- b の別名
BEGIN
RETURN user_id + length(comment);
END
$$;・外向きのIN引数名(a,b)は維持しつつ、内部では意味のある名前で扱える
ワークアラウンド2:新関数(v2)を作り、旧関数をラッパ化
-- 新API(望む引数名)
CREATE OR REPLACE FUNCTION f_v2(user_id int, comment text)
RETURNS int
LANGUAGE plpgsql AS $$
BEGIN
RETURN user_id + length(comment);
END
$$;
-- 後方互換:旧APIは内部で新APIへ委譲
CREATE OR REPLACE FUNCTION f(a int, b text)
RETURNS int
LANGUAGE sql AS $$
SELECT f_v2(a, b);
$$;・既存の呼び出しを壊さずに“新しい名前のAPI”を併存できる
・十分な移行期間を設け、旧APIは段階的に廃止
恒久対策:本当にIN引数名を変える必要がある場合の手順
-- 1) 影響調査:呼び出し側で named notation を使っていないか確認
-- (DB内の依存はpg_depend、アプリコードはgrep/検索等)
-- 2) ドロップ&再作成(※すべての呼び出し箇所を書き換えた上で)
DROP FUNCTION IF EXISTS public.f(int, text);
CREATE FUNCTION public.f(user_id int, comment text)
RETURNS int
LANGUAGE plpgsql AS $$ ... $$;・CREATE OR REPLACEでは変えられないため、DROP → CREATE が唯一の方法
・当然ながら、呼び出し側(特にnamed notation使用箇所)を全面更新する
依存関係の洗い出し(DB内)
-- 対象関数のOIDを確認
SELECT 'public.f(int, text)'::regprocedure AS proc, oid FROM pg_proc
WHERE oid = 'public.f(int, text)'::regprocedure;
-- その関数に依存しているDBオブジェクトを列挙
SELECT pg_describe_object(d.classid, d.objid, d.objsubid) AS dependent
FROM pg_depend d
WHERE d.refobjid = 'public.f(int, text)'::regprocedure
ORDER BY 1;・ビュー/関数/トリガ/拡張など、DB内の依存を事前に把握できる
OUT/INOUTパラメータと戻り値に関する注意
・OUT/INOUTは“戻り値の列名”の意味も持つ
・名前変更は依存ビュー/SELECT * に影響し得るため慎重に
・型や戻り値の変更は CREATE OR REPLACE の範囲外(原則はDROP→CREATE)デフォルト引数・順序の変更での落とし穴
-- デフォルト値の追加/変更はCREATE OR REPLACEで可能だが、
-- named/position両方式の互換性に配慮すること
CREATE OR REPLACE FUNCTION f(a int, b text DEFAULT '')
RETURNS int AS $$ ... $$ LANGUAGE plpgsql;
-- 順序変更は推奨しない(position呼び出しが破綻する)最小再現→エラー→解消の通し例
-- 1) 準備:最初の定義
CREATE OR REPLACE FUNCTION f(a int, b text)
RETURNS int LANGUAGE plpgsql AS $$
BEGIN
RETURN a + length(b);
END $$;
-- 2) NG:IN引数名を変えて置換(エラー)
CREATE OR REPLACE FUNCTION f(x int, y text)
RETURNS int LANGUAGE plpgsql AS $$
BEGIN
RETURN x + length(y);
END $$;
-- ERROR: cannot change name of input parameter in function
-- 3) OK案A:引数名を戻し、内部で別名を付与
CREATE OR REPLACE FUNCTION f(a int, b text)
RETURNS int LANGUAGE plpgsql AS $$
DECLARE
user_id ALIAS FOR $1;
comment ALIAS FOR $2;
BEGIN
RETURN user_id + length(comment);
END $$;
-- 4) OK案B:新APIを作って旧APIから委譲
CREATE OR REPLACE FUNCTION f_v2(user_id int, comment text)
RETURNS int LANGUAGE plpgsql AS $$
BEGIN
RETURN user_id + length(comment);
END $$;
CREATE OR REPLACE FUNCTION f(a int, b text)
RETURNS int LANGUAGE sql AS $$
SELECT f_v2(a, b);
$$;
[/code]運用チェックリスト
□ named notation(argname => value)で呼ばれていないか全箇所を確認
□ DB内の依存(pg_depend)とアプリコードの両方を洗い出し
□ 互換維持が必要なら「内部ALIAS」または「v2 + ラッパ」方式を採用
□ どうしても改名するなら、DROP→CREATEと呼び出し側の一括修正を同一リリースで実施
□ OUT/INOUTや戻り値列名がビュー等に波及しないか点検
□ デフォルト引数や順序変更は慎重に(position/named両対応を考慮)まとめ:安全な改名の原則
・CREATE OR REPLACEでIN引数名は変えられない → 仕様
・見通しだけ改善したいなら内部ALIASで十分
・API改名は「新関数 + 旧ラッパ」で段階移行
・本当に改名が必要なら DROP→CREATE と呼び出し側修正をセットで-
前の記事
PostgreSQL『ERROR: update or delete on table violates foreign key constraint』の原因と対処 2025.09.19
-
次の記事
PostgreSQL『connection limit exceeded for non-superusers』の原因と対処 2025.09.24
コメントを書く