41.13. ÐоÑÑиÑование из Oracle PL/SQL #
Ð ÑÑом Ñазделе ÑаÑÑмаÑÑиваÑÑÑÑ ÑазлиÑÐ¸Ñ Ð¼ÐµÐ¶Ð´Ñ ÑзÑками PostgreSQL PL/pgSQL и Oracle PL/SQL, ÑÑÐ¾Ð±Ñ Ð¿Ð¾Ð¼Ð¾ÑÑ ÑазÑабоÑÑикам, пеÑеноÑÑÑим пÑÐ¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¸Ð· Oracle® в PostgreSQL.
PL/pgSQL во Ð¼Ð½Ð¾Ð³Ð¸Ñ Ð°ÑпекÑÐ°Ñ Ð¿Ð¾Ñ Ð¾Ð¶ на PL/SQL . ÐÑо блоÑно-ÑÑÑÑкÑÑÑиÑованнÑй, импеÑаÑивнÑй ÑзÑк, в коÑоÑом вÑе пеÑеменнÑе Ð´Ð¾Ð»Ð¶Ð½Ñ Ð¾Ð±ÑÑвлÑÑÑÑÑ. ÐÑиÑваиваниÑ, ÑÐ¸ÐºÐ»Ñ Ð¸ ÑÑловнÑе опеÑаÑоÑÑ Ð² Ð¾Ð±Ð¾Ð¸Ñ ÑзÑÐºÐ°Ñ Ð¿Ð¾Ñ Ð¾Ð¶Ð¸. ÐÑновнÑе оÑлиÑиÑ, коÑоÑÑе Ð½ÐµÐ¾Ð±Ñ Ð¾Ð´Ð¸Ð¼Ð¾ имеÑÑ Ð² Ð²Ð¸Ð´Ñ Ð¿Ñи поÑÑиÑовании Ñ PL/SQL в PL/pgSQL, ÑледÑÑÑие:
ÐÑли имÑ, иÑполÑзÑемое в SQL-команде, Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ ÐºÐ°Ðº именем ÑÑолбÑа ÑаблиÑÑ, ÑигÑÑиÑÑÑÑей в команде, Ñак и ÑÑÑлкой на пеÑеменнÑÑ ÑÑнкÑии, Ñо PL/SQL ÑÑиÑаеÑ, ÑÑо ÑÑо Ð¸Ð¼Ñ ÑÑолбÑа ÑаблиÑÑ. Ðднако PL/pgSQL по ÑмолÑÐ°Ð½Ð¸Ñ Ð²ÑдаÑÑ Ð¾ÑибкÑ, ÑообÑÐ°Ñ Ð¾ Ñакой неоднознаÑноÑÑи. УÑÑановив
plpgsql.variable_conflict=use_column, ÑÑо поведение можно поменÑÑÑ Ð½Ð° пÑинÑÑое в PL/SQL и опиÑанное в ÐодÑазделе 41.11.1. РпеÑвÑÑ Ð¾ÑеÑедÑ, бÑло Ð±Ñ Ð¿ÑавилÑно избегаÑÑ ÑÐ°ÐºÐ¸Ñ Ð´Ð²ÑÑмÑÑленноÑÑей, но еÑли ÑÑебÑеÑÑÑ Ð¿Ð¾ÑÑиÑоваÑÑ Ð±Ð¾Ð»ÑÑое колиÑеÑÑво кода, завиÑÑÑее Ð¾Ñ Ð´Ð°Ð½Ð½Ð¾Ð³Ð¾ поведениÑ, Ñо ÑÑÑановка пеÑеменнойvariable_conflictÐ¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð»ÑÑÑим ÑеÑением.Ð PostgreSQL Ñело ÑÑнкÑии должно бÑÑÑ Ð·Ð°Ð¿Ð¸Ñано в виде ÑÑÑоки. ÐоÑÑÐ¾Ð¼Ñ Ð½Ñжно иÑполÑзоваÑÑ Ð·Ð½Ð°Ðº доллаÑа в каÑеÑÑве кавÑÑек или ÑкÑаниÑоваÑÑ Ð¾Ð´Ð¸Ð½Ð¾ÑнÑе кавÑÑки в Ñеле ÑÑнкÑии. (См. ÐодÑаздел 41.12.1.)
Ðмена Ñипов даннÑÑ ÑаÑÑо ÑÑебÑÑÑ ÐºÐ¾ÑÑекÑиÑовки. ÐапÑимеÑ, в Oracle ÑÑÑоковÑе знаÑÐµÐ½Ð¸Ñ ÑаÑÑо обÑÑвлÑÑÑÑÑ Ñ Ñипом
varchar2, не ÑвлÑÑÑимÑÑ ÑÑандаÑÑнÑм Ñипом SQL. Ð PostgreSQL вмеÑÑо него нÑжно иÑполÑзоваÑÑvarcharилиtext. ÐодобнÑм обÑазом, ÑипnumberнÑжно заменÑÑÑ Ð½Ð°numericили дÑÑгой ÑиÑловой Ñип, еÑли найдÑÑÑÑ Ð±Ð¾Ð»ÐµÐµ Ð¿Ð¾Ð´Ñ Ð¾Ð´ÑÑий.ÐÐ»Ñ Ð³ÑÑппиÑовки ÑÑнкÑий вмеÑÑо пакеÑов иÑполÑзÑÑÑÑÑ ÑÑ ÐµÐ¼Ñ.
Так как пакеÑов неÑ, Ð½ÐµÑ Ð¸ пакеÑнÑÑ Ð¿ÐµÑеменнÑÑ . ÐÑо неÑколÑко ÑаздÑажаеÑ. ÐмеÑÑо ÑÑого можно Ñ ÑаниÑÑ ÑоÑÑоÑние каждого ÑеанÑа во вÑеменнÑÑ ÑаблиÑÐ°Ñ .
ЦелоÑиÑленнÑе ÑиклÑ
FORÑ ÑказаниемREVERSEÑабоÑаÑÑ Ð¿Ð¾-ÑазномÑ. Ð PL/SQL знаÑение ÑÑÑÑÑика ÑменÑÑаеÑÑÑ Ð¾Ñ Ð²ÑоÑого ÑиÑла к пеÑвомÑ, в Ñо вÑÐµÐ¼Ñ ÐºÐ°Ðº в PL/pgSQL ÑÑÑÑÑик ÑменÑÑаеÑÑÑ Ð¾Ñ Ð¿ÐµÑвого ко вÑоÑомÑ. ÐоÑÑÐ¾Ð¼Ñ Ð¿Ñи поÑÑиÑовании нÑжно менÑÑÑ Ð¼ÐµÑÑами гÑаниÑÑ Ñикла. ÐÑо пеÑалÑно, но вÑÑд ли бÑÐ´ÐµÑ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¾. (См. ÐодÑаздел 41.6.5.5.)ЦиклÑ
FORпо запÑоÑам (не кÑÑÑоÑам) Ñакже ÑабоÑаÑÑ Ð¿Ð¾-ÑазномÑ. ÐеÑÐµÐ¼ÐµÐ½Ð½Ð°Ñ Ñикла должна бÑÑÑ Ð¾Ð±ÑÑвлена, в Ñо вÑÐµÐ¼Ñ ÐºÐ°Ðº в PL/SQL она обÑÑвлÑеÑÑÑ Ð½ÐµÑвно. ÐÑеимÑÑеÑÑво в Ñом, ÑÑо знаÑÐµÐ½Ð¸Ñ Ð¿ÐµÑеменнÑÑ Ð´Ð¾ÑÑÑÐ¿Ð½Ñ Ð¸ поÑле вÑÑ Ð¾Ð´Ð° из Ñикла.СÑÑеÑÑвÑÑÑ Ð½ÐµÐºÐ¾ÑоÑÑе оÑлиÑÐ¸Ñ Ð² ноÑаÑии пÑи иÑполÑзовании кÑÑÑоÑнÑÑ Ð¿ÐµÑеменнÑÑ .
41.13.1. ÐÑимеÑÑ Ð¿Ð¾ÑÑиÑÐ¾Ð²Ð°Ð½Ð¸Ñ #
ÐÑимеÑ 41.9 показÑваеÑ, как поÑÑиÑоваÑÑ Ð¿ÑоÑÑÑÑ ÑÑнкÑÐ¸Ñ Ð¸Ð· PL/SQL в PL/pgSQL.
ÐÑÐ¸Ð¼ÐµÑ 41.9. ÐоÑÑиÑование пÑоÑÑой ÑÑнкÑии из PL/SQL в PL/pgSQL
ФÑнкÑÐ¸Ñ Oracle PL/SQL:
CREATE OR REPLACE FUNCTION cs_fmt_browser_version(v_name varchar2,
v_version varchar2)
RETURN varchar2 IS
BEGIN
IF v_version IS NULL THEN
RETURN v_name;
END IF;
RETURN v_name || '/' || v_version;
END;
/
show errors;ÐÑойдемÑÑ Ð¿Ð¾ ÑÑой ÑÑнкÑии и поÑмоÑÑим ÑазлиÑÐ¸Ñ Ð¿Ð¾ ÑÑÐ°Ð²Ð½ÐµÐ½Ð¸Ñ Ñ PL/pgSQL:
ÐÐ¼Ñ Ñипа
varchar2нÑжно ÑмениÑÑ Ð½Ð°varcharилиtext. РпÑимеÑÐ°Ñ Ð´Ð°Ð½Ð½Ð¾Ð³Ð¾ Ñаздела Ð¼Ñ Ð±Ñдем иÑполÑзоваÑÑvarchar, но обÑÑно лÑÑÑе вÑбÑаÑÑtext, еÑли не ÑÑебÑеÑÑÑ Ð¾Ð³ÑаниÑиваÑÑ Ð´Ð»Ð¸Ð½Ñ ÑÑÑок.ÐлÑÑевое Ñлово
RETURNв пÑоÑоÑипе ÑÑнкÑии (не в Ñеле ÑÑнкÑии) заменÑеÑÑÑ Ð½Ð°RETURNSв PostgreSQL. ÐÑоме Ñого,ISÑÑановиÑÑÑAS, и нÑжно добавиÑÑ Ð¿ÑедложениеLANGUAGE, поÑÐ¾Ð¼Ñ ÑÑо PL/pgSQL â не единÑÑвеннÑй возможнÑй ÑзÑк.Ð PostgreSQL Ñело ÑÑнкÑии ÑвлÑеÑÑÑ ÑÑÑокой, поÑÑÐ¾Ð¼Ñ Ð½Ñжно иÑполÑзоваÑÑ ÐºÐ°Ð²ÑÑки или знаки доллаÑа. ÐÑо заменÑÐµÑ Ð·Ð°Ð²ÐµÑÑаÑÑий
/в Ð¿Ð¾Ð´Ñ Ð¾Ð´Ðµ Oracle.Ðоманда
show errorsне ÑÑÑеÑÑвÑÐµÑ Ð² PostgreSQL и не ÑÑебÑеÑÑÑ, Ñак как оÑибки бÑдÑÑ Ð²ÑводиÑÑÑÑ Ð°Ð²ÑомаÑиÑеÑки.
ÐÐ¾Ñ ÐºÐ°Ðº ÑÑа ÑÑнкÑÐ¸Ñ Ð±ÑÐ´ÐµÑ Ð²ÑглÑдеÑÑ Ð¿Ð¾Ñле поÑÑиÑÐ¾Ð²Ð°Ð½Ð¸Ñ Ð² 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;ÐÑимеÑ 41.10 показÑваеÑ, как поÑÑиÑоваÑÑ ÑÑнкÑиÑ, коÑоÑÐ°Ñ ÑоздаÑÑ Ð´ÑÑгÑÑ ÑÑнкÑиÑ, и как обÑабаÑÑваÑÑ Ð¿ÑÐ¾Ð±Ð»ÐµÐ¼Ñ Ñ ÐºÐ°Ð²ÑÑками.
ÐÑÐ¸Ð¼ÐµÑ 41.10. ÐоÑÑиÑование ÑÑнкÑии, ÑоздаÑÑей дÑÑгÑÑ ÑÑнкÑиÑ, из PL/SQL в PL/pgSQL
СледÑÑÑÐ°Ñ Ð¿ÑоÑедÑÑа полÑÑÐ°ÐµÑ ÑÑÑоки из SELECT и ÑÑÑÐ¾Ð¸Ñ Ð±Ð¾Ð»ÑÑÑÑ ÑÑнкÑиÑ, в ÑелÑÑ
ÑÑÑекÑивноÑÑи возвÑаÑаÑÑÑÑ ÑезÑлÑÑÐ°Ñ Ð² опеÑаÑоÑаÑ
IF.
ÐеÑÑÐ¸Ñ 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 VARCHAR2,
v_domain IN VARCHAR2, v_url IN VARCHAR2) RETURN VARCHAR2 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 PROCEDURE cs_update_referrer_type_proc() AS $func$
DECLARE
referrer_keys CURSOR IS
SELECT * FROM cs_referrer_keys
ORDER BY try_order;
func_body text;
func_cmd text;
BEGIN
func_body := 'BEGIN';
FOR referrer_key IN referrer_keys 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 ÑодеÑÐ¶Ð°Ñ ÐºÐ°Ð²ÑÑки.
ÐÑимеÑ 41.11 показÑваеÑ, как поÑÑиÑоваÑÑ ÑÑнкÑÐ¸Ñ Ñ Ð²ÑÑ
однÑми паÑамеÑÑами (OUT) и манипÑлиÑÑÑÑÑÑ ÑÑÑоками. Ð PostgreSQL Ð½ÐµÑ Ð²ÑÑÑоенной ÑÑнкÑии instr, но ÐµÑ Ð¼Ð¾Ð¶Ð½Ð¾ ÑоздаÑÑ, иÑполÑзÑÑ ÐºÐ¾Ð¼Ð±Ð¸Ð½Ð°ÑÐ¸Ñ Ð´ÑÑгиÑ
ÑÑнкÑий. Ð ÐодÑаздел 41.13.3 пÑиведена ÑеализаÑии instr на PL/pgSQL, коÑоÑÐ°Ñ Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð¿Ð¾Ð»ÐµÐ·Ð½Ð° вам пÑи поÑÑиÑовании ваÑиÑ
ÑÑнкÑий.
ÐÑÐ¸Ð¼ÐµÑ 41.11. ÐоÑÑиÑование из PL/SQL в PL/pgSQL пÑоÑедÑÑÑ, коÑоÑÐ°Ñ Ð¼Ð°Ð½Ð¸Ð¿ÑлиÑÑÐµÑ ÑÑÑоками и ÑодеÑÐ¶Ð¸Ñ OUT паÑамеÑÑÑ
СледÑÑÑÐ°Ñ Ð¿ÑоÑедÑÑа на ÑзÑке Oracle PL/SQL ÑазбиÑÐ°ÐµÑ URL и возвÑаÑÐ°ÐµÑ ÑоÑÑавлÑÑÑие его ÑлеменÑÑ (ÑеÑвеÑ, пÑÑÑ Ð¸ запÑоÑ).
ÐеÑÑÐ¸Ñ Oracle:
CREATE OR REPLACE PROCEDURE cs_parse_url(
v_url IN VARCHAR2,
v_host OUT VARCHAR2, -- ÐозвÑаÑаеÑÑÑ ÐºÐ°Ðº ÑезÑлÑÑаÑ
v_path OUT VARCHAR2, -- Ð ÑÑо Ñоже
v_query OUT VARCHAR2) -- Ð ÑÑо
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');ÐÑимеÑ 41.12 показÑваеÑ, как поÑÑиÑоваÑÑ Ð¿ÑоÑедÑÑÑ, иÑполÑзÑÑÑÑÑ Ð±Ð¾Ð»ÑÑое колиÑеÑÑво ÑпеÑиÑиÑеÑÐºÐ¸Ñ Ð´Ð»Ñ Oracle возможноÑÑей.
ÐÑÐ¸Ð¼ÐµÑ 41.12. ÐоÑÑиÑование пÑоÑедÑÑÑ Ð¸Ð· PL/SQL в PL/pgSQL
ÐеÑÑÐ¸Ñ Oracle:
CREATE OR REPLACE PROCEDURE cs_create_job(v_job_id IN INTEGER) IS
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
COMMIT; -- оÑвободиÑÑ Ð±Ð»Ð¾ÐºÐ¸ÑовкÑ
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, now());
EXCEPTION
WHEN dup_val_on_index THEN NULL; -- ниÑего не делаÑÑ, еÑли задание Ñже еÑÑÑ
END;
COMMIT;
END;
/
show errorsÐÐ¾Ñ ÐºÐ°Ðº ÑÑÑ Ð¿ÑоÑедÑÑÑ Ð¼Ð¾Ð¶Ð½Ð¾ пеÑепиÑаÑÑ Ð½Ð° PL/pgSQL:
CREATE OR REPLACE PROCEDURE cs_create_job(v_job_id integer) 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
COMMIT; -- оÑвободиÑÑ Ð±Ð»Ð¾ÐºÐ¸ÑовкÑ
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;
COMMIT;
END;
$$ LANGUAGE plpgsql;СинÑакÑÐ¸Ñ | |
Ðмена иÑклÑÑений, поддеÑживаемÑе PL/pgSQL, оÑлиÑаÑÑÑÑ Ð¾Ñ Ð¸ÑклÑÑений в Oracle. ÐолиÑеÑÑво вÑÑÑоеннÑÑ Ð¸Ð¼Ñн иÑклÑÑений знаÑиÑелÑно болÑÑе (Ñм. ÐÑиложение A). РнаÑÑоÑÑее вÑÐµÐ¼Ñ Ð½ÐµÑ ÑпоÑоба задаÑÑ Ð¿Ð¾Ð»ÑзоваÑелÑÑкое Ð¸Ð¼Ñ Ð¸ÑклÑÑениÑ, Ñ Ð¾ÑÑ Ð²Ð¼ÐµÑÑо ÑÑого можно вÑзÑваÑÑ Ð¾ÑÐ¸Ð±ÐºÑ Ñ Ð·Ð°Ð´Ð°Ð½Ð½Ñм полÑзоваÑелем знаÑением SQLSTATE. |
41.13.2. Ðа ÑÑо еÑÑ Ð¾Ð±ÑаÑиÑÑ Ð²Ð½Ð¸Ð¼Ð°Ð½Ð¸Ðµ #
Ð ÑÑом Ñазделе ÑаÑÑмаÑÑиваÑÑÑÑ ÐµÑÑ Ð½ÐµÑколÑко веÑей, на коÑоÑÑе нÑжно обÑаÑаÑÑ Ð²Ð½Ð¸Ð¼Ð°Ð½Ð¸Ðµ пÑи поÑÑиÑовании ÑÑнкÑий из Oracle PL/SQL в PostgreSQL.
41.13.2.1. ÐеÑвнÑй оÑÐºÐ°Ñ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ð¹ поÑле Ð²Ð¾Ð·Ð½Ð¸ÐºÐ½Ð¾Ð²ÐµÐ½Ð¸Ñ Ð¸ÑклÑÑÐµÐ½Ð¸Ñ #
Ð PL/pgSQL пÑи пеÑеÑ
ваÑе иÑклÑÑÐµÐ½Ð¸Ñ Ð² ÑекÑии EXCEPTION вÑе Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð² базе даннÑÑ
Ñ Ð½Ð°Ñала блока авÑомаÑиÑеÑки оÑкаÑÑваÑÑÑÑ. Ð Oracle ÑÑо ÑквиваленÑно ÑледÑÑÑемÑ:
BEGIN
SAVEPOINT s1;
... здеÑÑ ÐºÐ¾Ð´ ...
EXCEPTION
WHEN ... THEN
ROLLBACK TO s1;
... здеÑÑ ÐºÐ¾Ð´ ...
WHEN ... THEN
ROLLBACK TO s1;
... здеÑÑ ÐºÐ¾Ð´ ...
END; ÐÑи поÑÑиÑовании пÑоÑедÑÑÑ Oracle, коÑоÑÐ°Ñ Ð¸ÑполÑзÑÐµÑ SAVEPOINT и ROLLBACK TO в Ñаком же ÑÑиле, задаÑа пÑоÑÑаÑ: доÑÑаÑоÑно ÑбÑаÑÑ Ð¾Ð¿ÐµÑаÑоÑÑ SAVEPOINT и ROLLBACK TO. ÐÑли же SAVEPOINT и ROLLBACK TO иÑполÑзÑÑÑÑÑ Ð¿Ð¾-дÑÑгомÑ, Ñо пÑидÑÑÑÑ Ð¿Ð¾Ð´ÑмаÑÑ.
41.13.2.2. EXECUTE #
PL/pgSQL веÑÑÐ¸Ñ EXECUTE ÑабоÑÐ°ÐµÑ Ð°Ð½Ð°Ð»Ð¾Ð³Ð¸Ñно веÑÑии в PL/SQL, но нÑжно помниÑÑ Ð¾Ð± иÑполÑзовании quote_literal и quote_ident, как опиÑано в ÐодÑазделе 41.5.4. Ðез иÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ ÑÑиÑ
ÑÑнкÑий конÑÑÑÑкÑии Ñипа EXECUTE 'SELECT * FROM $1'; бÑдÑÑ ÑабоÑаÑÑ Ð½ÐµÐ½Ð°Ð´Ñжно.
41.13.2.3. ÐпÑимизаÑÐ¸Ñ ÑÑнкÑий на PL/pgSQL #
ÐÐ»Ñ Ð¾Ð¿ÑимизаÑии иÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ PostgreSQL пÑедоÑÑавлÑÐµÑ Ð´Ð²Ð° модиÑикаÑоÑа пÑи Ñоздании ÑÑнкÑии: «изменÑивоÑÑÑ» (бÑÐ´ÐµÑ Ð»Ð¸ ÑÑнкÑÐ¸Ñ Ð²Ñегда возвÑаÑаÑÑ ÑÐ¾Ñ Ð¶Ðµ ÑезÑлÑÑÐ°Ñ Ð¿Ñи ÑÐµÑ Ð¶Ðµ аÑгÑменÑÐ°Ñ ) и «ÑÑÑогоÑÑÑ» (возвÑаÑÐ°ÐµÑ Ð»Ð¸ ÑÑнкÑÐ¸Ñ NULL, еÑли Ñ Ð¾ÑÑ Ð±Ñ Ð¾Ð´Ð¸Ð½ из аÑгÑменÑов NULL). ÐÐ»Ñ Ð¿Ð¾Ð»ÑÑÐµÐ½Ð¸Ñ Ð¿Ð¾Ð´Ñобной инÑоÑмаÑии обÑаÑиÑеÑÑ Ðº ÑпÑавоÑной ÑÑÑаниÑе CREATE FUNCTION.
ÐÑи иÑполÑзовании ÑÑиÑ
аÑÑибÑÑов опÑимизаÑии опеÑаÑÐ¾Ñ CREATE FUNCTION Ð¼Ð¾Ð¶ÐµÑ Ð²ÑглÑдеÑÑ Ð¿ÑимеÑно Ñак:
CREATE FUNCTION foo(...) RETURNS integer AS $$ ... $$ LANGUAGE plpgsql STRICT IMMUTABLE;
41.13.3. ÐÑиложение #
ÐÑÐ¾Ñ Ñаздел ÑодеÑÐ¶Ð¸Ñ ÐºÐ¾Ð´ Ð´Ð»Ñ ÑовмеÑÑимÑÑ
Ñ Oracle ÑÑнкÑий instr, коÑоÑÑе можно иÑполÑзоваÑÑ Ð´Ð»Ñ ÑпÑоÑÐµÐ½Ð¸Ñ Ð¿Ð¾ÑÑиÑованиÑ.
--
-- instr functions that mimic Oracle's counterpart
-- Syntax: instr(string1, string2 [, n [, m]])
-- where [] denotes optional parameters.
--
-- Search string1, beginning at the nth character, for the mth occurrence
-- of string2. If n is negative, search backwards, starting at the abs(n)'th
-- character from the end of string1.
-- If n is not passed, assume 1 (search starts at first character).
-- If m is not passed, assume 1 (find first occurrence).
-- Returns starting index of string2 in string1, or 0 if string2 is not found.
--
CREATE FUNCTION instr(varchar, varchar) RETURNS integer AS $$
BEGIN
RETURN instr($1, $2, 1);
END;
$$ LANGUAGE plpgsql STRICT IMMUTABLE;
CREATE FUNCTION instr(string varchar, string_to_search_for 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_for IN temp_str);
IF pos = 0 THEN
RETURN 0;
ELSE
RETURN pos + beg_index - 1;
END IF;
ELSIF beg_index < 0 THEN
ss_length := char_length(string_to_search_for);
length := char_length(string);
beg := length + 1 + beg_index;
WHILE beg > 0 LOOP
temp_str := substring(string FROM beg FOR ss_length);
IF string_to_search_for = temp_str THEN
RETURN beg;
END IF;
beg := beg - 1;
END LOOP;
RETURN 0;
ELSE
RETURN 0;
END IF;
END;
$$ LANGUAGE plpgsql STRICT IMMUTABLE;
CREATE FUNCTION instr(string varchar, string_to_search_for 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 occur_index <= 0 THEN
RAISE 'argument ''%'' is out of range', occur_index
USING ERRCODE = '22003';
END IF;
IF beg_index > 0 THEN
beg := beg_index - 1;
FOR i IN 1..occur_index LOOP
temp_str := substring(string FROM beg + 1);
pos := position(string_to_search_for IN temp_str);
IF pos = 0 THEN
RETURN 0;
END IF;
beg := beg + pos;
END LOOP;
RETURN beg;
ELSIF beg_index < 0 THEN
ss_length := char_length(string_to_search_for);
length := char_length(string);
beg := length + 1 + beg_index;
WHILE beg > 0 LOOP
temp_str := substring(string FROM beg FOR ss_length);
IF string_to_search_for = temp_str 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;
ELSE
RETURN 0;
END IF;
END;
$$ LANGUAGE plpgsql STRICT IMMUTABLE;