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

2200S
2026년 06월 16일 | DBMS Error 가이드

이 글에서 다루는 내용

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

2200S invalid xml comment 는?

PostgreSQL 에러 코드 2200S (invalid_xml_comment) 는 XML 데이터를 처리하는 과정에서 XML 주석(comment)이 XML 표준 규격에 맞지 않는 형식으로 작성되었을 때 발생하는 에러입니다. PostgreSQL은 XML 데이터 타입과 관련 함수들을 통해 XML 유효성 검사를 엄격하게 수행하며, W3C XML 1.0 스펙을 기반으로 주석 형식을 검증합니다. 주로 XMLPARSE(), xmlcomment(), XMLROOT() 등의 XML 관련 함수나 XML 타입 컬럼에 데이터를 삽입할 때 잘못된 주석 구조가 포함된 경우에 이 에러가 트리거됩니다.


주요 발생 원인

1. XML 주석 내부에 ‘–‘ (이중 하이픈) 포함

XML 표준(XML 1.0 Spec Section 2.5)에 따르면, XML 주석 내부에 이중 하이픈(--)이 포함되면 안 됩니다. 많은 개발자들이 SQL의 주석 스타일(--)에 익숙하여 XML 주석 안에서도 동일하게 사용하는 실수를 저지릅니다. 예를 들어 형태는 PostgreSQL에서 즉각적으로 2200S 에러를 발생시킵니다.

2. XML 주석 종료 태그의 잘못된 형식

XML 주석은 반드시 로 종료되어야 합니다. 종료 태그 직전에 하이픈이 홀수 개로 붙거나(--->, ---->), 닫는 태그 자체가 누락된 경우 파서가 주석을 올바르게 인식하지 못합니다. 이런 오류는 애플리케이션 레이어에서 동적으로 XML을 생성할 때 문자열 연결 로직의 버그로 인해 자주 발생합니다.

3. 애플리케이션에서 특수문자 미처리 후 XML 주석 삽입

외부 시스템이나 사용자 입력값을 XML 주석에 그대로 삽입할 때, 입력값에 --나 기타 XML 비호환 문자가 포함되어 있을 경우 에러가 발생합니다. 특히 REST API나 ETL 파이프라인을 통해 들어오는 비정형 데이터를 XML 주석으로 메타데이터화하는 패턴에서 빈번하게 목격됩니다. 사전 입력값 검증(validation) 없이 바로 DB에 저장하려는 시도가 이 에러의 근본 원인이 됩니다.


해결 방법

원인 1 해결: 이중 하이픈 제거 또는 치환

XML 주석 내부의 --를 단일 하이픈이나 다른 문자로 대체해야 합니다.

-- 잘못된 예시: XML 주석 내 '--' 포함 시 에러 발생
SELECT xmlcomment('이것은 -- 잘못된 주석입니다');
-- ERROR:  invalid xml comment

-- 올바른 예시 1: 이중 하이픈을 단일 하이픈으로 변경
SELECT xmlcomment('이것은 - 올바른 주석입니다');

-- 올바른 예시 2: 이중 하이픈을 공백으로 대체
SELECT xmlcomment('이것은  올바른 주석입니다');

-- 애플리케이션에서 동적으로 주석을 생성할 경우, 입력값 전처리
SELECT xmlcomment(
    replace('사용자 입력값: test--value', '--', '- -')
);

원인 2 해결: 올바른 XML 주석 형식 사용

XML 주석 종료 구문을 반드시 --> 형식으로 맞춰야 합니다.

