저자:로베르토 멜로 (<rmello@fslc.usu.edu)
이 섹션에서는 Oracle의 PL/SQL과 Oracle의 PL/SQL 간의 차이점을 설명합니다. 도움을 주기 위해 PostgreSQL의 PL/pgSQL 언어 개발자는 Oracle에서 PostgreSQL로 애플리케이션을 이식합니다. 대부분의 여기 코드는ArsDigita 클릭스트림 모듈내가 PostgreSQL로 이식했을 때 인턴십을 했습니다오픈포스 주식회사2000년 여름.
PL/pgSQL은 여러 측면에서 PL/SQL과 유사합니다. 블록입니다 구조화된 명령형 언어(모든 변수는 선언). PL/SQL에는 PostgreSQL보다 더 많은 기능이 있습니다. 대응하지만 PL/pgSQL은 많은 양의 작업을 허용합니다. 기능이 지속적으로 개선되고 있습니다.
Oracle에서 포팅할 때 명심해야 할 몇 가지 사항 PostgreSQL로:
PostgreSQL에는 기본 매개변수가 없습니다.
PostgreSQL에서 함수를 오버로드할 수 있습니다. 이것은 종종 기본 매개변수 부족 문제를 해결하는 데 사용됩니다.
할당, 루프 및 조건은 유사합니다.
PostgreSQL에서는 커서가 필요하지 않습니다. 쿼리를 FOR 문(아래 예 참조)
PostgreSQL에서는필요탈출하다 작은따옴표. 참조섹션 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. 간단한 기능
다음은 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코드용.
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. 이 특히 절차는 우리에게 가르쳐줄 수 있기 때문에 흥미롭습니다. 몇 가지:
이 절차를 다음으로 포팅할 수 있는 방법 중 하나를 살펴보겠습니다. 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';
참고:나는 패키지에 대해 많은 일을 하지 않았습니다. 그러니 여기에 실수가 있으면 알려주세요.
패키지는 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';
PostgreSQL 버전실행잘 작동하지만 사용해야 한다는 점을 기억해야 합니다quote_literal(TEXT)그리고quote_string(TEXT)설명된 대로섹션 24.2.5.3. 유형의 구성''SELECT * from $1'' 실행;작동하지 않습니다 이 기능을 사용하지 않는 한.
PostgreSQL은 두 가지 함수 생성 수정자를 제공합니다. 실행 최적화:캐시 가능(함수는 동일한 값이 주어지면 항상 동일한 결과를 반환합니다. 인수) 및엄격함(기능 인수 중 하나라도 NULL이면 NULL을 반환합니다. 상담하세요함수 생성자세한 내용은 참조하세요.
이러한 최적화 속성을 사용하려면 다음을 수행해야 합니다. 사용하다함께당신의 수식어함수 생성성명. 뭔가 좋아요:
CREATE FUNCTION foo(...) 정수를 '로 반환합니다. ... ' 언어 'plpgsql' WITH(제한적, 캐시 가능);
--
-- 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';