Pasar argumentos a psql

10

Estoy ejecutando un script plpgsql en Postgres 8.3 - Me gustaría pasar argumentos a este script a través de psql. Actualmente estoy ejecutando el script como:

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

Encontré este enlace que explica la variable de entorno PGOPTIONS, pero eso no funciona para argumentos "personalizados". es decir, recibo un error porque la configuración no aparece en el archivo 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"

¿Alguna otra idea? Idealmente, me gustaría evitar las variables de entorno ...

Jmoney38
fuente
Creo que estás buscando el -vargumento de psql.
dezso
Intenté eso: para recuperarlo en el script, llamo "SELECT current_setting ('pretend') INTO _result", sin éxito.
Jmoney38

Respuestas:

5

Estrictamente hablando, no existe un "script plpgsql": PL / pgSQL es el lenguaje de procedimiento predeterminado de PostgreSQL. Es un script SQL o una función / procedimiento plpgsql. Su ejemplo parece indicar un script SQL.

En su lugar, puede crear una función plpgsql (o sql) (del lado del servidor) que tome cualquier número de argumentos. Es muy simple siempre que los argumentos lo sean values. Se vuelve un poco más complicado si los argumentos incluyen identificadores. Entonces tendrá que usar PL / pgSQL con SQL dinámico y EXECUTE.

PL / pgSQL está preinstalado de forma predeterminada en PostgreSQL 9.0 o posterior. Sin embargo, debe instalarlo una vez por base de datos en Postgres 8.3:

CREATE LANGUGAGE plpgsql;

Hablando de la versión: debería considerar actualizar a una versión actual de PostgreSQL. v8.3 es muy antiguo por ahora, al final de su vida útil a principios de 2013.

Como parece tener un script SQL listo, demostraré una función SQL. Función ficticia simple con dos argumentos enteros:

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

Puede encontrar muchos ejemplos más sofisticados para plpgsql aquí en dba.SE o en SO .

Puede llamar a esta función y entregar parámetros en un script de shell: ejemplo básico para una llamada en un script de shell que utiliza parámetros de entrada para parámetros enteros (no se necesitan comillas simples alrededor del valor):

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

O con cualquier tipo de datos:

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

-cejecuta una cadena de comando y luego sale. Más información sobre los argumentos de línea de comandos de psql en el manual .

Erwin Brandstetter
fuente
Gracias por la respuesta. De hecho, soy bastante consciente de plpgsql. Este script al que me refiero es un archivo que contiene numerosas funciones. Tengo una función "principal" en el sentido de la programación orientada a C. Las últimas 2 líneas dentro del script / archivo son 1) llamando a la función "principal" y luego 2) descartando la función. Entonces, en esta configuración, esencialmente tengo un script autónomo que se puede ejecutar para hacer el trabajo (psql -f). Me gusta su punto sobre llamar a una función con los "argumentos de la aplicación" a través de psql -c. Probablemente iré por esa ruta, porque no puedo seguir la ruta de agregar valores al archivo postgres.conf.
Jmoney38
5

Para agregar otra funcionalidad para -v... Si está tratando de agregar la cita, agréguela en la línea de comando:

psql -v action="'drop'"

y esto ejecutará el código para:

select * where :action;

Lo mismo que

select * where 'drop';
cline
fuente
4

Prueba -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 desea usar current_settingand SETo setval, debe agregar una fila postgresql.confpara agregar la opción.

dezso
fuente
2

Desde mi experiencia, la desautorización de una variable psql dentro de una declaración plpgsql como en CREATE FUNCTION BEGIN o DO BEGIN da como resultado un error de sintaxis:

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

Mi solución es crear una tabla temporal con una sola columna y almacenar el valor en ella. Se puede acceder a esta tabla temporal a través de plpgsql y, por lo tanto, puedo pasar variables psql utilizadas en bloques 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=#

Para usar variables psql adicionales en las declaraciones CREATE FUNCTION o DO, puede crear una columna por variable necesaria.

Jerry Mindek
fuente
0

Esto no es muy elegante pero funciona (pseudocódigo):

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

Este enfoque le proporcionará una resolución completa en tiempo de ejecución de los entornos ... así que tan pronto como su script establezca de antemano todas las variables de shell a continuación funcionará ( se ha ejecutado miles de veces contra diferentes dbs y hosts ):

    -- 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
fuente