복붙노트

[SQL] 어떻게 동적으로 PostgreSQL의 8.2 TG_TABLE_NAME를 사용 하는가?

SQL

어떻게 동적으로 PostgreSQL의 8.2 TG_TABLE_NAME를 사용 하는가?

동적으로 생성하고 SQL 문을 실행하는 TG_TABLE_NAME를 사용 PostgreSQL의 8.2 트리거 함수를 작성하려합니다. 나는 PostgreSQL의 이후 버전에 대한 예는 모든 종류의를 찾을 수 있습니다,하지만 난 때문에 몇 가지 요구 사항 8.2에 붙어입니다. 그것은 작동하지만, 거의 동적 인 의미로 여기 내 기능은 다음과 같습니다

CREATE OR REPLACE FUNCTION cdc_TABLENAME_function() RETURNS trigger AS $cdc_function$
        DECLARE 
        op  cdc_operation_enum;
    BEGIN
        op = TG_OP;

        IF (TG_WHEN = 'BEFORE') THEN
            IF (TG_OP = 'UPDATE') THEN
                op = 'UPDATE_BEFORE';
            END IF;

            INSERT INTO cdc_test VALUES (DEFAULT,DEFAULT,op,DEFAULT,DEFAULT,OLD.*); 
        ELSE
            IF (TG_OP = 'UPDATE') THEN
                op = 'UPDATE_AFTER';
            END IF;

            INSERT INTO cdc_test VALUES (DEFAULT,DEFAULT,op,DEFAULT,DEFAULT,NEW.*); 
        END IF;

        IF (TG_OP = 'DELETE') THEN
            RETURN OLD;
        ELSE
            RETURN NEW;
        END IF;
    END;

이 현재 작성 방법, 나는 모든 테이블에 대해 별도의 트리거 함수를 작성해야합니다. 동적으로 내 INSERT 문을 작성하고 단지로 접두사 TG_TABLE_NAME을 사용하고자하는 'cdc_'모든 테이블이 같은 명명 규칙을 따라야하기 때문이다. 그럼 내가 모든 테이블 호출 한 함수에 대한 모든 트리거를 가질 수 있습니다.

해결법

  1. ==============================

    1.나는 몇 년 다시 똑같은 일을 찾고 있었다. 하나의 트리거 그들 모두를 지배하는 기능! 나는, 유즈넷 목록에 요청 아무 소용, 다양한 접근을 시도했다. 이 문제에 대한 합의가이 작업을 수행 할 수 없습니다이었다. PostgreSQL의 8.3 또는 그 이상의 단점.

    나는 몇 년 다시 똑같은 일을 찾고 있었다. 하나의 트리거 그들 모두를 지배하는 기능! 나는, 유즈넷 목록에 요청 아무 소용, 다양한 접근을 시도했다. 이 문제에 대한 합의가이 작업을 수행 할 수 없습니다이었다. PostgreSQL의 8.3 또는 그 이상의 단점.

    PostgreSQL의 8.4 이후 당신은 할 수 있습니다 :

    EXECUTE 'INSERT INTO ' || TG_RELID::regclass::text || ' SELECT ($1).*'
    USING NEW;
    

    페이지 8.2을 사용하면 문제가있다 :

    시스템의 모든 테이블 이름은 같은 이름의 복합 형 역할을 할 수 있습니다. 따라서 당신은 매개 변수로 NEW / OLD을받는 함수를 작성하고 실행할 수 있습니다. 동적으로 생성하고 모든 트리거 이벤트에 해당 기능을 파괴 할 수있다 :

    트리거 기능 :

    CREATE OR REPLACE FUNCTION trg_cdc()
      RETURNS trigger AS
    $func$
    DECLARE
       op      text := TG_OP || '_' || TG_WHEN;
       tbl     text := quote_ident(TG_TABLE_SCHEMA) || '.'
                    || quote_ident(TG_TABLE_NAME);
       cdc_tbl text := quote_ident(TG_TABLE_SCHEMA) || '.'
                    || quote_ident('cdc_' || TG_TABLE_NAME);
    BEGIN
    
    EXECUTE 'CREATE FUNCTION f_cdc(n ' || tbl || ', op text)
      RETURNS void AS $x$ BEGIN
      INSERT INTO ' || cdc_tbl || ' SELECT op, (n).*;
    END $x$ LANGUAGE plpgsql';
    
    CASE TG_OP
    WHEN 'INSERT', 'UPDATE' THEN
       PERFORM f_cdc(NEW, op);
    WHEN 'DELETE' THEN
       PERFORM f_cdc(OLD, op);
    ELSE
       RAISE EXCEPTION 'Unknown TG_OP: "%". Should not occur!', TG_OP;
    END CASE;
    
    EXECUTE 'DROP FUNCTION f_cdc(' || tbl || ', text)';
    
    IF TG_OP = 'DELETE' THEN
        RETURN OLD;
    ELSE
        RETURN NEW;
    END IF;
    
    END
    $func$  LANGUAGE plpgsql;
    

    방아쇠:

    CREATE TRIGGER cdc
    BEFORE INSERT OR UPDATE OR DELETE ON my_tbl
    FOR EACH ROW EXECUTE PROCEDURE trg_cdc();
    

    표 이름은 사용자 입력처럼 처리해야한다. 사용에서 quote_ident ()는 SQL 주입에 대한 방어.

    그러나,이 방법은 생성하고 모든 단일 트리거 이벤트에 대한 기능을 놓습니다. 꽤 오버 헤드, 나는 그것을 위해 갈 것이다. 당신은 어떤 카탈로그 테이블을 많이 진공 청소기로 청소해야합니다.

    PostgreSQL는 함수 오버로드를 지원한다. 따라서, 동일한 기본 이름 (그러나 다른 유형 파라미터)의 테이블 당 하나 개의 기능이 공존 할 수있다. 당신은 중간을 극적으로 당신이 방아쇠를 만들 때와 같은 시간에 테이블 당 한 번 f_cdc (..)를 생성하여 소음을 줄일 수 있습니다. 즉, 테이블 당 하나 개의 작은 기능입니다. 당신은 테이블 정의의 변화를 관찰해야하지만, 테이블은 자주 변경하지 않아야합니다. 빠르고 우아한 트리거, 작은 도착, CREATE 및 트리거 기능에서 DROP 기능 제거합니다.

    나 자신은 8.2 PG에서 그 일을 볼 수 있었다. 나 자신이 더 이상 페이지 8.2에서 아무것도 볼 수 있다는 점을 제외하고. 그것은 어쩌면 당신은 결국 어떻게 든 업그레이드 할 수 있습니다 2011 년 12 월 삶의 끝에 도달했습니다.

  2. ==============================

    2.또한 몇 년 전에 비슷한 질문을했다.

    또한 몇 년 전에 비슷한 질문을했다.

    그것은 당신에게 유용한 아이디어를 제공하면 그 질문에 살펴보고 참조 :

    삽입 NEW. *에서 PL / pgSQL의 EXECUTE 사용하여 일반 트리거에서

  3. from https://stackoverflow.com/questions/7519044/how-to-dynamically-use-tg-table-name-in-postgresql-8-2 by cc-by-sa and MIT license