Советы по разработке в PL/pgSQL
Эта страница переведена при помощи нейросети GigaChat.
Один хороший способ разработки на 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 – использование графического инструмента доступа к базе данных, который облегчает разработку на процедурном языке. Одним из примеров такого инструмента является pgAdmin, хотя существуют и другие. Эти инструменты часто предоставляют удобные функции, такие как экранирование одиночных кавычек и упрощение повторного создания и отладки функций.
Обработка кавычек
Код функции PL/pgSQL указан в CREATE FUNCTION
как строковый литерал. Если пишется строка в обычном порядке со скобками, то любые одиночные кавычки внутри тела функции должны быть удвоены. Аналогично все обратные косые черты также должны быть удвоены (предполагая использование синтаксиса с экранированием в строках). Удвоение кавычек в лучшем случае утомительно, а в более сложных случаях код может стать совершенно непонятным, потому что может легко понадобиться полдюжины или больше смежных знаков кавычек. Вместо этого при создании тела функции рекомендуется использовать знаки доллара в качестве кавычек. При таком подходе никогда не потребуется дублировать кавычки, но придется позаботиться о том, чтобы иметь разные долларовые разделители для каждого уровня вложенности. Например, можно написать команду CREATE FUNCTION
следующим образом:
CREATE OR REPLACE FUNCTION testfunc(integer) RETURNS integer AS $PROC$
....
$PROC$ LANGUAGE plpgsql;
В этом контексте можно использовать кавычки для простых строковых литералов в командах SQL и $$
для ограничения фрагментов команд 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). Вероятно, это понадобится только в функции, которая генерирует другие функции, как в примере «Перенос функции, которая создает другую функцию из PL/SQL в PL/pgSQL». Например:
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
, потому что перед использованием оно будет повторно процитировано.
Дополнительные проверки времени компиляции и выполнения
Чтобы помочь пользователю обнаружить случаи простых, но распространенных проблем до того, как они нанесут вред, PL/pgSQL предоставляет дополнительные checks
. При включении, в зависимости от конфигурации, они могут использоваться для выдачи либо WARNING
или ERROR
во время компиляции функции. Функция, которая получила WARNING
, может быть выполнена без создания дополнительных сообщений, поэтому рекомендуется протестировать ее в отдельной среде разработки.
Установка plpgsql.extra_warnings
или plpgsql.extra_errors
соответственно на all
рекомендуется в средах разработки и/или тестирования.
Эти дополнительные проверки включаются через переменные конфигурации 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)