mirror of
https://github.com/osm-search/Nominatim.git
synced 2026-03-07 02:24:08 +00:00
adapt interpolation handling to use separate place_interpolation table
This commit is contained in:
@@ -2,11 +2,106 @@
|
|||||||
--
|
--
|
||||||
-- This file is part of Nominatim. (https://nominatim.org)
|
-- This file is part of Nominatim. (https://nominatim.org)
|
||||||
--
|
--
|
||||||
-- Copyright (C) 2022 by the Nominatim developer community.
|
-- Copyright (C) 2026 by the Nominatim developer community.
|
||||||
-- For a full list of authors see the git log.
|
-- For a full list of authors see the git log.
|
||||||
|
|
||||||
-- Functions for address interpolation objects in location_property_osmline.
|
-- Functions for address interpolation objects in location_property_osmline.
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION place_interpolation_insert()
|
||||||
|
RETURNS TRIGGER
|
||||||
|
AS $$
|
||||||
|
DECLARE
|
||||||
|
existing RECORD;
|
||||||
|
existingplacex BIGINT[];
|
||||||
|
|
||||||
|
BEGIN
|
||||||
|
-- Remove the place from the list of places to be deleted
|
||||||
|
DELETE FROM place_interpolation_to_be_deleted pdel
|
||||||
|
WHERE pdel.osm_type = NEW.osm_type and pdel.osm_id = NEW.osm_id;
|
||||||
|
|
||||||
|
SELECT * INTO existing FROM place_interpolation p
|
||||||
|
WHERE p.osm_type = NEW.osm_type AND p.osm_id = NEW.osm_id;
|
||||||
|
|
||||||
|
IF NOT (NEW.type in ('odd', 'even', 'all') OR NEW.type similar to '[1-9]') THEN
|
||||||
|
-- the new interpolation is illegal, simply remove existing entries
|
||||||
|
DELETE FROM location_property_osmline o
|
||||||
|
WHERE o.osm_type = NEW.osm_type AND o.osm_id = NEW.osm_id;
|
||||||
|
ELSE
|
||||||
|
-- Get the existing entry from the interpolation table.
|
||||||
|
SELECT array_agg(place_id) INTO existingplacex
|
||||||
|
FROM location_property_osmline o
|
||||||
|
WHERE o.osm_type = NEW.osm_type AND o.osm_id = NEW.osm_id;
|
||||||
|
|
||||||
|
IF array_length(existingplacex, 1) is NULL THEN
|
||||||
|
INSERT INTO location_property_osmline (osm_type, osm_id, type, address, linegeo)
|
||||||
|
VALUES (NEW.osm_type, NEW.osm_id, NEW.type, NEW.address, NEW.geometry);
|
||||||
|
ELSE
|
||||||
|
-- Update the interpolation table:
|
||||||
|
-- The first entry gets the original data, all other entries
|
||||||
|
-- are removed and will be recreated on indexing.
|
||||||
|
-- (An interpolation can be split up, if it has more than 2 address nodes)
|
||||||
|
-- Update unconditionally here as the changes might be coming from the
|
||||||
|
-- nodes on the interpolation.
|
||||||
|
UPDATE location_property_osmline
|
||||||
|
SET type = NEW.type,
|
||||||
|
address = NEW.address,
|
||||||
|
linegeo = NEW.geometry,
|
||||||
|
startnumber = null,
|
||||||
|
indexed_status = 1
|
||||||
|
WHERE place_id = existingplacex[1];
|
||||||
|
IF array_length(existingplacex, 1) > 1 THEN
|
||||||
|
DELETE FROM location_property_osmline
|
||||||
|
WHERE place_id = any(existingplacex[2:]);
|
||||||
|
END IF;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- need to invalidate nodes because they might copy address info
|
||||||
|
IF NEW.address is not NULL
|
||||||
|
AND (existing.osm_type is NULL
|
||||||
|
OR coalesce(existing.address, ''::hstore) != NEW.address)
|
||||||
|
THEN
|
||||||
|
UPDATE placex SET indexed_status = 2
|
||||||
|
WHERE osm_type = 'N' AND osm_id = ANY(NEW.nodes)
|
||||||
|
AND indexed_status = 0;
|
||||||
|
END IF;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- finally update/insert place_interpolation itself
|
||||||
|
|
||||||
|
IF existing.osm_type is not NULL THEN
|
||||||
|
IF existing.type != NEW.type
|
||||||
|
OR coalesce(existing.address, ''::hstore) != coalesce(NEW.address, ''::hstore)
|
||||||
|
OR existing.geometry::text != NEW.geometry::text
|
||||||
|
THEN
|
||||||
|
UPDATE place_interpolation p
|
||||||
|
SET type = NEW.type,
|
||||||
|
address = NEW.address,
|
||||||
|
geometry = NEW.geometry
|
||||||
|
WHERE p.osm_type = NEW.osm_type AND p.osm_id = NEW.osm_id;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
RETURN NULL;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
RETURN NEW;
|
||||||
|
END;
|
||||||
|
$$ LANGUAGE plpgsql;
|
||||||
|
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION place_interpolation_delete()
|
||||||
|
RETURNS TRIGGER
|
||||||
|
AS $$
|
||||||
|
DECLARE
|
||||||
|
deferred BOOLEAN;
|
||||||
|
BEGIN
|
||||||
|
{% if debug %}RAISE WARNING 'Delete for % % %/%', OLD.osm_type, OLD.osm_id, OLD.class, OLD.type;{% endif %}
|
||||||
|
|
||||||
|
INSERT INTO place_interpolation_to_be_deleted (osm_type, osm_id)
|
||||||
|
VALUES(OLD.osm_type, OLD.osm_id);
|
||||||
|
|
||||||
|
RETURN NULL;
|
||||||
|
END;
|
||||||
|
$$ LANGUAGE plpgsql;
|
||||||
|
|
||||||
CREATE OR REPLACE FUNCTION get_interpolation_address(in_address HSTORE, wayid BIGINT)
|
CREATE OR REPLACE FUNCTION get_interpolation_address(in_address HSTORE, wayid BIGINT)
|
||||||
RETURNS HSTORE
|
RETURNS HSTORE
|
||||||
@@ -28,7 +123,7 @@ BEGIN
|
|||||||
and indexed_status < 100
|
and indexed_status < 100
|
||||||
LOOP
|
LOOP
|
||||||
-- mark it as a derived address
|
-- mark it as a derived address
|
||||||
RETURN location.address || in_address || hstore('_inherited', '');
|
RETURN location.address || coalesce(in_address, '{}'::hstore) || hstore('_inherited', '');
|
||||||
END LOOP;
|
END LOOP;
|
||||||
|
|
||||||
RETURN in_address;
|
RETURN in_address;
|
||||||
@@ -73,51 +168,6 @@ $$
|
|||||||
LANGUAGE plpgsql STABLE PARALLEL SAFE;
|
LANGUAGE plpgsql STABLE PARALLEL SAFE;
|
||||||
|
|
||||||
|
|
||||||
CREATE OR REPLACE FUNCTION reinsert_interpolation(way_id BIGINT, addr HSTORE,
|
|
||||||
geom GEOMETRY)
|
|
||||||
RETURNS INT
|
|
||||||
AS $$
|
|
||||||
DECLARE
|
|
||||||
existing BIGINT[];
|
|
||||||
BEGIN
|
|
||||||
IF addr is NULL OR NOT addr ? 'interpolation'
|
|
||||||
OR NOT (addr->'interpolation' in ('odd', 'even', 'all')
|
|
||||||
or addr->'interpolation' similar to '[1-9]')
|
|
||||||
THEN
|
|
||||||
-- the new interpolation is illegal, simply remove existing entries
|
|
||||||
DELETE FROM location_property_osmline WHERE osm_id = way_id;
|
|
||||||
ELSE
|
|
||||||
-- Get the existing entry from the interpolation table.
|
|
||||||
SELECT array_agg(place_id) INTO existing
|
|
||||||
FROM location_property_osmline WHERE osm_id = way_id;
|
|
||||||
|
|
||||||
IF existing IS NULL or array_length(existing, 1) = 0 THEN
|
|
||||||
INSERT INTO location_property_osmline (osm_id, address, linegeo)
|
|
||||||
VALUES (way_id, addr, geom);
|
|
||||||
ELSE
|
|
||||||
-- Update the interpolation table:
|
|
||||||
-- The first entry gets the original data, all other entries
|
|
||||||
-- are removed and will be recreated on indexing.
|
|
||||||
-- (An interpolation can be split up, if it has more than 2 address nodes)
|
|
||||||
UPDATE location_property_osmline
|
|
||||||
SET address = addr,
|
|
||||||
linegeo = geom,
|
|
||||||
startnumber = null,
|
|
||||||
indexed_status = 1
|
|
||||||
WHERE place_id = existing[1];
|
|
||||||
IF array_length(existing, 1) > 1 THEN
|
|
||||||
DELETE FROM location_property_osmline
|
|
||||||
WHERE place_id = any(existing[2:]);
|
|
||||||
END IF;
|
|
||||||
END IF;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
RETURN 1;
|
|
||||||
END;
|
|
||||||
$$
|
|
||||||
LANGUAGE plpgsql;
|
|
||||||
|
|
||||||
|
|
||||||
CREATE OR REPLACE FUNCTION osmline_insert()
|
CREATE OR REPLACE FUNCTION osmline_insert()
|
||||||
RETURNS TRIGGER
|
RETURNS TRIGGER
|
||||||
AS $$
|
AS $$
|
||||||
@@ -128,20 +178,32 @@ BEGIN
|
|||||||
NEW.indexed_date := now();
|
NEW.indexed_date := now();
|
||||||
|
|
||||||
IF NEW.indexed_status IS NULL THEN
|
IF NEW.indexed_status IS NULL THEN
|
||||||
IF NEW.address is NULL OR NOT NEW.address ? 'interpolation'
|
IF NOT(NEW.type in ('odd', 'even', 'all') OR NEW.type similar to '[1-9]') THEN
|
||||||
OR NOT (NEW.address->'interpolation' in ('odd', 'even', 'all')
|
-- alphabetic interpolation is not supported
|
||||||
or NEW.address->'interpolation' similar to '[1-9]')
|
RETURN NULL;
|
||||||
THEN
|
END IF;
|
||||||
-- alphabetic interpolation is not supported
|
|
||||||
|
IF NEW.address is not NULL AND NEW.address ? 'housenumber' THEN
|
||||||
|
IF NEW.address->'housenumber' not similar to '[0-9]+-[0-9]+' THEN
|
||||||
|
-- housenumber needs to look like an interpolation
|
||||||
RETURN NULL;
|
RETURN NULL;
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
NEW.indexed_status := 1; --STATUS_NEW
|
centroid := ST_Centroid(NEW.linegeo);
|
||||||
|
-- interpolation of a housenumber, make sure we have a line to interpolate on
|
||||||
|
NEW.geometry := ST_MakeLine(centroid, ST_Project(centroid, 0.0000001, 0));
|
||||||
|
ELSE
|
||||||
centroid := get_center_point(NEW.linegeo);
|
centroid := get_center_point(NEW.linegeo);
|
||||||
NEW.country_code := lower(get_country_code(centroid));
|
IF NEW.osm_type != 'W' THEN
|
||||||
|
RETURN NULL;
|
||||||
|
END IF;
|
||||||
|
END IF;
|
||||||
|
|
||||||
NEW.partition := get_partition(NEW.country_code);
|
NEW.indexed_status := 1; --STATUS_NEW
|
||||||
NEW.geometry_sector := geometry_sector(NEW.partition, centroid);
|
NEW.country_code := lower(get_country_code(centroid));
|
||||||
|
|
||||||
|
NEW.partition := get_partition(NEW.country_code);
|
||||||
|
NEW.geometry_sector := geometry_sector(NEW.partition, centroid);
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
RETURN NEW;
|
RETURN NEW;
|
||||||
@@ -167,6 +229,7 @@ DECLARE
|
|||||||
sectiongeo GEOMETRY;
|
sectiongeo GEOMETRY;
|
||||||
postcode TEXT;
|
postcode TEXT;
|
||||||
stepmod SMALLINT;
|
stepmod SMALLINT;
|
||||||
|
splitstring TEXT[];
|
||||||
BEGIN
|
BEGIN
|
||||||
-- deferred delete
|
-- deferred delete
|
||||||
IF OLD.indexed_status = 100 THEN
|
IF OLD.indexed_status = 100 THEN
|
||||||
@@ -182,157 +245,173 @@ BEGIN
|
|||||||
get_center_point(NEW.linegeo),
|
get_center_point(NEW.linegeo),
|
||||||
NEW.linegeo);
|
NEW.linegeo);
|
||||||
|
|
||||||
-- Cannot find a parent street. We will not be able to display a reliable
|
|
||||||
-- address, so drop entire interpolation.
|
|
||||||
IF NEW.parent_place_id is NULL THEN
|
|
||||||
DELETE FROM location_property_osmline where place_id = OLD.place_id;
|
|
||||||
RETURN NULL;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
NEW.token_info := token_strip_info(NEW.token_info);
|
NEW.token_info := token_strip_info(NEW.token_info);
|
||||||
IF NEW.address ? '_inherited' THEN
|
IF NEW.address ? '_inherited' THEN
|
||||||
NEW.address := hstore('interpolation', NEW.address->'interpolation');
|
NEW.address := NULL;
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
-- If the line was newly inserted, split the line as necessary.
|
-- If the line was newly inserted, split the line as necessary.
|
||||||
IF OLD.indexed_status = 1 THEN
|
IF NEW.parent_place_id is not NULL AND NEW.startnumber is NULL THEN
|
||||||
IF NEW.address->'interpolation' in ('odd', 'even') THEN
|
IF NEW.type in ('odd', 'even') THEN
|
||||||
NEW.step := 2;
|
NEW.step := 2;
|
||||||
stepmod := CASE WHEN NEW.address->'interpolation' = 'odd' THEN 1 ELSE 0 END;
|
stepmod := CASE WHEN NEW.type = 'odd' THEN 1 ELSE 0 END;
|
||||||
ELSE
|
ELSE
|
||||||
NEW.step := CASE WHEN NEW.address->'interpolation' = 'all'
|
NEW.step := CASE WHEN NEW.type = 'all' THEN 1 ELSE (NEW.type)::SMALLINT END;
|
||||||
THEN 1
|
|
||||||
ELSE (NEW.address->'interpolation')::SMALLINT END;
|
|
||||||
stepmod := NULL;
|
stepmod := NULL;
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
SELECT nodes INTO waynodes
|
IF NEW.address is not NULL AND NEW.address ? 'housenumer' THEN
|
||||||
FROM planet_osm_ways WHERE id = NEW.osm_id;
|
-- interpolation interval is in housenumber
|
||||||
|
splitstring := string_to_array(NEW.address->'housenumber', '-');
|
||||||
|
NEW.startnumber := (splitstring[1])::INTEGER;
|
||||||
|
NEW.endnumber := (splitstring[2])::INTEGER;
|
||||||
|
|
||||||
IF array_upper(waynodes, 1) IS NULL THEN
|
IF stepmod is not NULL THEN
|
||||||
RETURN NEW;
|
IF NEW.startnumber % NEW.step != stepmod THEN
|
||||||
END IF;
|
NEW.startnumber := NEW.startnumber + 1;
|
||||||
|
|
||||||
linegeo := null;
|
|
||||||
SELECT null::integer as hnr INTO prevnode;
|
|
||||||
|
|
||||||
-- Go through all nodes on the interpolation line that have a housenumber.
|
|
||||||
FOR nextnode IN
|
|
||||||
SELECT DISTINCT ON (nodeidpos)
|
|
||||||
osm_id, address, geometry,
|
|
||||||
-- Take the postcode from the node only if it has a housenumber itself.
|
|
||||||
-- Note that there is a corner-case where the node has a wrongly
|
|
||||||
-- formatted postcode and therefore 'postcode' contains a derived
|
|
||||||
-- variant.
|
|
||||||
CASE WHEN address ? 'postcode' THEN placex.postcode ELSE NULL::text END as postcode,
|
|
||||||
(address->'housenumber')::integer as hnr
|
|
||||||
FROM placex, generate_series(1, array_upper(waynodes, 1)) nodeidpos
|
|
||||||
WHERE osm_type = 'N' and osm_id = waynodes[nodeidpos]::BIGINT
|
|
||||||
and address is not NULL and address ? 'housenumber'
|
|
||||||
and address->'housenumber' ~ '^[0-9]{1,6}$'
|
|
||||||
and ST_Distance(NEW.linegeo, geometry) < 0.0005
|
|
||||||
ORDER BY nodeidpos
|
|
||||||
LOOP
|
|
||||||
{% if debug %}RAISE WARNING 'processing point % (%)', nextnode.hnr, ST_AsText(nextnode.geometry);{% endif %}
|
|
||||||
IF linegeo is null THEN
|
|
||||||
linegeo := NEW.linegeo;
|
|
||||||
ELSE
|
|
||||||
splitpoint := ST_LineLocatePoint(linegeo, nextnode.geometry);
|
|
||||||
IF splitpoint = 0 THEN
|
|
||||||
-- Corner case where the splitpoint falls on the first point
|
|
||||||
-- and thus would not return a geometry. Skip that section.
|
|
||||||
sectiongeo := NULL;
|
|
||||||
ELSEIF splitpoint = 1 THEN
|
|
||||||
-- Point is at the end of the line.
|
|
||||||
sectiongeo := linegeo;
|
|
||||||
linegeo := NULL;
|
|
||||||
ELSE
|
|
||||||
-- Split the line.
|
|
||||||
sectiongeo := ST_LineSubstring(linegeo, 0, splitpoint);
|
|
||||||
linegeo := ST_LineSubstring(linegeo, splitpoint, 1);
|
|
||||||
END IF;
|
END IF;
|
||||||
|
IF NEW.endnumber % NEW.step != stepmod THEN
|
||||||
|
NEW.endnumber := NEW.endnumber - 1;
|
||||||
|
END IF;
|
||||||
|
ELSE
|
||||||
|
NEW.endnumber := NEW.startnumber + ((NEW.endnumber - NEW.startnumber) / NEW.step) * NEW.step;
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
IF prevnode.hnr is not null
|
IF NEW.startnumber = NEW.endnumber THEN
|
||||||
-- Check if there are housenumbers to interpolate between the
|
NEW.geometry := ST_PointN(NEW.geometry, 1);
|
||||||
-- regularly mapped housenumbers.
|
ELSEIF NEW.startnumber > NEW.endnumber THEN
|
||||||
-- (Conveniently also fails if one of the house numbers is not a number.)
|
NEW.startnumber := NULL;
|
||||||
and abs(prevnode.hnr - nextnode.hnr) > NEW.step
|
END IF;
|
||||||
-- If the interpolation geometry is broken or two nodes are at the
|
ELSE
|
||||||
-- same place, then splitting might produce a point. Ignore that.
|
-- classic interpolation way
|
||||||
and ST_GeometryType(sectiongeo) = 'ST_LineString'
|
SELECT nodes INTO waynodes
|
||||||
THEN
|
FROM planet_osm_ways WHERE id = NEW.osm_id;
|
||||||
IF prevnode.hnr < nextnode.hnr THEN
|
|
||||||
startnumber := prevnode.hnr;
|
|
||||||
endnumber := nextnode.hnr;
|
|
||||||
ELSE
|
|
||||||
startnumber := nextnode.hnr;
|
|
||||||
endnumber := prevnode.hnr;
|
|
||||||
sectiongeo := ST_Reverse(sectiongeo);
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
-- Adjust the interpolation, so that only inner housenumbers
|
IF array_upper(waynodes, 1) IS NULL THEN
|
||||||
-- are taken into account.
|
RETURN NEW;
|
||||||
IF stepmod is null THEN
|
END IF;
|
||||||
newstart := startnumber + NEW.step;
|
|
||||||
|
linegeo := null;
|
||||||
|
SELECT null::integer as hnr INTO prevnode;
|
||||||
|
|
||||||
|
-- Go through all nodes on the interpolation line that have a housenumber.
|
||||||
|
FOR nextnode IN
|
||||||
|
SELECT DISTINCT ON (nodeidpos)
|
||||||
|
osm_id, address, geometry,
|
||||||
|
-- Take the postcode from the node only if it has a housenumber itself.
|
||||||
|
-- Note that there is a corner-case where the node has a wrongly
|
||||||
|
-- formatted postcode and therefore 'postcode' contains a derived
|
||||||
|
-- variant.
|
||||||
|
CASE WHEN address ? 'postcode' THEN placex.postcode ELSE NULL::text END as postcode,
|
||||||
|
(address->'housenumber')::integer as hnr
|
||||||
|
FROM placex, generate_series(1, array_upper(waynodes, 1)) nodeidpos
|
||||||
|
WHERE osm_type = 'N' and osm_id = waynodes[nodeidpos]::BIGINT
|
||||||
|
and address is not NULL and address ? 'housenumber'
|
||||||
|
and address->'housenumber' ~ '^[0-9]{1,6}$'
|
||||||
|
and ST_Distance(NEW.linegeo, geometry) < 0.0005
|
||||||
|
ORDER BY nodeidpos
|
||||||
|
LOOP
|
||||||
|
{% if debug %}RAISE WARNING 'processing point % (%)', nextnode.hnr, ST_AsText(nextnode.geometry);{% endif %}
|
||||||
|
IF linegeo is null THEN
|
||||||
|
linegeo := NEW.linegeo;
|
||||||
ELSE
|
ELSE
|
||||||
newstart := startnumber + 1;
|
splitpoint := ST_LineLocatePoint(linegeo, nextnode.geometry);
|
||||||
moddiff := newstart % NEW.step - stepmod;
|
IF splitpoint = 0 THEN
|
||||||
IF moddiff < 0 THEN
|
-- Corner case where the splitpoint falls on the first point
|
||||||
newstart := newstart + (NEW.step + moddiff);
|
-- and thus would not return a geometry. Skip that section.
|
||||||
|
sectiongeo := NULL;
|
||||||
|
ELSEIF splitpoint = 1 THEN
|
||||||
|
-- Point is at the end of the line.
|
||||||
|
sectiongeo := linegeo;
|
||||||
|
linegeo := NULL;
|
||||||
ELSE
|
ELSE
|
||||||
newstart := newstart + moddiff;
|
-- Split the line.
|
||||||
|
sectiongeo := ST_LineSubstring(linegeo, 0, splitpoint);
|
||||||
|
linegeo := ST_LineSubstring(linegeo, splitpoint, 1);
|
||||||
END IF;
|
END IF;
|
||||||
END IF;
|
END IF;
|
||||||
newend := newstart + ((endnumber - 1 - newstart) / NEW.step) * NEW.step;
|
|
||||||
|
|
||||||
-- If newstart and newend are the same, then this returns a point.
|
IF prevnode.hnr is not null
|
||||||
sectiongeo := ST_LineSubstring(sectiongeo,
|
-- Check if there are housenumbers to interpolate between the
|
||||||
(newstart - startnumber)::float / (endnumber - startnumber)::float,
|
-- regularly mapped housenumbers.
|
||||||
(newend - startnumber)::float / (endnumber - startnumber)::float);
|
-- (Conveniently also fails if one of the house numbers is not a number.)
|
||||||
startnumber := newstart;
|
and abs(prevnode.hnr - nextnode.hnr) > NEW.step
|
||||||
endnumber := newend;
|
-- If the interpolation geometry is broken or two nodes are at the
|
||||||
|
-- same place, then splitting might produce a point. Ignore that.
|
||||||
|
and ST_GeometryType(sectiongeo) = 'ST_LineString'
|
||||||
|
THEN
|
||||||
|
IF prevnode.hnr < nextnode.hnr THEN
|
||||||
|
startnumber := prevnode.hnr;
|
||||||
|
endnumber := nextnode.hnr;
|
||||||
|
ELSE
|
||||||
|
startnumber := nextnode.hnr;
|
||||||
|
endnumber := prevnode.hnr;
|
||||||
|
sectiongeo := ST_Reverse(sectiongeo);
|
||||||
|
END IF;
|
||||||
|
|
||||||
-- determine postcode
|
-- Adjust the interpolation, so that only inner housenumbers
|
||||||
postcode := coalesce(prevnode.postcode, nextnode.postcode, postcode);
|
-- are taken into account.
|
||||||
IF postcode is NULL and NEW.parent_place_id > 0 THEN
|
IF stepmod is null THEN
|
||||||
SELECT placex.postcode FROM placex
|
newstart := startnumber + NEW.step;
|
||||||
WHERE place_id = NEW.parent_place_id INTO postcode;
|
ELSE
|
||||||
END IF;
|
newstart := startnumber + 1;
|
||||||
IF postcode is NULL THEN
|
moddiff := newstart % NEW.step - stepmod;
|
||||||
postcode := get_nearest_postcode(NEW.country_code, nextnode.geometry);
|
IF moddiff < 0 THEN
|
||||||
|
newstart := newstart + (NEW.step + moddiff);
|
||||||
|
ELSE
|
||||||
|
newstart := newstart + moddiff;
|
||||||
|
END IF;
|
||||||
|
END IF;
|
||||||
|
newend := newstart + ((endnumber - 1 - newstart) / NEW.step) * NEW.step;
|
||||||
|
|
||||||
|
-- If newstart and newend are the same, then this returns a point.
|
||||||
|
sectiongeo := ST_LineSubstring(sectiongeo,
|
||||||
|
(newstart - startnumber)::float / (endnumber - startnumber)::float,
|
||||||
|
(newend - startnumber)::float / (endnumber - startnumber)::float);
|
||||||
|
startnumber := newstart;
|
||||||
|
endnumber := newend;
|
||||||
|
|
||||||
|
-- determine postcode
|
||||||
|
postcode := coalesce(prevnode.postcode, nextnode.postcode, postcode);
|
||||||
|
IF postcode is NULL and NEW.parent_place_id > 0 THEN
|
||||||
|
SELECT placex.postcode FROM placex
|
||||||
|
WHERE place_id = NEW.parent_place_id INTO postcode;
|
||||||
|
END IF;
|
||||||
|
IF postcode is NULL THEN
|
||||||
|
postcode := get_nearest_postcode(NEW.country_code, nextnode.geometry);
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- Add the interpolation. If this is the first segment, just modify
|
||||||
|
-- the interpolation to be inserted, otherwise add an additional one
|
||||||
|
-- (marking it indexed already).
|
||||||
|
IF NEW.startnumber IS NULL THEN
|
||||||
|
NEW.startnumber := startnumber;
|
||||||
|
NEW.endnumber := endnumber;
|
||||||
|
NEW.linegeo := ST_ReducePrecision(sectiongeo, 0.0000001);
|
||||||
|
NEW.postcode := postcode;
|
||||||
|
ELSE
|
||||||
|
INSERT INTO location_property_osmline
|
||||||
|
(linegeo, partition, osm_type, osm_id, parent_place_id,
|
||||||
|
startnumber, endnumber, step, type,
|
||||||
|
address, postcode, country_code,
|
||||||
|
geometry_sector, indexed_status)
|
||||||
|
VALUES (ST_ReducePrecision(sectiongeo, 0.0000001),
|
||||||
|
NEW.partition, NEW.osm_type, NEW.osm_id, NEW.parent_place_id,
|
||||||
|
startnumber, endnumber, NEW.step, NEW.type,
|
||||||
|
NEW.address, postcode,
|
||||||
|
NEW.country_code, NEW.geometry_sector, 0);
|
||||||
|
END IF;
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
-- Add the interpolation. If this is the first segment, just modify
|
-- early break if we are out of line string,
|
||||||
-- the interpolation to be inserted, otherwise add an additional one
|
-- might happen when a line string loops back on itself
|
||||||
-- (marking it indexed already).
|
IF linegeo is null or ST_GeometryType(linegeo) != 'ST_LineString' THEN
|
||||||
IF NEW.startnumber IS NULL THEN
|
RETURN NEW;
|
||||||
NEW.startnumber := startnumber;
|
|
||||||
NEW.endnumber := endnumber;
|
|
||||||
NEW.linegeo := ST_ReducePrecision(sectiongeo, 0.0000001);
|
|
||||||
NEW.postcode := postcode;
|
|
||||||
ELSE
|
|
||||||
INSERT INTO location_property_osmline
|
|
||||||
(linegeo, partition, osm_id, parent_place_id,
|
|
||||||
startnumber, endnumber, step,
|
|
||||||
address, postcode, country_code,
|
|
||||||
geometry_sector, indexed_status)
|
|
||||||
VALUES (ST_ReducePrecision(sectiongeo, 0.0000001),
|
|
||||||
NEW.partition, NEW.osm_id, NEW.parent_place_id,
|
|
||||||
startnumber, endnumber, NEW.step,
|
|
||||||
NEW.address, postcode,
|
|
||||||
NEW.country_code, NEW.geometry_sector, 0);
|
|
||||||
END IF;
|
END IF;
|
||||||
END IF;
|
|
||||||
|
|
||||||
-- early break if we are out of line string,
|
prevnode := nextnode;
|
||||||
-- might happen when a line string loops back on itself
|
END LOOP;
|
||||||
IF linegeo is null or ST_GeometryType(linegeo) != 'ST_LineString' THEN
|
END IF;
|
||||||
RETURN NEW;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
prevnode := nextnode;
|
|
||||||
END LOOP;
|
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
RETURN NEW;
|
RETURN NEW;
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ DECLARE
|
|||||||
existing RECORD;
|
existing RECORD;
|
||||||
existingplacex RECORD;
|
existingplacex RECORD;
|
||||||
existingline BIGINT[];
|
existingline BIGINT[];
|
||||||
interpol RECORD;
|
|
||||||
BEGIN
|
BEGIN
|
||||||
{% if debug %}
|
{% if debug %}
|
||||||
RAISE WARNING 'place_insert: % % % % %',NEW.osm_type,NEW.osm_id,NEW.class,NEW.type,st_area(NEW.geometry);
|
RAISE WARNING 'place_insert: % % % % %',NEW.osm_type,NEW.osm_id,NEW.class,NEW.type,st_area(NEW.geometry);
|
||||||
@@ -55,41 +54,6 @@ BEGIN
|
|||||||
DELETE from import_polygon_error where osm_type = NEW.osm_type and osm_id = NEW.osm_id;
|
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;
|
DELETE from import_polygon_delete where osm_type = NEW.osm_type and osm_id = NEW.osm_id;
|
||||||
|
|
||||||
-- ---- Interpolation Lines
|
|
||||||
|
|
||||||
IF NEW.class='place' and NEW.type='houses'
|
|
||||||
and NEW.osm_type='W' and ST_GeometryType(NEW.geometry) = 'ST_LineString'
|
|
||||||
THEN
|
|
||||||
PERFORM reinsert_interpolation(NEW.osm_id, NEW.address, NEW.geometry);
|
|
||||||
|
|
||||||
-- Now invalidate all address nodes on the line.
|
|
||||||
-- They get their parent from the interpolation.
|
|
||||||
UPDATE placex p SET indexed_status = 2
|
|
||||||
FROM planet_osm_ways w
|
|
||||||
WHERE w.id = NEW.osm_id and p.osm_type = 'N' and p.osm_id = any(w.nodes)
|
|
||||||
and indexed_status = 0;
|
|
||||||
|
|
||||||
-- If there is already an entry in place, just update that, if necessary.
|
|
||||||
IF existing.osm_type is not null THEN
|
|
||||||
IF coalesce(existing.address, ''::hstore) != coalesce(NEW.address, ''::hstore)
|
|
||||||
OR existing.geometry::text != NEW.geometry::text
|
|
||||||
THEN
|
|
||||||
UPDATE place
|
|
||||||
SET name = NEW.name,
|
|
||||||
address = NEW.address,
|
|
||||||
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;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
RETURN NULL;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
RETURN NEW;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
-- ---- All other place types.
|
-- ---- All other place types.
|
||||||
|
|
||||||
-- When an area is changed from large to small: log and discard change
|
-- When an area is changed from large to small: log and discard change
|
||||||
@@ -109,29 +73,6 @@ BEGIN
|
|||||||
RETURN null;
|
RETURN null;
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
-- If an address node is part of a interpolation line and changes or is
|
|
||||||
-- newly inserted (happens when the node already existed but now gets address
|
|
||||||
-- information), then mark the interpolation line for reparenting.
|
|
||||||
-- (Already here, because interpolation lines are reindexed before nodes,
|
|
||||||
-- so in the second call it would be too late.)
|
|
||||||
IF NEW.osm_type='N'
|
|
||||||
and coalesce(existing.address, ''::hstore) != coalesce(NEW.address, ''::hstore)
|
|
||||||
THEN
|
|
||||||
FOR interpol IN
|
|
||||||
SELECT DISTINCT osm_id, address, geometry FROM place, planet_osm_ways w
|
|
||||||
WHERE NEW.geometry && place.geometry
|
|
||||||
and place.osm_type = 'W'
|
|
||||||
and place.address ? 'interpolation'
|
|
||||||
and exists (SELECT * FROM location_property_osmline
|
|
||||||
WHERE osm_id = place.osm_id
|
|
||||||
and indexed_status in (0, 2))
|
|
||||||
and w.id = place.osm_id and NEW.osm_id = any (w.nodes)
|
|
||||||
LOOP
|
|
||||||
PERFORM reinsert_interpolation(interpol.osm_id, interpol.address,
|
|
||||||
interpol.geometry);
|
|
||||||
END LOOP;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
-- Get the existing placex entry.
|
-- Get the existing placex entry.
|
||||||
SELECT * INTO existingplacex
|
SELECT * INTO existingplacex
|
||||||
FROM placex
|
FROM placex
|
||||||
|
|||||||
@@ -53,12 +53,10 @@ BEGIN
|
|||||||
-- See if we can inherit additional address tags from an interpolation.
|
-- See if we can inherit additional address tags from an interpolation.
|
||||||
-- These will become permanent.
|
-- These will become permanent.
|
||||||
FOR location IN
|
FOR location IN
|
||||||
SELECT (address - 'interpolation'::text - 'housenumber'::text) as address
|
SELECT address as address
|
||||||
FROM place, planet_osm_ways w
|
FROM place_interpolation
|
||||||
WHERE place.osm_type = 'W' and place.address ? 'interpolation'
|
WHERE p.osm_id = any(place_interpolation.nodes)
|
||||||
and place.geometry && p.geometry
|
AND address is not NULL AND not address ? 'housenumber'
|
||||||
and place.osm_id = w.id
|
|
||||||
and p.osm_id = any(w.nodes)
|
|
||||||
LOOP
|
LOOP
|
||||||
result.address := location.address || result.address;
|
result.address := location.address || result.address;
|
||||||
END LOOP;
|
END LOOP;
|
||||||
|
|||||||
@@ -624,18 +624,22 @@ BEGIN
|
|||||||
and placex.type = place_to_be_deleted.type
|
and placex.type = place_to_be_deleted.type
|
||||||
and not deferred;
|
and not deferred;
|
||||||
|
|
||||||
-- Mark for delete in interpolations
|
-- Clear todo list.
|
||||||
UPDATE location_property_osmline SET indexed_status = 100 FROM place_to_be_deleted
|
TRUNCATE TABLE place_to_be_deleted;
|
||||||
WHERE place_to_be_deleted.osm_type = 'W'
|
|
||||||
and place_to_be_deleted.class = 'place'
|
|
||||||
and place_to_be_deleted.type = 'houses'
|
|
||||||
and location_property_osmline.osm_id = place_to_be_deleted.osm_id
|
|
||||||
and not deferred;
|
|
||||||
|
|
||||||
-- Clear todo list.
|
-- delete from place_interpolation table
|
||||||
TRUNCATE TABLE place_to_be_deleted;
|
ALTER TABLE place_interpolation DISABLE TRIGGER place_interpolation_before_delete;
|
||||||
|
DELETE FROM place_interpolation p USING place_interpolation_to_be_deleted d
|
||||||
|
WHERE p.osm_type = d.osm_type AND p.osm_id = d.osm_id;
|
||||||
|
ALTER TABLE place_interpolation ENABLE TRIGGER place_interpolation_before_delete;
|
||||||
|
|
||||||
RETURN NULL;
|
UPDATE location_property_osmline o SET indexed_status = 100
|
||||||
|
FROM place_interpolation_to_be_deleted d
|
||||||
|
WHERE o.osm_type = d.osm_Type AND o.osm_id = d.osm_id;
|
||||||
|
|
||||||
|
TRUNCATE TABLE place_interpolation_to_be_deleted;
|
||||||
|
|
||||||
|
RETURN NULL;
|
||||||
END;
|
END;
|
||||||
$$ LANGUAGE plpgsql;
|
$$ LANGUAGE plpgsql;
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
--
|
--
|
||||||
-- This file is part of Nominatim. (https://nominatim.org)
|
-- This file is part of Nominatim. (https://nominatim.org)
|
||||||
--
|
--
|
||||||
-- Copyright (C) 2025 by the Nominatim developer community.
|
-- Copyright (C) 2026 by the Nominatim developer community.
|
||||||
-- For a full list of authors see the git log.
|
-- For a full list of authors see the git log.
|
||||||
|
|
||||||
-- Indices used only during search and update.
|
-- Indices used only during search and update.
|
||||||
@@ -67,11 +67,16 @@ CREATE INDEX IF NOT EXISTS idx_osmline_parent_osm_id
|
|||||||
---
|
---
|
||||||
-- Table needed for running updates with osm2pgsql on place.
|
-- Table needed for running updates with osm2pgsql on place.
|
||||||
CREATE TABLE IF NOT EXISTS place_to_be_deleted (
|
CREATE TABLE IF NOT EXISTS place_to_be_deleted (
|
||||||
osm_type CHAR(1),
|
osm_type CHAR(1) NOT NULL,
|
||||||
osm_id BIGINT,
|
osm_id BIGINT NOT NULL,
|
||||||
class TEXT,
|
class TEXT NOT NULL,
|
||||||
type TEXT,
|
type TEXT NOT NULL,
|
||||||
deferred BOOLEAN
|
deferred BOOLEAN NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS place_interpolation_to_be_deleted (
|
||||||
|
osm_type CHAR(1) NOT NULL,
|
||||||
|
osm_id BIGINT NOT NULL
|
||||||
);
|
);
|
||||||
---
|
---
|
||||||
CREATE INDEX IF NOT EXISTS idx_location_postcodes_parent_place_id
|
CREATE INDEX IF NOT EXISTS idx_location_postcodes_parent_place_id
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
--
|
--
|
||||||
-- This file is part of Nominatim. (https://nominatim.org)
|
-- This file is part of Nominatim. (https://nominatim.org)
|
||||||
--
|
--
|
||||||
-- Copyright (C) 2025 by the Nominatim developer community.
|
-- Copyright (C) 2026 by the Nominatim developer community.
|
||||||
-- For a full list of authors see the git log.
|
-- For a full list of authors see the git log.
|
||||||
|
|
||||||
-- insert creates the location tables, creates location indexes if indexed == true
|
-- insert creates the location tables, creates location indexes if indexed == true
|
||||||
@@ -31,3 +31,8 @@ CREATE TRIGGER location_postcodes_before_delete BEFORE DELETE ON location_postco
|
|||||||
FOR EACH ROW EXECUTE PROCEDURE postcodes_delete();
|
FOR EACH ROW EXECUTE PROCEDURE postcodes_delete();
|
||||||
CREATE TRIGGER location_postcodes_before_insert BEFORE INSERT ON location_postcodes
|
CREATE TRIGGER location_postcodes_before_insert BEFORE INSERT ON location_postcodes
|
||||||
FOR EACH ROW EXECUTE PROCEDURE postcodes_insert();
|
FOR EACH ROW EXECUTE PROCEDURE postcodes_insert();
|
||||||
|
|
||||||
|
CREATE TRIGGER place_interpolation_before_insert BEFORE INSERT ON place_interpolation
|
||||||
|
FOR EACH ROW EXECUTE PROCEDURE place_interpolation_insert();
|
||||||
|
CREATE TRIGGER place_interpolation_before_delete BEFORE DELETE ON place_interpolation
|
||||||
|
FOR EACH ROW EXECUTE PROCEDURE place_interpolation_delete();
|
||||||
|
|||||||
@@ -32,8 +32,3 @@ CREATE INDEX planet_osm_rels_relation_members_idx ON planet_osm_rels USING gin(p
|
|||||||
WITH (fastupdate=off)
|
WITH (fastupdate=off)
|
||||||
{{db.tablespace.address_index}};
|
{{db.tablespace.address_index}};
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
-- Needed for lookups if a node is part of an interpolation.
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_place_interpolations
|
|
||||||
ON place USING gist(geometry) {{db.tablespace.address_index}}
|
|
||||||
WHERE osm_type = 'W' and address ? 'interpolation';
|
|
||||||
|
|||||||
Reference in New Issue
Block a user