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

42P18
2026년 09월 10일 | DBMS Error 가이드

이 글에서 다루는 내용

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

42P18 indeterminate datatype 는?

PostgreSQL 에러 코드 42P18은 쿼리 파서 또는 플래너가 특정 표현식의 데이터 타입을 결정할 수 없을 때 발생하는 에러입니다. 주로 NULL 리터럴, 파라미터 바인딩($1, $2 등), 또는 타입 정보가 없는 배열 리터럴처럼 문맥만으로 타입을 추론하기 어려운 상황에서 나타납니다. PostgreSQL은 강타입(strongly typed) 시스템을 채택하고 있어, 모든 표현식은 실행 계획을 세우기 전에 정확한 데이터 타입이 확정되어야 하며, 이를 확정하지 못하면 indeterminate datatype 에러를 발생시킵니다.

주요 발생 원인

  • 타입 캐스팅 없이 사용된 NULL 리터럴

가장 흔한 원인으로, NULL 자체는 어떤 타입도 될 수 있기 때문에 PostgreSQL이 문맥만으로 타입을 추론하지 못하는 경우가 많습니다. 특히 함수 오버로딩이 존재하거나, UNION, CASE 구문 내에서 단독으로 NULL을 사용할 때 에러가 발생합니다. 플리너가 어떤 타입의 NULL인지 판단하지 못하면 실행 계획 자체를 수립할 수 없습니다.

  • 바인딩 파라미터($1, $2)의 타입 미지정

Prepared Statement나 PL/pgSQL에서 $1, $2와 같은 파라미터를 사용할 때, 해당 파라미터의 타입 정보가 전달되지 않거나 추론할 수 없는 경우에 발생합니다. 예를 들어, SELECT $1처럼 파라미터 단독으로 쓰이거나, 함수 인자로 전달할 때 여러 오버로드 중 어떤 것을 선택해야 할지 모호한 상황이 이에 해당합니다. 클라이언트 라이브러리에서 타입 OID를 명시하지 않으면 동일한 문제가 발생합니다.

  • 타입 정보 없는 배열 리터럴 또는 복합 표현식 사용

ARRAY[]와 같이 빈 배열 리터럴을 사용하거나, 요소 타입이 명시되지 않은 배열을 함수나 연산자에 전달할 때 발생합니다. 또한 ROW() 생성자나 복합 타입 생성 시에도 각 필드의 타입이 문맥에서 유추되지 않으면 동일한 에러가 발생할 수 있습니다. 이는 동적 SQL을 생성하는 애플리케이션에서 특히 자주 발생합니다.

해결 방법

원인 1: NULL 리터럴에 명시적 타입 캐스팅 추가

문제가 되는 쿼리:

-- 에러 발생: NULL의 타입을 알 수 없음
SELECT COALESCE(NULL, NULL);

-- 에러 발생: UNION에서 NULL 타입 불명확
SELECT NULL
UNION ALL
SELECT NULL;

해결된 쿼리:

-- NULL에 명시적 타입 캐스팅
SELECT COALESCE(NULL::INTEGER, NULL::INTEGER);

-- UNION에서 타입 명시
SELECT NULL::TEXT AS col
UNION ALL
SELECT NULL::TEXT;

-- CASE 구문에서도 동일하게 적용
SELECT CASE
    WHEN 1 = 1 THEN NULL::VARCHAR(100)
    ELSE 'some value'
END;

원인 2: 바인딩 파라미터에 타입 명시

문제가 되는 쿼리:

-- 에러 발생: $1의 타입을 결정할 수 없음
PREPARE my_stmt AS SELECT $1;

-- psql에서 타입 없이 파라미터 사용
PREPARE bad_example AS
    SELECT * FROM users WHERE id = $1 OR name = $1;

해결된 쿼리:

-- 타입을 명시하여 Prepared Statement 작성
PREPARE my_stmt(INTEGER) AS SELECT $1;
EXECUTE my_stmt(42);

-- 파라미터에 캐스팅 추가
PREPARE good_example(INTEGER, TEXT) AS
    SELECT * FROM users WHERE id = $1 OR name = $2;
EXECUTE good_example(1, 'Alice');

