41.12. СовеÑÑ Ð¿Ð¾ ÑазÑабоÑке на PL/pgSQL #
ХоÑоÑий ÑпоÑоб ÑазÑабаÑÑваÑÑ Ð½Ð° PL/pgSQL заклÑÑаеÑÑÑ Ð² Ñом, ÑÑÐ¾Ð±Ñ Ð² одном окне Ñ ÑекÑÑовÑм ÑедакÑоÑом по вÑбоÑÑ ÑоздаваÑÑ ÑекÑÑÑ ÑÑнкÑий, а в дÑÑгом окне Ñ psql загÑÑжаÑÑ Ð¸ ÑеÑÑиÑоваÑÑ ÑÑи ÑÑнкÑии. Ð Ñаком ÑлÑÑае Ñдобно запиÑÑваÑÑ ÑÑнкÑиÑ, иÑполÑзÑÑ CREATE OR REPLACE FUNCTION. Таким обÑазом, можно легко загÑÑзиÑÑ Ñайл Ð´Ð»Ñ Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ð¾Ð¿ÑÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ ÑÑнкÑии. ÐапÑимеÑ:
CREATE OR REPLACE FUNCTION testfunc(integer) RETURNS integer AS $$
....
$$ LANGUAGE plpgsql;Ð psql, можно загÑÑзиÑÑ Ð¸Ð»Ð¸ пеÑезагÑÑзиÑÑ Ñакой Ñайл опÑÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ ÑÑнкÑии, вÑполнив:
\i filename.sql
а заÑем ÑÑÐ°Ð·Ñ Ð²ÑполнÑÑÑ ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ SQL Ð´Ð»Ñ ÑеÑÑиÑÐ¾Ð²Ð°Ð½Ð¸Ñ ÑÑнкÑии.
ÐÑÑ Ð¾Ð´Ð¸Ð½ Ñ Ð¾ÑоÑий ÑпоÑоб ÑазÑабаÑÑваÑÑ Ð½Ð° PL/pgSQL ÑвÑзан Ñ Ð¸ÑполÑзованием GUI инÑÑÑÑменÑов, облегÑаÑÑÐ¸Ñ ÑазÑабоÑÐºÑ Ð½Ð° пÑоÑедÑÑном ÑзÑке. Ðдин из пÑимеÑов Ñакого инÑÑÑÑменÑа pgAdmin, Ñ Ð¾ÑÑ ÐµÑÑÑ Ð¸ дÑÑгие. Такие инÑÑÑÑменÑÑ ÑаÑÑо пÑедоÑÑавлÑÑÑ ÑдобнÑе возможноÑÑи, Ñакие как ÑкÑаниÑование одинаÑнÑÑ ÐºÐ°Ð²ÑÑек, оÑладка и повÑоÑное Ñоздание ÑÑнкÑий.
41.12.1. ÐбÑабоÑка кавÑÑек #
Ðод ÑÑнкÑии на PL/pgSQL ÑказÑваеÑÑÑ Ð² команде CREATE FUNCTION в виде ÑÑÑоки. ÐÑли запиÑÑваÑÑ ÑÑÑÐ¾ÐºÑ ÐºÐ°Ðº обÑÑно, внÑÑÑи одинаÑнÑÑ
кавÑÑек, Ñо лÑбой Ñимвол одинаÑной кавÑÑки должен дÑблиÑоваÑÑÑÑ, Ñак же как и должен дÑблиÑоваÑÑÑÑ ÐºÐ°Ð¶Ð´Ñй знак обÑаÑной коÑой ÑеÑÑÑ (еÑли иÑполÑзÑеÑÑÑ ÑинÑакÑÐ¸Ñ Ñ ÑкÑаниÑованием в ÑÑÑокаÑ
). ÐÑблиÑование кавÑÑек в лÑÑÑем ÑлÑÑае ÑÑомиÑелÑно, а в более ÑложнÑÑ
ÑлÑÑаÑÑ
код Ð¼Ð¾Ð¶ÐµÑ ÑÑаÑÑ ÑовеÑÑенно непонÑÑнÑм, Ñак как легко Ð¼Ð¾Ð¶ÐµÑ Ð¿Ð¾ÑÑебоваÑÑÑÑ ÑеÑÑÑе или более идÑÑиÑ
подÑÑд кавÑÑек. ÐмеÑÑо ÑÑого пÑи Ñоздании Ñела ÑÑнкÑии ÑекомендÑеÑÑÑ Ð¸ÑполÑзоваÑÑ Ð·Ð½Ð°ÐºÐ¸ доллаÑа в каÑеÑÑве кавÑÑек (Ñм. ÐодÑаздел 4.1.2.4). ÐÑи Ñаком подÑ
оде никогда не поÑÑебÑеÑÑÑ Ð´ÑблиÑоваÑÑ ÐºÐ°Ð²ÑÑки, но пÑидÑÑÑÑ Ð¿Ð¾Ð·Ð°Ð±Ð¾ÑиÑÑÑÑ Ð¾ Ñом, ÑÑÐ¾Ð±Ñ Ð¸Ð¼ÐµÑÑ ÑазнÑе доллаÑовÑе ÑазделиÑели Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð³Ð¾ ÑÑÐ¾Ð²Ð½Ñ Ð²Ð»Ð¾Ð¶ÐµÐ½Ð½Ð¾ÑÑи. ÐапÑимеÑ, ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ CREATE FUNCTION можно запиÑаÑÑ Ñак:
CREATE OR REPLACE FUNCTION testfunc(integer) RETURNS integer AS $PROC$
....
$PROC$ LANGUAGE plpgsql; ÐнÑÑÑи можно иÑполÑзоваÑÑ ÐºÐ°Ð²ÑÑки Ð´Ð»Ñ Ð¿ÑоÑÑÑÑ
ÑекÑÑовÑÑ
ÑÑÑок и $$ Ð´Ð»Ñ ÑазгÑаниÑÐµÐ½Ð¸Ñ ÑÑагменÑов SQL-командÑ, ÑобиÑаемой из оÑделÑнÑÑ
ÑÑÑок. ÐÑли нÑжно взÑÑÑ Ð² кавÑÑки ÑекÑÑ, коÑоÑÑй вклÑÑÐ°ÐµÑ $$, можно иÑполÑзоваÑÑ $Q$, и Ñак далее.
СледÑÑÑÐ°Ñ ÑаблиÑа показÑваеÑ, как пÑименÑÑÑÑÑ Ð·Ð½Ð°ÐºÐ¸ кавÑÑек, еÑли не иÑполÑзÑеÑÑÑ ÑкÑаниÑование доллаÑами. ÐÑо Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð¿Ð¾Ð»ÐµÐ·Ð½Ð¾ пÑи пеÑеводе кода, не иÑполÑзÑÑÑего ÑкÑаниÑование знаками доллаÑа, в неÑÑо более понÑÑное.
- 1 кавÑÑка #
РнаÑале и конÑе Ñела ÑÑнкÑии, напÑимеÑ:
CREATE FUNCTION foo() RETURNS integer AS ' .... ' LANGUAGE plpgsql;ÐнÑÑÑи Ñакой ÑÑнкÑии лÑÐ±Ð°Ñ ÐºÐ°Ð²ÑÑка должна дÑблиÑоваÑÑÑÑ.
- 2 кавÑÑки #
ÐÐ»Ñ ÑÑÑоковÑÑ Ð»Ð¸ÑеÑалов внÑÑÑи Ñела ÑÑнкÑии, напÑимеÑ:
a_output := ''Blah''; SELECT * FROM users WHERE f_name=''foobar'';
ÐÑи иÑполÑзовании знаков доллаÑа можно пÑоÑÑо напиÑаÑÑ:
a_output := 'Blah'; SELECT * FROM users WHERE f_name='foobar';
и именно ÑÑо ÑÐ²Ð¸Ð´Ð¸Ñ Ð¸ÑполниÑÐµÐ»Ñ PL/pgSQL в Ð¾Ð±Ð¾Ð¸Ñ ÑлÑÑаÑÑ .
- 4 кавÑÑки #
Ðогда нÑÐ¶Ð½Ñ Ð¾Ð´Ð¸Ð½Ð°ÑнÑе кавÑÑки в ÑÑÑоковой конÑÑанÑе внÑÑÑи Ñела ÑÑнкÑии, напÑимеÑ:
a_output := a_output || '' AND name LIKE ''''foobar'''' AND xyz''
Ð
a_outputбÑÐ´ÐµÑ Ð´Ð¾Ð±Ð°Ð²Ð»ÐµÐ½Ð¾:AND name LIKE 'foobar' AND xyzÐÑи иÑполÑзовании знаков доллаÑа ÑÑо запиÑÑваеÑÑÑ Ñак:
a_output := a_output || $$ AND name LIKE 'foobar' AND xyz$$
бÑдÑÑе внимаÑелÑнÑ, пÑи ÑÑом не должно бÑÑÑ Ð²Ð½ÐµÑнего доллаÑового ÑазделиÑелÑ
$$.- 6 кавÑÑек #
Ðогда нÑÐ¶Ð½Ñ Ð¾Ð´Ð¸Ð½Ð°ÑнÑе кавÑÑки в ÑÑÑоковой конÑÑанÑе внÑÑÑи Ñела ÑÑнкÑии, пÑи ÑÑом кавÑÑки Ð½Ð°Ñ Ð¾Ð´ÑÑÑÑ Ð² конÑе ÑÑÑоковой конÑÑанÑÑ. ÐапÑимеÑ:
a_output := a_output || '' AND name LIKE ''''foobar''''''
Ð
a_outputбÑÐ´ÐµÑ Ð´Ð¾Ð±Ð°Ð²Ð»ÐµÐ½Ð¾:AND name LIKE 'foobar'.ÐÑи иÑполÑзовании знаков доллаÑа ÑÑо запиÑÑваеÑÑÑ Ñак:
a_output := a_output || $$ AND name LIKE 'foobar'$$
- 10 кавÑÑек #
Ðогда нÑÐ¶Ð½Ñ Ð´Ð²Ðµ одиноÑнÑе кавÑÑки в ÑÑÑоковой конÑÑанÑе (ÑÑо Ñже 8 кавÑÑек), пÑимÑкаÑÑие к конÑÑ ÑÑÑоковой конÑÑанÑÑ (еÑÑ 2). ÐеÑоÑÑно, Ñакое Ð¼Ð¾Ð¶ÐµÑ Ð¿Ð¾Ð½Ð°Ð´Ð¾Ð±Ð¸ÑÑÑÑ Ð¿Ñи ÑазÑабоÑке ÑÑнкÑии, коÑоÑÐ°Ñ Ð³ÐµÐ½ÐµÑиÑÑÐµÑ Ð´ÑÑгие ÑÑнкÑии, как показано в ÐÑимеÑе 41.10. ÐапÑимеÑ:
a_output := a_output || '' if v_'' || referrer_keys.kind || '' like '''''''''' || referrer_keys.key_string || '''''''''' then return '''''' || referrer_keys.referrer_type || ''''''; end if;'';ÐнаÑение
a_outputзаÑем бÑдеÑ:if v_... like ''...'' then return ''...''; end if;
ÐÑи иÑполÑзовании знаков доллаÑа:
a_output := a_output || $$ if v_$$ || referrer_keys.kind || $$ like '$$ || referrer_keys.key_string || $$' then return '$$ || referrer_keys.referrer_type || $$'; end if;$$;где пÑедполагаеÑÑÑ, ÑÑо нÑÐ¶Ð½Ñ ÑолÑко одиноÑнÑе кавÑÑки в
a_output, Ñак как поÑÑебÑеÑÑÑ Ð¿Ð¾Ð²ÑоÑное взÑÑие в кавÑÑки пеÑед иÑполÑзованием.
41.12.2. ÐополниÑелÑнÑе пÑовеÑки во вÑÐµÐ¼Ñ ÐºÐ¾Ð¼Ð¿Ð¸Ð»ÑÑии и во вÑÐµÐ¼Ñ Ð²ÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ #
ЧÑÐ¾Ð±Ñ Ð¿Ð¾Ð¼Ð¾ÑÑ Ð½Ð°Ð¹Ñи и пÑедÑпÑедиÑÑ Ð¿ÑоÑÑÑе, но ÑаÑÑо вÑÑÑеÑаÑÑиеÑÑ Ð¿ÑоблемÑ, PL/PgSQL пÑедоÑÑавлÑÐµÑ Ð´Ð¾Ð¿Ð¾Ð»Ð½Ð¸ÑелÑнÑе пÑовеÑки. ÐÑли они вклÑÑÐµÐ½Ñ Ð² конÑигÑÑаÑии, Ñо во вÑÐµÐ¼Ñ ÐºÐ¾Ð¼Ð¿Ð¸Ð»ÑÑии ÑÑнкÑий бÑдÑÑ Ð²ÑдаваÑÑÑÑ Ð´Ð¾Ð¿Ð¾Ð»Ð½Ð¸ÑелÑнÑе ÑообÑÐµÐ½Ð¸Ñ WARNING или оÑибки ERROR. ФÑнкÑиÑ, пÑи компилÑÑии коÑоÑой вÑдавалоÑÑ WARNING, пÑи поÑледÑÑÑем вÑполнении не бÑÐ´ÐµÑ Ð²ÑдаваÑÑ ÑÑо ÑообÑение и ÐµÑ Ð¼Ð¾Ð¶Ð½Ð¾ пÑоÑеÑÑиÑоваÑÑ Ð² оÑделÑной ÑÑеде ÑазÑабоÑки.
Ð ÑÑеде ÑазÑабоÑки и/или ÑеÑÑиÑÐ¾Ð²Ð°Ð½Ð¸Ñ Ð¸Ð¼ÐµÐµÑ ÑмÑÑл ÑÑÑановиÑÑ Ð·Ð½Ð°Ñение "all" Ð´Ð»Ñ Ð¿Ð°ÑамеÑÑа plpgsql.extra_warnings или plpgsql.extra_errors.
ÐÐ»Ñ Ð²ÐºÐ»ÑÑÐµÐ½Ð¸Ñ ÑÑиÑ
пÑовеÑок пÑедназнаÑÐµÐ½Ñ Ð¿Ð°ÑамеÑÑÑ plpgsql.extra_warnings (Ð´Ð»Ñ Ð¿ÑедÑпÑеждений) и plpgsql.extra_errors (Ð´Ð»Ñ Ð¾Ñибок). ÐÐ°Ð¶Ð´Ð¾Ð¼Ñ Ð¸Ð· паÑамеÑÑов можно пÑиÑвоиÑÑ ÑпиÑок знаÑений, ÑазделÑннÑÑ
запÑÑÑми, знаÑение "none" или "all". Ðо ÑмолÑÐ°Ð½Ð¸Ñ Ð¸ÑполÑзÑеÑÑÑ "none". РнаÑÑоÑÑий Ð¼Ð¾Ð¼ÐµÐ½Ñ Ð´Ð¾ÑÑÑÐ¿Ð½Ñ ÑледÑÑÑие дополниÑелÑнÑе пÑовеÑки:
shadowed_variables#ÐÑовеÑÑеÑ, ÑÑо обÑÑвление новой пеÑеменной не ÑкÑÑÐ²Ð°ÐµÑ Ñанее обÑÑвленнÑÑ Ð¿ÐµÑеменнÑÑ.
strict_multi_assignment#ÐекоÑоÑÑе ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ PL/pgSQL допÑÑкаÑÑ Ð¿ÑиÑваивание знаÑений ÑÑÐ°Ð·Ñ Ð½ÐµÑколÑким пеÑеменнÑм, напÑимеÑ
SELECT INTO. ÐбÑÑно колиÑеÑÑво ÑелевÑÑ Ð¿ÐµÑеменнÑÑ Ð´Ð¾Ð»Ð¶Ð½Ð¾ ÑовпадаÑÑ Ñ ÐºÐ¾Ð»Ð¸ÑеÑÑвом иÑÑ Ð¾Ð´Ð½ÑÑ , Ñ Ð¾ÑÑ PL/pgSQL бÑÐ´ÐµÑ Ð¸ÑполÑзоваÑÑNULLвмеÑÑо пÑопÑÑеннÑÑ Ð·Ð½Ð°Ñений, а дополниÑелÑнÑе пеÑеменнÑе игноÑиÑоваÑÑ. ÐÑи вклÑÑении ÑÑой пÑовеÑки PL/pgSQL бÑÐ´ÐµÑ Ð²ÑдаваÑÑ Ð¿ÑедÑпÑеждение (WARNING) или оÑÐ¸Ð±ÐºÑ (ERROR) пÑи неÑовпадении колиÑеÑÑва ÑелевÑÑ Ð¿ÐµÑеменнÑÑ Ñ ÐºÐ¾Ð»Ð¸ÑеÑÑвом иÑÑ Ð¾Ð´Ð½ÑÑ .too_many_rows#ÐÑи вклÑÑении ÑÑой пÑовеÑки PL/pgSQL бÑÐ´ÐµÑ ÐºÐ¾Ð½ÑÑолиÑоваÑÑ ÑлÑÑаи, когда запÑÐ¾Ñ Ñ Ð¿Ñедложением
INTOвозвÑаÑÐ°ÐµÑ Ð±Ð¾Ð»ÑÑе одной ÑÑÑоки. ÐÑедложениеINTOÐ¼Ð¾Ð¶ÐµÑ Ð¾Ð±ÑабоÑаÑÑ ÑолÑко Ð¾Ð´Ð½Ñ ÑÑÑокÑ, поÑÑÐ¾Ð¼Ñ Ð·Ð°Ð¿ÑоÑ, возвÑаÑаÑÑий неÑколÑко ÑÑÑок, как пÑавило оказÑваеÑÑÑ Ð½ÐµÑÑÑекÑивнÑм и/или недеÑеÑминиÑованнÑм, а ÑледоваÑелÑно, ÑкоÑее вÑего, ÑвлÑеÑÑÑ Ð¾ÑибоÑнÑм.
СледÑÑÑий пÑÐ¸Ð¼ÐµÑ Ð¿Ð¾ÐºÐ°Ð·ÑÐ²Ð°ÐµÑ ÑÑÑÐµÐºÑ Ð¿ÑиÑÐ²Ð°Ð¸Ð²Ð°Ð½Ð¸Ñ plpgsql.extra_warnings знаÑÐµÐ½Ð¸Ñ shadowed_variables:
SET plpgsql.extra_warnings TO 'shadowed_variables';
CREATE FUNCTION foo(f1 int) RETURNS int AS $$
DECLARE
f1 int;
BEGIN
RETURN f1;
END;
$$ LANGUAGE plpgsql;
WARNING: variable "f1" shadows a previously defined variable
LINE 3: f1 int;
^
CREATE FUNCTION ÐÑÐ¸Ð¼ÐµÑ Ð½Ð¸Ð¶Ðµ показÑÐ²Ð°ÐµÑ ÑÑÑÐµÐºÑ Ð¿ÑиÑÐ²Ð°Ð¸Ð²Ð°Ð½Ð¸Ñ plpgsql.extra_warnings знаÑÐµÐ½Ð¸Ñ strict_multi_assignment:
SET plpgsql.extra_warnings TO 'strict_multi_assignment'; CREATE OR REPLACE FUNCTION public.foo() RETURNS void LANGUAGE plpgsql AS $$ DECLARE x int; y int; BEGIN SELECT 1 INTO x, y; SELECT 1, 2 INTO x, y; SELECT 1, 2, 3 INTO x, y; END; $$; SELECT foo(); WARNING: number of source and target fields in assignment does not match DETAIL: strict_multi_assignment check of extra_warnings is active. HINT: Make sure the query returns the exact list of columns. WARNING: number of source and target fields in assignment does not match DETAIL: strict_multi_assignment check of extra_warnings is active. HINT: Make sure the query returns the exact list of columns. foo ----- (1 row)