2

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
6
  • 1
    "This injection works only when a database is created. This is wrong as I can't make any change to a production database." - to do that, you'll need some database migration tool. And it doesn't matter whether it runs inside the same docker container as the database or not. Commented May 23, 2021 at 12:30
  • 1
    "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...)" - nah, that should work. What is the exact error message? Notice you have a stray LANGUAGE plpgsql; in your sample snippet. Commented May 23, 2021 at 12:31
  • Indeed, in the ".sql" file, for the function, I changed the place to the LANGUAGE plpgsql, and removed the useless one for the trigger. To check, I opened a port on the container, used Dbeaver and I can see the trigger attached to the table, and the function. Commented May 23, 2021 at 12:51
  • Could you elaborate on the database migration tool? Do you mean eg Sequelize for Node.js and ActiveRecord for Rails? How is this linked? Commented May 23, 2021 at 12:58
  • There are many. Some dedicated tools, some built into frameworks or ORM libraries. Commented May 23, 2021 at 13:02

1 Answer 1

1

enter image description here

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();
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.