42.11. pl/pgsql아래 후드

이 섹션에서는 자주 중요한 구현 세부 사항에 대해 설명합니다.​​pl/pgsql사용자가 알고 있습니다.

42.11.1. 변수 대체

a 내 SQL 문 및 표현식pl/pgsql함수는 함수의 토토 캔와 매개 토토 캔를 참조 할 수 있습니다. 무대 뒤에서pl/pgsql그러한 참조의 쿼리 매개 토토 캔를 대체합니다. 매개 토토 캔는 매개 토토 캔 또는 열 참조가 구문 적으로 허용되는 위치에서만 대체됩니다. 극단적 인 경우, 열악한 프로그래밍 스타일 의이 예를 고려하십시오.

foo (foo) 값 (foo)에 삽입;

첫 번째 발생foo구문 적으로 테이블 이름이어야하므로 함수의 토토 캔가있는 경우에도 대체되지 않아야합니다.foo. 두 번째 발생은 테이블 열의 이름이어야하므로 대체되지 않습니다. 세 번째 사건만이 함수 토토 캔에 대한 언급의 후보입니다.

참고

PostgreSQL9.0 이전의 버전은 세 가지 경우 모두에서 변수를 대체하여 구문 오류로 이어집니다.

변수 이름은 표 열의 이름과 구문 적으로 다르지 않기 때문에 테이블을 참조하는 명령문에는 모호성이있을 수 있습니다. 주어진 이름은 테이블 열을 참조 할 수 있습니까? 이전 예를 변경하자

dest에 삽입 (col) SRC에서 foo + bar를 선택하십시오.

여기,destSRC테이블 이름이어야합니다.col의 열이어야합니다dest그러나fooandbar| 함수의 토토 캔이거나의 열 토토 캔 일 수 있습니다.SRC.

기본적으로pl/pgsqlSQL 문의 이름이 변수 또는 테이블 열을 참조 할 수있는 경우 오류를보고합니다. 변수 또는 열 이름을 바꾸거나 모호한 참조 자격을 갖추거나 말함으로써 그러한 문제를 해결할 수 있습니다pl/pgsql선호하는 해석.

가장 간단한 솔루션은 토토 캔 또는 열의 이름을 바꾸는 것입니다. 일반적인 코딩 규칙은에 대해 다른 명명 규칙을 사용하는 것입니다.pl/pgsql열 이름에 사용하는 것보다 토토 캔. 예를 들어, 지속적으로 함수 토토 캔 이름을 지정하는 경우V_뭔가열 이름 중 어느 것도 시작하는 동안V_, 충돌이 발생하지 않을 것입니다.

또는 대안 적으로 모호한 참조 자격을 얻을 수 있습니다. 위의 예에서src.foo테이블 열에 대한 명백한 참조입니다. 토토 캔에 대한 명백한 참조를 만들려면 레이블이 붙은 블록에 선언하고 블록의 레이블을 사용하십시오 (참조배트맨 토토 PostgreSQL : 문서 : 13 : 42.2. pl/pgsql의 구조). 예를 들어,

<< 블록 
선언하다
    foo int;
시작하다
    foo : = ...;
    SRC에서 DEST (COL)에 삽입 (COL) SELECT BLOCK.FOO + BAR;

여기block.foo열이 있더라도 토토 캔를 의미fooinSRC. 함수 매개 토토 캔 및와 같은 특수 토토 캔발견, 함수 이름으로 표시된 외부 블록으로 암시 적으로 선언되기 때문에 함수 이름에 따라 자격을 갖추 수 있습니다..

때로는 큰 몸체에서 모든 모호한 참조를 고치는 것이 비현실적입니다pl/pgsql코드. 그러한 경우를 지정할 수 있습니다.pl/pgsql토토 캔로 모호한 참조를 해결해야합니다 (pl/pgsql의 행동 전PostgreSQL9.0) 또는 테이블 열 (과 같은 일부 시스템과 호환됩니다Oracle).

시스템 전체 에서이 동작을 변경하려면 구성 매개 토토 캔를 설정하십시오.plpgsql.variable_conflict오류, use_variable또는use_column(where오류공장 기본값입니다). 이 매개 변수는 다음의 후속 문자 편집에 영향을 미칩니다pl/pgsql함수이지만 현재 세션에서는 이미 정리되지 않았습니다. 이 설정을 변경하면의 동작에 예상치 못한 변화가 발생할 수 있기 때문입니다.pl/pgsql함수, 슈퍼업자에 의해서만 변경 될 수 있습니다.

