2026년 06월 04일 | DBMS Error 가이드
이 글에서 다루는 내용
22021 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.
22021 character not in repertoire 는?
PostgreSQL 에러 코드 22021은 character not in repertoire 에러로, 특정 문자 인코딩 레퍼토리(repertoire)에 포함되지 않는 문자를 삽입하거나 변환하려 할 때 발생합니다. 쉽게 말해, 데이터베이스나 컬럼이 허용하는 문자 집합 범위를 벗어난 문자를 처리하려 할 때 PostgreSQL이 이 에러를 발생시킵니다. 실무에서는 주로 멀티바이트 문자(한국어, 일본어, 중국어, 이모지 등)를 잘못된 인코딩 설정 환경에서 저장하거나 변환할 때 자주 마주치게 됩니다.
주요 발생 원인
- 데이터베이스 인코딩과 클라이언트 인코딩 불일치
가장 흔한 원인입니다. 데이터베이스는 SQL_ASCII 또는 LATIN1로 설정되어 있는데, 클라이언트에서 UTF-8로 인코딩된 한글이나 특수문자를 전송하면 PostgreSQL이 해당 바이트 시퀀스를 레퍼토리 안에서 찾지 못해 에러가 발생합니다. 특히 레거시 시스템에서 마이그레이션 작업 중 이 문제를 매우 자주 겪습니다.
SQL_ASCII인코딩 데이터베이스에서 멀티바이트 문자 처리
SQL_ASCII는 사실상 인코딩 검사를 거의 하지 않는 특수한 설정으로, 어떤 바이트라도 저장할 수 있는 것처럼 보이지만 문자열 함수(upper(), lower(), length() 등)를 호출하는 순간 문제가 발생합니다. SQL_ASCII 환경에서 멀티바이트 문자에 대해 문자열 처리를 시도하면 레퍼토리 에러가 즉시 발생합니다. 이는 SQL_ASCII가 단일 바이트 ASCII 문자만을 레퍼토리로 간주하기 때문입니다.
convert()또는convert_to()함수 사용 시 인코딩 변환 불가 문자 포함
특정 인코딩에서 다른 인코딩으로 변환할 때, 원본 문자가 대상 인코딩의 레퍼토리에 없으면 이 에러가 발생합니다. 예를 들어, UTF-8 문자열에 포함된 이모지(emoji)나 특수 유니코드 문자를 LATIN1로 변환하려 하면 변환이 불가능하여 22021 에러가 발생합니다.
해결 방법
원인 1 해결: 데이터베이스 인코딩 확인 및 재생성
먼저 현재 데이터베이스 인코딩을 확인합니다.
-- 현재 데이터베이스 인코딩 확인
SELECT datname, pg_encoding_to_char(encoding) AS encoding
FROM pg_database
WHERE datname = current_database();
-- 클라이언트 인코딩 확인
SHOW client_encoding;
-- 서버 인코딩 확인
SHOW server_encoding;
인코딩이 SQL_ASCII 또는 LATIN1이라면, UTF-8 데이터베이스를 새로 생성하고 데이터를 마이그레이션하는 것이 근본적인 해결책입니다.
-- UTF-8 인코딩으로 새 데이터베이스 생성
CREATE DATABASE mydb_utf8
ENCODING = 'UTF8'
LC_COLLATE = 'ko_KR.UTF-8'
LC_CTYPE = 'ko_KR.UTF-8'
TEMPLATE = template0;
-- 클라이언트 인코딩을 UTF-8로 강제 설정
SET client_encoding TO 'UTF8';
기존 데이터베이스의 인코딩 자체는 변경할 수 없으므로, pg_dump를 통해 데이터를 내보낸 뒤 새 데이터베이스에 임포트해야 합니다.
# 기존 DB 덤프 (UTF-8 강제)
pg_dump -h localhost -U postgres -d olddb --encoding=UTF8 -f olddb_dump.sql
# 새 UTF-8 DB에 임포트
psql -h localhost -U postgres -d mydb_utf8 -f olddb_dump.sql
원인 2 해결: SQL_ASCII 환경에서 문자열 함수 사용 시 우회
SQL_ASCII 데이터베이스를 당장 변경할 수 없는 상황이라면, 문자열 함수 적용 전 bytea 타입으로 캐스팅하거나 문제 문자를 필터링하는 방식을 사용합니다.
-- 문제가 되는 케이스 (SQL_ASCII DB에서 한글 length 계산)
-- SELECT length('안녕하세요'); -- 이 경우 에러 발생 가능
-- 우회 방법 1: octet_length 사용 (바이트 수 반환, 인코딩 무관)
SELECT octet_length('안녕하세요') AS byte_length;
-- 우회 방법 2: 특정 컬럼에서 ASCII 범위를 벗어난 문자 필터링
SELECT *
FROM my_table
WHERE col ~ '^[\x00-\x7F]*$'; -- ASCII 문자만 포함된 행 조회
-- 우회 방법 3: 문제 문자를 replace로 제거 후 처리
SELECT length(regexp_replace(my_column, '[^\x00-\x7F]', '', 'g'))
FROM my_table;
원인 3 해결: 인코딩 변환 시 문제 문자 처리
convert() 또는 convert_to() 사용 시 변환 불가 문자가 있을 경우, 사전에 필터링하거나 pg_catalog.convert() 함수의 예외 처리를 활용합니다.
-- UTF-8 문자열을 LATIN1으로 변환 시 문제 발생 예시
-- SELECT convert('한글 텍스트'::bytea, 'UTF8', 'LATIN1'); -- 에러 발생
-- 해결 방법 1: 변환 가능 여부 사전 확인 (PL/pgSQL 예외 처리)
CREATE OR REPLACE FUNCTION safe_convert(p_text TEXT, p_from TEXT, p_to TEXT)
RETURNS BYTEA AS $$
BEGIN
RETURN convert(p_text::bytea, p_from, p_to);
EXCEPTION
WHEN character_not_in_repertoire THEN
RAISE WARNING '변환 불가 문자 포함: %', p_text;
RETURN NULL;
END;
$$ LANGUAGE plpgsql;
-- 함수 사용 예시
SELECT safe_convert('Hello World', 'UTF8', 'LATIN1');
SELECT safe_convert('안녕하세요', 'UTF8', 'LATIN1'); -- NULL 반환 및 경고 출력
-- 해결 방법 2: 변환 전 ASCII 범위 문자만 추출
SELECT convert(
regexp_replace(my_column, '[^\x00-\xFF]', '?', 'g')::bytea,
'UTF8',
'LATIN1'
)
FROM my_table;
예방 방법
- 프로젝트 초기부터 UTF-8 인코딩으로 데이터베이스를 생성하고 표준화하세요.
신규 프로젝트라면 반드시 UTF8 인코딩으로 데이터베이스를 생성하고, postgresql.conf에서 client_encoding = 'UTF8'을 기본값으로 설정하세요. 또한 애플리케이션 연결 문자열에도 인코딩을 명시적으로 지정하여 클라이언트-서버 인코딩 불일치를 원천 차단해야 합니다.
“`sql
— postgresql.conf 설정 확인
SHOW client_encoding;
SHOW server_encoding;
— 세션 레벨에서 인코딩 강제 설정 (애플리케이션 연결 시)
ALTER ROLE myapp_user SET client_encoding TO ‘UTF8’;
“`
- 데이터 입력 단계에서 인코딩 검증 로직을 적용하세요.
데이터가 데이터베이스에 입력되기 전, 애플리케이션 레벨 또는 PostgreSQL CHECK CONSTRAINT를 활용하여 허용되지 않는 문자가 포함되어 있는지 사전 검증하는 로직을 구현하세요. 이를 통해 에러가 실제 운영 환경에서 예기치 않게 발생하는 것을 방지할 수 있습니다.
“`sql
— 입력값에 대한 CHECK CONSTRAINT 예시 (ASCII만 허용 컬럼)
ALTER TABLE my_table
ADD CONSTRAINT chk_ascii_only
CHECK (my_column ~ ‘^[\x00-\x7F]*$’);
“`
관련 에러
22000(data_exception):22021의 상위 카테고리 에러로, 데이터 관련 예외의 일반적인 코드입니다.22P05(untranslatable_character): 특정 문자를 서버 인코딩으로 변환할 수 없을 때 발생하는 에러로,22021과 매우 유사한 상황에서 발생합니다. 클라이언트 인코딩에서 서버 인코딩으로의 변환 실패 시 주로 이 코드가 사용됩니다.42846(cannot_coerce): 데이터 타입 변환 불가 에러로, 인코딩 관련 캐스팅 문제 시 함께 나타날 수 있습니다.22021과22P05의 차이:22021은 문자가 해당 인코딩 레퍼토리 자체에 존재하지 않을 때,22P05는 변환 과정에서 매핑이 불가능할 때 발생한다는 차이가 있습니다. 실무에서는 두 에러를 함께 처리하는 예외 핸들러를 작성하는 것이 좋습니다.
주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.
본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.