0

I am not sure whether I am doing the right thing or not, but the issue is this:

I want to ensure that network x [from 1990 to 2000] has only stations [whos start/end time fall within 1990-2000]

CREATE TABLE network
(
  id bigint NOT NULL,
  alternate_code character varying(5),
  code character varying(5) NOT NULL,
  description character varying(250),
  end_time timestamp with time zone,
  historical_code character varying(5),
  last_updated timestamp with time zone DEFAULT current_timestamp,
  start_time timestamp with time zone NOT NULL,
  version bigint,
  CONSTRAINT network_pkey PRIMARY KEY (id),
  CONSTRAINT unq_network_0 UNIQUE (code, start_time, end_time),
  CONSTRAINT network_check CHECK (start_time < end_time)
)
WITH (
  OIDS=FALSE
);


CREATE CONSTRAINT TRIGGER time_check_consistency
  AFTER INSERT OR UPDATE
  ON network
  DEFERRABLE INITIALLY DEFERRED
  FOR EACH ROW
  EXECUTE PROCEDURE network_time_check_consistency();


CREATE OR REPLACE FUNCTION network_time_check_consistency()
  RETURNS trigger AS
$BODY$
begin
    RAISE NOTICE 'Message: % %',:new.id,:new.start_time;
    IF EXISTS(select 1 from station where network_id= :new.id and (start_time < :new.start_time or end_time > :new.end_time)) THEN
    RAISE EXCEPTION 'Invalid network time range (station out of range).';
    END IF;
    RETURN NULL;
END;


CREATE TABLE station
(
  id bigint NOT NULL,
  alternate_code character varying(5),
  code character varying(5) NOT NULL,
  creation_time timestamp with time zone,
  description character varying(255),
  elevation numeric(7,1) NOT NULL,
  end_time timestamp with time zone,
  geology character varying(255),
  historical_code character varying(5),
  last_updated timestamp with time zone DEFAULT current_timestamp,
  latitude numeric(8,6) NOT NULL,
  longitude numeric(9,6) NOT NULL,
  start_time timestamp with time zone NOT NULL,
  termination_time timestamp with time zone,
  vault character varying(255),
  version bigint,
  network_id bigint NOT NULL,
  station_id bigint,
  CONSTRAINT station_pkey PRIMARY KEY (id),
  CONSTRAINT fk_station_network_id FOREIGN KEY (network_id)
      REFERENCES network (id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION,
  CONSTRAINT fk_station_station_id FOREIGN KEY (station_id)
      REFERENCES site (id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION,
  CONSTRAINT unq_station_0 UNIQUE (network_id, code, start_time, end_time),
  CONSTRAINT station_check CHECK (start_time < end_time),
  CONSTRAINT station_latitude_check CHECK ((90::numeric >= latitude)::smallint >= (-90)),
  CONSTRAINT station_longitude_check CHECK ((180::numeric >= longitude)::smallint >= (-180))
)
WITH (
  OIDS=FALSE
);


CREATE CONSTRAINT TRIGGER time_check_consistency
  AFTER INSERT OR UPDATE
  ON station
  DEFERRABLE INITIALLY DEFERRED
  FOR EACH ROW
  EXECUTE PROCEDURE station_time_check_consistency();


CREATE OR REPLACE FUNCTION station_time_check_consistency()
  RETURNS trigger AS
$BODY$
begin
    IF EXISTS(select 1 from channnel where station_id= station_in_id and (start_time < in_starttime or end_time > in_endtime)) THEN
    RAISE EXCEPTION 'Invalid station time range (channel[s] out of range).';
    END IF;

    IF EXISTS(select 1 from network where id= network_in_id and (start_time > in_starttime or end_time < in_endtime)) THEN
    RAISE EXCEPTION 'Invalid station time range (network out of range).';
    END IF;
    RETURN NULL;
END;

if I do this:

begin
    update network set start_time='1990-01-01' where id=44201;
    RAISE NOTICE 'FINISHED 1...';
    update station set start_time='1991-01-01' where id=44202;
    RAISE NOTICE 'FINISHED 2...';
    commit;
end;

I get:

ERROR:  Invalid network time range (station out of range).
CONTEXT:  edb-spl function inline_code_block line 6 at COMMIT

I thought the 'DEFERRABLE INITIALLY DEFERRED' will delay the check until the transaction is complete and both times are changed, but this is not happening, Is my understanding correct?.

yaza
  • 181
  • 1
  • 2
  • 7
  • Please add aliases to the {station/channel} tables in the exists subqueries. – joop Oct 10 '14 at 14:37
  • BTW: the question is incomplete : definitions for tables site and channel are missing, and at the end of the functions the `$body$ language plpgsql;` is missing. Also: you don't want `:` before `new.` also it is not clear where `in_starttime` and `in_endtime` stem from. Please post real, complete code. – joop Oct 10 '14 at 16:14
  • Are you asking for the whole schema. If you don't know the answer then don't bother. The question is regarding DEFERRABLE INITIALLY DEFERRED and how it works, everything else I posted is extra to clarify further. – yaza Oct 10 '14 at 16:27
  • 1
    It is Okay to use a stripped-down schema in the question, but it at least should be usable. Imagine five people spending 15..30 minutes trying to make sense of it, and failing. BTW: are you using enterprise-DB ? – joop Oct 10 '14 at 16:47
  • BTW: the thing seems to work fine if you add the corrections in my first two comments. (plus some tedious changes on the schema) – joop Oct 10 '14 at 17:01

0 Answers0