2026년 07월 06일 | DBMS Error 가이드
이 글에서 다루는 내용
42602 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.
42602 invalid name 는?
PostgreSQL 에러 코드 42602 (invalid_name) 는 데이터베이스 객체의 이름이 PostgreSQL 명명 규칙을 위반했을 때 발생하는 에러입니다. 테이블, 컬럼, 인덱스, 함수 등의 이름을 정의하거나 참조할 때 허용되지 않는 문자, 잘못된 형식, 또는 예약어 충돌 등으로 인해 이 에러가 트리거됩니다. 실무에서는 주로 동적 SQL 생성, 외부 시스템에서 넘어온 식별자 처리, 또는 특수 문자가 포함된 이름을 다룰 때 빈번하게 발생합니다.
주요 발생 원인
1. 허용되지 않는 특수문자 또는 숫자로 시작하는 식별자
PostgreSQL 식별자(Identifier)는 반드시 문자(a-z, A-Z) 또는 언더스코어(_)로 시작해야 하며, 이후에는 문자, 숫자, 언더스코어, 달러 기호($)만 허용됩니다. 숫자로 시작하거나 하이픈(-), 공백, 특수기호(@, #, !, % 등)를 포함한 이름을 큰따옴표 없이 사용하려 할 때 이 에러가 발생합니다. 특히 외부 API나 스프레드시트에서 가져온 컬럼명을 그대로 사용하려는 경우에 흔히 마주치게 됩니다.
2. 동적 SQL에서 사용자 입력값을 식별자로 직접 사용
EXECUTE 또는 format() 함수를 이용한 동적 SQL을 작성할 때, 검증되지 않은 문자열을 테이블명이나 컬럼명으로 직접 삽입하면 42602 에러가 발생할 수 있습니다. 사용자가 입력한 문자열에 공백이나 특수문자가 포함된 경우, 이를 식별자로 파싱하는 과정에서 에러가 트리거됩니다. 이는 보안적으로도 SQL 인젝션 위험성이 있어 반드시 quote_ident() 함수를 사용해야 합니다.
3. 빈 문자열 또는 NULL 값을 식별자로 사용하는 경우
동적으로 생성된 식별자가 빈 문자열('')이거나 NULL인 경우에도 42602 에러가 발생합니다. 애플리케이션 로직에서 변수 초기화가 제대로 되지 않았거나, 설정 파일에서 잘못된 값이 전달될 때 나타나는 패턴입니다. 이런 경우 에러 메시지가 단순히 invalid name으로만 표시되어 원인 파악이 어려울 수 있습니다.
해결 방법
원인 1 해결: 올바른 식별자 명명 규칙 적용
특수문자가 포함된 이름을 반드시 사용해야 한다면 큰따옴표(double quote) 로 감싸야 합니다. 단, 이 방법을 사용하면 대소문자 구분이 생기므로 항상 일관되게 큰따옴표를 사용해야 합니다.
-- 에러 발생 예시: 숫자로 시작하는 컬럼명
CREATE TABLE sales_data (
1st_quarter INT, -- 42602 에러 발생!
total-amount NUMERIC -- 42602 에러 발생!
);
-- 올바른 방법 1: 큰따옴표로 감싸기 (비권장, 불가피한 경우만)
CREATE TABLE sales_data (
"1st_quarter" INT,
"total-amount" NUMERIC
);
-- 올바른 방법 2: 명명 규칙에 맞게 변경 (권장)
CREATE TABLE sales_data (
first_quarter INT,
total_amount NUMERIC
);
-- 기존 컬럼명 변경
ALTER TABLE sales_data RENAME COLUMN "1st_quarter" TO first_quarter;
ALTER TABLE sales_data RENAME COLUMN "total-amount" TO total_amount;
원인 2 해결: 동적 SQL에서 quote_ident() 사용
동적 SQL을 작성할 때는 반드시 quote_ident() 함수나 format() 함수의 %I 지정자를 사용하여 식별자를 안전하게 처리해야 합니다.
-- 위험한 방법: 직접 문자열 연결 (에러 및 SQL 인젝션 위험)
DO $$
DECLARE
tbl_name TEXT := 'user input; DROP TABLE users;--';
BEGIN
EXECUTE 'SELECT * FROM ' || tbl_name; -- 위험!
END;
$$;
-- 안전한 방법 1: quote_ident() 사용
DO $$
DECLARE
tbl_name TEXT := 'my_table';
BEGIN
EXECUTE 'SELECT * FROM ' || quote_ident(tbl_name);
END;
$$;
-- 안전한 방법 2: format() + %I 지정자 사용 (권장)
DO $$
DECLARE
schema_name TEXT := 'public';
tbl_name TEXT := 'employees';
col_name TEXT := 'department';
BEGIN
EXECUTE format(
'SELECT %I FROM %I.%I WHERE %I IS NOT NULL',
col_name, schema_name, tbl_name, col_name
);
END;
$$;
-- 프로시저에서 동적 테이블 생성 시 안전하게 처리
CREATE OR REPLACE PROCEDURE create_partition(p_table_name TEXT, p_date TEXT)
LANGUAGE plpgsql AS $$
BEGIN
-- 입력값 유효성 검사
IF p_table_name !~ '^[a-zA-Z_][a-zA-Z0-9_]*$' THEN
RAISE EXCEPTION '유효하지 않은 테이블 이름: %', p_table_name;
END IF;
EXECUTE format(
'CREATE TABLE IF NOT EXISTS %I PARTITION OF %I FOR VALUES IN (%L)',
p_table_name || '_' || p_date,
p_table_name,
p_date
);
END;
$$;
원인 3 해결: 식별자 유효성 검사 추가
동적 SQL을 실행하기 전에 식별자가 유효한지 반드시 검증하는 로직을 추가하세요.
-- 식별자 유효성 검사 함수 생성
CREATE OR REPLACE FUNCTION validate_identifier(p_name TEXT)
RETURNS BOOLEAN
LANGUAGE plpgsql AS $$
BEGIN
-- NULL 또는 빈 문자열 체크
IF p_name IS NULL OR p_name = '' THEN
RAISE EXCEPTION '42602: 식별자는 NULL이거나 빈 문자열일 수 없습니다.';
END IF;
-- 길이 체크 (PostgreSQL 최대 63바이트)
IF length(p_name) > 63 THEN
RAISE EXCEPTION '42602: 식별자는 63자를 초과할 수 없습니다: %', p_name;
END IF;
-- 명명 규칙 체크 (정규식)
IF p_name !~ '^[a-zA-Z_][a-zA-Z0-9_$]*$' THEN
RAISE EXCEPTION '42602: 유효하지 않은 식별자 형식: %', p_name;
END IF;
RETURN TRUE;
END;
$$;
-- 사용 예시
DO $$
DECLARE
col_name TEXT := 'total_sales';
BEGIN
PERFORM validate_identifier(col_name);
EXECUTE format(
'ALTER TABLE monthly_report ADD COLUMN IF NOT EXISTS %I NUMERIC DEFAULT 0',
col_name
);
RAISE NOTICE '컬럼 % 가 성공적으로 추가되었습니다.', col_name;
END;
$$;
예방 방법
1. 데이터베이스 명명 규칙(Naming Convention) 표준화 및 문서화
팀 내에서 통일된 명명 규칙을 정의하고 이를 문서화하여 개발 초기 단계부터 적용하세요. PostgreSQL에서는 스네이크 케이스(snake_case) 를 표준으로 권장하며, 모든 식별자는 소문자, 숫자, 언더스코어만 사용하도록 컨벤션을 수립하는 것이 최선입니다. 마이그레이션 스크립트나 ORM 설정에서도 이 규칙을 강제하는 린터(Linter) 또는 CI/CD 검사를 도입하면 실수를 사전에 방지할 수 있습니다.
2. 동적 SQL 작성 시 항상 format() + %I 패턴 사용 의무화
PL/pgSQL 내부의 모든 동적 SQL에서 식별자를 처리할 때는 반드시 format() 함수의 %I 지정자만 사용하도록 팀 코딩 표준에 명시하세요. 문자열 직접 연결(||)로 식별자를 구성하는 패턴은 코드 리뷰에서 반드시 거부하고, quote_ident() 또는 format(%I)를 사용한 패턴만 허용하도록 규정을 수립해야 합니다. 이 방법은 42602 에러 예방뿐만 아니라 SQL 인젝션 방지에도 핵심적인 보안 대책입니다.
관련 에러
- 42601 (syntax_error): 잘못된 SQL 문법으로 인한 에러로, 42602와 함께 파싱 단계에서 발생하는 경우가 많습니다. 동적 SQL에서 두 에러가 연달아 나타나기도 합니다.
- 42939 (reserved_name): PostgreSQL 예약어를 식별자로 사용하려 할 때 발생하며,
user,table,select등 시스템 예약 키워드를 테이블명 또는 컬럼명으로 사용하는 경우 트리거됩니다. - 42P01 (undefined_table): 존재하지 않는 테이블을 참조할 때 발생하며, 동적 SQL에서 잘못된 이름으로 생성된 테이블을 조회할 때 42602 이후 연달아 나타날 수 있습니다.
- 22023 (invalid_parameter_value):
quote_ident()또는format()함수에 잘못된 값이 전달될 때 관련하여 나타날 수 있는 에러입니다.
주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.
본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.