橸誗蓼麪庖 Oracle 䔇 PL/SQL 启 PostgreSQL 䔇 PL/pgSQL 臺蘔幋閘䔇噞彆婯橕脘凹闼底傯 Oracle 劏 PostgreSQL 䓂洉庫䫘䔇庺橬欔婞媷㔗
PL/pgSQL 婯 PL/SQL 婘螩崔桹麵鄘麂婩䌂嚚㔗垄滇婔䓉庖䂷悇䔇䖽嘪臺愫(变傴攓)䔇臺蘔幽婫媙釂弄滯欔橬埻麟㔗蕋唚㔕冻䯇㔕溇傽京鄘冽䌂嚚㔗婘傯 Oracle 劏 PostgreSQL 䓂洉䔇施唍媙釂螄嘟婔底庋愙
婘 PostgreSQL 婺埗昄澇橬䚺䩕唚㔗
嘹埇傖婘 PostgreSQL 麯麉蘘庘昄㔗認婻䬹攓婩䫘庯䂘嚔䚺幟䚺䩕埗昄䔇閞鵻㔗
婉脘嘪䫘噾赆庘昄嚘䫘䔇彖劯劉䔇埗昄劉㔗套悩檪埗昄劉䫘 function_name.parameter_name 鍊垔䔇臺Oracle 噕螩嘹認湙啔㔗婘 PL/pgSQL 婺嘹庫臖镪噉婯彖劉潡臘劉喾仕㔗
婘PL/pgSQL麯婉驔襕橩湺埻襕檪变傴櫆婘 FOR 臺埖麯儌埇傖庖(蓕冋37-6)㔗
婘 PostgreSQL 麯庘昄嘷媙釂喍潊庖严婾桺橸啹溴嘹驔襕嘪䫘䆯噄严䘯垔潡蔙锄锩庘昄嘷麯麵䔇剘嚘埙(蓕誗37.2.1)㔗
庫臖䫘昇嚟檪庘昄䂇䂺潊婉劯䔇䂇蔯婉滇䫘寙㔗
啹婺澇橬寙欔傖幘澇橬寙亓彆䔇埻麟㔗認婔䗹橬施唍毺螘寯㔗嘹埇傖婘婘施臘麯媺庻嚔臺亓彆䔇䪽攕㔗
冋37-5 暫䴺庖套嘘傯 PL/SQL 劏 PL/pgSQL 䓂洉婔婻䞔剘䔇庘昄㔗
冋37-5. 傯 PL/SQL 劏 PL/pgSQL 䓂洉婔婻䞔剘䔇庘昄
婋麵滇婔婻 Oracle PL/SQL 庘昄
CREATE OR REPLACE FUNCTION cs_fmt_browser_version(v_name varchar, v_version varchar) RETURN varchar IS BEGIN IF v_version IS NULL THEN RETURN v_name; END IF; RETURN v_name || '/' || v_version; END; / show errors;
螷潏傸臂婔镉認婻庘昄䇽劯䩋䩋 PL/pgSQL 婯幋䔇婉劯
婘庘昄寘傋麯䔇 RETURN(婉滇庘昄嘷麯䔇)噿髞庖彄庖 PostgreSQL 麯儌滇 RETURNS 㔗誻橬IS 埻潊 AS 幽婫嘹誻驔襕嵂媹婔婻 LANGUAGE 床埖啹婺 PL/pgSQL 幽麂嫇婔埇䫘䔇庘昄臺蘔㔗
婘 PostgreSQL 麯庘昄嘷赆螴婺滇婔婻庖严婾桺橸欔傖嘹驔襕嘪䫘剘嚘埙潡蔙䆯噄严䘯垔垄認婻寙啘严傼敪庖 Oracle 橔劯䔇闼婻 /
婘 PostgreSQL 麯澇橬 show errors 变傴婉驔襕認婻变傴滇啹婺髍臇滇躻媘檖只䔇㔗
婋麵滇認婻庘昄䓂洉彄 PostgreSQL 幋劯䔇湙床
CREATE OR REPLACE FUNCTION cs_fmt_browser_version(v_name varchar, v_version varchar) RETURNS varchar AS $$ BEGIN IF v_version IS NULL THEN RETURN v_name; END IF; RETURN v_name || '/' || v_version; END; $$ LANGUAGE plpgsql;
冋37-6暫䴺庖套嘘䓂洉婔婻录傺埥崡婔婻庘昄䔇庘昄䔇桹濘傖埪暫䴺庖套嘘崇䊖嚘埙锄锩䔇閞鵻㔗
冋37-6. 傯 PL/SQL 劏 PL/pgSQL 䓂洉婔婻录傺噽垄庘昄䔇庘昄
婋麵䔇誺䘋傯婔婻 SELECT 臺埖婺檷埡苖幾臯䇽劯婺庖柊醻昽䯺埽䫘 IF 臺埖婺䔇䂷悩彽嘩庖婔婻噘崓䔇庘昄㔗臙䬹彆濘懟婘橩湺启 FOR 冻䯇麯麵䔇婉劯㔗
認滇 Oracle 䔇䬽橸
CREATE OR REPLACE PROCEDURE cs_update_referrer_type_proc IS CURSOR referrer_keys IS SELECT * FROM cs_referrer_keys ORDER BY try_order; func_cmd VARCHAR(4000); BEGIN func_cmd := 'CREATE OR REPLACE FUNCTION cs_find_referrer_type(v_host IN VARCHAR, v_domain IN VARCHAR, v_url IN VARCHAR) RETURN VARCHAR IS BEGIN'; FOR referrer_key IN referrer_keys LOOP func_cmd := func_cmd || ' IF v_' || referrer_key.kind || ' LIKE ''' || referrer_key.key_string || ''' THEN RETURN ''' || referrer_key.referrer_type || '''; END IF;'; END LOOP; func_cmd := func_cmd || ' RETURN NULL; END;'; EXECUTE IMMEDIATE func_cmd; END; / show errors;
麵滇認婻庘昄婘 PostgreSQL 麯麵䔇湙床
CREATE OR REPLACE FUNCTION cs_update_referrer_type_proc() RETURNS void AS $func$ DECLARE referrer_key RECORD; -- 弄滯婔婻婘 FOR 麯䫘䔇锔䫘䔇螄嘘 func_body text; func_cmd text; BEGIN func_body := 'BEGIN'; -- 臙濘懟滇套嘘婘婔婻 FOR 冻䯇婺嘪䫘 FOR <record> 悇锹欆柟劇溇䂷悩䔇 FOR referrer_key IN SELECT * FROM cs_referrer_keys ORDER BY try_order LOOP func_body := func_body || ' IF v_' || referrer_key.kind || ' LIKE ' || quote_literal(referrer_key.key_string) || ' THEN RETURN ' || quote_literal(referrer_key.referrer_type) || '; END IF;' ; END LOOP; func_body := func_body || ' RETURN NULL; END;'; func_cmd := 'CREATE OR REPLACE FUNCTION cs_find_referrer_type(v_host varchar, v_domain varchar, v_url varchar) RETURNS varchar AS ' || quote_literal(func_body) || ' LANGUAGE plpgsql;' ; EXECUTE func_cmd; END; $func$ LANGUAGE plpgsql;
臙濘懟庘昄嘷滇套嘘䋸䆋彽嘩幽婫嚹锐䂍 quote_literal 凹噽婺䔇剘嚘埙崉彽埯傘䔇㔗驔襕認婻檔噓滇啹婺方濘嘪䫘䆯噄严䘯垔垔幬桄庘昄澇濘媺臕 referrer_key.key_string 庖枕誺準䔇庖严婾嚔蓼悊潊傔幽湙床㔗埇傖啺螆 referrer_key.kind 滇埻橬 host, domain, url 嘖滇 referrer_key.key_string埇脘滇傂嘘婩薪䬹彆滇垄埇脘寙劆䆯噄严㔗認婻庘昄垂鍙婪滇凹寘準 Oracle 䬽橸䔇婔婻櫹誕啹婺套悩婘 referrer_key.key_string 潡 referrer_key.referrer_type 寙劆剘嚘埙䔇施唍垄婉嚔䫘潊橬懕䖙䔇傼乕㔗
冋37-7暫䴺庖套嘘䓂洉婔婻婥橬 OUT 埗昄启庖严婾崇䊖䔇庘昄㔗PostgreSQL 麯麵澇橬喙䘞 instr
庘昄嘖滇嘹埇傖䫘噽垄庘昄䔇䂇劽準䂘嚔垄㔗婘誗37.11.3麯橬婔婻 PL/pgSQL 䔇 instr
垂䯄嘹埇傖䫘垄螷嘹䔇䓂洉埻冖敘䞔剘底㔗
冋37-7. 傯 PL/SQL 劏 PL/pgSQL 䓂洉婔婻庖严婾淉嘩启 OUT 埗昄䔇誺䘋
婋麵䔇 Oracle PL/SQL 誺䘋䫘庯彖悊婔婻 URL 幽婫誫啂苖幾婻噄䘹(婂橺㔕虇冇㔕变傴)㔗
婋麵滇 Oracle 䔇䬽橸
CREATE OR REPLACE PROCEDURE cs_parse_url( v_url IN VARCHAR, v_host OUT VARCHAR, -- 認婻埻麟滇襕嚹啂䔇 v_path OUT VARCHAR, -- 認婻幘滇 v_query OUT VARCHAR) -- 誻橬認婻 IS a_pos1 INTEGER; a_pos2 INTEGER; BEGIN v_host := NULL; v_path := NULL; v_query := NULL; a_pos1 := instr(v_url, '//'); IF a_pos1 = 0 THEN RETURN; END IF; a_pos2 := instr(v_url, '/', a_pos1 + 2); IF a_pos2 = 0 THEN v_host := substr(v_url, a_pos1 + 2); v_path := '/'; RETURN; END IF; v_host := substr(v_url, a_pos1 + 2, a_pos2 - a_pos1 - 2); a_pos1 := instr(v_url, '?', a_pos2 + 1); IF a_pos1 = 0 THEN v_path := substr(v_url, a_pos2); RETURN; END IF; v_path := substr(v_url, a_pos2, a_pos1 - a_pos2); v_query := substr(v_url, a_pos1 + 1); END; / show errors;
婋麵儌滇檪認婻誺䘋䪂臏潊 PL/pgSQL 埇脘䔇湙床
CREATE OR REPLACE FUNCTION cs_parse_url( v_url IN VARCHAR, v_host OUT VARCHAR, -- 認婻儖赆嚹啂 v_path OUT VARCHAR, -- 認婻幘嚹啂 v_query OUT VARCHAR) -- 誻橬認婻 AS $$ DECLARE a_pos1 INTEGER; a_pos2 INTEGER; BEGIN v_host := NULL; v_path := NULL; v_query := NULL; a_pos1 := instr(v_url, '//'); IF a_pos1 = 0 THEN RETURN; END IF; a_pos2 := instr(v_url, '/', a_pos1 + 2); IF a_pos2 = 0 THEN v_host := substr(v_url, a_pos1 + 2); v_path := '/'; RETURN; END IF; v_host := substr(v_url, a_pos1 + 2, a_pos2 - a_pos1 - 2); a_pos1 := instr(v_url, '?', a_pos2 + 1); IF a_pos1 = 0 THEN v_path := substr(v_url, a_pos2); RETURN; END IF; v_path := substr(v_url, a_pos2, a_pos1 - a_pos2); v_query := substr(v_url, a_pos1 + 1); END; $$ LANGUAGE plpgsql;
認婻庘昄埇傖認幽䫘
SELECT * FROM cs_parse_url('http://foobar.com/query.cgi?baz');
冋37-8暫䴺庖套嘘婔婻嘪䫘劇䓉 Oracle 婷橬䬹攓䔇誺䘋㔗
冋37-8. 傯 PL/SQL 劏 PL/pgSQL 䓂洉婔婻誺䘋
Oracle 䬽橸
CREATE OR REPLACE PROCEDURE cs_create_job(v_job_id IN INTEGER) IS a_running_job_count INTEGER; PRAGMA AUTONOMOUS_TRANSACTION;(1) BEGIN LOCK TABLE cs_jobs IN EXCLUSIVE MODE;(2) SELECT count(*) INTO a_running_job_count FROM cs_jobs WHERE end_stamp IS NULL; IF a_running_job_count > 0 THEN COMMIT; -- free lock(3) raise_application_error(-20000, 'Unable to create a new job: a job is currently running.'); END IF; DELETE FROM cs_active_job; INSERT INTO cs_active_job(job_id) VALUES (v_job_id); BEGIN INSERT INTO cs_jobs (job_id, start_stamp) VALUES (v_job_id, sysdate); EXCEPTION WHEN dup_val_on_index THEN NULL; -- 套悩噾䂟庻婘彆拙媄 END; COMMIT; END; / show errors
償認湙䔇誺䘋埇傖冽垹滷䫘誫啂 void 䔇庘昄䓂洉彄 PostgreSQL 麯㔗凹認婻誺䘋䬹彆懘噘轼滇啹婺垄埇傖昍婔底婩薪
婋麵滇檪認婻誺䘋䓂洉彄 PL/pgSQL 麯䔇婔䓉桹濘
CREATE OR REPLACE FUNCTION cs_create_job(v_job_id integer) RETURNS void AS $$ DECLARE a_running_job_count integer; BEGIN LOCK TABLE cs_jobs IN EXCLUSIVE MODE; SELECT count(*) INTO a_running_job_count FROM cs_jobs WHERE end_stamp IS NULL; IF a_running_job_count > 0 THEN RAISE EXCEPTION 'Unable to create a new job: a job is currently running';(1) END IF; DELETE FROM cs_active_job; INSERT INTO cs_active_job(job_id) VALUES (v_job_id); BEGIN INSERT INTO cs_jobs (job_id, start_stamp) VALUES (v_job_id, now()); EXCEPTION WHEN unique_violation THEN (2) -- 套悩噾䂟庻婘彆拙媄 END; END; $$ LANGUAGE plpgsql;昘婻誺䘋启 Oracle 䔇京昽䔇婂襕䔇媘脘傋噞彆滇婘 cs_jobs 婪毕橬䔇毐傡髕儖媺毕彄脄䫘䔇庋媇䂷溘㔗劯湙套悩脄䫘蔙劯準锔庺(懫套臘啹婺髍臇)認婻誺䘋䔇昽悩儖赆啂悔毬㔗
橸誗蓼麪庹婻傯 Oracle PL/SQL 庘昄劏 PostgreSQL 䓂洉䔇庹婻噽垄桹麵䔇庋愙㔗
婘 PL/pgSQL 麯套悩婔婻嚗婩赆 EXCEPTION 床埖托诙闼幽欔橬躻認婻庖䔇 BEGIN 傖準䔇昄扞康櫹埻鄘嚔赆躻媘啂悔㔗幘儌滇臘認婻臯婺京庯嘹婘 Oracle 麯䔇
BEGIN SAVEPOINT s1; ... code here ... EXCEPTION WHEN ... THEN ROLLBACK TO s1; ... code here ... WHEN ... THEN ROLLBACK TO s1; ... code here ... END;
套悩嘹婘檪認幽嘪䫘 SAVEPOINT 启 ROLLBACK TO 䔇 Oracle 誺䘋䪂臏誺準闼幽嘹䔇昂凪冽喘幾埻襕䩕䘖 SAVEPOINT 启 ROLLBACK TO 剿埇㔗套悩嘹襕䪂臏䔇誺䘋嘪䫘庖婉劯䔇 SAVEPOINT 启 ROLLBACK TO 闼幽儌驔襕愿愿庖㔗
PostgreSQL 䬽橸䔇 EXECUTE 誊蘸冖䌂嚚 PL/SQL 婉悩嘹媙釂螄嘟襕償誗37.6.5麯柟誄䔇闼湙䫘 quote_literal
启 quote_ident
㔗套悩嘹婉䫘認底庘昄闼幽償 EXECUTE 'SELECT * FROM $1'; 認湙䔇悇锹滇婉嚔誊蘸䔇㔗
PostgreSQL 䂍嘹婴婻录傺庘昄䔇媞閄臉䫘準嚻寡欓臯"volatility"(滷埻䔇婘䂍庺䔇埗昄䕩劯施庘昄攂滇誫啂䕩劯䂷悩)启"strictness"(婖湚䔇套悩傂嘘埗昄滇 NULL 闼幽庘昄誫啂 NULL)㔗埗蔄 CREATE FUNCTION 䔇欋喯诙埡䂖誗㔗
套悩襕嘪䫘認底嚻寡匂攓闼幽嘹䔇 CREATE FUNCTION 臺埖埇脘䩋蕙準償認湙
CREATE FUNCTION foo(...) RETURNS integer AS $$ ... $$ LANGUAGE plpgsql STRICT IMMUTABLE;
橸誗寙劆 Oracle 噚垹䔇 instr
庘昄嘹埇傖䫘垄䞔寡嘹䔇䓂洉誺䘋㔗
-- -- 昇拘 Oracle 楗媕䔇 instr 庘昄 -- 臺濘: instr(string1, string2, [n], [m]) 認麯䔇 [] 臘䴺埇锬埗昄 -- -- 傯 string1 䔇丸 n 婻庖严嚔哋凂欆 string2 䔇丸 m 婻庺䯄㔗 -- 套悩 n 滇蘘昄彍傯劯劏嬉五㔗套悩澇橬嚹锐 m 啺垔婺 1(傯丸婔婻庖严嚔哋欆)㔗 -- CREATE FUNCTION instr(varchar, varchar) RETURNS integer AS $$ DECLARE pos integer; BEGIN pos:= instr($1, $2, 1); RETURN pos; END; $$ LANGUAGE plpgsql STRICT IMMUTABLE; CREATE FUNCTION instr(string varchar, string_to_search varchar, beg_index integer) RETURNS integer AS $$ DECLARE pos integer NOT NULL DEFAULT 0; temp_str varchar; beg integer; length integer; ss_length integer; BEGIN IF beg_index > 0 THEN temp_str := substring(string FROM beg_index); pos := position(string_to_search IN temp_str); IF pos = 0 THEN RETURN 0; ELSE RETURN pos + beg_index - 1; END IF; ELSE ss_length := char_length(string_to_search); length := char_length(string); beg := length + beg_index - ss_length + 2; WHILE beg > 0 LOOP temp_str := substring(string FROM beg FOR ss_length); pos := position(string_to_search IN temp_str); IF pos > 0 THEN RETURN beg; END IF; beg := beg - 1; END LOOP; RETURN 0; END IF; END; $$ LANGUAGE plpgsql STRICT IMMUTABLE; CREATE FUNCTION instr(string varchar, string_to_search varchar, beg_index integer, occur_index integer) RETURNS integer AS $$ DECLARE pos integer NOT NULL DEFAULT 0; occur_number integer NOT NULL DEFAULT 0; temp_str varchar; beg integer; i integer; length integer; ss_length integer; BEGIN IF beg_index > 0 THEN beg := beg_index; temp_str := substring(string FROM beg_index); FOR i IN 1..occur_index LOOP pos := position(string_to_search IN temp_str); IF i = 1 THEN beg := beg + pos - 1; ELSE beg := beg + pos; END IF; temp_str := substring(string FROM beg + 1); END LOOP; IF pos = 0 THEN RETURN 0; ELSE RETURN beg; END IF; ELSE ss_length := char_length(string_to_search); length := char_length(string); beg := length + beg_index - ss_length + 2; WHILE beg > 0 LOOP temp_str := substring(string FROM beg FOR ss_length); pos := position(string_to_search IN temp_str); IF pos > 0 THEN occur_number := occur_number + 1; IF occur_number = occur_index THEN RETURN beg; END IF; END IF; beg := beg - 1; END LOOP; RETURN 0; END IF; END; $$ LANGUAGE plpgsql STRICT IMMUTABLE;