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

22023
2026년 08월 13일 | DBMS Error 가이드

이 글에서 다루는 내용

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

22023 invalid parameter value 는?

PostgreSQL 에러 코드 22023 (invalid_parameter_value)은 함수나 명령어에 전달된 파라미터 값이 유효하지 않거나 허용 범위를 벗어났을 때 발생하는 오류입니다. 이 에러는 주로 내장 함수, 타입 변환, 날짜/시간 연산, 시스템 설정 변경 등 다양한 상황에서 발생하며, SQL 표준 클래스 22(데이터 예외)에 속합니다. 특히 애플리케이션에서 사용자 입력값을 검증 없이 그대로 SQL 함수에 전달할 때 자주 마주치게 되는 에러입니다.


주요 발생 원인

1. 날짜/시간 함수에 잘못된 포맷 또는 범위의 값 전달

가장 흔한 원인 중 하나로, date_trunc(), to_timestamp(), interval 관련 함수에 지원하지 않는 단위(unit)나 잘못된 형식의 문자열을 넘길 때 발생합니다. 예를 들어 date_trunc('minutes', now())처럼 복수형 단위를 사용하거나, to_timestamp()에 형식에 맞지 않는 문자열을 전달하면 이 에러가 즉시 발생합니다. 실무에서는 프론트엔드나 외부 API로부터 동적으로 받은 날짜 단위 문자열을 그대로 쿼리에 삽입할 때 특히 주의해야 합니다.

2. SET 명령어나 시스템 파라미터에 허용되지 않는 값 설정

SET 명령어를 통해 PostgreSQL 런타임 파라미터를 변경할 때, 해당 파라미터가 허용하지 않는 값을 입력하면 22023 에러가 발생합니다. 예를 들어 SET work_mem = '-1MB'처럼 음수 값을 지정하거나, SET client_encoding = 'INVALID_ENCODING'처럼 존재하지 않는 인코딩을 설정하려 할 때 이 오류가 나타납니다. 마이그레이션 스크립트나 세션 초기화 코드에서 하드코딩된 값이 PostgreSQL 버전 업그레이드 후 유효하지 않게 되는 경우도 자주 발생합니다.

3. 문자열 처리 및 정규식 함수에 잘못된 패턴 또는 플래그 전달

regexp_replace(), regexp_match(), substring() 등 정규식 기반 함수에 유효하지 않은 정규식 패턴이나 지원되지 않는 플래그를 전달하면 이 에러가 발생합니다. 또한 encode()/decode() 함수에 base64, hex, escape 외의 지원되지 않는 인코딩 방식을 지정하거나, format() 함수에 잘못된 형식 지정자를 사용하는 경우도 이에 해당합니다. 이 유형의 에러는 동적 쿼리 생성 로직에서 사용자 입력이 정규식 파라미터로 직접 삽입될 때 특히 위험합니다.


해결 방법

원인 1 해결: 날짜/시간 함수 파라미터 수정

date_trunc() 함수는 반드시 단수형 단위를 사용해야 합니다. 아래 예제를 참고하세요.

-- 잘못된 예 (22023 에러 발생)
SELECT date_trunc('minutes', now());
-- ERROR:  unit "minutes" not recognized for type timestamp with time zone

-- 올바른 예
SELECT date_trunc('minute', now());

-- 잘못된 예: 지원하지 않는 단위
SELECT date_trunc('quarter', now());
-- 참고: 'quarter'는 PostgreSQL 9.x에서는 지원하지 않는 버전도 있음

-- 동적 단위 사용 시 화이트리스트 검증 권장
DO $$
DECLARE
    v_unit TEXT := 'hour'; -- 외부에서 받은 값이라 가정
    v_allowed TEXT[] := ARRAY['microseconds','milliseconds','second','minute',
                               'hour','day','week','month','quarter','year',
                               'decade','century','millennium'];
BEGIN
    IF v_unit = ANY(v_allowed) THEN
        EXECUTE format('SELECT date_trunc(%L, now())', v_unit);
    ELSE
        RAISE EXCEPTION '허용되지 않는 날짜 단위: %', v_unit;
    END IF;
END $$;

-- to_timestamp 올바른 사용
SELECT to_timestamp('2024-01-15 14:30:00', 'YYYY-MM-DD HH24:MI:SS');

-- 잘못된 포맷 예시 (형식 불일치)
-- SELECT to_timestamp('15/01/2024', 'YYYY-MM-DD'); -- 에러 발생 가능
SELECT to_timestamp('15/01/2024', 'DD/MM/YYYY');   -- 올바른 형식 매핑

원인 2 해결: 시스템 파라미터 유효한 값으로 설정

-- 잘못된 예 (22023 에러 발생)
SET work_mem = '-1MB';
-- ERROR:  invalid value for parameter "work_mem": "-1MB"

-- 올바른 예: 양수 값과 올바른 단위 사용
SET work_mem = '64MB';
SET work_mem = '256MB';

-- 현재 허용 파라미터 범위 확인
SELECT name, setting, unit, min_val, max_val, enumvals, context
FROM pg_settings
WHERE name = 'work_mem';

-- 잘못된 클라이언트 인코딩 설정
-- SET client_encoding = 'INVALID'; -- 에러 발생

-- 지원 인코딩 목록 확인 후 설정
SELECT pg_encoding_to_char(conforencoding) 
FROM pg_conversion 
GROUP BY conforencoding;

SET client_encoding = 'UTF8';   -- 올바른 예

-- 세션 레벨에서 안전하게 파라미터 변경
DO $$
BEGIN
    PERFORM set_config('work_mem', '128MB', true); -- 세션 한정
EXCEPTION WHEN invalid_parameter_value THEN
    RAISE WARNING '파라미터 설정 실패, 기본값 유지: %', SQLERRM;
END $$;

원인 3 해결: 정규식 및 문자열 함수 파라미터 검증

-- 잘못된 정규식 플래그 사용 (22023 에러 발생)
SELECT regexp_replace('Hello World', 'world', 'PostgreSQL', 'z');
-- ERROR:  invalid regular expression option: "z"

-- 올바른 플래그 사용 (i: 대소문자 무시, g: 전체 치환)
SELECT regexp_replace('Hello World', 'world', 'PostgreSQL', 'i');
SELECT regexp_replace('aaa bbb aaa', 'aaa', 'xxx', 'g');

-- encode/decode 잘못된 형식 지정
-- SELECT encode('test'::bytea, 'base32'); -- 에러 발생

-- 지원되는 형식만 사용
SELECT encode('Hello'::bytea, 'base64');  -- base64
SELECT encode('Hello'::bytea, 'hex');     -- hex
SELECT encode('Hello'::bytea, 'escape'); -- escape

-- 안전한 정규식 처리를 위한 래퍼 함수
CREATE OR REPLACE FUNCTION safe_regexp_replace(
    p_source TEXT,
    p_pattern TEXT,
    p_replacement TEXT,
    p_flags TEXT DEFAULT ''
) RETURNS TEXT AS $$
DECLARE
    v_allowed_flags TEXT := '^[gimsw]*$'; -- 허용 플래그 패턴
    v_result TEXT;
BEGIN
    -- 플래그 유효성 검증
    IF p_flags !~ v_allowed_flags THEN
        RAISE EXCEPTION '유효하지 않은 정규식 플래그: %', p_flags
            USING ERRCODE = '22023';
    END IF;
    
    BEGIN
        v_result := regexp_replace(p_source, p_pattern, p_replacement, p_flags);
    EXCEPTION WHEN OTHERS THEN
        RAISE EXCEPTION '정규식 처리 오류: % (패턴: %)', SQLERRM, p_pattern
            USING ERRCODE = SQLSTATE;
    END;
    
    RETURN v_result;
END;
$$ LANGUAGE plpgsql;

-- 사용 예
SELECT safe_regexp_replace('Hello World', 'world', 'DB', 'i');

예방 방법

1. 입력값 화이트리스트 검증 및 방어적 PL/pgSQL 코딩

외부에서 동적으로 전달되는 함수 파라미터(날짜 단위, 인코딩명, 정규식 플래그 등)는 절대로 검증 없이 SQL에 삽입하지 마세요. 허용 가능한 값의 화이트리스트를 ARRAY나 별도 테이블로 관리하고, 입력값이 해당 목록에 포함되는지 반드시 사전 확인해야 합니다. 또한 PL/pgSQL 블록 내에서 BEGIN...EXCEPTION WHEN invalid_parameter_value THEN 구문을 활용하여 에러를 우아하게 처리하고, 상세 로그를 남기는 방어적 코딩 습관을 들이세요.

-- pg_settings를 활용한 사전 유효성 검증 예시
CREATE OR REPLACE FUNCTION safe_set_parameter(p_name TEXT, p_value TEXT)
RETURNS VOID AS $$
BEGIN
    -- 파라미터 존재 여부 확인
    IF NOT EXISTS (SELECT 1 FROM pg_settings WHERE name = p_name) THEN
        RAISE EXCEPTION '알 수 없는 파라미터: %', p_name;
    END IF;
    
    -- 파라미터 설정 시도 및 예외 처리
    EXECUTE format('SET %I = %L', p_name, p_value);
EXCEPTION 
    WHEN invalid_parameter_value THEN
        RAISE EXCEPTION '파라미터 [%] 에 유효하지 않은 값 [%]: %', 
                        p_name, p_value, SQLERRM;
END;
$$ LANGUAGE plpgsql;

2. 개발/스테이징 환경에서 충분한 테스트 및 PostgreSQL 버전 호환성 확인

PostgreSQL 버전이 업그레이드될 때 일부 함수의 허용 파라미터 범위나 형식이 변경될 수 있습니다. 마이그레이션 전 반드시 pg_upgrade 체크리스트와 릴리즈 노트를 확인하고, 모든 동적 파라미터를 사용하는 쿼리를 스테이징 환경에서 실행해 검증하세요. CI/CD 파이프라인에 SQL 함수 파라미터 유효성을 자동으로 검사하는 테스트를 포함시키면 프로덕션 장애를 예방하는 데 매우 효과적입니다.


관련 에러

  • 22007 (invalid_datetime_format): 날짜/시간 문자열의 형식 자체가 잘못된 경우 발생하며, 22023과 함께 날짜 처리 오류의 쌍벽을 이룹니다.
  • 22008 (datetime_field_overflow): 날짜/시간 값이 유효 범위를 초과할 때 발생합니다. 예: '9999-12-31' 이후 날짜 연산.
  • 42704 (undefined_object): 존재하지 않는 인코딩명이나 커서명 등을 참조할 때 발생하며, 22023과 혼동되는 경우가 있습니다.
  • 22P02 (invalid_text_representation): 텍스트를 특정 타입으로 변환할 때 형식이 맞지 않으면 발생합니다. CAST 실패 시 자주 보이는 에러입니다.
  • 42601 (syntax_error): 동적 SQL 생성 시 파라미터 문제가 구문 오류로 이어지는 경우, 22023보다 먼저 이 에러가 발생할 수 있습니다.

DBMS 에러 코드 시리즈

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

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

댓글 남기기