]> git.openstreetmap.org Git - nominatim.git/blobdiff - sql/functions/placex_triggers.sql
Merge pull request #2027 from lonvia/remove-duplicate-admin-boundaries
[nominatim.git] / sql / functions / placex_triggers.sql
index 27fa3643b0b9ce2f61f76a9b7c984f576830e03c..1e2aac4c96fcc88a6e188eacf43a0888135458e6 100644 (file)
@@ -494,33 +494,6 @@ END;
 $$
 LANGUAGE plpgsql;
 
-CREATE OR REPLACE FUNCTION get_parent_address_level(geom GEOMETRY, in_level SMALLINT)
-  RETURNS SMALLINT
-  AS $$
-DECLARE
-  address_rank SMALLINT;
-BEGIN
-  IF in_level <= 3 or in_level > 15 THEN
-    address_rank := 3;
-  ELSE
-    SELECT rank_address INTO address_rank
-      FROM placex
-      WHERE osm_type = 'R' and class = 'boundary' and type = 'administrative'
-            and admin_level < in_level
-            and geometry ~ geom and _ST_Covers(geometry, geom)
-      ORDER BY admin_level desc LIMIT 1;
-  END IF;
-
-  IF address_rank is NULL or address_rank <= 3 THEN
-    RETURN 3;
-  END IF;
-
-  RETURN address_rank;
-END;
-$$
-LANGUAGE plpgsql;
-
-
 CREATE OR REPLACE FUNCTION placex_update()
   RETURNS TRIGGER
   AS $$
@@ -610,26 +583,51 @@ BEGIN
      and NEW.osm_type = 'R' and NEW.rank_address > 0
   THEN
     -- First, check that admin boundaries do not overtake each other rank-wise.
-    parent_address_level := get_parent_address_level(NEW.centroid, NEW.admin_level);
-    IF parent_address_level >= NEW.rank_address THEN
-      IF parent_address_level >= 24 THEN
-        NEW.rank_address := 25;
-      ELSE
-        NEW.rank_address := parent_address_level + 2;
-      END IF;
-    END IF;
-    -- Second check that the boundary is not completely contained in a
-    -- place area with a higher address rank
+    parent_address_level := 3;
     FOR location IN
-      SELECT rank_address FROM placex
-      WHERE class = 'place' and rank_address < 24
-            and rank_address > NEW.rank_address
-            and geometry ~ NEW.geometry
-            and ST_Relate(geometry, NEW.geometry, 'T*T***FF*') -- contains but not equal
-      ORDER BY rank_address desc LIMIT 1
+      SELECT rank_address,
+             (CASE WHEN extratags ? 'wikidata' and NEW.extratags ? 'wikidata'
+                        and extratags->'wikidata' = NEW.extratags->'wikidata'
+                   THEN ST_Equals(geometry, NEW.geometry)
+                   ELSE false END) as is_same
+      FROM placex
+      WHERE osm_type = 'R' and class = 'boundary' and type = 'administrative'
+            and admin_level < NEW.admin_level and admin_level > 3
+            and rank_address > 0
+            and geometry && NEW.centroid and _ST_Covers(geometry, NEW.centroid)
+      ORDER BY admin_level desc LIMIT 1
     LOOP
-        NEW.rank_address := location.rank_address + 2;
+      IF location.is_same THEN
+        -- Looks like the same boundary is replicated on multiple admin_levels.
+        -- Usual tagging in Poland. Remove our boundary from addresses.
+        NEW.rank_address := 0;
+      ELSE
+        parent_address_level := location.rank_address;
+        IF location.rank_address >= NEW.rank_address THEN
+          IF location.rank_address >= 24 THEN
+            NEW.rank_address := 25;
+          ELSE
+            NEW.rank_address := location.rank_address + 2;
+          END IF;
+        END IF;
+      END IF;
     END LOOP;
+
+    IF NEW.rank_address > 9 THEN
+        -- Second check that the boundary is not completely contained in a
+        -- place area with a higher address rank
+        FOR location IN
+          SELECT rank_address FROM placex
+          WHERE class = 'place' and rank_address < 24
+                and rank_address > NEW.rank_address
+                and geometry && NEW.geometry
+                and geometry ~ NEW.geometry -- needed because ST_Relate does not do bbox cover test
+                and ST_Relate(geometry, NEW.geometry, 'T*T***FF*') -- contains but not equal
+          ORDER BY rank_address desc LIMIT 1
+        LOOP
+          NEW.rank_address := location.rank_address + 2;
+        END LOOP;
+    END IF;
   ELSEIF NEW.class = 'place' and NEW.osm_type = 'N'
      and NEW.rank_address between 16 and 23
   THEN
@@ -640,7 +638,7 @@ BEGIN
         SELECT rank_address FROM placex
         WHERE osm_type = 'R' and class = 'boundary' and type = 'administrative'
               and rank_address = NEW.rank_address
-              and geometry ~ NEW.centroid and _ST_Covers(geometry, NEW.centroid)
+              and geometry && NEW.centroid and _ST_Covers(geometry, NEW.centroid)
         LIMIT 1
     LOOP
       NEW.rank_address = NEW.rank_address + 2;
@@ -743,10 +741,10 @@ BEGIN
     IF NEW.osm_type = 'N' AND addr_street IS NULL AND addr_place IS NULL
        AND NEW.housenumber IS NULL THEN
       FOR location IN
-        -- The additional ~ condition works around the misguided query
+        -- The additional && condition works around the misguided query
         -- planner of postgis 3.0.
         SELECT address from placex where ST_Covers(geometry, NEW.centroid)
-            and geometry ~ NEW.centroid
+            and geometry && NEW.centroid
             and (address ? 'housenumber' or address ? 'street' or address ? 'place')
             and rank_search > 28 AND ST_GeometryType(geometry) in ('ST_Polygon','ST_MultiPolygon')
             limit 1
@@ -801,7 +799,8 @@ BEGIN
           IF NEW.rank_search <= 25 and NEW.rank_address > 0 THEN
             result := add_location(NEW.place_id, NEW.country_code, NEW.partition,
                                    name_vector, NEW.rank_search, NEW.rank_address,
-                                   upper(trim(NEW.address->'postcode')), NEW.geometry);
+                                   upper(trim(NEW.address->'postcode')), NEW.geometry,
+                                   NEW.centroid);
             --DEBUG: RAISE WARNING 'Place added to location table';
           END IF;
 
@@ -932,7 +931,7 @@ BEGIN
   IF NEW.name IS NOT NULL THEN
 
     IF NEW.rank_search <= 25 and NEW.rank_address > 0 THEN
-      result := add_location(NEW.place_id, NEW.country_code, NEW.partition, name_vector, NEW.rank_search, NEW.rank_address, upper(trim(NEW.address->'postcode')), NEW.geometry);
+      result := add_location(NEW.place_id, NEW.country_code, NEW.partition, name_vector, NEW.rank_search, NEW.rank_address, upper(trim(NEW.address->'postcode')), NEW.geometry, NEW.centroid);
       --DEBUG: RAISE WARNING 'added to location (full)';
     END IF;