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

2200B
2026년 06월 05일 | DBMS Error 가이드

이 글에서 다루는 내용

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

2200B escape character conflict 는?

PostgreSQL 에러 코드 2200Bescape character conflict 에러로, SQL 표준의 LIKE 또는 SIMILAR TO 패턴 매칭에서 이스케이프 문자(escape character)가 충돌하거나 잘못 지정되었을 때 발생합니다. 구체적으로는 LIKE 연산자와 함께 사용하는 ESCAPE 절에서 퍼센트(%) 또는 언더스코어(_)와 같은 와일드카드 문자를 이스케이프 문자로 지정하려 할 때, 또는 이스케이프 문자가 둘 이상의 문자로 구성되어 있을 때 발생합니다. 이 에러는 주로 동적 SQL을 생성하는 애플리케이션이나 복잡한 패턴 매칭 쿼리를 다루는 환경에서 자주 목격되며, 데이터 검색 기능의 장애로 이어질 수 있어 빠른 진단과 수정이 필요합니다.


주요 발생 원인

1. ESCAPE 절에 와일드카드 문자(%, _)를 이스케이프 문자로 사용한 경우

LIKE 연산자의 ESCAPE 절에는 패턴 매칭에 특별한 의미를 가지는 %(퍼센트)나 _(언더스코어)를 이스케이프 문자로 지정할 수 없습니다. 이 두 문자는 이미 LIKE 패턴 내에서 예약된 와일드카드 역할을 하므로, 이를 이스케이프 문자로 재정의하는 것은 논리적 충돌을 일으켜 PostgreSQL이 escape character conflict 에러를 발생시킵니다.

-- 에러 발생 예시: % 를 이스케이프 문자로 사용
SELECT * FROM products
WHERE product_code LIKE '100%' ESCAPE '%';
-- ERROR: invalid escape string
-- HINT: Escape string must be empty or one character.

-- 에러 발생 예시: _ 를 이스케이프 문자로 사용
SELECT * FROM products
WHERE product_code LIKE '100_' ESCAPE '_';
-- ERROR: 2200B escape character conflict

2. 이스케이프 문자가 두 글자 이상인 경우

SQL 표준 및 PostgreSQL 명세에 따르면 ESCAPE 절에 지정하는 이스케이프 문자는 반드시 단일 문자(one character)이거나 빈 문자열이어야 합니다. 개발자가 \\, ##, || 같이 두 글자 이상의 문자열을 이스케이프 문자로 지정하면 PostgreSQL은 이를 유효하지 않은 이스케이프 문자로 간주하고 2200B 에러를 발생시킵니다. 동적 SQL 생성 시 이스케이프 처리 로직에 버그가 있을 때 흔히 발생하는 패턴입니다.

-- 에러 발생 예시: 두 글자 이스케이프 문자 사용
SELECT * FROM orders
WHERE order_ref LIKE 'ORD##001' ESCAPE '##';
-- ERROR: 2200B escape character conflict

-- 에러 발생 예시: 백슬래시 두 개 사용
SELECT * FROM orders
WHERE order_ref LIKE 'ORD\\001' ESCAPE '\\';
-- ERROR: 2200B escape character conflict

3. 애플리케이션 레이어에서 이스케이프 문자가 동적으로 잘못 생성되는 경우

ORM(Object-Relational Mapping) 프레임워크나 쿼리 빌더 라이브러리가 사용자 입력값을 동적으로 SQL에 삽입하는 과정에서 이스케이프 처리를 잘못 구현하면, 런타임에 유효하지 않은 이스케이프 문자가 ESCAPE 절에 삽입될 수 있습니다. 특히 사용자 입력에 특수문자가 포함된 경우, 애플리케이션이 해당 문자를 이스케이프 문자로 오인하거나 중복 이스케이프 처리를 수행하여 두 글자 이상의 문자열이 ESCAPE 절로 전달되는 상황이 자주 발생합니다.

-- 잘못된 동적 SQL 생성 예 (파라미터가 잘못 처리된 경우)
-- 애플리케이션에서 escape_char 변수가 '!!' 로 설정된 경우
SELECT * FROM customers
WHERE email LIKE '%gmail.com' ESCAPE '!!';
-- ERROR: 2200B escape character conflict

-- 올바른 동적 SQL: 단일 문자 이스케이프 지정
SELECT * FROM customers
WHERE email LIKE '%gmail.com' ESCAPE '!';
-- 정상 동작

해결 방법

원인 1 해결: 와일드카드 문자 대신 다른 문자를 이스케이프 문자로 사용

