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 cela 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 ...
À proprement 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 (côté serveur) fonction plpgsql (ou sql) à la place, qui accepte un nombre illimité d'arguments. C'est très simple tant que les arguments 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 une mise à nivea vers 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 des 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)"
-c
exécute une chaîne de commande, puis se ferme. En savoir plus sur les arguments de ligne de commande de psql dans le manuel .
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';
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_setting
et SET
ou setval
, vous devez ajouter une ligne à postgresql.conf
pour ajouter l'option.
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 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.
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
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 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