2026년 09월 16일 | DBMS Error 가이드
이 글에서 다루는 내용
42P13 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.
42P13 invalid function definition 는?
PostgreSQL 에러 코드 42P13은 함수(Function) 또는 프로시저(Procedure)를 생성하거나 수정할 때 함수 정의 자체가 잘못되었을 경우 발생합니다. 이 에러는 단순한 문법 오류와는 달리, 함수의 구조적 정의 — 예를 들어 반환 타입, 언어 지정, 함수 속성 등의 논리적 모순 — 에서 비롯됩니다. 주로 CREATE FUNCTION, CREATE OR REPLACE FUNCTION, CREATE PROCEDURE 구문을 실행할 때 발생하며, 특히 복잡한 PL/pgSQL 함수나 트리거 함수를 작성할 때 자주 마주치게 됩니다.
주요 발생 원인
1. 트리거 함수의 반환 타입 오류
트리거 함수는 반드시 RETURNS TRIGGER로 선언되어야 하며, 함수 본문 내에서는 RETURN NEW, RETURN OLD, 또는 RETURN NULL을 반환해야 합니다. 만약 RETURNS void나 RETURNS integer처럼 트리거가 아닌 타입을 반환하도록 선언한 뒤 트리거로 등록하거나, 반대로 RETURNS TRIGGER로 선언했음에도 일반 함수처럼 사용하려고 하면 이 에러가 발생합니다. 이는 실무에서 신규 개발자들이 가장 자주 저지르는 실수 중 하나입니다.
2. LANGUAGE 절 누락 또는 잘못된 언어 지정
PostgreSQL에서 함수를 정의할 때는 반드시 LANGUAGE 절을 명시해야 하며, 지원되지 않는 언어를 지정하거나 아예 누락하면 42P13 에러가 발생합니다. 예를 들어 LANGUAGE plpgsql 대신 오타로 LANGUAGE plpgsq 혹은 설치되지 않은 LANGUAGE python을 지정하는 경우가 해당됩니다. 또한 SQL 함수에서 PL/pgSQL 전용 문법(DECLARE, BEGIN...END 블록 등)을 사용하는 것도 이 원인에 해당합니다.
3. RETURNS TABLE과 OUT 파라미터 혼용
RETURNS TABLE(...)과 OUT 파라미터를 동시에 사용하는 것은 PostgreSQL에서 허용되지 않습니다. 두 방식 모두 함수의 출력 구조를 정의하는 방법이기 때문에 함께 사용하면 정의 충돌이 발생하여 42P13 에러를 유발합니다. 실무에서 기존 함수를 리팩터링하거나 타 DB에서 마이그레이션할 때 이런 혼용 실수가 종종 발생합니다.
해결 방법
원인 1 해결: 트리거 함수 반환 타입 수정
잘못된 예시:
-- 잘못된 트리거 함수 정의 (RETURNS void 사용)
CREATE OR REPLACE FUNCTION update_timestamp()
RETURNS void
LANGUAGE plpgsql
AS $$
BEGIN
NEW.updated_at := NOW();
RETURN NEW; -- 42P13 에러 발생!
END;
$$;
올바른 예시:
-- 올바른 트리거 함수 정의 (RETURNS TRIGGER 사용)
CREATE OR REPLACE FUNCTION update_timestamp()
RETURNS TRIGGER
LANGUAGE plpgsql
AS $$
BEGIN
NEW.updated_at := NOW();
RETURN NEW;
END;
$$;
-- 트리거 등록
CREATE TRIGGER trg_update_timestamp
BEFORE UPDATE ON orders
FOR EACH ROW
EXECUTE FUNCTION update_timestamp();
원인 2 해결: LANGUAGE 절 올바르게 지정
잘못된 예시:
-- LANGUAGE 누락 또는 오타
CREATE OR REPLACE FUNCTION get_user_count()
RETURNS INTEGER
AS $$
BEGIN
RETURN (SELECT COUNT(*) FROM users);
END;
$$;
-- ERROR: 42P13: no language specified
올바른 예시:
-- PL/pgSQL 함수로 올바르게 정의
CREATE OR REPLACE FUNCTION get_user_count()
RETURNS INTEGER
LANGUAGE plpgsql
AS $$
BEGIN
RETURN (SELECT COUNT(*) FROM users);
END;
$$;
-- 또는 단순 SQL 함수로 정의할 경우
CREATE OR REPLACE FUNCTION get_user_count()
RETURNS INTEGER
LANGUAGE sql
AS $$
SELECT COUNT(*)::INTEGER FROM users;
$$;
설치된 언어 확인 방법:
-- 현재 DB에서 사용 가능한 언어 목록 확인
SELECT lanname, lanpltrusted
FROM pg_language
ORDER BY lanname;
원인 3 해결: RETURNS TABLE과 OUT 파라미터 혼용 제거
잘못된 예시:
-- RETURNS TABLE과 OUT 파라미터 혼용 (42P13 에러 발생)
CREATE OR REPLACE FUNCTION get_active_users(
OUT user_id INTEGER,
OUT user_name TEXT
)
RETURNS TABLE(user_id INTEGER, user_name TEXT) -- 충돌!
LANGUAGE plpgsql
AS $$
BEGIN
RETURN QUERY SELECT id, name FROM users WHERE active = TRUE;
END;
$$;
올바른 예시 (RETURNS TABLE 단독 사용):
-- RETURNS TABLE만 사용하는 올바른 방법
CREATE OR REPLACE FUNCTION get_active_users()
RETURNS TABLE(user_id INTEGER, user_name TEXT)
LANGUAGE plpgsql
AS $$
BEGIN
RETURN QUERY
SELECT id, name
FROM users
WHERE active = TRUE;
END;
$$;
-- 호출 방법
SELECT * FROM get_active_users();
올바른 예시 (OUT 파라미터 단독 사용):
-- OUT 파라미터만 사용하는 올바른 방법
CREATE OR REPLACE FUNCTION get_user_info(
IN p_user_id INTEGER,
OUT user_name TEXT,
OUT user_email TEXT
)
LANGUAGE plpgsql
AS $$
BEGIN
SELECT name, email
INTO user_name, user_email
FROM users
WHERE id = p_user_id;
END;
$$;
-- 호출 방법
SELECT * FROM get_user_info(1);
예방 방법
1. 함수 작성 전 템플릿 표준화
팀 내에서 함수 유형별(일반 함수, 트리거 함수, 집계 함수 등) 표준 템플릿을 미리 정의하고 공유하세요. 트리거 함수는 항상 RETURNS TRIGGER를, 일반 함수는 반드시 LANGUAGE 절을 포함한 템플릿을 사용하면 실수를 크게 줄일 수 있습니다. CI/CD 파이프라인에 pg_dump나 스키마 검증 스크립트를 포함시켜 배포 전에 자동으로 검증하는 프로세스를 갖추는 것이 이상적입니다.
-- 트리거 함수 표준 템플릿
CREATE OR REPLACE FUNCTION schema_name.function_name()
RETURNS TRIGGER
LANGUAGE plpgsql
SECURITY DEFINER -- 필요 시 추가
AS $$
BEGIN
-- 로직 작성
RETURN NEW; -- INSERT/UPDATE는 NEW, DELETE는 OLD
END;
$$;
2. 개발 환경에서 사전 검증 및 코드 리뷰 프로세스 도입
운영 환경에 적용하기 전에 반드시 개발/스테이징 환경에서 함수를 먼저 실행해보고, \df+ 함수명 명령어로 함수 정의를 확인하는 습관을 들이세요. 또한 pg_proc 시스템 카탈로그를 활용하면 함수 정의의 세부 내용을 조회하여 이상 여부를 사전에 파악할 수 있습니다.
-- 함수 정의 상세 확인
SELECT
p.proname AS function_name,
pg_get_function_result(p.oid) AS return_type,
pg_get_function_arguments(p.oid) AS arguments,
l.lanname AS language,
p.prosrc AS source_code
FROM pg_proc p
JOIN pg_language l ON p.prolang = l.oid
WHERE p.proname = 'your_function_name'
AND p.pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'public');
관련 에러
42601(syntax_error): SQL 문법 자체의 오류로,42P13과 혼동하기 쉽지만42601은 파서 수준의 문법 오류이고42P13은 함수 정의의 의미론적 오류입니다.42883(undefined_function): 존재하지 않는 함수를 호출할 때 발생하며, 함수가 잘못 정의되어 생성 자체가 실패한 경우 후속으로 이 에러가 나타날 수 있습니다.0A000(feature_not_supported): 특정 PostgreSQL 버전에서 지원하지 않는 함수 기능을 사용할 때 발생하며,42P13과 유사한 상황에서 마주칠 수 있습니다.42P16(invalid_table_definition): 테이블 정의 오류로, 함수 정의 오류인42P13의 테이블 버전에 해당합니다.
주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.
본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.