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

42939
2026년 09월 09일 | DBMS Error 가이드

이 글에서 다루는 내용

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

42939 reserved name 는?

PostgreSQL 에러 코드 42939(reserved_name)는 사용자가 PostgreSQL 내부적으로 예약된 이름을 식별자(테이블명, 컬럼명, 함수명, 타입명 등)로 사용하려 할 때 발생합니다. PostgreSQL은 내부 동작에 필요한 특정 키워드나 이름을 시스템 레벨에서 보호하고 있으며, 이러한 예약어를 그대로 객체 이름으로 사용하면 해당 에러가 발생합니다. 특히 커스텀 타입, 함수, 연산자 등을 생성할 때 자주 마주치며, 데이터베이스 마이그레이션 작업이나 레거시 시스템을 PostgreSQL로 전환하는 과정에서도 빈번하게 나타납니다.


주요 발생 원인

  • PostgreSQL 예약 키워드를 객체 이름으로 사용

가장 흔한 원인으로, all, analyze, any, array, as, asc, default, desc, distinct, from, grant, group, having, in, initially, intersect, into, lateral, leading, limit, offset, only, order, returning, select, table, then, to, trailing, union, unique, using, variadic, when, where, window, with 등 SQL 표준 및 PostgreSQL 전용 예약어를 테이블명이나 컬럼명으로 사용하면 이 에러가 발생합니다. 단순히 큰따옴표로 감싸면 회피 가능한 경우도 있지만, 42939 에러는 시스템이 내부적으로 강하게 보호하는 이름에 대해 큰따옴표로도 허용하지 않는 상황에서 발생합니다.

  • 커스텀 데이터 타입 또는 함수 이름이 내부 예약 이름과 충돌

PostgreSQL은 내장 타입(int, text, boolean, timestamp 등)과 내장 함수(now(), current_user, session_user 등)의 이름을 보호합니다. 사용자가 CREATE TYPE 또는 CREATE FUNCTION 구문으로 이와 동일한 이름의 객체를 만들려 할 때 42939 에러가 발생합니다. 특히 다른 DBMS(Oracle, MySQL 등)에서 마이그레이션 시 기존 시스템의 타입명이나 함수명이 PostgreSQL 내부 예약 이름과 겹쳐 문제가 되는 경우가 많습니다.

  • 확장(Extension) 설치 또는 스키마 조작 시 이름 충돌

PostgreSQL 확장 모듈을 설치하거나 pg_catalog, information_schema 등 시스템 스키마에 영향을 주는 작업을 수행할 때 내부 예약 이름과 충돌이 발생할 수 있습니다. 일부 레거시 확장 또는 직접 작성한 C 언어 확장이 PostgreSQL 버전 업그레이드 이후 내부 이름 체계가 변경되어 충돌하는 경우도 포함됩니다. 이 경우는 단순한 이름 변경으로 해결되지 않고, 스키마 설계 전반을 재검토해야 할 수도 있습니다.


해결 방법

원인 1 해결: 예약어 대신 대체 이름 사용

가장 근본적인 해결책은 예약어와 겹치지 않는 이름으로 변경하는 것입니다.

-- 잘못된 예: 예약어 'order'를 테이블명으로 사용
CREATE TABLE order (
    id SERIAL PRIMARY KEY,
    customer_id INT NOT NULL,
    total_amount NUMERIC(10, 2)
);
-- ERROR:  42939: "order" is a reserved name

-- 올바른 예: 의미 있는 접두사/접미사 추가
CREATE TABLE orders (
    id SERIAL PRIMARY KEY,
    customer_id INT NOT NULL,
    total_amount NUMERIC(10, 2)
);

-- 또는 도메인 접두사를 붙이는 방식
CREATE TABLE shop_order (
    id SERIAL PRIMARY KEY,
    customer_id INT NOT NULL,
    total_amount NUMERIC(10, 2)
);

일부 경우에는 큰따옴표(double quote)로 감싸서 식별자로 인식시킬 수 있습니다. 단, 이는 항상 큰따옴표를 함께 사용해야 하므로 유지보수가 어렵고 권장하지 않습니다.

-- 큰따옴표 사용 (권장하지 않음, 유지보수 어려움)
CREATE TABLE "order" (
    id SERIAL PRIMARY KEY,
    customer_id INT NOT NULL
);

-- 이후 쿼리에서도 반드시 큰따옴표 사용 필요
SELECT * FROM "order" WHERE id = 1;

원인 2 해결: 커스텀 타입/함수 이름 변경

