How to insert stored functions and triggers in a Postgres container - postgresql

I have a containerized Postgres database and I am trying to create a function and a trigger: a simple notification on a new row insertion.
It may seem stupid but I am unable to find how to write the code, where should I push it to the Postgres container, and how to programmatically insert the code inside the container.
I can see the following file structure
Database/Schemas/public/
|---tables
| |___requests (tablename)
| |__Triggers
|
|___Functions
I only (vaguely) found a way to copy the code inside when using the /docker-entrypoint-initdb.d/ folder (a COPY in the Dockerfile).
This injection works only - as per the Docker/Postgres documentation - when a database is created. This means I have to drop and recreate the database. This is wrong as I can't make any change to a production database.
Furthermore, when I adjoin the other SQL commands to the CREATE TABLE command in the .sql file, then the order of execution of these commands leads to errors (unknown table...).
My init.sqlfile programmatically copied into the /docker-entrypoint-initdb.d/ folder is:
-- init_table.sql
CREATE TABLE IF NOT EXISTS public.requests (
id serial PRIMARY KEY,
...,
);
-- create_function_notify.sql
CREATE OR REPLACE FUNCTION notify_insert() RETURNS trigger AS
$$
BEGIN
PERFORM pg_notify('new_notif', row_to_json(NEW)::text);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- create_trigger_new_event.sql
CREATE TRIGGER new_event
AFTER INSERT
ON public.requests
FOR EACH ROW
EXECUTE PROCEDURE notify_insert();
LANGUAGE plpgsql;
I also tried a "sh" version (dixit PG docs) without success: it throws an error around "$$".
#/bin/sh
set -e
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
CREATE OR REPLACE FUNCTION notify_insert() RETURNS trigger AS
$$
LANGUAGE plpgsql;
EOSQL

A Dockerfile instruction COPY ./pg_notify.sql /docker-entrypoint-initdb.d/ sets up the desired trigger and notification related function to the containerized Postgres database (on creation only).
Following Bergi's remark, the correct code is:
-- pg_notify.sql
CREATE TABLE IF NOT EXISTS public.requests (
id serial PRIMARY KEY,
app varchar,
url varchar,
ip varchar,
host varchar,
req_at VARCHAR,
d BIGINT
);
CREATE OR REPLACE FUNCTION notify_insert() RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGIN
PERFORM pg_notify('new_notification', row_to_json(NEW)::text);
RETURN NEW;
END;
$$;
CREATE TRIGGER new_event
AFTER INSERT
ON requests
FOR EACH ROW
EXECUTE PROCEDURE notify_insert();

Related

I got error when trying to run docker-compose up --build. And i got an error in my sql seed data

I got this error while trying to run docker-compose up --build, I'm using postgresql as my database service. I think there's wrong with my query.When i remove the CREATE TRIGGER it somehow run without erros.
LINE 13: CREATE TRIGGER update_communication
backend-postgres-1 |^
Here is my sql file
CREATE OR REPLACE FUNCTION dts.save_communication_revision()
RETURNS TRIGGER
LANGUAGE PLPGSQL
AS
$$
BEGIN
INSERT INTO dts.communication_revisions(com_id, class_id, com_subject, user_id, com_source_name, "com_dateCreated", "com_dateReceived", com_urgency, com_source_position, com_source_office, com_draft, com_other_remarks, "com_controlNo", com_due_date)
VALUES(OLD.com_id, OLD.class_id, OLD.com_subject, OLD.user_id, OLD.com_source_name, OLD."com_dateCreated", OLD."com_dateReceived", OLD.com_urgency, OLD.com_source_position, OLD.com_source_office, OLD.com_draft, OLD.com_other_remarks, OLD."com_controlNo", OLD.com_due_date);
END;
$$
CREATE TRIGGER update_communication
AFTER UPDATE
ON dts.communications
FOR EACH ROW
EXECUTE PROCEDURE dts.save_communication_revision();
END;
$$;
Just added this semicolon.

How to create a function in PostgreSQL like SQL Server BACKUP DATABASE TO DISK

I'm trying without success to create a function in Postgres that save a table or database taking one or two parameters. In this case I was trying to create it with only one parameter(name of the table or database) and backup this table/db
--SELECT backup_table(sports)
CREATE FUNCTION backup_table(TEXT) RETURNS BOOLEAN AS
$$
DECLARE
table_x ALIAS FOR $1;
BEGIN
COPY table_x FROM 'C:/path/backup_db' WITH (FORMAT CSV);
RAISE NOTICE 'Saved correctly the table %',$1;
RETURN BOOLEAN;
END;
$$ LANGUAGE plpgsql;
I've always receive the error when I try to execute the function SELECT backup_table(sports):
"The column sports doesnt exists."
SQL state: 42703
Character: 21
The idea is to create the function like the equivalent of SQL Server BACKUP DATABASE TO DISK, or equivalent to pg_dump command
pg_dump -U -W -F t sports > C:/path/backup_db;
I know about SQL but now I'm just stuck with this error.

Using pg_dump with no owner information still outputting role information

