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

42P02
2026년 09월 12일 | DBMS Error 가이드

이 글에서 다루는 내용

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

42P02 undefined parameter 는?

PostgreSQL 에러 코드 42P02는 “undefined parameter”로, SQL 구문이나 함수/프로시저 내에서 참조된 파라미터($1, $2 등)가 정의되지 않았거나 존재하지 않을 때 발생합니다. 주로 prepared statement, PL/pgSQL 함수, 또는 동적 쿼리를 작성할 때 파라미터 바인딩이 올바르게 이루어지지 않은 경우에 나타납니다. 이 에러는 개발 단계뿐만 아니라 운영 환경에서도 빈번히 발생하므로, 원인을 정확히 파악하고 빠르게 해결하는 것이 중요합니다.


주요 발생 원인

1. Prepared Statement에서 파라미터 개수 불일치

Prepared statement를 작성할 때 선언한 파라미터 개수보다 더 많은 파라미터 플레이스홀더($1, $2, …)를 쿼리 본문에 사용하면 이 에러가 발생합니다. 예를 들어 PREPARE 구문에서 파라미터를 1개만 선언했는데, 쿼리 내부에서 $2를 참조하면 PostgreSQL은 해당 파라미터가 정의되지 않았다고 판단합니다. 이는 가장 흔하게 발생하는 원인 중 하나이며, 복잡한 쿼리일수록 실수가 발생하기 쉽습니다.

2. PL/pgSQL 함수 내 잘못된 파라미터 참조

PL/pgSQL 함수나 프로시저를 작성할 때 함수 시그니처에 선언되지 않은 파라미터 인덱스를 참조하거나, EXECUTE를 이용한 동적 SQL에서 USING 절의 파라미터와 쿼리 내 플레이스홀더의 순서 또는 개수가 맞지 않을 때 발생합니다. 동적 SQL은 런타임에 쿼리가 구성되므로 컴파일 타임에 오류를 잡기 어렵고, 실제 실행 시점에 42P02 에러가 발생하여 디버깅이 까다롭습니다. 특히 대형 프로젝트에서 동적 쿼리를 여러 곳에서 조합하는 경우 더욱 주의가 필요합니다.

3. 클라이언트 라이브러리 또는 ORM의 파라미터 바인딩 오류

Python의 psycopg2, Java의 JDBC, 또는 각종 ORM(SQLAlchemy, Hibernate 등)을 통해 쿼리를 실행할 때 파라미터 바인딩 방식이 올바르지 않으면 이 에러가 발생할 수 있습니다. 특히 라이브러리마다 파라미터 플레이스홀더 표기법이 다르기 때문에(%s, ?, $1 등), 잘못된 포맷을 사용하거나 파라미터 리스트가 비어 있을 때 PostgreSQL 서버로 잘못된 쿼리가 전달됩니다. ORM 업그레이드 이후 호환성 변경으로 인해 갑자기 발생하는 경우도 있어 주의가 필요합니다.


해결 방법

원인 1 해결: Prepared Statement 파라미터 개수 맞추기

PREPARE 구문에서 선언한 파라미터 타입의 개수와 쿼리 본문의 플레이스홀더 개수를 반드시 일치시켜야 합니다.

-- 잘못된 예시: 파라미터 1개 선언, $2 참조로 42P02 발생
PREPARE get_employee (INT) AS
  SELECT * FROM employees WHERE department_id = $1 AND salary > $2;

-- 올바른 예시: 파라미터 2개 선언
PREPARE get_employee (INT, NUMERIC) AS
  SELECT * FROM employees WHERE department_id = $1 AND salary > $2;

-- 실행
EXECUTE get_employee(10, 50000);

-- 사용 후 정리
DEALLOCATE get_employee;

원인 2 해결: PL/pgSQL 동적 SQL 파라미터 수정

EXECUTE … USING 구문 사용 시, 쿼리 문자열 내의 $1, $2 플레이스홀더와 USING 절의 값 목록을 정확히 대응시켜야 합니다.

-- 잘못된 예시: $2를 참조하지만 USING에 값이 1개뿐
CREATE OR REPLACE FUNCTION get_emp_by_dept(p_dept_id INT)
RETURNS TABLE(emp_name TEXT, salary NUMERIC) AS $$
DECLARE
  v_query TEXT;
BEGIN
  v_query := 'SELECT name, salary FROM employees WHERE department_id = $1 AND active = $2';
  -- 아래 USING에 $2에 해당하는 값이 없어 42P02 발생
  RETURN QUERY EXECUTE v_query USING p_dept_id;
END;
$$ LANGUAGE plpgsql;

-- 올바른 예시: USING에 $2 값도 함께 전달
CREATE OR REPLACE FUNCTION get_emp_by_dept(p_dept_id INT, p_active BOOLEAN DEFAULT TRUE)
RETURNS TABLE(emp_name TEXT, salary NUMERIC) AS $$
DECLARE
  v_query TEXT;
BEGIN
  v_query := 'SELECT name, salary FROM employees WHERE department_id = $1 AND active = $2';
  RETURN QUERY EXECUTE v_query USING p_dept_id, p_active;
END;
$$ LANGUAGE plpgsql;

-- 함수 호출 예시
SELECT * FROM get_emp_by_dept(10);
SELECT * FROM get_emp_by_dept(10, FALSE);

