Skip to content

Instantly share code, notes, and snippets.

@perrygeo
Last active January 24, 2023 16:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save perrygeo/7121b8adba10769f8c3d3a4659468ffb to your computer and use it in GitHub Desktop.
Save perrygeo/7121b8adba10769f8c3d3a4659468ffb to your computer and use it in GitHub Desktop.
DROP TABLE if EXISTS boundaries;
CREATE TABLE boundaries (
id BIGSERIAL primary key,
geometry geometry(multipolygon, 4326) NOT null
);
CREATE INDEX idx_boundaries_geometry
ON boundaries
USING gist (geometry);
CREATE or replace FUNCTION boundaries_no_overlap()
RETURNS trigger
LANGUAGE plpgsql AS
$$
BEGIN
-- To avoid concurrent insert/update, lock the table but allow read access
LOCK boundaries IN SHARE MODE;
IF (
SELECT count(1)
FROM boundaries as b
WHERE b.id <> new.id
AND ST_Overlaps(b.geometry, new.geometry)
) > 0
THEN
RAISE EXCEPTION 'This field geometry is invalid, overlaps existing boundaries(s)';
END IF;
RETURN NEW;
END;
$$;
CREATE TRIGGER boundaries_overlap_check
BEFORE INSERT OR UPDATE
ON boundaries
FOR EACH ROW EXECUTE PROCEDURE boundaries_no_overlap();
------------------------------------------------
-- TESTING
------------------------------------------------
-- GOOD
insert into boundaries (geometry)
values ('MULTIPOLYGON(((10 20, 20 20, 20 10, 10 10, 10 20)))');
-- to the right touches but does not overlap
insert into boundaries (geometry)
values ('MULTIPOLYGON(((20 20, 30 20, 30 10, 20 10, 20 20)))');
-- update to nudge it right
update boundaries
set geometry = 'MULTIPOLYGON(((21 20, 31 20, 31 10, 21 10, 21 20)))'
where id = 2;
------------------------------------------------
-- BAD, overlaping
insert into boundaries (geometry)
values ('MULTIPOLYGON(((22 20, 32 20, 32 10, 22 10, 22 20)))');
update boundaries
set geometry = 'MULTIPOLYGON(((22 20, 32 20, 32 10, 22 10, 22 20)))'
where id = 1;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment