2026년 08월 13일 | DBMS Error 가이드
이 글에서 다루는 내용
2201B 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.
2201B invalid regular expression 는?
PostgreSQL 에러 코드 2201B(invalid_regular_expression)는 정규 표현식(Regular Expression) 함수나 연산자에 전달된 패턴이 문법적으로 올바르지 않을 때 발생합니다. REGEXP_MATCH, REGEXP_REPLACE, REGEXP_SPLIT_TO_TABLE, ~ 연산자 등 정규식을 사용하는 모든 PostgreSQL 기능에서 공통적으로 나타날 수 있습니다. 잘못된 수량자, 닫히지 않은 괄호, 지원되지 않는 정규식 문법 등이 대표적인 원인이며, 특히 다른 언어나 데이터베이스에서 사용하던 정규식 문법을 그대로 이식할 때 자주 발생합니다.
주요 발생 원인
1. 괄호 또는 대괄호가 닫히지 않은 패턴
정규 표현식에서 여는 괄호 (나 여는 대괄호 [를 열었지만 대응하는 닫는 기호를 작성하지 않은 경우가 가장 흔한 원인입니다. 예를 들어 (abc처럼 여는 소괄호만 있고 닫는 소괄호가 없거나, [a-z처럼 문자 클래스가 닫히지 않은 경우 PostgreSQL의 정규식 엔진은 즉시 2201B 에러를 발생시킵니다. 이 오류는 동적으로 생성된 쿼리에서 문자열 조합 실수로 특히 자주 발생하므로 주의가 필요합니다.
2. 지원되지 않는 정규식 문법 또는 플래그 사용
PostgreSQL은 POSIX ERE(Extended Regular Expression) 표준을 기반으로 한 자체 정규식 엔진을 사용합니다. 다른 프로그래밍 언어(Python, JavaScript, Java 등)에서 사용하는 PCRE(Perl Compatible Regular Expressions) 문법 중 일부는 PostgreSQL에서 지원되지 않습니다. 대표적인 예로 후방 탐색(Lookbehind) (?<=...), 원자 그룹(Atomic Group) (?>...), 조건부 패턴 (?(cond)yes|no) 등이 있으며, 이러한 문법을 사용하면 2201B 에러가 발생합니다.
3. 잘못된 수량자 또는 이스케이프 시퀀스
수량자를 잘못 사용하면 정규식 엔진이 패턴을 파싱하지 못합니다. 예를 들어 {3,1}처럼 최솟값이 최댓값보다 큰 범위 수량자, 단독으로 사용된 *나 + 앞에 패턴 없이 사용하는 경우, 또는 백슬래시(\) 뒤에 의미 없는 문자를 사용하는 잘못된 이스케이프 시퀀스가 이에 해당합니다. SQL 문자열 내에서는 백슬래시를 이스케이프하기 위해 \\를 사용해야 하므로 이중 이스케이프 처리 실수가 빈번하게 발생합니다.
해결 방법
원인 1 해결: 괄호/대괄호 불일치 수정
패턴을 작성할 때 괄호 쌍이 올바른지 확인하고, 동적으로 생성하는 경우 패턴을 로그로 출력해 육안으로 검토합니다.
-- 에러 발생 예시: 닫히지 않은 소괄호
SELECT regexp_match('hello world', '(hello');
-- ERROR: invalid regular expression: parentheses () not balanced
-- 수정된 쿼리: 괄호를 올바르게 닫음
SELECT regexp_match('hello world', '(hello)');
-- 결과: {hello}
-- 에러 발생 예시: 닫히지 않은 문자 클래스
SELECT 'test123' ~ '[a-z';
-- ERROR: invalid regular expression: brackets [] not balanced
-- 수정된 쿼리: 대괄호를 올바르게 닫음
SELECT 'test123' ~ '[a-z]+';
-- 결과: true
-- 디버깅용: 패턴 확인 쿼리
DO $$
DECLARE
v_pattern TEXT := '(hello)';
BEGIN
-- 패턴 유효성 사전 검증
PERFORM regexp_match('test', v_pattern);
RAISE NOTICE '패턴이 유효합니다: %', v_pattern;
EXCEPTION
WHEN invalid_regular_expression THEN
RAISE WARNING '잘못된 정규식 패턴: % - %', v_pattern, SQLERRM;
END;
$$;
원인 2 해결: PostgreSQL 지원 문법으로 대체
PCRE 전용 문법을 PostgreSQL POSIX ERE 호환 문법으로 변환합니다.
-- 에러 발생 예시: PCRE 후방 탐색 (PostgreSQL 미지원)
SELECT regexp_replace('foobar', '(?<=foo)bar', 'baz');
-- ERROR: invalid regular expression: invalid backreference number
-- PostgreSQL 방식으로 대체: 그룹 캡처 활용
SELECT regexp_replace('foobar', '(foo)(bar)', '\1baz');
-- 결과: foobaz
-- 에러 발생 예시: PCRE 비캡처 그룹의 일부 고급 문법
SELECT 'hello' ~ '(?i:HELLO)'; -- 일부 버전에서 문제 발생 가능
-- 안전한 PostgreSQL 방식: 대소문자 무시 플래그 사용
SELECT 'hello' ~* 'HELLO';
-- 결과: true
-- 이메일 패턴 검증 예시 (PostgreSQL 호환)
SELECT
email,
email ~ '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$' AS is_valid
FROM (
VALUES
('user@example.com'),
('invalid-email'),
('another@test.org')
) AS t(email);
원인 3 해결: 수량자 및 이스케이프 수정
수량자 범위를 올바르게 설정하고, SQL 문자열 내 이스케이프를 이중으로 처리합니다.
-- 에러 발생 예시: 잘못된 범위 수량자 (최소 > 최대)
SELECT 'aaa' ~ 'a{3,1}';
-- ERROR: invalid regular expression: invalid repetition count(s)
-- 수정된 쿼리: 올바른 범위 수량자
SELECT 'aaa' ~ 'a{1,3}';
-- 결과: true
-- 에러 발생 예시: 백슬래시 이스케이프 실수
SELECT 'abc123' ~ '\d+';
-- PostgreSQL에서 \d는 기본적으로 지원되지 않음
-- 수정된 쿼리: POSIX 문자 클래스 사용
SELECT 'abc123' ~ '[0-9]+';
-- 결과: true
-- 또는 이스케이프 문자열 구문 사용
SELECT 'abc123' ~ E'[[:digit:]]+';
-- 결과: true
-- 실무 예시: 전화번호 패턴 유효성 검사
SELECT
phone,
phone ~ '^[0-9]{2,3}-[0-9]{3,4}-[0-9]{4}$' AS is_valid_phone
FROM (
VALUES
('010-1234-5678'),
('02-123-4567'),
('invalid-phone')
) AS t(phone);
-- 예외 처리를 포함한 안전한 정규식 사용 함수
CREATE OR REPLACE FUNCTION safe_regexp_match(
p_input TEXT,
p_pattern TEXT
)
RETURNS TEXT[] AS $$
BEGIN
RETURN regexp_match(p_input, p_pattern);
EXCEPTION
WHEN invalid_regular_expression THEN
RAISE WARNING '유효하지 않은 정규식 패턴: %', p_pattern;
RETURN NULL;
END;
$$ LANGUAGE plpgsql;
-- 사용 예시
SELECT safe_regexp_match('hello world', '(hello)\s(\w+)');
-- 결과: {hello,world}
SELECT safe_regexp_match('hello', '(invalid[');
-- WARNING: 유효하지 않은 정규식 패턴: (invalid[
-- 결과: NULL
예방 방법
1. 정규식 유효성 검사 함수를 표준화하여 사전 검증 수행
운영 환경에 정규식 패턴을 적용하기 전에 별도의 검증 함수를 통해 패턴의 유효성을 미리 확인하는 습관을 들여야 합니다. 아래와 같이 예외 처리를 내포한 래퍼 함수를 만들어 애플리케이션 레벨에서 활용하면, 잘못된 패턴이 프로덕션 쿼리에 노출되는 것을 사전에 차단할 수 있습니다.
-- 정규식 유효성 검사 유틸리티 함수
CREATE OR REPLACE FUNCTION validate_regex(p_pattern TEXT)
RETURNS BOOLEAN AS $$
BEGIN
PERFORM regexp_match('', p_pattern);
RETURN TRUE;
EXCEPTION
WHEN invalid_regular_expression THEN
RETURN FALSE;
END;
$$ LANGUAGE plpgsql IMMUTABLE;
-- 활용 예시: 사용자 입력 패턴 저장 전 검증
SELECT
pattern,
validate_regex(pattern) AS is_valid
FROM (
VALUES
('^[A-Za-z]+$'),
('(unclosed'),
('[0-9]{2,4}')
) AS t(pattern);
2. PostgreSQL 정규식 문법 레퍼런스를 팀 내 공유하고 코드 리뷰 체계 수립
다른 언어나 환경에서 사용하던 정규식 패턴을 PostgreSQL에 그대로 이식하는 것은 위험합니다. 팀 내에서 PostgreSQL 공식 문서의 정규식 챕터(9.7. Pattern Matching)를 기반으로 허용되는 문법 목록을 정리하고, 정규식이 포함된 쿼리는 반드시 DBA 또는 숙련된 개발자의 코드 리뷰를 거치도록 프로세스를 수립하는 것이 좋습니다. 특히 외부 입력값을 정규식 패턴으로 사용하는 경우 SQL 인젝션 위험과 결합될 수 있으므로 더욱 엄격한 검증이 필요합니다.
관련 에러
- 2201C
invalid_argument_for_nth_value:NTH_VALUE윈도우 함수에서 잘못된 인수를 전달할 때 발생하며, 정규식과 직접 연관은 없지만 동일한 22000번대 데이터 예외 클래스에 속합니다. - 2201W
invalid_row_count_in_limit_clause: LIMIT 절에 잘못된 값을 사용할 때 발생하는 동일 클래스의 에러입니다. - 22019
invalid_escape_character: 정규식 이스케이프 처리 실수와 혼동되기 쉬우며,LIKE패턴에서 잘못된 이스케이프 문자를 사용할 때 발생합니다. 정규식 문법 오류와 증상이 유사하므로 에러 코드를 정확히 구분해야 합니다. - 22025
invalid_escape_sequence: 문자열 내 잘못된 이스케이프 시퀀스를 사용할 때 발생하며, 정규식 패턴 문자열을 동적으로 구성할 때 함께 나타날 수 있습니다.
주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.
본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.