원인 3 해결: 클라이언트 라이브러리 파라미터 바인딩 수정

각 라이브러리에서 권장하는 파라미터 바인딩 방식을 확인하고, 플레이스홀더와 실제 파라미터 값의 개수를 일치시켜야 합니다.

-- PostgreSQL 네이티브 방식으로 직접 테스트할 때
-- psycopg2 스타일 확인용 (Python에서 %s 사용 권장)
-- 아래는 서버에서 직접 검증하는 방법:

-- 1단계: 현재 세션의 prepared statement 목록 확인
SELECT name, statement, parameter_types
FROM pg_prepared_statements;

-- 2단계: 문제가 되는 prepared statement 제거
DEALLOCATE ALL;

-- 3단계: 올바른 파라미터로 다시 준비
PREPARE safe_query (TEXT, INT, DATE) AS
  SELECT order_id, customer_name, order_date
  FROM orders
  WHERE customer_name = $1
    AND status_code = $2
    AND order_date >= $3;

-- 4단계: 실행 확인
EXECUTE safe_query('홍길동', 1, '2024-01-01');

추가: 동적 SQL에서 파라미터 검증 함수 활용

-- 파라미터 개수를 사전에 검증하는 헬퍼 함수 예시
CREATE OR REPLACE FUNCTION safe_dynamic_query(
  p_query TEXT,
  p_params ANYARRAY
) RETURNS VOID AS $$
DECLARE
  v_param_count INT;
BEGIN
  -- 쿼리 내 $N 패턴 개수 추출
  SELECT COUNT(DISTINCT match[1])
  INTO v_param_count
  FROM regexp_matches(p_query, '\$(\d+)', 'g') AS match;

  IF v_param_count <> array_length(p_params, 1) THEN
    RAISE EXCEPTION '파라미터 개수 불일치: 쿼리에 % 개 필요, % 개 제공됨',
      v_param_count, array_length(p_params, 1)
      USING ERRCODE = '42P02';
  END IF;

  RAISE NOTICE '파라미터 검증 통과: % 개', v_param_count;
END;
$$ LANGUAGE plpgsql;

예방 방법

1. Prepared Statement는 항상 pg_prepared_statements 뷰로 검증하라

운영 환경에 배포하기 전에 반드시 pg_prepared_statements 뷰를 통해 파라미터 타입과 개수를 사전에 검증하는 습관을 들여야 합니다. CI/CD 파이프라인에 쿼리 검증 단계를 추가하여, 파라미터 불일치가 운영 환경에 반영되기 전에 자동으로 감지하도록 구성하는 것이 Best Practice입니다. 특히 팀 단위 개발에서는 쿼리 리뷰 체크리스트에 파라미터 개수 확인 항목을 필수로 포함시키세요.

-- 배포 전 검증 쿼리
SELECT
  name,
  statement,
  parameter_types,
  array_length(parameter_types, 1) AS param_count,
  from_sql
FROM pg_prepared_statements
ORDER BY prepare_time DESC;

2. PL/pgSQL 함수에서 동적 SQL 사용 시 FORMAT() 함수를 적극 활용하라

동적 SQL을 문자열 연결(||)로 조합하면 파라미터 관리가 어렵고 SQL 인젝션에도 취약합니다. PostgreSQL의 FORMAT() 함수와 %L(리터럴), %I(식별자) 포맷 지정자를 사용하면 파라미터를 안전하게 쿼리에 삽입할 수 있으며, USING 절과 함께 사용하면 42P02 에러 발생 가능성을 크게 줄일 수 있습니다.

-- FORMAT()을 활용한 안전한 동적 쿼리 작성 예시
CREATE OR REPLACE FUNCTION get_table_stats(p_schema TEXT, p_table TEXT)
RETURNS TABLE(column_name TEXT, data_type TEXT) AS $$
DECLARE
  v_query TEXT;
BEGIN
  -- %I로 식별자를 안전하게 처리하고, $1은 USING으로 바인딩
  v_query := FORMAT(
    'SELECT column_name::TEXT, data_type::TEXT
     FROM information_schema.columns
     WHERE table_schema = %L
       AND table_name = %L
     ORDER BY ordinal_position',
    p_schema, p_table
  );

  RETURN QUERY EXECUTE v_query;
END;
$$ LANGUAGE plpgsql;

-- 사용 예시
SELECT * FROM get_table_stats('public', 'employees');

관련 에러

  • 42601 (syntax_error): 쿼리 문법 자체가 잘못된 경우로, 파라미터 플레이스홀더 위치가 문법적으로 허용되지 않는 곳에 사용될 때 함께 발생할 수 있습니다.
  • 42883 (undefined_function): 함수 호출 시 인수 타입이 맞지 않아 해당 함수를 찾지 못할 때 발생하며, 파라미터 타입 불일치 문제와 연관됩니다.
  • 08P01 (protocol_violation): 클라이언트가 PostgreSQL 프로토콜에 맞지 않는 방식으로 파라미터를 전송할 때 발생하며, 42P02와 함께 클라이언트 라이브러리 문제에서 동시에 나타나기도 합니다.
  • 22023 (invalid_parameter_value): 파라미터 자체는 정의되어 있지만, 그 값이 해당 컨텍스트에서 허용되지 않는 값일 때 발생합니다.
DBMS 에러 코드 시리즈

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

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

댓글 남기기