2026년 08월 17일 | DBMS Error 가이드
이 글에서 다루는 내용
2200F 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.
2200F zero length character string 는?
PostgreSQL 에러 코드 2200F (zero_length_character_string)는 길이가 0인 문자열, 즉 빈 문자열('')이 허용되지 않는 컨텍스트에서 사용될 때 발생하는 에러입니다. 주로 정규 표현식 함수, 특정 문자열 처리 함수, 또는 타입 변환 과정에서 빈 문자열이 입력값으로 전달될 때 이 에러가 트리거됩니다. SQL 표준(SQLSTATE 22)의 데이터 예외 계열에 속하며, 런타임 시 데이터 유효성 검사에 실패했음을 의미합니다.
주요 발생 원인
1. 정규 표현식 함수에 빈 패턴 전달
regexp_replace(), regexp_match(), regexp_split_to_table() 등 PostgreSQL의 정규 표현식 함수는 패턴 인자로 빈 문자열을 허용하지 않습니다. 예를 들어 사용자 입력을 그대로 정규 표현식 패턴으로 전달하는 동적 쿼리에서 입력값이 비어 있으면 즉시 이 에러가 발생합니다. 이 경우는 실무에서 가장 빈번하게 마주치는 원인이며, 특히 검색 기능 구현 시 필터 조건이 비어 있을 때 자주 발생합니다.
-- 에러 발생 예시
SELECT regexp_replace('hello world', '', 'X');
-- ERROR: invalid regular expression: 2200F zero_length_character_string
SELECT regexp_match('test string', '');
-- ERROR: invalid regular expression: 2200F zero_length_character_string
2. SIMILAR TO 또는 LIKE 연산자와 빈 패턴의 조합
SIMILAR TO 연산자는 SQL 표준 정규 표현식을 사용하는데, 내부적으로 빈 패턴을 처리하지 못합니다. 동적으로 생성된 WHERE 절에서 패턴 변수가 빈 문자열로 설정되면 예상치 못한 에러가 발생할 수 있습니다. 이 경우는 ORM 프레임워크나 동적 SQL을 생성하는 미들웨어 레이어에서 특히 주의가 필요합니다.
-- 에러 발생 예시 (일부 PostgreSQL 버전 및 컨텍스트)
SELECT 'test' SIMILAR TO '';
-- 빈 패턴으로 인한 예기치 않은 동작 발생 가능
-- 함수 내부에서의 패턴 검증
CREATE OR REPLACE FUNCTION search_users(pattern TEXT)
RETURNS TABLE(username TEXT) AS $$
BEGIN
-- pattern이 ''인 경우 에러 발생
RETURN QUERY
SELECT name FROM users WHERE name ~ pattern;
END;
$$ LANGUAGE plpgsql;
3. 타입 변환 및 캐스팅 과정에서의 빈 문자열
일부 PostgreSQL 타입 변환 함수나 캐스팅 연산에서 빈 문자열이 유효하지 않은 입력으로 간주될 수 있습니다. 예를 들어, 빈 문자열을 특정 도메인 타입이나 커스텀 타입으로 변환하려 할 때 해당 타입의 입력 함수가 이 에러를 발생시킬 수 있습니다. 사용자 정의 도메인에 CHECK 제약 조건이 있는 경우 빈 문자열이 제약 조건을 위반하면서 연쇄적으로 이 에러가 발생하기도 합니다.
-- 커스텀 도메인 예시
CREATE DOMAIN non_empty_text AS TEXT
CHECK (VALUE <> '' AND VALUE IS NOT NULL);
-- 에러 발생
INSERT INTO employees (name) VALUES (''::non_empty_text);
-- ERROR: value for domain non_empty_text violates check constraint
-- ENUM 또는 특수 타입 변환 시
SELECT ''::xml;
-- 일부 버전에서 zero length 관련 에러 발생 가능
해결 방법
원인 1 해결: 정규 표현식 함수 호출 전 빈 문자열 검사
함수 호출 전에 반드시 패턴이 비어 있지 않은지 확인하고, 빈 문자열인 경우 대안 로직을 적용하세요.
-- NULLIF를 활용한 안전한 처리
SELECT CASE
WHEN pattern IS NULL OR pattern = '' THEN original_text
ELSE regexp_replace(original_text, pattern, replacement)
END AS result
FROM (VALUES ('hello world', '', 'X')) AS t(original_text, pattern, replacement);
-- 실무용 안전한 래퍼 함수 작성
CREATE OR REPLACE FUNCTION safe_regexp_replace(
input_text TEXT,
pattern TEXT,
replacement TEXT,
flags TEXT DEFAULT ''
)
RETURNS TEXT AS $$
BEGIN
-- 빈 패턴 방어 로직
IF pattern IS NULL OR length(pattern) = 0 THEN
RETURN input_text;
END IF;
RETURN regexp_replace(input_text, pattern, replacement, flags);
EXCEPTION
WHEN SQLSTATE '2200F' THEN
RAISE WARNING 'zero_length_character_string caught for pattern: [%]', pattern;
RETURN input_text;
END;
$$ LANGUAGE plpgsql IMMUTABLE;
-- 사용 예시
SELECT safe_regexp_replace('hello world', '', 'X'); -- 'hello world' 반환
SELECT safe_regexp_replace('hello world', 'l', 'L'); -- 'heLLo worLd' 반환
원인 2 해결: 동적 패턴 검색 시 조건 분기 처리
-- 동적 검색 함수 개선 버전
CREATE OR REPLACE FUNCTION search_users(pattern TEXT)
RETURNS TABLE(username TEXT) AS $$
BEGIN
-- 빈 패턴이면 전체 반환
IF pattern IS NULL OR trim(pattern) = '' THEN
RETURN QUERY SELECT name FROM users;
RETURN;
END IF;
-- 유효한 패턴인 경우에만 정규식 적용
RETURN QUERY
SELECT name FROM users
WHERE name ~* pattern;
EXCEPTION
WHEN SQLSTATE '2200F' THEN
RAISE EXCEPTION 'Invalid search pattern provided: %', pattern;
END;
$$ LANGUAGE plpgsql;
-- COALESCE와 NULLIF 조합으로 인라인 처리
SELECT *
FROM products
WHERE
(:search_term = '' OR product_name ~* NULLIF(:search_term, ''));
원인 3 해결: 도메인 및 타입 변환 방어 처리
-- 삽입 전 빈 문자열 검증 트리거
CREATE OR REPLACE FUNCTION validate_non_empty_fields()
RETURNS TRIGGER AS $$
BEGIN
IF NEW.name IS NOT NULL AND length(trim(NEW.name)) = 0 THEN
RAISE EXCEPTION 'Column "name" must not be an empty string (SQLSTATE 2200F prevention)';
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER trg_validate_employees_name
BEFORE INSERT OR UPDATE ON employees
FOR EACH ROW EXECUTE FUNCTION validate_non_empty_fields();
-- 애플리케이션 레이어에서 데이터 정제 후 삽입
INSERT INTO employees (name)
SELECT NULLIF(trim(input_name), '') -- 빈 문자열은 NULL로 변환
FROM staging_data
WHERE input_name IS NOT NULL;
예방 방법
1. 입력 유효성 검증 레이어 구축
애플리케이션 레이어와 데이터베이스 레이어 양쪽에서 이중으로 빈 문자열을 검증하는 습관을 들이세요. PostgreSQL의 CHECK 제약 조건과 BEFORE 트리거를 활용하면 잘못된 데이터가 DB에 저장되기 전에 차단할 수 있습니다. 특히 정규 표현식 함수를 사용하는 모든 저장 프로시저에는 반드시 입력값 길이 검증 로직을 포함시켜야 합니다.
-- 테이블 레벨 CHECK 제약 조건 추가
ALTER TABLE users
ADD CONSTRAINT chk_username_not_empty
CHECK (username IS NULL OR length(trim(username)) > 0);
-- 공통 검증 함수 라이브러리화
CREATE OR REPLACE FUNCTION is_valid_pattern(p TEXT)
RETURNS BOOLEAN AS $$
SELECT p IS NOT NULL AND length(trim(p)) > 0;
$$ LANGUAGE sql IMMUTABLE;
2. 예외 처리 블록과 로깅 표준화
운영 환경에서는 SQLSTATE '2200F'를 명시적으로 캐치하는 예외 처리 블록을 모든 정규 표현식 관련 함수에 추가하고, 발생 시 충분한 컨텍스트 정보를 로그에 남겨 빠른 디버깅이 가능하도록 하세요. 중앙화된 에러 로깅 테이블을 운영하면 패턴을 분석하고 근본 원인을 파악하는 데 큰 도움이 됩니다.
-- 중앙 에러 로깅 테이블 및 패턴
CREATE TABLE IF NOT EXISTS db_error_log (
id BIGSERIAL PRIMARY KEY,
error_code TEXT,
error_msg TEXT,
context JSONB,
occurred_at TIMESTAMPTZ DEFAULT now()
);
-- 예외 처리 + 로깅 패턴
CREATE OR REPLACE FUNCTION safe_search(pattern TEXT)
RETURNS SETOF TEXT AS $$
BEGIN
RETURN QUERY SELECT data FROM my_table WHERE data ~ pattern;
EXCEPTION
WHEN SQLSTATE '2200F' THEN
INSERT INTO db_error_log(error_code, error_msg, context)
VALUES ('2200F', 'zero_length_character_string',
jsonb_build_object('pattern', pattern, 'function', 'safe_search'));
RAISE WARNING '2200F error logged for pattern: [%]', pattern;
END;
$$ LANGUAGE plpgsql;
관련 에러
- 22001 (string_data_right_truncation): 문자열 데이터가 컬럼의 최대 길이를 초과할 때 발생하며, 2200F와 반대 방향의 문자열 길이 관련 에러입니다.
- 22P02 (invalid_text_representation): 텍스트를 특정 타입으로 변환할 수 없을 때 발생하며, 빈 문자열 캐스팅 문제와 함께 나타나는 경우가 많습니다.
- 2201B (invalid_regular_expression): 정규 표현식 자체가 문법적으로 잘못되었을 때 발생하며, 2200F와 마찬가지로 regexp 계열 함수에서 주로 발생합니다. 빈 문자열 패턴은 종종 이 두 에러 코드 중 하나로 나타납니다.
- 23514 (check_violation): 도메인이나 테이블의 CHECK 제약 조건을 위반했을 때 발생하며, 빈 문자열 방어 로직을 CHECK 제약으로 구현한 경우 2200F 대신 이 에러가 반환될 수 있습니다.
주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.
본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.