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

2202E
2026년 08월 08일 | DBMS Error 가이드

이 글에서 다루는 내용

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

2202E array subscript error 는?

PostgreSQL 에러 코드 2202E는 배열(Array)의 첨자(subscript)를 잘못 사용했을 때 발생하는 에러입니다. 배열 인덱스가 허용되지 않는 값(예: NULL, 소수점, 또는 배열의 차원을 초과하는 슬라이스 범위)으로 지정될 때 주로 발생합니다. 이 에러는 데이터 조회, 업데이트, 또는 함수 내부에서 배열 요소에 접근할 때 빈번하게 나타나며, 잘못된 첨자 처리로 인해 쿼리 전체가 실패할 수 있습니다.


주요 발생 원인

  • 배열 슬라이스에서 잘못된 범위 지정

PostgreSQL에서 배열 슬라이스를 사용할 때 array[lower:upper] 형식으로 범위를 지정합니다. 이 때 lowerupper보다 크거나, 음수 범위, 또는 논리적으로 맞지 않는 범위를 지정하면 2202E 에러가 발생할 수 있습니다. 특히 동적으로 계산된 인덱스를 사용할 경우 런타임에서 이 문제가 드러납니다.

“`sql

— 잘못된 슬라이스 범위 예시

SELECT (ARRAY[10, 20, 30, 40, 50])[3:1];

— ERROR: 2202E: array subscript out of range (lower > upper)

“`

  • NULL 값을 배열 첨자로 사용

배열 인덱스에 NULL 값이 들어오면 PostgreSQL은 해당 요소에 접근할 수 없어 에러를 발생시킵니다. 이는 특히 사용자 입력값이나 조인 결과에서 NULL이 유입될 때 자주 발생하며, 검증 로직 없이 바로 배열 인덱스에 사용하면 쿼리가 실패합니다. 런타임 환경에서는 NULL이 유입되는 경로를 추적하기 어렵기 때문에 더욱 주의가 필요합니다.

“`sql

— NULL 첨자 사용 예시

DO $$

DECLARE

idx INTEGER := NULL;

arr INTEGER[] := ARRAY[1, 2, 3];

BEGIN

— NULL 인덱스로 접근 시 에러 발생

RAISE NOTICE ‘%’, arr[idx];

END;

$$;

— ERROR: 2202E: array subscript in slice must not be null

“`

  • 다차원 배열에서 잘못된 차원 접근

PostgreSQL은 다차원 배열을 지원하지만, 차원 수와 맞지 않는 첨자를 사용하면 에러가 발생합니다. 예를 들어 1차원 배열에 2차원 인덱스를 사용하거나, 슬라이스와 단일 인덱스를 혼용할 때 문제가 생깁니다. 복잡한 중첩 배열 구조를 다루는 코드에서 특히 주의해야 합니다.

“`sql

— 다차원 배열 잘못된 접근 예시

SELECT (ARRAY[[1,2],[3,4]])[1:2][NULL:2];

— ERROR: 2202E: array subscript in slice must not be null

“`


해결 방법

1. 슬라이스 범위 유효성 검사 추가

슬라이스를 사용하기 전에 lowerupper 값이 논리적으로 올바른지 확인하고, 조건문으로 범위를 보정하세요.

-- 안전한 슬라이스 접근 함수 예시
CREATE OR REPLACE FUNCTION safe_array_slice(
  arr INTEGER[],
  lower_idx INTEGER,
  upper_idx INTEGER
)
RETURNS INTEGER[] AS $$
BEGIN
  -- 유효성 검사: lower가 upper보다 크면 빈 배열 반환
  IF lower_idx IS NULL OR upper_idx IS NULL THEN
    RETURN ARRAY[]::INTEGER[];
  END IF;

  IF lower_idx > upper_idx THEN
    RAISE WARNING 'lower_idx(%) > upper_idx(%), returning empty array', lower_idx, upper_idx;
    RETURN ARRAY[]::INTEGER[];
  END IF;

  -- 배열 범위 내로 클램핑
  lower_idx := GREATEST(lower_idx, array_lower(arr, 1));
  upper_idx := LEAST(upper_idx, array_upper(arr, 1));

  RETURN arr[lower_idx:upper_idx];
END;
$$ LANGUAGE plpgsql;

-- 사용 예시
SELECT safe_array_slice(ARRAY[10, 20, 30, 40, 50], 3, 1);
-- 결과: {} (빈 배열, 에러 없음)

SELECT safe_array_slice(ARRAY[10, 20, 30, 40, 50], 2, 4);
-- 결과: {20, 30, 40}

2. NULL 첨자 방어 처리

배열 인덱스를 사용하기 전에 반드시 COALESCE 또는 NULLIF를 활용해 NULL을 처리하세요.

