PostgreSQL 오류 42704

반응형
PostgreSQL 오류 42704 원인과 해결

postgresql error 42704

SQLSTATE 42704는 PostgreSQL이 “요청한 객체(Object)를 찾을 수 없다”고 판단할 때 발생한다. 테이블·뷰·컬럼뿐 아니라 타입/연산자/확장/시퀀스/함수 등 범위가 넓어, 검색 경로와 식별자 규칙부터 잡는 게 빠르다.

개요

PostgreSQL에서 SQLSTATE 42704는 일반적으로 Undefined Object 계열로 분류된다. 흔히 “relation does not exist”, “type does not exist”, “operator does not exist”처럼 특정 객체를 참조했지만 해당 객체가 현재 세션에서 해석되지 않는 상황에서 발생한다.

실무 기준으로 보면
42704는 “진짜로 객체가 없음”과 “객체는 있는데 내가 못 찾는 상태(search_path/권한/대소문자)”가 섞여 있다.
그래서 무작정 재생성보다 현재 세션이 무엇을 어디에서 찾는지를 먼저 확인하는 게 정답이다.

환경

  • PostgreSQL 전 버전 공통적으로 발생 가능
  • 발생 지점: 애플리케이션 SQL 실행, 마이그레이션/DDL, 확장 설치, 함수/연산자/타입 사용 시
  • 특히 자주: 멀티 스키마(tenant), ORM, 마이그레이션 도구 사용, 대소문자 섞인 식별자

증상

로그/에러 메시지는 상황에 따라 다양하지만 아래 유형이 대표적이다.

ERROR:  relation "xxx" does not exist
SQLSTATE: 42704
ERROR:  type "xxx" does not exist
SQLSTATE: 42704
ERROR:  operator does not exist: xxx
SQLSTATE: 42704
ERROR:  function xxx(...) does not exist
SQLSTATE: 42704

메시지에서 relation/type/operator/function 중 무엇이 “없다”라고 나오는지 확인하면 점검 방향이 바로 좁혀진다.

1차 점검

1) 현재 DB/스키마 검색 경로 확인

SELECT current_database();
SHOW search_path;

객체가 다른 스키마에 있는데 search_path에 포함되지 않으면 “없는 것”으로 해석될 수 있다. 특히 운영에서 가장 흔한 원인이 이 케이스다.

2) 객체 존재 여부를 카탈로그로 확인

테이블/뷰(=relation) 확인:

SELECT n.nspname AS schema, c.relname AS name, c.relkind
FROM pg_class c
JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relname = '대상객체명'
ORDER BY 1;

타입 확인:

SELECT n.nspname AS schema, t.typname AS type
FROM pg_type t
JOIN pg_namespace n ON n.oid = t.typnamespace
WHERE t.typname = '대상타입명'
ORDER BY 1;

함수 확인(이름만):

SELECT n.nspname AS schema, p.proname AS func
FROM pg_proc p
JOIN pg_namespace n ON n.oid = p.pronamespace
WHERE p.proname = '대상함수명'
ORDER BY 1;

3) 대소문자/따옴표(quoted identifier) 이슈 여부

PostgreSQL은 따옴표 없이 만든 식별자를 내부적으로 소문자로 접는다. 반면, 따옴표로 만든 식별자는 대소문자를 그대로 유지한다.

-- 예: 이렇게 만들면 실제 이름이 UserTable(대소문자 유지)
CREATE TABLE "UserTable" (id bigint);

-- 이렇게 조회하면 소문자 usertable로 찾기 때문에 못 찾을 수 있음
SELECT * FROM UserTable;  -- 실패 가능

-- 이렇게 해야 동일 객체로 인식
SELECT * FROM "UserTable";

4) 권한 문제로 “존재를 못 보는” 케이스도 확인

-- 테이블 권한 예시
SELECT grantee, privilege_type
FROM information_schema.role_table_grants
WHERE table_name = '대상객체명';

보통 권한 문제는 42501(권한 없음)으로 더 자주 나타나지만, 일부 구성/도구에서는 “없음”처럼 보이게 처리되는 경우도 있어 함께 점검한다.

심화 분석

케이스 A) 스키마 미지정/검색경로 문제

객체가 app.orders에 있는데 public만 search_path에 있으면, SELECT * FROM orders;는 실패한다. 이런 경우는 스키마를 명시하는 것이 가장 확실하다.

