2026년 10월 19일 | DBMS Error 가이드
이 글에서 다루는 내용
2200G 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.
2200G most specific type mismatch 는?
PostgreSQL 에러 코드 2200G는 most specific type mismatch로, SQL 표준에서 정의된 타입 계층 구조에서 가장 구체적인 타입(most specific type)이 일치하지 않을 때 발생하는 에러입니다. 주로 사용자 정의 타입(UDT), 구조화된 타입(structured type), 또는 XML/JSON 등의 복합 데이터 타입을 다루는 함수나 프로시저에서 인자 타입이 기대하는 타입과 정확히 맞지 않을 때 나타납니다. 특히 PostgreSQL에서 다형성 함수(polymorphic function)나 오버로딩된 함수를 호출할 때 컴파일러가 가장 적합한 함수 시그니처를 찾지 못하는 경우에도 이 에러가 트리거될 수 있습니다.
주요 발생 원인
- 함수 인자의 타입 불일치 (Type Mismatch in Function Arguments)
PostgreSQL에서 함수를 정의할 때 특정 타입을 요구하는 파라미터에 호환되지 않는 타입의 값을 전달하면 이 에러가 발생합니다. 예를 들어, anyelement 또는 사용자 정의 도메인 타입을 파라미터로 받는 함수에 잘못된 캐스팅 없이 다른 타입의 값을 넣으면 PostgreSQL은 가장 구체적인 타입을 결정하지 못합니다. 이는 특히 PL/pgSQL 함수 내부에서 변수 선언 타입과 실제 할당되는 값의 타입이 다를 때 자주 발생합니다.
- 복합 타입(Composite Type) 또는 도메인 타입 사용 시 불일치
PostgreSQL은 복합 타입이나 도메인 타입을 다룰 때 타입 계층 구조를 엄격하게 검사합니다. 부모 타입(base type)으로 선언된 컬럼이나 변수에 자식 도메인 타입의 값을 대입하거나, 반대로 더 구체적인 타입을 요구하는 곳에 범용 타입을 넣으려 할 때 에러가 발생합니다. 특히 CREATE DOMAIN으로 만든 도메인 타입은 기반 타입과 완전히 동일하지 않기 때문에, 명시적인 캐스트 없이는 함수 오버로딩 해결 과정에서 충돌이 생길 수 있습니다.
- 다형성 함수(Polymorphic Function)에서의 타입 추론 실패
PostgreSQL은 anyelement, anyarray, anynonarray, anyrange 등의 다형성 타입을 지원합니다. 이러한 다형성 함수를 호출할 때 PostgreSQL 내부적으로 실제 타입을 추론하는데, 여러 인자가 서로 다른 구체적인 타입을 가리킬 경우 타입 추론에 실패하여 2200G 에러가 발생합니다. 특히 함수에 anyelement 파라미터가 두 개 이상 있는데 각각 다른 타입의 인자를 전달하면 “most specific type”을 결정할 수 없어 에러로 이어집니다.
해결 방법
원인 1 해결: 명시적 타입 캐스팅 사용
함수 호출 시 인자에 명시적인 타입 캐스팅을 추가하여 PostgreSQL이 정확한 타입을 인식하도록 합니다.
-- 문제 발생 예시: 타입 불일치
CREATE OR REPLACE FUNCTION get_value(p_input anyelement)
RETURNS anyelement AS $$
BEGIN
RETURN p_input;
END;
$$ LANGUAGE plpgsql;
-- 잘못된 호출 (정수와 텍스트 혼합)
SELECT get_value(1), get_value('hello'); -- 에러 발생 가능
-- 해결: 명시적 캐스팅으로 타입 명확화
SELECT get_value(1::integer);
SELECT get_value('hello'::text);
-- 또는 함수 자체를 구체적인 타입으로 오버로딩
CREATE OR REPLACE FUNCTION get_value(p_input integer)
RETURNS integer AS $$
BEGIN
RETURN p_input;
END;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION get_value(p_input text)
RETURNS text AS $$
BEGIN
RETURN p_input;
END;
$$ LANGUAGE plpgsql;
원인 2 해결: 도메인 타입 사용 시 명시적 캐스트 추가
-- 도메인 타입 정의
CREATE DOMAIN positive_integer AS integer CHECK (VALUE > 0);
-- 문제 발생 예시
CREATE OR REPLACE FUNCTION process_positive(val positive_integer)
RETURNS text AS $$
BEGIN
RETURN '값: ' || val::text;
END;
$$ LANGUAGE plpgsql;
-- 일반 integer를 그냥 넣으면 타입 불일치 가능
-- SELECT process_positive(5); -- 경우에 따라 에러
-- 해결: 명시적 도메인 타입 캐스팅
SELECT process_positive(5::positive_integer);
-- 또는 함수 파라미터를 기반 타입으로 받고 내부에서 검증
CREATE OR REPLACE FUNCTION process_positive_safe(val integer)
RETURNS text AS $$
BEGIN
IF val <= 0 THEN
RAISE EXCEPTION '양수만 허용됩니다: %', val;
END IF;
RETURN '값: ' || val::text;
END;
$$ LANGUAGE plpgsql;
SELECT process_positive_safe(5);
원인 3 해결: 다형성 함수에서 타입 통일
-- 문제 발생 예시: anyelement에 다른 타입 전달
CREATE OR REPLACE FUNCTION compare_values(a anyelement, b anyelement)
RETURNS boolean AS $$
BEGIN
RETURN a = b;
END;
$$ LANGUAGE plpgsql;
-- 에러 발생: a와 b의 타입이 다름
-- SELECT compare_values(1, 'hello'); -- 2200G 에러!
-- 해결 1: 같은 타입으로 맞춰서 호출
SELECT compare_values(1::integer, 2::integer);
SELECT compare_values('foo'::text, 'bar'::text);
-- 해결 2: 타입을 명확히 지정한 별도 함수 작성
CREATE OR REPLACE FUNCTION compare_int(a integer, b integer)
RETURNS boolean AS $$
BEGIN
RETURN a = b;
END;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION compare_text(a text, b text)
RETURNS boolean AS $$
BEGIN
RETURN a = b;
END;
$$ LANGUAGE plpgsql;
-- 타입 안전하게 호출
SELECT compare_int(10, 20);
SELECT compare_text('PostgreSQL', 'DBA');
-- 해결 3: 내부 캐스팅을 통한 유연한 비교 함수
CREATE OR REPLACE FUNCTION compare_as_text(a text, b text)
RETURNS boolean AS $$
BEGIN
RETURN a = b;
END;
$$ LANGUAGE plpgsql;
-- 호출 시 text로 캐스팅
SELECT compare_as_text(1::text, 1::text);
SELECT compare_as_text(now()::text, now()::text);
PL/pgSQL 내부 변수 타입 불일치 해결
-- 문제: 변수 타입과 할당 타입 불일치
CREATE OR REPLACE FUNCTION bad_type_function()
RETURNS void AS $$
DECLARE
v_num integer;
BEGIN
-- 잘못된 예: numeric을 integer 변수에 직접 할당
v_num := 3.14; -- 암묵적 truncation, 경우에 따라 에러
END;
$$ LANGUAGE plpgsql;
-- 해결: 명시적 캐스팅 또는 올바른 타입 선언
CREATE OR REPLACE FUNCTION good_type_function()
RETURNS void AS $$
DECLARE
v_num integer;
v_float numeric;
BEGIN
v_float := 3.14;
v_num := v_float::integer; -- 명시적 캐스팅
RAISE NOTICE '정수 값: %', v_num;
END;
$$ LANGUAGE plpgsql;
SELECT good_type_function();
예방 방법
- 함수 설계 시 구체적인 타입 명시 원칙 준수
함수를 설계할 때는 가능한 한 anyelement와 같은 추상적인 다형성 타입 대신 구체적인 데이터 타입을 사용하고, 필요한 경우 동일한 이름의 함수를 여러 타입으로 오버로딩하는 방식을 채택하세요. 또한 코드 리뷰 단계에서 함수 시그니처와 호출부의 타입을 반드시 대조 확인하고, CI/CD 파이프라인에 정적 분석 도구(예: pgTAP 테스트 프레임워크)를 도입하여 타입 불일치를 사전에 검출하는 체계를 마련하세요.
“`sql
— Best Practice: 구체적 타입 오버로딩
CREATE OR REPLACE FUNCTION safe_add(a integer, b integer) RETURNS integer AS $$
SELECT a + b;
$$ LANGUAGE sql IMMUTABLE STRICT;
CREATE OR REPLACE FUNCTION safe_add(a numeric, b numeric) RETURNS numeric AS $$
SELECT a + b;
$$ LANGUAGE sql IMMUTABLE STRICT;
“`
- 도메인 타입 및 복합 타입 사용 시 캐스팅 레이어 명문화
조직 내 PostgreSQL 코딩 컨벤션에 “도메인 타입이나 복합 타입을 함수 인자로 전달할 때는 반드시 명시적 캐스팅을 사용한다”는 규칙을 문서화하세요. 또한 공통 유틸리티 함수를 만들어 타입 변환 로직을 중앙화하면, 분산된 캐스팅 코드로 인한 실수를 줄이고 유지보수성을 높일 수 있습니다.
“`sql
— Best Practice: 타입 변환 유틸리티 함수 중앙화
CREATE OR REPLACE FUNCTION to_positive_int(val anyelement)
RETURNS positive_integer AS $$
BEGIN
RETURN val::integer::positive_integer;
EXCEPTION
WHEN OTHERS THEN
RAISE EXCEPTION ‘양수 정수로 변환 불가: % (타입: %)’, val, pg_typeof(val);
END;
$$ LANGUAGE plpgsql;
“`
관련 에러
- 42804 (datatype_mismatch): 가장 자주 혼동되는 에러로, 컬럼이나 표현식의 데이터 타입이 예상 타입과 다를 때 발생합니다. 2200G보다 더 일반적인 타입 불일치 상황에서 나타납니다.
- 42883 (undefined_function): 주어진 인자 타입의 조합에 맞는 함수를 찾지 못할 때 발생하며, 다형성 함수 오버로딩 실패와 밀접한 관련이 있습니다.
- 22023 (invalid_parameter_value): 함수나 연산자에 전달된 파라미터 값이 유효하지 않을 때 발생하며, 타입은 맞지만 값의 범위나 형식이 잘못된 경우에 해당합니다.
- 42P18 (indeterminate_datatype): 데이터 타입을 결정할 수 없을 때 발생하는 에러로,
NULL리터럴이나 타입이 명확하지 않은 표현식을 사용할 때 주로 나타납니다.
주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.
본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.