PostgreSQL 42723 오류 원인과 해결 방법 완벽 가이드

42723
2026년 07월 10일 | DBMS Error 가이드

이 글에서 다루는 내용

42723 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.

42723 duplicate function 란?

PostgreSQL 에러 코드 42723은 duplicate function 에러로, 동일한 이름과 동일한 인자 타입(시그니처)을 가진 함수가 같은 스키마 내에 이미 존재할 때 발생합니다. PostgreSQL은 함수 오버로딩을 지원하기 때문에 같은 이름이라도 인자의 타입이나 개수가 다르면 별개의 함수로 간주하지만, 시그니처까지 완전히 동일한 경우에는 이 에러를 발생시킵니다. 주로 CREATE FUNCTION 또는 CREATE PROCEDURE 구문을 실행할 때 발생하며, 마이그레이션 스크립트 중복 실행이나 팀 협업 환경에서 여러 개발자가 동시에 작업할 때 자주 마주치게 됩니다.


주요 발생 원인

1. 동일한 CREATE FUNCTION 스크립트의 중복 실행

마이그레이션 스크립트나 배포 자동화 파이프라인에서 같은 함수 생성 DDL이 두 번 이상 실행될 때 발생하는 가장 흔한 원인입니다. CI/CD 환경에서 멱등성(idempotency)을 고려하지 않고 스크립트를 작성하면, 재배포 시마다 에러가 반복됩니다. 특히 Flyway, Liquibase 같은 마이그레이션 도구를 사용하지 않거나 잘못 설정한 경우에 빈번하게 발생합니다.

2. OR REPLACE 키워드 누락

기존에 존재하는 함수를 수정하려는 의도로 CREATE FUNCTION을 실행하면서 OR REPLACE 옵션을 빠뜨린 경우입니다. 개발자가 함수의 로직을 변경하거나 버그를 수정할 때, 기존 함수를 먼저 삭제하지 않고 그냥 CREATE FUNCTION만 실행하면 동일 시그니처 충돌로 인해 이 에러가 발생합니다. 특히 다른 RDBMS(Oracle, MySQL 등)에서 PostgreSQL로 전환한 경우, 다른 DB의 CREATE OR REPLACE 문법 습관이 없어 자주 발생합니다.

3. 스키마 혼동 또는 search_path 설정 오류

search_path가 잘못 설정되어 개발자가 의도한 스키마와 다른 스키마에 함수가 이미 생성되어 있는 경우입니다. 예를 들어 public 스키마에 이미 동일 함수가 존재하는데, search_pathpublic을 먼저 탐색하도록 설정되어 있으면 다른 스키마에 함수를 생성하려는 시도가 충돌을 일으킬 수 있습니다. 멀티 테넌트 아키텍처나 스키마 분리 전략을 사용하는 대규모 시스템에서 특히 주의가 필요합니다.


해결 방법

원인 1 해결 — CREATE OR REPLACE FUNCTION 사용

가장 간단하고 권장되는 해결책은 CREATE OR REPLACE FUNCTION을 사용하는 것입니다. 이 구문은 함수가 없으면 새로 생성하고, 이미 있으면 대체합니다.

-- 문제가 되는 코드
CREATE FUNCTION calculate_discount(price NUMERIC, rate NUMERIC)
RETURNS NUMERIC AS $$
BEGIN
    RETURN price * rate;
END;
$$ LANGUAGE plpgsql;

-- 해결된 코드: OR REPLACE 추가
CREATE OR REPLACE FUNCTION calculate_discount(price NUMERIC, rate NUMERIC)
RETURNS NUMERIC AS $$
BEGIN
    RETURN price * (1 - rate);
END;
$$ LANGUAGE plpgsql;

> ⚠️ 주의: CREATE OR REPLACE FUNCTION은 함수의 반환 타입을 변경할 수 없습니다. 반환 타입 변경이 필요하다면 아래 방법(DROP 후 재생성)을 사용해야 합니다.


원인 2 해결 — DROP 후 재생성 (반환 타입 변경 시)

반환 타입을 변경해야 하는 경우에는 기존 함수를 먼저 삭제한 후 재생성해야 합니다.

-- 기존 함수 삭제 (CASCADE: 의존 객체도 함께 삭제)
DROP FUNCTION IF EXISTS calculate_discount(NUMERIC, NUMERIC);

-- 반환 타입을 변경하여 재생성
CREATE FUNCTION calculate_discount(price NUMERIC, rate NUMERIC)
RETURNS FLOAT AS $$
BEGIN
    RETURN price * (1 - rate);
END;
$$ LANGUAGE plpgsql;

IF EXISTS 옵션을 사용하면 함수가 없을 때도 에러 없이 실행할 수 있어 스크립트의 멱등성을 보장합니다.