SELECT * FROM app.orders;

케이스 B) 확장(extension) 미설치로 타입/연산자/함수가 없음

예를 들어 uuid_generate_v4()uuid-ossp 확장이 없으면 “함수 없음”으로 뜬다. pg_trgm가 없으면 특정 연산자/GIN 인덱스 관련 기능을 못 찾는 메시지가 나온다.

-- 설치 여부 확인
SELECT extname FROM pg_extension ORDER BY 1;

-- 필요 시(권한 필요) 설치
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS pg_trgm;

케이스 C) 타입 캐스팅/연산자 해석 실패

“operator does not exist”는 값 타입이 기대와 달라서 연산자 해석이 안 되는 경우가 많다. 이때는 명시적 캐스팅으로 해결되는 경우가 많다.

-- 예시: text와 integer 비교가 섞여 연산자 해석이 실패할 때
SELECT * FROM t WHERE some_text_col = 10::text;
-- 또는
SELECT * FROM t WHERE some_int_col = '10'::integer;

케이스 D) 시퀀스/컬럼 기본값이 가리키는 객체가 사라짐

마이그레이션 중 시퀀스가 삭제/이름 변경되어 기본값이 깨지면 “sequence does not exist” 류로 이어질 수 있다. 기본값을 확인해 “무엇을 참조하는지”부터 보는 게 빠르다.

-- 컬럼 기본값 확인
SELECT column_name, column_default
FROM information_schema.columns
WHERE table_schema = '스키마'
  AND table_name = '테이블명'
  AND column_default IS NOT NULL;

복구

1) 스키마 명시로 즉시 복구(가장 안전)

SELECT * FROM 스키마.테이블;
SELECT 스키마.함수명(...);

2) search_path를 세션/롤 단위로 정리

단기적으로는 세션에서만 고치고, 재발 방지를 위해 롤(계정) 단위로 고정하는 흐름이 일반적이다.

-- 세션 단위
SET search_path TO app, public;

-- 롤 단위(권한 필요)
ALTER ROLE app_user SET search_path TO app, public;

3) quoted identifier 정리(가능하면 “따옴표 식별자”를 줄이기)

이미 따옴표로 만든 객체가 많다면, 애플리케이션 SQL에서 정확히 따옴표를 맞추는 게 우선이다. 장기적으로는 소문자 스네이크 케이스로 리네이밍해 운영 복잡도를 줄이는 편이 낫다.

4) 확장 설치/마이그레이션 재적용

기능을 사용하기 전제인 확장이 누락되었거나, 마이그레이션이 일부만 적용된 경우라면 대상 환경(DB/스키마)을 분명히 한 뒤 재적용한다.

-- 확장 설치
CREATE EXTENSION IF NOT EXISTS pgcrypto;

-- 마이그레이션 도구 사용 시에는
-- (예: schema_migrations 테이블/버전 상태 확인 후 재실행)

재발 방지

1) 스키마 규칙을 표준화

  • 애플리케이션에서 사용하는 기본 스키마를 1개로 고정(예: app)
  • SQL에서 중요한 객체는 스키마를 명시하는 룰 도입(특히 배치/운영 스크립트)

2) search_path를 코드가 아니라 계정(ROLE)에 고정

  • 환경마다 다른 search_path가 숨어 있으면, 배포 후 특정 환경에서만 42704가 터진다
  • ROLE에 고정하면 “어느 커넥션이든 동일한 해석”이 된다

3) 식별자 정책: 따옴표 없이 소문자 스네이크 케이스

객체명에 대문자/특수문자를 섞어 따옴표를 강제하면, 운영에서 “보이는 이름”과 “찾는 이름”이 달라져 장애가 반복된다.

4) 확장/의존성 체크를 배포 파이프라인에 포함

  • 필수 확장 목록을 문서화하고, 배포 시 pg_extension 검사로 누락을 차단
  • 마이그레이션은 “적용됨/미적용됨”을 항상 버전 테이블로 검증
현장 결론
42704는 “없다”가 아니라 “내 세션이 못 찾는다”가 더 흔하다.
스키마 명시 + search_path 표준화 + 따옴표 식별자 최소화가 재발을 가장 크게 줄인다.
반응형