39.6. УпÑавлÑÑÑие ÑÑÑÑкÑÑÑÑ
- 39.6.1. ÐÐ¾Ð¼Ð°Ð½Ð´Ñ Ð´Ð»Ñ Ð²Ð¾Ð·Ð²ÑаÑа знаÑÐµÐ½Ð¸Ñ Ð¸Ð· ÑÑнкÑии
- 39.6.2. УÑловнÑе опеÑаÑоÑÑ
- 39.6.3. ÐÑоÑÑÑе ÑиклÑ
- 39.6.4. Цикл по ÑезÑлÑÑаÑам запÑоÑа
- 39.6.5. Цикл по ÑлеменÑам маÑÑива
- 39.6.6. ÐбÑабоÑка оÑибок
- 39.6.7. ÐолÑÑение инÑоÑмаÑии о меÑÑе вÑполнениÑ
- 39.6.2. УÑловнÑе опеÑаÑоÑÑ
УпÑавлÑÑÑие ÑÑÑÑкÑÑÑÑ, веÑоÑÑно, наиболее Ð¿Ð¾Ð»ÐµÐ·Ð½Ð°Ñ Ð¸ Ð²Ð°Ð¶Ð½Ð°Ñ ÑаÑÑÑ PL/pgSQL. С Ð¸Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ Ð¼Ð¾Ð¶Ð½Ð¾ оÑÐµÐ½Ñ Ð³Ð¸Ð±ÐºÐ¾ и ÑÑÑекÑивно манипÑлиÑоваÑÑ Ð´Ð°Ð½Ð½Ñми Postgres Pro.
39.6.1. ÐÐ¾Ð¼Ð°Ð½Ð´Ñ Ð´Ð»Ñ Ð²Ð¾Ð·Ð²ÑаÑа знаÑÐµÐ½Ð¸Ñ Ð¸Ð· ÑÑнкÑии
Ðве ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ Ð¿Ð¾Ð·Ð²Ð¾Ð»ÑÑÑ Ð²ÐµÑнÑÑÑ Ð´Ð°Ð½Ð½Ñе из ÑÑнкÑии: RETURN и RETURN NEXT.
39.6.1.1. RETURN
RETURN вÑÑажение;RETURN Ñ Ð¿Ð¾ÑледÑÑÑим вÑÑажением пÑекÑаÑÐ°ÐµÑ Ð²Ñполнение ÑÑнкÑии и возвÑаÑÐ°ÐµÑ Ð·Ð½Ð°Ñение вÑÑÐ°Ð¶ÐµÐ½Ð¸Ñ Ð² вÑзÑваÑÑÑÑ Ð¿ÑогÑаммÑ. ÐÑа ÑоÑма иÑполÑзÑеÑÑÑ Ð´Ð»Ñ ÑÑнкÑий PL/pgSQL, коÑоÑÑе не возвÑаÑаÑÑ Ð½Ð°Ð±Ð¾Ñ ÑÑÑок.
Ð ÑÑнкÑии, возвÑаÑаÑÑей ÑкалÑÑнÑй Ñип, ÑезÑлÑÑиÑÑÑÑее вÑÑажение авÑомаÑиÑеÑки пÑиводиÑÑÑ Ðº ÑÐ¸Ð¿Ñ Ð²Ð¾Ð·Ð²ÑаÑаемого знаÑениÑ. Ðднако еÑли возвÑаÑаемÑй Ñип âÑоÑÑавной (ÑÑÑока), возвÑаÑаемое вÑÑажение должно в ÑоÑноÑÑи ÑодеÑжаÑÑ ÑÑебÑемÑй Ð½Ð°Ð±Ð¾Ñ ÑÑолбÑов. ÐÑи ÑÑом Ð¼Ð¾Ð¶ÐµÑ Ð¿Ð¾ÑÑебоваÑÑÑÑ Ñвное пÑиведение Ñипов.
ÐÐ»Ñ ÑÑнкÑии Ñ Ð²ÑÑ
однÑми паÑамеÑÑами пÑоÑÑо иÑполÑзÑйÑе RETURN без вÑÑажениÑ. ÐÑдÑÑ Ð²Ð¾Ð·Ð²ÑаÑÐµÐ½Ñ ÑекÑÑие знаÑÐµÐ½Ð¸Ñ Ð²ÑÑ
однÑÑ
паÑамеÑÑов.
ÐÐ»Ñ ÑÑнкÑии, возвÑаÑаÑÑей void, RETURN можно иÑполÑзоваÑÑ Ð² лÑбом меÑÑе, но без вÑÑÐ°Ð¶ÐµÐ½Ð¸Ñ Ð¿Ð¾Ñле RETURN.
ÐозвÑаÑаемое знаÑение ÑÑнкÑии не Ð¼Ð¾Ð¶ÐµÑ Ð¾ÑÑаÑÑÑÑ Ð½Ðµ опÑеделÑннÑм. ÐÑли доÑÑигнÑÑ ÐºÐ¾Ð½ÐµÑ Ð±Ð»Ð¾ÐºÐ° веÑÑ
него ÑÑовнÑ, а опеÑаÑÐ¾Ñ RETURN Ñак и не вÑÑÑеÑилÑÑ, пÑоиÑÑ
Ð¾Ð´Ð¸Ñ Ð¾Ñибка вÑемени иÑполнениÑ. ÐÑо не каÑаеÑÑÑ ÑÑнкÑий Ñ Ð²ÑÑ
однÑми паÑамеÑÑами и ÑÑнкÑий, возвÑаÑаÑÑиÑ
void. ÐÐ»Ñ Ð½Ð¸Ñ
опеÑаÑÐ¾Ñ RETURN вÑполнÑеÑÑÑ Ð°Ð²ÑомаÑиÑеÑки по оконÑании блока веÑÑ
него ÑÑовнÑ.
ÐеÑколÑко пÑимеÑов:
-- ФÑнкÑии, возвÑаÑаÑÑие ÑкалÑÑнÑй Ñип даннÑÑ RETURN 1 + 2; RETURN scalar_var; -- ФÑнкÑии, возвÑаÑаÑÑие ÑоÑÑавной Ñип даннÑÑ RETURN composite_type_var; RETURN (1, 2, 'three'::text); -- ÑÑебÑеÑÑÑ Ð¿Ñиведение Ñипов
39.6.1.2. RETURN NEXT и RETURN QUERY
RETURN NEXTвÑÑажение; RETURN QUERYзапÑоÑ; RETURN QUERY EXECUTEÑÑÑока-командÑ[USINGвÑÑажение[, ...]];
ÐÐ»Ñ ÑÑнкÑий на PL/pgSQL, возвÑаÑаÑÑиÑ
SETOF , нÑжно дейÑÑвоваÑÑ Ð½ÐµÑколÑко по-иномÑ. ÐÑделÑнÑе ÑлеменÑÑ Ð²Ð¾Ð·Ð²ÑаÑаемого знаÑÐµÐ½Ð¸Ñ ÑоÑмиÑÑÑÑÑÑ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð°Ð¼Ð¸ некий_ÑипRETURN NEXT или RETURN QUERY, а ÑиналÑÐ½Ð°Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð° RETURN без аÑгÑменÑов завеÑÑÐ°ÐµÑ Ð²Ñполнение ÑÑнкÑии. RETURN NEXT иÑполÑзÑеÑÑÑ ÐºÐ°Ðº Ñо ÑкалÑÑнÑми, Ñак и Ñ ÑоÑÑавнÑми Ñипами даннÑÑ
. ÐÐ»Ñ ÑоÑÑавного Ñипа ÑезÑлÑÑÐ°Ñ ÑÑнкÑии возвÑаÑаеÑÑÑ Ð² виде ÑаблиÑÑ. RETURN QUERY добавлÑÐµÑ ÑезÑлÑÑÐ°Ñ Ð²ÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ð·Ð°Ð¿ÑоÑа к ÑезÑлÑÑаÑÑ ÑÑнкÑии. RETURN NEXT и RETURN QUERY можно Ñвободно ÑмеÑиваÑÑ Ð² Ñеле ÑÑнкÑии, в ÑÑом ÑлÑÑае иÑ
ÑезÑлÑÑаÑÑ Ð±ÑдÑÑ Ð¾Ð±ÑединенÑ.
RETURN NEXT и RETURN QUERY не вÑполнÑÑÑ Ð²Ð¾Ð·Ð²ÑÐ°Ñ Ð¸Ð· ÑÑнкÑии. Ðни пÑоÑÑо добавлÑÑÑ ÑÑÑоки в ÑезÑлÑÑиÑÑÑÑее множеÑÑво. ÐаÑем вÑполнение пÑодолжаеÑÑÑ Ñо ÑледÑÑÑего опеÑаÑоÑа в ÑÑнкÑии. УÑпеÑное вÑполнение RETURN NEXT и RETURN QUERY ÑоÑмиÑÑÐµÑ Ð¼Ð½Ð¾Ð¶ÐµÑÑво ÑÑÑок ÑезÑлÑÑаÑа. ÐÐ»Ñ Ð²ÑÑ
ода из ÑÑнкÑии иÑполÑзÑеÑÑÑ RETURN, обÑзаÑелÑно без аÑгÑменÑов (или можно пÑоÑÑо дождаÑÑÑÑ Ð¾ÐºÐ¾Ð½ÑÐ°Ð½Ð¸Ñ Ð²ÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ ÑÑнкÑии).
RETURN QUERY Ð¸Ð¼ÐµÐµÑ ÑазновидноÑÑÑ RETURN QUERY EXECUTE, пÑедназнаÑеннÑÑ Ð´Ð»Ñ Ð´Ð¸Ð½Ð°Ð¼Ð¸ÑеÑкого вÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ð·Ð°Ð¿ÑоÑа. Ð ÑекÑÑ Ð·Ð°Ð¿ÑоÑа можно добавиÑÑ Ð¿Ð°ÑамеÑÑÑ, иÑполÑзÑÑ USING, Ñак же как и Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð¾Ð¹ EXECUTE.
ÐÐ»Ñ ÑÑнкÑии Ñ Ð²ÑÑ
однÑми паÑамеÑÑами пÑоÑÑо иÑполÑзÑйÑе RETURN NEXT без аÑгÑменÑов. ÐÑи каждом иÑполнении RETURN NEXT ÑекÑÑие знаÑÐµÐ½Ð¸Ñ Ð²ÑÑ
однÑÑ
паÑамеÑÑов ÑоÑ
ÑанÑÑÑÑÑ Ð´Ð»Ñ Ð¿Ð¾ÑледÑÑÑего возвÑаÑа в каÑеÑÑве ÑÑÑоки ÑезÑлÑÑаÑа. ÐбÑаÑиÑе внимание, ÑÑо еÑли ÑÑнкÑÐ¸Ñ Ñ Ð²ÑÑ
однÑми паÑамеÑÑами должна возвÑаÑаÑÑ Ð¼Ð½Ð¾Ð¶ÐµÑÑво знаÑений, Ñо пÑи обÑÑвлении нÑжно ÑказÑваÑÑ RETURNS SETOF. ÐÑи ÑÑом еÑли вÑÑ
однÑÑ
паÑамеÑÑов неÑколÑко, Ñо иÑполÑзÑеÑÑÑ RETURNS SETOF record, а еÑли ÑолÑко один Ñ Ñипом некий_Ñип, Ñо RETURNS SETOF .некий_Ñип
ÐÑÐ¸Ð¼ÐµÑ Ð¸ÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ RETURN NEXT:
CREATE TABLE foo (fooid INT, foosubid INT, fooname TEXT);
INSERT INTO foo VALUES (1, 2, 'three');
INSERT INTO foo VALUES (4, 5, 'six');
CREATE OR REPLACE FUNCTION get_all_foo() RETURNS SETOF foo AS
$BODY$
DECLARE
r foo%rowtype;
BEGIN
FOR r IN
SELECT * FROM foo WHERE fooid > 0
LOOP
-- здеÑÑ Ð²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ð° обÑабоÑка даннÑÑ
RETURN NEXT r; -- возвÑаÑаеÑÑÑ ÑекÑÑÐ°Ñ ÑÑÑока запÑоÑа
END LOOP;
RETURN;
END;
$BODY$
LANGUAGE plpgsql;
SELECT * FROM get_all_foo();ÐÑÐ¸Ð¼ÐµÑ Ð¸ÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ RETURN QUERY:
CREATE FUNCTION get_available_flightid(date) RETURNS SETOF integer AS
$BODY$
BEGIN
RETURN QUERY SELECT flightid
FROM flight
WHERE flightdate >= $1
AND flightdate < ($1 + 1);
-- Так как вÑполнение еÑÑ Ð½Ðµ законÑено, можно пÑовеÑиÑÑ, бÑли ли возвÑаÑÐµÐ½Ñ ÑÑÑоки,
-- и вÑдаÑÑ Ð¸ÑклÑÑение, еÑли неÑ.
IF NOT FOUND THEN
RAISE EXCEPTION 'ÐÐµÑ ÑейÑов на даÑÑ: %.', $1;
END IF;
RETURN;
END;
$BODY$
LANGUAGE plpgsql;
-- ÐозвÑаÑÐ°ÐµÑ Ð´Ð¾ÑÑÑпнÑе ÑейÑÑ Ð»Ð¸Ð±Ð¾ вÑзÑÐ²Ð°ÐµÑ Ð¸ÑклÑÑение, еÑли ÑаковÑÑ
неÑ.
SELECT * FROM get_available_flightid(CURRENT_DATE);ÐÑимеÑание
Ð ÑекÑÑей ÑеализаÑии RETURN NEXT и RETURN QUERY ÑезÑлÑÑиÑÑÑÑее множеÑÑво накапливаеÑÑÑ Ñеликом, пÑежде Ñем бÑÐ´ÐµÑ Ð²Ð¾Ð·Ð²ÑаÑено из ÑÑнкÑии. ÐÑли множеÑÑво оÑÐµÐ½Ñ Ð±Ð¾Ð»ÑÑое, Ñо ÑÑо Ð¼Ð¾Ð¶ÐµÑ Ð¾ÑÑиÑаÑелÑно ÑказаÑÑÑÑ Ð½Ð° пÑоизводиÑелÑноÑÑи, Ñак как пÑи неÑ
ваÑке опеÑаÑивной памÑÑи даннÑе запиÑÑваÑÑÑÑ Ð½Ð° диÑк. Ð ÑледÑÑÑиÑ
веÑÑиÑÑ
PL/pgSQL ÑÑо огÑаниÑение бÑÐ´ÐµÑ ÑнÑÑо. РнаÑÑоÑÑее вÑÐµÐ¼Ñ ÑпÑавлÑÑÑ ÐºÐ¾Ð»Ð¸ÑеÑÑвом опеÑаÑивной памÑÑи в подобнÑÑ
ÑлÑÑаÑÑ
можно паÑамеÑÑом конÑигÑÑаÑии work_mem. ÐÑи налиÑии Ñвободной памÑÑи админиÑÑÑаÑоÑÑ Ð´Ð¾Ð»Ð¶Ð½Ñ ÑаÑÑмоÑÑеÑÑ Ð²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ð¾ÑÑÑ ÑвелиÑÐµÐ½Ð¸Ñ Ð·Ð½Ð°ÑÐµÐ½Ð¸Ñ Ð´Ð°Ð½Ð½Ð¾Ð³Ð¾ паÑамеÑÑа.
39.6.2. УÑловнÑе опеÑаÑоÑÑ
ÐпеÑаÑоÑÑ IF и CASE позволÑÑÑ Ð²ÑполнÑÑÑ ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ Ð² завиÑимоÑÑи Ð¾Ñ Ð¾Ð¿ÑеделÑннÑÑ
ÑÑловий. PL/pgSQL поддеÑÐ¶Ð¸Ð²Ð°ÐµÑ ÑÑи ÑоÑÐ¼Ñ IF:
IF ... THEN ... END IFIF ... THEN ... ELSE ... END IFIF ... THEN ... ELSIF ... THEN ... ELSE ... END IF
и две ÑоÑÐ¼Ñ CASE:
CASE ... WHEN ... THEN ... ELSE ... END CASECASE WHEN ... THEN ... ELSE ... END CASE
39.6.2.1. IF-THEN
IFлогиÑеÑкое-вÑÑажениеTHENопеÑаÑоÑÑEND IF;
IF-THEN ÑÑо пÑоÑÑейÑÐ°Ñ ÑоÑма IF. ÐпеÑаÑоÑÑ Ð¼ÐµÐ¶Ð´Ñ THEN и END IF вÑполнÑÑÑÑÑ, еÑли ÑÑловие (логиÑеÑкое-вÑÑажение) иÑÑинно. РпÑоÑивном ÑлÑÑае они опÑÑкаÑÑÑÑ.
ÐÑимеÑ:
IF v_user_id <> 0 THEN
UPDATE users SET email = v_email WHERE user_id = v_user_id;
END IF;39.6.2.2. IF-THEN-ELSE
IFлогиÑеÑкое-вÑÑажениеTHENопеÑаÑоÑÑELSEопеÑаÑоÑÑEND IF;
IF-THEN-ELSE добавлÑÐµÑ Ðº IF-THEN возможноÑÑÑ ÑказаÑÑ Ð°Ð»ÑÑеÑнаÑивнÑй Ð½Ð°Ð±Ð¾Ñ Ð¾Ð¿ÐµÑаÑоÑов, коÑоÑÑе бÑдÑÑ Ð²ÑполненÑ, еÑли ÑÑловие не иÑÑинно (в Ñом ÑиÑле, еÑли ÑÑловие NULL).
ÐÑимеÑÑ:
IF parentid IS NULL OR parentid = ''
THEN
RETURN fullname;
ELSE
RETURN hp_true_filename(parentid) || '/' || fullname;
END IF;IF v_count > 0 THEN
INSERT INTO users_count (count) VALUES (v_count);
RETURN 't';
ELSE
RETURN 'f';
END IF;39.6.2.3. IF-THEN-ELSIF
IFлогиÑеÑкое-вÑÑажениеTHENопеÑаÑоÑÑ[ELSIFлогиÑеÑкое-вÑÑажениеTHENопеÑаÑоÑÑ[ELSIFлогиÑеÑкое-вÑÑажениеTHENопеÑаÑоÑÑ...]] [ELSEопеÑаÑоÑÑ] END IF;
РнекоÑоÑÑÑ
ÑлÑÑаÑÑ
двÑÑ
алÑÑеÑнаÑив недоÑÑаÑоÑно. IF-THEN-ELSIF обеÑпеÑÐ¸Ð²Ð°ÐµÑ ÑдобнÑй ÑпоÑоб пÑовеÑки неÑколÑкиÑ
ваÑианÑов по оÑеÑеди. УÑÐ»Ð¾Ð²Ð¸Ñ Ð² IF поÑледоваÑелÑно пÑовеÑÑÑÑÑÑ Ð´Ð¾ ÑеÑ
поÑ, пока не бÑÐ´ÐµÑ Ð½Ð°Ð¹Ð´ÐµÐ½Ð¾ пеÑвое иÑÑинное. ÐоÑле ÑÑого опеÑаÑоÑÑ, оÑноÑÑÑиеÑÑ Ðº ÑÑÐ¾Ð¼Ñ ÑÑловиÑ, вÑполнÑÑÑÑÑ, и ÑпÑавление пеÑеÑ
Ð¾Ð´Ð¸Ñ Ðº ÑледÑÑÑей поÑле END IF команде. (ÐÑе поÑледÑÑÑие ÑÑÐ»Ð¾Ð²Ð¸Ñ Ð½Ðµ пÑовеÑÑÑÑÑÑ.) ÐÑли ни одно из ÑÑловий IF не ÑвлÑеÑÑÑ Ð¸ÑÑиннÑм, Ñо вÑполнÑеÑÑÑ Ð±Ð»Ð¾Ðº ELSE (еÑли пÑиÑÑÑÑÑвÑеÑ).
ÐÑимеÑ:
IF number = 0 THEN
result := 'zero';
ELSIF number > 0 THEN
result := 'positive';
ELSIF number < 0 THEN
result := 'negative';
ELSE
-- оÑÑаÑÑÑÑ ÑолÑко один ваÑианÑ: number Ð¸Ð¼ÐµÐµÑ Ð·Ð½Ð°Ñение NULL
result := 'NULL';
END IF;ÐмеÑÑо клÑÑевого Ñлова ELSIF можно иÑполÑзоваÑÑ ELSEIF.
ÐÑÑгой ваÑÐ¸Ð°Ð½Ñ ÑделаÑÑ Ñо же Ñамое, ÑÑо иÑполÑзование вложеннÑÑ
опеÑаÑоÑов IF-THEN-ELSE, как в ÑледÑÑÑем пÑимеÑе:
IF demo_row.sex = 'm' THEN
pretty_sex := 'man';
ELSE
IF demo_row.sex = 'f' THEN
pretty_sex := 'woman';
END IF;
END IF;Ðднако ÑÑо ÑÑебÑÐµÑ Ð½Ð°Ð¿Ð¸ÑÐ°Ð½Ð¸Ñ ÑооÑвеÑÑÑвÑÑÑиÑ
END IF Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð³Ð¾ IF, ÑÑо пÑи налиÑии неÑколÑкиÑ
алÑÑеÑнаÑив Ð´ÐµÐ»Ð°ÐµÑ ÐºÐ¾Ð´ более гÑомоздким, Ñем иÑполÑзование ELSIF.
39.6.2.4. ÐÑоÑÑой CASE
CASEвÑÑажение-поиÑкаWHENвÑÑажение[,вÑÑажение[...]] THENопеÑаÑоÑÑ[WHENвÑÑажение[,вÑÑажение[...]] THENопеÑаÑоÑÑ...] [ELSEопеÑаÑоÑÑ] END CASE;
ÐÑоÑÑÐ°Ñ ÑоÑма CASE ÑеализÑÐµÑ ÑÑловное вÑполнение на оÑнове ÑÑÐ°Ð²Ð½ÐµÐ½Ð¸Ñ Ð¾Ð¿ÐµÑандов. ÐÑÑажение-поиÑка вÑÑиÑлÑеÑÑÑ (один Ñаз) и поÑледоваÑелÑно ÑÑавниваеÑÑÑ Ñ ÐºÐ°Ð¶Ð´Ñм вÑÑажением в ÑÑловиÑÑ
WHEN. ÐÑли Ñовпадение найдено, Ñо вÑполнÑÑÑÑÑ ÑооÑвеÑÑÑвÑÑÑие опеÑаÑоÑÑ Ð¸ ÑпÑавление пеÑеÑ
Ð¾Ð´Ð¸Ñ Ðº ÑледÑÑÑей поÑле END CASE команде. (ÐÑе поÑледÑÑÑие вÑÑÐ°Ð¶ÐµÐ½Ð¸Ñ WHEN не пÑовеÑÑÑÑÑÑ.) ÐÑли Ñовпадение не бÑло найдено, Ñо вÑполнÑÑÑÑÑ Ð¾Ð¿ÐµÑаÑоÑÑ Ð² ELSE. Ðо еÑли ELSE неÑ, Ñо вÑзÑваеÑÑÑ Ð¸ÑклÑÑение CASE_NOT_FOUND.
ÐÑимеÑ:
CASE x
WHEN 1, 2 THEN
msg := 'один или два';
ELSE
msg := 'знаÑение, оÑлиÑное Ð¾Ñ Ð¾Ð´Ð¸Ð½ или два';
END CASE;39.6.2.5. CASE Ñ Ð¿ÐµÑебоÑом ÑÑловий
CASE
WHEN логиÑеÑкое-вÑÑажение THEN
опеÑаÑоÑÑ
[WHEN логиÑеÑкое-вÑÑажение THEN опеÑаÑоÑÑ ...]
[ELSE опеÑаÑоÑÑ]
END CASE;ÐÑа ÑоÑма CASE ÑеализÑÐµÑ ÑÑловное вÑполнение, оÑновÑваÑÑÑ Ð½Ð° иÑÑинноÑÑи логиÑеÑкиÑ
ÑÑловий. Ðаждое логиÑеÑкое-вÑÑажение в пÑедложении WHEN вÑÑиÑлÑеÑÑÑ Ð¿Ð¾ поÑÑÐ´ÐºÑ Ð´Ð¾ ÑеÑ
поÑ, пока не бÑÐ´ÐµÑ Ð½Ð°Ð¹Ð´ÐµÐ½Ð¾ иÑÑинное. ÐаÑем вÑполнÑÑÑÑÑ ÑооÑвеÑÑÑвÑÑÑие опеÑаÑоÑÑ Ð¸ ÑпÑавление пеÑеÑ
Ð¾Ð´Ð¸Ñ Ðº ÑледÑÑÑей поÑле END CASE команде. (ÐÑе поÑледÑÑÑие вÑÑÐ°Ð¶ÐµÐ½Ð¸Ñ WHEN не пÑовеÑÑÑÑÑÑ.) ÐÑли ни одно из ÑÑловий не окажеÑÑÑ Ð¸ÑÑиннÑм, Ñо вÑполнÑÑÑÑÑ Ð¾Ð¿ÐµÑаÑоÑÑ Ð² ELSE. Ðо еÑли ELSE неÑ, Ñо вÑзÑваеÑÑÑ Ð¸ÑклÑÑение CASE_NOT_FOUND.
ÐÑимеÑ:
CASE
WHEN x BETWEEN 0 AND 10 THEN
msg := 'знаÑение в диапазоне Ð¼ÐµÐ¶Ð´Ñ 0 и 10';
WHEN x BETWEEN 11 AND 20 THEN
msg := 'знаÑение в диапазоне Ð¼ÐµÐ¶Ð´Ñ 11 и 20';
END CASE;ÐÑа ÑоÑма CASE полноÑÑÑÑ ÑквиваленÑа IF-THEN-ELSIF, за иÑклÑÑением Ñого, ÑÑо пÑи невÑполнении вÑеÑ
ÑÑловий и оÑÑÑÑÑÑвии ELSE, IF-THEN-ELSIF ниÑего не делаеÑ, а CASE вÑзÑÐ²Ð°ÐµÑ Ð¾ÑибкÑ.
39.6.3. ÐÑоÑÑÑе ÑиклÑ
ÐпеÑаÑоÑÑ LOOP, EXIT, CONTINUE, WHILE, FOR и FOREACH позволÑÑÑ Ð¿Ð¾Ð²ÑоÑиÑÑ ÑеÑÐ¸Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´ в ÑÑнкÑии на PL/pgSQL.
39.6.3.1. LOOP
[<<меÑка>>] LOOPопеÑаÑоÑÑEND LOOP [меÑка];
LOOP оÑганизÑÐµÑ Ð±ÐµÐ·ÑÑловнÑй Ñикл, коÑоÑÑй повÑоÑÑеÑÑÑ Ð´Ð¾ беÑконеÑноÑÑи, пока не бÑÐ´ÐµÑ Ð¿ÑекÑаÑÑн опеÑаÑоÑами EXIT или RETURN. ÐÐ»Ñ Ð²Ð»Ð¾Ð¶ÐµÐ½Ð½ÑÑ
Ñиклов можно иÑполÑзоваÑÑ Ð¼ÐµÑÐºÑ Ð² опеÑаÑоÑаÑ
EXIT и CONTINUE, ÑÑÐ¾Ð±Ñ ÑказаÑÑ, к ÐºÐ°ÐºÐ¾Ð¼Ñ ÑÐ¸ÐºÐ»Ñ ÑÑи опеÑаÑоÑÑ Ð¾ÑноÑÑÑÑÑ.
39.6.3.2. EXIT
EXIT [меÑка] [WHENлогиÑеÑкое-вÑÑажение];
ÐÑли меÑка не Ñказана, Ñо завеÑÑаеÑÑÑ ÑамÑй внÑÑÑенний Ñикл, далее вÑполнÑеÑÑÑ Ð¾Ð¿ÐµÑаÑоÑ, ÑледÑÑÑий за END LOOP. ÐÑли меÑка Ñказана, Ñо она должна оÑноÑиÑÑÑÑ Ðº ÑекÑÑÐµÐ¼Ñ Ð¸Ð»Ð¸ внеÑÐ½ÐµÐ¼Ñ ÑиклÑ, или ÑÑо Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð¼ÐµÑка блока. ÐÑи ÑÑом в именованном Ñикле/блоке вÑполнение пÑекÑаÑаеÑÑÑ, а ÑпÑавление пеÑеÑ
Ð¾Ð´Ð¸Ñ Ðº ÑледÑÑÑÐµÐ¼Ñ Ð¾Ð¿ÐµÑаÑоÑÑ Ð¿Ð¾Ñле ÑооÑвеÑÑÑвÑÑÑего END.
ÐÑи налиÑии WHEN Ñикл пÑекÑаÑаеÑÑÑ, ÑолÑко еÑли логиÑеÑкое-вÑÑажение иÑÑинно. РпÑоÑивном ÑлÑÑае ÑпÑавление пеÑеÑ
Ð¾Ð´Ð¸Ñ Ðº опеÑаÑоÑÑ, ÑледÑÑÑÐµÐ¼Ñ Ð·Ð° EXIT.
EXIT можно иÑполÑзоваÑÑ Ñо вÑеми Ñипами Ñиклов, не ÑолÑко Ñ Ð±ÐµÐ·ÑÑловнÑм.
Ðогда EXIT иÑполÑзÑеÑÑÑ Ð´Ð»Ñ Ð²ÑÑ
ода из блока, ÑпÑавление пеÑеÑ
Ð¾Ð´Ð¸Ñ Ðº ÑледÑÑÑÐµÐ¼Ñ Ð¾Ð¿ÐµÑаÑоÑÑ Ð¿Ð¾Ñле оконÑÐ°Ð½Ð¸Ñ Ð±Ð»Ð¾ÐºÐ°. ÐбÑаÑиÑе внимание, ÑÑо Ð´Ð»Ñ Ð²ÑÑ
ода из блока нÑжно обÑзаÑелÑно ÑказÑваÑÑ Ð¼ÐµÑкÑ. EXIT без меÑки не позволÑÐµÑ Ð¿ÑекÑаÑиÑÑ ÑабоÑÑ Ð±Ð»Ð¾ÐºÐ°. (ÐÑо изменение по ÑÑÐ°Ð²Ð½ÐµÐ½Ð¸Ñ Ñ Ð²ÐµÑÑиÑми PostgreSQL до 8.4, в коÑоÑÑÑ
ÑазÑеÑалоÑÑ Ð¸ÑполÑзоваÑÑ EXIT без меÑки Ð´Ð»Ñ Ð¿ÑекÑаÑÐµÐ½Ð¸Ñ ÑабоÑÑ ÑекÑÑего блока.)
ÐÑимеÑÑ:
LOOP
-- здеÑÑ Ð¿ÑоизводÑÑÑÑ Ð²ÑÑиÑлениÑ
IF count > 0 THEN
EXIT; -- вÑÑ
од из Ñикла
END IF;
END LOOP;
LOOP
-- здеÑÑ Ð¿ÑоизводÑÑÑÑ Ð²ÑÑиÑлениÑ
EXIT WHEN count > 0; -- аналогиÑно пÑедÑдÑÑÐµÐ¼Ñ Ð¿ÑимеÑÑ
END LOOP;
<<ablock>>
BEGIN
-- здеÑÑ Ð¿ÑоизводÑÑÑÑ Ð²ÑÑиÑлениÑ
IF stocks > 100000 THEN
EXIT ablock; -- вÑÑ
од из блока BEGIN
END IF;
-- вÑÑиÑÐ»ÐµÐ½Ð¸Ñ Ð½Ðµ бÑдÑÑ Ð²ÑполненÑ, еÑли stocks > 100000
END;39.6.3.3. CONTINUE
CONTINUE [меÑка] [WHENлогиÑеÑкое-вÑÑажение];
ÐÑли меÑка не Ñказана, Ñо наÑинаеÑÑÑ ÑледÑÑÑÐ°Ñ Ð¸ÑеÑаÑÐ¸Ñ Ñамого внÑÑÑеннего Ñикла. То еÑÑÑ Ð²Ñе оÑÑавÑиеÑÑ Ð² Ñикле опеÑаÑоÑÑ Ð¿ÑопÑÑкаÑÑÑÑ, и ÑпÑавление пеÑеÑ
Ð¾Ð´Ð¸Ñ Ðº ÑпÑавлÑÑÑÐµÐ¼Ñ Ð²ÑÑÐ°Ð¶ÐµÐ½Ð¸Ñ Ñикла (еÑли еÑÑÑ) Ð´Ð»Ñ Ð¾Ð¿ÑеделениÑ, нÑжна ли еÑÑ Ð¾Ð´Ð½Ð° иÑеÑаÑÐ¸Ñ Ñикла. ÐÑли меÑка пÑиÑÑÑÑÑвÑеÑ, Ñо она ÑказÑÐ²Ð°ÐµÑ Ð½Ð° меÑÐºÑ Ñикла, вÑполнение коÑоÑого бÑÐ´ÐµÑ Ð¿Ñодолжено.
ÐÑи налиÑии WHEN ÑледÑÑÑÐ°Ñ Ð¸ÑеÑаÑÐ¸Ñ Ñикла наÑинаеÑÑÑ ÑолÑко Ñогда, когда логиÑеÑкое-вÑÑажение иÑÑинно. РпÑоÑивном ÑлÑÑае ÑпÑавление пеÑеÑ
Ð¾Ð´Ð¸Ñ Ðº опеÑаÑоÑÑ, ÑледÑÑÑÐµÐ¼Ñ Ð·Ð° CONTINUE.
CONTINUE можно иÑполÑзоваÑÑ Ñо вÑеми Ñипами Ñиклов, не ÑолÑко Ñ Ð±ÐµÐ·ÑÑловнÑм.
ÐÑимеÑÑ:
LOOP
-- здеÑÑ Ð¿ÑоизводÑÑÑÑ Ð²ÑÑиÑлениÑ
EXIT WHEN count > 100;
CONTINUE WHEN count < 50;
-- вÑÑиÑÐ»ÐµÐ½Ð¸Ñ Ð´Ð»Ñ count в диапазоне 50 .. 100
END LOOP;39.6.3.4. WHILE
[<<меÑка>>] WHILEлогиÑеÑкое-вÑÑажениеLOOPопеÑаÑоÑÑEND LOOP [меÑка];
WHILE вÑполнÑÐµÑ ÑеÑÐ¸Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´ до ÑеÑ
поÑ, пока иÑÑинно логиÑеÑкое-вÑÑажение. ÐÑÑажение пÑовеÑÑеÑÑÑ Ð½ÐµÐ¿Ð¾ÑÑедÑÑвенно пеÑед каждÑм вÑ
одом в Ñело Ñикла.
ÐÑимеÑ:
WHILE amount_owed > 0 AND gift_certificate_balance > 0 LOOP
-- здеÑÑ Ð¿ÑоизводÑÑÑÑ Ð²ÑÑиÑлениÑ
END LOOP;
WHILE NOT done LOOP
-- здеÑÑ Ð¿ÑоизводÑÑÑÑ Ð²ÑÑиÑлениÑ
END LOOP;39.6.3.5. FOR (ÑелоÑиÑленнÑй ваÑианÑ)
[<<меÑка>>] FORимÑIN [REVERSE]вÑÑажение..вÑÑажение[BYвÑÑажение] LOOPопеÑаÑоÑÑEND LOOP [меÑка];
Ð ÑÑой ÑоÑме Ñикла FOR иÑеÑаÑии вÑполнÑÑÑÑÑ Ð¿Ð¾ Ð´Ð¸Ð°Ð¿Ð°Ð·Ð¾Ð½Ñ ÑелÑÑ
ÑиÑел. ÐеÑÐµÐ¼ÐµÐ½Ð½Ð°Ñ Ð¸Ð¼Ñ Ð°Ð²ÑомаÑиÑеÑки опÑеделÑеÑÑÑ Ñ Ñипом integer и ÑÑÑеÑÑвÑÐµÑ ÑолÑко внÑÑÑи Ñикла (еÑли Ñже ÑÑÑеÑÑвÑÐµÑ Ð¿ÐµÑÐµÐ¼ÐµÐ½Ð½Ð°Ñ Ñ Ñаким именем, Ñо внÑÑÑи Ñикла она бÑÐ´ÐµÑ Ð¸Ð³Ð½Ð¾ÑиÑоваÑÑÑÑ). ÐÑÑÐ°Ð¶ÐµÐ½Ð¸Ñ Ð´Ð»Ñ Ð½Ð¸Ð¶Ð½ÐµÐ¹ и веÑÑ
ней гÑаниÑÑ Ð´Ð¸Ð°Ð¿Ð°Ð·Ð¾Ð½Ð° ÑиÑел вÑÑиÑлÑÑÑÑÑ Ð¾Ð´Ð¸Ð½ Ñаз пÑи вÑ
оде в Ñикл. ÐÑли не Ñказано BY, Ñо Ñаг иÑеÑаÑии 1, в пÑоÑивном ÑлÑÑае иÑполÑзÑеÑÑÑ Ð·Ð½Ð°Ñение в BY, коÑоÑое вÑÑиÑлÑеÑÑÑ, опÑÑÑ Ð¶Ðµ, один Ñаз пÑи вÑ
оде в Ñикл. ÐÑли Ñказано REVERSE, Ñо поÑле каждой иÑеÑаÑии велиÑина Ñага вÑÑиÑаеÑÑÑ, а не добавлÑеÑÑÑ.
ÐÑимеÑÑ ÑелоÑиÑленного FOR:
FOR i IN 1..10 LOOP
-- внÑÑÑи Ñикла пеÑÐµÐ¼ÐµÐ½Ð½Ð°Ñ i бÑÐ´ÐµÑ Ð¸Ð¼ÐµÑÑ Ð·Ð½Ð°ÑÐµÐ½Ð¸Ñ 1,2,3,4,5,6,7,8,9,10
END LOOP;
FOR i IN REVERSE 10..1 LOOP
-- внÑÑÑи Ñикла пеÑÐµÐ¼ÐµÐ½Ð½Ð°Ñ i бÑÐ´ÐµÑ Ð¸Ð¼ÐµÑÑ Ð·Ð½Ð°ÑÐµÐ½Ð¸Ñ 10,9,8,7,6,5,4,3,2,1
END LOOP;
FOR i IN REVERSE 10..1 BY 2 LOOP
-- внÑÑÑи Ñикла пеÑÐµÐ¼ÐµÐ½Ð½Ð°Ñ i бÑÐ´ÐµÑ Ð¸Ð¼ÐµÑÑ Ð·Ð½Ð°ÑÐµÐ½Ð¸Ñ 10,8,6,4,2
END LOOP;ÐÑли нижнÑÑ Ð³ÑаниÑа Ñикла болÑÑе веÑÑ
ней гÑаниÑÑ (или менÑÑе, в ÑлÑÑае REVERSE), Ñо Ñело Ñикла не вÑполнÑеÑÑÑ Ð²Ð¾Ð¾Ð±Ñе. ÐÑи ÑÑом оÑибка не возникаеÑ.
ÐÑли Ñ Ñиклом FOR ÑвÑзана меÑка, к ÑелоÑиÑленной пеÑеменной Ñикла можно обÑаÑаÑÑÑÑ Ð¿Ð¾ имени, ÑказÑÐ²Ð°Ñ ÑÑÑ Ð¼ÐµÑкÑ.
39.6.4. Цикл по ÑезÑлÑÑаÑам запÑоÑа
ÐÑÑгой ваÑÐ¸Ð°Ð½Ñ FOR позволÑÐµÑ Ð¾ÑганизоваÑÑ Ñикл по ÑезÑлÑÑаÑам запÑоÑа. СинÑакÑиÑ:
[ <<меÑка>> ] FORÑелÑINзапÑоÑLOOPопеÑаÑоÑÑEND LOOP [меÑка];
ÐеÑÐµÐ¼ÐµÐ½Ð½Ð°Ñ ÑÐµÐ»Ñ Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ ÑÑÑоковой пеÑеменной, пеÑеменной Ñипа record или ÑазделÑннÑм запÑÑÑми ÑпиÑком ÑкалÑÑнÑÑ
пеÑеменнÑÑ
. ÐеÑеменной ÑÐµÐ»Ñ Ð¿Ð¾ÑледоваÑелÑно пÑиÑваиваÑÑÑÑ ÑÑÑоки ÑезÑлÑÑаÑа запÑоÑа, и Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð¹ ÑÑÑоки вÑполнÑеÑÑÑ Ñело Ñикла. ÐÑимеÑ:
CREATE FUNCTION refresh_mviews() RETURNS integer AS $$
DECLARE
mviews RECORD;
BEGIN
RAISE NOTICE 'Refreshing all materialized views...';
FOR mviews IN
SELECT n.nspname AS mv_schema,
c.relname AS mv_name,
pg_catalog.pg_get_userbyid(c.relowner) AS owner
FROM pg_catalog.pg_class c
LEFT JOIN pg_catalog.pg_namespace n ON (n.oid = c.relnamespace)
WHERE c.relkind = 'm'
ORDER BY 1
LOOP
-- ÐдеÑÑ "mviews" ÑодеÑÐ¶Ð¸Ñ Ð¾Ð´Ð½Ñ Ð·Ð°Ð¿Ð¸ÑÑ Ñ Ð¸Ð½ÑоÑмаÑией о маÑпÑедÑÑавлении
RAISE NOTICE 'Refreshing materialized view %.% (owner: %)...',
quote_ident(mviews.mv_schema),
quote_ident(mviews.mv_name),
quote_ident(mviews.owner);
EXECUTE format('REFRESH MATERIALIZED VIEW %I.%I', mviews.mv_schema, mviews.mv_name);
END LOOP;
RAISE NOTICE 'Done refreshing materialized views.';
RETURN 1;
END;
$$ LANGUAGE plpgsql; ÐÑли Ñикл завеÑÑаеÑÑÑ Ð¿Ð¾ команде EXIT, Ñо поÑледнÑÑ Ð¿ÑиÑÐ²Ð¾ÐµÐ½Ð½Ð°Ñ ÑÑÑока доÑÑÑпна и поÑле Ñикла.
РкаÑеÑÑве запÑоÑа в ÑÑом Ñипе опеÑаÑоÑа FOR Ð¼Ð¾Ð¶ÐµÑ Ð·Ð°Ð´Ð°Ð²Ð°ÑÑÑÑ Ð»ÑÐ±Ð°Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð° SQL, возвÑаÑаÑÑÐ°Ñ ÑÑÑоки. ЧаÑе вÑего ÑÑо SELECT, но Ñакже можно иÑполÑзоваÑÑ Ð¸ INSERT, UPDATE или DELETE Ñ Ð¿Ñедложением RETURNING. ÐÑоме Ñого, возможно пÑименение и некоÑоÑÑÑ
ÑлÑжебнÑÑ
команд, напÑÐ¸Ð¼ÐµÑ EXPLAIN.
ÐÐ»Ñ Ð¿ÐµÑеменнÑÑ PL/pgSQL в ÑекÑÑе запÑоÑа вÑполнÑеÑÑÑ Ð¿Ð¾Ð´ÑÑановка знаÑений, план запÑоÑа кеÑиÑÑеÑÑÑ Ð´Ð»Ñ Ð²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ð¾Ð³Ð¾ повÑоÑного иÑполÑзованиÑ, как подÑобно опиÑано в ÐодÑазделе 39.10.1 и ÐодÑазделе 39.10.2.
ÐÑÑ Ð¾Ð´Ð½Ð° ÑазновидноÑÑÑ ÑÑого Ñипа Ñикла FOR-IN-EXECUTE:
[ <<меÑка>> ] FORÑелÑIN EXECUTEвÑÑажение_пÑовеÑки[ USINGвÑÑажение[, ... ] ] LOOPопеÑаÑоÑÑEND LOOP [меÑка];
Ðна поÑ
ожа на пÑедÑдÑÑÑÑ ÑоÑмÑ, за иÑклÑÑением Ñого, ÑÑо ÑекÑÑ Ð·Ð°Ð¿ÑоÑа ÑказÑваеÑÑÑ Ð² виде ÑÑÑокового вÑÑажениÑ. ТекÑÑ Ð·Ð°Ð¿ÑоÑа ÑоÑмиÑÑеÑÑÑ Ð¸ Ð´Ð»Ñ Ð½ÐµÐ³Ð¾ ÑÑÑоиÑÑÑ Ð¿Ð»Ð°Ð½ вÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ð¿Ñи каждом вÑ
оде в Ñикл. ÐÑо даÑÑ Ð¿ÑогÑаммиÑÑÑ Ð²ÑÐ±Ð¾Ñ Ð¼ÐµÐ¶Ð´Ñ ÑкоÑоÑÑÑÑ Ð¿ÑедваÑиÑелÑно ÑазобÑанного запÑоÑа и гибкоÑÑÑÑ Ð´Ð¸Ð½Ð°Ð¼Ð¸ÑеÑкого запÑоÑа, Ñак же, как и в ÑлÑÑае Ñ Ð¾Ð±ÑÑнÑм опеÑаÑоÑом EXECUTE. Ðак и в EXECUTE, знаÑÐµÐ½Ð¸Ñ Ð¿Ð°ÑамеÑÑов могÑÑ Ð±ÑÑÑ Ð´Ð¾Ð±Ð°Ð²Ð»ÐµÐ½Ñ Ð² ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ Ñ Ð¸ÑполÑзованием USING.
ÐÑÑ Ð¾Ð´Ð¸Ð½ ÑпоÑоб оÑганизоваÑÑ Ñикл по ÑезÑлÑÑаÑам запÑоÑа ÑÑо обÑÑвиÑÑ ÐºÑÑÑоÑ. ÐпиÑание в ÐодÑазделе 39.7.4.
39.6.5. Цикл по ÑлеменÑам маÑÑива
Цикл FOREACH оÑÐµÐ½Ñ Ð¿Ð¾Ñ
ож на FOR. ÐÑлиÑие в Ñом, ÑÑо вмеÑÑо пеÑебоÑа ÑÑÑок SQL-запÑоÑа пÑоиÑÑ
Ð¾Ð´Ð¸Ñ Ð¿ÐµÑÐµÐ±Ð¾Ñ ÑлеменÑов маÑÑива. (Ð Ñелом, FOREACH пÑедназнаÑен Ð´Ð»Ñ Ð¿ÐµÑебоÑа вÑÑажений ÑоÑÑавного Ñипа. ÐаÑианÑÑ ÑеализаÑии Ñикла Ð´Ð»Ñ ÑабоÑÑ Ñ Ð¿ÑоÑими ÑоÑÑавнÑми вÑÑажениÑми помимо маÑÑивов могÑÑ Ð±ÑÑÑ Ð´Ð¾Ð±Ð°Ð²Ð»ÐµÐ½Ñ Ð² бÑдÑÑем.) СинÑакÑÐ¸Ñ Ñикла FOREACH:
[ <<меÑка>> ] FOREACHÑелÑ[ SLICEÑиÑло] IN ARRAYвÑÑажениеLOOPопеÑаÑоÑÑEND LOOP [меÑка];
Ðез ÑÐºÐ°Ð·Ð°Ð½Ð¸Ñ SLICE, или еÑли SLICE Ñавен 0, Ñикл вÑполнÑеÑÑÑ Ð¿Ð¾ вÑем ÑлеменÑам маÑÑива, полÑÑенного из вÑÑажениÑ. ÐеÑеменной ÑÐµÐ»Ñ Ð¿Ð¾ÑледоваÑелÑно пÑиÑваиваеÑÑÑ ÐºÐ°Ð¶Ð´Ñй ÑÐ»ÐµÐ¼ÐµÐ½Ñ Ð¼Ð°ÑÑива и Ð´Ð»Ñ Ð½ÐµÐ³Ð¾ вÑполнÑеÑÑÑ Ñело Ñикла. ÐÑÐ¸Ð¼ÐµÑ Ñикла по ÑлеменÑам ÑелоÑиÑленного маÑÑива:
CREATE FUNCTION sum(int[]) RETURNS int8 AS $$
DECLARE
s int8 := 0;
x int;
BEGIN
FOREACH x IN ARRAY $1
LOOP
s := s + x;
END LOOP;
RETURN s;
END;
$$ LANGUAGE plpgsql; ÐбÑ
од ÑлеменÑов пÑоводиÑÑÑ Ð² Ñом поÑÑдке, в коÑоÑом они ÑоÑ
ÑанÑлиÑÑ, незавиÑимо Ð¾Ñ ÑазмеÑноÑÑи маÑÑива. Ðак пÑавило, ÑÐµÐ»Ñ ÑÑо одиноÑÐ½Ð°Ñ Ð¿ÐµÑеменнаÑ, но Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð¸ ÑпиÑком пеÑеменнÑÑ
, когда ÑлеменÑÑ Ð¼Ð°ÑÑива имеÑÑ ÑоÑÑавной Ñип (запиÑи). Ð ÑÑом ÑлÑÑае пеÑеменнÑм пÑиÑваиваÑÑÑÑ Ð·Ð½Ð°ÑÐµÐ½Ð¸Ñ Ð¸Ð· поÑледоваÑелÑнÑÑ
ÑÑолбÑов ÑоÑÑавного ÑлеменÑа маÑÑива.
ÐÑи положиÑелÑном знаÑении SLICE FOREACH вÑполнÑÐµÑ Ð¸ÑеÑаÑии по ÑÑезам маÑÑива, а не по оÑделÑнÑм ÑлеменÑам. ÐнаÑение SLICE должно бÑÑÑ ÑелÑм ÑиÑлом, не пÑевÑÑаÑÑим ÑазмеÑноÑÑи маÑÑива. ÐеÑÐµÐ¼ÐµÐ½Ð½Ð°Ñ ÑÐµÐ»Ñ Ð´Ð¾Ð»Ð¶Ð½Ð° бÑÑÑ Ð¼Ð°ÑÑивом, коÑоÑÑй полÑÑÐ°ÐµÑ Ð¿Ð¾ÑледоваÑелÑнÑе ÑÑÐµÐ·Ñ Ð¸ÑÑ
одного маÑÑива, где ÑазмеÑноÑÑÑ ÐºÐ°Ð¶Ð´Ð¾Ð³Ð¾ ÑÑеза задаÑÑÑÑ Ð·Ð½Ð°Ñением SLICE. ÐÑÐ¸Ð¼ÐµÑ Ñикла по одномеÑнÑм ÑÑезам:
CREATE FUNCTION scan_rows(int[]) RETURNS void AS $$
DECLARE
x int[];
BEGIN
FOREACH x SLICE 1 IN ARRAY $1
LOOP
RAISE NOTICE 'row = %', x;
END LOOP;
END;
$$ LANGUAGE plpgsql;
SELECT scan_rows(ARRAY[[1,2,3],[4,5,6],[7,8,9],[10,11,12]]);
NOTICE: row = {1,2,3}
NOTICE: row = {4,5,6}
NOTICE: row = {7,8,9}
NOTICE: row = {10,11,12}39.6.6. ÐбÑабоÑка оÑибок
Ðо ÑмолÑÐ°Ð½Ð¸Ñ Ð»ÑÐ±Ð°Ñ Ð²Ð¾Ð·Ð½Ð¸ÐºÐ°ÑÑÐ°Ñ Ð¾Ñибка пÑеÑÑÐ²Ð°ÐµÑ Ð²Ñполнение ÑÑнкÑии на PL/pgSQL и ÑÑанзакÑиÑ, в коÑоÑÐ°Ñ Ð¾Ð½Ð° вÑполнÑеÑÑÑ. ÐÑполÑзование в блоке ÑекÑии EXCEPTION позволÑÐµÑ Ð¿ÐµÑеÑ
ваÑÑваÑÑ Ð¸ обÑабаÑÑваÑÑ Ð¾Ñибки. СинÑакÑÐ¸Ñ ÑекÑии EXCEPTION ÑаÑÑиÑÑÐµÑ ÑинÑакÑÐ¸Ñ Ð¾Ð±ÑÑного блока:
[ <<меÑка>> ] [ DECLAREобÑÑвлениÑ] BEGINопеÑаÑоÑÑEXCEPTION WHENÑÑловие[ ORÑÑловие... ] THENопеÑаÑоÑÑ_обÑабоÑÑика[ WHENÑÑловие[ ORÑÑловие... ] THENопеÑаÑоÑÑ_обÑабоÑÑика... ] END;
ÐÑли оÑибок не бÑло, Ñо вÑполнÑÑÑÑÑ Ð²Ñе опеÑаÑоÑÑ Ð±Ð»Ð¾ÐºÐ° и ÑпÑавление пеÑеÑ
Ð¾Ð´Ð¸Ñ Ðº ÑледÑÑÑÐµÐ¼Ñ Ð¾Ð¿ÐµÑаÑоÑÑ Ð¿Ð¾Ñле END. Ðо еÑли пÑи вÑполнении опеÑаÑоÑа пÑоиÑÑ
Ð¾Ð´Ð¸Ñ Ð¾Ñибка, Ñо далÑнейÑÐ°Ñ Ð¾Ð±ÑабоÑка пÑекÑаÑаеÑÑÑ Ð¸ ÑпÑавление пеÑеÑ
Ð¾Ð´Ð¸Ñ Ðº ÑпиÑÐºÑ Ð¸ÑклÑÑений в ÑекÑии EXCEPTION. Ð ÑÑом ÑпиÑке иÑеÑÑÑ Ð¿ÐµÑвое иÑклÑÑение, ÑÑловие коÑоÑого ÑооÑвеÑÑÑвÑÐµÑ Ð¾Ñибке. ÐÑли иÑклÑÑение найдено, Ñо вÑполнÑÑÑÑÑ ÑооÑвеÑÑÑвÑÑÑие опеÑаÑоÑÑ_обÑабоÑÑика и ÑпÑавление пеÑеÑ
Ð¾Ð´Ð¸Ñ Ðº ÑледÑÑÑÐµÐ¼Ñ Ð¾Ð¿ÐµÑаÑоÑÑ Ð¿Ð¾Ñле END. ÐÑли иÑклÑÑение не найдено, Ñо оÑибка пеÑедаÑÑÑÑ Ð½Ð°ÑÑжÑ, как бÑдÑо ÑекÑии EXCEPTION не бÑло. ÐÑи ÑÑом оÑÐ¸Ð±ÐºÑ Ð¼Ð¾Ð¶Ð½Ð¾ пеÑеÑ
ваÑиÑÑ Ð² ÑекÑии EXCEPTION внеÑнего блока. ÐÑли оÑибка Ñак и не бÑла пеÑеÑ
ваÑена, Ñо обÑабоÑка ÑÑнкÑии пÑекÑаÑаеÑÑÑ.
РкаÑеÑÑве ÑÑÐ»Ð¾Ð²Ð¸Ñ Ð¼Ð¾Ð¶ÐµÑ Ð·Ð°Ð´Ð°Ð²Ð°ÑÑÑÑ Ð¾Ð´Ð½Ð¾ из имÑн, пеÑеÑиÑленнÑÑ
в ÐÑиложении A. ÐÑли задаÑÑÑÑ Ð¸Ð¼Ñ ÐºÐ°ÑегоÑии, ÐµÐ¼Ñ ÑооÑвеÑÑÑвÑÑÑ Ð²Ñе оÑибки в данной каÑегоÑии. СпеÑиалÑÐ½Ð¾Ð¼Ñ Ð¸Ð¼ÐµÐ½Ð¸ ÑÑÐ»Ð¾Ð²Ð¸Ñ OTHERS (дÑÑгие) ÑооÑвеÑÑÑвÑÑÑ Ð²Ñе ÑÐ¸Ð¿Ñ Ð¾Ñибок, кÑоме QUERY_CANCELED и ASSERT_FAILURE. (Ð ÑÑи два Ñипа оÑибок можно пеÑеÑ
ваÑиÑÑ Ð¿Ð¾ имени, но ÑаÑÑо ÑÑо неÑазÑмно.) Ðмена ÑÑловий воÑпÑинимаÑÑÑÑ Ð±ÐµÐ· ÑÑÑÑа ÑегиÑÑÑа. УÑловие оÑибки Ñакже можно задаÑÑ ÐºÐ¾Ð´Ð¾Ð¼ SQLSTATE; напÑимеÑ, ÑÑи два ваÑианÑа ÑавнознаÑнÑ:
WHEN division_by_zero THEN ... WHEN SQLSTATE '22012' THEN ...
ÐÑли пÑи вÑполнении опеÑаÑоÑов_обÑабоÑÑика Ð²Ð¾Ð·Ð½Ð¸ÐºÐ½ÐµÑ Ð½Ð¾Ð²Ð°Ñ Ð¾Ñибка, Ñо она не Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð¿ÐµÑеÑ
ваÑена в ÑÑой ÑекÑии EXCEPTION. ÐÑибка пеÑедаÑÑÑÑ Ð½Ð°ÑÑÐ¶Ñ Ð¸ ÐµÑ Ð¼Ð¾Ð¶Ð½Ð¾ пеÑеÑ
ваÑиÑÑ Ð² ÑекÑии EXCEPTION внеÑнего блока.
ÐÑи вÑполнении команд в ÑекÑии EXCEPTION локалÑнÑе пеÑеменнÑе ÑÑнкÑии на PL/pgSQL ÑоÑ
ÑанÑÑÑ Ñе знаÑениÑ, коÑоÑÑе бÑли на Ð¼Ð¾Ð¼ÐµÐ½Ñ Ð²Ð¾Ð·Ð½Ð¸ÐºÐ½Ð¾Ð²ÐµÐ½Ð¸Ñ Ð¾Ñибки. Ðднако вÑе Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð² базе даннÑÑ
, вÑполненнÑе в блоке, бÑдÑÑ Ð¾ÑмененÑ. РкаÑеÑÑве пÑимеÑа ÑаÑÑмоÑÑим ÑледÑÑÑий ÑÑагменÑ:
INSERT INTO mytab(firstname, lastname) VALUES('Tom', 'Jones');
BEGIN
UPDATE mytab SET firstname = 'Joe' WHERE lastname = 'Jones';
x := x + 1;
y := x / 0;
EXCEPTION
WHEN division_by_zero THEN
RAISE NOTICE 'пеÑеÑ
ваÑили оÑÐ¸Ð±ÐºÑ division_by_zero';
RETURN x;
END; ÐÑи пÑиÑвоении знаÑÐµÐ½Ð¸Ñ Ð¿ÐµÑеменной y пÑоизойдÑÑ Ð¾Ñибка division_by_zero. Ðна бÑÐ´ÐµÑ Ð¿ÐµÑеÑ
ваÑена в ÑекÑии EXCEPTION. ÐпеÑаÑÐ¾Ñ RETURN веÑнÑÑ Ð·Ð½Ð°Ñение x, ÑвелиÑенное на единиÑÑ, но Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ ÑделаннÑе командой UPDATE бÑдÑÑ Ð¾ÑмененÑ. ÐзменениÑ, вÑполненнÑе командой INSERT, коÑоÑÐ°Ñ Ð¿ÑедÑеÑÑвÑÐµÑ Ð±Ð»Ð¾ÐºÑ, не бÑдÑÑ Ð¾ÑмененÑ. Ð ÑезÑлÑÑаÑе, база даннÑÑ
бÑÐ´ÐµÑ ÑодеÑжаÑÑ Tom Jones, а не Joe Jones.
ÐодÑказка
ÐалиÑие ÑекÑии EXCEPTION знаÑиÑелÑно ÑвелиÑÐ¸Ð²Ð°ÐµÑ Ð½Ð°ÐºÐ»Ð°Ð´Ð½Ñе ÑаÑÑ
Ð¾Ð´Ñ Ð½Ð° вÑ
од/вÑÑ
од из блока, поÑÑÐ¾Ð¼Ñ Ð½Ðµ иÑполÑзÑйÑе EXCEPTION без надобноÑÑи.
ÐÑÐ¸Ð¼ÐµÑ 39.2. ÐбÑабоÑка иÑклÑÑений Ð´Ð»Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´ UPDATE/INSERT
Ð ÑÑом пÑимеÑе обÑабоÑка иÑклÑÑений Ð¿Ð¾Ð¼Ð¾Ð³Ð°ÐµÑ Ð²ÑполниÑÑ Ð»Ð¸Ð±Ð¾ ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ UPDATE, либо INSERT, в завиÑимоÑÑи Ð¾Ñ ÑиÑÑаÑии. Ðднако в ÑовÑеменнÑÑ
пÑиложениÑÑ
вмеÑÑо ÑÑого пÑиÑма ÑекомендÑеÑÑÑ Ð¸ÑполÑзоваÑÑ INSERT Ñ ON CONFLICT DO UPDATE. ÐаннÑй пÑÐ¸Ð¼ÐµÑ Ð¿ÑедназнаÑен в пеÑвÑÑ Ð¾ÑеÑÐµÐ´Ñ Ð´Ð»Ñ Ð´ÐµÐ¼Ð¾Ð½ÑÑÑаÑии ÑпÑÐ°Ð²Ð»ÐµÐ½Ð¸Ñ Ð²Ñполнением PL/pgSQL:
CREATE TABLE db (a INT PRIMARY KEY, b TEXT);
CREATE FUNCTION merge_db(key INT, data TEXT) RETURNS VOID AS
$$
BEGIN
LOOP
-- ÑнаÑала попÑÑаÑÑÑÑ Ð¸Ð·Ð¼ÐµÐ½Ð¸ÑÑ Ð·Ð°Ð¿Ð¸ÑÑ Ð¿Ð¾ клÑÑÑ
UPDATE db SET b = data WHERE a = key;
IF found THEN
RETURN;
END IF;
-- запиÑи Ñ Ñаким клÑÑом неÑ, поÑÑÐ¾Ð¼Ñ ÐµÑ Ð½Ñжно добавиÑÑ
-- еÑли паÑаллелÑно бÑÐ´ÐµÑ Ð²ÑÑавлена запиÑÑ Ñ Ñаким же клÑÑом,
-- пÑоизойдÑÑ Ð¾Ñибка ÑникалÑноÑÑи
BEGIN
INSERT INTO db(a,b) VALUES (key, data);
RETURN;
EXCEPTION WHEN unique_violation THEN
-- здеÑÑ Ð½Ðµ нÑжно ниÑего делаÑÑ,
-- пÑоÑÑо пÑодолжиÑÑ Ñикл, ÑÑÐ¾Ð±Ñ Ð¿Ð¾Ð²ÑоÑиÑÑ UPDATE.
END;
END LOOP;
END;
$$
LANGUAGE plpgsql;
SELECT merge_db(1, 'david');
SELECT merge_db(1, 'dennis'); Ð ÑÑом коде пÑедполагаеÑÑÑ, ÑÑо оÑибка unique_violation вÑзÑваеÑÑÑ Ñамой командой INSERT, а не, Ñкажем, внÑÑÑенним опеÑаÑоÑом INSERT в ÑÑнкÑии ÑÑиггеÑа Ð´Ð»Ñ ÑÑой ÑаблиÑÑ. ÐекоÑÑекÑное поведение Ñакже возможно, еÑли в ÑаблиÑе бÑÐ´ÐµÑ Ð½ÐµÑколÑко ÑникалÑнÑÑ
индекÑов; Ñогда опеÑаÑÐ¸Ñ Ð±ÑÐ´ÐµÑ Ð¿Ð¾Ð²ÑоÑÑÑÑÑÑ Ð²Ð½Ðµ завиÑимоÑÑи Ð¾Ñ Ñого, наÑÑÑение какого индекÑа вÑзвало оÑибкÑ. ÐÑполÑзÑÑ ÑÑедÑÑва, ÑаÑÑмоÑÑеннÑе далее, можно ÑделаÑÑ ÐºÐ¾Ð´ более надÑжнÑм, пÑовеÑÑÑ, ÑÑо пеÑеÑ
ваÑена именно Ð¾Ð¶Ð¸Ð´Ð°ÐµÐ¼Ð°Ñ Ð¾Ñибка.
39.6.6.1. ÐолÑÑение инÑоÑмаÑии об оÑибке
ÐÑи обÑабоÑке иÑклÑÑений ÑаÑÑо бÑÐ²Ð°ÐµÑ Ð½ÐµÐ¾Ð±Ñ
одимÑм полÑÑиÑÑ Ð´ÐµÑалÑнÑÑ Ð¸Ð½ÑоÑмаÑÐ¸Ñ Ð¾ пÑоизоÑедÑей оÑибке. ÐÐ»Ñ ÑÑого в PL/pgSQL еÑÑÑ Ð´Ð²Ð° ÑпоÑоба: иÑполÑзование ÑпеÑиалÑнÑÑ
пеÑеменнÑÑ
и команда GET STACKED DIAGNOSTICS.
ÐнÑÑÑи ÑекÑии EXCEPTION ÑпеÑиалÑÐ½Ð°Ñ Ð¿ÐµÑÐµÐ¼ÐµÐ½Ð½Ð°Ñ SQLSTATE ÑодеÑÐ¶Ð¸Ñ ÐºÐ¾Ð´ оÑибки, Ð´Ð»Ñ ÐºÐ¾ÑоÑой бÑло вÑзвано иÑклÑÑение (ÑпиÑок возможнÑÑ
кодов оÑибок пÑиведÑн в ТаблиÑе A.1). СпеÑиалÑÐ½Ð°Ñ Ð¿ÐµÑÐµÐ¼ÐµÐ½Ð½Ð°Ñ SQLERRM ÑодеÑÐ¶Ð¸Ñ ÑообÑение об оÑибке, ÑвÑзанное Ñ Ð¸ÑклÑÑением. ÐÑи пеÑеменнÑе ÑвлÑÑÑÑÑ Ð½ÐµÐ¾Ð¿ÑеделÑннÑми вне ÑекÑии EXCEPTION.
Также в обÑабоÑÑике иÑклÑÑÐµÐ½Ð¸Ñ Ð¼Ð¾Ð¶Ð½Ð¾ полÑÑиÑÑ Ð¸Ð½ÑоÑмаÑÐ¸Ñ Ð¾ ÑекÑÑем иÑклÑÑении командой GET STACKED DIAGNOSTICS, коÑоÑÐ°Ñ Ð¸Ð¼ÐµÐµÑ Ð²Ð¸Ð´:
GET STACKED DIAGNOSTICSпеÑеменнаÑ{ = | := }ÑлеменÑ[ , ... ];
ÐаждÑй ÑÐ»ÐµÐ¼ÐµÐ½Ñ Ð¿ÑедÑÑавлÑеÑÑÑ ÐºÐ»ÑÑевÑм Ñловом, ÑказÑваÑÑим, какое знаÑение ÑоÑÑоÑÐ½Ð¸Ñ Ð½Ñжно пÑиÑвоиÑÑ Ð·Ð°Ð´Ð°Ð½Ð½Ð¾Ð¹ пеÑеменной (она должна имеÑÑ Ð¿Ð¾Ð´Ñ
одÑÑий Ñип даннÑÑ
, ÑÑÐ¾Ð±Ñ Ð¿ÑинÑÑÑ ÐµÐ³Ð¾). ÐоÑÑÑпнÑе в наÑÑоÑÑее вÑÐµÐ¼Ñ ÑлеменÑÑ ÑоÑÑоÑÐ½Ð¸Ñ Ð¿Ð¾ÐºÐ°Ð·Ð°Ð½Ñ Ð² ТаблиÑе 39.2.
ТаблиÑа 39.2. ÐлеменÑÑ Ð´Ð¸Ð°Ð³Ð½Ð¾ÑÑики оÑибок
| ÐÐ¼Ñ | Тип | ÐпиÑание |
|---|---|---|
RETURNED_SQLSTATE | text | код иÑклÑÑениÑ, возвÑаÑаемÑй SQLSTATE |
COLUMN_NAME | text | Ð¸Ð¼Ñ ÑÑолбÑа, оÑноÑÑÑегоÑÑ Ðº иÑклÑÑÐµÐ½Ð¸Ñ |
CONSTRAINT_NAME | text | Ð¸Ð¼Ñ Ð¾Ð³ÑаниÑÐµÐ½Ð¸Ñ ÑелоÑÑноÑÑи, оÑноÑÑÑегоÑÑ Ðº иÑклÑÑÐµÐ½Ð¸Ñ |
PG_DATATYPE_NAME | text | Ð¸Ð¼Ñ Ñипа даннÑÑ , оÑноÑÑÑегоÑÑ Ðº иÑклÑÑÐµÐ½Ð¸Ñ |
MESSAGE_TEXT | text | ÑекÑÑ Ð¾Ñновного ÑообÑÐµÐ½Ð¸Ñ Ð¸ÑклÑÑÐµÐ½Ð¸Ñ |
TABLE_NAME | text | Ð¸Ð¼Ñ ÑаблиÑÑ, оÑноÑÑÑейÑÑ Ðº иÑклÑÑÐµÐ½Ð¸Ñ |
SCHEMA_NAME | text | Ð¸Ð¼Ñ ÑÑ ÐµÐ¼Ñ, оÑноÑÑÑейÑÑ Ðº иÑклÑÑÐµÐ½Ð¸Ñ |
PG_EXCEPTION_DETAIL | text | ÑекÑÑ Ð´ÐµÑалÑного ÑообÑÐµÐ½Ð¸Ñ Ð¸ÑклÑÑÐµÐ½Ð¸Ñ (еÑли еÑÑÑ) |
PG_EXCEPTION_HINT | text | ÑекÑÑ Ð¿Ð¾Ð´Ñказки к иÑклÑÑÐµÐ½Ð¸Ñ (еÑли еÑÑÑ) |
PG_EXCEPTION_CONTEXT | text | ÑÑÑоки ÑекÑÑа, опиÑÑваÑÑие ÑÑек вÑзовов в Ð¼Ð¾Ð¼ÐµÐ½Ñ Ð¸ÑклÑÑÐµÐ½Ð¸Ñ (Ñм. ÐодÑаздел 39.6.7) |
ÐÑли иÑклÑÑение не ÑÑÑÐ°Ð½Ð°Ð²Ð»Ð¸Ð²Ð°ÐµÑ Ð·Ð½Ð°Ñение Ð´Ð»Ñ Ð¸Ð´ÐµÐ½ÑиÑикаÑоÑа, Ñо возвÑаÑаеÑÑÑ Ð¿ÑÑÑÐ°Ñ ÑÑÑока.
ÐÑимеÑ:
DECLARE
text_var1 text;
text_var2 text;
text_var3 text;
BEGIN
-- здеÑÑ Ð¿ÑоиÑÑ
Ð¾Ð´Ð¸Ñ Ð¾Ð±ÑабоÑка, коÑоÑÐ°Ñ Ð¼Ð¾Ð¶ÐµÑ Ð²ÑзваÑÑ Ð¸ÑклÑÑение
...
EXCEPTION WHEN OTHERS THEN
GET STACKED DIAGNOSTICS text_var1 = MESSAGE_TEXT,
text_var2 = PG_EXCEPTION_DETAIL,
text_var3 = PG_EXCEPTION_HINT;
END;39.6.7. ÐолÑÑение инÑоÑмаÑии о меÑÑе вÑполнениÑ
Ðоманда GET DIAGNOSTICS, Ñанее опиÑÐ°Ð½Ð½Ð°Ñ Ð² ÐодÑазделе 39.5.5, полÑÑÐ°ÐµÑ Ð¸Ð½ÑоÑмаÑÐ¸Ñ Ð¾ ÑекÑÑем ÑоÑÑоÑнии вÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ ÐºÐ¾Ð´Ð° (Ñогда как команда GET STACKED DIAGNOSTICS, ÑаÑÑмоÑÑÐµÐ½Ð½Ð°Ñ Ñанее, вÑдаÑÑ Ð¸Ð½ÑоÑмаÑÐ¸Ñ Ð¾ ÑоÑÑоÑнии вÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ð² Ð¼Ð¾Ð¼ÐµÐ½Ñ Ð¿ÑедÑдÑÑей оÑибки). ÐÑ ÑÐ»ÐµÐ¼ÐµÐ½Ñ ÑоÑÑоÑÐ½Ð¸Ñ PG_CONTEXT позволÑÐµÑ Ð¾Ð¿ÑеделиÑÑ ÑекÑÑее меÑÑо вÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ ÐºÐ¾Ð´Ð°. PG_CONTEXT возвÑаÑÐ°ÐµÑ ÑекÑÑ Ñ Ð½ÐµÑколÑкими ÑÑÑоками, опиÑÑваÑÑий ÑÑек вÑзова. РпеÑвой ÑÑÑоке оÑмеÑаеÑÑÑ ÑекÑÑÐ°Ñ ÑÑнкÑÐ¸Ñ Ð¸ вÑполнÑÐµÐ¼Ð°Ñ Ð² даннÑй Ð¼Ð¾Ð¼ÐµÐ½Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð° GET DIAGNOSTICS, а во вÑоÑой и поÑледÑÑÑиÑ
ÑÑÑокаÑ
оÑмеÑаÑÑÑÑ ÑÑнкÑии вÑÑе по ÑÑÐµÐºÑ Ð²Ñзовов. ÐапÑимеÑ:
CREATE OR REPLACE FUNCTION outer_func() RETURNS integer AS $$
BEGIN
RETURN inner_func();
END;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION inner_func() RETURNS integer AS $$
DECLARE
stack text;
BEGIN
GET DIAGNOSTICS stack = PG_CONTEXT;
RAISE NOTICE E'--- СÑек вÑзова ---\n%', stack;
RETURN 1;
END;
$$ LANGUAGE plpgsql;
SELECT outer_func();
NOTICE: --- СÑек вÑзова ---
PL/pgSQL function inner_func() line 5 at GET DIAGNOSTICS
PL/pgSQL function outer_func() line 3 at RETURN
CONTEXT: PL/pgSQL function outer_func() line 3 at RETURN
outer_func
------------
1
(1 row)GET STACKED DIAGNOSTICS ... PG_EXCEPTION_CONTEXT возвÑаÑÐ°ÐµÑ Ð¿Ð¾Ñ
ожий ÑÑек вÑзовов, но опиÑÑÐ²Ð°ÐµÑ Ð½Ðµ ÑекÑÑее меÑÑо, а меÑÑо, в коÑоÑом пÑоизоÑла оÑибка.