-- 잘못된 예: 내장 타입명과 동일한 커스텀 타입 생성
CREATE TYPE text AS ENUM ('small', 'medium', 'large');
-- ERROR:  42939: "text" is a reserved name

-- 올바른 예: 명확한 도메인 이름 사용
CREATE TYPE product_size AS ENUM ('small', 'medium', 'large');

-- 함수명 충돌 예시
CREATE FUNCTION now() RETURNS TIMESTAMPTZ AS $$
    SELECT CURRENT_TIMESTAMP;
$$ LANGUAGE SQL;
-- ERROR:  42939: "now" is a reserved name

-- 올바른 예: 애플리케이션 고유 접두사 부여
CREATE FUNCTION app_current_time() RETURNS TIMESTAMPTZ AS $$
    SELECT CURRENT_TIMESTAMP;
$$ LANGUAGE SQL;

-- 기존에 잘못 생성된 타입이 있다면 이름 변경
ALTER TYPE old_reserved_type_name RENAME TO new_safe_type_name;

원인 3 해결: 스키마 분리 및 search_path 활용

-- 별도 스키마를 만들어 충돌 가능성 최소화
CREATE SCHEMA myapp;

-- 스키마를 명시하여 시스템 예약 이름과 분리
CREATE TABLE myapp.order_detail (
    id SERIAL PRIMARY KEY,
    order_id INT NOT NULL,
    product_id INT NOT NULL,
    quantity INT DEFAULT 1
);

-- search_path 설정으로 기본 스키마 지정
SET search_path TO myapp, public;

-- 예약어 충돌 여부 사전 확인 쿼리
SELECT word, catdesc
FROM pg_get_keywords()
WHERE word = 'order'  -- 확인하려는 단어 입력
  AND catdesc LIKE '%reserved%';

예약어 목록 확인 방법

-- PostgreSQL에서 예약된 키워드 전체 목록 확인
SELECT word, catdesc
FROM pg_get_keywords()
WHERE catdesc = 'reserved'
ORDER BY word;

-- 특정 단어가 예약어인지 확인
SELECT word, catdesc
FROM pg_get_keywords()
WHERE word IN ('order', 'select', 'table', 'index', 'user');

예방 방법

  • 네이밍 컨벤션(Naming Convention) 수립 및 준수

팀 내에서 PostgreSQL 예약어와 충돌하지 않는 네이밍 규칙을 사전에 정의하고, 모든 데이터베이스 객체에 일관되게 적용합니다. 예를 들어 테이블명은 복수형(orders, users, products), 커스텀 타입명은 도메인 접두사(app_, biz_)를 붙이는 방식을 사용하면 예약어와의 충돌을 원천적으로 차단할 수 있습니다. DDL 작성 전 반드시 pg_get_keywords() 함수로 사용하려는 이름이 예약어인지 확인하는 습관을 들이는 것이 중요합니다.

“`sql

— DDL 작성 전 예약어 확인 습관화

SELECT word, catdesc

FROM pg_get_keywords()

WHERE word = ‘사용하려는_이름’;

“`

  • CI/CD 파이프라인에 DDL 린트(Lint) 도구 통합

sqlfluff, pgTAP, 또는 커스텀 스크립트를 CI/CD 파이프라인에 통합하여 DDL 스크립트가 배포되기 전에 예약어 충돌을 자동으로 감지합니다. 코드 리뷰 단계에서 DBA 또는 시니어 엔지니어가 반드시 DDL 변경 사항을 검토하는 프로세스를 수립하면, 프로덕션 환경에서의 42939 에러 발생을 사전에 차단할 수 있습니다.


관련 에러

  • 42601 (syntax_error): 예약어를 잘못된 위치에서 사용할 때 발생하는 문법 오류로, 42939와 혼동하기 쉽습니다. 42601은 SQL 문법 자체의 문제이고, 42939는 이름 예약 충돌입니다.
  • 42P07 (duplicate_table): 이미 존재하는 테이블 이름으로 객체를 생성하려 할 때 발생하며, 이름 충돌 계열의 에러입니다.
  • 42723 (duplicate_function): 동일한 시그니처의 함수가 이미 존재할 때 발생하며, 커스텀 함수 생성 시 42939와 함께 자주 마주칩니다.
  • 42704 (undefined_object): 예약어와 관련된 객체를 DROP하거나 ALTER하려 할 때, 해당 객체가 시스템에 존재하지 않는 이름으로 인식될 경우 발생할 수 있습니다.
DBMS 에러 코드 시리즈

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

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

댓글 남기기