이 문서는 지원되지 않는 PostgreSQL 버전에 대한 것입니다.
당신은 다음과 같은 페이지를 보고 싶을 수도 있습니다.PostgreSQL : 문서 : 17 : 41.13. Oracle 토토 사이트/SQL에서 포팅버전 또는 위에 나열된 다른 지원 버전 중 하나를 사용하세요.

24.5. Oracle PL/SQL에서 포팅

저자:로베르토 멜로 ()

이 섹션에서는 Oracle의 PL/SQL과 Oracle의 PL/SQL 간의 차이점을 설명합니다. 도움을 주기 위해 PostgreSQL의 PL/pgSQL 언어 개발자는 Oracle에서 PostgreSQL로 애플리케이션을 이식합니다. 대부분의 여기 코드는ArsDigita 클릭스트림 모듈내가 PostgreSQL로 이식했을 때 인턴십을 했습니다오픈포스 주식회사2000년 여름.

PL/pgSQL은 여러 측면에서 PL/SQL과 유사합니다. 블록입니다 구조화된 명령형 언어(모든 변수는 선언). PL/SQL에는 PostgreSQL보다 더 많은 기능이 있습니다. 대응하지만 PL/pgSQL은 많은 양의 작업을 허용합니다. 기능이 지속적으로 개선되고 있습니다.

24.5.1. 메인 차이점

Oracle에서 포팅할 때 명심해야 할 몇 가지 사항 PostgreSQL로:

  • PostgreSQL에는 기본 매개변수가 없습니다.

  • PostgreSQL에서 함수를 오버로드할 수 있습니다. 이것은 종종 기본 매개변수 부족 문제를 해결하는 데 사용됩니다.

  • 할당, 루프 및 조건은 유사합니다.

  • PostgreSQL에서는 커서가 필요하지 않습니다. 쿼리를 FOR 문(아래 예 참조)

  • PostgreSQL에서는필요탈출하다 작은따옴표. 참조섹션 24.5.1.1.

24.5.1.1. 그에 대한 인용문: 싱글 탈출 인용문

PostgreSQL에서는 작은따옴표를 이스케이프해야 합니다. 기능 정의. 이는 매우 재미있는 코드로 이어질 수 있습니다. 특히 다음과 같은 함수를 생성하는 경우에는 더욱 그렇습니다. 다음과 같이 다른 함수를 생성합니다.예 24-6. 많은 것을 피할 때 명심해야 할 한 가지 작은따옴표는 시작/끝을 제외한 것입니다. 다른 모든 제품은 짝수 수량으로 제공됩니다.

테이블 24-1특종을 제공합니다. (너는 이 작은 것을 좋아할 것이다. 차트.)

표 24-1. 작은따옴표 이스케이프 차트

아니요. 인용문 사용법 결과
1 시작/종료하려면 함수 본문
함수 생성 foo()는 정수를 '...'로 반환합니다.
언어 '윈 토토pgsql';
그대로
2 임무에서, 문자열 등을 구분하는 SELECT
a_output := ''어쩌고'';
SELECT * FROM 사용자 WHERE f_name=''foobar'';
SELECT * 어디에서 사용자로부터 선택 f_name='foobar';
4 두 개가 필요할 때 결과 문자열에 작은따옴표를 사용하지 않고 해당 문자열을 종료합니다.
a_output := a_output || '' AND 이름 
    LIKE ''''foobar'''' AND ...''
