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

22010
2026년 10월 16일 | DBMS Error 가이드

이 글에서 다루는 내용

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

22010 invalid indicator parameter value 는?

PostgreSQL 에러 코드 22010 (invalid_indicator_parameter_value)은 SQLSTATE 표준 에러로, 프로그램이 데이터베이스에 값을 전달할 때 사용하는 인디케이터 파라미터(indicator parameter)의 값이 유효하지 않을 때 발생합니다. 인디케이터 파라미터란 주로 Embedded SQL(ECPG) 또는 CLI/ODBC 인터페이스에서 호스트 변수의 NULL 여부나 길이 정보를 전달하기 위해 사용하는 특수 변수입니다. 이 에러는 인디케이터 변수에 허용 범위를 벗어난 값(-1, 0, 양의 정수 외의 값)이 입력되거나, NULL을 허용하지 않는 컬럼에 NULL 인디케이터를 잘못 전달할 때 주로 나타납니다.


주요 발생 원인

  • 인디케이터 변수에 잘못된 값(-1 이외의 음수 또는 허용 범위 외 값) 사용

ECPG(Embedded C for PostgreSQL)나 ODBC 드라이버를 사용할 때, 인디케이터 변수는 반드시 -1(NULL을 의미), 0(정상 값), 또는 양의 정수(데이터 잘림 발생 시 원본 길이)만 가져야 합니다. 개발자가 실수로 -2, -99와 같은 임의의 음수 값을 인디케이터 변수에 설정하거나, 초기화되지 않은 변수를 그대로 사용할 경우 PostgreSQL은 해당 값을 해석할 수 없어 22010 에러를 반환합니다.

예를 들어 C 코드에서 indicator = -2;처럼 잘못된 값을 설정한 후 EXEC SQL INSERT 구문을 실행하면 에러가 발생합니다. 이는 초기화 누락이나 로직 오류로 인한 실수가 가장 흔한 원인입니다.

  • NULL 불허(NOT NULL) 컬럼에 NULL 인디케이터(-1)를 전달

테이블의 특정 컬럼이 NOT NULL 제약 조건을 가지고 있음에도 불구하고, 호스트 프로그램이 해당 컬럼에 대한 인디케이터 변수를 -1(NULL)로 설정하여 INSERT 또는 UPDATE를 시도하는 경우 에러가 발생할 수 있습니다. 이 상황은 단순히 NULL 제약 위반처럼 보이지만, 일부 드라이버 레이어에서는 22010으로 분류하여 반환하기도 합니다.

특히 여러 테이블을 대상으로 동일한 코드 로직을 재사용할 때, 특정 테이블의 컬럼 제약 조건을 놓치는 경우가 많으므로 각 테이블의 스키마를 면밀히 검토해야 합니다.

  • ODBC/JDBC 드라이버 또는 ORM 레이어의 파라미터 바인딩 오류

애플리케이션에서 직접 SQL을 작성하지 않고 ORM(예: Hibernate, SQLAlchemy) 또는 ODBC/JDBC 드라이버를 통해 쿼리를 실행할 때, 내부적으로 파라미터 인디케이터를 잘못 생성하거나 전달하는 경우가 있습니다. 특히 드라이버 버전 불일치, 잘못된 드라이버 설정, 또는 특수한 데이터 타입(예: NULL이 포함된 배열, 복합 타입)을 처리할 때 이 문제가 발생할 수 있습니다.

이 경우 애플리케이션 로그만으로는 원인을 특정하기 어려우므로 PostgreSQL 서버 로그(log_min_messages = debug5)와 함께 드라이버 수준의 디버깅이 필요합니다.


해결 방법

원인 1 해결: 인디케이터 변수 값 검증 및 초기화

ECPG를 사용하는 C 프로그램에서는 인디케이터 변수를 반드시 올바르게 초기화하고, 허용된 값만 사용해야 합니다.

-- ECPG 코드 예시 (C 언어와 혼용)
-- 잘못된 예시 (에러 발생 가능)
EXEC SQL BEGIN DECLARE SECTION;
    int emp_id;
    short ind_emp_id; /* 인디케이터 변수 - 초기화 누락! */
    varchar emp_name[50];
    short ind_emp_name;
EXEC SQL END DECLARE SECTION;

/* ind_emp_id가 초기화되지 않아 쓰레기 값(-2, -99 등)이 들어갈 수 있음 */
EXEC SQL INSERT INTO employees (id, name)
    VALUES (:emp_id :ind_emp_id, :emp_name :ind_emp_name);

-- 올바른 예시 (인디케이터 변수를 명시적으로 초기화)
/*
   인디케이터 값 규칙:
    0  = 정상 값 (NULL 아님)
   -1  = NULL 값
   양수 = 잘림 발생 (문자열 원본 길이)
*/
ind_emp_id = 0;      /* NULL이 아닌 정상 값 */
ind_emp_name = -1;   /* NULL 값으로 처리하고 싶을 때 */

EXEC SQL INSERT INTO employees (id, name)
    VALUES (:emp_id :ind_emp_id, :emp_name :ind_emp_name);
-- PostgreSQL에서 인디케이터 상태를 확인하기 위한 진단 쿼리
-- (실제 값 삽입 전 테이블 제약 조건 확인)
SELECT
    column_name,
    is_nullable,
    data_type,
    column_default
FROM
    information_schema.columns
WHERE
    table_schema = 'public'
    AND table_name = 'employees'
ORDER BY
    ordinal_position;

원인 2 해결: NOT NULL 컬럼 제약 조건 사전 확인

애플리케이션 코드에서 인디케이터 변수를 설정하기 전에, 대상 컬럼이 NULL을 허용하는지 확인하는 로직을 추가합니다.

