postgresqltriggerstime-travel

Timetravel in postgres - violating PRIMARY KEY constraint


I wanted to use timetravel function (F.39. spi, PostgreSQL 9.1 Documentation) in my application, however it doesn't seem to work properly for me. With inserting rows into table everything works just fine, I get start and stop date properly, but when I'm trying to update those rows postgres gives me error about violating of PRIMARY KEY constraint. He's trying to insert a tuple with the same primary id as previous tuple...

It's insane to remove primary key constraints from all tables in the database but it's the functionality I need. So maybe you have some expierience with timetravel?

Any sort of help will be appreciated. Thanks in advance.

DDL:

CREATE TABLE cities
(
  city_id serial NOT NULL, 
  state_id integer, 
  name character varying(80) NOT NULL,
  start_date abstime,
  stop_date abstime,
  CONSTRAINT pk_cities PRIMARY KEY (city_id ),
  CONSTRAINT fk_cities_states FOREIGN KEY (state_id)
      REFERENCES states (state_id) MATCH SIMPLE
      ON UPDATE CASCADE ON DELETE NO ACTION
)
WITH (
  OIDS=FALSE
);



-- Trigger: time_travel on cities

-- DROP TRIGGER time_travel ON cities;

CREATE TRIGGER time_travel
  BEFORE INSERT OR UPDATE OR DELETE
  ON cities
  FOR EACH ROW
  EXECUTE PROCEDURE timetravel('start_date', 'stop_date');

STATEMENT GIVEN:

INSERT INTO cities(
            state_id, name)
    VALUES (20,'Paris');

and that's ok. I get start_date and stop_date. But by:

UPDATE cities SET name='Rome' WHERE name='Paris'

I get error- described earlier.

Schema of states

-- Table: states

-- DROP TABLE states;

CREATE TABLE states
(
  state_id serial NOT NULL, -- unikatowy numer wojewodztwa
  country_id integer, -- identyfikator panstwa, w ktorym znajduje sie wojewodztwo
  name character varying(50), -- nazwa wojewodztwa
  CONSTRAINT pk_states PRIMARY KEY (state_id ),
  CONSTRAINT uq_states_state_id UNIQUE (state_id )
)
WITH (
  OIDS=FALSE
);

Unfortunately,as a new user I'm not allowed to post images here. You can see them there:

Sample data from table cities: korpusvictifrew.cba.pl/postgres_cities.png

Sample data from table states: korpusvictifrew.cba.pl/states_data.png


Solution

  • Time travel converts an UPDATE into an UPDATE of the old record's stop_date and an INSERT of a new one with the changed data plus an infinity stop_date. You can't have more than one record for city_id due to pk_cities. The time travel triggers do not allow you to break that requirement.

    You cannot use this:

    CONSTRAINT pk_cities PRIMARY KEY (city_id )
    

    You must use this

    CONSTRAINT pk_cities PRIMARY KEY (city_id, stop_date)