원인 3 해결 — 스키마 명시 및 search_path 확인

함수 생성 전에 현재 search_path와 스키마 내 함수 존재 여부를 반드시 확인하세요.

-- 현재 search_path 확인
SHOW search_path;

-- 특정 스키마에 동일 함수가 있는지 확인
SELECT n.nspname AS schema_name,
       p.proname AS function_name,
       pg_get_function_identity_arguments(p.oid) AS arguments
FROM pg_proc p
JOIN pg_namespace n ON p.pronamespace = n.oid
WHERE p.proname = 'calculate_discount';

-- 스키마를 명시하여 함수 생성
CREATE OR REPLACE FUNCTION myapp_schema.calculate_discount(price NUMERIC, rate NUMERIC)
RETURNS NUMERIC AS $$
BEGIN
    RETURN price * (1 - rate);
END;
$$ LANGUAGE plpgsql;

멱등성 보장을 위한 완전한 스크립트 패턴

실무 마이그레이션 환경에서 안전하게 사용할 수 있는 패턴입니다.

-- 트랜잭션 내에서 안전하게 처리
BEGIN;

-- 함수 존재 여부와 무관하게 항상 성공하는 패턴
DROP FUNCTION IF EXISTS myapp_schema.calculate_discount(NUMERIC, NUMERIC);

CREATE FUNCTION myapp_schema.calculate_discount(price NUMERIC, rate NUMERIC)
RETURNS NUMERIC AS $$
BEGIN
    IF rate < 0 OR rate > 1 THEN
        RAISE EXCEPTION 'Rate must be between 0 and 1, got: %', rate;
    END IF;
    RETURN price * (1 - rate);
END;
$$ LANGUAGE plpgsql
   SECURITY DEFINER
   SET search_path = myapp_schema, public;

COMMENT ON FUNCTION myapp_schema.calculate_discount(NUMERIC, NUMERIC)
IS '상품 할인가 계산 함수. rate는 0~1 사이 소수값으로 입력';

COMMIT;

예방 방법

1. 모든 함수 생성 스크립트에 CREATE OR REPLACE 패턴 표준화

팀 내 코딩 컨벤션으로 CREATE FUNCTION 대신 항상 CREATE OR REPLACE FUNCTION을 사용하도록 강제하세요. pg_dump로 백업 후 복원하는 경우에도 이 패턴이 적용되어 있으면 중복 실행에 안전합니다. 코드 리뷰 체크리스트나 린터(예: sqlfluff)에 해당 규칙을 추가하여 PR 단계에서 걸러낼 수 있도록 하는 것이 이상적입니다.

-- 팀 표준 함수 생성 템플릿
CREATE OR REPLACE FUNCTION schema_name.function_name(
    param1 DATA_TYPE,
    param2 DATA_TYPE
)
RETURNS RETURN_TYPE
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = schema_name, public
AS $$
BEGIN
    -- 함수 본문
END;
$$;

2. 함수 레지스트리 관리 및 배포 전 사전 검증 자동화

배포 파이프라인에서 함수를 생성하기 전에 기존 함수 목록을 조회하고 시그니처 충돌 여부를 자동으로 검증하는 단계를 추가하세요. 아래 쿼리를 배포 전 검증 스크립트로 활용할 수 있습니다.

-- 배포 전 함수 목록 검증 쿼리
SELECT
    n.nspname                                          AS schema_name,
    p.proname                                          AS function_name,
    pg_get_function_identity_arguments(p.oid)          AS arguments,
    pg_get_function_result(p.oid)                      AS return_type,
    p.prosecdef                                        AS security_definer,
    p.provolatile                                      AS volatility,
    obj_description(p.oid, 'pg_proc')                  AS description
FROM pg_proc p
JOIN pg_namespace n ON p.pronamespace = n.oid
WHERE n.nspname NOT IN ('pg_catalog', 'information_schema')
ORDER BY n.nspname, p.proname;

관련 에러

  • 42710 (duplicate_object): 이미 존재하는 객체(테이블, 인덱스 등)를 다시 생성하려 할 때 발생하는 유사 에러입니다.
  • 42P13 (invalid_function_definition): 함수 정의 자체가 잘못된 경우 발생하며, 반환 타입 불일치나 언어 지정 오류 시 나타납니다.
  • 0A000 (feature_not_supported): CREATE OR REPLACE로 함수의 반환 타입을 변경하려 할 때 발생하며, 이 경우 반드시 DROP 후 재생성이 필요합니다.
  • 2BP01 (dependent_objects_exist): 함수를 삭제할 때 해당 함수에 의존하는 뷰나 다른 함수가 있는 경우 발생합니다. DROP FUNCTION ... CASCADE 사용 시 주의가 필요합니다.

DBMS 에러 코드 시리즈

주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.

본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.

댓글 남기기