그리고 이름 LIKE 'foobar' AND ...
6 두 배를 원할 때 결과 문자열에 따옴표를 붙입니다.그리고해당 문자열을 종료합니다.
a_output := a_output || '' AND 이름 
    LIKE ''''foobar''''''
그리고 이름 LIKE 'foobar'
10 두 개를 원할 때 결과 문자열의 작은따옴표(이를 설명합니다. 8개의 견적에 대해)그리고종료 그 문자열(2개 더). 아마도 당신은 다른 생성을 위해 함수를 사용하고 있다면 함수(예:예 24-6).
a_output := a_output || '' v_''인 경우 || 
    Referrer_keys.kind || ''처럼 '''''''''' 
    || Referrer_keys.key_string || '''''''''' 
    그런 다음 ''''''를 반환합니다 || Referrer_keys.referrer_type 
    || ''''''; 다음 경우 종료;'';
만약 v_<... ''<...''와 같은 다음 반환 ''<...''; 다음과 같은 경우 종료;

24.5.2. 포팅 기능

예 24-5. 간단한 기능

다음은 Oracle 함수입니다:

함수 생성 또는 교체 cs_fmt_browser_version(v_name IN varchar, v_version IN varchar)
반환 varchar IS
시작
    v_version이 NULL인 경우
        RETURN v_name;
    종료하면;
    RETURN v_name || '/' || v_version;
끝;
/
오류 표시;

이 기능을 살펴보고 차이점을 살펴보겠습니다. PL/pgSQL:

  • 또는 교체절이 아님 허용됩니다. 함수를 명시적으로 삭제해야 합니다. 비슷한 결과를 얻기 위해 만들기 전에.

  • 포스트그레SQL하지 않습니다 명명된 매개변수가 있습니다. 명시적으로 별칭을 지정해야 합니다. 함수 내부에 있습니다.

  • 오라클은 할 수 있습니다IN, 아웃INOUT매개변수가 함수에 전달되었습니다.INOUT18707_18830"IN"매개변수 및 함수는 단일 항목만 반환할 수 있습니다. 값.

  • 반환키워드 함수 프로토타입(함수 본문 아님)은 다음과 같습니다.반품PostgreSQL에서.

  • PostgreSQL에서 함수는 단일을 사용하여 생성됩니다. 따옴표를 구분 기호로 사용하므로 작은 따옴표를 이스케이프 처리해야 합니다. 함수 내부에서(이는 상당히 짜증날 수 있음) 시간; 참조섹션 24.5.1.1).

  • /오류 표시명령은 다음과 같습니다 PostgreSQL에는 존재하지 않습니다.

이 기능이 이식된 것처럼 보이는지 봅시다 PostgreSQL로:

드롭 기능 cs_fmt_browser_version(varchar, varchar);
함수 생성 cs_fmt_browser_version(varchar, varchar)
RETRUNS varchar AS '
선언
    $1에 대한 v_name 별칭;
    $2에 대한 v_version 별칭;
시작
    v_version이 NULL인 경우
        v_name을 반환합니다.
    종료하면;
    RETURN v_name || ''/'' || v_version;
끝;
' 언어 'plpgsql';

예 24-6. 또 다른 것을 생성하는 함수 기능

다음 절차는 a에서 행을 가져옵니다.선택문을 작성하고 큰 함수를 빌드합니다. 결과는 다음과 같습니다.IF문장, 효율성을 위해서. 특히 주목하세요. 커서의 차이점,for루프, PostgreSQL에서는 작은따옴표를 이스케이프 처리해야 합니다.

프로시저 생성 또는 교체 cs_update_referrer_type_proc는 다음과 같습니다. 
    커서 Referrer_keys는 
        cs_referrer_keys에서 *를 선택하세요. 
        try_order로 주문;

    a_output varchar(4000); 
시작하다 
    a_output := '함수 cs_find_referrer_type(v_host IN varchar, v_domain IN varchar, 
v_url IN varchar) return varchar가 시작됩니다'; 

    Referrer_keys 루프의 Referrer_key에 대해 
        a_output := a_output || ' v_'인 경우 || Referrer_key.kind || ''''처럼 || 
