Používám skript plpgsql v Postgresu 8.3 - Chtěl bych do tohoto skriptu předat argumenty pomocí psql. Momentálně spouštím skript jako:
psql -d database -u user -f update_file.sql
Narazil jsem na Tento odkaz , který vysvětluje proměnnou prostředí PGOPTIONS, ale to nefunguje pro "vlastní" argumenty. tj. zobrazí se chyba, protože nastavení není uvedeno v souboru 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"
Máte nějaké další nápady? V ideálním případě bych se chtěl vyhnout proměnným prostředí ...
Přísně vzato neexistuje nic jako „skript plpgsql“ - PL/pgSQL je výchozí procedurální jazyk PostgreSQL. Je to buď skript SQL nebo plpgsql funkce/procedura. Zdá se, že váš příklad naznačuje skript SQL.
Místo toho můžete vytvořit funkci plpgsql (nebo sql) na straně serveru, která vezme libovolný počet argumentů. Je to velmi jednoduché, pokud jsou argumenty values
. Pokud argumenty obsahují identifikátory, je to trochu složitější. Pak budete muset použít PL/pgSQL s dynamickým SQL a EXECUTE
.
PL/pgSQL je standardně předinstalován v PostgreSQL 9.0 nebo novější. Musíte ji nainstalovat jednou pro každou databázi v Postgres 8.3, i když:
CREATE LANGUGAGE plpgsql;
Když už mluvíme o verzi: měli byste zvažte upgrade na současnou verzi PostgreSQL. v8.3 je nyní velmi starý, konec životnosti na začátku roku 2013.
Protože se zdá, že máte připravený skript SQL, ukážu funkci SQL. Jednoduchá fiktivní funkce se dvěma celočíselnými argumenty:
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$;
Najdete mnoho sofistikovanějších příkladů pro plpgsql zde na dba.SE nebo na SO .
Tuto funkci můžete zavolat a předat parametry ve skriptu Shell: Základní příklad volání ve skriptu Shell, který používá vstupní parametry pro celočíselné parametry (bez uvozovek kolem potřebné hodnoty):
psql mydb -c "SELECT func($1, $2)"
Nebo s jakýmkoli typem dat:
psql mydb -c "SELECT func2('$1'::text, '$2'::numeric)"
-c
provede jeden příkazový řetězec a poté skončí. Více o argumentech příkazového řádku psql v manuál .
Chcete-li přidat další funkci pro -v
... Pokud se pokoušíte přidat nabídku, přidejte ji do příkazového řádku:
psql -v action="'drop'"
a tím se spustí kód pro:
select * where :action;
Stejný jako
select * where 'drop';
Snaž se -v
:
$ psql -U postgres -v something=\'blah-blah\'
psql (9.1.3)
Type "help" for help.
postgres=# select :something;
?column?
----------
blah-blah
(1 row)
Pokud chcete použít current_setting
a SET
nebo setval
, musíte připojit řádek k postgresql.conf
pro přidání možnosti.
Z mé zkušenosti vyplývá, že dereffing psql proměnné uvnitř deklarace plpgsql, například v CREATE FUNCTION BEGIN nebo DO BEGIN, vede k chybě 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 $$...
Mým řešením je vytvořit dočasnou tabulku s jedním sloupcem a do ní uložit hodnotu. Tato dočasná tabulka je přístupná pomocí plpgsql, a tak mohu předávat proměnné psql používané v blocích 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=#
Chcete-li použít další proměnné psql v CREATE FUNCTION nebo DO prohlášení, můžete vytvořit sloupec pro každou potřebnou proměnnou.
Není to moc elegantní, ale funguje to (pseudokód):
cat <<EOF
UPDATE tablename SET field=$arg1 WHERE field = $arg2;
EOF | psql database
Tento přístup vám poskytne plné běhové rozlišení env vars ... takže jakmile váš skript nastaví předem všechny proměnné Shell níže, bude to fungovat ( byl spuštěn tisícekrát proti různým dbs) a hostitelé ):
-- 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