2026년 10월 21일 | DBMS Error 가이드
이 글에서 다루는 내용
22024 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.
22024 unterminated c string 는?
PostgreSQL 에러 코드 22024 (unterminated_c_string)은 C 언어 스타일의 문자열, 즉 null 종단 문자(\0)로 끝나야 하는 문자열이 올바르게 종료되지 않았을 때 발생합니다. 이 에러는 주로 bytea 타입 데이터, 외부 함수 연동, 또는 잘못된 이스케이프 시퀀스가 포함된 문자열을 PostgreSQL이 처리하는 과정에서 나타납니다. 특히 레거시 시스템에서 마이그레이션하거나, 외부 언어(Python, C, Java 등)에서 raw 바이트를 PostgreSQL로 전달할 때 빈번하게 마주치는 에러입니다.
주요 발생 원인
1. 잘못된 이스케이프 시퀀스 또는 null 바이트가 포함된 문자열
가장 흔한 원인으로, 문자열 리터럴 내부에 null 바이트(\x00 또는 \000)가 포함되어 있거나, C 스타일 이스케이프 처리 중 종료 문자를 올바르게 인식하지 못하는 경우입니다. PostgreSQL은 내부적으로 많은 문자열 처리를 C 언어 방식으로 수행하기 때문에, null 바이트가 중간에 등장하면 문자열의 끝으로 오인하거나 반대로 끝을 찾지 못해 에러가 발생합니다. 특히 standard_conforming_strings = off 환경에서 백슬래시(\) 이스케이프를 처리할 때 이 문제가 자주 발생합니다.
2. bytea 데이터 또는 바이너리 데이터를 text로 잘못 캐스팅
bytea 타입의 이진 데이터를 명시적 변환 없이 text 또는 varchar 타입에 직접 삽입하거나 비교할 때 이 에러가 발생할 수 있습니다. 바이너리 데이터에는 null 바이트를 포함한 임의의 바이트 시퀀스가 존재할 수 있으며, 이를 C 문자열로 처리하려 하면 PostgreSQL 내부에서 문자열 종료 지점을 올바르게 파악하지 못합니다. 데이터 마이그레이션 또는 ETL 파이프라인에서 타입 처리를 소홀히 할 경우 이 문제가 대량 발생할 수 있습니다.
3. 외부 C 확장 함수 또는 PL/C 함수에서의 잘못된 문자열 반환
PostgreSQL 확장 개발 시 C 언어로 작성된 함수가 올바르게 null-terminate된 문자열(\0으로 끝나는)을 반환하지 않으면 PostgreSQL 코어가 해당 문자열을 읽을 때 이 에러를 발생시킵니다. PG_RETURN_CSTRING() 매크로를 사용하거나 Datum을 반환할 때 메모리 할당 및 종료 문자 처리를 정확히 해야 합니다. 이 경우는 발견이 어렵고, 특정 입력값에서만 재현되는 경우가 많아 디버깅이 까다롭습니다.
해결 방법
원인 1 해결: 이스케이프 문자 및 null 바이트 처리
먼저 현재 세션의 standard_conforming_strings 설정을 확인하고, 문제가 되는 문자열에서 null 바이트를 제거하거나 이스케이프 처리합니다.
-- 현재 설정 확인
SHOW standard_conforming_strings;
-- 권장 설정: on으로 변경 (백슬래시를 리터럴로 처리)
SET standard_conforming_strings = on;
-- null 바이트가 포함된 문자열 탐지
SELECT id, content
FROM my_table
WHERE content LIKE '%' || chr(0) || '%';
-- null 바이트 제거 후 업데이트
UPDATE my_table
SET content = replace(content, chr(0), '')
WHERE content LIKE '%' || chr(0) || '%';
-- 안전한 문자열 삽입 예시 (E'' 이스케이프 문법 사용)
INSERT INTO my_table (content)
VALUES (E'Hello World'); -- 올바른 방식
-- 문제가 될 수 있는 예시 (null 바이트 포함)
-- INSERT INTO my_table (content) VALUES (E'Hello\x00World'); -- 위험!
원인 2 해결: bytea 타입 명시적 변환
-- 잘못된 방식: bytea를 text로 직접 비교
-- SELECT * FROM files WHERE file_data = 'some text'; -- 에러 발생 가능
-- 올바른 방식: encode 함수로 변환 후 처리
SELECT id, encode(file_data, 'hex') AS hex_representation
FROM files;
-- bytea를 text로 안전하게 변환
SELECT id, convert_from(file_data, 'UTF8') AS text_content
FROM files
WHERE octet_length(file_data) > 0;
-- null 바이트 포함 여부 확인 (bytea)
SELECT id
FROM files
WHERE file_data @> '\x00'::bytea;
-- bytea 데이터에서 null 바이트 제거
UPDATE files
SET file_data = replace(file_data, '\x00'::bytea, ''::bytea)
WHERE file_data @> '\x00'::bytea;
-- 안전한 bytea 삽입
INSERT INTO files (file_data)
VALUES (decode('48656c6c6f', 'hex')); -- 'Hello'를 hex로 인코딩하여 삽입
원인 3 해결: C 확장 함수 디버깅
-- 문제가 되는 함수 호출 전 입력값 검증
DO $$
DECLARE
v_input TEXT := 'test_input';
BEGIN
-- null 바이트 포함 여부 사전 검증
IF position(chr(0) IN v_input) > 0 THEN
RAISE EXCEPTION '입력값에 null 바이트가 포함되어 있습니다: %', v_input;
END IF;
-- 안전한 경우에만 외부 함수 호출
PERFORM my_c_extension_function(v_input);
END;
$$;
-- 확장 함수 버전 및 상태 확인
SELECT name, default_version, installed_version
FROM pg_available_extensions
WHERE name = 'my_extension';
-- 문제가 되는 함수의 정의 확인
SELECT proname, prosrc, prolang
FROM pg_proc
WHERE proname = 'my_c_extension_function';
예방 방법
1. 데이터 입력 시 null 바이트 사전 필터링 및 입력 유효성 검사 트리거 구성
애플리케이션 레벨과 데이터베이스 레벨 양쪽에서 null 바이트를 사전 차단하는 것이 가장 효과적인 예방책입니다. 아래와 같이 트리거를 설정하면 테이블에 데이터가 삽입되거나 수정될 때 자동으로 null 바이트를 검사하고 제거합니다.
-- null 바이트 자동 정리 트리거 함수 생성
CREATE OR REPLACE FUNCTION sanitize_null_bytes()
RETURNS TRIGGER AS $$
BEGIN
-- text 타입 컬럼의 null 바이트 제거
NEW.content := replace(NEW.content, chr(0), '');
NEW.title := replace(NEW.title, chr(0), '');
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- 트리거 연결
CREATE TRIGGER trg_sanitize_null_bytes
BEFORE INSERT OR UPDATE ON my_table
FOR EACH ROW EXECUTE FUNCTION sanitize_null_bytes();
또한 애플리케이션 코드(Python, Java 등)에서 PostgreSQL에 데이터를 전달하기 전에 반드시 null 바이트를 제거하는 유틸리티 함수를 공통 모듈로 만들어 팀 전체가 사용하도록 표준화하는 것이 좋습니다.
2. standard_conforming_strings 설정 통일 및 postgresql.conf 관리
모든 환경(개발, 스테이징, 운영)에서 standard_conforming_strings = on으로 통일하여 이스케이프 처리 방식의 불일치를 방지합니다. PostgreSQL 9.1 이후부터 기본값이 on으로 변경되었으나, 레거시 시스템이나 오래된 드라이버를 사용하는 경우 여전히 off로 설정된 경우가 있습니다.
-- postgresql.conf에 설정 (영구 적용)
-- standard_conforming_strings = on
-- 현재 세션에서 즉시 적용
SET standard_conforming_strings = on;
-- 특정 데이터베이스 수준으로 설정
ALTER DATABASE mydb SET standard_conforming_strings = on;
-- 설정 확인
SELECT name, setting, source
FROM pg_settings
WHERE name = 'standard_conforming_strings';
관련 에러
- 22000 (data_exception):
22024의 상위 카테고리 에러로, 데이터 값 처리 전반에 걸친 문제를 포괄합니다. - 22021 (character_not_in_repertoire): 지정된 문자 집합에 포함되지 않는 문자를 삽입하거나 변환할 때 발생하며, 인코딩 관련 에러로
22024와 함께 나타나는 경우가 많습니다. - 22P02 (invalid_text_representation): 텍스트를 특정 타입으로 변환할 때 형식이 맞지 않는 경우 발생하며, 잘못된 바이너리 데이터를 텍스트로 처리할 때
22024와 혼동되기 쉽습니다. - 42601 (syntax_error): 문자열 리터럴이 올바르게 닫히지 않아 SQL 파싱 단계에서 실패할 경우 발생하며,
22024와 유사한 증상을 보이나 발생 시점이 실행 전 파싱 단계라는 점이 다릅니다.
주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.
본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.