Есть ли какой-нибудь синтаксис для переменной psql внутри функций PostgreSQL? - PullRequest
7 голосов
/ 16 июля 2010

Я пишу PSQL-скрипт и использую переменные (для psql --variable key = значение синтаксис командной строки).

Это прекрасно работает для области верхнего уровня, например select * from: key , но я создаю функции со сценарием, и мне нужно значение переменной внутри них.

Итак, синтаксис вроде

create function foo() returns void as
$$
declare
begin
    grant select on my_table to group :user;
end;
$$
language plpgsql;

не удается в : пользователь .

Насколько я понимаю, переменные psql - это простая функция подстановки макросов, но она не обрабатывает тела функций. Есть ли какой-нибудь синтаксис для таких случаев? Окружение : пользователь с $$ работает над заменой, но psql завершается с ошибкой на $$ .

Есть ли другой способ сделать это, кроме автономной обработки макросов (sed, awk и т. Д.)?

Ответы [ 2 ]

8 голосов
/ 16 июля 2010

PSQL SET переменные не интерполируются внутри строк в кавычках.Я не знаю этого наверняка, но я думаю, что нет никакого выхода или другой хитрости, чтобы включить там SET переменную интерполяцию.

Можно подумать, что вы могли бы втиснуть :user без кавычек между двумякавычки PL / pgSQL, чтобы получить желаемый эффект.Но, похоже, это не работает ... Я думаю, что синтаксис требует единственной строки, а не выражения, объединяющего строки.Могу ошибиться.

В любом случае, это не имеет значения.Есть другой подход (как отметил Паско): написать хранимую процедуру для принятия аргумента PL / pgSQL.Вот как это будет выглядеть.

CREATE OR REPLACE FUNCTION foo("user" TEXT) RETURNS void AS
$$
BEGIN
        EXECUTE 'GRANT SELECT ON my_table TO GROUP ' || quote_ident(user);
END;    
$$ LANGUAGE plpgsql;

Примечания к этой функции:

  1. EXECUTE генерирует соответствующий GRANT при каждом вызове, используя наш аргумент процедуры.В разделе руководства PG под названием « Выполнение динамических команд » подробно объясняется EXECUTE.
  2. Объявление аргумента процедуры user должно заключаться в двойные кавычки.Двойные кавычки заставляют его интерпретировать как идентификатор.

Как только вы определили функцию, подобную этой, вы можете вызывать ее с помощью интерполированных переменных PSQL.Вот схема.

  1. Выполнить psql --variable user="'whoever'" --file=myscript.sql.Вокруг имени пользователя требуются одинарные кавычки!
  2. В myscript.sql определите функцию, как указано выше.
  3. В myscript.sql введите select foo(:user);.Здесь мы полагаемся на те одинарные кавычки, которые мы помещаем в значение user.

Хотя это, кажется, работает, мне кажется довольно коротким.Я думал, что SET переменные предназначены для настройки во время выполнения.Перенос данных в SET кажется странным.

Редактировать : вот конкретная причина, по которой не используют SET переменные.С man-страницы: «Эти назначения выполняются на очень ранней стадии запуска, поэтому переменные, зарезервированные для внутренних целей, могут быть перезаписаны позже».Если Postgres решит использовать переменную с именем user (или что-то еще, что вы выберете), он может перезаписать ваш аргумент сценария чем-то, что вы никогда не предполагали.Фактически, psql уже берет USER для себя - это работает только потому, что SET чувствителен к регистру.Это почти сломало вещи с самого начала!

4 голосов
/ 16 июля 2010

Вы можете использовать метод, описанный Даном Ларокко, чтобы сделать его вроде бы хакерски работающим (не стучать в Дана) - но psql на самом деле не ваш друг для такой работы (если предположить, что такая работа - это скрипты и не разовые вещи). Если у вас есть функция, перепишите ее, чтобы получить параметр, подобный следующему:

create function foo(v_user text) returns void as
$$
begin
    execute 'grant select on my_table to group '||quote_ident(v_user);
end;
$$
language plpgsql;

(quote_ident () делает так, что вам не нужно проверять двойные кавычки, он обрабатывает все это.)

Но затем используйте реальный язык сценариев, такой как Perl, Python, Ruby и т. Д., Который имеет драйвер Postgres для вызова вашей функции с параметром.

Psql имеет свое место, я просто не уверен, что это оно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...