Referrer_key.key_string || ''' 그런 다음 '''를 반환 || referrer_key.referrer_type || 
'''; 종료하면;'; 
    끝 루프; 

    a_output := a_output || ' null을 반환; 끝;'; 
    즉시 a_output을 실행합니다. 
끝; 
/ 
오류 표시

이 함수가 PostgreSQL에서 어떻게 끝나는지는 다음과 같습니다:

CREATE FUNCTION cs_update_referrer_type_proc() 정수 AS '를 반환합니다.
선언
    Referrer_keys 기록;  -- FOR에 사용할 일반 레코드를 선언합니다.
    a_output varchar(4000);
시작 
    a_output := ''함수 생성 cs_find_referrer_type(varchar,varchar,varchar) 
                  varchar AS ''''를 반환합니다. 
                     선언 
                         $1에 대한 v_host 별칭; 
                         $2에 대한 v_domain 별칭; 
                         $3에 대한 v_url 별칭; ''; 

    -- 
    -- FOR 루프에서 쿼리 결과를 검색하는 방법에 주목하세요.
    -- FOR <record 구문을 사용합니다.
    --

    FOR Referrer_keys IN 선택 * cs_referrer_keys 순서 by try_order LOOP
        a_output := a_output || '' v_''인 경우 || Referrer_keys.kind || ''처럼 '''''''''' 
                 || Referrer_keys.key_string || '''''''''' 그런 다음 ''''''를 반환합니다. 
                 || referrer_keys.referrer_type || ''''''; 종료하면;''; 
    엔드 루프; 

    a_output := a_output || '' null을 반환합니다. 끝; '''' 언어 ''''plpgsql'''';''; 

    -- 변수를 대체하지 않기 때문에 작동합니다.
    -- 그렇지 않으면 실패할 것입니다. 함수를 실행하는 다른 방법은 PERFORM을 참조하세요.

    a_output을 실행합니다. 
끝; 
' 언어 'plpgsql';

예 24-7. 문자열이 많은 프로시저 조작 및 OUT 매개변수

다음 Oracle PL/SQL 프로시저는 구문 분석에 사용됩니다. URL을 지정하고 여러 요소(호스트, 경로 및 쿼리)를 반환합니다. 그것은 PL/pgSQL 함수에서는 하나의 값만 사용할 수 있기 때문에 프로시저입니다. 반환됩니다(참조섹션 24.5.3). PostgreSQL에서 이 문제를 해결하는 한 가지 방법은 다음과 같습니다. 절차를 세 가지 다른 기능으로 나눕니다. 호스트를 반환하고, 다른 하나는 경로로, 다른 하나는 경로로 반환합니다. 쿼리.

프로시저 cs_parse_url 생성 또는 교체(
    v_url IN varchar,
    v_host OUT varchar, -- 다시 전달됩니다.
    v_path OUT varchar, -- 이것도 마찬가지입니다.
    v_query OUT varchar) -- 그리고 이건
이다
    a_pos1 정수;
    a_pos2 정수;
시작하다
    v_host := NULL;
    v_path := NULL;
    v_query := NULL;
    a_pos1 := instr(v_url, '//'); -- PostgreSQL에는 instr 함수가 없습니다.

    a_pos1 = 0이면
        반환;
    종료하면;
    a_pos2 := instr(v_url, '/', a_pos1 + 2);
    a_pos2 = 0이면
        v_host := substr(v_url, a_pos1 + 2);
        v_path := '/';
        반품;
    종료하면;

    v_host := substr(v_url, a_pos1 + 2, a_pos2 - a_pos1 - 2);
    a_pos1 := instr(v_url, '?', a_pos2 + 1);

    a_pos1 = 0이면
        v_path := substr(v_url, a_pos2);
        반품;
    종료하면;

    v_path := substr(v_url, a_pos2, a_pos1 - a_pos2);
    v_query := substr(v_url, a_pos1 + 1);
끝;
/
오류 표시;

이 절차를 다음과 같이 번역할 수 있습니다. 포스트그레SQL:

drop 함수 cs_parse_url_host(varchar); 
함수 cs_parse_url_host(varchar) 생성은 varchar를 '로 반환합니다. 
선언하다 
    $1에 대한 v_url 별칭; 
    v_host varchar; 
    v_path varchar; 
    a_pos1 정수; 
    a_pos2 정수; 
    a_pos3 정수; 
