Question

I have the following update trigger for a tsvector column

CREATE TRIGGER tsvector_user_update
BEFORE INSERT OR UPDATE ON users
FOR EACH ROW EXECUTE PROCEDURE 
tsvector_update_trigger(user_tsv, 'pg_catalog.english', firstname, surname, email, card_id);

This works fine, however my card_id column (text) contains a pre-amble that the user is not aware of (it is added after the card is scanned), so I would like to strip out the pre-amble when the tsvector value is generated, I have tried the trigger function as a start

CREATE FUNCTION user_change_trigger() RETURNS trigger AS $$
BEGIN
NEW.user_tsv = setweight(to_tsvector('pg_catalog.english', coalesce(NEW.firstname,'')), 'A') ||
    setweight(to_tsvector('pg_catalog.english', coalesce(NEW.surname,'')), 'A') ||
    setweight(to_tsvector('pg_catalog.english', coalesce(REGEXP_REPLACE(NEW.card_id, '^\d+PRE', ''),'')), 'B') ||
    setweight(to_tsvector('pg_catalog.english', coalesce(NEW.email,'')), 'C');
    return new;
END

$$ LANGUAGE plpgsql;

CREATE TRIGGER tsvectorupdate BEFORE INSERT OR UPDATE
ON users FOR EACH ROW EXECUTE PROCEDURE user_change_trigger();

Which executes, but I get the following:

WARNING:  nonstandard use of escape in a string literal

And no updated tsvector

The pre-amble is an integer followed by 'PRE'.

(PostgreSQL 9.0)

Was it helpful?

Solution

Basic trigger design

The problem is of principal nature. In PostgreSQL you create a trigger function that does the work. I don't see your trigger function in the question.

Then you create a trigger which makes use of this function. You can only pass constants to a trigger function. Consider this quote from the manual about CREATE TRIGGER

function_name

A user-supplied function that is declared as taking no arguments and returning type trigger, which is executed when the trigger fires.

arguments

An optional comma-separated list of arguments to be provided to the function when the trigger is executed. The arguments are literal string constants. Simple names and numeric constants can be written here, too, but they will all be converted to strings. Please check the description of the implementation language of the trigger function to find out how these arguments can be accessed within the function; it might be different from normal function arguments.

Bold emphasis mine.

Use NEW to access the column values inside the trigger function. You don't need to pass them as arguments. Get a grip on the basic concept first. Start here.

regexp_replace()

Use:

regexp_replace(card_id, '^\d+PRE', '')

.. since the leading characters are supposed to be digits only (and at least one of them).

Proper trigger & function

The following test case works for me on PostgreSQL 9.1.6. Your version looks basically good to me, I only made minor changes. But keep reading ...

Create test environment (will be rolled back at the end):

BEGIN;
CREATE SCHEMA test;
SET search_path = test;

CREATE TABLE users (
    users_id serial primary key
   ,firstname text
   ,surname text
   ,card_id text
   ,email text
   ,user_tsv tsvector
   );

Trigger function:

CREATE FUNCTION user_change_trigger()
  RETURNS trigger AS
$func$
BEGIN

NEW.user_tsv :=
   setweight(to_tsvector('pg_catalog.english', coalesce(NEW.firstname,'')), 'A')
|| setweight(to_tsvector('pg_catalog.english', coalesce(NEW.surname,'')), 'A')
|| setweight(to_tsvector('pg_catalog.english', coalesce(regexp_replace(NEW.card_id, '^\d+PRE', ''),'')), 'B')
|| setweight(to_tsvector('pg_catalog.english', coalesce(NEW.email,'')), 'C');

RETURN NEW;
END

$func$ LANGUAGE plpgsql;

The assignment operator of plpgsql is := - unlike SQL where = is used.

Trigger:

CREATE TRIGGER tsvectorupdate
BEFORE INSERT OR UPDATE ON users
FOR EACH ROW EXECUTE PROCEDURE user_change_trigger();

Tests:

INSERT INTO users (firstname, surname, card_id, email)
VALUES ('Erwin', 'Brandstetter', '123PRE456', 'foo@dummy.org')
RETURNING *;

-- looks good!

UPDATE users SET firstname = 'Walter' WHERE TRUE
RETURNING *;

-- looks good, too!

Clean up:

ROLLBACK;

standard_conforming_strings

Explore your setting of standard_conforming_strings. The WARNING suggests that you don't have this setting on, which would require that you double the backslash in:

'^\\d+PRE'
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top