%_ 대신 일반적으로 사용되는 단일 특수문자(예: !, \, #, ^)를 이스케이프 문자로 지정합니다. 아래는 상품 코드에서 실제 언더스코어 문자를 포함한 행을 검색하는 올바른 예시입니다.

-- 잘못된 방법 (에러 발생)
SELECT * FROM products
WHERE product_code LIKE 'ITEM_001' ESCAPE '_';

-- 올바른 방법: ! 를 이스케이프 문자로 사용
SELECT * FROM products
WHERE product_code LIKE 'ITEM!_001' ESCAPE '!';

-- 올바른 방법: # 를 이스케이프 문자로 사용
SELECT * FROM products
WHERE product_code LIKE 'ITEM#_001' ESCAPE '#';

-- 실제 % 문자를 포함한 데이터 검색 예
SELECT * FROM discount_table
WHERE description LIKE '50!% OFF' ESCAPE '!';

원인 2 해결: 이스케이프 문자를 단일 문자로 교정

두 글자 이상의 이스케이프 문자를 사용하는 쿼리를 수정하여 단일 문자를 사용하도록 교정합니다. 이스케이프가 필요 없는 경우에는 ESCAPE 절 자체를 생략하거나 빈 문자열을 지정할 수도 있습니다.

-- 잘못된 방법
SELECT * FROM logs
WHERE log_message LIKE 'ERROR##%' ESCAPE '##';

-- 올바른 방법: 단일 문자 사용
SELECT * FROM logs
WHERE log_message LIKE 'ERROR#%' ESCAPE '#';

-- ESCAPE 절 생략 (이스케이프 불필요한 경우)
SELECT * FROM logs
WHERE log_message LIKE 'ERROR%';

-- 빈 이스케이프 문자열 사용 (이스케이프 비활성화)
SELECT * FROM logs
WHERE log_message LIKE 'ERROR%' ESCAPE '';

원인 3 해결: 애플리케이션 이스케이프 로직 수정 및 PostgreSQL 함수 활용

애플리케이션 레이어에서 LIKE 패턴을 안전하게 구성하려면 PostgreSQL의 regexp_replace() 함수나 직접 구현한 이스케이프 함수를 활용하는 것을 권장합니다.

-- 사용자 입력값을 안전하게 LIKE 패턴으로 변환하는 함수 생성
CREATE OR REPLACE FUNCTION escape_like_pattern(p_input TEXT, p_escape_char TEXT DEFAULT '!')
RETURNS TEXT AS $$
BEGIN
    -- 이스케이프 문자 자체를 먼저 이스케이프 처리
    RETURN replace(
        replace(
            replace(p_input, p_escape_char, p_escape_char || p_escape_char),
            '%', p_escape_char || '%'
        ),
        '_', p_escape_char || '_'
    );
END;
$$ LANGUAGE plpgsql IMMUTABLE STRICT;

-- 함수 사용 예시: 사용자가 'user_name%test' 를 입력한 경우
SELECT * FROM users
WHERE username LIKE '%' || escape_like_pattern('user_name%test') || '%' ESCAPE '!';
-- 실행되는 패턴: '%user!_name!%test%' ESCAPE '!'

-- 함수 동작 확인
SELECT escape_like_pattern('100% complete_task');
-- 결과: '100!% complete!_task'

-- Prepared Statement 를 활용한 안전한 동적 쿼리 (psql 예시)
PREPARE safe_search (TEXT) AS
    SELECT * FROM products
    WHERE product_name LIKE '%' || escape_like_pattern($1) || '%' ESCAPE '!';

EXECUTE safe_search('20% discount_item');

예방 방법

1. 이스케이프 처리 전담 함수를 표준화하여 DB 레이어에서 관리

모든 LIKE 패턴 생성 로직을 애플리케이션 레이어에 분산시키지 않고, 위에서 소개한 escape_like_pattern() 같은 전담 함수를 PostgreSQL 데이터베이스에 정의하고 모든 팀이 일관되게 사용하도록 코드 리뷰와 개발 가이드라인에 명시합니다. 이를 통해 개발자 개인의 실수로 인한 잘못된 이스케이프 처리를 원천 차단할 수 있으며, 이스케이프 문자를 ! 하나로 표준화하면 유지보수도 훨씬 용이해집니다.

-- 개발팀 공통 사용 예시 (표준화된 패턴)
-- 항상 단일 이스케이프 문자 '!' 를 사용하는 것으로 팀 내 표준화
SELECT *
FROM product_catalog
WHERE product_name LIKE escape_like_pattern(:user_input, '!') ESCAPE '!';

2. CI/CD 파이프라인에 ESCAPE 절 정적 분석 룰 추가

팀의 CI/CD 파이프라인 또는 코드 린트(lint) 도구에 LIKE … ESCAPE 패턴을 감지하는 정적 분석 규칙을 추가하여, 두 글자 이상의 이스케이프 문자나 %, _를 이스케이프 문자로 사용하는 코드가 프로덕션에 배포되기 전에 자동으로 차단되도록 설정합니다. sqlfluff, pgTAP 기반의 DB 테스트, 또는 자체 스크립트를 활용하여 이러한 패턴을 조기에 발견할 수 있습니다.

-- pgTAP 기반 테스트 예시: 이스케이프 함수의 정확성 검증
SELECT plan(3);

SELECT is(
    escape_like_pattern('hello%world'),
    'hello!%world',
    '% 문자가 올바르게 이스케이프 되어야 함'
);

SELECT is(
    escape_like_pattern('user_name'),
    'user!_name',
    '_ 문자가 올바르게 이스케이프 되어야 함'
);

SELECT is(
    escape_like_pattern('50! discount'),
    '50!! discount',
    '이스케이프 문자 자체가 올바르게 이스케이프 되어야 함'
);

SELECT * FROM finish();

관련 에러

  • 22025 (invalid escape sequence): 이스케이프 시퀀스 자체가 유효하지 않을 때 발생하며, 2200B와 함께 LIKE 패턴 관련 트러블슈팅 시 자주 마주치는 에러입니다.
  • 22019 (invalid escape character): 이스케이프 문자로 허용되지 않는 문자가 지정되었을 때 발생하며, 2200B와 혼동되기 쉽습니다.
  • 2201B (invalid regular expression): SIMILAR TO 또는 regexp_match() 등 정규식 기반 패턴 매칭에서 잘못된 정규식이 사용될 때 발생하며, 패턴 매칭 에러군에 속합니다.
  • 42601 (syntax error): 동적 SQL 생성 과정에서 이스케이프 처리 오류가 SQL 구문 오류로 이어질 때 함께 발생하는 경우가 있어, 2200B 디버깅 시 로그에서 같이 확인해야 합니다.

DBMS 에러 코드 시리즈

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

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

댓글 남기기