기능 텍스트의 시작 부분에서 이러한 특수 명령 중 하나를 삽입하여 기능별로 동작을 설정할 수도 있습니다.

#variable_conflict 오류
#variable_conflict use_variable
#variable_conflict use_column

이 명령은 그들이 기록한 함수에만 영향을 미치고의 설정을 무시합니다.plpgsql.variable_conflict. 예는입니다.

함수 만들기 stamp_user (id int, 댓글 텍스트)를 $$로 반환합니다.
    #variable_conflict use_variable
    선언하다
        Curtime timestamp : = now ();
    시작하다
        업데이트 사용자가 set last_modified = curtime, comment = comment
          여기서 users.id = id;
    끝;
$$ 언어 plpgsql;

in업데이트명령,CURTIME, 댓글id함수의 토토 캔와 매개 토토 캔를 참조하십시오.사용자그 이름의 열이 있습니다. 우리는에 대한 참조 자격을 갖추어야한다는 점에 주목하십시오.users.idin여기서테이블 열을 참조하는 조항. 그러나 우리는에 대한 참조 자격을 갖추지 않아도됩니다.댓글업데이트목록, 구문 적으로이어야하기 때문에사용자. 우리는에 따라 동일한 기능을 쓸 수 있습니다.variable_conflict이런 식으로 설정 :

함수 만들기 stamp_user (id int, 댓글 텍스트)는 void를 $$로 반환합니다.
    << fn 
    선언하다
        Curtime timestamp : = now ();
    시작하다
        업데이트 사용자가 set last_modified = fn.curtime, comment = stamp_user.comment입니다
          여기서 users.id = stamp_user.id;
    끝;
$$ 언어 plpgsql;

가변 대체는에 주어진 명령 문자열에서 발생하지 않습니다.execute또는 그 변형 중 하나. 그러한 명령에 다양한 값을 삽입 해야하는 경우 문자열 값 구성의 일부로 그렇게하거나사용,섹션 42.5.4.

가변 대체는 현재에서만 작동합니다select, 삽입, 업데이트삭제명령, 기본 SQL 엔진은이 명령에서만 쿼리 매개 변수를 허용하기 때문입니다. 다른 명령문 유형 (일반적으로 유틸리티 명령문이라고 함)에서 비정상적인 이름 또는 값을 사용하려면 유틸리티 문을 문자열로 구성하고executeit.

42.11.2. 캐싱 계획

thepl/pgsql통역사는 함수의 소스 텍스트를 구문 분석하고 기능을 처음으로 호출 할 때 (각 세션 내에서) 내부 이진 명령 트리를 생성합니다. 지침 트리는를 완전히 번역합니다.pl/pgsql진술 구조이지만 개인SQL표현 및SQL함수에 사용 된 명령은 즉시 변환되지 않습니다.

각 표현 및SQL명령은 기능에서 처음 실행됩니다.pl/pgsql통역사는 명령을 구문 분석하고 분석하여를 사용하여 준비 된 문을 작성합니다.SPIManager 'sSPI_PREPARE함수. 그 표현에 대한 후속 방문 또는 명령은 준비된 진술을 재사용합니다. 따라서, 거의 방문하지 않는 조건부 코드 경로가있는 함수는 현재 세션 내에서 결코 실행되지 않는 명령을 분석하는 오버 헤드가 발생하지 않습니다. 단점은 특정 표현식 또는 명령의 오류가 함수의 일부에 실행 중에 도달 할 때까지 감지 할 수 없다는 것입니다. (초기 구문 분석 패스 중에는 Trivial Syntax 오류가 감지되지만 실행 될 때까지 더 깊은 것은 감지되지 않습니다.)

pl/pgsql(또는 더 정확하게 SPI 관리자)는 특정 준비된 진술과 관련된 실행 계획을 캐시하려고 시도 할 수 있습니다. 캐시 된 계획이 사용되지 않으면 문을 방문 할 때마다 새로운 실행 계획이 생성되고 현재 매개 변수 값 (즉,pl/pgsql변수 값)을 사용하여 선택한 계획을 최적화 할 수 있습니다. 문에 매개 변수가 없거나 여러 번 실행되는 경우 SPI 관리자는 A 생성을 고려합니다.제네릭특정 매개 변수 값에 의존하지 않는 계획 및 재사용을위한 캐싱. 일반적으로 이것은 실행 계획이 값에별로 민감하지 않은 경우에만 발생합니다.pl/pgsql토토 캔에 참조. 그렇다면 매번 계획을 생성하는 것은 순 승리입니다. 보다준비준비된 진술의 행동에 대한 자세한 내용은

