-- db schema for patch tracker.  note that every distinct command (omitting
-- comments) must be preceded and followed by a blank line.

CREATE TABLE packages (
  id INTEGER UNIQUE NOT NULL PRIMARY KEY,
  name TEXT NOT NULL,
  version TEXT NOT NULL,
  format TEXT NOT NULL,
  loc TEXT NOT NULL,
  diffgz_name TEXT DEFAULT NULL,
  diffgz_size INTEGER DEFAULT NULL,
  diffgz_md5sum varchar(32) DEFAULT NULL
);

CREATE UNIQUE INDEX idx_pkg_name_version ON packages (name,version);

CREATE TABLE suites (
  id INTEGER UNIQUE NOT NULL PRIMARY KEY,
  name TEXT UNIQUE NOT NULL,
  UNIQUE (name) ON CONFLICT IGNORE
);

CREATE TABLE components (
  id INTEGER UNIQUE NOT NULL PRIMARY KEY,
  name TEXT UNIQUE NOT NULL,
  UNIQUE (name) ON CONFLICT IGNORE
);

CREATE TABLE package_rel_map (
  package_id INTEGER NOT NULL
    CONSTRAINT fk_package_id REFERENCES packages(id),
  suite_id INTEGER NOT NULL
    CONSTRAINT fk_suite_id REFERENCES suites(id) ON DELETE CASCADE,
  component_id INTEGER NOT NULL
    CONSTRAINT fk_component_id REFERENCES components(id),
  UNIQUE (package_id, suite_id, component_id) ON CONFLICT IGNORE
);

-- sqlite doesn't actually implement FK constraints, therefore we
-- help out a little and do it ourselves via triggers

-- before insert on the package relation mapping, catch invalid references

CREATE TRIGGER fki_package_rel_map_suite_id_suites_id
  BEFORE INSERT ON [package_rel_map]
  FOR EACH ROW BEGIN
    SELECT RAISE(ROLLBACK, 'INSERT on "package_rel_map" violates FK constraint on "suites.id"')
    WHERE (SELECT id FROM suites WHERE id = NEW.suite_id) IS NULL;
  END;

CREATE TRIGGER fki_package_rel_map_package_id_packages_id
  BEFORE INSERT ON [package_rel_map]
  FOR EACH ROW BEGIN
    SELECT RAISE(ROLLBACK, 'INSERT on "package_rel_map" violates FK constraint on "packages.id"')
    WHERE (SELECT id FROM packages WHERE id = NEW.package_id) IS NULL;
  END;

CREATE TRIGGER fki_package_rel_map_component_id_components_id
  BEFORE INSERT ON [package_rel_map]
  FOR EACH ROW BEGIN
    SELECT RAISE(ROLLBACK, 'INSERT on "package_rel_map" violates FK constraint on "components.id"')
    WHERE (SELECT id FROM components WHERE id =NEW.component_id) IS NULL;
  END;

-- the same but for updates

CREATE TRIGGER fku_package_rel_map_suite_id_suites_id
  BEFORE UPDATE ON [package_rel_map]
  FOR EACH ROW BEGIN
    SELECT RAISE(ROLLBACK, 'update on "package_rel_map" violates FK constraint on "suites.id"')
      WHERE (SELECT id FROM suites WHERE id = NEW.suite_id) IS NULL;
  END;

CREATE TRIGGER fku_package_rel_map_package_id_packages_id
  BEFORE UPDATE ON [package_rel_map]
  FOR EACH ROW BEGIN
    SELECT RAISE(ROLLBACK, 'update on "package_rel_map" violates FK constraint on "packages.id"')
      WHERE (SELECT id FROM packages WHERE id = NEW.package_id) IS NULL;
  END;

CREATE TRIGGER fku_package_rel_map_component_id_components_id
  BEFORE UPDATE ON [package_rel_map]
  FOR EACH ROW BEGIN
    SELECT RAISE(ROLLBACK, 'update on "package_rel_map" violates FK constraint on "components.id"')
     WHERE (SELECT id FROM components WHERE id=NEW.component_id) IS NULL;
  END;

-- when a package/component/suite id is deleted, clean up any references
-- that would otherwise be orphaned

CREATE TRIGGER fkdc_package_rel_map_suite_id_suites_id
  BEFORE DELETE ON suites
  FOR EACH ROW BEGIN
    DELETE FROM package_rel_map WHERE package_rel_map.suite_id = OLD.id;
  END;

CREATE TRIGGER fkdc_package_rel_map_component_id_components_id
  BEFORE DELETE ON components
  FOR EACH ROW BEGIN
    DELETE FROM package_rel_map WHERE package_rel_map.component_id = OLD.id;
  END;

CREATE TRIGGER fkdc_package_rel_map_package_id_packages_id
  BEFORE DELETE ON packages
  FOR EACH ROW BEGIN
    DELETE FROM package_rel_map WHERE package_rel_map.package_id = OLD.id;
  END;

-- when a package relation mapping is deleted or updated, delete the package 
-- record for the old relation if no other references to that package exist

CREATE TRIGGER fkdc_packages_id_package_rel_map_package_id
  BEFORE DELETE ON package_rel_map
  FOR EACH ROW BEGIN
    DELETE FROM packages WHERE packages.id = OLD.package_id
      AND (SELECT package_id FROM package_rel_map 
                     WHERE package_id = OLD.package_id AND rowid != OLD.rowid) 
      IS NULL;
  END;

CREATE TRIGGER fku_package_rel_map_prune_packages_package_id
  BEFORE UPDATE ON [package_rel_map]
  FOR EACH ROW BEGIN
    DELETE FROM packages WHERE packages.id = OLD.package_id
      AND (OLD.package_id != NEW.package_id)
      AND (SELECT package_id FROM package_rel_map 
                     WHERE package_id = OLD.package_id AND rowid != OLD.rowid) 
      IS NULL;
  END;
