Passer des arguments à psql

10

J'exécute un script plpgsql dans Postgres 8.3 - Je voudrais passer des arguments à ce script via psql. J'exécute actuellement le script comme:

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

Je suis tombé sur ce lien qui explique la variable d'environnement PGOPTIONS, mais qui ne fonctionne pas pour les arguments "personnalisés". c'est-à-dire que je reçois une erreur car le paramètre n'est pas répertorié dans le fichier 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"

D'autres idées? Idéalement, j'aimerais éviter les variables d'environnement ...

Jmoney38
la source
Je pense que vous recherchez l' -vargument de psql.
dezso
J'ai essayé cela - pour le récupérer dans le script, j'appelle "SELECT current_setting ('pretend') INTO _result" - sans succès.
Jmoney38

Réponses:

5

À strictement parler, il n'existe pas de "script plpgsql" - PL / pgSQL est le langage procédural par défaut de PostgreSQL. Il s'agit soit d'un script SQL, soit d'une fonction / procédure plpgsql. Votre exemple semble indiquer un script SQL.

Vous pouvez créer une fonction plpgsql (ou sql) ( côté serveur ) à la place, qui accepte un nombre illimité d'arguments. C'est très simple tant que les arguments le sont values. Cela devient un peu plus compliqué si les arguments incluent des identifiants. Ensuite, vous devrez utiliser PL / pgSQL avec SQL dynamique et EXECUTE.

PL / pgSQL est préinstallé par défaut dans PostgreSQL 9.0 ou version ultérieure. Vous devez l'installer une fois par base de données dans Postgres 8.3, cependant:

CREATE LANGUGAGE plpgsql;

En parlant de la version: vous devriez envisager de passer à une version actuelle de PostgreSQL. La v8.3 est désormais très ancienne, en fin de vie début 2013.

Puisque vous semblez avoir un script SQL prêt, je vais vous montrer une fonction SQL. Fonction factice simple avec deux arguments entiers:

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

Vous pouvez trouver de nombreux exemples plus sophistiqués pour plpgsql ici sur dba.SE ou sur SO .

Vous pouvez appeler cette fonction et remettre des paramètres dans un script shell: Exemple de base pour un appel dans un script shell qui utilise des paramètres d'entrée pour les paramètres entiers (pas de guillemets simples autour de la valeur requise):

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

Ou avec n'importe quel type de données:

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

-cexécute une chaîne de commande, puis se ferme. Plus d'informations sur les arguments en ligne de commande de psql dans le manuel .

Erwin Brandstetter
la source
Merci pour la réponse - je suis en fait tout à fait au courant de plpgsql - Ce script dont je parle est un fichier qui contient de nombreuses fonctions. J'ai une fonction "principale" dans le sens d'une programmation orientée C. Les 2 dernières lignes du script / fichier sont 1) appelant la fonction "principale" puis 2) supprimant la fonction. Donc, dans cette configuration, j'ai essentiellement un script autonome qui peut être exécuté pour faire du travail (psql -f). J'aime votre point sur l'appel d'une fonction avec les "arguments de l'application" via psql -c. Je vais probablement suivre cette voie, car je ne peux pas suivre la voie de l'ajout de valeurs au fichier postgres.conf.
Jmoney38
5

Pour ajouter une autre fonctionnalité pour -v... Si vous essayez d'ajouter la citation, ajoutez-la dans la ligne de commande:

psql -v action="'drop'"

et cela exécutera le code pour:

select * where :action;

Le même que

select * where 'drop';
cline
la source
4

Essayez -v:

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

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

Si vous souhaitez utiliser current_settinget SETou setval, vous devez ajouter une ligne à postgresql.confpour ajouter l'option.

dezso
la source
2

D'après mon expérience, la suppression d'une variable psql dans une déclaration plpgsql comme dans CREATE FUNCTION BEGIN ou DO BEGIN entraîne une erreur de syntaxe:

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

Ma solution consiste à créer une table temporaire avec une seule colonne et à y stocker la valeur. Cette table temporaire est accessible via plpgsql et je peux donc passer des variables psql utilisées avec dans des blocs 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=#

Pour utiliser des variables psql supplémentaires dans les déclarations CREATE FUNCTION ou DO, vous pouvez créer une colonne par variable requise.

Jerry Mindek
la source
0

Ce n'est pas très élégant mais ça marche (pseudocode):

cat <<EOF
   UPDATE tablename SET field=$arg1 WHERE field = $arg2;
EOF | psql database
JohnP
la source
0

Cette approche vous fournira une résolution d'exécution complète des vars env ... donc dès que votre script définit à l'avance toutes les variables de shell ci-dessous, cela fonctionnera ( a été exécuté des milliers de fois contre différents dbs et hôtes ):

    -- 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
la source