왜냐하면pl/pgsql준비된 진술을 저장하고 때로는 이런 방식으로 실행 계획을 저장합니다.pl/pgsql함수는 모든 실행에서 동일한 테이블과 열을 참조해야합니다. 즉, 매개 변수를 SQL 명령의 테이블 또는 열의 이름으로 사용할 수 없습니다. 이 제한 사항을 해결하려면를 사용하여 동적 명령을 구축 할 수 있습니다.pl/pgsql execute성명서 - 새로운 구문 분석 분석을 수행하고 모든 실행에 대한 새로운 실행 계획을 구성하는 가격으로.

레코드 변수의 변이 가능한 특성은 이와 관련하여 또 다른 문제를 제시합니다. 레코드 변수의 필드가 표현식 또는 명령문에 사용되면 필드의 데이터 유형은 기능의 한 호출에서 다음 호출로 변경해서는 안됩니다. 각 표현식은 표현식에 도달 할 때 존재하는 데이터 유형을 사용하여 분석되므로..execute필요할 때이 문제를 해결하는 데 사용할 수 있습니다.

동일한 함수가 둘 이상의 테이블의 트리거로 사용되는 경우pl/pgsql그러한 각 테이블에 대해 독립적으로 명령문을 준비하고 캐시합니다. 즉, 각 기능뿐만 아니라 각 트리거 기능 및 테이블 조합에 대한 캐시가 있습니다. 이것은 다양한 데이터 유형의 일부 문제를 완화시킵니다. 예를 들어 트리거 함수는라는 열에서 성공적으로 작동 할 수 있습니다.다른 테이블에 다른 유형이있는 경우에도

마찬가지로, 다형성 인수 유형을 갖는 기능은 그들이 호출 한 실제 인수 유형의 각 조합에 대해 별도의 명령문 캐시를 가지고 있으므로 데이터 유형 차이가 예상치 못한 실패를 유발하지 않도록합니다..

Statement Caching은 때때로 시간에 민감한 값의 해석에 놀라운 영향을 미칠 수 있습니다. 예를 들어이 두 기능 사이에는 차이가 있습니다.

함수 생성 logfunc1 (logtxt 텍스트)은 $$로 void를 반환합니다
    시작하다
        Logtable 값 (logtxt, 'now')에 삽입;
    끝;
$$ 언어 plpgsql;

및 :

함수 생성 logfunc2 (logtxt 텍스트)는 void를 $$로 반환합니다
    선언하다
        곡선 타임 스탬프;
    시작하다
        큐 타임 : = '지금';
        Logtable 값 (logtxt, curtime)에 삽입;
    끝;
$$ 언어 plpgsql;

의 경우logfunc1, ThePostgreSQLMain Parser는 분석 시점을 알고 있습니다삽입String'now'타임 스탬프,이기 때문에logtable그 유형입니다. 따라서,'now'A로 변환됩니다타임 스탬프삽입분석 된 다음의 모든 호출에 사용됩니다.logfunc1세션 수명 동안. 말할 것도없이, 이것은 프로그래머가 원했던 것이 아닙니다. 더 나은 아이디어는 사용하는 것입니다.now ()또는current_timestamp기능.

의 경우logfunc2, ThePostgreSQLMain Parser는 어떤 유형을 모릅니다'now'따라서 유형의 데이터 값을 반환해야합니다텍스트문자열 포함now. 이어지는 지역 토토 캔에 대한 할당 중CURTIME,pl/pgsql통역사는이 문자열을 |타임 스탬프전화로 입력하십시오텍스트 아웃andTimeStamp_in변환 기능. 따라서 컴퓨팅 타임 스탬프는 프로그래머가 예상하는대로 각 실행에 대해 업데이트됩니다. 이것은 예상대로 작동하지만 크게 효율적이지 않으므로 사용하십시오.now ()함수는 여전히 더 나은 아이디어가 될 것입니다.

정정 제출

문서에 맞지 않는 내용이 있으면 일치하지 않습니다. 특정 기능에 대한 귀하의 경험 또는 추가 설명이 필요합니다. 사용이 양식문서 문제를보고하려면