Передача аргументов в psql

10

Я запускаю сценарий plpgsql в Postgres 8.3 - я хотел бы передать аргументы этому сценарию через psql. В настоящее время я выполняю скрипт как:

psql -d database -u user -f update_file.sql 

Я наткнулся на эту ссылку, которая объясняет переменную среды PGOPTIONS, но она не работает для «пользовательских» аргументов. то есть я получаю сообщение об ошибке, поскольку этот параметр не указан в файле postgres.conf.

-bash-3.2$ export PGOPTIONS='--pretend=true'
-bash-3.2$ psql -d my_db -f update_database.sql
psql: FATAL:  unrecognized configuration parameter "pretend"

Есть еще идеи? В идеале я бы хотел избежать переменных окружения ...

Jmoney38
источник
Я думаю, что вы ищете -vаргумент PSQL.
Дезсо
Я пытался это - чтобы получить его в сценарии, я вызываю "SELECT current_setting ('pretend') INTO _result" - безуспешно.
Jmoney38

Ответы:

5

Строго говоря, «сценария plpgsql» не существует - PL / pgSQL является процедурным языком по умолчанию PostgreSQL. Это либо сценарий SQL, либо функция / процедура plpgsql. Ваш пример, кажется, указывает на сценарий SQL.

Вместо этого вы можете создать (на стороне сервера) функцию plpgsql (или sql) , которая принимает любое количество аргументов. Это очень просто, пока аргументы values. Это становится немного сложнее, если аргументы включают идентификаторы. Тогда вам придется использовать PL / pgSQL с динамическим SQL и EXECUTE.

PL / pgSQL предустановлен по умолчанию в PostgreSQL 9.0 или новее. Вы должны установить его один раз для каждой базы данных в Postgres 8.3, хотя:

CREATE LANGUGAGE plpgsql;

Говоря о версии: вы должны рассмотреть возможность обновления до текущей версии PostgreSQL. v8.3 к настоящему моменту устарел, его конец жизни пришелся на начало 2013 года.

Поскольку у вас есть готовый сценарий SQL, я продемонстрирую функцию SQL. Простая фиктивная функция с двумя целочисленными аргументами:

CREATE OR REPLACE FUNCTION func(int, int)
    LANGUAGE sql RETURNS void AS 
$func$
    UPDATE tbl1 SET col1 = $1 WHERE id = $2;
    UPDATE tbl2 SET col1 = $1 WHERE id = $2;
$func$;

Вы можете найти много более сложных примеров для plpgsql здесь, на dba.SE или на SO .

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

psql mydb -c "SELECT func($1, $2)"

Или с любым типом данных:

psql mydb -c "SELECT func2('$1'::text, '$2'::numeric)"

-cвыполняет одну командную строку и затем завершается. Подробнее об аргументах командной строки psql в руководстве .

Эрвин Брандштеттер
источник
Спасибо за ответ - я на самом деле вполне осведомлен о plpgsql - этот скрипт, на который я ссылаюсь, является файлом, который содержит множество функций. У меня есть «основная» функция в смысле C-ориентированного программирования. Последние 2 строки в скрипте / файле: 1) вызов "основной" функции и затем 2) удаление функции. Итак, в этой настройке у меня по сути есть автономный скрипт, который можно запустить для выполнения работы (psql -f). Мне нравится ваша точка зрения о вызове функции с "аргументами приложения" через psql -c. Я, вероятно, пойду по этому пути, потому что я не могу пойти по пути добавления значений в файл postgres.conf.
Jmoney38
5

Чтобы добавить еще одну функциональность для -v... Если вы пытаетесь добавить цитату, добавьте ее в командной строке:

psql -v action="'drop'"

и это запустит код для:

select * where :action;

Такой же как

select * where 'drop';
Cline
источник
4

Попробуй -v:

$ psql -U postgres -v something=\'blah-blah\'
psql (9.1.3)
Type "help" for help.

postgres=# select :something;
 ?column?
----------
 blah-blah
(1 row)

Если вы хотите использовать current_settingи SETили setval, вам нужно добавить строку, postgresql.confчтобы добавить опцию.

Dezso
источник
2

Исходя из моего опыта, разыменование переменной psql внутри объявления plpgsql, такого как CREATE FUNCTION BEGIN или DO BEGIN, приводит к синтаксической ошибке:

/tmp $ psql -U jmindek -v action=drop
psql (9.3.4)
Type "help" for help.

jmindek=# select :'action';
 ?column? 
----------
 drop
(1 row)

jmindek=# DO $$ BEGIN RAISE INFO 'The value in variable action is (%)',:x; END $$;     
ERROR:  syntax error at or near ":"
LINE 1: ... RAISE INFO 'The value in variable action is (%)',:x; END $$...

Мое решение - создать временную таблицу с одним столбцом и сохранить в ней значение. Эта временная таблица доступна через plpgsql, и поэтому я могу передавать переменные psql, используемые в блоках DO.

 ~ $ psql -v action=drop
psql (9.3.4)
Type "help" for help.

jmindek=# create temporary table actions (type text);                                                             CREATE TABLE
jmindek=# insert into actions values (:'action');                                                                 INSERT 0 1
jmindek=# do $$                                                                                                   declare                                                                                                            action_type text := null;                                                                                        begin                                                                                                               select type from actions into action_type;                                                                        raise info 'Hello, the action is (%)',action_type;                                                              end $$;
INFO:  Hello, the action is (drop)
DO
jmindek=#

Чтобы использовать дополнительные переменные psql в объявлениях CREATE FUNCTION или DO, вы можете создать столбец для каждой необходимой переменной.

Джерри Миндек
источник
0

Это не очень элегантно, но работает (псевдокод):

cat <<EOF
   UPDATE tablename SET field=$arg1 WHERE field = $arg2;
EOF | psql database
JohnP
источник
0

Этот подход обеспечит вам полное разрешение env vars во время выполнения ... так что, как только ваш скрипт установит все переменные оболочки ниже, он сработает ( был запущен тысячи раз для разных dbs и хостов ):

    -- start run.sh

       # 01 create / modify the app user
       sql_script="$pgsql_scripts_dir/01.create-qto-app-user.pgsql"
       PGPASSWORD="${postgres_db_useradmin_pw:-}" psql -q -t -X -w -U "${postgres_db_useradmin:-}" \
          -h $postgres_db_host -p $postgres_db_port \
          -v ON_ERROR_STOP=1 \
          -v postgres_db_user_pw="${postgres_db_user_pw:-}" \
          -v postgres_db_name="${postgres_db_name:-}" \
          -f "$sql_script" "${postgres_db_name:-}" > "$tmp_log_file" 2>&1
       ret=$?
       cat "$tmp_log_file" ; cat "$tmp_log_file" >> $log_file # show it and save it
       test $ret -ne 0 && sleep 3
       test $ret -ne 0 && doExit 1 "pid: $$ psql ret $ret - failed to run sql_script: $sql_script !!!"
    -- stop run.sh

    -- start fun.sql
            DO
            $do$
            BEGIN
               IF NOT EXISTS (
                  SELECT
                  FROM   pg_catalog.pg_roles
                  WHERE  rolname = 'usrqtoapp') THEN
                     CREATE ROLE usrqtoapp WITH PASSWORD ':postgres_db_user_pw' LOGIN ;
               END IF;
            END
            $do$;
            ALTER ROLE usrqtoapp WITH PASSWORD  :'postgres_db_user_pw' LOGIN ;

    -- eof run.sql
Йордан Георгиев
источник