-- COALESCE로 NULL 방어
DO $$
DECLARE
  idx INTEGER := NULL;
  arr INTEGER[] := ARRAY[1, 2, 3];
  result INTEGER;
BEGIN
  -- NULL을 기본값 1로 치환
  result := arr[COALESCE(idx, 1)];
  RAISE NOTICE 'result: %', result;
END;
$$;

-- 실제 쿼리에서의 NULL 방어 예시
SELECT
  product_id,
  -- 인덱스가 NULL일 경우 첫 번째 요소 반환
  tags[COALESCE(target_index, 1)] AS selected_tag
FROM (
  SELECT
    1 AS product_id,
    ARRAY['electronics', 'sale', 'new'] AS tags,
    NULL::INTEGER AS target_index
) sub;

3. 다차원 배열 접근 시 차원 확인

array_ndims() 함수를 활용해 배열의 차원을 먼저 확인하고 접근하세요.

-- 배열 차원 정보 확인
DO $$
DECLARE
  my_arr INTEGER[][] := ARRAY[[1,2,3],[4,5,6]];
  ndims INTEGER;
  dim1_lower INTEGER;
  dim1_upper INTEGER;
BEGIN
  ndims := array_ndims(my_arr);
  dim1_lower := array_lower(my_arr, 1);
  dim1_upper := array_upper(my_arr, 1);

  RAISE NOTICE '차원 수: %, 1차원 범위: % ~ %',
    ndims, dim1_lower, dim1_upper;

  -- 안전한 접근
  IF ndims >= 2 THEN
    RAISE NOTICE '(1,2) 요소: %', my_arr[1][2];
  END IF;
END;
$$;

예방 방법

  • 배열 접근 전 항상 경계값 검증 함수를 사용하세요

배열을 다루는 로직에서는 array_lower(), array_upper(), array_length(), array_ndims() 함수를 적극 활용하여 인덱스가 항상 유효한 범위 내에 있음을 보장해야 합니다. 특히 사용자 입력값이나 외부 데이터에서 인덱스를 받아올 때는 반드시 래퍼(wrapper) 함수로 감싸서 NULL 처리와 범위 검증을 수행하세요.

“`sql

— 범용 배열 요소 안전 접근 함수

CREATE OR REPLACE FUNCTION safe_array_get(

arr ANYARRAY,

idx INTEGER,

default_val ANYELEMENT DEFAULT NULL

)

RETURNS ANYELEMENT AS $$

BEGIN

IF idx IS NULL

OR idx < array_lower(arr, 1)

OR idx > array_upper(arr, 1) THEN

RETURN default_val;

END IF;

RETURN arr[idx];

END;

$$ LANGUAGE plpgsql;

“`

  • PL/pgSQL 함수 내 예외 처리로 에러를 격리하세요

배열 연산이 빈번한 스토어드 프로시저나 함수에서는 EXCEPTION WHEN OTHERS THEN 블록을 사용해 2202E 에러를 포함한 배열 관련 에러를 명시적으로 잡고 로깅하세요. 이를 통해 전체 트랜잭션 실패를 방지하고 문제 발생 시 빠르게 추적할 수 있습니다.

“`sql

CREATE OR REPLACE FUNCTION process_array_data(arr INTEGER[], idx INTEGER)

RETURNS INTEGER AS $$

DECLARE

result INTEGER;

BEGIN

result := arr[idx];

RETURN result;

EXCEPTION

WHEN SQLSTATE ‘2202E’ THEN

RAISE WARNING ‘Array subscript error: idx=%, arr length=%’,

idx, array_length(arr, 1);

RETURN NULL;

WHEN OTHERS THEN

RAISE WARNING ‘Unexpected error: %’, SQLERRM;

RETURN NULL;

END;

$$ LANGUAGE plpgsql;

“`


관련 에러

  • 2202 (array_subscript_error): 2202E의 상위 클래스 에러로, 배열 첨자 관련 에러의 일반적인 카테고리입니다.
  • 2202H (invalid_tablesample_argument): 배열과 직접 관련은 없지만 동일한 22 클래스(데이터 예외)에 속합니다.
  • 22P02 (invalid_text_representation): 문자열을 배열로 변환할 때 형식이 잘못된 경우 발생하며, 배열 초기화 시 함께 주의해야 합니다.
  • 2202D (null_value_not_allowed): NULL이 허용되지 않는 맥락에서 NULL 배열 값을 처리할 때 발생할 수 있습니다.
  • 42703 (undefined_column): 배열 컬럼명을 잘못 참조했을 때 발생하며, 배열 첨자 에러와 혼동되는 경우가 있습니다.

DBMS 에러 코드 시리즈

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

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

댓글 남기기