-- 잘못된 예시: 주석 종료 태그에 하이픈 중복
SELECT XMLPARSE(DOCUMENT '<?xml version="1.0"?><!---잘못된 종료--->
<root><data>test</data></root>');
-- ERROR:  invalid xml comment

-- 올바른 예시: 표준 XML 주석 형식
SELECT XMLPARSE(DOCUMENT '<?xml version="1.0"?><!-- 올바른 주석 -->
<root><data>test</data></root>');

-- XML 타입 컬럼에 올바른 형식으로 삽입
CREATE TABLE xml_documents (
    id SERIAL PRIMARY KEY,
    content XML
);

INSERT INTO xml_documents (content)
VALUES (XMLPARSE(DOCUMENT
    '<?xml version="1.0" encoding="UTF-8"?>
     <!-- 문서 생성일: 2024-01-15 -->
     <report>
         <title>월간 보고서</title>
         <body>내용</body>
     </report>'
));

원인 3 해결: 사용자 입력값 사전 검증 및 이스케이프 처리

-- 입력값에서 XML 주석 비호환 문자를 제거하는 함수 생성
CREATE OR REPLACE FUNCTION sanitize_xml_comment(input_text TEXT)
RETURNS TEXT
LANGUAGE plpgsql
AS $$
DECLARE
    sanitized TEXT;
BEGIN
    -- 이중 하이픈을 '- -'로 교체
    sanitized := replace(input_text, '--', '- -');
    -- 주석 끝에 하이픈이 오는 경우 처리 (예: "text-" -> "text ")
    sanitized := regexp_replace(sanitized, '-+$', '');
    RETURN sanitized;
END;
$$;

-- 함수를 활용한 안전한 XML 주석 삽입
INSERT INTO xml_documents (content)
VALUES (
    XMLPARSE(DOCUMENT
        format(
            '<?xml version="1.0"?><!-- %s --><root><data>%s</data></root>',
            sanitize_xml_comment('사용자 입력: some--data'),
            'value'
        )
    )
);

-- 기존 데이터 검증 쿼리 (문제 있는 XML 찾기)
SELECT id, content
FROM xml_documents
WHERE content::TEXT ~ '--(?!>)';

실전 디버깅: 에러 재현 및 확인

-- 에러 발생 상황 재현
DO $$
BEGIN
    BEGIN
        PERFORM xmlcomment('invalid--comment');
    EXCEPTION
        WHEN invalid_xml_comment THEN
            RAISE NOTICE 'SQLSTATE: %, MESSAGE: %', SQLSTATE, SQLERRM;
    END;
END;
$$;
-- NOTICE:  SQLSTATE: 2200S, MESSAGE: invalid xml comment

-- xmlcomment() 함수 정상 동작 확인
SELECT
    xmlcomment('정상적인 주석') AS valid_comment,
    xmlcomment('하이픈 하나 - 는 괜찮습니다') AS also_valid;

예방 방법

1. XML 주석 생성 전용 래퍼 함수 표준화

팀 내에서 XML 주석을 생성할 때 반드시 xmlcomment() 내장 함수 또는 자체 검증 래퍼 함수를 사용하도록 코딩 컨벤션을 수립하세요. 원시 문자열 연결(string concatenation)로 XML을 수동 조립하는 방식은 철저히 금지하고, 모든 입력값은 sanitize_xml_comment() 같은 전처리 함수를 거친 후 사용하도록 파이프라인을 구성하는 것이 좋습니다.

-- 표준화된 XML 문서 생성 함수 예시
CREATE OR REPLACE FUNCTION create_xml_document(
    p_comment TEXT,
    p_root_element TEXT,
    p_content TEXT
)
RETURNS XML
LANGUAGE plpgsql
AS $$
BEGIN
    RETURN XMLPARSE(DOCUMENT
        format(
            '<?xml version="1.0" encoding="UTF-8"?>%s<%s>%s</%s>',
            xmlcomment(sanitize_xml_comment(p_comment)),
            p_root_element,
            xmlescape(p_content),
            p_root_element
        )
    );
END;
$$;

2. CHECK 제약 조건 및 트리거를 통한 DB 레벨 검증

애플리케이션 레이어의 방어만으로는 부족합니다. 데이터베이스 레벨에서도 XML 데이터의 유효성을 보장하는 CHECK 제약 조건이나 BEFORE INSERT/UPDATE 트리거를 설정하여 이중 방어선을 구축하세요.

-- XML 컬럼에 유효성 검사 트리거 추가
CREATE OR REPLACE FUNCTION validate_xml_content()
RETURNS TRIGGER
LANGUAGE plpgsql
AS $$
BEGIN
    -- XML 캐스팅 시도로 유효성 검증 (실패 시 에러 발생)
    PERFORM XMLPARSE(DOCUMENT NEW.content::TEXT);
    RETURN NEW;
EXCEPTION
    WHEN invalid_xml_comment THEN
        RAISE EXCEPTION '유효하지 않은 XML 주석이 포함되어 있습니다. 입력값을 확인하세요. SQLSTATE: %', SQLSTATE;
    WHEN OTHERS THEN
        RAISE EXCEPTION 'XML 유효성 검사 실패: %', SQLERRM;
END;
$$;

CREATE TRIGGER trg_validate_xml
BEFORE INSERT OR UPDATE ON xml_documents
FOR EACH ROW EXECUTE FUNCTION validate_xml_content();

관련 에러

  • 2200N (invalid_xml_content): XML 주석이 아닌 XML 콘텐츠 자체가 유효하지 않을 때 발생. 태그 미매칭, 잘못된 인코딩 등이 원인.
  • 2200M (invalid_xml_document): XML 문서 전체 구조가 well-formed XML 규격을 위반할 때 발생. XMLPARSE(DOCUMENT ...) 사용 시 자주 조우.
  • 2200T (invalid_xml_processing_instruction): XML 처리 지시자(Processing Instruction)의 형식이 올바르지 않을 때 발생. 형식 위반 시 트리거.
  • 22000 (data_exception): 위 XML 관련 에러들의 상위 에러 클래스. XML 처리 중 발생하는 모든 데이터 예외의 부모 카테고리.

DBMS 에러 코드 시리즈

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

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

댓글 남기기