2026년 10월 24일 | DBMS Error 가이드
이 글에서 다루는 내용
2200S 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.
2200S invalid xml comment 는?
PostgreSQL 에러 코드 2200S: invalid xml comment는 XML 데이터를 처리하는 과정에서 XML 주석 형식이 올바르지 않을 때 발생하는 에러입니다. XML 표준에 따르면 주석은 반드시 로 끝나야 하며, 주석 내부에 --(더블 하이픈)이 포함되거나 -로 끝나는 경우 유효하지 않은 XML 주석으로 간주됩니다. PostgreSQL의 XML 파싱 엔진이 이러한 규칙을 위반한 XML 문서를 처리하려 할 때 이 에러가 발생하며, XMLPARSE, XMLCOMMENT, xml 타입 캐스팅 등 다양한 XML 관련 함수와 연산에서 나타날 수 있습니다.
주요 발생 원인
- XML 주석 내부에 더블 하이픈(
--) 포함
XML 1.0 표준(W3C)에 따르면, XML 주석 내부에 -- 문자열이 포함되면 안 됩니다. 이는 XML 파서가 --를 주석의 종료 신호로 혼동할 수 있기 때문이며, PostgreSQL은 이 규칙을 엄격하게 적용합니다. 예를 들어 처럼 작성하면 즉시 이 에러가 발생합니다.
XMLCOMMENT()함수에 유효하지 않은 문자열 전달
PostgreSQL의 내장 함수 XMLCOMMENT(text)는 전달받은 문자열을 XML 주석으로 변환합니다. 이 함수에 --를 포함하거나 -로 끝나는 문자열을 전달하면 에러가 발생합니다. 애플리케이션에서 동적으로 주석 내용을 생성할 때 입력값 검증 없이 사용자 입력을 그대로 넘기는 경우 자주 발생합니다.
- 외부 시스템에서 생성된 XML 데이터를 그대로 삽입
외부 API, 레거시 시스템, 또는 다른 데이터베이스에서 생성된 XML 데이터를 PostgreSQL에 삽입할 때, 해당 데이터가 XML 표준을 완전히 준수하지 않는 경우가 많습니다. 특히 SQL 주석(--)과 XML 주석을 혼동하여 생성된 XML이나, 자동 생성 도구에서 만들어진 비표준 XML이 이 문제를 일으킵니다.
해결 방법
원인 1 해결: XML 주석 내부 더블 하이픈 제거
더블 하이픈이 포함된 XML을 직접 삽입하려는 경우, 해당 문자를 대체하거나 제거해야 합니다.
-- 잘못된 예 (에러 발생)
SELECT XMLPARSE(DOCUMENT '<?xml version="1.0"?><!-- 이것은 -- 잘못된 주석 --><root/>');
-- ERROR: invalid xml comment
-- 올바른 예: 더블 하이픈 제거
SELECT XMLPARSE(DOCUMENT '<?xml version="1.0"?><!-- 이것은 올바른 주석 --><root/>');
-- 올바른 예: 더블 하이픈을 단일 하이픈으로 치환 후 삽입
SELECT XMLPARSE(DOCUMENT
replace('<?xml version="1.0"?><!-- 이것은 -- 잘못된 주석 --><root/>', '--', '-')
);
-- XML 주석이 하이픈으로 끝나는 경우도 에러 발생
-- 잘못된 예
SELECT XMLPARSE(DOCUMENT '<?xml version="1.0"?><!-- 주석 끝에 하이픈- --><root/>');
-- ERROR: invalid xml comment
-- 올바른 예: 끝 하이픈 제거
SELECT XMLPARSE(DOCUMENT '<?xml version="1.0"?><!-- 주석 끝에 하이픈 없음 --><root/>');
원인 2 해결: XMLCOMMENT() 함수 사용 시 입력값 검증
-- 잘못된 예: -- 포함된 문자열 전달
SELECT XMLCOMMENT('이것은 -- 잘못된 주석입니다');
-- ERROR: invalid xml comment
-- 잘못된 예: - 로 끝나는 문자열 전달
SELECT XMLCOMMENT('이것은 잘못된 주석입니다-');
-- ERROR: invalid xml comment
-- 올바른 예: 안전하게 문자열 정제 후 사용
SELECT XMLCOMMENT(
rtrim(
replace('이것은 -- 잘못된 주석입니다', '--', '-'),
'-'
)
);
-- 실무 함수: XML 주석 안전 생성 함수
CREATE OR REPLACE FUNCTION safe_xmlcomment(p_text TEXT)
RETURNS XML AS $$
DECLARE
v_cleaned TEXT;
BEGIN
-- 더블 하이픈을 단일 하이픈으로 치환
v_cleaned := replace(p_text, '--', '-');
-- 끝에 오는 하이픈 제거
v_cleaned := rtrim(v_cleaned, '-');
-- 빈 문자열 처리
IF v_cleaned IS NULL OR trim(v_cleaned) = '' THEN
RETURN XMLCOMMENT('empty');
END IF;
RETURN XMLCOMMENT(v_cleaned);
END;
$$ LANGUAGE plpgsql;
-- 사용 예시
SELECT safe_xmlcomment('이것은 -- 사용자 입력 -- 주석입니다-');
-- 결과: <!-- 이것은 - 사용자 입력 - 주석입니다-->
원인 3 해결: 외부 XML 데이터 정제 후 삽입
-- 외부 XML 데이터를 삽입하기 전에 유효성 검사 및 정제
-- 방법 1: xml_is_well_formed() 함수로 사전 검증
SELECT xml_is_well_formed('<?xml version="1.0"?><!-- 잘못된 -- 주석 --><root/>');
-- 결과: false (PostgreSQL 버전에 따라 다를 수 있음)
-- 방법 2: 트랜잭션 내에서 에러 처리
DO $$
DECLARE
v_xml_data TEXT := '<?xml version="1.0"?><!-- 외부 -- 데이터 --><root><item>값</item></root>';
v_parsed XML;
BEGIN
BEGIN
v_parsed := XMLPARSE(DOCUMENT v_xml_data);
-- 유효한 경우 삽입 진행
INSERT INTO xml_documents (doc_id, xml_data, created_at)
VALUES (nextval('xml_doc_seq'), v_parsed, NOW());
RAISE NOTICE '삽입 성공';
EXCEPTION WHEN SQLSTATE '2200S' THEN
-- 주석 정제 후 재시도
v_xml_data := regexp_replace(v_xml_data, '--(?!>)', '-', 'g');
BEGIN
v_parsed := XMLPARSE(DOCUMENT v_xml_data);
INSERT INTO xml_documents (doc_id, xml_data, created_at)
VALUES (nextval('xml_doc_seq'), v_parsed, NOW());
RAISE NOTICE '정제 후 삽입 성공';
EXCEPTION WHEN OTHERS THEN
RAISE WARNING '삽입 실패: %', SQLERRM;
END;
END;
END;
$$;
-- 방법 3: XML 주석 자체를 제거하는 방법
-- 주석이 불필요한 경우, 정규식으로 완전히 제거
CREATE OR REPLACE FUNCTION strip_xml_comments(p_xml_text TEXT)
RETURNS TEXT AS $$
BEGIN
RETURN regexp_replace(p_xml_text, '<!--.*?-->', '', 'g');
END;
$$ LANGUAGE plpgsql;
-- 사용 예
SELECT XMLPARSE(DOCUMENT
strip_xml_comments('<?xml version="1.0"?><!-- 잘못된 -- 주석 --><root><item>데이터</item></root>')
);
예방 방법
- XML 데이터 생성 시 전용 라이브러리 또는 함수 사용
XML을 직접 문자열로 조합하는 방식 대신, PostgreSQL의 내장 XML 함수(XMLELEMENT, XMLFOREST, XMLAGG, XMLCOMMENT 등)를 활용하여 XML을 생성하세요. 이 함수들은 XML 표준을 준수하는 방식으로 데이터를 생성하므로 주석 형식 오류를 사전에 방지할 수 있습니다. 외부 언어(Python, Java 등)에서 XML을 생성할 때도 반드시 검증된 XML 라이브러리(lxml, JAXB 등)를 사용하고, 문자열 연결 방식의 XML 생성은 지양해야 합니다.
“`sql
— 권장: 내장 함수로 XML 구성
SELECT XMLELEMENT(
NAME “report”,
XMLCOMMENT(‘생성일: ‘ || TO_CHAR(NOW(), ‘YYYY-MM-DD’)),
XMLELEMENT(NAME “data”, ‘값’)
);
“`
- 입력 데이터 검증 레이어 구축 (Check Constraint 또는 트리거 활용)
XML 데이터를 저장하는 테이블에 Check Constraint 또는 BEFORE INSERT/UPDATE 트리거를 추가하여, 유효하지 않은 XML이 데이터베이스에 저장되지 않도록 방어선을 구축하세요. 이를 통해 운영 환경에서 에러가 발생하기 전에 문제를 조기에 발견할 수 있습니다.
“`sql
— 트리거를 활용한 XML 유효성 검사
CREATE OR REPLACE FUNCTION validate_xml_before_insert()
RETURNS TRIGGER AS $$
BEGIN
BEGIN
PERFORM XMLPARSE(DOCUMENT NEW.xml_data::TEXT);
EXCEPTION WHEN OTHERS THEN
RAISE EXCEPTION ‘Invalid XML data: %. SQLSTATE: %’, SQLERRM, SQLSTATE;
END;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER trg_validate_xml
BEFORE INSERT OR UPDATE ON xml_documents
FOR EACH ROW EXECUTE FUNCTION validate_xml_before_insert();
“`
관련 에러
2200M: invalid XML document: XML 문서 자체가 Well-Formed 하지 않을 때 발생하며, 태그 불일치, 잘못된 루트 요소 등이 원인입니다.2200N: invalid XML content: XML 컨텐츠(Document 가 아닌 Fragment) 가 유효하지 않을 때 발생합니다.22000: data exception: XML 처리와 관련된 일반적인 데이터 예외의 상위 에러 클래스입니다.2200T: invalid XML processing instruction: XML 처리 명령(Processing Instruction)의 형식이 잘못되었을 때 발생합니다.
주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.
본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.