Führen Sie Systembefehle in postgresql aus

8

Meine Anforderung besteht darin, einen Systembefehl wie (ls) oder C-Programm auszuführen, wenn ein Trigger ausgeführt wird. Gibt es eine Möglichkeit, eine Triggerfunktion zu erstellen, um dieses Problem zu lösen?

mrg
quelle
2
Sie können eine nicht vertrauenswürdige Sprache wie PL / Perl verwenden, mit der Sie Betriebssystembefehle aufrufen können: postgresql.org/docs/current/static/plperl-trusted.html
a_horse_with_no_name

Antworten:

13

Sie können leicht tun, was @a_horse_with_no_name in seinem Kommentar vorschlägt. Es gibt aber auch eine interessante Möglichkeit, PL / pgSQL als Funktionssprache zu verwenden.

Dies verwendet eine Funktion des COPYBefehls, der in PostgreSQL 9.3 eingeführt wurde. Es kann jetzt einen Befehl als Ziel / Quelle annehmen, genau dort, wo Sie im Normalfall einen Dateinamen oder STDIN / STDOUT verwenden würden:

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

Natürlich benötigen Sie eine Tabelle, um die Ausgabe zu platzieren, aber Sie können sie ignorieren, wenn Sie möchten.

Sehen Sie sich ein kleines Beispiel an:

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

Hinweis: Die Funktion muss mit Superuser-Rechten ausgeführt werden, dh entweder INSERTals Superuser ausführen oder die Funktion mit definieren SECURITY DEFINER. In jedem anderen Fall erhalten Sie eine Fehlermeldung:

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.
dezso
quelle
Beachten Sie, dass für den TO PROGRAMTeil ein Zeichenfolgenliteral erforderlich ist. Wenn Sie also einen dynamischen Befehl wünschen, müssen Sie das Ganze einschließen EXECUTE. Siehe stackoverflow.com/a/42626659/5419599 .
Wildcard
Können Sie mir bitte bei meiner Frage helfen: stackoverflow.com/questions/61071706/…
ankit
6

Wenn Sie sich nur etwas Relatives ansehen müssen, können $PGDATASie pg_ls_data verwenden

SELECT pg_ls_dir('pg_xlog');

Ansonsten eine einfache Funktion wie diese:

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;

Gibt Ihnen folgende Ausgabe:

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:=#
Kassandry
quelle
1
Bitte beachten Sie, dass dies auch nur mit Superuser-Rechten (oder mit SECURITY DEFINER) ausgeführt werden kann.
Dekso
@dezso Ganz richtig. Vielen Dank, dass Sie diesen Punkt hinzugefügt haben. =)
Kassandry