web-dev-qa-db-fra.com

Exécuter des commandes système dans postgresql

Mon exigence est d'exécuter une commande système comme (ls) ou un programme C lorsqu'un déclencheur s'exécute. Existe-t-il un moyen de créer une fonction de déclenchement pour résoudre ce problème.

8
mrg

Vous pouvez facilement faire ce que @ a_horse_with_no_name suggère dans son commentaire. Mais il existe également un moyen intéressant de le faire, en utilisant PL/pgSQL comme langage de fonction.

Cela utilise une fonctionnalité de la commande COPY , introduite dans PostgreSQL 9.3. Il peut désormais prendre une commande comme cible/source, exactement là où vous utiliseriez un nom de fichier ou STDIN/STDOUT dans des cas normaux:

COPY table_name [ ( column_name [, ...] ) ]
    FROM { 'filename' | PROGRAM 'command' | STDIN }
    [ [ WITH ] ( option [, ...] ) ]

Évidemment, vous avez besoin d'une table pour mettre la sortie, mais vous pouvez l'ignorer, si vous le souhaitez.

Voir un petit exemple:

CREATE TABLE trigger_test (
    tt_id serial PRIMARY KEY,
    command_output text
);

CREATE OR REPLACE FUNCTION trigger_test_execute_command()
RETURNS TRIGGER
LANGUAGE plpgsql
AS $BODY$
BEGIN
    COPY trigger_test (command_output) FROM PROGRAM 'echo 123';
    RETURN NULL;
END;
$BODY$;

CREATE TABLE trigger_test_source (
    s_id integer PRIMARY KEY
);

CREATE TRIGGER tr_trigger_test_execute_command
    AFTER INSERT
    ON trigger_test_source
    FOR EACH STATEMENT
    EXECUTE PROCEDURE trigger_test_execute_command();

INSERT INTO trigger_test_source VALUES (2);

TABLE trigger_test;
 tt_id │ command_output 
───────┼────────────────
     1 │ 123

Remarque: la fonction doit s'exécuter avec les droits de superutilisateur - c'est-à-dire soit faire le INSERT en tant que superutilisateur, soit définir la fonction avec SECURITY DEFINER. Dans tous les autres cas, vous obtiendrez une erreur:

ERROR:  must be superuser to COPY to or from an external program
HINT:  Anyone can COPY to stdout or from stdin. psql's \copy command also works for anyone.
13
dezso

Si vous avez juste besoin de regarder quelque chose par rapport à $PGDATA vous pouvez utiliser pg_ls_data

SELECT pg_ls_dir('pg_xlog');

Sinon, une simple fonction comme celle-ci:

CREATE OR REPLACE FUNCTION ls(location text) RETURNS text AS $BODY$
    use warnings;
    use strict;
    my $location = $_[0];
    my $output = `ls -l $location`;
    return($output);
$BODY$ LANGUAGE plperlu;

Vous donnera une sortie comme celle-ci:

user1@[local]:5432:user1:=# SELECT * FROM ls('/usr/local/pgsql/data');
                                       ls                                            
-----------------------------------------------------------------------------------------
 total 104                                                                              +
 -rw-------  1 pgsql  pgsql      4 Jan 14 14:33 PG_VERSION                              +
 drwx------  8 pgsql  pgsql      8 Jan 15 12:27 base                                    +
 drwx------  2 pgsql  pgsql     54 Feb  4 01:30 global                                  +
 drwx------  2 pgsql  pgsql      4 Jan 15 12:57 pg_clog                                 +
 drwx------  2 pgsql  pgsql      2 Jan 14 14:33 pg_commit_ts                            +
 drwx------  2 pgsql  pgsql      2 Jan 14 14:33 pg_dynshmem                             +
 -rw-------  1 pgsql  pgsql   4458 Feb  4 01:29 pg_hba.conf                             +
 -rw-------  1 pgsql  pgsql   1725 Jan 20 15:29 pg_ident.conf                           +
 drwx------  4 pgsql  pgsql      5 Feb  4 02:14 pg_logical                              +
 drwx------  4 pgsql  pgsql      4 Jan 14 14:33 pg_multixact                            +
 drwx------  2 pgsql  pgsql      3 Feb  4 01:29 pg_notify                               +
 drwx------  2 pgsql  pgsql      2 Jan 14 14:33 pg_replslot                             +
 drwx------  2 pgsql  pgsql      2 Jan 14 14:33 pg_serial                               +
 drwx------  2 pgsql  pgsql      2 Jan 14 14:33 pg_snapshots                            +
 drwx------  2 pgsql  pgsql      2 Feb  4 01:29 pg_stat                                 +
 drwx------  2 pgsql  pgsql      8 Feb  4 02:17 pg_stat_tmp                             +
 drwx------  2 pgsql  pgsql      3 Jan 15 13:08 pg_subtrans                             +
 drwx------  2 pgsql  pgsql      2 Jan 14 14:33 pg_tblspc                               +
 drwx------  2 pgsql  pgsql      2 Jan 14 14:33 pg_twophase                             +
 lrwxr-xr-x  1 pgsql  pgsql     29 Jan 14 14:34 pg_xlog -> /usr/local/pgsql/xlog/pg_xlog+
 -rw-------  1 pgsql  pgsql     88 Jan 14 14:33 postgresql.auto.conf                    +
 -rw-------  1 pgsql  pgsql  21821 Jan 20 15:27 postgresql.conf                         +
 -rw-------  1 pgsql  pgsql     53 Feb  4 01:29 postmaster.opts                         +
 -rw-------  1 pgsql  pgsql     79 Feb  4 01:29 postmaster.pid                          +

(1 row)

Time: 4.361 ms
user1@[local]:5432:user1:=#
5
Kassandry