Przekazywanie argumentów do psql

10

Używam skryptu plpgsql w Postgresie 8.3 - chciałbym przekazać argumenty do tego skryptu poprzez psql. Obecnie wykonuję skrypt w następujący sposób:

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

Natknąłem się na ten link, który wyjaśnia zmienną środowiskową PGOPTIONS, ale to nie działa dla „niestandardowych” argumentów. tzn. pojawia się błąd, ponieważ ustawienia nie ma na liście w pliku 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"

Jakieś inne pomysły? Idealnie chciałbym uniknąć zmiennych środowiskowych ...

Jmoney38
źródło
Myślę, że szukasz -vargumentu psql.
dezso
Próbowałem tego - aby pobrać go ze skryptu, nazywam „SELECT current_setting ('udawaj') INTO _result” - bez powodzenia.
Jmoney38

Odpowiedzi:

5

Ściśle mówiąc, nie ma czegoś takiego jak „skrypt plpgsql” - PL / pgSQL jest domyślnym językiem proceduralnym PostgreSQL. Jest to albo skrypt SQL, albo funkcja / procedura plpgsql. Twój przykład wskazuje na skrypt SQL.

Zamiast tego możesz utworzyć funkcję plpgsql (lub sql) (po stronie serwera ) , która przyjmuje dowolną liczbę argumentów. To bardzo proste, o ile argumenty są values. To staje się nieco bardziej skomplikowane, jeśli argumenty zawierają identyfikatory. Następnie będziesz musiał używać PL / pgSQL z dynamicznym SQL i EXECUTE.

PL / pgSQL jest domyślnie wstępnie zainstalowany w PostgreSQL 9.0 lub nowszym. Musisz zainstalować go raz na bazę danych w Postgres 8.3, jednak:

CREATE LANGUGAGE plpgsql;

Mówiąc o wersji: powinieneś rozważyć aktualizację do aktualnej wersji PostgreSQL. Wersja 8.3 jest już bardzo stara, wycofana z życia na początku 2013 roku.

Ponieważ wydaje się, że masz gotowy skrypt SQL, przedstawię funkcję SQL. Prosta funkcja fikcyjna z dwoma argumentami liczb całkowitych:

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$;

Możesz znaleźć wiele bardziej wyrafinowanych przykładów dla pliku plpgsql tutaj na dba.SE lub na SO .

Możesz wywołać tę funkcję i przekazać parametry w skrypcie powłoki: Podstawowy przykład wywołania w skrypcie powłoki, który używa parametrów wejściowych dla parametrów liczb całkowitych (nie są potrzebne pojedyncze cudzysłowy wokół wartości):

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

Lub z dowolnym typem danych:

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

-cwykonuje jeden ciąg polecenia, a następnie kończy działanie. Więcej informacji o argumentach psql w wierszu poleceń w podręczniku .

Erwin Brandstetter
źródło
Dzięki za odpowiedź - właściwie jestem całkiem świadomy plpgsql - Ten skrypt, o którym mówię, jest plikiem zawierającym wiele funkcji. Mam funkcję „główną” w sensie programowania zorientowanego na język C. Ostatnie 2 wiersze w skrypcie / pliku to 1) wywołanie funkcji „głównej”, a następnie 2) upuszczenie funkcji. Tak więc w tej konfiguracji mam w zasadzie samodzielny skrypt, który można uruchomić w celu wykonania pracy (psql -f). Podoba mi się twoja uwaga na temat wywoływania funkcji za pomocą „argumentów aplikacji” za pomocą psql -c. Prawdopodobnie pójdę tą drogą, ponieważ nie mogę iść drogą dodawania wartości do pliku postgres.conf.
Jmoney38,
5

Aby dodać kolejną funkcjonalność dla -v... Jeśli próbujesz dodać cytat, dodaj go w wierszu polecenia:

psql -v action="'drop'"

i to uruchomi kod dla:

select * where :action;

Taki sam jak

select * where 'drop';
Cline
źródło
4

Spróbuj -v:

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

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

Jeśli chcesz użyć current_settingi SETlub setval, musisz dodać wiersz, postgresql.confaby dodać opcję.

dezso
źródło
2

Z mojego doświadczenia, wyrejestrowanie zmiennej psql w deklaracji plpgsql, takiej jak w CREATE FUNCTION BEGIN lub DO BEGIN, powoduje błąd składniowy:

/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 $$...

Moim rozwiązaniem jest utworzenie tabeli tymczasowej z jedną kolumną i zapisanie w niej wartości. Ta tabela tymczasowa jest dostępna przez plpgsql, a zatem mogę przekazać zmienne psql używane w blokach 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=#

Aby użyć dodatkowych zmiennych psql w deklaracjach CREATE FUNCTION lub DO, możesz utworzyć kolumnę dla potrzebnej zmiennej.

Jerry Mindek
źródło
0

Nie jest to zbyt eleganckie, ale działa (pseudokod):

cat <<EOF
   UPDATE tablename SET field=$arg1 WHERE field = $arg2;
EOF | psql database
JohnP
źródło
0

Takie podejście zapewni pełną rozdzielczość w czasie wykonywania zmiennych env ... tak więc, jak tylko skrypt ustawi wcześniej wszystkie zmienne powłoki poniżej, zadziała ( został uruchomiony tysiące razy na różnych dbs i hostach ):

    -- 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
Yordan Georgiev
źródło