Solution to exercises for lecture 4: Views, Triggers, Rules and Lore

1. The World View

CREATE VIEW truth.true_now(sid, stmt_text) AS
SELECT DISTINCT s.sid, s.stmt_text
FROM truth.statement AS s
     JOIN truth.true_at AS t USING (sid)
WHERE t.true_from <= now() AND
      (t.true_until IS NULL OR
       t.true_until > now());

2. Trigger Happy

2.1 Automated Truth Maintenance

-- Handle inserts
CREATE FUNCTION truth.ins_stmt_fn() RETURNS trigger AS
$body$
  BEGIN
    INSERT INTO truth.true_at
    VALUES (NEW.sid, now(), NULL);
    RETURN NEW;
  END;
$body$ language plpgsql;

CREATE TRIGGER ins_stmt 
INSTEAD OF INSERT ON truth.true_now
FOR EACH ROW EXECUTE PROCEDURE truth.ins_stmt_fn();

-- Handle deletes
CREATE FUNCTION truth.del_stmt_fn() RETURNS trigger AS
$body$
  BEGIN
    UPDATE truth.true_at
    SET true_until = now()
    WHERE sid = OLD.sid AND true_from <= now() AND
          (true_until IS NULL OR true_until >= now()); -- Only update the currently true statements
    RETURN OLD;
  END;
$body$ language plpgsql;

CREATE TRIGGER del_stmt 
INSTEAD OF DELETE ON truth.true_now
FOR EACH ROW EXECUTE PROCEDURE truth.del_stmt_fn();

2.2 Automated Contradiction Maintenance

-- Handle insert into truth.contradicion
-- Using triggers and a new table:
CREATE TABLE truth.contradiction_all (
    sid1 text,
    sid2 text,
    PRIMARY KEY (sid1, sid2)
);

CREATE FUNCTION truth.con_ins_fn() RETURNS trigger AS
$body$
  BEGIN
    INSERT INTO truth.contradiction_all
    VALUES (NEW.sid1, NEW.sid2), (NEW.sid2, NEW.sid1)
    ON CONFLICT DO NOTHING;
    RETURN NEW;
  END;
$body$ language plpgsql;

CREATE TRIGGER con_ins
AFTER INSERT ON truth.contradiction
FOR EACH ROW EXECUTE PROCEDURE truth.con_ins_fn();

-- Using a VIEW:
CREATE VIEW truth.contradiction_all AS
SELECT sid1, sid2
FROM truth.contradiction
UNION ALL
SELECT sid2, sid1
FROM truth.contradiction;

-- Handle inserts on truth.true_at with contradictions
CREATE FUNCTION truth.con_stmt_fn() RETURNS trigger AS
$body$
  BEGIN
    UPDATE truth.true_at
    SET true_until = now()
    WHERE (NEW.sid, sid) IN (SELECT sid1, sid2 FROM truth.contradiction_all) AND
          true_from <= now() AND
          (true_until IS NULL OR true_until >= now()); -- Only update the currently true statements
    RETURN NEW;
  END;
$body$ language plpgsql;

CREATE TRIGGER con_stmt 
INSTEAD OF INSERT ON truth.true_now
FOR EACH ROW EXECUTE PROCEDURE truth.con_stmt_fn();

3 PostgreSQL Rules

-- Handle insert to truth.true_now
CREATE RULE ins_true_now_rule AS
ON INSERT TO truth.true_now DO INSTEAD
INSERT INTO truth.true_at
VALUES (NEW.sid, now(), NULL);

-- Handle deletes to truth.true_now
CREATE RULE del_true_now_rule AS
ON DELETE TO truth.true_now DO INSTEAD
UPDATE truth.true_at
SET true_until = now()
WHERE OLD.sid = sid AND
      true_from <= now() AND
      (true_until IS NULL OR true_until >= now());

-- Handle insert into truth.contradicion
CREATE RULE con_ins_rule AS
ON INSERT TO truth.contradiction DO ALSO
INSERT INTO truth.contradiction_all
VALUES (NEW.sid1, NEW.sid2), (NEW.sid2, NEW.sid1)
ON CONFLICT DO NOTHING;

-- Handle inserts on truth.true_at with contradictions
CREATE RULE ins_true_now_con_rule AS
ON INSERT TO truth.true_now DO INSTEAD
UPDATE truth.true_at
SET true_until = now()
WHERE (NEW.sid, sid) IN (SELECT sid1, sid2 FROM truth.contradiction_all) AND
      true_from <= now() AND
      (true_until IS NULL OR true_until >= now());

4 World Lore

4.1 The World View Revisited

CREATE RELATION truth.true_now (
    sid text NOT NULL,
    stmt_text text NOT NULL
);

truth.true_now(sid, stmt) <- truth.statement(sid, stmt), truth.true_at(sid, tf, tu)
                             : t.true_from <= now() AND
                               (t.true_until IS NULL OR t.true_until > now())

4.2 Contradicting Lore

CREATE RELATION FROM TABLE truth.contradiction (
  sid1 text NOT NULL,
  sid2 text NOT NULL
); -- Primary key constraint unecessary here

-- Note that we do not need an auxillary table, as
-- Lore-rules can be recursive without a problem
truth.contradiction(s1, s2) -> truth.contradiction(s2, s1);

Or using the SQL-like syntax:

CREATE RELATION FROM TABLE truth.contradiction (
  sid1 text NOT NULL,
  sid2 text NOT NULL
); -- Primary key constraint unecessary here

CREATE FORWARD IMPLICATION truth.contradition AS
SELECT sid2, sid1 FROM truth.contradiction;

4.3 Implied Contradiction


IMPORT 'http://leifhka.org/in5800/data/ministry_of_truth_implications.lore';

truth.implication(s1, s2), truth.contradiction(s2, s3) -> truth.contradiction(s1, s3);

truth.true_now(sid2, stmt2) <- truth.true_now(sid1, stmt1),
                               truth.implication(sid1, sid2),
                               truth.statement(sid2, stmt2);

Full Lore-script

Here you can download a complete script containing the full (non-overlapping) functionality implemented in all of this weeks exercises.