I dumped a database using pg_dump -O -x expecting all ownership and role information to be ignored, however, it is still including specific mentions to manager roles in the original database which are failing to be imported because they don't exist in the new database which I'm importing into. See the snippet of the dump.sql file:
--
-- Name: reassign_owned(); Type: FUNCTION; Schema: public; Owner: -
--
CREATE FUNCTION reassign_owned() RETURNS event_trigger
LANGUAGE plpgsql
AS $$
begin
-- do not execute if member of rds_superuser
IF EXISTS (select 1 from pg_catalog.pg_roles where rolname = 'rds_superuser')
AND pg_has_role(current_user, 'rds_superuser', 'member') THEN
RETURN;
END IF;
-- do not execute if not member of manager role
IF NOT pg_has_role(current_user, 'rdsbroker_xxxxx_manager', 'member') THEN
RETURN;
END IF;
-- do not execute if superuser
IF EXISTS (SELECT 1 FROM pg_user WHERE usename = current_user and usesuper = true) THEN
RETURN;
END IF;
EXECUTE 'reassign owned by "' || current_user || '" to "rdsbroker_xxxxx_manager"';
end
$$;
-O means that pg_dump itself does not emit ownership information. It doesn't cause it to edit the source code of any functions it might dump, in an attempt to prevent those functions from doing what they were written to do.
I've done a quick search in pg_dump and pg_restore source code and I see no usage of REASSIGN OWNED statement.

Function to create Foreign Server, does not create foreign server

I have created the function below to create a Foreign Server. The function runs without error, but nothing gets created. This is not a rights issue as I can run the individual commands just fine and the server gets created.
CREATE OR REPLACE FUNCTION sch.helper_create_linked_server(servername text, host text, port text, dbname text, localuser text, remoteuser text, password text, timeout text)
RETURNS void
LANGUAGE plpgsql
AS $function$
declare srv_name text;
tmp text;
begin
CREATE EXTENSION IF NOT EXISTS postgres_fdw;
CREATE EXTENSION IF NOT EXISTS dblink;
execute format($s$ select srvname from pg_foreign_server where srvname = %L $s$, servername) into srv_name;
if srv_name is null then
execute format($ex$
CREATE SERVER %1$I
FOREIGN DATA WRAPPER postgres_fdw
OPTIONS (host %2$L, port %3$L, dbname %4$L, connect_timeout %5$L);
$ex$, servername, host, port, dbname, timeout, remoteuser);
raise info 'server created: %', servername;
execute format($ex$
create user mapping for %I
server %I
options (user %L, password %L)
$ex$, localuser, servername, remoteuser, password);
raise info '%', 'umapping created';
perform format($$ ALTER SERVER %1$I OWNER TO %2$I $$, servername, remoteuser);
raise info '%', 'assigned user to server';
end if;
end $function$
I have printed out the command that gets generated and it is correct. This is how I call the function:
perform sch.helper_create_linked_server(link_name, conn_props->>'endpoint', conn_props->>'port', conn_props->>'db', conn_props->>'user', conn_props->>'user', rs_pwd, conn_props->>'timeout');
Also, all the raise info messages are printed as well, so the code is running. And no, the server is not already created.
I cannot see why this will not create.
Any advice appreciated.
Thanks!

Postgresql Error type " " does not exist

I get this error:
Caused by: org.postgresql.util.PSQLException: ERROR: type
"tool_parse_numbers_record" does not exist
Where: compilation of PL/pgSQL function "tool_parse_numbers" near line 2
I am restoring my database in a docker container like this:
FROM postgres:9.4
ENV POSTGRES_USER iwb
ENV POSTGRES_PASSWORD 1907
ENV POSTGRES_DB iwb
ADD ./1_schema.sql /docker-entrypoint-initdb.d/
ADD ./2_data.sql /docker-entrypoint-initdb.d/
Here's type definition in schema.sql file:
CREATE TYPE tool_parse_numbers_record AS (
satir character varying(4000)
);
Here's top part of function definition in schema.sql:
CREATE FUNCTION tool_parse_numbers(pstr text, pdelimeter text DEFAULT
'|'::text) RETURNS SETOF tool_parse_numbers_record
LANGUAGE plpgsql SECURITY DEFINER
AS $$
DECLARE
And this is how database is restored:
CREATE FUNCTION tool_parse_numbers(pstr text, pdelimeter text DEFAULT
'|'::text) RETURNS SETOF tool_parse_numbers_record
LANGUAGE plpgsql SECURITY DEFINER
AS $BODY$
DECLARE
EDIT:
I changed dockerfile to create types before functions:
ADD ./1_type.sql /docker-entrypoint-initdb.d/
ADD ./2_table.sql /docker-entrypoint-initdb.d/
ADD ./3_func.sql /docker-entrypoint-initdb.d/
ADD ./4_rest_table.sql /docker-entrypoint-initdb.d/
ADD ./5_data.sql /docker-entrypoint-initdb.d/
How do I fix it?
Are you sure that the type is created before the function?
Is the type created in the same schema as the function? (Is not SET search_path somewhere in the sql file used?)
$$ and $BODY$ starts "dolar quoted string", which are terminated by the same ($$ or $BODY$). Instead of BODY you can have any characters (or any), it just allowes to write $$, ", etc. inside the string without problems.
Why postgres use $BODY$ and not $ILOVEBEER$ remains unknown.
When I extracted the database to schema.sql file, owner was set to postgres:
ALTER FUNCTION iwb.tool_parse_numbers(pstr text, pdelimeter text) OWNER TO postgres;
So I changed owner to iwb since it's like that in docker file
ENV POSTGRES_USER iwb
And it worked!