Calling external program from PostgreSQL trigger - postgresql

I would like to execute external program (such as .net c# console) when PostgreSQL trigger is fired. How can I achieve it?

Postgres cannot normally run external programs for security reasons.
The typical solution is to use NOTIFY and have a daemon LISTEN to it. There are solutions for every major scripting language out there ...
Examples for Java from #Craig: How to refresh JPA entities when backend database changes asynchronously?
Relevant manual page for PHP.

Since Postgres 9.3 there is a solution for invoking external programs. It is - for security reasons - limited to superusers and IMHO intended for exporting data, rather than doing a "notification on trigger":
COPY (SELECT 1) TO PROGRAM '/bin/touch /tmp/created_by_postgres'
If you want to actually export data to the invoked programm, you can provide any SELECT or a table name instead of SELECT 1. The query results will then be passed to the invoked program via its standard input.
You can find documentation of the feature in the Postgres docs:
http://www.postgresql.org/docs/9.3/static/sql-copy.html

You can execute external scripts from inside trigger function with an "untrusted" language, like plpythonu.
More details here: https://www.postgresql.org/docs/current/plpython.html
Trigger function example:
CREATE FUNCTION execute_python_script()
RETURNS trigger
AS $$
begin
import subprocess
result = subprocess.run(['/path/to/your/bin/python', '/some_folder/some_sub_folder/script.py'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
end;
$$
LANGUAGE plpythonu;
Trigger example:
CREATE TRIGGER trigger_name
AFTER INSERT ON table
EXECUTE PROCEDURE execute_python_script();

Related

PgAdmin won't allow RAISE NOTICE

When I try to use RAISE NOTICE in a Query tool in PgAdmin I just get "ERROR: syntax error at or near "RAISE"". This is stopping defining a stored procedure which uses RAISE NOTICE.
I have simply typed the following into a Query Tool window:
RAISE NOTICE 'Bob';
I am using PgAdmin 6.3 (the latest), just updated from v4.5 which had the same problem.
RAISE is part of pl/pgsql, Postgres's default procedural language. It is not available in a direct SQL context, or any function or stored procedure defined with LANGUAGE sql rather than LANGUAGE plpgsql.
If you're used to a different DBMS like MySQL or SQL Server, you might expect to have procedural code (variables, conditionals, loops, etc) available by default, but that's not how Postgres works. In order to use procedural code, you need to be inside a function, stored procedure, or DO statement.

How to not execute INSERT in read-only transaction

Postgres server is in hot standbuy mode.
Asynchronou streaming binary replication is used.
Command like
INSERT INTO logfile (logdate) values (current_date)
Causes error
cannot execute INSERT in a read-only transaction.
Maybe it should be changed to
INSERT INTO logfile (logdate)
SELECT current_date
WHERE ???
What where condition should used ?
It should work starting at Postgres 9.0
If direct where clause is not possible, maybe some plpgsql function can used in where.
Maybe
show transaction_read_only
result should captured or some function can used.
Alternately application can determine if database is read-only in startup. Should show transaction_read_only result used for this.
Running INSERT on a standby server is not possible in pure (non-procedural) SQL because when the server is in standby mode, all the data-modification queries are rejected in planning phase, before it's executed.
It's possible with conditionals in PL/PgSQL.
DO $code$
BEGIN
IF NOT pg_is_in_recovery() THEN
INSERT INTO logfile (logdate) VALUES (current_date);
END IF;
END;
$code$;
However, it's probably not recommended - it's usually better to test pg_is_in_recovery() once (in application code) and then act accordingly.
I'm using pg_is_in_recovery() system function instead of transaction_read_only GUC because it's not exactly the same thing. But if you prefer that, please use:
SELECT current_setting('transaction_read_only')::bool
More info: DO command, conditionals in PL/PgSQL, system information functions.

Loading Postgres functions with dependencies

I'm using quite a few Postgres functions (both sql and pl/pgsql) in a particular application. Some of the sql functions depend on other sql functions, e.g.
create or replace function my_function ()
returns table (a text, b text) as
$$
select * from my_other_function();
$$
language sql;
For my_function to load properly, my_other_function has to be loaded first, else I get a my_other_function does not exist error. To manage this, I have been manually ensuring that my_other_function does get loaded first, but it would be nice not to have to do that.
In other words, is there a way to load all of my functions without regard to order and somehow check that all the necessary dependencies are available (function objects) after the fact?
I'm using Postgres 9.6.
You can use SETcheck_function_bodies= false; prior creating your functions to suppress the error.

How to execute a python script form a stored procedure in PostgreSql?

I want to execute a python script form a stored procedure in PostgreSql
I want something like this:
CREATE TRIGGER executePython
AFTER INSERT ON mytable
FOR EACH ROW
BEGIN
SYSTEM('python MyApp');
END;
Anyone can help me, please?
Are you able to install extensions? If so, you can use the the PL/Python extension
CREATE FUNCTION callMyApp()
RETURNS VOID
AS $$
import subprocess
subprocess.call(['/usr/bin/python', '/path/to/MyApp'])
$$ LANGUAGE plpythonu;
CREATE TRIGGER executePython
AFTER INSERT ON messages
FOR EACH ROW EXECUTE PROCEDURE callMyApp();
Note that this will run as the postgres user, so there may be permission issues.
There's also an extension called PL/SH, which might be of use, but doesn't appear to be an official package.
CREATE FUNCTION executePython()
RETURNS VOID
AS $$
#!/bin/sh
python /path/to/MyApp
$$
LANGUAGE plsh;
This blog post might be of interest to you, as well.
Also, this is nearly a duplicate of this thread entitled Run a shell script when a database record is written to postgres.
(Note: I haven't tested any of this code.)

What is the purpose of pgScript in PostgreSQL?

I have failed to understand the need for pgScript, which could be executed using pgAdmin tool. When it should be used? What it can do that plpgSQL cannot do? What is equivalent of it in Microsoft SQL Server?
pgScript is a client-side scripting language, while pl/PgSQL runs on the server. This means they have entirely different use cases. For example, PgScript can manage transaction status while pl/PgSQL cannot, but pl/Pgsql can be used to extend the language of SQL while pgScript cannot do that.
Additionally it means the two will handle many other things quite differently ranging from query plans to dynamic SQL, and while pgScript requires round trips between queries pl/Pgsql does not.
One use for pgScript is to define variables and use them later in your SQLs.
For example, you could do something like this:
declare #mytbl, #maxid;
set #mytbl = 'sometable';
set #maxid = 2500;
set #res = select count(*) from #mytbl where id <= #maxid;
print #res;
This approach is to just have any variables you want to change at the top of your script, rather than those getting buried deep inside complex SQL queries.
Of course, pgScript is a feature available only inside PgAdmin III client like #{Craig Ringer} mentioned in his comment.
I used DDL script generator from Toad Data Modeler.
I ran the script using normal query execution in PgAdmin-III but it kept giving me error:
"ERROR: relation "user" already exists SQL state: 42P07".
I ran Execute pgScript in PgAdmin-III and it worked fine.