X-Git-Url: https://git.openstreetmap.org/nominatim.git/blobdiff_plain/e55abf8105775ff3692f6a0caf1f18bed325b85b..98b93df83d35f9062c85a5c93692206dfcbfa92d:/sql/functions.sql diff --git a/sql/functions.sql b/sql/functions.sql index bb1081fb..49a6e972 100644 --- a/sql/functions.sql +++ b/sql/functions.sql @@ -347,7 +347,7 @@ BEGIN w := getorcreate_word_id(s); - IF NOT (ARRAY[w] <@ result) THEN + IF w IS NOT NULL AND NOT (ARRAY[w] <@ result) THEN result := result || w; END IF; @@ -415,7 +415,7 @@ BEGIN w := getorcreate_word_id(s); - IF NOT (ARRAY[w] <@ result) THEN + IF w IS NOT NULL AND NOT (ARRAY[w] <@ result) THEN result := result || w; END IF; @@ -495,6 +495,12 @@ BEGIN --DEBUG: RAISE WARNING 'get_country_code, start: %', ST_AsText(place_centre); + -- Try for a OSM polygon + FOR nearcountry IN select country_code from location_area_country where country_code is not null and not isguess and st_covers(geometry, place_centre) limit 1 + LOOP + RETURN nearcountry.country_code; + END LOOP; + --DEBUG: RAISE WARNING 'osm fallback: %', ST_AsText(place_centre); -- Try for OSM fallback data @@ -504,12 +510,6 @@ BEGIN RETURN nearcountry.country_code; END LOOP; - -- Try for a OSM polygon - FOR nearcountry IN select country_code from location_area_country where country_code is not null and not isguess and st_covers(geometry, place_centre) limit 1 - LOOP - RETURN nearcountry.country_code; - END LOOP; - --DEBUG: RAISE WARNING 'natural earth: %', ST_AsText(place_centre); -- Natural earth data @@ -823,9 +823,13 @@ BEGIN FOR nodeidpos in 1..array_upper(waynodes, 1) LOOP - select min(place_id) from placex where osm_type = 'N' and osm_id = waynodes[nodeidpos]::BIGINT and type = 'house' INTO search_place_id; + -- If there is a place of a type other than place/house, use that because + -- it is guaranteed to be the original node. For place/house types use the + -- one with the smallest id because the original node was created first. + -- Ignore all nodes marked for deletion. (Might happen when the type changes.) + select place_id from placex where osm_type = 'N' and osm_id = waynodes[nodeidpos]::BIGINT and indexed_status < 100 order by (type = 'house'),place_id limit 1 INTO search_place_id; IF search_place_id IS NULL THEN - -- null record of right type + -- if no such node exists, create a record of the right type select * from placex where osm_type = 'N' and osm_id = waynodes[nodeidpos]::BIGINT and type = 'house' limit 1 INTO nextnode; select ST_SetSRID(ST_Point(lon::float/10000000,lat::float/10000000),4326) from planet_osm_nodes where id = waynodes[nodeidpos] INTO nextnode.geometry; IF nextnode.geometry IS NULL THEN @@ -890,8 +894,8 @@ BEGIN -- ideally postcodes should move up to the way insert into placex (osm_type, osm_id, class, type, admin_level, housenumber, street, addr_place, isin, postcode, country_code, parent_place_id, rank_address, rank_search, indexed_status, geometry) - values ('N',prevnode.osm_id, prevnode.class, prevnode.type, prevnode.admin_level, housenum, prevnode.street, prevnode.addr_place, prevnode.isin, coalesce(prevnode.postcode, defpostalcode), - prevnode.country_code, prevnode.parent_place_id, prevnode.rank_address, prevnode.rank_search, 1, ST_Line_Interpolate_Point(linegeo, (housenum::float-orginalstartnumber::float)/originalnumberrange::float)); + values ('N',prevnode.osm_id, 'place', 'house', prevnode.admin_level, housenum, prevnode.street, prevnode.addr_place, prevnode.isin, coalesce(prevnode.postcode, defpostalcode), + prevnode.country_code, prevnode.parent_place_id, prevnode.rank_address, prevnode.rank_search, 1, ST_LineInterpolatePoint(linegeo, (housenum::float-orginalstartnumber::float)/originalnumberrange::float)); newpoints := newpoints + 1; --RAISE WARNING 'interpolation number % % ',prevnode.place_id,housenum; END LOOP; @@ -934,10 +938,6 @@ BEGIN --DEBUG: RAISE WARNING '% %',NEW.osm_type,NEW.osm_id; -- just block these - IF NEW.class = 'highway' and NEW.type in ('turning_circle','traffic_signals','mini_roundabout','noexit','crossing') THEN --- RAISE WARNING 'bad highway %',NEW.osm_id; - RETURN null; - END IF; IF NEW.class in ('landuse','natural') and NEW.name is null THEN -- RAISE WARNING 'empty landuse %',NEW.osm_id; RETURN null; @@ -1090,10 +1090,10 @@ BEGIN ELSEIF NEW.type in ('national_park') THEN NEW.rank_search := 18; NEW.rank_address := 18; - ELSEIF NEW.type in ('suburb','croft','subdivision') THEN + ELSEIF NEW.type in ('suburb','croft','subdivision','isolated_dwelling') THEN NEW.rank_search := 20; NEW.rank_address := NEW.rank_search; - ELSEIF NEW.type in ('farm','locality','islet','isolated_dwelling','mountain_pass') THEN + ELSEIF NEW.type in ('farm','locality','islet','mountain_pass') THEN NEW.rank_search := 20; NEW.rank_address := 0; -- Irish townlands, tagged as place=locality and locality=townland @@ -1123,7 +1123,11 @@ BEGIN return NULL; END IF; NEW.rank_search := NEW.admin_level * 2; - NEW.rank_address := NEW.rank_search; + IF NEW.type = 'administrative' THEN + NEW.rank_address := NEW.rank_search; + ELSE + NEW.rank_address := 0; + END IF; ELSEIF NEW.class = 'landuse' AND ST_GeometryType(NEW.geometry) in ('ST_Polygon','ST_MultiPolygon') THEN NEW.rank_search := 22; NEW.rank_address := NEW.rank_search; @@ -1241,7 +1245,7 @@ BEGIN -- Note: won't work on initial import because the classtype tables -- do not yet exist. It won't hurt either. classtable := 'place_classtype_' || NEW.class || '_' || NEW.type; - SELECT count(*)>0 FROM pg_tables WHERE tablename = classtable INTO result; + SELECT count(*)>0 FROM pg_tables WHERE tablename = classtable and schemaname = current_schema() INTO result; IF result THEN EXECUTE 'INSERT INTO ' || classtable::regclass || ' (place_id, centroid) VALUES ($1,$2)' USING NEW.place_id, ST_Centroid(NEW.geometry); @@ -1480,9 +1484,9 @@ BEGIN FOR relation IN SELECT place_id FROM placex WHERE ST_DWithin(location.geometry, placex.geometry, 0.001) and placex.rank_search = 26 and st_geometrytype(location.geometry) in ('ST_LineString') - ORDER BY (ST_distance(placex.geometry, ST_Line_Interpolate_Point(location.geometry,0))+ - ST_distance(placex.geometry, ST_Line_Interpolate_Point(location.geometry,0.5))+ - ST_distance(placex.geometry, ST_Line_Interpolate_Point(location.geometry,1))) ASC limit 1 + ORDER BY (ST_distance(placex.geometry, ST_LineInterpolatePoint(location.geometry,0))+ + ST_distance(placex.geometry, ST_LineInterpolatePoint(location.geometry,0.5))+ + ST_distance(placex.geometry, ST_LineInterpolatePoint(location.geometry,1))) ASC limit 1 LOOP --RAISE WARNING 'using nearest street to address interpolation line,0.001 %',relation; NEW.parent_place_id := relation.place_id; @@ -1672,6 +1676,11 @@ BEGIN END IF; END IF; + END IF; + + -- Name searches can be done for ways as well as relations + IF NEW.osm_type in ('W','R') AND NEW.rank_search < 26 THEN + -- not found one yet? how about doing a name search IF NEW.centroid IS NULL AND (NEW.name->'name') is not null and make_standard_name(NEW.name->'name') != '' THEN @@ -1828,19 +1837,21 @@ BEGIN INSERT INTO place_addressline VALUES (NEW.place_id, location.place_id, true, location_isaddress, location.distance, location.rank_address); IF location_isaddress THEN - address_havelevel[location.rank_address] := true; - IF NOT location.isguess THEN - SELECT geometry FROM placex WHERE place_id = location.place_id INTO location_parent; - END IF; - END IF; ---RAISE WARNING ' Terms: (%) %',location, nameaddress_vector; + address_havelevel[location.rank_address] := true; + IF NOT location.isguess THEN + SELECT geometry FROM placex WHERE place_id = location.place_id INTO location_parent; + END IF; + + IF location.rank_address > parent_place_id_rank THEN + NEW.parent_place_id = location.place_id; + parent_place_id_rank = location.rank_address; + END IF; - IF location.rank_address > parent_place_id_rank THEN - NEW.parent_place_id = location.place_id; - parent_place_id_rank = location.rank_address; END IF; +--RAISE WARNING ' Terms: (%) %',location, nameaddress_vector; + END IF; END LOOP; @@ -1942,7 +1953,7 @@ BEGIN -- mark everything linked to this place for re-indexing --DEBUG: RAISE WARNING 'placex_delete:03 % %',OLD.osm_type,OLD.osm_id; UPDATE placex set indexed_status = 2 from place_addressline where address_place_id = OLD.place_id - and placex.place_id = place_addressline.place_id and indexed_status = 0; + and placex.place_id = place_addressline.place_id and indexed_status = 0 and place_addressline.isaddress; --DEBUG: RAISE WARNING 'placex_delete:04 % %',OLD.osm_type,OLD.osm_id; DELETE FROM place_addressline where address_place_id = OLD.place_id; @@ -1976,7 +1987,7 @@ BEGIN -- remove from tables for special search classtable := 'place_classtype_' || OLD.class || '_' || OLD.type; - SELECT count(*)>0 FROM pg_tables WHERE tablename = classtable INTO b; + SELECT count(*)>0 FROM pg_tables WHERE tablename = classtable and schemaname = current_schema() INTO b; IF b THEN EXECUTE 'DELETE FROM ' || classtable::regclass || ' WHERE place_id = $1' USING OLD.place_id; END IF; @@ -2033,9 +2044,6 @@ BEGIN END IF; -- Just block these - lots and pointless - IF NEW.class = 'highway' and NEW.type in ('turning_circle','traffic_signals','mini_roundabout','noexit','crossing') THEN - RETURN null; - END IF; IF NEW.class in ('landuse','natural') and NEW.name is null THEN RETURN null; END IF; @@ -2082,10 +2090,24 @@ BEGIN DELETE from import_polygon_error where osm_type = NEW.osm_type and osm_id = NEW.osm_id; DELETE from import_polygon_delete where osm_type = NEW.osm_type and osm_id = NEW.osm_id; - -- To paraphrase, if there isn't an existing item, OR if the admin level has changed, OR if it is a major change in geometry - IF existingplacex.osm_type IS NULL THEN + -- To paraphrase, if there isn't an existing item, OR if the admin level has changed + IF existingplacex.osm_type IS NULL OR + coalesce(existingplacex.admin_level, 15) != coalesce(NEW.admin_level, 15) + THEN + + IF existingplacex.osm_type IS NOT NULL THEN + -- sanity check: ignore admin_level changes on places with too many active children + -- or we end up reindexing entire countries because somebody accidentally deleted admin_level + --LIMIT INDEXING: SELECT count(*) FROM (SELECT 'a' FROM placex , place_addressline where address_place_id = existingplacex.place_id and placex.place_id = place_addressline.place_id and indexed_status = 0 and place_addressline.isaddress LIMIT 100001) sub INTO i; + --LIMIT INDEXING: IF i > 100000 THEN + --LIMIT INDEXING: RETURN null; + --LIMIT INDEXING: END IF; + END IF; IF existing.osm_type IS NOT NULL THEN + -- pathological case caused by the triggerless copy into place during initial import + -- force delete even for large areas, it will be reinserted later + UPDATE place set geometry = ST_SetSRID(ST_Point(0,0), 4326) where osm_type = NEW.osm_type and osm_id = NEW.osm_id and class = NEW.class and type = NEW.type; DELETE from place where osm_type = NEW.osm_type and osm_id = NEW.osm_id and class = NEW.class and type = NEW.type; END IF; @@ -2230,6 +2252,7 @@ BEGIN postcode = NEW.postcode, country_code = NEW.country_code, extratags = NEW.extratags, + admin_level = NEW.admin_level, geometry = NEW.geometry where osm_type = NEW.osm_type and osm_id = NEW.osm_id and class = NEW.class and type = NEW.type; @@ -2243,6 +2266,7 @@ BEGIN country_code = NEW.country_code, parent_place_id = null, extratags = NEW.extratags, + admin_level = CASE WHEN NEW.admin_level > 15 THEN 15 ELSE NEW.admin_level END, indexed_status = 2, geometry = NEW.geometry where place_id = existingplacex.place_id; @@ -2468,7 +2492,7 @@ BEGIN CASE WHEN class = 'place' and type = 'postcode' THEN hstore('name', postcode) ELSE name END as name, class, type, admin_level, fromarea, isaddress, CASE WHEN address_place_id = for_place_id AND rank_address = 0 THEN 100 WHEN rank_address = 11 THEN 5 ELSE rank_address END as rank_address, - distance,calculated_country_code + distance,calculated_country_code,postcode from place_addressline join placex on (address_place_id = placex.place_id) where place_addressline.place_id = for_place_id and (cached_rank_address > 0 AND cached_rank_address < searchrankaddress) @@ -2483,6 +2507,9 @@ BEGIN IF searchpostcode IS NOT NULL and location.type = 'postcode' THEN location.isaddress := FALSE; END IF; + IF searchpostcode IS NULL and location.isaddress and location.type != 'postcode' and location.postcode IS NOT NULL THEN + searchpostcode := location.postcode; + END IF; IF location.rank_address = 4 AND location.isaddress THEN hadcountry := true; END IF; @@ -3080,10 +3107,10 @@ BEGIN diameter := 0.001; -- 50 to 100 meters END IF; IF diameter > 0 THEN - IF NEW.rank_search >= 26 THEN + IF rank >= 26 THEN -- roads may cause reparenting for >27 rank places update placex set indexed_status = 2 where indexed_status = 0 and rank_search > rank and ST_DWithin(placex.geometry, placegeom, diameter); - ELSEIF NEW.rank_search >= 16 THEN + ELSEIF rank >= 16 THEN -- up to rank 16, street-less addresses may need reparenting update placex set indexed_status = 2 where indexed_status = 0 and rank_search > rank and ST_DWithin(placex.geometry, placegeom, diameter) and (rank_search < 28 or name is not null or addr_place is not null); ELSE