Передача аргумента в процедурный скрипт psql

У меня есть командный сценарий цикла на psql, который выглядит так:

скрипт.sql

DO $$DECLARE
    data_rec RECORD;
    r RECORD;
    r2 RECORD;
BEGIN
select mytables.data_id into data_rec from mytables where id = :arg1;

    FOR r IN select * from
    (select * from ...)
    LOOP
        FOR r2 IN select * from
        (...)
              LOOP
            ......
          END LOOP;
    END LOOP;
END$$;

И я хочу передать arg1 в качестве аргумента из командной строки:

psql -h db.server.com -f script.sql -v arg1=1234 > foo.out

Но я продолжаю получать синтаксическую ошибку в where id = :arg1, поэтому у меня нет идей, как передать простой параметр в этот скрипт. Предложения приветствуются


person diffeomorphism    schedule 06.06.2014    source источник


Ответы (1)


Есть несколько вариантов, как это сделать. Анонимный блок относительно сильно изолирован от клиентской среды, поэтому параметризация не интуитивно понятна, но это несложно.

Вы можете использовать переменные сеанса на стороне сервера. Эти переменные доступны из обеих сред.

postgres=# \set txt Ahoj
postgres=# set myvars.txt to :'txt'; -- fill server side variable
SET
postgres=# do $$ begin raise notice '%', current_setting('myvars.txt'); end;$$;
NOTICE:  Ahoj
DO

Немного более сложный пример

bash-4.1$ cat test.sh
echo "
set myvars.msgcount TO :'msgcount'; 
DO \$\$ 
BEGIN 
  FOR i IN 1..current_setting('myvars.msgcount')::int LOOP 
    RAISE NOTICE 'Hello';
  END LOOP; 
END \$\$" | psql postgres -v msgcount=$1


bash-4.1$ sh test.sh 10
SET
Time: 0.935 ms
NOTICE:  Hello
NOTICE:  Hello
NOTICE:  Hello
NOTICE:  Hello
NOTICE:  Hello
NOTICE:  Hello
NOTICE:  Hello
NOTICE:  Hello
NOTICE:  Hello
NOTICE:  Hello
DO
Time: 1.709 ms
person Pavel Stehule    schedule 06.06.2014
comment
Я понимаю вашу точку зрения (по моему удаленному ответу) - особенно в случае с телом функции оно не анализируется как выражение, в котором вы можете объединять строки, поэтому вы не можете $$ ... '$$ || :var || $$' ... $$ его. - person Craig Ringer; 06.06.2014
comment
@CraigRinger Я думаю, поэтому ваше решение возможно, но я не предпочитаю его - дизайн, основанный на переменных на стороне сервера, более чистый и автоматически защищен от SQL-инъекций. Вероятно, с классическими атаками проблем нет, но могут быть проблемы с некоторыми специфическими данными, содержащими апострофы или какие-то другие специальные символы. - person Pavel Stehule; 06.06.2014
comment
Чтобы использовать сеансовые переменные на стороне сервера (они же настраиваемые параметры) в Postgres 9.1 или более ранних версиях, необходимо установить параметр custom_variable_classes в postgresql.conf< /я>. - person klin; 06.06.2014