-- NOT NULL 제약이 있는 컬럼에 NULL 삽입 시도 (에러 발생 시나리오)
-- 아래처럼 스키마를 먼저 확인하여 인디케이터 설정에 반영해야 함

-- 1. 테이블의 NOT NULL 컬럼 목록 확인
SELECT
    c.column_name,
    c.is_nullable,
    c.data_type,
    tc.constraint_type
FROM
    information_schema.columns c
LEFT JOIN information_schema.key_column_usage kcu
    ON c.table_name = kcu.table_name
    AND c.column_name = kcu.column_name
LEFT JOIN information_schema.table_constraints tc
    ON kcu.constraint_name = tc.constraint_name
WHERE
    c.table_schema = 'public'
    AND c.table_name = 'employees'
    AND c.is_nullable = 'NO';

-- 2. NOT NULL 컬럼에는 절대 -1(NULL) 인디케이터를 설정하지 말 것
-- 올바른 INSERT 예시: emp_id는 NOT NULL이므로 인디케이터를 0으로 설정
-- ECPG 예시:
-- ind_emp_id = 0;   /* NOT NULL 컬럼 → 인디케이터는 반드시 0 */
-- ind_emp_name = -1; /* NULLABLE 컬럼 → NULL 전달 가능 */

EXEC SQL INSERT INTO employees (id, name)
    VALUES (:emp_id :ind_emp_id, :emp_name :ind_emp_name);

원인 3 해결: 드라이버 레벨 디버깅 및 파라미터 바인딩 점검

ODBC나 JDBC를 사용하는 경우 드라이버 로그를 활성화하고, 파라미터 바인딩을 명시적으로 처리합니다.

-- PostgreSQL 서버 측에서 파라미터 로깅 활성화 (디버깅용)
-- postgresql.conf 또는 세션 레벨에서 설정

-- 세션 레벨 디버그 로깅 설정
SET log_min_messages = 'debug5';
SET log_error_verbosity = 'verbose';

-- 파라미터 바인딩 문제를 우회하는 방법: CAST를 이용한 명시적 타입 변환
-- ODBC/JDBC에서 NULL 처리가 불안정한 경우, 서버 측에서 COALESCE로 방어
CREATE OR REPLACE FUNCTION safe_insert_employee(
    p_id     INTEGER,
    p_name   VARCHAR(50),
    p_salary NUMERIC DEFAULT NULL
)
RETURNS VOID AS $$
BEGIN
    INSERT INTO employees (id, name, salary)
    VALUES (
        p_id,
        COALESCE(p_name, 'Unknown'),  -- NULL 방어 처리
        p_salary                       -- NULLABLE 컬럼은 그대로
    );
EXCEPTION
    WHEN SQLSTATE '22010' THEN
        RAISE NOTICE '인디케이터 파라미터 오류 발생: id=%, name=%', p_id, p_name;
        RAISE;
END;
$$ LANGUAGE plpgsql;

-- 함수 호출 예시
SELECT safe_insert_employee(1, 'Hong Gil-dong', 5000000);
SELECT safe_insert_employee(2, NULL, NULL); -- p_name은 COALESCE로 'Unknown' 처리

예방 방법

  • 인디케이터 변수의 명시적 초기화 정책 수립

ECPG를 사용하는 프로젝트에서는 모든 인디케이터 변수를 선언과 동시에 반드시 초기화하는 코딩 표준을 팀 내에 정착시켜야 합니다. 코드 리뷰 체크리스트에 “인디케이터 변수 초기화 여부 확인” 항목을 추가하고, 정적 분석 도구(예: Cppcheck, Valgrind)를 CI/CD 파이프라인에 통합하여 초기화되지 않은 변수 사용을 자동으로 감지하세요. 또한 가능하다면 래퍼 함수나 매크로를 만들어 인디케이터 설정 로직을 중앙화함으로써 실수를 줄일 수 있습니다.

  • 데이터베이스 스키마와 애플리케이션 로직의 동기화 체계 구축

테이블 스키마가 변경될 때마다 애플리케이션의 인디케이터 설정 로직도 함께 검토하는 프로세스를 만들어야 합니다. 특히 컬럼의 NOT NULL 제약이 추가되거나 제거될 때, 이를 반영하는 코드 변경이 누락되면 22010 에러가 운영 환경에서 예기치 않게 발생할 수 있습니다. 이를 방지하기 위해 스키마 마이그레이션 도구(Flyway, Liquibase)와 통합 테스트를 함께 사용하고, 주요 컬럼의 NULL 허용 여부를 자동으로 검증하는 테스트 케이스를 반드시 포함시키세요.


관련 에러

  • 22002 (null_value_no_indicator_parameter): 인디케이터 파라미터 자체가 제공되지 않은 상태에서 NULL 값을 받았을 때 발생합니다. 22010과 함께 ECPG 환경에서 자주 쌍으로 등장하는 에러입니다.
  • 23502 (not_null_violation): NOT NULL 제약 조건이 설정된 컬럼에 NULL 값을 삽입하려 할 때 발생하며, 22010과 원인이 겹치는 경우가 많습니다.
  • 22001 (string_data_right_truncation): 문자열 데이터가 컬럼의 최대 길이를 초과할 때 발생하며, 인디케이터 변수의 양수 값(잘림 원본 길이)과 관련이 있습니다.
  • 07002 (count_field_incorrect): 바인딩된 파라미터의 수가 맞지 않을 때 발생하며, ODBC 환경에서 22010과 함께 디버깅해야 하는 경우가 많습니다.

DBMS 에러 코드 시리즈

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

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

댓글 남기기