-- PL/pgSQL 함수 내에서 타입 명시
CREATE OR REPLACE FUNCTION get_value(p_input TEXT)
RETURNS TEXT AS $$
BEGIN
    RETURN p_input::TEXT;
END;
$$ LANGUAGE plpgsql;

원인 3: 배열 리터럴 및 복합 표현식에 타입 명시

문제가 되는 쿼리:

-- 에러 발생: 빈 배열의 타입 불명확
SELECT ARRAY[];

-- 에러 발생: 타입 없는 배열을 함수에 전달
SELECT unnest(ARRAY[]);

-- ROW 생성자 타입 불명확
SELECT ROW(NULL, NULL);

해결된 쿼리:

-- 배열 타입 명시
SELECT ARRAY[]::INTEGER[];
SELECT ARRAY[]::TEXT[];

-- unnest에 타입이 명확한 배열 전달
SELECT unnest(ARRAY[]::TEXT[]);
SELECT unnest(ARRAY['a', 'b', 'c']::TEXT[]);

-- ROW 생성자에 타입 캐스팅
SELECT ROW(NULL::INTEGER, NULL::TEXT);

-- 복합 타입 사용 시 타입 명시
SELECT (NULL::myschema.my_composite_type).*;

-- 동적 SQL에서 FORMAT 활용
DO $$
DECLARE
    v_sql TEXT;
BEGIN
    v_sql := FORMAT('SELECT %L::INTEGER', '42');
    EXECUTE v_sql;
END;
$$;

애플리케이션 레벨 해결 (예: Python psycopg2)

-- 서버 사이드: 타입이 명확한 파라미터 사용
PREPARE typed_stmt(UUID, TIMESTAMPTZ) AS
    INSERT INTO events (id, created_at)
    VALUES ($1, $2);
# Python psycopg2에서 타입 OID 명시
import psycopg2
from psycopg2 import sql

conn = psycopg2.connect("dbname=mydb")
cur = conn.cursor()

# 타입을 명시하여 파라미터 전달
cur.execute(
    "SELECT %s::integer, %s::text",
    (42, 'hello')
)

예방 방법

  • 코딩 표준으로 명시적 타입 캐스팅 의무화

팀 내 SQL 코딩 컨벤션에 “NULL 리터럴 및 바인딩 파라미터 사용 시 반드시 명시적 캐스팅을 추가한다”는 규칙을 포함시키세요. 코드 리뷰 체크리스트에 해당 항목을 추가하고, 가능하다면 정적 분석 도구(예: SQLFluff, pgTAP)를 CI/CD 파이프라인에 통합하여 자동 검사를 수행하도록 합니다. 특히 ORM을 사용하더라도 raw query를 작성할 때는 반드시 이 규칙을 적용해야 합니다.

  • Prepared Statement 작성 시 파라미터 타입 명시 습관화

PREPARE 구문을 사용할 때는 항상 파라미터 타입을 명시하는 습관을 들이세요. 클라이언트 라이브러리(JDBC, psycopg2, libpq 등)에서 파라미터를 바인딩할 때도 타입 OID를 명시적으로 지정하는 방식을 표준으로 삼으면, 런타임에 발생할 수 있는 42P18 에러를 사전에 방지할 수 있습니다. 또한 스테이징 환경에서 충분한 쿼리 테스트를 거친 후 프로덕션에 배포하는 프로세스를 준수하면 이러한 문제를 조기에 발견할 수 있습니다.

관련 에러

  • 42883 (undefined_function): 타입이 맞지 않아 해당하는 함수 오버로드를 찾지 못할 때 발생하며, 42P18과 함께 자주 연쇄 발생합니다.
  • 42804 (datatype_mismatch): 표현식의 타입이 기대하는 타입과 다를 때 발생하며, 타입 캐스팅 누락 시 나타납니다.
  • 42P08 (ambiguous_parameter): 함수 호출 시 파라미터가 여러 오버로드에 모두 적용 가능하여 모호할 때 발생합니다.
  • 42702 (ambiguous_column): 컬럼 참조가 모호할 때 발생하며, 타입 추론 실패와 유사한 맥락에서 나타날 수 있습니다.

DBMS 에러 코드 시리즈

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

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

댓글 남기기