Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trigger for checking a given value before INSERT or UPDATE on PostgreSQL

I have to create a trigger to update a database where there are products. Products have an expiration date and before inserting or updating a product I must check if the expirationDate is superior to the current timestamp. If it is I must do the insert/update regularly (this is what I have problems with). If not I just simply ignore it.

Here's the code that I have written.

CREATE FUNCTION product_expiration_date()
RETURNS trigger AS $BODY$

BEGIN
IF new.expirationDate > CURRENT_TIMESTAMP THEN
    INSERT INTO Product VALUES (new).*; 
END IF;
RETURN NULL;
END;
$BODY$
LANGUAGE 'plpgsql';

CREATE TRIGGER verify_expiration_date BEFORE INSERT OR UPDATE ON Product 
FOR EACH ROW EXECUTE PROCEDURE product_expiration_date();
like image 246
CMJunior Avatar asked Nov 29 '22 11:11

CMJunior


2 Answers

Your trigger function should return NEW when the condition to check is satisfied and you want the INSERT/UPDATE to happen, otherwise NULL to skip the operation, or better, raise an exception with a specific error message.

It must not execute itself the INSERT it was called for, this will be done by the SQL engine with the values in NEW.

Code to skip the operation:

IF new.expirationDate > CURRENT_TIMESTAMP THEN
  RETURN NEW;
ELSE 
  RETURN NULL;
END IF;

Or with an exception:

IF new.expirationDate > CURRENT_TIMESTAMP THEN
  RETURN NEW;
ELSE 
  RAISE EXCEPTION 'Invalid expiration date';
END IF;

See Overview of Trigger Behavior in the doc for more.

like image 69
Daniel Vérité Avatar answered Jan 16 '23 15:01

Daniel Vérité


CHECK constraint

The easiest way to achieve this goal is via the CHECK constraint, which is an SQL standard feature.

ALTER TABLE Product
ADD CONSTRAINT verify_expiration_date_check
CHECK (expirationDate < CURRENT_TIMESTAMP)

Trigger function

You could also use a BEFORE INSERT or BEFORE UPDATE trigger, but that's more suitable when the validation rule needs to inspect multiple tables, not just the current on that triggered the check.

Now, if you really want to use a trigger function, this is how it would look like in your case

First, you need to create the trigger function:

CREATE OR REPLACE FUNCTION product_expiration_date()
  RETURNS TRIGGER AS $$
BEGIN
  IF NEW.expirationDate > CURRENT_TIMESTAMP
  THEN
    RAISE EXCEPTION 'Product [id:%] expired!',
    NEW.id;
  END IF;
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

Notice that we are throwing an exception using RAISE if the expirationDate is greater than the current timestamp.

Now, you need to pass this trigger function to an INSERT and UPDATE trigger:

CREATE TRIGGER verify_expiration_date 
BEFORE INSERT OR UPDATE ON Product 
FOR EACH ROW EXECUTE PROCEDURE product_expiration_date();

Although you could use a trigger function, it's much easier to use a CHECK constraint.

like image 33
Vlad Mihalcea Avatar answered Jan 16 '23 15:01

Vlad Mihalcea