시작하다 
    v_host := NULL; 
    a_pos1 := instr(v_url,''//''); 

    a_pos1 = 0이면 
        ''''를 반환합니다.  -- 공백을 반환합니다.
    종료하면; 

    a_pos2 := instr(v_url,''/'',a_pos1 + 2); 
    a_pos2 = 0이면 
        v_host := substr(v_url, a_pos1 + 2); 
        v_path := ''/''; 
        v_host를 반환합니다; 
    종료하면; 

    v_host := substr(v_url, a_pos1 + 2, a_pos2 - a_pos1 - 2 ); 
    v_host를 반환합니다. 
끝; 
' 언어 'plpgsql';

참고:PostgreSQL에는 다음이 없습니다.instr함수이므로 문제를 해결할 수 있습니다. 다른 기능을 조합하여 사용합니다. 나는 지쳤다 이렇게 하고 내 것을 만들었어요instr완전히 다음과 같이 동작하는 함수 오라클(삶을 더 쉽게 만듭니다). 참조섹션 24.5.6코드용.

24.5.3. 절차

Oracle 절차는 다음 작업에 좀 더 많은 유연성을 제공합니다. 개발자는 명시적으로 반환할 필요가 없지만 INOUT 또는 OUT 매개변수를 사용하면 됩니다.

예:

프로시저 cs_create_job 생성 또는 교체(v_job_id in 정수)
이다
    a_running_job_count 정수;
    pragmaautonomous_transaction;(1)시작
    단독 모드에서 cs_jobs 테이블을 잠급니다.(2)cs_jobs에서 a_running_job_count로 count(*) 선택
    여기서 end_stamp는 null입니다.

    a_running_job_count  0이면
        커밋; -- 자유 잠금(3)raise_application_error(-20000, '새 작업을 생성할 수 없습니다: 작업이 현재 실행 중입니다.');
    종료하면;

    cs_active_job에서 삭제;
    cs_active_job(job_id) 값(v_job_id)에 삽입;

    시작하다
        cs_jobs(job_id, start_stamp) 값(v_job_id, sysdate)에 삽입합니다.
        dup_val_on_index가 null인 경우 예외; -- 이미 존재하더라도 걱정하지 마세요.(4)끝;
    커밋;
끝;
/
오류 표시

이러한 절차는 PostgreSQL로 쉽게 변환될 수 있습니다 를 반환하는 함수INTEGER. 이 특히 절차는 우리에게 가르쳐줄 수 있기 때문에 흥미롭습니다. 몇 가지:

(1)
없습니다프라그마문장 PostgreSQL에서.
(2)
만약 당신이 다음을 수행한다면락 테이블에 PL/pgSQL의 경우 호출이 완료될 때까지 잠금이 해제되지 않습니다. 거래가 완료되었습니다.
(3)
PL/pgSQL에서도 트랜잭션을 가질 수 없습니다 절차. 전체 함수(및 다음과 같은 다른 함수 거기에서)는 트랜잭션과 PostgreSQL에서 실행됩니다. 문제가 발생하면 결과를 롤백합니다. 그러므로 하나만시작문은 다음과 같습니다 허용됩니다.
(4)
다음으로 대체되어야 하는 예외는IF진술.

이 절차를 다음으로 포팅할 수 있는 방법 중 하나를 살펴보겠습니다. PL/pgSQL:

drop 함수 cs_create_job(integer);
함수 생성 cs_create_job(integer)은 ' 선언으로 정수를 반환합니다.
    $1에 대한 v_job_id 별칭;
    a_running_job_count 정수;
    a_num 정수;
    -- pragmaautonomous_transaction;
시작하다
    단독 모드에서 cs_jobs 테이블을 잠급니다.
    end_stamp가 null인 cs_jobs에서 a_running_job_count로 count(*)를 선택합니다.

    a_running_job_count  0이면
        -- 커밋; -- 무료 잠금
        예외 발생 ''새 작업을 생성할 수 없습니다: 작업이 현재 실행 중입니다.'';
    종료하면;

    cs_active_job에서 삭제;
    cs_active_job(job_id) 값(v_job_id)에 삽입;

    SELECT count(*)를 a_num FROM cs_jobs WHERE job_id=v_job_id;
    IF NOT FOUND THEN -- 마지막 쿼리에서 아무것도 반환되지 않은 경우
        -- 이 작업은 테이블에 없으므로 삽입해 보겠습니다.
        cs_jobs(job_id, start_stamp) 값(v_job_id, sysdate())에 삽입합니다.
        1을 반환합니다.
    그 외
        raise NOTICE ''작업이 이미 실행 중입니다.'';(1)END IF;

    0을 반환합니다.
끝;
' 언어 'plpgsql';
(1)
알림(또는 오류)을 어떻게 제기할 수 있는지 알아보세요. PL/pgSQL.

24.5.4. 패키지

참고:나는 패키지에 대해 많은 일을 하지 않았습니다. 그러니 여기에 실수가 있으면 알려주세요.

패키지는 Oracle이 PL/SQL을 캡슐화하기 위해 제공하는 방법입니다. 명령문과 함수를 Java 클래스와 같은 하나의 엔터티로 통합합니다. 메소드와 객체를 정의하는 곳입니다. 당신은 이것들에 접근할 수 있습니다 a가 있는 객체/메서드"."(점). 다음은 오라클의 예입니다. ACS 4의 패키지(ArsDigita 커뮤니티 시스템):

패키지 본문 AC 생성 또는 교체
~로
  함수 add_user(
    users.user_id%TYPE의 user_id 기본값은 null입니다.
    acs_objects.object_type%TYPE의 object_type
               기본 '사용자',
    acs_objects.creation_date%TYPE의 Creation_date
               기본 시스템 날짜,
    acs_objects.creation_user%TYPE의 Creation_user
               기본 null,
    acs_objects.creation_ip%TYPE의 Creation_ip 기본값은 null,
  ...
  ) users.user_id%TYPE을 반환합니다.
  이다
    v_user_id users.user_id%TYPE;
    v_rel_id 멤버십_rels.rel_id%TYPE;
  시작하다
    v_user_id := acs_user.new (user_id, object_type, 생성_날짜,
                생성_사용자, 생성_ip, 이메일,
    ...
    v_user_id를 반환합니다.
  끝;
AC 종료;
/
오류 표시

우리는 다른 객체를 생성하여 이것을 PostgreSQL로 포팅합니다 표준 이름을 가진 함수로 Oracle 패키지의 컨벤션. 우리는 다른 세부 사항에 주의를 기울여야 합니다. PostgreSQL 함수에 기본 매개변수가 없는 것과 같습니다. 위 패키지는 다음과 같습니다.

함수 생성 acs__add_user(integer,integer,varchar,datetime,integer,integer,...)
RETURNS 정수 AS '
선언
    $1에 대한 user_id 별칭;
    $2에 대한 object_type 별칭;
    $3에 대한 생성_날짜 별칭;
    $4에 대한 Creation_user 별칭;
    $5에 대한 Creation_ip 별칭;
    ...
    v_user_id users.user_id%TYPE;
    v_rel_id 멤버십_rels.rel_id%TYPE;
시작
    v_user_id := acs_user__new(user_id,object_type,creation_date,creation_user,creation_ip, ...);
    ...

    v_user_id를 반환합니다.
끝;
' 언어 'plpgsql';

24.5.5. 기타 볼만한 사항 에 대한

24.5.5.1. 실행

PostgreSQL 버전실행잘 작동하지만 사용해야 한다는 점을 기억해야 합니다quote_literal(TEXT)그리고quote_string(TEXT)설명된 대로섹션 24.2.5.3. 유형의 구성''SELECT * from $1'' 실행;작동하지 않습니다 이 기능을 사용하지 않는 한.

24.5.5.2. PL/pgSQL 최적화 기능

PostgreSQL은 두 가지 함수 생성 수정자를 제공합니다. 실행 최적화:캐시 가능(함수는 동일한 값이 주어지면 항상 동일한 결과를 반환합니다. 인수) 및엄격함(기능 인수 중 하나라도 NULL이면 NULL을 반환합니다. 상담하세요함수 생성자세한 내용은 참조하세요.

이러한 최적화 속성을 사용하려면 다음을 수행해야 합니다. 사용하다함께당신의 수식어함수 생성성명. 뭔가 좋아요:

CREATE FUNCTION foo(...) 정수를 '로 반환합니다.
...
' 언어 'plpgsql'
WITH(제한적, 캐시 가능);

24.5.6. 부록

24.5.6.1. 내 코드instr함수

--
-- Oracle의 대응 기능을 모방한 instr 함수
-- 구문: instr(string1,string2,[n],[m]) 여기서 []는 선택적 매개변수를 나타냅니다.
-- 
-- n번째 문자부터 시작하는 string1에서 m번째 문자를 검색합니다.
-- string2의 발생. n이 음수이면 뒤로 검색합니다. 만약 m이
-- 전달되지 않았습니다. 1로 가정합니다(검색은 첫 번째 문자부터 시작됩니다).
--
-- 로베르토 멜로(rmello@fslc.usu.edu)
-- Robert Gaszewski 수정(graszew@poland.com)
-- GPL v2 이상에 따라 라이센스가 부여됩니다.
--

삭제 함수 instr(varchar,varchar);
CREATE FUNCTION instr(varchar,varchar) 정수 AS '를 반환합니다.
선언
    위치 정수;
시작
    pos:= instr($1,$2,1);
    반환 위치;
끝;
' 언어 'plpgsql';

삭제 함수 instr(varchar,varchar,integer);
CREATE FUNCTION instr(varchar,varchar,integer) 정수 AS '를 반환합니다.
선언
    $1에 대한 문자열 별칭;
    string_to_search $2에 대한 별칭;
    $3에 대한 beg_index 별칭;
    위치 정수 NOT NULL DEFAULT 0;
    temp_str varchar;
    정수를 구걸하다;
    길이 정수;
    ss_length 정수;
시작
    IF beg_index  0 그러면

       temp_str := substring(string FROM beg_index);
       pos := position(string_to_search IN temp_str);

       IF pos = 0이면
                 0을 반환합니다.
             그 외
                 RETURN pos + beg_index - 1;
             종료하면;
    그 외
       ss_length := char_length(string_to_search);
       길이 := char_length(string);
       구걸 := 길이 + 구걸_색인 - ss_length + 2;

       구걸하는 동안  0 LOOP

           temp_str := substring(string FROM beg FOR ss_length);
                 pos := position(string_to_search IN temp_str);

                 IF 위치  0 THEN
                           반환 구걸;
                 종료하면;

                 구걸하다 := 구걸하다 - 1;
       엔드 루프;
       0을 반환합니다.
    종료하면;
끝;
' 언어 'plpgsql';

--
-- Robert Gaszewski 작성(graszew@poland.com)
-- GPL v2 이상에 따라 라이센스가 부여됩니다.
--
삭제 함수 instr(varchar,varchar,integer,integer);
CREATE FUNCTION instr(varchar,varchar,integer,integer) 정수 AS '를 반환합니다.
선언
    $1에 대한 문자열 별칭;
    string_to_search $2에 대한 별칭;
    $3에 대한 beg_index 별칭;
    $4에 대한 발생_색인 별칭;
    위치 정수 NOT NULL DEFAULT 0;
    발생_번호 정수 NOT NULL DEFAULT 0;
    temp_str varchar;
    정수를 구걸하다;
    나는 정수;
    길이 정수;
    ss_length 정수;
시작
    IF beg_index  0 그러면
        구걸 := 구걸_index;
        temp_str := substring(string FROM beg_index);

        FOR i IN 1..occur_index LOOP
            pos := position(string_to_search IN temp_str);

            I = 1이면
                구걸 := 구걸 + pos - 1;
            그 외
                구걸하다 := 구걸하다 + pos;
            종료하면;

            temp_str := substring(string FROM beg + 1);
        엔드 루프;

        IF pos = 0이면
            0을 반환합니다.
        그 외
            반환 구걸;
        종료하면;
    그 외
        ss_length := char_length(string_to_search);
        길이 := char_length(string);
        구걸 := 길이 + 구걸_색인 - ss_length + 2;

        구걸하는 동안  0 LOOP
            temp_str := substring(string FROM beg FOR ss_length);
            pos := position(string_to_search IN temp_str);

            IF 위치  0 THEN
                발생_번호 := 발생_번호 + 1;

                IF 발생_번호 = 발생_인덱스 THEN
                    반환 구걸;
                종료하면;
            종료하면;

            구걸하다 := 구걸하다 - 1;
        엔드 루프;

        0을 반환합니다.
    종료하면;
끝;
' 언어 'plpgsql';