Skip to content

Instantly share code, notes, and snippets.

@rmarianski
Last active September 18, 2015 17:45
Show Gist options
  • Save rmarianski/c1b80ee6240641c1c9ca to your computer and use it in GitHub Desktop.
Save rmarianski/c1b80ee6240641c1c9ca to your computer and use it in GitHub Desktop.
db migration 20150918
-- functions.sql will get run first
-- point.sql and polygon.sql will get run in parallel
-- cleanup-point.sql will get run after the new code gets deployed
-- diffs will be turned off before applying updates, and then re-enabled
-- nothing should lock the tables for reading though
--------------------------------------------------------------------------------
-- functions.sql
CREATE OR REPLACE FUNCTION mz_calculate_poi_level(
aerialway_val text,
aeroway_val text,
amenity_val text,
barrier_val text,
craft_val text,
highway_val text,
historic_val text,
leisure_val text,
lock_val text,
man_made_val text,
natural_val text,
office_val text,
power_val text,
railway_val text,
shop_val text,
tourism_val text,
waterway_val text,
way_area real
)
RETURNS SMALLINT AS $$
DECLARE
zoom smallint;
BEGIN
zoom =
CASE WHEN natural_val IN ('peak', 'volcano') THEN 11
WHEN railway_val IN ('station') THEN 12
WHEN (aeroway_val IN ('aerodrome', 'airport')
OR aerialway_val IN ('station')
OR railway_val IN ('halt', 'tram_stop')
OR tourism_val IN ('alpine_hut', 'zoo')) THEN 13
WHEN (natural_val IN ('spring')
OR railway_val IN ('level_crossing')) THEN 14
WHEN (amenity_val IN ('hospital')
OR barrier_val IN ('gate')
OR craft_val IN ('sawmill')
OR highway_val IN ('gate', 'mini_roundabout')
OR lock_val IN ('yes')
OR man_made_val IN ('lighthouse', 'power_wind')
OR natural_val IN ('cave_entrance')
OR power_val IN ('generator')
OR waterway_val IN ('lock')) THEN 15
WHEN (aeroway_val IN ('helipad')
OR amenity_val IN ('biergarten', 'bus_station', 'car_sharing',
'picnic_site', 'place_of_worship',
'prison', 'pub', 'recycling', 'shelter')
OR barrier_val IN ('block', 'bollard', 'lift_gate')
OR craft_val IN ('brewery', 'winery', 'sawmill')
OR highway_val IN ('ford')
OR historic_val IN ('archaeological_site')
OR man_made_val IN ('windmill')
OR natural_val IN ('tree')
OR shop_val IN ('department_store', 'supermarket')
OR tourism_val IN ('camp_site', 'caravan_site', 'information', 'viewpoint')) THEN 16
WHEN (aeroway_val IN ('gate')
OR amenity_val IN (
'atm', 'bank', 'bar', 'bicycle_rental', 'bicycle_parking', 'bus_stop',
'cafe', 'cinema', 'courthouse', 'drinking_water', 'embassy', 'emergency_phone',
'fast_food', 'fire_station', 'fuel', 'library', 'parking', 'pharmacy',
'police', 'post_box', 'post_office', 'restaurant', 'telephone', 'theatre',
'toilets', 'veterinary')
OR craft_val IN ('brewery', 'carpenter', 'confectionery', 'dressmaker',
'electrician', 'gardener', 'handicraft', 'hvac', 'metal_construction',
'painter', 'photographer', 'photographic_laboratory', 'plumber',
'pottery', 'sawmill', 'shoemaker', 'stonemason', 'tailor', 'winery')
OR highway_val IN ('bus_stop', 'traffic_signals')
OR historic_val IN ('memorial')
OR leisure_val IN ('playground', 'slipway')
OR man_made_val IN ('mast', 'water_tower')
OR office_val IN ('accountant', 'administrative', 'advertising_agency',
'architect', 'association', 'company', 'consulting', 'educational_institution',
'employment_agency', 'estate_agent', 'financial', 'foundation', 'government',
'insurance', 'it', 'lawyer', 'newspaper', 'ngo', 'notary', 'physician',
'political_party', 'religion', 'research', 'tax_advisor', 'telecommunication',
'therapist', 'travel_agent', 'yes')
OR shop_val IN ('bakery', 'bicycle', 'books', 'butcher', 'car', 'car_repair',
'clothes', 'computer', 'convenience',
'doityourself', 'dry_cleaning', 'fashion', 'florist', 'gift',
'greengrocer', 'hairdresser', 'jewelry', 'mobile_phone',
'optician', 'pet')
OR tourism_val IN ('bed_and_breakfast', 'chalet', 'guest_house',
'hostel', 'hotel', 'motel', 'museum')
OR railway_val IN ('subway_entrance')) THEN 17
WHEN (amenity_val IN ('bench', 'waste_basket')) THEN 18
ELSE NULL END;
RETURN (CASE
WHEN way_area > 1.0e7 THEN zoom - 4
WHEN way_area > 1.0e6 THEN zoom - 3
WHEN way_area > 1.0e5 THEN zoom - 2
WHEN way_area > 1.0e4 THEN zoom - 1
ELSE zoom END);
END;
$$ LANGUAGE plpgsql IMMUTABLE;
-- adds the prefix onto every key in an hstore value
CREATE OR REPLACE FUNCTION mz_hstore_add_prefix(
tags hstore,
prefix text)
RETURNS hstore AS $$
DECLARE
new_tags hstore;
BEGIN
SELECT hstore(array_agg(prefix || key), array_agg(value))
INTO STRICT new_tags
FROM each(tags);
RETURN new_tags;
END;
$$ LANGUAGE plpgsql IMMUTABLE;
-- OSM tags are often structured as a list separated by ':'s.
-- to preserve some kind of ordering information, we want to
-- insert an element in this "list" after the first element.
-- i.e: mz_insert_one_level('foo:bar', 'x') -> 'foo:x:bar'.
CREATE OR REPLACE FUNCTION mz_insert_one_level(
tag text,
str text)
RETURNS text AS $$
DECLARE
arr text[] = string_to_array(tag, ':');
fst text = arr[1];
len int = array_upper(arr, 1);
rst text[] = arr[2:len];
BEGIN
RETURN array_to_string(ARRAY[fst, str] || rst, ':');
END;
$$ LANGUAGE plpgsql IMMUTABLE;
-- adds an infix value into every key in an hstore value after
-- the first element. so 'foo:bar=>bat' with infix 'x' becomes
-- 'foo:x:bar=>bat'.
CREATE OR REPLACE FUNCTION mz_hstore_add_infix(
tags hstore,
infix text)
RETURNS hstore AS $$
DECLARE
new_tags hstore;
BEGIN
SELECT hstore(array_agg(mz_insert_one_level(key, infix)), array_agg(value))
INTO STRICT new_tags
FROM each(tags);
RETURN new_tags;
END;
$$ LANGUAGE plpgsql IMMUTABLE;
--------------------------------------------------------------------------------
-- point.sql
ALTER TABLE planet_osm_point ADD COLUMN mz_poi_min_zoom SMALLINT;
UPDATE planet_osm_point SET
mz_poi_min_zoom = mz_calculate_poi_level("aerialway", "aeroway", "amenity", "barrier", "craft", "highway", "historic", "leisure", "lock", "man_made", "natural", "office", "power", "railway", "shop", "tourism", "waterway", 0::real)
WHERE coalesce("aerialway", "aeroway", "amenity", "barrier", "craft", "highway", "historic", "leisure", "lock", "man_made", "natural", "office", "power", "railway", "shop", "tourism", "waterway") IS NOT NULL;
CREATE OR REPLACE FUNCTION mz_trigger_function_point()
RETURNS TRIGGER AS $$
BEGIN
NEW.mz_poi_min_zoom := mz_calculate_poi_level(NEW."aerialway", NEW."aeroway", NEW."amenity", NEW."barrier", NEW."craft", NEW."highway", NEW."historic", NEW."leisure", NEW."lock", NEW."man_made", NEW."natural", NEW."office", NEW."power", NEW."railway", NEW."shop", NEW."tourism", NEW."waterway", 0::real);
RETURN NEW;
END;
$$ LANGUAGE plpgsql VOLATILE;
CREATE TRIGGER mz_trigger_point BEFORE INSERT OR UPDATE ON planet_osm_point FOR EACH ROW EXECUTE PROCEDURE mz_trigger_function_point();
--------------------------------------------------------------------------------
-- polygon.sql
DROP TRIGGER mz_trigger_landuse ON planet_osm_polygon;
DROP FUNCTION mz_trigger_function_landuse();
ALTER TABLE planet_osm_polygon ADD COLUMN mz_poi_min_zoom SMALLINT;
UPDATE planet_osm_polygon SET
mz_poi_min_zoom = mz_calculate_poi_level("aerialway", "aeroway", "amenity", "barrier", "craft", "highway", "historic", "leisure", "lock", "man_made", "natural", "office", "power", "railway", "shop", "tourism", "waterway", way_area)
WHERE coalesce("aerialway", "aeroway", "amenity", "barrier", "craft", "highway", "historic", "leisure", "lock", "man_made", "natural", "office", "power", "railway", "shop", "tourism", "waterway") IS NOT NULL;
CREATE OR REPLACE FUNCTION mz_trigger_function_polygon()
RETURNS TRIGGER AS $$
DECLARE
mz_is_landuse BOOLEAN = mz_calculate_is_landuse(NEW."landuse", NEW."leisure", NEW."natural", NEW."highway", NEW."amenity", NEW."aeroway", NEW."tourism", NEW."man_made", NEW."power");
mz_poi_min_zoom SMALLINT = mz_calculate_poi_level(NEW."aerialway", NEW."aeroway", NEW."amenity", NEW."barrier", NEW."craft", NEW."highway", NEW."historic", NEW."leisure", NEW."lock", NEW."man_made", NEW."natural", NEW."office", NEW."power", NEW."railway", NEW."shop", NEW."tourism", NEW."waterway", NEW.way_area);
BEGIN
IF mz_is_landuse THEN
NEW.mz_is_landuse := TRUE;
ELSE
NEW.mz_is_landuse := NULL;
END IF;
NEW.mz_poi_min_zoom := mz_poi_min_zoom;
IF mz_is_landuse OR mz_poi_min_zoom IS NOT NULL THEN
NEW.mz_centroid := ST_Centroid(NEW.way);
ELSE
NEW.mz_centroid := NULL;
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql VOLATILE;
CREATE TRIGGER mz_trigger_polygon BEFORE INSERT OR UPDATE ON planet_osm_polygon FOR EACH ROW EXECUTE PROCEDURE mz_trigger_function_polygon();
--------------------------------------------------------------------------------
-- cleanup-point.sql - to be run after new code gets deployed
DROP INDEX planet_osm_point_level_index;
DROP FUNCTION mz_calculate_poi_level(text, text, text, text, text, text, text, text, text,text, text, text, text, text, text, text, text);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment